Rewrite pg_freespacemap to match the new FSM implementation. I missed these
authorHeikki Linnakangas
Tue, 30 Sep 2008 11:17:07 +0000 (11:17 +0000)
committerHeikki Linnakangas
Tue, 30 Sep 2008 11:17:07 +0000 (11:17 +0000)
changes from the main FSM commit for some reason.

contrib/pg_freespacemap/Makefile
contrib/pg_freespacemap/pg_freespacemap.c
contrib/pg_freespacemap/pg_freespacemap.sql.in
contrib/pg_freespacemap/uninstall_pg_freespacemap.sql

index 5631ef5d54bf1f0af124aea2a5b82fa15bd1307d..daeab59d46fcab7c10b6b9cf107abfa8f4736d1c 100644 (file)
@@ -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
index 22f9f7f779bbc8a59df320d426d478846d2be780..57a7e4490d8c220e04598b3e9c16c9680af344a8 100644 (file)
 /*-------------------------------------------------------------------------
  *
  * 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);
 }
index 0ab5e1d1eae6fdc00cd01aa9455b0a0faa6e7ecb..992fbcd99174a39d9926567088aa0c020dc74547 100644 (file)
@@ -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;
index 9000bc83521183f314407b288fdbc58c54aa0436..a8bf64387d9ce1dc30d4c0b109a6c9bfbc47e91b 100644 (file)
@@ -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;