2
2
use bytes:: { Buf , BufMut , BytesMut } ;
3
3
use log:: { info, trace} ;
4
4
use std:: collections:: HashMap ;
5
+ use tokio:: time:: Instant ;
5
6
6
7
use crate :: config:: { get_config, reload_config, VERSION } ;
7
8
use crate :: errors:: Error ;
8
9
use crate :: messages:: * ;
9
10
use crate :: pool:: get_all_pools;
10
- use crate :: stats:: get_stats;
11
+ use crate :: stats:: {
12
+ get_address_stats, get_client_stats, get_pool_stats, get_server_stats, ClientState , ServerState ,
13
+ } ;
11
14
use crate :: ClientServerMap ;
12
15
13
16
pub fn generate_server_info_for_admin ( ) -> BytesMut {
72
75
trace ! ( "SHOW POOLS" ) ;
73
76
show_pools ( stream) . await
74
77
}
78
+ "CLIENTS" => {
79
+ trace ! ( "SHOW CLIENTS" ) ;
80
+ show_clients ( stream) . await
81
+ }
82
+ "SERVERS" => {
83
+ trace ! ( "SHOW SERVERS" ) ;
84
+ show_servers ( stream) . await
85
+ }
75
86
"STATS" => {
76
87
trace ! ( "SHOW STATS" ) ;
77
88
show_stats ( stream) . await
@@ -91,7 +102,8 @@ async fn show_lists<T>(stream: &mut T) -> Result<(), Error>
91
102
where
92
103
T : tokio:: io:: AsyncWrite + std:: marker:: Unpin ,
93
104
{
94
- let stats = get_stats ( ) ;
105
+ let client_stats = get_client_stats ( ) ;
106
+ let server_stats = get_server_stats ( ) ;
95
107
96
108
let columns = vec ! [ ( "list" , DataType :: Text ) , ( "items" , DataType :: Int4 ) ] ;
97
109
@@ -111,18 +123,18 @@ where
111
123
res. put ( data_row ( & vec ! [ "pools" . to_string( ) , databases. to_string( ) ] ) ) ;
112
124
res. put ( data_row ( & vec ! [
113
125
"free_clients" . to_string( ) ,
114
- stats
126
+ client_stats
115
127
. keys( )
116
- . map ( |address_id| stats [ & address_id ] [ "cl_idle" ] )
117
- . sum :: < i64 > ( )
128
+ . filter ( |client_id| client_stats . get ( client_id ) . unwrap ( ) . state == ClientState :: Idle )
129
+ . count ( )
118
130
. to_string( ) ,
119
131
] ) ) ;
120
132
res. put ( data_row ( & vec ! [
121
133
"used_clients" . to_string( ) ,
122
- stats
134
+ client_stats
123
135
. keys( )
124
- . map ( |address_id| stats [ & address_id ] [ "cl_active" ] )
125
- . sum :: < i64 > ( )
136
+ . filter ( |client_id| client_stats . get ( client_id ) . unwrap ( ) . state == ClientState :: Active )
137
+ . count ( )
126
138
. to_string( ) ,
127
139
] ) ) ;
128
140
res. put ( data_row ( & vec ! [
@@ -131,18 +143,18 @@ where
131
143
] ) ) ;
132
144
res. put ( data_row ( & vec ! [
133
145
"free_servers" . to_string( ) ,
134
- stats
146
+ server_stats
135
147
. keys( )
136
- . map ( |address_id| stats [ & address_id ] [ "sv_idle" ] )
137
- . sum :: < i64 > ( )
148
+ . filter ( |server_id| server_stats . get ( server_id ) . unwrap ( ) . state == ServerState :: Idle )
149
+ . count ( )
138
150
. to_string( ) ,
139
151
] ) ) ;
140
152
res. put ( data_row ( & vec ! [
141
153
"used_servers" . to_string( ) ,
142
- stats
154
+ server_stats
143
155
. keys( )
144
- . map ( |address_id| stats [ & address_id ] [ "sv_active" ] )
145
- . sum :: < i64 > ( )
156
+ . filter ( |server_id| server_stats . get ( server_id ) . unwrap ( ) . state == ServerState :: Active )
157
+ . count ( )
146
158
. to_string( ) ,
147
159
] ) ) ;
148
160
res. put ( data_row ( & vec ! [ "dns_names" . to_string( ) , "0" . to_string( ) ] ) ) ;
@@ -182,11 +194,12 @@ async fn show_pools<T>(stream: &mut T) -> Result<(), Error>
182
194
where
183
195
T : tokio:: io:: AsyncWrite + std:: marker:: Unpin ,
184
196
{
185
- let stats = get_stats ( ) ;
197
+ let all_pool_stats = get_pool_stats ( ) ;
186
198
187
199
let columns = vec ! [
188
200
( "database" , DataType :: Text ) ,
189
201
( "user" , DataType :: Text ) ,
202
+ ( "pool_mode" , DataType :: Text ) ,
190
203
( "cl_idle" , DataType :: Numeric ) ,
191
204
( "cl_active" , DataType :: Numeric ) ,
192
205
( "cl_waiting" , DataType :: Numeric ) ,
@@ -198,32 +211,27 @@ where
198
211
( "sv_login" , DataType :: Numeric ) ,
199
212
( "maxwait" , DataType :: Numeric ) ,
200
213
( "maxwait_us" , DataType :: Numeric ) ,
201
- ( "pool_mode" , DataType :: Text ) ,
202
214
] ;
203
215
204
216
let mut res = BytesMut :: new ( ) ;
205
217
res. put ( row_description ( & columns) ) ;
206
- for ( _, pool) in get_all_pools ( ) {
207
- let pool_config = & pool. settings ;
208
- for shard in 0 ..pool. shards ( ) {
209
- for server in 0 ..pool. servers ( shard) {
210
- let address = pool. address ( shard, server) ;
211
- let stats = match stats. get ( & address. id ) {
212
- Some ( stats) => stats. clone ( ) ,
213
- None => HashMap :: new ( ) ,
214
- } ;
218
+ for ( ( pool_name, username) , pool) in get_all_pools ( ) {
219
+ let def = HashMap :: default ( ) ;
220
+ let pool_stats = all_pool_stats
221
+ . get ( & ( pool_name. clone ( ) , username. clone ( ) ) )
222
+ . unwrap_or ( & def) ;
215
223
216
- let mut row = vec ! [ address. name( ) , pool_config. user. username. clone( ) ] ;
217
-
218
- for column in & columns[ 2 ..columns. len ( ) - 1 ] {
219
- let value = stats. get ( column. 0 ) . unwrap_or ( & 0 ) . to_string ( ) ;
220
- row. push ( value) ;
221
- }
222
-
223
- row. push ( pool_config. pool_mode . to_string ( ) ) ;
224
- res. put ( data_row ( & row) ) ;
225
- }
224
+ let pool_config = & pool. settings ;
225
+ let mut row = vec ! [
226
+ pool_name. clone( ) ,
227
+ username. clone( ) ,
228
+ pool_config. pool_mode. to_string( ) ,
229
+ ] ;
230
+ for column in & columns[ 3 ..columns. len ( ) ] {
231
+ let value = pool_stats. get ( column. 0 ) . unwrap_or ( & 0 ) . to_string ( ) ;
232
+ row. push ( value) ;
226
233
}
234
+ res. put ( data_row ( & row) ) ;
227
235
}
228
236
229
237
res. put ( command_complete ( "SHOW" ) ) ;
@@ -387,6 +395,7 @@ where
387
395
T : tokio:: io:: AsyncWrite + std:: marker:: Unpin ,
388
396
{
389
397
let columns = vec ! [
398
+ ( "instance" , DataType :: Text ) ,
390
399
( "database" , DataType :: Text ) ,
391
400
( "user" , DataType :: Text ) ,
392
401
( "total_xact_count" , DataType :: Numeric ) ,
@@ -396,32 +405,32 @@ where
396
405
( "total_xact_time" , DataType :: Numeric ) ,
397
406
( "total_query_time" , DataType :: Numeric ) ,
398
407
( "total_wait_time" , DataType :: Numeric ) ,
408
+ ( "total_errors" , DataType :: Numeric ) ,
399
409
( "avg_xact_count" , DataType :: Numeric ) ,
400
410
( "avg_query_count" , DataType :: Numeric ) ,
401
411
( "avg_recv" , DataType :: Numeric ) ,
402
412
( "avg_sent" , DataType :: Numeric ) ,
413
+ ( "avg_errors" , DataType :: Numeric ) ,
403
414
( "avg_xact_time" , DataType :: Numeric ) ,
404
415
( "avg_query_time" , DataType :: Numeric ) ,
405
416
( "avg_wait_time" , DataType :: Numeric ) ,
406
417
] ;
407
418
408
- let stats = get_stats ( ) ;
419
+ let all_stats = get_address_stats ( ) ;
409
420
let mut res = BytesMut :: new ( ) ;
410
421
res. put ( row_description ( & columns) ) ;
411
422
412
- for ( ( _db_name , username) , pool) in get_all_pools ( ) {
423
+ for ( ( db , username) , pool) in get_all_pools ( ) {
413
424
for shard in 0 ..pool. shards ( ) {
414
425
for server in 0 ..pool. servers ( shard) {
415
426
let address = pool. address ( shard, server) ;
416
- let stats = match stats . get ( & address. id ) {
427
+ let stats = match all_stats . get ( & address. id ) {
417
428
Some ( stats) => stats. clone ( ) ,
418
429
None => HashMap :: new ( ) ,
419
430
} ;
420
431
421
- let mut row = vec ! [ address. name( ) ] ;
422
- row. push ( username. clone ( ) ) ;
423
-
424
- for column in & columns[ 2 ..] {
432
+ let mut row = vec ! [ address. name( ) , db. clone( ) , username. clone( ) ] ;
433
+ for column in & columns[ 3 ..] {
425
434
row. push ( stats. get ( column. 0 ) . unwrap_or ( & 0 ) . to_string ( ) ) ;
426
435
}
427
436
@@ -439,3 +448,107 @@ where
439
448
440
449
write_all_half ( stream, res) . await
441
450
}
451
+
452
+ /// Show currently connected clients
453
+ async fn show_clients < T > ( stream : & mut T ) -> Result < ( ) , Error >
454
+ where
455
+ T : tokio:: io:: AsyncWrite + std:: marker:: Unpin ,
456
+ {
457
+ let columns = vec ! [
458
+ ( "client_id" , DataType :: Text ) ,
459
+ ( "database" , DataType :: Text ) ,
460
+ ( "user" , DataType :: Text ) ,
461
+ ( "application_name" , DataType :: Text ) ,
462
+ ( "state" , DataType :: Text ) ,
463
+ ( "transaction_count" , DataType :: Numeric ) ,
464
+ ( "query_count" , DataType :: Numeric ) ,
465
+ ( "error_count" , DataType :: Numeric ) ,
466
+ ( "age_seconds" , DataType :: Numeric ) ,
467
+ ] ;
468
+
469
+ let new_map = get_client_stats ( ) ;
470
+ let mut res = BytesMut :: new ( ) ;
471
+ res. put ( row_description ( & columns) ) ;
472
+
473
+ for ( _, client) in new_map {
474
+ let row = vec ! [
475
+ format!( "{:#010X}" , client. client_id) ,
476
+ client. pool_name,
477
+ client. username,
478
+ client. application_name. clone( ) ,
479
+ client. state. to_string( ) ,
480
+ client. transaction_count. to_string( ) ,
481
+ client. query_count. to_string( ) ,
482
+ client. error_count. to_string( ) ,
483
+ Instant :: now( )
484
+ . duration_since( client. connect_time)
485
+ . as_secs( )
486
+ . to_string( ) ,
487
+ ] ;
488
+
489
+ res. put ( data_row ( & row) ) ;
490
+ }
491
+
492
+ res. put ( command_complete ( "SHOW" ) ) ;
493
+
494
+ // ReadyForQuery
495
+ res. put_u8 ( b'Z' ) ;
496
+ res. put_i32 ( 5 ) ;
497
+ res. put_u8 ( b'I' ) ;
498
+
499
+ write_all_half ( stream, res) . await
500
+ }
501
+
502
+ /// Show currently connected servers
503
+ async fn show_servers < T > ( stream : & mut T ) -> Result < ( ) , Error >
504
+ where
505
+ T : tokio:: io:: AsyncWrite + std:: marker:: Unpin ,
506
+ {
507
+ let columns = vec ! [
508
+ ( "server_id" , DataType :: Text ) ,
509
+ ( "database_name" , DataType :: Text ) ,
510
+ ( "user" , DataType :: Text ) ,
511
+ ( "address_id" , DataType :: Text ) ,
512
+ ( "application_name" , DataType :: Text ) ,
513
+ ( "state" , DataType :: Text ) ,
514
+ ( "transaction_count" , DataType :: Numeric ) ,
515
+ ( "query_count" , DataType :: Numeric ) ,
516
+ ( "bytes_sent" , DataType :: Numeric ) ,
517
+ ( "bytes_received" , DataType :: Numeric ) ,
518
+ ( "age_seconds" , DataType :: Numeric ) ,
519
+ ] ;
520
+
521
+ let new_map = get_server_stats ( ) ;
522
+ let mut res = BytesMut :: new ( ) ;
523
+ res. put ( row_description ( & columns) ) ;
524
+
525
+ for ( _, server) in new_map {
526
+ let row = vec ! [
527
+ format!( "{:#010X}" , server. server_id) ,
528
+ server. pool_name,
529
+ server. username,
530
+ server. address_name,
531
+ server. application_name,
532
+ server. state. to_string( ) ,
533
+ server. transaction_count. to_string( ) ,
534
+ server. query_count. to_string( ) ,
535
+ server. bytes_sent. to_string( ) ,
536
+ server. bytes_received. to_string( ) ,
537
+ Instant :: now( )
538
+ . duration_since( server. connect_time)
539
+ . as_secs( )
540
+ . to_string( ) ,
541
+ ] ;
542
+
543
+ res. put ( data_row ( & row) ) ;
544
+ }
545
+
546
+ res. put ( command_complete ( "SHOW" ) ) ;
547
+
548
+ // ReadyForQuery
549
+ res. put_u8 ( b'Z' ) ;
550
+ res. put_i32 ( 5 ) ;
551
+ res. put_u8 ( b'I' ) ;
552
+
553
+ write_all_half ( stream, res) . await
554
+ }
0 commit comments