⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgstat.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ---------- * pgstat.c * *	All the statistics collector stuff hacked up in one big, ugly file. * *	TODO:	- Separate collector, postmaster and backend stuff *			  into different files. * *			- Add some automatic call for pgstat vacuuming. * *			- Add a pgstat config column to pg_database, so this *			  entire thing can be enabled/disabled on a per db base. * *	Copyright (c) 2001-2003, PostgreSQL Global Development Group * *	$Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.45.2.2 2003/11/15 17:24:19 tgl Exp $ * ---------- */#include "postgres.h"#include <unistd.h>#include <fcntl.h>#include <sys/param.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <signal.h>#include "pgstat.h"#include "access/xact.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/pg_shadow.h"#include "catalog/pg_database.h"#include "libpq/pqsignal.h"#include "libpq/libpq.h"#include "mb/pg_wchar.h"#include "miscadmin.h"#include "utils/memutils.h"#include "storage/backendid.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "utils/rel.h"#include "utils/hsearch.h"#include "utils/ps_status.h"#include "utils/syscache.h"/* ---------- * GUC parameters * ---------- */bool		pgstat_collect_startcollector = true;bool		pgstat_collect_resetonpmstart = true;bool		pgstat_collect_querystring = false;bool		pgstat_collect_tuplelevel = false;bool		pgstat_collect_blocklevel = false;/* ---------- * Other global variables * ---------- */bool		pgstat_is_running = false;/* ---------- * Local data * ---------- */static int	pgStatSock = -1;static int	pgStatPipe[2];static struct sockaddr_storage pgStatAddr;static int	pgStatPmPipe[2] = {-1, -1};static int	pgStatPid;static time_t last_pgstat_start_time;static long pgStatNumMessages = 0;static bool pgStatRunningInCollector = FALSE;static int	pgStatTabstatAlloc = 0;static int	pgStatTabstatUsed = 0;static PgStat_MsgTabstat **pgStatTabstatMessages = NULL;#define TABSTAT_QUANTUM		4	/* we alloc this many at a time */static int	pgStatXactCommit = 0;static int	pgStatXactRollback = 0;static TransactionId pgStatDBHashXact = InvalidTransactionId;static HTAB *pgStatDBHash = NULL;static HTAB *pgStatBeDead = NULL;static PgStat_StatBeEntry *pgStatBeTable = NULL;static int	pgStatNumBackends = 0;static char pgStat_tmpfname[MAXPGPATH];static char pgStat_fname[MAXPGPATH];/* ---------- * Local function forward declarations * ---------- */static void pgstat_main(void);static void pgstat_recvbuffer(void);static void pgstat_die(SIGNAL_ARGS);static int	pgstat_add_backend(PgStat_MsgHdr *msg);static void pgstat_sub_backend(int procpid);static void pgstat_drop_database(Oid databaseid);static void pgstat_write_statsfile(void);static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,					  PgStat_StatBeEntry **betab,					  int *numbackends);static void pgstat_setheader(PgStat_MsgHdr *hdr, int mtype);static void pgstat_send(void *msg, int len);static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);static void pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len);static void pgstat_recv_activity(PgStat_MsgActivity *msg, int len);static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len);static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);/* ------------------------------------------------------------ * Public functions called from postmaster follow * ------------------------------------------------------------ *//* ---------- * pgstat_init() - * *	Called from postmaster at startup. Create the resources required *	by the statistics collector process.  If unable to do so, do not *	fail --- better to let the postmaster start with stats collection *	disabled. * ---------- */voidpgstat_init(void){	ACCEPT_TYPE_ARG3 alen;	struct addrinfo *addrs = NULL,			   *addr,				hints;	int			ret;	/*	 * Force start of collector daemon if something to collect	 */	if (pgstat_collect_querystring ||		pgstat_collect_tuplelevel ||		pgstat_collect_blocklevel)		pgstat_collect_startcollector = true;	/*	 * Initialize the filenames for the status reports.	 */	snprintf(pgStat_tmpfname, MAXPGPATH,			 PGSTAT_STAT_TMPFILE, DataDir, getpid());	snprintf(pgStat_fname, MAXPGPATH,			 PGSTAT_STAT_FILENAME, DataDir);	/*	 * If we don't have to start a collector or should reset the collected	 * statistics on postmaster start, simply remove the file.	 */	if (!pgstat_collect_startcollector || pgstat_collect_resetonpmstart)		unlink(pgStat_fname);	/*	 * Nothing else required if collector will not get started	 */	if (!pgstat_collect_startcollector)		return;	/*	 * Create the UDP socket for sending and receiving statistic messages	 */	hints.ai_flags = AI_PASSIVE;	hints.ai_family = PF_UNSPEC;	hints.ai_socktype = SOCK_DGRAM;	hints.ai_protocol = 0;	hints.ai_addrlen = 0;	hints.ai_addr = NULL;	hints.ai_canonname = NULL;	hints.ai_next = NULL;	ret = getaddrinfo_all("localhost", NULL, &hints, &addrs);	if (ret || !addrs)	{		ereport(LOG,				(errmsg("could not resolve \"localhost\": %s",						gai_strerror(ret))));		goto startup_failed;	}	/*	 * On some platforms, getaddrinfo_all() may return multiple addresses	 * only one of which will actually work (eg, both IPv6 and IPv4 addresses	 * when kernel will reject IPv6).  Worse, the failure may occur at the	 * bind() or perhaps even connect() stage.  So we must loop through the	 * results till we find a working combination.  We will generate LOG	 * messages, but no error, for bogus combinations.	 */	for (addr = addrs; addr; addr = addr->ai_next)	{#ifdef HAVE_UNIX_SOCKETS		/* Ignore AF_UNIX sockets, if any are returned. */		if (addr->ai_family == AF_UNIX)			continue;#endif		/*		 * Create the socket.		 */		if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) < 0)		{			ereport(LOG,					(errcode_for_socket_access(),					 errmsg("could not create socket for statistics collector: %m")));			continue;		}		/*		 * Bind it to a kernel assigned port on localhost and get the assigned		 * port via getsockname().		 */		if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)		{			ereport(LOG,					(errcode_for_socket_access(),					 errmsg("could not bind socket for statistics collector: %m")));			closesocket(pgStatSock);			pgStatSock = -1;			continue;		}		alen = sizeof(pgStatAddr);		if (getsockname(pgStatSock, (struct sockaddr *) &pgStatAddr, &alen) < 0)		{			ereport(LOG,					(errcode_for_socket_access(),					 errmsg("could not get address of socket for statistics collector: %m")));			closesocket(pgStatSock);			pgStatSock = -1;			continue;		}		/*		 * Connect the socket to its own address.  This saves a few cycles by		 * not having to respecify the target address on every send. This also		 * provides a kernel-level check that only packets from this same		 * address will be received.		 */		if (connect(pgStatSock, (struct sockaddr *) &pgStatAddr, alen) < 0)		{			ereport(LOG,					(errcode_for_socket_access(),					 errmsg("could not connect socket for statistics collector: %m")));			closesocket(pgStatSock);			pgStatSock = -1;			continue;		}		/* If we get here, we have a working socket */		break;	}	/* Did we find a working address? */	if (!addr || pgStatSock < 0)	{		ereport(LOG,				(errcode_for_socket_access(),				 errmsg("disabling statistics collector for lack of working socket")));		goto startup_failed;	}	/*	 * Set the socket to non-blocking IO.  This ensures that if the	 * collector falls behind (despite the buffering process), statistics	 * messages will be discarded; backends won't block waiting to send	 * messages to the collector.	 */	if (FCNTL_NONBLOCK(pgStatSock) < 0)	{		ereport(LOG,				(errcode_for_socket_access(),		errmsg("could not set statistics collector socket to nonblocking mode: %m")));		goto startup_failed;	}	/*	 * Create the pipe that controls the statistics collector shutdown	 */	if (pipe(pgStatPmPipe) < 0)	{		ereport(LOG,				(errcode_for_socket_access(),		  errmsg("could not create pipe for statistics collector: %m")));		goto startup_failed;	}	freeaddrinfo_all(hints.ai_family, addrs);	return;startup_failed:	if (addrs)		freeaddrinfo_all(hints.ai_family, addrs);	if (pgStatSock >= 0)		closesocket(pgStatSock);	pgStatSock = -1;	/* Adjust GUC variables to suppress useless activity */	pgstat_collect_startcollector = false;	pgstat_collect_querystring = false;	pgstat_collect_tuplelevel = false;	pgstat_collect_blocklevel = false;}/* ---------- * pgstat_start() - * *	Called from postmaster at startup or after an existing collector *	died.  Attempt to fire up a fresh statistics collector. * *	Note: if fail, we will be called again from the postmaster main loop. * ---------- */voidpgstat_start(void){	time_t		curtime;	/*	 * Do nothing if no collector needed	 */	if (pgstat_is_running || !pgstat_collect_startcollector)		return;	/*	 * Do nothing if too soon since last collector start.  This is a	 * safety valve to protect against continuous respawn attempts if the	 * collector is dying immediately at launch.  Note that since we will	 * be re-called from the postmaster main loop, we will get another	 * chance later.	 */	curtime = time(NULL);	if ((unsigned int) (curtime - last_pgstat_start_time) <		(unsigned int) PGSTAT_RESTART_INTERVAL)		return;	last_pgstat_start_time = curtime;	/*	 * Check that the socket is there, else pgstat_init failed.	 */	if (pgStatSock < 0)	{		ereport(LOG,				(errmsg("statistics collector startup skipped")));		/*		 * We can only get here if someone tries to manually turn		 * pgstat_collect_startcollector on after it had been off.		 */		pgstat_collect_startcollector = false;		return;	}	/*	 * Okay, fork off the collector.  Remember its PID for	 * pgstat_ispgstat.	 */	fflush(stdout);	fflush(stderr);#ifdef __BEOS__	/* Specific beos actions before backend startup */	beos_before_backend_startup();#endif	switch ((pgStatPid = (int) fork()))	{		case -1:#ifdef __BEOS__			/* Specific beos actions */			beos_backend_startup_failed();#endif			ereport(LOG,					(errmsg("could not fork statistics buffer: %m")));			return;		case 0:			break;		default:			pgstat_is_running = true;			return;	}	/* in postmaster child ... */#ifdef __BEOS__	/* Specific beos actions after backend startup */	beos_backend_startup();#endif	IsUnderPostmaster = true;	/* we are a postmaster subprocess now */	MyProcPid = getpid();		/* reset MyProcPid */	/* Lose the postmaster's on-exit routines */	on_exit_reset();	/* Close the postmaster's sockets, except for pgstat link */	ClosePostmasterPorts(false);	/* Drop our connection to postmaster's shared memory, as well */	PGSharedMemoryDetach();	pgstat_main();	exit(0);}/* ---------- * pgstat_ispgstat() - * *	Called from postmaster to check if a terminated child process *	was the statistics collector. * ---------- */boolpgstat_ispgstat(int pid){	if (!pgstat_is_running)		return false;	if (pgStatPid != pid)		return false;	/* Oh dear ... */	pgstat_is_running = false;	return true;}/* ---------- * pgstat_close_sockets() - * *	Called when postmaster forks a non-pgstat child process, to close off *	file descriptors that should not be held open in child processes. * ---------- */voidpgstat_close_sockets(void){	if (pgStatPmPipe[0] >= 0)		closesocket(pgStatPmPipe[0]);	pgStatPmPipe[0] = -1;	if (pgStatPmPipe[1] >= 0)		closesocket(pgStatPmPipe[1]);	pgStatPmPipe[1] = -1;}/* ---------- * pgstat_beterm() - * *	Called from postmaster to tell collector a backend terminated. * ---------- */voidpgstat_beterm(int pid){	PgStat_MsgBeterm msg;	if (pgStatSock < 0)		return;	MemSet(&(msg.m_hdr), 0, sizeof(msg.m_hdr));	msg.m_hdr.m_type = PGSTAT_MTYPE_BETERM;	msg.m_hdr.m_procpid = pid;	pgstat_send(&msg, sizeof(msg));}/* ------------------------------------------------------------ * Public functions used by backends follow *------------------------------------------------------------ *//* ---------- * pgstat_bestart() - * *	Tell the collector that this new backend is soon ready to process *	queries. Called from tcop/postgres.c before entering the mainloop. * ---------- */voidpgstat_bestart(void){	PgStat_MsgBestart msg;	if (pgStatSock < 0)		return;	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);	pgstat_send(&msg, sizeof(msg));}/* ---------- * pgstat_report_activity() - * *	Called in tcop/postgres.c to tell the collector what the backend *	is actually doing (usually "<IDLE>" or the start of the query to *	be executed). * ---------- */voidpgstat_report_activity(const char *what){	PgStat_MsgActivity msg;	int			len;	if (!pgstat_collect_querystring || pgStatSock < 0)		return;	len = strlen(what);	len = pg_mbcliplen((const unsigned char *) what, len,					   PGSTAT_ACTIVITY_SIZE - 1);	memcpy(msg.m_what, what, len);	msg.m_what[len] = '\0';	len += offsetof(PgStat_MsgActivity, m_what) +1;	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ACTIVITY);	pgstat_send(&msg, len);}/* ---------- * pgstat_report_tabstat() -

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -