]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xlogutils.c
Commit to match discussed elog() changes. Only update is that LOG is
[postgresql] / src / backend / access / transam / xlogutils.c
1 /*-------------------------------------------------------------------------
2  *
3  * xlogutils.c
4  *
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * $Header: /cvsroot/pgsql/src/backend/access/transam/xlogutils.c,v 1.22 2002/03/02 21:39:20 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14
15 #include "access/htup.h"
16 #include "access/xlogutils.h"
17 #include "catalog/pg_database.h"
18 #include "storage/bufpage.h"
19 #include "storage/smgr.h"
20 #include "utils/hsearch.h"
21 #include "utils/relcache.h"
22
23
24 /*
25  * ---------------------------------------------------------------
26  *
27  * Index support functions
28  *
29  *----------------------------------------------------------------
30  */
31
32 /*
33  * Check if specified heap tuple was inserted by given
34  * xaction/command and return
35  *
36  * - -1 if not
37  * - 0  if there is no tuple at all
38  * - 1  if yes
39  */
40 int
41 XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
42                                    TransactionId xid, CommandId cid)
43 {
44         Relation        reln;
45         Buffer          buffer;
46         Page            page;
47         ItemId          lp;
48         HeapTupleHeader htup;
49
50         reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
51         if (!RelationIsValid(reln))
52                 return (0);
53
54         buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
55         if (!BufferIsValid(buffer))
56                 return (0);
57
58         LockBuffer(buffer, BUFFER_LOCK_SHARE);
59         page = (Page) BufferGetPage(buffer);
60         if (PageIsNew((PageHeader) page) ||
61                 ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
62         {
63                 UnlockAndReleaseBuffer(buffer);
64                 return (0);
65         }
66         lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
67         if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
68         {
69                 UnlockAndReleaseBuffer(buffer);
70                 return (0);
71         }
72
73         htup = (HeapTupleHeader) PageGetItem(page, lp);
74
75         Assert(PageGetSUI(page) == ThisStartUpID);
76         if (!TransactionIdEquals(htup->t_xmin, xid) || htup->t_cmin != cid)
77         {
78                 UnlockAndReleaseBuffer(buffer);
79                 return (-1);
80         }
81
82         UnlockAndReleaseBuffer(buffer);
83         return (1);
84 }
85
86 /*
87  * MUST BE CALLED ONLY ON RECOVERY.
88  *
89  * Check if exists valid (inserted by not aborted xaction) heap tuple
90  * for given item pointer
91  */
92 bool
93 XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr)
94 {
95         Relation        reln;
96         Buffer          buffer;
97         Page            page;
98         ItemId          lp;
99         HeapTupleHeader htup;
100
101         reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
102         if (!RelationIsValid(reln))
103                 return (false);
104
105         buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
106         if (!BufferIsValid(buffer))
107                 return (false);
108
109         LockBuffer(buffer, BUFFER_LOCK_SHARE);
110         page = (Page) BufferGetPage(buffer);
111         if (PageIsNew((PageHeader) page) ||
112                 ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
113         {
114                 UnlockAndReleaseBuffer(buffer);
115                 return (false);
116         }
117
118         if (PageGetSUI(page) != ThisStartUpID)
119         {
120                 Assert(PageGetSUI(page) < ThisStartUpID);
121                 UnlockAndReleaseBuffer(buffer);
122                 return (true);
123         }
124
125         lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
126         if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
127         {
128                 UnlockAndReleaseBuffer(buffer);
129                 return (false);
130         }
131
132         htup = (HeapTupleHeader) PageGetItem(page, lp);
133
134         /* MUST CHECK WASN'T TUPLE INSERTED IN PREV STARTUP */
135
136         if (!(htup->t_infomask & HEAP_XMIN_COMMITTED))
137         {
138                 if (htup->t_infomask & HEAP_XMIN_INVALID ||
139                         (htup->t_infomask & HEAP_MOVED_IN &&
140                          TransactionIdDidAbort((TransactionId) htup->t_cmin)) ||
141                         TransactionIdDidAbort(htup->t_xmin))
142                 {
143                         UnlockAndReleaseBuffer(buffer);
144                         return (false);
145                 }
146         }
147
148         UnlockAndReleaseBuffer(buffer);
149         return (true);
150 }
151
152 /*
153  * ---------------------------------------------------------------
154  *
155  * Storage related support functions
156  *
157  *----------------------------------------------------------------
158  */
159
160 Buffer
161 XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno)
162 {
163         BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
164         Buffer          buffer;
165
166         if (blkno >= lastblock)
167         {
168                 buffer = InvalidBuffer;
169                 if (extend)                             /* we do this in recovery only - no locks */
170                 {
171                         Assert(InRecovery);
172                         while (lastblock <= blkno)
173                         {
174                                 if (buffer != InvalidBuffer)
175                                         ReleaseBuffer(buffer);          /* must be WriteBuffer()? */
176                                 buffer = ReadBuffer(reln, P_NEW);
177                                 lastblock++;
178                         }
179                 }
180                 if (buffer != InvalidBuffer)
181                         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
182                 return (buffer);
183         }
184
185         buffer = ReadBuffer(reln, blkno);
186         if (buffer != InvalidBuffer)
187                 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
188         return (buffer);
189 }
190
191 /*
192  * "Relation" cache
193  */
194
195 typedef struct XLogRelDesc
196 {
197         RelationData reldata;
198         struct XLogRelDesc *lessRecently;
199         struct XLogRelDesc *moreRecently;
200 } XLogRelDesc;
201
202 typedef struct XLogRelCacheEntry
203 {
204         RelFileNode rnode;
205         XLogRelDesc *rdesc;
206 } XLogRelCacheEntry;
207
208 static HTAB *_xlrelcache;
209 static XLogRelDesc *_xlrelarr = NULL;
210 static Form_pg_class _xlpgcarr = NULL;
211 static int      _xlast = 0;
212 static int      _xlcnt = 0;
213
214 #define _XLOG_RELCACHESIZE      512
215
216 static void
217 _xl_init_rel_cache(void)
218 {
219         HASHCTL         ctl;
220
221         _xlcnt = _XLOG_RELCACHESIZE;
222         _xlast = 0;
223         _xlrelarr = (XLogRelDesc *) malloc(sizeof(XLogRelDesc) * _xlcnt);
224         memset(_xlrelarr, 0, sizeof(XLogRelDesc) * _xlcnt);
225         _xlpgcarr = (Form_pg_class) malloc(sizeof(FormData_pg_class) * _xlcnt);
226         memset(_xlpgcarr, 0, sizeof(FormData_pg_class) * _xlcnt);
227
228         _xlrelarr[0].moreRecently = &(_xlrelarr[0]);
229         _xlrelarr[0].lessRecently = &(_xlrelarr[0]);
230
231         memset(&ctl, 0, sizeof(ctl));
232         ctl.keysize = sizeof(RelFileNode);
233         ctl.entrysize = sizeof(XLogRelCacheEntry);
234         ctl.hash = tag_hash;
235
236         _xlrelcache = hash_create("XLOG relcache", _XLOG_RELCACHESIZE,
237                                                           &ctl, HASH_ELEM | HASH_FUNCTION);
238 }
239
240 static void
241 _xl_remove_hash_entry(XLogRelDesc *rdesc)
242 {
243         Form_pg_class tpgc = rdesc->reldata.rd_rel;
244         XLogRelCacheEntry *hentry;
245
246         rdesc->lessRecently->moreRecently = rdesc->moreRecently;
247         rdesc->moreRecently->lessRecently = rdesc->lessRecently;
248
249         hentry = (XLogRelCacheEntry *) hash_search(_xlrelcache,
250                                   (void *) &(rdesc->reldata.rd_node), HASH_REMOVE, NULL);
251         if (hentry == NULL)
252                 elog(PANIC, "_xl_remove_hash_entry: file was not found in cache");
253
254         if (rdesc->reldata.rd_fd >= 0)
255                 smgrclose(DEFAULT_SMGR, &(rdesc->reldata));
256
257         memset(rdesc, 0, sizeof(XLogRelDesc));
258         memset(tpgc, 0, sizeof(FormData_pg_class));
259         rdesc->reldata.rd_rel = tpgc;
260
261         return;
262 }
263
264 static XLogRelDesc *
265 _xl_new_reldesc(void)
266 {
267         XLogRelDesc *res;
268
269         _xlast++;
270         if (_xlast < _xlcnt)
271         {
272                 _xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]);
273                 return (&(_xlrelarr[_xlast]));
274         }
275
276         /* reuse */
277         res = _xlrelarr[0].moreRecently;
278
279         _xl_remove_hash_entry(res);
280
281         _xlast--;
282         return (res);
283 }
284
285
286 void
287 XLogInitRelationCache(void)
288 {
289         CreateDummyCaches();
290         _xl_init_rel_cache();
291 }
292
293 void
294 XLogCloseRelationCache(void)
295 {
296         HASH_SEQ_STATUS status;
297         XLogRelCacheEntry *hentry;
298
299         DestroyDummyCaches();
300
301         if (!_xlrelarr)
302                 return;
303
304         hash_seq_init(&status, _xlrelcache);
305
306         while ((hentry = (XLogRelCacheEntry *) hash_seq_search(&status)) != NULL)
307                 _xl_remove_hash_entry(hentry->rdesc);
308
309         hash_destroy(_xlrelcache);
310
311         free(_xlrelarr);
312         free(_xlpgcarr);
313
314         _xlrelarr = NULL;
315 }
316
317 Relation
318 XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
319 {
320         XLogRelDesc *res;
321         XLogRelCacheEntry *hentry;
322         bool            found;
323
324         hentry = (XLogRelCacheEntry *)
325                 hash_search(_xlrelcache, (void *) &rnode, HASH_FIND, NULL);
326
327         if (hentry)
328         {
329                 res = hentry->rdesc;
330
331                 res->lessRecently->moreRecently = res->moreRecently;
332                 res->moreRecently->lessRecently = res->lessRecently;
333         }
334         else
335         {
336                 res = _xl_new_reldesc();
337
338                 sprintf(RelationGetPhysicalRelationName(&(res->reldata)), "%u", rnode.relNode);
339
340                 /* unexisting DB id */
341                 res->reldata.rd_lockInfo.lockRelId.dbId = RecoveryDb;
342                 res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
343                 res->reldata.rd_node = rnode;
344
345                 hentry = (XLogRelCacheEntry *)
346                         hash_search(_xlrelcache, (void *) &rnode, HASH_ENTER, &found);
347
348                 if (hentry == NULL)
349                         elog(PANIC, "XLogOpenRelation: out of memory for cache");
350
351                 if (found)
352                         elog(PANIC, "XLogOpenRelation: file found on insert into cache");
353
354                 hentry->rdesc = res;
355
356                 res->reldata.rd_targblock = InvalidBlockNumber;
357                 res->reldata.rd_fd = -1;
358                 res->reldata.rd_fd = smgropen(DEFAULT_SMGR, &(res->reldata),
359                                                                           true /* allow failure */ );
360         }
361
362         res->moreRecently = &(_xlrelarr[0]);
363         res->lessRecently = _xlrelarr[0].lessRecently;
364         _xlrelarr[0].lessRecently = res;
365         res->lessRecently->moreRecently = res;
366
367         if (res->reldata.rd_fd < 0) /* file doesn't exist */
368                 return (NULL);
369
370         return (&(res->reldata));
371 }