@@ -118,7 +118,8 @@ typedef enum TBlockState
118
118
/* subtransaction states */
119
119
TBLOCK_SUBBEGIN , /* starting a subtransaction */
120
120
TBLOCK_SUBINPROGRESS , /* live subtransaction */
121
- TBLOCK_SUBEND , /* RELEASE received */
121
+ TBLOCK_SUBRELEASE , /* RELEASE received */
122
+ TBLOCK_SUBCOMMIT , /* COMMIT received while TBLOCK_SUBINPROGRESS */
122
123
TBLOCK_SUBABORT , /* failed subxact, awaiting ROLLBACK */
123
124
TBLOCK_SUBABORT_END , /* failed subxact, ROLLBACK received */
124
125
TBLOCK_SUBABORT_PENDING , /* live subxact, ROLLBACK received */
@@ -272,7 +273,7 @@ static TransactionId RecordTransactionAbort(bool isSubXact);
272
273
static void StartTransaction (void );
273
274
274
275
static void StartSubTransaction (void );
275
- static void CommitSubTransaction (void );
276
+ static void CommitSubTransaction (bool isTopLevel );
276
277
static void AbortSubTransaction (void );
277
278
static void CleanupSubTransaction (void );
278
279
static void PushTransaction (void );
@@ -2442,7 +2443,8 @@ StartTransactionCommand(void)
2442
2443
case TBLOCK_BEGIN :
2443
2444
case TBLOCK_SUBBEGIN :
2444
2445
case TBLOCK_END :
2445
- case TBLOCK_SUBEND :
2446
+ case TBLOCK_SUBRELEASE :
2447
+ case TBLOCK_SUBCOMMIT :
2446
2448
case TBLOCK_ABORT_END :
2447
2449
case TBLOCK_SUBABORT_END :
2448
2450
case TBLOCK_ABORT_PENDING :
@@ -2572,17 +2574,32 @@ CommitTransactionCommand(void)
2572
2574
break ;
2573
2575
2574
2576
/*
2575
- * We were issued a COMMIT or RELEASE command, so we end the
2577
+ * We were issued a RELEASE command, so we end the
2576
2578
* 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 .
2579
2581
*/
2580
- case TBLOCK_SUBEND :
2582
+ case TBLOCK_SUBRELEASE :
2581
2583
do
2582
2584
{
2583
- CommitSubTransaction ();
2585
+ CommitSubTransaction (false );
2584
2586
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 );
2586
2603
/* If we had a COMMIT command, finish off the main xact too */
2587
2604
if (s -> blockState == TBLOCK_END )
2588
2605
{
@@ -2597,10 +2614,8 @@ CommitTransactionCommand(void)
2597
2614
s -> blockState = TBLOCK_DEFAULT ;
2598
2615
}
2599
2616
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 ));
2604
2619
break ;
2605
2620
2606
2621
/*
@@ -2814,7 +2829,8 @@ AbortCurrentTransaction(void)
2814
2829
* applies if we get a failure while ending a subtransaction.
2815
2830
*/
2816
2831
case TBLOCK_SUBBEGIN :
2817
- case TBLOCK_SUBEND :
2832
+ case TBLOCK_SUBRELEASE :
2833
+ case TBLOCK_SUBCOMMIT :
2818
2834
case TBLOCK_SUBABORT_PENDING :
2819
2835
case TBLOCK_SUBRESTART :
2820
2836
AbortSubTransaction ();
@@ -3122,7 +3138,8 @@ BeginTransactionBlock(void)
3122
3138
case TBLOCK_BEGIN :
3123
3139
case TBLOCK_SUBBEGIN :
3124
3140
case TBLOCK_END :
3125
- case TBLOCK_SUBEND :
3141
+ case TBLOCK_SUBRELEASE :
3142
+ case TBLOCK_SUBCOMMIT :
3126
3143
case TBLOCK_ABORT_END :
3127
3144
case TBLOCK_SUBABORT_END :
3128
3145
case TBLOCK_ABORT_PENDING :
@@ -3232,7 +3249,7 @@ EndTransactionBlock(void)
3232
3249
while (s -> parent != NULL )
3233
3250
{
3234
3251
if (s -> blockState == TBLOCK_SUBINPROGRESS )
3235
- s -> blockState = TBLOCK_SUBEND ;
3252
+ s -> blockState = TBLOCK_SUBCOMMIT ;
3236
3253
else
3237
3254
elog (FATAL , "EndTransactionBlock: unexpected state %s" ,
3238
3255
BlockStateAsString (s -> blockState ));
@@ -3290,7 +3307,8 @@ EndTransactionBlock(void)
3290
3307
case TBLOCK_BEGIN :
3291
3308
case TBLOCK_SUBBEGIN :
3292
3309
case TBLOCK_END :
3293
- case TBLOCK_SUBEND :
3310
+ case TBLOCK_SUBRELEASE :
3311
+ case TBLOCK_SUBCOMMIT :
3294
3312
case TBLOCK_ABORT_END :
3295
3313
case TBLOCK_SUBABORT_END :
3296
3314
case TBLOCK_ABORT_PENDING :
@@ -3382,7 +3400,8 @@ UserAbortTransactionBlock(void)
3382
3400
case TBLOCK_BEGIN :
3383
3401
case TBLOCK_SUBBEGIN :
3384
3402
case TBLOCK_END :
3385
- case TBLOCK_SUBEND :
3403
+ case TBLOCK_SUBRELEASE :
3404
+ case TBLOCK_SUBCOMMIT :
3386
3405
case TBLOCK_ABORT_END :
3387
3406
case TBLOCK_SUBABORT_END :
3388
3407
case TBLOCK_ABORT_PENDING :
@@ -3427,7 +3446,8 @@ DefineSavepoint(char *name)
3427
3446
case TBLOCK_BEGIN :
3428
3447
case TBLOCK_SUBBEGIN :
3429
3448
case TBLOCK_END :
3430
- case TBLOCK_SUBEND :
3449
+ case TBLOCK_SUBRELEASE :
3450
+ case TBLOCK_SUBCOMMIT :
3431
3451
case TBLOCK_ABORT :
3432
3452
case TBLOCK_SUBABORT :
3433
3453
case TBLOCK_ABORT_END :
@@ -3483,7 +3503,8 @@ ReleaseSavepoint(List *options)
3483
3503
case TBLOCK_BEGIN :
3484
3504
case TBLOCK_SUBBEGIN :
3485
3505
case TBLOCK_END :
3486
- case TBLOCK_SUBEND :
3506
+ case TBLOCK_SUBRELEASE :
3507
+ case TBLOCK_SUBCOMMIT :
3487
3508
case TBLOCK_ABORT :
3488
3509
case TBLOCK_SUBABORT :
3489
3510
case TBLOCK_ABORT_END :
@@ -3534,7 +3555,7 @@ ReleaseSavepoint(List *options)
3534
3555
for (;;)
3535
3556
{
3536
3557
Assert (xact -> blockState == TBLOCK_SUBINPROGRESS );
3537
- xact -> blockState = TBLOCK_SUBEND ;
3558
+ xact -> blockState = TBLOCK_SUBRELEASE ;
3538
3559
if (xact == target )
3539
3560
break ;
3540
3561
xact = xact -> parent ;
@@ -3583,7 +3604,8 @@ RollbackToSavepoint(List *options)
3583
3604
case TBLOCK_BEGIN :
3584
3605
case TBLOCK_SUBBEGIN :
3585
3606
case TBLOCK_END :
3586
- case TBLOCK_SUBEND :
3607
+ case TBLOCK_SUBRELEASE :
3608
+ case TBLOCK_SUBCOMMIT :
3587
3609
case TBLOCK_ABORT_END :
3588
3610
case TBLOCK_SUBABORT_END :
3589
3611
case TBLOCK_ABORT_PENDING :
@@ -3691,7 +3713,8 @@ BeginInternalSubTransaction(char *name)
3691
3713
case TBLOCK_DEFAULT :
3692
3714
case TBLOCK_BEGIN :
3693
3715
case TBLOCK_SUBBEGIN :
3694
- case TBLOCK_SUBEND :
3716
+ case TBLOCK_SUBRELEASE :
3717
+ case TBLOCK_SUBCOMMIT :
3695
3718
case TBLOCK_ABORT :
3696
3719
case TBLOCK_SUBABORT :
3697
3720
case TBLOCK_ABORT_END :
@@ -3726,7 +3749,7 @@ ReleaseCurrentSubTransaction(void)
3726
3749
BlockStateAsString (s -> blockState ));
3727
3750
Assert (s -> state == TRANS_INPROGRESS );
3728
3751
MemoryContextSwitchTo (CurTransactionContext );
3729
- CommitSubTransaction ();
3752
+ CommitSubTransaction (false );
3730
3753
s = CurrentTransactionState ; /* changed by pop */
3731
3754
Assert (s -> state == TRANS_INPROGRESS );
3732
3755
}
@@ -3757,7 +3780,8 @@ RollbackAndReleaseCurrentSubTransaction(void)
3757
3780
case TBLOCK_SUBBEGIN :
3758
3781
case TBLOCK_INPROGRESS :
3759
3782
case TBLOCK_END :
3760
- case TBLOCK_SUBEND :
3783
+ case TBLOCK_SUBRELEASE :
3784
+ case TBLOCK_SUBCOMMIT :
3761
3785
case TBLOCK_ABORT :
3762
3786
case TBLOCK_ABORT_END :
3763
3787
case TBLOCK_SUBABORT_END :
@@ -3831,7 +3855,8 @@ AbortOutOfAnyTransaction(void)
3831
3855
*/
3832
3856
case TBLOCK_SUBBEGIN :
3833
3857
case TBLOCK_SUBINPROGRESS :
3834
- case TBLOCK_SUBEND :
3858
+ case TBLOCK_SUBRELEASE :
3859
+ case TBLOCK_SUBCOMMIT :
3835
3860
case TBLOCK_SUBABORT_PENDING :
3836
3861
case TBLOCK_SUBRESTART :
3837
3862
AbortSubTransaction ();
@@ -3903,7 +3928,8 @@ TransactionBlockStatusCode(void)
3903
3928
case TBLOCK_INPROGRESS :
3904
3929
case TBLOCK_SUBINPROGRESS :
3905
3930
case TBLOCK_END :
3906
- case TBLOCK_SUBEND :
3931
+ case TBLOCK_SUBRELEASE :
3932
+ case TBLOCK_SUBCOMMIT :
3907
3933
case TBLOCK_PREPARE :
3908
3934
return 'T' ; /* in transaction */
3909
3935
case TBLOCK_ABORT :
@@ -3987,9 +4013,13 @@ StartSubTransaction(void)
3987
4013
*
3988
4014
* The caller has to make sure to always reassign CurrentTransactionState
3989
4015
* 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.
3990
4020
*/
3991
4021
static void
3992
- CommitSubTransaction (void )
4022
+ CommitSubTransaction (bool isTopLevel )
3993
4023
{
3994
4024
TransactionState s = CurrentTransactionState ;
3995
4025
@@ -4036,15 +4066,21 @@ CommitSubTransaction(void)
4036
4066
4037
4067
/*
4038
4068
* The only lock we actually release here is the subtransaction XID lock.
4039
- * The rest just get transferred to the parent resource owner.
4040
4069
*/
4041
4070
CurrentResourceOwner = s -> curTransactionOwner ;
4042
4071
if (TransactionIdIsValid (s -> transactionId ))
4043
4072
XactLockTableDelete (s -> transactionId );
4044
4073
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
+ */
4045
4081
ResourceOwnerRelease (s -> curTransactionOwner ,
4046
4082
RESOURCE_RELEASE_LOCKS ,
4047
- true, false );
4083
+ true, isTopLevel );
4048
4084
ResourceOwnerRelease (s -> curTransactionOwner ,
4049
4085
RESOURCE_RELEASE_AFTER_LOCKS ,
4050
4086
true, false);
@@ -4398,8 +4434,10 @@ BlockStateAsString(TBlockState blockState)
4398
4434
return "SUB BEGIN" ;
4399
4435
case TBLOCK_SUBINPROGRESS :
4400
4436
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" ;
4403
4441
case TBLOCK_SUBABORT :
4404
4442
return "SUB ABORT" ;
4405
4443
case TBLOCK_SUBABORT_END :
0 commit comments