From d3de08a008252aba78ce9e5ca8c83d34dbbc0418 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Tue, 30 Sep 2008 11:17:07 +0000
Subject: [PATCH] Rewrite pg_freespacemap to match the new FSM implementation.
 I missed these changes from the main FSM commit for some reason.

---
 contrib/pg_freespacemap/Makefile              |   2 +-
 contrib/pg_freespacemap/pg_freespacemap.c     | 388 +-----------------
 .../pg_freespacemap/pg_freespacemap.sql.in    |   2 +-
 .../uninstall_pg_freespacemap.sql             |   2 +-
 4 files changed, 25 insertions(+), 369 deletions(-)

diff --git a/contrib/pg_freespacemap/Makefile b/contrib/pg_freespacemap/Makefile
index 5631ef5d54b..daeab59d46f 100644
--- a/contrib/pg_freespacemap/Makefile
+++ b/contrib/pg_freespacemap/Makefile
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/contrib/pg_freespacemap/Makefile,v 1.4 2007/11/10 23:59:51 momjian Exp $
+# $PostgreSQL: pgsql/contrib/pg_freespacemap/Makefile,v 1.5 2008/09/30 11:17:07 heikki Exp $
 
 MODULE_big = pg_freespacemap
 OBJS	= pg_freespacemap.o
