1 /*-------------------------------------------------------------------------
5 * PostgreSQL transaction log manager utility routines
7 * This file contains support routines that are used by XLOG replay functions.
8 * None of this code is used during normal system operation.
11 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.34 2004/08/29 05:06:41 momjian Exp $
16 *-------------------------------------------------------------------------
20 #include "access/xlogutils.h"
21 #include "storage/bufmgr.h"
22 #include "storage/smgr.h"
23 #include "utils/hsearch.h"
28 * Storage related support functions
33 XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno)
35 BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
38 if (blkno >= lastblock)
40 buffer = InvalidBuffer;
41 if (extend) /* we do this in recovery only - no locks */
44 while (lastblock <= blkno)
46 if (buffer != InvalidBuffer)
47 ReleaseBuffer(buffer); /* must be WriteBuffer()? */
48 buffer = ReadBuffer(reln, P_NEW);
52 if (buffer != InvalidBuffer)
53 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
57 buffer = ReadBuffer(reln, blkno);
58 if (buffer != InvalidBuffer)
59 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
65 * Lightweight "Relation" cache --- this substitutes for the normal relcache
69 typedef struct XLogRelDesc
72 struct XLogRelDesc *lessRecently;
73 struct XLogRelDesc *moreRecently;
76 typedef struct XLogRelCacheEntry
82 static HTAB *_xlrelcache;
83 static XLogRelDesc *_xlrelarr = NULL;
84 static Form_pg_class _xlpgcarr = NULL;
85 static int _xlast = 0;
86 static int _xlcnt = 0;
88 #define _XLOG_RELCACHESIZE 512
91 _xl_init_rel_cache(void)
95 _xlcnt = _XLOG_RELCACHESIZE;
97 _xlrelarr = (XLogRelDesc *) malloc(sizeof(XLogRelDesc) * _xlcnt);
98 memset(_xlrelarr, 0, sizeof(XLogRelDesc) * _xlcnt);
99 _xlpgcarr = (Form_pg_class) malloc(sizeof(FormData_pg_class) * _xlcnt);
100 memset(_xlpgcarr, 0, sizeof(FormData_pg_class) * _xlcnt);
102 _xlrelarr[0].moreRecently = &(_xlrelarr[0]);
103 _xlrelarr[0].lessRecently = &(_xlrelarr[0]);
105 memset(&ctl, 0, sizeof(ctl));
106 ctl.keysize = sizeof(RelFileNode);
107 ctl.entrysize = sizeof(XLogRelCacheEntry);
110 _xlrelcache = hash_create("XLOG relcache", _XLOG_RELCACHESIZE,
111 &ctl, HASH_ELEM | HASH_FUNCTION);
115 _xl_remove_hash_entry(XLogRelDesc *rdesc)
117 Form_pg_class tpgc = rdesc->reldata.rd_rel;
118 XLogRelCacheEntry *hentry;
120 rdesc->lessRecently->moreRecently = rdesc->moreRecently;
121 rdesc->moreRecently->lessRecently = rdesc->lessRecently;
123 hentry = (XLogRelCacheEntry *) hash_search(_xlrelcache,
124 (void *) &(rdesc->reldata.rd_node), HASH_REMOVE, NULL);
126 elog(PANIC, "_xl_remove_hash_entry: file was not found in cache");
128 if (rdesc->reldata.rd_smgr != NULL)
129 smgrclose(rdesc->reldata.rd_smgr);
131 memset(rdesc, 0, sizeof(XLogRelDesc));
132 memset(tpgc, 0, sizeof(FormData_pg_class));
133 rdesc->reldata.rd_rel = tpgc;
137 _xl_new_reldesc(void)
144 _xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]);
145 return (&(_xlrelarr[_xlast]));
149 res = _xlrelarr[0].moreRecently;
151 _xl_remove_hash_entry(res);
159 XLogInitRelationCache(void)
161 _xl_init_rel_cache();
165 XLogCloseRelationCache(void)
167 HASH_SEQ_STATUS status;
168 XLogRelCacheEntry *hentry;
173 hash_seq_init(&status, _xlrelcache);
175 while ((hentry = (XLogRelCacheEntry *) hash_seq_search(&status)) != NULL)
176 _xl_remove_hash_entry(hentry->rdesc);
178 hash_destroy(_xlrelcache);
187 * Open a relation during XLOG replay
190 XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
193 XLogRelCacheEntry *hentry;
196 hentry = (XLogRelCacheEntry *)
197 hash_search(_xlrelcache, (void *) &rnode, HASH_FIND, NULL);
203 res->lessRecently->moreRecently = res->moreRecently;
204 res->moreRecently->lessRecently = res->lessRecently;
208 res = _xl_new_reldesc();
210 sprintf(RelationGetRelationName(&(res->reldata)), "%u", rnode.relNode);
212 res->reldata.rd_node = rnode;
215 * We set up the lockRelId in case anything tries to lock the
216 * dummy relation. Note that this is fairly bogus since relNode
217 * may be different from the relation's OID. It shouldn't really
218 * matter though, since we are presumably running by ourselves and
219 * can't have any lock conflicts ...
221 res->reldata.rd_lockInfo.lockRelId.dbId = rnode.dbNode;
222 res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
224 hentry = (XLogRelCacheEntry *)
225 hash_search(_xlrelcache, (void *) &rnode, HASH_ENTER, &found);
228 elog(PANIC, "XLogOpenRelation: out of memory for cache");
231 elog(PANIC, "XLogOpenRelation: file found on insert into cache");
235 res->reldata.rd_targblock = InvalidBlockNumber;
236 res->reldata.rd_smgr = smgropen(res->reldata.rd_node);
239 * Create the target file if it doesn't already exist. This lets
240 * us cope if the replay sequence contains writes to a relation
241 * that is later deleted. (The original coding of this routine
242 * would instead return NULL, causing the writes to be suppressed.
243 * But that seems like it risks losing valuable data if the
244 * filesystem loses an inode during a crash. Better to write the
245 * data until we are actually told to delete the file.)
247 smgrcreate(res->reldata.rd_smgr, res->reldata.rd_istemp, true);
250 res->moreRecently = &(_xlrelarr[0]);
251 res->lessRecently = _xlrelarr[0].lessRecently;
252 _xlrelarr[0].lessRecently = res;
253 res->lessRecently->moreRecently = res;
255 return (&(res->reldata));
259 * Close a relation during XLOG replay
261 * This is called when the relation is about to be deleted; we need to ensure
262 * that there is no dangling smgr reference in the xlog relation cache.
264 * Currently, we don't bother to physically remove the relation from the
265 * cache, we just let it age out normally.
268 XLogCloseRelation(RelFileNode rnode)
271 XLogRelCacheEntry *hentry;
273 hentry = (XLogRelCacheEntry *)
274 hash_search(_xlrelcache, (void *) &rnode, HASH_FIND, NULL);
277 return; /* not in cache so no work */
279 rdesc = hentry->rdesc;
281 if (rdesc->reldata.rd_smgr != NULL)
282 smgrclose(rdesc->reldata.rd_smgr);
283 rdesc->reldata.rd_smgr = NULL;