@@ -118,7 +118,8 @@ typedef enum TBlockState
118118 /* subtransaction states */
119119 TBLOCK_SUBBEGIN , /* starting a subtransaction */
120120 TBLOCK_SUBINPROGRESS , /* live subtransaction */
121- TBLOCK_SUBEND , /* RELEASE received */
121+ TBLOCK_SUBRELEASE , /* RELEASE received */
122+ TBLOCK_SUBCOMMIT , /* COMMIT received while TBLOCK_SUBINPROGRESS */
122123 TBLOCK_SUBABORT , /* failed subxact, awaiting ROLLBACK */
123124 TBLOCK_SUBABORT_END , /* failed subxact, ROLLBACK received */
124125 TBLOCK_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)
24422443 case TBLOCK_BEGIN :
24432444 case TBLOCK_SUBBEGIN :
24442445 case TBLOCK_END :
2445- case TBLOCK_SUBEND :
2446+ case TBLOCK_SUBRELEASE :
2447+ case TBLOCK_SUBCOMMIT :
24462448 case TBLOCK_ABORT_END :
24472449 case TBLOCK_SUBABORT_END :
24482450 case TBLOCK_ABORT_PENDING :
@@ -2572,17 +2574,32 @@ CommitTransactionCommand(void)
25722574 break ;
25732575
25742576 /*
2575- * We were issued a COMMIT 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 we are all the
2578- * way out or find an INPROGRESS transaction .
2579+ * The parent might be ended too, so repeat till we find an
2580+ * INPROGRESS transaction or subtransaction .
25792581 */
2580- case TBLOCK_SUBEND :
2582+ case TBLOCK_SUBRELEASE :
25812583 do
25822584 {
2583- CommitSubTransaction ();
2585+ CommitSubTransaction (false );
25842586 s = 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 */
25872604 if (s -> blockState == TBLOCK_END )
25882605 {
@@ -2597,10 +2614,8 @@ CommitTransactionCommand(void)
25972614 s -> blockState = TBLOCK_DEFAULT ;
25982615 }
25992616 else
2600- {
2601- Assert (s -> blockState == TBLOCK_INPROGRESS ||
2602- s -> blockState == TBLOCK_SUBINPROGRESS );
2603- }
2617+ elog (ERROR , "CommitTransactionCommand: unexpected state %s" ,
2618+ BlockStateAsString (s -> blockState ));
26042619 break ;
26052620
26062621 /*
@@ -2814,7 +2829,8 @@ AbortCurrentTransaction(void)
28142829 * applies if we get a failure while ending a subtransaction.
28152830 */
28162831 case TBLOCK_SUBBEGIN :
2817- case TBLOCK_SUBEND :
2832+ case TBLOCK_SUBRELEASE :
2833+ case TBLOCK_SUBCOMMIT :
28182834 case TBLOCK_SUBABORT_PENDING :
28192835 case TBLOCK_SUBRESTART :
28202836 AbortSubTransaction ();
@@ -3122,7 +3138,8 @@ BeginTransactionBlock(void)
31223138 case TBLOCK_BEGIN :
31233139 case TBLOCK_SUBBEGIN :
31243140 case TBLOCK_END :
3125- case TBLOCK_SUBEND :
3141+ case TBLOCK_SUBRELEASE :
3142+ case TBLOCK_SUBCOMMIT :
31263143 case TBLOCK_ABORT_END :
31273144 case TBLOCK_SUBABORT_END :
31283145 case TBLOCK_ABORT_PENDING :
@@ -3232,7 +3249,7 @@ EndTransactionBlock(void)
32323249 while (s -> parent != NULL )
32333250 {
32343251 if (s -> blockState == TBLOCK_SUBINPROGRESS )
3235- s -> blockState = TBLOCK_SUBEND ;
3252+ s -> blockState = TBLOCK_SUBCOMMIT ;
32363253 else
32373254 elog (FATAL , "EndTransactionBlock: unexpected state %s" ,
32383255 BlockStateAsString (s -> blockState ));
@@ -3290,7 +3307,8 @@ EndTransactionBlock(void)
32903307 case TBLOCK_BEGIN :
32913308 case TBLOCK_SUBBEGIN :
32923309 case TBLOCK_END :
3293- case TBLOCK_SUBEND :
3310+ case TBLOCK_SUBRELEASE :
3311+ case TBLOCK_SUBCOMMIT :
32943312 case TBLOCK_ABORT_END :
32953313 case TBLOCK_SUBABORT_END :
32963314 case TBLOCK_ABORT_PENDING :
@@ -3382,7 +3400,8 @@ UserAbortTransactionBlock(void)
33823400 case TBLOCK_BEGIN :
33833401 case TBLOCK_SUBBEGIN :
33843402 case TBLOCK_END :
3385- case TBLOCK_SUBEND :
3403+ case TBLOCK_SUBRELEASE :
3404+ case TBLOCK_SUBCOMMIT :
33863405 case TBLOCK_ABORT_END :
33873406 case TBLOCK_SUBABORT_END :
33883407 case TBLOCK_ABORT_PENDING :
@@ -3427,7 +3446,8 @@ DefineSavepoint(char *name)
34273446 case TBLOCK_BEGIN :
34283447 case TBLOCK_SUBBEGIN :
34293448 case TBLOCK_END :
3430- case TBLOCK_SUBEND :
3449+ case TBLOCK_SUBRELEASE :
3450+ case TBLOCK_SUBCOMMIT :
34313451 case TBLOCK_ABORT :
34323452 case TBLOCK_SUBABORT :
34333453 case TBLOCK_ABORT_END :
@@ -3483,7 +3503,8 @@ ReleaseSavepoint(List *options)
34833503 case TBLOCK_BEGIN :
34843504 case TBLOCK_SUBBEGIN :
34853505 case TBLOCK_END :
3486- case TBLOCK_SUBEND :
3506+ case TBLOCK_SUBRELEASE :
3507+ case TBLOCK_SUBCOMMIT :
34873508 case TBLOCK_ABORT :
34883509 case TBLOCK_SUBABORT :
34893510 case TBLOCK_ABORT_END :
@@ -3534,7 +3555,7 @@ ReleaseSavepoint(List *options)
35343555 for (;;)
35353556 {
35363557 Assert (xact -> blockState == TBLOCK_SUBINPROGRESS );
3537- xact -> blockState = TBLOCK_SUBEND ;
3558+ xact -> blockState = TBLOCK_SUBRELEASE ;
35383559 if (xact == target )
35393560 break ;
35403561 xact = xact -> parent ;
@@ -3583,7 +3604,8 @@ RollbackToSavepoint(List *options)
35833604 case TBLOCK_BEGIN :
35843605 case TBLOCK_SUBBEGIN :
35853606 case TBLOCK_END :
3586- case TBLOCK_SUBEND :
3607+ case TBLOCK_SUBRELEASE :
3608+ case TBLOCK_SUBCOMMIT :
35873609 case TBLOCK_ABORT_END :
35883610 case TBLOCK_SUBABORT_END :
35893611 case TBLOCK_ABORT_PENDING :
@@ -3691,7 +3713,8 @@ BeginInternalSubTransaction(char *name)
36913713 case TBLOCK_DEFAULT :
36923714 case TBLOCK_BEGIN :
36933715 case TBLOCK_SUBBEGIN :
3694- case TBLOCK_SUBEND :
3716+ case TBLOCK_SUBRELEASE :
3717+ case TBLOCK_SUBCOMMIT :
36953718 case TBLOCK_ABORT :
36963719 case TBLOCK_SUBABORT :
36973720 case TBLOCK_ABORT_END :
@@ -3726,7 +3749,7 @@ ReleaseCurrentSubTransaction(void)
37263749 BlockStateAsString (s -> blockState ));
37273750 Assert (s -> state == TRANS_INPROGRESS );
37283751 MemoryContextSwitchTo (CurTransactionContext );
3729- CommitSubTransaction ();
3752+ CommitSubTransaction (false );
37303753 s = CurrentTransactionState ; /* changed by pop */
37313754 Assert (s -> state == TRANS_INPROGRESS );
37323755}
@@ -3757,7 +3780,8 @@ RollbackAndReleaseCurrentSubTransaction(void)
37573780 case TBLOCK_SUBBEGIN :
37583781 case TBLOCK_INPROGRESS :
37593782 case TBLOCK_END :
3760- case TBLOCK_SUBEND :
3783+ case TBLOCK_SUBRELEASE :
3784+ case TBLOCK_SUBCOMMIT :
37613785 case TBLOCK_ABORT :
37623786 case TBLOCK_ABORT_END :
37633787 case TBLOCK_SUBABORT_END :
@@ -3831,7 +3855,8 @@ AbortOutOfAnyTransaction(void)
38313855 */
38323856 case TBLOCK_SUBBEGIN :
38333857 case TBLOCK_SUBINPROGRESS :
3834- case TBLOCK_SUBEND :
3858+ case TBLOCK_SUBRELEASE :
3859+ case TBLOCK_SUBCOMMIT :
38353860 case TBLOCK_SUBABORT_PENDING :
38363861 case TBLOCK_SUBRESTART :
38373862 AbortSubTransaction ();
@@ -3903,7 +3928,8 @@ TransactionBlockStatusCode(void)
39033928 case TBLOCK_INPROGRESS :
39043929 case TBLOCK_SUBINPROGRESS :
39053930 case TBLOCK_END :
3906- case TBLOCK_SUBEND :
3931+ case TBLOCK_SUBRELEASE :
3932+ case TBLOCK_SUBCOMMIT :
39073933 case TBLOCK_PREPARE :
39083934 return 'T' ; /* in transaction */
39093935 case 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{
39944024 TransactionState 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 */
40414070 CurrentResourceOwner = s -> curTransactionOwner ;
40424071 if (TransactionIdIsValid (s -> transactionId ))
40434072 XactLockTableDelete (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+ */
40454081 ResourceOwnerRelease (s -> curTransactionOwner ,
40464082 RESOURCE_RELEASE_LOCKS ,
4047- true, false );
4083+ true, isTopLevel );
40484084 ResourceOwnerRelease (s -> curTransactionOwner ,
40494085 RESOURCE_RELEASE_AFTER_LOCKS ,
40504086 true, false);
@@ -4398,8 +4434,10 @@ BlockStateAsString(TBlockState blockState)
43984434 return "SUB BEGIN" ;
43994435 case TBLOCK_SUBINPROGRESS :
44004436 return "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" ;
44034441 case TBLOCK_SUBABORT :
44044442 return "SUB ABORT" ;
44054443 case TBLOCK_SUBABORT_END :
0 commit comments