@@ -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,
904907void
905908AtEOXact_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)
960966void
961967AtEOSubXact_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 );
0 commit comments