mirror of https://github.com/postgres/postgres
changes from the main FSM commit for some reason.REL8_5_ALPHA1_BRANCH
parent
4e6ac2e19b
commit
d3de08a008
@ -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); |
||||
Oid relid = PG_GETARG_OID(0); |
||||
uint32 blkno = PG_GETARG_UINT32(1); |
||||
int16 freespace; |
||||
Relation rel; |
||||
|
||||
/*
|
||||
* 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; |
||||
} |
||||
rel = relation_open(relid, AccessShareLock); |
||||
|
||||
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]; |
||||
|
||||
values[0] = ObjectIdGetDatum(record->reltablespace); |
||||
nulls[0] = false; |
||||
values[1] = ObjectIdGetDatum(record->reldatabase); |
||||
nulls[1] = false; |
||||
values[2] = ObjectIdGetDatum(record->relfilenode); |
||||
nulls[2] = false; |
||||
|
||||
/*
|
||||
* 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); |
||||
} |
||||
|
Loading…
Reference in new issue