hs_signaling.1.diff
text/x-diff
Filename: hs_signaling.1.diff
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/access/transam/xact.c | 43 | 2 |
| src/backend/commands/vacuum.c | 1 | 1 |
| src/backend/postmaster/autovacuum.c | 6 | 5 |
| src/backend/storage/ipc/ipc.c | 1 | 3 |
| src/backend/storage/ipc/procarray.c | 3 | 8 |
| src/backend/storage/ipc/procsignal.c | 62 | 10 |
| src/backend/storage/ipc/standby.c | 8 | 1 |
| src/backend/tcop/postgres.c | 137 | 131 |
| src/backend/utils/adt/misc.c | 10 | 0 |
| src/backend/utils/init/globals.c | 1 | 3 |
| src/include/access/xact.h | 1 | 0 |
| src/include/catalog/pg_proc.h | 2 | 0 |
| src/include/miscadmin.h | 17 | 6 |
| src/include/storage/procarray.h | 2 | 1 |
| src/include/storage/procsignal.h | 11 | 0 |
| src/include/tcop/tcopprot.h | 5 | 0 |
| src/include/utils/builtins.h | 1 | 0 |
diff -cr cvs/src/backend/access/transam/xact.c cvs.build/src/backend/access/transam/xact.c
*** cvs/src/backend/access/transam/xact.c 2009-12-24 13:55:12.000000000 +0100
--- cvs.build/src/backend/access/transam/xact.c 2010-01-05 11:25:17.000000000 +0100
***************
*** 313,320 ****
/*
* IsAbortedTransactionBlockState
*
! * This returns true if we are currently running a query
! * within an aborted transaction block.
*/
bool
IsAbortedTransactionBlockState(void)
--- 313,319 ----
/*
* IsAbortedTransactionBlockState
*
! * This returns true if we are within an aborted transaction block.
*/
bool
IsAbortedTransactionBlockState(void)
***************
*** 2692,2697 ****
--- 2691,2738 ----
}
/*
+ * AbortTransactionAndAnySubtransactions
+ *
+ * Similar to AbortCurrentTransaction but if any subtransactions
+ * in progress we abort them and all of their parents. So this is
+ * used when the caller wishes to make the abort untrappable by the user.
+ */
+ void
+ AbortTransactionAndAnySubtransactions(void)
+ {
+ TransactionState s = CurrentTransactionState;
+
+ switch (s->blockState)
+ {
+ case TBLOCK_DEFAULT:
+ case TBLOCK_STARTED:
+ case TBLOCK_BEGIN:
+ case TBLOCK_INPROGRESS:
+ case TBLOCK_END:
+ case TBLOCK_ABORT:
+ case TBLOCK_SUBABORT:
+ case TBLOCK_ABORT_END:
+ case TBLOCK_ABORT_PENDING:
+ case TBLOCK_PREPARE:
+ case TBLOCK_SUBABORT_END:
+ case TBLOCK_SUBABORT_RESTART:
+ AbortCurrentTransaction();
+ break;
+
+ case TBLOCK_SUBINPROGRESS:
+ case TBLOCK_SUBBEGIN:
+ case TBLOCK_SUBEND:
+ case TBLOCK_SUBABORT_PENDING:
+ case TBLOCK_SUBRESTART:
+ AbortSubTransaction();
+ CleanupSubTransaction();
+ AbortTransactionAndAnySubtransactions();
+ break;
+ }
+ }
+
+
+ /*
* PreventTransactionChain
*
* This routine is to be called by statements that must not run inside
diff -cr cvs/src/backend/commands/vacuum.c cvs.build/src/backend/commands/vacuum.c
*** cvs/src/backend/commands/vacuum.c 2009-12-24 13:55:13.000000000 +0100
--- cvs.build/src/backend/commands/vacuum.c 2010-01-03 20:24:26.000000000 +0100
***************
*** 3936,3942 ****
CHECK_FOR_INTERRUPTS();
/* Nap if appropriate */
! if (VacuumCostActive && !InterruptPending &&
VacuumCostBalance >= VacuumCostLimit)
{
int msec;
--- 3936,3942 ----
CHECK_FOR_INTERRUPTS();
/* Nap if appropriate */
! if (VacuumCostActive && !IsInterruptEventPending &&
VacuumCostBalance >= VacuumCostLimit)
{
int msec;
diff -cr cvs/src/backend/postmaster/autovacuum.c cvs.build/src/backend/postmaster/autovacuum.c
*** cvs/src/backend/postmaster/autovacuum.c 2009-12-09 11:24:41.000000000 +0100
--- cvs.build/src/backend/postmaster/autovacuum.c 2010-01-07 00:22:21.000000000 +0100
***************
*** 479,488 ****
/* Prevents interrupts while cleaning up */
HOLD_INTERRUPTS();
! /* Forget any pending QueryCancel request */
! QueryCancelPending = false;
disable_sig_alarm(true);
! QueryCancelPending = false; /* again in case timeout occurred */
/* Report the error to the server log */
EmitErrorReport();
--- 479,489 ----
/* Prevents interrupts while cleaning up */
HOLD_INTERRUPTS();
! /* Forget any pending CancelQuery request */
! ClearInterruptEventPending(CancelQueryPending);
disable_sig_alarm(true);
! /* again in case timeout occurred */
! ClearInterruptEventPending(CancelQueryPending);
/* Report the error to the server log */
EmitErrorReport();
***************
*** 2233,2244 ****
autovacuum_do_vac_analyze(tab, bstrategy);
/*
! * Clear a possible query-cancel signal, to avoid a late reaction
* to an automatically-sent signal because of vacuuming the
* current table (we're done with it, so it would make no sense to
* cancel at this point.)
*/
! QueryCancelPending = false;
}
PG_CATCH();
{
--- 2234,2245 ----
autovacuum_do_vac_analyze(tab, bstrategy);
/*
! * Clear a possible cancel-query signal, to avoid a late reaction
* to an automatically-sent signal because of vacuuming the
* current table (we're done with it, so it would make no sense to
* cancel at this point.)
*/
! ClearInterruptEventPending(CancelQueryPending);
}
PG_CATCH();
{
diff -cr cvs/src/backend/storage/ipc/ipc.c cvs.build/src/backend/storage/ipc/ipc.c
*** cvs/src/backend/storage/ipc/ipc.c 2009-12-09 11:24:52.000000000 +0100
--- cvs.build/src/backend/storage/ipc/ipc.c 2010-01-03 20:33:49.000000000 +0100
***************
*** 155,163 ****
* close up shop already. Note that the signal handlers will not set
* these flags again, now that proc_exit_inprogress is set.
*/
! InterruptPending = false;
! ProcDiePending = false;
! QueryCancelPending = false;
/* And let's just make *sure* we're not interrupted ... */
ImmediateInterruptOK = false;
InterruptHoldoffCount = 1;
--- 155,161 ----
* close up shop already. Note that the signal handlers will not set
* these flags again, now that proc_exit_inprogress is set.
*/
! ZeroInterruptEventPending();
/* And let's just make *sure* we're not interrupted ... */
ImmediateInterruptOK = false;
InterruptHoldoffCount = 1;
diff -cr cvs/src/backend/storage/ipc/procarray.c cvs.build/src/backend/storage/ipc/procarray.c
*** cvs/src/backend/storage/ipc/procarray.c 2009-12-24 13:55:18.000000000 +0100
--- cvs.build/src/backend/storage/ipc/procarray.c 2010-01-06 20:02:31.000000000 +0100
***************
*** 52,57 ****
--- 52,58 ----
#include "access/twophase.h"
#include "miscadmin.h"
#include "storage/procarray.h"
+ #include "storage/procsignal.h"
#include "storage/standby.h"
#include "utils/builtins.h"
#include "utils/snapmgr.h"
***************
*** 1704,1710 ****
* Returns pid of the process signaled, or 0 if not found.
*/
pid_t
! CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode)
{
ProcArrayStruct *arrayP = procArray;
int index;
--- 1705,1711 ----
* Returns pid of the process signaled, or 0 if not found.
*/
pid_t
! CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
{
ProcArrayStruct *arrayP = procArray;
int index;
***************
*** 1722,1733 ****
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;
-
pid = proc->pid;
break;
}
--- 1723,1728 ----
***************
*** 1741,1747 ****
* Kill the pid if it's still here. If not, that's what we wanted
* so ignore any errors.
*/
! kill(pid, SIGINT);
}
return pid;
--- 1736,1742 ----
* 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);
}
return pid;
diff -cr cvs/src/backend/storage/ipc/procsignal.c cvs.build/src/backend/storage/ipc/procsignal.c
*** cvs/src/backend/storage/ipc/procsignal.c 2009-12-09 11:24:52.000000000 +0100
--- cvs.build/src/backend/storage/ipc/procsignal.c 2010-01-07 12:00:33.000000000 +0100
***************
*** 24,29 ****
--- 24,31 ----
#include "storage/procsignal.h"
#include "storage/shmem.h"
#include "storage/sinval.h"
+ #include "storage/standby.h"
+ #include "tcop/tcopprot.h"
/*
***************
*** 170,195 ****
SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
{
volatile ProcSignalSlot *slot;
if (backendId != InvalidBackendId)
{
! slot = &ProcSignalSlots[backendId - 1];
!
/*
! * Note: Since there's no locking, it's possible that the target
* process detaches from shared memory and exits right after this
! * test, before we set the flag and send signal. And the signal slot
! * might even be recycled by a new process, so it's remotely possible
! * that we set a flag for a wrong process. That's OK, all the signals
! * are such that no harm is done if they're mistakenly fired.
*/
if (slot->pss_pid == pid)
{
/* Atomically set the proper flag */
slot->pss_signalFlags[reason] = true;
/* Send signal */
! return kill(pid, SIGUSR1);
}
}
else
{
--- 172,210 ----
SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
{
volatile ProcSignalSlot *slot;
+ int ret;
if (backendId != InvalidBackendId)
{
! Assert(backendId <= MaxBackends);
/*
! * If we did not get a lock, it would be possible that the target
* process detaches from shared memory and exits right after this
! * test, before we set the flag and send the signal. And the signal
! * slot might even be recycled by a new process, so it's remotely
! * possible that we set a flag for a wrong process. That's OK for
! * harmless signal reasons. As soon as we get a cancel-something signal
! * reason (which really should not happen all that often), we take the
! * time to grab a shared lock on ProcArray before we start to search
! * that backend and hold it until we have sent the signal.
*/
+ if (!IsHarmlessSignal(reason))
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ slot = &ProcSignalSlots[backendId - 1];
+
if (slot->pss_pid == pid)
{
/* Atomically set the proper flag */
slot->pss_signalFlags[reason] = true;
/* Send signal */
! ret = kill(pid, SIGUSR1);
}
+
+ if (!IsHarmlessSignal(reason))
+ LWLockRelease(ProcArrayLock);
+
+ return ret;
}
else
{
***************
*** 200,205 ****
--- 215,228 ----
* process, which will have a slot near the end of the array.
*/
int i;
+ bool found = false;
+
+ /*
+ * If the signal is not a harmless one, grab a lock to be sure we
+ * send it to the correct backend.
+ */
+ if (!IsHarmlessSignal(reason))
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
for (i = NumProcSignalSlots - 1; i >= 0; i--)
{
***************
*** 207,220 ****
if (slot->pss_pid == pid)
{
! /* the above note about race conditions applies here too */
/* Atomically set the proper flag */
slot->pss_signalFlags[reason] = true;
/* Send signal */
! return kill(pid, SIGUSR1);
}
}
}
errno = ESRCH;
--- 230,250 ----
if (slot->pss_pid == pid)
{
! found = true;
/* Atomically set the proper flag */
slot->pss_signalFlags[reason] = true;
/* Send signal */
! ret = kill(pid, SIGUSR1);
! break;
}
}
+
+ if (!IsHarmlessSignal(reason))
+ LWLockRelease(ProcArrayLock);
+
+ if (found)
+ return ret;
}
errno = ESRCH;
***************
*** 252,262 ****
--- 282,314 ----
{
int save_errno = errno;
+ /* signal reasons that notify a backend of an event */
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
HandleCatchupInterrupt();
if (CheckProcSignal(PROCSIG_NOTIFY_INTERRUPT))
HandleNotifyInterrupt();
+ /* signal reasons that request the backend to cancel some action */
+
+ /* pg_cancel_idle_transaction() */
+ if (CheckProcSignal(PROCSIG_CANCEL_IDLE_TRANSACTION))
+ HandleCancelAction(false, true, false);
+
+ /* Hot standby */
+ if (CheckProcSignal(PROCSIG_CONFLICT_ERROR_INTERRUPT))
+ {
+ SetInterruptEventPending(ConflictErrorPending);
+ HandleCancelAction(true, true, false);
+ }
+
+ /* Hot standby */
+ if (CheckProcSignal(PROCSIG_CONFLICT_FATAL_INTERRUPT))
+ {
+ SetInterruptEventPending(ConflictFatalPending);
+ HandleCancelAction(false, false, true);
+ }
+
errno = save_errno;
}
+
diff -cr cvs/src/backend/storage/ipc/standby.c cvs.build/src/backend/storage/ipc/standby.c
*** cvs/src/backend/storage/ipc/standby.c 2009-12-19 02:32:35.000000000 +0100
--- cvs.build/src/backend/storage/ipc/standby.c 2010-01-06 19:35:02.000000000 +0100
***************
*** 219,229 ****
{
pid_t pid;
/*
* Now find out who to throw out of the balloon.
*/
Assert(VirtualTransactionIdIsValid(*waitlist));
! pid = CancelVirtualTransaction(*waitlist, cancel_mode);
if (pid != 0)
{
--- 219,236 ----
{
pid_t pid;
+ ProcSignalReason sigmode;
+
+ if (cancel_mode == CONFLICT_MODE_ERROR)
+ sigmode = PROCSIG_CONFLICT_ERROR_INTERRUPT;
+ else
+ sigmode = PROCSIG_CONFLICT_FATAL_INTERRUPT;
+
/*
* Now find out who to throw out of the balloon.
*/
Assert(VirtualTransactionIdIsValid(*waitlist));
! pid = CancelVirtualTransaction(*waitlist, sigmode);
if (pid != 0)
{
diff -cr cvs/src/backend/tcop/postgres.c cvs.build/src/backend/tcop/postgres.c
*** cvs/src/backend/tcop/postgres.c 2009-12-24 13:55:18.000000000 +0100
--- cvs.build/src/backend/tcop/postgres.c 2010-01-07 12:46:26.000000000 +0100
***************
*** 479,486 ****
/* Allow "die" interrupt to be processed while waiting */
ImmediateInterruptOK = true;
! /* And don't forget to detect one that already arrived */
! QueryCancelPending = false;
CHECK_FOR_INTERRUPTS();
}
}
--- 479,486 ----
/* Allow "die" interrupt to be processed while waiting */
ImmediateInterruptOK = true;
! /* And don't forget to detect those that already arrived */
! ZeroInterruptEventPending();
CHECK_FOR_INTERRUPTS();
}
}
***************
*** 494,500 ****
if (DoingCommandRead)
{
ImmediateInterruptOK = false;
! QueryCancelPending = false; /* forget any CANCEL signal */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
--- 494,501 ----
if (DoingCommandRead)
{
ImmediateInterruptOK = false;
! /* forget any CANCEL signal */
! ZeroInterruptEventPending();
DisableNotifyInterrupt();
DisableCatchupInterrupt();
***************
*** 2593,2661 ****
void
die(SIGNAL_ARGS)
{
! int save_errno = errno;
!
! /* Don't joggle the elbow of proc_exit */
! if (!proc_exit_inprogress)
! {
! InterruptPending = true;
! ProcDiePending = true;
!
! /*
! * 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;
}
/*
! * Query-cancel signal from postmaster: abort current transaction
! * at soonest convenient time
*/
void
StatementCancelHandler(SIGNAL_ARGS)
{
int save_errno = errno;
/*
! * Don't joggle the elbow of proc_exit
*/
! if (!proc_exit_inprogress)
! {
! InterruptPending = true;
! QueryCancelPending = true;
! /*
! * If it's safe to interrupt, and we're waiting for a lock, service
! * the interrupt immediately. No point in interrupting if we're
! * waiting for input, however.
! */
! if (InterruptHoldoffCount == 0 && CritSectionCount == 0 &&
! (DoingCommandRead || ImmediateInterruptOK))
! {
! /* 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;
--- 2594,2668 ----
void
die(SIGNAL_ARGS)
{
! HandleCancelAction(false, false, true);
}
/*
! * Query-cancel signal from postmaster: abort current query at soonest
! * convenient time, do not abort an idle transaction however.
*/
void
StatementCancelHandler(SIGNAL_ARGS)
{
+ HandleCancelAction(true, false, false);
+ }
+
+ void
+ HandleCancelAction(bool cancelQuery,
+ bool cancelIdleTransaction,
+ bool cancelSession)
+ {
int save_errno = errno;
+ /* Don't joggle the elbow of proc_exit */
+ if (proc_exit_inprogress)
+ return;
+
/*
! * Check cancel requests against internal states, we might want to
! * ignore a request.
*/
! if (cancelQuery && DoingCommandRead)
! cancelQuery = false;
! if (cancelIdleTransaction)
! {
! if (!DoingCommandRead)
! cancelIdleTransaction = false;
! else if (!IsTransactionOrTransactionBlock())
! cancelIdleTransaction = false;
! else if (IsAbortedTransactionBlockState())
! cancelIdleTransaction = false;
! }
! if (!cancelQuery && !cancelIdleTransaction && !cancelSession)
! return;
!
! /*
! * Set the global variable InterruptPendingEvent to whatever is left set
! * to true after the previous checks.
! */
! if (cancelQuery)
! SetInterruptEventPending(CancelQueryPending);
! if (cancelIdleTransaction)
! SetInterruptEventPending(CancelIdleTransactionPending);
! if (cancelSession)
! SetInterruptEventPending(CancelSessionPending);
!
! /*
! * If it's safe to interrupt, and we're waiting for a lock, service
! * the interrupt immediately.
! */
! if (InterruptHoldoffCount == 0 && CritSectionCount == 0 &&
! ImmediateInterruptOK)
! {
! /* 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;
***************
*** 2685,2704 ****
* ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro
*
* If an interrupt condition is pending, and it's safe to service it,
! * then clear the flag and accept the interrupt. Called only when
! * InterruptPending is true.
*/
void
ProcessInterrupts(void)
{
/* OK to accept interrupt now? */
if (InterruptHoldoffCount != 0 || CritSectionCount != 0)
return;
! InterruptPending = false;
! if (ProcDiePending)
{
- ProcDiePending = false;
- QueryCancelPending = false; /* ProcDie trumps QueryCancel */
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
--- 2692,2712 ----
* ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro
*
* If an interrupt condition is pending, and it's safe to service it,
! * then clear the flag and accept the interrupt. Called only when
! * InterruptPendingEvent != NothingPending.
*/
void
ProcessInterrupts(void)
{
+ const char *msg;
+ int code;
+
/* OK to accept interrupt now? */
if (InterruptHoldoffCount != 0 || CritSectionCount != 0)
return;
!
! if (InterruptPendingEvent & CancelSessionPending)
{
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
***************
*** 2706,2722 ****
if (ClientAuthInProgress && whereToSendOutput == DestRemote)
whereToSendOutput = DestNone;
if (IsAutoVacuumWorkerProcess())
! ereport(FATAL,
! (errcode(ERRCODE_ADMIN_SHUTDOWN),
! errmsg("terminating autovacuum process due to administrator command")));
else
! ereport(FATAL,
! (errcode(ERRCODE_ADMIN_SHUTDOWN),
! errmsg("terminating connection due to administrator command")));
}
! if (QueryCancelPending)
{
- QueryCancelPending = false;
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
--- 2714,2742 ----
if (ClientAuthInProgress && whereToSendOutput == DestRemote)
whereToSendOutput = DestNone;
if (IsAutoVacuumWorkerProcess())
! {
! code = ERRCODE_ADMIN_SHUTDOWN;
! msg = "terminating autovacuum process due to administrator command";
! }
! else if (InterruptPendingEvent & ConflictFatalPending)
! {
! Assert(RecoveryInProgress());
! code = ERRCODE_QUERY_CANCELED;
! msg = "canceling session due to conflict with recovery";
! }
else
! {
! code = ERRCODE_ADMIN_SHUTDOWN;
! msg = "terminating connection due to administrator command";
! }
!
! ZeroInterruptEventPending();
!
! ereport(FATAL, (errcode(code),
! errmsg(msg)));
}
! if (InterruptPendingEvent & CancelQueryPending)
{
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
DisableCatchupInterrupt();
***************
*** 2724,2795 ****
if (ClientAuthInProgress && whereToSendOutput == DestRemote)
whereToSendOutput = DestNone;
if (ClientAuthInProgress)
! ereport(ERROR,
! (errcode(ERRCODE_QUERY_CANCELED),
! errmsg("canceling authentication due to timeout")));
else if (cancel_from_timeout)
! ereport(ERROR,
! (errcode(ERRCODE_QUERY_CANCELED),
! errmsg("canceling statement due to statement timeout")));
else if (IsAutoVacuumWorkerProcess())
! ereport(ERROR,
! (errcode(ERRCODE_QUERY_CANCELED),
! errmsg("canceling autovacuum task")));
! else
{
! int cancelMode = MyProc->recoveryConflictMode;
! /*
! * 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)
! {
! cancelMode = CONFLICT_MODE_FATAL;
! }
! switch (cancelMode)
! {
! case CONFLICT_MODE_FATAL:
! 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.
! */
! Assert(RecoveryInProgress());
! AbortOutOfAnyTransaction();
! ereport(ERROR,
! (errcode(ERRCODE_QUERY_CANCELED),
! errmsg("canceling statement due to conflict with recovery")));
! return;
!
! default:
! /* No conflict pending, so fall through */
! break;
! }
! ereport(ERROR,
! (errcode(ERRCODE_QUERY_CANCELED),
! errmsg("canceling statement due to user request")));
}
}
! /* If we get here, do nothing (probably, QueryCancelPending was reset) */
}
--- 2744,2794 ----
if (ClientAuthInProgress && whereToSendOutput == DestRemote)
whereToSendOutput = DestNone;
if (ClientAuthInProgress)
! msg = "canceling authentication due to timeout";
else if (cancel_from_timeout)
! msg = "canceling statement due to statement timeout";
else if (IsAutoVacuumWorkerProcess())
! msg = "canceling autovacuum task";
! else if (InterruptPendingEvent & ConflictErrorPending)
{
! Assert(RecoveryInProgress());
! msg = "canceling statement due to conflict with recovery";
! }
! else
! msg = "canceling statement due to user request";
! ZeroInterruptEventPending();
! ereport(ERROR,
! (errcode(ERRCODE_QUERY_CANCELED),
! errmsg(msg)));
! }
! if (InterruptPendingEvent & CancelIdleTransactionPending)
! {
! ImmediateInterruptOK = false; /* not idle anymore */
! DisableNotifyInterrupt();
! DisableCatchupInterrupt();
! if (InterruptPendingEvent & ConflictErrorPending)
! {
! Assert(RecoveryInProgress());
! msg = "canceling statement due to conflict with recovery";
}
+ else
+ msg = "canceling idle transaction due to administrator request";
+
+ ZeroInterruptEventPending();
+
+ ereport(NOTICE,
+ (errcode(ERRCODE_QUERY_CANCELED),
+ errmsg(msg)));
+
+ AbortTransactionAndAnySubtransactions();
+
+ set_ps_display("idle in transaction (aborted)", false);
+ pgstat_report_activity("<IDLE> in transaction (aborted)");
}
! /* If we get here, do nothing (probably, CancelQueryPending was reset) */
}
***************
*** 3507,3518 ****
HOLD_INTERRUPTS();
/*
! * Forget any pending QueryCancel request, since we're returning to
* the idle loop anyway, and cancel the statement timer if running.
*/
! QueryCancelPending = false;
disable_sig_alarm(true);
! QueryCancelPending = false; /* again in case timeout occurred */
/*
* Turn off these interrupts too. This is only needed here and not in
--- 3506,3518 ----
HOLD_INTERRUPTS();
/*
! * Forget any pending CancelQuery request, since we're returning to
* the idle loop anyway, and cancel the statement timer if running.
*/
! ZeroInterruptEventPending();
disable_sig_alarm(true);
! /* again in case timeout occurred */
! ZeroInterruptEventPending();
/*
* Turn off these interrupts too. This is only needed here and not in
***************
*** 3603,3609 ****
*/
if (send_ready_for_query)
{
! if (IsTransactionOrTransactionBlock())
{
set_ps_display("idle in transaction", false);
pgstat_report_activity("<IDLE> in transaction");
--- 3603,3614 ----
*/
if (send_ready_for_query)
{
! 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");
***************
*** 3626,3632 ****
* conditional since we don't want, say, reads on behalf of COPY FROM
* STDIN doing the same thing.)
*/
! QueryCancelPending = false; /* forget any earlier CANCEL signal */
DoingCommandRead = true;
/*
--- 3631,3638 ----
* conditional since we don't want, say, reads on behalf of COPY FROM
* STDIN doing the same thing.)
*/
! /* forget any earlier cancel signals */
! ZeroInterruptEventPending();
DoingCommandRead = true;
/*
diff -cr cvs/src/backend/utils/adt/misc.c cvs.build/src/backend/utils/adt/misc.c
*** cvs/src/backend/utils/adt/misc.c 2009-12-09 11:24:45.000000000 +0100
--- cvs.build/src/backend/utils/adt/misc.c 2010-01-07 12:38:52.000000000 +0100
***************
*** 30,35 ****
--- 30,36 ----
#include "storage/fd.h"
#include "storage/pmsignal.h"
#include "storage/procarray.h"
+ #include "storage/procsignal.h"
#include "utils/builtins.h"
#include "tcop/tcopprot.h"
***************
*** 117,122 ****
--- 118,132 ----
}
Datum
+ pg_cancel_idle_transaction(PG_FUNCTION_ARGS)
+ {
+ int ret;
+ pid_t pid = PG_GETARG_INT32(0);
+ ret = SendProcSignal(pid, PROCSIG_CANCEL_IDLE_TRANSACTION, InvalidBackendId);
+ PG_RETURN_BOOL(ret == 0);
+ }
+
+ Datum
pg_reload_conf(PG_FUNCTION_ARGS)
{
if (!superuser())
diff -cr cvs/src/backend/utils/init/globals.c cvs.build/src/backend/utils/init/globals.c
*** cvs/src/backend/utils/init/globals.c 2009-12-09 11:24:42.000000000 +0100
--- cvs.build/src/backend/utils/init/globals.c 2010-01-03 20:58:09.000000000 +0100
***************
*** 25,33 ****
ProtocolVersion FrontendProtocol;
! volatile bool InterruptPending = false;
! volatile bool QueryCancelPending = false;
! volatile bool ProcDiePending = false;
volatile bool ImmediateInterruptOK = false;
volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 CritSectionCount = 0;
--- 25,31 ----
ProtocolVersion FrontendProtocol;
! volatile int InterruptPendingEvent = NothingPending;
volatile bool ImmediateInterruptOK = false;
volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 CritSectionCount = 0;
diff -cr cvs/src/include/access/xact.h cvs.build/src/include/access/xact.h
*** cvs/src/include/access/xact.h 2009-12-24 13:55:28.000000000 +0100
--- cvs.build/src/include/access/xact.h 2010-01-04 08:01:52.000000000 +0100
***************
*** 189,194 ****
--- 189,195 ----
extern void StartTransactionCommand(void);
extern void CommitTransactionCommand(void);
extern void AbortCurrentTransaction(void);
+ extern void AbortTransactionAndAnySubtransactions(void);
extern void BeginTransactionBlock(void);
extern bool EndTransactionBlock(void);
extern bool PrepareTransactionBlock(char *gid);
diff -cr cvs/src/include/catalog/pg_proc.h cvs.build/src/include/catalog/pg_proc.h
*** cvs/src/include/catalog/pg_proc.h 2009-12-24 13:55:29.000000000 +0100
--- cvs.build/src/include/catalog/pg_proc.h 2010-01-04 07:45:01.000000000 +0100
***************
*** 3268,3273 ****
--- 3268,3275 ----
DATA(insert OID = 2171 ( pg_cancel_backend PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_cancel_backend _null_ _null_ _null_ ));
DESCR("cancel a server process' current query");
+ DATA(insert OID = 2179 ( pg_cancel_idle_transaction PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_cancel_idle_transaction _null_ _null_ _null_ ));
+ DESCR("cancel a server process' idle transaction");
DATA(insert OID = 2096 ( pg_terminate_backend PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_terminate_backend _null_ _null_ _null_ ));
DESCR("terminate a server process");
DATA(insert OID = 2172 ( pg_start_backup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 16" _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ ));
diff -cr cvs/src/include/miscadmin.h cvs.build/src/include/miscadmin.h
*** cvs/src/include/miscadmin.h 2009-12-24 13:55:28.000000000 +0100
--- cvs.build/src/include/miscadmin.h 2010-01-06 21:13:35.000000000 +0100
***************
*** 64,74 ****
*
*****************************************************************************/
/* in globals.c */
! /* these are marked volatile because they are set by signal handlers: */
! extern PGDLLIMPORT volatile bool InterruptPending;
! extern volatile bool QueryCancelPending;
! extern volatile bool ProcDiePending;
/* these are marked volatile because they are examined by signal handlers: */
extern volatile bool ImmediateInterruptOK;
--- 64,85 ----
*
*****************************************************************************/
+ #define NothingPending 0
+ #define CancelQueryPending 1
+ #define CancelIdleTransactionPending 2
+ #define CancelQueryOrTransactionPending 4
+ #define CancelSessionPending 8
+ #define ConflictErrorPending 16
+ #define ConflictFatalPending 32
+
+ #define IsInterruptEventPending (InterruptPendingEvent != NothingPending)
+ #define SetInterruptEventPending(ev) (InterruptPendingEvent |= ev)
+ #define ClearInterruptEventPending(ev) (InterruptPendingEvent &= ~ev)
+ #define ZeroInterruptEventPending() (InterruptPendingEvent = NothingPending)
+
/* in globals.c */
! /* this is marked volatile because it is set by signal handlers: */
! extern PGDLLIMPORT volatile int InterruptPendingEvent;
/* these are marked volatile because they are examined by signal handlers: */
extern volatile bool ImmediateInterruptOK;
***************
*** 82,88 ****
#define CHECK_FOR_INTERRUPTS() \
do { \
! if (InterruptPending) \
ProcessInterrupts(); \
} while(0)
#else /* WIN32 */
--- 93,99 ----
#define CHECK_FOR_INTERRUPTS() \
do { \
! if (IsInterruptEventPending) \
ProcessInterrupts(); \
} while(0)
#else /* WIN32 */
***************
*** 91,97 ****
do { \
if (UNBLOCKED_SIGNAL_QUEUE()) \
pgwin32_dispatch_queued_signals(); \
! if (InterruptPending) \
ProcessInterrupts(); \
} while(0)
#endif /* WIN32 */
--- 102,108 ----
do { \
if (UNBLOCKED_SIGNAL_QUEUE()) \
pgwin32_dispatch_queued_signals(); \
! if (IsInterruptEventPending) \
ProcessInterrupts(); \
} while(0)
#endif /* WIN32 */
diff -cr cvs/src/include/storage/procarray.h cvs.build/src/include/storage/procarray.h
*** cvs/src/include/storage/procarray.h 2009-12-24 13:55:33.000000000 +0100
--- cvs.build/src/include/storage/procarray.h 2010-01-06 19:36:15.000000000 +0100
***************
*** 15,20 ****
--- 15,21 ----
#define PROCARRAY_H
#include "storage/lock.h"
+ #include "storage/procsignal.h"
#include "storage/standby.h"
#include "utils/snapshot.h"
***************
*** 59,65 ****
extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin,
Oid dbOid, bool skipExistingConflicts);
extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid,
! int cancel_mode);
extern int CountActiveBackends(void);
extern int CountDBBackends(Oid databaseid);
--- 60,66 ----
extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin,
Oid dbOid, bool skipExistingConflicts);
extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid,
! ProcSignalReason sigmode);
extern int CountActiveBackends(void);
extern int CountDBBackends(Oid databaseid);
diff -cr cvs/src/include/storage/procsignal.h cvs.build/src/include/storage/procsignal.h
*** cvs/src/include/storage/procsignal.h 2009-12-09 11:24:53.000000000 +0100
--- cvs.build/src/include/storage/procsignal.h 2010-01-07 00:34:26.000000000 +0100
***************
*** 32,40 ****
--- 32,51 ----
PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */
PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */
+ IDX_PROCSIG_HARMLESS, /* not a real identifier but an index.
+ * we treat harmless signals different than
+ * harmful ones. */
+
+ PROCSIG_CANCEL_IDLE_TRANSACTION, /* pg_backend_cancel_idle_transaction() */
+
+ PROCSIG_CONFLICT_ERROR_INTERRUPT, /* used by HotStandby for conflict */
+ PROCSIG_CONFLICT_FATAL_INTERRUPT, /* resolution. */
+
NUM_PROCSIGNALS /* Must be last! */
} ProcSignalReason;
+ #define IsHarmlessSignal(reason) (reason < IDX_PROCSIG_HARMLESS)
+
/*
* prototypes for functions in procsignal.c
*/
diff -cr cvs/src/include/tcop/tcopprot.h cvs.build/src/include/tcop/tcopprot.h
*** cvs/src/include/tcop/tcopprot.h 2009-12-09 11:24:53.000000000 +0100
--- cvs.build/src/include/tcop/tcopprot.h 2010-01-07 00:22:38.000000000 +0100
***************
*** 64,69 ****
--- 64,74 ----
extern void quickdie(SIGNAL_ARGS);
extern void StatementCancelHandler(SIGNAL_ARGS);
extern void FloatExceptionHandler(SIGNAL_ARGS);
+
+ extern void HandleCancelAction(bool cancelQuery,
+ bool cancelIdleTransaction,
+ bool cancelSession);
+
extern void prepare_for_client_read(void);
extern void client_read_ended(void);
extern const char *process_postgres_switches(int argc, char *argv[],
diff -cr cvs/src/include/utils/builtins.h cvs.build/src/include/utils/builtins.h
*** cvs/src/include/utils/builtins.h 2009-12-24 13:55:33.000000000 +0100
--- cvs.build/src/include/utils/builtins.h 2010-01-06 21:52:12.000000000 +0100
***************
*** 443,448 ****
--- 443,449 ----
extern Datum current_database(PG_FUNCTION_ARGS);
extern Datum current_query(PG_FUNCTION_ARGS);
extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
+ extern Datum pg_cancel_idle_transaction(PG_FUNCTION_ARGS);
extern Datum pg_terminate_backend(PG_FUNCTION_ARGS);
extern Datum pg_reload_conf(PG_FUNCTION_ARGS);
extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);