1 /*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
9 *-------------------------------------------------------------------------
16 #include "access/xlog.h"
17 #include "access/transam.h"
18 #include "access/xact.h"
19 #include "storage/bufpage.h"
20 #include "storage/bufmgr.h"
21 #include "storage/smgr.h"
22 #include "access/htup.h"
23 #include "access/xlogutils.h"
24 #include "catalog/pg_database.h"
25 #include "lib/hasht.h"
28 * ---------------------------------------------------------------
30 * Index support functions
32 *----------------------------------------------------------------
36 * Check if specified heap tuple was inserted by given
37 * xaction/command and return
40 * - 0 if there is no tuple at all
44 XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
45 TransactionId xid, CommandId cid)
53 reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
54 if (!RelationIsValid(reln))
57 buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
58 if (!BufferIsValid(buffer))
61 LockBuffer(buffer, BUFFER_LOCK_SHARE);
62 page = (Page) BufferGetPage(buffer);
63 if (PageIsNew((PageHeader) page) ||
64 ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
66 UnlockAndReleaseBuffer(buffer);
69 lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
70 if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
72 UnlockAndReleaseBuffer(buffer);
76 htup = (HeapTupleHeader) PageGetItem(page, lp);
78 Assert(PageGetSUI(page) == ThisStartUpID);
79 if (htup->t_xmin != xid || htup->t_cmin != cid)
81 UnlockAndReleaseBuffer(buffer);
85 UnlockAndReleaseBuffer(buffer);
90 * MUST BE CALLED ONLY ON RECOVERY.
92 * Check if exists valid (inserted by not aborted xaction) heap tuple
93 * for given item pointer
96 XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr)
102 HeapTupleHeader htup;
104 reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
105 if (!RelationIsValid(reln))
108 buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
109 if (!BufferIsValid(buffer))
112 LockBuffer(buffer, BUFFER_LOCK_SHARE);
113 page = (Page) BufferGetPage(buffer);
114 if (PageIsNew((PageHeader) page) ||
115 ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
117 UnlockAndReleaseBuffer(buffer);
121 if (PageGetSUI(page) != ThisStartUpID)
123 Assert(PageGetSUI(page) < ThisStartUpID);
124 UnlockAndReleaseBuffer(buffer);
128 lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
129 if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
131 UnlockAndReleaseBuffer(buffer);
135 htup = (HeapTupleHeader) PageGetItem(page, lp);
137 /* MUST CHECK WASN'T TUPLE INSERTED IN PREV STARTUP */
139 if (!(htup->t_infomask & HEAP_XMIN_COMMITTED))
141 if (htup->t_infomask & HEAP_XMIN_INVALID ||
142 (htup->t_infomask & HEAP_MOVED_IN &&
143 TransactionIdDidAbort((TransactionId)htup->t_cmin)) ||
144 TransactionIdDidAbort(htup->t_xmin))
146 UnlockAndReleaseBuffer(buffer);
151 UnlockAndReleaseBuffer(buffer);
156 * Open pg_log in recovery
158 extern Relation LogRelation; /* pg_log relation */
161 XLogOpenLogRelation(void)
163 Relation logRelation;
165 Assert(!LogRelation);
166 logRelation = (Relation) malloc(sizeof(RelationData));
167 memset(logRelation, 0, sizeof(RelationData));
168 logRelation->rd_rel = (Form_pg_class) malloc(sizeof(FormData_pg_class));
169 memset(logRelation->rd_rel, 0, sizeof(FormData_pg_class));
171 sprintf(RelationGetPhysicalRelationName(logRelation), "pg_log");
172 logRelation->rd_node.tblNode = InvalidOid;
173 logRelation->rd_node.relNode = RelOid_pg_log;
174 logRelation->rd_unlinked = false; /* must exists */
175 logRelation->rd_fd = -1;
176 logRelation->rd_fd = smgropen(DEFAULT_SMGR, logRelation);
177 if (logRelation->rd_fd < 0)
178 elog(STOP, "XLogOpenLogRelation: failed to open pg_log");
179 LogRelation = logRelation;
183 * ---------------------------------------------------------------
185 * Storage related support functions
187 *----------------------------------------------------------------
191 XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno)
193 BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
196 if (blkno >= lastblock)
198 buffer = InvalidBuffer;
199 if (extend) /* we do this in recovery only - no locks */
202 while (lastblock <= blkno)
204 buffer = ReadBuffer(reln, P_NEW);
208 if (buffer != InvalidBuffer)
209 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
213 buffer = ReadBuffer(reln, blkno);
214 if (buffer != InvalidBuffer)
215 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
223 typedef struct XLogRelDesc
225 RelationData reldata;
226 struct XLogRelDesc *lessRecently;
227 struct XLogRelDesc *moreRecently;
230 typedef struct XLogRelCacheEntry
236 static HTAB *_xlrelcache;
237 static XLogRelDesc *_xlrelarr = NULL;
238 static Form_pg_class _xlpgcarr = NULL;
239 static int _xlast = 0;
240 static int _xlcnt = 0;
241 #define _XLOG_INITRELCACHESIZE 32
242 #define _XLOG_MAXRELCACHESIZE 512
245 _xl_init_rel_cache(void)
249 _xlcnt = _XLOG_INITRELCACHESIZE;
251 _xlrelarr = (XLogRelDesc*) malloc(sizeof(XLogRelDesc) * _xlcnt);
252 memset(_xlrelarr, 0, sizeof(XLogRelDesc) * _xlcnt);
253 _xlpgcarr = (Form_pg_class) malloc(sizeof(FormData_pg_class) * _xlcnt);
254 memset(_xlpgcarr, 0, sizeof(FormData_pg_class) * _xlcnt);
256 _xlrelarr[0].moreRecently = &(_xlrelarr[0]);
257 _xlrelarr[0].lessRecently = &(_xlrelarr[0]);
259 memset(&ctl, 0, (int) sizeof(ctl));
260 ctl.keysize = sizeof(RelFileNode);
261 ctl.datasize = sizeof(XLogRelDesc*);
264 _xlrelcache = hash_create(_XLOG_INITRELCACHESIZE, &ctl,
265 HASH_ELEM | HASH_FUNCTION);
269 _xl_remove_hash_entry(XLogRelDesc **edata, int dummy)
271 XLogRelCacheEntry *hentry;
273 XLogRelDesc *rdesc = *edata;
274 Form_pg_class tpgc = rdesc->reldata.rd_rel;
276 rdesc->lessRecently->moreRecently = rdesc->moreRecently;
277 rdesc->moreRecently->lessRecently = rdesc->lessRecently;
279 hentry = (XLogRelCacheEntry*) hash_search(_xlrelcache,
280 (char*)&(rdesc->reldata.rd_node), HASH_REMOVE, &found);
283 elog(STOP, "_xl_remove_hash_entry: can't delete from cache");
285 elog(STOP, "_xl_remove_hash_entry: file was not found in cache");
287 if (rdesc->reldata.rd_fd >= 0)
288 smgrclose(DEFAULT_SMGR, &(rdesc->reldata));
290 memset(rdesc, 0, sizeof(XLogRelDesc));
291 memset(tpgc, 0, sizeof(FormData_pg_class));
292 rdesc->reldata.rd_rel = tpgc;
298 _xl_new_reldesc(void)
303 _xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]);
304 return(&(_xlrelarr[_xlast]));
307 if ( 2 * _xlcnt <= _XLOG_MAXRELCACHESIZE)
309 _xlrelarr = (XLogRelDesc*) realloc(_xlrelarr,
310 2 * sizeof(XLogRelDesc) * _xlcnt);
311 memset(&(_xlrelarr[_xlcnt]), 0, sizeof(XLogRelDesc) * _xlcnt);
312 _xlpgcarr = (Form_pg_class) realloc(_xlpgcarr,
313 2 * sizeof(FormData_pg_class) * _xlcnt);
314 memset(&(_xlpgcarr[_xlcnt]), 0, sizeof(FormData_pg_class) * _xlcnt);
316 _xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]);
317 return(&(_xlrelarr[_xlast]));
321 XLogRelDesc *res = _xlrelarr[0].moreRecently;
323 _xl_remove_hash_entry(&res, 0);
330 extern void CreateDummyCaches(void);
331 extern void DestroyDummyCaches(void);
334 XLogInitRelationCache(void)
337 _xl_init_rel_cache();
341 XLogCloseRelationCache(void)
344 DestroyDummyCaches();
349 HashTableWalk(_xlrelcache, (HashtFunc)_xl_remove_hash_entry, 0);
350 hash_destroy(_xlrelcache);
359 XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
362 XLogRelCacheEntry *hentry;
365 hentry = (XLogRelCacheEntry*)
366 hash_search(_xlrelcache, (char*)&rnode, HASH_FIND, &found);
369 elog(STOP, "XLogOpenRelation: error in cache");
375 res->lessRecently->moreRecently = res->moreRecently;
376 res->moreRecently->lessRecently = res->lessRecently;
380 res = _xl_new_reldesc();
382 sprintf(RelationGetPhysicalRelationName(&(res->reldata)), "%u", rnode.relNode);
384 /* unexisting DB id */
385 res->reldata.rd_lockInfo.lockRelId.dbId = RecoveryDb;
386 res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
387 res->reldata.rd_node = rnode;
389 hentry = (XLogRelCacheEntry*)
390 hash_search(_xlrelcache, (char*)&rnode, HASH_ENTER, &found);
393 elog(STOP, "XLogOpenRelation: can't insert into cache");
396 elog(STOP, "XLogOpenRelation: file found on insert into cache");
400 res->reldata.rd_unlinked = true; /* look smgropen */
401 res->reldata.rd_fd = -1;
402 res->reldata.rd_fd = smgropen(DEFAULT_SMGR, &(res->reldata));
405 res->moreRecently = &(_xlrelarr[0]);
406 res->lessRecently = _xlrelarr[0].lessRecently;
407 _xlrelarr[0].lessRecently = res;
408 res->lessRecently->moreRecently = res;
410 if (res->reldata.rd_fd < 0) /* file doesn't exist */
413 return(&(res->reldata));