OSDN Git Service

Split out pg_freespace views to one for relations and another for pages,
authorBruce Momjian <bruce@momjian.us>
Wed, 26 Apr 2006 22:46:09 +0000 (22:46 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 26 Apr 2006 22:46:09 +0000 (22:46 +0000)
pg_freespacemap_relations and pg_freespacemap_pages.

Mark Kirkwood

contrib/pg_freespacemap/README.pg_freespacemap
contrib/pg_freespacemap/pg_freespacemap.c
contrib/pg_freespacemap/pg_freespacemap.sql.in

index 8657acc..e4340b3 100644 (file)
@@ -1,15 +1,17 @@
 Pg_freespacemap - Real time queries on the free space map (FSM).
 ---------------
 
-  This module consists of a C function 'pg_freespacemap()' that returns 
-  a set of records, and a view 'pg_freespacemap' to wrapper the function.
+  This module consists of two C functions: 'pg_freespacemap_relations()' and
+  'pg_freespacemap_pages()' that return a set of records, plus two views 
+  'pg_freespacemap_relations' and 'pg_freespacemap_pages' for more
+  user-friendly access to the functions.
 
   The module provides the ability to examine the contents of the free space
   map, without having to restart or rebuild the server with additional
   debugging code.
 
-  By default public access is REVOKED from both of these, just in case there
-  are security issues lurking.
+  By default public access is REVOKED from the functions and views, just in 
+  case there are security issues present in the code.
 
 
 Installation
@@ -22,7 +24,7 @@ Installation
   $ gmake install
 
 
-  To register the functions:
+  To register the functions and views:
 
   $ psql -d <database> -f pg_freespacemap.sql
 
@@ -30,67 +32,130 @@ Installation
 Notes
 -----
 
-  The definition of the columns exposed in the view is:
+  The definitions for the columns exposed in the views are:
+
+   pg_freespacemap_relations
 
        Column     |  references          | Description
   ----------------+----------------------+------------------------------------
    reltablespace  | pg_tablespace.oid    | Tablespace oid of the relation.
    reldatabase    | pg_database.oid      | Database for the relation.
    relfilenode    | pg_class.relfilenode | Refilenode of the relation.
-   relblocknumber |                      | Offset of the page in the relation.
-   bytes          |                      | Free bytes in the block/page, or NULL
+   avgrequest     |                      | Moving average of free space 
+                  |                      | requests.
+   lastpagecount  |                      | Count of pages examined for useful
+                  |                      | free space.
+   nextpage       |                      | page index (from 0) to start next 
+                  |                      | search at.
+
+
+   pg_freespacemap_pages
+
+       Column     |  references          | Description
+  ----------------+----------------------+------------------------------------
+   reltablespace  | pg_tablespace.oid    | Tablespace oid of the relation.
+   reldatabase    | pg_database.oid      | Database for the relation.
+   relfilenode    | pg_class.relfilenode | Refilenode of the relation.
+   relblocknumber |                      | Page offset in the relation.
+   bytes          |                      | Free bytes in the page, or NULL
                   |                      | for an index page (see below).
 
 
-  There is one row for each page in the free space map.
+  For pg_freespacemap_relations, there is one row for each relation in the free
+  space map.
+
+  For pg_freespacemap_pages, there is one row for each page in the free space 
+  map.
 
-  Because the map is shared by all the databases, there are pages from
-  relations not belonging to the current database.
+  Because the map is shared by all the databases, there are relations and pages
+  from relations not belonging to the current database.
 
-  The free space map can contain pages for btree indexes if they were emptied 
-  by a vacuum process. The bytes field is set to NULL in this case.
+  The view 'freespacemap_pages'  can contain pages for btree indexes if they 
+  were emptied by a vacuum process. The bytes field is set to NULL in this case.
 
-  When the pg_freespacemap view is accessed, internal free space map locks are
-  taken, and a copy of the map data is made for the view to display. 
-  This ensures that the view produces a consistent set of results, while not 
+  When either of the views are accessed, internal free space map locks are
+  taken, and a copy of the map data is made for them to display. 
+  This ensures that the views produce a consistent set of results, while not 
   blocking normal activity longer than necessary.  Nonetheless there 
-  could be some impact on database performance if this view is read often.
+  could be some impact on database performance if they are read often.
 
 
-Sample output
+Sample output - pg_freespacemap_relations
 -------------
 
-  regression=# \d pg_freespacemap
-     View "public.pg_freespacemap"
-      Column     |  Type   | Modifiers 
- ----------------+---------+-----------
-  reltablespace  | oid     | 
-  reldatabase    | oid     | 
-  relfilenode    | oid     | 
-  relblocknumber | bigint  | 
-  bytes          | integer | 
- View definition:
+regression=# \d pg_freespacemap_relations
+View "public.pg_freespacemap_relations"
+    Column     |  Type   | Modifiers 
+---------------+---------+-----------
+ reltablespace | oid     | 
+ reldatabase   | oid     | 
+ relfilenode   | oid     | 
+ avgrequest    | bigint  | 
+ lastpagecount | integer | 
+ nextpage      | integer | 
+View definition:
+ SELECT p.reltablespace, p.reldatabase, p.relfilenode, p.avgrequest, p.lastpagecount, p.nextpage
+   FROM pg_freespacemap_relations() p(reltablespace oid, reldatabase oid, relfilenode oid, avgrequest bigint, lastpagecount integer, nextpage integer);
+
+regression=# SELECT c.relname, r.avgrequest, r.lastpagecount, r.nextpage
+             FROM pg_freespacemap_relations r INNER JOIN pg_class c
+             ON c.relfilenode = r.relfilenode INNER JOIN pg_database d
+             ON r.reldatabase = d.oid AND (d.datname = current_database()) 
+             ORDER BY c.relname LIMIT 10;
+   relname    | avgrequest | lastpagecount | nextpage 
+--------------+------------+---------------+----------
+ a_star       |        250 |             1 |        0
+ abstime_tbl  |        249 |             1 |        0
+ aggtest      |        250 |             1 |        0
+ altinhoid    |        250 |             1 |        0
+ altstartwith |        250 |             1 |        0
+ arrtest      |        254 |             1 |        0
+ b_star       |        250 |             1 |        0
+ box_tbl      |        250 |             1 |        0
+ bt_f8_heap   |         92 |             1 |        0
+ bt_i4_heap   |         94 |             1 |        0
+(10 rows)
+
+regression=# 
+
+
+Sample output - pg_freespacemap_pages
+-------------
+
+regression=# \d pg_freespacemap_pages;
+ View "public.pg_freespacemap_pages"
+     Column     |  Type   | Modifiers 
+----------------+---------+-----------
+ reltablespace  | oid     | 
+ reldatabase    | oid     | 
+ relfilenode    | oid     | 
+ relblocknumber | bigint  | 
+ bytes          | integer | 
+View definition:
  SELECT p.reltablespace, p.reldatabase, p.relfilenode, p.relblocknumber, p.bytes
- FROM pg_freespacemap() p(reltablespace oid, reldatabase oid, relfilenode oid, relblocknumber bigint, bytes integer);
-
-  regression=# SELECT c.relname, m.relblocknumber, m.bytes  
-               FROM pg_freespacemap m INNER JOIN pg_class c 
-               ON c.relfilenode = m.relfilenode LIMIT 10;
-      relname             | relblocknumber |  bytes 
-  ------------------------+----------------+--------
-  sql_features            |              5 |   2696
-  sql_implementation_info |              0 |   7104
-  sql_languages           |              0 |   8016
-  sql_packages            |              0 |   7376
-  sql_sizing              |              0 |   6032
-  pg_authid               |              0 |   7424
-  pg_toast_2618           |             13 |   4588
-  pg_toast_2618           |             12 |   1680
-  pg_toast_2618           |             10 |   1436
-  pg_toast_2618           |              7 |   1136
-  (10 rows)
-
-  regression=# 
+   FROM pg_freespacemap_pages() p(reltablespace oid, reldatabase oid, relfilenode oid, relblocknumber bigint, bytes integer);
+
+regression=# SELECT c.relname, p.relblocknumber, p.bytes
+             FROM pg_freespacemap_pages p INNER JOIN pg_class c
+             ON c.relfilenode = p.relfilenode INNER JOIN pg_database d
+             ON (p.reldatabase = d.oid AND d.datname = current_database()) 
+             ORDER BY c.relname LIMIT 10;
+   relname    | relblocknumber | bytes 
+--------------+----------------+-------
+ a_star       |              0 |  8040
+ abstime_tbl  |              0 |  7908
+ aggtest      |              0 |  8008
+ altinhoid    |              0 |  8128
+ altstartwith |              0 |  8128
+ arrtest      |              0 |  7172
+ b_star       |              0 |  7976
+ box_tbl      |              0 |  7912
+ bt_f8_heap   |             54 |  7728
+ bt_i4_heap   |             49 |  8008
+(10 rows)
+
+regression=# 
+
 
 
 Author
index 7225be2..4b29801 100644 (file)
@@ -1,9 +1,9 @@
 /*-------------------------------------------------------------------------
  *
  * pg_freespacemap.c
- *       display some contents of the free space map.
+ *       display some contents of the free space relation and page maps.
  *
- *       $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.3 2006/04/26 22:41:18 momjian Exp $
+ *       $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.4 2006/04/26 22:46:09 momjian Exp $
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 #include "utils/relcache.h"
 
 #define                NUM_FREESPACE_PAGES_ELEM        5
+#define                NUM_FREESPACE_RELATIONS_ELEM    6
 
 #if defined(WIN32) || defined(__CYGWIN__)
 /* Need DLLIMPORT for some things that are not so marked in main headers */
 extern DLLIMPORT int   MaxFSMPages;
+extern DLLIMPORT int   MaxFSMRelations;
 extern DLLIMPORT volatile uint32 InterruptHoldoffCount;
 #endif
 
-Datum          pg_freespacemap(PG_FUNCTION_ARGS);
+Datum          pg_freespacemap_pages(PG_FUNCTION_ARGS);
+Datum          pg_freespacemap_relations(PG_FUNCTION_ARGS);
 
 
 /*
- * Record structure holding the to be exposed free space data.
+ * Record structure holding the to be exposed free space page data.
  */
 typedef struct
 {
@@ -40,7 +43,24 @@ typedef struct
 
 
 /*
- * Function context for data persisting over repeated calls.
+ * Record structure holding the to be exposed free space relation data.
+ */
+typedef struct
+{
+
+       uint32                          reltablespace;
+       uint32                          reldatabase;
+       uint32                          relfilenode;
+       int64                           avgrequest;
+       int                                     lastpagecount;
+       int                                     nextpage;
+
+}      FreeSpaceRelationsRec;
+
+
+
+/*
+ * Function context for page data persisting over repeated calls.
  */
 typedef struct
 {
@@ -53,11 +73,24 @@ typedef struct
 
 
 /*
- * Function returning data from the Free Space Map (FSM).
+ * Function context for relation data persisting over repeated calls.
+ */
+typedef struct
+{
+
+       AttInMetadata           *attinmeta;
+       FreeSpaceRelationsRec   *record;
+       char                            *values[NUM_FREESPACE_RELATIONS_ELEM];
+
+}      FreeSpaceRelationsContext;
+
+
+/*
+ * Function returning page data from the Free Space Map (FSM).
  */
-PG_FUNCTION_INFO_V1(pg_freespacemap);
+PG_FUNCTION_INFO_V1(pg_freespacemap_pages);
 Datum
-pg_freespacemap(PG_FUNCTION_ARGS)
+pg_freespacemap_pages(PG_FUNCTION_ARGS)
 {
 
        FuncCallContext                 *funcctx;
@@ -250,3 +283,162 @@ pg_freespacemap(PG_FUNCTION_ARGS)
                SRF_RETURN_DONE(funcctx);
 
 }
+
+
+/*
+ * Function returning relation data from the Free Space Map (FSM).
+ */
+PG_FUNCTION_INFO_V1(pg_freespacemap_relations);
+Datum
+pg_freespacemap_relations(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())
+       {
+               uint32                          i;
+               uint32                          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);
+
+               /* Construct a tuple to return. */
+               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",
+                                                  INT8OID, -1, 0);
+               TupleDescInitEntry(tupledesc, (AttrNumber) 5, "lastpageCount",
+                                                  INT4OID, -1, 0);
+               TupleDescInitEntry(tupledesc, (AttrNumber) 6, "nextpage",
+                                                  INT4OID, -1, 0);
+
+               /* Generate attribute metadata needed later to produce tuples */
+               funcctx->attinmeta = TupleDescGetAttInMetadata(tupledesc);
+
+               /*
+                * Create a function context for cross-call persistence and initialize
+                * the counters.
+                */
+               fctx = (FreeSpaceRelationsContext *) palloc(sizeof(FreeSpaceRelationsContext));
+               funcctx->user_fctx = fctx;
+
+               /* Set an upper bound on the calls */
+               funcctx->max_calls = numRelations;      
+
+
+               /* Allocate numRelations worth of FreeSpaceRelationsRec records, 
+                * this is also an upper bound.
+                */
+               fctx->record = (FreeSpaceRelationsRec *) palloc(sizeof(FreeSpaceRelationsRec) * numRelations);
+
+               /* allocate the strings for tuple formation */
+               fctx->values[0] = (char *) palloc(3 * sizeof(uint32) + 1);
+               fctx->values[1] = (char *) palloc(3 * sizeof(uint32) + 1);
+               fctx->values[2] = (char *) palloc(3 * sizeof(uint32) + 1);
+               fctx->values[3] = (char *) palloc(3 * sizeof(int64) + 1);
+               fctx->values[4] = (char *) palloc(3 * sizeof(int32) + 1);
+               fctx->values[5] = (char *) palloc(3 * sizeof(int32) + 1);
+
+
+               /* 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].lastpagecount = fsmrel->lastPageCount;
+                       fctx->record[i].nextpage = fsmrel->nextPage;
+
+                       i++;
+
+
+               }
+
+               /* Set the real no. of calls as we know it now! */
+               funcctx->max_calls = i;
+
+               /* Release free space map. */
+               LWLockRelease(FreeSpaceLock);
+       }
+
+       funcctx = SRF_PERCALL_SETUP();
+
+       /* Get the saved state */
+       fctx = funcctx->user_fctx;
+
+
+       if (funcctx->call_cntr < funcctx->max_calls)
+       {
+               uint32          i = funcctx->call_cntr;
+               char            *values[NUM_FREESPACE_RELATIONS_ELEM];
+               int                     j;
+
+               /*
+                * Use a temporary values array, initially pointing to fctx->values,
+                * so it can be reassigned w/o losing the storage for subsequent
+                * calls.
+                */
+               for (j = 0; j < NUM_FREESPACE_RELATIONS_ELEM; j++)
+               {
+                       values[j] = fctx->values[j];
+               }
+
+
+               sprintf(values[0], "%u", fctx->record[i].reltablespace);
+               sprintf(values[1], "%u", fctx->record[i].reldatabase);
+               sprintf(values[2], "%u", fctx->record[i].relfilenode);
+               sprintf(values[3], INT64_FORMAT, fctx->record[i].avgrequest);
+               sprintf(values[4], "%d", fctx->record[i].lastpagecount);
+               sprintf(values[5], "%d", fctx->record[i].nextpage);
+
+
+
+               /* Build and return the tuple. */
+               tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+               result = HeapTupleGetDatum(tuple);
+
+
+               SRF_RETURN_NEXT(funcctx, result);
+       }
+       else
+               SRF_RETURN_DONE(funcctx);
+
+
+}
index b690269..ff0619b 100644 (file)
@@ -2,18 +2,34 @@
 BEGIN;
 SET search_path = public;
 
