Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.

SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row.  In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result.  This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.

The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow.  However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads.  To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed.  The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all.  Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.

Patch by me.  Review by Michael Paquier and Andres Freund.
This commit is contained in:
Robert Haas 2013-07-02 09:47:01 -04:00
parent 384f933046
commit 568d4138c6
69 changed files with 617 additions and 353 deletions

View File

@ -2046,7 +2046,7 @@ get_pkey_attnames(Relation rel, int16 *numatts)
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(indexRelation, IndexIndrelidIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid(indexTuple = systable_getnext(scan)))
{

View File

@ -727,7 +727,7 @@ exec_object_restorecon(struct selabel_handle * sehnd, Oid catalogId)
rel = heap_open(catalogId, AccessShareLock);
sscan = systable_beginscan(rel, InvalidOid, false,
SnapshotNow, 0, NULL);
NULL, 0, NULL);
while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
{
Form_pg_database datForm;

View File

@ -713,7 +713,7 @@ amrestrpos (IndexScanDesc scan);
When using an MVCC-compliant snapshot, there is no problem because
the new occupant of the slot is certain to be too new to pass the
snapshot test. However, with a non-MVCC-compliant snapshot (such as
<literal>SnapshotNow</>), it would be possible to accept and return
<literal>SnapshotAny</>), it would be possible to accept and return
a row that does not in fact match the scan keys. We could defend
against this scenario by requiring the scan keys to be rechecked
against the heap row in all cases, but that is too expensive. Instead,

View File

@ -80,7 +80,7 @@ static HeapScanDesc heap_beginscan_internal(Relation relation,
Snapshot snapshot,
int nkeys, ScanKey key,
bool allow_strat, bool allow_sync,
bool is_bitmapscan);
bool is_bitmapscan, bool temp_snap);
static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup,
TransactionId xid, CommandId cid, int options);
static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
@ -1286,7 +1286,17 @@ heap_beginscan(Relation relation, Snapshot snapshot,
int nkeys, ScanKey key)
{
return heap_beginscan_internal(relation, snapshot, nkeys, key,
true, true, false);
true, true, false, false);
}
HeapScanDesc
heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
{
Oid relid = RelationGetRelid(relation);
Snapshot snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
return heap_beginscan_internal(relation, snapshot, nkeys, key,
true, true, false, true);
}
HeapScanDesc
@ -1295,7 +1305,7 @@ heap_beginscan_strat(Relation relation, Snapshot snapshot,
bool allow_strat, bool allow_sync)
{
return heap_beginscan_internal(relation, snapshot, nkeys, key,
allow_strat, allow_sync, false);
allow_strat, allow_sync, false, false);
}
HeapScanDesc
@ -1303,14 +1313,14 @@ heap_beginscan_bm(Relation relation, Snapshot snapshot,
int nkeys, ScanKey key)
{
return heap_beginscan_internal(relation, snapshot, nkeys, key,
false, false, true);
false, false, true, false);
}
static HeapScanDesc
heap_beginscan_internal(Relation relation, Snapshot snapshot,
int nkeys, ScanKey key,
bool allow_strat, bool allow_sync,
bool is_bitmapscan)
bool is_bitmapscan, bool temp_snap)
{
HeapScanDesc scan;
@ -1335,6 +1345,7 @@ heap_beginscan_internal(Relation relation, Snapshot snapshot,
scan->rs_strategy = NULL; /* set in initscan */
scan->rs_allow_strat = allow_strat;
scan->rs_allow_sync = allow_sync;
scan->rs_temp_snap = temp_snap;
/*
* we can use page-at-a-time mode if it's an MVCC-safe snapshot
@ -1421,6 +1432,9 @@ heap_endscan(HeapScanDesc scan)
if (scan->rs_strategy != NULL)
FreeAccessStrategy(scan->rs_strategy);
if (scan->rs_temp_snap)
UnregisterSnapshot(scan->rs_snapshot);
pfree(scan);
}

View File

@ -28,6 +28,7 @@
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
@ -231,7 +232,7 @@ BuildIndexValueDescription(Relation indexRelation,
* rel: catalog to scan, already opened and suitably locked
* indexId: OID of index to conditionally use
* indexOK: if false, forces a heap scan (see notes below)
* snapshot: time qual to use (usually should be SnapshotNow)
* snapshot: time qual to use (NULL for a recent catalog snapshot)
* nkeys, key: scan keys
*
* The attribute numbers in the scan key should be set for the heap case.
@ -266,6 +267,19 @@ systable_beginscan(Relation heapRelation,
sysscan->heap_rel = heapRelation;
sysscan->irel = irel;
if (snapshot == NULL)
{
Oid relid = RelationGetRelid(heapRelation);
snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
sysscan->snapshot = snapshot;
}
else
{
/* Caller is responsible for any snapshot. */
sysscan->snapshot = NULL;
}
if (irel)
{
int i;
@ -401,6 +415,9 @@ systable_endscan(SysScanDesc sysscan)
else
heap_endscan(sysscan->scan);
if (sysscan->snapshot)
UnregisterSnapshot(sysscan->snapshot);
pfree(sysscan);
}
@ -444,6 +461,19 @@ systable_beginscan_ordered(Relation heapRelation,
sysscan->heap_rel = heapRelation;
sysscan->irel = indexRelation;
if (snapshot == NULL)
{
Oid relid = RelationGetRelid(heapRelation);
snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
sysscan->snapshot = snapshot;
}
else
{
/* Caller is responsible for any snapshot. */
sysscan->snapshot = NULL;
}
/* Change attribute numbers to be index column numbers. */
for (i = 0; i < nkeys; i++)
{
@ -494,5 +524,7 @@ systable_endscan_ordered(SysScanDesc sysscan)
{
Assert(sysscan->irel);
index_endscan(sysscan->iscan);
if (sysscan->snapshot)
UnregisterSnapshot(sysscan->snapshot);
pfree(sysscan);
}

View File

@ -141,9 +141,10 @@ deletes index entries before deleting tuples, the super-exclusive lock
guarantees that VACUUM can't delete any heap tuple that an indexscanning
process might be about to visit. (This guarantee works only for simple
indexscans that visit the heap in sync with the index scan, not for bitmap
scans. We only need the guarantee when using non-MVCC snapshot rules such
as SnapshotNow, so in practice this is only important for system catalog
accesses.)
scans. We only need the guarantee when using non-MVCC snapshot rules; in
an MVCC snapshot, it wouldn't matter if the heap tuple were replaced with
an unrelated tuple at the same TID, because the new tuple wouldn't be
visible to our scan anyway.)
Because a page can be split even while someone holds a pin on it, it is
possible that an indexscan will return items that are no longer stored on

View File

@ -69,11 +69,14 @@ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
appendStringInfo(buf, " catalog %u", msg->cat.catId);
else if (msg->id == SHAREDINVALRELCACHE_ID)
appendStringInfo(buf, " relcache %u", msg->rc.relId);
/* remaining cases not expected, but print something anyway */
/* not expected, but print something anyway */
else if (msg->id == SHAREDINVALSMGR_ID)
appendStringInfo(buf, " smgr");
/* not expected, but print something anyway */
else if (msg->id == SHAREDINVALRELMAP_ID)
appendStringInfo(buf, " relmap");
else if (msg->id == SHAREDINVALSNAPSHOT_ID)
appendStringInfo(buf, " snapshot %u", msg->sn.relId);
else
appendStringInfo(buf, " unknown id %d", msg->id);
}

View File

@ -611,7 +611,7 @@ boot_openrel(char *relname)
{
/* We can now load the pg_type data */
rel = heap_open(TypeRelationId, NoLock);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
i = 0;
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
++i;
@ -620,7 +620,7 @@ boot_openrel(char *relname)
while (i-- > 0)
*app++ = ALLOC(struct typmap, 1);
*app = NULL;
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
app = Typ;
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
@ -918,7 +918,7 @@ gettype(char *type)
}
elog(DEBUG4, "external type: %s", type);
rel = heap_open(TypeRelationId, NoLock);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
i = 0;
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
++i;
@ -927,7 +927,7 @@ gettype(char *type)
while (i-- > 0)
*app++ = ALLOC(struct typmap, 1);
*app = NULL;
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
app = Typ;
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
{

View File

@ -788,7 +788,7 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
ObjectIdGetDatum(namespaceId));
rel = heap_open(ProcedureRelationId, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow, 1, key);
scan = heap_beginscan_catalog(rel, 1, key);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
@ -833,7 +833,7 @@ getRelationsInNamespace(Oid namespaceId, char relkind)
CharGetDatum(relkind));
rel = heap_open(RelationRelationId, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow, 2, key);
scan = heap_beginscan_catalog(rel, 2, key);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
@ -1332,7 +1332,7 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
ObjectIdGetDatum(objid));
scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tuple = systable_getnext(scan);
@ -1452,7 +1452,7 @@ RemoveDefaultACLById(Oid defaclOid)
ObjectIdGetDatum(defaclOid));
scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tuple = systable_getnext(scan);
@ -2705,7 +2705,7 @@ ExecGrant_Largeobject(InternalGrant *istmt)
scan = systable_beginscan(relation,
LargeObjectMetadataOidIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
@ -3468,7 +3468,7 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
return pg_language_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_LARGEOBJECT:
return pg_largeobject_aclmask_snapshot(table_oid, roleid,
mask, how, SnapshotNow);
mask, how, NULL);
case ACL_KIND_NAMESPACE:
return pg_namespace_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_TABLESPACE:
@ -3856,10 +3856,13 @@ pg_language_aclmask(Oid lang_oid, Oid roleid,
* Exported routine for examining a user's privileges for a largeobject
*
* When a large object is opened for reading, it is opened relative to the
* caller's snapshot, but when it is opened for writing, it is always relative
* to SnapshotNow, as documented in doc/src/sgml/lobj.sgml. This function
* takes a snapshot argument so that the permissions check can be made relative
* to the same snapshot that will be used to read the underlying data.
* caller's snapshot, but when it is opened for writing, a current
* MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
* takes a snapshot argument so that the permissions check can be made
* relative to the same snapshot that will be used to read the underlying
* data. The caller will actually pass NULL for an instantaneous MVCC
* snapshot, since all we do with the snapshot argument is pass it through
* to systable_beginscan().
*/
AclMode
pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
@ -4644,7 +4647,7 @@ pg_language_ownercheck(Oid lan_oid, Oid roleid)
* Ownership check for a largeobject (specified by OID)
*
* This is only used for operations like ALTER LARGE OBJECT that are always
* relative to SnapshotNow.
* relative to an up-to-date snapshot.
*/
bool
pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
@ -4670,7 +4673,7 @@ pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
scan = systable_beginscan(pg_lo_meta,
LargeObjectMetadataOidIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
@ -5032,7 +5035,7 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid)
scan = systable_beginscan(pg_extension,
ExtensionOidIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))

