diff options
Diffstat (limited to 'src/backend/storage/freespace/freespace.c')
-rw-r--r-- | src/backend/storage/freespace/freespace.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c new file mode 100644 index 00000000000..84f7066348e --- /dev/null +++ b/src/backend/storage/freespace/freespace.c @@ -0,0 +1,183 @@ +/*------------------------------------------------------------------------- + * + * freespace.c + * POSTGRES free space map for quickly finding free space in relations + * + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/storage/freespace/freespace.c,v 1.1 2001/06/27 23:31:39 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "storage/freespace.h" +#include "storage/itemid.h" +#include "storage/shmem.h" + + +/* + * Shared free-space-map objects + * + * 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; +typedef struct FSMChunk FSMChunk; + +/* Header for whole map */ +struct FSMHeader +{ + HTAB *relationHash; /* hashtable of FSMRelation entries */ + FSMRelation *relationList; /* FSMRelations in order by recency of use */ + int numRelations; /* number of FSMRelations now in use */ + FSMChunk *freeChunks; /* linked list of currently-free chunks */ +}; + +/* + * 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 *nextRel; /* next rel in order by recency of use */ + FSMRelation *priorRel; /* prior rel in order by recency of use */ + FSMChunk *relChunks; /* linked list of page info chunks */ +}; + +#define SHMEM_FSMHASH_KEYSIZE sizeof(RelFileNode) +#define SHMEM_FSMHASH_DATASIZE (sizeof(FSMRelation) - SHMEM_FSMHASH_KEYSIZE) + +#define CHUNKPAGES 32 /* each chunk can store this many pages */ + +struct FSMChunk +{ + FSMChunk *next; /* linked-list link */ + int numPages; /* number of pages described here */ + BlockNumber pages[CHUNKPAGES]; /* page numbers within relation */ + ItemLength bytes[CHUNKPAGES]; /* free space available on each page */ +}; + + +SPINLOCK FreeSpaceLock; /* in Shmem or created in + * CreateSpinlocks() */ + +int MaxFSMRelations; /* these are set by guc.c */ +int MaxFSMPages; + +static FSMHeader *FreeSpaceMap; /* points to FSMHeader in shared memory */ + + +/* + * InitFreeSpaceMap -- Initialize the freespace module. + * + * This must be called once during shared memory initialization. + * It builds the empty free space map table. FreeSpaceLock must also be + * initialized at some point, but is not touched here --- we assume there is + * no need for locking, since only the calling process can be accessing shared + * memory as yet. FreeSpaceShmemSize() was called previously while computing + * the space needed for shared memory. + */ +void +InitFreeSpaceMap(void) +{ + HASHCTL info; + FSMChunk *chunks, + *prevchunk; + int nchunks; + + /* Create table header */ + FreeSpaceMap = (FSMHeader *) ShmemAlloc(sizeof(FSMHeader)); + if (FreeSpaceMap == NULL) + elog(FATAL, "Insufficient shared memory for free space map"); + MemSet(FreeSpaceMap, 0, sizeof(FSMHeader)); + + /* Create hashtable for FSMRelations */ + info.keysize = SHMEM_FSMHASH_KEYSIZE; + info.datasize = SHMEM_FSMHASH_DATASIZE; + info.hash = tag_hash; + + FreeSpaceMap->relationHash = ShmemInitHash("Free Space Map Hash", + MaxFSMRelations / 10, + MaxFSMRelations, + &info, + (HASH_ELEM | HASH_FUNCTION)); + + if (!FreeSpaceMap->relationHash) + elog(FATAL, "Insufficient shared memory for free space map"); + + /* Allocate FSMChunks and fill up the free-chunks list */ + nchunks = (MaxFSMPages - 1) / CHUNKPAGES + 1; + + chunks = (FSMChunk *) ShmemAlloc(nchunks * sizeof(FSMChunk)); + if (chunks == NULL) + elog(FATAL, "Insufficient shared memory for free space map"); + + prevchunk = NULL; + while (nchunks-- > 0) + { + chunks->next = prevchunk; + prevchunk = chunks; + chunks++; + } + FreeSpaceMap->freeChunks = prevchunk; +} + + +int +FreeSpaceShmemSize(void) +{ + int size; + int nchunks; + + /* + * There is no point in allowing less than one "chunk" per relation, + * so force MaxFSMPages to be at least CHUNKPAGES * MaxFSMRelations. + */ + Assert(MaxFSMRelations > 0); + if (MaxFSMPages < CHUNKPAGES * MaxFSMRelations) + MaxFSMPages = CHUNKPAGES * MaxFSMRelations; + + /* table header */ + size = MAXALIGN(sizeof(FSMHeader)); + + /* hash table, including the FSMRelation objects */ + size += hash_estimate_size(MaxFSMRelations, + SHMEM_FSMHASH_KEYSIZE, + SHMEM_FSMHASH_DATASIZE); + + /* FSMChunk objects */ + nchunks = (MaxFSMPages - 1) / CHUNKPAGES + 1; + + size += MAXALIGN(nchunks * sizeof(FSMChunk)); + + return size; +} + + +void +FreeSpaceMapForgetRel(RelFileNode *rel) +{ +} + + +#ifdef FREESPACE_DEBUG +/* + * Dump contents of freespace map for debugging. + * + * We assume caller holds the FreeSpaceLock, or is otherwise unconcerned + * about other processes. + */ +void +DumpFreeSpace(void) +{ +} + +#endif /* FREESPACE_DEBUG */ |