--- Register the function.
-CREATE OR REPLACE FUNCTION pg_freespacemap()
+
+-- Register the functions.
+CREATE OR REPLACE FUNCTION pg_freespacemap_pages()
 RETURNS SETOF RECORD
-AS 'MODULE_PATHNAME', 'pg_freespacemap'
+AS 'MODULE_PATHNAME', 'pg_freespacemap_pages'
 LANGUAGE C;
 
--- Create a view for convenient access.
-CREATE VIEW pg_freespacemap AS
-       SELECT P.* FROM pg_freespacemap() AS P
+CREATE OR REPLACE FUNCTION pg_freespacemap_relations()
+RETURNS SETOF RECORD
+AS 'MODULE_PATHNAME', 'pg_freespacemap_relations'
+LANGUAGE C;
+
+
+-- Create views for convenient access.
+CREATE VIEW pg_freespacemap_pages AS
+       SELECT P.* FROM pg_freespacemap_pages() AS P
        (reltablespace oid, reldatabase oid, relfilenode oid, relblocknumber int8, bytes int4);
  
+CREATE VIEW pg_freespacemap_relations AS
+       SELECT P.* FROM pg_freespacemap_relations() AS P
+       (reltablespace oid, reldatabase oid, relfilenode oid, avgrequest int8, lastpagecount integer, nextpage integer);
+
 -- Don't want these to be available at public.
-REVOKE ALL ON FUNCTION pg_freespacemap() FROM PUBLIC;
-REVOKE ALL ON pg_freespacemap FROM PUBLIC;
+REVOKE ALL ON FUNCTION pg_freespacemap_pages() FROM PUBLIC;
+REVOKE ALL ON pg_freespacemap_pages FROM PUBLIC;
+
+REVOKE ALL ON FUNCTION pg_freespacemap_relations() FROM PUBLIC;
+REVOKE ALL ON pg_freespacemap_relations FROM PUBLIC;
+
 COMMIT;