1 /*-------------------------------------------------------------------------
4 * code to create and destroy physical storage for relations
6 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/storage.c
14 * Some of this code used to be in storage/smgr/smgr.c, and the
15 * function names still reflect that.
17 *-------------------------------------------------------------------------
22 #include "access/visibilitymap.h"
23 #include "access/xact.h"
24 #include "access/xlog.h"
25 #include "access/xloginsert.h"
26 #include "access/xlogutils.h"
27 #include "catalog/catalog.h"
28 #include "catalog/storage.h"
29 #include "catalog/storage_xlog.h"
30 #include "storage/freespace.h"
31 #include "storage/smgr.h"
32 #include "utils/memutils.h"
33 #include "utils/rel.h"
36 * We keep a list of all relations (represented as RelFileNode values)
37 * that have been created or deleted in the current transaction. When
38 * a relation is created, we create the physical file immediately, but
39 * remember it so that we can delete the file again if the current
40 * transaction is aborted. Conversely, a deletion request is NOT
41 * executed immediately, but is just entered in the list. When and if
42 * the transaction commits, we can delete the physical file.
44 * To handle subtransactions, every entry is marked with its transaction
45 * nesting level. At subtransaction commit, we reassign the subtransaction's
46 * entries to the parent nesting level. At subtransaction abort, we can
47 * immediately execute the abort-time actions for all entries of the current
50 * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
51 * unbetimes. It'd probably be OK to keep it in TopTransactionContext,
52 * but I'm being paranoid.
55 typedef struct PendingRelDelete
57 RelFileNode relnode; /* relation that may need to be deleted */
58 BackendId backend; /* InvalidBackendId if not a temp rel */
59 bool atCommit; /* T=delete at commit; F=delete at abort */
60 int nestLevel; /* xact nesting level of request */
61 struct PendingRelDelete *next; /* linked-list link */
64 static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
67 * RelationCreateStorage
68 * Create physical storage for a relation.
70 * Create the underlying disk file storage for the relation. This only
71 * creates the main fork; additional forks are created lazily by the
72 * modules that need them.
74 * This function is transactional. The creation is WAL-logged, and if the
75 * transaction aborts later on, the storage will be destroyed.
78 RelationCreateStorage(RelFileNode rnode, char relpersistence)
80 PendingRelDelete *pending;
85 switch (relpersistence)
87 case RELPERSISTENCE_TEMP:
88 backend = MyBackendId;
91 case RELPERSISTENCE_UNLOGGED:
92 backend = InvalidBackendId;
95 case RELPERSISTENCE_PERMANENT:
96 backend = InvalidBackendId;
100 elog(ERROR, "invalid relpersistence: %c", relpersistence);
101 return; /* placate compiler */
104 srel = smgropen(rnode, backend);
105 smgrcreate(srel, MAIN_FORKNUM, false);
108 log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
110 /* Add the relation to the list of stuff to delete at abort */
111 pending = (PendingRelDelete *)
112 MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
113 pending->relnode = rnode;
114 pending->backend = backend;
115 pending->atCommit = false; /* delete if abort */
116 pending->nestLevel = GetCurrentTransactionNestLevel();
117 pending->next = pendingDeletes;
118 pendingDeletes = pending;
122 * Perform XLogInsert of a XLOG_SMGR_CREATE record to WAL.
125 log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum)
127 xl_smgr_create xlrec;
131 * Make an XLOG entry reporting the file creation.
133 xlrec.rnode = *rnode;
134 xlrec.forkNum = forkNum;
136 rdata.data = (char *) &xlrec;
137 rdata.len = sizeof(xlrec);
138 rdata.buffer = InvalidBuffer;
141 XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
145 * RelationDropStorage
146 * Schedule unlinking of physical storage at transaction commit.
149 RelationDropStorage(Relation rel)
151 PendingRelDelete *pending;
153 /* Add the relation to the list of stuff to delete at commit */
154 pending = (PendingRelDelete *)
155 MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
156 pending->relnode = rel->rd_node;
157 pending->backend = rel->rd_backend;
158 pending->atCommit = true; /* delete if commit */
159 pending->nestLevel = GetCurrentTransactionNestLevel();
160 pending->next = pendingDeletes;
161 pendingDeletes = pending;
164 * NOTE: if the relation was created in this transaction, it will now be
165 * present in the pending-delete list twice, once with atCommit true and
166 * once with atCommit false. Hence, it will be physically deleted at end
167 * of xact in either case (and the other entry will be ignored by
168 * smgrDoPendingDeletes, so no error will occur). We could instead remove
169 * the existing list entry and delete the physical file immediately, but
170 * for now I'll keep the logic simple.
173 RelationCloseSmgr(rel);
177 * RelationPreserveStorage
178 * Mark a relation as not to be deleted after all.
180 * We need this function because relation mapping changes are committed
181 * separately from commit of the whole transaction, so it's still possible
182 * for the transaction to abort after the mapping update is done.
183 * When a new physical relation is installed in the map, it would be
184 * scheduled for delete-on-abort, so we'd delete it, and be in trouble.
185 * The relation mapper fixes this by telling us to not delete such relations
186 * after all as part of its commit.
188 * We also use this to reuse an old build of an index during ALTER TABLE, this
189 * time removing the delete-at-commit entry.
191 * No-op if the relation is not among those scheduled for deletion.
194 RelationPreserveStorage(RelFileNode rnode, bool atCommit)
196 PendingRelDelete *pending;
197 PendingRelDelete *prev;
198 PendingRelDelete *next;
201 for (pending = pendingDeletes; pending != NULL; pending = next)
203 next = pending->next;
204 if (RelFileNodeEquals(rnode, pending->relnode)
205 && pending->atCommit == atCommit)
207 /* unlink and delete list entry */
211 pendingDeletes = next;
213 /* prev does not change */
217 /* unrelated entry, don't touch it */
225 * Physically truncate a relation to the specified number of blocks.
227 * This includes getting rid of any buffers for the blocks that are to be
231 RelationTruncate(Relation rel, BlockNumber nblocks)
236 /* Open it at the smgr level if not already done */
237 RelationOpenSmgr(rel);
240 * Make sure smgr_targblock etc aren't pointing somewhere past new end
242 rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
243 rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
244 rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
246 /* Truncate the FSM first if it exists */
247 fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
249 FreeSpaceMapTruncateRel(rel, nblocks);
251 /* Truncate the visibility map too if it exists. */
252 vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
254 visibilitymap_truncate(rel, nblocks);
257 * We WAL-log the truncation before actually truncating, which means
258 * trouble if the truncation fails. If we then crash, the WAL replay
259 * likely isn't going to succeed in the truncation either, and cause a
260 * PANIC. It's tempting to put a critical section here, but that cure
261 * would be worse than the disease. It would turn a usually harmless
262 * failure to truncate, that might spell trouble at WAL replay, into a
265 if (RelationNeedsWAL(rel))
268 * Make an XLOG entry reporting the file truncation.
272 xl_smgr_truncate xlrec;
274 xlrec.blkno = nblocks;
275 xlrec.rnode = rel->rd_node;
277 rdata.data = (char *) &xlrec;
278 rdata.len = sizeof(xlrec);
279 rdata.buffer = InvalidBuffer;
282 lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
285 * Flush, because otherwise the truncation of the main relation might
286 * hit the disk before the WAL record, and the truncation of the FSM
287 * or visibility map. If we crashed during that window, we'd be left
288 * with a truncated heap, but the FSM or visibility map would still
289 * contain entries for the non-existent heap pages.
295 /* Do the real work */
296 smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
300 * smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
302 * This also runs when aborting a subxact; we want to clean up a failed
303 * subxact immediately.
305 * Note: It's possible that we're being asked to remove a relation that has
306 * no physical storage in any fork. In particular, it's possible that we're
307 * cleaning up an old temporary relation for which RemovePgTempFiles has
308 * already recovered the physical storage.
311 smgrDoPendingDeletes(bool isCommit)
313 int nestLevel = GetCurrentTransactionNestLevel();
314 PendingRelDelete *pending;
315 PendingRelDelete *prev;
316 PendingRelDelete *next;
320 SMgrRelation *srels = NULL;
323 for (pending = pendingDeletes; pending != NULL; pending = next)
325 next = pending->next;
326 if (pending->nestLevel < nestLevel)
328 /* outer-level entries should not be processed yet */
333 /* unlink list entry first, so we don't retry on failure */
337 pendingDeletes = next;
338 /* do deletion if called for */
339 if (pending->atCommit == isCommit)
343 srel = smgropen(pending->relnode, pending->backend);
345 /* allocate the initial array, or extend it, if needed */
349 srels = palloc(sizeof(SMgrRelation) * maxrels);
351 else if (maxrels <= nrels)
354 srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
357 srels[nrels++] = srel;
359 /* must explicitly free the list entry */
361 /* prev does not change */
367 smgrdounlinkall(srels, nrels, false);
369 for (i = 0; i < nrels; i++)
377 * smgrGetPendingDeletes() -- Get a list of non-temp relations to be deleted.
379 * The return value is the number of relations scheduled for termination.
380 * *ptr is set to point to a freshly-palloc'd array of RelFileNodes.
381 * If there are no relations to be deleted, *ptr is set to NULL.
383 * Only non-temporary relations are included in the returned list. This is OK
384 * because the list is used only in contexts where temporary relations don't
385 * matter: we're either writing to the two-phase state file (and transactions
386 * that have touched temp tables can't be prepared) or we're writing to xlog
387 * (and all temporary files will be zapped if we restart anyway, so no need
388 * for redo to do it also).
390 * Note that the list does not include anything scheduled for termination
391 * by upper-level transactions.
394 smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
396 int nestLevel = GetCurrentTransactionNestLevel();
399 PendingRelDelete *pending;
402 for (pending = pendingDeletes; pending != NULL; pending = pending->next)
404 if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
405 && pending->backend == InvalidBackendId)
413 rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
415 for (pending = pendingDeletes; pending != NULL; pending = pending->next)
417 if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
418 && pending->backend == InvalidBackendId)
420 *rptr = pending->relnode;
428 * PostPrepare_smgr -- Clean up after a successful PREPARE
430 * What we have to do here is throw away the in-memory state about pending
431 * relation deletes. It's all been recorded in the 2PC state file and
432 * it's no longer smgr's job to worry about it.
435 PostPrepare_smgr(void)
437 PendingRelDelete *pending;
438 PendingRelDelete *next;
440 for (pending = pendingDeletes; pending != NULL; pending = next)
442 next = pending->next;
443 pendingDeletes = next;
444 /* must explicitly free the list entry */
451 * AtSubCommit_smgr() --- Take care of subtransaction commit.
453 * Reassign all items in the pending-deletes list to the parent transaction.
456 AtSubCommit_smgr(void)
458 int nestLevel = GetCurrentTransactionNestLevel();
459 PendingRelDelete *pending;
461 for (pending = pendingDeletes; pending != NULL; pending = pending->next)
463 if (pending->nestLevel >= nestLevel)
464 pending->nestLevel = nestLevel - 1;
469 * AtSubAbort_smgr() --- Take care of subtransaction abort.
471 * Delete created relations and forget about deleted relations.
472 * We can execute these operations immediately because we know this
473 * subtransaction will not commit.
476 AtSubAbort_smgr(void)
478 smgrDoPendingDeletes(false);
482 smgr_redo(XLogRecPtr lsn, XLogRecord *record)
484 uint8 info = record->xl_info & ~XLR_INFO_MASK;
486 /* Backup blocks are not used in smgr records */
487 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
489 if (info == XLOG_SMGR_CREATE)
491 xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
494 reln = smgropen(xlrec->rnode, InvalidBackendId);
495 smgrcreate(reln, xlrec->forkNum, true);
497 else if (info == XLOG_SMGR_TRUNCATE)
499 xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
503 reln = smgropen(xlrec->rnode, InvalidBackendId);
506 * Forcibly create relation if it doesn't exist (which suggests that
507 * it was dropped somewhere later in the WAL sequence). As in
508 * XLogReadBuffer, we prefer to recreate the rel and replay the log as
509 * best we can until the drop is seen.
511 smgrcreate(reln, MAIN_FORKNUM, true);
514 * Before we perform the truncation, update minimum recovery point to
515 * cover this WAL record. Once the relation is truncated, there's no
516 * going back. The buffer manager enforces the WAL-first rule for
517 * normal updates to relation files, so that the minimum recovery
518 * point is always updated before the corresponding change in the data
519 * file is flushed to disk. We have to do the same manually here.
521 * Doing this before the truncation means that if the truncation fails
522 * for some reason, you cannot start up the system even after restart,
523 * until you fix the underlying situation so that the truncation will
524 * succeed. Alternatively, we could update the minimum recovery point
525 * after truncation, but that would leave a small window where the
526 * WAL-first rule could be violated.
530 smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
532 /* Also tell xlogutils.c about it */
533 XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
535 /* Truncate FSM and VM too */
536 rel = CreateFakeRelcacheEntry(xlrec->rnode);
538 if (smgrexists(reln, FSM_FORKNUM))
539 FreeSpaceMapTruncateRel(rel, xlrec->blkno);
540 if (smgrexists(reln, VISIBILITYMAP_FORKNUM))
541 visibilitymap_truncate(rel, xlrec->blkno);
543 FreeFakeRelcacheEntry(rel);
546 elog(PANIC, "smgr_redo: unknown op code %u", info);