Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Ensure snapshot is registered within ScanPgRelation().
authorAndres Freund <andres@anarazel.de>
Sat, 28 Mar 2020 18:52:11 +0000 (11:52 -0700)
committerAndres Freund <andres@anarazel.de>
Sat, 28 Mar 2020 19:05:05 +0000 (12:05 -0700)
In 9.4 I added support to use a historical snapshot in
ScanPgRelation(), while adding logical decoding. Unfortunately a
conflict with the concurrent removal of SnapshotNow was incorrectly
resolved, leading to an unregistered snapshot being used.

It is not correct to use an unregistered (or non-active) snapshot for
anything non-trivial, because catalog invalidations can cause the
snapshot to be invalidated.

Luckily it seems unlikely to actively cause problems in practice, as
ScanPgRelation() requires that we already have a lock on the relation,
we only look for a single row, and we don't appear to rely on the
result's tid to be correct. It however is clearly wrong and potential
negative consequences would likely be hard to find. So it seems worth
backpatching the fix, even without a concrete hazard.

Discussion: https://postgr.es/m/20200229052459.wzhqnbhrriezg4v2@alap3.anarazel.de
Backpatch: 9.5-

src/backend/utils/cache/relcache.c

index 6ec89fadd6cb6ab0bdf28e3a10ad792b45792684..038424da05faddad5281c75c9a384d47ed03eaa2 100644 (file)
@@ -300,7 +300,7 @@ ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
    Relation    pg_class_desc;
    SysScanDesc pg_class_scan;
    ScanKeyData key[1];
-   Snapshot    snapshot;
+   Snapshot    snapshot = NULL;
 
    /*
     * If something goes wrong during backend startup, we might find ourselves
@@ -330,12 +330,12 @@ ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
    /*
     * The caller might need a tuple that's newer than the one the historic
     * snapshot; currently the only case requiring to do so is looking up the
-    * relfilenode of non mapped system relations during decoding.
+    * relfilenode of non mapped system relations during decoding. That
+    * snapshot cant't change in the midst of a relcache build, so there's no
+    * need to register the snapshot.
     */
    if (force_non_historic)
        snapshot = GetNonHistoricCatalogSnapshot(RelationRelationId);
-   else
-       snapshot = GetCatalogSnapshot(RelationRelationId);
 
    pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
                                       indexOK && criticalRelcachesBuilt,