mirror of
https://github.com/postgres/postgres.git
synced 2026-04-21 06:08:26 -04:00
Separate RecoveryConflictReasons from procsignals
Share the same PROCSIG_RECOVERY_CONFLICT flag for all recovery conflict reasons. To distinguish, have a bitmask in PGPROC to indicate the reason(s). Reviewed-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://www.postgresql.org/message-id/4cc13ba1-4248-4884-b6ba-4805349e7f39@iki.fi
This commit is contained in:
parent
ddc3250208
commit
17f51ea818
18 changed files with 258 additions and 186 deletions
|
|
@ -60,6 +60,7 @@
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/md.h"
|
#include "storage/md.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "postmaster/bgwriter.h"
|
#include "postmaster/bgwriter.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "storage/standby.h"
|
#include "storage/standby.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "utils/injection_point.h"
|
#include "utils/injection_point.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -2114,9 +2114,9 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes,
|
||||||
slot_idle_secs);
|
slot_idle_secs);
|
||||||
|
|
||||||
if (MyBackendType == B_STARTUP)
|
if (MyBackendType == B_STARTUP)
|
||||||
(void) SendProcSignal(active_pid,
|
(void) SignalRecoveryConflict(GetPGProcByNumber(active_proc),
|
||||||
PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT,
|
active_pid,
|
||||||
active_proc);
|
RECOVERY_CONFLICT_LOGICALSLOT);
|
||||||
else
|
else
|
||||||
(void) kill(active_pid, SIGTERM);
|
(void) kill(active_pid, SIGTERM);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/proclist.h"
|
#include "storage/proclist.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "storage/read_stream.h"
|
#include "storage/read_stream.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "storage/standby.h"
|
#include "storage/standby.h"
|
||||||
|
|
@ -6570,7 +6571,7 @@ LockBufferForCleanup(Buffer buffer)
|
||||||
* deadlock_timeout for it.
|
* deadlock_timeout for it.
|
||||||
*/
|
*/
|
||||||
if (logged_recovery_conflict)
|
if (logged_recovery_conflict)
|
||||||
LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
|
LogRecoveryConflict(RECOVERY_CONFLICT_BUFFERPIN,
|
||||||
waitStart, GetCurrentTimestamp(),
|
waitStart, GetCurrentTimestamp(),
|
||||||
NULL, false);
|
NULL, false);
|
||||||
|
|
||||||
|
|
@ -6621,7 +6622,7 @@ LockBufferForCleanup(Buffer buffer)
|
||||||
if (TimestampDifferenceExceeds(waitStart, now,
|
if (TimestampDifferenceExceeds(waitStart, now,
|
||||||
DeadlockTimeout))
|
DeadlockTimeout))
|
||||||
{
|
{
|
||||||
LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
|
LogRecoveryConflict(RECOVERY_CONFLICT_BUFFERPIN,
|
||||||
waitStart, now, NULL, true);
|
waitStart, now, NULL, true);
|
||||||
logged_recovery_conflict = true;
|
logged_recovery_conflict = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@
|
||||||
#include "port/pg_lfind.h"
|
#include "port/pg_lfind.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/injection_point.h"
|
#include "utils/injection_point.h"
|
||||||
|
|
@ -708,6 +709,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
|
||||||
/* be sure this is cleared in abort */
|
/* be sure this is cleared in abort */
|
||||||
proc->delayChkptFlags = 0;
|
proc->delayChkptFlags = 0;
|
||||||
|
|
||||||
|
pg_atomic_write_u32(&proc->pendingRecoveryConflicts, 0);
|
||||||
|
|
||||||
/* must be cleared with xid/xmin: */
|
/* must be cleared with xid/xmin: */
|
||||||
/* avoid unnecessarily dirtying shared cachelines */
|
/* avoid unnecessarily dirtying shared cachelines */
|
||||||
if (proc->statusFlags & PROC_VACUUM_STATE_MASK)
|
if (proc->statusFlags & PROC_VACUUM_STATE_MASK)
|
||||||
|
|
@ -748,6 +751,8 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
|
||||||
/* be sure this is cleared in abort */
|
/* be sure this is cleared in abort */
|
||||||
proc->delayChkptFlags = 0;
|
proc->delayChkptFlags = 0;
|
||||||
|
|
||||||
|
pg_atomic_write_u32(&proc->pendingRecoveryConflicts, 0);
|
||||||
|
|
||||||
/* must be cleared with xid/xmin: */
|
/* must be cleared with xid/xmin: */
|
||||||
/* avoid unnecessarily dirtying shared cachelines */
|
/* avoid unnecessarily dirtying shared cachelines */
|
||||||
if (proc->statusFlags & PROC_VACUUM_STATE_MASK)
|
if (proc->statusFlags & PROC_VACUUM_STATE_MASK)
|
||||||
|
|
@ -929,6 +934,7 @@ ProcArrayClearTransaction(PGPROC *proc)
|
||||||
|
|
||||||
proc->vxid.lxid = InvalidLocalTransactionId;
|
proc->vxid.lxid = InvalidLocalTransactionId;
|
||||||
proc->xmin = InvalidTransactionId;
|
proc->xmin = InvalidTransactionId;
|
||||||
|
pg_atomic_write_u32(&proc->pendingRecoveryConflicts, 0);
|
||||||
|
|
||||||
Assert(!(proc->statusFlags & PROC_VACUUM_STATE_MASK));
|
Assert(!(proc->statusFlags & PROC_VACUUM_STATE_MASK));
|
||||||
Assert(!proc->delayChkptFlags);
|
Assert(!proc->delayChkptFlags);
|
||||||
|
|
@ -3440,12 +3446,46 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SignalVirtualTransaction - used in recovery conflict processing
|
* SignalRecoveryConflict -- signal that a process is blocking recovery
|
||||||
*
|
*
|
||||||
* Returns pid of the process signaled, or 0 if not found.
|
* The 'pid' is redundant with 'proc', but it acts as a cross-check to
|
||||||
|
* detect process had exited and the PGPROC entry was reused for a different
|
||||||
|
* process.
|
||||||
|
*
|
||||||
|
* Returns true if the process was signaled, or false if not found.
|
||||||
*/
|
*/
|
||||||
pid_t
|
bool
|
||||||
SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
|
SignalRecoveryConflict(PGPROC *proc, pid_t pid, RecoveryConflictReason reason)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
LWLockAcquire(ProcArrayLock, LW_SHARED);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kill the pid if it's still here. If not, that's what we wanted so
|
||||||
|
* ignore any errors.
|
||||||
|
*/
|
||||||
|
if (proc->pid == pid)
|
||||||
|
{
|
||||||
|
(void) pg_atomic_fetch_or_u32(&proc->pendingRecoveryConflicts, (1 << reason));
|
||||||
|
|
||||||
|
/* wake up the process */
|
||||||
|
(void) SendProcSignal(pid, PROCSIG_RECOVERY_CONFLICT, GetNumberFromPGProc(proc));
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWLockRelease(ProcArrayLock);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SignalRecoveryConflictWithVirtualXID -- signal that a VXID is blocking recovery
|
||||||
|
*
|
||||||
|
* Like SignalRecoveryConflict, but the target is identified by VXID
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
SignalRecoveryConflictWithVirtualXID(VirtualTransactionId vxid, RecoveryConflictReason reason)
|
||||||
{
|
{
|
||||||
ProcArrayStruct *arrayP = procArray;
|
ProcArrayStruct *arrayP = procArray;
|
||||||
int index;
|
int index;
|
||||||
|
|
@ -3467,11 +3507,13 @@ SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
|
||||||
pid = proc->pid;
|
pid = proc->pid;
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
|
(void) pg_atomic_fetch_or_u32(&proc->pendingRecoveryConflicts, (1 << reason));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kill the pid if it's still here. If not, that's what we
|
* Kill the pid if it's still here. If not, that's what we
|
||||||
* wanted so ignore any errors.
|
* wanted so ignore any errors.
|
||||||
*/
|
*/
|
||||||
(void) SendProcSignal(pid, sigmode, vxid.procNumber);
|
(void) SendProcSignal(pid, PROCSIG_RECOVERY_CONFLICT, vxid.procNumber);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -3479,7 +3521,50 @@ SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
|
||||||
|
|
||||||
LWLockRelease(ProcArrayLock);
|
LWLockRelease(ProcArrayLock);
|
||||||
|
|
||||||
return pid;
|
return pid != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SignalRecoveryConflictWithDatabase --- signal all backends specified database
|
||||||
|
*
|
||||||
|
* Like SignalRecoveryConflict, but signals all backends using the database.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SignalRecoveryConflictWithDatabase(Oid databaseid, RecoveryConflictReason reason)
|
||||||
|
{
|
||||||
|
ProcArrayStruct *arrayP = procArray;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
/* tell all backends to die */
|
||||||
|
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
|
||||||
|
|
||||||
|
for (index = 0; index < arrayP->numProcs; index++)
|
||||||
|
{
|
||||||
|
int pgprocno = arrayP->pgprocnos[index];
|
||||||
|
PGPROC *proc = &allProcs[pgprocno];
|
||||||
|
|
||||||
|
if (databaseid == InvalidOid || proc->databaseId == databaseid)
|
||||||
|
{
|
||||||
|
VirtualTransactionId procvxid;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
GET_VXID_FROM_PGPROC(procvxid, *proc);
|
||||||
|
|
||||||
|
pid = proc->pid;
|
||||||
|
if (pid != 0)
|
||||||
|
{
|
||||||
|
(void) pg_atomic_fetch_or_u32(&proc->pendingRecoveryConflicts, (1 << reason));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kill the pid if it's still here. If not, that's what we
|
||||||
|
* wanted so ignore any errors.
|
||||||
|
*/
|
||||||
|
(void) SendProcSignal(pid, PROCSIG_RECOVERY_CONFLICT, procvxid.procNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LWLockRelease(ProcArrayLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -3601,45 +3686,6 @@ CountDBConnections(Oid databaseid)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* CancelDBBackends --- cancel backends that are using specified database
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
CancelDBBackends(Oid databaseid, ProcSignalReason sigmode)
|
|
||||||
{
|
|
||||||
ProcArrayStruct *arrayP = procArray;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
/* tell all backends to die */
|
|
||||||
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
|
|
||||||
|
|
||||||
for (index = 0; index < arrayP->numProcs; index++)
|
|
||||||
{
|
|
||||||
int pgprocno = arrayP->pgprocnos[index];
|
|
||||||
PGPROC *proc = &allProcs[pgprocno];
|
|
||||||
|
|
||||||
if (databaseid == InvalidOid || proc->databaseId == databaseid)
|
|
||||||
{
|
|
||||||
VirtualTransactionId procvxid;
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
GET_VXID_FROM_PGPROC(procvxid, *proc);
|
|
||||||
|
|
||||||
pid = proc->pid;
|
|
||||||
if (pid != 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Kill the pid if it's still here. If not, that's what we
|
|
||||||
* wanted so ignore any errors.
|
|
||||||
*/
|
|
||||||
(void) SendProcSignal(pid, sigmode, procvxid.procNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LWLockRelease(ProcArrayLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CountUserBackends --- count backends that are used by specified user
|
* CountUserBackends --- count backends that are used by specified user
|
||||||
* (only regular backends, not any type of background worker)
|
* (only regular backends, not any type of background worker)
|
||||||
|
|
|
||||||
|
|
@ -697,26 +697,8 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
|
||||||
if (CheckProcSignal(PROCSIG_PARALLEL_APPLY_MESSAGE))
|
if (CheckProcSignal(PROCSIG_PARALLEL_APPLY_MESSAGE))
|
||||||
HandleParallelApplyMessageInterrupt();
|
HandleParallelApplyMessageInterrupt();
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE))
|
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT))
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE);
|
HandleRecoveryConflictInterrupt();
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_TABLESPACE))
|
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_TABLESPACE);
|
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_LOCK))
|
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_LOCK);
|
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT))
|
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
|
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT))
|
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT);
|
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK))
|
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
|
||||||
|
|
||||||
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
|
|
||||||
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
|
|
||||||
|
|
||||||
SetLatch(MyLatch);
|
SetLatch(MyLatch);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,13 +71,13 @@ static volatile sig_atomic_t got_standby_delay_timeout = false;
|
||||||
static volatile sig_atomic_t got_standby_lock_timeout = false;
|
static volatile sig_atomic_t got_standby_lock_timeout = false;
|
||||||
|
|
||||||
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||||
ProcSignalReason reason,
|
RecoveryConflictReason reason,
|
||||||
uint32 wait_event_info,
|
uint32 wait_event_info,
|
||||||
bool report_waiting);
|
bool report_waiting);
|
||||||
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason);
|
static void SendRecoveryConflictWithBufferPin(RecoveryConflictReason reason);
|
||||||
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
|
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
|
||||||
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
|
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
|
||||||
static const char *get_recovery_conflict_desc(ProcSignalReason reason);
|
static const char *get_recovery_conflict_desc(RecoveryConflictReason reason);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* InitRecoveryTransactionEnvironment
|
* InitRecoveryTransactionEnvironment
|
||||||
|
|
@ -271,7 +271,7 @@ WaitExceedsMaxStandbyDelay(uint32 wait_event_info)
|
||||||
* to be resolved or not.
|
* to be resolved or not.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start,
|
LogRecoveryConflict(RecoveryConflictReason reason, TimestampTz wait_start,
|
||||||
TimestampTz now, VirtualTransactionId *wait_list,
|
TimestampTz now, VirtualTransactionId *wait_list,
|
||||||
bool still_waiting)
|
bool still_waiting)
|
||||||
{
|
{
|
||||||
|
|
@ -358,7 +358,8 @@ LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||||
ProcSignalReason reason, uint32 wait_event_info,
|
RecoveryConflictReason reason,
|
||||||
|
uint32 wait_event_info,
|
||||||
bool report_waiting)
|
bool report_waiting)
|
||||||
{
|
{
|
||||||
TimestampTz waitStart = 0;
|
TimestampTz waitStart = 0;
|
||||||
|
|
@ -384,19 +385,19 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||||
/* Is it time to kill it? */
|
/* Is it time to kill it? */
|
||||||
if (WaitExceedsMaxStandbyDelay(wait_event_info))
|
if (WaitExceedsMaxStandbyDelay(wait_event_info))
|
||||||
{
|
{
|
||||||
pid_t pid;
|
bool signaled;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now find out who to throw out of the balloon.
|
* Now find out who to throw out of the balloon.
|
||||||
*/
|
*/
|
||||||
Assert(VirtualTransactionIdIsValid(*waitlist));
|
Assert(VirtualTransactionIdIsValid(*waitlist));
|
||||||
pid = SignalVirtualTransaction(*waitlist, reason);
|
signaled = SignalRecoveryConflictWithVirtualXID(*waitlist, reason);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait a little bit for it to die so that we avoid flooding
|
* Wait a little bit for it to die so that we avoid flooding
|
||||||
* an unresponsive backend when system is heavily loaded.
|
* an unresponsive backend when system is heavily loaded.
|
||||||
*/
|
*/
|
||||||
if (pid != 0)
|
if (signaled)
|
||||||
pg_usleep(5000L);
|
pg_usleep(5000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -489,7 +490,7 @@ ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon,
|
||||||
backends = GetConflictingVirtualXIDs(snapshotConflictHorizon,
|
backends = GetConflictingVirtualXIDs(snapshotConflictHorizon,
|
||||||
locator.dbOid);
|
locator.dbOid);
|
||||||
ResolveRecoveryConflictWithVirtualXIDs(backends,
|
ResolveRecoveryConflictWithVirtualXIDs(backends,
|
||||||
PROCSIG_RECOVERY_CONFLICT_SNAPSHOT,
|
RECOVERY_CONFLICT_SNAPSHOT,
|
||||||
WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT,
|
WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
|
@ -560,7 +561,7 @@ ResolveRecoveryConflictWithTablespace(Oid tsid)
|
||||||
temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
|
temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
|
||||||
InvalidOid);
|
InvalidOid);
|
||||||
ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
|
ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
|
||||||
PROCSIG_RECOVERY_CONFLICT_TABLESPACE,
|
RECOVERY_CONFLICT_TABLESPACE,
|
||||||
WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE,
|
WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
@ -581,7 +582,7 @@ ResolveRecoveryConflictWithDatabase(Oid dbid)
|
||||||
*/
|
*/
|
||||||
while (CountDBBackends(dbid) > 0)
|
while (CountDBBackends(dbid) > 0)
|
||||||
{
|
{
|
||||||
CancelDBBackends(dbid, PROCSIG_RECOVERY_CONFLICT_DATABASE);
|
SignalRecoveryConflictWithDatabase(dbid, RECOVERY_CONFLICT_DATABASE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait awhile for them to die so that we avoid flooding an
|
* Wait awhile for them to die so that we avoid flooding an
|
||||||
|
|
@ -665,7 +666,7 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict)
|
||||||
* because the caller, WaitOnLock(), has already reported that.
|
* because the caller, WaitOnLock(), has already reported that.
|
||||||
*/
|
*/
|
||||||
ResolveRecoveryConflictWithVirtualXIDs(backends,
|
ResolveRecoveryConflictWithVirtualXIDs(backends,
|
||||||
PROCSIG_RECOVERY_CONFLICT_LOCK,
|
RECOVERY_CONFLICT_LOCK,
|
||||||
PG_WAIT_LOCK | locktag.locktag_type,
|
PG_WAIT_LOCK | locktag.locktag_type,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
@ -723,8 +724,8 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict)
|
||||||
*/
|
*/
|
||||||
while (VirtualTransactionIdIsValid(*backends))
|
while (VirtualTransactionIdIsValid(*backends))
|
||||||
{
|
{
|
||||||
SignalVirtualTransaction(*backends,
|
(void) SignalRecoveryConflictWithVirtualXID(*backends,
|
||||||
PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
||||||
backends++;
|
backends++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -802,7 +803,7 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||||
/*
|
/*
|
||||||
* We're already behind, so clear a path as quickly as possible.
|
* We're already behind, so clear a path as quickly as possible.
|
||||||
*/
|
*/
|
||||||
SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
|
SendRecoveryConflictWithBufferPin(RECOVERY_CONFLICT_BUFFERPIN);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -842,7 +843,7 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||||
ProcWaitForSignal(WAIT_EVENT_BUFFER_CLEANUP);
|
ProcWaitForSignal(WAIT_EVENT_BUFFER_CLEANUP);
|
||||||
|
|
||||||
if (got_standby_delay_timeout)
|
if (got_standby_delay_timeout)
|
||||||
SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
|
SendRecoveryConflictWithBufferPin(RECOVERY_CONFLICT_BUFFERPIN);
|
||||||
else if (got_standby_deadlock_timeout)
|
else if (got_standby_deadlock_timeout)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
@ -858,7 +859,7 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||||
* not be so harmful because the period that the buffer is kept pinned
|
* not be so harmful because the period that the buffer is kept pinned
|
||||||
* is basically no so long. But we should fix this?
|
* is basically no so long. But we should fix this?
|
||||||
*/
|
*/
|
||||||
SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
SendRecoveryConflictWithBufferPin(RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -873,10 +874,10 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
|
SendRecoveryConflictWithBufferPin(RecoveryConflictReason reason)
|
||||||
{
|
{
|
||||||
Assert(reason == PROCSIG_RECOVERY_CONFLICT_BUFFERPIN ||
|
Assert(reason == RECOVERY_CONFLICT_BUFFERPIN ||
|
||||||
reason == PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
reason == RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We send signal to all backends to ask them if they are holding the
|
* We send signal to all backends to ask them if they are holding the
|
||||||
|
|
@ -884,7 +885,7 @@ SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
|
||||||
* innocent, but we let the SIGUSR1 handling in each backend decide their
|
* innocent, but we let the SIGUSR1 handling in each backend decide their
|
||||||
* own fate.
|
* own fate.
|
||||||
*/
|
*/
|
||||||
CancelDBBackends(InvalidOid, reason);
|
SignalRecoveryConflictWithDatabase(InvalidOid, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1489,35 +1490,33 @@ LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
|
||||||
|
|
||||||
/* Return the description of recovery conflict */
|
/* Return the description of recovery conflict */
|
||||||
static const char *
|
static const char *
|
||||||
get_recovery_conflict_desc(ProcSignalReason reason)
|
get_recovery_conflict_desc(RecoveryConflictReason reason)
|
||||||
{
|
{
|
||||||
const char *reasonDesc = _("unknown reason");
|
const char *reasonDesc = _("unknown reason");
|
||||||
|
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
|
case RECOVERY_CONFLICT_BUFFERPIN:
|
||||||
reasonDesc = _("recovery conflict on buffer pin");
|
reasonDesc = _("recovery conflict on buffer pin");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOCK:
|
case RECOVERY_CONFLICT_LOCK:
|
||||||
reasonDesc = _("recovery conflict on lock");
|
reasonDesc = _("recovery conflict on lock");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
|
case RECOVERY_CONFLICT_TABLESPACE:
|
||||||
reasonDesc = _("recovery conflict on tablespace");
|
reasonDesc = _("recovery conflict on tablespace");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
|
case RECOVERY_CONFLICT_SNAPSHOT:
|
||||||
reasonDesc = _("recovery conflict on snapshot");
|
reasonDesc = _("recovery conflict on snapshot");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT:
|
case RECOVERY_CONFLICT_LOGICALSLOT:
|
||||||
reasonDesc = _("recovery conflict on replication slot");
|
reasonDesc = _("recovery conflict on replication slot");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
case RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
||||||
reasonDesc = _("recovery conflict on buffer deadlock");
|
reasonDesc = _("recovery conflict on buffer deadlock");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_DATABASE:
|
case RECOVERY_CONFLICT_DATABASE:
|
||||||
reasonDesc = _("recovery conflict on database");
|
reasonDesc = _("recovery conflict on database");
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return reasonDesc;
|
return reasonDesc;
|
||||||
|
|
|
||||||
|
|
@ -504,6 +504,7 @@ InitProcess(void)
|
||||||
Assert(dlist_is_empty(&(MyProc->myProcLocks[i])));
|
Assert(dlist_is_empty(&(MyProc->myProcLocks[i])));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
pg_atomic_write_u32(&MyProc->pendingRecoveryConflicts, 0);
|
||||||
|
|
||||||
/* Initialize fields for sync rep */
|
/* Initialize fields for sync rep */
|
||||||
MyProc->waitLSN = InvalidXLogRecPtr;
|
MyProc->waitLSN = InvalidXLogRecPtr;
|
||||||
|
|
@ -1445,7 +1446,7 @@ ProcSleep(LOCALLOCK *locallock)
|
||||||
* because the startup process here has already waited
|
* because the startup process here has already waited
|
||||||
* longer than deadlock_timeout.
|
* longer than deadlock_timeout.
|
||||||
*/
|
*/
|
||||||
LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_LOCK,
|
LogRecoveryConflict(RECOVERY_CONFLICT_LOCK,
|
||||||
standbyWaitStart, now,
|
standbyWaitStart, now,
|
||||||
cnt > 0 ? vxids : NULL, true);
|
cnt > 0 ? vxids : NULL, true);
|
||||||
logged_recovery_conflict = true;
|
logged_recovery_conflict = true;
|
||||||
|
|
@ -1686,7 +1687,7 @@ ProcSleep(LOCALLOCK *locallock)
|
||||||
* startup process waited longer than deadlock_timeout for it.
|
* startup process waited longer than deadlock_timeout for it.
|
||||||
*/
|
*/
|
||||||
if (InHotStandby && logged_recovery_conflict)
|
if (InHotStandby && logged_recovery_conflict)
|
||||||
LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_LOCK,
|
LogRecoveryConflict(RECOVERY_CONFLICT_LOCK,
|
||||||
standbyWaitStart, GetCurrentTimestamp(),
|
standbyWaitStart, GetCurrentTimestamp(),
|
||||||
NULL, false);
|
NULL, false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/procsignal.h"
|
#include "storage/procsignal.h"
|
||||||
#include "storage/sinval.h"
|
#include "storage/sinval.h"
|
||||||
|
#include "storage/standby.h"
|
||||||
#include "tcop/backend_startup.h"
|
#include "tcop/backend_startup.h"
|
||||||
#include "tcop/fastpath.h"
|
#include "tcop/fastpath.h"
|
||||||
#include "tcop/pquery.h"
|
#include "tcop/pquery.h"
|
||||||
|
|
@ -155,10 +156,6 @@ static const char *userDoption = NULL; /* -D switch */
|
||||||
static bool EchoQuery = false; /* -E switch */
|
static bool EchoQuery = false; /* -E switch */
|
||||||
static bool UseSemiNewlineNewline = false; /* -j switch */
|
static bool UseSemiNewlineNewline = false; /* -j switch */
|
||||||
|
|
||||||
/* whether or not, and why, we were canceled by conflict with recovery */
|
|
||||||
static volatile sig_atomic_t RecoveryConflictPending = false;
|
|
||||||
static volatile sig_atomic_t RecoveryConflictPendingReasons[NUM_PROCSIGNALS];
|
|
||||||
|
|
||||||
/* reused buffer to pass to SendRowDescriptionMessage() */
|
/* reused buffer to pass to SendRowDescriptionMessage() */
|
||||||
static MemoryContext row_description_context = NULL;
|
static MemoryContext row_description_context = NULL;
|
||||||
static StringInfoData row_description_buf;
|
static StringInfoData row_description_buf;
|
||||||
|
|
@ -2537,34 +2534,31 @@ errdetail_params(ParamListInfo params)
|
||||||
* Add an errdetail() line showing conflict source.
|
* Add an errdetail() line showing conflict source.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
errdetail_recovery_conflict(ProcSignalReason reason)
|
errdetail_recovery_conflict(RecoveryConflictReason reason)
|
||||||
{
|
{
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
|
case RECOVERY_CONFLICT_BUFFERPIN:
|
||||||
errdetail("User was holding shared buffer pin for too long.");
|
errdetail("User was holding shared buffer pin for too long.");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOCK:
|
case RECOVERY_CONFLICT_LOCK:
|
||||||
errdetail("User was holding a relation lock for too long.");
|
errdetail("User was holding a relation lock for too long.");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
|
case RECOVERY_CONFLICT_TABLESPACE:
|
||||||
errdetail("User was or might have been using tablespace that must be dropped.");
|
errdetail("User was or might have been using tablespace that must be dropped.");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
|
case RECOVERY_CONFLICT_SNAPSHOT:
|
||||||
errdetail("User query might have needed to see row versions that must be removed.");
|
errdetail("User query might have needed to see row versions that must be removed.");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT:
|
case RECOVERY_CONFLICT_LOGICALSLOT:
|
||||||
errdetail("User was using a logical replication slot that must be invalidated.");
|
errdetail("User was using a logical replication slot that must be invalidated.");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
case RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
||||||
errdetail("User transaction caused buffer deadlock with recovery.");
|
errdetail("User transaction caused buffer deadlock with recovery.");
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_DATABASE:
|
case RECOVERY_CONFLICT_DATABASE:
|
||||||
errdetail("User was connected to a database that must be dropped.");
|
errdetail("User was connected to a database that must be dropped.");
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
/* no errdetail */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -3067,15 +3061,14 @@ FloatExceptionHandler(SIGNAL_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the next CHECK_FOR_INTERRUPTS() to check for a particular type of
|
* Tell the next CHECK_FOR_INTERRUPTS() to process recovery conflicts. Runs
|
||||||
* recovery conflict. Runs in a SIGUSR1 handler.
|
* in a SIGUSR1 handler.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
HandleRecoveryConflictInterrupt(ProcSignalReason reason)
|
HandleRecoveryConflictInterrupt(void)
|
||||||
{
|
{
|
||||||
RecoveryConflictPendingReasons[reason] = true;
|
if (pg_atomic_read_u32(&MyProc->pendingRecoveryConflicts) != 0)
|
||||||
RecoveryConflictPending = true;
|
InterruptPending = true;
|
||||||
InterruptPending = true;
|
|
||||||
/* latch will be set by procsignal_sigusr1_handler */
|
/* latch will be set by procsignal_sigusr1_handler */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3083,11 +3076,11 @@ HandleRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
* Check one individual conflict reason.
|
* Check one individual conflict reason.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
ProcessRecoveryConflictInterrupt(RecoveryConflictReason reason)
|
||||||
{
|
{
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
case RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we aren't waiting for a lock we can never deadlock.
|
* If we aren't waiting for a lock we can never deadlock.
|
||||||
|
|
@ -3098,21 +3091,20 @@ ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
/* Intentional fall through to check wait for pin */
|
/* Intentional fall through to check wait for pin */
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
|
case RECOVERY_CONFLICT_BUFFERPIN:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If PROCSIG_RECOVERY_CONFLICT_BUFFERPIN is requested but we
|
* If RECOVERY_CONFLICT_BUFFERPIN is requested but we aren't
|
||||||
* aren't blocking the Startup process there is nothing more to
|
* blocking the Startup process there is nothing more to do.
|
||||||
* do.
|
|
||||||
*
|
*
|
||||||
* When PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK is requested,
|
* When RECOVERY_CONFLICT_STARTUP_DEADLOCK is requested, if we're
|
||||||
* if we're waiting for locks and the startup process is not
|
* waiting for locks and the startup process is not waiting for
|
||||||
* waiting for buffer pin (i.e., also waiting for locks), we set
|
* buffer pin (i.e., also waiting for locks), we set the flag so
|
||||||
* the flag so that ProcSleep() will check for deadlocks.
|
* that ProcSleep() will check for deadlocks.
|
||||||
*/
|
*/
|
||||||
if (!HoldingBufferPinThatDelaysRecovery())
|
if (!HoldingBufferPinThatDelaysRecovery())
|
||||||
{
|
{
|
||||||
if (reason == PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK &&
|
if (reason == RECOVERY_CONFLICT_STARTUP_DEADLOCK &&
|
||||||
GetStartupBufferPinWaitBufId() < 0)
|
GetStartupBufferPinWaitBufId() < 0)
|
||||||
CheckDeadLockAlert();
|
CheckDeadLockAlert();
|
||||||
return;
|
return;
|
||||||
|
|
@ -3121,9 +3113,9 @@ ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
/* Intentional fall through to error handling */
|
/* Intentional fall through to error handling */
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOCK:
|
case RECOVERY_CONFLICT_LOCK:
|
||||||
case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
|
case RECOVERY_CONFLICT_TABLESPACE:
|
||||||
case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
|
case RECOVERY_CONFLICT_SNAPSHOT:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we aren't in a transaction any longer then ignore.
|
* If we aren't in a transaction any longer then ignore.
|
||||||
|
|
@ -3133,34 +3125,34 @@ ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
|
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT:
|
case RECOVERY_CONFLICT_LOGICALSLOT:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're not in a subtransaction then we are OK to throw an
|
* If we're not in a subtransaction then we are OK to throw an
|
||||||
* ERROR to resolve the conflict. Otherwise drop through to the
|
* ERROR to resolve the conflict. Otherwise drop through to the
|
||||||
* FATAL case.
|
* FATAL case.
|
||||||
*
|
*
|
||||||
* PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT is a special case that
|
* RECOVERY_CONFLICT_LOGICALSLOT is a special case that always
|
||||||
* always throws an ERROR (ie never promotes to FATAL), though it
|
* throws an ERROR (ie never promotes to FATAL), though it still
|
||||||
* still has to respect QueryCancelHoldoffCount, so it shares this
|
* has to respect QueryCancelHoldoffCount, so it shares this code
|
||||||
* code path. Logical decoding slots are only acquired while
|
* path. Logical decoding slots are only acquired while
|
||||||
* performing logical decoding. During logical decoding no user
|
* performing logical decoding. During logical decoding no user
|
||||||
* controlled code is run. During [sub]transaction abort, the
|
* controlled code is run. During [sub]transaction abort, the
|
||||||
* slot is released. Therefore user controlled code cannot
|
* slot is released. Therefore user controlled code cannot
|
||||||
* intercept an error before the replication slot is released.
|
* intercept an error before the replication slot is released.
|
||||||
*
|
*
|
||||||
* XXX other times that we can throw just an ERROR *may* be
|
* XXX other times that we can throw just an ERROR *may* be
|
||||||
* PROCSIG_RECOVERY_CONFLICT_LOCK if no locks are held in parent
|
* RECOVERY_CONFLICT_LOCK if no locks are held in parent
|
||||||
* transactions
|
* transactions
|
||||||
*
|
*
|
||||||
* PROCSIG_RECOVERY_CONFLICT_SNAPSHOT if no snapshots are held by
|
* RECOVERY_CONFLICT_SNAPSHOT if no snapshots are held by parent
|
||||||
* parent transactions and the transaction is not
|
* transactions and the transaction is not transaction-snapshot
|
||||||
* transaction-snapshot mode
|
* mode
|
||||||
*
|
*
|
||||||
* PROCSIG_RECOVERY_CONFLICT_TABLESPACE if no temp files or
|
* RECOVERY_CONFLICT_TABLESPACE if no temp files or cursors open
|
||||||
* cursors open in parent transactions
|
* in parent transactions
|
||||||
*/
|
*/
|
||||||
if (reason == PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT ||
|
if (reason == RECOVERY_CONFLICT_LOGICALSLOT ||
|
||||||
!IsSubTransaction())
|
!IsSubTransaction())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
@ -3187,8 +3179,7 @@ ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
* Re-arm and defer this interrupt until later. See
|
* Re-arm and defer this interrupt until later. See
|
||||||
* similar code in ProcessInterrupts().
|
* similar code in ProcessInterrupts().
|
||||||
*/
|
*/
|
||||||
RecoveryConflictPendingReasons[reason] = true;
|
(void) pg_atomic_fetch_or_u32(&MyProc->pendingRecoveryConflicts, (1 << reason));
|
||||||
RecoveryConflictPending = true;
|
|
||||||
InterruptPending = true;
|
InterruptPending = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -3222,7 +3213,7 @@ ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
" database and repeat your command.")));
|
" database and repeat your command.")));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROCSIG_RECOVERY_CONFLICT_DATABASE:
|
case RECOVERY_CONFLICT_DATABASE:
|
||||||
|
|
||||||
/* The database is being dropped; terminate the session */
|
/* The database is being dropped; terminate the session */
|
||||||
pgstat_report_recovery_conflict(reason);
|
pgstat_report_recovery_conflict(reason);
|
||||||
|
|
@ -3243,6 +3234,8 @@ ProcessRecoveryConflictInterrupt(ProcSignalReason reason)
|
||||||
static void
|
static void
|
||||||
ProcessRecoveryConflictInterrupts(void)
|
ProcessRecoveryConflictInterrupts(void)
|
||||||
{
|
{
|
||||||
|
uint32 pending;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't need to worry about joggling the elbow of proc_exit, because
|
* We don't need to worry about joggling the elbow of proc_exit, because
|
||||||
* proc_exit_prepare() holds interrupts, so ProcessInterrupts() won't call
|
* proc_exit_prepare() holds interrupts, so ProcessInterrupts() won't call
|
||||||
|
|
@ -3250,17 +3243,27 @@ ProcessRecoveryConflictInterrupts(void)
|
||||||
*/
|
*/
|
||||||
Assert(!proc_exit_inprogress);
|
Assert(!proc_exit_inprogress);
|
||||||
Assert(InterruptHoldoffCount == 0);
|
Assert(InterruptHoldoffCount == 0);
|
||||||
Assert(RecoveryConflictPending);
|
|
||||||
|
|
||||||
RecoveryConflictPending = false;
|
/* Are any recovery conflict pending? */
|
||||||
|
pending = pg_atomic_read_membarrier_u32(&MyProc->pendingRecoveryConflicts);
|
||||||
|
if (pending == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for (ProcSignalReason reason = PROCSIG_RECOVERY_CONFLICT_FIRST;
|
/*
|
||||||
reason <= PROCSIG_RECOVERY_CONFLICT_LAST;
|
* Check the conflicts one by one, clearing each flag only before
|
||||||
|
* processing the particular conflict. This ensures that if multiple
|
||||||
|
* conflicts are pending, we come back here to process the remaining
|
||||||
|
* conflicts, if an error is thrown during processing one of them.
|
||||||
|
*/
|
||||||
|
for (RecoveryConflictReason reason = 0;
|
||||||
|
reason < NUM_RECOVERY_CONFLICT_REASONS;
|
||||||
reason++)
|
reason++)
|
||||||
{
|
{
|
||||||
if (RecoveryConflictPendingReasons[reason])
|
if ((pending & (1 << reason)) != 0)
|
||||||
{
|
{
|
||||||
RecoveryConflictPendingReasons[reason] = false;
|
/* clear the flag */
|
||||||
|
(void) pg_atomic_fetch_and_u32(&MyProc->pendingRecoveryConflicts, ~(1 << reason));
|
||||||
|
|
||||||
ProcessRecoveryConflictInterrupt(reason);
|
ProcessRecoveryConflictInterrupt(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3451,7 +3454,7 @@ ProcessInterrupts(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RecoveryConflictPending)
|
if (pg_atomic_read_u32(&MyProc->pendingRecoveryConflicts) != 0)
|
||||||
ProcessRecoveryConflictInterrupts();
|
ProcessRecoveryConflictInterrupts();
|
||||||
|
|
||||||
if (IdleInTransactionSessionTimeoutPending)
|
if (IdleInTransactionSessionTimeoutPending)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "storage/procsignal.h"
|
#include "storage/standby.h"
|
||||||
#include "utils/pgstat_internal.h"
|
#include "utils/pgstat_internal.h"
|
||||||
#include "utils/timestamp.h"
|
#include "utils/timestamp.h"
|
||||||
|
|
||||||
|
|
@ -88,31 +88,31 @@ pgstat_report_recovery_conflict(int reason)
|
||||||
|
|
||||||
dbentry = pgstat_prep_database_pending(MyDatabaseId);
|
dbentry = pgstat_prep_database_pending(MyDatabaseId);
|
||||||
|
|
||||||
switch (reason)
|
switch ((RecoveryConflictReason) reason)
|
||||||
{
|
{
|
||||||
case PROCSIG_RECOVERY_CONFLICT_DATABASE:
|
case RECOVERY_CONFLICT_DATABASE:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we drop the information about the database as soon as it
|
* Since we drop the information about the database as soon as it
|
||||||
* replicates, there is no point in counting these conflicts.
|
* replicates, there is no point in counting these conflicts.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
|
case RECOVERY_CONFLICT_TABLESPACE:
|
||||||
dbentry->conflict_tablespace++;
|
dbentry->conflict_tablespace++;
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOCK:
|
case RECOVERY_CONFLICT_LOCK:
|
||||||
dbentry->conflict_lock++;
|
dbentry->conflict_lock++;
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
|
case RECOVERY_CONFLICT_SNAPSHOT:
|
||||||
dbentry->conflict_snapshot++;
|
dbentry->conflict_snapshot++;
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
|
case RECOVERY_CONFLICT_BUFFERPIN:
|
||||||
dbentry->conflict_bufferpin++;
|
dbentry->conflict_bufferpin++;
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT:
|
case RECOVERY_CONFLICT_LOGICALSLOT:
|
||||||
dbentry->conflict_logicalslot++;
|
dbentry->conflict_logicalslot++;
|
||||||
break;
|
break;
|
||||||
case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
case RECOVERY_CONFLICT_STARTUP_DEADLOCK:
|
||||||
dbentry->conflict_startup_deadlock++;
|
dbentry->conflict_startup_deadlock++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/hsearch.h"
|
#include "utils/hsearch.h"
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,16 @@ struct PGPROC
|
||||||
|
|
||||||
BackendType backendType; /* what kind of process is this? */
|
BackendType backendType; /* what kind of process is this? */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While in hot standby mode, shows that a conflict signal has been sent
|
||||||
|
* for the current transaction. Set/cleared while holding ProcArrayLock,
|
||||||
|
* though not required. Accessed without lock, if needed.
|
||||||
|
*
|
||||||
|
* This is a bitmask; each bit corresponds to a RecoveryConflictReason
|
||||||
|
* enum value.
|
||||||
|
*/
|
||||||
|
pg_atomic_uint32 pendingRecoveryConflicts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Info about LWLock the process is currently waiting for, if any.
|
* Info about LWLock the process is currently waiting for, if any.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,15 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
|
||||||
bool excludeXmin0, bool allDbs, int excludeVacuum,
|
bool excludeXmin0, bool allDbs, int excludeVacuum,
|
||||||
int *nvxids);
|
int *nvxids);
|
||||||
extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid);
|
extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid);
|
||||||
extern pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode);
|
|
||||||
|
extern bool SignalRecoveryConflict(PGPROC *proc, pid_t pid, RecoveryConflictReason reason);
|
||||||
|
extern bool SignalRecoveryConflictWithVirtualXID(VirtualTransactionId vxid, RecoveryConflictReason reason);
|
||||||
|
extern void SignalRecoveryConflictWithDatabase(Oid databaseid, RecoveryConflictReason reason);
|
||||||
|
|
||||||
|
|
||||||
extern bool MinimumActiveBackends(int min);
|
extern bool MinimumActiveBackends(int min);
|
||||||
extern int CountDBBackends(Oid databaseid);
|
extern int CountDBBackends(Oid databaseid);
|
||||||
extern int CountDBConnections(Oid databaseid);
|
extern int CountDBConnections(Oid databaseid);
|
||||||
extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode);
|
|
||||||
extern int CountUserBackends(Oid roleid);
|
extern int CountUserBackends(Oid roleid);
|
||||||
extern bool CountOtherDBBackends(Oid databaseId,
|
extern bool CountOtherDBBackends(Oid databaseId,
|
||||||
int *nbackends, int *nprepared);
|
int *nbackends, int *nprepared);
|
||||||
|
|
|
||||||
|
|
@ -36,20 +36,12 @@ typedef enum
|
||||||
PROCSIG_BARRIER, /* global barrier interrupt */
|
PROCSIG_BARRIER, /* global barrier interrupt */
|
||||||
PROCSIG_LOG_MEMORY_CONTEXT, /* ask backend to log the memory contexts */
|
PROCSIG_LOG_MEMORY_CONTEXT, /* ask backend to log the memory contexts */
|
||||||
PROCSIG_PARALLEL_APPLY_MESSAGE, /* Message from parallel apply workers */
|
PROCSIG_PARALLEL_APPLY_MESSAGE, /* Message from parallel apply workers */
|
||||||
|
PROCSIG_RECOVERY_CONFLICT, /* backend is blocking recovery, check
|
||||||
/* Recovery conflict reasons */
|
* PGPROC->pendingRecoveryConflicts for the
|
||||||
PROCSIG_RECOVERY_CONFLICT_FIRST,
|
* reason */
|
||||||
PROCSIG_RECOVERY_CONFLICT_DATABASE = PROCSIG_RECOVERY_CONFLICT_FIRST,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_TABLESPACE,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_LOCK,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_SNAPSHOT,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
|
|
||||||
PROCSIG_RECOVERY_CONFLICT_LAST = PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
|
|
||||||
} ProcSignalReason;
|
} ProcSignalReason;
|
||||||
|
|
||||||
#define NUM_PROCSIGNALS (PROCSIG_RECOVERY_CONFLICT_LAST + 1)
|
#define NUM_PROCSIGNALS (PROCSIG_RECOVERY_CONFLICT + 1)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include "datatype/timestamp.h"
|
#include "datatype/timestamp.h"
|
||||||
#include "storage/lock.h"
|
#include "storage/lock.h"
|
||||||
#include "storage/procsignal.h"
|
|
||||||
#include "storage/relfilelocator.h"
|
#include "storage/relfilelocator.h"
|
||||||
#include "storage/standbydefs.h"
|
#include "storage/standbydefs.h"
|
||||||
|
|
||||||
|
|
@ -25,6 +24,37 @@ extern PGDLLIMPORT int max_standby_archive_delay;
|
||||||
extern PGDLLIMPORT int max_standby_streaming_delay;
|
extern PGDLLIMPORT int max_standby_streaming_delay;
|
||||||
extern PGDLLIMPORT bool log_recovery_conflict_waits;
|
extern PGDLLIMPORT bool log_recovery_conflict_waits;
|
||||||
|
|
||||||
|
/* Recovery conflict reasons */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/* Backend is connected to a database that is being dropped */
|
||||||
|
RECOVERY_CONFLICT_DATABASE,
|
||||||
|
|
||||||
|
/* Backend is using a tablespace that is being dropped */
|
||||||
|
RECOVERY_CONFLICT_TABLESPACE,
|
||||||
|
|
||||||
|
/* Backend is holding a lock that is blocking recovery */
|
||||||
|
RECOVERY_CONFLICT_LOCK,
|
||||||
|
|
||||||
|
/* Backend is holding a snapshot that is blocking recovery */
|
||||||
|
RECOVERY_CONFLICT_SNAPSHOT,
|
||||||
|
|
||||||
|
/* Backend is using a logical replication slot that must be invalidated */
|
||||||
|
RECOVERY_CONFLICT_LOGICALSLOT,
|
||||||
|
|
||||||
|
/* Backend is holding a pin on a buffer that is blocking recovery */
|
||||||
|
RECOVERY_CONFLICT_BUFFERPIN,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The backend is requested to check for deadlocks. The startup process
|
||||||
|
* doesn't check for deadlock directly, because we want to kill one of the
|
||||||
|
* other backends instead of the startup process.
|
||||||
|
*/
|
||||||
|
RECOVERY_CONFLICT_STARTUP_DEADLOCK,
|
||||||
|
} RecoveryConflictReason;
|
||||||
|
|
||||||
|
#define NUM_RECOVERY_CONFLICT_REASONS (RECOVERY_CONFLICT_STARTUP_DEADLOCK + 1)
|
||||||
|
|
||||||
extern void InitRecoveryTransactionEnvironment(void);
|
extern void InitRecoveryTransactionEnvironment(void);
|
||||||
extern void ShutdownRecoveryTransactionEnvironment(void);
|
extern void ShutdownRecoveryTransactionEnvironment(void);
|
||||||
|
|
||||||
|
|
@ -43,7 +73,7 @@ extern void CheckRecoveryConflictDeadlock(void);
|
||||||
extern void StandbyDeadLockHandler(void);
|
extern void StandbyDeadLockHandler(void);
|
||||||
extern void StandbyTimeoutHandler(void);
|
extern void StandbyTimeoutHandler(void);
|
||||||
extern void StandbyLockTimeoutHandler(void);
|
extern void StandbyLockTimeoutHandler(void);
|
||||||
extern void LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start,
|
extern void LogRecoveryConflict(RecoveryConflictReason reason, TimestampTz wait_start,
|
||||||
TimestampTz now, VirtualTransactionId *wait_list,
|
TimestampTz now, VirtualTransactionId *wait_list,
|
||||||
bool still_waiting);
|
bool still_waiting);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ extern void die(SIGNAL_ARGS);
|
||||||
pg_noreturn extern void quickdie(SIGNAL_ARGS);
|
pg_noreturn extern void quickdie(SIGNAL_ARGS);
|
||||||
extern void StatementCancelHandler(SIGNAL_ARGS);
|
extern void StatementCancelHandler(SIGNAL_ARGS);
|
||||||
pg_noreturn extern void FloatExceptionHandler(SIGNAL_ARGS);
|
pg_noreturn extern void FloatExceptionHandler(SIGNAL_ARGS);
|
||||||
extern void HandleRecoveryConflictInterrupt(ProcSignalReason reason);
|
extern void HandleRecoveryConflictInterrupt(void);
|
||||||
extern void ProcessClientReadInterrupt(bool blocked);
|
extern void ProcessClientReadInterrupt(bool blocked);
|
||||||
extern void ProcessClientWriteInterrupt(bool blocked);
|
extern void ProcessClientWriteInterrupt(bool blocked);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2489,6 +2489,7 @@ RecordCacheArrayEntry
|
||||||
RecordCacheEntry
|
RecordCacheEntry
|
||||||
RecordCompareData
|
RecordCompareData
|
||||||
RecordIOData
|
RecordIOData
|
||||||
|
RecoveryConflictReason
|
||||||
RecoveryLockEntry
|
RecoveryLockEntry
|
||||||
RecoveryLockXidEntry
|
RecoveryLockXidEntry
|
||||||
RecoveryPauseState
|
RecoveryPauseState
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue