1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Rethink the way FSM truncation works. Instead of WAL-logging FSM

truncations in FSM code, call FreeSpaceMapTruncateRel from smgr_redo. To
make that cleaner from modularity point of view, move the WAL-logging one
level up to RelationTruncate, and move RelationTruncate and all the
related WAL-logging to new src/backend/catalog/storage.c file. Introduce
new RelationCreateStorage and RelationDropStorage functions that are used
instead of calling smgrcreate/smgrscheduleunlink directly. Move the
pending rel deletion stuff from smgrcreate/smgrscheduleunlink to the new
functions. This leaves smgr.c as a thin wrapper around md.c; all the
transactional stuff is now in storage.c.

This will make it easier to add new forks with similar truncation logic,
like the visibility map.
This commit is contained in:
Heikki Linnakangas
2008-11-19 10:34:52 +00:00
parent 26e6c896c9
commit 3396000684
30 changed files with 675 additions and 794 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.241 2008/11/11 13:19:16 heikki Exp $
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.242 2008/11/19 10:34:52 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@ -1695,8 +1695,6 @@ void
BufmgrCommit(void)
{
/* Nothing to do in bufmgr anymore... */
smgrcommit();
}
/*
@ -1848,26 +1846,6 @@ RelationGetNumberOfBlocks(Relation relation)
return smgrnblocks(relation->rd_smgr, MAIN_FORKNUM);
}
/*
* RelationTruncate
* Physically truncate a relation to the specified number of blocks.
*
* As of Postgres 8.1, this includes getting rid of any buffers for the
* blocks that are to be dropped; previously, callers had to do that.
*/
void
RelationTruncate(Relation rel, BlockNumber nblocks)
{
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
/* Make sure rd_targblock isn't pointing somewhere past end */
rel->rd_targblock = InvalidBlockNumber;
/* Do the real work */
smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks, rel->rd_istemp);
}
/* ---------------------------------------------------------------------
* DropRelFileNodeBuffers
*

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.66 2008/10/31 19:40:27 heikki Exp $
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.67 2008/11/19 10:34:52 heikki Exp $
*
*
* NOTES:
@ -47,7 +47,7 @@
* MaxFSMRequestSize depends on the architecture and BLCKSZ, but assuming
* default 8k BLCKSZ, and that MaxFSMRequestSize is 24 bytes, the categories
* look like this
*
*
*
* Range Category
* 0 - 31 0
@ -93,15 +93,6 @@ typedef struct
/* Address of the root page. */
static const FSMAddress FSM_ROOT_ADDRESS = { FSM_ROOT_LEVEL, 0 };
/* XLOG record types */
#define XLOG_FSM_TRUNCATE 0x00 /* truncate */
typedef struct
{
RelFileNode node; /* truncated relation */
BlockNumber nheapblocks; /* new number of blocks in the heap */
} xl_fsm_truncate;
/* functions to navigate the tree */
static FSMAddress fsm_get_child(FSMAddress parent, uint16 slot);
static FSMAddress fsm_get_parent(FSMAddress child, uint16 *slot);
@ -110,7 +101,7 @@ static BlockNumber fsm_get_heap_blk(FSMAddress addr, uint16 slot);
static BlockNumber fsm_logical_to_physical(FSMAddress addr);
static Buffer fsm_readbuf(Relation rel, FSMAddress addr, bool extend);
static void fsm_extend(Relation rel, BlockNumber nfsmblocks);
static void fsm_extend(Relation rel, BlockNumber nfsmblocks, bool createstorage);
/* functions to convert amount of free space to a FSM category */
static uint8 fsm_space_avail_to_cat(Size avail);
@ -123,8 +114,6 @@ static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
static BlockNumber fsm_search(Relation rel, uint8 min_cat);
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
static void fsm_redo_truncate(xl_fsm_truncate *xlrec);
/******** Public API ********/
@ -275,6 +264,13 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
RelationOpenSmgr(rel);
/*
* If no FSM has been created yet for this relation, there's nothing to
* truncate.
*/
if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
return;
/* Get the location in the FSM of the first removed heap block */
first_removed_address = fsm_get_location(nblocks, &first_removed_slot);
@ -306,43 +302,12 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
/* Truncate the unused FSM pages */
smgrtruncate(rel->rd_smgr, FSM_FORKNUM, new_nfsmblocks, rel->rd_istemp);
/*
* FSM truncations are WAL-logged, because we must never return a block
* that doesn't exist in the heap, not even if we crash before the FSM
* truncation has made it to disk. smgrtruncate() writes its own WAL
* record, but that's not enough to zero out the last remaining FSM page.
* (if we didn't need to zero out anything above, we can skip this)
*/
if (!rel->rd_istemp && first_removed_slot != 0)
{
xl_fsm_truncate xlrec;
XLogRecData rdata;
XLogRecPtr recptr;
xlrec.node = rel->rd_node;
xlrec.nheapblocks = nblocks;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xl_fsm_truncate);
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
recptr = XLogInsert(RM_FREESPACE_ID, XLOG_FSM_TRUNCATE, &rdata);
/*
* Flush, because otherwise the truncation of the main relation
* might hit the disk before the WAL record of truncating the
* FSM is flushed. If we crashed during that window, we'd be
* left with a truncated heap, without a truncated FSM.
*/
XLogFlush(recptr);
}
/*
* Need to invalidate the relcache entry, because rd_fsm_nblocks_cache
* seen by other backends is no longer valid.
*/
CacheInvalidateRelcache(rel);
if (!InRecovery)
CacheInvalidateRelcache(rel);
rel->rd_fsm_nblocks_cache = new_nfsmblocks;
}
@ -538,14 +503,19 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
RelationOpenSmgr(rel);
if (rel->rd_fsm_nblocks_cache == InvalidBlockNumber ||
if (rel->rd_fsm_nblocks_cache == InvalidBlockNumber ||
rel->rd_fsm_nblocks_cache <= blkno)
rel->rd_fsm_nblocks_cache = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
{
if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
fsm_extend(rel, blkno + 1, true);
else
rel->rd_fsm_nblocks_cache = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
}
if (blkno >= rel->rd_fsm_nblocks_cache)
{
if (extend)
fsm_extend(rel, blkno + 1);
fsm_extend(rel, blkno + 1, false);
else
return InvalidBuffer;
}
@ -566,10 +536,11 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
/*
* Ensure that the FSM fork is at least n_fsmblocks long, extending
* it if necessary with empty pages. And by empty, I mean pages filled
* with zeros, meaning there's no free space.
* with zeros, meaning there's no free space. If createstorage is true,
* the FSM file might need to be created first.
*/
static void
fsm_extend(Relation rel, BlockNumber n_fsmblocks)
fsm_extend(Relation rel, BlockNumber n_fsmblocks, bool createstorage)
{
BlockNumber n_fsmblocks_now;
Page pg;
@ -589,7 +560,15 @@ fsm_extend(Relation rel, BlockNumber n_fsmblocks)
*/
LockRelationForExtension(rel, ExclusiveLock);
n_fsmblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
/* Create the FSM file first if it doesn't exist */
if (createstorage && !smgrexists(rel->rd_smgr, FSM_FORKNUM))
{
smgrcreate(rel->rd_smgr, FSM_FORKNUM, false);
n_fsmblocks_now = 0;
}
else
n_fsmblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
while (n_fsmblocks_now < n_fsmblocks)
{
smgrextend(rel->rd_smgr, FSM_FORKNUM, n_fsmblocks_now,
@ -799,75 +778,3 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
return max_avail;
}
/****** WAL-logging ******/
static void
fsm_redo_truncate(xl_fsm_truncate *xlrec)
{
FSMAddress first_removed_address;
uint16 first_removed_slot;
BlockNumber fsmblk;
Buffer buf;
/* Get the location in the FSM of the first removed heap block */
first_removed_address = fsm_get_location(xlrec->nheapblocks,
&first_removed_slot);
fsmblk = fsm_logical_to_physical(first_removed_address);
/*
* Zero out the tail of the last remaining FSM page. We rely on the
* replay of the smgr truncation record to remove completely unused
* pages.
*/
buf = XLogReadBufferExtended(xlrec->node, FSM_FORKNUM, fsmblk,
RBM_ZERO_ON_ERROR);
if (BufferIsValid(buf))
{
Page page = BufferGetPage(buf);
if (PageIsNew(page))
PageInit(page, BLCKSZ, 0);
fsm_truncate_avail(page, first_removed_slot);
MarkBufferDirty(buf);
UnlockReleaseBuffer(buf);
}
}
void
fsm_redo(XLogRecPtr lsn, XLogRecord *record)
{
uint8 info = record->xl_info & ~XLR_INFO_MASK;
switch (info)
{
case XLOG_FSM_TRUNCATE:
fsm_redo_truncate((xl_fsm_truncate *) XLogRecGetData(record));
break;
default:
elog(PANIC, "fsm_redo: unknown op code %u", info);
}
}
void
fsm_desc(StringInfo buf, uint8 xl_info, char *rec)
{
uint8 info = xl_info & ~XLR_INFO_MASK;
switch (info)
{
case XLOG_FSM_TRUNCATE:
{
xl_fsm_truncate *xlrec = (xl_fsm_truncate *) rec;
appendStringInfo(buf, "truncate: rel %u/%u/%u; nheapblocks %u;",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->nheapblocks);
break;
}
default:
appendStringInfo(buf, "UNKNOWN");
break;
}
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/freespace/indexfsm.c,v 1.2 2008/10/06 08:04:11 heikki Exp $
* $PostgreSQL: pgsql/src/backend/storage/freespace/indexfsm.c,v 1.3 2008/11/19 10:34:52 heikki Exp $
*
*
* NOTES:
@ -30,20 +30,6 @@
* Exported routines
*/
/*
* InitIndexFreeSpaceMap - Create or reset the FSM fork for relation.
*/
void
InitIndexFreeSpaceMap(Relation rel)
{
/* Create FSM fork if it doesn't exist yet, or truncate it if it does */
RelationOpenSmgr(rel);
if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
smgrcreate(rel->rd_smgr, FSM_FORKNUM, rel->rd_istemp, false);
else
smgrtruncate(rel->rd_smgr, FSM_FORKNUM, 0, rel->rd_istemp);
}
/*
* GetFreeIndexPage - return a free page from the FSM
*
@ -79,18 +65,6 @@ RecordUsedIndexPage(Relation rel, BlockNumber usedBlock)
RecordPageWithFreeSpace(rel, usedBlock, 0);
}
/*
* IndexFreeSpaceMapTruncate - adjust for truncation of a relation.
*
* We need to delete any stored data past the new relation length, so that
* we don't bogusly return removed block numbers.
*/
void
IndexFreeSpaceMapTruncate(Relation rel, BlockNumber nblocks)
{
FreeSpaceMapTruncateRel(rel, nblocks);
}
/*
* IndexFreeSpaceMapVacuum - scan and fix any inconsistencies in the FSM
*/

View File

@ -11,13 +11,12 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.113 2008/11/11 13:19:16 heikki Exp $
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.114 2008/11/19 10:34:52 heikki Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/xact.h"
#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "commands/tablespace.h"
@ -25,7 +24,6 @@
#include "storage/ipc.h"
#include "storage/smgr.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
/*
@ -58,8 +56,6 @@ typedef struct f_smgr
void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum,
BlockNumber nblocks, bool isTemp);
void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum);
void (*smgr_commit) (void); /* may be NULL */
void (*smgr_abort) (void); /* may be NULL */
void (*smgr_pre_ckpt) (void); /* may be NULL */
void (*smgr_sync) (void); /* may be NULL */
void (*smgr_post_ckpt) (void); /* may be NULL */
@ -70,7 +66,7 @@ static const f_smgr smgrsw[] = {
/* magnetic disk */
{mdinit, NULL, mdclose, mdcreate, mdexists, mdunlink, mdextend,
mdread, mdwrite, mdnblocks, mdtruncate, mdimmedsync,
NULL, NULL, mdpreckpt, mdsync, mdpostckpt
mdpreckpt, mdsync, mdpostckpt
}
};
@ -82,65 +78,6 @@ static const int NSmgr = lengthof(smgrsw);
*/
static HTAB *SMgrRelationHash = NULL;
/*
* We keep a list of all relations (represented as RelFileNode values)
* that have been created or deleted in the current transaction. When
* a relation is created, we create the physical file immediately, but
* remember it so that we can delete the file again if the current
* transaction is aborted. Conversely, a deletion request is NOT
* executed immediately, but is just entered in the list. When and if
* the transaction commits, we can delete the physical file.
*
* To handle subtransactions, every entry is marked with its transaction
* nesting level. At subtransaction commit, we reassign the subtransaction's
* entries to the parent nesting level. At subtransaction abort, we can
* immediately execute the abort-time actions for all entries of the current
* nesting level.
*
* NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
* unbetimes. It'd probably be OK to keep it in TopTransactionContext,
* but I'm being paranoid.
*/
typedef struct PendingRelDelete
{
RelFileNode relnode; /* relation that may need to be deleted */
ForkNumber forknum; /* fork number that may need to be deleted */
int which; /* which storage manager? */
bool isTemp; /* is it a temporary relation? */
bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
struct PendingRelDelete *next; /* linked-list link */
} PendingRelDelete;
static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
/*
* Declarations for smgr-related XLOG records
*
* Note: we log file creation and truncation here, but logging of deletion
* actions is handled by xact.c, because it is part of transaction commit.
*/
/* XLOG gives us high 4 bits */
#define XLOG_SMGR_CREATE 0x10
#define XLOG_SMGR_TRUNCATE 0x20
typedef struct xl_smgr_create
{
RelFileNode rnode;
ForkNumber forknum;
} xl_smgr_create;
typedef struct xl_smgr_truncate
{
BlockNumber blkno;
RelFileNode rnode;
ForkNumber forknum;
} xl_smgr_truncate;
/* local function prototypes */
static void smgrshutdown(int code, Datum arg);
static void smgr_internal_unlink(RelFileNode rnode, ForkNumber forknum,
@ -341,18 +278,11 @@ smgrclosenode(RelFileNode rnode)
* to be created.
*
* If isRedo is true, it is okay for the underlying file to exist
* already because we are in a WAL replay sequence. In this case
* we should make no PendingRelDelete entry; the WAL sequence will
* tell whether to drop the file.
* already because we are in a WAL replay sequence.
*/
void
smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isTemp, bool isRedo)
smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
{
XLogRecPtr lsn;
XLogRecData rdata;
xl_smgr_create xlrec;
PendingRelDelete *pending;
/*
* Exit quickly in WAL replay mode if we've already opened the file.
* If it's open, it surely must exist.
@ -374,69 +304,6 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isTemp, bool isRedo)
isRedo);
(*(smgrsw[reln->smgr_which].smgr_create)) (reln, forknum, isRedo);
if (isRedo)
return;
/*
* Make an XLOG entry showing the file creation. If we abort, the file
* will be dropped at abort time.
*/
xlrec.rnode = reln->smgr_rnode;
xlrec.forknum = forknum;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
/* Add the relation to the list of stuff to delete at abort */
pending = (PendingRelDelete *)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending->relnode = reln->smgr_rnode;
pending->forknum = forknum;
pending->which = reln->smgr_which;
pending->isTemp = isTemp;
pending->atCommit = false; /* delete if abort */
pending->nestLevel = GetCurrentTransactionNestLevel();
pending->next = pendingDeletes;
pendingDeletes = pending;
}
/*
* smgrscheduleunlink() -- Schedule unlinking a relation at xact commit.
*
* The fork is marked to be removed from the store if we successfully
* commit the current transaction.
*/
void
smgrscheduleunlink(SMgrRelation reln, ForkNumber forknum, bool isTemp)
{
PendingRelDelete *pending;
/* Add the relation to the list of stuff to delete at commit */
pending = (PendingRelDelete *)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending->relnode = reln->smgr_rnode;
pending->forknum = forknum;
pending->which = reln->smgr_which;
pending->isTemp = isTemp;
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.
*/
}
/*
@ -573,27 +440,6 @@ smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks,
/* Do the truncation */
(*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, forknum, nblocks,
isTemp);
if (!isTemp)
{
/*
* Make an XLOG entry showing the file truncation.
*/
XLogRecPtr lsn;
XLogRecData rdata;
xl_smgr_truncate xlrec;
xlrec.blkno = nblocks;
xlrec.rnode = reln->smgr_rnode;
xlrec.forknum = forknum;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
}
}
/*
@ -626,187 +472,6 @@ smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
}
/*
* PostPrepare_smgr -- Clean up after a successful PREPARE
*
* What we have to do here is throw away the in-memory state about pending
* relation deletes. It's all been recorded in the 2PC state file and
* it's no longer smgr's job to worry about it.
*/
void
PostPrepare_smgr(void)
{
PendingRelDelete *pending;
PendingRelDelete *next;
for (pending = pendingDeletes; pending != NULL; pending = next)
{
next = pending->next;
pendingDeletes = next;
/* must explicitly free the list entry */
pfree(pending);
}
}
/*
* smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
*
* This also runs when aborting a subxact; we want to clean up a failed
* subxact immediately.
*/
void
smgrDoPendingDeletes(bool isCommit)
{
int nestLevel = GetCurrentTransactionNestLevel();
PendingRelDelete *pending;
PendingRelDelete *prev;
PendingRelDelete *next;
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)
smgr_internal_unlink(pending->relnode,
pending->forknum,
pending->which,
pending->isTemp,
false);
/* must explicitly free the list entry */
pfree(pending);
/* prev does not change */
}
}
}
/*
* smgrGetPendingDeletes() -- Get a list of relations to be deleted.
*
* The return value is the number of relations scheduled for termination.
* *ptr is set to point to a freshly-palloc'd array of RelFileForks.
* If there are no relations to be deleted, *ptr is set to NULL.
*
* If haveNonTemp isn't NULL, the bool it points to gets set to true if
* there is any non-temp table pending to be deleted; false if not.
*
* Note that the list does not include anything scheduled for termination
* by upper-level transactions.
*/
int
smgrGetPendingDeletes(bool forCommit, RelFileFork **ptr, bool *haveNonTemp)
{
int nestLevel = GetCurrentTransactionNestLevel();
int nrels;
RelFileFork *rptr;
PendingRelDelete *pending;
nrels = 0;
if (haveNonTemp)
*haveNonTemp = false;
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
nrels++;
}
if (nrels == 0)
{
*ptr = NULL;
return 0;
}
rptr = (RelFileFork *) palloc(nrels * sizeof(RelFileFork));
*ptr = rptr;
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
{
rptr->rnode = pending->relnode;
rptr->forknum = pending->forknum;
rptr++;
}
if (haveNonTemp && !pending->isTemp)
*haveNonTemp = true;
}
return nrels;
}
/*
* AtSubCommit_smgr() --- Take care of subtransaction commit.
*
* Reassign all items in the pending-deletes list to the parent transaction.
*/
void
AtSubCommit_smgr(void)
{
int nestLevel = GetCurrentTransactionNestLevel();
PendingRelDelete *pending;
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel)
pending->nestLevel = nestLevel - 1;
}
}
/*
* AtSubAbort_smgr() --- Take care of subtransaction abort.
*
* Delete created relations and forget about deleted relations.
* We can execute these operations immediately because we know this
* subtransaction will not commit.
*/
void
AtSubAbort_smgr(void)
{
smgrDoPendingDeletes(false);
}
/*
* smgrcommit() -- Prepare to commit changes made during the current
* transaction.
*
* This is called before we actually commit.
*/
void
smgrcommit(void)
{
int i;
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_commit)
(*(smgrsw[i].smgr_commit)) ();
}
}
/*
* smgrabort() -- Clean up after transaction abort.
*/
void
smgrabort(void)
{
int i;
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_abort)
(*(smgrsw[i].smgr_abort)) ();
}
}
/*
* smgrpreckpt() -- Prepare for checkpoint.
*/
@ -852,80 +517,3 @@ smgrpostckpt(void)
}
}
void
smgr_redo(XLogRecPtr lsn, XLogRecord *record)
{
uint8 info = record->xl_info & ~XLR_INFO_MASK;
if (info == XLOG_SMGR_CREATE)
{
xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
SMgrRelation reln;
reln = smgropen(xlrec->rnode);
smgrcreate(reln, xlrec->forknum, false, true);
}
else if (info == XLOG_SMGR_TRUNCATE)
{
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
SMgrRelation reln;
reln = smgropen(xlrec->rnode);
/*
* Forcibly create relation if it doesn't exist (which suggests that
* it was dropped somewhere later in the WAL sequence). As in
* XLogOpenRelation, we prefer to recreate the rel and replay the log
* as best we can until the drop is seen.
*/
smgrcreate(reln, xlrec->forknum, false, true);
/* Can't use smgrtruncate because it would try to xlog */
/*
* First, force bufmgr to drop any buffers it has for the to-be-
* truncated blocks. We must do this, else subsequent XLogReadBuffer
* operations will not re-extend the file properly.
*/
DropRelFileNodeBuffers(xlrec->rnode, xlrec->forknum, false,
xlrec->blkno);
/* Do the truncation */
(*(smgrsw[reln->smgr_which].smgr_truncate)) (reln,
xlrec->forknum,
xlrec->blkno,
false);
/* Also tell xlogutils.c about it */
XLogTruncateRelation(xlrec->rnode, xlrec->forknum, xlrec->blkno);
}
else
elog(PANIC, "smgr_redo: unknown op code %u", info);
}
void
smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
{
uint8 info = xl_info & ~XLR_INFO_MASK;
if (info == XLOG_SMGR_CREATE)
{
xl_smgr_create *xlrec = (xl_smgr_create *) rec;
char *path = relpath(xlrec->rnode, xlrec->forknum);
appendStringInfo(buf, "file create: %s", path);
pfree(path);
}
else if (info == XLOG_SMGR_TRUNCATE)
{
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
char *path = relpath(xlrec->rnode, xlrec->forknum);
appendStringInfo(buf, "file truncate: %s to %u blocks", path,
xlrec->blkno);
pfree(path);
}
else
appendStringInfo(buf, "UNKNOWN");
}