Split out pg_freespace views to one for relations and another for pages,

pg_freespacemap_relations and pg_freespacemap_pages.

Mark Kirkwood
This commit is contained in:
Bruce Momjian 2006-04-26 22:46:09 +00:00
parent 028ec5cb0f
commit 136bea1540
3 changed files with 335 additions and 62 deletions

View 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.
Because the map is shared by all the databases, there are pages from
relations not belonging to the current database.
For pg_freespacemap_pages, there is one row for each page in the free space
map.
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.
Because the map is shared by all the databases, there are relations and pages
from relations not belonging to the current database.
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
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 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);
FROM pg_freespacemap_pages() 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=# 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=#
regression=#
Author

View 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"
@ -13,18 +13,21 @@
#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.
*/
PG_FUNCTION_INFO_V1(pg_freespacemap);
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_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);
}

View 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;