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