@@ -161,7 +161,7 @@ static void SnapBuildFreeSnapshot(Snapshot snap);
161161
162162static void SnapBuildSnapIncRefcount (Snapshot snap );
163163
164- static void SnapBuildDistributeNewCatalogSnapshot (SnapBuild * builder , XLogRecPtr lsn );
164+ static void SnapBuildDistributeSnapshotAndInval (SnapBuild * builder , XLogRecPtr lsn , TransactionId xid );
165165
166166static inline bool SnapBuildXidHasCatalogChanges (SnapBuild * builder , TransactionId xid ,
167167 uint32 xinfo );
@@ -720,23 +720,24 @@ SnapBuildProcessNewCid(SnapBuild *builder, TransactionId xid,
720720}
721721
722722/*
723- * Add a new Snapshot to all transactions we're decoding that currently are
724- * in-progress so they can see new catalog contents made by the transaction
725- * that just committed. This is necessary because those in-progress
726- * transactions will use the new catalog's contents from here on (at the very
727- * least everything they do needs to be compatible with newer catalog
728- * contents).
723+ * Add a new Snapshot and invalidation messages to all transactions we're
724+ * decoding that currently are in-progress so they can see new catalog contents
725+ * made by the transaction that just committed. This is necessary because those
726+ * in-progress transactions will use the new catalog's contents from here on
727+ * (at the very least everything they do needs to be compatible with newer
728+ * catalog contents).
729729 */
730730static void
731- SnapBuildDistributeNewCatalogSnapshot (SnapBuild * builder , XLogRecPtr lsn )
731+ SnapBuildDistributeSnapshotAndInval (SnapBuild * builder , XLogRecPtr lsn , TransactionId xid )
732732{
733733 dlist_iter txn_i ;
734734 ReorderBufferTXN * txn ;
735735
736736 /*
737737 * Iterate through all toplevel transactions. This can include
738738 * subtransactions which we just don't yet know to be that, but that's
739- * fine, they will just get an unnecessary snapshot queued.
739+ * fine, they will just get an unnecessary snapshot and invalidations
740+ * queued.
740741 */
741742 dlist_foreach (txn_i , & builder -> reorder -> toplevel_by_lsn )
742743 {
@@ -749,6 +750,14 @@ SnapBuildDistributeNewCatalogSnapshot(SnapBuild *builder, XLogRecPtr lsn)
749750 * transaction which in turn implies we don't yet need a snapshot at
750751 * all. We'll add a snapshot when the first change gets queued.
751752 *
753+ * Similarly, we don't need to add invalidations to a transaction whose
754+ * base snapshot is not yet set. Once a base snapshot is built, it will
755+ * include the xids of committed transactions that have modified the
756+ * catalog, thus reflecting the new catalog contents. The existing
757+ * catalog cache will have already been invalidated after processing
758+ * the invalidations in the transaction that modified catalogs,
759+ * ensuring that a fresh cache is constructed during decoding.
760+ *
752761 * NB: This works correctly even for subtransactions because
753762 * ReorderBufferAssignChild() takes care to transfer the base snapshot
754763 * to the top-level transaction, and while iterating the changequeue
@@ -758,13 +767,13 @@ SnapBuildDistributeNewCatalogSnapshot(SnapBuild *builder, XLogRecPtr lsn)
758767 continue ;
759768
760769 /*
761- * We don't need to add snapshot to prepared transactions as they
762- * should not see the new catalog contents.
770+ * We don't need to add snapshot or invalidations to prepared
771+ * transactions as they should not see the new catalog contents.
763772 */
764773 if (rbtxn_is_prepared (txn ))
765774 continue ;
766775
767- elog (DEBUG2 , "adding a new snapshot to %u at %X/%X" ,
776+ elog (DEBUG2 , "adding a new snapshot and invalidations to %u at %X/%X" ,
768777 txn -> xid , LSN_FORMAT_ARGS (lsn ));
769778
770779 /*
@@ -774,6 +783,33 @@ SnapBuildDistributeNewCatalogSnapshot(SnapBuild *builder, XLogRecPtr lsn)
774783 SnapBuildSnapIncRefcount (builder -> snapshot );
775784 ReorderBufferAddSnapshot (builder -> reorder , txn -> xid , lsn ,
776785 builder -> snapshot );
786+
787+ /*
788+ * Add invalidation messages to the reorder buffer of in-progress
789+ * transactions except the current committed transaction, for which we
790+ * will execute invalidations at the end.
791+ *
792+ * It is required, otherwise, we will end up using the stale catcache
793+ * contents built by the current transaction even after its decoding,
794+ * which should have been invalidated due to concurrent catalog
795+ * changing transaction.
796+ */
797+ if (txn -> xid != xid )
798+ {
799+ uint32 ninvalidations ;
800+ SharedInvalidationMessage * msgs = NULL ;
801+
802+ ninvalidations = ReorderBufferGetInvalidations (builder -> reorder ,
803+ xid , & msgs );
804+
805+ if (ninvalidations > 0 )
806+ {
807+ Assert (msgs != NULL );
808+
809+ ReorderBufferAddInvalidations (builder -> reorder , txn -> xid , lsn ,
810+ ninvalidations , msgs );
811+ }
812+ }
777813 }
778814}
779815
@@ -1045,8 +1081,11 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid,
10451081 /* refcount of the snapshot builder for the new snapshot */
10461082 SnapBuildSnapIncRefcount (builder -> snapshot );
10471083
1048- /* add a new catalog snapshot to all currently running transactions */
1049- SnapBuildDistributeNewCatalogSnapshot (builder , lsn );
1084+ /*
1085+ * Add a new catalog snapshot and invalidations messages to all
1086+ * currently running transactions.
1087+ */
1088+ SnapBuildDistributeSnapshotAndInval (builder , lsn , xid );
10501089 }
10511090}
10521091
0 commit comments