@@ -118,7 +118,8 @@ typedef enum TBlockState
118118/* subtransaction states */
119119TBLOCK_SUBBEGIN ,/* starting a subtransaction */
120120TBLOCK_SUBINPROGRESS ,/* live subtransaction */
121- TBLOCK_SUBEND ,/* RELEASE received */
121+ TBLOCK_SUBRELEASE ,/* RELEASE received */
122+ TBLOCK_SUBCOMMIT ,/* COMMIT received while TBLOCK_SUBINPROGRESS */
122123TBLOCK_SUBABORT ,/* failed subxact, awaiting ROLLBACK */
123124TBLOCK_SUBABORT_END ,/* failed subxact, ROLLBACK received */
124125TBLOCK_SUBABORT_PENDING ,/* live subxact, ROLLBACK received */
@@ -272,7 +273,7 @@ static TransactionId RecordTransactionAbort(bool isSubXact);
272273static void StartTransaction (void );
273274
274275static void StartSubTransaction (void );
275- static void CommitSubTransaction (void );
276+ static void CommitSubTransaction (bool isTopLevel );
276277static void AbortSubTransaction (void );
277278static void CleanupSubTransaction (void );
278279static void PushTransaction (void );
@@ -2442,7 +2443,8 @@ StartTransactionCommand(void)
24422443case TBLOCK_BEGIN :
24432444case TBLOCK_SUBBEGIN :
24442445case TBLOCK_END :
2445- case TBLOCK_SUBEND :
2446+ case TBLOCK_SUBRELEASE :
2447+ case TBLOCK_SUBCOMMIT :
24462448case TBLOCK_ABORT_END :
24472449case TBLOCK_SUBABORT_END :
24482450case TBLOCK_ABORT_PENDING :
@@ -2572,17 +2574,32 @@ CommitTransactionCommand(void)
25722574break ;
25732575
25742576/*
2575- * We were issued aCOMMIT or RELEASE command, so we end the
2577+ * We were issued a RELEASE command, so we end the
25762578 * current subtransaction and return to the parent transaction.
2577- * The parent might be ended too, so repeat till weare all the
2578- *way out orfind an INPROGRESS transaction .
2579+ * The parent might be ended too, so repeat till wefind an
2580+ *INPROGRESS transaction orsubtransaction .
25792581 */
2580- case TBLOCK_SUBEND :
2582+ case TBLOCK_SUBRELEASE :
25812583do
25822584{
2583- CommitSubTransaction ();
2585+ CommitSubTransaction (false );
25842586s = CurrentTransactionState ;/* changed by pop */
2585- }while (s -> blockState == TBLOCK_SUBEND );
2587+ }while (s -> blockState == TBLOCK_SUBRELEASE );
2588+
2589+ Assert (s -> blockState == TBLOCK_INPROGRESS ||
2590+ s -> blockState == TBLOCK_SUBINPROGRESS );
2591+ break ;
2592+
2593+ /*
2594+ * We were issued a COMMIT, so we end the current subtransaction
2595+ * hierarchy and perform final commit.
2596+ */
2597+ case TBLOCK_SUBCOMMIT :
2598+ do
2599+ {
2600+ CommitSubTransaction (true);
2601+ s = CurrentTransactionState ;/* changed by pop */
2602+ }while (s -> blockState == TBLOCK_SUBCOMMIT );
25862603/* If we had a COMMIT command, finish off the main xact too */
25872604if (s -> blockState == TBLOCK_END )
25882605{
@@ -2597,10 +2614,8 @@ CommitTransactionCommand(void)
25972614s -> blockState = TBLOCK_DEFAULT ;
25982615}
25992616else
2600- {
2601- Assert (s -> blockState == TBLOCK_INPROGRESS ||
2602- s -> blockState == TBLOCK_SUBINPROGRESS );
2603- }
2617+ elog (ERROR ,"CommitTransactionCommand: unexpected state %s" ,
2618+ BlockStateAsString (s -> blockState ));
26042619break ;
26052620
26062621/*
@@ -2814,7 +2829,8 @@ AbortCurrentTransaction(void)
28142829 * applies if we get a failure while ending a subtransaction.
28152830 */
28162831case TBLOCK_SUBBEGIN :
2817- case TBLOCK_SUBEND :
2832+ case TBLOCK_SUBRELEASE :
2833+ case TBLOCK_SUBCOMMIT :
28182834case TBLOCK_SUBABORT_PENDING :
28192835case TBLOCK_SUBRESTART :
28202836AbortSubTransaction ();
@@ -3122,7 +3138,8 @@ BeginTransactionBlock(void)
31223138case TBLOCK_BEGIN :
31233139case TBLOCK_SUBBEGIN :
31243140case TBLOCK_END :
3125- case TBLOCK_SUBEND :
3141+ case TBLOCK_SUBRELEASE :
3142+ case TBLOCK_SUBCOMMIT :
31263143case TBLOCK_ABORT_END :
31273144case TBLOCK_SUBABORT_END :
31283145case TBLOCK_ABORT_PENDING :
@@ -3232,7 +3249,7 @@ EndTransactionBlock(void)
32323249while (s -> parent != NULL )
32333250{
32343251if (s -> blockState == TBLOCK_SUBINPROGRESS )
3235- s -> blockState = TBLOCK_SUBEND ;
3252+ s -> blockState = TBLOCK_SUBCOMMIT ;
32363253else
32373254elog (FATAL ,"EndTransactionBlock: unexpected state %s" ,
32383255BlockStateAsString (s -> blockState ));
@@ -3290,7 +3307,8 @@ EndTransactionBlock(void)
32903307case TBLOCK_BEGIN :
32913308case TBLOCK_SUBBEGIN :
32923309case TBLOCK_END :
3293- case TBLOCK_SUBEND :
3310+ case TBLOCK_SUBRELEASE :
3311+ case TBLOCK_SUBCOMMIT :
32943312case TBLOCK_ABORT_END :
32953313case TBLOCK_SUBABORT_END :
32963314case TBLOCK_ABORT_PENDING :
@@ -3382,7 +3400,8 @@ UserAbortTransactionBlock(void)
33823400case TBLOCK_BEGIN :
33833401case TBLOCK_SUBBEGIN :
33843402case TBLOCK_END :
3385- case TBLOCK_SUBEND :
3403+ case TBLOCK_SUBRELEASE :
3404+ case TBLOCK_SUBCOMMIT :
33863405case TBLOCK_ABORT_END :
33873406case TBLOCK_SUBABORT_END :
33883407case TBLOCK_ABORT_PENDING :
@@ -3427,7 +3446,8 @@ DefineSavepoint(char *name)
34273446case TBLOCK_BEGIN :
34283447case TBLOCK_SUBBEGIN :
34293448case TBLOCK_END :
3430- case TBLOCK_SUBEND :
3449+ case TBLOCK_SUBRELEASE :
3450+ case TBLOCK_SUBCOMMIT :
34313451case TBLOCK_ABORT :
34323452case TBLOCK_SUBABORT :
34333453case TBLOCK_ABORT_END :
@@ -3483,7 +3503,8 @@ ReleaseSavepoint(List *options)
34833503case TBLOCK_BEGIN :
34843504case TBLOCK_SUBBEGIN :
34853505case TBLOCK_END :
3486- case TBLOCK_SUBEND :
3506+ case TBLOCK_SUBRELEASE :
3507+ case TBLOCK_SUBCOMMIT :
34873508case TBLOCK_ABORT :
34883509case TBLOCK_SUBABORT :
34893510case TBLOCK_ABORT_END :
@@ -3534,7 +3555,7 @@ ReleaseSavepoint(List *options)
35343555for (;;)
35353556{
35363557Assert (xact -> blockState == TBLOCK_SUBINPROGRESS );
3537- xact -> blockState = TBLOCK_SUBEND ;
3558+ xact -> blockState = TBLOCK_SUBRELEASE ;
35383559if (xact == target )
35393560break ;
35403561xact = xact -> parent ;
@@ -3583,7 +3604,8 @@ RollbackToSavepoint(List *options)
35833604case TBLOCK_BEGIN :
35843605case TBLOCK_SUBBEGIN :
35853606case TBLOCK_END :
3586- case TBLOCK_SUBEND :
3607+ case TBLOCK_SUBRELEASE :
3608+ case TBLOCK_SUBCOMMIT :
35873609case TBLOCK_ABORT_END :
35883610case TBLOCK_SUBABORT_END :
35893611case TBLOCK_ABORT_PENDING :
@@ -3691,7 +3713,8 @@ BeginInternalSubTransaction(char *name)
36913713case TBLOCK_DEFAULT :
36923714case TBLOCK_BEGIN :
36933715case TBLOCK_SUBBEGIN :
3694- case TBLOCK_SUBEND :
3716+ case TBLOCK_SUBRELEASE :
3717+ case TBLOCK_SUBCOMMIT :
36953718case TBLOCK_ABORT :
36963719case TBLOCK_SUBABORT :
36973720case TBLOCK_ABORT_END :
@@ -3726,7 +3749,7 @@ ReleaseCurrentSubTransaction(void)
37263749BlockStateAsString (s -> blockState ));
37273750Assert (s -> state == TRANS_INPROGRESS );
37283751MemoryContextSwitchTo (CurTransactionContext );
3729- CommitSubTransaction ();
3752+ CommitSubTransaction (false );
37303753s = CurrentTransactionState ;/* changed by pop */
37313754Assert (s -> state == TRANS_INPROGRESS );
37323755}
@@ -3757,7 +3780,8 @@ RollbackAndReleaseCurrentSubTransaction(void)
37573780case TBLOCK_SUBBEGIN :
37583781case TBLOCK_INPROGRESS :
37593782case TBLOCK_END :
3760- case TBLOCK_SUBEND :
3783+ case TBLOCK_SUBRELEASE :
3784+ case TBLOCK_SUBCOMMIT :
37613785case TBLOCK_ABORT :
37623786case TBLOCK_ABORT_END :
37633787case TBLOCK_SUBABORT_END :
@@ -3831,7 +3855,8 @@ AbortOutOfAnyTransaction(void)
38313855 */
38323856case TBLOCK_SUBBEGIN :
38333857case TBLOCK_SUBINPROGRESS :
3834- case TBLOCK_SUBEND :
3858+ case TBLOCK_SUBRELEASE :
3859+ case TBLOCK_SUBCOMMIT :
38353860case TBLOCK_SUBABORT_PENDING :
38363861case TBLOCK_SUBRESTART :
38373862AbortSubTransaction ();
@@ -3903,7 +3928,8 @@ TransactionBlockStatusCode(void)
39033928case TBLOCK_INPROGRESS :
39043929case TBLOCK_SUBINPROGRESS :
39053930case TBLOCK_END :
3906- case TBLOCK_SUBEND :
3931+ case TBLOCK_SUBRELEASE :
3932+ case TBLOCK_SUBCOMMIT :
39073933case TBLOCK_PREPARE :
39083934return 'T' ;/* in transaction */
39093935case TBLOCK_ABORT :
@@ -3987,9 +4013,13 @@ StartSubTransaction(void)
39874013 *
39884014 *The caller has to make sure to always reassign CurrentTransactionState
39894015 *if it has a local pointer to it after calling this function.
4016+ *
4017+ *isTopLevel means that this CommitSubTransaction() is being issued as a
4018+ *sequence of actions leading directly to a main transaction commit
4019+ *allowing some actions to be optimised.
39904020 */
39914021static void
3992- CommitSubTransaction (void )
4022+ CommitSubTransaction (bool isTopLevel )
39934023{
39944024TransactionState s = CurrentTransactionState ;
39954025
@@ -4036,15 +4066,21 @@ CommitSubTransaction(void)
40364066
40374067/*
40384068 * The only lock we actually release here is the subtransaction XID lock.
4039- * The rest just get transferred to the parent resource owner.
40404069 */
40414070CurrentResourceOwner = s -> curTransactionOwner ;
40424071if (TransactionIdIsValid (s -> transactionId ))
40434072XactLockTableDelete (s -> transactionId );
40444073
4074+ /*
4075+ * Other locks should get transferred to their parent resource owner.
4076+ * Doing that is an O(N^2) operation, so if isTopLevel then we can just
4077+ * leave the lock records as they are, knowing they will all get released
4078+ * by the top level commit using ProcReleaseLocks(). We only optimize
4079+ * this for commit; aborts may need to do other cleanup.
4080+ */
40454081ResourceOwnerRelease (s -> curTransactionOwner ,
40464082RESOURCE_RELEASE_LOCKS ,
4047- true,false );
4083+ true,isTopLevel );
40484084ResourceOwnerRelease (s -> curTransactionOwner ,
40494085RESOURCE_RELEASE_AFTER_LOCKS ,
40504086 true, false);
@@ -4398,8 +4434,10 @@ BlockStateAsString(TBlockState blockState)
43984434return "SUB BEGIN" ;
43994435case TBLOCK_SUBINPROGRESS :
44004436return "SUB INPROGRS" ;
4401- case TBLOCK_SUBEND :
4402- return "SUB END" ;
4437+ case TBLOCK_SUBRELEASE :
4438+ return "SUB RELEASE" ;
4439+ case TBLOCK_SUBCOMMIT :
4440+ return "SUB COMMIT" ;
44034441case TBLOCK_SUBABORT :
44044442return "SUB ABORT" ;
44054443case TBLOCK_SUBABORT_END :