Skip to content

Commit 6cb4aff

Browse files
committed
Avoid setup work for invalidation messages at start-of-(sub)xact.
Instead of initializing a new TransInvalidationInfo for every transaction or subtransaction, we can just do it for those transactions or subtransactions that actually need to queue invalidation messages. That also avoids needing to free those entries at the end of a transaction or subtransaction that does not generate any invalidation messages, which is by far the common case. Patch by me. Review by Simon Riggs and Andres Freund.
1 parent 8f8314b commit 6cb4aff

File tree

3 files changed

+81
-50
lines changed

3 files changed

+81
-50
lines changed

src/backend/access/transam/xact.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,7 +1838,6 @@ StartTransaction(void)
18381838
* initialize other subsystems for new transaction
18391839
*/
18401840
AtStart_GUC();
1841-
AtStart_Inval();
18421841
AtStart_Cache();
18431842
AfterTriggerBeginXact();
18441843

@@ -4151,7 +4150,6 @@ StartSubTransaction(void)
41514150
*/
41524151
AtSubStart_Memory();
41534152
AtSubStart_ResourceOwner();
4154-
AtSubStart_Inval();
41554153
AtSubStart_Notify();
41564154
AfterTriggerBeginSubXact();
41574155

src/backend/utils/cache/inval.c

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -693,19 +693,32 @@ AcceptInvalidationMessages(void)
693693
}
694694

695695
/*
696-
* AtStart_Inval
697-
* Initialize inval lists at start of a main transaction.
696+
* PrepareInvalidationState
697+
* Initialize inval lists for the current (sub)transaction.
698698
*/
699-
void
700-
AtStart_Inval(void)
699+
static void
700+
PrepareInvalidationState(void)
701701
{
702-
Assert(transInvalInfo == NULL);
703-
transInvalInfo = (TransInvalidationInfo *)
702+
TransInvalidationInfo *myInfo;
703+
704+
if (transInvalInfo != NULL &&
705+
transInvalInfo->my_level == GetCurrentTransactionNestLevel())
706+
return;
707+
708+
myInfo = (TransInvalidationInfo *)
704709
MemoryContextAllocZero(TopTransactionContext,
705710
sizeof(TransInvalidationInfo));
706-
transInvalInfo->my_level = GetCurrentTransactionNestLevel();
707-
SharedInvalidMessagesArray = NULL;
708-
numSharedInvalidMessagesArray = 0;
711+
myInfo->parent = transInvalInfo;
712+
myInfo->my_level = GetCurrentTransactionNestLevel();
713+
714+
/*
715+
* If there's any previous entry, this one should be for a deeper
716+
* nesting level.
717+
*/
718+
Assert(transInvalInfo == NULL ||
719+
myInfo->my_level > transInvalInfo->my_level);
720+
721+
transInvalInfo = myInfo;
709722
}
710723

711724
/*
@@ -726,24 +739,6 @@ PostPrepare_Inval(void)
726739
AtEOXact_Inval(false);
727740
}
728741

729-
/*
730-
* AtSubStart_Inval
731-
* Initialize inval lists at start of a subtransaction.
732-
*/
733-
void
734-
AtSubStart_Inval(void)
735-
{
736-
TransInvalidationInfo *myInfo;
737-
738-
Assert(transInvalInfo != NULL);
739-
myInfo = (TransInvalidationInfo *)
740-
MemoryContextAllocZero(TopTransactionContext,
741-
sizeof(TransInvalidationInfo));
742-
myInfo->parent = transInvalInfo;
743-
myInfo->my_level = GetCurrentTransactionNestLevel();
744-
transInvalInfo = myInfo;
745-
}
746-
747742
/*
748743
* Collect invalidation messages into SharedInvalidMessagesArray array.
749744
*/
@@ -803,8 +798,16 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
803798
{
804799
MemoryContext oldcontext;
805800

801+
/* Quick exit if we haven't done anything with invalidation messages. */
802+
if (transInvalInfo == NULL)
803+
{
804+
*RelcacheInitFileInval = false;
805+
*msgs = NULL;
806+
return 0;
807+
}
808+
806809
/* Must be at top of stack */
807-
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
810+
Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL);
808811

809812
/*
810813
* Relcache init file invalidation requires processing both before and
@@ -904,11 +907,15 @@ ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
904907
void
905908
AtEOXact_Inval(bool isCommit)
906909
{
910+
/* Quick exit if no messages */
911+
if (transInvalInfo == NULL)
912+
return;
913+
914+
/* Must be at top of stack */
915+
Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL);
916+
907917
if (isCommit)
908918
{
909-
/* Must be at top of stack */
910-
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
911-
912919
/*
913920
* Relcache init file invalidation requires processing both before and
914921
* after we send the SI messages. However, we need not do anything
@@ -926,17 +933,16 @@ AtEOXact_Inval(bool isCommit)
926933
if (transInvalInfo->RelcacheInitFileInval)
927934
RelationCacheInitFilePostInvalidate();
928935
}
929-
else if (transInvalInfo != NULL)
936+
else
930937
{
931-
/* Must be at top of stack */
932-
Assert(transInvalInfo->parent == NULL);
933-
934938
ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
935939
LocalExecuteInvalidationMessage);
936940
}
937941