View File

@ -218,20 +218,16 @@ IsReservedName(const char *name)
* Given the OID of a relation, determine whether it's supposed to be
* shared across an entire database cluster.
*
* Hard-wiring this list is pretty grotty, but we really need it so that
* we can compute the locktag for a relation (and then lock it) without
* having already read its pg_class entry. If we try to retrieve relisshared
* from pg_class with no pre-existing lock, there is a race condition against
* anyone who is concurrently committing a change to the pg_class entry:
* since we read system catalog entries under SnapshotNow, it's possible
* that both the old and new versions of the row are invalid at the instants
* we scan them. We fix this by insisting that updaters of a pg_class
* row must hold exclusive lock on the corresponding rel, and that users
* of a relation must hold at least AccessShareLock on the rel *before*
* trying to open its relcache entry. But to lock a rel, you have to
* know if it's shared. Fortunately, the set of shared relations is
* fairly static, so a hand-maintained list of their OIDs isn't completely
* impractical.
* In older releases, this had to be hard-wired so that we could compute the
* locktag for a relation and lock it before examining its catalog entry.
* Since we now have MVCC catalog access, the race conditions that made that
* a hard requirement are gone, so we could look at relaxing this restriction.
* However, if we scanned the pg_class entry to find relisshared, and only
* then locked the relation, pg_class could get updated in the meantime,
* forcing us to scan the relation again, which would definitely be complex
* and might have undesirable performance consequences. Fortunately, the set
* of shared relations is fairly static, so a hand-maintained list of their
* OIDs isn't completely impractical.
*/
bool
IsSharedRelation(Oid relationId)

View File

@ -558,7 +558,7 @@ findDependentObjects(const ObjectAddress *object,
nkeys = 2;
scan = systable_beginscan(*depRel, DependDependerIndexId, true,
SnapshotNow, nkeys, key);
NULL, nkeys, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -733,7 +733,7 @@ findDependentObjects(const ObjectAddress *object,
nkeys = 2;
scan = systable_beginscan(*depRel, DependReferenceIndexId, true,
SnapshotNow, nkeys, key);
NULL, nkeys, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -1069,7 +1069,7 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
nkeys = 2;
scan = systable_beginscan(*depRel, DependDependerIndexId, true,
SnapshotNow, nkeys, key);
NULL, nkeys, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{

View File

@ -1386,7 +1386,7 @@ RelationRemoveInheritance(Oid relid)
ObjectIdGetDatum(relid));
scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
SnapshotNow, 1, &key);
NULL, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
simple_heap_delete(catalogRelation, &tuple->t_self);
@ -1450,7 +1450,7 @@ DeleteAttributeTuples(Oid relid)
ObjectIdGetDatum(relid));
scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
/* Delete all the matching tuples */
while ((atttup = systable_getnext(scan)) != NULL)
@ -1491,7 +1491,7 @@ DeleteSystemAttributeTuples(Oid relid)
Int16GetDatum(0));
scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
/* Delete all the matching tuples */
while ((atttup = systable_getnext(scan)) != NULL)
@ -1623,7 +1623,7 @@ RemoveAttrDefault(Oid relid, AttrNumber attnum,
Int16GetDatum(attnum));
scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
SnapshotNow, 2, scankeys);
NULL, 2, scankeys);
/* There should be at most one matching tuple, but we loop anyway */
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
@ -1677,7 +1677,7 @@ RemoveAttrDefaultById(Oid attrdefId)
ObjectIdGetDatum(attrdefId));
scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
SnapshotNow, 1, scankeys);
NULL, 1, scankeys);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
@ -2374,7 +2374,7 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
ObjectIdGetDatum(RelationGetNamespace(rel)));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
{
@ -2640,7 +2640,7 @@ RemoveStatistics(Oid relid, AttrNumber attnum)
}
scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
SnapshotNow, nkeys, key);
NULL, nkeys, key);
/* we must loop even when attnum != 0, in case of inherited stats */
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
@ -2885,7 +2885,7 @@ heap_truncate_find_FKs(List *relationIds)
fkeyRel = heap_open(ConstraintRelationId, AccessShareLock);
fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
SnapshotNow, 0, NULL);
NULL, 0, NULL);
while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
{

View File

@ -1845,7 +1845,7 @@ index_update_stats(Relation rel,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
pg_class_scan = heap_beginscan_catalog(pg_class, 1, key);
tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
tuple = heap_copytuple(tuple);
heap_endscan(pg_class_scan);
@ -2181,15 +2181,10 @@ IndexBuildHeapScan(Relation heapRelation,
* Prepare for scan of the base relation. In a normal index build, we use
* SnapshotAny because we must retrieve all tuples and do our own time
* qual checks (because we have to index RECENTLY_DEAD tuples). In a
* concurrent build, we take a regular MVCC snapshot and index whatever's
* live according to that. During bootstrap we just use SnapshotNow.
* concurrent build, or during bootstrap, we take a regular MVCC snapshot
* and index whatever's live according to that.
*/
if (IsBootstrapProcessingMode())
{
snapshot = SnapshotNow;
OldestXmin = InvalidTransactionId; /* not used */
}
else if (indexInfo->ii_Concurrent)
if (IsBootstrapProcessingMode() || indexInfo->ii_Concurrent)
{
snapshot = RegisterSnapshot(GetTransactionSnapshot());
OldestXmin = InvalidTransactionId; /* not used */
@ -2500,7 +2495,7 @@ IndexBuildHeapScan(Relation heapRelation,
heap_endscan(scan);
/* we can now forget our snapshot, if set */
if (indexInfo->ii_Concurrent)
if (IsBootstrapProcessingMode() || indexInfo->ii_Concurrent)
UnregisterSnapshot(snapshot);
ExecDropSingleTupleTableSlot(slot);
@ -2520,10 +2515,10 @@ IndexBuildHeapScan(Relation heapRelation,
*
* When creating an exclusion constraint, we first build the index normally
* and then rescan the heap to check for conflicts. We assume that we only
* need to validate tuples that are live according to SnapshotNow, and that
* these were correctly indexed even in the presence of broken HOT chains.
* This should be OK since we are holding at least ShareLock on the table,
* meaning there can be no uncommitted updates from other transactions.
* need to validate tuples that are live according to an up-to-date snapshot,
* and that these were correctly indexed even in the presence of broken HOT
* chains. This should be OK since we are holding at least ShareLock on the
* table, meaning there can be no uncommitted updates from other transactions.
* (Note: that wouldn't necessarily work for system catalogs, since many
* operations release write lock early on the system catalogs.)
*/
@ -2540,6 +2535,7 @@ IndexCheckExclusion(Relation heapRelation,
TupleTableSlot *slot;
EState *estate;
ExprContext *econtext;
Snapshot snapshot;
/*
* If we are reindexing the target index, mark it as no longer being
@ -2568,8 +2564,9 @@ IndexCheckExclusion(Relation heapRelation,
/*
* Scan all live tuples in the base relation.
*/
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan_strat(heapRelation, /* relation */
SnapshotNow, /* snapshot */
snapshot, /* snapshot */
0, /* number of keys */
NULL, /* scan key */
true, /* buffer access strategy OK */
@ -2612,6 +2609,7 @@ IndexCheckExclusion(Relation heapRelation,
}
heap_endscan(scan);
UnregisterSnapshot(snapshot);
ExecDropSingleTupleTableSlot(slot);

View File

@ -4013,8 +4013,8 @@ fetch_search_path_array(Oid *sarray, int sarray_len)
* a nonexistent object OID, rather than failing. This is to avoid race
* condition errors when a query that's scanning a catalog using an MVCC
* snapshot uses one of these functions. The underlying IsVisible functions
* operate on SnapshotNow semantics and so might see the object as already
* gone when it's still visible to the MVCC snapshot. (There is no race
* always use an up-to-date snapshot and so might see the object as already
* gone when it's still visible to the transaction snapshot. (There is no race
* condition in the current coding because we don't accept sinval messages
* between the SearchSysCacheExists test and the subsequent lookup.)
*/

View File

@ -1481,7 +1481,7 @@ get_catalog_object_by_oid(Relation catalog, Oid objectId)
ObjectIdGetDatum(objectId));
scan = systable_beginscan(catalog, oidIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
{
@ -1544,7 +1544,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(rcscan);
@ -1644,7 +1644,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
true, SnapshotNow, 1, skey);
true, NULL, 1, skey);
tup = systable_getnext(adscan);
@ -1750,7 +1750,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(amscan);
@ -1800,7 +1800,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(amscan);
@ -1848,7 +1848,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(rcscan);
@ -1883,7 +1883,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(tgscan);
@ -2064,7 +2064,7 @@ getObjectDescription(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
true, SnapshotNow, 1, skey);
true, NULL, 1, skey);
tup = systable_getnext(rcscan);
@ -2816,7 +2816,7 @@ getObjectIdentity(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
true, SnapshotNow, 1, skey);
true, NULL, 1, skey);
tup = systable_getnext(adscan);
@ -2921,7 +2921,7 @@ getObjectIdentity(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(amscan);
@ -2965,7 +2965,7 @@ getObjectIdentity(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(amscan);
@ -3218,7 +3218,7 @@ getObjectIdentity(const ObjectAddress *object)
ObjectIdGetDatum(object->objectId));
rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
true, SnapshotNow, 1, skey);
true, NULL, 1, skey);
tup = systable_getnext(rcscan);

View File

@ -166,7 +166,7 @@ RemoveCollationById(Oid collationOid)
ObjectIdGetDatum(collationOid));
scandesc = systable_beginscan(rel, CollationOidIndexId, true,
SnapshotNow, 1, &scanKeyData);
NULL, 1, &scanKeyData);
tuple = systable_getnext(scandesc);

View File

@ -412,7 +412,7 @@ ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
ObjectIdGetDatum(objNamespace));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
{
@ -506,7 +506,7 @@ ChooseConstraintName(const char *name1, const char *name2,
ObjectIdGetDatum(namespaceid));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
found = (HeapTupleIsValid(systable_getnext(conscan)));
@ -699,7 +699,7 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
ObjectIdGetDatum(ownerId));
scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
}
else
{
@ -709,7 +709,7 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
ObjectIdGetDatum(ownerId));
scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
}
while (HeapTupleIsValid((tup = systable_getnext(scan))))
@ -778,7 +778,7 @@ get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
ObjectIdGetDatum(relid));
scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
@ -836,7 +836,7 @@ get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
ObjectIdGetDatum(typid));
scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
@ -903,7 +903,7 @@ check_functional_grouping(Oid relid,
ObjectIdGetDatum(relid));
scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{

View File

@ -166,8 +166,7 @@ RemoveConversionById(Oid conversionOid)
/* open pg_conversion */
rel = heap_open(ConversionRelationId, RowExclusiveLock);
scan = heap_beginscan(rel, SnapshotNow,
1, &scanKeyData);
scan = heap_beginscan_catalog(rel, 1, &scanKeyData);
/* search for the target tuple */
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))

