This patch changes pgstat.c to use palloc(), AllocateFile() and
FreeFile() rather than malloc(), fopen() and fclose(), respectively.

I changed more_tabstat_space() (which is invoked at various times
indirectly throughout the backend) to allocate memory in its own private
memory context, rather than use malloc() -- we can't just use
CurrentMemoryContext because that may not be sufficiently long-lived.

Barring any objections I intend to apply this to HEAD tomorrow.

-Neil

--- src/backend/postmaster/pgstat.c
+++ src/backend/postmaster/pgstat.c
@@ -42,6 +42,7 @@
 #include "miscadmin.h"
 #include "postmaster/postmaster.h"
 #include "storage/backendid.h"
+#include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
 #include "storage/pmsignal.h"
@@ -118,6 +119,7 @@
 
 static bool pgStatRunningInCollector = FALSE;
 
+static MemoryContext tabstatCxt = NULL;
 static int	pgStatTabstatAlloc = 0;
 static int	pgStatTabstatUsed = 0;
 static PgStat_MsgTabstat **pgStatTabstatMessages = NULL;
@@ -682,7 +683,7 @@
 /* ----------
  * pgstat_report_activity() -
  *
- *	Called in tcop/postgres.c to tell the collector what the backend
+ *	Called from tcop/postgres.c to tell the collector what the backend
  *	is actually doing (usually "<IDLE>" or the start of the query to
  *	be executed).
  * ----------
@@ -988,49 +988,44 @@
 /*
  * Create or enlarge the pgStatTabstatMessages array
  */
-static bool
+static void
 more_tabstat_space(void)
 {
 	PgStat_MsgTabstat *newMessages;
 	PgStat_MsgTabstat **msgArray;
 	int			newAlloc = pgStatTabstatAlloc + TABSTAT_QUANTUM;
 	int			i;
+	MemoryContext oldCxt;
 
+	if (tabstatCxt == NULL)
+		tabstatCxt = AllocSetContextCreate(TopMemoryContext,
+										   "per-backend statistics buffer",
+										   ALLOCSET_DEFAULT_MINSIZE,
+										   ALLOCSET_DEFAULT_INITSIZE,
+										   ALLOCSET_DEFAULT_MAXSIZE);
+
+	oldCxt = MemoryContextSwitchTo(tabstatCxt);
+
 	/* 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;
-	}
+		palloc0(sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
 
 	/* Create or enlarge the pointer array */
 	if (pgStatTabstatMessages == NULL)
 		msgArray = (PgStat_MsgTabstat **)
-			malloc(sizeof(PgStat_MsgTabstat *) * newAlloc);
+			palloc(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;
-	}
+			repalloc(pgStatTabstatMessages,
+					 sizeof(PgStat_MsgTabstat *) * newAlloc);
 
-	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;
+	Assert(pgStatTabstatUsed < pgStatTabstatAlloc);
+	MemoryContextSwitchTo(oldCxt);
 }
 
 /* ----------
@@ -1102,14 +1097,7 @@
 	 * 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);
-	}
+		more_tabstat_space();
 
 	/*
 	 * Use the first entry of the next message buffer.
@@ -1146,10 +1139,8 @@
 	 * new xact-counters.
 	 */
 	if (pgStatTabstatAlloc == 0)
-	{
-		if (!more_tabstat_space())
-			return;
-	}
+		more_tabstat_space();
+
 	if (pgStatTabstatUsed == 0)
 	{
 		pgStatTabstatUsed++;
@@ -1180,10 +1178,8 @@
 	 * new xact-counters.
 	 */
 	if (pgStatTabstatAlloc == 0)
-	{
-		if (!more_tabstat_space())
-			return;
-	}
+		more_tabstat_space();
+
 	if (pgStatTabstatUsed == 0)
 	{
 		pgStatTabstatUsed++;
@@ -1529,13 +1527,8 @@
 	/*
 	 * Create the known backends table
 	 */
-	pgStatBeTable = (PgStat_StatBeEntry *) malloc(
+	pgStatBeTable = (PgStat_StatBeEntry *) palloc0(
 							   sizeof(PgStat_StatBeEntry) * MaxBackends);
-	if (pgStatBeTable == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_OUT_OF_MEMORY),
-			 errmsg("out of memory in statistics collector --- abort")));
-	memset(pgStatBeTable, 0, sizeof(PgStat_StatBeEntry) * MaxBackends);
 
 	readPipe = pgStatPipe[0];
 
@@ -1804,11 +1799,7 @@
 	/*
 	 * Allocate the message buffer
 	 */
-	msgbuffer = (char *) malloc(PGSTAT_RECVBUFFERSZ);
-	if (msgbuffer == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_OUT_OF_MEMORY),
-			 errmsg("out of memory in statistics collector --- abort")));
+	msgbuffer = (char *) palloc(PGSTAT_RECVBUFFERSZ);
 
 	/*
 	 * Loop forever
@@ -2416,7 +2412,7 @@
 	 * simply return zero for anything and the collector simply starts
 	 * from scratch with empty counters.
 	 */
