pgpool2.git / summary / log / commit / refs

commit    fa0513ea2ea5f99bbd3d78f1cd2dfbf571d137d5
Author:   Guillaume Lelarge <guillaume at lelarge.info>
Date:     Tue Aug 10 13:21:51 2010 +0000

    Add support for more "SHOW" commands: pool_nodes, pool_processes, pool_nodes,
    and pool_version.


doc/pgpool-en.html | 132 ++++++- pool_process_query.c | 42 ++- pool_process_reporting.c | 879 ++++++++++++++++++++++++++++++++++++++++++++++- pool_proto_modules.c | 41 ++- pool_proto_modules.h | 6 +- 5 files changed, 1076 insertions(+), 24 deletions(-) diff --git a/doc/pgpool-en.html b/doc/pgpool-en.html index a53c7d7b9..ae5e625d6 100644 --- a/doc/pgpool-en.html +++ b/doc/pgpool-en.html @@ -33,6 +33,7 @@ Last modified: Tue Aug 10 12:00:20 JST 2010 <li><a href="#master_slave_mode">Master slave mode</a></li> <li><a href="#start">Starting/Stopping pgpool-II</a></li> <li><a href="#reload">Reloading pgpool-II configuration files</a></li> + <li><a href="#show-commands">SHOW commands</a></li> <li><a href="#online-recovery">Online recovery</a></li> <li><a href="#restriction">Restrictions</a></li> <li><a href="#reference">References</a></li> @@ -1627,6 +1628,135 @@ Please note that some configuration items are not changed with relaoding. Also configuration reflects its changes after new session starts. </p> +<h1><a name="show-commands"></a>SHOW commands</h1> +<h2>Overview</h2> +<p> +pgpool-II offers to grab informations via SHOW commands. SHOW is a real SQL +statement, but pgPool-II intercepts this command if it asks for specific +pgPool-II informations. Those are: +<ul> + <li>pool_status, to get the configuration</li> + <li>pool_nodes, to get the nodes informations</li> + <li>pool_processes, to get informations on pgPool-II processes</li> + <li>pool_pools, to get informations on pgPool-II pools</li> + <li>pool_version, to get the pgPool_II release</li> +</ul> +</p> +<p>"pool_status" SQL statement was already available in previous releases, +but the other ones appear in release 3.0.</p> +<h2>pool_status</h2> +<p>"SHOW pool_status" sends back a list of configuration parameters with +their name, value, and description. Here is an excerpt of the result: +<pre> +benchs2=# show pool_status; + item | value | description +-------------------------------+---------------------------------+------------------------------------------------------------------ + listen_addresses | 127.0.0.1 | host name(s) or IP address(es) to listen to + port | 9999 | pgpool accepting port number + socket_dir | /tmp | pgpool socket directory + num_init_children | 5 | # of children initially pre-forked + child_life_time | 300 | if idle for this seconds, child exits +</pre> +</p> +<h2>pool_nodes</h2> +<p>"SHOW pool_nodes" sends back a list of all configured nodes. It +displays the hostname, the port, the status, and the weight (only meaningful +if you use the load balancing mode). The possible values in the status column +are explained in the <a href="#pcp_node_info">pcp_node_info reference</a>. +<pre> +benchs2=# show pool_nodes; + hostname | port | status | lb_weight +-------------+------+--------+------------------- + 127.0.0.1 | 5432 | 2 | 1073741823.500000 + 192.168.1.7 | 5432 | 3 | 1073741823.500000 +(2 lignes) +</pre> +</p> +<h2>pool_processes</h2> +<p>"SHOW pool_processes" sends back a list of all pgPool-II processes waiting +for connections and dealing with a connection. +</p> +<p> +It has 6 columns: +<ul> +<li>pool_pid is the PID of the pgPool-II process</li> +<li>start_time is the time and date when this process was launched (in a number of seconds since 1970-01-01)</li> +<li>database is the database name for the currently active pool for this process</li> +<li>username is the user name used in the connection for the currently active pool for this process</li> +<li>create_time is the creation time and date of the connection</li> +<li>pool_counter counts the number of times this connection is used</li> +</ul> +</p> +<p>It'll always return num_init_children lines.</p> +<pre> +benchs2=# show pool_processes; + pool_pid | start_time | database | username | create_time | pool_counter +----------+------------+-----------+-----------+-------------+-------------- + 4318 | 1281433036 | | | | + 4319 | 1281433036 | | | | + 4320 | 1281433036 | benchs2 | guillaume | 1281433038 | 1 + 4321 | 1281433036 | | | | + 4322 | 1281433036 | | | | +(5 lines) +</pre> +<h2>pool_pools</h2> +<p>"SHOW pool_pools" sends back a list of pools handled by pgPool-II. +their name, value, and description. Here is an excerpt of the result: +</p> +<p> +It has 6 columns: +<ul> +<li>pool_pid is the PID of the pgPool-II process</li> +<li>start_time is the time and date when this process was launched (in a number of seconds since 1970-01-01)</li> +<li>pool_id is the pool identifier (should be between 0 and max_pool-1)</li> +<li>database is the database name for the pool id of this process</li> +<li>username is the user name used in the connection for the pool id of this process</li> +<li>create_time is the creation time and date of the connection</li> +<li>majorversion and minorversion are the version of the protocol used in this connection</li> +<li>pool_counter counts the number of times this connection is used</li> +<li>pool_backendpid is the PID of the PostgreSQL process</li> +<li>pool_connected is a boolean value that shows the currenlty active pool of a process (0 is inactive, 1 is active)</li> +</ul> +</p> +<p>It'll always return num_init_children*max_pool lines.</p> +<pre> +benchs2=# show pool_pools; + pool_pid | start_time | pool_id | database | username | create_time | majorversion | minorversion | pool_counter | pool_backendpid | pool_connected +----------+------------+---------+----------+-----------+-------------+--------------+--------------+--------------+-----------------+---------------- + 4318 | 1281433036 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4318 | 1281433036 | 1 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4318 | 1281433036 | 2 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4318 | 1281433036 | 3 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4319 | 1281433036 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4319 | 1281433036 | 1 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4319 | 1281433036 | 2 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4319 | 1281433036 | 3 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4320 | 1281433036 | 0 | benchs2 | guillaume | 1281433038 | 3 | 0 | 1 | 4327 | 1 + 4320 | 1281433036 | 1 | | | 0 | 0 | 0 | 0 | 0 | 1 + 4320 | 1281433036 | 2 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4320 | 1281433036 | 3 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4321 | 1281433036 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4321 | 1281433036 | 1 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4321 | 1281433036 | 2 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4321 | 1281433036 | 3 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4322 | 1281433036 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4322 | 1281433036 | 1 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4322 | 1281433036 | 2 | | | 0 | 0 | 0 | 0 | 0 | 0 + 4322 | 1281433036 | 3 | | | 0 | 0 | 0 | 0 | 0 | 0 +(20 lines) +</pre> +</p> +<h2>pool_version</h2> +<p>"SHOW pool_version" displays a string containing the pgPool-II release +number. Here is an example of it: +<pre> +benchs2=# show pool_version; + pool_version +------------------------ + 3.0-dev (umiyameboshi) +(1 line) +</pre> +</p> <h1><a name="online-recovery"></a>Online Recovery</h1> <h2>Overview</h2> <p> @@ -2307,7 +2437,7 @@ not distinguish nodes status, ie attached/detached. ALL nodes are counted. </p> -<h3>pcp_node_info</h3> +<h3><a name="pcp_node_info"/>pcp_node_info</h3> <pre> Format: diff --git a/pool_process_query.c b/pool_process_query.c index 163017391..1b9c228a2 100644 --- a/pool_process_query.c +++ b/pool_process_query.c @@ -459,7 +459,11 @@ POOL_STATUS pool_parallel_exec(POOL_CONNECTION *frontend, fd_set writemask; fd_set exceptmask; unsigned long donemask[FD_SETSIZE / BITS]; - static char *sq = "show pool_status"; + static char *sq_config = "show pool_status"; + static char *sq_pools = "show pool_pools"; + static char *sq_processes = "show pool_processes"; + static char *sq_nodes = "show pool_nodes"; + static char *sq_version = "show pool_version"; POOL_STATUS status; struct timeval timeout; int num_fds; @@ -486,14 +490,46 @@ POOL_STATUS pool_parallel_exec(POOL_CONNECTION *frontend, } /* process status reporting? */ - if (strncasecmp(sq, string, strlen(sq)) == 0) + if (strncasecmp(sq_config, string, strlen(sq_config)) == 0) + { + pool_debug("config reporting"); + config_reporting(frontend, backend); + pool_unset_query_in_progress(); + return POOL_CONTINUE; + } + + if (strncasecmp(sq_pools, string, strlen(sq_pools)) == 0) + { + pool_debug("pools reporting"); + pools_reporting(frontend, backend); + pool_unset_query_in_progress(); + return POOL_CONTINUE; + } + + if (strncasecmp(sq_processes, string, strlen(sq_processes)) == 0) { pool_debug("process reporting"); - process_reporting(frontend, backend); + processes_reporting(frontend, backend); pool_unset_query_in_progress(); return POOL_CONTINUE; } + if (strncasecmp(sq_nodes, string, strlen(sq_nodes)) == 0) + { + pool_debug("nodes reporting"); + nodes_reporting(frontend, backend); + pool_unset_query_in_progress(); + return POOL_CONTINUE; + } + + if (strncasecmp(sq_version, string, strlen(sq_version)) == 0) + { + pool_debug("version reporting"); + version_reporting(frontend, backend); + pool_unset_query_in_progress(); + return POOL_CONTINUE; + } + /* In this loop,forward the query to the all backends */ for (i=0;i<NUM_BACKENDS;i++) { diff --git a/pool_process_reporting.c b/pool_process_reporting.c index d34a6cc96..5fd158997 100644 --- a/pool_process_reporting.c +++ b/pool_process_reporting.c @@ -18,17 +18,74 @@ * suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * - * Process "show pool_status" query. + * Process pgPool-II "SHOW" queries. */ #include "pool.h" #include "pool_proto_modules.h" #include "pool_stream.h" #include "pool_config.h" +#include "version.h" #include <string.h> #include <netinet/in.h> -void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) +/* some length definitions */ +#define POOLCONFIG_MAXNAMELEN 32 +#define POOLCONFIG_MAXVALLEN 512 +#define POOLCONFIG_MAXDESCLEN 64 +#define POOLCONFIG_MAXIDENTLEN 63 +#define POOLCONFIG_MAXPORTLEN 6 +#define POOLCONFIG_MAXSTATLEN 2 +#define POOLCONFIG_MAXWEIGHTLEN 20 +#define POOLCONFIG_MAXDATELEN 20 +#define POOLCONFIG_MAXCOUNTLEN 16 + +/* config report struct*/ +typedef struct { + char name[POOLCONFIG_MAXNAMELEN+1]; + char value[POOLCONFIG_MAXVALLEN+1]; + char desc[POOLCONFIG_MAXDESCLEN+1]; +} POOL_REPORT_STATUS; + +/* nodes report struct */ +typedef struct { + char hostname[POOLCONFIG_MAXIDENTLEN+1]; + char port[POOLCONFIG_MAXIDENTLEN+1]; + char status[POOLCONFIG_MAXSTATLEN+1]; + char lb_weight[POOLCONFIG_MAXWEIGHTLEN+1]; +} POOL_REPORT_NODES; + +/* processes report struct */ +typedef struct { + char pool_pid[POOLCONFIG_MAXCOUNTLEN+1]; + char start_time[POOLCONFIG_MAXDATELEN+1]; + char database[POOLCONFIG_MAXIDENTLEN+1]; + char username[POOLCONFIG_MAXIDENTLEN+1]; + char create_time[POOLCONFIG_MAXDATELEN+1]; + char pool_counter[POOLCONFIG_MAXCOUNTLEN+1]; +} POOL_REPORT_PROCESSES; + +/* pools reporting struct */ +typedef struct { + char pool_pid[POOLCONFIG_MAXCOUNTLEN+1]; + char start_time[POOLCONFIG_MAXDATELEN+1]; + char pool_id[POOLCONFIG_MAXCOUNTLEN+1]; + char database[POOLCONFIG_MAXIDENTLEN+1]; + char username[POOLCONFIG_MAXIDENTLEN+1]; + char create_time[POOLCONFIG_MAXDATELEN+1]; + char pool_majorversion[POOLCONFIG_MAXCOUNTLEN+1]; + char pool_minorversion[POOLCONFIG_MAXCOUNTLEN+1]; + char pool_counter[POOLCONFIG_MAXCOUNTLEN+1]; + char pool_backendpid[POOLCONFIG_MAXCOUNTLEN+1]; + char pool_connected[POOLCONFIG_MAXCOUNTLEN+1]; +} POOL_REPORT_POOLS; + +/* version struct */ +typedef struct { + char version[POOLCONFIG_MAXVALLEN+1]; +} POOL_REPORT_VERSION; + +void config_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) { static char *cursorname = "blank"; static short num_fields = 3; @@ -45,16 +102,6 @@ void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) static unsigned char nullmap[2] = {0xff, 0xff}; int nbytes = (num_fields + 7)/8; -#define POOLCONFIG_MAXNAMELEN 32 -#define POOLCONFIG_MAXVALLEN 512 -#define POOLCONFIG_MAXDESCLEN 64 - - typedef struct { - char name[POOLCONFIG_MAXNAMELEN+1]; - char value[POOLCONFIG_MAXVALLEN+1]; - char desc[POOLCONFIG_MAXDESCLEN+1]; - } POOL_REPORT_STATUS; - /* * Report data buffer. * 128 is the max number of configuration items. @@ -63,7 +110,7 @@ void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) */ #define MAXITEMS (128 + MAX_NUM_BACKENDS*4) - static POOL_REPORT_STATUS status[MAXITEMS]; + POOL_REPORT_STATUS status[MAXITEMS]; short nrows; int size; @@ -522,7 +569,7 @@ void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) len += sizeof(int) + strlen(status[i].desc); len = htonl(len); pool_write(frontend, &len, sizeof(len)); - s = htons(3); + s = htons(num_fields); pool_write(frontend, &s, sizeof(s)); len = htonl(strlen(status[i].name)); @@ -559,3 +606,807 @@ void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) pool_flush(frontend); } + +void nodes_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) +{ + static char *cursorname = "blank"; + static short num_fields = 4; + static char *field_names[] = {"hostname", "port", "status", "lb_weight"}; + static int oid = 0; + static short fsize = -1; + static int mod = 0; + short n; + int i; + short s; + int len; + short colnum; + short nrows; + int size; + int hsize; + + static unsigned char nullmap[2] = {0xff, 0xff}; + int nbytes = (num_fields + 7)/8; + + POOL_REPORT_NODES nodes[NUM_BACKENDS]; + + BackendInfo *bi = NULL; + + for (i = 0; i < NUM_BACKENDS; i++) + { + bi = pool_get_node_info(i); + + strncpy(nodes[i].hostname, bi->backend_hostname, strlen(bi->backend_hostname)+1); + snprintf(nodes[i].port, POOLCONFIG_MAXIDENTLEN, "%d", bi->backend_port); + snprintf(nodes[i].status, POOLCONFIG_MAXSTATLEN, "%d", bi->backend_status); + snprintf(nodes[i].lb_weight, POOLCONFIG_MAXWEIGHTLEN, "%f", bi->backend_weight); + } + + nrows = i; + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* cursor response */ + pool_write(frontend, "P", 1); + pool_write(frontend, cursorname, strlen(cursorname)+1); + } + + /* row description */ + pool_write(frontend, "T", 1); + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = sizeof(num_fields) + sizeof(len); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + len += strlen(f)+1; + len += sizeof(oid); + len += sizeof(colnum); + len += sizeof(oid); + len += sizeof(s); + len += sizeof(mod); + len += sizeof(s); + } + + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + } + + n = htons(num_fields); + pool_write(frontend, &n, sizeof(short)); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + + pool_write(frontend, f, strlen(f)+1); /* field name */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + pool_write(frontend, &oid, sizeof(oid)); /* table oid */ + colnum = htons(i); + pool_write(frontend, &colnum, sizeof(colnum)); /* column number */ + } + + pool_write(frontend, &oid, sizeof(oid)); /* data type oid */ + s = htons(fsize); + pool_write(frontend, &s, sizeof(fsize)); /* field size */ + pool_write(frontend, &mod, sizeof(mod)); /* modifier */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + s = htons(0); + pool_write(frontend, &s, sizeof(fsize)); /* field format (text) */ + } + } + pool_flush(frontend); + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* ascii row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + pool_write_and_flush(frontend, nullmap, nbytes); + + size = strlen(nodes[i].hostname); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, nodes[i].hostname, size); + + size = strlen(nodes[i].port); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, nodes[i].port, size); + + size = strlen(nodes[i].status); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, nodes[i].status, size); + + size = strlen(nodes[i].lb_weight); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, nodes[i].lb_weight, size); + } + } + else + { + /* data row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + len = sizeof(len) + sizeof(nrows); + len += sizeof(int) + strlen(nodes[i].hostname); + len += sizeof(int) + strlen(nodes[i].port); + len += sizeof(int) + strlen(nodes[i].status); + len += sizeof(int) + strlen(nodes[i].lb_weight); + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + s = htons(num_fields); + pool_write(frontend, &s, sizeof(s)); + + len = htonl(strlen(nodes[i].hostname)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, nodes[i].hostname, strlen(nodes[i].hostname)); + + len = htonl(strlen(nodes[i].port)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, nodes[i].port, strlen(nodes[i].port)); + + len = htonl(strlen(nodes[i].status)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, nodes[i].status, strlen(nodes[i].status)); + + len = htonl(strlen(nodes[i].lb_weight)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, nodes[i].lb_weight, strlen(nodes[i].lb_weight)); + } + } + + /* complete command response */ + pool_write(frontend, "C", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + strlen("SELECT")+1); + pool_write(frontend, &len, sizeof(len)); + } + pool_write(frontend, "SELECT", strlen("SELECT")+1); + + /* ready for query */ + pool_write(frontend, "Z", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + 1); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, "I", 1); + } + + pool_flush(frontend); +} + +void pools_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) +{ + static char *cursorname = "blank"; + static short num_fields = 11; + static char *field_names[] = {"pool_pid", "start_time", "pool_id", "database", "username", "create_time", + "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"}; + static int oid = 0; + static short fsize = -1; + static int mod = 0; + short n; + int child, pool, poolBE; + short s; + int len; + short colnum; + int i; + + static unsigned char nullmap[2] = {0xff, 0xff}; + int nbytes = (num_fields + 7)/8; + + POOL_REPORT_POOLS pools[MAX_NUM_BACKENDS * pool_config->max_pool]; + + short nrows; + int size; + int hsize; + + ProcessInfo *pi = NULL; + int proc_id; + + int lines = 0; + for (child = 0; child < pool_config->num_init_children; child++) + { + proc_id = process_info[child].pid; + pi = pool_get_process_info(proc_id); + + for (pool = 0; pool < pool_config->max_pool; pool++) + { + poolBE = pool*MAX_NUM_BACKENDS; + snprintf(pools[lines].pool_pid, POOLCONFIG_MAXCOUNTLEN, "%d", proc_id); + snprintf(pools[lines].start_time, POOLCONFIG_MAXDATELEN, "%ld", pi->start_time); + snprintf(pools[lines].pool_id, POOLCONFIG_MAXCOUNTLEN, "%d", pool); + strncpy(pools[lines].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN); + strncpy(pools[lines].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN); + snprintf(pools[lines].create_time, POOLCONFIG_MAXDATELEN, "%ld", pi->connection_info[poolBE].create_time); + snprintf(pools[lines].pool_counter, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].counter); + snprintf(pools[lines].pool_majorversion, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].major); + snprintf(pools[lines].pool_minorversion, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].minor); + snprintf(pools[lines].pool_counter, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].counter); + snprintf(pools[lines].pool_backendpid, POOLCONFIG_MAXCOUNTLEN, "%d", ntohl(pi->connection_info[poolBE].pid)); + snprintf(pools[lines].pool_connected, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].connected); + lines++; + } + } + + nrows = lines; + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* cursor response */ + pool_write(frontend, "P", 1); + pool_write(frontend, cursorname, strlen(cursorname)+1); + } + + /* row description */ + pool_write(frontend, "T", 1); + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = sizeof(num_fields) + sizeof(len); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + len += strlen(f)+1; + len += sizeof(oid); + len += sizeof(colnum); + len += sizeof(oid); + len += sizeof(s); + len += sizeof(mod); + len += sizeof(s); + } + + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + } + + n = htons(num_fields); + pool_write(frontend, &n, sizeof(short)); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + + pool_write(frontend, f, strlen(f)+1); /* field name */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + pool_write(frontend, &oid, sizeof(oid)); /* table oid */ + colnum = htons(i); + pool_write(frontend, &colnum, sizeof(colnum)); /* column number */ + } + + pool_write(frontend, &oid, sizeof(oid)); /* data type oid */ + s = htons(fsize); + pool_write(frontend, &s, sizeof(fsize)); /* field size */ + pool_write(frontend, &mod, sizeof(mod)); /* modifier */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + s = htons(0); + pool_write(frontend, &s, sizeof(fsize)); /* field format (text) */ + } + } + pool_flush(frontend); + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* ascii row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + pool_write_and_flush(frontend, nullmap, nbytes); + + size = strlen(pools[i].pool_pid); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_pid, size); + + size = strlen(pools[i].start_time); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].start_time, size); + + size = strlen(pools[i].pool_id); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_id, size); + + size = strlen(pools[i].database); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].database, size); + + size = strlen(pools[i].username); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].username, size); + + size = strlen(pools[i].create_time); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].create_time, size); + + size = strlen(pools[i].pool_majorversion); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_majorversion, size); + + size = strlen(pools[i].pool_minorversion); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_minorversion, size); + + size = strlen(pools[i].pool_counter); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_counter, size); + + size = strlen(pools[i].pool_backendpid); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_backendpid, size); + + size = strlen(pools[i].pool_connected); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, pools[i].pool_connected, size); + } + } + else + { + /* data row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + len = sizeof(len) + sizeof(nrows); + len += sizeof(int) + strlen(pools[i].pool_pid); + len += sizeof(int) + strlen(pools[i].start_time); + len += sizeof(int) + strlen(pools[i].pool_id); + len += sizeof(int) + strlen(pools[i].database); + len += sizeof(int) + strlen(pools[i].username); + len += sizeof(int) + strlen(pools[i].create_time); + len += sizeof(int) + strlen(pools[i].pool_majorversion); + len += sizeof(int) + strlen(pools[i].pool_minorversion); + len += sizeof(int) + strlen(pools[i].pool_counter); + len += sizeof(int) + strlen(pools[i].pool_backendpid); + len += sizeof(int) + strlen(pools[i].pool_connected); + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + s = htons(num_fields); + pool_write(frontend, &s, sizeof(s)); + + len = htonl(strlen(pools[i].pool_pid)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_pid, strlen(pools[i].pool_pid)); + + len = htonl(strlen(pools[i].start_time)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].start_time, strlen(pools[i].start_time)); + + len = htonl(strlen(pools[i].pool_id)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_id, strlen(pools[i].pool_id)); + + len = htonl(strlen(pools[i].database)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].database, strlen(pools[i].database)); + + len = htonl(strlen(pools[i].username)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].username, strlen(pools[i].username)); + + len = htonl(strlen(pools[i].create_time)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].create_time, strlen(pools[i].create_time)); + + len = htonl(strlen(pools[i].pool_majorversion)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_majorversion, strlen(pools[i].pool_majorversion)); + + len = htonl(strlen(pools[i].pool_minorversion)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_minorversion, strlen(pools[i].pool_minorversion)); + + len = htonl(strlen(pools[i].pool_counter)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_counter, strlen(pools[i].pool_counter)); + + len = htonl(strlen(pools[i].pool_backendpid)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_backendpid, strlen(pools[i].pool_backendpid)); + + len = htonl(strlen(pools[i].pool_connected)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, pools[i].pool_connected, strlen(pools[i].pool_connected)); + } + } + + /* complete command response */ + pool_write(frontend, "C", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + strlen("SELECT")+1); + pool_write(frontend, &len, sizeof(len)); + } + pool_write(frontend, "SELECT", strlen("SELECT")+1); + + /* ready for query */ + pool_write(frontend, "Z", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + 1); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, "I", 1); + } + + pool_flush(frontend); +} + +void processes_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) +{ + static char *cursorname = "blank"; + static short num_fields = 6; + static char *field_names[] = {"pool_pid", "start_time", "database", "username", "create_time", "pool_counter"}; + static int oid = 0; + static short fsize = -1; + static int mod = 0; + short n; + int child; + int pool; + int poolBE; + short s; + int len; + short colnum; + POOL_REPORT_PROCESSES processes[pool_config->num_init_children]; + short nrows; + int size; + int hsize; + int i; + + static unsigned char nullmap[2] = {0xff, 0xff}; + int nbytes = (num_fields + 7)/8; + + ProcessInfo *pi = NULL; + int proc_id; + + for (child = 0; child < pool_config->num_init_children; child++) + { + proc_id = process_info[child].pid; + pi = pool_get_process_info(proc_id); + + snprintf(processes[child].pool_pid, POOLCONFIG_MAXCOUNTLEN, "%d", proc_id); + snprintf(processes[child].start_time, POOLCONFIG_MAXDATELEN, "%ld", pi->start_time); + strncpy(processes[child].database, "", POOLCONFIG_MAXIDENTLEN); + strncpy(processes[child].username, "", POOLCONFIG_MAXIDENTLEN); + strncpy(processes[child].create_time, "", POOLCONFIG_MAXDATELEN); + strncpy(processes[child].pool_counter, "", POOLCONFIG_MAXCOUNTLEN); + + for (pool = 0; pool < pool_config->max_pool; pool++) + { + poolBE = pool*MAX_NUM_BACKENDS; + if (pi->connection_info[poolBE].connected && strlen(pi->connection_info[poolBE].database) > 0 && strlen(pi->connection_info[poolBE].user) > 0) + { + strncpy(processes[child].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN); + strncpy(processes[child].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN); + snprintf(processes[child].create_time, POOLCONFIG_MAXDATELEN, "%ld", pi->connection_info[poolBE].create_time); + snprintf(processes[child].pool_counter, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].counter); + } + } + } + + nrows = child; + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* cursor response */ + pool_write(frontend, "P", 1); + pool_write(frontend, cursorname, strlen(cursorname)+1); + } + + /* row description */ + pool_write(frontend, "T", 1); + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = sizeof(num_fields) + sizeof(len); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + len += strlen(f)+1; + len += sizeof(oid); + len += sizeof(colnum); + len += sizeof(oid); + len += sizeof(s); + len += sizeof(mod); + len += sizeof(s); + } + + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + } + + n = htons(num_fields); + pool_write(frontend, &n, sizeof(short)); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + + pool_write(frontend, f, strlen(f)+1); /* field name */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + pool_write(frontend, &oid, sizeof(oid)); /* table oid */ + colnum = htons(i); + pool_write(frontend, &colnum, sizeof(colnum)); /* column number */ + } + + pool_write(frontend, &oid, sizeof(oid)); /* data type oid */ + s = htons(fsize); + pool_write(frontend, &s, sizeof(fsize)); /* field size */ + pool_write(frontend, &mod, sizeof(mod)); /* modifier */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + s = htons(0); + pool_write(frontend, &s, sizeof(fsize)); /* field format (text) */ + } + } + pool_flush(frontend); + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* ascii row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + pool_write_and_flush(frontend, nullmap, nbytes); + + size = strlen(processes[i].pool_pid); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, processes[i].pool_pid, size); + + size = strlen(processes[i].start_time); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, processes[i].start_time, size); + + size = strlen(processes[i].database); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, processes[i].database, size); + + size = strlen(processes[i].username); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, processes[i].username, size); + + size = strlen(processes[i].create_time); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, processes[i].create_time, size); + + size = strlen(processes[i].pool_counter); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, processes[i].pool_counter, size); + } + } + else + { + /* data row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + len = sizeof(len) + sizeof(nrows); + len += sizeof(int) + strlen(processes[i].pool_pid); + len += sizeof(int) + strlen(processes[i].start_time); + len += sizeof(int) + strlen(processes[i].database); + len += sizeof(int) + strlen(processes[i].username); + len += sizeof(int) + strlen(processes[i].create_time); + len += sizeof(int) + strlen(processes[i].pool_counter); + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + s = htons(num_fields); + pool_write(frontend, &s, sizeof(s)); + + len = htonl(strlen(processes[i].pool_pid)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, processes[i].pool_pid, strlen(processes[i].pool_pid)); + + len = htonl(strlen(processes[i].start_time)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, processes[i].start_time, strlen(processes[i].start_time)); + + len = htonl(strlen(processes[i].database)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, processes[i].database, strlen(processes[i].database)); + + len = htonl(strlen(processes[i].username)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, processes[i].username, strlen(processes[i].username)); + + len = htonl(strlen(processes[i].create_time)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, processes[i].create_time, strlen(processes[i].create_time)); + + len = htonl(strlen(processes[i].pool_counter)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, processes[i].pool_counter, strlen(processes[i].pool_counter)); + } + } + + /* complete command response */ + pool_write(frontend, "C", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + strlen("SELECT")+1); + pool_write(frontend, &len, sizeof(len)); + } + pool_write(frontend, "SELECT", strlen("SELECT")+1); + + /* ready for query */ + pool_write(frontend, "Z", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + 1); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, "I", 1); + } + + pool_flush(frontend); +} + +void version_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) +{ + static char *cursorname = "blank"; + static short num_fields = 1; + static char *field_names[] = {"pool_version"}; + static int oid = 0; + static short fsize = -1; + static int mod = 0; + short n; + int i; + short s; + int len; + short colnum; + short nrows; + int size; + int hsize; + + static unsigned char nullmap[2] = {0xff, 0xff}; + int nbytes = (num_fields + 7)/8; + + POOL_REPORT_VERSION version[1]; + + snprintf(version[0].version, POOLCONFIG_MAXVALLEN, "%s (%s)", VERSION, PGPOOLVERSION); + + nrows = 1; + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* cursor response */ + pool_write(frontend, "P", 1); + pool_write(frontend, cursorname, strlen(cursorname)+1); + } + + /* row description */ + pool_write(frontend, "T", 1); + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = sizeof(num_fields) + sizeof(len); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + len += strlen(f)+1; + len += sizeof(oid); + len += sizeof(colnum); + len += sizeof(oid); + len += sizeof(s); + len += sizeof(mod); + len += sizeof(s); + } + + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + } + + n = htons(num_fields); + pool_write(frontend, &n, sizeof(short)); + + for (i=0;i<num_fields;i++) + { + char *f = field_names[i]; + + pool_write(frontend, f, strlen(f)+1); /* field name */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + pool_write(frontend, &oid, sizeof(oid)); /* table oid */ + colnum = htons(i); + pool_write(frontend, &colnum, sizeof(colnum)); /* column number */ + } + + pool_write(frontend, &oid, sizeof(oid)); /* data type oid */ + s = htons(fsize); + pool_write(frontend, &s, sizeof(fsize)); /* field size */ + pool_write(frontend, &mod, sizeof(mod)); /* modifier */ + + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + s = htons(0); + pool_write(frontend, &s, sizeof(fsize)); /* field format (text) */ + } + } + pool_flush(frontend); + + if (MAJOR(backend) == PROTO_MAJOR_V2) + { + /* ascii row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + pool_write_and_flush(frontend, nullmap, nbytes); + + size = strlen(version[i].version); + hsize = htonl(size+4); + pool_write(frontend, &hsize, sizeof(hsize)); + pool_write(frontend, version[i].version, size); + } + } + else + { + /* data row */ + for (i=0;i<nrows;i++) + { + pool_write(frontend, "D", 1); + len = sizeof(len) + sizeof(nrows); + len += sizeof(int) + strlen(version[i].version); + len = htonl(len); + pool_write(frontend, &len, sizeof(len)); + s = htons(num_fields); + pool_write(frontend, &s, sizeof(s)); + + len = htonl(strlen(version[i].version)); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, version[i].version, strlen(version[i].version)); + } + } + + /* complete command response */ + pool_write(frontend, "C", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + strlen("SELECT")+1); + pool_write(frontend, &len, sizeof(len)); + } + pool_write(frontend, "SELECT", strlen("SELECT")+1); + + /* ready for query */ + pool_write(frontend, "Z", 1); + if (MAJOR(backend) == PROTO_MAJOR_V3) + { + len = htonl(sizeof(len) + 1); + pool_write(frontend, &len, sizeof(len)); + pool_write(frontend, "I", 1); + } + + pool_flush(frontend); +} + diff --git a/pool_proto_modules.c b/pool_proto_modules.c index 97e4748e7..861207e12 100644 --- a/pool_proto_modules.c +++ b/pool_proto_modules.c @@ -104,7 +104,11 @@ static int* find_victim_nodes(int *ntuples, int nmembers, int master_node, int * POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int len, char *contents) { - static char *sq = "show pool_status"; + static char *sq_config = "show pool_status"; + static char *sq_pools = "show pool_pools"; + static char *sq_processes = "show pool_processes"; + static char *sq_nodes = "show pool_nodes"; + static char *sq_version = "show pool_version"; int commit; List *parse_tree_list; Node *node = NULL; @@ -233,14 +237,41 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, } } - /* process status reporting? */ - if (IsA(node, VariableShowStmt) && strncasecmp(sq, contents, strlen(sq)) == 0) + /* status reporting? */ + if ((IsA(node, VariableShowStmt) && strncasecmp(sq_config, contents, strlen(sq_config)) == 0) + || (IsA(node, VariableShowStmt) && strncasecmp(sq_pools, contents, strlen(sq_pools)) == 0) + || (IsA(node, VariableShowStmt) && strncasecmp(sq_processes, contents, strlen(sq_processes)) == 0) + || (IsA(node, VariableShowStmt) && strncasecmp(sq_nodes, contents, strlen(sq_nodes)) == 0) + || (IsA(node, VariableShowStmt) && strncasecmp(sq_version, contents, strlen(sq_version)) == 0)) { StartupPacket *sp; char psbuf[1024]; - pool_debug("process reporting"); - process_reporting(frontend, backend); + if (strncasecmp(sq_config, contents, strlen(sq_config)) == 0) + { + pool_debug("config reporting"); + config_reporting(frontend, backend); + } + else if (strncasecmp(sq_pools, contents, strlen(sq_pools)) == 0) + { + pool_debug("pools reporting"); + pools_reporting(frontend, backend); + } + else if (strncasecmp(sq_processes, contents, strlen(sq_processes)) == 0) + { + pool_debug("processes reporting"); + processes_reporting(frontend, backend); + } + else if (strncasecmp(sq_nodes, contents, strlen(sq_nodes)) == 0) + { + pool_debug("nodes reporting"); + nodes_reporting(frontend, backend); + } + else if (strncasecmp(sq_version, contents, strlen(sq_version)) == 0) + { + pool_debug("version reporting"); + version_reporting(frontend, backend); + } /* show ps status */ sp = MASTER_CONNECTION(backend)->sp; diff --git a/pool_proto_modules.h b/pool_proto_modules.h index 4247629e0..b52237d9a 100644 --- a/pool_proto_modules.h +++ b/pool_proto_modules.h @@ -172,7 +172,11 @@ extern bool is_partition_table(POOL_CONNECTION_POOL *backend, Node *node); extern POOL_STATUS pool_discard_packet(POOL_CONNECTION_POOL *cp); extern int is_drop_database(Node *node); /* returns non 0 if this is a DROP DATABASE command */ -extern void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend); +extern void config_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend); +extern void pools_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend); +extern void processes_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend); +extern void nodes_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend); +extern void version_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend); extern POOL_STATUS send_simplequery_message(POOL_CONNECTION *backend, int len, char *string, int major); extern POOL_STATUS send_extended_protocol_message(POOL_CONNECTION_POOL *backend, [parent: a2b948819ac6]