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 base.
14 * Copyright (c) 2001-2003, PostgreSQL Global Development Group
16 * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.71 2004/05/24 02:47:47 momjian 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"
55 #include "utils/guc.h"
59 extern pid_t win32_forkexec(const char* path, char *argv[]);
66 bool pgstat_collect_startcollector = true;
67 bool pgstat_collect_resetonpmstart = true;
68 bool pgstat_collect_querystring = false;
69 bool pgstat_collect_tuplelevel = false;
70 bool pgstat_collect_blocklevel = false;
73 * Other global variables
76 bool pgstat_is_running = false;
82 NON_EXEC_STATIC int pgStatSock = -1;
83 static int pgStatPipe[2];
84 static struct sockaddr_storage pgStatAddr;
85 static int pgStatPmPipe[2] = {-1, -1};
86 static int pgStatCollectorPmPipe[2] = {-1, -1};
89 static time_t last_pgstat_start_time;
91 static long pgStatNumMessages = 0;
93 static bool pgStatRunningInCollector = FALSE;
95 static int pgStatTabstatAlloc = 0;
96 static int pgStatTabstatUsed = 0;
97 static PgStat_MsgTabstat **pgStatTabstatMessages = NULL;
99 #define TABSTAT_QUANTUM 4 /* we alloc this many at a time */
101 static int pgStatXactCommit = 0;
102 static int pgStatXactRollback = 0;
104 static TransactionId pgStatDBHashXact = InvalidTransactionId;
105 static HTAB *pgStatDBHash = NULL;
106 static HTAB *pgStatBeDead = NULL;
107 static PgStat_StatBeEntry *pgStatBeTable = NULL;
108 static int pgStatNumBackends = 0;
110 static char pgStat_tmpfname[MAXPGPATH];
111 static char pgStat_fname[MAXPGPATH];
115 * Local function forward declarations
119 static pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType);
120 static void pgstat_parseArgs(PGSTAT_FORK_ARGS);
122 NON_EXEC_STATIC void pgstat_main(PGSTAT_FORK_ARGS);
123 NON_EXEC_STATIC void pgstat_mainChild(PGSTAT_FORK_ARGS);
124 static void pgstat_mainInit(void);
125 static void pgstat_recvbuffer(void);
126 static void pgstat_die(SIGNAL_ARGS);
128 static int pgstat_add_backend(PgStat_MsgHdr *msg);
129 static void pgstat_sub_backend(int procpid);
130 static void pgstat_drop_database(Oid databaseid);
131 static void pgstat_write_statsfile(void);
132 static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
133 PgStat_StatBeEntry **betab,
136 static void pgstat_setheader(PgStat_MsgHdr *hdr, int mtype);
137 static void pgstat_send(void *msg, int len);
139 static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
140 static void pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len);
141 static void pgstat_recv_activity(PgStat_MsgActivity *msg, int len);
142 static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len);
143 static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);
144 static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);
145 static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
148 /* ------------------------------------------------------------
149 * Public functions called from postmaster follow
150 * ------------------------------------------------------------
156 pgstat_init_forkexec_backend(void)
158 Assert(DataDir != NULL);
159 snprintf(pgStat_fname, MAXPGPATH,
160 PGSTAT_STAT_FILENAME, DataDir);
168 * Called from postmaster at startup. Create the resources required
169 * by the statistics collector process. If unable to do so, do not
170 * fail --- better to let the postmaster start with stats collection
177 ACCEPT_TYPE_ARG3 alen;
178 struct addrinfo *addrs = NULL,
187 #define TESTBYTEVAL ((char) 199)
190 * Force start of collector daemon if something to collect
192 if (pgstat_collect_querystring ||
193 pgstat_collect_tuplelevel ||
194 pgstat_collect_blocklevel)
195 pgstat_collect_startcollector = true;
198 * Initialize the filenames for the status reports.
200 snprintf(pgStat_tmpfname, MAXPGPATH,
201 PGSTAT_STAT_TMPFILE, DataDir, getpid());
202 snprintf(pgStat_fname, MAXPGPATH,
203 PGSTAT_STAT_FILENAME, DataDir);
206 * If we don't have to start a collector or should reset the collected
207 * statistics on postmaster start, simply remove the file.
209 if (!pgstat_collect_startcollector || pgstat_collect_resetonpmstart)
210 unlink(pgStat_fname);
213 * Nothing else required if collector will not get started
215 if (!pgstat_collect_startcollector)
219 * Create the UDP socket for sending and receiving statistic messages
221 hints.ai_flags = AI_PASSIVE;
222 hints.ai_family = PF_UNSPEC;
223 hints.ai_socktype = SOCK_DGRAM;
224 hints.ai_protocol = 0;
225 hints.ai_addrlen = 0;
226 hints.ai_addr = NULL;
227 hints.ai_canonname = NULL;
228 hints.ai_next = NULL;
229 ret = getaddrinfo_all("localhost", NULL, &hints, &addrs);
233 (errmsg("could not resolve \"localhost\": %s",
234 gai_strerror(ret))));
239 * On some platforms, getaddrinfo_all() may return multiple addresses
240 * only one of which will actually work (eg, both IPv6 and IPv4 addresses
241 * when kernel will reject IPv6). Worse, the failure may occur at the
242 * bind() or perhaps even connect() stage. So we must loop through the
243 * results till we find a working combination. We will generate LOG
244 * messages, but no error, for bogus combinations.
246 for (addr = addrs; addr; addr = addr->ai_next)
248 #ifdef HAVE_UNIX_SOCKETS
249 /* Ignore AF_UNIX sockets, if any are returned. */
250 if (addr->ai_family == AF_UNIX)
256 if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) < 0)
259 (errcode_for_socket_access(),
260 errmsg("could not create socket for statistics collector: %m")));
265 * Bind it to a kernel assigned port on localhost and get the assigned
266 * port via getsockname().
268 if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
271 (errcode_for_socket_access(),
272 errmsg("could not bind socket for statistics collector: %m")));
273 closesocket(pgStatSock);
278 alen = sizeof(pgStatAddr);
279 if (getsockname(pgStatSock, (struct sockaddr *) &pgStatAddr, &alen) < 0)
282 (errcode_for_socket_access(),
283 errmsg("could not get address of socket for statistics collector: %m")));
284 closesocket(pgStatSock);
290 * Connect the socket to its own address. This saves a few cycles by
291 * not having to respecify the target address on every send. This also
292 * provides a kernel-level check that only packets from this same
293 * address will be received.
295 if (connect(pgStatSock, (struct sockaddr *) &pgStatAddr, alen) < 0)
298 (errcode_for_socket_access(),
299 errmsg("could not connect socket for statistics collector: %m")));
300 closesocket(pgStatSock);
306 * Try to send and receive a one-byte test message on the socket.
307 * This is to catch situations where the socket can be created but
308 * will not actually pass data (for instance, because kernel packet
309 * filtering rules prevent it).
311 test_byte = TESTBYTEVAL;
312 if (send(pgStatSock, &test_byte, 1, 0) != 1)
315 (errcode_for_socket_access(),
316 errmsg("could not send test message on socket for statistics collector: %m")));
317 closesocket(pgStatSock);
323 * There could possibly be a little delay before the message can be
324 * received. We arbitrarily allow up to half a second before deciding
327 for (;;) /* need a loop to handle EINTR */
330 FD_SET(pgStatSock, &rset);
333 sel_res = select(pgStatSock+1, &rset, NULL, NULL, &tv);
334 if (sel_res >= 0 || errno != EINTR)
340 (errcode_for_socket_access(),
341 errmsg("select() failed in statistics collector: %m")));
342 closesocket(pgStatSock);
346 if (sel_res == 0 || !FD_ISSET(pgStatSock, &rset))
349 * This is the case we actually think is likely, so take pains to
350 * give a specific message for it.
352 * errno will not be set meaningfully here, so don't use it.
355 (ERRCODE_CONNECTION_FAILURE,
356 errmsg("test message did not get through on socket for statistics collector")));
357 closesocket(pgStatSock);
362 test_byte++; /* just make sure variable is changed */
364 if (recv(pgStatSock, &test_byte, 1, 0) != 1)
367 (errcode_for_socket_access(),
368 errmsg("could not receive test message on socket for statistics collector: %m")));
369 closesocket(pgStatSock);
374 if (test_byte != TESTBYTEVAL) /* strictly paranoia ... */
377 (ERRCODE_INTERNAL_ERROR,
378 errmsg("incorrect test message transmission on socket for statistics collector")));
379 closesocket(pgStatSock);
384 /* If we get here, we have a working socket */
388 /* Did we find a working address? */
389 if (!addr || pgStatSock < 0)
392 (errcode_for_socket_access(),
393 errmsg("disabling statistics collector for lack of working socket")));
398 * Set the socket to non-blocking IO. This ensures that if the
399 * collector falls behind (despite the buffering process), statistics
400 * messages will be discarded; backends won't block waiting to send
401 * messages to the collector.
403 if (!set_noblock(pgStatSock))
406 (errcode_for_socket_access(),
407 errmsg("could not set statistics collector socket to nonblocking mode: %m")));
412 * Create the pipe that controls the statistics collector shutdown
414 if (pgpipe(pgStatPmPipe) < 0 || pgpipe(pgStatCollectorPmPipe) < 0)
417 (errcode_for_socket_access(),
418 errmsg("could not create pipe for statistics collector: %m")));
422 freeaddrinfo_all(hints.ai_family, addrs);
428 freeaddrinfo_all(hints.ai_family, addrs);
431 closesocket(pgStatSock);
434 /* Adjust GUC variables to suppress useless activity */
435 pgstat_collect_startcollector = false;
436 pgstat_collect_querystring = false;
437 pgstat_collect_tuplelevel = false;
438 pgstat_collect_blocklevel = false;
445 * pgstat_forkexec() -
447 * Used to format up the arglist for, then fork and exec, statistics
448 * (buffer and collector) processes
452 pgstat_forkexec(STATS_PROCESS_TYPE procType)
456 int ac = 0, bufc = 0, i;
457 char pgstatBuf[12][MAXPGPATH];
459 av[ac++] = "postgres";
462 case STAT_PROC_BUFFER:
463 av[ac++] = "-statBuf";
466 case STAT_PROC_COLLECTOR:
467 av[ac++] = "-statCol";
474 /* Sockets + pipes */
476 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatSock);
477 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[0]);
478 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[1]);
479 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[0]);
480 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[1]);
481 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[0]);
482 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[1]);
485 snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",MaxBackends);
487 /* + the pstat file names, and postgres pathname */
488 snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_tmpfname);
489 snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_fname);
490 snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",postgres_exec_path);
491 snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",DataDir);
493 /* Add to the arg list */
494 Assert(bufc <= lengthof(pgstatBuf));
495 for (i = 0; i < bufc; i++)
496 av[ac++] = pgstatBuf[i];
499 Assert(ac <= lengthof(av));
501 /* Fire off execv in child */
503 pid = win32_forkexec(postgres_exec_path, av);
505 if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
506 /* FIXME: [fork/exec] suggestions for what to do here? Can't call elog... */
509 return pid; /* Parent returns pid */
514 * pgstat_parseArgs() -
516 * Used to unformat the arglist for exec'ed statistics
517 * (buffer and collector) processes
521 pgstat_parseArgs(PGSTAT_FORK_ARGS)
525 if (find_my_exec(argv[0], my_exec_path) < 0)
527 gettext("%s: could not locate my own executable path"),
530 get_pkglib_path(my_exec_path, pkglib_path);
533 pgStatSock = atoi(argv[argc++]);
534 pgStatPmPipe[0] = atoi(argv[argc++]);
535 pgStatPmPipe[1] = atoi(argv[argc++]);
536 pgStatCollectorPmPipe[0] = atoi(argv[argc++]);
537 pgStatCollectorPmPipe[1] = atoi(argv[argc++]);
538 pgStatPipe[0] = atoi(argv[argc++]);
539 pgStatPipe[1] = atoi(argv[argc++]);
540 MaxBackends = atoi(argv[argc++]);
541 StrNCpy(pgStat_tmpfname,argv[argc++],MAXPGPATH);
542 StrNCpy(pgStat_fname, argv[argc++],MAXPGPATH);
543 StrNCpy(postgres_exec_path, argv[argc++],MAXPGPATH);
544 DataDir = strdup(argv[argc++]);
546 read_nondefault_variables();
554 * Called from postmaster at startup or after an existing collector
555 * died. Attempt to fire up a fresh statistics collector.
557 * Note: if fail, we will be called again from the postmaster main loop.
566 * Do nothing if no collector needed
568 if (pgstat_is_running || !pgstat_collect_startcollector)
572 * Do nothing if too soon since last collector start. This is a
573 * safety valve to protect against continuous respawn attempts if the
574 * collector is dying immediately at launch. Note that since we will
575 * be re-called from the postmaster main loop, we will get another
578 curtime = time(NULL);
579 if ((unsigned int) (curtime - last_pgstat_start_time) <
580 (unsigned int) PGSTAT_RESTART_INTERVAL)
582 last_pgstat_start_time = curtime;
585 * Check that the socket is there, else pgstat_init failed.
590 (errmsg("statistics collector startup skipped")));
593 * We can only get here if someone tries to manually turn
594 * pgstat_collect_startcollector on after it had been off.
596 pgstat_collect_startcollector = false;
601 * Okay, fork off the collector. Remember its PID for
609 /* Specific beos actions before backend startup */
610 beos_before_backend_startup();
614 switch ((pgStatPid = (int) pgstat_forkexec(STAT_PROC_BUFFER)))
616 switch ((pgStatPid = (int) fork()))
621 /* Specific beos actions */
622 beos_backend_startup_failed();
625 (errmsg("could not fork statistics buffer: %m")));
630 /* in postmaster child ... */
632 /* Specific beos actions after backend startup */
633 beos_backend_startup();
635 /* Close the postmaster's sockets, except for pgstat link */
636 ClosePostmasterPorts(false);
638 /* Drop our connection to postmaster's shared memory, as well */
639 PGSharedMemoryDetach();
646 pgstat_is_running = true;
653 * pgstat_ispgstat() -
655 * Called from postmaster to check if a terminated child process
656 * was the statistics collector.
660 pgstat_ispgstat(int pid)
662 if (!pgstat_is_running)
665 if (pgStatPid != pid)
669 pgstat_is_running = false;
676 * pgstat_close_sockets() -
678 * Called when postmaster forks a non-pgstat child process, to close off
679 * file descriptors that should not be held open in child processes.
683 pgstat_close_sockets(void)
685 if (pgStatPmPipe[0] >= 0)
686 closesocket(pgStatPmPipe[0]);
687 pgStatPmPipe[0] = -1;
688 if (pgStatPmPipe[1] >= 0)
689 closesocket(pgStatPmPipe[1]);
690 pgStatPmPipe[1] = -1;
691 if (pgStatCollectorPmPipe[0] >= 0)
692 closesocket(pgStatCollectorPmPipe[0]);
693 pgStatCollectorPmPipe[0] = -1;
694 if (pgStatCollectorPmPipe[1] >= 0)
695 closesocket(pgStatCollectorPmPipe[1]);
696 pgStatCollectorPmPipe[1] = -1;
703 * Called from postmaster to tell collector a backend terminated.
707 pgstat_beterm(int pid)
709 PgStat_MsgBeterm msg;
714 MemSet(&(msg.m_hdr), 0, sizeof(msg.m_hdr));
715 msg.m_hdr.m_type = PGSTAT_MTYPE_BETERM;
716 msg.m_hdr.m_procpid = pid;
718 pgstat_send(&msg, sizeof(msg));
722 /* ------------------------------------------------------------
723 * Public functions used by backends follow
724 *------------------------------------------------------------
731 * Tell the collector that this new backend is soon ready to process
732 * queries. Called from tcop/postgres.c before entering the mainloop.
738 PgStat_MsgBestart msg;
743 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);
744 pgstat_send(&msg, sizeof(msg));
749 * pgstat_report_activity() -
751 * Called in tcop/postgres.c to tell the collector what the backend
752 * is actually doing (usually "<IDLE>" or the start of the query to
757 pgstat_report_activity(const char *what)
759 PgStat_MsgActivity msg;
762 if (!pgstat_collect_querystring || pgStatSock < 0)
766 len = pg_mbcliplen((const unsigned char *) what, len,
767 PGSTAT_ACTIVITY_SIZE - 1);
769 memcpy(msg.m_what, what, len);
770 msg.m_what[len] = '\0';
771 len += offsetof(PgStat_MsgActivity, m_what) +1;
773 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ACTIVITY);
774 pgstat_send(&msg, len);
779 * pgstat_report_tabstat() -
781 * Called from tcop/postgres.c to send the so far collected
782 * per table access statistics to the collector.
786 pgstat_report_tabstat(void)
790 if (pgStatSock < 0 ||
791 !(pgstat_collect_querystring ||
792 pgstat_collect_tuplelevel ||
793 pgstat_collect_blocklevel))
795 /* Not reporting stats, so just flush whatever we have */
796 pgStatTabstatUsed = 0;
801 * For each message buffer used during the last query set the header
802 * fields and send it out.
804 for (i = 0; i < pgStatTabstatUsed; i++)
806 PgStat_MsgTabstat *tsmsg = pgStatTabstatMessages[i];
810 n = tsmsg->m_nentries;
811 len = offsetof(PgStat_MsgTabstat, m_entry[0]) +
812 n * sizeof(PgStat_TableEntry);
814 tsmsg->m_xact_commit = pgStatXactCommit;
815 tsmsg->m_xact_rollback = pgStatXactRollback;
816 pgStatXactCommit = 0;
817 pgStatXactRollback = 0;
819 pgstat_setheader(&tsmsg->m_hdr, PGSTAT_MTYPE_TABSTAT);
820 pgstat_send(tsmsg, len);
823 pgStatTabstatUsed = 0;
828 * pgstat_vacuum_tabstat() -
830 * Will tell the collector about objects he can get rid of.
834 pgstat_vacuum_tabstat(void)
842 HASH_SEQ_STATUS hstat;
843 PgStat_StatDBEntry *dbentry;
844 PgStat_StatTabEntry *tabentry;
847 PgStat_MsgTabpurge msg;
855 * If not done for this transaction, read the statistics collector
856 * stats file into some hash tables.
858 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
860 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
861 &pgStatBeTable, &pgStatNumBackends);
862 pgStatDBHashXact = GetCurrentTransactionId();
866 * Lookup our own database entry
868 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
869 (void *) &MyDatabaseId,
874 if (dbentry->tables == NULL)
878 * Initialize our messages table counter to zero
883 * Check for all tables if they still exist.
885 hash_seq_init(&hstat, dbentry->tables);
886 while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&hstat)) != NULL)
889 * Check if this relation is still alive by looking up it's
890 * pg_class tuple in the system catalog cache.
892 reltup = SearchSysCache(RELOID,
893 ObjectIdGetDatum(tabentry->tableid),
895 if (HeapTupleIsValid(reltup))
897 ReleaseSysCache(reltup);
902 * Add this tables Oid to the message
904 msg.m_tableid[msg.m_nentries++] = tabentry->tableid;
908 * If the message is full, send it out and reinitialize ot zero
910 if (msg.m_nentries >= PGSTAT_NUM_TABPURGE)
912 len = offsetof(PgStat_MsgTabpurge, m_tableid[0])
913 +msg.m_nentries * sizeof(Oid);
915 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE);
916 pgstat_send(&msg, len);
925 if (msg.m_nentries > 0)
927 len = offsetof(PgStat_MsgTabpurge, m_tableid[0])
928 +msg.m_nentries * sizeof(Oid);
930 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE);
931 pgstat_send(&msg, len);
935 * Read pg_database and remember the Oid's of all existing databases
939 dbidlist = (Oid *) palloc(sizeof(Oid) * dbidalloc);
941 dbrel = heap_openr(DatabaseRelationName, AccessShareLock);
942 dbscan = heap_beginscan(dbrel, SnapshotNow, 0, NULL);
943 while ((dbtup = heap_getnext(dbscan, ForwardScanDirection)) != NULL)
945 if (dbidused >= dbidalloc)
948 dbidlist = (Oid *) repalloc((char *) dbidlist,
949 sizeof(Oid) * dbidalloc);
951 dbidlist[dbidused++] = HeapTupleGetOid(dbtup);
953 heap_endscan(dbscan);
954 heap_close(dbrel, AccessShareLock);
957 * Search the database hash table for dead databases and tell the
958 * collector to drop them as well.
960 hash_seq_init(&hstat, pgStatDBHash);
961 while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL)
963 Oid dbid = dbentry->databaseid;
965 for (i = 0; i < dbidused; i++)
967 if (dbidlist[i] == dbid)
974 if (dbid != InvalidOid)
977 pgstat_drop_database(dbid);
982 * Free the dbid list.
984 pfree((char *) dbidlist);
987 * Tell the caller how many removeable objects we found
994 * pgstat_drop_database() -
996 * Tell the collector that we just dropped a database.
997 * This is the only message that shouldn't get lost in space. Otherwise
998 * the collector will keep the statistics for the dead DB until his
999 * stats file got removed while the postmaster is down.
1003 pgstat_drop_database(Oid databaseid)
1005 PgStat_MsgDropdb msg;
1010 msg.m_databaseid = databaseid;
1012 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DROPDB);
1013 pgstat_send(&msg, sizeof(msg));
1018 * pgstat_reset_counters() -
1020 * Tell the statistics collector to reset counters for our database.
1024 pgstat_reset_counters(void)
1026 PgStat_MsgResetcounter msg;
1033 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1034 errmsg("must be superuser to reset statistics counters")));
1036 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER);
1037 pgstat_send(&msg, sizeof(msg));
1044 * Send some junk data to the collector to increase traffic.
1050 PgStat_MsgDummy msg;
1055 pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DUMMY);
1056 pgstat_send(&msg, sizeof(msg));
1060 * Create or enlarge the pgStatTabstatMessages array
1063 more_tabstat_space(void)
1065 PgStat_MsgTabstat *newMessages;
1066 PgStat_MsgTabstat **msgArray;
1067 int newAlloc = pgStatTabstatAlloc + TABSTAT_QUANTUM;
1070 /* Create (another) quantum of message buffers */
1071 newMessages = (PgStat_MsgTabstat *)
1072 malloc(sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
1073 if (newMessages == NULL)
1076 (errcode(ERRCODE_OUT_OF_MEMORY),
1077 errmsg("out of memory")));
1081 /* Create or enlarge the pointer array */
1082 if (pgStatTabstatMessages == NULL)
1083 msgArray = (PgStat_MsgTabstat **)
1084 malloc(sizeof(PgStat_MsgTabstat *) * newAlloc);
1086 msgArray = (PgStat_MsgTabstat **)
1087 realloc(pgStatTabstatMessages,
1088 sizeof(PgStat_MsgTabstat *) * newAlloc);
1089 if (msgArray == NULL)
1093 (errcode(ERRCODE_OUT_OF_MEMORY),
1094 errmsg("out of memory")));
1098 MemSet(newMessages, 0, sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
1099 for (i = 0; i < TABSTAT_QUANTUM; i++)
1100 msgArray[pgStatTabstatAlloc + i] = newMessages++;
1101 pgStatTabstatMessages = msgArray;
1102 pgStatTabstatAlloc = newAlloc;
1108 * pgstat_initstats() -
1110 * Called from various places usually dealing with initialization
1111 * of Relation or Scan structures. The data placed into these
1112 * structures from here tell where later to count for buffer reads,
1113 * scans and tuples fetched.
1117 pgstat_initstats(PgStat_Info *stats, Relation rel)
1119 Oid rel_id = rel->rd_id;
1120 PgStat_TableEntry *useent;
1121 PgStat_MsgTabstat *tsmsg;
1126 * Initialize data not to count at all.
1128 stats->tabentry = NULL;
1129 stats->no_stats = FALSE;
1130 stats->heap_scan_counted = FALSE;
1131 stats->index_scan_counted = FALSE;
1133 if (pgStatSock < 0 ||
1134 !(pgstat_collect_tuplelevel ||
1135 pgstat_collect_blocklevel))
1137 stats->no_stats = TRUE;
1142 * Search the already-used message slots for this relation.
1144 for (mb = 0; mb < pgStatTabstatUsed; mb++)
1146 tsmsg = pgStatTabstatMessages[mb];
1148 for (i = tsmsg->m_nentries; --i >= 0; )
1150 if (tsmsg->m_entry[i].t_id == rel_id)
1152 stats->tabentry = (void *) &(tsmsg->m_entry[i]);
1157 if (tsmsg->m_nentries >= PGSTAT_NUM_TABENTRIES)
1161 * Not found, but found a message buffer with an empty slot
1162 * instead. Fine, let's use this one.
1164 i = tsmsg->m_nentries++;
1165 useent = &tsmsg->m_entry[i];
1166 MemSet(useent, 0, sizeof(PgStat_TableEntry));
1167 useent->t_id = rel_id;
1168 stats->tabentry = (void *) useent;
1173 * If we ran out of message buffers, we just allocate more.
1175 if (pgStatTabstatUsed >= pgStatTabstatAlloc)
1177 if (!more_tabstat_space())
1179 stats->no_stats = TRUE;
1182 Assert(pgStatTabstatUsed < pgStatTabstatAlloc);
1186 * Use the first entry of the next message buffer.
1188 mb = pgStatTabstatUsed++;
1189 tsmsg = pgStatTabstatMessages[mb];
1190 tsmsg->m_nentries = 1;
1191 useent = &tsmsg->m_entry[0];
1192 MemSet(useent, 0, sizeof(PgStat_TableEntry));
1193 useent->t_id = rel_id;
1194 stats->tabentry = (void *) useent;
1199 * pgstat_count_xact_commit() -
1201 * Called from access/transam/xact.c to count transaction commits.
1205 pgstat_count_xact_commit(void)
1207 if (!(pgstat_collect_querystring ||
1208 pgstat_collect_tuplelevel ||
1209 pgstat_collect_blocklevel))
1215 * If there was no relation activity yet, just make one existing
1216 * message buffer used without slots, causing the next report to tell
1217 * new xact-counters.
1219 if (pgStatTabstatAlloc == 0)
1221 if (!more_tabstat_space())
1224 if (pgStatTabstatUsed == 0)
1226 pgStatTabstatUsed++;
1227 pgStatTabstatMessages[0]->m_nentries = 0;
1233 * pgstat_count_xact_rollback() -
1235 * Called from access/transam/xact.c to count transaction rollbacks.
1239 pgstat_count_xact_rollback(void)
1241 if (!(pgstat_collect_querystring ||
1242 pgstat_collect_tuplelevel ||
1243 pgstat_collect_blocklevel))
1246 pgStatXactRollback++;
1249 * If there was no relation activity yet, just make one existing
1250 * message buffer used without slots, causing the next report to tell
1251 * new xact-counters.
1253 if (pgStatTabstatAlloc == 0)
1255 if (!more_tabstat_space())
1258 if (pgStatTabstatUsed == 0)
1260 pgStatTabstatUsed++;
1261 pgStatTabstatMessages[0]->m_nentries = 0;
1267 * pgstat_fetch_stat_dbentry() -
1269 * Support function for the SQL-callable pgstat* functions. Returns
1270 * the collected statistics for one database or NULL. NULL doesn't mean
1271 * that the database doesn't exist, it is just not yet known by the
1272 * collector, so the caller is better off to report ZERO instead.
1275 PgStat_StatDBEntry *
1276 pgstat_fetch_stat_dbentry(Oid dbid)
1278 PgStat_StatDBEntry *dbentry;
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 the requested database
1295 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
1298 if (dbentry == NULL)
1306 * pgstat_fetch_stat_tabentry() -
1308 * Support function for the SQL-callable pgstat* functions. Returns
1309 * the collected statistics for one table or NULL. NULL doesn't mean
1310 * that the table doesn't exist, it is just not yet known by the
1311 * collector, so the caller is better off to report ZERO instead.
1314 PgStat_StatTabEntry *
1315 pgstat_fetch_stat_tabentry(Oid relid)
1317 PgStat_StatDBEntry *dbentry;
1318 PgStat_StatTabEntry *tabentry;
1321 * If not done for this transaction, read the statistics collector
1322 * stats file into some hash tables. Be careful with the
1323 * read_statsfile() call below!
1325 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1327 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1328 &pgStatBeTable, &pgStatNumBackends);
1329 pgStatDBHashXact = GetCurrentTransactionId();
1333 * Lookup our database.
1335 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
1336 (void *) &MyDatabaseId,
1338 if (dbentry == NULL)
1342 * Now inside the DB's table hash table lookup the requested one.
1344 if (dbentry->tables == NULL)
1346 tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
1349 if (tabentry == NULL)
1357 * pgstat_fetch_stat_beentry() -
1359 * Support function for the SQL-callable pgstat* functions. Returns
1360 * the actual activity slot of one active backend. The caller is
1361 * responsible for a check if the actual user is permitted to see
1362 * that info (especially the querystring).
1365 PgStat_StatBeEntry *
1366 pgstat_fetch_stat_beentry(int beid)
1368 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1370 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1371 &pgStatBeTable, &pgStatNumBackends);
1372 pgStatDBHashXact = GetCurrentTransactionId();
1375 if (beid < 1 || beid > pgStatNumBackends)
1378 return &pgStatBeTable[beid - 1];
1383 * pgstat_fetch_stat_numbackends() -
1385 * Support function for the SQL-callable pgstat* functions. Returns
1386 * the maximum current backend id.
1390 pgstat_fetch_stat_numbackends(void)
1392 if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))
1394 pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
1395 &pgStatBeTable, &pgStatNumBackends);
1396 pgStatDBHashXact = GetCurrentTransactionId();
1399 return pgStatNumBackends;
1404 /* ------------------------------------------------------------
1405 * Local support functions follow
1406 * ------------------------------------------------------------
1411 * pgstat_setheader() -
1413 * Set common header fields in a statistics message
1417 pgstat_setheader(PgStat_MsgHdr *hdr, int mtype)
1419 hdr->m_type = mtype;
1420 hdr->m_backendid = MyBackendId;
1421 hdr->m_procpid = MyProcPid;
1422 hdr->m_databaseid = MyDatabaseId;
1423 hdr->m_userid = GetSessionUserId();
1430 * Send out one statistics message to the collector
1434 pgstat_send(void *msg, int len)
1439 ((PgStat_MsgHdr *) msg)->m_size = len;
1441 send(pgStatSock, msg, len, 0);
1442 /* We deliberately ignore any error from send() */
1446 /* ------------------------------------------------------------
1447 * Local functions implementing the statistics collector itself follow
1448 *------------------------------------------------------------
1452 pgstat_mainInit(void)
1454 IsUnderPostmaster = true; /* we are a postmaster subprocess now */
1457 /* In EXEC case we will not have inherited these settings */
1458 IsPostmasterEnvironment = true;
1459 whereToSendOutput = None;
1461 /* Setup global context */
1462 MemoryContextInit(); /* before any elog'ing can occur */
1463 InitializeGUCOptions();
1466 MyProcPid = getpid(); /* reset MyProcPid */
1468 /* Lose the postmaster's on-exit routines */
1472 * Ignore all signals usually bound to some action in the postmaster,
1473 * except for SIGCHLD --- see pgstat_recvbuffer.
1475 pqsignal(SIGHUP, SIG_IGN);
1476 pqsignal(SIGINT, SIG_IGN);
1477 pqsignal(SIGTERM, SIG_IGN);
1478 pqsignal(SIGQUIT, SIG_IGN);
1479 pqsignal(SIGALRM, SIG_IGN);
1480 pqsignal(SIGPIPE, SIG_IGN);
1481 pqsignal(SIGUSR1, SIG_IGN);
1482 pqsignal(SIGUSR2, SIG_IGN);
1483 pqsignal(SIGCHLD, pgstat_die);
1484 pqsignal(SIGTTIN, SIG_DFL);
1485 pqsignal(SIGTTOU, SIG_DFL);
1486 pqsignal(SIGCONT, SIG_DFL);
1487 pqsignal(SIGWINCH, SIG_DFL);
1494 * Start up the statistics collector itself. This is the body of the
1495 * postmaster child process.
1498 NON_EXEC_STATIC void
1499 pgstat_main(PGSTAT_FORK_ARGS)
1501 pgstat_mainInit(); /* Note: for *both* EXEC_BACKEND and regular cases */
1503 pgstat_parseArgs(argc,argv);
1507 * Close the writing end of the postmaster pipe, so we'll see it
1508 * closing when the postmaster terminates and can terminate as well.
1510 closesocket(pgStatPmPipe[1]);
1511 pgStatPmPipe[1] = -1;
1512 closesocket(pgStatCollectorPmPipe[1]);
1513 pgStatCollectorPmPipe[1] = -1;
1516 * Start a buffering process to read from the socket, so we have a
1517 * little more time to process incoming messages.
1519 * NOTE: the process structure is: postmaster is parent of buffer process
1520 * is parent of collector process. This way, the buffer can detect
1521 * collector failure via SIGCHLD, whereas otherwise it wouldn't notice
1522 * collector failure until it tried to write on the pipe. That would
1523 * mean that after the postmaster started a new collector, we'd have
1524 * two buffer processes competing to read from the UDP socket --- not
1527 if (pgpipe(pgStatPipe) < 0)
1530 (errcode_for_socket_access(),
1531 errmsg("could not create pipe for statistics buffer: %m")));
1536 /* child becomes collector process */
1537 switch (pgstat_forkexec(STAT_PROC_COLLECTOR))
1544 (errmsg("could not fork statistics collector: %m")));
1547 #ifndef EXEC_BACKEND
1549 /* child becomes collector process */
1555 /* parent becomes buffer process */
1556 closesocket(pgStatPipe[0]);
1557 pgstat_recvbuffer();
1563 NON_EXEC_STATIC void
1564 pgstat_mainChild(PGSTAT_FORK_ARGS)
1572 struct timeval timeout;
1573 struct timeval next_statwrite;
1574 bool need_statwrite;
1578 pgstat_mainInit(); /* Note: only in EXEC_BACKEND case */
1579 pgstat_parseArgs(argc,argv);
1581 MyProcPid = getpid(); /* reset MyProcPid */
1584 closesocket(pgStatPipe[1]);
1585 closesocket(pgStatSock);
1586 pmPipe = pgStatCollectorPmPipe[0];
1589 * In the child we can have default SIGCHLD handling (in case we want
1590 * to call system() here...)
1592 pqsignal(SIGCHLD, SIG_DFL);
1595 * Identify myself via ps
1597 init_ps_display("stats collector process", "", "");
1601 * Arrange to write the initial status file right away
1603 gettimeofday(&next_statwrite, NULL);
1604 need_statwrite = TRUE;
1607 * Read in an existing statistics stats file or initialize the stats
1610 pgStatRunningInCollector = TRUE;
1611 pgstat_read_statsfile(&pgStatDBHash, InvalidOid, NULL, NULL);
1614 * Create the dead backend hashtable
1616 memset(&hash_ctl, 0, sizeof(hash_ctl));
1617 hash_ctl.keysize = sizeof(int);
1618 hash_ctl.entrysize = sizeof(PgStat_StatBeDead);
1619 hash_ctl.hash = tag_hash;
1620 pgStatBeDead = hash_create("Dead Backends", PGSTAT_BE_HASH_SIZE,
1621 &hash_ctl, HASH_ELEM | HASH_FUNCTION);
1622 if (pgStatBeDead == NULL)
1624 /* assume the problem is out-of-memory */
1626 (errcode(ERRCODE_OUT_OF_MEMORY),
1627 errmsg("out of memory in statistics collector --- abort")));
1632 * Create the known backends table
1634 pgStatBeTable = (PgStat_StatBeEntry *) malloc(
1635 sizeof(PgStat_StatBeEntry) * MaxBackends);
1636 if (pgStatBeTable == NULL)
1639 (errcode(ERRCODE_OUT_OF_MEMORY),
1640 errmsg("out of memory in statistics collector --- abort")));
1643 memset(pgStatBeTable, 0, sizeof(PgStat_StatBeEntry) * MaxBackends);
1645 readPipe = pgStatPipe[0];
1648 * Process incoming messages and handle all the reporting stuff until
1649 * there are no more messages.
1654 * If we need to write the status file again (there have been
1655 * changes in the statistics since we wrote it last) calculate the
1656 * timeout until we have to do so.
1662 gettimeofday(&now, NULL);
1663 /* avoid assuming that tv_sec is signed */
1664 if (now.tv_sec > next_statwrite.tv_sec ||
1665 (now.tv_sec == next_statwrite.tv_sec &&
1666 now.tv_usec >= next_statwrite.tv_usec))
1669 timeout.tv_usec = 0;
1673 timeout.tv_sec = next_statwrite.tv_sec - now.tv_sec;
1674 timeout.tv_usec = next_statwrite.tv_usec - now.tv_usec;
1675 if (timeout.tv_usec < 0)
1678 timeout.tv_usec += 1000000;
1684 * Setup the descriptor set for select(2)
1687 FD_SET(readPipe, &rfds);
1690 * Now wait for something to do.
1692 nready = select(readPipe+1, &rfds, NULL, NULL,
1693 (need_statwrite) ? &timeout : NULL);
1699 (errcode_for_socket_access(),
1700 errmsg("select() failed in statistics collector: %m")));
1705 * If there are no descriptors ready, our timeout for writing the
1706 * stats file happened.
1710 pgstat_write_statsfile();
1711 need_statwrite = FALSE;
1717 * Check if there is a new statistics message to collect.
1719 if (FD_ISSET(readPipe, &rfds))
1722 * We may need to issue multiple read calls in case the buffer
1723 * process didn't write the message in a single write, which
1724 * is possible since it dumps its buffer bytewise. In any
1725 * case, we'd need two reads since we don't know the message
1729 int targetlen = sizeof(PgStat_MsgHdr); /* initial */
1730 bool pipeEOF = false;
1732 while (nread < targetlen)
1734 len = piperead(readPipe, ((char *) &msg) + nread,
1741 (errcode_for_socket_access(),
1742 errmsg("could not read from statistics collector pipe: %m")));
1745 if (len == 0) /* EOF on the pipe! */
1751 if (nread == sizeof(PgStat_MsgHdr))
1753 /* we have the header, compute actual msg length */
1754 targetlen = msg.msg_hdr.m_size;
1755 if (targetlen < (int) sizeof(PgStat_MsgHdr) ||
1756 targetlen > (int) sizeof(msg))
1759 * Bogus message length implies that we got out of
1760 * sync with the buffer process somehow. Abort so
1761 * that we can restart both processes.
1764 (errmsg("invalid statistics message length")));
1771 * EOF on the pipe implies that the buffer process exited.
1772 * Fall out of outer loop.
1778 * Distribute the message to the specific function handling
1781 switch (msg.msg_hdr.m_type)
1783 case PGSTAT_MTYPE_DUMMY:
1786 case PGSTAT_MTYPE_BESTART:
1787 pgstat_recv_bestart((PgStat_MsgBestart *) &msg, nread);
1790 case PGSTAT_MTYPE_BETERM:
1791 pgstat_recv_beterm((PgStat_MsgBeterm *) &msg, nread);
1794 case PGSTAT_MTYPE_TABSTAT:
1795 pgstat_recv_tabstat((PgStat_MsgTabstat *) &msg, nread);
1798 case PGSTAT_MTYPE_TABPURGE:
1799 pgstat_recv_tabpurge((PgStat_MsgTabpurge *) &msg, nread);
1802 case PGSTAT_MTYPE_ACTIVITY:
1803 pgstat_recv_activity((PgStat_MsgActivity *) &msg, nread);
1806 case PGSTAT_MTYPE_DROPDB:
1807 pgstat_recv_dropdb((PgStat_MsgDropdb *) &msg, nread);
1810 case PGSTAT_MTYPE_RESETCOUNTER:
1811 pgstat_recv_resetcounter((PgStat_MsgResetcounter *) &msg,
1820 * Globally count messages.
1822 pgStatNumMessages++;
1825 * If this is the first message after we wrote the stats file
1826 * the last time, setup the timeout that it'd be written.
1828 if (!need_statwrite)
1830 gettimeofday(&next_statwrite, NULL);
1831 next_statwrite.tv_usec += ((PGSTAT_STAT_INTERVAL) * 1000);
1832 next_statwrite.tv_sec += (next_statwrite.tv_usec / 1000000);
1833 next_statwrite.tv_usec %= 1000000;
1834 need_statwrite = TRUE;
1839 * Note that we do NOT check for postmaster exit inside the loop;
1840 * only EOF on the buffer pipe causes us to fall out. This
1841 * ensures we don't exit prematurely if there are still a few
1842 * messages in the buffer or pipe at postmaster shutdown.
1847 * Okay, we saw EOF on the buffer pipe, so there are no more messages
1848 * to process. If the buffer process quit because of postmaster
1849 * shutdown, we want to save the final stats to reuse at next startup.
1850 * But if the buffer process failed, it seems best not to (there may
1851 * even now be a new collector firing up, and we don't want it to read
1852 * a partially- rewritten stats file). We can tell whether the
1853 * postmaster is still alive by checking to see if the postmaster pipe
1854 * is still open. If it is read-ready (ie, EOF), the postmaster must
1858 FD_SET(pmPipe, &rfds);
1860 timeout.tv_usec = 0;
1861 nready = select(pmPipe+1,&rfds,NULL,NULL,&timeout);
1862 if (nready > 0 && FD_ISSET(pmPipe, &rfds))
1863 pgstat_write_statsfile();
1868 * pgstat_recvbuffer() -
1870 * This is the body of the separate buffering process. Its only
1871 * purpose is to receive messages from the UDP socket as fast as
1872 * possible and forward them over a pipe into the collector itself.
1873 * If the collector is slow to absorb messages, they are buffered here.
1877 pgstat_recvbuffer(void)
1881 int writePipe = pgStatPipe[1];
1882 int pmPipe = pgStatPmPipe[0];
1888 PgStat_Msg input_buffer;
1890 int msg_send = 0; /* next send index in buffer */
1891 int msg_recv = 0; /* next receive index */
1892 int msg_have = 0; /* number of bytes stored */
1893 bool overflow = false;
1896 * Identify myself via ps
1898 init_ps_display("stats buffer process", "", "");
1902 * We want to die if our child collector process does. There are two
1903 * ways we might notice that it has died: receive SIGCHLD, or get a
1904 * write failure on the pipe leading to the child. We can set SIGPIPE
1905 * to kill us here. Our SIGCHLD handler was already set up before we
1906 * forked (must do it that way, else it's a race condition).
1908 pqsignal(SIGPIPE, SIG_DFL);
1909 PG_SETMASK(&UnBlockSig);
1912 * Set the write pipe to nonblock mode, so that we cannot block when
1913 * the collector falls behind.
1915 if (!set_noblock(writePipe))
1918 (errcode_for_socket_access(),
1919 errmsg("could not set statistics collector pipe to nonblocking mode: %m")));
1924 * Allocate the message buffer
1926 msgbuffer = (char *) malloc(PGSTAT_RECVBUFFERSZ);
1927 if (msgbuffer == NULL)
1930 (errcode(ERRCODE_OUT_OF_MEMORY),
1931 errmsg("out of memory in statistics collector --- abort")));
1945 * As long as we have buffer space we add the socket to the read
1948 if (msg_have <= (int) (PGSTAT_RECVBUFFERSZ - sizeof(PgStat_Msg)))
1950 FD_SET(pgStatSock, &rfds);
1959 (errmsg("statistics buffer is full")));
1965 * If we have messages to write out, we add the pipe to the write
1966 * descriptor set. Otherwise, we check if the postmaster might
1971 FD_SET(writePipe, &wfds);
1972 if (writePipe > maxfd)
1977 FD_SET(pmPipe, &rfds);
1983 * Wait for some work to do.
1985 nready = select(maxfd + 1, &rfds, &wfds, NULL, NULL);
1991 (errcode_for_socket_access(),
1992 errmsg("select() failed in statistics buffer: %m")));
1997 * If there is a message on the socket, read it and check for
2000 if (FD_ISSET(pgStatSock, &rfds))
2002 len = recv(pgStatSock, (char *) &input_buffer,
2003 sizeof(PgStat_Msg), 0);
2007 (errcode_for_socket_access(),
2008 errmsg("could not read statistics message: %m")));
2013 * We ignore messages that are smaller than our common header
2015 if (len < sizeof(PgStat_MsgHdr))
2019 * The received length must match the length in the header
2021 if (input_buffer.msg_hdr.m_size != len)
2025 * O.K. - we accept this message. Copy it to the circular
2031 xfr = PGSTAT_RECVBUFFERSZ - msg_recv;
2035 memcpy(msgbuffer + msg_recv,
2036 ((char *) &input_buffer) + frm,
2039 if (msg_recv == PGSTAT_RECVBUFFERSZ)
2048 * If the collector is ready to receive, write some data into his
2049 * pipe. We may or may not be able to write all that we have.
2051 * NOTE: if what we have is less than PIPE_BUF bytes but more than
2052 * the space available in the pipe buffer, most kernels will
2053 * refuse to write any of it, and will return EAGAIN. This means
2054 * we will busy-loop until the situation changes (either because
2055 * the collector caught up, or because more data arrives so that
2056 * we have more than PIPE_BUF bytes buffered). This is not good,
2057 * but is there any way around it? We have no way to tell when
2058 * the collector has caught up...
2060 if (FD_ISSET(writePipe, &wfds))
2062 xfr = PGSTAT_RECVBUFFERSZ - msg_send;
2066 len = pipewrite(writePipe, msgbuffer + msg_send, xfr);
2069 if (errno == EINTR || errno == EAGAIN)
2070 continue; /* not enough space in pipe */
2072 (errcode_for_socket_access(),
2073 errmsg("could not write to statistics collector pipe: %m")));
2076 /* NB: len < xfr is okay */
2078 if (msg_send == PGSTAT_RECVBUFFERSZ)
2084 * Make sure we forwarded all messages before we check for
2085 * Postmaster termination.
2087 if (msg_have != 0 || FD_ISSET(pgStatSock, &rfds))
2091 * If the pipe from the postmaster is ready for reading, the
2092 * kernel must have closed it on exit() (the postmaster never
2093 * really writes to it). So we've done our job.
2095 if (FD_ISSET(pmPipe, &rfds))
2101 pgstat_die(SIGNAL_ARGS)
2108 * pgstat_add_backend() -
2110 * Support function to keep our backend list up to date.
2114 pgstat_add_backend(PgStat_MsgHdr *msg)
2116 PgStat_StatDBEntry *dbentry;
2117 PgStat_StatBeEntry *beentry;
2118 PgStat_StatBeDead *deadbe;
2122 * Check that the backend ID is valid
2124 if (msg->m_backendid < 1 || msg->m_backendid > MaxBackends)
2127 (errmsg("invalid server process ID %d", msg->m_backendid)));
2132 * Get the slot for this backendid.
2134 beentry = &pgStatBeTable[msg->m_backendid - 1];
2135 if (beentry->databaseid != InvalidOid)
2138 * If the slot contains the PID of this backend, everything is
2139 * fine and we got nothing to do.
2141 if (beentry->procpid == msg->m_procpid)
2146 * Lookup if this backend is known to be dead. This can be caused due
2147 * to messages arriving in the wrong order - i.e. Postmaster's BETERM
2148 * message might have arrived before we received all the backends
2149 * stats messages, or even a new backend with the same backendid was
2150 * faster in sending his BESTART.
2152 * If the backend is known to be dead, we ignore this add.
2154 deadbe = (PgStat_StatBeDead *) hash_search(pgStatBeDead,
2155 (void *) &(msg->m_procpid),
2161 * Backend isn't known to be dead. If it's slot is currently used, we
2162 * have to kick out the old backend.
2164 if (beentry->databaseid != InvalidOid)
2165 pgstat_sub_backend(beentry->procpid);
2168 * Put this new backend into the slot.
2170 beentry->databaseid = msg->m_databaseid;
2171 beentry->procpid = msg->m_procpid;
2172 beentry->userid = msg->m_userid;
2173 beentry->activity_start_sec = 0;
2174 beentry->activity_start_usec = 0;
2175 MemSet(beentry->activity, 0, PGSTAT_ACTIVITY_SIZE);
2178 * Lookup or create the database entry for this backends DB.
2180 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
2181 (void *) &(msg->m_databaseid),
2182 HASH_ENTER, &found);
2183 if (dbentry == NULL)
2186 (errcode(ERRCODE_OUT_OF_MEMORY),
2187 errmsg("out of memory in statistics collector --- abort")));
2192 * If not found, initialize the new one.
2198 dbentry->tables = NULL;
2199 dbentry->n_xact_commit = 0;
2200 dbentry->n_xact_rollback = 0;
2201 dbentry->n_blocks_fetched = 0;
2202 dbentry->n_blocks_hit = 0;
2203 dbentry->n_connects = 0;
2204 dbentry->destroy = 0;
2206 memset(&hash_ctl, 0, sizeof(hash_ctl));
2207 hash_ctl.keysize = sizeof(Oid);
2208 hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
2209 hash_ctl.hash = tag_hash;
2210 dbentry->tables = hash_create("Per-database table",
2211 PGSTAT_TAB_HASH_SIZE,
2213 HASH_ELEM | HASH_FUNCTION);
2214 if (dbentry->tables == NULL)
2216 /* assume the problem is out-of-memory */
2218 (errcode(ERRCODE_OUT_OF_MEMORY),
2219 errmsg("out of memory in statistics collector --- abort")));
2225 * Count number of connects to the database
2227 dbentry->n_connects++;
2234 * pgstat_sub_backend() -
2236 * Remove a backend from the actual backends list.
2240 pgstat_sub_backend(int procpid)
2243 PgStat_StatBeDead *deadbe;
2247 * Search in the known-backends table for the slot containing this
2250 for (i = 0; i < MaxBackends; i++)
2252 if (pgStatBeTable[i].databaseid != InvalidOid &&
2253 pgStatBeTable[i].procpid == procpid)
2256 * That's him. Add an entry to the known to be dead backends.
2257 * Due to possible misorder in the arrival of UDP packets it's
2258 * possible that even if we know the backend is dead, there
2259 * could still be messages queued that arrive later. Those
2260 * messages must not cause our number of backends statistics
2261 * to get screwed up, so we remember for a couple of seconds
2262 * that this PID is dead and ignore them (only the counting of
2263 * backends, not the table access stats they sent).
2265 deadbe = (PgStat_StatBeDead *) hash_search(pgStatBeDead,
2272 (errcode(ERRCODE_OUT_OF_MEMORY),
2273 errmsg("out of memory in statistics collector --- abort")));
2278 deadbe->backendid = i + 1;
2279 deadbe->destroy = PGSTAT_DESTROY_COUNT;
2283 * Declare the backend slot empty.
2285 pgStatBeTable[i].databaseid = InvalidOid;
2291 * No big problem if not found. This can happen if UDP messages arrive
2292 * out of order here.
2298 * pgstat_write_statsfile() -
2304 pgstat_write_statsfile(void)
2306 HASH_SEQ_STATUS hstat;
2307 HASH_SEQ_STATUS tstat;
2308 PgStat_StatDBEntry *dbentry;
2309 PgStat_StatTabEntry *tabentry;
2310 PgStat_StatBeDead *deadbe;
2315 * Open the statistics temp file to write out the current values.
2317 fpout = fopen(pgStat_tmpfname, PG_BINARY_W);
2321 (errcode_for_file_access(),
2322 errmsg("could not open temporary statistics file \"%s\": %m",
2328 * Walk through the database table.
2330 hash_seq_init(&hstat, pgStatDBHash);
2331 while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL)
2334 * If this database is marked destroyed, count down and do so if
2337 if (dbentry->destroy > 0)
2339 if (--(dbentry->destroy) == 0)
2341 if (dbentry->tables != NULL)
2342 hash_destroy(dbentry->tables);
2344 if (hash_search(pgStatDBHash,
2345 (void *) &(dbentry->databaseid),
2346 HASH_REMOVE, NULL) == NULL)
2349 (errmsg("database hash table corrupted "
2350 "during cleanup --- abort")));
2356 * Don't include statistics for it.
2362 * Write out the DB line including the number of life backends.
2365 fwrite(dbentry, sizeof(PgStat_StatDBEntry), 1, fpout);
2368 * Walk through the databases access stats per table.
2370 hash_seq_init(&tstat, dbentry->tables);
2371 while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&tstat)) != NULL)
2374 * If table entry marked for destruction, same as above for
2375 * the database entry.
2377 if (tabentry->destroy > 0)
2379 if (--(tabentry->destroy) == 0)
2381 if (hash_search(dbentry->tables,
2382 (void *) &(tabentry->tableid),
2383 HASH_REMOVE, NULL) == NULL)
2386 (errmsg("tables hash table for "
2387 "database %u corrupted during "
2388 "cleanup --- abort",
2389 dbentry->databaseid)));
2397 * At least we think this is still a life table. Print it's
2401 fwrite(tabentry, sizeof(PgStat_StatTabEntry), 1, fpout);
2405 * Mark the end of this DB
2411 * Write out the known running backends to the stats file.
2415 fwrite(&i, sizeof(i), 1, fpout);
2417 for (i = 0; i < MaxBackends; i++)
2419 if (pgStatBeTable[i].databaseid != InvalidOid)
2422 fwrite(&pgStatBeTable[i], sizeof(PgStat_StatBeEntry), 1, fpout);
2427 * No more output to be done. Close the temp file and replace the old
2428 * pgstat.stat with it.
2431 if (fclose(fpout) < 0)
2434 (errcode_for_file_access(),
2435 errmsg("could not close temporary statistics file \"%s\": %m",
2440 if (rename(pgStat_tmpfname, pgStat_fname) < 0)
2443 (errcode_for_file_access(),
2444 errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m",
2445 pgStat_tmpfname, pgStat_fname)));
2450 * Clear out the dead backends table
2452 hash_seq_init(&hstat, pgStatBeDead);
2453 while ((deadbe = (PgStat_StatBeDead *) hash_seq_search(&hstat)) != NULL)
2456 * Count down the destroy delay and remove entries where it
2459 if (--(deadbe->destroy) <= 0)
2461 if (hash_search(pgStatBeDead,
2462 (void *) &(deadbe->procpid),
2463 HASH_REMOVE, NULL) == NULL)
2466 (errmsg("dead-server-process hash table corrupted "
2467 "during cleanup --- abort")));
2476 * pgstat_read_statsfile() -
2478 * Reads in an existing statistics collector and initializes the
2479 * databases hash table (who's entries point to the tables hash tables)
2480 * and the current backend table.
2484 pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
2485 PgStat_StatBeEntry **betab, int *numbackends)
2487 PgStat_StatDBEntry *dbentry;
2488 PgStat_StatDBEntry dbbuf;
2489 PgStat_StatTabEntry *tabentry;
2490 PgStat_StatTabEntry tabbuf;
2492 HTAB *tabhash = NULL;
2494 int maxbackends = 0;
2495 int havebackends = 0;
2497 MemoryContext use_mcxt;
2501 * If running in the collector we use the DynaHashCxt memory context.
2502 * If running in a backend, we use the TopTransactionContext instead,
2503 * so the caller must only know the last XactId when this call
2504 * happened to know if his tables are still valid or already gone!
2506 if (pgStatRunningInCollector)
2513 use_mcxt = TopTransactionContext;
2514 mcxt_flags = HASH_CONTEXT;
2518 * Create the DB hashtable
2520 memset(&hash_ctl, 0, sizeof(hash_ctl));
2521 hash_ctl.keysize = sizeof(Oid);
2522 hash_ctl.entrysize = sizeof(PgStat_StatDBEntry);
2523 hash_ctl.hash = tag_hash;
2524 hash_ctl.hcxt = use_mcxt;
2525 *dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
2526 HASH_ELEM | HASH_FUNCTION | mcxt_flags);
2527 if (*dbhash == NULL)
2529 /* assume the problem is out-of-memory */
2530 if (pgStatRunningInCollector)
2533 (errcode(ERRCODE_OUT_OF_MEMORY),
2534 errmsg("out of memory in statistics collector --- abort")));
2537 /* in backend, can do normal error */
2539 (errcode(ERRCODE_OUT_OF_MEMORY),
2540 errmsg("out of memory")));
2544 * Initialize the number of known backends to zero, just in case we do
2545 * a silent error return below.
2547 if (numbackends != NULL)
2553 * Try to open the status file. If it doesn't exist, the backends
2554 * simply return zero for anything and the collector simply starts
2555 * from scratch with empty counters.
2557 if ((fpin = fopen(pgStat_fname, PG_BINARY_R)) == NULL)
2561 * We found an existing collector stats file. Read it and put all the
2562 * hashtable entries into place.
2566 switch (fgetc(fpin))
2569 * 'D' A PgStat_StatDBEntry struct describing a database
2570 * follows. Subsequently, zero to many 'T' entries will
2571 * follow until a 'd' is encountered.
2574 if (fread(&dbbuf, 1, sizeof(dbbuf), fpin) != sizeof(dbbuf))
2576 ereport(pgStatRunningInCollector ? LOG : WARNING,
2577 (errmsg("corrupted pgstat.stat file")));
2583 * Add to the DB hash
2585 dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash,
2586 (void *) &dbbuf.databaseid,
2589 if (dbentry == NULL)
2591 if (pgStatRunningInCollector)
2594 (errcode(ERRCODE_OUT_OF_MEMORY),
2595 errmsg("out of memory in statistics collector --- abort")));
2602 (errcode(ERRCODE_OUT_OF_MEMORY),
2603 errmsg("out of memory")));
2608 ereport(pgStatRunningInCollector ? LOG : WARNING,
2609 (errmsg("corrupted pgstat.stat file")));
2614 memcpy(dbentry, &dbbuf, sizeof(PgStat_StatDBEntry));
2615 dbentry->tables = NULL;
2616 dbentry->destroy = 0;
2617 dbentry->n_backends = 0;
2620 * Don't collect tables if not the requested DB
2622 if (onlydb != InvalidOid && onlydb != dbbuf.databaseid)
2625 memset(&hash_ctl, 0, sizeof(hash_ctl));
2626 hash_ctl.keysize = sizeof(Oid);
2627 hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
2628 hash_ctl.hash = tag_hash;
2629 hash_ctl.hcxt = use_mcxt;
2630 dbentry->tables = hash_create("Per-database table",
2631 PGSTAT_TAB_HASH_SIZE,
2633 HASH_ELEM | HASH_FUNCTION | mcxt_flags);
2634 if (dbentry->tables == NULL)
2636 /* assume the problem is out-of-memory */
2637 if (pgStatRunningInCollector)
2640 (errcode(ERRCODE_OUT_OF_MEMORY),
2641 errmsg("out of memory in statistics collector --- abort")));
2644 /* in backend, can do normal error */
2647 (errcode(ERRCODE_OUT_OF_MEMORY),
2648 errmsg("out of memory")));
2652 * Arrange that following 'T's add entries to this
2653 * databases tables hash table.
2655 tabhash = dbentry->tables;
2659 * 'd' End of this database.
2666 * 'T' A PgStat_StatTabEntry follows.
2669 if (fread(&tabbuf, 1, sizeof(tabbuf), fpin) != sizeof(tabbuf))
2671 ereport(pgStatRunningInCollector ? LOG : WARNING,
2672 (errmsg("corrupted pgstat.stat file")));
2678 * Skip if table belongs to a not requested database.
2680 if (tabhash == NULL)
2683 tabentry = (PgStat_StatTabEntry *) hash_search(tabhash,
2684 (void *) &tabbuf.tableid,
2685 HASH_ENTER, &found);
2686 if (tabentry == NULL)
2688 if (pgStatRunningInCollector)
2691 (errcode(ERRCODE_OUT_OF_MEMORY),
2692 errmsg("out of memory in statistics collector --- abort")));
2695 /* in backend, can do normal error */
2698 (errcode(ERRCODE_OUT_OF_MEMORY),
2699 errmsg("out of memory")));
2704 ereport(pgStatRunningInCollector ? LOG : WARNING,
2705 (errmsg("corrupted pgstat.stat file")));
2710 memcpy(tabentry, &tabbuf, sizeof(tabbuf));
2714 * 'M' The maximum number of backends to expect follows.
2717 if (betab == NULL || numbackends == NULL)
2722 if (fread(&maxbackends, 1, sizeof(maxbackends), fpin) !=
2723 sizeof(maxbackends))
2725 ereport(pgStatRunningInCollector ? LOG : WARNING,
2726 (errmsg("corrupted pgstat.stat file")));
2730 if (maxbackends == 0)
2737 * Allocate space (in TopTransactionContext too) for the
2740 if (use_mcxt == NULL)
2741 *betab = (PgStat_StatBeEntry *) malloc(
2742 sizeof(PgStat_StatBeEntry) * maxbackends);
2744 *betab = (PgStat_StatBeEntry *) MemoryContextAlloc(
2746 sizeof(PgStat_StatBeEntry) * maxbackends);
2750 * 'B' A PgStat_StatBeEntry follows.
2753 if (betab == NULL || numbackends == NULL)
2765 * Read it directly into the table.
2767 if (fread(&(*betab)[havebackends], 1,
2768 sizeof(PgStat_StatBeEntry), fpin) !=
2769 sizeof(PgStat_StatBeEntry))
2771 ereport(pgStatRunningInCollector ? LOG : WARNING,
2772 (errmsg("corrupted pgstat.stat file")));
2778 * Count backends per database here.
2780 dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash,
2781 (void *) &((*betab)[havebackends].databaseid),
2784 dbentry->n_backends++;
2787 if (numbackends != 0)
2788 *numbackends = havebackends;
2789 if (havebackends >= maxbackends)
2797 * 'E' The EOF marker of a complete stats file.
2804 ereport(pgStatRunningInCollector ? LOG : WARNING,
2805 (errmsg("corrupted pgstat.stat file")));
2816 * pgstat_recv_bestart() -
2818 * Process a backend starup message.
2822 pgstat_recv_bestart(PgStat_MsgBestart *msg, int len)
2824 pgstat_add_backend(&msg->m_hdr);
2829 * pgstat_recv_beterm() -
2831 * Process a backend termination message.
2835 pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len)
2837 pgstat_sub_backend(msg->m_hdr.m_procpid);
2842 * pgstat_recv_activity() -
2844 * Remember what the backend is doing.
2848 pgstat_recv_activity(PgStat_MsgActivity *msg, int len)
2850 PgStat_StatBeEntry *entry;
2853 * Here we check explicitly for 0 return, since we don't want to
2854 * mangle the activity of an active backend by a delayed packed from a
2857 if (pgstat_add_backend(&msg->m_hdr) != 0)
2860 entry = &(pgStatBeTable[msg->m_hdr.m_backendid - 1]);
2862 strncpy(entry->activity, msg->m_what, PGSTAT_ACTIVITY_SIZE);
2864 entry->activity_start_sec =
2865 GetCurrentAbsoluteTimeUsec(&entry->activity_start_usec);
2870 * pgstat_recv_tabstat() -
2872 * Count what the backend has done.
2876 pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
2878 PgStat_TableEntry *tabmsg = &(msg->m_entry[0]);
2879 PgStat_StatDBEntry *dbentry;
2880 PgStat_StatTabEntry *tabentry;
2885 * Make sure the backend is counted for.
2887 if (pgstat_add_backend(&msg->m_hdr) < 0)
2891 * Lookup the database in the hashtable.
2893 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
2894 (void *) &(msg->m_hdr.m_databaseid),
2900 * If the database is marked for destroy, this is a delayed UDP packet
2901 * and not worth being counted.
2903 if (dbentry->destroy > 0)
2906 dbentry->n_xact_commit += (PgStat_Counter) (msg->m_xact_commit);
2907 dbentry->n_xact_rollback += (PgStat_Counter) (msg->m_xact_rollback);
2910 * Process all table entries in the message.
2912 for (i = 0; i < msg->m_nentries; i++)
2914 tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
2915 (void *) &(tabmsg[i].t_id),
2916 HASH_ENTER, &found);
2917 if (tabentry == NULL)
2920 (errcode(ERRCODE_OUT_OF_MEMORY),
2921 errmsg("out of memory in statistics collector --- abort")));
2928 * If it's a new table entry, initialize counters to the
2929 * values we just got.
2931 tabentry->numscans = tabmsg[i].t_numscans;
2932 tabentry->tuples_returned = tabmsg[i].t_tuples_returned;
2933 tabentry->tuples_fetched = tabmsg[i].t_tuples_fetched;
2934 tabentry->tuples_inserted = tabmsg[i].t_tuples_inserted;
2935 tabentry->tuples_updated = tabmsg[i].t_tuples_updated;
2936 tabentry->tuples_deleted = tabmsg[i].t_tuples_deleted;
2937 tabentry->blocks_fetched = tabmsg[i].t_blocks_fetched;
2938 tabentry->blocks_hit = tabmsg[i].t_blocks_hit;
2940 tabentry->destroy = 0;
2945 * Otherwise add the values to the existing entry.
2947 tabentry->numscans += tabmsg[i].t_numscans;
2948 tabentry->tuples_returned += tabmsg[i].t_tuples_returned;
2949 tabentry->tuples_fetched += tabmsg[i].t_tuples_fetched;
2950 tabentry->tuples_inserted += tabmsg[i].t_tuples_inserted;
2951 tabentry->tuples_updated += tabmsg[i].t_tuples_updated;
2952 tabentry->tuples_deleted += tabmsg[i].t_tuples_deleted;
2953 tabentry->blocks_fetched += tabmsg[i].t_blocks_fetched;
2954 tabentry->blocks_hit += tabmsg[i].t_blocks_hit;
2958 * And add the block IO to the database entry.
2960 dbentry->n_blocks_fetched += tabmsg[i].t_blocks_fetched;
2961 dbentry->n_blocks_hit += tabmsg[i].t_blocks_hit;
2967 * pgstat_recv_tabpurge() -
2969 * Arrange for dead table removal.
2973 pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len)
2975 PgStat_StatDBEntry *dbentry;
2976 PgStat_StatTabEntry *tabentry;
2980 * Make sure the backend is counted for.
2982 if (pgstat_add_backend(&msg->m_hdr) < 0)
2986 * Lookup the database in the hashtable.
2988 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
2989 (void *) &(msg->m_hdr.m_databaseid),
2995 * If the database is marked for destroy, this is a delayed UDP packet
2996 * and the tables will go away at DB destruction.
2998 if (dbentry->destroy > 0)
3002 * Process all table entries in the message.
3004 for (i = 0; i < msg->m_nentries; i++)
3006 tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables,
3007 (void *) &(msg->m_tableid[i]),
3010 tabentry->destroy = PGSTAT_DESTROY_COUNT;
3016 * pgstat_recv_dropdb() -
3018 * Arrange for dead database removal
3022 pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len)
3024 PgStat_StatDBEntry *dbentry;
3027 * Make sure the backend is counted for.
3029 if (pgstat_add_backend(&msg->m_hdr) < 0)
3033 * Lookup the database in the hashtable.
3035 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
3036 (void *) &(msg->m_databaseid),
3042 * Mark the database for destruction.
3044 dbentry->destroy = PGSTAT_DESTROY_COUNT;
3049 * pgstat_recv_dropdb() -
3051 * Arrange for dead database removal
3055 pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
3058 PgStat_StatDBEntry *dbentry;
3061 * Make sure the backend is counted for.
3063 if (pgstat_add_backend(&msg->m_hdr) < 0)
3067 * Lookup the database in the hashtable.
3069 dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
3070 (void *) &(msg->m_hdr.m_databaseid),
3076 * We simply throw away all the databases table entries by recreating
3077 * a new hash table for them.
3079 if (dbentry->tables != NULL)
3080 hash_destroy(dbentry->tables);
3082 dbentry->tables = NULL;
3083 dbentry->n_xact_commit = 0;
3084 dbentry->n_xact_rollback = 0;
3085 dbentry->n_blocks_fetched = 0;
3086 dbentry->n_blocks_hit = 0;
3087 dbentry->n_connects = 0;
3088 dbentry->destroy = 0;
3090 memset(&hash_ctl, 0, sizeof(hash_ctl));
3091 hash_ctl.keysize = sizeof(Oid);
3092 hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
3093 hash_ctl.hash = tag_hash;
3094 dbentry->tables = hash_create("Per-database table",
3095 PGSTAT_TAB_HASH_SIZE,
3097 HASH_ELEM | HASH_FUNCTION);
3098 if (dbentry->tables == NULL)
3100 /* assume the problem is out-of-memory */
3102 (errcode(ERRCODE_OUT_OF_MEMORY),
3103 errmsg("out of memory in statistics collector --- abort")));