Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7cb7122

Browse files
Remove O(N^2) performance issue with multiple SAVEPOINTs.
Subtransaction locks now released en masse at main commit, rather than repeatedly re-scanning for locks as we ascend the nested transaction tree. Split transaction state TBLOCK_SUBEND into two states, TBLOCK_SUBCOMMIT and TBLOCK_SUBRELEASE to allow the commit path to be optimised using the existing code in ResourceOwnerRelease() which appears to have been intended for this usage, judging from comments therein.
1 parent 8e5ac74 commit 7cb7122

File tree

1 file changed

+70
-32
lines changed
  • src/backend/access/transam

1 file changed

+70
-32
lines changed

src/backend/access/transam/xact.c

+70-32
Original file line numberDiff line numberDiff line change
@@ -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);
272273
static void StartTransaction(void);
273274

274275
static void StartSubTransaction(void);
275-
static void CommitSubTransaction(void);
276+
static void CommitSubTransaction(bool isTopLevel);
276277
static void AbortSubTransaction(void);
277278
static void CleanupSubTransaction(void);
278279
static 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
*/
39914021
static 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

Comments
 (0)