View File

@ -43,7 +43,7 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(roleid));
scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
SnapshotNow, 2, scankey);
NULL, 2, scankey);
tuple = systable_getnext(scan);
/*
@ -205,7 +205,7 @@ DropSetting(Oid databaseid, Oid roleid)
numkeys++;
}
scan = heap_beginscan(relsetting, SnapshotNow, numkeys, keys);
scan = heap_beginscan_catalog(relsetting, numkeys, keys);
while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
{
simple_heap_delete(relsetting, &tup->t_self);
@ -226,7 +226,8 @@ DropSetting(Oid databaseid, Oid roleid)
* databaseid/roleid.
*/
void
ApplySetting(Oid databaseid, Oid roleid, Relation relsetting, GucSource source)
ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
Relation relsetting, GucSource source)
{
SysScanDesc scan;
ScanKeyData keys[2];
@ -244,7 +245,7 @@ ApplySetting(Oid databaseid, Oid roleid, Relation relsetting, GucSource source)
ObjectIdGetDatum(roleid));
scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
SnapshotNow, 2, keys);
snapshot, 2, keys);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
bool isnull;

View File

@ -211,7 +211,7 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId,
ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -261,7 +261,7 @@ deleteDependencyRecordsForClass(Oid classId, Oid objectId,
ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -343,7 +343,7 @@ changeDependencyFor(Oid classId, Oid objectId,
ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
@ -407,7 +407,7 @@ isObjectPinned(const ObjectAddress *object, Relation rel)
ObjectIdGetDatum(object->objectId));
scan = systable_beginscan(rel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
/*
* Since we won't generate additional pg_depend entries for pinned
@ -467,7 +467,7 @@ getExtensionOfObject(Oid classId, Oid objectId)
ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
@ -520,7 +520,7 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
ObjectIdGetDatum(seqId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
@ -580,7 +580,7 @@ getOwnedSequences(Oid relid)
ObjectIdGetDatum(relid));
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -643,7 +643,7 @@ get_constraint_index(Oid constraintId)
Int32GetDatum(0));
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 3, key);
NULL, 3, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -701,7 +701,7 @@ get_index_constraint(Oid indexId)
Int32GetDatum(0));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 3, key);
NULL, 3, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{

View File

@ -156,7 +156,7 @@ EnumValuesDelete(Oid enumTypeOid)
ObjectIdGetDatum(enumTypeOid));
scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -483,6 +483,9 @@ restart:
* (for example, enum_in and enum_out do so). The worst that can happen
* is a transient failure to find any valid value of the row. This is
* judged acceptable in view of the infrequency of use of RenumberEnumType.
*
* XXX. Now that we have MVCC catalog scans, the above reasoning is no longer
* correct. Should we revisit any decisions here?
*/
static void
RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)

View File

@ -81,7 +81,7 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
ObjectIdGetDatum(parentrelId));
scan = systable_beginscan(relation, InheritsParentIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
while ((inheritsTuple = systable_getnext(scan)) != NULL)
{
@ -325,7 +325,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
ObjectIdGetDatum(this_relid));
inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while ((inhtup = systable_getnext(inhscan)) != NULL)
{

View File

@ -104,7 +104,7 @@ LargeObjectDrop(Oid loid)
scan = systable_beginscan(pg_lo_meta,
LargeObjectMetadataOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
@ -126,7 +126,7 @@ LargeObjectDrop(Oid loid)
scan = systable_beginscan(pg_largeobject,
LargeObjectLOidPNIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
simple_heap_delete(pg_largeobject, &tuple->t_self);
@ -145,11 +145,11 @@ LargeObjectDrop(Oid loid)
* We don't use the system cache for large object metadata, for fear of
* using too much local memory.
*
* This function always scans the system catalog using SnapshotNow, so it
* should not be used when a large object is opened in read-only mode (because
* large objects opened in read only mode are supposed to be viewed relative
* to the caller's snapshot, whereas in read-write mode they are relative to
* SnapshotNow).
* This function always scans the system catalog using an up-to-date snapshot,
* so it should not be used when a large object is opened in read-only mode
* (because large objects opened in read only mode are supposed to be viewed
* relative to the caller's snapshot, whereas in read-write mode they are
* relative to a current snapshot).
*/
bool
LargeObjectExists(Oid loid)
@ -170,7 +170,7 @@ LargeObjectExists(Oid loid)
sd = systable_beginscan(pg_lo_meta,
LargeObjectMetadataOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tuple = systable_getnext(sd);
if (HeapTupleIsValid(tuple))

View File

@ -126,7 +126,7 @@ RangeDelete(Oid rangeTypeOid)
ObjectIdGetDatum(rangeTypeOid));
scan = systable_beginscan(pg_range, RangeTypidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{

View File

@ -220,7 +220,7 @@ shdepChangeDep(Relation sdepRel,
Int32GetDatum(objsubid));
scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
SnapshotNow, 4, key);
NULL, 4, key);
while ((scantup = systable_getnext(scan)) != NULL)
{
@ -554,7 +554,7 @@ checkSharedDependencies(Oid classId, Oid objectId,
ObjectIdGetDatum(objectId));
scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -729,7 +729,7 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId)
ObjectIdGetDatum(templateDbId));
scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
/* Set up to copy the tuples except for inserting newDbId */
memset(values, 0, sizeof(values));
@ -792,7 +792,7 @@ dropDatabaseDependencies(Oid databaseId)
/* We leave the other index fields unspecified */
scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -936,7 +936,7 @@ shdepDropDependency(Relation sdepRel,
}
scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
SnapshotNow, nkeys, key);
NULL, nkeys, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -1125,7 +1125,7 @@ isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
ObjectIdGetDatum(objectId));
scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
/*
* Since we won't generate additional pg_shdepend entries for pinned
@ -1212,7 +1212,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
ObjectIdGetDatum(roleid));
scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while ((tuple = systable_getnext(scan)) != NULL)
{
@ -1319,7 +1319,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
ObjectIdGetDatum(roleid));
scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while ((tuple = systable_getnext(scan)) != NULL)
{

View File

@ -480,6 +480,11 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
* against concurrent SnapshotNow scans of pg_index. Therefore this is unsafe
* to execute with less than full exclusive lock on the parent table;
* otherwise concurrent executions of RelationGetIndexList could miss indexes.
*
* XXX: Now that we have MVCC catalog access, SnapshotNow scans of pg_index
* shouldn't be common enough to worry about. The above comment needs
* to be updated, and it may be possible to simplify the logic here in other
* ways also.
*/
void
mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
@ -1583,7 +1588,7 @@ get_tables_to_cluster(MemoryContext cluster_context)
Anum_pg_index_indisclustered,
BTEqualStrategyNumber, F_BOOLEQ,
BoolGetDatum(true));
scan = heap_beginscan(indRelation, SnapshotNow, 1, &entry);
scan = heap_beginscan_catalog(indRelation, 1, &entry);
while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
index = (Form_pg_index) GETSTRUCT(indexTuple);

View File

@ -187,7 +187,7 @@ CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
description = heap_open(DescriptionRelationId, RowExclusiveLock);
sd = systable_beginscan(description, DescriptionObjIndexId, true,
SnapshotNow, 3, skey);
NULL, 3, skey);
while ((oldtuple = systable_getnext(sd)) != NULL)
{
@ -281,7 +281,7 @@ CreateSharedComments(Oid oid, Oid classoid, char *comment)
shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while ((oldtuple = systable_getnext(sd)) != NULL)
{
@ -363,7 +363,7 @@ DeleteComments(Oid oid, Oid classoid, int32 subid)
description = heap_open(DescriptionRelationId, RowExclusiveLock);
sd = systable_beginscan(description, DescriptionObjIndexId, true,
SnapshotNow, nkeys, skey);
NULL, nkeys, skey);
while ((oldtuple = systable_getnext(sd)) != NULL)
simple_heap_delete(description, &oldtuple->t_self);
@ -399,7 +399,7 @@ DeleteSharedComments(Oid oid, Oid classoid)
shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while ((oldtuple = systable_getnext(sd)) != NULL)
simple_heap_delete(shdescription, &oldtuple->t_self);
@ -442,7 +442,7 @@ GetComment(Oid oid, Oid classoid, int32 subid)
tupdesc = RelationGetDescr(description);
sd = systable_beginscan(description, DescriptionObjIndexId, true,
SnapshotNow, 3, skey);
NULL, 3, skey);
comment = NULL;
while ((tuple = systable_getnext(sd)) != NULL)

View File

