diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 5ecd3c5725b03b0118b332b21049593811d0e440..1a89d78ba95060f33b9f784efdb56713dfd9e8ea 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.280 2010/01/09 16:49:27 sriggs Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.281 2010/01/16 10:05:50 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -313,8 +313,7 @@ IsTransactionState(void) /* * IsAbortedTransactionBlockState * - * This returns true if we are currently running a query - * within an aborted transaction block. + * This returns true if we are within an aborted transaction block. */ bool IsAbortedTransactionBlockState(void) diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 01a7c2123f1534ccda836dd167e7de67bd7e713d..6075de55c53f688842df62293389d93a69ddcf7e 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.55 2010/01/10 15:44:28 sriggs Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.56 2010/01/16 10:05:50 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -324,6 +324,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) /* must be cleared with xid/xmin: */ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK; proc->inCommit = false; /* be sure this is cleared in abort */ + proc->recoveryConflictPending = false; /* Clear the subtransaction-XID cache too while holding the lock */ proc->subxids.nxids = 0; @@ -350,6 +351,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) /* must be cleared with xid/xmin: */ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK; proc->inCommit = false; /* be sure this is cleared in abort */ + proc->recoveryConflictPending = false; Assert(proc->subxids.nxids == 0); Assert(proc->subxids.overflowed == false); @@ -377,7 +379,7 @@ ProcArrayClearTransaction(PGPROC *proc) proc->xid = InvalidTransactionId; proc->lxid = InvalidLocalTransactionId; proc->xmin = InvalidTransactionId; - proc->recoveryConflictMode = 0; + proc->recoveryConflictPending = false; /* redundant, but just in case */ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK; @@ -1665,7 +1667,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, if (proc->pid == 0) continue; - if (skipExistingConflicts && proc->recoveryConflictMode > 0) + if (skipExistingConflicts && proc->recoveryConflictPending) continue; if (!OidIsValid(dbOid) || @@ -1704,7 +1706,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, * Returns pid of the process signaled, or 0 if not found. */ pid_t -CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode) +CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode) { ProcArrayStruct *arrayP = procArray; int index; @@ -1722,28 +1724,22 @@ CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode) if (procvxid.backendId == vxid.backendId && procvxid.localTransactionId == vxid.localTransactionId) { - /* - * Issue orders for the proc to read next time it receives SIGINT - */ - if (proc->recoveryConflictMode < cancel_mode) - proc->recoveryConflictMode = cancel_mode; - + proc->recoveryConflictPending = true; 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, vxid.backendId); + } break; } } LWLockRelease(ProcArrayLock); - if (pid != 0) - { - /* - * Kill the pid if it's still here. If not, that's what we wanted - * so ignore any errors. - */ - kill(pid, SIGINT); - } - return pid; } @@ -1834,6 +1830,7 @@ CancelDBBackends(Oid databaseid) { ProcArrayStruct *arrayP = procArray; int index; + pid_t pid = 0; /* tell all backends to die */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); @@ -1844,8 +1841,21 @@ CancelDBBackends(Oid databaseid) if (proc->databaseId == databaseid) { - proc->recoveryConflictMode = CONFLICT_MODE_FATAL; - kill(proc->pid, SIGINT); + VirtualTransactionId procvxid; + + GET_VXID_FROM_PGPROC(procvxid, *proc); + + proc->recoveryConflictPending = true; + 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, PROCSIG_RECOVERY_CONFLICT_DATABASE, + procvxid.backendId); + } } } diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 753306ca2950b6c245c698ada4c02bd2e35a34c8..453d94aea5bc4762ab0a0017ed14a27e2ec78577 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/procsignal.c,v 1.2 2010/01/02 16:57:51 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/procsignal.c,v 1.3 2010/01/16 10:05:50 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,8 @@ #include "storage/procsignal.h" #include "storage/shmem.h" #include "storage/sinval.h" +#include "storage/standby.h" +#include "tcop/tcopprot.h" /* @@ -258,5 +260,17 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_NOTIFY_INTERRUPT)) HandleNotifyInterrupt(); + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE)) + RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE); + + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_TABLESPACE)) + RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_TABLESPACE); + + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_LOCK)) + RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_LOCK); + + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT)) + RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); + errno = save_errno; } diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index bc9302c4bca5a0a53286a18f25873d517b569d2b..5eca3c89dba7a0c1380d55cff68a193acfb822a8 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -3,19 +3,15 @@ * standby.c * Misc functions used in Hot Standby mode. * - * InitRecoveryTransactionEnvironment() - * ShutdownRecoveryTransactionEnvironment() - * - * ResolveRecoveryConflictWithVirtualXIDs() - * * All functions for handling RM_STANDBY_ID, which relate to * AccessExclusiveLocks and starting snapshots for Hot Standby mode. + * Plus conflict recovery processing. * * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.4 2010/01/14 11:08:02 sriggs Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.5 2010/01/16 10:05:50 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -38,7 +34,7 @@ int vacuum_defer_cleanup_age; static List *RecoveryLockList; static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, - char *reason, int cancel_mode); + ProcSignalReason reason); static void ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid); static void LogCurrentRunningXacts(RunningTransactions CurrRunningXacts); static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks); @@ -162,17 +158,13 @@ WaitExceedsMaxStandbyDelay(void) * recovery processing. Judgement has already been passed on it within * a specific rmgr. Here we just issue the orders to the procs. The procs * then throw the required error as instructed. - * - * We may ask for a specific cancel_mode, typically ERROR or FATAL. */ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, - char *reason, int cancel_mode) + ProcSignalReason reason) { char waitactivitymsg[100]; - Assert(cancel_mode > 0); - while (VirtualTransactionIdIsValid(*waitlist)) { long wait_s; @@ -206,12 +198,6 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, len = 100; memcpy(waitactivitymsg, oldactivitymsg, len); - ereport(trace_recovery(DEBUG5), - (errmsg("virtual transaction %u/%u is blocking %s", - waitlist->backendId, - waitlist->localTransactionId, - reason))); - pgstat_report_waiting(true); logged = true; @@ -226,40 +212,14 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, * Now find out who to throw out of the balloon. */ Assert(VirtualTransactionIdIsValid(*waitlist)); - pid = CancelVirtualTransaction(*waitlist, cancel_mode); + pid = CancelVirtualTransaction(*waitlist, reason); + /* + * Wait awhile for it to die so that we avoid flooding an + * unresponsive backend when system is heavily loaded. + */ if (pid != 0) - { - /* - * Startup process debug messages - */ - switch (cancel_mode) - { - case CONFLICT_MODE_FATAL: - elog(trace_recovery(DEBUG1), - "recovery disconnects session with pid %ld because of conflict with %s", - (long) pid, - reason); - break; - case CONFLICT_MODE_ERROR: - elog(trace_recovery(DEBUG1), - "recovery cancels virtual transaction %u/%u pid %ld because of conflict with %s", - waitlist->backendId, - waitlist->localTransactionId, - (long) pid, - reason); - break; - default: - /* No conflict pending, so fall through */ - break; - } - - /* - * Wait awhile for it to die so that we avoid flooding an - * unresponsive backend when system is heavily loaded. - */ pg_usleep(5000); - } } } @@ -285,8 +245,7 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid) true); ResolveRecoveryConflictWithVirtualXIDs(backends, - "snapshot conflict", - CONFLICT_MODE_ERROR); + PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); } void @@ -317,8 +276,7 @@ ResolveRecoveryConflictWithTablespace(Oid tsid) InvalidOid, false); ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, - "drop tablespace", - CONFLICT_MODE_ERROR); + PROCSIG_RECOVERY_CONFLICT_TABLESPACE); } void @@ -379,8 +337,7 @@ ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid) } ResolveRecoveryConflictWithVirtualXIDs(backends, - "exclusive lock", - CONFLICT_MODE_ERROR); + PROCSIG_RECOVERY_CONFLICT_LOCK); if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false) != LOCKACQUIRE_NOT_AVAIL) diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 91065b368cd3ff5845efb1c4516359698e7a7652..ac891827ec1c4b0665ba06f67ff520d17ad0c8cd 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.212 2010/01/15 09:19:03 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.213 2010/01/16 10:05:50 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -324,7 +324,7 @@ InitProcess(void) MyProc->waitProcLock = NULL; for (i = 0; i < NUM_LOCK_PARTITIONS; i++) SHMQueueInit(&(MyProc->myProcLocks[i])); - MyProc->recoveryConflictMode = 0; + MyProc->recoveryConflictPending = false; /* * We might be reusing a semaphore that belonged to a failed process. So diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index ad8678e2200954b133c750ca14bcc5274e4ef90f..8d55e3575a0866abdac6dcb135dc548ea0fc4f71 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.582 2010/01/15 09:19:04 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.583 2010/01/16 10:05:50 sriggs Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -63,7 +63,6 @@ #include "storage/proc.h" #include "storage/procsignal.h" #include "storage/sinval.h" -#include "storage/standby.h" #include "tcop/fastpath.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" @@ -173,6 +172,8 @@ static int UseNewLine = 1; /* Use newlines query delimiters (the default) */ static int UseNewLine = 0; /* Use EOF as query delimiters */ #endif /* TCOP_DONTUSENEWLINE */ +/* whether we were cancelled during recovery by conflict processing or not */ +static bool RecoveryConflictPending = false; /* ---------------------------------------------------------------- * decls for routines only used in this file @@ -186,6 +187,7 @@ static List *pg_rewrite_query(Query *query); static bool check_log_statement(List *stmt_list); static int errdetail_execute(List *raw_parsetree_list); static int errdetail_params(ParamListInfo params); +static int errdetail_abort(void); static void start_xact_command(void); static void finish_xact_command(void); static bool IsTransactionExitStmt(Node *parsetree); @@ -944,7 +946,8 @@ exec_simple_query(const char *query_string) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " - "commands ignored until end of transaction block"))); + "commands ignored until end of transaction block"), + errdetail_abort())); /* Make sure we are in a transaction command */ start_xact_command(); @@ -1253,7 +1256,8 @@ exec_parse_message(const char *query_string, /* string to execute */ ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " - "commands ignored until end of transaction block"))); + "commands ignored until end of transaction block"), + errdetail_abort())); /* * Set up a snapshot if parse analysis/planning will need one. @@ -1533,7 +1537,8 @@ exec_bind_message(StringInfo input_message) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " - "commands ignored until end of transaction block"))); + "commands ignored until end of transaction block"), + errdetail_abort())); /* * Create the portal. Allow silent replacement of an existing portal only @@ -1974,7 +1979,8 @@ exec_execute_message(const char *portal_name, long max_rows) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " - "commands ignored until end of transaction block"))); + "commands ignored until end of transaction block"), + errdetail_abort())); /* Check for cancel signal before we start execution */ CHECK_FOR_INTERRUPTS(); @@ -2234,6 +2240,20 @@ errdetail_params(ParamListInfo params) return 0; } +/* + * errdetail_abort + * + * Add an errdetail() line showing abort reason, if any. + */ +static int +errdetail_abort(void) +{ + if (MyProc->recoveryConflictPending) + errdetail("abort reason: recovery conflict"); + + return 0; +} + /* * exec_describe_statement_message * @@ -2291,7 +2311,8 @@ exec_describe_statement_message(const char *stmt_name) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " - "commands ignored until end of transaction block"))); + "commands ignored until end of transaction block"), + errdetail_abort())); if (whereToSendOutput != DestRemote) return; /* can't actually do anything... */ @@ -2371,7 +2392,8 @@ exec_describe_portal_message(const char *portal_name) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " - "commands ignored until end of transaction block"))); + "commands ignored until end of transaction block"), + errdetail_abort())); if (whereToSendOutput != DestRemote) return; /* can't actually do anything... */ @@ -2678,6 +2700,97 @@ SigHupHandler(SIGNAL_ARGS) got_SIGHUP = true; } +/* + * RecoveryConflictInterrupt: out-of-line portion of recovery conflict + * handling ollowing receipt of SIGUSR1. Designed to be similar to die() + * and StatementCancelHandler(). Called only by a normal user backend + * that begins a transaction during recovery. + */ +void +RecoveryConflictInterrupt(ProcSignalReason reason) +{ + int save_errno = errno; + + /* + * Don't joggle the elbow of proc_exit + */ + if (!proc_exit_inprogress) + { + switch (reason) + { + case PROCSIG_RECOVERY_CONFLICT_LOCK: + case PROCSIG_RECOVERY_CONFLICT_TABLESPACE: + case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT: + /* + * If we aren't in a transaction any longer then ignore. + */ + if (!IsTransactionOrTransactionBlock()) + return; + + /* + * If we can abort just the current subtransaction then we + * are OK to throw an ERROR to resolve the conflict. Otherwise + * drop through to the FATAL case. + * + * XXX other times that we can throw just an ERROR *may* be + * PROCSIG_RECOVERY_CONFLICT_LOCK + * if no locks are held in parent transactions + * + * PROCSIG_RECOVERY_CONFLICT_SNAPSHOT + * if no snapshots are held by parent transactions + * and the transaction is not serializable + * + * PROCSIG_RECOVERY_CONFLICT_TABLESPACE + * if no temp files or cursors open in parent transactions + */ + if (!IsSubTransaction()) + { + /* + * If we already aborted then we no longer need to cancel. + * We do this here since we do not wish to ignore aborted + * subtransactions, which must cause FATAL, currently. + */ + if (IsAbortedTransactionBlockState()) + return; + + RecoveryConflictPending = true; + QueryCancelPending = true; + InterruptPending = true; + break; + } + + /* Intentional drop through to session cancel */ + + case PROCSIG_RECOVERY_CONFLICT_DATABASE: + RecoveryConflictPending = true; + ProcDiePending = true; + InterruptPending = true; + break; + + default: + elog(FATAL, "Unknown conflict mode"); + } + + /* + * If it's safe to interrupt, and we're waiting for input or a lock, + * service the interrupt immediately + */ + if (ImmediateInterruptOK && InterruptHoldoffCount == 0 && + CritSectionCount == 0) + { + /* bump holdoff count to make ProcessInterrupts() a no-op */ + /* until we are done getting ready for it */ + InterruptHoldoffCount++; + LockWaitCancel(); /* prevent CheckDeadLock from running */ + DisableNotifyInterrupt(); + DisableCatchupInterrupt(); + InterruptHoldoffCount--; + ProcessInterrupts(); + } + } + + errno = save_errno; +} /* * ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro @@ -2707,6 +2820,10 @@ ProcessInterrupts(void) ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN), errmsg("terminating autovacuum process due to administrator command"))); + else if (RecoveryConflictPending) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating connection due to conflict with recovery"))); else ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN), @@ -2745,57 +2862,26 @@ ProcessInterrupts(void) (errcode(ERRCODE_QUERY_CANCELED), errmsg("canceling autovacuum task"))); } + if (RecoveryConflictPending) { - int cancelMode = MyProc->recoveryConflictMode; + ImmediateInterruptOK = false; /* not idle anymore */ + DisableNotifyInterrupt(); + DisableCatchupInterrupt(); - /* - * XXXHS: We don't yet have a clean way to cancel an - * idle-in-transaction session, so make it FATAL instead. - * This isn't as bad as it looks because we don't issue a - * CONFLICT_MODE_ERROR for a session with proc->xmin == 0 - * on cleanup conflicts. There's a possibility that we - * marked somebody as a conflict and then they go idle. - */ - if (DoingCommandRead && IsTransactionBlock() && - cancelMode == CONFLICT_MODE_ERROR) + if (DoingCommandRead) { - cancelMode = CONFLICT_MODE_FATAL; + ProcDiePending = false; + QueryCancelPending = false; + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating connection due to conflict with recovery"))); } - - switch (cancelMode) + else { - case CONFLICT_MODE_FATAL: - ImmediateInterruptOK = false; /* not idle anymore */ - DisableNotifyInterrupt(); - DisableCatchupInterrupt(); - Assert(RecoveryInProgress()); - ereport(FATAL, - (errcode(ERRCODE_QUERY_CANCELED), - errmsg("canceling session due to conflict with recovery"))); - - case CONFLICT_MODE_ERROR: - /* - * We are aborting because we need to release - * locks. So we need to abort out of all - * subtransactions to make sure we release - * all locks at whatever their level. - * - * XXX Should we try to examine the - * transaction tree and cancel just enough - * subxacts to remove locks? Doubt it. - */ - ImmediateInterruptOK = false; /* not idle anymore */ - DisableNotifyInterrupt(); - DisableCatchupInterrupt(); - Assert(RecoveryInProgress()); - AbortOutOfAnyTransaction(); - ereport(ERROR, - (errcode(ERRCODE_QUERY_CANCELED), - errmsg("canceling statement due to conflict with recovery"))); - - default: - /* No conflict pending, so fall through */ - break; + QueryCancelPending = false; + ereport(ERROR, + (errcode(ERRCODE_QUERY_CANCELED), + errmsg("canceling statement due to conflict with recovery"))); } } @@ -3637,7 +3723,12 @@ PostgresMain(int argc, char *argv[], const char *username) */ if (send_ready_for_query) { - if (IsTransactionOrTransactionBlock()) + if (IsAbortedTransactionBlockState()) + { + set_ps_display("idle in transaction (aborted)", false); + pgstat_report_activity("<IDLE> in transaction (aborted)"); + } + else if (IsTransactionOrTransactionBlock()) { set_ps_display("idle in transaction", false); pgstat_report_activity("<IDLE> in transaction"); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index cee02c359d70d670407d958df73b286ed6ccd969..5050090324583710def8810b4247ffbc1825cf3d 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.117 2010/01/15 09:19:09 heikki Exp $ + * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.118 2010/01/16 10:05:50 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -96,11 +96,11 @@ struct PGPROC uint8 vacuumFlags; /* vacuum-related flags, see above */ /* - * While in hot standby mode, setting recoveryConflictMode instructs - * the backend to commit suicide. Possible values are the same as those - * passed to ResolveRecoveryConflictWithVirtualXIDs(). + * 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. */ - int recoveryConflictMode; + bool recoveryConflictPending; /* Info about LWLock the process is currently waiting for, if any. */ bool lwWaiting; /* true if waiting for an LW lock */ diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index 4572f489af812a91a2e0a0933b0f5c69e6b8f3a0..42953b0843cf48438434d3f5063a1e2d4bbebcec 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.29 2010/01/10 15:44:28 sriggs Exp $ + * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.30 2010/01/16 10:05:56 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -15,6 +15,7 @@ #define PROCARRAY_H #include "storage/lock.h" +#include "storage/procsignal.h" #include "storage/standby.h" #include "utils/snapshot.h" @@ -58,8 +59,7 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin, int *nvxids); extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, bool skipExistingConflicts); -extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, - int cancel_mode); +extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode); extern int CountActiveBackends(void); extern int CountDBBackends(Oid databaseid); diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index 9b707520ef8a78e50e800f46219e256e64334148..cbe0e24c6725b3ee0ff6f6102c217ea31747574a 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/procsignal.h,v 1.2 2010/01/02 16:58:08 momjian Exp $ + * $PostgreSQL: pgsql/src/include/storage/procsignal.h,v 1.3 2010/01/16 10:05:57 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +32,12 @@ typedef enum PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ + /* Recovery conflict reasons */ + PROCSIG_RECOVERY_CONFLICT_DATABASE, + PROCSIG_RECOVERY_CONFLICT_TABLESPACE, + PROCSIG_RECOVERY_CONFLICT_LOCK, + PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, + NUM_PROCSIGNALS /* Must be last! */ } ProcSignalReason; diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index 3f2e2c2d85587fdd2701428d5aadcfb42a2aa977..8c982cffb633d08303b6ac0057c2297098d475dd 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.3 2010/01/14 11:08:02 sriggs Exp $ + * $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.4 2010/01/16 10:05:57 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -19,11 +19,6 @@ extern int vacuum_defer_cleanup_age; -/* cancel modes for ResolveRecoveryConflictWithVirtualXIDs */ -#define CONFLICT_MODE_NOT_SET 0 -#define CONFLICT_MODE_ERROR 1 /* Conflict can be resolved by canceling query */ -#define CONFLICT_MODE_FATAL 2 /* Conflict can only be resolved by disconnecting session */ - extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid); extern void ResolveRecoveryConflictWithTablespace(Oid tsid); extern void ResolveRecoveryConflictWithDatabase(Oid dbid); diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 891979dc8a20fe58b349328b82a80ba9947efea7..b46160160ea7961e1c7e02cb3d8f224c3950fab5 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.102 2010/01/02 16:58:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.103 2010/01/16 10:05:59 sriggs Exp $ * * OLD COMMENTS * This file was created so that other c files could get the two @@ -21,6 +21,7 @@ #include "executor/execdesc.h" #include "nodes/parsenodes.h" +#include "storage/procsignal.h" #include "utils/guc.h" @@ -64,6 +65,7 @@ extern void die(SIGNAL_ARGS); extern void quickdie(SIGNAL_ARGS); extern void StatementCancelHandler(SIGNAL_ARGS); extern void FloatExceptionHandler(SIGNAL_ARGS); +extern void RecoveryConflictInterrupt(ProcSignalReason reason); /* called from SIGUSR1 handler */ extern void prepare_for_client_read(void); extern void client_read_ended(void); extern const char *process_postgres_switches(int argc, char *argv[],