diff --git a/contrib/pg_freespacemap/pg_freespacemap.c b/contrib/pg_freespacemap/pg_freespacemap.c
index 22f9f7f779b..57a7e4490d8 100644
--- a/contrib/pg_freespacemap/pg_freespacemap.c
+++ b/contrib/pg_freespacemap/pg_freespacemap.c
@@ -1,393 +1,49 @@
 /*-------------------------------------------------------------------------
  *
  * pg_freespacemap.c
- *	  display some contents of the free space relation and page maps.
+ *	  display contents of a free space map
  *
- *	  $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.10 2008/05/12 00:00:43 alvherre Exp $
+ *	  $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.11 2008/09/30 11:17:07 heikki Exp $
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "access/heapam.h"
 #include "access/htup.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "storage/freespace.h"
-#include "storage/lmgr.h"
+#include "utils/builtins.h"
 
 
-#define		NUM_FREESPACE_PAGES_ELEM	5
-#define		NUM_FREESPACE_RELATIONS_ELEM	7
-
 PG_MODULE_MAGIC;
 
-Datum		pg_freespacemap_pages(PG_FUNCTION_ARGS);
-Datum		pg_freespacemap_relations(PG_FUNCTION_ARGS);
-
-
-/*
- * Record structure holding the to be exposed per-page data.
- */
-typedef struct
-{
-	Oid			reltablespace;
-	Oid			reldatabase;
-	Oid			relfilenode;
-	BlockNumber relblocknumber;
-	Size		bytes;
-	bool		isindex;
-}	FreeSpacePagesRec;
-
-
-/*
- * Record structure holding the to be exposed per-relation data.
- */
-typedef struct
-{
-	Oid			reltablespace;
-	Oid			reldatabase;
-	Oid			relfilenode;
-	Size		avgrequest;
-	BlockNumber interestingpages;
-	int			storedpages;
-	int			nextpage;
-	bool		isindex;
-}	FreeSpaceRelationsRec;
-
-
-
-/*
- * Function context for page data persisting over repeated calls.
- */
-typedef struct
-{
-	TupleDesc	tupdesc;
-	FreeSpacePagesRec *record;
-}	FreeSpacePagesContext;
-
-
-/*
- * Function context for relation data persisting over repeated calls.
- */
-typedef struct
-{
-	TupleDesc	tupdesc;
-	FreeSpaceRelationsRec *record;
-}	FreeSpaceRelationsContext;
-
-
-/*
- * Function returning page data from the Free Space Map (FSM).
- */
-PG_FUNCTION_INFO_V1(pg_freespacemap_pages);
-
-Datum
-pg_freespacemap_pages(PG_FUNCTION_ARGS)
-{
-	FuncCallContext *funcctx;
-	Datum		result;
-	MemoryContext oldcontext;
-	FreeSpacePagesContext *fctx;	/* User function context. */
-	TupleDesc	tupledesc;
-	HeapTuple	tuple;
-	FSMHeader  *FreeSpaceMap;	/* FSM main structure. */
-	FSMRelation *fsmrel;		/* Individual relation. */
-
-	if (SRF_IS_FIRSTCALL())
-	{
-		int			i;
-		int			numPages;	/* Max possible no. of pages in map. */
-		int			nPages;		/* Mapped pages for a relation. */
-
-		/*
-		 * Get the free space map data structure.
-		 */
-		FreeSpaceMap = GetFreeSpaceMap();
-
-		numPages = MaxFSMPages;
-
-		funcctx = SRF_FIRSTCALL_INIT();
-
-		/* Switch context when allocating stuff to be used in later calls */
-		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-		/*
-		 * Create a function context for cross-call persistence.
-		 */
-		fctx = (FreeSpacePagesContext *) palloc(sizeof(FreeSpacePagesContext));
-		funcctx->user_fctx = fctx;
-
-		/* Construct a tuple descriptor for the result rows. */
-		tupledesc = CreateTemplateTupleDesc(NUM_FREESPACE_PAGES_ELEM, false);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 1, "reltablespace",
-						   OIDOID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 2, "reldatabase",
-						   OIDOID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 3, "relfilenode",
-						   OIDOID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 4, "relblocknumber",
-						   INT8OID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 5, "bytes",
-						   INT4OID, -1, 0);
-
-		fctx->tupdesc = BlessTupleDesc(tupledesc);
-
-		/*
-		 * Allocate numPages worth of FreeSpacePagesRec records, this is an
-		 * upper bound.
-		 */
-		fctx->record = (FreeSpacePagesRec *) palloc(sizeof(FreeSpacePagesRec) * numPages);
-
-		/* Return to original context when allocating transient memory */
-		MemoryContextSwitchTo(oldcontext);
-
-		/*
-		 * Lock free space map and scan though all the relations. For each
-		 * relation, gets all its mapped pages.
-		 */
-		LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);
-
-		i = 0;
-
-		for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
-		{
-			if (fsmrel->isIndex)
-			{
-				/* Index relation. */
-				IndexFSMPageData *page;
-
-				page = (IndexFSMPageData *)
-					(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);
-
-				for (nPages = 0; nPages < fsmrel->storedPages; nPages++)
-				{
-					fctx->record[i].reltablespace = fsmrel->key.spcNode;
-					fctx->record[i].reldatabase = fsmrel->key.dbNode;
-					fctx->record[i].relfilenode = fsmrel->key.relNode;
-					fctx->record[i].relblocknumber = IndexFSMPageGetPageNum(page);
-					fctx->record[i].bytes = 0;
-					fctx->record[i].isindex = true;
-
-					page++;
-					i++;
-				}
-			}
-			else
-			{
-				/* Heap relation. */
-				FSMPageData *page;
-
-				page = (FSMPageData *)
-					(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);
-
-				for (nPages = 0; nPages < fsmrel->storedPages; nPages++)
-				{
-					fctx->record[i].reltablespace = fsmrel->key.spcNode;
-					fctx->record[i].reldatabase = fsmrel->key.dbNode;
-					fctx->record[i].relfilenode = fsmrel->key.relNode;
-					fctx->record[i].relblocknumber = FSMPageGetPageNum(page);
-					fctx->record[i].bytes = FSMPageGetSpace(page);
-					fctx->record[i].isindex = false;
-
-					page++;
-					i++;
-				}
-			}
-		}
-
-		/* Release free space map. */
-		LWLockRelease(FreeSpaceLock);
-
-		/* Set the real no. of calls as we know it now! */
-		Assert(i <= numPages);
-		funcctx->max_calls = i;
-	}
-
-	funcctx = SRF_PERCALL_SETUP();
-
-	/* Get the saved state */
-	fctx = funcctx->user_fctx;
-
-	if (funcctx->call_cntr < funcctx->max_calls)
-	{
-		int			i = funcctx->call_cntr;
-		FreeSpacePagesRec *record = &fctx->record[i];
-		Datum		values[NUM_FREESPACE_PAGES_ELEM];
-		bool		nulls[NUM_FREESPACE_PAGES_ELEM];
-
-		values[0] = ObjectIdGetDatum(record->reltablespace);
-		nulls[0] = false;
-		values[1] = ObjectIdGetDatum(record->reldatabase);
-		nulls[1] = false;
-		values[2] = ObjectIdGetDatum(record->relfilenode);
-		nulls[2] = false;
-		values[3] = Int64GetDatum((int64) record->relblocknumber);
-		nulls[3] = false;
-
-		/*
-		 * Set (free) bytes to NULL for an index relation.
-		 */
-		if (record->isindex)
-		{
-			nulls[4] = true;
-		}
-		else
-		{
-			values[4] = UInt32GetDatum(record->bytes);
-			nulls[4] = false;
-		}
-
-		/* Build and return the tuple. */
-		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
-
-		SRF_RETURN_NEXT(funcctx, result);
-	}
-	else
-		SRF_RETURN_DONE(funcctx);
-}
-
+Datum		pg_freespace(PG_FUNCTION_ARGS);
+Datum		pg_freespacedump(PG_FUNCTION_ARGS);
 
 /*
- * Function returning relation data from the Free Space Map (FSM).
+ * Returns the amount of free space on a given page, according to the
+ * free space map.
  */
