Skip to content

Commit 04e346d

Browse files
committed
Track transaction time
1 parent cbf4d58 commit 04e346d

File tree

4 files changed

+56
-12
lines changed

4 files changed

+56
-12
lines changed

src/client.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,9 +1204,12 @@ where
12041204
if !server.in_transaction() {
12051205
// Report transaction executed statistics.
12061206
self.stats.transaction();
1207-
server
1208-
.stats()
1209-
.transaction(self.server_parameters.get_application_name());
1207+
server.stats().transaction(
1208+
Instant::now()
1209+
.duration_since(server.transaction_start().into())
1210+
.as_millis() as u64,
1211+
self.server_parameters.get_application_name(),
1212+
);
12101213

12111214
// Release server back to the pool if we are in transaction mode.
12121215
// If we are in session mode, we keep the server until the client disconnects.
@@ -1460,9 +1463,12 @@ where
14601463

14611464
if !server.in_transaction() {
14621465
self.stats.transaction();
1463-
server
1464-
.stats()
1465-
.transaction(self.server_parameters.get_application_name());
1466+
server.stats().transaction(
1467+
Instant::now()
1468+
.duration_since(server.transaction_start().into())
1469+
.as_millis() as u64,
1470+
self.server_parameters.get_application_name(),
1471+
);
14661472

14671473
// Release server back to the pool if we are in transaction mode.
14681474
// If we are in session mode, we keep the server until the client disconnects.
@@ -1511,9 +1517,12 @@ where
15111517

15121518
if !server.in_transaction() {
15131519
self.stats.transaction();
1514-
server
1515-
.stats()
1516-
.transaction(self.server_parameters.get_application_name());
1520+
server.stats().transaction(
1521+
Instant::now()
1522+
.duration_since(server.transaction_start().into())
1523+
.as_millis() as u64,
1524+
self.server_parameters.get_application_name(),
1525+
);
15171526

15181527
// Release server back to the pool if we are in transaction mode.
15191528
// If we are in session mode, we keep the server until the client disconnects.

src/server.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use std::sync::Arc;
1515
use std::time::SystemTime;
1616
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, BufStream};
1717
use tokio::net::TcpStream;
18+
use tokio::time::Instant;
1819
use tokio_rustls::rustls::{OwnedTrustAnchor, RootCertStore};
1920
use tokio_rustls::{client::TlsStream, TlsConnector};
2021

@@ -285,6 +286,9 @@ pub struct Server {
285286
/// Is the server inside a transaction or idle.
286287
in_transaction: bool,
287288

289+
/// The time the most recent transaction started.
290+
transaction_start: Instant,
291+
288292
/// Is there more data for the client to read.
289293
data_available: bool,
290294

@@ -804,6 +808,7 @@ impl Server {
804808
process_id,
805809
secret_key,
806810
in_transaction: false,
811+
transaction_start: Instant::now(),
807812
in_copy_mode: false,
808813
data_available: false,
809814
bad: false,
@@ -936,6 +941,7 @@ impl Server {
936941
// In transaction.
937942
'T' => {
938943
self.in_transaction = true;
944+
self.transaction_start = Instant::now();
939945
}
940946

941947
// Idle, transaction over.
@@ -1220,6 +1226,12 @@ impl Server {
12201226
self.in_transaction
12211227
}
12221228

1229+
/// The start time of the most recent transaction.
1230+
/// Will be stale if not in a transaction.
1231+
pub fn transaction_start(&self) -> Instant {
1232+
self.transaction_start
1233+
}
1234+
12231235
/// Currently copying data from client to server or vice-versa.
12241236
pub fn in_copy_mode(&self) -> bool {
12251237
self.in_copy_mode

src/stats/server.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,12 @@ impl ServerStats {
187187
/// we report each individual queries outside a transaction as a transaction
188188
/// We only count the initial BEGIN as a transaction, all queries within do not
189189
/// count as transactions
190-
pub fn transaction(&self, application_name: &str) {
190+
pub fn transaction(&self, milliseconds: u64, application_name: &str) {
191191
self.set_application(application_name.to_string());
192192

193193
self.transaction_count.fetch_add(1, Ordering::Relaxed);
194194
self.address.stats.xact_count_add();
195+
self.address.stats.xact_time_add(milliseconds);
195196
}
196197

197198
/// Report data sent to a server

tests/ruby/stats_spec.rb

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
it "updates *_query_time and *_wait_time" do
1717
connections = Array.new(3) { PG::connect("#{pgcat_conn_str}?application_name=one_query") }
1818
connections.each do |c|
19-
Thread.new { c.async_exec("SELECT pg_sleep(0.25)") }
19+
Thread.new { c.async_exec("BEGIN; SELECT pg_sleep(0.25); COMMIT;") }
2020
end
2121
sleep(1)
2222
connections.map(&:close)
@@ -25,10 +25,32 @@
2525
sleep(15.5)
2626
admin_conn = PG::connect(processes.pgcat.admin_connection_string)
2727
results = admin_conn.async_exec("SHOW STATS")[0]
28-
admin_conn.close
2928
expect(results["total_query_time"].to_i).to be_within(200).of(750)
3029
expect(results["avg_query_time"].to_i).to be_within(50).of(250)
3130

31+
expect(results["total_xact_time"].to_i).to be_within(200).of(750)
32+
expect(results["avg_xact_time"].to_i).to be_within(50).of(250)
33+
34+
expect(results["total_wait_time"].to_i).to_not eq(0)
35+
expect(results["avg_wait_time"].to_i).to_not eq(0)
36+
37+
connections = Array.new(3) { PG::connect("#{pgcat_conn_str}?application_name=one_query") }
38+
connections.each do |c|
39+
Thread.new { c.async_exec("SELECT pg_sleep(0.25);") }
40+
end
41+
sleep(1)
42+
connections.map(&:close)
43+
44+
results = admin_conn.async_exec("SHOW STATS")[0]
45+
admin_conn.close
46+
# This should increase with more queries
47+
expect(results["total_query_time"].to_i).to be_within(400).of(1500)
48+
expect(results["avg_query_time"].to_i).to be_within(50).of(250)
49+
50+
# This should not increase as we did not run any additional transactions
51+
expect(results["total_xact_time"].to_i).to be_within(200).of(750)
52+
expect(results["avg_xact_time"].to_i).to be_within(50).of(250)
53+
3254
expect(results["total_wait_time"].to_i).to_not eq(0)
3355
expect(results["avg_wait_time"].to_i).to_not eq(0)
3456
end

0 commit comments

Comments
 (0)