aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-01-24 21:50:09 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2010-01-24 21:50:09 +0000
commitce95d0f14d2a6374014e852a6a1f20d30a0f69f6 (patch)
treea7f1ef30ce70a74de1b89b3c27b00e7713a19b8e
parent34d7ef60e7ff5d34058822db33953c279818ceb8 (diff)
downloadpostgresql-ce95d0f14d2a6374014e852a6a1f20d30a0f69f6.tar.gz
postgresql-ce95d0f14d2a6374014e852a6a1f20d30a0f69f6.zip
Fix assorted core dumps and Assert failures that could occur during
AbortTransaction or AbortSubTransaction, when trying to clean up after an error that prevented (sub)transaction start from completing: * access to TopTransactionResourceOwner that might not exist * assert failure in AtEOXact_GUC, if AtStart_GUC not called yet * assert failure or core dump in AfterTriggerEndSubXact, if AfterTriggerBeginSubXact not called yet Per testing by injecting elog(ERROR) at successive steps in StartTransaction and StartSubTransaction. It's not clear whether all of these cases could really occur in the field, but at least one of them is easily exposed by simple stress testing, as per my accidental discovery yesterday.
-rw-r--r--src/backend/access/transam/xact.c53
-rw-r--r--src/backend/commands/trigger.c15
-rw-r--r--src/backend/utils/misc/guc.c11
3 files changed, 48 insertions, 31 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b2e32d699fb..d032c411db7 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.195.4.5 2009/12/09 21:58:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.195.4.6 2010/01/24 21:50:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1699,32 +1699,35 @@ AbortTransaction(void)
/*
* Post-abort cleanup. See notes in CommitTransaction() concerning
- * ordering.
+ * ordering. We can skip all of it if the transaction failed before
+ * creating a resource owner.
*/
+ if (TopTransactionResourceOwner != NULL)
+ {
+ CallXactCallbacks(XACT_EVENT_ABORT);
- CallXactCallbacks(XACT_EVENT_ABORT);
-
- ResourceOwnerRelease(TopTransactionResourceOwner,
- RESOURCE_RELEASE_BEFORE_LOCKS,
- false, true);
- AtEOXact_Buffers(false);
- AtEOXact_Inval(false);
- smgrDoPendingDeletes(false);
- ResourceOwnerRelease(TopTransactionResourceOwner,
- RESOURCE_RELEASE_LOCKS,
- false, true);
- ResourceOwnerRelease(TopTransactionResourceOwner,
- RESOURCE_RELEASE_AFTER_LOCKS,
- false, true);
-
- AtEOXact_GUC(false, 1);
- AtEOXact_SPI(false);
- AtEOXact_on_commit_actions(false);
- AtEOXact_Namespace(false);
- smgrabort();
- AtEOXact_Files();
- AtEOXact_HashTables(false);
- pgstat_count_xact_rollback();
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ false, true);
+ AtEOXact_Buffers(false);
+ AtEOXact_Inval(false);
+ smgrDoPendingDeletes(false);
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_LOCKS,
+ false, true);
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ false, true);
+
+ AtEOXact_GUC(false, 1);
+ AtEOXact_SPI(false);
+ AtEOXact_on_commit_actions(false);
+ AtEOXact_Namespace(false);
+ smgrabort();
+ AtEOXact_Files();
+ AtEOXact_HashTables(false);
+ pgstat_count_xact_rollback();
+ }
/*
* State remains TRANS_ABORT until CleanupTransaction().
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2d4b356a7f4..84c40637f57 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.177.4.7 2009/10/27 20:15:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.177.4.8 2010/01/24 21:50:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2530,10 +2530,9 @@ AfterTriggerEndSubXact(bool isCommit)
/*
* Pop the prior state if needed.
*/
- Assert(my_level < afterTriggers->maxtransdepth);
-
if (isCommit)
{
+ Assert(my_level < afterTriggers->maxtransdepth);
/* If we saved a prior state, we don't need it anymore */
state = afterTriggers->state_stack[my_level];
if (state != NULL)
@@ -2546,7 +2545,15 @@ AfterTriggerEndSubXact(bool isCommit)
else
{
/*
- * Aborting --- restore the pointers from the stacks.
+ * Aborting. It is possible subxact start failed before calling
+ * AfterTriggerBeginSubXact, in which case we mustn't risk touching
+ * stack levels that aren't there.
+ */
+ if (my_level >= afterTriggers->maxtransdepth)
+ return;
+
+ /*
+ * Restore the pointers from the stacks.
*/
afterTriggers->events = afterTriggers->events_stack[my_level];
afterTriggers->query_depth = afterTriggers->depth_stack[my_level];
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 06b7f54e887..6e4f0bd2a41 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.252.4.7 2009/12/09 21:58:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.252.4.8 2010/01/24 21:50:09 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -2848,7 +2848,14 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
{
int i;
- Assert(nestLevel > 0 && nestLevel <= GUCNestLevel);
+ /*
+ * Note: it's possible to get here with GUCNestLevel == nestLevel-1 during
+ * abort, if there is a failure during transaction start before
+ * AtStart_GUC is called.
+ */
+ Assert(nestLevel > 0 &&
+ (nestLevel <= GUCNestLevel ||
+ (nestLevel == GUCNestLevel + 1 && !isCommit)));
/* Quick exit if nothing's changed in this transaction */
if (!guc_dirty)