#include "storage/block.h"
#include "storage/relfilenode.h"
#include "utils/relcache.h"
Go to the source code of this file.
Functions | |
void | RelationCreateStorage (RelFileNode rnode, char relpersistence) |
void | RelationDropStorage (Relation rel) |
void | RelationPreserveStorage (RelFileNode rnode, bool atCommit) |
void | RelationTruncate (Relation rel, BlockNumber nblocks) |
void | smgrDoPendingDeletes (bool isCommit) |
int | smgrGetPendingDeletes (bool forCommit, RelFileNode **ptr) |
void | AtSubCommit_smgr (void) |
void | AtSubAbort_smgr (void) |
void | PostPrepare_smgr (void) |
void AtSubAbort_smgr | ( | void | ) |
Definition at line 470 of file storage.c.
References smgrDoPendingDeletes().
Referenced by AbortSubTransaction().
{ smgrDoPendingDeletes(false); }
void AtSubCommit_smgr | ( | void | ) |
Definition at line 450 of file storage.c.
References GetCurrentTransactionNestLevel(), PendingRelDelete::nestLevel, and PendingRelDelete::next.
Referenced by CommitSubTransaction().
{ int nestLevel = GetCurrentTransactionNestLevel(); PendingRelDelete *pending; for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel) pending->nestLevel = nestLevel - 1; } }
void PostPrepare_smgr | ( | void | ) |
Definition at line 429 of file storage.c.
References PendingRelDelete::next, and pfree().
Referenced by PrepareTransaction().
{ PendingRelDelete *pending; PendingRelDelete *next; for (pending = pendingDeletes; pending != NULL; pending = next) { next = pending->next; pendingDeletes = next; /* must explicitly free the list entry */ pfree(pending); } }
void RelationCreateStorage | ( | RelFileNode | rnode, | |
char | relpersistence | |||
) |
Definition at line 76 of file storage.c.
References PendingRelDelete::atCommit, PendingRelDelete::backend, elog, ERROR, GetCurrentTransactionNestLevel(), log_smgrcreate(), MAIN_FORKNUM, MemoryContextAlloc(), MyBackendId, PendingRelDelete::nestLevel, PendingRelDelete::next, RelFileNodeBackend::node, PendingRelDelete::relnode, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, SMgrRelationData::smgr_rnode, smgrcreate(), smgropen(), and TopMemoryContext.
Referenced by ATExecSetTableSpace(), heap_create(), and RelationSetNewRelfilenode().
{ PendingRelDelete *pending; SMgrRelation srel; BackendId backend; bool needs_wal; switch (relpersistence) { case RELPERSISTENCE_TEMP: backend = MyBackendId; needs_wal = false; break; case RELPERSISTENCE_UNLOGGED: backend = InvalidBackendId; needs_wal = false; break; case RELPERSISTENCE_PERMANENT: backend = InvalidBackendId; needs_wal = true; break; default: elog(ERROR, "invalid relpersistence: %c", relpersistence); return; /* placate compiler */ } srel = smgropen(rnode, backend); smgrcreate(srel, MAIN_FORKNUM, false); if (needs_wal) log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM); /* Add the relation to the list of stuff to delete at abort */ pending = (PendingRelDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); pending->relnode = rnode; pending->backend = backend; pending->atCommit = false; /* delete if abort */ pending->nestLevel = GetCurrentTransactionNestLevel(); pending->next = pendingDeletes; pendingDeletes = pending; }
void RelationDropStorage | ( | Relation | rel | ) |
Definition at line 147 of file storage.c.
References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), MemoryContextAlloc(), PendingRelDelete::nestLevel, PendingRelDelete::next, RelationData::rd_backend, RelationData::rd_node, RelationCloseSmgr, PendingRelDelete::relnode, and TopMemoryContext.
Referenced by ATExecSetTableSpace(), DefineQueryRewrite(), heap_drop_with_catalog(), index_drop(), and RelationSetNewRelfilenode().
{ PendingRelDelete *pending; /* Add the relation to the list of stuff to delete at commit */ pending = (PendingRelDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); pending->relnode = rel->rd_node; pending->backend = rel->rd_backend; pending->atCommit = true; /* delete if commit */ pending->nestLevel = GetCurrentTransactionNestLevel(); pending->next = pendingDeletes; pendingDeletes = pending; /* * NOTE: if the relation was created in this transaction, it will now be * present in the pending-delete list twice, once with atCommit true and * once with atCommit false. Hence, it will be physically deleted at end * of xact in either case (and the other entry will be ignored by * smgrDoPendingDeletes, so no error will occur). We could instead remove * the existing list entry and delete the physical file immediately, but * for now I'll keep the logic simple. */ RelationCloseSmgr(rel); }
void RelationPreserveStorage | ( | RelFileNode | rnode, | |
bool | atCommit | |||
) |
Definition at line 192 of file storage.c.
References PendingRelDelete::atCommit, PendingRelDelete::next, pfree(), RelFileNodeEquals, and PendingRelDelete::relnode.
Referenced by ATExecAddIndex(), and write_relmap_file().
{ PendingRelDelete *pending; PendingRelDelete *prev; PendingRelDelete *next; prev = NULL; for (pending = pendingDeletes; pending != NULL; pending = next) { next = pending->next; if (RelFileNodeEquals(rnode, pending->relnode) && pending->atCommit == atCommit) { /* unlink and delete list entry */ if (prev) prev->next = next; else pendingDeletes = next; pfree(pending); /* prev does not change */ } else { /* unrelated entry, don't touch it */ prev = pending; } } }
void RelationTruncate | ( | Relation | rel, | |
BlockNumber | nblocks | |||
) |
Definition at line 229 of file storage.c.
References xl_smgr_truncate::blkno, XLogRecData::buffer, XLogRecData::data, FreeSpaceMapTruncateRel(), FSM_FORKNUM, XLogRecData::len, MAIN_FORKNUM, XLogRecData::next, RelationData::rd_node, RelationData::rd_smgr, RelationNeedsWAL, RelationOpenSmgr, xl_smgr_truncate::rnode, SMgrRelationData::smgr_fsm_nblocks, SMgrRelationData::smgr_targblock, SMgrRelationData::smgr_vm_nblocks, smgrexists(), smgrtruncate(), VISIBILITYMAP_FORKNUM, visibilitymap_truncate(), XLOG_SMGR_TRUNCATE, XLogFlush(), and XLogInsert().
Referenced by heap_truncate_one_rel(), lazy_truncate_heap(), RelationTruncateIndexes(), and spgvacuumscan().
{ bool fsm; bool vm; /* Open it at the smgr level if not already done */ RelationOpenSmgr(rel); /* * Make sure smgr_targblock etc aren't pointing somewhere past new end */ rel->rd_smgr->smgr_targblock = InvalidBlockNumber; rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber; rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; /* Truncate the FSM first if it exists */ fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM); if (fsm) FreeSpaceMapTruncateRel(rel, nblocks); /* Truncate the visibility map too if it exists. */ vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM); if (vm) visibilitymap_truncate(rel, nblocks); /* * We WAL-log the truncation before actually truncating, which means * trouble if the truncation fails. If we then crash, the WAL replay * likely isn't going to succeed in the truncation either, and cause a * PANIC. It's tempting to put a critical section here, but that cure * would be worse than the disease. It would turn a usually harmless * failure to truncate, that might spell trouble at WAL replay, into a * certain PANIC. */ if (RelationNeedsWAL(rel)) { /* * Make an XLOG entry reporting the file truncation. */ XLogRecPtr lsn; XLogRecData rdata; xl_smgr_truncate xlrec; xlrec.blkno = nblocks; xlrec.rnode = rel->rd_node; rdata.data = (char *) &xlrec; rdata.len = sizeof(xlrec); rdata.buffer = InvalidBuffer; rdata.next = NULL; lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata); /* * Flush, because otherwise the truncation of the main relation might * hit the disk before the WAL record, and the truncation of the FSM * or visibility map. If we crashed during that window, we'd be left * with a truncated heap, but the FSM or visibility map would still * contain entries for the non-existent heap pages. */ if (fsm || vm) XLogFlush(lsn); } /* Do the real work */ smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks); }
void smgrDoPendingDeletes | ( | bool | isCommit | ) |
Definition at line 309 of file storage.c.
References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), i, PendingRelDelete::nestLevel, PendingRelDelete::next, palloc(), pfree(), PendingRelDelete::relnode, repalloc(), smgrclose(), smgrdounlinkall(), and smgropen().
Referenced by AbortTransaction(), AtSubAbort_smgr(), and CommitTransaction().
{ int nestLevel = GetCurrentTransactionNestLevel(); PendingRelDelete *pending; PendingRelDelete *prev; PendingRelDelete *next; int nrels = 0, i = 0, maxrels = 8; SMgrRelation *srels = palloc(maxrels * sizeof(SMgrRelation)); prev = NULL; for (pending = pendingDeletes; pending != NULL; pending = next) { next = pending->next; if (pending->nestLevel < nestLevel) { /* outer-level entries should not be processed yet */ prev = pending; } else { /* unlink list entry first, so we don't retry on failure */ if (prev) prev->next = next; else pendingDeletes = next; /* do deletion if called for */ if (pending->atCommit == isCommit) { SMgrRelation srel; srel = smgropen(pending->relnode, pending->backend); /* extend the array if needed (double the size) */ if (maxrels <= nrels) { maxrels *= 2; srels = repalloc(srels, sizeof(SMgrRelation) * maxrels); } srels[nrels++] = srel; } /* must explicitly free the list entry */ pfree(pending); /* prev does not change */ } } if (nrels > 0) { smgrdounlinkall(srels, nrels, false); for (i = 0; i < nrels; i++) smgrclose(srels[i]); } pfree(srels); }
int smgrGetPendingDeletes | ( | bool | forCommit, | |
RelFileNode ** | ptr | |||
) |
Definition at line 388 of file storage.c.
References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), InvalidBackendId, PendingRelDelete::nestLevel, PendingRelDelete::next, palloc(), and PendingRelDelete::relnode.
Referenced by RecordTransactionAbort(), RecordTransactionCommit(), and StartPrepare().
{ int nestLevel = GetCurrentTransactionNestLevel(); int nrels; RelFileNode *rptr; PendingRelDelete *pending; nrels = 0; for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit && pending->backend == InvalidBackendId) nrels++; } if (nrels == 0) { *ptr = NULL; return 0; } rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode)); *ptr = rptr; for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit && pending->backend == InvalidBackendId) { *rptr = pending->relnode; rptr++; } } return nrels; }