938942
/* Need not free anything explicitly */
939943
transInvalInfo = NULL;
944+
SharedInvalidMessagesArray = NULL;
945+
numSharedInvalidMessagesArray = 0;
940946
}
941947

942948
/*
@@ -960,18 +966,38 @@ AtEOXact_Inval(bool isCommit)
960966
void
961967
AtEOSubXact_Inval(bool isCommit)
962968
{
963-
int my_level = GetCurrentTransactionNestLevel();
969+
int my_level;
964970
TransInvalidationInfo *myInfo = transInvalInfo;
965971

966-
if (isCommit)
972+
/* Quick exit if no messages. */
973+
if (myInfo == NULL)
974+
return;
975+
976+
/* Also bail out quickly if messages are not for this level. */
977+
my_level = GetCurrentTransactionNestLevel();
978+
if (myInfo->my_level != my_level)
967979
{
968-
/* Must be at non-top of stack */
969-
Assert(myInfo != NULL && myInfo->parent != NULL);
970-
Assert(myInfo->my_level == my_level);
980+
Assert(myInfo->my_level < my_level);
981+
return;
982+
}
971983

984+
if (isCommit)
985+
{
972986
/* If CurrentCmdInvalidMsgs still has anything, fix it */
973987
CommandEndInvalidationMessages();
974988

989+
/*
990+
* We create invalidation stack entries lazily, so the parent might
991+
* not have one. Instead of creating one, moving all the data over,
992+
* and then freeing our own, we can just adjust the level of our own
993+
* entry.
994+
*/
995+
if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
996+
{
997+
myInfo->my_level--;
998+
return;
999+
}
1000+
9751001
/* Pass up my inval messages to parent */
9761002
AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
9771003
&myInfo->PriorCmdInvalidMsgs);
@@ -986,11 +1012,8 @@ AtEOSubXact_Inval(bool isCommit)
9861012
/* Need not free anything else explicitly */
9871013
pfree(myInfo);
9881014
}
989-
else if (myInfo != NULL && myInfo->my_level == my_level)
1015+
else
9901016
{
991-
/* Must be at non-top of stack */
992-
Assert(myInfo->parent != NULL);
993-
9941017
ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
9951018
LocalExecuteInvalidationMessage);
9961019

@@ -1074,6 +1097,12 @@ CacheInvalidateHeapTuple(Relation relation,
10741097
if (IsToastRelation(relation))
10751098
return;
10761099

1100+
/*
1101+
* If we're not prepared to queue invalidation messages for this
1102+
* subtransaction level, get ready now.
1103+
*/
1104+
PrepareInvalidationState();
1105+
10771106
/*
10781107
* First let the catcache do its thing
10791108
*/
@@ -1159,6 +1188,8 @@ CacheInvalidateCatalog(Oid catalogId)
11591188
{
11601189
Oid databaseId;
11611190

1191+
PrepareInvalidationState();
1192+
11621193
if (IsSharedRelation(catalogId))
11631194
databaseId = InvalidOid;
11641195
else
@@ -1182,6 +1213,8 @@ CacheInvalidateRelcache(Relation relation)
11821213
Oid databaseId;
11831214
Oid relationId;
11841215

1216+
PrepareInvalidationState();
1217+
11851218
relationId = RelationGetRelid(relation);
11861219
if (relation->rd_rel->relisshared)
11871220
databaseId = InvalidOid;
@@ -1202,6 +1235,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
12021235
Oid databaseId;
12031236
Oid relationId;
12041237

1238+
PrepareInvalidationState();
1239+
12051240
relationId = HeapTupleGetOid(classTuple);
12061241
if (classtup->relisshared)
12071242
databaseId = InvalidOid;
@@ -1221,6 +1256,8 @@ CacheInvalidateRelcacheByRelid(Oid relid)
12211256
{
12221257
HeapTuple tup;
12231258

1259+
PrepareInvalidationState();
1260+
12241261
tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12251262
if (!HeapTupleIsValid(tup))
12261263
elog(ERROR, "cache lookup failed for relation %u", relid);

src/include/utils/inval.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid);
2525

2626
extern void AcceptInvalidationMessages(void);
2727

28-
extern void AtStart_Inval(void);
29-
30-
extern void AtSubStart_Inval(void);
31-
3228
extern void AtEOXact_Inval(bool isCommit);
3329

3430
extern void AtEOSubXact_Inval(bool isCommit);

0 commit comments

Comments
 (0)