]> granicus.if.org Git - postgresql/blob - src/backend/catalog/storage.c
Remove cvs keywords from all files.
[postgresql] / src / backend / catalog / storage.c
1 /*-------------------------------------------------------------------------
2  *
3  * storage.c
4  *        code to create and destroy physical storage for relations
5  *
6  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/catalog/storage.c
12  *
13  * NOTES
14  *        Some of this code used to be in storage/smgr/smgr.c, and the
15  *        function names still reflect that.
16  *
17  *-------------------------------------------------------------------------
18  */
19
20 #include "postgres.h"
21
22 #include "access/visibilitymap.h"
23 #include "access/xact.h"
24 #include "access/xlogutils.h"
25 #include "catalog/catalog.h"
26 #include "catalog/storage.h"
27 #include "storage/freespace.h"
28 #include "storage/smgr.h"
29 #include "utils/memutils.h"
30 #include "utils/rel.h"
31
32 /*
33  * We keep a list of all relations (represented as RelFileNode values)
34  * that have been created or deleted in the current transaction.  When
35  * a relation is created, we create the physical file immediately, but
36  * remember it so that we can delete the file again if the current
37  * transaction is aborted.      Conversely, a deletion request is NOT
38  * executed immediately, but is just entered in the list.  When and if
39  * the transaction commits, we can delete the physical file.
40  *
41  * To handle subtransactions, every entry is marked with its transaction
42  * nesting level.  At subtransaction commit, we reassign the subtransaction's
43  * entries to the parent nesting level.  At subtransaction abort, we can
44  * immediately execute the abort-time actions for all entries of the current
45  * nesting level.
46  *
47  * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
48  * unbetimes.  It'd probably be OK to keep it in TopTransactionContext,
49  * but I'm being paranoid.
50  */
51
52 typedef struct PendingRelDelete
53 {
54         RelFileNode relnode;            /* relation that may need to be deleted */
55         BackendId       backend;                /* InvalidBackendId if not a temp rel */
56         bool            atCommit;               /* T=delete at commit; F=delete at abort */
57         int                     nestLevel;              /* xact nesting level of request */
58         struct PendingRelDelete *next;          /* linked-list link */
59 } PendingRelDelete;
60
61 static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
62
63 /*
64  * Declarations for smgr-related XLOG records
65  *
66  * Note: we log file creation and truncation here, but logging of deletion
67  * actions is handled by xact.c, because it is part of transaction commit.
68  */
69
70 /* XLOG gives us high 4 bits */
71 #define XLOG_SMGR_CREATE        0x10
72 #define XLOG_SMGR_TRUNCATE      0x20
73
74 typedef struct xl_smgr_create
75 {
76         RelFileNode rnode;
77 } xl_smgr_create;
78
79 typedef struct xl_smgr_truncate
80 {
81         BlockNumber blkno;
82         RelFileNode rnode;
83 } xl_smgr_truncate;
84
85
86 /*
87  * RelationCreateStorage
88  *              Create physical storage for a relation.
89  *
90  * Create the underlying disk file storage for the relation. This only
91  * creates the main fork; additional forks are created lazily by the
92  * modules that need them.
93  *
94  * This function is transactional. The creation is WAL-logged, and if the
95  * transaction aborts later on, the storage will be destroyed.
96  */
97 void
98 RelationCreateStorage(RelFileNode rnode, bool istemp)
99 {
100         PendingRelDelete *pending;
101         XLogRecPtr      lsn;
102         XLogRecData rdata;
103         xl_smgr_create xlrec;
104         SMgrRelation srel;
105         BackendId       backend = istemp ? MyBackendId : InvalidBackendId;
106
107         srel = smgropen(rnode, backend);
108         smgrcreate(srel, MAIN_FORKNUM, false);
109
110         if (!istemp)
111         {
112                 /*
113                  * Make an XLOG entry reporting the file creation.
114                  */
115                 xlrec.rnode = rnode;
116
117                 rdata.data = (char *) &xlrec;
118                 rdata.len = sizeof(xlrec);
119                 rdata.buffer = InvalidBuffer;
120                 rdata.next = NULL;
121
122                 lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
123         }
124
125         /* Add the relation to the list of stuff to delete at abort */
126         pending = (PendingRelDelete *)
127                 MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
128         pending->relnode = rnode;
129         pending->backend = backend;
130         pending->atCommit = false;      /* delete if abort */
131         pending->nestLevel = GetCurrentTransactionNestLevel();
132         pending->next = pendingDeletes;
133         pendingDeletes = pending;
134 }
135
136 /*
137  * RelationDropStorage
138  *              Schedule unlinking of physical storage at transaction commit.
139  */
140 void
141 RelationDropStorage(Relation rel)
142 {
143         PendingRelDelete *pending;
144
145         /* Add the relation to the list of stuff to delete at commit */
146         pending = (PendingRelDelete *)
147                 MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
148         pending->relnode = rel->rd_node;
149         pending->backend = rel->rd_backend;
150         pending->atCommit = true;       /* delete if commit */
151         pending->nestLevel = GetCurrentTransactionNestLevel();
152         pending->next = pendingDeletes;
153         pendingDeletes = pending;
154
155         /*
156          * NOTE: if the relation was created in this transaction, it will now be
157          * present in the pending-delete list twice, once with atCommit true and
158          * once with atCommit false.  Hence, it will be physically deleted at end
159          * of xact in either case (and the other entry will be ignored by
160          * smgrDoPendingDeletes, so no error will occur).  We could instead remove
161          * the existing list entry and delete the physical file immediately, but
162          * for now I'll keep the logic simple.
163          */
164
165         RelationCloseSmgr(rel);
166 }
167
168 /*
169  * RelationPreserveStorage
170  *              Mark a relation as not to be deleted after all.
171  *
172  * We need this function because relation mapping changes are committed
173  * separately from commit of the whole transaction, so it's still possible
174  * for the transaction to abort after the mapping update is done.
175  * When a new physical relation is installed in the map, it would be
176  * scheduled for delete-on-abort, so we'd delete it, and be in trouble.
177  * The relation mapper fixes this by telling us to not delete such relations
178  * after all as part of its commit.
179  *
180  * No-op if the relation is not among those scheduled for deletion.
181  */
182 void
183 RelationPreserveStorage(RelFileNode rnode)
184 {
185         PendingRelDelete *pending;
186         PendingRelDelete *prev;
187         PendingRelDelete *next;
188
189         prev = NULL;
190         for (pending = pendingDeletes; pending != NULL; pending = next)
191         {
192                 next = pending->next;
193                 if (RelFileNodeEquals(rnode, pending->relnode))
194                 {
195                         /* we should only find delete-on-abort entries, else trouble */
196                         if (pending->atCommit)
197                                 elog(ERROR, "cannot preserve a delete-on-commit relation");
198                         /* unlink and delete list entry */
199                         if (prev)
200                                 prev->next = next;
201                         else
202                                 pendingDeletes = next;
203                         pfree(pending);
204                         /* prev does not change */
205                 }
206                 else
207                 {
208                         /* unrelated entry, don't touch it */
209                         prev = pending;
210                 }
211         }
212 }
213
214 /*
215  * RelationTruncate
216  *              Physically truncate a relation to the specified number of blocks.
217  *
218  * This includes getting rid of any buffers for the blocks that are to be
219  * dropped.
220  */
221 void
222 RelationTruncate(Relation rel, BlockNumber nblocks)
223 {
224         bool            fsm;
225         bool            vm;
226
227         /* Open it at the smgr level if not already done */
228         RelationOpenSmgr(rel);
229
230         /*
231          * Make sure smgr_targblock etc aren't pointing somewhere past new end
232          */
233         rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
234         rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
235         rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
236
237         /* Truncate the FSM first if it exists */
238         fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
239         if (fsm)
240                 FreeSpaceMapTruncateRel(rel, nblocks);
241
242         /* Truncate the visibility map too if it exists. */
243         vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
244         if (vm)
245                 visibilitymap_truncate(rel, nblocks);
246
247         /*
248          * We WAL-log the truncation before actually truncating, which means
249          * trouble if the truncation fails. If we then crash, the WAL replay
250          * likely isn't going to succeed in the truncation either, and cause a
251          * PANIC. It's tempting to put a critical section here, but that cure
252          * would be worse than the disease. It would turn a usually harmless
253          * failure to truncate, that might spell trouble at WAL replay, into a
254          * certain PANIC.
255          */
256         if (!rel->rd_istemp)
257         {
258                 /*
259                  * Make an XLOG entry reporting the file truncation.
260                  */
261                 XLogRecPtr      lsn;
262                 XLogRecData rdata;
263                 xl_smgr_truncate xlrec;
264
265                 xlrec.blkno = nblocks;
266                 xlrec.rnode = rel->rd_node;
267
268                 rdata.data = (char *) &xlrec;
269                 rdata.len = sizeof(xlrec);
270                 rdata.buffer = InvalidBuffer;
271                 rdata.next = NULL;
272
273                 lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
274
275                 /*
276                  * Flush, because otherwise the truncation of the main relation might
277                  * hit the disk before the WAL record, and the truncation of the FSM
278                  * or visibility map. If we crashed during that window, we'd be left
279                  * with a truncated heap, but the FSM or visibility map would still
280                  * contain entries for the non-existent heap pages.
281                  */
282                 if (fsm || vm)
283                         XLogFlush(lsn);
284         }
285
286         /* Do the real work */
287         smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
288 }
289
290 /*
291  *      smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
292  *
293  * This also runs when aborting a subxact; we want to clean up a failed
294  * subxact immediately.
295  *
296  * Note: It's possible that we're being asked to remove a relation that has
297  * no physical storage in any fork. In particular, it's possible that we're
298  * cleaning up an old temporary relation for which RemovePgTempFiles has
299  * already recovered the physical storage.
300  */
301 void
302 smgrDoPendingDeletes(bool isCommit)
303 {
304         int                     nestLevel = GetCurrentTransactionNestLevel();
305         PendingRelDelete *pending;
306         PendingRelDelete *prev;
307         PendingRelDelete *next;
308
309         prev = NULL;
310         for (pending = pendingDeletes; pending != NULL; pending = next)
311         {
312                 next = pending->next;
313                 if (pending->nestLevel < nestLevel)
314                 {
315                         /* outer-level entries should not be processed yet */
316                         prev = pending;
317                 }
318                 else
319                 {
320                         /* unlink list entry first, so we don't retry on failure */
321                         if (prev)
322                                 prev->next = next;
323                         else
324                                 pendingDeletes = next;
325                         /* do deletion if called for */
326                         if (pending->atCommit == isCommit)
327                         {
328                                 SMgrRelation srel;
329                                 int                     i;
330
331                                 srel = smgropen(pending->relnode, pending->backend);
332                                 for (i = 0; i <= MAX_FORKNUM; i++)
333                                 {
334                                         if (smgrexists(srel, i))
335                                                 smgrdounlink(srel, i, false);
336                                 }
337                                 smgrclose(srel);
338                         }
339                         /* must explicitly free the list entry */
340                         pfree(pending);
341                         /* prev does not change */
342                 }
343         }
344 }
345
346 /*
347  * smgrGetPendingDeletes() -- Get a list of non-temp relations to be deleted.
348  *
349  * The return value is the number of relations scheduled for termination.
350  * *ptr is set to point to a freshly-palloc'd array of RelFileNodes.
351  * If there are no relations to be deleted, *ptr is set to NULL.
352  *
353  * Only non-temporary relations are included in the returned list.  This is OK
354  * because the list is used only in contexts where temporary relations don't
355  * matter: we're either writing to the two-phase state file (and transactions
356  * that have touched temp tables can't be prepared) or we're writing to xlog
357  * (and all temporary files will be zapped if we restart anyway, so no need
358  * for redo to do it also).
359  *
360  * Note that the list does not include anything scheduled for termination
361  * by upper-level transactions.
362  */
363 int
364 smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
365 {
366         int                     nestLevel = GetCurrentTransactionNestLevel();
367         int                     nrels;
368         RelFileNode *rptr;
369         PendingRelDelete *pending;
370
371         nrels = 0;
372         for (pending = pendingDeletes; pending != NULL; pending = pending->next)
373         {
374                 if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
375                         && pending->backend == InvalidBackendId)
376                         nrels++;
377         }
378         if (nrels == 0)
379         {
380                 *ptr = NULL;
381                 return 0;
382         }
383         rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
384         *ptr = rptr;
385         for (pending = pendingDeletes; pending != NULL; pending = pending->next)
386         {
387                 if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
388                         && pending->backend == InvalidBackendId)
389                 {
390                         *rptr = pending->relnode;
391                         rptr++;
392                 }
393         }
394         return nrels;
395 }
396
397 /*
398  *      PostPrepare_smgr -- Clean up after a successful PREPARE
399  *
400  * What we have to do here is throw away the in-memory state about pending
401  * relation deletes.  It's all been recorded in the 2PC state file and
402  * it's no longer smgr's job to worry about it.
403  */
404 void
405 PostPrepare_smgr(void)
406 {
407         PendingRelDelete *pending;
408         PendingRelDelete *next;
409
410         for (pending = pendingDeletes; pending != NULL; pending = next)
411         {
412                 next = pending->next;
413                 pendingDeletes = next;
414                 /* must explicitly free the list entry */
415                 pfree(pending);
416         }
417 }
418
419
420 /*
421  * AtSubCommit_smgr() --- Take care of subtransaction commit.
422  *
423  * Reassign all items in the pending-deletes list to the parent transaction.
424  */
425 void
426 AtSubCommit_smgr(void)
427 {
428         int                     nestLevel = GetCurrentTransactionNestLevel();
429         PendingRelDelete *pending;
430
431         for (pending = pendingDeletes; pending != NULL; pending = pending->next)
432         {
433                 if (pending->nestLevel >= nestLevel)
434                         pending->nestLevel = nestLevel - 1;
435         }
436 }
437
438 /*
439  * AtSubAbort_smgr() --- Take care of subtransaction abort.
440  *
441  * Delete created relations and forget about deleted relations.
442  * We can execute these operations immediately because we know this
443  * subtransaction will not commit.
444  */
445 void
446 AtSubAbort_smgr(void)
447 {
448         smgrDoPendingDeletes(false);
449 }
450
451 void
452 smgr_redo(XLogRecPtr lsn, XLogRecord *record)
453 {
454         uint8           info = record->xl_info & ~XLR_INFO_MASK;
455
456         /* Backup blocks are not used in smgr records */
457         Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
458
459         if (info == XLOG_SMGR_CREATE)
460         {
461                 xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
462                 SMgrRelation reln;
463
464                 reln = smgropen(xlrec->rnode, InvalidBackendId);
465                 smgrcreate(reln, MAIN_FORKNUM, true);
466         }
467         else if (info == XLOG_SMGR_TRUNCATE)
468         {
469                 xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
470                 SMgrRelation reln;
471                 Relation        rel;
472
473                 reln = smgropen(xlrec->rnode, InvalidBackendId);
474
475                 /*
476                  * Forcibly create relation if it doesn't exist (which suggests that
477                  * it was dropped somewhere later in the WAL sequence).  As in
478                  * XLogOpenRelation, we prefer to recreate the rel and replay the log
479                  * as best we can until the drop is seen.
480                  */
481                 smgrcreate(reln, MAIN_FORKNUM, true);
482
483                 smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
484
485                 /* Also tell xlogutils.c about it */
486                 XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
487
488                 /* Truncate FSM and VM too */
489                 rel = CreateFakeRelcacheEntry(xlrec->rnode);
490
491                 if (smgrexists(reln, FSM_FORKNUM))
492                         FreeSpaceMapTruncateRel(rel, xlrec->blkno);
493                 if (smgrexists(reln, VISIBILITYMAP_FORKNUM))
494                         visibilitymap_truncate(rel, xlrec->blkno);
495
496                 FreeFakeRelcacheEntry(rel);
497         }
498         else
499                 elog(PANIC, "smgr_redo: unknown op code %u", info);
500 }
501
502 void
503 smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
504 {
505         uint8           info = xl_info & ~XLR_INFO_MASK;
506
507         if (info == XLOG_SMGR_CREATE)
508         {
509                 xl_smgr_create *xlrec = (xl_smgr_create *) rec;
510                 char       *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
511
512                 appendStringInfo(buf, "file create: %s", path);
513                 pfree(path);
514         }
515         else if (info == XLOG_SMGR_TRUNCATE)
516         {
517                 xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
518                 char       *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
519
520                 appendStringInfo(buf, "file truncate: %s to %u blocks", path,
521                                                  xlrec->blkno);
522                 pfree(path);
523         }
524         else
525                 appendStringInfo(buf, "UNKNOWN");
526 }