-PG_FUNCTION_INFO_V1(pg_freespacemap_relations);
+PG_FUNCTION_INFO_V1(pg_freespace);
 
 Datum
-pg_freespacemap_relations(PG_FUNCTION_ARGS)
+pg_freespace(PG_FUNCTION_ARGS)
 {
-	FuncCallContext *funcctx;
-	Datum		result;
-	MemoryContext oldcontext;
-	FreeSpaceRelationsContext *fctx;	/* User function context. */
-	TupleDesc	tupledesc;
-	HeapTuple	tuple;
-	FSMHeader  *FreeSpaceMap;	/* FSM main structure. */
-	FSMRelation *fsmrel;		/* Individual relation. */
-
-	if (SRF_IS_FIRSTCALL())
-	{
-		int			i;
-		int			numRelations;		/* Max no. of Relations in map. */
-
-		/*
-		 * Get the free space map data structure.
-		 */
-		FreeSpaceMap = GetFreeSpaceMap();
-
-		numRelations = MaxFSMRelations;
-
-		funcctx = SRF_FIRSTCALL_INIT();
-
-		/* Switch context when allocating stuff to be used in later calls */
-		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-		/*
-		 * Create a function context for cross-call persistence.
-		 */
-		fctx = (FreeSpaceRelationsContext *) palloc(sizeof(FreeSpaceRelationsContext));
-		funcctx->user_fctx = fctx;
-
-		/* Construct a tuple descriptor for the result rows. */
-		tupledesc = CreateTemplateTupleDesc(NUM_FREESPACE_RELATIONS_ELEM, false);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 1, "reltablespace",
-						   OIDOID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 2, "reldatabase",
-						   OIDOID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 3, "relfilenode",
-						   OIDOID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 4, "avgrequest",
-						   INT4OID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 5, "interestingpages",
-						   INT4OID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 6, "storedpages",
-						   INT4OID, -1, 0);
-		TupleDescInitEntry(tupledesc, (AttrNumber) 7, "nextpage",
-						   INT4OID, -1, 0);
-
-		fctx->tupdesc = BlessTupleDesc(tupledesc);
-
-		/*
-		 * Allocate numRelations worth of FreeSpaceRelationsRec records, this
-		 * is also an upper bound.
-		 */
-		fctx->record = (FreeSpaceRelationsRec *) palloc(sizeof(FreeSpaceRelationsRec) * numRelations);
-
-		/* Return to original context when allocating transient memory */
-		MemoryContextSwitchTo(oldcontext);
-
-		/*
-		 * Lock free space map and scan though all the relations.
-		 */
-		LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);
-
-		i = 0;
-
-		for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
-		{
-			fctx->record[i].reltablespace = fsmrel->key.spcNode;
-			fctx->record[i].reldatabase = fsmrel->key.dbNode;
-			fctx->record[i].relfilenode = fsmrel->key.relNode;
-			fctx->record[i].avgrequest = (int64) fsmrel->avgRequest;
-			fctx->record[i].interestingpages = fsmrel->interestingPages;
-			fctx->record[i].storedpages = fsmrel->storedPages;
-			fctx->record[i].nextpage = fsmrel->nextPage;
-			fctx->record[i].isindex = fsmrel->isIndex;
-
-			i++;
-		}
-
-		/* Release free space map. */
-		LWLockRelease(FreeSpaceLock);
-
-		/* Set the real no. of calls as we know it now! */
-		Assert(i <= numRelations);
-		funcctx->max_calls = i;
-	}
-
-	funcctx = SRF_PERCALL_SETUP();
-
-	/* Get the saved state */
-	fctx = funcctx->user_fctx;
-
-	if (funcctx->call_cntr < funcctx->max_calls)
-	{
-		int			i = funcctx->call_cntr;
-		FreeSpaceRelationsRec *record = &fctx->record[i];
-		Datum		values[NUM_FREESPACE_RELATIONS_ELEM];
-		bool		nulls[NUM_FREESPACE_RELATIONS_ELEM];
+	Oid		relid = PG_GETARG_OID(0);
+	uint32	blkno = PG_GETARG_UINT32(1);
+	int16	freespace;
+	Relation rel;
 
-		values[0] = ObjectIdGetDatum(record->reltablespace);
-		nulls[0] = false;
-		values[1] = ObjectIdGetDatum(record->reldatabase);
-		nulls[1] = false;
-		values[2] = ObjectIdGetDatum(record->relfilenode);
-		nulls[2] = false;
+	rel = relation_open(relid, AccessShareLock);
 
-		/*
-		 * avgrequest isn't meaningful for an index
-		 */
-		if (record->isindex)
-		{
-			nulls[3] = true;
-		}
-		else
-		{
-			values[3] = UInt32GetDatum(record->avgrequest);
-			nulls[3] = false;
-		}
-		values[4] = Int32GetDatum(record->interestingpages);
-		nulls[4] = false;
-		values[5] = Int32GetDatum(record->storedpages);
-		nulls[5] = false;
-		values[6] = Int32GetDatum(record->nextpage);
-		nulls[6] = false;
+	if (!BlockNumberIsValid(blkno))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid block number")));
 
-		/* Build and return the tuple. */
-		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+	freespace = GetRecordedFreeSpace(rel, blkno);
 
-		SRF_RETURN_NEXT(funcctx, result);
-	}
-	else
-		SRF_RETURN_DONE(funcctx);
+	relation_close(rel, AccessShareLock);
+	PG_RETURN_INT16(freespace);
 }
