1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Add contrib/pg_freespacemap to display free space map information.

Mark Kirkwood
This commit is contained in:
Bruce Momjian
2006-02-12 03:55:53 +00:00
parent 6c0d4aabe2
commit d5dd3d451e
8 changed files with 481 additions and 98 deletions

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.50 2005/10/29 00:31:51 petere Exp $
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.51 2006/02/12 03:55:53 momjian Exp $
*
*
* NOTES:
@ -71,44 +71,6 @@
#include "storage/shmem.h"
/* Initial value for average-request moving average */
#define INITIAL_AVERAGE ((Size) (BLCKSZ / 32))
/*
* Number of pages and bytes per allocation chunk. Indexes can squeeze 50%
* more pages into the same space because they don't need to remember how much
* free space on each page. The nominal number of pages, CHUNKPAGES, is for
* regular rels, and INDEXCHUNKPAGES is for indexes. CHUNKPAGES should be
* even so that no space is wasted in the index case.
*/
#define CHUNKPAGES 16
#define CHUNKBYTES (CHUNKPAGES * sizeof(FSMPageData))
#define INDEXCHUNKPAGES ((int) (CHUNKBYTES / sizeof(IndexFSMPageData)))
/*
* Typedefs and macros for items in the page-storage arena. We use the
* existing ItemPointer and BlockId data structures, which are designed
* to pack well (they should be 6 and 4 bytes apiece regardless of machine
* alignment issues). Unfortunately we can't use the ItemPointer access
* macros, because they include Asserts insisting that ip_posid != 0.
*/
typedef ItemPointerData FSMPageData;
typedef BlockIdData IndexFSMPageData;
#define FSMPageGetPageNum(ptr) \
BlockIdGetBlockNumber(&(ptr)->ip_blkid)
#define FSMPageGetSpace(ptr) \
((Size) (ptr)->ip_posid)
#define FSMPageSetPageNum(ptr, pg) \
BlockIdSet(&(ptr)->ip_blkid, pg)
#define FSMPageSetSpace(ptr, sz) \
((ptr)->ip_posid = (OffsetNumber) (sz))
#define IndexFSMPageGetPageNum(ptr) \
BlockIdGetBlockNumber(ptr)
#define IndexFSMPageSetPageNum(ptr, pg) \
BlockIdSet(ptr, pg)
/*----------
* During database shutdown, we store the contents of FSM into a disk file,
* which is re-read during startup. This way we don't have a startup
@ -156,63 +118,6 @@ typedef struct FsmCacheRelHeader
int32 storedPages; /* # of pages stored in arena */
} FsmCacheRelHeader;
/*
* Shared free-space-map objects
*
* The per-relation objects are indexed by a hash table, and are also members
* of two linked lists: one ordered by recency of usage (most recent first),
* and the other ordered by physical location of the associated storage in
* the page-info arena.
*
* Each relation owns one or more chunks of per-page storage in the "arena".
* The chunks for each relation are always consecutive, so that it can treat
* its page storage as a simple array. We further insist that its page data
* be ordered by block number, so that binary search is possible.
*
* Note: we handle pointers to these items as pointers, not as SHMEM_OFFSETs.
* This assumes that all processes accessing the map will have the shared
* memory segment mapped at the same place in their address space.
*/
typedef struct FSMHeader FSMHeader;
typedef struct FSMRelation FSMRelation;
/* Header for whole map */
struct FSMHeader
{
FSMRelation *usageList; /* FSMRelations in usage-recency order */
FSMRelation *usageListTail; /* tail of usage-recency list */
FSMRelation *firstRel; /* FSMRelations in arena storage order */
FSMRelation *lastRel; /* tail of storage-order list */
int numRels; /* number of FSMRelations now in use */
double sumRequests; /* sum of requested chunks over all rels */
char *arena; /* arena for page-info storage */
int totalChunks; /* total size of arena, in chunks */
int usedChunks; /* # of chunks assigned */
/* NB: there are totalChunks - usedChunks free chunks at end of arena */
};
/*
* Per-relation struct --- this is an entry in the shared hash table.
* The hash key is the RelFileNode value (hence, we look at the physical
* relation ID, not the logical ID, which is appropriate).
*/
struct FSMRelation
{
RelFileNode key; /* hash key (must be first) */
FSMRelation *nextUsage; /* next rel in usage-recency order */
FSMRelation *priorUsage; /* prior rel in usage-recency order */
FSMRelation *nextPhysical; /* next rel in arena-storage order */
FSMRelation *priorPhysical; /* prior rel in arena-storage order */
bool isIndex; /* if true, we store only page numbers */
Size avgRequest; /* moving average of space requests */
int lastPageCount; /* pages passed to RecordRelationFreeSpace */
int firstChunk; /* chunk # of my first chunk in arena */
int storedPages; /* # of pages stored in arena */
int nextPage; /* index (from 0) to start next search at */
};
int MaxFSMRelations; /* these are set by guc.c */
int MaxFSMPages;
@ -1838,6 +1743,17 @@ fsm_current_allocation(FSMRelation *fsmrel)
}
/*
* Return the FreeSpaceMap structure for examination.
*/
FSMHeader *
GetFreeSpaceMap(void)
{
return FreeSpaceMap;
}
#ifdef FREESPACE_DEBUG
/*
* Dump contents of freespace map for debugging.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/storage/freespace.h,v 1.18 2005/08/20 23:26:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/storage/freespace.h,v 1.19 2006/02/12 03:55:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,7 @@
#include "storage/block.h"
#include "storage/relfilenode.h"
#include "storage/itemptr.h"
/*
@ -28,6 +29,101 @@ typedef struct PageFreeSpaceInfo
} PageFreeSpaceInfo;
/* Initial value for average-request moving average */
#define INITIAL_AVERAGE ((Size) (BLCKSZ / 32))
/*
* Number of pages and bytes per allocation chunk. Indexes can squeeze 50%
* more pages into the same space because they don't need to remember how much
* free space on each page. The nominal number of pages, CHUNKPAGES, is for
* regular rels, and INDEXCHUNKPAGES is for indexes. CHUNKPAGES should be
* even so that no space is wasted in the index case.
*/
#define CHUNKPAGES 16
#define CHUNKBYTES (CHUNKPAGES * sizeof(FSMPageData))
#define INDEXCHUNKPAGES ((int) (CHUNKBYTES / sizeof(IndexFSMPageData)))
/*
* Typedefs and macros for items in the page-storage arena. We use the
* existing ItemPointer and BlockId data structures, which are designed
* to pack well (they should be 6 and 4 bytes apiece regardless of machine
* alignment issues). Unfortunately we can't use the ItemPointer access
* macros, because they include Asserts insisting that ip_posid != 0.
*/
typedef ItemPointerData FSMPageData;
typedef BlockIdData IndexFSMPageData;
#define FSMPageGetPageNum(ptr) \
BlockIdGetBlockNumber(&(ptr)->ip_blkid)
#define FSMPageGetSpace(ptr) \
((Size) (ptr)->ip_posid)
#define FSMPageSetPageNum(ptr, pg) \
BlockIdSet(&(ptr)->ip_blkid, pg)
#define FSMPageSetSpace(ptr, sz) \
((ptr)->ip_posid = (OffsetNumber) (sz))
#define IndexFSMPageGetPageNum(ptr) \
BlockIdGetBlockNumber(ptr)
#define IndexFSMPageSetPageNum(ptr, pg) \
BlockIdSet(ptr, pg)
/*
* Shared free-space-map objects
*
* The per-relation objects are indexed by a hash table, and are also members
* of two linked lists: one ordered by recency of usage (most recent first),
* and the other ordered by physical location of the associated storage in
* the page-info arena.
*
* Each relation owns one or more chunks of per-page storage in the "arena".
* The chunks for each relation are always consecutive, so that it can treat
* its page storage as a simple array. We further insist that its page data
* be ordered by block number, so that binary search is possible.
*
* Note: we handle pointers to these items as pointers, not as SHMEM_OFFSETs.
* This assumes that all processes accessing the map will have the shared
* memory segment mapped at the same place in their address space.
*/
typedef struct FSMHeader FSMHeader;
typedef struct FSMRelation FSMRelation;
/* Header for whole map */
struct FSMHeader
{
FSMRelation *usageList; /* FSMRelations in usage-recency order */
FSMRelation *usageListTail; /* tail of usage-recency list */
FSMRelation *firstRel; /* FSMRelations in arena storage order */
FSMRelation *lastRel; /* tail of storage-order list */
int numRels; /* number of FSMRelations now in use */
double sumRequests; /* sum of requested chunks over all rels */
char *arena; /* arena for page-info storage */
int totalChunks; /* total size of arena, in chunks */
int usedChunks; /* # of chunks assigned */
/* NB: there are totalChunks - usedChunks free chunks at end of arena */
};
/*
* Per-relation struct --- this is an entry in the shared hash table.
* The hash key is the RelFileNode value (hence, we look at the physical
* relation ID, not the logical ID, which is appropriate).
*/
struct FSMRelation
{
RelFileNode key; /* hash key (must be first) */
FSMRelation *nextUsage; /* next rel in usage-recency order */
FSMRelation *priorUsage; /* prior rel in usage-recency order */
FSMRelation *nextPhysical; /* next rel in arena-storage order */
FSMRelation *priorPhysical; /* prior rel in arena-storage order */
bool isIndex; /* if true, we store only page numbers */
Size avgRequest; /* moving average of space requests */
int lastPageCount; /* pages passed to RecordRelationFreeSpace */
int firstChunk; /* chunk # of my first chunk in arena */
int storedPages; /* # of pages stored in arena */
int nextPage; /* index (from 0) to start next search at */
};
/* GUC variables */
extern int MaxFSMRelations;
extern int MaxFSMPages;
@ -62,6 +158,7 @@ extern void PrintFreeSpaceMapStatistics(int elevel);
extern void DumpFreeSpaceMap(int code, Datum arg);
extern void LoadFreeSpaceMap(void);
extern FSMHeader *GetFreeSpaceMap(void);
#ifdef FREESPACE_DEBUG
extern void DumpFreeSpace(void);