4 * All the statistics collector stuff hacked up in one big, ugly file.
6 * TODO: - Separate collector, postmaster and backend stuff
7 * into different files.
9 * - Add some automatic call for pgstat vacuuming.
11 * - Add a pgstat config column to pg_database, so this
12 * entire thing can be enabled/disabled on a per db basis.
14 * Copyright (c) 2001-2003, PostgreSQL Global Development Group
16 * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.72 2004/05/28 05:12:58 tgl Exp $
23 #include <sys/param.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
35 #include "access/xact.h"
36 #include "access/heapam.h"
37 #include "catalog/catname.h"
38 #include "catalog/pg_shadow.h"
39 #include "catalog/pg_database.h"
40 #include "libpq/pqsignal.h"
41 #include "libpq/libpq.h"
42 #include "mb/pg_wchar.h"
43 #include "miscadmin.h"
44 #include "utils/memutils.h"
45 #include "storage/backendid.h"
46 #include "storage/ipc.h"
47 #include "storage/pg_shmem.h"
48 #include "tcop/tcopprot.h"
49 #include "utils/rel.h"
50 #include "utils/hsearch.h"
51 #include "utils/ps_status.h"
52 #include "utils/syscache.h"
59 bool pgstat_collect_startcollector = true;
60 bool pgstat_collect_resetonpmstart = true;
61 bool pgstat_collect_querystring = false;
62 bool pgstat_collect_tuplelevel = false;
63 bool pgstat_collect_blocklevel = false;
66 * Other global variables
69 bool pgstat_is_running = false;
75 NON_EXEC_STATIC int pgStatSock = -1;
76 static int pgStatPipe[2];
77 static struct sockaddr_storage pgStatAddr;
78 static int pgStatPmPipe[2] = {-1, -1};
79 static int pgStatCollectorPmPipe[2] = {-1, -1};
82 static time_t last_pgstat_start_time;
84 static long pgStatNumMessages = 0;
86 static bool pgStatRunningInCollector = FALSE;
88 static int pgStatTabstatAlloc = 0;
89 static int pgStatTabstatUsed = 0;
90 static PgStat_MsgTabstat **pgStatTabstatMessages = NULL;
92 #define TABSTAT_QUANTUM 4 /* we alloc this many at a time */
94 static int pgStatXactCommit = 0;
95 static int pgStatXactRollback = 0;
97 static TransactionId pgStatDBHashXact = InvalidTransactionId;
98 static HTAB *pgStatDBHash = NULL;
99 static HTAB *pgStatBeDead = NULL;
100 static PgStat_StatBeEntry *pgStatBeTable = NULL;
101 static int pgStatNumBackends = 0;
103 static char pgStat_fname[MAXPGPATH];
104 static char pgStat_tmpfname[MAXPGPATH];
108 * Local function forward declarations
113 typedef enum STATS_PROCESS_TYPE
117 } STATS_PROCESS_TYPE;
119 static pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType);
120 static void pgstat_parseArgs(int argc, char *argv[]);
124 NON_EXEC_STATIC void PgstatBufferMain(int argc, char *argv[]);
125 NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]);
126 static void pgstat_recvbuffer(void);
127 static void pgstat_die(SIGNAL_ARGS);
129 static int pgstat_add_backend(PgStat_MsgHdr *msg);
130 static void pgstat_sub_backend(int procpid);
131 static void pgstat_drop_database(Oid databaseid);
132 static void pgstat_write_statsfile(void);
133 static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
134 PgStat_StatBeEntry **betab,
137 static void pgstat_setheader(PgStat_MsgHdr *hdr, int mtype);
138 static void pgstat_send(void *msg, int len);
140 static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
141 static void pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len);
142 static void pgstat_recv_activity(PgStat_MsgActivity *msg, int len);
143 static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len);
144 static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);
145 static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);
146 static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
149 /* ------------------------------------------------------------
150 * Public functions called from postmaster follow
151 * ------------------------------------------------------------
157 * Called from postmaster at startup. Create the resources required
158 * by the statistics collector process. If unable to do so, do not
159 * fail --- better to let the postmaster start with stats collection
166 ACCEPT_TYPE_ARG3 alen;
167 struct addrinfo *addrs = NULL,
176 #define TESTBYTEVAL ((char) 199)
179 * Force start of collector daemon if something to collect
181 if (pgstat_collect_querystring ||
182 pgstat_collect_tuplelevel ||
183 pgstat_collect_blocklevel)
184 pgstat_collect_startcollector = true;
187 * Initialize the filename for the status reports. (In the EXEC_BACKEND
188 * case, this only sets the value in the postmaster. The collector
189 * subprocess will recompute the value for itself, and individual
190 * backends must do so also if they want to access the file.)
192 snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
195 * If we don't have to start a collector or should reset the collected
196 * statistics on postmaster start, simply remove the file.
198 if (!pgstat_collect_startcollector || pgstat_collect_resetonpmstart)
199 unlink(pgStat_fname);
202 * Nothing else required if collector will not get started
204 if (!pgstat_collect_startcollector)
208 * Create the UDP socket for sending and receiving statistic messages
210 hints.ai_flags = AI_PASSIVE;
211 hints.ai_family = PF_UNSPEC;
212 hints.ai_socktype = SOCK_DGRAM;
213 hints.ai_protocol = 0;
214 hints.ai_addrlen = 0;
215 hints.ai_addr = NULL;
216 hints.ai_canonname = NULL;
217 hints.ai_next = NULL;
218 ret = getaddrinfo_all("localhost", NULL, &hints, &addrs);
222 (errmsg("could not resolve \"localhost\": %s",
223 gai_strerror(ret))));
228 * On some platforms, getaddrinfo_all() may return multiple addresses
229 * only one of which will actually work (eg, both IPv6 and IPv4 addresses
230 * when kernel will reject IPv6). Worse, the failure may occur at the
231 * bind() or perhaps even connect() stage. So we must loop through the
232 * results till we find a working combination. We will generate LOG
233 * messages, but no error, for bogus combinations.
235 for (addr = addrs; addr; addr = addr->ai_next)
237 #ifdef HAVE_UNIX_SOCKETS
238 /* Ignore AF_UNIX sockets, if any are returned. */
239 if (addr->ai_family == AF_UNIX)
245 if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) < 0)
248 (errcode_for_socket_access(),
249 errmsg("could not create socket for statistics collector: %m")));
254 * Bind it to a kernel assigned port on localhost and get the assigned
255 * port via getsockname().
257 if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
260 (errcode_for_socket_access(),
261 errmsg("could not bind socket for statistics collector: %m")));
262 closesocket(pgStatSock);
267 alen = sizeof(pgStatAddr);
268 if (getsockname(pgStatSock, (struct sockaddr *) &pgStatAddr, &alen) < 0)
271 (errcode_for_socket_access(),
272 errmsg("could not get address of socket for statistics collector: %m")));
273 closesocket(pgStatSock);
279 * Connect the socket to its own address. This saves a few cycles by
280 * not having to respecify the target address on every send. This also
281 * provides a kernel-level check that only packets from this same
282 * address will be received.
284 if (connect(pgStatSock, (struct sockaddr *) &pgStatAddr, alen) < 0)
287 (errcode_for_socket_access(),
288 errmsg("could not connect socket for statistics collector: %m")));
289 closesocket(pgStatSock);
295 * Try to send and receive a one-byte test message on the socket.
296 * This is to catch situations where the socket can be created but
297 * will not actually pass data (for instance, because kernel packet
298 * filtering rules prevent it).
300 test_byte = TESTBYTEVAL;
301 if (send(pgStatSock, &test_byte, 1, 0) != 1)
304 (errcode_for_socket_access(),
305 errmsg("could not send test message on socket for statistics collector: %m")));
306 closesocket(pgStatSock);
312 * There could possibly be a little delay before the message can be
313 * received. We arbitrarily allow up to half a second before deciding
316 for (;;) /* need a loop to handle EINTR */
319 FD_SET(pgStatSock, &rset);
322 sel_res = select(pgStatSock+1, &rset, NULL, NULL, &tv);
323 if (sel_res >= 0 || errno != EINTR)
329 (errcode_for_socket_access(),
330 errmsg("select() failed in statistics collector: %m")));
331 closesocket(pgStatSock);
335 if (sel_res == 0 || !FD_ISSET(pgStatSock, &rset))
338 * This is the case we actually think is likely, so take pains to
339 * give a specific message for it.
341 * errno will not be set meaningfully here, so don't use it.
344 (ERRCODE_CONNECTION_FAILURE,
345 errmsg("test message did not get through on socket for statistics collector")));
346 closesocket(pgStatSock);
351 test_byte++; /* just make sure variable is changed */
353 if (recv(pgStatSock, &test_byte, 1, 0) != 1)
356 (errcode_for_socket_access(),
357 errmsg("could not receive test message on socket for statistics collector: %m")));
358 closesocket(pgStatSock);
363 if (test_byte != TESTBYTEVAL) /* strictly paranoia ... */
366 (ERRCODE_INTERNAL_ERROR,
367 errmsg("incorrect test message transmission on socket for statistics collector")));
368 closesocket(pgStatSock);
373 /* If we get here, we have a working socket */
377 /* Did we find a working address? */
378 if (!addr || pgStatSock < 0)
381 (errcode_for_socket_access(),
382 errmsg("disabling statistics collector for lack of working socket")));
387 * Set the socket to non-blocking IO. This ensures that if the
388 * collector falls behind (despite the buffering process), statistics
389 * messages will be discarded; backends won't block waiting to send
390 * messages to the collector.
392 if (!set_noblock(pgStatSock))
395 (errcode_for_socket_access(),
396 errmsg("could not set statistics collector socket to nonblocking mode: %m")));
401 * Create the pipe that controls the statistics collector shutdown
403 if (pgpipe(pgStatPmPipe) < 0 || pgpipe(pgStatCollectorPmPipe) < 0)
406 (errcode_for_socket_access(),
407 errmsg("could not create pipe for statistics collector: %m")));
411 freeaddrinfo_all(hints.ai_family, addrs);
417 freeaddrinfo_all(hints.ai_family, addrs);
420 closesocket(pgStatSock);
423 /* Adjust GUC variables to suppress useless activity */
424 pgstat_collect_startcollector = false;
425 pgstat_collect_querystring = false;
426 pgstat_collect_tuplelevel = false;
427 pgstat_collect_blocklevel = false;
434 * pgstat_forkexec() -
436 * Format up the arglist for, then fork and exec, statistics
437 * (buffer and collector) processes
440 pgstat_forkexec(STATS_PROCESS_TYPE procType)
443 int ac = 0, bufc = 0, i;
444 char pgstatBuf[7][32];
446 av[ac++] = "postgres";
450 case STAT_PROC_BUFFER:
451 av[ac++] = "-forkbuf";
454 case STAT_PROC_COLLECTOR:
455 av[ac++] = "-forkcol";
462 av[ac++] = NULL; /* filled in by postmaster_forkexec */
464 /* postgres_exec_path is not passed by write_backend_variables */
465 av[ac++] = postgres_exec_path;
467 /* Sockets + pipes (those not passed by write_backend_variables) */
468 snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[0]);
469 snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[1]);
470 snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[0]);
471 snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[1]);
472 snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[0]);
473 snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[1]);
475 /* Add to the arg list */
476 Assert(bufc <= lengthof(pgstatBuf));
477 for (i = 0; i < bufc; i++)
478 av[ac++] = pgstatBuf[i];
481 Assert(ac < lengthof(av));
483 return postmaster_forkexec(ac, av);
488 * pgstat_parseArgs() -
490 * Extract data from the arglist for exec'ed statistics
491 * (buffer and collector) processes
494 pgstat_parseArgs(int argc, char *argv[])
499 StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
500 pgStatPmPipe[0] = atoi(argv[argc++]);
501 pgStatPmPipe[1] = atoi(argv[argc++]);
502 pgStatCollectorPmPipe[0] = atoi(argv[argc++]);
503 pgStatCollectorPmPipe[1] = atoi(argv[argc++]);
504 pgStatPipe[0] = atoi(argv[argc++]);
505 pgStatPipe[1] = atoi(argv[argc++]);
508 #endif /* EXEC_BACKEND */
514 * Called from postmaster at startup or after an existing collector
515 * died. Attempt to fire up a fresh statistics collector.
517 * Note: if fail, we will be called again from the postmaster main loop.
526 * Do nothing if no collector needed
528 if (pgstat_is_running || !pgstat_collect_startcollector)
532 * Do nothing if too soon since last collector start. This is a
533 * safety valve to protect against continuous respawn attempts if the
534 * collector is dying immediately at launch. Note that since we will
535 * be re-called from the postmaster main loop, we will get another
538 curtime = time(NULL);
539 if ((unsigned int) (curtime - last_pgstat_start_time) <
540 (unsigned int) PGSTAT_RESTART_INTERVAL)
542 last_pgstat_start_time = curtime;
545 * Check that the socket is there, else pgstat_init failed.
550 (errmsg("statistics collector startup skipped")));
553 * We can only get here if someone tries to manually turn
554 * pgstat_collect_startcollector on after it had been off.
556 pgstat_collect_startcollector = false;
561 * Okay, fork off the collector. Remember its PID for
569 /* Specific beos actions before backend startup */
570 beos_before_backend_startup();
574 switch ((pgStatPid = (int) pgstat_forkexec(STAT_PROC_BUFFER)))
576 switch ((pgStatPid = (int) fork()))
581 /* Specific beos actions */
582 beos_backend_startup_failed();
585 (errmsg("could not fork statistics buffer: %m")));
590 /* in postmaster child ... */
592 /* Specific beos actions after backend startup */
593 beos_backend_startup();
595 /* Close the postmaster's sockets, except for pgstat link */
596 ClosePostmasterPorts(false);
598 /* Drop our connection to postmaster's shared memory, as well */
599 PGSharedMemoryDetach();
601 PgstatBufferMain(0, NULL);
606 pgstat_is_running = true;
613 * pgstat_ispgstat() -
615 * Called from postmaster to check if a terminated child process
616 * was the statistics collector.
620 pgstat_ispgstat(int pid)
622 if (!pgstat_is_running)
625 if (pgStatPid != pid)
629 pgstat_is_running = false;
636 * pgstat_close_sockets() -
638 * Called when postmaster forks a non-pgstat child process, to close off
639 * file descriptors that should not be held open in child processes.
643 pgstat_close_sockets(void)
645 if (pgStatPmPipe[0] >= 0)
646 closesocket(pgStatPmPipe[0]);
647 pgStatPmPipe[0] = -1;
648 if (pgStatPmPipe[1] >= 0)
649 closesocket(pgStatPmPipe[1]);
650 pgStatPmPipe[1] = -1;
651 if (pgStatCollectorPmPipe[0] >= 0)
652 closesocket(pgStatCollectorPmPipe[0]);
653 pgStatCollectorPmPipe[0] = -1;
654 if (pgStatCollectorPmPipe[1] >= 0)
655 closesocket(pgStatCollectorPmPipe[1]);
656 pgStatCollectorPmPipe[1] = -1;
663 * Called from postmaster to tell collector a backend terminated.
667 pgstat_beterm(int pid)
669 PgStat_MsgBeterm msg;
674 MemSet(&(msg.m_hdr), 0, sizeof(msg.m_hdr));
675 msg.m_hdr.m_type = PGSTAT_MTYPE_BETERM;
676 msg.m_hdr.m_procpid = pid;
678 pgstat_send(&msg, sizeof(msg));
682 /* ------------------------------------------------------------
683 * Public functions used by backends follow
684 *------------------------------------------------------------
691 * Tell the collector that this new backend is soon ready to process
692 * queries. Called from tcop/postgres.c before entering the mainloop.
698 PgStat_MsgBestart msg;
703 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);
704 pgstat_send(&msg, sizeof(msg));
709 * pgstat_report_activity() -
711 * Called in tcop/postgres.c to tell the collector what the backend
712 * is actually doing (usually "<IDLE>" or the start of the query to
717 pgstat_report_activity(const char *what)
719 PgStat_MsgActivity msg;
722 if (!pgstat_collect_querystring || pgStatSock < 0)
726 len = pg_mbcliplen((const unsigned char *) what, len,
727 PGSTAT_ACTIVITY_SIZE - 1);
729 memcpy(msg.m_what, what, len);
730 msg.m_what[len] = '\0';
731 len += offsetof(PgStat_MsgActivity, m_what) +1;
733 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ACTIVITY);
734 pgstat_send(&msg, len);
739 * pgstat_report_tabstat() -
741 * Called from tcop/postgres.c to send the so far collected
742 * per table access statistics to the collector.
746 pgstat_report_tabstat(void)
750 if (pgStatSock < 0 ||
751 !(pgstat_collect_querystring ||
752 pgstat_collect_tuplelevel ||
753 pgstat_collect_blocklevel))
755 /* Not reporting stats, so just flush whatever we have */
756 pgStatTabstatUsed = 0;
761 * For each message buffer used during the last query set the header
762 * fields and send it out.
764 for (i = 0; i < pgStatTabstatUsed; i++)
766 PgStat_MsgTabstat *tsmsg = pgStatTabstatMessages[i];
770 n = tsmsg->m_nentries;
771 len = offsetof(PgStat_MsgTabstat, m_entry[0]) +
772 n * sizeof(PgStat_TableEntry);
774 tsmsg->m_xact_commit = pgStatXactCommit;
775 tsmsg->m_xact_rollback = pgStatXactRollback;
776 pgStatXactCommit = 0;
777 pgStatXactRollback = 0;
779 pgstat_setheader(&tsmsg->m_hdr, PGSTAT_MTYPE_TABSTAT);
780 pgstat_send(tsmsg, len);
783 pgStatTabstatUsed = 0;
788 * pgstat_vacuum_tabstat() -
790 * Will tell the collector about objects he can get rid of.
794 pgstat_vacuum_tabstat(void)
802 HASH_SEQ_STATUS hstat;
803 PgStat_StatDBEntry *dbentry;
804 PgStat_StatTabEntry *tabentry;
807 PgStat_MsgTabpurge msg;
815 * If not done for this transaction, read the statistics collector
816 * stats file into some hash tables.
818 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
820 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
821 &pgStatBeTable, &pgStatNumBackends);
822 pgStatDBHashXact = GetCurrentTransactionId();
826 * Lookup our own database entry
828 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
829 (void *) &MyDatabaseId,
834 if (dbentry->tables == NULL)
838 * Initialize our messages table counter to zero
843 * Check for all tables if they still exist.
845 hash_seq_init(&hstat, dbentry->tables);
846 while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&hstat)) != NULL)
849 * Check if this relation is still alive by looking up it's
850 * pg_class tuple in the system catalog cache.
852 reltup = SearchSysCache(RELOID,
853 ObjectIdGetDatum(tabentry->tableid),
855 if (HeapTupleIsValid(reltup))
857 ReleaseSysCache(reltup);
862 * Add this tables Oid to the message
864 msg.m_tableid[msg.m_nentries++] = tabentry->tableid;
868 * If the message is full, send it out and reinitialize ot zero
870 if (msg.m_nentries >= PGSTAT_NUM_TABPURGE)
872 len = offsetof(PgStat_MsgTabpurge, m_tableid[0])
873 +msg.m_nentries * sizeof(Oid);
875 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE);
876 pgstat_send(&msg, len);
885 if (msg.m_nentries > 0)
887 len = offsetof(PgStat_MsgTabpurge, m_tableid[0])
888 +msg.m_nentries * sizeof(Oid);
890 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE);
891 pgstat_send(&msg, len);
895 * Read pg_database and remember the Oid's of all existing databases
899 dbidlist = (Oid *) palloc(sizeof(Oid) * dbidalloc);
901 dbrel = heap_openr(DatabaseRelationName, AccessShareLock);
902 dbscan = heap_beginscan(dbrel, SnapshotNow, 0, NULL);
903 while ((dbtup = heap_getnext(dbscan, ForwardScanDirection)) != NULL)
905 if (dbidused >= dbidalloc)
908 dbidlist = (Oid *) repalloc((char *) dbidlist,
909 sizeof(Oid) * dbidalloc);
911 dbidlist[dbidused++] = HeapTupleGetOid(dbtup);
913 heap_endscan(dbscan);
914 heap_close(dbrel, AccessShareLock);
917 * Search the database hash table for dead databases and tell the
918 * collector to drop them as well.
920 hash_seq_init(&hstat, pgStatDBHash);
921 while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL)
923 Oid dbid = dbentry->databaseid;
925 for (i = 0; i < dbidused; i++)
927 if (dbidlist[i] == dbid)
934 if (dbid != InvalidOid)
937 pgstat_drop_database(dbid);
942 * Free the dbid list.
944 pfree((char *) dbidlist);
947 * Tell the caller how many removeable objects we found
954 * pgstat_drop_database() -
956 * Tell the collector that we just dropped a database.
957 * This is the only message that shouldn't get lost in space. Otherwise
958 * the collector will keep the statistics for the dead DB until his
959 * stats file got removed while the postmaster is down.
963 pgstat_drop_database(Oid databaseid)
965 PgStat_MsgDropdb msg;
970 msg.m_databaseid = databaseid;
972 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DROPDB);
973 pgstat_send(&msg, sizeof(msg));
978 * pgstat_reset_counters() -
980 * Tell the statistics collector to reset counters for our database.
984 pgstat_reset_counters(void)
986 PgStat_MsgResetcounter msg;
993 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
994 errmsg("must be superuser to reset statistics counters")));
996 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER);
997 pgstat_send(&msg, sizeof(msg));
1004 * Send some junk data to the collector to increase traffic.
1010 PgStat_MsgDummy msg;
1015 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DUMMY);
1016 pgstat_send(&msg, sizeof(msg));
1020 * Create or enlarge the pgStatTabstatMessages array
1023 more_tabstat_space(void)
1025 PgStat_MsgTabstat *newMessages;
1026 PgStat_MsgTabstat **msgArray;
1027 int newAlloc = pgStatTabstatAlloc + TABSTAT_QUANTUM;
1030 /* Create (another) quantum of message buffers */
1031 newMessages = (PgStat_MsgTabstat *)
1032 malloc(sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
1033 if (newMessages == NULL)
1036 (errcode(ERRCODE_OUT_OF_MEMORY),
1037 errmsg("out of memory")));
1041 /* Create or enlarge the pointer array */
1042 if (pgStatTabstatMessages == NULL)
1043 msgArray = (PgStat_MsgTabstat **)
1044 malloc(sizeof(PgStat_MsgTabstat *) * newAlloc);
1046 msgArray = (PgStat_MsgTabstat **)
1047 realloc(pgStatTabstatMessages,
1048 sizeof(PgStat_MsgTabstat *) * newAlloc);
1049 if (msgArray == NULL)
1053 (errcode(ERRCODE_OUT_OF_MEMORY),
1054 errmsg("out of memory")));
1058 MemSet(newMessages, 0, sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
1059 for (i = 0; i < TABSTAT_QUANTUM; i++)
1060 msgArray[pgStatTabstatAlloc + i] = newMessages++;
1061 pgStatTabstatMessages = msgArray;
1062 pgStatTabstatAlloc = newAlloc;
1068 * pgstat_initstats() -
1070 * Called from various places usually dealing with initialization
1071 * of Relation or Scan structures. The data placed into these
1072 * structures from here tell where later to count for buffer reads,
1073 * scans and tuples fetched.
1077 pgstat_initstats(PgStat_Info *stats, Relation rel)
1079 Oid rel_id = rel->rd_id;
1080 PgStat_TableEntry *useent;
1081 PgStat_MsgTabstat *tsmsg;
1086 * Initialize data not to count at all.
1088 stats->tabentry = NULL;
1089 stats->no_stats = FALSE;
1090 stats->heap_scan_counted = FALSE;
1091 stats->index_scan_counted = FALSE;
1093 if (pgStatSock < 0 ||
1094 !(pgstat_collect_tuplelevel ||
1095 pgstat_collect_blocklevel))
1097 stats->no_stats = TRUE;
1102 * Search the already-used message slots for this relation.
1104 for (mb = 0; mb < pgStatTabstatUsed; mb++)
1106 tsmsg = pgStatTabstatMessages[mb];
1108 for (i = tsmsg->m_nentries; --i >= 0; )
1110 if (tsmsg->m_entry[i].t_id == rel_id)
1112 stats->tabentry = (void *) &(tsmsg->m_entry[i]);
1117 if (tsmsg->m_nentries >= PGSTAT_NUM_TABENTRIES)
1121 * Not found, but found a message buffer with an empty slot
1122 * instead. Fine, let's use this one.
1124 i = tsmsg->m_nentries++;
1125 useent = &tsmsg->m_entry[i];
1126 MemSet(useent, 0, sizeof(PgStat_TableEntry));
1127 useent->t_id = rel_id;
1128 stats->tabentry = (void *) useent;
1133 * If we ran out of message buffers, we just allocate more.
1135 if (pgStatTabstatUsed >= pgStatTabstatAlloc)
1137 if (!more_tabstat_space())
1139 stats->no_stats = TRUE;
1142 Assert(pgStatTabstatUsed < pgStatTabstatAlloc);
1146 * Use the first entry of the next message buffer.
1148 mb = pgStatTabstatUsed++;
1149 tsmsg = pgStatTabstatMessages[mb];
1150 tsmsg->m_nentries = 1;
1151 useent = &tsmsg->m_entry[0];
1152 MemSet(useent, 0, sizeof(PgStat_TableEntry));
1153 useent->t_id = rel_id;
1154 stats->tabentry = (void *) useent;
1159 * pgstat_count_xact_commit() -
1161 * Called from access/transam/xact.c to count transaction commits.
1165 pgstat_count_xact_commit(void)
1167 if (!(pgstat_collect_querystring ||
1168 pgstat_collect_tuplelevel ||
1169 pgstat_collect_blocklevel))
1175 * If there was no relation activity yet, just make one existing
1176 * message buffer used without slots, causing the next report to tell
1177 * new xact-counters.
1179 if (pgStatTabstatAlloc == 0)
1181 if (!more_tabstat_space())
1184 if (pgStatTabstatUsed == 0)
1186 pgStatTabstatUsed++;
1187 pgStatTabstatMessages[0]->m_nentries = 0;
1193 * pgstat_count_xact_rollback() -
1195 * Called from access/transam/xact.c to count transaction rollbacks.
1199 pgstat_count_xact_rollback(void)
1201 if (!(pgstat_collect_querystring ||
1202 pgstat_collect_tuplelevel ||
1203 pgstat_collect_blocklevel))
1206 pgStatXactRollback++;
1209 * If there was no relation activity yet, just make one existing
1210 * message buffer used without slots, causing the next report to tell
1211 * new xact-counters.
1213 if (pgStatTabstatAlloc == 0)
1215 if (!more_tabstat_space())
1218 if (pgStatTabstatUsed == 0)
1220 pgStatTabstatUsed++;
1221 pgStatTabstatMessages[0]->m_nentries = 0;
1227 * pgstat_fetch_stat_dbentry() -
1229 * Support function for the SQL-callable pgstat* functions. Returns
1230 * the collected statistics for one database or NULL. NULL doesn't mean
1231 * that the database doesn't exist, it is just not yet known by the
1232 * collector, so the caller is better off to report ZERO instead.
1235 PgStat_StatDBEntry *
1236 pgstat_fetch_stat_dbentry(Oid dbid)
1238 PgStat_StatDBEntry *dbentry;
1241 * If not done for this transaction, read the statistics collector
1242 * stats file into some hash tables. Be careful with the
1243 * read_statsfile() call below!
1245 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1247 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1248 &pgStatBeTable, &pgStatNumBackends);
1249 pgStatDBHashXact = GetCurrentTransactionId();
1253 * Lookup the requested database
1255 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
1258 if (dbentry == NULL)
1266 * pgstat_fetch_stat_tabentry() -
1268 * Support function for the SQL-callable pgstat* functions. Returns
1269 * the collected statistics for one table or NULL. NULL doesn't mean
1270 * that the table doesn't exist, it is just not yet known by the
1271 * collector, so the caller is better off to report ZERO instead.
1274 PgStat_StatTabEntry *
1275 pgstat_fetch_stat_tabentry(Oid relid)
1277 PgStat_StatDBEntry *dbentry;
1278 PgStat_StatTabEntry *tabentry;
1281 * If not done for this transaction, read the statistics collector
1282 * stats file into some hash tables. Be careful with the
1283 * read_statsfile() call below!
1285 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1287 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1288 &pgStatBeTable, &pgStatNumBackends);
1289 pgStatDBHashXact = GetCurrentTransactionId();
1293 * Lookup our database.
1295 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
1296 (void *) &MyDatabaseId,
1298 if (dbentry == NULL)
1302 * Now inside the DB's table hash table lookup the requested one.
1304 if (dbentry->tables == NULL)
1306 tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
1309 if (tabentry == NULL)
1317 * pgstat_fetch_stat_beentry() -
1319 * Support function for the SQL-callable pgstat* functions. Returns
1320 * the actual activity slot of one active backend. The caller is
1321 * responsible for a check if the actual user is permitted to see
1322 * that info (especially the querystring).
1325 PgStat_StatBeEntry *
1326 pgstat_fetch_stat_beentry(int beid)
1328 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1330 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1331 &pgStatBeTable, &pgStatNumBackends);
1332 pgStatDBHashXact = GetCurrentTransactionId();
1335 if (beid < 1 || beid > pgStatNumBackends)
1338 return &pgStatBeTable[beid - 1];
1343 * pgstat_fetch_stat_numbackends() -
1345 * Support function for the SQL-callable pgstat* functions. Returns
1346 * the maximum current backend id.
1350 pgstat_fetch_stat_numbackends(void)
1352 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1354 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1355 &pgStatBeTable, &pgStatNumBackends);
1356 pgStatDBHashXact = GetCurrentTransactionId();
1359 return pgStatNumBackends;
1364 /* ------------------------------------------------------------
1365 * Local support functions follow
1366 * ------------------------------------------------------------
1371 * pgstat_setheader() -
1373 * Set common header fields in a statistics message
1377 pgstat_setheader(PgStat_MsgHdr *hdr, int mtype)
1379 hdr->m_type = mtype;
1380 hdr->m_backendid = MyBackendId;
1381 hdr->m_procpid = MyProcPid;
1382 hdr->m_databaseid = MyDatabaseId;
1383 hdr->m_userid = GetSessionUserId();
1390 * Send out one statistics message to the collector
1394 pgstat_send(void *msg, int len)
1399 ((PgStat_MsgHdr *) msg)->m_size = len;
1401 send(pgStatSock, msg, len, 0);
1402 /* We deliberately ignore any error from send() */
1407 * PgstatBufferMain() -
1409 * Start up the statistics buffer process. This is the body of the
1410 * postmaster child process.
1412 * The argc/argv parameters are valid only in EXEC_BACKEND case.
1415 NON_EXEC_STATIC void
1416 PgstatBufferMain(int argc, char *argv[])
1418 IsUnderPostmaster = true; /* we are a postmaster subprocess now */
1420 MyProcPid = getpid(); /* reset MyProcPid */
1422 /* Lose the postmaster's on-exit routines */
1426 * Ignore all signals usually bound to some action in the postmaster,
1427 * except for SIGCHLD --- see pgstat_recvbuffer.
1429 pqsignal(SIGHUP, SIG_IGN);
1430 pqsignal(SIGINT, SIG_IGN);
1431 pqsignal(SIGTERM, SIG_IGN);
1432 pqsignal(SIGQUIT, SIG_IGN);
1433 pqsignal(SIGALRM, SIG_IGN);
1434 pqsignal(SIGPIPE, SIG_IGN);
1435 pqsignal(SIGUSR1, SIG_IGN);
1436 pqsignal(SIGUSR2, SIG_IGN);
1437 pqsignal(SIGCHLD, pgstat_die);
1438 pqsignal(SIGTTIN, SIG_DFL);
1439 pqsignal(SIGTTOU, SIG_DFL);
1440 pqsignal(SIGCONT, SIG_DFL);
1441 pqsignal(SIGWINCH, SIG_DFL);
1442 /* unblock will happen in pgstat_recvbuffer */
1445 pgstat_parseArgs(argc,argv);
1449 * Close the writing end of the postmaster pipe, so we'll see it
1450 * closing when the postmaster terminates and can terminate as well.
1452 closesocket(pgStatPmPipe[1]);
1453 pgStatPmPipe[1] = -1;
1454 closesocket(pgStatCollectorPmPipe[1]);
1455 pgStatCollectorPmPipe[1] = -1;
1458 * Start a buffering process to read from the socket, so we have a
1459 * little more time to process incoming messages.
1461 * NOTE: the process structure is: postmaster is parent of buffer process
1462 * is parent of collector process. This way, the buffer can detect
1463 * collector failure via SIGCHLD, whereas otherwise it wouldn't notice
1464 * collector failure until it tried to write on the pipe. That would
1465 * mean that after the postmaster started a new collector, we'd have
1466 * two buffer processes competing to read from the UDP socket --- not
1469 if (pgpipe(pgStatPipe) < 0)
1472 (errcode_for_socket_access(),
1473 errmsg("could not create pipe for statistics buffer: %m")));
1478 /* child becomes collector process */
1479 switch (pgstat_forkexec(STAT_PROC_COLLECTOR))
1486 (errmsg("could not fork statistics collector: %m")));
1489 #ifndef EXEC_BACKEND
1491 /* child becomes collector process */
1492 PgstatCollectorMain(0, NULL);
1497 /* parent becomes buffer process */
1498 closesocket(pgStatPipe[0]);
1499 pgstat_recvbuffer();
1506 * PgstatCollectorMain() -
1508 * Start up the statistics collector itself. This is the body of the
1509 * postmaster grandchild process.
1511 * The argc/argv parameters are valid only in EXEC_BACKEND case.
1514 NON_EXEC_STATIC void
1515 PgstatCollectorMain(int argc, char *argv[])
1523 struct timeval timeout;
1524 struct timeval next_statwrite;
1525 bool need_statwrite;
1528 MyProcPid = getpid(); /* reset MyProcPid */
1531 * Reset signal handling. With the exception of restoring default
1532 * SIGCHLD handling, this is a no-op in the non-EXEC_BACKEND case
1533 * because we'll have inherited these settings from the buffer process;
1534 * but it's not a no-op for EXEC_BACKEND.
1536 pqsignal(SIGHUP, SIG_IGN);
1537 pqsignal(SIGINT, SIG_IGN);
1538 pqsignal(SIGTERM, SIG_IGN);
1539 pqsignal(SIGQUIT, SIG_IGN);
1540 pqsignal(SIGALRM, SIG_IGN);
1541 pqsignal(SIGPIPE, SIG_IGN);
1542 pqsignal(SIGUSR1, SIG_IGN);
1543 pqsignal(SIGUSR2, SIG_IGN);
1544 pqsignal(SIGCHLD, SIG_DFL);
1545 pqsignal(SIGTTIN, SIG_DFL);
1546 pqsignal(SIGTTOU, SIG_DFL);
1547 pqsignal(SIGCONT, SIG_DFL);
1548 pqsignal(SIGWINCH, SIG_DFL);
1549 PG_SETMASK(&UnBlockSig);
1552 pgstat_parseArgs(argc,argv);
1555 /* Close unwanted files */
1556 closesocket(pgStatPipe[1]);
1557 closesocket(pgStatSock);
1558 pmPipe = pgStatCollectorPmPipe[0];
1561 * Identify myself via ps
1563 init_ps_display("stats collector process", "", "");
1567 * Initialize filenames needed for status reports.
1569 snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
1570 /* tmpfname need only be set correctly in this process */
1571 snprintf(pgStat_tmpfname, MAXPGPATH, PGSTAT_STAT_TMPFILE,
1575 * Arrange to write the initial status file right away
1577 gettimeofday(&next_statwrite, NULL);
1578 need_statwrite = TRUE;
1581 * Read in an existing statistics stats file or initialize the stats
1584 pgStatRunningInCollector = TRUE;
1585 pgstat_read_statsfile(&pgStatDBHash, InvalidOid, NULL, NULL);
1588 * Create the dead backend hashtable
1590 memset(&hash_ctl, 0, sizeof(hash_ctl));
1591 hash_ctl.keysize = sizeof(int);
1592 hash_ctl.entrysize = sizeof(PgStat_StatBeDead);
1593 hash_ctl.hash = tag_hash;
1594 pgStatBeDead = hash_create("Dead Backends", PGSTAT_BE_HASH_SIZE,
1595 &hash_ctl, HASH_ELEM | HASH_FUNCTION);
1596 if (pgStatBeDead == NULL)
1598 /* assume the problem is out-of-memory */
1600 (errcode(ERRCODE_OUT_OF_MEMORY),
1601 errmsg("out of memory in statistics collector --- abort")));
1606 * Create the known backends table
1608 pgStatBeTable = (PgStat_StatBeEntry *) malloc(
1609 sizeof(PgStat_StatBeEntry) * MaxBackends);
1610 if (pgStatBeTable == NULL)
1613 (errcode(ERRCODE_OUT_OF_MEMORY),
1614 errmsg("out of memory in statistics collector --- abort")));
1617 memset(pgStatBeTable, 0, sizeof(PgStat_StatBeEntry) * MaxBackends);
1619 readPipe = pgStatPipe[0];
1622 * Process incoming messages and handle all the reporting stuff until
1623 * there are no more messages.
1628 * If we need to write the status file again (there have been
1629 * changes in the statistics since we wrote it last) calculate the
1630 * timeout until we have to do so.
1636 gettimeofday(&now, NULL);
1637 /* avoid assuming that tv_sec is signed */
1638 if (now.tv_sec > next_statwrite.tv_sec ||
1639 (now.tv_sec == next_statwrite.tv_sec &&
1640 now.tv_usec >= next_statwrite.tv_usec))
1643 timeout.tv_usec = 0;
1647 timeout.tv_sec = next_statwrite.tv_sec - now.tv_sec;
1648 timeout.tv_usec = next_statwrite.tv_usec - now.tv_usec;
1649 if (timeout.tv_usec < 0)
1652 timeout.tv_usec += 1000000;
1658 * Setup the descriptor set for select(2)
1661 FD_SET(readPipe, &rfds);
1664 * Now wait for something to do.
1666 nready = select(readPipe+1, &rfds, NULL, NULL,
1667 (need_statwrite) ? &timeout : NULL);
1673 (errcode_for_socket_access(),
1674 errmsg("select() failed in statistics collector: %m")));
1679 * If there are no descriptors ready, our timeout for writing the
1680 * stats file happened.
1684 pgstat_write_statsfile();
1685 need_statwrite = FALSE;
1691 * Check if there is a new statistics message to collect.
1693 if (FD_ISSET(readPipe, &rfds))
1696 * We may need to issue multiple read calls in case the buffer
1697 * process didn't write the message in a single write, which
1698 * is possible since it dumps its buffer bytewise. In any
1699 * case, we'd need two reads since we don't know the message
1703 int targetlen = sizeof(PgStat_MsgHdr); /* initial */
1704 bool pipeEOF = false;
1706 while (nread < targetlen)
1708 len = piperead(readPipe, ((char *) &msg) + nread,
1715 (errcode_for_socket_access(),
1716 errmsg("could not read from statistics collector pipe: %m")));
1719 if (len == 0) /* EOF on the pipe! */
1725 if (nread == sizeof(PgStat_MsgHdr))
1727 /* we have the header, compute actual msg length */
1728 targetlen = msg.msg_hdr.m_size;
1729 if (targetlen < (int) sizeof(PgStat_MsgHdr) ||
1730 targetlen > (int) sizeof(msg))
1733 * Bogus message length implies that we got out of
1734 * sync with the buffer process somehow. Abort so
1735 * that we can restart both processes.
1738 (errmsg("invalid statistics message length")));
1745 * EOF on the pipe implies that the buffer process exited.
1746 * Fall out of outer loop.
1752 * Distribute the message to the specific function handling
1755 switch (msg.msg_hdr.m_type)
1757 case PGSTAT_MTYPE_DUMMY:
1760 case PGSTAT_MTYPE_BESTART:
1761 pgstat_recv_bestart((PgStat_MsgBestart *) &msg, nread);
1764 case PGSTAT_MTYPE_BETERM:
1765 pgstat_recv_beterm((PgStat_MsgBeterm *) &msg, nread);
1768 case PGSTAT_MTYPE_TABSTAT:
1769 pgstat_recv_tabstat((PgStat_MsgTabstat *) &msg, nread);
1772 case PGSTAT_MTYPE_TABPURGE:
1773 pgstat_recv_tabpurge((PgStat_MsgTabpurge *) &msg, nread);
1776 case PGSTAT_MTYPE_ACTIVITY:
1777 pgstat_recv_activity((PgStat_MsgActivity *) &msg, nread);
1780 case PGSTAT_MTYPE_DROPDB:
1781 pgstat_recv_dropdb((PgStat_MsgDropdb *) &msg, nread);
1784 case PGSTAT_MTYPE_RESETCOUNTER:
1785 pgstat_recv_resetcounter((PgStat_MsgResetcounter *) &msg,
1794 * Globally count messages.
1796 pgStatNumMessages++;
1799 * If this is the first message after we wrote the stats file
1800 * the last time, setup the timeout that it'd be written.
1802 if (!need_statwrite)
1804 gettimeofday(&next_statwrite, NULL);
1805 next_statwrite.tv_usec += ((PGSTAT_STAT_INTERVAL) * 1000);
1806 next_statwrite.tv_sec += (next_statwrite.tv_usec / 1000000);
1807 next_statwrite.tv_usec %= 1000000;
1808 need_statwrite = TRUE;
1813 * Note that we do NOT check for postmaster exit inside the loop;
1814 * only EOF on the buffer pipe causes us to fall out. This
1815 * ensures we don't exit prematurely if there are still a few
1816 * messages in the buffer or pipe at postmaster shutdown.
1821 * Okay, we saw EOF on the buffer pipe, so there are no more messages
1822 * to process. If the buffer process quit because of postmaster
1823 * shutdown, we want to save the final stats to reuse at next startup.
1824 * But if the buffer process failed, it seems best not to (there may
1825 * even now be a new collector firing up, and we don't want it to read
1826 * a partially- rewritten stats file). We can tell whether the
1827 * postmaster is still alive by checking to see if the postmaster pipe
1828 * is still open. If it is read-ready (ie, EOF), the postmaster must
1832 FD_SET(pmPipe, &rfds);
1834 timeout.tv_usec = 0;
1835 nready = select(pmPipe+1,&rfds,NULL,NULL,&timeout);
1836 if (nready > 0 && FD_ISSET(pmPipe, &rfds))
1837 pgstat_write_statsfile();
1842 * pgstat_recvbuffer() -
1844 * This is the body of the separate buffering process. Its only
1845 * purpose is to receive messages from the UDP socket as fast as
1846 * possible and forward them over a pipe into the collector itself.
1847 * If the collector is slow to absorb messages, they are buffered here.
1851 pgstat_recvbuffer(void)
1855 int writePipe = pgStatPipe[1];
1856 int pmPipe = pgStatPmPipe[0];
1862 PgStat_Msg input_buffer;
1864 int msg_send = 0; /* next send index in buffer */
1865 int msg_recv = 0; /* next receive index */
1866 int msg_have = 0; /* number of bytes stored */
1867 bool overflow = false;
1870 * Identify myself via ps
1872 init_ps_display("stats buffer process", "", "");
1876 * We want to die if our child collector process does. There are two
1877 * ways we might notice that it has died: receive SIGCHLD, or get a
1878 * write failure on the pipe leading to the child. We can set SIGPIPE
1879 * to kill us here. Our SIGCHLD handler was already set up before we
1880 * forked (must do it that way, else it's a race condition).
1882 pqsignal(SIGPIPE, SIG_DFL);
1883 PG_SETMASK(&UnBlockSig);
1886 * Set the write pipe to nonblock mode, so that we cannot block when
1887 * the collector falls behind.
1889 if (!set_noblock(writePipe))
1892 (errcode_for_socket_access(),
1893 errmsg("could not set statistics collector pipe to nonblocking mode: %m")));
1898 * Allocate the message buffer
1900 msgbuffer = (char *) malloc(PGSTAT_RECVBUFFERSZ);
1901 if (msgbuffer == NULL)
1904 (errcode(ERRCODE_OUT_OF_MEMORY),
1905 errmsg("out of memory in statistics collector --- abort")));
1919 * As long as we have buffer space we add the socket to the read
1922 if (msg_have <= (int) (PGSTAT_RECVBUFFERSZ - sizeof(PgStat_Msg)))
1924 FD_SET(pgStatSock, &rfds);
1933 (errmsg("statistics buffer is full")));
1939 * If we have messages to write out, we add the pipe to the write
1940 * descriptor set. Otherwise, we check if the postmaster might
1945 FD_SET(writePipe, &wfds);
1946 if (writePipe > maxfd)
1951 FD_SET(pmPipe, &rfds);
1957 * Wait for some work to do.
1959 nready = select(maxfd + 1, &rfds, &wfds, NULL, NULL);
1965 (errcode_for_socket_access(),
1966 errmsg("select() failed in statistics buffer: %m")));
1971 * If there is a message on the socket, read it and check for
1974 if (FD_ISSET(pgStatSock, &rfds))
1976 len = recv(pgStatSock, (char *) &input_buffer,
1977 sizeof(PgStat_Msg), 0);
1981 (errcode_for_socket_access(),
1982 errmsg("could not read statistics message: %m")));
1987 * We ignore messages that are smaller than our common header
1989 if (len < sizeof(PgStat_MsgHdr))
1993 * The received length must match the length in the header
1995 if (input_buffer.msg_hdr.m_size != len)
1999 * O.K. - we accept this message. Copy it to the circular
2005 xfr = PGSTAT_RECVBUFFERSZ - msg_recv;
2009 memcpy(msgbuffer + msg_recv,
2010 ((char *) &input_buffer) + frm,
2013 if (msg_recv == PGSTAT_RECVBUFFERSZ)
2022 * If the collector is ready to receive, write some data into his
2023 * pipe. We may or may not be able to write all that we have.
2025 * NOTE: if what we have is less than PIPE_BUF bytes but more than
2026 * the space available in the pipe buffer, most kernels will
2027 * refuse to write any of it, and will return EAGAIN. This means
2028 * we will busy-loop until the situation changes (either because
2029 * the collector caught up, or because more data arrives so that
2030 * we have more than PIPE_BUF bytes buffered). This is not good,
2031 * but is there any way around it? We have no way to tell when
2032 * the collector has caught up...
2034 if (FD_ISSET(writePipe, &wfds))
2036 xfr = PGSTAT_RECVBUFFERSZ - msg_send;
2040 len = pipewrite(writePipe, msgbuffer + msg_send, xfr);
2043 if (errno == EINTR || errno == EAGAIN)
2044 continue; /* not enough space in pipe */
2046 (errcode_for_socket_access(),
2047 errmsg("could not write to statistics collector pipe: %m")));
2050 /* NB: len < xfr is okay */
2052 if (msg_send == PGSTAT_RECVBUFFERSZ)
2058 * Make sure we forwarded all messages before we check for
2059 * Postmaster termination.
2061 if (msg_have != 0 || FD_ISSET(pgStatSock, &rfds))
2065 * If the pipe from the postmaster is ready for reading, the
2066 * kernel must have closed it on exit() (the postmaster never
2067 * really writes to it). So we've done our job.
2069 if (FD_ISSET(pmPipe, &rfds))
2075 pgstat_die(SIGNAL_ARGS)
2082 * pgstat_add_backend() -
2084 * Support function to keep our backend list up to date.
2088 pgstat_add_backend(PgStat_MsgHdr *msg)
2090 PgStat_StatDBEntry *dbentry;
2091 PgStat_StatBeEntry *beentry;
2092 PgStat_StatBeDead *deadbe;
2096 * Check that the backend ID is valid
2098 if (msg->m_backendid < 1 || msg->m_backendid > MaxBackends)
2101 (errmsg("invalid server process ID %d", msg->m_backendid)));
2106 * Get the slot for this backendid.
2108 beentry = &pgStatBeTable[msg->m_backendid - 1];
2109 if (beentry->databaseid != InvalidOid)
2112 * If the slot contains the PID of this backend, everything is
2113 * fine and we got nothing to do.
2115 if (beentry->procpid == msg->m_procpid)
2120 * Lookup if this backend is known to be dead. This can be caused due
2121 * to messages arriving in the wrong order - i.e. Postmaster's BETERM
2122 * message might have arrived before we received all the backends
2123 * stats messages, or even a new backend with the same backendid was
2124 * faster in sending his BESTART.
2126 * If the backend is known to be dead, we ignore this add.
2128 deadbe = (PgStat_StatBeDead *) hash_search(pgStatBeDead,
2129 (void *) &(msg->m_procpid),
2135 * Backend isn't known to be dead. If it's slot is currently used, we
2136 * have to kick out the old backend.
2138 if (beentry->databaseid != InvalidOid)
2139 pgstat_sub_backend(beentry->procpid);
2142 * Put this new backend into the slot.
2144 beentry->databaseid = msg->m_databaseid;
2145 beentry->procpid = msg->m_procpid;
2146 beentry->userid = msg->m_userid;
2147 beentry->activity_start_sec = 0;
2148 beentry->activity_start_usec = 0;
2149 MemSet(beentry->activity, 0, PGSTAT_ACTIVITY_SIZE);
2152 * Lookup or create the database entry for this backends DB.
2154 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
2155 (void *) &(msg->m_databaseid),
2156 HASH_ENTER, &found);
2157 if (dbentry == NULL)
2160 (errcode(ERRCODE_OUT_OF_MEMORY),
2161 errmsg("out of memory in statistics collector --- abort")));
2166 * If not found, initialize the new one.
2172 dbentry->tables = NULL;
2173 dbentry->n_xact_commit = 0;
2174 dbentry->n_xact_rollback = 0;
2175 dbentry->n_blocks_fetched = 0;
2176 dbentry->n_blocks_hit = 0;
2177 dbentry->n_connects = 0;
2178 dbentry->destroy = 0;
2180 memset(&hash_ctl, 0, sizeof(hash_ctl));
2181 hash_ctl.keysize = sizeof(Oid);
2182 hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
2183 hash_ctl.hash = tag_hash;
2184 dbentry->tables = hash_create("Per-database table",
2185 PGSTAT_TAB_HASH_SIZE,
2187 HASH_ELEM | HASH_FUNCTION);
2188 if (dbentry->tables == NULL)
2190 /* assume the problem is out-of-memory */
2192 (errcode(ERRCODE_OUT_OF_MEMORY),
2193 errmsg("out of memory in statistics collector --- abort")));
2199 * Count number of connects to the database
2201 dbentry->n_connects++;
2208 * pgstat_sub_backend() -
2210 * Remove a backend from the actual backends list.
2214 pgstat_sub_backend(int procpid)
2217 PgStat_StatBeDead *deadbe;
2221 * Search in the known-backends table for the slot containing this
2224 for (i = 0; i < MaxBackends; i++)
2226 if (pgStatBeTable[i].databaseid != InvalidOid &&
2227 pgStatBeTable[i].procpid == procpid)
2230 * That's him. Add an entry to the known to be dead backends.
2231 * Due to possible misorder in the arrival of UDP packets it's
2232 * possible that even if we know the backend is dead, there
2233 * could still be messages queued that arrive later. Those
2234 * messages must not cause our number of backends statistics
2235 * to get screwed up, so we remember for a couple of seconds
2236 * that this PID is dead and ignore them (only the counting of
2237 * backends, not the table access stats they sent).
2239 deadbe = (PgStat_StatBeDead *) hash_search(pgStatBeDead,
2246 (errcode(ERRCODE_OUT_OF_MEMORY),
2247 errmsg("out of memory in statistics collector --- abort")));
2252 deadbe->backendid = i + 1;
2253 deadbe->destroy = PGSTAT_DESTROY_COUNT;
2257 * Declare the backend slot empty.
2259 pgStatBeTable[i].databaseid = InvalidOid;
2265 * No big problem if not found. This can happen if UDP messages arrive
2266 * out of order here.
2272 * pgstat_write_statsfile() -
2278 pgstat_write_statsfile(void)
2280 HASH_SEQ_STATUS hstat;
2281 HASH_SEQ_STATUS tstat;
2282 PgStat_StatDBEntry *dbentry;
2283 PgStat_StatTabEntry *tabentry;
2284 PgStat_StatBeDead *deadbe;
2289 * Open the statistics temp file to write out the current values.
2291 fpout = fopen(pgStat_tmpfname, PG_BINARY_W);
2295 (errcode_for_file_access(),
2296 errmsg("could not open temporary statistics file \"%s\": %m",
2302 * Walk through the database table.
2304 hash_seq_init(&hstat, pgStatDBHash);
2305 while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL)
2308 * If this database is marked destroyed, count down and do so if
2311 if (dbentry->destroy > 0)
2313 if (--(dbentry->destroy) == 0)
2315 if (dbentry->tables != NULL)
2316 hash_destroy(dbentry->tables);
2318 if (hash_search(pgStatDBHash,
2319 (void *) &(dbentry->databaseid),
2320 HASH_REMOVE, NULL) == NULL)
2323 (errmsg("database hash table corrupted "
2324 "during cleanup --- abort")));
2330 * Don't include statistics for it.
2336 * Write out the DB line including the number of life backends.
2339 fwrite(dbentry, sizeof(PgStat_StatDBEntry), 1, fpout);
2342 * Walk through the databases access stats per table.
2344 hash_seq_init(&tstat, dbentry->tables);
2345 while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&tstat)) != NULL)
2348 * If table entry marked for destruction, same as above for
2349 * the database entry.
2351 if (tabentry->destroy > 0)
2353 if (--(tabentry->destroy) == 0)
2355 if (hash_search(dbentry->tables,
2356 (void *) &(tabentry->tableid),
2357 HASH_REMOVE, NULL) == NULL)
2360 (errmsg("tables hash table for "
2361 "database %u corrupted during "
2362 "cleanup --- abort",
2363 dbentry->databaseid)));
2371 * At least we think this is still a life table. Print it's
2375 fwrite(tabentry, sizeof(PgStat_StatTabEntry), 1, fpout);
2379 * Mark the end of this DB
2385 * Write out the known running backends to the stats file.
2389 fwrite(&i, sizeof(i), 1, fpout);
2391 for (i = 0; i < MaxBackends; i++)
2393 if (pgStatBeTable[i].databaseid != InvalidOid)
2396 fwrite(&pgStatBeTable[i], sizeof(PgStat_StatBeEntry), 1, fpout);
2401 * No more output to be done. Close the temp file and replace the old
2402 * pgstat.stat with it.
2405 if (fclose(fpout) < 0)
2408 (errcode_for_file_access(),
2409 errmsg("could not close temporary statistics file \"%s\": %m",
2414 if (rename(pgStat_tmpfname, pgStat_fname) < 0)
2417 (errcode_for_file_access(),
2418 errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m",
2419 pgStat_tmpfname, pgStat_fname)));
2424 * Clear out the dead backends table
2426 hash_seq_init(&hstat, pgStatBeDead);
2427 while ((deadbe = (PgStat_StatBeDead *) hash_seq_search(&hstat)) != NULL)
2430 * Count down the destroy delay and remove entries where it
2433 if (--(deadbe->destroy) <= 0)
2435 if (hash_search(pgStatBeDead,
2436 (void *) &(deadbe->procpid),
2437 HASH_REMOVE, NULL) == NULL)
2440 (errmsg("dead-server-process hash table corrupted "
2441 "during cleanup --- abort")));
2450 * pgstat_read_statsfile() -
2452 * Reads in an existing statistics collector and initializes the
2453 * databases hash table (who's entries point to the tables hash tables)
2454 * and the current backend table.
2458 pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
2459 PgStat_StatBeEntry **betab, int *numbackends)
2461 PgStat_StatDBEntry *dbentry;
2462 PgStat_StatDBEntry dbbuf;
2463 PgStat_StatTabEntry *tabentry;
2464 PgStat_StatTabEntry tabbuf;
2466 HTAB *tabhash = NULL;
2468 int maxbackends = 0;
2469 int havebackends = 0;
2471 MemoryContext use_mcxt;
2475 * If running in the collector we use the DynaHashCxt memory context.
2476 * If running in a backend, we use the TopTransactionContext instead,
2477 * so the caller must only know the last XactId when this call
2478 * happened to know if his tables are still valid or already gone!
2480 if (pgStatRunningInCollector)
2487 use_mcxt = TopTransactionContext;
2488 mcxt_flags = HASH_CONTEXT;
2492 * Create the DB hashtable
2494 memset(&hash_ctl, 0, sizeof(hash_ctl));
2495 hash_ctl.keysize = sizeof(Oid);
2496 hash_ctl.entrysize = sizeof(PgStat_StatDBEntry);
2497 hash_ctl.hash = tag_hash;
2498 hash_ctl.hcxt = use_mcxt;
2499 *dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
2500 HASH_ELEM | HASH_FUNCTION | mcxt_flags);
2501 if (*dbhash == NULL)
2503 /* assume the problem is out-of-memory */
2504 if (pgStatRunningInCollector)
2507 (errcode(ERRCODE_OUT_OF_MEMORY),
2508 errmsg("out of memory in statistics collector --- abort")));
2511 /* in backend, can do normal error */
2513 (errcode(ERRCODE_OUT_OF_MEMORY),
2514 errmsg("out of memory")));
2518 * Initialize the number of known backends to zero, just in case we do
2519 * a silent error return below.
2521 if (numbackends != NULL)
2527 * In EXEC_BACKEND case, we won't have inherited pgStat_fname from
2528 * postmaster, so compute it first time through.
2531 if (pgStat_fname[0] == '\0')
2533 Assert(DataDir != NULL);
2534 snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
2539 * Try to open the status file. If it doesn't exist, the backends
2540 * simply return zero for anything and the collector simply starts
2541 * from scratch with empty counters.
2543 if ((fpin = fopen(pgStat_fname, PG_BINARY_R)) == NULL)
2547 * We found an existing collector stats file. Read it and put all the
2548 * hashtable entries into place.
2552 switch (fgetc(fpin))
2555 * 'D' A PgStat_StatDBEntry struct describing a database
2556 * follows. Subsequently, zero to many 'T' entries will
2557 * follow until a 'd' is encountered.
2560 if (fread(&dbbuf, 1, sizeof(dbbuf), fpin) != sizeof(dbbuf))
2562 ereport(pgStatRunningInCollector ? LOG : WARNING,
2563 (errmsg("corrupted pgstat.stat file")));
2569 * Add to the DB hash
2571 dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash,
2572 (void *) &dbbuf.databaseid,
2575 if (dbentry == NULL)
2577 if (pgStatRunningInCollector)
2580 (errcode(ERRCODE_OUT_OF_MEMORY),
2581 errmsg("out of memory in statistics collector --- abort")));
2588 (errcode(ERRCODE_OUT_OF_MEMORY),
2589 errmsg("out of memory")));
2594 ereport(pgStatRunningInCollector ? LOG : WARNING,
2595 (errmsg("corrupted pgstat.stat file")));
2600 memcpy(dbentry, &dbbuf, sizeof(PgStat_StatDBEntry));
2601 dbentry->tables = NULL;
2602 dbentry->destroy = 0;
2603 dbentry->n_backends = 0;
2606 * Don't collect tables if not the requested DB
2608 if (onlydb != InvalidOid && onlydb != dbbuf.databaseid)
2611 memset(&hash_ctl, 0, sizeof(hash_ctl));
2612 hash_ctl.keysize = sizeof(Oid);
2613 hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
2614 hash_ctl.hash = tag_hash;
2615 hash_ctl.hcxt = use_mcxt;
2616 dbentry->tables = hash_create("Per-database table",
2617 PGSTAT_TAB_HASH_SIZE,
2619 HASH_ELEM | HASH_FUNCTION | mcxt_flags);
2620 if (dbentry->tables == NULL)
2622 /* assume the problem is out-of-memory */
2623 if (pgStatRunningInCollector)
2626 (errcode(ERRCODE_OUT_OF_MEMORY),
2627 errmsg("out of memory in statistics collector --- abort")));
2630 /* in backend, can do normal error */
2633 (errcode(ERRCODE_OUT_OF_MEMORY),
2634 errmsg("out of memory")));
2638 * Arrange that following 'T's add entries to this
2639 * databases tables hash table.
2641 tabhash = dbentry->tables;
2645 * 'd' End of this database.
2652 * 'T' A PgStat_StatTabEntry follows.
2655 if (fread(&tabbuf, 1, sizeof(tabbuf), fpin) != sizeof(tabbuf))
2657 ereport(pgStatRunningInCollector ? LOG : WARNING,
2658 (errmsg("corrupted pgstat.stat file")));
2664 * Skip if table belongs to a not requested database.
2666 if (tabhash == NULL)
2669 tabentry = (PgStat_StatTabEntry *) hash_search(tabhash,
2670 (void *) &tabbuf.tableid,
2671 HASH_ENTER, &found);
2672 if (tabentry == NULL)
2674 if (pgStatRunningInCollector)
2677 (errcode(ERRCODE_OUT_OF_MEMORY),
2678 errmsg("out of memory in statistics collector --- abort")));
2681 /* in backend, can do normal error */
2684 (errcode(ERRCODE_OUT_OF_MEMORY),
2685 errmsg("out of memory")));
2690 ereport(pgStatRunningInCollector ? LOG : WARNING,
2691 (errmsg("corrupted pgstat.stat file")));
2696 memcpy(tabentry, &tabbuf, sizeof(tabbuf));
2700 * 'M' The maximum number of backends to expect follows.
2703 if (betab == NULL || numbackends == NULL)
2708 if (fread(&maxbackends, 1, sizeof(maxbackends), fpin) !=
2709 sizeof(maxbackends))
2711 ereport(pgStatRunningInCollector ? LOG : WARNING,
2712 (errmsg("corrupted pgstat.stat file")));
2716 if (maxbackends == 0)
2723 * Allocate space (in TopTransactionContext too) for the
2726 if (use_mcxt == NULL)
2727 *betab = (PgStat_StatBeEntry *) malloc(
2728 sizeof(PgStat_StatBeEntry) * maxbackends);
2730 *betab = (PgStat_StatBeEntry *) MemoryContextAlloc(
2732 sizeof(PgStat_StatBeEntry) * maxbackends);
2736 * 'B' A PgStat_StatBeEntry follows.
2739 if (betab == NULL || numbackends == NULL)
2751 * Read it directly into the table.
2753 if (fread(&(*betab)[havebackends], 1,
2754 sizeof(PgStat_StatBeEntry), fpin) !=
2755 sizeof(PgStat_StatBeEntry))
2757 ereport(pgStatRunningInCollector ? LOG : WARNING,
2758 (errmsg("corrupted pgstat.stat file")));
2764 * Count backends per database here.
2766 dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash,
2767 (void *) &((*betab)[havebackends].databaseid),
2770 dbentry->n_backends++;
2773 if (numbackends != 0)
2774 *numbackends = havebackends;
2775 if (havebackends >= maxbackends)
2783 * 'E' The EOF marker of a complete stats file.
2790 ereport(pgStatRunningInCollector ? LOG : WARNING,
2791 (errmsg("corrupted pgstat.stat file")));
2802 * pgstat_recv_bestart() -
2804 * Process a backend starup message.
2808 pgstat_recv_bestart(PgStat_MsgBestart *msg, int len)
2810 pgstat_add_backend(&msg->m_hdr);
2815 * pgstat_recv_beterm() -
2817 * Process a backend termination message.
2821 pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len)
2823 pgstat_sub_backend(msg->m_hdr.m_procpid);
2828 * pgstat_recv_activity() -
2830 * Remember what the backend is doing.
2834 pgstat_recv_activity(PgStat_MsgActivity *msg, int len)
2836 PgStat_StatBeEntry *entry;
2839 * Here we check explicitly for 0 return, since we don't want to
2840 * mangle the activity of an active backend by a delayed packed from a
2843 if (pgstat_add_backend(&msg->m_hdr) != 0)
2846 entry = &(pgStatBeTable[msg->m_hdr.m_backendid - 1]);
2848 strncpy(entry->activity, msg->m_what, PGSTAT_ACTIVITY_SIZE);
2850 entry->activity_start_sec =
2851 GetCurrentAbsoluteTimeUsec(&entry->activity_start_usec);
2856 * pgstat_recv_tabstat() -
2858 * Count what the backend has done.
2862 pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
2864 PgStat_TableEntry *tabmsg = &(msg->m_entry[0]);
2865 PgStat_StatDBEntry *dbentry;
2866 PgStat_StatTabEntry *tabentry;
2871 * Make sure the backend is counted for.
2873 if (pgstat_add_backend(&msg->m_hdr) < 0)
2877 * Lookup the database in the hashtable.
2879 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
2880 (void *) &(msg->m_hdr.m_databaseid),
2886 * If the database is marked for destroy, this is a delayed UDP packet
2887 * and not worth being counted.
2889 if (dbentry->destroy > 0)
2892 dbentry->n_xact_commit += (PgStat_Counter) (msg->m_xact_commit);
2893 dbentry->n_xact_rollback += (PgStat_Counter) (msg->m_xact_rollback);
2896 * Process all table entries in the message.
2898 for (i = 0; i < msg->m_nentries; i++)
2900 tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
2901 (void *) &(tabmsg[i].t_id),
2902 HASH_ENTER, &found);
2903 if (tabentry == NULL)
2906 (errcode(ERRCODE_OUT_OF_MEMORY),
2907 errmsg("out of memory in statistics collector --- abort")));
2914 * If it's a new table entry, initialize counters to the
2915 * values we just got.
2917 tabentry->numscans = tabmsg[i].t_numscans;
2918 tabentry->tuples_returned = tabmsg[i].t_tuples_returned;
2919 tabentry->tuples_fetched = tabmsg[i].t_tuples_fetched;
2920 tabentry->tuples_inserted = tabmsg[i].t_tuples_inserted;
2921 tabentry->tuples_updated = tabmsg[i].t_tuples_updated;
2922 tabentry->tuples_deleted = tabmsg[i].t_tuples_deleted;
2923 tabentry->blocks_fetched = tabmsg[i].t_blocks_fetched;
2924 tabentry->blocks_hit = tabmsg[i].t_blocks_hit;
2926 tabentry->destroy = 0;
2931 * Otherwise add the values to the existing entry.
2933 tabentry->numscans += tabmsg[i].t_numscans;
2934 tabentry->tuples_returned += tabmsg[i].t_tuples_returned;
2935 tabentry->tuples_fetched += tabmsg[i].t_tuples_fetched;
2936 tabentry->tuples_inserted += tabmsg[i].t_tuples_inserted;
2937 tabentry->tuples_updated += tabmsg[i].t_tuples_updated;
2938 tabentry->tuples_deleted += tabmsg[i].t_tuples_deleted;
2939 tabentry->blocks_fetched += tabmsg[i].t_blocks_fetched;
2940 tabentry->blocks_hit += tabmsg[i].t_blocks_hit;
2944 * And add the block IO to the database entry.
2946 dbentry->n_blocks_fetched += tabmsg[i].t_blocks_fetched;
2947 dbentry->n_blocks_hit += tabmsg[i].t_blocks_hit;
2953 * pgstat_recv_tabpurge() -
2955 * Arrange for dead table removal.
2959 pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len)
2961 PgStat_StatDBEntry *dbentry;
2962 PgStat_StatTabEntry *tabentry;
2966 * Make sure the backend is counted for.
2968 if (pgstat_add_backend(&msg->m_hdr) < 0)
2972 * Lookup the database in the hashtable.
2974 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
2975 (void *) &(msg->m_hdr.m_databaseid),
2981 * If the database is marked for destroy, this is a delayed UDP packet
2982 * and the tables will go away at DB destruction.
2984 if (dbentry->destroy > 0)
2988 * Process all table entries in the message.
2990 for (i = 0; i < msg->m_nentries; i++)
2992 tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
2993 (void *) &(msg->m_tableid[i]),
2996 tabentry->destroy = PGSTAT_DESTROY_COUNT;
3002 * pgstat_recv_dropdb() -
3004 * Arrange for dead database removal
3008 pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len)
3010 PgStat_StatDBEntry *dbentry;
3013 * Make sure the backend is counted for.
3015 if (pgstat_add_backend(&msg->m_hdr) < 0)
3019 * Lookup the database in the hashtable.
3021 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
3022 (void *) &(msg->m_databaseid),
3028 * Mark the database for destruction.
3030 dbentry->destroy = PGSTAT_DESTROY_COUNT;
3035 * pgstat_recv_dropdb() -
3037 * Arrange for dead database removal
3041 pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
3044 PgStat_StatDBEntry *dbentry;
3047 * Make sure the backend is counted for.
3049 if (pgstat_add_backend(&msg->m_hdr) < 0)
3053 * Lookup the database in the hashtable.
3055 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
3056 (void *) &(msg->m_hdr.m_databaseid),
3062 * We simply throw away all the databases table entries by recreating
3063 * a new hash table for them.
3065 if (dbentry->tables != NULL)
3066 hash_destroy(dbentry->tables);
3068 dbentry->tables = NULL;
3069 dbentry->n_xact_commit = 0;
3070 dbentry->n_xact_rollback = 0;
3071 dbentry->n_blocks_fetched = 0;
3072 dbentry->n_blocks_hit = 0;
3073 dbentry->n_connects = 0;
3074 dbentry->destroy = 0;
3076 memset(&hash_ctl, 0, sizeof(hash_ctl));
3077 hash_ctl.keysize = sizeof(Oid);
3078 hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
3079 hash_ctl.hash = tag_hash;
3080 dbentry->tables = hash_create("Per-database table",
3081 PGSTAT_TAB_HASH_SIZE,
3083 HASH_ELEM | HASH_FUNCTION);
3084 if (dbentry->tables == NULL)
3086 /* assume the problem is out-of-memory */
3088 (errcode(ERRCODE_OUT_OF_MEMORY),
3089 errmsg("out of memory in statistics collector --- abort")));