/* pools reporting struct */
typedef struct
{
- int pool_pid;
- time_t start_time;
- int pool_id;
- int backend_id;
+ char pool_pid[POOLCONFIG_MAXCOUNTLEN + 1];
+ char start_time[POOLCONFIG_MAXDATELEN + 1];
+ char pool_id[POOLCONFIG_MAXCOUNTLEN + 1];
+ char backend_id[POOLCONFIG_MAXCOUNTLEN + 1];
char database[POOLCONFIG_MAXIDENTLEN + 1];
char username[POOLCONFIG_MAXIDENTLEN + 1];
- time_t create_time;
- int pool_majorversion;
- int pool_minorversion;
- int pool_counter;
- int pool_backendpid;
- int pool_connected;
+ 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 */
extern char *role_to_str(SERVER_ROLE role);
extern int * pool_health_check_stats_offsets(int *n);
+extern int * pool_report_pools_offsets(int *n);
/* ------------------------------
* pcp_error.c
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2020 PgPool Global Development Group
+ * Copyright (c) 2003-2021 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
extern void send_config_var_detail_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *name, const char *value, const char *description);
extern void send_config_var_value_only_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *value);
extern char *get_backend_status_string(BACKEND_STATUS status);
+
+extern int * pool_report_pools_offsets(int *n);
#endif
process_process_info_response(PCPConnInfo * pcpConn, char *buf, int len)
{
char *index;
- ProcessInfo *processInfo = NULL;
+ int *offsets;
+ int i, n;
+ int maxstr;
+ char *p;
+ POOL_REPORT_POOLS *pools = NULL;
+
+ offsets = pool_report_pools_offsets(&n);
if (strcmp(buf, "ArraySize") == 0)
{
if (PCPResultStatus(pcpConn->pcpResInfo) != PCP_RES_INCOMPLETE)
goto INVALID_RESPONSE;
- processInfo = palloc0(sizeof(ProcessInfo));
- processInfo->connection_info = palloc0(sizeof(ConnectionInfo));
-
- index = (char *) memchr(buf, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->pid = atoi(index);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- strlcpy(processInfo->connection_info->database, index, SM_DATABASE);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- strlcpy(processInfo->connection_info->user, index, SM_USER);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->start_time = atol(index);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->create_time = atol(index);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->major = atoi(index);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->minor = atoi(index);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->counter = atoi(index);
-
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->backend_id = atoi(index);
+ pools = palloc0(sizeof(POOL_REPORT_POOLS));
+ p = (char *)pools;
+ buf += strlen(buf) + 1;
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->pid = atoi(index);
+ for (i = 0; i < n; i++)
+ {
+ if (i == n -1)
+ maxstr = sizeof(POOL_REPORT_POOLS) - offsets[i];
+ else
+ maxstr = offsets[i + 1] - offsets[i];
- index = (char *) memchr(index, '\0', len);
- if (index == NULL)
- goto INVALID_RESPONSE;
- index += 1;
- processInfo->connection_info->connected = atoi(index);
+ StrNCpy(p + offsets[i], buf, maxstr -1);
+ buf += strlen(buf) + 1;
+ }
- if (setNextResultBinaryData(pcpConn->pcpResInfo, (void *) processInfo, sizeof(ProcessInfo), free_processInfo) < 0)
+ if (setNextResultBinaryData(pcpConn->pcpResInfo, (void *) pools, sizeof(POOL_REPORT_POOLS), NULL) < 0)
goto INVALID_RESPONSE;
return;
INVALID_RESPONSE:
- if (processInfo)
+ if (pools)
{
- if (processInfo->connection_info)
- pfree(processInfo->connection_info);
- pfree(processInfo);
+ pfree(pools);
}
pcp_internal_error(pcpConn,
"command failed. invalid response");
errdetail("%d process(es) found", process_count)));
}
+/*
+ * pcp_process_info
+ */
static void
inform_process_info(PCP_CONNECTION * frontend, char *buf)
{
int wsize;
int num_proc = pool_config->num_init_children;
int i;
+ int *offsets;
+ int n;
+ POOL_REPORT_POOLS *pools;
proc_id = atoi(buf);
/* Finally, indicate that all data is sent */
char fin_code[] = "CommandComplete";
- POOL_REPORT_POOLS *pools = get_pools(&num_proc);
+ pools = get_pools(&num_proc);
if (proc_id == 0)
{
pcp_write(frontend, con_info_size, strlen(con_info_size) + 1);
do_pcp_flush(frontend);
+ offsets = pool_report_pools_offsets(&n);
+
/* Second, send process information for all connection_info */
for (i = 0; i < num_proc; i++)
{
+ int j;
char code[] = "ProcessInfo";
- char proc_pid[16];
- char proc_start_time[20];
- char proc_create_time[20];
- char majorversion[5];
- char minorversion[5];
- char pool_counter[16];
- char backend_id[16];
- char backend_pid[16];
- char connected[2];
-
- if (proc_id != 0 && proc_id != pools[i].pool_pid)
- continue;
+ int pool_pid;
- snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
- snprintf(proc_start_time, sizeof(proc_start_time), "%ld", pools[i].start_time);
- snprintf(proc_create_time, sizeof(proc_create_time), "%ld", pools[i].create_time);
- snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
- snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
- snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
- snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
- snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
- snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);
+ pool_pid = atoi(pools[i].pool_pid);
+
+ if (proc_id != 0 && pool_pid != proc_id)
+ continue;
pcp_write(frontend, "p", 1);
- wsize = htonl(sizeof(code) +
- strlen(proc_pid) + 1 +
- strlen(pools[i].database) + 1 +
- strlen(pools[i].username) + 1 +
- strlen(proc_start_time) + 1 +
- strlen(proc_create_time) + 1 +
- strlen(majorversion) + 1 +
- strlen(minorversion) + 1 +
- strlen(pool_counter) + 1 +
- strlen(backend_id) + 1 +
- strlen(backend_pid) + 1 +
- strlen(connected) + 1 +
- sizeof(int));
+
+ wsize = 0;
+ for (j = 0; j < n; j++)
+ {
+ wsize += strlen((char *)&pools[i] + offsets[j]) + 1;
+ }
+ wsize += sizeof(code) + sizeof(int);
+ wsize = htonl(wsize);
+
+ /* send packet length to frontend */
pcp_write(frontend, &wsize, sizeof(int));
+ /* send "this is a record" to frontend */
pcp_write(frontend, code, sizeof(code));
- pcp_write(frontend, proc_pid, strlen(proc_pid) + 1);
- pcp_write(frontend, pools[i].database, strlen(pools[i].database) + 1);
- pcp_write(frontend, pools[i].username, strlen(pools[i].username) + 1);
- pcp_write(frontend, proc_start_time, strlen(proc_start_time) + 1);
- pcp_write(frontend, proc_create_time, strlen(proc_create_time) + 1);
- pcp_write(frontend, majorversion, strlen(majorversion) + 1);
- pcp_write(frontend, minorversion, strlen(minorversion) + 1);
- pcp_write(frontend, pool_counter, strlen(pool_counter) + 1);
- pcp_write(frontend, backend_id, strlen(backend_id) + 1);
- pcp_write(frontend, backend_pid, strlen(backend_pid) + 1);
- pcp_write(frontend, connected, strlen(connected) + 1);
+
+ /* send each process info data to frontend */
+ for (j = 0; j < n; j++)
+ {
+ pcp_write(frontend, (char *)&pools[i] + offsets[j], strlen((char *)&pools[i] + offsets[j]) + 1);
+ }
+
do_pcp_flush(frontend);
}
{
bool printed = false;
int i;
- char *frmt;
- char strcreatetime[128];
- char strstarttime[128];
+ char *format;
int array_size = pcp_result_slot_count(pcpResInfo);
+ const char *titles[] = {
+ "Database", "Username", "Start time", "Creation time",
+ "Major", "Minor", "Counter", "Backend PID",
+ "Connected", "PID", "Backend ID"
+ };
+ const char *types[] = {
+ "s", "s", "s", "s",
+ "s", "s", "s", "s",
+ "s", "s", "s"
+ };
+
+
if (verbose)
- {
- frmt = "Database : %s\n"
- "Username : %s\n"
- "Start time : %s\n"
- "Creation time: %s\n"
- "Major : %d\n"
- "Minor : %d\n"
- "Counter : %d\n"
- "Backend PID : %d\n"
- "Connected : %d\n"
- "PID : %d\n"
- "Backend ID : %d\n";
- }
+ format = format_titles(titles, types, sizeof(titles)/sizeof(char *));
else
{
- frmt = "%s %s %s %s %d %d %d %d %d %d %d\n";
+ format = "%s %s %s %s %s %s %s %s %s %s %s\n";
}
for (i = 0; i < array_size; i++)
{
- ProcessInfo *process_info = (ProcessInfo *) pcp_get_binary_data(pcpResInfo, i);
+ POOL_REPORT_POOLS *pools = (POOL_REPORT_POOLS *) pcp_get_binary_data(pcpResInfo, i);
- if (process_info == NULL)
+ if (pools == NULL)
break;
- if ((!all) && (process_info->connection_info->database[0] == '\0'))
+ if ((!all) && (pools->database[0] == '\0'))
continue;
printed = true;
- *strcreatetime = *strstarttime = '\0';
-
- if (process_info->start_time)
- strftime(strstarttime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->start_time));
- if (process_info->connection_info->create_time)
- strftime(strcreatetime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->connection_info->create_time));
-
- printf(frmt,
- process_info->connection_info->database,
- process_info->connection_info->user,
- strstarttime,
- strcreatetime,
- process_info->connection_info->major,
- process_info->connection_info->minor,
- process_info->connection_info->counter,
- process_info->connection_info->pid,
- process_info->connection_info->connected,
- process_info->pid,
- process_info->connection_info->backend_id);
+ printf(format,
+ pools->database,
+ pools->username,
+ pools->start_time,
+ pools->create_time,
+ pools->pool_majorversion,
+ pools->pool_minorversion,
+ pools->pool_counter,
+ pools->pool_backendpid,
+ pools->pool_connected,
+ pools->pool_pid,
+ pools->backend_id);
}
if (printed == false)
printf("No process information available\n\n");
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2020 PgPool Global Development Group
+ * Copyright (c) 2003-2021 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
*n = sizeof(offsettbl)/sizeof(int);
return offsettbl;
}
+
+/*
+ * Returns an array consisting of POOL_REPORT_POOLS struct member offsets.
+ * The reason why we have this as a function is the table data needs to be
+ * shared by both PCP server and clients. Number of struct members will be
+ * stored in *n.
+ */
+int * pool_report_pools_offsets(int *n)
+{
+
+ static int offsettbl[] = {
+ offsetof(POOL_REPORT_POOLS, pool_pid),
+ offsetof(POOL_REPORT_POOLS, start_time),
+ offsetof(POOL_REPORT_POOLS, pool_id),
+ offsetof(POOL_REPORT_POOLS, backend_id),
+ offsetof(POOL_REPORT_POOLS, database),
+ offsetof(POOL_REPORT_POOLS, username),
+ offsetof(POOL_REPORT_POOLS, create_time),
+ offsetof(POOL_REPORT_POOLS, pool_majorversion),
+ offsetof(POOL_REPORT_POOLS, pool_minorversion),
+ offsetof(POOL_REPORT_POOLS, pool_counter),
+ offsetof(POOL_REPORT_POOLS, pool_backendpid),
+ offsetof(POOL_REPORT_POOLS, pool_connected)
+ };
+
+ *n = sizeof(offsettbl)/sizeof(int);
+ return offsettbl;
+}
}
+/*
+ * Used by pcp_proc_info and SHOW pool_pools
+ */
POOL_REPORT_POOLS *
get_pools(int *nrows)
{
for (backend_id = 0; backend_id < NUM_BACKENDS; backend_id++)
{
poolBE = pool * MAX_NUM_BACKENDS + backend_id;
- pools[lines].pool_pid = proc_id;
- pools[lines].start_time = pi->start_time;
- pools[lines].pool_id = pool;
- pools[lines].backend_id = backend_id;
+ snprintf(pools[lines].pool_pid, sizeof(pools[lines].pool_pid), "%d", proc_id);
+
+ if (pi->start_time)
+ strftime(pools[lines].start_time, sizeof(pools[lines].start_time), "%Y-%m-%d %H:%M:%S",
+ localtime(&pi->start_time));
+ else
+ *(pools[lines].start_time) = '\0';
+
+ snprintf(pools[lines].pool_id, sizeof(pools[lines].pool_id), "%d", pool);
+
+ snprintf(pools[lines].backend_id, sizeof(pools[lines].backend_id), "%d", backend_id);
+
if (strlen(pi->connection_info[poolBE].database) == 0)
{
StrNCpy(pools[lines].database, "", POOLCONFIG_MAXIDENTLEN);
StrNCpy(pools[lines].username, "", POOLCONFIG_MAXIDENTLEN);
- pools[lines].create_time = 0;
- pools[lines].pool_majorversion = 0;
- pools[lines].pool_minorversion = 0;
+ *(pools[lines].create_time) = '\0';
+ snprintf(pools[lines].pool_majorversion, sizeof(pools[lines].pool_majorversion), "%d", 0);
+ snprintf(pools[lines].pool_minorversion, sizeof(pools[lines].pool_minorversion), "%d", 0);
}
else
{
StrNCpy(pools[lines].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN);
StrNCpy(pools[lines].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN);
- pools[lines].create_time = pi->connection_info[poolBE].create_time;
- pools[lines].pool_majorversion = pi->connection_info[poolBE].major;
- pools[lines].pool_minorversion = pi->connection_info[poolBE].minor;
+ strftime(pools[lines].create_time, sizeof(pools[lines].create_time), "%Y-%m-%d %H:%M:%S",
+ localtime(&pi->connection_info[poolBE].create_time));
+ snprintf(pools[lines].pool_majorversion, sizeof(pools[lines].pool_majorversion), "%d",
+ pi->connection_info[poolBE].major);
+ snprintf(pools[lines].pool_minorversion, sizeof(pools[lines].pool_minorversion), "%d",
+ pi->connection_info[poolBE].minor);
}
- pools[lines].pool_counter = pi->connection_info[poolBE].counter;
- pools[lines].pool_backendpid = ntohl(pi->connection_info[poolBE].pid);
- pools[lines].pool_connected = pi->connection_info[poolBE].connected;
+ snprintf(pools[lines].pool_counter, sizeof(pools[lines].pool_counter), "%d",
+ pi->connection_info[poolBE].counter);
+ snprintf(pools[lines].pool_backendpid, sizeof(pools[lines].pool_backendpid), "%d",
+ ntohl(pi->connection_info[poolBE].pid));
+ snprintf(pools[lines].pool_connected, sizeof(pools[lines].pool_connected), "%d",
+ pi->connection_info[poolBE].connected);
+
lines++;
}
}
return pools;
}
+/*
+ * SHOW pool_pools;
+ */
void
pools_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
{
- static short num_fields = 12;
+ short num_fields;
static char *field_names[] = {"pool_pid", "start_time", "pool_id", "backend_id", "database", "username", "create_time",
- "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
- short s;
- int len;
- int i;
- static unsigned char nullmap[2] = {0xff, 0xff};
- int nbytes = (num_fields + 7) / 8;
- int nrows;
- int size;
- int hsize;
- char proc_pid[16];
- char pool_id[16];
- char proc_start_time[20];
- char proc_create_time[20];
- char majorversion[5];
- char minorversion[5];
- char pool_counter[16];
- char backend_id[16];
- char backend_pid[16];
- char connected[2];
-
- POOL_REPORT_POOLS *pools = get_pools(&nrows);
-
- send_row_description(frontend, backend, num_fields, field_names);
-
- if (MAJOR(backend) == PROTO_MAJOR_V2)
- hsize = 4;
- else
- hsize = 0;
+ "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
+ int n;
+ int *offsettbl;
+ int nrows;
+ POOL_REPORT_POOLS *pools;
- /* ascii row */
- for (i = 0; i < nrows; i++)
- {
- snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
- snprintf(pool_id, sizeof(pool_id), "%d", pools[i].pool_id);
- if (pools[i].start_time)
- strftime(proc_start_time, sizeof(proc_start_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].start_time));
- else
- *proc_start_time = '\0';
- if (pools[i].create_time)
- strftime(proc_create_time, sizeof(proc_create_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].create_time));
- else
- *proc_create_time = '\0';
- snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
- snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
- snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
- snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
- snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
- snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);
-
- if (MAJOR(backend) == PROTO_MAJOR_V2)
- {
- pool_write(frontend, "D", 1);
- pool_write_and_flush(frontend, nullmap, nbytes);
- }
- else
- {
- pool_write(frontend, "D", 1);
- len = 6; /* int32 + int16; */
- len += 4 + strlen(proc_pid); /* int32 + data */
- len += 4 + strlen(proc_start_time); /* int32 + data */
- len += 4 + strlen(pool_id); /* int32 + data */
- len += 4 + strlen(backend_id); /* int32 + data */
- len += 4 + strlen(pools[i].database); /* int32 + data */
- len += 4 + strlen(pools[i].username); /* int32 + data */
- len += 4 + strlen(proc_create_time); /* int32 + data */
- len += 4 + strlen(majorversion); /* int32 + data */
- len += 4 + strlen(minorversion); /* int32 + data */
- len += 4 + strlen(pool_counter); /* int32 + data */
- len += 4 + strlen(backend_pid); /* int32 + data */
- len += 4 + strlen(connected); /* int32 + data */
-
- len = htonl(len);
- pool_write(frontend, &len, sizeof(len));
- s = htons(num_fields);
- pool_write(frontend, &s, sizeof(s));
- }
-
- len = strlen(proc_pid);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, proc_pid, len);
-
- len = strlen(proc_start_time);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, proc_start_time, len);
-
- len = strlen(pool_id);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, pool_id, len);
-
- len = strlen(backend_id);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, backend_id, len);
-
- len = strlen(pools[i].database);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, pools[i].database, len);
-
- len = strlen(pools[i].username);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, pools[i].username, len);
-
- len = strlen(proc_create_time);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, proc_create_time, len);
-
- len = strlen(majorversion);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, majorversion, len);
-
- len = strlen(minorversion);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, minorversion, len);
-
- len = strlen(pool_counter);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, pool_counter, len);
-
- len = strlen(backend_pid);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, backend_pid, len);
-
- len = strlen(connected);
- size = htonl(len + hsize);
- pool_write(frontend, &size, sizeof(size));
- pool_write(frontend, connected, len);
- }
+ num_fields = sizeof(field_names) / sizeof(char *);
+ offsettbl = pool_report_pools_offsets(&n);
+ pools = get_pools(&nrows);
- send_complete_and_ready(frontend, backend, "SELECT", nrows);
+ send_row_description_and_data_rows(frontend, backend, num_fields, field_names, offsettbl,
+ (char *)pools, sizeof(POOL_REPORT_POOLS), nrows);
pfree(pools);
}