diff --git a/contrib/pg_freespacemap/pg_freespacemap.sql.in b/contrib/pg_freespacemap/pg_freespacemap.sql.in
index 0ab5e1d1eae..992fbcd9917 100644
--- a/contrib/pg_freespacemap/pg_freespacemap.sql.in
+++ b/contrib/pg_freespacemap/pg_freespacemap.sql.in
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.sql.in,v 1.9 2008/09/30 10:52:09 heikki Exp $ */
+/* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.sql.in,v 1.10 2008/09/30 11:17:07 heikki Exp $ */
 
 -- Adjust this setting to control where the objects get created.
 SET search_path = public;
diff --git a/contrib/pg_freespacemap/uninstall_pg_freespacemap.sql b/contrib/pg_freespacemap/uninstall_pg_freespacemap.sql
index 9000bc83521..a8bf64387d9 100644
--- a/contrib/pg_freespacemap/uninstall_pg_freespacemap.sql
+++ b/contrib/pg_freespacemap/uninstall_pg_freespacemap.sql
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/contrib/pg_freespacemap/uninstall_pg_freespacemap.sql,v 1.3 2007/11/13 04:24:28 momjian Exp $ */
+/* $PostgreSQL: pgsql/contrib/pg_freespacemap/uninstall_pg_freespacemap.sql,v 1.4 2008/09/30 11:17:07 heikki Exp $ */
 
 -- Adjust this setting to control where the objects get dropped.
 SET search_path = public;
-- 
GitLab