aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c56
1 files changed, 53 insertions, 3 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f2e892374b0..e8c4820a71e 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.578 2009/12/16 23:05:00 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.579 2009/12/19 01:32:36 sriggs Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -62,6 +62,7 @@
#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"
@@ -2643,8 +2644,8 @@ StatementCancelHandler(SIGNAL_ARGS)
* the interrupt immediately. No point in interrupting if we're
* waiting for input, however.
*/
- if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
- CritSectionCount == 0 && !DoingCommandRead)
+ if (InterruptHoldoffCount == 0 && CritSectionCount == 0 &&
+ (DoingCommandRead || ImmediateInterruptOK))
{
/* bump holdoff count to make ProcessInterrupts() a no-op */
/* until we are done getting ready for it */
@@ -2735,9 +2736,58 @@ ProcessInterrupts(void)
(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) */
}