]> granicus.if.org Git - postgresql/commitdiff
Rewrite pg_freespacemap to match the new FSM implementation. I missed these
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 30 Sep 2008 11:17:07 +0000 (11:17 +0000)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
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;