@@ -693,19 +693,32 @@ AcceptInvalidationMessages(void)
693693}
694694
695695/*
696- *AtStart_Inval
697- *Initialize inval listsat start of a main transaction.
696+ *PrepareInvalidationState
697+ *Initialize inval listsfor 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 * )
704709MemoryContextAllocZero (TopTransactionContext ,
705710sizeof (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)
726739AtEOXact_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{
804799MemoryContext 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+
907917if (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)
926933if (transInvalInfo -> RelcacheInitFileInval )
927934RelationCacheInitFilePostInvalidate ();
928935}
929- else if ( transInvalInfo != NULL )
936+ else
930937{
931- /* Must be at top of stack */
932- Assert (transInvalInfo -> parent == NULL );
933-
934938ProcessInvalidationMessages (& transInvalInfo -> PriorCmdInvalidMsgs ,
935939LocalExecuteInvalidationMessage );
936940}
937941
938942/* Need not free anything explicitly */
939943transInvalInfo = 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 ;
964970TransInvalidationInfo * 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 */
973987CommandEndInvalidationMessages ();
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 */
9761002AppendInvalidationMessages (& myInfo -> parent -> PriorCmdInvalidMsgs ,
9771003& myInfo -> PriorCmdInvalidMsgs );
@@ -986,11 +1012,8 @@ AtEOSubXact_Inval(bool isCommit)
9861012/* Need not free anything else explicitly */
9871013pfree (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-
9941017ProcessInvalidationMessages (& myInfo -> PriorCmdInvalidMsgs ,
9951018LocalExecuteInvalidationMessage );
9961019
@@ -1074,6 +1097,12 @@ CacheInvalidateHeapTuple(Relation relation,
10741097if (IsToastRelation (relation ))
10751098return ;
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{
11601189Oid databaseId ;
11611190
1191+ PrepareInvalidationState ();
1192+
11621193if (IsSharedRelation (catalogId ))
11631194databaseId = InvalidOid ;
11641195else
@@ -1182,6 +1213,8 @@ CacheInvalidateRelcache(Relation relation)
11821213Oid databaseId ;
11831214Oid relationId ;
11841215
1216+ PrepareInvalidationState ();
1217+
11851218relationId = RelationGetRelid (relation );
11861219if (relation -> rd_rel -> relisshared )
11871220databaseId = InvalidOid ;
@@ -1202,6 +1235,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
12021235Oid databaseId ;
12031236Oid relationId ;
12041237
1238+ PrepareInvalidationState ();
1239+
12051240relationId = HeapTupleGetOid (classTuple );
12061241if (classtup -> relisshared )
12071242databaseId = InvalidOid ;
@@ -1221,6 +1256,8 @@ CacheInvalidateRelcacheByRelid(Oid relid)
12211256{
12221257HeapTuple tup ;
12231258
1259+ PrepareInvalidationState ();
1260+
12241261tup = SearchSysCache1 (RELOID ,ObjectIdGetDatum (relid ));
12251262if (!HeapTupleIsValid (tup ))
12261263elog (ERROR ,"cache lookup failed for relation %u" ,relid );