mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-23 01:20:41 +02:00
Rethink the delay-checkpoint-end mechanism in the back-branches.
The back-patch of commit bbace5697d
had
the unfortunate effect of changing the layout of PGPROC in the
back-branches, which could break extensions. This happened because it
changed the delayChkpt from type bool to type int. So, change it back,
and add a new bool delayChkptEnd field instead. The new field should
fall within what used to be padding space within the struct, and so
hopefully won't cause any extensions to break.
Per report from Markus Wanner and discussion with Tom Lane and others.
Patch originally by me, somewhat revised by Markus Wanner per a
suggestion from Michael Paquier. A very similar patch was developed
by Kyotaro Horiguchi, but I failed to see the email in which that was
posted before writing one of my own.
Discussion: http://postgr.es/m/CA+Tgmoao-kUD9c5nG5sub3F7tbo39+cdr8jKaOVEs_1aBWcJ3Q@mail.gmail.com
Discussion: http://postgr.es/m/20220406.164521.17171257901083417.horikyota.ntt@gmail.com
This commit is contained in:
parent
79fed072ba
commit
6270ee4450
@ -3069,8 +3069,8 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
|||||||
* crash/basebackup, even though the state of the data directory would
|
* crash/basebackup, even though the state of the data directory would
|
||||||
* require it.
|
* require it.
|
||||||
*/
|
*/
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_START) == 0);
|
Assert(!MyPgXact->delayChkpt);
|
||||||
MyPgXact->delayChkpt |= DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = true;
|
||||||
|
|
||||||
/* WAL log truncation */
|
/* WAL log truncation */
|
||||||
WriteMTruncateXlogRec(newOldestMultiDB,
|
WriteMTruncateXlogRec(newOldestMultiDB,
|
||||||
@ -3096,7 +3096,7 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
|||||||
/* Then offsets */
|
/* Then offsets */
|
||||||
PerformOffsetsTruncation(oldestMulti, newOldestMulti);
|
PerformOffsetsTruncation(oldestMulti, newOldestMulti);
|
||||||
|
|
||||||
MyPgXact->delayChkpt &= ~DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = false;
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
LWLockRelease(MultiXactTruncationLock);
|
LWLockRelease(MultiXactTruncationLock);
|
||||||
|
@ -476,8 +476,9 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
|
|||||||
}
|
}
|
||||||
pgxact->xid = xid;
|
pgxact->xid = xid;
|
||||||
pgxact->xmin = InvalidTransactionId;
|
pgxact->xmin = InvalidTransactionId;
|
||||||
pgxact->delayChkpt = 0;
|
pgxact->delayChkpt = false;
|
||||||
pgxact->vacuumFlags = 0;
|
pgxact->vacuumFlags = 0;
|
||||||
|
proc->delayChkptEnd = false;
|
||||||
proc->pid = 0;
|
proc->pid = 0;
|
||||||
proc->databaseId = databaseid;
|
proc->databaseId = databaseid;
|
||||||
proc->roleId = owner;
|
proc->roleId = owner;
|
||||||
@ -1175,8 +1176,8 @@ EndPrepare(GlobalTransaction gxact)
|
|||||||
|
|
||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_START) == 0);
|
Assert(!MyPgXact->delayChkpt);
|
||||||
MyPgXact->delayChkpt |= DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = true;
|
||||||
|
|
||||||
XLogBeginInsert();
|
XLogBeginInsert();
|
||||||
for (record = records.head; record != NULL; record = record->next)
|
for (record = records.head; record != NULL; record = record->next)
|
||||||
@ -1219,7 +1220,7 @@ EndPrepare(GlobalTransaction gxact)
|
|||||||
* checkpoint starting after this will certainly see the gxact as a
|
* checkpoint starting after this will certainly see the gxact as a
|
||||||
* candidate for fsyncing.
|
* candidate for fsyncing.
|
||||||
*/
|
*/
|
||||||
MyPgXact->delayChkpt &= ~DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remember that we have this GlobalTransaction entry locked for us. If
|
* Remember that we have this GlobalTransaction entry locked for us. If
|
||||||
@ -2353,8 +2354,8 @@ RecordTransactionCommitPrepared(TransactionId xid,
|
|||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
/* See notes in RecordTransactionCommit */
|
/* See notes in RecordTransactionCommit */
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_START) == 0);
|
Assert(!MyPgXact->delayChkpt);
|
||||||
MyPgXact->delayChkpt |= DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit the XLOG commit record. Note that we mark 2PC commits as
|
* Emit the XLOG commit record. Note that we mark 2PC commits as
|
||||||
@ -2402,7 +2403,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
|
|||||||
TransactionIdCommitTree(xid, nchildren, children);
|
TransactionIdCommitTree(xid, nchildren, children);
|
||||||
|
|
||||||
/* Checkpoint can proceed now */
|
/* Checkpoint can proceed now */
|
||||||
MyPgXact->delayChkpt &= ~DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = false;
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
|
|
||||||
|
@ -1239,9 +1239,9 @@ RecordTransactionCommit(void)
|
|||||||
* This makes checkpoint's determination of which xacts are delayChkpt
|
* This makes checkpoint's determination of which xacts are delayChkpt
|
||||||
* a bit fuzzy, but it doesn't matter.
|
* a bit fuzzy, but it doesn't matter.
|
||||||
*/
|
*/
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_START) == 0);
|
Assert(!MyPgXact->delayChkpt);
|
||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
MyPgXact->delayChkpt |= DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = true;
|
||||||
|
|
||||||
SetCurrentTransactionStopTimestamp();
|
SetCurrentTransactionStopTimestamp();
|
||||||
|
|
||||||
@ -1342,7 +1342,7 @@ RecordTransactionCommit(void)
|
|||||||
*/
|
*/
|
||||||
if (markXidCommitted)
|
if (markXidCommitted)
|
||||||
{
|
{
|
||||||
MyPgXact->delayChkpt &= ~DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = false;
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9064,27 +9064,25 @@ CreateCheckPoint(int flags)
|
|||||||
* and we will correctly flush the update below. So we cannot miss any
|
* and we will correctly flush the update below. So we cannot miss any
|
||||||
* xacts we need to wait for.
|
* xacts we need to wait for.
|
||||||
*/
|
*/
|
||||||
vxids = GetVirtualXIDsDelayingChkpt(&nvxids, DELAY_CHKPT_START);
|
vxids = GetVirtualXIDsDelayingChkpt(&nvxids);
|
||||||
if (nvxids > 0)
|
if (nvxids > 0)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pg_usleep(10000L); /* wait for 10 msec */
|
pg_usleep(10000L); /* wait for 10 msec */
|
||||||
} while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids,
|
} while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids));
|
||||||
DELAY_CHKPT_START));
|
|
||||||
}
|
}
|
||||||
pfree(vxids);
|
pfree(vxids);
|
||||||
|
|
||||||
CheckPointGuts(checkPoint.redo, flags);
|
CheckPointGuts(checkPoint.redo, flags);
|
||||||
|
|
||||||
vxids = GetVirtualXIDsDelayingChkpt(&nvxids, DELAY_CHKPT_COMPLETE);
|
vxids = GetVirtualXIDsDelayingChkptEnd(&nvxids);
|
||||||
if (nvxids > 0)
|
if (nvxids > 0)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pg_usleep(10000L); /* wait for 10 msec */
|
pg_usleep(10000L); /* wait for 10 msec */
|
||||||
} while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids,
|
} while (HaveVirtualXIDsDelayingChkptEnd(vxids, nvxids));
|
||||||
DELAY_CHKPT_COMPLETE));
|
|
||||||
}
|
}
|
||||||
pfree(vxids);
|
pfree(vxids);
|
||||||
|
|
||||||
|
@ -899,7 +899,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
|
|||||||
/*
|
/*
|
||||||
* Ensure no checkpoint can change our view of RedoRecPtr.
|
* Ensure no checkpoint can change our view of RedoRecPtr.
|
||||||
*/
|
*/
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_START) != 0);
|
Assert(MyPgXact->delayChkpt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update RedoRecPtr so that we can make the right decision
|
* Update RedoRecPtr so that we can make the right decision
|
||||||
|
@ -262,8 +262,8 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
|
|||||||
* the blocks to not exist on disk at all, but not for them to have the
|
* the blocks to not exist on disk at all, but not for them to have the
|
||||||
* wrong contents.
|
* wrong contents.
|
||||||
*/
|
*/
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_COMPLETE) == 0);
|
Assert(!MyProc->delayChkptEnd);
|
||||||
MyPgXact->delayChkpt |= DELAY_CHKPT_COMPLETE;
|
MyProc->delayChkptEnd = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We WAL-log the truncation before actually truncating, which means
|
* We WAL-log the truncation before actually truncating, which means
|
||||||
@ -311,7 +311,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
|
|||||||
smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
|
smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
|
||||||
|
|
||||||
/* We've done all the critical work, so checkpoints are OK now. */
|
/* We've done all the critical work, so checkpoints are OK now. */
|
||||||
MyPgXact->delayChkpt &= ~DELAY_CHKPT_COMPLETE;
|
MyProc->delayChkptEnd = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3471,8 +3471,8 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
|
|||||||
* essential that CreateCheckpoint waits for virtual transactions
|
* essential that CreateCheckpoint waits for virtual transactions
|
||||||
* rather than full transactionids.
|
* rather than full transactionids.
|
||||||
*/
|
*/
|
||||||
Assert((MyPgXact->delayChkpt & DELAY_CHKPT_START) == 0);
|
Assert(!MyPgXact->delayChkpt);
|
||||||
MyPgXact->delayChkpt |= DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = true;
|
||||||
delayChkpt = true;
|
delayChkpt = true;
|
||||||
lsn = XLogSaveBufferForHint(buffer, buffer_std);
|
lsn = XLogSaveBufferForHint(buffer, buffer_std);
|
||||||
}
|
}
|
||||||
@ -3506,7 +3506,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
|
|||||||
UnlockBufHdr(bufHdr, buf_state);
|
UnlockBufHdr(bufHdr, buf_state);
|
||||||
|
|
||||||
if (delayChkpt)
|
if (delayChkpt)
|
||||||
MyPgXact->delayChkpt &= ~DELAY_CHKPT_START;
|
MyPgXact->delayChkpt = false;
|
||||||
|
|
||||||
if (dirtied)
|
if (dirtied)
|
||||||
{
|
{
|
||||||
|
@ -151,6 +151,11 @@ static void DisplayXidCache(void);
|
|||||||
#define xc_slow_answer_inc() ((void) 0)
|
#define xc_slow_answer_inc() ((void) 0)
|
||||||
#endif /* XIDCACHE_DEBUG */
|
#endif /* XIDCACHE_DEBUG */
|
||||||
|
|
||||||
|
static VirtualTransactionId *GetVirtualXIDsDelayingChkptGuts(int *nvxids,
|
||||||
|
int type);
|
||||||
|
static bool HaveVirtualXIDsDelayingChkptGuts(VirtualTransactionId *vxids,
|
||||||
|
int nvxids, int type);
|
||||||
|
|
||||||
/* Primitives for KnownAssignedXids array handling for standby */
|
/* Primitives for KnownAssignedXids array handling for standby */
|
||||||
static void KnownAssignedXidsCompress(bool force);
|
static void KnownAssignedXidsCompress(bool force);
|
||||||
static void KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid,
|
static void KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid,
|
||||||
@ -434,8 +439,9 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
|
|||||||
/* must be cleared with xid/xmin: */
|
/* must be cleared with xid/xmin: */
|
||||||
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
|
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
|
||||||
|
|
||||||
/* be sure this is cleared in abort */
|
/* be sure these are cleared in abort */
|
||||||
pgxact->delayChkpt = 0;
|
pgxact->delayChkpt = false;
|
||||||
|
proc->delayChkptEnd = false;
|
||||||
|
|
||||||
proc->recoveryConflictPending = false;
|
proc->recoveryConflictPending = false;
|
||||||
|
|
||||||
@ -459,8 +465,9 @@ ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact,
|
|||||||
/* must be cleared with xid/xmin: */
|
/* must be cleared with xid/xmin: */
|
||||||
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
|
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
|
||||||
|
|
||||||
/* be sure this is cleared in abort */
|
/* be sure these are cleared in abort */
|
||||||
pgxact->delayChkpt = 0;
|
pgxact->delayChkpt = false;
|
||||||
|
proc->delayChkptEnd = false;
|
||||||
|
|
||||||
proc->recoveryConflictPending = false;
|
proc->recoveryConflictPending = false;
|
||||||
|
|
||||||
@ -2269,26 +2276,28 @@ GetOldestSafeDecodingTransactionId(bool catalogOnly)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetVirtualXIDsDelayingChkpt -- Get the VXIDs of transactions that are
|
* GetVirtualXIDsDelayingChkptGuts -- Get the VXIDs of transactions that are
|
||||||
* delaying checkpoint because they have critical actions in progress.
|
* delaying the start or end of a checkpoint because they have critical
|
||||||
|
* actions in progress.
|
||||||
*
|
*
|
||||||
* Constructs an array of VXIDs of transactions that are currently in commit
|
* Constructs an array of VXIDs of transactions that are currently in commit
|
||||||
* critical sections, as shown by having specified delayChkpt bits set in their
|
* critical sections, as shown by having specified delayChkpt or delayChkptEnd
|
||||||
* PGXACT.
|
* set.
|
||||||
*
|
*
|
||||||
* Returns a palloc'd array that should be freed by the caller.
|
* Returns a palloc'd array that should be freed by the caller.
|
||||||
* *nvxids is the number of valid entries.
|
* *nvxids is the number of valid entries.
|
||||||
*
|
*
|
||||||
* Note that because backends set or clear delayChkpt without holding any lock,
|
* Note that because backends set or clear delayChkpt and delayChkptEnd
|
||||||
* the result is somewhat indeterminate, but we don't really care. Even in
|
* without holding any lock, the result is somewhat indeterminate, but we
|
||||||
* a multiprocessor with delayed writes to shared memory, it should be certain
|
* don't really care. Even in a multiprocessor with delayed writes to
|
||||||
* that setting of delayChkpt will propagate to shared memory when the backend
|
* shared memory, it should be certain that setting of delayChkpt will
|
||||||
* takes a lock, so we cannot fail to see a virtual xact as delayChkpt if
|
* propagate to shared memory when the backend takes a lock, so we cannot
|
||||||
* it's already inserted its commit record. Whether it takes a little while
|
* fail to see a virtual xact as delayChkpt if it's already inserted its
|
||||||
* for clearing of delayChkpt to propagate is unimportant for correctness.
|
* commit record. Whether it takes a little while for clearing of
|
||||||
|
* delayChkpt to propagate is unimportant for correctness.
|
||||||
*/
|
*/
|
||||||
VirtualTransactionId *
|
static VirtualTransactionId *
|
||||||
GetVirtualXIDsDelayingChkpt(int *nvxids, int type)
|
GetVirtualXIDsDelayingChkptGuts(int *nvxids, int type)
|
||||||
{
|
{
|
||||||
VirtualTransactionId *vxids;
|
VirtualTransactionId *vxids;
|
||||||
ProcArrayStruct *arrayP = procArray;
|
ProcArrayStruct *arrayP = procArray;
|
||||||
@ -2309,7 +2318,8 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type)
|
|||||||
volatile PGPROC *proc = &allProcs[pgprocno];
|
volatile PGPROC *proc = &allProcs[pgprocno];
|
||||||
volatile PGXACT *pgxact = &allPgXact[pgprocno];
|
volatile PGXACT *pgxact = &allPgXact[pgprocno];
|
||||||
|
|
||||||
if ((pgxact->delayChkpt & type) != 0)
|
if (((type & DELAY_CHKPT_START) && pgxact->delayChkpt) ||
|
||||||
|
((type & DELAY_CHKPT_COMPLETE) && proc->delayChkptEnd))
|
||||||
{
|
{
|
||||||
VirtualTransactionId vxid;
|
VirtualTransactionId vxid;
|
||||||
|
|
||||||
@ -2325,6 +2335,26 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type)
|
|||||||
return vxids;
|
return vxids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetVirtualXIDsDelayingChkpt - Get the VXIDs of transactions that are
|
||||||
|
* delaying the start of a checkpoint.
|
||||||
|
*/
|
||||||
|
VirtualTransactionId *
|
||||||
|
GetVirtualXIDsDelayingChkpt(int *nvxids)
|
||||||
|
{
|
||||||
|
return GetVirtualXIDsDelayingChkptGuts(nvxids, DELAY_CHKPT_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetVirtualXIDsDelayingChkptEnd - Get the VXIDs of transactions that are
|
||||||
|
* delaying the end of a checkpoint.
|
||||||
|
*/
|
||||||
|
VirtualTransactionId *
|
||||||
|
GetVirtualXIDsDelayingChkptEnd(int *nvxids)
|
||||||
|
{
|
||||||
|
return GetVirtualXIDsDelayingChkptGuts(nvxids, DELAY_CHKPT_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HaveVirtualXIDsDelayingChkpt -- Are any of the specified VXIDs delaying?
|
* HaveVirtualXIDsDelayingChkpt -- Are any of the specified VXIDs delaying?
|
||||||
*
|
*
|
||||||
@ -2334,8 +2364,9 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type)
|
|||||||
* Note: this is O(N^2) in the number of vxacts that are/were delaying, but
|
* Note: this is O(N^2) in the number of vxacts that are/were delaying, but
|
||||||
* those numbers should be small enough for it not to be a problem.
|
* those numbers should be small enough for it not to be a problem.
|
||||||
*/
|
*/
|
||||||
bool
|
static bool
|
||||||
HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type)
|
HaveVirtualXIDsDelayingChkptGuts(VirtualTransactionId *vxids, int nvxids,
|
||||||
|
int type)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
ProcArrayStruct *arrayP = procArray;
|
ProcArrayStruct *arrayP = procArray;
|
||||||
@ -2354,7 +2385,8 @@ HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type)
|
|||||||
|
|
||||||
GET_VXID_FROM_PGPROC(vxid, *proc);
|
GET_VXID_FROM_PGPROC(vxid, *proc);
|
||||||
|
|
||||||
if ((pgxact->delayChkpt & type) != 0 &&
|
if ((((type & DELAY_CHKPT_START) && pgxact->delayChkpt) ||
|
||||||
|
((type & DELAY_CHKPT_COMPLETE) && proc->delayChkptEnd)) &&
|
||||||
VirtualTransactionIdIsValid(vxid))
|
VirtualTransactionIdIsValid(vxid))
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -2377,6 +2409,28 @@ HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HaveVirtualXIDsDelayingChkpt -- Are any of the specified VXIDs delaying
|
||||||
|
* the start of a checkpoint?
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids)
|
||||||
|
{
|
||||||
|
return HaveVirtualXIDsDelayingChkptGuts(vxids, nvxids,
|
||||||
|
DELAY_CHKPT_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HaveVirtualXIDsDelayingChkptEnd -- Are any of the specified VXIDs delaying
|
||||||
|
* the end of a checkpoint?
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
HaveVirtualXIDsDelayingChkptEnd(VirtualTransactionId *vxids, int nvxids)
|
||||||
|
{
|
||||||
|
return HaveVirtualXIDsDelayingChkptGuts(vxids, nvxids,
|
||||||
|
DELAY_CHKPT_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BackendPidGetProc -- get a backend's PGPROC given its PID
|
* BackendPidGetProc -- get a backend's PGPROC given its PID
|
||||||
*
|
*
|
||||||
|
@ -77,36 +77,8 @@ struct XidCache
|
|||||||
#define INVALID_PGPROCNO PG_INT32_MAX
|
#define INVALID_PGPROCNO PG_INT32_MAX
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for PGPROC.delayChkpt
|
* Flags used only for type of internal functions
|
||||||
*
|
* GetVirtualXIDsDelayingChkptGuts and HaveVirtualXIDsDelayingChkptGuts.
|
||||||
* These flags can be used to delay the start or completion of a checkpoint
|
|
||||||
* for short periods. A flag is in effect if the corresponding bit is set in
|
|
||||||
* the PGPROC of any backend.
|
|
||||||
*
|
|
||||||
* For our purposes here, a checkpoint has three phases: (1) determine the
|
|
||||||
* location to which the redo pointer will be moved, (2) write all the
|
|
||||||
* data durably to disk, and (3) WAL-log the checkpoint.
|
|
||||||
*
|
|
||||||
* Setting DELAY_CHKPT_START prevents the system from moving from phase 1
|
|
||||||
* to phase 2. This is useful when we are performing a WAL-logged modification
|
|
||||||
* of data that will be flushed to disk in phase 2. By setting this flag
|
|
||||||
* before writing WAL and clearing it after we've both written WAL and
|
|
||||||
* performed the corresponding modification, we ensure that if the WAL record
|
|
||||||
* is inserted prior to the new redo point, the corresponding data changes will
|
|
||||||
* also be flushed to disk before the checkpoint can complete. (In the
|
|
||||||
* extremely common case where the data being modified is in shared buffers
|
|
||||||
* and we acquire an exclusive content lock on the relevant buffers before
|
|
||||||
* writing WAL, this mechanism is not needed, because phase 2 will block
|
|
||||||
* until we release the content lock and then flush the modified data to
|
|
||||||
* disk.)
|
|
||||||
*
|
|
||||||
* Setting DELAY_CHKPT_COMPLETE prevents the system from moving from phase 2
|
|
||||||
* to phase 3. This is useful if we are performing a WAL-logged operation that
|
|
||||||
* might invalidate buffers, such as relation truncation. In this case, we need
|
|
||||||
* to ensure that any buffers which were invalidated and thus not flushed by
|
|
||||||
* the checkpoint are actaully destroyed on disk. Replay can cope with a file
|
|
||||||
* or block that doesn't exist, but not with a block that has the wrong
|
|
||||||
* contents.
|
|
||||||
*/
|
*/
|
||||||
#define DELAY_CHKPT_START (1<<0)
|
#define DELAY_CHKPT_START (1<<0)
|
||||||
#define DELAY_CHKPT_COMPLETE (1<<1)
|
#define DELAY_CHKPT_COMPLETE (1<<1)
|
||||||
@ -185,6 +157,12 @@ struct PGPROC
|
|||||||
*/
|
*/
|
||||||
XLogRecPtr waitLSN; /* waiting for this LSN or higher */
|
XLogRecPtr waitLSN; /* waiting for this LSN or higher */
|
||||||
int syncRepState; /* wait state for sync rep */
|
int syncRepState; /* wait state for sync rep */
|
||||||
|
bool delayChkptEnd; /* true if this proc delays checkpoint end;
|
||||||
|
* this doesn't have anything to do with
|
||||||
|
* sync rep but we don't want to change
|
||||||
|
* the size of PGPROC in released branches
|
||||||
|
* and thus must fit this new field into
|
||||||
|
* existing padding space */
|
||||||
SHM_QUEUE syncRepLinks; /* list link if process is in syncrep queue */
|
SHM_QUEUE syncRepLinks; /* list link if process is in syncrep queue */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -267,7 +245,7 @@ typedef struct PGXACT
|
|||||||
|
|
||||||
uint8 vacuumFlags; /* vacuum-related flags, see above */
|
uint8 vacuumFlags; /* vacuum-related flags, see above */
|
||||||
bool overflowed;
|
bool overflowed;
|
||||||
int delayChkpt; /* for DELAY_CHKPT_* flags */
|
bool delayChkpt; /* true if this proc delays checkpoint start */
|
||||||
|
|
||||||
uint8 nxids;
|
uint8 nxids;
|
||||||
} PGXACT;
|
} PGXACT;
|
||||||
|
@ -92,9 +92,12 @@ extern TransactionId GetOldestXmin(Relation rel, int flags);
|
|||||||
extern TransactionId GetOldestActiveTransactionId(void);
|
extern TransactionId GetOldestActiveTransactionId(void);
|
||||||
extern TransactionId GetOldestSafeDecodingTransactionId(bool catalogOnly);
|
extern TransactionId GetOldestSafeDecodingTransactionId(bool catalogOnly);
|
||||||
|
|
||||||
extern VirtualTransactionId *GetVirtualXIDsDelayingChkpt(int *nvxids, int type);
|
extern VirtualTransactionId *GetVirtualXIDsDelayingChkpt(int *nvxids);
|
||||||
|
extern VirtualTransactionId *GetVirtualXIDsDelayingChkptEnd(int *nvxids);
|
||||||
extern bool HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids,
|
extern bool HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids,
|
||||||
int nvxids, int type);
|
int nvxids);
|
||||||
|
extern bool HaveVirtualXIDsDelayingChkptEnd(VirtualTransactionId *vxids,
|
||||||
|
int nvxids);
|
||||||
|
|
||||||
extern PGPROC *BackendPidGetProc(int pid);
|
extern PGPROC *BackendPidGetProc(int pid);
|
||||||
extern PGPROC *BackendPidGetProcWithLock(int pid);
|
extern PGPROC *BackendPidGetProcWithLock(int pid);
|
||||||
|
Loading…
Reference in New Issue
Block a user