Skip to content

Commit 05b4ccc

Browse files
authored
More statistics (#20)
* cleaner stats * remove shard selection there
1 parent 659b1e0 commit 05b4ccc

File tree

5 files changed

+136
-51
lines changed

5 files changed

+136
-51
lines changed

src/client.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub struct Client {
5757
default_server_role: Option<Role>,
5858

5959
// Client parameters, e.g. user, client_encoding, etc.
60+
#[allow(dead_code)]
6061
parameters: HashMap<String, String>,
6162

6263
// Statistics
@@ -302,8 +303,11 @@ impl Client {
302303

303304
// Release server
304305
if self.transaction_mode {
306+
self.stats.client_idle();
307+
305308
shard = None;
306309
role = self.default_server_role;
310+
307311
break;
308312
}
309313
}
@@ -371,8 +375,11 @@ impl Client {
371375
self.stats.transaction();
372376

373377
if self.transaction_mode {
378+
self.stats.client_idle();
379+
374380
shard = None;
375381
role = self.default_server_role;
382+
376383
break;
377384
}
378385
}

src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub enum Role {
1717
pub struct Address {
1818
pub host: String,
1919
pub port: String,
20+
pub shard: usize,
2021
pub role: Role,
2122
}
2223

src/pool.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl ConnectionPool {
5757
let mut pools = Vec::new();
5858
let mut replica_addresses = Vec::new();
5959

60-
for server in &shard.servers {
60+
for (idx, server) in shard.servers.iter().enumerate() {
6161
let role = match server.2.as_ref() {
6262
"primary" => Role::Primary,
6363
"replica" => Role::Replica,
@@ -71,6 +71,7 @@ impl ConnectionPool {
7171
host: server.0.clone(),
7272
port: server.1.to_string(),
7373
role: role,
74+
shard: idx,
7475
};
7576

7677
let manager = ServerPool::new(
@@ -165,6 +166,9 @@ impl ConnectionPool {
165166
None => 0, // TODO: pick a shard at random
166167
};
167168

169+
// We are waiting for a server now.
170+
self.stats.client_waiting();
171+
168172
let addresses = &self.addresses[shard];
169173

170174
// Make sure if a specific role is requested, it's available in the pool.
@@ -237,7 +241,8 @@ impl ConnectionPool {
237241
};
238242

239243
if !with_health_check {
240-
self.stats.checkout_time(now.elapsed().as_millis());
244+
self.stats.checkout_time(now.elapsed().as_micros());
245+
self.stats.client_active();
241246
return Ok((conn, address.clone()));
242247
}
243248

@@ -253,7 +258,8 @@ impl ConnectionPool {
253258
// Check if health check succeeded
254259
Ok(res) => match res {
255260
Ok(_) => {
256-
self.stats.checkout_time(now.elapsed().as_millis());
261+
self.stats.checkout_time(now.elapsed().as_micros());
262+
self.stats.client_active();
257263
return Ok((conn, address.clone()));
258264
}
259265
Err(_) => {
@@ -385,13 +391,10 @@ impl ManageConnection for ServerPool {
385391
println!(">> Creating a new connection for the pool");
386392

387393
Server::startup(
388-
&self.address.host,
389-
&self.address.port,
390-
&self.user.name,
391-
&self.user.password,
394+
&self.address,
395+
&self.user,
392396
&self.database,
393397
self.client_server_map.clone(),
394-
self.address.role,
395398
self.stats.clone(),
396399
)
397400
.await

src/server.rs

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,17 @@ use tokio::io::{AsyncReadExt, BufReader};
88
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
99
use tokio::net::TcpStream;
1010

11-
use crate::config::{Address, Role};
11+
use crate::config::{Address, User};
1212
use crate::errors::Error;
1313
use crate::messages::*;
1414
use crate::stats::Reporter;
1515
use crate::ClientServerMap;
1616

1717
/// Server state.
1818
pub struct Server {
19-
// Server host, e.g. localhost
20-
host: String,
21-
22-
// Server port: e.g. 5432
23-
port: String,
19+
// Server host, e.g. localhost,
20+
// port, e.g. 5432, and role, e.g. primary or replica.
21+
address: Address,
2422

2523
// Buffered read socket
2624
read: BufReader<OwnedReadHalf>,
@@ -50,9 +48,6 @@ pub struct Server {
5048
// Mapping of clients and servers used for query cancellation.
5149
client_server_map: ClientServerMap,
5250

53-
// Server role, e.g. primary or replica.
54-
role: Role,
55-
5651
// Server connected at
5752
connected_at: chrono::naive::NaiveDateTime,
5853

@@ -64,25 +59,23 @@ impl Server {
6459
/// Pretend to be the Postgres client and connect to the server given host, port and credentials.
6560
/// Perform the authentication and return the server in a ready-for-query mode.
6661
pub async fn startup(
67-
host: &str,
68-
port: &str,
69-
user: &str,
70-
password: &str,
62+
address: &Address,
63+
user: &User,
7164
database: &str,
7265
client_server_map: ClientServerMap,
73-
role: Role,
7466
stats: Reporter,
7567
) -> Result<Server, Error> {
76-
let mut stream = match TcpStream::connect(&format!("{}:{}", host, port)).await {
77-
Ok(stream) => stream,
78-
Err(err) => {
79-
println!(">> Could not connect to server: {}", err);
80-
return Err(Error::SocketError);
81-
}
82-
};
68+
let mut stream =
69+
match TcpStream::connect(&format!("{}:{}", &address.host, &address.port)).await {
70+
Ok(stream) => stream,
71+
Err(err) => {
72+
println!(">> Could not connect to server: {}", err);
73+
return Err(Error::SocketError);
74+
}
75+
};
8376

8477
// Send the startup packet.
85-
startup(&mut stream, user, database).await?;
78+
startup(&mut stream, &user.name, database).await?;
8679

8780
let mut server_info = BytesMut::with_capacity(25);
8881
let mut backend_id: i32 = 0;
@@ -117,7 +110,8 @@ impl Server {
117110
Err(_) => return Err(Error::SocketError),
118111
};
119112

120-
md5_password(&mut stream, user, password, &salt[..]).await?;
113+
md5_password(&mut stream, &user.name, &user.password, &salt[..])
114+
.await?;
121115
}
122116

123117
// Authentication handshake complete.
@@ -189,8 +183,7 @@ impl Server {
189183
let (read, write) = stream.into_split();
190184

191185
return Ok(Server {
192-
host: host.to_string(),
193-
port: port.to_string(),
186+
address: address.clone(),
194187
read: BufReader::new(read),
195188
write: write,
196189
buffer: BytesMut::with_capacity(8196),
@@ -201,7 +194,6 @@ impl Server {
201194
data_available: false,
202195
bad: false,
203196
client_server_map: client_server_map,
204-
role: role,
205197
connected_at: chrono::offset::Utc::now().naive_utc(),
206198
stats: stats,
207199
});
@@ -382,8 +374,8 @@ impl Server {
382374
(
383375
self.backend_id,
384376
self.secret_key,
385-
self.host.clone(),
386-
self.port.clone(),
377+
self.address.host.clone(),
378+
self.address.port.clone(),
387379
),
388380
);
389381
}
@@ -422,11 +414,7 @@ impl Server {
422414
}
423415

424416
pub fn address(&self) -> Address {
425-
Address {
426-
host: self.host.to_string(),
427-
port: self.port.to_string(),
428-
role: self.role,
429-
}
417+
self.address.clone()
430418
}
431419
}
432420

src/stats.rs

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ pub enum StatisticName {
1414
Transactions,
1515
DataSent,
1616
DataReceived,
17+
ClientsWaiting,
18+
ClientsActive,
19+
ClientsIdle,
1720
}
1821

1922
#[derive(Debug)]
@@ -76,6 +79,54 @@ impl Reporter {
7679

7780
let _ = self.tx.try_send(statistic);
7881
}
82+
83+
pub fn client_waiting(&mut self) {
84+
let statistic = Statistic {
85+
name: StatisticName::ClientsWaiting,
86+
value: 1,
87+
};
88+
89+
let _ = self.tx.try_send(statistic);
90+
91+
let statistic = Statistic {
92+
name: StatisticName::ClientsIdle,
93+
value: -1,
94+
};
95+
96+
let _ = self.tx.try_send(statistic);
97+
}
98+
99+
pub fn client_active(&mut self) {
100+
let statistic = Statistic {
101+
name: StatisticName::ClientsWaiting,
102+
value: -1,
103+
};
104+
105+
let _ = self.tx.try_send(statistic);
106+
107+
let statistic = Statistic {
108+
name: StatisticName::ClientsActive,
109+
value: 1,
110+
};
111+
112+
let _ = self.tx.try_send(statistic);
113+
}
114+
115+
pub fn client_idle(&mut self) {
116+
let statistic = Statistic {
117+
name: StatisticName::ClientsActive,
118+
value: -1,
119+
};
120+
121+
let _ = self.tx.try_send(statistic);
122+
123+
let statistic = Statistic {
124+
name: StatisticName::ClientsIdle,
125+
value: 1,
126+
};
127+
128+
let _ = self.tx.try_send(statistic);
129+
}
79130
}
80131

81132
pub struct Collector {
@@ -93,12 +144,18 @@ impl Collector {
93144

94145
pub async fn collect(&mut self) {
95146
let mut stats = HashMap::from([
96-
("queries", 0),
97-
("transactions", 0),
98-
("data_sent", 0),
99-
("data_received", 0),
100-
("checkout_time", 0),
147+
("total_query_count", 0),
148+
("total_xact_count", 0),
149+
("total_sent", 0),
150+
("total_received", 0),
151+
("total_wait_time", 0),
152+
("maxwait_us", 0),
153+
("maxwait", 0),
154+
("cl_waiting", 0),
155+
("cl_active", 0),
156+
("cl_idle", 0),
101157
]);
158+
102159
let mut now = Instant::now();
103160

104161
loop {
@@ -113,32 +170,61 @@ impl Collector {
113170
// Some are counters, some are gauges...
114171
match stat.name {
115172
StatisticName::Queries => {
116-
let counter = stats.entry("queries").or_insert(0);
173+
let counter = stats.entry("total_query_count").or_insert(0);
117174
*counter += stat.value;
118175
}
119176

120177
StatisticName::Transactions => {
121-
let counter = stats.entry("transactions").or_insert(0);
178+
let counter = stats.entry("total_xact_count").or_insert(0);
122179
*counter += stat.value;
123180
}
124181

125182
StatisticName::DataSent => {
126-
let counter = stats.entry("data_sent").or_insert(0);
183+
let counter = stats.entry("total_sent").or_insert(0);
127184
*counter += stat.value;
128185
}
129186

130187
StatisticName::DataReceived => {
131-
let counter = stats.entry("data_received").or_insert(0);
188+
let counter = stats.entry("total_received").or_insert(0);
132189
*counter += stat.value;
133190
}
134191

135192
StatisticName::CheckoutTime => {
136-
let counter = stats.entry("checkout_time").or_insert(0);
193+
let counter = stats.entry("total_wait_time").or_insert(0);
194+
*counter += stat.value;
195+
196+
let counter = stats.entry("maxwait_us").or_insert(0);
137197

138198
// Report max time here
139199
if stat.value > *counter {
140200
*counter = stat.value;
141201
}
202+
203+
let counter = stats.entry("maxwait").or_insert(0);
204+
let seconds = *counter / 1_000_000;
205+
206+
if seconds > *counter {
207+
*counter = seconds;
208+
}
209+
}
210+
211+
StatisticName::ClientsActive => {
212+
let counter = stats.entry("cl_active").or_insert(0);
213+
214+
*counter += stat.value;
215+
*counter = std::cmp::max(*counter, 0);
216+
}
217+
218+
StatisticName::ClientsWaiting => {
219+
let counter = stats.entry("cl_waiting").or_insert(0);
220+
*counter += stat.value;
221+
*counter = std::cmp::max(*counter, 0);
222+
}
223+
224+
StatisticName::ClientsIdle => {
225+
let counter = stats.entry("cl_idle").or_insert(0);
226+
*counter += stat.value;
227+
*counter = std::cmp::max(*counter, 0);
142228
}
143229
};
144230

0 commit comments

Comments
 (0)