@@ -693,19 +693,32 @@ AcceptInvalidationMessages(void)
693
693
}
694
694
695
695
/*
696
- * AtStart_Inval
697
- * Initialize inval lists at start of a main transaction.
696
+ * PrepareInvalidationState
697
+ * Initialize inval lists for the current (sub) transaction.
698
698
*/
699
- void
700
- AtStart_Inval (void )
699
+ static void
700
+ PrepareInvalidationState (void )
701
701
{
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 * )
704
709
MemoryContextAllocZero (TopTransactionContext ,
705
710
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 ;
709
722
}
710
723
711
724
/*
@@ -726,24 +739,6 @@ PostPrepare_Inval(void)
726
739
AtEOXact_Inval (false);
727
740
}
728
741
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
-
747
742
/*
748
743
* Collect invalidation messages into SharedInvalidMessagesArray array.
749
744
*/
@@ -803,8 +798,16 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
803
798
{
804
799
MemoryContext oldcontext ;
805
800
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
+
806
809
/* Must be at top of stack */
807
- Assert (transInvalInfo != NULL && transInvalInfo -> parent == NULL );
810
+ Assert (transInvalInfo -> my_level == 1 && transInvalInfo -> parent == NULL );
808
811
809
812
/*
810
813
* Relcache init file invalidation requires processing both before and
@@ -904,11 +907,15 @@ ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
904
907
void
905
908
AtEOXact_Inval (bool isCommit )
906
909
{
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
+
907
917
if (isCommit )
908
918
{
909
- /* Must be at top of stack */
910
- Assert (transInvalInfo != NULL && transInvalInfo -> parent == NULL );
911
-
912
919
/*
913
920
* Relcache init file invalidation requires processing both before and
914
921
* after we send the SI messages. However, we need not do anything
@@ -926,17 +933,16 @@ AtEOXact_Inval(bool isCommit)
926
933
if (transInvalInfo -> RelcacheInitFileInval )
927
934
RelationCacheInitFilePostInvalidate ();
928
935
}
929
- else if ( transInvalInfo != NULL )
936
+ else
930
937
{
931
- /* Must be at top of stack */
932
- Assert (transInvalInfo -> parent == NULL );
933
-
934
938
ProcessInvalidationMessages (& transInvalInfo -> PriorCmdInvalidMsgs ,
935
939
LocalExecuteInvalidationMessage );
936
940
}
937
941
938
942
/* Need not free anything explicitly */
939
943
transInvalInfo = NULL ;
944
+ SharedInvalidMessagesArray = NULL ;
945
+ numSharedInvalidMessagesArray = 0 ;
940
946
}
941
947
942
948
/*
@@ -960,18 +966,38 @@ AtEOXact_Inval(bool isCommit)
960
966
void
961
967
AtEOSubXact_Inval (bool isCommit )
962
968
{
963
- int my_level = GetCurrentTransactionNestLevel () ;
969
+ int my_level ;
964
970
TransInvalidationInfo * myInfo = transInvalInfo ;
965
971
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 )
967
979
{
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
+ }
971
983
984
+ if (isCommit )
985
+ {
972
986
/* If CurrentCmdInvalidMsgs still has anything, fix it */
973
987
CommandEndInvalidationMessages ();
974
988
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
+
975
1001
/* Pass up my inval messages to parent */
976
1002
AppendInvalidationMessages (& myInfo -> parent -> PriorCmdInvalidMsgs ,
977
1003
& myInfo -> PriorCmdInvalidMsgs );
@@ -986,11 +1012,8 @@ AtEOSubXact_Inval(bool isCommit)
986
1012
/* Need not free anything else explicitly */
987
1013
pfree (myInfo );
988
1014
}
989
- else if ( myInfo != NULL && myInfo -> my_level == my_level )
1015
+ else
990
1016
{
991
- /* Must be at non-top of stack */
992
- Assert (myInfo -> parent != NULL );
993
-
994
1017
ProcessInvalidationMessages (& myInfo -> PriorCmdInvalidMsgs ,
995
1018
LocalExecuteInvalidationMessage );
996
1019
@@ -1074,6 +1097,12 @@ CacheInvalidateHeapTuple(Relation relation,
1074
1097
if (IsToastRelation (relation ))
1075
1098
return ;
1076
1099
1100
+ /*
1101
+ * If we're not prepared to queue invalidation messages for this
1102
+ * subtransaction level, get ready now.
1103
+ */
1104
+ PrepareInvalidationState ();
1105
+
1077
1106
/*
1078
1107
* First let the catcache do its thing
1079
1108
*/
@@ -1159,6 +1188,8 @@ CacheInvalidateCatalog(Oid catalogId)
1159
1188
{
1160
1189
Oid databaseId ;
1161
1190
1191
+ PrepareInvalidationState ();
1192
+
1162
1193
if (IsSharedRelation (catalogId ))
1163
1194
databaseId = InvalidOid ;
1164
1195
else
@@ -1182,6 +1213,8 @@ CacheInvalidateRelcache(Relation relation)
1182
1213
Oid databaseId ;
1183
1214
Oid relationId ;
1184
1215
1216
+ PrepareInvalidationState ();
1217
+
1185
1218
relationId = RelationGetRelid (relation );
1186
1219
if (relation -> rd_rel -> relisshared )
1187
1220
databaseId = InvalidOid ;
@@ -1202,6 +1235,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
1202
1235
Oid databaseId ;
1203
1236
Oid relationId ;
1204
1237
1238
+ PrepareInvalidationState ();
1239
+
1205
1240
relationId = HeapTupleGetOid (classTuple );
1206
1241
if (classtup -> relisshared )
1207
1242
databaseId = InvalidOid ;
@@ -1221,6 +1256,8 @@ CacheInvalidateRelcacheByRelid(Oid relid)
1221
1256
{
1222
1257
HeapTuple tup ;
1223
1258
1259
+ PrepareInvalidationState ();
1260
+
1224
1261
tup = SearchSysCache1 (RELOID , ObjectIdGetDatum (relid ));
1225
1262
if (!HeapTupleIsValid (tup ))
1226
1263
elog (ERROR , "cache lookup failed for relation %u" , relid );
0 commit comments