#include "postgres.h"#include "access/visibilitymap.h"#include "access/xact.h"#include "access/xlogutils.h"#include "catalog/catalog.h"#include "catalog/storage.h"#include "catalog/storage_xlog.h"#include "storage/freespace.h"#include "storage/smgr.h"#include "utils/memutils.h"#include "utils/rel.h"
Go to the source code of this file.
Data Structures | |
| struct | PendingRelDelete |
Typedefs | |
| typedef struct PendingRelDelete | PendingRelDelete |
Functions | |
| void | RelationCreateStorage (RelFileNode rnode, char relpersistence) |
| void | log_smgrcreate (RelFileNode *rnode, ForkNumber forkNum) |
| 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 | PostPrepare_smgr (void) |
| void | AtSubCommit_smgr (void) |
| void | AtSubAbort_smgr (void) |
| void | smgr_redo (XLogRecPtr lsn, XLogRecord *record) |
Variables | |
| static PendingRelDelete * | pendingDeletes = NULL |
| typedef struct PendingRelDelete PendingRelDelete |
| 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 log_smgrcreate | ( | RelFileNode * | rnode, | |
| ForkNumber | forkNum | |||
| ) |
Definition at line 123 of file storage.c.
References XLogRecData::buffer, XLogRecData::data, xl_smgr_create::forkNum, XLogRecData::len, XLogRecData::next, xl_smgr_create::rnode, XLOG_SMGR_CREATE, and XLogInsert().
Referenced by heap_create_init_fork(), and RelationCreateStorage().
{
xl_smgr_create xlrec;
XLogRecData rdata;
/*
* Make an XLOG entry reporting the file creation.
*/
xlrec.rnode = *rnode;
xlrec.forkNum = forkNum;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
}
| 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 smgr_redo | ( | XLogRecPtr | lsn, | |
| XLogRecord * | record | |||
| ) |
Definition at line 476 of file storage.c.
References Assert, xl_smgr_truncate::blkno, CreateFakeRelcacheEntry(), elog, xl_smgr_create::forkNum, FreeFakeRelcacheEntry(), FreeSpaceMapTruncateRel(), FSM_FORKNUM, InvalidBackendId, MAIN_FORKNUM, PANIC, xl_smgr_truncate::rnode, xl_smgr_create::rnode, smgrcreate(), smgrexists(), smgropen(), smgrtruncate(), VISIBILITYMAP_FORKNUM, visibilitymap_truncate(), XLogRecord::xl_info, XLOG_SMGR_CREATE, XLOG_SMGR_TRUNCATE, XLogFlush(), XLogRecGetData, XLogTruncateRelation(), and XLR_BKP_BLOCK_MASK.
{
uint8 info = record->xl_info & ~XLR_INFO_MASK;
/* Backup blocks are not used in smgr records */
Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
if (info == XLOG_SMGR_CREATE)
{
xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
SMgrRelation reln;
reln = smgropen(xlrec->rnode, InvalidBackendId);
smgrcreate(reln, xlrec->forkNum, true);
}
else if (info == XLOG_SMGR_TRUNCATE)
{
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
SMgrRelation reln;
Relation rel;
reln = smgropen(xlrec->rnode, InvalidBackendId);
/*
* Forcibly create relation if it doesn't exist (which suggests that
* it was dropped somewhere later in the WAL sequence). As in
* XLogReadBuffer, we prefer to recreate the rel and replay the log as
* best we can until the drop is seen.
*/
smgrcreate(reln, MAIN_FORKNUM, true);
/*
* Before we perform the truncation, update minimum recovery point
* to cover this WAL record. Once the relation is truncated, there's
* no going back. The buffer manager enforces the WAL-first rule
* for normal updates to relation files, so that the minimum recovery
* point is always updated before the corresponding change in the
* data file is flushed to disk. We have to do the same manually
* here.
*
* Doing this before the truncation means that if the truncation fails
* for some reason, you cannot start up the system even after restart,
* until you fix the underlying situation so that the truncation will
* succeed. Alternatively, we could update the minimum recovery point
* after truncation, but that would leave a small window where the
* WAL-first rule could be violated.
*/
XLogFlush(lsn);
smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
/* Also tell xlogutils.c about it */
XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
/* Truncate FSM and VM too */
rel = CreateFakeRelcacheEntry(xlrec->rnode);
if (smgrexists(reln, FSM_FORKNUM))
FreeSpaceMapTruncateRel(rel, xlrec->blkno);
if (smgrexists(reln, VISIBILITYMAP_FORKNUM))
visibilitymap_truncate(rel, xlrec->blkno);
FreeFakeRelcacheEntry(rel);
}
else
elog(PANIC, "smgr_redo: unknown op code %u", info);
}
| 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;
}
PendingRelDelete* pendingDeletes = NULL [static] |
1.7.1