@ -133,7 +133,6 @@ createdb(const CreatedbStmt *stmt)
int notherbackends;
int npreparedxacts;
createdb_failure_params fparms;
Snapshot snapshot;
/* Extract options from the statement node tree */
foreach(option, stmt->options)
@ -537,29 +536,6 @@ createdb(const CreatedbStmt *stmt)
*/
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
/*
* Take an MVCC snapshot to use while scanning through pg_tablespace. For
* safety, register the snapshot (this prevents it from changing if
* something else were to request a snapshot during the loop).
*
* Traversing pg_tablespace with an MVCC snapshot is necessary to provide
* us with a consistent view of the tablespaces that exist. Using
* SnapshotNow here would risk seeing the same tablespace multiple times,
* or worse not seeing a tablespace at all, if its tuple is moved around
* by a concurrent update (eg an ACL change).
*
* Inconsistency of this sort is inherent to all SnapshotNow scans, unless
* some lock is held to prevent concurrent updates of the rows being
* sought. There should be a generic fix for that, but in the meantime
* it's worth fixing this case in particular because we are doing very
* heavyweight operations within the scan, so that the elapsed time for
* the scan is vastly longer than for most other catalog scans. That
* means there's a much wider window for concurrent updates to cause
* trouble here than anywhere else. XXX this code should be changed
* whenever a generic fix is implemented.
*/
snapshot = RegisterSnapshot(GetLatestSnapshot());
/*
* Once we start copying subdirectories, we need to be able to clean 'em
* up if we fail. Use an ENSURE block to make sure this happens. (This
@ -577,7 +553,7 @@ createdb(const CreatedbStmt *stmt)
* each one to the new database.
*/
rel = heap_open(TableSpaceRelationId, AccessShareLock);
scan = heap_beginscan(rel, snapshot, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Oid srctablespace = HeapTupleGetOid(tuple);
@ -682,9 +658,6 @@ createdb(const CreatedbStmt *stmt)
PG_END_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
PointerGetDatum(&fparms));
/* Free our snapshot */
UnregisterSnapshot(snapshot);
return dboid;
}
@ -1214,7 +1187,7 @@ movedb(const char *dbname, const char *tblspcname)
BTEqualStrategyNumber, F_NAMEEQ,
NameGetDatum(dbname));
sysscan = systable_beginscan(pgdbrel, DatabaseNameIndexId, true,
SnapshotNow, 1, &scankey);
NULL, 1, &scankey);
oldtuple = systable_getnext(sysscan);
if (!HeapTupleIsValid(oldtuple)) /* shouldn't happen... */
ereport(ERROR,
@ -1403,7 +1376,7 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
BTEqualStrategyNumber, F_NAMEEQ,
NameGetDatum(stmt->dbname));
scan = systable_beginscan(rel, DatabaseNameIndexId, true,
SnapshotNow, 1, &scankey);
NULL, 1, &scankey);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
@ -1498,7 +1471,7 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
BTEqualStrategyNumber, F_NAMEEQ,
NameGetDatum(dbname));
scan = systable_beginscan(rel, DatabaseNameIndexId, true,
SnapshotNow, 1, &scankey);
NULL, 1, &scankey);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
@ -1637,7 +1610,7 @@ get_db_info(const char *name, LOCKMODE lockmode,
NameGetDatum(name));
scan = systable_beginscan(relation, DatabaseNameIndexId, true,
SnapshotNow, 1, &scanKey);
NULL, 1, &scanKey);
tuple = systable_getnext(scan);
@ -1751,20 +1724,9 @@ remove_dbtablespaces(Oid db_id)
Relation rel;
HeapScanDesc scan;
HeapTuple tuple;
Snapshot snapshot;
/*
* As in createdb(), we'd better use an MVCC snapshot here, since this
* scan can run for a long time. Duplicate visits to tablespaces would be
* harmless, but missing a tablespace could result in permanently leaked
* files.
*
* XXX change this when a generic fix for SnapshotNow races is implemented
*/
snapshot = RegisterSnapshot(GetLatestSnapshot());
rel = heap_open(TableSpaceRelationId, AccessShareLock);
scan = heap_beginscan(rel, snapshot, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Oid dsttablespace = HeapTupleGetOid(tuple);
@ -1810,7 +1772,6 @@ remove_dbtablespaces(Oid db_id)
heap_endscan(scan);
heap_close(rel, AccessShareLock);
UnregisterSnapshot(snapshot);
}
/*
@ -1832,19 +1793,9 @@ check_db_file_conflict(Oid db_id)
Relation rel;
HeapScanDesc scan;
HeapTuple tuple;
Snapshot snapshot;
/*
* As in createdb(), we'd better use an MVCC snapshot here; missing a
* tablespace could result in falsely reporting the OID is unique, with
* disastrous future consequences per the comment above.
*
* XXX change this when a generic fix for SnapshotNow races is implemented
*/
snapshot = RegisterSnapshot(GetLatestSnapshot());
rel = heap_open(TableSpaceRelationId, AccessShareLock);
scan = heap_beginscan(rel, snapshot, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Oid dsttablespace = HeapTupleGetOid(tuple);
@ -1870,7 +1821,6 @@ check_db_file_conflict(Oid db_id)
heap_endscan(scan);
heap_close(rel, AccessShareLock);
UnregisterSnapshot(snapshot);
return result;
}
@ -1927,7 +1877,7 @@ get_database_oid(const char *dbname, bool missing_ok)
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(dbname));
scan = systable_beginscan(pg_database, DatabaseNameIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
dbtuple = systable_getnext(scan);

View File

@ -128,7 +128,7 @@ get_extension_oid(const char *extname, bool missing_ok)
CStringGetDatum(extname));
scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scandesc);
@ -173,7 +173,7 @@ get_extension_name(Oid ext_oid)
ObjectIdGetDatum(ext_oid));
scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scandesc);
@ -212,7 +212,7 @@ get_extension_schema(Oid ext_oid)
ObjectIdGetDatum(ext_oid));
scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scandesc);
@ -1609,7 +1609,7 @@ RemoveExtensionById(Oid extId)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(extId));
scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
SnapshotNow, 1, entry);
NULL, 1, entry);
tuple = systable_getnext(scandesc);
@ -2107,7 +2107,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
ObjectIdGetDatum(CurrentExtensionObject));
extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
extTup = systable_getnext(extScan);
@ -2256,7 +2256,7 @@ extension_config_remove(Oid extensionoid, Oid tableoid)
ObjectIdGetDatum(extensionoid));
extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
extTup = systable_getnext(extScan);
@ -2464,7 +2464,7 @@ AlterExtensionNamespace(List *names, const char *newschema)
ObjectIdGetDatum(extensionOid));
extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
extTup = systable_getnext(extScan);
@ -2512,7 +2512,7 @@ AlterExtensionNamespace(List *names, const char *newschema)
ObjectIdGetDatum(extensionOid));
depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
{
@ -2622,7 +2622,7 @@ ExecAlterExtensionStmt(AlterExtensionStmt *stmt)
CStringGetDatum(stmt->extname));
extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
extTup = systable_getnext(extScan);
@ -2772,7 +2772,7 @@ ApplyExtensionUpdates(Oid extensionOid,
ObjectIdGetDatum(extensionOid));
extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
extTup = systable_getnext(extScan);

View File

@ -1607,7 +1607,7 @@ DropCastById(Oid castOid)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(castOid));
scan = systable_beginscan(relation, CastOidIndexId, true,
SnapshotNow, 1, &scankey);
NULL, 1, &scankey);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))

View File

@ -1358,7 +1358,7 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
ObjectIdGetDatum(am_id));
scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -1838,7 +1838,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
* indirectly by reindex_relation).
*/
relationRelation = heap_open(RelationRelationId, AccessShareLock);
scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(relationRelation, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);

View File

@ -614,7 +614,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
ObjectIdGetDatum(amoid));
scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -1622,7 +1622,7 @@ RemoveAmOpEntryById(Oid entryOid)
rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
/* we expect exactly one match */
tup = systable_getnext(scan);
@ -1651,7 +1651,7 @@ RemoveAmProcEntryById(Oid entryOid)
rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
/* we expect exactly one match */
tup = systable_getnext(scan);

View File

@ -455,7 +455,7 @@ find_language_template(const char *languageName)
BTEqualStrategyNumber, F_NAMEEQ,
NameGetDatum(languageName));
scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
SnapshotNow, 1, &key);
NULL, 1, &key);
tup = systable_getnext(scan);
if (HeapTupleIsValid(tup))

View File

@ -167,7 +167,7 @@ GetSharedSecurityLabel(const ObjectAddress *object, const char *provider)
pg_shseclabel = heap_open(SharedSecLabelRelationId, AccessShareLock);
scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
SnapshotNow, 3, keys);
NULL, 3, keys);
tuple = systable_getnext(scan);
if (HeapTupleIsValid(tuple))
@ -224,7 +224,7 @@ GetSecurityLabel(const ObjectAddress *object, const char *provider)
pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
SnapshotNow, 4, keys);
NULL, 4, keys);
tuple = systable_getnext(scan);
if (HeapTupleIsValid(tuple))
@ -284,7 +284,7 @@ SetSharedSecurityLabel(const ObjectAddress *object,
pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock);
scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
SnapshotNow, 3, keys);
NULL, 3, keys);
oldtup = systable_getnext(scan);
if (HeapTupleIsValid(oldtup))
@ -375,7 +375,7 @@ SetSecurityLabel(const ObjectAddress *object,
pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
SnapshotNow, 4, keys);
NULL, 4, keys);
oldtup = systable_getnext(scan);
if (HeapTupleIsValid(oldtup))
@ -434,7 +434,7 @@ DeleteSharedSecurityLabel(Oid objectId, Oid classId)
pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock);
scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
simple_heap_delete(pg_shseclabel, &oldtup->t_self);
systable_endscan(scan);
@ -485,7 +485,7 @@ DeleteSecurityLabel(const ObjectAddress *object)
pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
SnapshotNow, nkeys, skey);
NULL, nkeys, skey);
while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
simple_heap_delete(pg_seclabel, &oldtup->t_self);
systable_endscan(scan);

View File

