SAVEPOINTs and COMMIT performance
As part of a performance investigation for a customer I've noticed an
O(N^2) performance issue on COMMITs of transactions that contain many
SAVEPOINTs. I've consistently measured COMMIT times of around 9 seconds,
with 49% CPU, mostly in LockReassignCurrentOwner().
BEGIN;
INSERT...
SAVEPOINT ...
INSERT...
SAVEPOINT ...
... (repeat 10,000 times)
COMMIT;
The way SAVEPOINTs work is that each is nested within the previous one,
so that at COMMIT time we must recursively commit all the
subtransactions before we issue final commit.
That's a shame because ResourceOwnerReleaseInternal() contains an
optimisation to speed up final commit, by calling ProcReleaseLocks().
What we actually do is recursively call LockReassignCurrentOwner() which
sequentially scans LockMethodLocalHash at each level of transaction. The
comments refer to this as "retail" rather than the wholesale method,
which never gets to execute anything worthwhile in this case.
This issue does NOT occur in PLpgSQL functions that contain many
EXCEPTION clauses in a loop, since in that case the subtransactions are
started and committed from the top level so that the subxact nesting
never goes too deep.
Fix looks like we need special handling for the depth-first case, rather
than just a recursion loop in CommitTransactionCommand().
Issues looks like it goes all the way back, no fix for 9.0.
I notice also that the nesting model of SAVEPOINTs also means that
read-only subtransactions will still generate an xid when followed by a
DML statement. That's unnecessary, but required given current design.
--
Simon Riggs www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Training and Services
Did this ever get addressed?
---------------------------------------------------------------------------
Simon Riggs wrote:
As part of a performance investigation for a customer I've noticed an
O(N^2) performance issue on COMMITs of transactions that contain many
SAVEPOINTs. I've consistently measured COMMIT times of around 9 seconds,
with 49% CPU, mostly in LockReassignCurrentOwner().BEGIN;
INSERT...
SAVEPOINT ...
INSERT...
SAVEPOINT ...
... (repeat 10,000 times)
COMMIT;The way SAVEPOINTs work is that each is nested within the previous one,
so that at COMMIT time we must recursively commit all the
subtransactions before we issue final commit.That's a shame because ResourceOwnerReleaseInternal() contains an
optimisation to speed up final commit, by calling ProcReleaseLocks().What we actually do is recursively call LockReassignCurrentOwner() which
sequentially scans LockMethodLocalHash at each level of transaction. The
comments refer to this as "retail" rather than the wholesale method,
which never gets to execute anything worthwhile in this case.This issue does NOT occur in PLpgSQL functions that contain many
EXCEPTION clauses in a loop, since in that case the subtransactions are
started and committed from the top level so that the subxact nesting
never goes too deep.Fix looks like we need special handling for the depth-first case, rather
than just a recursion loop in CommitTransactionCommand().Issues looks like it goes all the way back, no fix for 9.0.
I notice also that the nesting model of SAVEPOINTs also means that
read-only subtransactions will still generate an xid when followed by a
DML statement. That's unnecessary, but required given current design.--
Simon Riggs www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Training and Services--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
On Sun, 2011-02-06 at 12:11 -0500, Bruce Momjian wrote:
Did this ever get addressed?
Patch attached.
Seems like the easiest fix I can come up with.
Simon Riggs wrote:
As part of a performance investigation for a customer I've noticed an
O(N^2) performance issue on COMMITs of transactions that contain many
SAVEPOINTs. I've consistently measured COMMIT times of around 9 seconds,
with 49% CPU, mostly in LockReassignCurrentOwner().BEGIN;
INSERT...
SAVEPOINT ...
INSERT...
SAVEPOINT ...
... (repeat 10,000 times)
COMMIT;The way SAVEPOINTs work is that each is nested within the previous one,
so that at COMMIT time we must recursively commit all the
subtransactions before we issue final commit.That's a shame because ResourceOwnerReleaseInternal() contains an
optimisation to speed up final commit, by calling ProcReleaseLocks().What we actually do is recursively call LockReassignCurrentOwner() which
sequentially scans LockMethodLocalHash at each level of transaction. The
comments refer to this as "retail" rather than the wholesale method,
which never gets to execute anything worthwhile in this case.This issue does NOT occur in PLpgSQL functions that contain many
EXCEPTION clauses in a loop, since in that case the subtransactions are
started and committed from the top level so that the subxact nesting
never goes too deep.Fix looks like we need special handling for the depth-first case, rather
than just a recursion loop in CommitTransactionCommand().Issues looks like it goes all the way back, no fix for 9.0.
I notice also that the nesting model of SAVEPOINTs also means that
read-only subtransactions will still generate an xid when followed by a
DML statement. That's unnecessary, but required given current design.--
Simon Riggs www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Training and Services--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Simon Riggs http://www.2ndQuadrant.com/books/
PostgreSQL Development, 24x7 Support, Training and Services
Attachments:
savepoint_commit_performance.v1.patchtext/x-patch; charset=UTF-8; name=savepoint_commit_performance.v1.patchDownload
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 18e9ce1..07c84b4 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -269,7 +269,7 @@ static TransactionId RecordTransactionAbort(bool isSubXact);
static void StartTransaction(void);
static void StartSubTransaction(void);
-static void CommitSubTransaction(void);
+static void CommitSubTransaction(bool isTopLevel);
static void AbortSubTransaction(void);
static void CleanupSubTransaction(void);
static void PushTransaction(void);
@@ -2518,7 +2518,7 @@ CommitTransactionCommand(void)
case TBLOCK_SUBEND:
do
{
- CommitSubTransaction();
+ CommitSubTransaction(true);
s = CurrentTransactionState; /* changed by pop */
} while (s->blockState == TBLOCK_SUBEND);
/* If we had a COMMIT command, finish off the main xact too */
@@ -3664,7 +3664,7 @@ ReleaseCurrentSubTransaction(void)
BlockStateAsString(s->blockState));
Assert(s->state == TRANS_INPROGRESS);
MemoryContextSwitchTo(CurTransactionContext);
- CommitSubTransaction();
+ CommitSubTransaction(false);
s = CurrentTransactionState; /* changed by pop */
Assert(s->state == TRANS_INPROGRESS);
}
@@ -3925,9 +3925,13 @@ StartSubTransaction(void)
*
* The caller has to make sure to always reassign CurrentTransactionState
* if it has a local pointer to it after calling this function.
+ *
+ * isTopLevel means that this CommitSubTransaction() is being issued as a
+ * sequence of actions leading directly to a main transaction commit
+ * allowing some actions to be optimised.
*/
static void
-CommitSubTransaction(void)
+CommitSubTransaction(bool isTopLevel)
{
TransactionState s = CurrentTransactionState;
@@ -3974,15 +3978,21 @@ CommitSubTransaction(void)
/*
* The only lock we actually release here is the subtransaction XID lock.
- * The rest just get transferred to the parent resource owner.
*/
CurrentResourceOwner = s->curTransactionOwner;
if (TransactionIdIsValid(s->transactionId))
XactLockTableDelete(s->transactionId);
+ /*
+ * Other locks should get transferred to their parent resource owner.
+ * Doing that is an O(N^2) operation, so if isTopLevel then we can just
+ * leave the lock records as they are, knowing they will all get released
+ * by the top level commit using ProcReleaseLocks(). We only optimize
+ * this for commit; aborts may need to do other cleanup.
+ */
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_LOCKS,
- true, false);
+ true, isTopLevel);
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_AFTER_LOCKS,
true, false);
What happened to this patch?
---------------------------------------------------------------------------
Simon Riggs wrote:
On Sun, 2011-02-06 at 12:11 -0500, Bruce Momjian wrote:
Did this ever get addressed?
Patch attached.
Seems like the easiest fix I can come up with.
Simon Riggs wrote:
As part of a performance investigation for a customer I've noticed an
O(N^2) performance issue on COMMITs of transactions that contain many
SAVEPOINTs. I've consistently measured COMMIT times of around 9 seconds,
with 49% CPU, mostly in LockReassignCurrentOwner().BEGIN;
INSERT...
SAVEPOINT ...
INSERT...
SAVEPOINT ...
... (repeat 10,000 times)
COMMIT;The way SAVEPOINTs work is that each is nested within the previous one,
so that at COMMIT time we must recursively commit all the
subtransactions before we issue final commit.That's a shame because ResourceOwnerReleaseInternal() contains an
optimisation to speed up final commit, by calling ProcReleaseLocks().What we actually do is recursively call LockReassignCurrentOwner() which
sequentially scans LockMethodLocalHash at each level of transaction. The
comments refer to this as "retail" rather than the wholesale method,
which never gets to execute anything worthwhile in this case.This issue does NOT occur in PLpgSQL functions that contain many
EXCEPTION clauses in a loop, since in that case the subtransactions are
started and committed from the top level so that the subxact nesting
never goes too deep.Fix looks like we need special handling for the depth-first case, rather
than just a recursion loop in CommitTransactionCommand().Issues looks like it goes all the way back, no fix for 9.0.
I notice also that the nesting model of SAVEPOINTs also means that
read-only subtransactions will still generate an xid when followed by a
DML statement. That's unnecessary, but required given current design.--
Simon Riggs www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Training and Services--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers--
Simon Riggs http://www.2ndQuadrant.com/books/
PostgreSQL Development, 24x7 Support, Training and Services
[ Attachment, skipping... ]
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
On Fri, Mar 11, 2011 at 7:18 AM, Bruce Momjian <bruce@momjian.us> wrote:
What happened to this patch?
I added it to the next CommitFest. It would be reasonably to apply it
sooner, perhaps, but nobody's reviewed it. Want to volunteer?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On 06.02.2011 23:09, Simon Riggs wrote:
On Sun, 2011-02-06 at 12:11 -0500, Bruce Momjian wrote:
Did this ever get addressed?
Patch attached.
Seems like the easiest fix I can come up with.
@@ -2518,7 +2518,7 @@ CommitTransactionCommand(void)
case TBLOCK_SUBEND:
do
{
- CommitSubTransaction();
+ CommitSubTransaction(true);
s = CurrentTransactionState; /* changed by pop */
} while (s->blockState == TBLOCK_SUBEND);
/* If we had a COMMIT command, finish off the main xact too */
We also get into this codepath at RELEASE SAVEPOINT, in which case it is
wrong to not reassign the locks to the parent subtransaction.
--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com
On Mon, Jun 6, 2011 at 10:33 AM, Heikki Linnakangas
<heikki.linnakangas@enterprisedb.com> wrote:
On 06.02.2011 23:09, Simon Riggs wrote:
On Sun, 2011-02-06 at 12:11 -0500, Bruce Momjian wrote:
Did this ever get addressed?
Patch attached.
Seems like the easiest fix I can come up with.
@@ -2518,7 +2518,7 @@ CommitTransactionCommand(void) case TBLOCK_SUBEND: do { - CommitSubTransaction(); + CommitSubTransaction(true); s = CurrentTransactionState; /* changed by pop */ } while (s->blockState == TBLOCK_SUBEND); /* If we had a COMMIT command, finish off the main xact too */We also get into this codepath at RELEASE SAVEPOINT, in which case it is
wrong to not reassign the locks to the parent subtransaction.
Agreed.
Thanks for the review.
I'll change that.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
On Mon, Jun 6, 2011 at 10:33 AM, Heikki Linnakangas
<heikki.linnakangas@enterprisedb.com> wrote:
On 06.02.2011 23:09, Simon Riggs wrote:
On Sun, 2011-02-06 at 12:11 -0500, Bruce Momjian wrote:
Did this ever get addressed?
Patch attached.
Seems like the easiest fix I can come up with.
@@ -2518,7 +2518,7 @@ CommitTransactionCommand(void) case TBLOCK_SUBEND: do { - CommitSubTransaction(); + CommitSubTransaction(true); s = CurrentTransactionState; /* changed by pop */ } while (s->blockState == TBLOCK_SUBEND); /* If we had a COMMIT command, finish off the main xact too */We also get into this codepath at RELEASE SAVEPOINT, in which case it is
wrong to not reassign the locks to the parent subtransaction.
Attached patch splits TBLOCK_SUBEND state into two new states:
TBLOCK_SUBCOMMIT and TBLOCK_SUBRELEASE, so that we can do the right
thing.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Attachments:
savepoint_commit_performance.v2.patchapplication/octet-stream; name=savepoint_commit_performance.v2.patchDownload
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 7f01a83..e8821f7 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -118,7 +118,8 @@ typedef enum TBlockState
/* subtransaction states */
TBLOCK_SUBBEGIN, /* starting a subtransaction */
TBLOCK_SUBINPROGRESS, /* live subtransaction */
- TBLOCK_SUBEND, /* RELEASE received */
+ TBLOCK_SUBRELEASE, /* RELEASE received */
+ TBLOCK_SUBCOMMIT, /* COMMIT received while TBLOCK_SUBINPROGRESS */
TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK */
TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received */
TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */
@@ -272,7 +273,7 @@ static TransactionId RecordTransactionAbort(bool isSubXact);
static void StartTransaction(void);
static void StartSubTransaction(void);
-static void CommitSubTransaction(void);
+static void CommitSubTransaction(bool isTopLevel);
static void AbortSubTransaction(void);
static void CleanupSubTransaction(void);
static void PushTransaction(void);
@@ -2442,7 +2443,8 @@ StartTransactionCommand(void)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT_END:
case TBLOCK_SUBABORT_END:
case TBLOCK_ABORT_PENDING:
@@ -2572,17 +2574,32 @@ CommitTransactionCommand(void)
break;
/*
- * We were issued a COMMIT or RELEASE command, so we end the
+ * We were issued a RELEASE command, so we end the
* current subtransaction and return to the parent transaction.
- * The parent might be ended too, so repeat till we are all the
- * way out or find an INPROGRESS transaction.
+ * The parent might be ended too, so repeat till we find an
+ * INPROGRESS transaction or subtransaction.
*/
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
do
{
- CommitSubTransaction();
+ CommitSubTransaction(false);
s = CurrentTransactionState; /* changed by pop */
- } while (s->blockState == TBLOCK_SUBEND);
+ } while (s->blockState == TBLOCK_SUBRELEASE);
+
+ Assert(s->blockState == TBLOCK_INPROGRESS ||
+ s->blockState == TBLOCK_SUBINPROGRESS);
+ break;
+
+ /*
+ * We were issued a COMMIT, so we end the current subtransaction
+ * hierarchy and perform final commit.
+ */
+ case TBLOCK_SUBCOMMIT:
+ do
+ {
+ CommitSubTransaction(true);
+ s = CurrentTransactionState; /* changed by pop */
+ } while (s->blockState == TBLOCK_SUBCOMMIT);
/* If we had a COMMIT command, finish off the main xact too */
if (s->blockState == TBLOCK_END)
{
@@ -2597,10 +2614,8 @@ CommitTransactionCommand(void)
s->blockState = TBLOCK_DEFAULT;
}
else
- {
- Assert(s->blockState == TBLOCK_INPROGRESS ||
- s->blockState == TBLOCK_SUBINPROGRESS);
- }
+ elog(ERROR, "CommitTransactionCommand: unexpected state %s",
+ BlockStateAsString(s->blockState));
break;
/*
@@ -2814,7 +2829,8 @@ AbortCurrentTransaction(void)
* applies if we get a failure while ending a subtransaction.
*/
case TBLOCK_SUBBEGIN:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_SUBABORT_PENDING:
case TBLOCK_SUBRESTART:
AbortSubTransaction();
@@ -3122,7 +3138,8 @@ BeginTransactionBlock(void)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT_END:
case TBLOCK_SUBABORT_END:
case TBLOCK_ABORT_PENDING:
@@ -3232,7 +3249,7 @@ EndTransactionBlock(void)
while (s->parent != NULL)
{
if (s->blockState == TBLOCK_SUBINPROGRESS)
- s->blockState = TBLOCK_SUBEND;
+ s->blockState = TBLOCK_SUBCOMMIT;
else
elog(FATAL, "EndTransactionBlock: unexpected state %s",
BlockStateAsString(s->blockState));
@@ -3290,7 +3307,8 @@ EndTransactionBlock(void)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT_END:
case TBLOCK_SUBABORT_END:
case TBLOCK_ABORT_PENDING:
@@ -3382,7 +3400,8 @@ UserAbortTransactionBlock(void)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT_END:
case TBLOCK_SUBABORT_END:
case TBLOCK_ABORT_PENDING:
@@ -3427,7 +3446,8 @@ DefineSavepoint(char *name)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT:
case TBLOCK_SUBABORT:
case TBLOCK_ABORT_END:
@@ -3483,7 +3503,8 @@ ReleaseSavepoint(List *options)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT:
case TBLOCK_SUBABORT:
case TBLOCK_ABORT_END:
@@ -3534,7 +3555,7 @@ ReleaseSavepoint(List *options)
for (;;)
{
Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
- xact->blockState = TBLOCK_SUBEND;
+ xact->blockState = TBLOCK_SUBRELEASE;
if (xact == target)
break;
xact = xact->parent;
@@ -3583,7 +3604,8 @@ RollbackToSavepoint(List *options)
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT_END:
case TBLOCK_SUBABORT_END:
case TBLOCK_ABORT_PENDING:
@@ -3691,7 +3713,8 @@ BeginInternalSubTransaction(char *name)
case TBLOCK_DEFAULT:
case TBLOCK_BEGIN:
case TBLOCK_SUBBEGIN:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT:
case TBLOCK_SUBABORT:
case TBLOCK_ABORT_END:
@@ -3726,7 +3749,7 @@ ReleaseCurrentSubTransaction(void)
BlockStateAsString(s->blockState));
Assert(s->state == TRANS_INPROGRESS);
MemoryContextSwitchTo(CurTransactionContext);
- CommitSubTransaction();
+ CommitSubTransaction(false);
s = CurrentTransactionState; /* changed by pop */
Assert(s->state == TRANS_INPROGRESS);
}
@@ -3757,7 +3780,8 @@ RollbackAndReleaseCurrentSubTransaction(void)
case TBLOCK_SUBBEGIN:
case TBLOCK_INPROGRESS:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_ABORT:
case TBLOCK_ABORT_END:
case TBLOCK_SUBABORT_END:
@@ -3831,7 +3855,8 @@ AbortOutOfAnyTransaction(void)
*/
case TBLOCK_SUBBEGIN:
case TBLOCK_SUBINPROGRESS:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_SUBABORT_PENDING:
case TBLOCK_SUBRESTART:
AbortSubTransaction();
@@ -3903,7 +3928,8 @@ TransactionBlockStatusCode(void)
case TBLOCK_INPROGRESS:
case TBLOCK_SUBINPROGRESS:
case TBLOCK_END:
- case TBLOCK_SUBEND:
+ case TBLOCK_SUBRELEASE:
+ case TBLOCK_SUBCOMMIT:
case TBLOCK_PREPARE:
return 'T'; /* in transaction */
case TBLOCK_ABORT:
@@ -3987,9 +4013,13 @@ StartSubTransaction(void)
*
* The caller has to make sure to always reassign CurrentTransactionState
* if it has a local pointer to it after calling this function.
+ *
+ * isTopLevel means that this CommitSubTransaction() is being issued as a
+ * sequence of actions leading directly to a main transaction commit
+ * allowing some actions to be optimised.
*/
static void
-CommitSubTransaction(void)
+CommitSubTransaction(bool isTopLevel)
{
TransactionState s = CurrentTransactionState;
@@ -4036,15 +4066,21 @@ CommitSubTransaction(void)
/*
* The only lock we actually release here is the subtransaction XID lock.
- * The rest just get transferred to the parent resource owner.
*/
CurrentResourceOwner = s->curTransactionOwner;
if (TransactionIdIsValid(s->transactionId))
XactLockTableDelete(s->transactionId);
+ /*
+ * Other locks should get transferred to their parent resource owner.
+ * Doing that is an O(N^2) operation, so if isTopLevel then we can just
+ * leave the lock records as they are, knowing they will all get released
+ * by the top level commit using ProcReleaseLocks(). We only optimize
+ * this for commit; aborts may need to do other cleanup.
+ */
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_LOCKS,
- true, false);
+ true, isTopLevel);
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_AFTER_LOCKS,
true, false);
@@ -4398,8 +4434,10 @@ BlockStateAsString(TBlockState blockState)
return "SUB BEGIN";
case TBLOCK_SUBINPROGRESS:
return "SUB INPROGRS";
- case TBLOCK_SUBEND:
- return "SUB END";
+ case TBLOCK_SUBRELEASE:
+ return "SUB RELEASE";
+ case TBLOCK_SUBCOMMIT:
+ return "SUB COMMIT";
case TBLOCK_SUBABORT:
return "SUB ABORT";
case TBLOCK_SUBABORT_END: