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

📄 pgstat.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
 * *	Called from tcop/postgres.c to send the so far collected *	per table access statistics to the collector. * ---------- */voidpgstat_report_tabstat(void){	int			i;	if (pgStatSock < 0 ||		!(pgstat_collect_querystring ||		  pgstat_collect_tuplelevel ||		  pgstat_collect_blocklevel))	{		/* Not reporting stats, so just flush whatever we have */		pgStatTabstatUsed = 0;		return;	}	/*	 * For each message buffer used during the last query set the header	 * fields and send it out.	 */	for (i = 0; i < pgStatTabstatUsed; i++)	{		PgStat_MsgTabstat *tsmsg = pgStatTabstatMessages[i];		int			n;		int			len;		n = tsmsg->m_nentries;		len = offsetof(PgStat_MsgTabstat, m_entry[0]) +			n * sizeof(PgStat_TableEntry);		tsmsg->m_xact_commit = pgStatXactCommit;		tsmsg->m_xact_rollback = pgStatXactRollback;		pgStatXactCommit = 0;		pgStatXactRollback = 0;		pgstat_setheader(&tsmsg->m_hdr, PGSTAT_MTYPE_TABSTAT);		pgstat_send(tsmsg, len);	}	pgStatTabstatUsed = 0;}/* ---------- * pgstat_vacuum_tabstat() - * *	Will tell the collector about objects he can get rid of. * ---------- */intpgstat_vacuum_tabstat(void){	Relation	dbrel;	HeapScanDesc dbscan;	HeapTuple	dbtup;	Oid		   *dbidlist;	int			dbidalloc;	int			dbidused;	HASH_SEQ_STATUS hstat;	PgStat_StatDBEntry *dbentry;	PgStat_StatTabEntry *tabentry;	HeapTuple	reltup;	int			nobjects = 0;	PgStat_MsgTabpurge msg;	int			len;	int			i;	if (pgStatSock < 0)		return 0;	/*	 * If not done for this transaction, read the statistics collector	 * stats file into some hash tables.	 */	if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))	{		pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,							  &pgStatBeTable, &pgStatNumBackends);		pgStatDBHashXact = GetCurrentTransactionId();	}	/*	 * Lookup our own database entry	 */	dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,												 (void *) &MyDatabaseId,												 HASH_FIND, NULL);	if (dbentry == NULL)		return -1;	if (dbentry->tables == NULL)		return 0;	/*	 * Initialize our messages table counter to zero	 */	msg.m_nentries = 0;	/*	 * Check for all tables if they still exist.	 */	hash_seq_init(&hstat, dbentry->tables);	while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&hstat)) != NULL)	{		/*		 * Check if this relation is still alive by looking up it's		 * pg_class tuple in the system catalog cache.		 */		reltup = SearchSysCache(RELOID,								ObjectIdGetDatum(tabentry->tableid),								0, 0, 0);		if (HeapTupleIsValid(reltup))		{			ReleaseSysCache(reltup);			continue;		}		/*		 * Add this tables Oid to the message		 */		msg.m_tableid[msg.m_nentries++] = tabentry->tableid;		nobjects++;		/*		 * If the message is full, send it out and reinitialize ot zero		 */		if (msg.m_nentries >= PGSTAT_NUM_TABPURGE)		{			len = offsetof(PgStat_MsgTabpurge, m_tableid[0])				+msg.m_nentries * sizeof(Oid);			pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE);			pgstat_send(&msg, len);			msg.m_nentries = 0;		}	}	/*	 * Send the rest	 */	if (msg.m_nentries > 0)	{		len = offsetof(PgStat_MsgTabpurge, m_tableid[0])			+msg.m_nentries * sizeof(Oid);		pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE);		pgstat_send(&msg, len);	}	/*	 * Read pg_database and remember the Oid's of all existing databases	 */	dbidalloc = 256;	dbidused = 0;	dbidlist = (Oid *) palloc(sizeof(Oid) * dbidalloc);	dbrel = heap_openr(DatabaseRelationName, AccessShareLock);	dbscan = heap_beginscan(dbrel, SnapshotNow, 0, NULL);	while ((dbtup = heap_getnext(dbscan, ForwardScanDirection)) != NULL)	{		if (dbidused >= dbidalloc)		{			dbidalloc *= 2;			dbidlist = (Oid *) repalloc((char *) dbidlist,										sizeof(Oid) * dbidalloc);		}		dbidlist[dbidused++] = HeapTupleGetOid(dbtup);	}	heap_endscan(dbscan);	heap_close(dbrel, AccessShareLock);	/*	 * Search the database hash table for dead databases and tell the	 * collector to drop them as well.	 */	hash_seq_init(&hstat, pgStatDBHash);	while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL)	{		Oid			dbid = dbentry->databaseid;		for (i = 0; i < dbidused; i++)		{			if (dbidlist[i] == dbid)			{				dbid = InvalidOid;				break;			}		}		if (dbid != InvalidOid)		{			nobjects++;			pgstat_drop_database(dbid);		}	}	/*	 * Free the dbid list.	 */	pfree((char *) dbidlist);	/*	 * Tell the caller how many removeable objects we found	 */	return nobjects;}/* ---------- * pgstat_drop_database() - * *	Tell the collector that we just dropped a database. *	This is the only message that shouldn't get lost in space. Otherwise *	the collector will keep the statistics for the dead DB until his *	stats file got removed while the postmaster is down. * ---------- */static voidpgstat_drop_database(Oid databaseid){	PgStat_MsgDropdb msg;	if (pgStatSock < 0)		return;	msg.m_databaseid = databaseid;	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DROPDB);	pgstat_send(&msg, sizeof(msg));}/* ---------- * pgstat_reset_counters() - * *	Tell the statistics collector to reset counters for our database. * ---------- */voidpgstat_reset_counters(void){	PgStat_MsgResetcounter msg;	if (pgStatSock < 0)		return;	if (!superuser())		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),			  errmsg("must be superuser to reset statistics counters")));	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER);	pgstat_send(&msg, sizeof(msg));}/* ---------- * pgstat_ping() - * *	Send some junk data to the collector to increase traffic. * ---------- */voidpgstat_ping(void){	PgStat_MsgDummy msg;	if (pgStatSock < 0)		return;	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DUMMY);	pgstat_send(&msg, sizeof(msg));}/* * Create or enlarge the pgStatTabstatMessages array */static boolmore_tabstat_space(void){	PgStat_MsgTabstat *newMessages;	PgStat_MsgTabstat **msgArray;	int			newAlloc = pgStatTabstatAlloc + TABSTAT_QUANTUM;	int			i;	/* Create (another) quantum of message buffers */	newMessages = (PgStat_MsgTabstat *)		malloc(sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);	if (newMessages == NULL)	{		ereport(LOG,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));		return false;	}	/* Create or enlarge the pointer array */	if (pgStatTabstatMessages == NULL)		msgArray = (PgStat_MsgTabstat **)			malloc(sizeof(PgStat_MsgTabstat *) * newAlloc);	else		msgArray = (PgStat_MsgTabstat **)			realloc(pgStatTabstatMessages,					sizeof(PgStat_MsgTabstat *) * newAlloc);	if (msgArray == NULL)	{		free(newMessages);		ereport(LOG,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));		return false;	}	MemSet(newMessages, 0, sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);	for (i = 0; i < TABSTAT_QUANTUM; i++)		msgArray[pgStatTabstatAlloc + i] = newMessages++;	pgStatTabstatMessages = msgArray;	pgStatTabstatAlloc = newAlloc;	return true;}/* ---------- * pgstat_initstats() - * *	Called from various places usually dealing with initialization *	of Relation or Scan structures. The data placed into these *	structures from here tell where later to count for buffer reads, *	scans and tuples fetched. * ---------- */voidpgstat_initstats(PgStat_Info *stats, Relation rel){	Oid			rel_id = rel->rd_id;	PgStat_TableEntry *useent;	PgStat_MsgTabstat *tsmsg;	int			mb;	int			i;	/*	 * Initialize data not to count at all.	 */	stats->tabentry = NULL;	stats->no_stats = FALSE;	stats->heap_scan_counted = FALSE;	stats->index_scan_counted = FALSE;	if (pgStatSock < 0 ||		!(pgstat_collect_tuplelevel ||		  pgstat_collect_blocklevel))	{		stats->no_stats = TRUE;		return;	}	/*	 * Search the already-used message slots for this relation.	 */	for (mb = 0; mb < pgStatTabstatUsed; mb++)	{		tsmsg = pgStatTabstatMessages[mb];		for (i = tsmsg->m_nentries; --i >= 0; )		{			if (tsmsg->m_entry[i].t_id == rel_id)			{				stats->tabentry = (void *) &(tsmsg->m_entry[i]);				return;			}		}		if (tsmsg->m_nentries >= PGSTAT_NUM_TABENTRIES)			continue;		/*		 * Not found, but found a message buffer with an empty slot		 * instead. Fine, let's use this one.		 */		i = tsmsg->m_nentries++;		useent = &tsmsg->m_entry[i];		MemSet(useent, 0, sizeof(PgStat_TableEntry));		useent->t_id = rel_id;		stats->tabentry = (void *) useent;		return;	}	/*	 * If we ran out of message buffers, we just allocate more.	 */	if (pgStatTabstatUsed >= pgStatTabstatAlloc)	{		if (!more_tabstat_space())		{			stats->no_stats = TRUE;			return;		}		Assert(pgStatTabstatUsed < pgStatTabstatAlloc);	}	/*	 * Use the first entry of the next message buffer.	 */	mb = pgStatTabstatUsed++;	tsmsg = pgStatTabstatMessages[mb];	tsmsg->m_nentries = 1;	useent = &tsmsg->m_entry[0];	MemSet(useent, 0, sizeof(PgStat_TableEntry));	useent->t_id = rel_id;	stats->tabentry = (void *) useent;}/* ---------- * pgstat_count_xact_commit() - * *	Called from access/transam/xact.c to count transaction commits. * ---------- */voidpgstat_count_xact_commit(void){	if (!(pgstat_collect_querystring ||		  pgstat_collect_tuplelevel ||		  pgstat_collect_blocklevel))		return;	pgStatXactCommit++;	/*	 * If there was no relation activity yet, just make one existing	 * message buffer used without slots, causing the next report to tell	 * new xact-counters.	 */	if (pgStatTabstatAlloc == 0)	{		if (!more_tabstat_space())			return;	}	if (pgStatTabstatUsed == 0)	{		pgStatTabstatUsed++;		pgStatTabstatMessages[0]->m_nentries = 0;	}}/* ---------- * pgstat_count_xact_rollback() - * *	Called from access/transam/xact.c to count transaction rollbacks. * ---------- */voidpgstat_count_xact_rollback(void){	if (!(pgstat_collect_querystring ||		  pgstat_collect_tuplelevel ||		  pgstat_collect_blocklevel))		return;	pgStatXactRollback++;	/*	 * If there was no relation activity yet, just make one existing	 * message buffer used without slots, causing the next report to tell	 * new xact-counters.	 */	if (pgStatTabstatAlloc == 0)	{		if (!more_tabstat_space())			return;	}	if (pgStatTabstatUsed == 0)	{		pgStatTabstatUsed++;		pgStatTabstatMessages[0]->m_nentries = 0;	}}/* ---------- * pgstat_fetch_stat_dbentry() - * *	Support function for the SQL-callable pgstat* functions. Returns *	the collected statistics for one database or NULL. NULL doesn't mean *	that the database doesn't exist, it is just not yet known by the *	collector, so the caller is better off to report ZERO instead. * ---------- */PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid){	PgStat_StatDBEntry *dbentry;	/*	 * If not done for this transaction, read the statistics collector	 * stats file into some hash tables. Be careful with the	 * read_statsfile() call below!	 */	if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))	{		pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,							  &pgStatBeTable, &pgStatNumBackends);		pgStatDBHashXact = GetCurrentTransactionId();	}	/*	 * Lookup the requested database	 */	dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,												 (void *) &dbid,												 HASH_FIND, NULL);	if (dbentry == NULL)		return NULL;	return dbentry;}/* ---------- * pgstat_fetch_stat_tabentry() - * *	Support function for the SQL-callable pgstat* functions. Returns *	the collected statistics for one table or NULL. NULL doesn't mean *	that the table doesn't exist, it is just not yet known by the *	collector, so the caller is better off to report ZERO instead. * ---------- */PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid){	PgStat_StatDBEntry *dbentry;	PgStat_StatTabEntry *tabentry;	/*	 * If not done for this transaction, read the statistics collector	 * stats file into some hash tables. Be careful with the	 * read_statsfile() call below!	 */	if (!TransactionIdEquals(pgStatDBHashXact, GetCurrentTransactionId()))	{		pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,							  &pgStatBeTable, &pgStatNumBackends);		pgStatDBHashXact = GetCurrentTransactionId();	}	/*	 * Lookup our database.	 */	dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash,												 (void *) &MyDatabaseId,												 HASH_FIND, NULL);	if (dbentry == NULL)

⌨️ 快捷键说明

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