-	if ((fpin = fopen(pgStat_fname, PG_BINARY_R)) == NULL)
+	if ((fpin = AllocateFile(pgStat_fname, PG_BINARY_R)) == NULL)
 		return;
 
 	/*
@@ -2437,8 +2437,7 @@
 				{
 					ereport(pgStatRunningInCollector ? LOG : WARNING,
 							(errmsg("corrupted pgstat.stat file")));
-					fclose(fpin);
-					return;
+					goto done;
 				}
 
 				/*
@@ -2450,7 +2449,6 @@
 															 &found);
 				if (dbentry == NULL)
 				{
-					fclose(fpin);
 					ereport(ERROR,
 							(errcode(ERRCODE_OUT_OF_MEMORY),
 							 errmsg("out of memory")));
@@ -2459,8 +2458,7 @@
 				{
 					ereport(pgStatRunningInCollector ? LOG : WARNING,
 							(errmsg("corrupted pgstat.stat file")));
-					fclose(fpin);
-					return;
+					goto done;
 				}
 
 				memcpy(dbentry, &dbbuf, sizeof(PgStat_StatDBEntry));
@@ -2479,19 +2478,10 @@
 				hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
 				hash_ctl.hash = tag_hash;
 				hash_ctl.hcxt = use_mcxt;
-				PG_TRY();
-				{
-					dbentry->tables = hash_create("Per-database table",
-												  PGSTAT_TAB_HASH_SIZE,
-												  &hash_ctl,
-												  HASH_ELEM | HASH_FUNCTION | mcxt_flags);
-				}
-				PG_CATCH();
-				{
-					fclose(fpin);
-					PG_RE_THROW();
-				}
-				PG_END_TRY();
+				dbentry->tables = hash_create("Per-database table",
+											  PGSTAT_TAB_HASH_SIZE,
+											  &hash_ctl,
+											  HASH_ELEM | HASH_FUNCTION | mcxt_flags);
 
 				/*
 				 * Arrange that following 'T's add entries to this
@@ -2515,8 +2506,7 @@
 				{
 					ereport(pgStatRunningInCollector ? LOG : WARNING,
 							(errmsg("corrupted pgstat.stat file")));
-					fclose(fpin);
-					return;
+					goto done;
 				}
 
 				/*
@@ -2529,19 +2528,15 @@
 												(void *) &tabbuf.tableid,
 													 HASH_ENTER, &found);
 				if (tabentry == NULL)
-				{
-					fclose(fpin);
 					ereport(ERROR,
 							(errcode(ERRCODE_OUT_OF_MEMORY),
 							 errmsg("out of memory")));
-				}
 
 				if (found)
 				{
 					ereport(pgStatRunningInCollector ? LOG : WARNING,
 							(errmsg("corrupted pgstat.stat file")));
-					fclose(fpin);
-					return;
+					goto done;
 				}
 
 				memcpy(tabentry, &tabbuf, sizeof(tabbuf));
@@ -2552,30 +2548,23 @@
 				 */
 			case 'M':
 				if (betab == NULL || numbackends == NULL)
-				{
-					fclose(fpin);
-					return;
-				}
+					goto done;
 				if (fread(&maxbackends, 1, sizeof(maxbackends), fpin) !=
 					sizeof(maxbackends))
 				{
 					ereport(pgStatRunningInCollector ? LOG : WARNING,
 							(errmsg("corrupted pgstat.stat file")));
-					fclose(fpin);
-					return;
+					goto done;
 				}
 				if (maxbackends == 0)
-				{
-					fclose(fpin);
-					return;
-				}
+					goto done;
 
 				/*
 				 * Allocate space (in TopTransactionContext too) for the
 				 * backend table.
 				 */
 				if (use_mcxt == NULL)
-					*betab = (PgStat_StatBeEntry *) malloc(
+					*betab = (PgStat_StatBeEntry *) palloc(
 							   sizeof(PgStat_StatBeEntry) * maxbackends);
 				else
 					*betab = (PgStat_StatBeEntry *) MemoryContextAlloc(
@@ -2587,16 +2580,8 @@
 				 * 'B'	A PgStat_StatBeEntry follows.
 				 */
 			case 'B':
-				if (betab == NULL || numbackends == NULL)
-				{
-					fclose(fpin);
-					return;
-				}
-				if (*betab == NULL)
-				{
-					fclose(fpin);
-					return;
-				}
+				if (betab == NULL || numbackends == NULL || *betab == NULL)
+					goto done;
 
 				/*
 				 * Read it directly into the table.
@@ -2607,8 +2599,7 @@
 				{
 					ereport(pgStatRunningInCollector ? LOG : WARNING,
 							(errmsg("corrupted pgstat.stat file")));
-					fclose(fpin);
-					return;
+					goto done;
 				}
 
 				/*
@@ -2624,28 +2623,25 @@
 				if (numbackends != 0)
 					*numbackends = havebackends;
 				if (havebackends >= maxbackends)
-				{
-					fclose(fpin);
-					return;
-				}
+					goto done;
+
 				break;
 
 				/*
 				 * 'E'	The EOF marker of a complete stats file.
 				 */
 			case 'E':
-				fclose(fpin);
-				return;
+				goto done;
 
 			default:
 				ereport(pgStatRunningInCollector ? LOG : WARNING,
 						(errmsg("corrupted pgstat.stat file")));
-				fclose(fpin);
-				return;
+				goto done;
 		}
 	}
 
-	fclose(fpin);
+done:
+	FreeFile(fpin);
 }
 
 /*
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to