1 /* -*-pgsql-c-*- */
2 /*
3 * $Header$
4 *
5 * pgpool: a language independent connection pool server for PostgreSQL
6 * written by Tatsuo Ishii
7 *
8 * Copyright (c) 2003-2018 PgPool Global Development Group
9 *
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby
12 * granted, provided that the above copyright notice appear in all
13 * copies and that both that copyright notice and this permission
14 * notice appear in supporting documentation, and that the name of the
15 * author not be used in advertising or publicity pertaining to
16 * distribution of the software without specific, written prior
17 * permission. The author makes no representations about the
18 * suitability of this software for any purpose. It is provided "as
19 * is" without express or implied warranty.
20 *
21 * Process pgPool-II "SHOW" queries.
22 */
23 #include "pool.h"
24 #include "protocol/pool_proto_modules.h"
25 #include "utils/elog.h"
26 #include "utils/pool_stream.h"
27 #include "pool_config.h"
28 #include "query_cache/pool_memqcache.h"
29 #include "version.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <netinet/in.h>
34
35
36 void
send_row_description(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,short num_fields,char ** field_names)37 send_row_description(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend,
38 short num_fields, char **field_names)
39 {
40 static char *cursorname = "blank";
41 static int oid = 0;
42 static short fsize = -1;
43 static int mod = 0;
44 short n;
45 int i;
46 short s;
47 int len;
48 short colnum;
49
50 if (MAJOR(backend) == PROTO_MAJOR_V2)
51 {
52 /* cursor response */
53 pool_write(frontend, "P", 1);
54 pool_write(frontend, cursorname, strlen(cursorname) + 1);
55 }
56
57 /* row description */
58 pool_write(frontend, "T", 1);
59
60 if (MAJOR(backend) == PROTO_MAJOR_V3)
61 {
62 /*
63 * information about computed byte in section "RowDescription (B)"
64 * here:
65 * http://www.postgresql.org/docs/current/static/protocol-message-formats.html
66 */
67
68 len = 6; /* int32 + int16 */
69
70 for (i = 0; i < num_fields; i++)
71 {
72 /* String + '\0' + 3* int32 + 3* int16 */
73 len += strlen(field_names[i]) + 1 + 18;
74 }
75
76 len = htonl(len);
77 pool_write(frontend, &len, sizeof(len));
78 }
79
80 n = htons(num_fields);
81 pool_write(frontend, &n, sizeof(short));
82
83 for (i = 0; i < num_fields; i++)
84 {
85 pool_write(frontend, field_names[i], strlen(field_names[i]) + 1); /* field name */
86
87 if (MAJOR(backend) == PROTO_MAJOR_V3)
88 {
89 pool_write(frontend, &oid, sizeof(oid)); /* table oid */
90 colnum = htons(i);
91 pool_write(frontend, &colnum, sizeof(colnum)); /* column number */
92 }
93
94 pool_write(frontend, &oid, sizeof(oid)); /* data type oid */
95 s = htons(fsize);
96 pool_write(frontend, &s, sizeof(fsize)); /* field size */
97 pool_write(frontend, &mod, sizeof(mod)); /* modifier */
98
99 if (MAJOR(backend) == PROTO_MAJOR_V3)
100 {
101 s = htons(0);
102 pool_write(frontend, &s, sizeof(fsize)); /* field format (text) */
103 }
104 }
105 pool_flush(frontend);
106 }
107
108 /*
109 * Send the command complete and ready for query message
110 * to frontend.
111 * If the num_row is lower than 0, it is not included
112 * to the command complete message.
113 */
114 void
send_complete_and_ready(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,const char * message,const int num_rows)115 send_complete_and_ready(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *message, const int num_rows)
116 {
117 int len;
118 int msg_len;
119 char msg[64];
120
121 if (num_rows >= 0)
122 msg_len = snprintf(msg, sizeof(msg), "%s %d", message, num_rows);
123 else
124 msg_len = snprintf(msg, sizeof(msg), "%s", message);
125
126 /* complete command response */
127 pool_write(frontend, "C", 1);
128 if (MAJOR(backend) == PROTO_MAJOR_V3)
129 {
130 len = htonl(4 + msg_len + 1);
131 pool_write(frontend, &len, sizeof(len));
132 }
133 pool_write(frontend, msg, msg_len + 1);
134
135 /* ready for query */
136 pool_write(frontend, "Z", 1);
137 if (MAJOR(backend) == PROTO_MAJOR_V3)
138 {
139 len = htonl(5);
140 pool_write(frontend, &len, sizeof(len));
141 pool_write(frontend, "I", 1);
142 }
143
144 pool_flush(frontend);
145 }
146
147 POOL_REPORT_CONFIG *
get_config(int * nrows)148 get_config(int *nrows)
149 {
150 int i,
151 j;
152 int len;
153
154 /*
155 * Report data buffer.
156 * 128 is the max number of configuration items.
157 * In addition, we need MAX_NUM_BACKENDS*4
158 * for backend descriptions.
159 */
160 #define MAXITEMS (256 + MAX_NUM_BACKENDS*4)
161
162 POOL_REPORT_CONFIG *status = palloc0(MAXITEMS * sizeof(POOL_REPORT_CONFIG));
163
164 /*
165 * we initialize the array with NULL values so when looping on it, we can
166 * use it as stop condition
167 */
168
169 i = 0;
170
171 /* CONNECTIONS */
172
173 /* - pgpool Connection Settings - */
174 StrNCpy(status[i].name, "listen_addresses", POOLCONFIG_MAXNAMELEN);
175 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->listen_addresses);
176 StrNCpy(status[i].desc, "host name(s) or IP address(es) to listen on", POOLCONFIG_MAXDESCLEN);
177 i++;
178
179 StrNCpy(status[i].name, "port", POOLCONFIG_MAXNAMELEN);
180 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->port);
181 StrNCpy(status[i].desc, "pgpool accepting port number", POOLCONFIG_MAXDESCLEN);
182 i++;
183
184 /* - pgpool Communication Manager Connection Settings - */
185 StrNCpy(status[i].name, "socket_dir", POOLCONFIG_MAXNAMELEN);
186 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->socket_dir);
187 StrNCpy(status[i].desc, "pgpool socket directory", POOLCONFIG_MAXDESCLEN);
188 i++;
189
190 StrNCpy(status[i].name, "pcp_listen_addresses", POOLCONFIG_MAXNAMELEN);
191 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_listen_addresses);
192 StrNCpy(status[i].desc, "host name(s) or IP address(es) for pcp process to listen on", POOLCONFIG_MAXDESCLEN);
193 i++;
194
195 StrNCpy(status[i].name, "pcp_port", POOLCONFIG_MAXNAMELEN);
196 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->pcp_port);
197 StrNCpy(status[i].desc, "PCP port # to bind", POOLCONFIG_MAXDESCLEN);
198 i++;
199
200 StrNCpy(status[i].name, "pcp_socket_dir", POOLCONFIG_MAXNAMELEN);
201 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_socket_dir);
202 StrNCpy(status[i].desc, "PCP socket directory", POOLCONFIG_MAXDESCLEN);
203 i++;
204
205 /* # - Authentication - */
206 StrNCpy(status[i].name, "enable_pool_hba", POOLCONFIG_MAXNAMELEN);
207 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->enable_pool_hba);
208 StrNCpy(status[i].desc, "if true, use pool_hba.conf for client authentication", POOLCONFIG_MAXDESCLEN);
209 i++;
210
211 StrNCpy(status[i].name, "pool_passwd", POOLCONFIG_MAXNAMELEN);
212 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pool_passwd);
213 StrNCpy(status[i].desc, "file name of pool_passwd for md5 authentication", POOLCONFIG_MAXDESCLEN);
214 i++;
215
216 StrNCpy(status[i].name, "authentication_timeout", POOLCONFIG_MAXNAMELEN);
217 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->authentication_timeout);
218 StrNCpy(status[i].desc, "maximum time in seconds to complete client authentication", POOLCONFIG_MAXNAMELEN);
219 i++;
220
221 StrNCpy(status[i].name, "allow_clear_text_frontend_auth", POOLCONFIG_MAXNAMELEN);
222 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->allow_clear_text_frontend_auth);
223 StrNCpy(status[i].desc, "allow to use clear text password auth when pool_passwd does not contain password", POOLCONFIG_MAXDESCLEN);
224 i++;
225
226 /* - SSL Connections - */
227 StrNCpy(status[i].name, "ssl", POOLCONFIG_MAXNAMELEN);
228 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ssl);
229 StrNCpy(status[i].desc, "SSL support", POOLCONFIG_MAXDESCLEN);
230 i++;
231
232 StrNCpy(status[i].name, "ssl_key", POOLCONFIG_MAXNAMELEN);
233 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_key);
234 StrNCpy(status[i].desc, "path to the SSL private key file", POOLCONFIG_MAXDESCLEN);
235 i++;
236
237 StrNCpy(status[i].name, "ssl_cert", POOLCONFIG_MAXNAMELEN);
238 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_cert);
239 StrNCpy(status[i].desc, "path to the SSL public certificate file", POOLCONFIG_MAXDESCLEN);
240 i++;
241
242 StrNCpy(status[i].name, "ssl_ca_cert", POOLCONFIG_MAXNAMELEN);
243 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ca_cert);
244 StrNCpy(status[i].desc, "path to a single PEM format file", POOLCONFIG_MAXDESCLEN);
245 i++;
246
247 StrNCpy(status[i].name, "ssl_ca_cert_dir", POOLCONFIG_MAXNAMELEN);
248 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ca_cert_dir);
249 StrNCpy(status[i].desc, "directory containing CA root certificate(s)", POOLCONFIG_MAXDESCLEN);
250 i++;
251
252 StrNCpy(status[i].name, "ssl_ciphers", POOLCONFIG_MAXNAMELEN);
253 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ciphers);
254 StrNCpy(status[i].desc, "allowed SSL ciphers", POOLCONFIG_MAXDESCLEN);
255 i++;
256
257 StrNCpy(status[i].name, "ssl_prefer_server_ciphers", POOLCONFIG_MAXNAMELEN);
258 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ssl_prefer_server_ciphers);
259 StrNCpy(status[i].desc, "Use server's SSL cipher preferences", POOLCONFIG_MAXDESCLEN);
260 i++;
261
262 /* POOLS */
263
264 /* - Pool size - */
265 StrNCpy(status[i].name, "num_init_children", POOLCONFIG_MAXNAMELEN);
266 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->num_init_children);
267 StrNCpy(status[i].desc, "# of children initially pre-forked", POOLCONFIG_MAXDESCLEN);
268 i++;
269
270 StrNCpy(status[i].name, "listen_backlog_multiplier", POOLCONFIG_MAXNAMELEN);
271 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->listen_backlog_multiplier);
272 StrNCpy(status[i].desc, "determines the size of the queue for pending connections", POOLCONFIG_MAXDESCLEN);
273 i++;
274
275 StrNCpy(status[i].name, "serialize_accept", POOLCONFIG_MAXNAMELEN);
276 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->serialize_accept);
277 StrNCpy(status[i].desc, "whether to serialize accept() call", POOLCONFIG_MAXDESCLEN);
278 i++;
279
280 StrNCpy(status[i].name, "max_pool", POOLCONFIG_MAXNAMELEN);
281 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->max_pool);
282 StrNCpy(status[i].desc, "max # of connection pool per child", POOLCONFIG_MAXDESCLEN);
283 i++;
284
285 /* - Life time - */
286 StrNCpy(status[i].name, "child_life_time", POOLCONFIG_MAXNAMELEN);
287 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->child_life_time);
288 StrNCpy(status[i].desc, "if idle for this seconds, child exits", POOLCONFIG_MAXDESCLEN);
289 i++;
290
291 StrNCpy(status[i].name, "child_max_connections", POOLCONFIG_MAXNAMELEN);
292 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->child_max_connections);
293 StrNCpy(status[i].desc, "if max_connections received, child exits", POOLCONFIG_MAXDESCLEN);
294 i++;
295
296 StrNCpy(status[i].name, "connection_life_time", POOLCONFIG_MAXNAMELEN);
297 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connection_life_time);
298 StrNCpy(status[i].desc, "if idle for this seconds, connection closes", POOLCONFIG_MAXDESCLEN);
299 i++;
300
301 StrNCpy(status[i].name, "client_idle_limit", POOLCONFIG_MAXNAMELEN);
302 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_idle_limit);
303 StrNCpy(status[i].desc, "if idle for this seconds, child connection closes", POOLCONFIG_MAXDESCLEN);
304 i++;
305
306 /* LOGS */
307
308 /* - Where to log - */
309 StrNCpy(status[i].name, "log_destination", POOLCONFIG_MAXNAMELEN);
310 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->log_destination_str);
311 StrNCpy(status[i].desc, "logging destination", POOLCONFIG_MAXDESCLEN);
312 i++;
313
314 /* - What to log - */
315 StrNCpy(status[i].name, "log_line_prefix", POOLCONFIG_MAXNAMELEN);
316 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->log_line_prefix);
317 StrNCpy(status[i].desc, "printf-style string to output at beginning of each log line", POOLCONFIG_MAXDESCLEN);
318 i++;
319
320 StrNCpy(status[i].name, "log_error_verbosity", POOLCONFIG_MAXNAMELEN);
321 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_error_verbosity);
322 StrNCpy(status[i].desc, "controls how much detail about error should be emitted", POOLCONFIG_MAXDESCLEN);
323 i++;
324
325 StrNCpy(status[i].name, "client_min_messages", POOLCONFIG_MAXNAMELEN);
326 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_min_messages);
327 StrNCpy(status[i].desc, "controls which message should be sent to client", POOLCONFIG_MAXDESCLEN);
328 i++;
329
330 StrNCpy(status[i].name, "log_min_messages", POOLCONFIG_MAXNAMELEN);
331 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_min_messages);
332 StrNCpy(status[i].desc, "controls which message should be emitted to server log", POOLCONFIG_MAXDESCLEN);
333 i++;
334
335 StrNCpy(status[i].name, "log_connections", POOLCONFIG_MAXNAMELEN);
336 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_connections);
337 StrNCpy(status[i].desc, "if true, print incoming connections to the log", POOLCONFIG_MAXDESCLEN);
338 i++;
339
340 StrNCpy(status[i].name, "log_hostname", POOLCONFIG_MAXNAMELEN);
341 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_hostname);
342 StrNCpy(status[i].desc, "if true, resolve hostname for ps and log print", POOLCONFIG_MAXDESCLEN);
343 i++;
344
345 StrNCpy(status[i].name, "log_statement", POOLCONFIG_MAXNAMELEN);
346 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_statement);
347 StrNCpy(status[i].desc, "if non 0, logs all SQL statements", POOLCONFIG_MAXDESCLEN);
348 i++;
349
350 StrNCpy(status[i].name, "log_per_node_statement", POOLCONFIG_MAXNAMELEN);
351 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_per_node_statement);
352 StrNCpy(status[i].desc, "if non 0, logs all SQL statements on each node", POOLCONFIG_MAXDESCLEN);
353 i++;
354
355 StrNCpy(status[i].name, "log_client_messages", POOLCONFIG_MAXNAMELEN);
356 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_client_messages);
357 StrNCpy(status[i].desc, "if non 0, logs any client messages", POOLCONFIG_MAXDESCLEN);
358 i++;
359
360 StrNCpy(status[i].name, "log_standby_delay", POOLCONFIG_MAXNAMELEN);
361 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_standby_delay);
362 StrNCpy(status[i].desc, "how to log standby delay", POOLCONFIG_MAXDESCLEN);
363 i++;
364
365 /* - Syslog specific - */
366 StrNCpy(status[i].name, "syslog_facility", POOLCONFIG_MAXNAMELEN);
367 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "LOCAL%d", (pool_config->syslog_facility / 8) - 16);
368 StrNCpy(status[i].desc, "syslog local faclity", POOLCONFIG_MAXDESCLEN);
369 i++;
370
371 StrNCpy(status[i].name, "syslog_ident", POOLCONFIG_MAXNAMELEN);
372 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->syslog_ident);
373 StrNCpy(status[i].desc, "syslog program ident string", POOLCONFIG_MAXDESCLEN);
374 i++;
375
376 /* FILE LOCATIONS */
377
378 StrNCpy(status[i].name, "pid_file_name", POOLCONFIG_MAXNAMELEN);
379 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pid_file_name);
380 StrNCpy(status[i].desc, "path to pid file", POOLCONFIG_MAXDESCLEN);
381 i++;
382
383 StrNCpy(status[i].name, "logdir", POOLCONFIG_MAXNAMELEN);
384 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->logdir);
385 StrNCpy(status[i].desc, "PgPool status file logging directory", POOLCONFIG_MAXDESCLEN);
386 i++;
387
388 /* CONNECTION POOLING */
389
390 StrNCpy(status[i].name, "connection_cache", POOLCONFIG_MAXNAMELEN);
391 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connection_cache);
392 StrNCpy(status[i].desc, "if true, cache connection pool", POOLCONFIG_MAXDESCLEN);
393 i++;
394
395 StrNCpy(status[i].name, "reset_query_list", POOLCONFIG_MAXNAMELEN);
396 *(status[i].value) = '\0';
397 for (j = 0; j < pool_config->num_reset_queries; j++)
398 {
399 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
400 strncat(status[i].value, pool_config->reset_query_list[j], len);
401 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
402 if (j != pool_config->num_reset_queries - 1)
403 strncat(status[i].value, ";", len);
404 }
405 StrNCpy(status[i].desc, "queries issued at the end of session", POOLCONFIG_MAXDESCLEN);
406 i++;
407
408 /* REPLICATION MODE */
409
410 StrNCpy(status[i].name, "replication_mode", POOLCONFIG_MAXNAMELEN);
411 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replication_mode);
412 StrNCpy(status[i].desc, "non 0 if operating in replication mode", POOLCONFIG_MAXDESCLEN);
413 i++;
414
415 StrNCpy(status[i].name, "replicate_select", POOLCONFIG_MAXNAMELEN);
416 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replicate_select);
417 StrNCpy(status[i].desc, "non 0 if SELECT statement is replicated", POOLCONFIG_MAXDESCLEN);
418 i++;
419
420 StrNCpy(status[i].name, "insert_lock", POOLCONFIG_MAXNAMELEN);
421 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->insert_lock);
422 StrNCpy(status[i].desc, "insert lock", POOLCONFIG_MAXDESCLEN);
423 i++;
424
425 StrNCpy(status[i].name, "lobj_lock_table", POOLCONFIG_MAXNAMELEN);
426 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->lobj_lock_table);
427 StrNCpy(status[i].desc, "table name used for large object replication control", POOLCONFIG_MAXDESCLEN);
428 i++;
429
430 /* - Degenerate handling - */
431 StrNCpy(status[i].name, "replication_stop_on_mismatch", POOLCONFIG_MAXNAMELEN);
432 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replication_stop_on_mismatch);
433 StrNCpy(status[i].desc, "stop replication mode on fatal error", POOLCONFIG_MAXDESCLEN);
434 i++;
435
436 StrNCpy(status[i].name, "failover_if_affected_tuples_mismatch", POOLCONFIG_MAXNAMELEN);
437 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->failover_if_affected_tuples_mismatch);
438 StrNCpy(status[i].desc, "failover if affected tuples are mismatch", POOLCONFIG_MAXDESCLEN);
439 i++;
440
441 /* LOAD BALANCING MODE */
442
443 StrNCpy(status[i].name, "load_balance_mode", POOLCONFIG_MAXNAMELEN);
444 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->load_balance_mode);
445 StrNCpy(status[i].desc, "non 0 if operating in load balancing mode", POOLCONFIG_MAXDESCLEN);
446 i++;
447
448 StrNCpy(status[i].name, "ignore_leading_white_space", POOLCONFIG_MAXNAMELEN);
449 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ignore_leading_white_space);
450 StrNCpy(status[i].desc, "ignore leading white spaces", POOLCONFIG_MAXDESCLEN);
451 i++;
452
453 StrNCpy(status[i].name, "white_function_list", POOLCONFIG_MAXNAMELEN);
454 *(status[i].value) = '\0';
455 for (j = 0; j < pool_config->num_white_function_list; j++)
456 {
457 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
458 strncat(status[i].value, pool_config->white_function_list[j], len);
459 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
460 if (j != pool_config->num_white_function_list - 1)
461 strncat(status[i].value, ",", len);
462 }
463 StrNCpy(status[i].desc, "functions those do not write to database", POOLCONFIG_MAXDESCLEN);
464 i++;
465
466 StrNCpy(status[i].name, "black_function_list", POOLCONFIG_MAXNAMELEN);
467 *(status[i].value) = '\0';
468 for (j = 0; j < pool_config->num_black_function_list; j++)
469 {
470 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
471 strncat(status[i].value, pool_config->black_function_list[j], len);
472 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
473 if (j != pool_config->num_black_function_list - 1)
474 strncat(status[i].value, ",", len);
475 }
476 StrNCpy(status[i].desc, "functions those write to database", POOLCONFIG_MAXDESCLEN);
477 i++;
478
479 StrNCpy(status[i].name, "black_query_pattern_list", POOLCONFIG_MAXNAMELEN);
480 *(status[i].value) = '\0';
481 for (j = 0; j < pool_config->num_black_query_pattern_list; j++)
482 {
483 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
484 strncat(status[i].value, pool_config->black_query_pattern_list[j], len);
485 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
486 if (j != pool_config->num_black_query_pattern_list - 1)
487 strncat(status[i].value, ";", len);
488 }
489 StrNCpy(status[i].desc, "query patterns that should be sent to primary node", POOLCONFIG_MAXDESCLEN);
490 i++;
491
492 StrNCpy(status[i].name, "disable_load_balance_on_write", POOLCONFIG_MAXNAMELEN);
493 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->disable_load_balance_on_write);
494 StrNCpy(status[i].desc, "Load balance behavior when write query is received", POOLCONFIG_MAXDESCLEN);
495 i++;
496
497 /* MASTER/SLAVE MODE */
498
499 StrNCpy(status[i].name, "master_slave_mode", POOLCONFIG_MAXNAMELEN);
500 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->master_slave_mode);
501 StrNCpy(status[i].desc, "if true, operate in master/slave mode", POOLCONFIG_MAXDESCLEN);
502 i++;
503
504 StrNCpy(status[i].name, "master_slave_sub_mode", POOLCONFIG_MAXNAMELEN);
505 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->master_slave_sub_mode);
506 StrNCpy(status[i].desc, "master/slave sub mode", POOLCONFIG_MAXDESCLEN);
507 i++;
508
509 /* - Streaming - */
510 StrNCpy(status[i].name, "sr_check_period", POOLCONFIG_MAXNAMELEN);
511 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->sr_check_period);
512 StrNCpy(status[i].desc, "sr check period", POOLCONFIG_MAXDESCLEN);
513 i++;
514
515 StrNCpy(status[i].name, "sr_check_user", POOLCONFIG_MAXNAMELEN);
516 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_user);
517 StrNCpy(status[i].desc, "sr check user", POOLCONFIG_MAXDESCLEN);
518 i++;
519 #ifdef NOT_USED /* for security reason */
520 StrNCpy(status[i].name, "sr_check_password", POOLCONFIG_MAXNAMELEN);
521 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_password);
522 StrNCpy(status[i].desc, "sr check password", POOLCONFIG_MAXDESCLEN);
523 i++;
524 #endif
525 StrNCpy(status[i].name, "sr_check_database", POOLCONFIG_MAXNAMELEN);
526 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_database);
527 StrNCpy(status[i].desc, "sr check database", POOLCONFIG_MAXDESCLEN);
528 i++;
529
530 StrNCpy(status[i].name, "delay_threshold", POOLCONFIG_MAXNAMELEN);
531 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, INT64_FORMAT, pool_config->delay_threshold);
532 StrNCpy(status[i].desc, "standby delay threshold", POOLCONFIG_MAXDESCLEN);
533 i++;
534
535 /* - Special commands - */
536 StrNCpy(status[i].name, "follow_master_command", POOLCONFIG_MAXNAMELEN);
537 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->follow_master_command);
538 StrNCpy(status[i].desc, "follow master command", POOLCONFIG_MAXDESCLEN);
539 i++;
540
541 StrNCpy(status[i].name, "database_redirect_preference_list", POOLCONFIG_MAXNAMELEN);
542 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->database_redirect_preference_list);
543 StrNCpy(status[i].desc, "redirect by database name", POOLCONFIG_MAXDESCLEN);
544 i++;
545
546 StrNCpy(status[i].name, "app_name_redirect_preference_list", POOLCONFIG_MAXNAMELEN);
547 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->app_name_redirect_preference_list);
548 StrNCpy(status[i].desc, "redirect by application name", POOLCONFIG_MAXDESCLEN);
549 i++;
550
551 StrNCpy(status[i].name, "allow_sql_comments", POOLCONFIG_MAXNAMELEN);
552 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->allow_sql_comments);
553 StrNCpy(status[i].desc, "allow SQL comments", POOLCONFIG_MAXDESCLEN);
554 i++;
555
556 /* HEALTH CHECK */
557
558 StrNCpy(status[i].name, "health_check_period", POOLCONFIG_MAXNAMELEN);
559 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_period);
560 StrNCpy(status[i].desc, "health check period", POOLCONFIG_MAXDESCLEN);
561 i++;
562
563 StrNCpy(status[i].name, "health_check_timeout", POOLCONFIG_MAXNAMELEN);
564 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_timeout);
565 StrNCpy(status[i].desc, "health check timeout", POOLCONFIG_MAXDESCLEN);
566 i++;
567
568 StrNCpy(status[i].name, "health_check_user", POOLCONFIG_MAXNAMELEN);
569 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_user);
570 StrNCpy(status[i].desc, "health check user", POOLCONFIG_MAXDESCLEN);
571 i++;
572 #ifdef NOT_USED /* for security reason */
573 StrNCpy(status[i].name, "health_check_password", POOLCONFIG_MAXNAMELEN);
574 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_password);
575 StrNCpy(status[i].desc, "health check password", POOLCONFIG_MAXDESCLEN);
576 i++;
577 #endif
578 StrNCpy(status[i].name, "health_check_database", POOLCONFIG_MAXNAMELEN);
579 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_database);
580 StrNCpy(status[i].desc, "health check database", POOLCONFIG_MAXDESCLEN);
581 i++;
582
583 StrNCpy(status[i].name, "health_check_max_retries", POOLCONFIG_MAXNAMELEN);
584 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_max_retries);
585 StrNCpy(status[i].desc, "health check max retries", POOLCONFIG_MAXDESCLEN);
586 i++;
587
588 StrNCpy(status[i].name, "health_check_retry_delay", POOLCONFIG_MAXNAMELEN);
589 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_retry_delay);
590 StrNCpy(status[i].desc, "health check retry delay", POOLCONFIG_MAXDESCLEN);
591 i++;
592
593 StrNCpy(status[i].name, "connect_timeout", POOLCONFIG_MAXNAMELEN);
594 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connect_timeout);
595 StrNCpy(status[i].desc, "connect timeout", POOLCONFIG_MAXDESCLEN);
596 i++;
597
598 /* FAILOVER AND FAILBACK */
599
600 StrNCpy(status[i].name, "failover_command", POOLCONFIG_MAXNAMELEN);
601 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->failover_command);
602 StrNCpy(status[i].desc, "failover command", POOLCONFIG_MAXDESCLEN);
603 i++;
604
605 StrNCpy(status[i].name, "failback_command", POOLCONFIG_MAXNAMELEN);
606 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->failback_command);
607 StrNCpy(status[i].desc, "failback command", POOLCONFIG_MAXDESCLEN);
608 i++;
609
610 StrNCpy(status[i].name, "failover_on_backend_error", POOLCONFIG_MAXNAMELEN);
611 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->failover_on_backend_error);
612 StrNCpy(status[i].desc, "failover on backend error", POOLCONFIG_MAXDESCLEN);
613 i++;
614
615 StrNCpy(status[i].name, "detach_false_primary", POOLCONFIG_MAXNAMELEN);
616 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->detach_false_primary);
617 StrNCpy(status[i].desc, "detach false primary", POOLCONFIG_MAXDESCLEN);
618 i++;
619
620 /* ONLINE RECOVERY */
621
622 StrNCpy(status[i].name, "recovery_user", POOLCONFIG_MAXNAMELEN);
623 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_user);
624 StrNCpy(status[i].desc, "online recovery user", POOLCONFIG_MAXDESCLEN);
625 i++;
626
627 StrNCpy(status[i].name, "recovery_1st_stage_command", POOLCONFIG_MAXNAMELEN);
628 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_1st_stage_command);
629 StrNCpy(status[i].desc, "execute a command in first stage.", POOLCONFIG_MAXDESCLEN);
630 i++;
631
632 StrNCpy(status[i].name, "recovery_2nd_stage_command", POOLCONFIG_MAXNAMELEN);
633 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_2nd_stage_command);
634 StrNCpy(status[i].desc, "execute a command in second stage.", POOLCONFIG_MAXDESCLEN);
635 i++;
636
637 StrNCpy(status[i].name, "recovery_timeout", POOLCONFIG_MAXNAMELEN);
638 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->recovery_timeout);
639 StrNCpy(status[i].desc, "max time in seconds to wait for the recovering node's postmaster", POOLCONFIG_MAXDESCLEN);
640 i++;
641
642 StrNCpy(status[i].name, "search_primary_node_timeout", POOLCONFIG_MAXNAMELEN);
643 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->search_primary_node_timeout);
644 StrNCpy(status[i].desc, "max time in seconds to search for primary node after failover", POOLCONFIG_MAXDESCLEN);
645 i++;
646
647 StrNCpy(status[i].name, "client_idle_limit_in_recovery", POOLCONFIG_MAXNAMELEN);
648 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_idle_limit_in_recovery);
649 StrNCpy(status[i].desc, "if idle for this seconds, child connection closes in recovery 2nd statge", POOLCONFIG_MAXDESCLEN);
650 i++;
651
652 /* OTHERS */
653
654 StrNCpy(status[i].name, "relcache_expire", POOLCONFIG_MAXNAMELEN);
655 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%ld", pool_config->relcache_expire);
656 StrNCpy(status[i].desc, "relation cache expiration time in seconds", POOLCONFIG_MAXDESCLEN);
657 i++;
658
659 StrNCpy(status[i].name, "relcache_size", POOLCONFIG_MAXNAMELEN);
660 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->relcache_size);
661 StrNCpy(status[i].desc, "number of relation cache entry", POOLCONFIG_MAXDESCLEN);
662 i++;
663
664 StrNCpy(status[i].name, "check_temp_table", POOLCONFIG_MAXNAMELEN);
665 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->check_temp_table);
666 StrNCpy(status[i].desc, "enable temporary table check", POOLCONFIG_MAXDESCLEN);
667 i++;
668
669 StrNCpy(status[i].name, "check_unlogged_table", POOLCONFIG_MAXNAMELEN);
670 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->check_unlogged_table);
671 StrNCpy(status[i].desc, "enable unlogged table check", POOLCONFIG_MAXDESCLEN);
672 i++;
673
674 /*
675 * add for watchdog
676 */
677 StrNCpy(status[i].name, "use_watchdog", POOLCONFIG_MAXNAMELEN);
678 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->use_watchdog);
679 StrNCpy(status[i].desc, "non 0 if operating in use_watchdog", POOLCONFIG_MAXDESCLEN);
680 i++;
681
682 StrNCpy(status[i].name, "wd_ipc_socket_dir", POOLCONFIG_MAXNAMELEN);
683 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_ipc_socket_dir);
684 StrNCpy(status[i].desc, "watchdog ipc socket directory", POOLCONFIG_MAXDESCLEN);
685 i++;
686
687 StrNCpy(status[i].name, "wd_lifecheck_method", POOLCONFIG_MAXNAMELEN);
688 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_lifecheck_method);
689 StrNCpy(status[i].desc, "method of watchdog lifecheck", POOLCONFIG_MAXDESCLEN);
690 i++;
691
692 StrNCpy(status[i].name, "clear_memqcache_on_escalation", POOLCONFIG_MAXNAMELEN);
693 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->clear_memqcache_on_escalation);
694 StrNCpy(status[i].desc, "If true, clear all the query caches in shared memory when escalation occurs", POOLCONFIG_MAXDESCLEN);
695 i++;
696
697 StrNCpy(status[i].name, "wd_escalation_command", POOLCONFIG_MAXNAMELEN);
698 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_escalation_command);
699 StrNCpy(status[i].desc, "command executed when escalation occurs", POOLCONFIG_MAXDESCLEN);
700 i++;
701
702 StrNCpy(status[i].name, "wd_de_escalation_command", POOLCONFIG_MAXNAMELEN);
703 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_de_escalation_command);
704 StrNCpy(status[i].desc, "command executed when master pgpool resigns occurs", POOLCONFIG_MAXDESCLEN);
705 i++;
706
707 StrNCpy(status[i].name, "trusted_servers", POOLCONFIG_MAXNAMELEN);
708 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->trusted_servers);
709 StrNCpy(status[i].desc, "upper server list to observe connection", POOLCONFIG_MAXDESCLEN);
710 i++;
711
712 StrNCpy(status[i].name, "delegate_IP", POOLCONFIG_MAXNAMELEN);
713 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->delegate_IP);
714 StrNCpy(status[i].desc, "delegate IP address of master pgpool", POOLCONFIG_MAXDESCLEN);
715 i++;
716
717 StrNCpy(status[i].name, "wd_hostname", POOLCONFIG_MAXNAMELEN);
718 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_hostname);
719 StrNCpy(status[i].desc, "Host name or IP address of this watchdog", POOLCONFIG_MAXDESCLEN);
720 i++;
721
722 StrNCpy(status[i].name, "wd_port", POOLCONFIG_MAXNAMELEN);
723 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_port);
724 StrNCpy(status[i].desc, "watchdog port number", POOLCONFIG_MAXDESCLEN);
725 i++;
726
727 StrNCpy(status[i].name, "wd_priority", POOLCONFIG_MAXNAMELEN);
728 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_priority);
729 StrNCpy(status[i].desc, "watchdog priority", POOLCONFIG_MAXDESCLEN);
730 i++;
731
732 StrNCpy(status[i].name, "wd_interval", POOLCONFIG_MAXNAMELEN);
733 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_interval);
734 StrNCpy(status[i].desc, "life check interval (second)", POOLCONFIG_MAXDESCLEN);
735 i++;
736
737 StrNCpy(status[i].name, "ping_path", POOLCONFIG_MAXNAMELEN);
738 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ping_path);
739 StrNCpy(status[i].desc, "path to ping command", POOLCONFIG_MAXDESCLEN);
740 i++;
741
742 StrNCpy(status[i].name, "if_cmd_path", POOLCONFIG_MAXNAMELEN);
743 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->if_cmd_path);
744 StrNCpy(status[i].desc, "path to interface up/down command", POOLCONFIG_MAXDESCLEN);
745 i++;
746
747 StrNCpy(status[i].name, "if_up_cmd", POOLCONFIG_MAXNAMELEN);
748 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->if_up_cmd);
749 StrNCpy(status[i].desc, "virtual interface up command with full parameters", POOLCONFIG_MAXDESCLEN);
750 i++;
751
752 StrNCpy(status[i].name, "if_down_cmd", POOLCONFIG_MAXNAMELEN);
753 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->if_down_cmd);
754 StrNCpy(status[i].desc, "virtual interface down command with full parameters", POOLCONFIG_MAXDESCLEN);
755 i++;
756
757 StrNCpy(status[i].name, "arping_path", POOLCONFIG_MAXNAMELEN);
758 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->arping_path);
759 StrNCpy(status[i].desc, "path to arping command", POOLCONFIG_MAXDESCLEN);
760 i++;
761
762 StrNCpy(status[i].name, "arping_cmd", POOLCONFIG_MAXNAMELEN);
763 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->arping_cmd);
764 StrNCpy(status[i].desc, "send ARP REQUESTi to neighbour host", POOLCONFIG_MAXDESCLEN);
765 i++;
766
767 StrNCpy(status[i].name, "wd_heartbeat_port", POOLCONFIG_MAXNAMELEN);
768 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_heartbeat_port);
769 StrNCpy(status[i].desc, "port number for receiving heartbeat signal", POOLCONFIG_MAXDESCLEN);
770 i++;
771
772 StrNCpy(status[i].name, "wd_heartbeat_keepalive", POOLCONFIG_MAXNAMELEN);
773 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_heartbeat_keepalive);
774 StrNCpy(status[i].desc, "interval time of sending heartbeat siganl (sec)", POOLCONFIG_MAXDESCLEN);
775 i++;
776
777 StrNCpy(status[i].name, "wd_heartbeat_deadtime", POOLCONFIG_MAXNAMELEN);
778 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_heartbeat_deadtime);
779 StrNCpy(status[i].desc, "deadtime interval for heartbeat siganl (sec)", POOLCONFIG_MAXDESCLEN);
780 i++;
781
782 StrNCpy(status[i].name, "wd_life_point", POOLCONFIG_MAXNAMELEN);
783 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_life_point);
784 StrNCpy(status[i].desc, "retry times of life check", POOLCONFIG_MAXDESCLEN);
785 i++;
786
787 StrNCpy(status[i].name, "wd_lifecheck_query", POOLCONFIG_MAXNAMELEN);
788 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_query);
789 StrNCpy(status[i].desc, "lifecheck query to pgpool from watchdog", POOLCONFIG_MAXDESCLEN);
790 i++;
791
792 StrNCpy(status[i].name, "wd_lifecheck_dbname", POOLCONFIG_MAXNAMELEN);
793 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_dbname);
794 StrNCpy(status[i].desc, "database name connected for lifecheck", POOLCONFIG_MAXDESCLEN);
795 i++;
796
797 StrNCpy(status[i].name, "wd_lifecheck_user", POOLCONFIG_MAXNAMELEN);
798 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_user);
799 StrNCpy(status[i].desc, "watchdog user monitoring pgpools in lifecheck", POOLCONFIG_MAXDESCLEN);
800 i++;
801
802 StrNCpy(status[i].name, "wd_lifecheck_password", POOLCONFIG_MAXNAMELEN);
803 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_password);
804 StrNCpy(status[i].desc, "password for watchdog user in lifecheck", POOLCONFIG_MAXDESCLEN);
805 i++;
806
807 StrNCpy(status[i].name, "wd_monitoring_interfaces_list", POOLCONFIG_MAXNAMELEN);
808 *(status[i].value) = '\0';
809 for (j = 0; j < pool_config->num_wd_monitoring_interfaces_list; j++)
810 {
811 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
812 strncat(status[i].value, pool_config->wd_monitoring_interfaces_list[j], len);
813 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
814 if (j != pool_config->num_wd_monitoring_interfaces_list - 1)
815 strncat(status[i].value, ",", len);
816 }
817 StrNCpy(status[i].desc, "interfaces to monitor by watchdog", POOLCONFIG_MAXDESCLEN);
818 i++;
819
820 /*
821 * end of watchdog
822 */
823
824 StrNCpy(status[i].name, "memory_cache_enabled", POOLCONFIG_MAXNAMELEN);
825 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memory_cache_enabled);
826 StrNCpy(status[i].desc, "If true, use the memory cache functionality, false by default", POOLCONFIG_MAXDESCLEN);
827 i++;
828
829 StrNCpy(status[i].name, "memqcache_method", POOLCONFIG_MAXNAMELEN);
830 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_method);
831 StrNCpy(status[i].desc, "Cache store method. either shmem(shared memory) or Memcached. shmem by default", POOLCONFIG_MAXDESCLEN);
832 i++;
833
834 StrNCpy(status[i].name, "memqcache_memcached_host", POOLCONFIG_MAXNAMELEN);
835 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->memqcache_memcached_host);
836 StrNCpy(status[i].desc, "Memcached host name. Mandatory if memqcache_method=memcached", POOLCONFIG_MAXDESCLEN);
837 i++;
838
839 StrNCpy(status[i].name, "memqcache_memcached_port", POOLCONFIG_MAXNAMELEN);
840 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_memcached_port);
841 StrNCpy(status[i].desc, "Memcached port number. Mondatory if memqcache_method=memcached", POOLCONFIG_MAXDESCLEN);
842 i++;
843
844 StrNCpy(status[i].name, "memqcache_total_size", POOLCONFIG_MAXNAMELEN);
845 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%ld", pool_config->memqcache_total_size);
846 StrNCpy(status[i].desc, "Total memory size in bytes for storing memory cache. Mandatory if memqcache_method=shmem", POOLCONFIG_MAXDESCLEN);
847 i++;
848
849 StrNCpy(status[i].name, "memqcache_max_num_cache", POOLCONFIG_MAXNAMELEN);
850 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_max_num_cache);
851 StrNCpy(status[i].desc, "Total number of cache entries", POOLCONFIG_MAXDESCLEN);
852 i++;
853
854 StrNCpy(status[i].name, "memqcache_expire", POOLCONFIG_MAXNAMELEN);
855 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_expire);
856 StrNCpy(status[i].desc, "Memory cache entry life time specified in seconds. 60 by default", POOLCONFIG_MAXDESCLEN);
857 i++;
858
859 StrNCpy(status[i].name, "memqcache_auto_cache_invalidation", POOLCONFIG_MAXNAMELEN);
860 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_auto_cache_invalidation);
861 StrNCpy(status[i].desc, "If true, invalidation of query cache is triggered by corresponding DDL/DML/DCL(and memqcache_expire). If false, it is only triggered by memqcache_expire. True by default.", POOLCONFIG_MAXDESCLEN);
862 i++;
863
864 StrNCpy(status[i].name, "memqcache_maxcache", POOLCONFIG_MAXNAMELEN);
865 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_maxcache);
866 StrNCpy(status[i].desc, "Maximum SELECT result size in bytes", POOLCONFIG_MAXDESCLEN);
867 i++;
868
869 StrNCpy(status[i].name, "memqcache_cache_block_size", POOLCONFIG_MAXNAMELEN);
870 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_cache_block_size);
871 StrNCpy(status[i].desc, "Cache block size in bytes. 8192 by default", POOLCONFIG_MAXDESCLEN);
872 i++;
873
874 StrNCpy(status[i].name, "memqcache_cache_oiddir", POOLCONFIG_MAXNAMELEN);
875 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->memqcache_oiddir);
876 StrNCpy(status[i].desc, "Tempory work directory to record table oids", POOLCONFIG_MAXDESCLEN);
877 i++;
878
879 StrNCpy(status[i].name, "memqcache_stats_start_time", POOLCONFIG_MAXNAMELEN);
880 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", ctime(&pool_get_memqcache_stats()->start_time));
881 StrNCpy(status[i].desc, "Start time of query cache stats", POOLCONFIG_MAXDESCLEN);
882 i++;
883
884 StrNCpy(status[i].name, "memqcache_no_cache_hits", POOLCONFIG_MAXNAMELEN);
885 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%lld", pool_get_memqcache_stats()->num_selects);
886 StrNCpy(status[i].desc, "Number of SELECTs not hitting query cache", POOLCONFIG_MAXDESCLEN);
887 i++;
888
889 StrNCpy(status[i].name, "memqcache_cache_hits", POOLCONFIG_MAXNAMELEN);
890 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%lld", pool_get_memqcache_stats()->num_cache_hits);
891 StrNCpy(status[i].desc, "Number of SELECTs hitting query cache", POOLCONFIG_MAXDESCLEN);
892 i++;
893
894 StrNCpy(status[i].name, "white_memqcache_table_list", POOLCONFIG_MAXNAMELEN);
895 *(status[i].value) = '\0';
896 for (j = 0; j < pool_config->num_white_memqcache_table_list; j++)
897 {
898 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
899 strncat(status[i].value, pool_config->white_memqcache_table_list[j], len);
900 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
901 if (j != pool_config->num_white_memqcache_table_list - 1)
902 strncat(status[i].value, ",", len);
903 }
904 StrNCpy(status[i].desc, "tables to memqcache", POOLCONFIG_MAXDESCLEN);
905 i++;
906
907 StrNCpy(status[i].name, "black_memqcache_table_list", POOLCONFIG_MAXNAMELEN);
908 *(status[i].value) = '\0';
909 for (j = 0; j < pool_config->num_black_memqcache_table_list; j++)
910 {
911 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
912 strncat(status[i].value, pool_config->black_memqcache_table_list[j], len);
913 len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
914 if (j != pool_config->num_black_memqcache_table_list - 1)
915 strncat(status[i].value, ",", len);
916 }
917 StrNCpy(status[i].desc, "tables not to memqcache", POOLCONFIG_MAXDESCLEN);
918 i++;
919
920 /* BACKENDS */
921
922 for (j = 0; j < NUM_BACKENDS; j++)
923 {
924 if (BACKEND_INFO(j).backend_port == 0)
925 continue;
926
927 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_hostname%d", j);
928 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_hostname);
929 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d hostname", j);
930 i++;
931
932 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_port%d", j);
933 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", BACKEND_INFO(j).backend_port);
934 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d port number", j);
935 i++;
936
937 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_weight%d", j);
938 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%f", BACKEND_INFO(j).backend_weight / RAND_MAX);
939 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "weight of backend #%d", j);
940 i++;
941
942 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_data_directory%d", j);
943 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_data_directory);
944 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "data directory for backend #%d", j);
945 i++;
946
947 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_status%d", j);
948 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", backend_status_to_str(&BACKEND_INFO(j)));
949 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "status of backend #%d", j);
950 i++;
951
952 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "standby_delay%d", j);
953 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, UINT64_FORMAT, BACKEND_INFO(j).standby_delay);
954 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "standby delay of backend #%d", j);
955 i++;
956
957 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_flag%d", j);
958 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_flag_to_str(BACKEND_INFO(j).flag));
959 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d flag", j);
960 i++;
961 }
962
963 for (j = 0; j < MAX_WATCHDOG_NUM; j++)
964 {
965 if (WD_INFO(j).pgpool_port == 0)
966 continue;
967
968 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "other_pgpool_hostname%d", j);
969 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", WD_INFO(j).hostname);
970 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "pgpool #%d hostname", j);
971 i++;
972
973 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "other_pgpool_port%d", j);
974 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", WD_INFO(j).pgpool_port);
975 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "pgpool #%d port number", j);
976 i++;
977
978 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "other_pgpool_wd_port%d", j);
979 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", WD_INFO(j).wd_port);
980 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "pgpool #%d watchdog port number", j);
981 i++;
982
983 }
984
985 for (j = 0; j < pool_config->num_hb_if; j++)
986 {
987 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "heartbeat_device%d", j);
988 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", WD_HB_IF(j).if_name);
989 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "name of NIC device #%d for sending hearbeat", j);
990 i++;
991
992 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "heartbeat_destination%d", j);
993 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", WD_HB_IF(j).addr);
994 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "destination host for sending heartbeat using NIC device %d", j);
995 i++;
996
997 snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "heartbeat_destination_port%d", j);
998 snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", WD_HB_IF(j).dest_port);
999 snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "destination port for sending heartbeat using NIC device %d", j);
1000 i++;
1001 }
1002
1003 *nrows = i;
1004 return status;
1005 }
1006
1007 void
send_config_var_detail_row(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,const char * name,const char * value,const char * description)1008 send_config_var_detail_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *name, const char *value, const char *description)
1009 {
1010 int size;
1011 int hsize;
1012 static short num_fields = 3;
1013
1014 if (MAJOR(backend) == PROTO_MAJOR_V2)
1015 {
1016
1017 int nbytes = (num_fields + 7) / 8;
1018 static unsigned char nullmap[2] = {0xff, 0xff};
1019
1020 /* ascii row */
1021 pool_write(frontend, "D", 1);
1022 pool_write_and_flush(frontend, nullmap, nbytes);
1023
1024 size = strlen(name);
1025 hsize = htonl(size + 4);
1026 pool_write(frontend, &hsize, sizeof(hsize));
1027 pool_write(frontend, (void *) name, size);
1028
1029 size = strlen(value);
1030 hsize = htonl(size + 4);
1031 pool_write(frontend, &hsize, sizeof(hsize));
1032 pool_write(frontend, (void *) value, size);
1033
1034 size = strlen(description);
1035 hsize = htonl(size + 4);
1036 pool_write(frontend, &hsize, sizeof(hsize));
1037 pool_write(frontend, (void *) description, size);
1038 }
1039 else
1040 {
1041 short s;
1042
1043 pool_write(frontend, "D", 1);
1044 size = 6; /* int32 + int16; */
1045 size += 4 + strlen(name); /* int32 + data; */
1046 size += 4 + strlen(value); /* int32 + data; */
1047 size += 4 + strlen(description); /* int32 + data; */
1048 hsize = htonl(size);
1049 pool_write(frontend, &hsize, sizeof(hsize));
1050 s = htons(num_fields);
1051 pool_write(frontend, &s, sizeof(s));
1052
1053 size = strlen(name);
1054 hsize = htonl(size);
1055 pool_write(frontend, &hsize, sizeof(hsize));
1056 pool_write(frontend, (void *) name, size);
1057
1058 size = strlen(value);
1059 hsize = htonl(size);
1060 pool_write(frontend, &hsize, sizeof(hsize));
1061 pool_write(frontend, (void *) value, size);
1062
1063 size = strlen(description);
1064 hsize = htonl(size);
1065 pool_write(frontend, &hsize, sizeof(hsize));
1066 pool_write(frontend, (void *) description, size);
1067 }
1068 }
1069
1070 void
send_config_var_value_only_row(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,const char * value)1071 send_config_var_value_only_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *value)
1072 {
1073 int size;
1074 int hsize;
1075 static short num_fields = 1;
1076
1077 if (MAJOR(backend) == PROTO_MAJOR_V2)
1078 {
1079
1080 int nbytes = (num_fields + 7) / 8;
1081 static unsigned char nullmap[2] = {0xff, 0xff};
1082
1083 /* ascii row */
1084 pool_write(frontend, "D", 1);
1085 pool_write_and_flush(frontend, nullmap, nbytes);
1086
1087 size = strlen(value);
1088 hsize = htonl(size + 4);
1089 pool_write(frontend, &hsize, sizeof(hsize));
1090 pool_write(frontend, (void *) value, size);
1091
1092 }
1093 else
1094 {
1095 short s;
1096
1097 pool_write(frontend, "D", 1);
1098 size = 6; /* int32 + int16; */
1099 size += 4 + strlen(value); /* int32 + data; */
1100 hsize = htonl(size);
1101 pool_write(frontend, &hsize, sizeof(hsize));
1102 s = htons(num_fields);
1103 pool_write(frontend, &s, sizeof(s));
1104
1105 size = strlen(value);
1106 hsize = htonl(size);
1107 pool_write(frontend, &hsize, sizeof(hsize));
1108 pool_write(frontend, (void *) value, size);
1109 }
1110 }
1111
1112 void
config_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1113 config_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1114 {
1115 static char *field_names[] = {"item", "value", "description"};
1116 static unsigned char nullmap[2] = {0xff, 0xff};
1117 static short num_fields = 3;
1118 short s;
1119 int nbytes = (num_fields + 7) / 8;
1120 int len;
1121 int nrows;
1122 int size;
1123 int hsize;
1124 int i;
1125
1126 POOL_REPORT_CONFIG *status = get_config(&nrows);
1127
1128 send_row_description(frontend, backend, num_fields, field_names);
1129
1130 if (MAJOR(backend) == PROTO_MAJOR_V2)
1131 {
1132 /* ascii row */
1133 for (i = 0; i < nrows; i++)
1134 {
1135 pool_write(frontend, "D", 1);
1136 pool_write_and_flush(frontend, nullmap, nbytes);
1137
1138 size = strlen(status[i].name);
1139 hsize = htonl(size + 4);
1140 pool_write(frontend, &hsize, sizeof(hsize));
1141 pool_write(frontend, status[i].name, size);
1142
1143 size = strlen(status[i].value);
1144 hsize = htonl(size + 4);
1145 pool_write(frontend, &hsize, sizeof(hsize));
1146 pool_write(frontend, status[i].value, size);
1147
1148 size = strlen(status[i].desc);
1149 hsize = htonl(size + 4);
1150 pool_write(frontend, &hsize, sizeof(hsize));
1151 pool_write(frontend, status[i].desc, size);
1152 }
1153 }
1154 else
1155 {
1156 /* data row */
1157 for (i = 0; i < nrows; i++)
1158 {
1159 pool_write(frontend, "D", 1);
1160 len = 6; /* int32 + int16; */
1161 len += 4 + strlen(status[i].name); /* int32 + data; */
1162 len += 4 + strlen(status[i].value); /* int32 + data; */
1163 len += 4 + strlen(status[i].desc); /* int32 + data; */
1164 len = htonl(len);
1165 pool_write(frontend, &len, sizeof(len));
1166 s = htons(num_fields);
1167 pool_write(frontend, &s, sizeof(s));
1168
1169 len = htonl(strlen(status[i].name));
1170 pool_write(frontend, &len, sizeof(len));
1171 pool_write(frontend, status[i].name, strlen(status[i].name));
1172
1173 len = htonl(strlen(status[i].value));
1174 pool_write(frontend, &len, sizeof(len));
1175 pool_write(frontend, status[i].value, strlen(status[i].value));
1176
1177 len = htonl(strlen(status[i].desc));
1178 pool_write(frontend, &len, sizeof(len));
1179 pool_write(frontend, status[i].desc, strlen(status[i].desc));
1180 }
1181 }
1182
1183 send_complete_and_ready(frontend, backend, "SELECT", nrows);
1184
1185 pfree(status);
1186 }
1187
1188 POOL_REPORT_NODES *
get_nodes(int * nrows)1189 get_nodes(int *nrows)
1190 {
1191 int i;
1192 POOL_REPORT_NODES *nodes = palloc(NUM_BACKENDS * sizeof(POOL_REPORT_NODES));
1193 BackendInfo *bi = NULL;
1194 POOL_SESSION_CONTEXT *session_context = pool_get_session_context(false);
1195 struct tm tm;
1196
1197 for (i = 0; i < NUM_BACKENDS; i++)
1198 {
1199 bi = pool_get_node_info(i);
1200
1201 snprintf(nodes[i].node_id, POOLCONFIG_MAXIDLEN, "%d", i);
1202 StrNCpy(nodes[i].hostname, bi->backend_hostname, strlen(bi->backend_hostname) + 1);
1203 snprintf(nodes[i].port, POOLCONFIG_MAXPORTLEN, "%d", bi->backend_port);
1204 snprintf(nodes[i].status, POOLCONFIG_MAXSTATLEN, "%s", backend_status_to_str(bi));
1205 snprintf(nodes[i].lb_weight, POOLCONFIG_MAXWEIGHTLEN, "%f", bi->backend_weight / RAND_MAX);
1206 snprintf(nodes[i].select, POOLCONFIG_MAXWEIGHTLEN, UINT64_FORMAT, stat_get_select_count(i));
1207 snprintf(nodes[i].load_balance_node, POOLCONFIG_MAXWEIGHTLEN, "%s",
1208 (session_context->load_balance_node_id == i) ? "true" : "false");
1209
1210 snprintf(nodes[i].delay, POOLCONFIG_MAXWEIGHTLEN, "%d", 0);
1211
1212 if (STREAM)
1213 {
1214 if (i == REAL_PRIMARY_NODE_ID)
1215 {
1216 snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "primary");
1217 }
1218 else
1219 {
1220 snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "standby");
1221 snprintf(nodes[i].delay, POOLCONFIG_MAXWEIGHTLEN, UINT64_FORMAT, bi->standby_delay);
1222 }
1223 }
1224 else
1225 {
1226 if (i == REAL_MASTER_NODE_ID)
1227 snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "master");
1228 else
1229 snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "slave");
1230 }
1231
1232 /* status last changed */
1233 localtime_r(&bi->status_changed_time, &tm);
1234 strftime(nodes[i].last_status_change, POOLCONFIG_MAXDATELEN, "%F %T", &tm);
1235 }
1236
1237 *nrows = i;
1238
1239 return nodes;
1240 }
1241
1242 void
nodes_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1243 nodes_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1244 {
1245 static char *field_names[] = {"node_id", "hostname", "port", "status", "lb_weight", "role", "select_cnt", "load_balance_node", "replication_delay", "last_status_change"};
1246 short num_fields = sizeof(field_names) / sizeof(char *);
1247 int i;
1248 short s;
1249 int len;
1250 int nrows;
1251 int size;
1252 int hsize;
1253 static unsigned char nullmap[2] = {0xff, 0xff};
1254 int nbytes = (num_fields + 7) / 8;
1255
1256 POOL_REPORT_NODES *nodes = get_nodes(&nrows);
1257
1258 send_row_description(frontend, backend, num_fields, field_names);
1259
1260 if (MAJOR(backend) == PROTO_MAJOR_V2)
1261 {
1262 /* ascii row */
1263 for (i = 0; i < nrows; i++)
1264 {
1265 pool_write(frontend, "D", 1);
1266 pool_write_and_flush(frontend, nullmap, nbytes);
1267
1268 size = strlen(nodes[i].node_id);
1269 hsize = htonl(size + 4);
1270 pool_write(frontend, &hsize, sizeof(hsize));
1271 pool_write(frontend, nodes[i].node_id, size);
1272
1273 size = strlen(nodes[i].hostname);
1274 hsize = htonl(size + 4);
1275 pool_write(frontend, &hsize, sizeof(hsize));
1276 pool_write(frontend, nodes[i].hostname, size);
1277
1278 size = strlen(nodes[i].port);
1279 hsize = htonl(size + 4);
1280 pool_write(frontend, &hsize, sizeof(hsize));
1281 pool_write(frontend, nodes[i].port, size);
1282
1283 size = strlen(nodes[i].status);
1284 hsize = htonl(size + 4);
1285 pool_write(frontend, &hsize, sizeof(hsize));
1286 pool_write(frontend, nodes[i].status, size);
1287
1288 size = strlen(nodes[i].lb_weight);
1289 hsize = htonl(size + 4);
1290 pool_write(frontend, &hsize, sizeof(hsize));
1291 pool_write(frontend, nodes[i].lb_weight, size);
1292
1293 size = strlen(nodes[i].role);
1294 hsize = htonl(size + 4);
1295 pool_write(frontend, &hsize, sizeof(hsize));
1296 pool_write(frontend, nodes[i].role, size);
1297
1298 size = strlen(nodes[i].select);
1299 hsize = htonl(size + 4);
1300 pool_write(frontend, &hsize, sizeof(hsize));
1301 pool_write(frontend, nodes[i].select, size);
1302
1303 size = strlen(nodes[i].load_balance_node);
1304 hsize = htonl(size + 4);
1305 pool_write(frontend, &hsize, sizeof(hsize));
1306 pool_write(frontend, nodes[i].load_balance_node, size);
1307
1308 size = strlen(nodes[i].delay);
1309 hsize = htonl(size + 4);
1310 pool_write(frontend, &hsize, sizeof(hsize));
1311 pool_write(frontend, nodes[i].delay, size);
1312
1313 size = strlen(nodes[i].last_status_change);
1314 hsize = htonl(size + 4);
1315 pool_write(frontend, &hsize, sizeof(hsize));
1316 pool_write(frontend, nodes[i].last_status_change, size);
1317 }
1318 }
1319 else
1320 {
1321 /* data row */
1322 for (i = 0; i < nrows; i++)
1323 {
1324 pool_write(frontend, "D", 1);
1325 len = 6; /* int32 + int16; */
1326 len += 4 + strlen(nodes[i].node_id); /* int32 + data; */
1327 len += 4 + strlen(nodes[i].hostname); /* int32 + data; */
1328 len += 4 + strlen(nodes[i].port); /* int32 + data; */
1329 len += 4 + strlen(nodes[i].status); /* int32 + data; */
1330 len += 4 + strlen(nodes[i].lb_weight); /* int32 + data; */
1331 len += 4 + strlen(nodes[i].role); /* int32 + data; */
1332 len += 4 + strlen(nodes[i].select); /* int32 + data; */
1333 len += 4 + strlen(nodes[i].load_balance_node); /* int32 + data; */
1334 len += 4 + strlen(nodes[i].delay); /* int32 + data; */
1335 len += 4 + strlen(nodes[i].last_status_change); /* int32 + data; */
1336 len = htonl(len);
1337 pool_write(frontend, &len, sizeof(len));
1338 s = htons(num_fields);
1339 pool_write(frontend, &s, sizeof(s));
1340
1341 len = htonl(strlen(nodes[i].node_id));
1342 pool_write(frontend, &len, sizeof(len));
1343 pool_write(frontend, nodes[i].node_id, strlen(nodes[i].node_id));
1344
1345 len = htonl(strlen(nodes[i].hostname));
1346 pool_write(frontend, &len, sizeof(len));
1347 pool_write(frontend, nodes[i].hostname, strlen(nodes[i].hostname));
1348
1349 len = htonl(strlen(nodes[i].port));
1350 pool_write(frontend, &len, sizeof(len));
1351 pool_write(frontend, nodes[i].port, strlen(nodes[i].port));
1352
1353 len = htonl(strlen(nodes[i].status));
1354 pool_write(frontend, &len, sizeof(len));
1355 pool_write(frontend, nodes[i].status, strlen(nodes[i].status));
1356
1357 len = htonl(strlen(nodes[i].lb_weight));
1358 pool_write(frontend, &len, sizeof(len));
1359 pool_write(frontend, nodes[i].lb_weight, strlen(nodes[i].lb_weight));
1360
1361 len = htonl(strlen(nodes[i].role));
1362 pool_write(frontend, &len, sizeof(len));
1363 pool_write(frontend, nodes[i].role, strlen(nodes[i].role));
1364
1365 len = htonl(strlen(nodes[i].select));
1366 pool_write(frontend, &len, sizeof(len));
1367 pool_write(frontend, nodes[i].select, strlen(nodes[i].select));
1368
1369 len = htonl(strlen(nodes[i].load_balance_node));
1370 pool_write(frontend, &len, sizeof(len));
1371 pool_write(frontend, nodes[i].load_balance_node, strlen(nodes[i].load_balance_node));
1372
1373 len = htonl(strlen(nodes[i].delay));
1374 pool_write(frontend, &len, sizeof(len));
1375 pool_write(frontend, nodes[i].delay, strlen(nodes[i].delay));
1376
1377 len = htonl(strlen(nodes[i].last_status_change));
1378 pool_write(frontend, &len, sizeof(len));
1379 pool_write(frontend, nodes[i].last_status_change, strlen(nodes[i].last_status_change));
1380 }
1381 }
1382
1383 send_complete_and_ready(frontend, backend, "SELECT", nrows);
1384
1385 pfree(nodes);
1386 }
1387
1388
1389 POOL_REPORT_POOLS *
get_pools(int * nrows)1390 get_pools(int *nrows)
1391 {
1392 int child,
1393 pool,
1394 poolBE,
1395 backend_id;
1396
1397 ProcessInfo *pi = NULL;
1398 int proc_id;
1399
1400 int lines = 0;
1401
1402 POOL_REPORT_POOLS *pools = palloc(
1403 pool_config->num_init_children * pool_config->max_pool * NUM_BACKENDS * sizeof(POOL_REPORT_POOLS)
1404 );
1405
1406 for (child = 0; child < pool_config->num_init_children; child++)
1407 {
1408 proc_id = process_info[child].pid;
1409 pi = pool_get_process_info(proc_id);
1410
1411 for (pool = 0; pool < pool_config->max_pool; pool++)
1412 {
1413 for (backend_id = 0; backend_id < NUM_BACKENDS; backend_id++)
1414 {
1415 poolBE = pool * MAX_NUM_BACKENDS + backend_id;
1416 pools[lines].pool_pid = proc_id;
1417 pools[lines].start_time = pi->start_time;
1418 pools[lines].pool_id = pool;
1419 pools[lines].backend_id = backend_id;
1420 if (strlen(pi->connection_info[poolBE].database) == 0)
1421 {
1422 StrNCpy(pools[lines].database, "", POOLCONFIG_MAXIDENTLEN);
1423 StrNCpy(pools[lines].username, "", POOLCONFIG_MAXIDENTLEN);
1424 pools[lines].create_time = 0;
1425 pools[lines].pool_majorversion = 0;
1426 pools[lines].pool_minorversion = 0;
1427 }
1428 else
1429 {
1430 StrNCpy(pools[lines].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN);
1431 StrNCpy(pools[lines].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN);
1432 pools[lines].create_time = pi->connection_info[poolBE].create_time;
1433 pools[lines].pool_majorversion = pi->connection_info[poolBE].major;
1434 pools[lines].pool_minorversion = pi->connection_info[poolBE].minor;
1435 }
1436 pools[lines].pool_counter = pi->connection_info[poolBE].counter;
1437 pools[lines].pool_backendpid = ntohl(pi->connection_info[poolBE].pid);
1438 pools[lines].pool_connected = pi->connection_info[poolBE].connected;
1439 lines++;
1440 }
1441 }
1442 }
1443
1444 *nrows = lines;
1445 return pools;
1446 }
1447
1448 void
pools_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1449 pools_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1450 {
1451 static short num_fields = 12;
1452 static char *field_names[] = {"pool_pid", "start_time", "pool_id", "backend_id", "database", "username", "create_time",
1453 "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
1454 short s;
1455 int len;
1456 int i;
1457 static unsigned char nullmap[2] = {0xff, 0xff};
1458 int nbytes = (num_fields + 7) / 8;
1459 int nrows;
1460 int size;
1461 int hsize;
1462 char proc_pid[16];
1463 char pool_id[16];
1464 char proc_start_time[20];
1465 char proc_create_time[20];
1466 char majorversion[5];
1467 char minorversion[5];
1468 char pool_counter[16];
1469 char backend_id[16];
1470 char backend_pid[16];
1471 char connected[2];
1472
1473 POOL_REPORT_POOLS *pools = get_pools(&nrows);
1474
1475 send_row_description(frontend, backend, num_fields, field_names);
1476
1477 if (MAJOR(backend) == PROTO_MAJOR_V2)
1478 hsize = 4;
1479 else
1480 hsize = 0;
1481
1482 /* ascii row */
1483 for (i = 0; i < nrows; i++)
1484 {
1485 snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
1486 snprintf(pool_id, sizeof(pool_id), "%d", pools[i].pool_id);
1487 if (pools[i].start_time)
1488 strftime(proc_start_time, sizeof(proc_start_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].start_time));
1489 else
1490 *proc_start_time = '\0';
1491 if (pools[i].create_time)
1492 strftime(proc_create_time, sizeof(proc_create_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].create_time));
1493 else
1494 *proc_create_time = '\0';
1495 snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
1496 snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
1497 snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
1498 snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
1499 snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
1500 snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);
1501
1502 if (MAJOR(backend) == PROTO_MAJOR_V2)
1503 {
1504 pool_write(frontend, "D", 1);
1505 pool_write_and_flush(frontend, nullmap, nbytes);
1506 }
1507 else
1508 {
1509 pool_write(frontend, "D", 1);
1510 len = 6; /* int32 + int16; */
1511 len += 4 + strlen(proc_pid); /* int32 + data */
1512 len += 4 + strlen(proc_start_time); /* int32 + data */
1513 len += 4 + strlen(pool_id); /* int32 + data */
1514 len += 4 + strlen(backend_id); /* int32 + data */
1515 len += 4 + strlen(pools[i].database); /* int32 + data */
1516 len += 4 + strlen(pools[i].username); /* int32 + data */
1517 len += 4 + strlen(proc_create_time); /* int32 + data */
1518 len += 4 + strlen(majorversion); /* int32 + data */
1519 len += 4 + strlen(minorversion); /* int32 + data */
1520 len += 4 + strlen(pool_counter); /* int32 + data */
1521 len += 4 + strlen(backend_pid); /* int32 + data */
1522 len += 4 + strlen(connected); /* int32 + data */
1523
1524 len = htonl(len);
1525 pool_write(frontend, &len, sizeof(len));
1526 s = htons(num_fields);
1527 pool_write(frontend, &s, sizeof(s));
1528 }
1529
1530 len = strlen(proc_pid);
1531 size = htonl(len + hsize);
1532 pool_write(frontend, &size, sizeof(size));
1533 pool_write(frontend, proc_pid, len);
1534
1535 len = strlen(proc_start_time);
1536 size = htonl(len + hsize);
1537 pool_write(frontend, &size, sizeof(size));
1538 pool_write(frontend, proc_start_time, len);
1539
1540 len = strlen(pool_id);
1541 size = htonl(len + hsize);
1542 pool_write(frontend, &size, sizeof(size));
1543 pool_write(frontend, pool_id, len);
1544
1545 len = strlen(backend_id);
1546 size = htonl(len + hsize);
1547 pool_write(frontend, &size, sizeof(size));
1548 pool_write(frontend, backend_id, len);
1549
1550 len = strlen(pools[i].database);
1551 size = htonl(len + hsize);
1552 pool_write(frontend, &size, sizeof(size));
1553 pool_write(frontend, pools[i].database, len);
1554
1555 len = strlen(pools[i].username);
1556 size = htonl(len + hsize);
1557 pool_write(frontend, &size, sizeof(size));
1558 pool_write(frontend, pools[i].username, len);
1559
1560 len = strlen(proc_create_time);
1561 size = htonl(len + hsize);
1562 pool_write(frontend, &size, sizeof(size));
1563 pool_write(frontend, proc_create_time, len);
1564
1565 len = strlen(majorversion);
1566 size = htonl(len + hsize);
1567 pool_write(frontend, &size, sizeof(size));
1568 pool_write(frontend, majorversion, len);
1569
1570 len = strlen(minorversion);
1571 size = htonl(len + hsize);
1572 pool_write(frontend, &size, sizeof(size));
1573 pool_write(frontend, minorversion, len);
1574
1575 len = strlen(pool_counter);
1576 size = htonl(len + hsize);
1577 pool_write(frontend, &size, sizeof(size));
1578 pool_write(frontend, pool_counter, len);
1579
1580 len = strlen(backend_pid);
1581 size = htonl(len + hsize);
1582 pool_write(frontend, &size, sizeof(size));
1583 pool_write(frontend, backend_pid, len);
1584
1585 len = strlen(connected);
1586 size = htonl(len + hsize);
1587 pool_write(frontend, &size, sizeof(size));
1588 pool_write(frontend, connected, len);
1589 }
1590
1591 send_complete_and_ready(frontend, backend, "SELECT", nrows);
1592
1593 pfree(pools);
1594 }
1595
1596 POOL_REPORT_PROCESSES *
get_processes(int * nrows)1597 get_processes(int *nrows)
1598 {
1599 int child;
1600 int pool;
1601 int poolBE;
1602 ProcessInfo *pi = NULL;
1603 int proc_id;
1604
1605 POOL_REPORT_PROCESSES *processes = palloc(pool_config->num_init_children * sizeof(POOL_REPORT_PROCESSES));
1606
1607 for (child = 0; child < pool_config->num_init_children; child++)
1608 {
1609 proc_id = process_info[child].pid;
1610 pi = pool_get_process_info(proc_id);
1611
1612 snprintf(processes[child].pool_pid, POOLCONFIG_MAXCOUNTLEN, "%d", proc_id);
1613 strftime(processes[child].start_time, POOLCONFIG_MAXDATELEN, "%Y-%m-%d %H:%M:%S", localtime(&pi->start_time));
1614 StrNCpy(processes[child].database, "", POOLCONFIG_MAXIDENTLEN);
1615 StrNCpy(processes[child].username, "", POOLCONFIG_MAXIDENTLEN);
1616 StrNCpy(processes[child].create_time, "", POOLCONFIG_MAXDATELEN);
1617 StrNCpy(processes[child].pool_counter, "", POOLCONFIG_MAXCOUNTLEN);
1618
1619 for (pool = 0; pool < pool_config->max_pool; pool++)
1620 {
1621 poolBE = pool * MAX_NUM_BACKENDS;
1622 if (pi->connection_info[poolBE].connected && strlen(pi->connection_info[poolBE].database) > 0 && strlen(pi->connection_info[poolBE].user) > 0)
1623 {
1624 StrNCpy(processes[child].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN);
1625 StrNCpy(processes[child].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN);
1626 strftime(processes[child].create_time, POOLCONFIG_MAXDATELEN, "%Y-%m-%d %H:%M:%S", localtime(&pi->connection_info[poolBE].create_time));
1627 snprintf(processes[child].pool_counter, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].counter);
1628 }
1629 }
1630 }
1631
1632 *nrows = child;
1633
1634 return processes;
1635 }
1636
1637 void
processes_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1638 processes_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1639 {
1640 static short num_fields = 6;
1641 static char *field_names[] = {"pool_pid", "start_time", "database", "username", "create_time", "pool_counter"};
1642 short s;
1643 int len;
1644 int nrows;
1645 int size;
1646 int hsize;
1647 int i;
1648 static unsigned char nullmap[2] = {0xff, 0xff};
1649 int nbytes = (num_fields + 7) / 8;
1650
1651 POOL_REPORT_PROCESSES *processes = get_processes(&nrows);
1652
1653 send_row_description(frontend, backend, num_fields, field_names);
1654
1655 if (MAJOR(backend) == PROTO_MAJOR_V2)
1656 {
1657 /* ascii row */
1658 for (i = 0; i < nrows; i++)
1659 {
1660 pool_write(frontend, "D", 1);
1661 pool_write_and_flush(frontend, nullmap, nbytes);
1662
1663 size = strlen(processes[i].pool_pid);
1664 hsize = htonl(size + 4);
1665 pool_write(frontend, &hsize, sizeof(hsize));
1666 pool_write(frontend, processes[i].pool_pid, size);
1667
1668 size = strlen(processes[i].start_time);
1669 hsize = htonl(size + 4);
1670 pool_write(frontend, &hsize, sizeof(hsize));
1671 pool_write(frontend, processes[i].start_time, size);
1672
1673 size = strlen(processes[i].database);
1674 hsize = htonl(size + 4);
1675 pool_write(frontend, &hsize, sizeof(hsize));
1676 pool_write(frontend, processes[i].database, size);
1677
1678 size = strlen(processes[i].username);
1679 hsize = htonl(size + 4);
1680 pool_write(frontend, &hsize, sizeof(hsize));
1681 pool_write(frontend, processes[i].username, size);
1682
1683 size = strlen(processes[i].create_time);
1684 hsize = htonl(size + 4);
1685 pool_write(frontend, &hsize, sizeof(hsize));
1686 pool_write(frontend, processes[i].create_time, size);
1687
1688 size = strlen(processes[i].pool_counter);
1689 hsize = htonl(size + 4);
1690 pool_write(frontend, &hsize, sizeof(hsize));
1691 pool_write(frontend, processes[i].pool_counter, size);
1692 }
1693 }
1694 else
1695 {
1696 /* data row */
1697 for (i = 0; i < nrows; i++)
1698 {
1699 pool_write(frontend, "D", 1);
1700 len = 6; /* int32 + int16; */
1701 len += 4 + strlen(processes[i].pool_pid); /* int32 + data */
1702 len += 4 + strlen(processes[i].start_time); /* int32 + data */
1703 len += 4 + strlen(processes[i].database); /* int32 + data */
1704 len += 4 + strlen(processes[i].username); /* int32 + data */
1705 len += 4 + strlen(processes[i].create_time); /* int32 + data */
1706 len += 4 + strlen(processes[i].pool_counter); /* int32 + data */
1707 len = htonl(len);
1708 pool_write(frontend, &len, sizeof(len));
1709 s = htons(num_fields);
1710 pool_write(frontend, &s, sizeof(s));
1711
1712 len = htonl(strlen(processes[i].pool_pid));
1713 pool_write(frontend, &len, sizeof(len));
1714 pool_write(frontend, processes[i].pool_pid, strlen(processes[i].pool_pid));
1715
1716 len = htonl(strlen(processes[i].start_time));
1717 pool_write(frontend, &len, sizeof(len));
1718 pool_write(frontend, processes[i].start_time, strlen(processes[i].start_time));
1719
1720 len = htonl(strlen(processes[i].database));
1721 pool_write(frontend, &len, sizeof(len));
1722 pool_write(frontend, processes[i].database, strlen(processes[i].database));
1723
1724 len = htonl(strlen(processes[i].username));
1725 pool_write(frontend, &len, sizeof(len));
1726 pool_write(frontend, processes[i].username, strlen(processes[i].username));
1727
1728 len = htonl(strlen(processes[i].create_time));
1729 pool_write(frontend, &len, sizeof(len));
1730 pool_write(frontend, processes[i].create_time, strlen(processes[i].create_time));
1731
1732 len = htonl(strlen(processes[i].pool_counter));
1733 pool_write(frontend, &len, sizeof(len));
1734 pool_write(frontend, processes[i].pool_counter, strlen(processes[i].pool_counter));
1735 }
1736 }
1737
1738 send_complete_and_ready(frontend, backend, "SELECT", nrows);
1739
1740 pfree(processes);
1741 }
1742
1743 POOL_REPORT_VERSION *
get_version(void)1744 get_version(void)
1745 {
1746 POOL_REPORT_VERSION *version = palloc(sizeof(POOL_REPORT_VERSION));
1747
1748 snprintf(version[0].version, POOLCONFIG_MAXVALLEN, "%s (%s)", VERSION, PGPOOLVERSION);
1749
1750 return version;
1751 }
1752
1753 void
version_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1754 version_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1755 {
1756 static short num_fields = 1;
1757 static char *field_names[] = {"pool_version"};
1758 short s;
1759 int len;
1760 int size;
1761 int hsize;
1762
1763 static unsigned char nullmap[2] = {0xff, 0xff};
1764 int nbytes = (num_fields + 7) / 8;
1765
1766 POOL_REPORT_VERSION *version = get_version();
1767
1768 send_row_description(frontend, backend, num_fields, field_names);
1769
1770 if (MAJOR(backend) == PROTO_MAJOR_V2)
1771 {
1772 /* ascii row */
1773 pool_write(frontend, "D", 1);
1774 pool_write_and_flush(frontend, nullmap, nbytes);
1775
1776 size = strlen(version[0].version);
1777 hsize = htonl(size + 4);
1778 pool_write(frontend, &hsize, sizeof(hsize));
1779 pool_write(frontend, version[0].version, size);
1780 }
1781 else
1782 {
1783 /* data row */
1784 pool_write(frontend, "D", 1);
1785 len = 6; /* int32 + int16; */
1786 len += 4 + strlen(version[0].version); /* int32 + data */
1787 len = htonl(len);
1788 pool_write(frontend, &len, sizeof(len));
1789 s = htons(num_fields);
1790 pool_write(frontend, &s, sizeof(s));
1791
1792 len = htonl(strlen(version[0].version));
1793 pool_write(frontend, &len, sizeof(len));
1794 pool_write(frontend, version[0].version, strlen(version[0].version));
1795 }
1796
1797 send_complete_and_ready(frontend, backend, "SELECT", 1);
1798
1799 pfree(version);
1800 }
1801
1802 /*
1803 * Show in memory cache reporting
1804 */
1805 void
cache_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1806 cache_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1807 {
1808 static char *field_names[] = {"num_cache_hits", "num_selects", "cache_hit_ratio", "num_hash_entries", "used_hash_entries", "num_cache_entries", "used_cache_entries_size", "free_cache_entries_size", "fragment_cache_entries_size"};
1809 short num_fields = sizeof(field_names) / sizeof(char *);
1810 int i;
1811 short s;
1812 int len;
1813 int size;
1814 int hsize;
1815 static unsigned char nullmap[2] = {0xff, 0xff};
1816 int nbytes = (num_fields + 7) / 8;
1817 volatile POOL_SHMEM_STATS *mystats;
1818 pool_sigset_t oldmask;
1819 double ratio;
1820
1821 #define POOL_CACHE_STATS_MAX_STRING_LEN 32
1822 typedef struct
1823 {
1824 int len; /* length of string excluding null terminate */
1825 char string[POOL_CACHE_STATS_MAX_STRING_LEN + 1];
1826 } MY_STRING_CACHE_STATS;
1827
1828 MY_STRING_CACHE_STATS *strp;
1829
1830 strp = palloc(num_fields * sizeof(MY_STRING_CACHE_STATS));
1831
1832 /*
1833 * Get raw cache stat data
1834 */
1835 POOL_SETMASK2(&BlockSig, &oldmask);
1836 pool_shmem_lock();
1837
1838 PG_TRY();
1839 {
1840 mystats = pool_get_shmem_storage_stats();
1841 }
1842 PG_CATCH();
1843 {
1844 pool_shmem_unlock();
1845 POOL_SETMASK(&oldmask);
1846 PG_RE_THROW();
1847 }
1848 PG_END_TRY();
1849 pool_shmem_unlock();
1850 POOL_SETMASK(&oldmask);
1851
1852 /*
1853 * Convert to string
1854 */
1855 i = 0;
1856 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%lld", mystats->cache_stats.num_cache_hits);
1857 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%lld", mystats->cache_stats.num_selects);
1858 if ((mystats->cache_stats.num_cache_hits + mystats->cache_stats.num_selects) == 0)
1859 {
1860 ratio = 0.0;
1861 }
1862 else
1863 {
1864 ratio = (double) mystats->cache_stats.num_cache_hits / (mystats->cache_stats.num_selects + mystats->cache_stats.num_cache_hits);
1865 }
1866 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%.2f", ratio);
1867 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%d", mystats->num_hash_entries);
1868 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%d", mystats->used_hash_entries);
1869 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%d", mystats->num_cache_entries);
1870 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%ld", mystats->used_cache_entries_size);
1871 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%ld", mystats->free_cache_entries_size);
1872 snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%ld", mystats->fragment_cache_entries_size);
1873
1874 /*
1875 * Calculate total data length
1876 */
1877 len = 2; /* number of fields (int16) */
1878 for (i = 0; i < num_fields; i++)
1879 {
1880 strp[i].len = strlen(strp[i].string);
1881 len += 4 /* length of string (int32) */
1882 + strp[i].len;
1883 }
1884
1885 /* Send row description */
1886 send_row_description(frontend, backend, num_fields, field_names);
1887
1888 /* Send each field */
1889 if (MAJOR(backend) == PROTO_MAJOR_V2)
1890 {
1891 pool_write(frontend, "D", 1);
1892 pool_write(frontend, nullmap, nbytes);
1893
1894 for (i = 0; i < num_fields; i++)
1895 {
1896 size = strp[i].len + 1;
1897 hsize = htonl(size + 4);
1898 pool_write(frontend, &hsize, sizeof(hsize));
1899 pool_write(frontend, strp[i].string, size);
1900 }
1901 }
1902 else
1903 {
1904 /* Kind */
1905 pool_write(frontend, "D", 1);
1906 /* Packet length */
1907 len = htonl(len + sizeof(int32));
1908 pool_write(frontend, &len, sizeof(len));
1909 /* Number of fields */
1910 s = htons(num_fields);
1911 pool_write(frontend, &s, sizeof(s));
1912
1913 for (i = 0; i < num_fields; i++)
1914 {
1915 hsize = htonl(strp[i].len);
1916 pool_write(frontend, &hsize, sizeof(hsize));
1917 pool_write(frontend, strp[i].string, strp[i].len);
1918 }
1919 }
1920
1921 send_complete_and_ready(frontend, backend, "SELECT", 1);
1922
1923 pfree(strp);
1924 }
1925