@ -2741,7 +2741,7 @@ AlterTableGetLockLevel(List *cmds)
* multiple DDL operations occur in a stream against frequently accessed
* tables.
*
* 1. Catalog tables are read using SnapshotNow, which has a race bug that
* 1. Catalog tables were read using SnapshotNow, which has a race bug that
* allows a scan to return no valid rows even when one is present in the
* case of a commit of a concurrent update of the catalog table.
* SnapshotNow also ignores transactions in progress, so takes the latest
@ -3753,6 +3753,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
MemoryContext oldCxt;
List *dropped_attrs = NIL;
ListCell *lc;
Snapshot snapshot;
if (newrel)
ereport(DEBUG1,
@ -3805,7 +3806,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
* Scan through the rows, generating a new row if needed and then
* checking all the constraints.
*/
scan = heap_beginscan(oldrel, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(oldrel, snapshot, 0, NULL);
/*
* Switch to per-tuple memory context and reset it for each tuple
@ -3906,6 +3908,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
MemoryContextSwitchTo(oldCxt);
heap_endscan(scan);
UnregisterSnapshot(snapshot);
ExecDropSingleTupleTableSlot(oldslot);
ExecDropSingleTupleTableSlot(newslot);
@ -4182,7 +4185,7 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
ObjectIdGetDatum(typeOid));
depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
{
@ -4281,7 +4284,7 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(typeOid));
scan = heap_beginscan(classRel, SnapshotNow, 1, key);
scan = heap_beginscan_catalog(classRel, 1, key);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
@ -6220,7 +6223,7 @@ ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(conrel, ConstraintRelidIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
while (HeapTupleIsValid(contuple = systable_getnext(scan)))
{
@ -6282,7 +6285,7 @@ ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
ObjectIdGetDatum(HeapTupleGetOid(contuple)));
tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
SnapshotNow, 1, &tgkey);
NULL, 1, &tgkey);
while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
{
@ -6343,7 +6346,7 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(conrel, ConstraintRelidIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
@ -6824,6 +6827,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
TupleTableSlot *slot;
Form_pg_constraint constrForm;
bool isnull;
Snapshot snapshot;
constrForm = (Form_pg_constraint) GETSTRUCT(constrtup);
@ -6849,7 +6853,8 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
slot = MakeSingleTupleTableSlot(tupdesc);
econtext->ecxt_scantuple = slot;
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(rel, snapshot, 0, NULL);
/*
* Switch to per-tuple memory context and reset it for each tuple
@ -6873,6 +6878,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
MemoryContextSwitchTo(oldcxt);
heap_endscan(scan);
UnregisterSnapshot(snapshot);
ExecDropSingleTupleTableSlot(slot);
FreeExecutorState(estate);
}
@ -6893,6 +6899,7 @@ validateForeignKeyConstraint(char *conname,
HeapScanDesc scan;
HeapTuple tuple;
Trigger trig;
Snapshot snapshot;
ereport(DEBUG1,
(errmsg("validating foreign key constraint \"%s\"", conname)));
@ -6924,7 +6931,8 @@ validateForeignKeyConstraint(char *conname,
* if that tuple had just been inserted. If any of those fail, it should
* ereport(ERROR) and that's that.
*/
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(rel, snapshot, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
@ -6956,6 +6964,7 @@ validateForeignKeyConstraint(char *conname,
}
heap_endscan(scan);
UnregisterSnapshot(snapshot);
}
static void
@ -7174,7 +7183,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(conrel, ConstraintRelidIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
@ -7255,7 +7264,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(childrelid));
scan = systable_beginscan(conrel, ConstraintRelidIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
/* scan for matching tuple - there should only be one */
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
@ -7655,7 +7664,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
Int32GetDatum((int32) attnum));
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 3, key);
NULL, 3, key);
while (HeapTupleIsValid(depTup = systable_getnext(scan)))
{
@ -7840,7 +7849,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
Int32GetDatum((int32) attnum));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 3, key);
NULL, 3, key);
while (HeapTupleIsValid(depTup = systable_getnext(scan)))
{
@ -8517,7 +8526,7 @@ change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relationOid));
scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
true, SnapshotNow, 1, key);
true, NULL, 1, key);
while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
{
Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
@ -8594,7 +8603,7 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lock
/* we leave refobjsubid unspecified */
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
@ -9188,7 +9197,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(child_rel)));
scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
/* inhseqno sequences start at 1 */
inhseqno = 0;
@ -9430,7 +9439,7 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(parent_rel)));
parent_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId,
true, SnapshotNow, 1, &parent_key);
true, NULL, 1, &parent_key);
while (HeapTupleIsValid(parent_tuple = systable_getnext(parent_scan)))
{
@ -9453,7 +9462,7 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(child_rel)));
child_scan = systable_beginscan(catalog_relation, ConstraintRelidIndexId,
true, SnapshotNow, 1, &child_key);
true, NULL, 1, &child_key);
while (HeapTupleIsValid(child_tuple = systable_getnext(child_scan)))
{
@ -9561,7 +9570,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
true, SnapshotNow, 1, key);
true, NULL, 1, key);
while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
{
@ -9595,7 +9604,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId,
true, SnapshotNow, 1, key);
true, NULL, 1, key);
while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
{
Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
@ -9637,7 +9646,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(parent_rel)));
scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
true, SnapshotNow, 1, key);
true, NULL, 1, key);
connames = NIL;
@ -9657,7 +9666,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
true, SnapshotNow, 1, key);
true, NULL, 1, key);
while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
{
@ -9749,7 +9758,7 @@ drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid)
Int32GetDatum(0));
scan = systable_beginscan(catalogRelation, DependDependerIndexId, true,
SnapshotNow, 3, key);
NULL, 3, key);
while (HeapTupleIsValid(depTuple = systable_getnext(scan)))
{
@ -9804,7 +9813,7 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
if (HeapTupleIsValid(systable_getnext(scan)))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@ -10260,7 +10269,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
/* we leave refobjsubid unspecified */
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{

View File

@ -400,7 +400,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(tablespacename));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
scandesc = heap_beginscan_catalog(rel, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
@ -831,7 +831,7 @@ RenameTableSpace(const char *oldname, const char *newname)
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(oldname));
scan = heap_beginscan(rel, SnapshotNow, 1, entry);
scan = heap_beginscan_catalog(rel, 1, entry);
tup = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
@ -861,7 +861,7 @@ RenameTableSpace(const char *oldname, const char *newname)
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(newname));
scan = heap_beginscan(rel, SnapshotNow, 1, entry);
scan = heap_beginscan_catalog(rel, 1, entry);
tup = heap_getnext(scan, ForwardScanDirection);
if (HeapTupleIsValid(tup))
ereport(ERROR,
@ -910,7 +910,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(stmt->tablespacename));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
scandesc = heap_beginscan_catalog(rel, 1, entry);
tup = heap_getnext(scandesc, ForwardScanDirection);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
@ -1311,7 +1311,7 @@ get_tablespace_oid(const char *tablespacename, bool missing_ok)
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(tablespacename));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
scandesc = heap_beginscan_catalog(rel, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
/* We assume that there can be at most one matching tuple */
@ -1357,7 +1357,7 @@ get_tablespace_name(Oid spc_oid)
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
scandesc = heap_beginscan_catalog(rel, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
/* We assume that there can be at most one matching tuple */

View File

@ -492,7 +492,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
SnapshotNow, 1, &key);
NULL, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
{
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
@ -1048,7 +1048,7 @@ RemoveTriggerById(Oid trigOid)
ObjectIdGetDatum(trigOid));
tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tup = systable_getnext(tgscan);
if (!HeapTupleIsValid(tup))
@ -1127,7 +1127,7 @@ get_trigger_oid(Oid relid, const char *trigname, bool missing_ok)
CStringGetDatum(trigname));
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
tup = systable_getnext(tgscan);
@ -1242,7 +1242,7 @@ renametrig(RenameStmt *stmt)
BTEqualStrategyNumber, F_NAMEEQ,
PointerGetDatum(stmt->newname));
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
@ -1262,7 +1262,7 @@ renametrig(RenameStmt *stmt)
BTEqualStrategyNumber, F_NAMEEQ,
PointerGetDatum(stmt->subname));
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
{
tgoid = HeapTupleGetOid(tuple);
@ -1359,7 +1359,7 @@ EnableDisableTrigger(Relation rel, const char *tgname,
nkeys = 1;
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
SnapshotNow, nkeys, keys);
NULL, nkeys, keys);
found = changed = false;
@ -1468,7 +1468,7 @@ RelationBuildTriggers(Relation relation)
tgrel = heap_open(TriggerRelationId, AccessShareLock);
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{
@ -4270,7 +4270,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
ObjectIdGetDatum(namespaceId));
conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
true, SnapshotNow, 2, skey);
true, NULL, 2, skey);
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
{
@ -4333,7 +4333,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
ObjectIdGetDatum(conoid));
tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{

View File

@ -921,7 +921,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
ObjectIdGetDatum(myself.objectId));
scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{
@ -1059,7 +1059,7 @@ DefineTSConfiguration(List *names, List *parameters)
ObjectIdGetDatum(sourceOid));
scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{
@ -1138,7 +1138,7 @@ RemoveTSConfigurationById(Oid cfgId)
ObjectIdGetDatum(cfgId));
scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
@ -1294,7 +1294,7 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
Int32GetDatum(tokens[i]));
scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{
@ -1333,7 +1333,7 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
ObjectIdGetDatum(cfgId));
scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{
@ -1450,7 +1450,7 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
Int32GetDatum(tokens[i]));
scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
SnapshotNow, 2, skey);
NULL, 2, skey);
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{

View File

@ -71,6 +71,7 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@ -2256,9 +2257,11 @@ AlterDomainNotNull(List *names, bool notNull)
TupleDesc tupdesc = RelationGetDescr(testrel);
HeapScanDesc scan;
HeapTuple tuple;
Snapshot snapshot;
/* Scan all tuples in this relation */
scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(testrel, snapshot, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
int i;
@ -2288,6 +2291,7 @@ AlterDomainNotNull(List *names, bool notNull)
}
}
heap_endscan(scan);
UnregisterSnapshot(snapshot);
/* Close each rel after processing, but keep lock */
heap_close(testrel, NoLock);
@ -2356,7 +2360,7 @@ AlterDomainDropConstraint(List *names, const char *constrName,
ObjectIdGetDatum(HeapTupleGetOid(tup)));
conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
/*
* Scan over the result set, removing any matching entries.
@ -2551,7 +2555,7 @@ AlterDomainValidateConstraint(List *names, char *constrName)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(domainoid));
scan = systable_beginscan(conrel, ConstraintTypidIndexId,
true, SnapshotNow, 1, &key);
true, NULL, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
@ -2638,9 +2642,11 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
TupleDesc tupdesc = RelationGetDescr(testrel);
HeapScanDesc scan;
HeapTuple tuple;
Snapshot snapshot;
/* Scan all tuples in this relation */
scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(testrel, snapshot, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
int i;
@ -2684,6 +2690,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
ResetExprContext(econtext);
}
heap_endscan(scan);
UnregisterSnapshot(snapshot);
/* Hold relation lock till commit (XXX bad for concurrency) */
heap_close(testrel, NoLock);
@ -2751,7 +2758,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
ObjectIdGetDatum(domainOid));
depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
NULL, 2, key);
while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
{
@ -3066,7 +3073,7 @@ GetDomainConstraints(Oid typeOid)
ObjectIdGetDatum(typeOid));
scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
SnapshotNow, 1, key);
NULL, 1, key);
while (HeapTupleIsValid(conTup = systable_getnext(scan)))
{

View File

@ -1006,7 +1006,7 @@ DropRole(DropRoleStmt *stmt)
ObjectIdGetDatum(roleid));
sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
true, SnapshotNow, 1, &scankey);
true, NULL, 1, &scankey);
while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
{
@ -1021,7 +1021,7 @@ DropRole(DropRoleStmt *stmt)
ObjectIdGetDatum(roleid));
sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
true, SnapshotNow, 1, &scankey);
true, NULL, 1, &scankey);
while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
{

View File

@ -351,7 +351,7 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
pgclass = heap_open(RelationRelationId, AccessShareLock);
scan = heap_beginscan(pgclass, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(pgclass, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
@ -735,7 +735,7 @@ vac_update_datfrozenxid(void)
relation = heap_open(RelationRelationId, AccessShareLock);
scan = systable_beginscan(relation, InvalidOid, false,
SnapshotNow, 0, NULL);
NULL, 0, NULL);
while ((classTup = systable_getnext(scan)) != NULL)
{
@ -852,7 +852,7 @@ vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti)
*/
relation = heap_open(DatabaseRelationId, AccessShareLock);
scan = heap_beginscan(relation, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(relation, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{

View File

@ -4,16 +4,16 @@
* Routines to support bitmapped scans of relations
*
* NOTE: it is critical that this plan type only be used with MVCC-compliant
* snapshots (ie, regular snapshots, not SnapshotNow or one of the other
* snapshots (ie, regular snapshots, not SnapshotAny or one of the other
* special snapshots). The reason is that since index and heap scans are
* decoupled, there can be no assurance that the index tuple prompting a
* visit to a particular heap TID still exists when the visit is made.
* Therefore the tuple might not exist anymore either (which is OK because
* heap_fetch will cope) --- but worse, the tuple slot could have been
* re-used for a newer tuple. With an MVCC snapshot the newer tuple is
* certain to fail the time qual and so it will not be mistakenly returned.
* With SnapshotNow we might return a tuple that doesn't meet the required
* index qual conditions.
* certain to fail the time qual and so it will not be mistakenly returned,
* but with anything else we might return a tuple that doesn't meet the
* required index qual conditions.
*
*
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group

View File

@ -1855,7 +1855,7 @@ get_database_list(void)
(void) GetTransactionSnapshot();
rel = heap_open(DatabaseRelationId, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(rel, 0, NULL);
while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
{
@ -2002,7 +2002,7 @@ do_autovacuum(void)
* wide tables there might be proportionally much more activity in the
* TOAST table than in its parent.
*/
relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
relScan = heap_beginscan_catalog(classRel, 0, NULL);
/*
* On the first pass, we collect main tables to vacuum, and also the main
@ -2120,7 +2120,7 @@ do_autovacuum(void)
BTEqualStrategyNumber, F_CHAREQ,
CharGetDatum(RELKIND_TOASTVALUE));
relScan = heap_beginscan(classRel, SnapshotNow, 1, &key);
relScan = heap_beginscan_catalog(classRel, 1, &key);
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);

View File

@ -59,6 +59,7 @@
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/timestamp.h"
#include "utils/tqual.h"
@ -1097,6 +1098,7 @@ pgstat_collect_oids(Oid catalogid)
Relation rel;
HeapScanDesc scan;
HeapTuple tup;
Snapshot snapshot;
memset(&hash_ctl, 0, sizeof(hash_ctl));
hash_ctl.keysize = sizeof(Oid);
@ -1109,7 +1111,8 @@ pgstat_collect_oids(Oid catalogid)
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
rel = heap_open(catalogid, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = heap_beginscan(rel, snapshot, 0, NULL);
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Oid thisoid = HeapTupleGetOid(tup);
@ -1119,6 +1122,7 @@ pgstat_collect_oids(Oid catalogid)
(void) hash_search(htab, (void *) &thisoid, HASH_ENTER, NULL);
}
heap_endscan(scan);
UnregisterSnapshot(snapshot);
heap_close(rel, AccessShareLock);
return htab;

View File

@ -38,6 +38,7 @@
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@ -418,14 +419,17 @@ DefineQueryRewrite(char *rulename,
event_relation->rd_rel->relkind != RELKIND_MATVIEW)
{
HeapScanDesc scanDesc;
Snapshot snapshot;
scanDesc = heap_beginscan(event_relation, SnapshotNow, 0, NULL);
snapshot = RegisterSnapshot(GetLatestSnapshot());
scanDesc = heap_beginscan(event_relation, snapshot, 0, NULL);
if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("could not convert table \"%s\" to a view because it is not empty",
RelationGetRelationName(event_relation))));
heap_endscan(scanDesc);
UnregisterSnapshot(snapshot);
if (event_relation->rd_rel->relhastriggers)
ereport(ERROR,

View File

@ -2092,8 +2092,8 @@ relation_is_updatable(Oid reloid, bool include_triggers)
/*
* If the relation doesn't exist, return zero rather than throwing an
* error. This is helpful since scanning an information_schema view under
* MVCC rules can result in referencing rels that were just deleted
* according to a SnapshotNow probe.
* MVCC rules can result in referencing rels that have actually been
* deleted already.
*/
if (rel == NULL)
return 0;

View File

@ -58,7 +58,7 @@ RemoveRewriteRuleById(Oid ruleOid)
ObjectIdGetDatum(ruleOid));
rcscan = systable_beginscan(RewriteRelation, RewriteOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
tuple = systable_getnext(rcscan);

View File

@ -143,7 +143,7 @@ get_rewrite_oid_without_relid(const char *rulename,
CStringGetDatum(rulename));
RewriteRelation = heap_open(RewriteRelationId, AccessShareLock);
scanDesc = heap_beginscan(RewriteRelation, SnapshotNow, 1, &scanKeyData);
scanDesc = heap_beginscan_catalog(RewriteRelation, 1, &scanKeyData);
htup = heap_getnext(scanDesc, ForwardScanDirection);
if (!HeapTupleIsValid(htup))

View File

@ -250,7 +250,7 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt)
if (flags & INV_WRITE)
{
retval->snapshot = SnapshotNow;
retval->snapshot = NULL; /* instantaneous MVCC snapshot */
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
}
else if (flags & INV_READ)
@ -270,7 +270,7 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt)
errmsg("invalid flags for opening a large object: %d",
flags)));
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
/* Can't use LargeObjectExists here because we need to specify snapshot */
if (!myLargeObjectExists(lobjId, retval->snapshot))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@ -288,9 +288,8 @@ inv_close(LargeObjectDesc *obj_desc)
{
Assert(PointerIsValid(obj_desc));
if (obj_desc->snapshot != SnapshotNow)
UnregisterSnapshotFromOwner(obj_desc->snapshot,
TopTransactionResourceOwner);
UnregisterSnapshotFromOwner(obj_desc->snapshot,
TopTransactionResourceOwner);
pfree(obj_desc);
}

View File

@ -697,7 +697,7 @@ pg_size_pretty_numeric(PG_FUNCTION_ARGS)
* That leads to a couple of choices. We work from the pg_class row alone
* rather than actually opening each relation, for efficiency. We don't
* fail if we can't find the relation --- some rows might be visible in
* the query's MVCC snapshot but already dead according to SnapshotNow.
* the query's MVCC snapshot even though the relations have been dropped.
* (Note: we could avoid using the catcache, but there's little point
* because the relation mapper also works "in the now".) We also don't
* fail if the relation doesn't have storage. In all these cases it

View File

@ -104,7 +104,7 @@ regprocin(PG_FUNCTION_ARGS)
hdesc = heap_open(ProcedureRelationId, AccessShareLock);
sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
{
@ -472,7 +472,7 @@ regoperin(PG_FUNCTION_ARGS)
hdesc = heap_open(OperatorRelationId, AccessShareLock);
sysscan = systable_beginscan(hdesc, OperatorNameNspIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
{
@ -843,7 +843,7 @@ regclassin(PG_FUNCTION_ARGS)
hdesc = heap_open(RelationRelationId, AccessShareLock);
sysscan = systable_beginscan(hdesc, ClassNameNspIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
result = HeapTupleGetOid(tuple);
@ -1007,7 +1007,7 @@ regtypein(PG_FUNCTION_ARGS)
hdesc = heap_open(TypeRelationId, AccessShareLock);
sysscan = systable_beginscan(hdesc, TypeNameNspIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
result = HeapTupleGetOid(tuple);

View File

@ -704,7 +704,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
ObjectIdGetDatum(trigid));
tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
ht_trig = systable_getnext(tgscan);
@ -1796,7 +1796,7 @@ pg_get_serial_sequence(PG_FUNCTION_ARGS)
Int32GetDatum(attnum));
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 3, key);
NULL, 3, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{

View File

@ -1182,7 +1182,7 @@ SearchCatCache(CatCache *cache,
scandesc = systable_beginscan(relation,
cache->cc_indexoid,
IndexScanOK(cache, cur_skey),
SnapshotNow,
NULL,
cache->cc_nkeys,
cur_skey);
@ -1461,7 +1461,7 @@ SearchCatCacheList(CatCache *cache,
scandesc = systable_beginscan(relation,
cache->cc_indexoid,
IndexScanOK(cache, cur_skey),
SnapshotNow,
NULL,
nkeys,
cur_skey);

View File

@ -129,13 +129,11 @@ BuildEventTriggerCache(void)
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/*
* Prepare to scan pg_event_trigger in name order. We use an MVCC
* snapshot to avoid getting inconsistent results if the table is being
* concurrently updated.
* Prepare to scan pg_event_trigger in name order.
*/
rel = relation_open(EventTriggerRelationId, AccessShareLock);
irel = index_open(EventTriggerNameIndexId, AccessShareLock);
scan = systable_beginscan_ordered(rel, irel, GetLatestSnapshot(), 0, NULL);
scan = systable_beginscan_ordered(rel, irel, NULL, 0, NULL);
/*
* Build a cache item for each pg_event_trigger tuple, and append each one

View File

@ -9,8 +9,8 @@
* consider that it is *still valid* so long as we are in the same command,
* ie, until the next CommandCounterIncrement() or transaction commit.
* (See utils/time/tqual.c, and note that system catalogs are generally
* scanned under SnapshotNow rules by the system, or plain user snapshots
* for user queries.) At the command boundary, the old tuple stops
* scanned under the most current snapshot available, rather than the
* transaction snapshot.) At the command boundary, the old tuple stops
* being valid and the new version, if any, becomes valid. Therefore,
* we cannot simply flush a tuple from the system caches during heap_update()
* or heap_delete(). The tuple is still good at that point; what's more,
@ -106,6 +106,7 @@
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/relmapper.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
@ -372,6 +373,29 @@ AddRelcacheInvalidationMessage(InvalidationListHeader *hdr,
AddInvalidationMessage(&hdr->rclist, &msg);
}
/*
* Add a snapshot inval entry
*/
static void
AddSnapshotInvalidationMessage(InvalidationListHeader *hdr,
Oid dbId, Oid relId)
{
SharedInvalidationMessage msg;
/* Don't add a duplicate item */
/* We assume dbId need not be checked because it will never change */
ProcessMessageList(hdr->rclist,
if (msg->sn.id == SHAREDINVALSNAPSHOT_ID &&
msg->sn.relId == relId)
return);
/* OK, add the item */
msg.sn.id = SHAREDINVALSNAPSHOT_ID;
msg.sn.dbId = dbId;
msg.sn.relId = relId;
AddInvalidationMessage(&hdr->rclist, &msg);
}
/*
* Append one list of invalidation messages to another, resetting
* the source list to empty.
@ -468,6 +492,19 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId)
transInvalInfo->RelcacheInitFileInval = true;
}
/*
* RegisterSnapshotInvalidation
*
* Register a invalidation event for MVCC scans against a given catalog.
* Only needed for catalogs that don't have catcaches.
*/
static void
RegisterSnapshotInvalidation(Oid dbId, Oid relId)
{
AddSnapshotInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
dbId, relId);
}
/*
* LocalExecuteInvalidationMessage
*
@ -482,6 +519,8 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
{
if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
{
InvalidateCatalogSnapshot();
CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue);
CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue);
@ -491,6 +530,8 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
{
if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
{
InvalidateCatalogSnapshot();
CatalogCacheFlushCatalog(msg->cat.catId);
/* CatalogCacheFlushCatalog calls CallSyscacheCallbacks as needed */
@ -532,6 +573,14 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
else if (msg->rm.dbId == MyDatabaseId)
RelationMapInvalidate(false);
}
else if (msg->id == SHAREDINVALSNAPSHOT_ID)
{
/* We only care about our own database and shared catalogs */
if (msg->rm.dbId == InvalidOid)
InvalidateCatalogSnapshot();
else if (msg->rm.dbId == MyDatabaseId)
InvalidateCatalogSnapshot();
}
else
elog(FATAL, "unrecognized SI message ID: %d", msg->id);
}
@ -552,6 +601,7 @@ InvalidateSystemCaches(void)
{
int i;
InvalidateCatalogSnapshot();
ResetCatalogCaches();
RelationCacheInvalidate(); /* gets smgr and relmap too */
@ -1006,8 +1056,15 @@ CacheInvalidateHeapTuple(Relation relation,
/*
* First let the catcache do its thing
*/
PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
RegisterCatcacheInvalidation);
tupleRelId = RelationGetRelid(relation);
if (RelationInvalidatesSnapshotsOnly(tupleRelId))
{
databaseId = IsSharedRelation(tupleRelId) ? InvalidOid : MyDatabaseId;
RegisterSnapshotInvalidation(databaseId, tupleRelId);
}
else
PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
RegisterCatcacheInvalidation);
/*
* Now, is this tuple one of the primary definers of a relcache entry?
@ -1015,8 +1072,6 @@ CacheInvalidateHeapTuple(Relation relation,
* Note we ignore newtuple here; we assume an update cannot move a tuple
* from being part of one relcache entry to being part of another.
*/
tupleRelId = RelationGetRelid(relation);
if (tupleRelId == RelationRelationId)
{
Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple);

View File

@ -265,8 +265,10 @@ static void unlink_initfile(const char *initfilename);
* This is used by RelationBuildDesc to find a pg_class
* tuple matching targetRelId. The caller must hold at least
* AccessShareLock on the target relid to prevent concurrent-update
* scenarios --- else our SnapshotNow scan might fail to find any
* version that it thinks is live.
* scenarios; it isn't guaranteed that all scans used to build the
* relcache entry will use the same snapshot. If, for example,
* an attribute were to be added after scanning pg_class and before
* scanning pg_attribute, relnatts wouldn't match.
*
* NB: the returned tuple has been copied into palloc'd storage
* and must eventually be freed with heap_freetuple.
@ -305,7 +307,7 @@ ScanPgRelation(Oid targetRelId, bool indexOK)
pg_class_desc = heap_open(RelationRelationId, AccessShareLock);
pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
indexOK && criticalRelcachesBuilt,
SnapshotNow,
NULL,
1, key);
pg_class_tuple = systable_getnext(pg_class_scan);
@ -480,7 +482,7 @@ RelationBuildTupleDesc(Relation relation)
pg_attribute_scan = systable_beginscan(pg_attribute_desc,
AttributeRelidNumIndexId,
criticalRelcachesBuilt,
SnapshotNow,
NULL,
2, skey);
/*
@ -663,7 +665,7 @@ RelationBuildRuleLock(Relation relation)
rewrite_tupdesc = RelationGetDescr(rewrite_desc);
rewrite_scan = systable_beginscan(rewrite_desc,
RewriteRelRulenameIndexId,
true, SnapshotNow,
true, NULL,
1, &key);
while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
@ -1313,7 +1315,7 @@ LookupOpclassInfo(Oid operatorClassOid,
ObjectIdGetDatum(operatorClassOid));
rel = heap_open(OperatorClassRelationId, AccessShareLock);
scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
SnapshotNow, 1, skey);
NULL, 1, skey);
if (HeapTupleIsValid(htup = systable_getnext(scan)))
{
@ -1348,7 +1350,7 @@ LookupOpclassInfo(Oid operatorClassOid,
ObjectIdGetDatum(opcentry->opcintype));
rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
SnapshotNow, 3, skey);
NULL, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan)))
{
@ -3317,7 +3319,7 @@ AttrDefaultFetch(Relation relation)
adrel = heap_open(AttrDefaultRelationId, AccessShareLock);
adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
found = 0;
while (HeapTupleIsValid(htup = systable_getnext(adscan)))
@ -3384,7 +3386,7 @@ CheckConstraintFetch(Relation relation)
conrel = heap_open(ConstraintRelationId, AccessShareLock);
conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
while (HeapTupleIsValid(htup = systable_getnext(conscan)))
{
@ -3487,7 +3489,7 @@ RelationGetIndexList(Relation relation)
indrel = heap_open(IndexRelationId, AccessShareLock);
indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
SnapshotNow, 1, &skey);
NULL, 1, &skey);
while (HeapTupleIsValid(htup = systable_getnext(indscan)))
{
@ -3938,7 +3940,7 @@ RelationGetExclusionInfo(Relation indexRelation,
conrel = heap_open(ConstraintRelationId, AccessShareLock);
conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
SnapshotNow, 1, skey);
NULL, 1, skey);
found = false;
while (HeapTupleIsValid(htup = systable_getnext(conscan)))

View File

@ -33,7 +33,10 @@
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_description.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_foreign_data_wrapper.h"
@ -47,6 +50,10 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_seclabel.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_shdescription.h"
#include "catalog/pg_shseclabel.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_ts_config.h"
@ -796,6 +803,10 @@ static CatCache *SysCache[
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
static Oid SysCacheRelationOid[lengthof(cacheinfo)];
static int SysCacheRelationOidSize;
static int oid_compare(const void *a, const void *b);
/*
* InitCatalogCache - initialize the caches
@ -809,6 +820,8 @@ void
InitCatalogCache(void)
{
int cacheId;
int i,
j = 0;
Assert(!CacheInitialized);
@ -825,11 +838,23 @@ InitCatalogCache(void)
if (!PointerIsValid(SysCache[cacheId]))
elog(ERROR, "could not initialize cache %u (%d)",
cacheinfo[cacheId].reloid, cacheId);
SysCacheRelationOid[SysCacheRelationOidSize++] =
cacheinfo[cacheId].reloid;
/* see comments for RelationInvalidatesSnapshotsOnly */
Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid));
}
/* Sort and dedup OIDs. */
pg_qsort(SysCacheRelationOid, SysCacheRelationOidSize,
sizeof(Oid), oid_compare);
for (i = 1; i < SysCacheRelationOidSize; ++i)
if (SysCacheRelationOid[i] != SysCacheRelationOid[j])
SysCacheRelationOid[++j] = SysCacheRelationOid[i];
SysCacheRelationOidSize = j + 1;
CacheInitialized = true;
}
/*
* InitCatalogCachePhase2 - finish initializing the caches
*
@ -1113,3 +1138,73 @@ SearchSysCacheList(int cacheId, int nkeys,
return SearchCatCacheList(SysCache[cacheId], nkeys,
key1, key2, key3, key4);
}
/*
* Certain relations that do not have system caches send snapshot invalidation
* messages in lieu of catcache messages. This is for the benefit of
* GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
* for scanning one of those catalogs, rather than taking a new one, if no
* invalidation has been received.
*
* Relations that have syscaches need not (and must not) be listed here. The
* catcache invalidation messages will also flush the snapshot. If you add a
* syscache for one of these relations, remove it from this list.
*/
bool
RelationInvalidatesSnapshotsOnly(Oid relid)
{
switch (relid)
{
case DbRoleSettingRelationId:
case DependRelationId:
case SharedDependRelationId:
case DescriptionRelationId:
case SharedDescriptionRelationId:
case SecLabelRelationId:
case SharedSecLabelRelationId:
return true;
default:
break;
}
return false;
}
/*
* Test whether a relation has a system cache.
*/
bool
RelationHasSysCache(Oid relid)
{
int low = 0,
high = SysCacheRelationOidSize - 1;
while (low <= high)
{
int middle = low + (high - low) / 2;
if (SysCacheRelationOid[middle] == relid)
return true;
if (SysCacheRelationOid[middle] < relid)
low = middle + 1;
else
high = middle - 1;
}
return false;
}
/*
* OID comparator for pg_qsort
*/
static int
oid_compare(const void *a, const void *b)
{
Oid oa = *((Oid *) a);
Oid ob = *((Oid *) b);
if (oa == ob)
return 0;
return (oa > ob) ? 1 : -1;
}

View File

@ -484,7 +484,7 @@ lookup_ts_config_cache(Oid cfgId)
maprel = heap_open(TSConfigMapRelationId, AccessShareLock);
mapidx = index_open(TSConfigMapIndexId, AccessShareLock);
mapscan = systable_beginscan_ordered(maprel, mapidx,
SnapshotNow, 1, &mapskey);
NULL, 1, &mapskey);
while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
{

View File

@ -1082,12 +1082,7 @@ load_enum_cache_data(TypeCacheEntry *tcache)
items = (EnumItem *) palloc(sizeof(EnumItem) * maxitems);
numitems = 0;
/*
* Scan pg_enum for the members of the target enum type. We use a current
* MVCC snapshot, *not* SnapshotNow, so that we see a consistent set of
* rows even if someone commits a renumbering of the enum meanwhile. See
* comments for RenumberEnumType in catalog/pg_enum.c for more info.
*/
/* Scan pg_enum for the members of the target enum type. */
ScanKeyInit(&skey,
Anum_pg_enum_enumtypid,
BTEqualStrategyNumber, F_OIDEQ,
@ -1096,7 +1091,7 @@ load_enum_cache_data(TypeCacheEntry *tcache)
enum_rel = heap_open(EnumRelationId, AccessShareLock);
enum_scan = systable_beginscan(enum_rel,
EnumTypIdLabelIndexId,
true, GetLatestSnapshot(),
true, NULL,
1, &skey);
while (HeapTupleIsValid(enum_tuple = systable_getnext(enum_scan)))

View File

@ -111,7 +111,7 @@ GetDatabaseTuple(const char *dbname)
relation = heap_open(DatabaseRelationId, AccessShareLock);
scan = systable_beginscan(relation, DatabaseNameIndexId,
criticalSharedRelcachesBuilt,
SnapshotNow,
NULL,
1, key);
tuple = systable_getnext(scan);
@ -154,7 +154,7 @@ GetDatabaseTupleByOid(Oid dboid)
relation = heap_open(DatabaseRelationId, AccessShareLock);
scan = systable_beginscan(relation, DatabaseOidIndexId,
criticalSharedRelcachesBuilt,
SnapshotNow,
NULL,
1, key);
tuple = systable_getnext(scan);
@ -997,18 +997,23 @@ static void
process_settings(Oid databaseid, Oid roleid)
{
Relation relsetting;
Snapshot snapshot;
if (!IsUnderPostmaster)
return;
relsetting = heap_open(DbRoleSettingRelationId, AccessShareLock);
/* Later settings are ignored if set earlier. */
ApplySetting(databaseid, roleid, relsetting, PGC_S_DATABASE_USER);
ApplySetting(InvalidOid, roleid, relsetting, PGC_S_USER);
ApplySetting(databaseid, InvalidOid, relsetting, PGC_S_DATABASE);
ApplySetting(InvalidOid, InvalidOid, relsetting, PGC_S_GLOBAL);
/* read all the settings under the same snapsot for efficiency */
snapshot = RegisterSnapshot(GetCatalogSnapshot(DbRoleSettingRelationId));
/* Later settings are ignored if set earlier. */
ApplySetting(snapshot, databaseid, roleid, relsetting, PGC_S_DATABASE_USER);
ApplySetting(snapshot, InvalidOid, roleid, relsetting, PGC_S_USER);
ApplySetting(snapshot, databaseid, InvalidOid, relsetting, PGC_S_DATABASE);
ApplySetting(snapshot, InvalidOid, InvalidOid, relsetting, PGC_S_GLOBAL);
UnregisterSnapshot(snapshot);
heap_close(relsetting, AccessShareLock);
}
@ -1078,7 +1083,7 @@ ThereIsAtLeastOneRole(void)
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
scan = heap_beginscan(pg_authid_rel, SnapshotNow, 0, NULL);
scan = heap_beginscan_catalog(pg_authid_rel, 0, NULL);
result = (heap_getnext(scan, ForwardScanDirection) != NULL);
heap_endscan(scan);

View File

@ -46,10 +46,12 @@
#include "storage/predicate.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/sinval.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/resowner_private.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@ -58,17 +60,26 @@
* mode, and to the latest one taken in a read-committed transaction.
* SecondarySnapshot is a snapshot that's always up-to-date as of the current
* instant, even in transaction-snapshot mode. It should only be used for
* special-purpose code (say, RI checking.)
* special-purpose code (say, RI checking.) CatalogSnapshot points to an
* MVCC snapshot intended to be used for catalog scans; we must refresh it
* whenever a system catalog change occurs.
*
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
*/
static SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC};
static SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC};
static SnapshotData CatalogSnapshotData = {HeapTupleSatisfiesMVCC};
/* Pointers to valid snapshots */
static Snapshot CurrentSnapshot = NULL;
static Snapshot SecondarySnapshot = NULL;
static Snapshot CatalogSnapshot = NULL;
/*
* Staleness detection for CatalogSnapshot.
*/
static bool CatalogSnapshotStale = true;
/*
* These are updated by GetSnapshotData. We initialize them this way
@ -177,6 +188,9 @@ GetTransactionSnapshot(void)
else
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
/* Don't allow catalog snapshot to be older than xact snapshot. */
CatalogSnapshotStale = true;
FirstSnapshotSet = true;
return CurrentSnapshot;
}
@ -184,6 +198,9 @@ GetTransactionSnapshot(void)
if (IsolationUsesXactSnapshot())
return CurrentSnapshot;
/* Don't allow catalog snapshot to be older than xact snapshot. */
CatalogSnapshotStale = true;
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
return CurrentSnapshot;
@ -206,6 +223,54 @@ GetLatestSnapshot(void)
return SecondarySnapshot;
}
/*
* GetCatalogSnapshot
* Get a snapshot that is sufficiently up-to-date for scan of the
* system catalog with the specified OID.
*/
Snapshot
GetCatalogSnapshot(Oid relid)
{
/*
* If the caller is trying to scan a relation that has no syscache,
* no catcache invalidations will be sent when it is updated. For a
* a few key relations, snapshot invalidations are sent instead. If
* we're trying to scan a relation for which neither catcache nor
* snapshot invalidations are sent, we must refresh the snapshot every
* time.
*/
if (!CatalogSnapshotStale && !RelationInvalidatesSnapshotsOnly(relid) &&
!RelationHasSysCache(relid))
CatalogSnapshotStale = true;
if (CatalogSnapshotStale)
{
/* Get new snapshot. */
CatalogSnapshot = GetSnapshotData(&CatalogSnapshotData);
/*
* Mark new snapshost as valid. We must do this last, in case an
* ERROR occurs inside GetSnapshotData().
*/
CatalogSnapshotStale = false;
}
return CatalogSnapshot;
}
/*
* Mark the current catalog snapshot as invalid. We could change this API
* to allow the caller to provide more fine-grained invalidation details, so
* that a change to relation A wouldn't prevent us from using our cached
* snapshot to scan relation B, but so far there's no evidence that the CPU
* cycles we spent tracking such fine details would be well-spent.
*/
void
InvalidateCatalogSnapshot()
{
CatalogSnapshotStale = true;
}
/*
* SnapshotSetCommandId
* Propagate CommandCounterIncrement into the static snapshots, if set

View File

@ -14,13 +14,13 @@
* Note that pg_dump runs in a transaction-snapshot mode transaction,
* so it sees a consistent snapshot of the database including system
* catalogs. However, it relies in part on various specialized backend
* functions like pg_get_indexdef(), and those things tend to run on
* SnapshotNow time, ie they look at the currently committed state. So
* it is possible to get 'cache lookup failed' error if someone
* performs DDL changes while a dump is happening. The window for this
* sort of thing is from the acquisition of the transaction snapshot to
* getSchemaData() (when pg_dump acquires AccessShareLock on every
* table it intends to dump). It isn't very large, but it can happen.
* functions like pg_get_indexdef(), and those things tend to look at
* the currently committed state. So it is possible to get 'cache
* lookup failed' error if someone performs DDL changes while a dump is
* happening. The window for this sort of thing is from the acquisition
* of the transaction snapshot to getSchemaData() (when pg_dump acquires
* AccessShareLock on every table it intends to dump). It isn't very large,
* but it can happen.
*
* http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
*

View File

@ -105,6 +105,8 @@ typedef struct HeapScanDescData *HeapScanDesc;
extern HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot,
int nkeys, ScanKey key);
extern HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys,
ScanKey key);
extern HeapScanDesc heap_beginscan_strat(Relation relation, Snapshot snapshot,
int nkeys, ScanKey key,
bool allow_strat, bool allow_sync);

View File

@ -32,6 +32,7 @@ typedef struct HeapScanDescData
bool rs_pageatatime; /* verify visibility page-at-a-time? */
bool rs_allow_strat; /* allow or disallow use of access strategy */
bool rs_allow_sync; /* allow or disallow use of syncscan */
bool rs_temp_snap; /* unregister snapshot at scan end? */
/* state set up at initscan time */
BlockNumber rs_nblocks; /* number of blocks to scan */
@ -101,6 +102,7 @@ typedef struct SysScanDescData
Relation irel; /* NULL if doing heap scan */
HeapScanDesc scan; /* only valid in heap-scan case */
IndexScanDesc iscan; /* only valid in index-scan case */
Snapshot snapshot; /* snapshot to unregister at end of scan */
} SysScanDescData;
#endif /* RELSCAN_H */

