1 /*-------------------------------------------------------------------------
4 * POSTGRES free space map for quickly finding free space in relations
7 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * $PostgreSQL: pgsql/src/include/storage/freespace.h,v 1.20 2006/03/05 15:58:59 momjian Exp $
12 *-------------------------------------------------------------------------
17 #include "storage/block.h"
18 #include "storage/relfilenode.h"
19 #include "storage/itemptr.h"
25 typedef struct PageFreeSpaceInfo
27 BlockNumber blkno; /* which page in relation */
28 Size avail; /* space available on this page */
32 /* Initial value for average-request moving average */
33 #define INITIAL_AVERAGE ((Size) (BLCKSZ / 32))
36 * Number of pages and bytes per allocation chunk. Indexes can squeeze 50%
37 * more pages into the same space because they don't need to remember how much
38 * free space on each page. The nominal number of pages, CHUNKPAGES, is for
39 * regular rels, and INDEXCHUNKPAGES is for indexes. CHUNKPAGES should be
40 * even so that no space is wasted in the index case.
43 #define CHUNKBYTES (CHUNKPAGES * sizeof(FSMPageData))
44 #define INDEXCHUNKPAGES ((int) (CHUNKBYTES / sizeof(IndexFSMPageData)))
48 * Typedefs and macros for items in the page-storage arena. We use the
49 * existing ItemPointer and BlockId data structures, which are designed
50 * to pack well (they should be 6 and 4 bytes apiece regardless of machine
51 * alignment issues). Unfortunately we can't use the ItemPointer access
52 * macros, because they include Asserts insisting that ip_posid != 0.
54 typedef ItemPointerData FSMPageData;
55 typedef BlockIdData IndexFSMPageData;
57 #define FSMPageGetPageNum(ptr) \
58 BlockIdGetBlockNumber(&(ptr)->ip_blkid)
59 #define FSMPageGetSpace(ptr) \
60 ((Size) (ptr)->ip_posid)
61 #define FSMPageSetPageNum(ptr, pg) \
62 BlockIdSet(&(ptr)->ip_blkid, pg)
63 #define FSMPageSetSpace(ptr, sz) \
64 ((ptr)->ip_posid = (OffsetNumber) (sz))
65 #define IndexFSMPageGetPageNum(ptr) \
66 BlockIdGetBlockNumber(ptr)
67 #define IndexFSMPageSetPageNum(ptr, pg) \
71 * Shared free-space-map objects
73 * The per-relation objects are indexed by a hash table, and are also members
74 * of two linked lists: one ordered by recency of usage (most recent first),
75 * and the other ordered by physical location of the associated storage in
76 * the page-info arena.
78 * Each relation owns one or more chunks of per-page storage in the "arena".
79 * The chunks for each relation are always consecutive, so that it can treat
80 * its page storage as a simple array. We further insist that its page data
81 * be ordered by block number, so that binary search is possible.
83 * Note: we handle pointers to these items as pointers, not as SHMEM_OFFSETs.
84 * This assumes that all processes accessing the map will have the shared
85 * memory segment mapped at the same place in their address space.
87 typedef struct FSMHeader FSMHeader;
88 typedef struct FSMRelation FSMRelation;
90 /* Header for whole map */
93 FSMRelation *usageList; /* FSMRelations in usage-recency order */
94 FSMRelation *usageListTail; /* tail of usage-recency list */
95 FSMRelation *firstRel; /* FSMRelations in arena storage order */
96 FSMRelation *lastRel; /* tail of storage-order list */
97 int numRels; /* number of FSMRelations now in use */
98 double sumRequests; /* sum of requested chunks over all rels */
99 char *arena; /* arena for page-info storage */
100 int totalChunks; /* total size of arena, in chunks */
101 int usedChunks; /* # of chunks assigned */
102 /* NB: there are totalChunks - usedChunks free chunks at end of arena */
106 * Per-relation struct --- this is an entry in the shared hash table.
107 * The hash key is the RelFileNode value (hence, we look at the physical
108 * relation ID, not the logical ID, which is appropriate).
112 RelFileNode key; /* hash key (must be first) */
113 FSMRelation *nextUsage; /* next rel in usage-recency order */
114 FSMRelation *priorUsage; /* prior rel in usage-recency order */
115 FSMRelation *nextPhysical; /* next rel in arena-storage order */
116 FSMRelation *priorPhysical; /* prior rel in arena-storage order */
117 bool isIndex; /* if true, we store only page numbers */
118 Size avgRequest; /* moving average of space requests */
119 int lastPageCount; /* pages passed to RecordRelationFreeSpace */
120 int firstChunk; /* chunk # of my first chunk in arena */
121 int storedPages; /* # of pages stored in arena */
122 int nextPage; /* index (from 0) to start next search at */
128 extern int MaxFSMRelations;
129 extern int MaxFSMPages;
133 * function prototypes
135 extern void InitFreeSpaceMap(void);
136 extern Size FreeSpaceShmemSize(void);
138 extern BlockNumber GetPageWithFreeSpace(RelFileNode *rel, Size spaceNeeded);
139 extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel,
143 extern Size GetAvgFSMRequestSize(RelFileNode *rel);
144 extern void RecordRelationFreeSpace(RelFileNode *rel,
146 PageFreeSpaceInfo *pageSpaces);
148 extern BlockNumber GetFreeIndexPage(RelFileNode *rel);
149 extern void RecordIndexFreeSpace(RelFileNode *rel,
153 extern void FreeSpaceMapTruncateRel(RelFileNode *rel, BlockNumber nblocks);
154 extern void FreeSpaceMapForgetRel(RelFileNode *rel);
155 extern void FreeSpaceMapForgetDatabase(Oid dbid);
157 extern void PrintFreeSpaceMapStatistics(int elevel);
159 extern void DumpFreeSpaceMap(int code, Datum arg);
160 extern void LoadFreeSpaceMap(void);
161 extern FSMHeader *GetFreeSpaceMap(void);
163 #ifdef FREESPACE_DEBUG
164 extern void DumpFreeSpace(void);
167 #endif /* FREESPACE_H */