From: Heikki Linnakangas Date: Tue, 30 Sep 2008 11:17:07 +0000 (+0000) Subject: Rewrite pg_freespacemap to match the new FSM implementation. I missed these X-Git-Tag: REL8_4_BETA1~944 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d3de08a008252aba78ce9e5ca8c83d34dbbc0418;p=postgresql Rewrite pg_freespacemap to match the new FSM implementation. I missed these changes from the main FSM commit for some reason. --- diff --git a/contrib/pg_freespacemap/Makefile b/contrib/pg_freespacemap/Makefile index 5631ef5d54..daeab59d46 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 22f9f7f779..57a7e4490d 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 0ab5e1d1ea..992fbcd991 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 9000bc8352..a8bf64387d 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;