View File

@ -24,8 +24,8 @@
*
* OAT_POST_ALTER should be invoked just after the object is altered,
* but before the command counter is incremented. An extension using the
* hook can use SnapshotNow and SnapshotSelf to get the old and new
* versions of the tuple.
* hook can use a current MVCC snapshot to get the old version of the tuple,
* and can use SnapshotSelf to get the new version of the tuple.
*
* OAT_NAMESPACE_SEARCH should be invoked prior to object name lookup under
* a particular namespace. This event is equivalent to usage permission

View File

@ -62,7 +62,7 @@ typedef FormData_pg_db_role_setting *Form_pg_db_role_setting;
*/
extern void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt);
extern void DropSetting(Oid databaseid, Oid roleid);
extern void ApplySetting(Oid databaseid, Oid roleid, Relation relsetting,
GucSource source);
extern void ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
Relation relsetting, GucSource source);
#endif /* PG_DB_ROLE_SETTING_H */

View File

@ -24,6 +24,7 @@
* * invalidate a relcache entry for a specific logical relation
* * invalidate an smgr cache entry for a specific physical relation
* * invalidate the mapped-relation mapping for a given database
* * invalidate any saved snapshot that might be used to scan a given relation
* More types could be added if needed. The message type is identified by
* the first "int8" field of the message struct. Zero or positive means a
* specific-catcache inval message (and also serves as the catcache ID field).
@ -43,11 +44,11 @@
* catcache inval messages must be generated for each of its caches, since
* the hash keys will generally be different.
*
* Catcache and relcache invalidations are transactional, and so are sent
* to other backends upon commit. Internally to the generating backend,
* they are also processed at CommandCounterIncrement so that later commands
* in the same transaction see the new state. The generating backend also
* has to process them at abort, to flush out any cache state it's loaded
* Catcache, relcache, and snapshot invalidations are transactional, and so
* are sent to other backends upon commit. Internally to the generating
* backend, they are also processed at CommandCounterIncrement so that later
* commands in the same transaction see the new state. The generating backend
* also has to process them at abort, to flush out any cache state it's loaded
* from no-longer-valid entries.
*
* smgr and relation mapping invalidations are non-transactional: they are
@ -98,6 +99,15 @@ typedef struct
Oid dbId; /* database ID, or 0 for shared catalogs */
} SharedInvalRelmapMsg;
#define SHAREDINVALSNAPSHOT_ID (-5)
typedef struct
{
int8 id; /* type field --- must be first */
Oid dbId; /* database ID, or 0 if a shared relation */
Oid relId; /* relation ID */
} SharedInvalSnapshotMsg;
typedef union
{
int8 id; /* type field --- must be first */
@ -106,6 +116,7 @@ typedef union
SharedInvalRelcacheMsg rc;
SharedInvalSmgrMsg sm;
SharedInvalRelmapMsg rm;
SharedInvalSnapshotMsg sn;
} SharedInvalidationMessage;

View File

@ -28,6 +28,9 @@ extern Snapshot GetTransactionSnapshot(void);
extern Snapshot GetLatestSnapshot(void);
extern void SnapshotSetCommandId(CommandId curcid);
extern Snapshot GetCatalogSnapshot(Oid relid);
extern void InvalidateCatalogSnapshot(void);
extern void PushActiveSnapshot(Snapshot snapshot);
extern void PushCopiedSnapshot(Snapshot snapshot);
extern void UpdateActiveSnapshotCommandId(void);

View File

@ -125,6 +125,9 @@ struct catclist;
extern struct catclist *SearchSysCacheList(int cacheId, int nkeys,
Datum key1, Datum key2, Datum key3, Datum key4);
extern bool RelationInvalidatesSnapshotsOnly(Oid);
extern bool RelationHasSysCache(Oid);
/*
* The use of the macros below rather than direct calls to the corresponding
* functions is encouraged, as it insulates the caller from changes in the