diff --git a/contrib/userlock/user_locks.c b/contrib/userlock/user_locks.c
index c27dc253d83..394a4fe1906 100644
--- a/contrib/userlock/user_locks.c
+++ b/contrib/userlock/user_locks.c
@@ -35,8 +35,7 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
SET_LOCKTAG_USERLOCK(tag, id1, id2);
- return (LockAcquire(&tag, false,
- lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL);
+ return (LockAcquire(&tag, lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL);
}
int
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index dfb6348e1d6..80ed7d829bc 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-
+
@@ -401,13 +401,6 @@
Can index storage data type differ from column data type?
-
- amconcurrent
- bool
-
- Does the access method support concurrent updates?
-
-
amclusterable
bool
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
index 7febd0c9072..1afa120766e 100644
--- a/doc/src/sgml/indexam.sgml
+++ b/doc/src/sgml/indexam.sgml
@@ -1,4 +1,4 @@
-
+
Index Access Method Interface Definition
@@ -94,8 +94,7 @@
Some of the flag columns of pg_am have nonobvious
implications. The requirements of amcanunique
- are discussed in , and those of
- amconcurrent in .
+ are discussed in .
The amcanmulticol flag asserts that the
access method supports multicolumn indexes, while
amoptionalkey asserts that it allows scans
@@ -474,11 +473,7 @@ amrestrpos (IndexScanDesc scan);
a concurrent delete may or may not be reflected in the results of a scan.
What is important is that insertions or deletions not cause the scan to
miss or multiply return entries that were not themselves being inserted or
- deleted. (For an index type that does not set
- pg_am>.amconcurrent>, it is sufficient to
- handle these cases for insertions or deletions performed by the same
- backend that's doing the scan. But when amconcurrent> is
- true, insertions or deletions from other backends must be handled as well.)
+ deleted.
@@ -506,31 +501,16 @@ amrestrpos (IndexScanDesc scan);
Index Locking Considerations
- An index access method can choose whether it supports concurrent updates
- of the index by multiple processes. If the method's
- pg_am>.amconcurrent> flag is true, then
- the core PostgreSQL system obtains
+ Index access methods must handle concurrent updates
+ of the index by multiple processes.
+ The core PostgreSQL system obtains
AccessShareLock> on the index during an index scan, and
- RowExclusiveLock> when updating the index. Since these lock
+ RowExclusiveLock> when updating the index (including plain
+ VACUUM>). Since these lock
types do not conflict, the access method is responsible for handling any
fine-grained locking it may need. An exclusive lock on the index as a whole
- will be taken only during index creation, destruction, or
- REINDEX>. When amconcurrent> is false,
- PostgreSQL still obtains
- AccessShareLock> during index scans, but it obtains
- AccessExclusiveLock> during any update. This ensures that
- updaters have sole use of the index. Note that this implicitly assumes
- that index scans are read-only; an access method that might modify the
- index during a scan will still have to do its own locking to handle the
- case of concurrent scans.
-
-
-
- Recall that a backend's own locks never conflict; therefore, even a
- non-concurrent index type must be prepared to handle the case where
- a backend is inserting or deleting entries in an index that it is itself
- scanning. (This is of course necessary to support an UPDATE>
- that uses the index to find the rows to be updated.)
+ will be taken only during index creation, destruction,
+ REINDEX>, or VACUUM FULL>.
@@ -567,7 +547,7 @@ amrestrpos (IndexScanDesc scan);
- For concurrent index types, an index scan must maintain a pin
+ An index scan must maintain a pin
on the index page holding the item last returned by
amgettuple>, and ambulkdelete> cannot delete
entries from pages that are pinned by other backends. The need
@@ -576,11 +556,10 @@ amrestrpos (IndexScanDesc scan);
- If an index is concurrent then it is possible for an index reader to
+ Without the third rule, it is possible for an index reader to
see an index entry just before it is removed by VACUUM>, and
then to arrive at the corresponding heap entry after that was removed by
- VACUUM>. (With a nonconcurrent index, this is not possible
- because of the conflicting index-level locks that will be taken out.)
+ VACUUM>.
This creates no serious problems if that item
number is still unused when the reader reaches it, since an empty
item slot will be ignored by heap_fetch()>. But what if a
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index c6551939a20..2bc80a26433 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.5 2006/07/31 20:08:59 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -572,7 +572,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation index = info->index;
- bool needLock = !RELATION_IS_LOCAL(index);
+ bool needLock;
BlockNumber npages,
blkno;
BlockNumber nFreePages,
@@ -591,10 +591,14 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
*/
stats->num_index_tuples = info->num_heap_tuples;
- if (info->vacuum_full) {
- LockRelation(index, AccessExclusiveLock);
+ /*
+ * If vacuum full, we already have exclusive lock on the index.
+ * Otherwise, need lock unless it's local to this backend.
+ */
+ if (info->vacuum_full)
needLock = false;
- }
+ else
+ needLock = !RELATION_IS_LOCAL(index);
if (needLock)
LockRelationForExtension(index, ExclusiveLock);
@@ -653,9 +657,6 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
if (needLock)
UnlockRelationForExtension(index, ExclusiveLock);
- if (info->vacuum_full)
- UnlockRelation(index, AccessExclusiveLock);
-
PG_RETURN_POINTER(stats);
}
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index e3bff5147c2..37b5631b281 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.25 2006/07/14 14:52:16 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.26 2006/07/31 20:08:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -517,7 +517,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
GistVacuum gv;
ArrayTuple res;
- LockRelation(rel, AccessExclusiveLock);
+ /* note: vacuum.c already acquired AccessExclusiveLock on index */
gv.index = rel;
initGISTstate(&(gv.giststate), rel);
@@ -543,8 +543,12 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
(errmsg("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery",
RelationGetRelationName(rel))));
+ /*
+ * If vacuum full, we already have exclusive lock on the index.
+ * Otherwise, need lock unless it's local to this backend.
+ */
if (info->vacuum_full)
- needLock = false; /* relation locked with AccessExclusiveLock */
+ needLock = false;
else
needLock = !RELATION_IS_LOCAL(rel);
@@ -613,9 +617,6 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
if (needLock)
UnlockRelationForExtension(rel, ExclusiveLock);
- if (info->vacuum_full)
- UnlockRelation(rel, AccessExclusiveLock);
-
PG_RETURN_POINTER(stats);
}
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 91460410bf9..f29407e8e5d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.217 2006/07/14 14:52:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.218 2006/07/31 20:08:59 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -51,6 +51,7 @@
#include "pgstat.h"
#include "storage/procarray.h"
#include "utils/inval.h"
+#include "utils/lsyscache.h"
#include "utils/relcache.h"
@@ -687,15 +688,16 @@ relation_open(Oid relationId, LOCKMODE lockmode)
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+ /* Get the lock before trying to open the relcache entry */
+ if (lockmode != NoLock)
+ LockRelationOid(relationId, lockmode);
+
/* The relcache does all the real work... */
r = RelationIdGetRelation(relationId);
if (!RelationIsValid(r))
elog(ERROR, "could not open relation with OID %u", relationId);
- if (lockmode != NoLock)
- LockRelation(r, lockmode);
-
return r;
}
@@ -713,26 +715,38 @@ conditional_relation_open(Oid relationId, LOCKMODE lockmode, bool nowait)
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+ /* Get the lock before trying to open the relcache entry */
+ if (lockmode != NoLock)
+ {
+ if (nowait)
+ {
+ if (!ConditionalLockRelationOid(relationId, lockmode))
+ {
+ /* try to throw error by name; relation could be deleted... */
+ char *relname = get_rel_name(relationId);
+
+ if (relname)
+ ereport(ERROR,
+ (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("could not obtain lock on relation \"%s\"",
+ relname)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("could not obtain lock on relation with OID %u",
+ relationId)));
+ }
+ }
+ else
+ LockRelationOid(relationId, lockmode);
+ }
+
/* The relcache does all the real work... */
r = RelationIdGetRelation(relationId);
if (!RelationIsValid(r))
elog(ERROR, "could not open relation with OID %u", relationId);
- if (lockmode != NoLock)
- {
- if (nowait)
- {
- if (!ConditionalLockRelation(r, lockmode))
- ereport(ERROR,
- (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
- errmsg("could not obtain lock on relation \"%s\"",
- RelationGetRelationName(r))));
- }
- else
- LockRelation(r, lockmode);
- }
-
return r;
}
@@ -749,12 +763,12 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
/*
* Check for shared-cache-inval messages before trying to open the
- * relation. This is needed to cover the case where the name identifies a
- * rel that has been dropped and recreated since the start of our
+ * relation. This is needed to cover the case where the name identifies
+ * a rel that has been dropped and recreated since the start of our
* transaction: if we don't flush the old syscache entry then we'll latch
- * onto that entry and suffer an error when we do LockRelation. Note that
- * relation_open does not need to do this, since a relation's OID never
- * changes.
+ * onto that entry and suffer an error when we do RelationIdGetRelation.
+ * Note that relation_open does not need to do this, since a relation's
+ * OID never changes.
*
* We skip this if asked for NoLock, on the assumption that the caller has
* already ensured some appropriate lock is held.
@@ -772,7 +786,7 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
/* ----------------
* relation_close - close any relation
*
- * If lockmode is not "NoLock", we first release the specified lock.
+ * If lockmode is not "NoLock", we then release the specified lock.
*
* Note that it is often sensible to hold a lock beyond relation_close;
* in that case, the lock is released automatically at xact end.
@@ -781,13 +795,15 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
void
relation_close(Relation relation, LOCKMODE lockmode)
{
- Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+ LockRelId relid = relation->rd_lockInfo.lockRelId;
- if (lockmode != NoLock)
- UnlockRelation(relation, lockmode);
+ Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
/* The relcache does the real work... */
RelationClose(relation);
+
+ if (lockmode != NoLock)
+ UnlockRelationId(&relid, lockmode);
}
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 11adf165c45..43ca366f0a6 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.62 2006/07/14 14:52:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.63 2006/07/31 20:08:59 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1004,7 +1004,7 @@ toast_save_datum(Relation rel, Datum value)
*/
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
toasttupDesc = toastrel->rd_att;
- toastidx = index_open(toastrel->rd_rel->reltoastidxid);
+ toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
/*
* Create the varattrib reference
@@ -1043,12 +1043,6 @@ toast_save_datum(Relation rel, Datum value)
data_p = VARATT_DATA(value);
data_todo = VARATT_SIZE(value) - VARHDRSZ;
- /*
- * We must explicitly lock the toast index because we aren't using an
- * index scan here.
- */
- LockRelation(toastidx, RowExclusiveLock);
-
/*
* Split up the item into chunks
*/
@@ -1098,8 +1092,7 @@ toast_save_datum(Relation rel, Datum value)
/*
* Done - close toast relation and return the reference
*/
- UnlockRelation(toastidx, RowExclusiveLock);
- index_close(toastidx);
+ index_close(toastidx, RowExclusiveLock);
heap_close(toastrel, RowExclusiveLock);
return PointerGetDatum(result);
@@ -1130,7 +1123,7 @@ toast_delete_datum(Relation rel, Datum value)
*/
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
RowExclusiveLock);
- toastidx = index_open(toastrel->rd_rel->reltoastidxid);
+ toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
/*
* Setup a scan key to fetch from the index by va_valueid (we don't
@@ -1144,7 +1137,7 @@ toast_delete_datum(Relation rel, Datum value)
/*
* Find the chunks by index
*/
- toastscan = index_beginscan(toastrel, toastidx, true,
+ toastscan = index_beginscan(toastrel, toastidx,
SnapshotToast, 1, &toastkey);
while ((toasttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
{
@@ -1158,7 +1151,7 @@ toast_delete_datum(Relation rel, Datum value)
* End scan and close relations
*/
index_endscan(toastscan);
- index_close(toastidx);
+ index_close(toastidx, RowExclusiveLock);
heap_close(toastrel, RowExclusiveLock);
}
@@ -1202,7 +1195,7 @@ toast_fetch_datum(varattrib *attr)
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
AccessShareLock);
toasttupDesc = toastrel->rd_att;
- toastidx = index_open(toastrel->rd_rel->reltoastidxid);
+ toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);
/*
* Setup a scan key to fetch from the index by va_valueid
@@ -1221,7 +1214,7 @@ toast_fetch_datum(varattrib *attr)
*/
nextidx = 0;
- toastscan = index_beginscan(toastrel, toastidx, true,
+ toastscan = index_beginscan(toastrel, toastidx,
SnapshotToast, 1, &toastkey);
while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
{
@@ -1282,7 +1275,7 @@ toast_fetch_datum(varattrib *attr)
* End scan and close relations
*/
index_endscan(toastscan);
- index_close(toastidx);
+ index_close(toastidx, AccessShareLock);
heap_close(toastrel, AccessShareLock);
return result;
@@ -1355,7 +1348,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
AccessShareLock);
toasttupDesc = toastrel->rd_att;
- toastidx = index_open(toastrel->rd_rel->reltoastidxid);
+ toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);
/*
* Setup a scan key to fetch from the index. This is either two keys or
@@ -1396,7 +1389,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
* The index is on (valueid, chunkidx) so they will come in order
*/
nextidx = startchunk;
- toastscan = index_beginscan(toastrel, toastidx, true,
+ toastscan = index_beginscan(toastrel, toastidx,
SnapshotToast, nscankeys, toastkey);
while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
{
@@ -1461,7 +1454,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
* End scan and close relations
*/
index_endscan(toastscan);
- index_close(toastidx);
+ index_close(toastidx, AccessShareLock);
heap_close(toastrel, AccessShareLock);
return result;
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 399386c8567..347d2b5365a 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.57 2006/07/03 22:45:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.58 2006/07/31 20:08:59 tgl Exp $
*
* NOTES
* many of the old access method routines have been turned into
@@ -87,7 +87,6 @@ RelationGetIndexScan(Relation indexRelation,
scan->keyData = NULL;
scan->is_multiscan = false; /* caller may change this */
- scan->have_lock = false; /* ditto */
scan->kill_prior_tuple = false;
scan->ignore_killed_tuples = true; /* default setting */
@@ -182,7 +181,7 @@ systable_beginscan(Relation heapRelation,
if (indexOK &&
!IgnoreSystemIndexes &&
!ReindexIsProcessingIndex(indexId))
- irel = index_open(indexId);
+ irel = index_open(indexId, AccessShareLock);
else
irel = NULL;
@@ -207,7 +206,7 @@ systable_beginscan(Relation heapRelation,
key[i].sk_attno = i + 1;
}
- sysscan->iscan = index_beginscan(heapRelation, irel, true,
+ sysscan->iscan = index_beginscan(heapRelation, irel,
snapshot, nkeys, key);
sysscan->scan = NULL;
}
@@ -253,7 +252,7 @@ systable_endscan(SysScanDesc sysscan)
if (sysscan->irel)
{
index_endscan(sysscan->iscan);
- index_close(sysscan->irel);
+ index_close(sysscan->irel, AccessShareLock);
}
else
heap_endscan(sysscan->scan);
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 900b34263d8..2663876f494 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,11 +8,10 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.93 2006/05/07 01:21:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.94 2006/07/31 20:08:59 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
- * index_openrv - open an index relation specified by a RangeVar
* index_close - close an index relation
* index_beginscan - start a scan of an index with amgettuple
* index_beginscan_multi - start a scan of an index with amgetmulti
@@ -111,7 +110,6 @@ do { \
} while(0)
static IndexScanDesc index_beginscan_internal(Relation indexRelation,
- bool need_index_lock,
int nkeys, ScanKey key);
@@ -123,26 +121,23 @@ static IndexScanDesc index_beginscan_internal(Relation indexRelation,
/* ----------------
* index_open - open an index relation by relation OID
*
- * Note: we acquire no lock on the index. A lock is not needed when
- * simply examining the index reldesc; the index's schema information
- * is considered to be protected by the lock that the caller had better
- * be holding on the parent relation. Some type of lock should be
- * obtained on the index before physically accessing it, however.
- * This is handled automatically for most uses by index_beginscan
- * and index_endscan for scan cases, or by ExecOpenIndices and
- * ExecCloseIndices for update cases. Other callers will need to
- * obtain their own locks.
+ * If lockmode is not "NoLock", the specified kind of lock is
+ * obtained on the index. (Generally, NoLock should only be
+ * used if the caller knows it has some appropriate lock on the
+ * index already.)
+ *
+ * An error is raised if the index does not exist.
*
* This is a convenience routine adapted for indexscan use.
* Some callers may prefer to use relation_open directly.
* ----------------
*/
Relation
-index_open(Oid relationId)
+index_open(Oid relationId, LOCKMODE lockmode)
{
Relation r;
- r = relation_open(relationId, NoLock);
+ r = relation_open(relationId, lockmode);
if (r->rd_rel->relkind != RELKIND_INDEX)
ereport(ERROR,
@@ -156,41 +151,26 @@ index_open(Oid relationId)
}
/* ----------------
- * index_openrv - open an index relation specified
- * by a RangeVar node
+ * index_close - close an index relation
*
- * As above, but relation is specified by a RangeVar.
- * ----------------
- */
-Relation
-index_openrv(const RangeVar *relation)
-{
- Relation r;
-
- r = relation_openrv(relation, NoLock);
-
- if (r->rd_rel->relkind != RELKIND_INDEX)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not an index",
- RelationGetRelationName(r))));
-
- pgstat_initstats(&r->pgstat_info, r);
-
- return r;
-}
-
-/* ----------------
- * index_close - close a index relation
+ * If lockmode is not "NoLock", we then release the specified lock.
*
- * presently the relcache routines do all the work we need
- * to open/close index relations.
+ * Note that it is often sensible to hold a lock beyond index_close;
+ * in that case, the lock is released automatically at xact end.
* ----------------
*/
void
-index_close(Relation relation)
+index_close(Relation relation, LOCKMODE lockmode)
{
+ LockRelId relid = relation->rd_lockInfo.lockRelId;
+
+ Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
+ /* The relcache does the real work... */
RelationClose(relation);
+
+ if (lockmode != NoLock)
+ UnlockRelationId(&relid, lockmode);
}
/* ----------------
@@ -229,24 +209,18 @@ index_insert(Relation indexRelation,
* index_getnext on this scan; index_getnext_indexitem will not use the
* heapRelation link (nor the snapshot). However, the caller had better
* be holding some kind of lock on the heap relation in any case, to ensure
- * no one deletes it (or the index) out from under us.
- *
- * Most callers should pass need_index_lock = true to cause the index code
- * to take AccessShareLock on the index for the duration of the scan. But
- * if it is known that a lock is already held on the index, pass false to
- * skip taking an unnecessary lock.
+ * no one deletes it (or the index) out from under us. Caller must also
+ * be holding a lock on the index.
*/
IndexScanDesc
index_beginscan(Relation heapRelation,
Relation indexRelation,
- bool need_index_lock,
Snapshot snapshot,
int nkeys, ScanKey key)
{
IndexScanDesc scan;
- scan = index_beginscan_internal(indexRelation, need_index_lock,
- nkeys, key);
+ scan = index_beginscan_internal(indexRelation, nkeys, key);
/*
* Save additional parameters into the scandesc. Everything else was set
@@ -267,14 +241,12 @@ index_beginscan(Relation heapRelation,
*/
IndexScanDesc
index_beginscan_multi(Relation indexRelation,
- bool need_index_lock,
Snapshot snapshot,
int nkeys, ScanKey key)
{
IndexScanDesc scan;
- scan = index_beginscan_internal(indexRelation, need_index_lock,
- nkeys, key);
+ scan = index_beginscan_internal(indexRelation, nkeys, key);
/*
* Save additional parameters into the scandesc. Everything else was set
@@ -291,34 +263,19 @@ index_beginscan_multi(Relation indexRelation,
*/
static IndexScanDesc
index_beginscan_internal(Relation indexRelation,
- bool need_index_lock,
int nkeys, ScanKey key)
{
IndexScanDesc scan;
FmgrInfo *procedure;
RELATION_CHECKS;
-
- RelationIncrementReferenceCount(indexRelation);
-
- /*
- * Acquire AccessShareLock for the duration of the scan, unless caller
- * says it already has lock on the index.
- *
- * Note: we could get an SI inval message here and consequently have to
- * rebuild the relcache entry. The refcount increment above ensures that
- * we will rebuild it and not just flush it...
- */
- if (need_index_lock)
- LockRelation(indexRelation, AccessShareLock);
-
- /*
- * LockRelation can clean rd_aminfo structure, so fill procedure after
- * LockRelation
- */
-
GET_REL_PROCEDURE(ambeginscan);
+ /*
+ * We hold a reference count to the relcache entry throughout the scan.
+ */
+ RelationIncrementReferenceCount(indexRelation);
+
/*
* Tell the AM to open a scan.
*/
@@ -328,9 +285,6 @@ index_beginscan_internal(Relation indexRelation,
Int32GetDatum(nkeys),
PointerGetDatum(key)));
- /* Save flag to tell index_endscan whether to release lock */
- scan->have_lock = need_index_lock;
-
return scan;
}
@@ -390,11 +344,7 @@ index_endscan(IndexScanDesc scan)
/* End the AM's scan */
FunctionCall1(procedure, PointerGetDatum(scan));
- /* Release index lock and refcount acquired by index_beginscan */
-
- if (scan->have_lock)
- UnlockRelation(scan->indexRelation, AccessShareLock);
-
+ /* Release index refcount acquired by index_beginscan */
RelationDecrementReferenceCount(scan->indexRelation);
/* Release the scan data structure itself */
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 9399b6d052b..08189bf07b2 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.222 2006/07/31 01:16:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.223 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1239,12 +1239,13 @@ build_indices(void)
Relation heap;
Relation ind;
+ /* need not bother with locks during bootstrap */
heap = heap_open(ILHead->il_heap, NoLock);
- ind = index_open(ILHead->il_ind);
+ ind = index_open(ILHead->il_ind, NoLock);
index_build(heap, ind, ILHead->il_info, false);
- index_close(ind);
+ index_close(ind, NoLock);
heap_close(heap, NoLock);
}
}
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index a7b50df950d..5d99acafc95 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -1,7 +1,8 @@
/*-------------------------------------------------------------------------
*
* catalog.c
- * routines concerned with catalog naming conventions
+ * routines concerned with catalog naming conventions and other
+ * bits of hard-wired knowledge
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
@@ -9,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.66 2006/03/05 15:58:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.67 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,8 +23,16 @@
#include "access/genam.h"
#include "access/transam.h"
#include "catalog/catalog.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_auth_members.h"
+#include "catalog/pg_authid.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
+#include "catalog/pg_pltemplate.h"
+#include "catalog/pg_shdepend.h"
+#include "catalog/pg_shdescription.h"
#include "catalog/pg_tablespace.h"
+#include "catalog/toasting.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/fmgroids.h"
@@ -217,6 +226,64 @@ IsReservedName(const char *name)
}
+/*
+ * IsSharedRelation
+ * 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.
+ */
+bool
+IsSharedRelation(Oid relationId)
+{
+ /* These are the shared catalogs (look for BKI_SHARED_RELATION) */
+ if (relationId == AuthIdRelationId ||
+ relationId == AuthMemRelationId ||
+ relationId == DatabaseRelationId ||
+ relationId == PLTemplateRelationId ||
+ relationId == SharedDescriptionRelationId ||
+ relationId == SharedDependRelationId ||
+ relationId == TableSpaceRelationId)
+ return true;
+ /* These are their indexes (see indexing.h) */
+ if (relationId == AuthIdRolnameIndexId ||
+ relationId == AuthIdOidIndexId ||
+ relationId == AuthMemRoleMemIndexId ||
+ relationId == AuthMemMemRoleIndexId ||
+ relationId == DatabaseNameIndexId ||
+ relationId == DatabaseOidIndexId ||
+ relationId == PLTemplateNameIndexId ||
+ relationId == SharedDescriptionObjIndexId ||
+ relationId == SharedDependDependerIndexId ||
+ relationId == SharedDependReferenceIndexId ||
+ relationId == TablespaceOidIndexId ||
+ relationId == TablespaceNameIndexId)
+ return true;
+ /* These are their toast tables and toast indexes (see toasting.h) */
+ if (relationId == PgAuthidToastTable ||
+ relationId == PgAuthidToastIndex ||
+ relationId == PgDatabaseToastTable ||
+ relationId == PgDatabaseToastIndex ||
+ relationId == PgShdescriptionToastTable ||
+ relationId == PgShdescriptionToastIndex)
+ return true;
+ return false;
+}
+
+
/*
* GetNewOid
* Generate a new OID that is unique within the given relation.
@@ -271,9 +338,9 @@ GetNewOid(Relation relation)
}
/* Otherwise, use the index to find a nonconflicting OID */
- indexrel = index_open(oidIndex);
+ indexrel = index_open(oidIndex, AccessShareLock);
newOid = GetNewOidWithIndex(relation, indexrel);
- index_close(indexrel);
+ index_close(indexrel, AccessShareLock);
return newOid;
}
@@ -309,7 +376,7 @@ GetNewOidWithIndex(Relation relation, Relation indexrel)
ObjectIdGetDatum(newOid));
/* see notes above about using SnapshotDirty */
- scan = index_beginscan(relation, indexrel, true,
+ scan = index_beginscan(relation, indexrel,
SnapshotDirty, 1, &key);
collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 361f6800877..922a0cebf71 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.310 2006/07/31 01:16:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.311 2006/07/31 20:09:00 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1971,24 +1971,17 @@ RemoveStatistics(Oid relid, AttrNumber attnum)
/*
- * RelationTruncateIndexes - truncate all
- * indexes associated with the heap relation to zero tuples.
+ * RelationTruncateIndexes - truncate all indexes associated
+ * with the heap relation to zero tuples.
*
* The routine will truncate and then reconstruct the indexes on
- * the relation specified by the heapId parameter.
+ * the specified relation. Caller must hold exclusive lock on rel.
*/
static void
-RelationTruncateIndexes(Oid heapId)
+RelationTruncateIndexes(Relation heapRelation)
{
- Relation heapRelation;
ListCell *indlist;
- /*
- * Open the heap rel. We need grab no lock because we assume
- * heap_truncate is holding an exclusive lock on the heap rel.
- */
- heapRelation = heap_open(heapId, NoLock);
-
/* Ask the relcache to produce a list of the indexes of the rel */
foreach(indlist, RelationGetIndexList(heapRelation))
{
@@ -1996,11 +1989,8 @@ RelationTruncateIndexes(Oid heapId)
Relation currentIndex;
IndexInfo *indexInfo;
- /* Open the index relation */
- currentIndex = index_open(indexId);
-
- /* Obtain exclusive lock on it, just to be sure */
- LockRelation(currentIndex, AccessExclusiveLock);
+ /* Open the index relation; use exclusive lock, just to be sure */
+ currentIndex = index_open(indexId, AccessExclusiveLock);
/* Fetch info needed for index_build */
indexInfo = BuildIndexInfo(currentIndex);
@@ -2013,11 +2003,8 @@ RelationTruncateIndexes(Oid heapId)
index_build(heapRelation, currentIndex, indexInfo, false);
/* We're done with this index */
- index_close(currentIndex);
+ index_close(currentIndex, NoLock);
}
-
- /* And now done with the heap; but keep lock until commit */
- heap_close(heapRelation, NoLock);
}
/*
@@ -2066,7 +2053,7 @@ heap_truncate(List *relids)
RelationTruncate(rel, 0);
/* If this relation has indexes, truncate the indexes too */
- RelationTruncateIndexes(RelationGetRelid(rel));
+ RelationTruncateIndexes(rel);
/*
* Close the relation, but keep exclusive lock on it until commit.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 092c9dcda10..0da209ff216 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.271 2006/07/31 01:16:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.272 2006/07/31 20:09:00 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -483,12 +483,8 @@ index_create(Oid heapRelationId,
/*
* We cannot allow indexing a shared relation after initdb (because
* there's no way to make the entry in other databases' pg_class).
- * Unfortunately we can't distinguish initdb from a manually started
- * standalone backend (toasting of shared rels happens after the bootstrap
- * phase, so checking IsBootstrapProcessingMode() won't work). However,
- * we can at least prevent this mistake under normal multi-user operation.
*/
- if (shared_relation && IsUnderPostmaster)
+ if (shared_relation && !IsBootstrapProcessingMode())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("shared indexes cannot be created after initdb")));
@@ -753,7 +749,7 @@ index_create(Oid heapRelationId,
* the exclusive lock on the index that we acquired above, until end of
* transaction.
*/
- index_close(indexRelation);
+ index_close(indexRelation, NoLock);
heap_close(heapRelation, NoLock);
return indexRelationId;
@@ -789,8 +785,7 @@ index_drop(Oid indexId)
heapId = IndexGetRelation(indexId);
userHeapRelation = heap_open(heapId, AccessExclusiveLock);
- userIndexRelation = index_open(indexId);
- LockRelation(userIndexRelation, AccessExclusiveLock);
+ userIndexRelation = index_open(indexId, AccessExclusiveLock);
/*
* Schedule physical removal of the file
@@ -804,7 +799,7 @@ index_drop(Oid indexId)
* try to rebuild it while we're deleting catalog entries. We keep the
* lock though.
*/
- index_close(userIndexRelation);
+ index_close(userIndexRelation, NoLock);
RelationForgetRelation(indexId);
@@ -982,11 +977,11 @@ FormIndexDatum(IndexInfo *indexInfo,
/*
- * index_update_stats --- update pg_class entry after CREATE INDEX
+ * index_update_stats --- update pg_class entry after CREATE INDEX or REINDEX
*
* This routine updates the pg_class row of either an index or its parent
- * relation after CREATE INDEX. Its rather bizarre API is designed to
- * ensure we can do all the necessary work in just one update.
+ * relation after CREATE INDEX or REINDEX. Its rather bizarre API is designed
+ * to ensure we can do all the necessary work in just one update.
*
* hasindex: set relhasindex to this value
* isprimary: if true, set relhaspkey true; else no change
@@ -1013,33 +1008,50 @@ index_update_stats(Relation rel, bool hasindex, bool isprimary,
Relation pg_class;
HeapTuple tuple;
Form_pg_class rd_rel;
- bool in_place_upd;
bool dirty;
/*
- * Find the tuple to update in pg_class. Normally we make a copy of the
- * tuple using the syscache, modify it, and apply heap_update. But in
- * bootstrap mode we can't use heap_update, so we use a nontransactional
- * update, ie, overwrite the tuple in-place.
+ * We always update the pg_class row using a non-transactional,
+ * overwrite-in-place update. There are several reasons for this:
*
- * We also must use an in-place update if reindexing pg_class itself,
- * because the target index may presently not be part of the set of
- * indexes that CatalogUpdateIndexes would update (see reindex_relation).
+ * 1. In bootstrap mode, we have no choice --- UPDATE wouldn't work.
+ *
+ * 2. We could be reindexing pg_class itself, in which case we can't
+ * move its pg_class row because CatalogUpdateIndexes might not know
+ * about all the indexes yet (see reindex_relation).
+ *
+ * 3. Because we execute CREATE INDEX with just share lock on the parent
+ * rel (to allow concurrent index creations), an ordinary update could
+ * suffer a tuple-concurrently-updated failure against another CREATE
+ * INDEX committing at about the same time. We can avoid that by having
+ * them both do nontransactional updates (we assume they will both be
+ * trying to change the pg_class row to the same thing, so it doesn't
+ * matter which goes first).
+ *
+ * 4. Even with just a single CREATE INDEX, there's a risk factor because
+ * someone else might be trying to open the rel while we commit, and this
+ * creates a race condition as to whether he will see both or neither of
+ * the pg_class row versions as valid. Again, a non-transactional update
+ * avoids the risk. It is indeterminate which state of the row the other
+ * process will see, but it doesn't matter (if he's only taking
+ * AccessShareLock, then it's not critical that he see relhasindex true).
+ *
+ * It is safe to use a non-transactional update even though our
+ * transaction could still fail before committing. Setting relhasindex
+ * true is safe even if there are no indexes (VACUUM will eventually fix
+ * it), and of course the relpages and reltuples counts are correct (or
+ * at least more so than the old values) regardless.
*/
+
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
- in_place_upd = IsBootstrapProcessingMode() ||
- ReindexIsProcessingHeap(RelationRelationId);
-
-restart:
-
- if (!in_place_upd)
- {
- tuple = SearchSysCacheCopy(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
- }
- else
+ /*
+ * Make a copy of the tuple to update. Normally we use the syscache,
+ * but we can't rely on that during bootstrap or while reindexing
+ * pg_class itself.
+ */
+ if (IsBootstrapProcessingMode() ||
+ ReindexIsProcessingHeap(RelationRelationId))
{
/* don't assume syscache will work */
HeapScanDesc pg_class_scan;
@@ -1055,6 +1067,13 @@ restart:
tuple = heap_copytuple(tuple);
heap_endscan(pg_class_scan);
}
+ else
+ {
+ /* normal case, use syscache */
+ tuple = SearchSysCacheCopy(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ }
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for relation %u", relid);
@@ -1101,53 +1120,8 @@ restart:
*/
if (dirty)
{
- if (in_place_upd)
- {
- heap_inplace_update(pg_class, tuple);
- }
- else
- {
- /*
- * Because PG allows concurrent CREATE INDEX commands, it's
- * possible that someone else tries to update the pg_class
- * row at about the same time we do. Hence, instead of using
- * simple_heap_update(), we must use full heap_update() and
- * cope with HeapTupleUpdated result. If we see that, just
- * go back and try the whole update again.
- */
- HTSU_Result result;
- ItemPointerData update_ctid;
- TransactionId update_xmax;
-
- result = heap_update(pg_class, &tuple->t_self, tuple,
- &update_ctid, &update_xmax,
- GetCurrentCommandId(), InvalidSnapshot,
- true /* wait for commit */ );
- switch (result)
- {
- case HeapTupleSelfUpdated:
- /* Tuple was already updated in current command? */
- elog(ERROR, "tuple already updated by self");
- break;
-
- case HeapTupleMayBeUpdated:
- /* done successfully */
- break;
-
- case HeapTupleUpdated:
- heap_freetuple(tuple);
- /* Must do CCI so we can see the updated tuple */
- CommandCounterIncrement();
- goto restart;
-
- default:
- elog(ERROR, "unrecognized heap_update status: %u", result);
- break;
- }
-
- /* Keep the catalog indexes up to date */
- CatalogUpdateIndexes(pg_class, tuple);
- }
+ heap_inplace_update(pg_class, tuple);
+ /* the above sends a cache inval message */
}
else
{
@@ -1571,8 +1545,7 @@ reindex_index(Oid indexId)
* Open the target index relation and get an exclusive lock on it, to
* ensure that no one else is touching this particular index.
*/
- iRel = index_open(indexId);
- LockRelation(iRel, AccessExclusiveLock);
+ iRel = index_open(indexId, AccessExclusiveLock);
/*
* If it's a shared index, we must do inplace processing (because we have
@@ -1628,7 +1601,7 @@ reindex_index(Oid indexId)
ResetReindexProcessing();
/* Close rels, but keep locks */
- index_close(iRel);
+ index_close(iRel, NoLock);
heap_close(heapRelation, NoLock);
}
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index e16afa0559d..f0cbaefd60e 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.151 2006/07/31 01:16:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.152 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -314,8 +314,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck)
{
Relation OldIndex;
- OldIndex = index_open(indexOid);
- LockRelation(OldIndex, AccessExclusiveLock);
+ OldIndex = index_open(indexOid, AccessExclusiveLock);
/*
* Check that index is in fact an index on the given relation
@@ -406,7 +405,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck)
errmsg("cannot cluster temporary tables of other sessions")));
/* Drop relcache refcnt on OldIndex, but keep lock */
- index_close(OldIndex);
+ index_close(OldIndex, NoLock);
}
/*
@@ -649,7 +648,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
*/
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
- OldIndex = index_open(OIDOldIndex);
+ OldIndex = index_open(OIDOldIndex, AccessExclusiveLock);
/*
* Their tuple descriptors should be exactly alike, but here we only need
@@ -669,7 +668,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
* Scan through the OldHeap on the OldIndex and copy each tuple into the
* NewHeap.
*/
- scan = index_beginscan(OldHeap, OldIndex, true,
+ scan = index_beginscan(OldHeap, OldIndex,
SnapshotNow, 0, (ScanKey) NULL);
while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)
@@ -724,7 +723,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
pfree(values);
pfree(nulls);
- index_close(OldIndex);
+ index_close(OldIndex, NoLock);
heap_close(OldHeap, NoLock);
heap_close(NewHeap, NoLock);
}
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index a3b35a640ea..6154a4ed3da 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.137 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.138 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -79,7 +79,7 @@ static SeqTable seqtab = NULL; /* Head of list of SeqTable items */
static SeqTableData *last_used_seq = NULL;
static int64 nextval_internal(Oid relid);
-static void acquire_share_lock(Relation seqrel, SeqTable seq);
+static Relation open_share_lock(SeqTable seq);
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
static void init_params(List *options, Form_pg_sequence new, bool isInit);
@@ -650,8 +650,7 @@ lastval(PG_FUNCTION_ARGS)
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("lastval is not yet defined in this session")));
- seqrel = relation_open(last_used_seq->relid, NoLock);
- acquire_share_lock(seqrel, last_used_seq);
+ seqrel = open_share_lock(last_used_seq);
/* nextval() must have already been called for this sequence */
Assert(last_used_seq->increment != 0);
@@ -802,16 +801,19 @@ setval3_oid(PG_FUNCTION_ARGS)
/*
+ * Open the sequence and acquire AccessShareLock if needed
+ *
* If we haven't touched the sequence already in this transaction,
* we need to acquire AccessShareLock. We arrange for the lock to
* be owned by the top transaction, so that we don't need to do it
* more than once per xact.
*/
-static void
-acquire_share_lock(Relation seqrel, SeqTable seq)
+static Relation
+open_share_lock(SeqTable seq)
{
TransactionId thisxid = GetTopTransactionId();
+ /* Get the lock if not already held in this xact */
if (seq->xid != thisxid)
{
ResourceOwner currentOwner;
@@ -820,7 +822,7 @@ acquire_share_lock(Relation seqrel, SeqTable seq)
PG_TRY();
{
CurrentResourceOwner = TopTransactionResourceOwner;
- LockRelation(seqrel, AccessShareLock);
+ LockRelationOid(seq->relid, AccessShareLock);
}
PG_CATCH();
{
@@ -831,9 +833,12 @@ acquire_share_lock(Relation seqrel, SeqTable seq)
PG_END_TRY();
CurrentResourceOwner = currentOwner;
- /* Flag that we have a lock in the current xact. */
+ /* Flag that we have a lock in the current xact */
seq->xid = thisxid;
}
+
+ /* We now know we have AccessShareLock, and can safely open the rel */
+ return relation_open(seq->relid, NoLock);
}
/*
@@ -843,19 +848,8 @@ acquire_share_lock(Relation seqrel, SeqTable seq)
static void
init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
{
+ SeqTable elm;
Relation seqrel;
- volatile SeqTable elm;
-
- /*
- * Open the sequence relation.
- */
- seqrel = relation_open(relid, NoLock);
-
- if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a sequence",
- RelationGetRelationName(seqrel))));
/* Look to see if we already have a seqtable entry for relation */
for (elm = seqtab; elm != NULL; elm = elm->next)
@@ -890,7 +884,16 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
seqtab = elm;
}
- acquire_share_lock(seqrel, elm);
+ /*
+ * Open the sequence relation.
+ */
+ seqrel = open_share_lock(elm);
+
+ if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a sequence",
+ RelationGetRelationName(seqrel))));
*p_elm = elm;
*p_rel = seqrel;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 53382ff3d47..3b408b411a6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.197 2006/07/31 01:16:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.198 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -5863,7 +5863,10 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
HeapTuple tuple;
Form_pg_class rd_rel;
- rel = relation_open(tableOid, NoLock);
+ /*
+ * Need lock here in case we are recursing to toast table or index
+ */
+ rel = relation_open(tableOid, AccessExclusiveLock);
/*
* We can never allow moving of shared or nailed-in-cache relations,
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 158e783c575..13e7cab721b 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.204 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.205 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,7 +36,6 @@
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
-#include "utils/relcache.h"
#include "utils/syscache.h"
@@ -2986,7 +2985,6 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
- Relation constraintRel;
Oid constraintNamespaceId;
/*
@@ -3010,13 +3008,9 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
pg_trigger->tgfoid == F_RI_FKEY_SETNULL_DEL ||
pg_trigger->tgfoid == F_RI_FKEY_SETDEFAULT_UPD ||
pg_trigger->tgfoid == F_RI_FKEY_SETDEFAULT_DEL)
- {
- constraintRel = RelationIdGetRelation(pg_trigger->tgconstrrelid);
- } else {
- constraintRel = RelationIdGetRelation(pg_trigger->tgrelid);
- }
- constraintNamespaceId = RelationGetNamespace(constraintRel);
- RelationClose(constraintRel);
+ constraintNamespaceId = get_rel_namespace(pg_trigger->tgconstrrelid);
+ else
+ constraintNamespaceId = get_rel_namespace(pg_trigger->tgrelid);
/*
* If this constraint is not in the schema we're
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1304e686813..6dfa6296d5a 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.95 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.96 2006/07/31 20:09:00 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -1625,6 +1625,8 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
SysScanDesc depScan;
HeapTuple depTup;
+ Assert(lockmode != NoLock);
+
/*
* We scan pg_depend to find those things that depend on the domain. (We
* assume we can ignore refobjsubid for a domain.)
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index eb0fce72edb..c21be2f4788 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.336 2006/07/30 02:07:18 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.337 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1138,7 +1138,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
* same process.
*/
onerelid = onerel->rd_lockInfo.lockRelId;
- LockRelationForSession(&onerelid, onerel->rd_istemp, lmode);
+ LockRelationIdForSession(&onerelid, lmode);
/*
* Remember the relation's TOAST relation for later
@@ -1175,7 +1175,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
/*
* Now release the session-level lock on the master table.
*/
- UnlockRelationForSession(&onerelid, lmode);
+ UnlockRelationIdForSession(&onerelid, lmode);
return;
}
@@ -3476,6 +3476,8 @@ vac_open_indexes(Relation relation, LOCKMODE lockmode,
ListCell *indexoidscan;
int i;
+ Assert(lockmode != NoLock);
+
indexoidlist = RelationGetIndexList(relation);
*nindexes = list_length(indexoidlist);
@@ -3489,11 +3491,8 @@ vac_open_indexes(Relation relation, LOCKMODE lockmode,
foreach(indexoidscan, indexoidlist)
{
Oid indexoid = lfirst_oid(indexoidscan);
- Relation ind;
- ind = index_open(indexoid);
- (*Irel)[i++] = ind;
- LockRelation(ind, lockmode);
+ (*Irel)[i++] = index_open(indexoid, lockmode);
}
list_free(indexoidlist);
@@ -3513,9 +3512,7 @@ vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
{
Relation ind = Irel[nindexes];
- if (lockmode != NoLock)
- UnlockRelation(ind, lockmode);
- index_close(ind);
+ index_close(ind, lockmode);
}
pfree(Irel);
}
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index d2727c4a470..2202e7b7e9a 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -31,7 +31,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.75 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.76 2006/07/31 20:09:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -164,7 +164,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
vacrelstats->minxid = RecentXmin;
/* Open all indexes of the relation */
- vac_open_indexes(onerel, ShareUpdateExclusiveLock, &nindexes, &Irel);
+ vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
hasindex = (nindexes > 0);
/* Do the vacuuming */
@@ -621,15 +621,6 @@ lazy_vacuum_index(Relation indrel,
pg_rusage_init(&ru0);
- /*
- * Acquire appropriate type of lock on index: must be exclusive if index
- * AM isn't concurrent-safe.
- */
- if (indrel->rd_am->amconcurrent)
- LockRelation(indrel, RowExclusiveLock);
- else
- LockRelation(indrel, AccessExclusiveLock);
-
ivinfo.index = indrel;
ivinfo.vacuum_full = false;
ivinfo.message_level = elevel;
@@ -640,14 +631,6 @@ lazy_vacuum_index(Relation indrel,
*stats = index_bulk_delete(&ivinfo, *stats,
lazy_tid_reaped, (void *) vacrelstats);
- /*
- * Release lock acquired above.
- */
- if (indrel->rd_am->amconcurrent)
- UnlockRelation(indrel, RowExclusiveLock);
- else
- UnlockRelation(indrel, AccessExclusiveLock);
-
ereport(elevel,
(errmsg("scanned index \"%s\" to remove %d row versions",
RelationGetRelationName(indrel),
@@ -668,15 +651,6 @@ lazy_cleanup_index(Relation indrel,
pg_rusage_init(&ru0);
- /*
- * Acquire appropriate type of lock on index: must be exclusive if index
- * AM isn't concurrent-safe.
- */
- if (indrel->rd_am->amconcurrent)
- LockRelation(indrel, RowExclusiveLock);
- else
- LockRelation(indrel, AccessExclusiveLock);
-
ivinfo.index = indrel;
ivinfo.vacuum_full = false;
ivinfo.message_level = elevel;
@@ -684,14 +658,6 @@ lazy_cleanup_index(Relation indrel,
stats = index_vacuum_cleanup(&ivinfo, stats);
- /*
- * Release lock acquired above.
- */
- if (indrel->rd_am->amconcurrent)
- UnlockRelation(indrel, RowExclusiveLock);
- else
- UnlockRelation(indrel, AccessExclusiveLock);
-
if (!stats)
return;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 11f2ae20f5e..c879de3bbc1 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.137 2006/07/14 14:52:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.138 2006/07/31 20:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -795,12 +795,6 @@ ExecCloseScanRelation(Relation scanrel)
*
* At entry, caller has already opened and locked
* resultRelInfo->ri_RelationDesc.
- *
- * This used to be horribly ugly code, and slow too because it
- * did a sequential scan of pg_index. Now we rely on the relcache
- * to cache a list of the OIDs of the indices associated with any
- * specific relation, and we use the pg_index syscache to get the
- * entries we need from pg_index.
* ----------------------------------------------------------------
*/
void
@@ -840,6 +834,7 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
/*
* For each index, open the index relation and save pg_index info.
+ * We acquire RowExclusiveLock, signifying we will update the index.
*/
i = 0;
foreach(l, indexoidlist)
@@ -848,31 +843,7 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
Relation indexDesc;
IndexInfo *ii;
- /*
- * Open and lock the index relation
- *
- * If the index AM supports concurrent updates, obtain
- * RowExclusiveLock to signify that we are updating the index. This
- * locks out only operations that need exclusive access, such as
- * relocating the index to a new tablespace.
- *
- * If the index AM is not safe for concurrent updates, obtain an
- * exclusive lock on the index to lock out other updaters as well as
- * readers (index_beginscan places AccessShareLock on the index).
- *
- * If there are multiple not-concurrent-safe indexes, all backends
- * must lock the indexes in the same order or we will get deadlocks
- * here. This is guaranteed by RelationGetIndexList(), which promises
- * to return the index list in OID order.
- *
- * The locks will be released in ExecCloseIndices.
- */
- indexDesc = index_open(indexOid);
-
- if (indexDesc->rd_am->amconcurrent)
- LockRelation(indexDesc, RowExclusiveLock);
- else
- LockRelation(indexDesc, AccessExclusiveLock);
+ indexDesc = index_open(indexOid, RowExclusiveLock);
/* extract index key information from the index's pg_index info */
ii = BuildIndexInfo(indexDesc);
@@ -907,12 +878,7 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
continue; /* shouldn't happen? */
/* Drop lock acquired by ExecOpenIndices */
- if (indexDescs[i]->rd_am->amconcurrent)
- UnlockRelation(indexDescs[i], RowExclusiveLock);
- else
- UnlockRelation(indexDescs[i], AccessExclusiveLock);
-
- index_close(indexDescs[i]);
+ index_close(indexDescs[i], RowExclusiveLock);
}
/*
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
index 7555b5a22ca..6a0303cddd1 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.19 2006/05/30 14:01:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.20 2006/07/31 20:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -201,7 +201,7 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node)
* close the index relation
*/
index_endscan(indexScanDesc);
- index_close(indexRelationDesc);
+ index_close(indexRelationDesc, NoLock);
}
/* ----------------------------------------------------------------
@@ -258,8 +258,14 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
/*
* Open the index relation.
+ *
+ * If the parent table is one of the target relations of the query, then
+ * InitPlan already opened and write-locked the index, so we can avoid
+ * taking another lock here. Otherwise we need a normal reader's lock.
*/
- indexstate->biss_RelationDesc = index_open(node->indexid);
+ relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
+ indexstate->biss_RelationDesc = index_open(node->indexid,
+ relistarget ? NoLock : AccessShareLock);
/*
* Initialize index-specific scan state
@@ -303,18 +309,9 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
/*
* Initialize scan descriptor.
- *
- * Note we acquire no locks here; the index machinery does its own locks
- * and unlocks. (We rely on having a lock on the parent table to
- * ensure the index won't go away!) Furthermore, if the parent table
- * is one of the target relations of the query, then InitPlan already
- * opened and write-locked the index, so we can tell the index machinery
- * not to bother getting an extra lock.
*/
- relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
indexstate->biss_ScanDesc =
index_beginscan_multi(indexstate->biss_RelationDesc,
- !relistarget,
estate->es_snapshot,
indexstate->biss_NumScanKeys,
indexstate->biss_ScanKeys);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 02f83667a45..84ee56beb0f 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.115 2006/07/14 14:52:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.116 2006/07/31 20:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -415,7 +415,7 @@ ExecEndIndexScan(IndexScanState *node)
* close the index relation
*/
index_endscan(indexScanDesc);
- index_close(indexRelationDesc);
+ index_close(indexRelationDesc, NoLock);
/*
* close the heap relation.
@@ -517,8 +517,14 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
/*
* Open the index relation.
+ *
+ * If the parent table is one of the target relations of the query, then
+ * InitPlan already opened and write-locked the index, so we can avoid
+ * taking another lock here. Otherwise we need a normal reader's lock.
*/
- indexstate->iss_RelationDesc = index_open(node->indexid);
+ relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
+ indexstate->iss_RelationDesc = index_open(node->indexid,
+ relistarget ? NoLock : AccessShareLock);
/*
* Initialize index-specific scan state
@@ -561,18 +567,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
/*
* Initialize scan descriptor.
- *
- * Note we acquire no locks here; the index machinery does its own locks
- * and unlocks. (We rely on having a lock on the parent table to
- * ensure the index won't go away!) Furthermore, if the parent table
- * is one of the target relations of the query, then InitPlan already
- * opened and write-locked the index, so we can tell the index machinery
- * not to bother getting an extra lock.
*/
- relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
indexstate->iss_ScanDesc = index_beginscan(currentRelation,
indexstate->iss_RelationDesc,
- !relistarget,
estate->es_snapshot,
indexstate->iss_NumScanKeys,
indexstate->iss_ScanKeys);
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index ff453336a16..bafe1b66731 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.121 2006/07/14 14:52:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.122 2006/07/31 20:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -64,7 +64,7 @@ static List *get_relation_constraints(Oid relationObjectId, RelOptInfo *rel);
* widths here, and we may as well cache the results for costsize.c.
*/
void
-get_relation_info(Oid relationObjectId, RelOptInfo *rel)
+get_relation_info(PlannerInfo *root, Oid relationObjectId, RelOptInfo *rel)
{
Index varno = rel->relid;
Relation relation;
@@ -105,9 +105,23 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
{
List *indexoidlist;
ListCell *l;
+ LOCKMODE lmode;
indexoidlist = RelationGetIndexList(relation);
+ /*
+ * For each index, we get the same type of lock that the executor will
+ * need, and do not release it. This saves a couple of trips to the
+ * shared lock manager while not creating any real loss of
+ * concurrency, because no schema changes could be happening on the
+ * index while we hold lock on the parent rel, and neither lock type
+ * blocks any other kind of index operation.
+ */
+ if (rel->relid == root->parse->resultRelation)
+ lmode = RowExclusiveLock;
+ else
+ lmode = AccessShareLock;
+
foreach(l, indexoidlist)
{
Oid indexoid = lfirst_oid(l);
@@ -120,13 +134,8 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
/*
* Extract info from the relation descriptor for the index.
- *
- * Note that we take no lock on the index; we assume our lock on
- * the parent table will protect the index's schema information.
- * When and if the executor actually uses the index, it will take
- * a lock as needed to protect the access to the index contents.
*/
- indexRelation = index_open(indexoid);
+ indexRelation = index_open(indexoid, lmode);
index = indexRelation->rd_index;
info = makeNode(IndexOptInfo);
@@ -203,7 +212,7 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
info->tuples = rel->tuples;
}
- index_close(indexRelation);
+ index_close(indexRelation, NoLock);
indexinfos = lcons(info, indexinfos);
}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index d20a8154612..8d06254a9f4 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.79 2006/07/14 14:52:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.80 2006/07/31 20:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -92,7 +92,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
{
case RTE_RELATION:
/* Table --- retrieve statistics from the system catalogs */
- get_relation_info(rte->relid, rel);
+ get_relation_info(root, rte->relid, rel);
break;
case RTE_SUBQUERY:
case RTE_FUNCTION:
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 90d47b09dcc..25a19b2b24b 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.25 2006/07/14 14:52:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.26 2006/07/31 20:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,7 +47,6 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
-#include "utils/relcache.h"
#include "utils/syscache.h"
@@ -764,7 +763,6 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
List **vacuum_tables,
List **toast_table_ids)
{
- Relation rel;
float4 reltuples; /* pg_class.reltuples */
/* constants from pg_autovacuum or GUC variables */
@@ -799,12 +797,7 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
if (!PointerIsValid(tabentry))
return;
- rel = RelationIdGetRelation(relid);
- /* The table was recently dropped? */
- if (!PointerIsValid(rel))
- return;
-
- reltuples = rel->rd_rel->reltuples;
+ reltuples = classForm->reltuples;
vactuples = tabentry->n_dead_tuples;
anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples -
tabentry->last_anl_tuples;
@@ -861,7 +854,7 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
*/
elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
- RelationGetRelationName(rel),
+ NameStr(classForm->relname),
vactuples, vacthresh, anltuples, anlthresh);
/* Determine if this table needs vacuum or analyze. */
@@ -880,7 +873,7 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
elog(DEBUG2, "autovac: will%s%s %s",
(dovacuum ? " VACUUM" : ""),
(doanalyze ? " ANALYZE" : ""),
- RelationGetRelationName(rel));
+ NameStr(classForm->relname));
/*
* we must record tables that have a toast table, even if we currently
@@ -907,8 +900,6 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
if (dovacuum)
*toast_table_ids = lappend_oid(*toast_table_ids, relid);
}
-
- RelationClose(rel);
}
/*
@@ -966,10 +957,10 @@ autovacuum_do_vac_analyze(List *relids, bool dovacuum, bool doanalyze,
* done with the current one, and exiting right after the last one, so we don't
* bother to report "" or some such.
*/
-#define MAX_AUTOVAC_ACTIV_LEN (NAMEDATALEN * 2 + 32)
static void
autovac_report_activity(VacuumStmt *vacstmt, List *relids)
{
+#define MAX_AUTOVAC_ACTIV_LEN (NAMEDATALEN * 2 + 32)
char activity[MAX_AUTOVAC_ACTIV_LEN];
/*
@@ -982,33 +973,32 @@ autovac_report_activity(VacuumStmt *vacstmt, List *relids)
/* Report the command and possible options */
if (vacstmt->vacuum)
snprintf(activity, MAX_AUTOVAC_ACTIV_LEN,
- "VACUUM%s%s%s",
- vacstmt->full ? " FULL" : "",
- vacstmt->freeze ? " FREEZE" : "",
- vacstmt->analyze ? " ANALYZE" : "");
+ "VACUUM%s%s%s",
+ vacstmt->full ? " FULL" : "",
+ vacstmt->freeze ? " FREEZE" : "",
+ vacstmt->analyze ? " ANALYZE" : "");
else if (vacstmt->analyze)
snprintf(activity, MAX_AUTOVAC_ACTIV_LEN,
- "ANALYZE");
+ "ANALYZE");
/* Report the qualified name of the first relation, if any */
- if (list_length(relids) > 0)
+ if (relids)
{
Oid relid = linitial_oid(relids);
- Relation rel;
+ char *relname = get_rel_name(relid);
+ char *nspname = get_namespace_name(get_rel_namespace(relid));
- rel = RelationIdGetRelation(relid);
- if (rel == NULL)
- elog(WARNING, "cache lookup failed for relation %u", relid);
- else
+ /*
+ * Paranoia is appropriate here in case relation was recently
+ * dropped --- the lsyscache routines we just invoked will return
+ * NULL rather than failing.
+ */
+ if (relname && nspname)
{
- char *nspname = get_namespace_name(RelationGetNamespace(rel));
int len = strlen(activity);
snprintf(activity + len, MAX_AUTOVAC_ACTIV_LEN - len,
- " %s.%s", nspname, RelationGetRelationName(rel));
-
- pfree(nspname);
- RelationClose(rel);
+ " %s.%s", nspname, relname);
}
}
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index fd6ae5abc32..582eabdb2ad 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -17,7 +17,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.118 2006/07/14 14:52:23 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.119 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -69,7 +69,7 @@ open_lo_relation(void)
if (lo_heap_r == NULL)
lo_heap_r = heap_open(LargeObjectRelationId, RowExclusiveLock);
if (lo_index_r == NULL)
- lo_index_r = index_open(LargeObjectLOidPNIndexId);
+ lo_index_r = index_open(LargeObjectLOidPNIndexId, RowExclusiveLock);
}
PG_CATCH();
{
@@ -103,7 +103,7 @@ close_lo_relation(bool isCommit)
CurrentResourceOwner = TopTransactionResourceOwner;
if (lo_index_r)
- index_close(lo_index_r);
+ index_close(lo_index_r, NoLock);
if (lo_heap_r)
heap_close(lo_heap_r, NoLock);
}
@@ -314,7 +314,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(obj_desc->id));
- sd = index_beginscan(lo_heap_r, lo_index_r, true,
+ sd = index_beginscan(lo_heap_r, lo_index_r,
obj_desc->snapshot, 1, skey);
/*
@@ -425,7 +425,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
BTGreaterEqualStrategyNumber, F_INT4GE,
Int32GetDatum(pageno));
- sd = index_beginscan(lo_heap_r, lo_index_r, true,
+ sd = index_beginscan(lo_heap_r, lo_index_r,
obj_desc->snapshot, 2, skey);
while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
@@ -541,7 +541,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
BTGreaterEqualStrategyNumber, F_INT4GE,
Int32GetDatum(pageno));
- sd = index_beginscan(lo_heap_r, lo_index_r, false /* got lock */,
+ sd = index_beginscan(lo_heap_r, lo_index_r,
obj_desc->snapshot, 2, skey);
oldtuple = NULL;
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 8e99d4be48f..ad7ee3e6013 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.85 2006/07/14 16:59:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.86 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,10 +18,13 @@
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/xact.h"
+#include "catalog/catalog.h"
+#include "catalog/namespace.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "storage/procarray.h"
#include "utils/inval.h"
+#include "utils/lsyscache.h"
/*
@@ -44,8 +47,106 @@ RelationInitLockInfo(Relation relation)
relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
}
+/*
+ * SetLocktagRelationOid
+ * Set up a locktag for a relation, given only relation OID
+ */
+static inline void
+SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
+{
+ Oid dbid;
+
+ if (IsSharedRelation(relid))
+ dbid = InvalidOid;
+ else
+ dbid = MyDatabaseId;
+
+ SET_LOCKTAG_RELATION(*tag, dbid, relid);
+}
+
+/*
+ * LockRelationOid
+ *
+ * Lock a relation given only its OID. This should generally be used
+ * before attempting to open the relation's relcache entry.
+ */
+void
+LockRelationOid(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ res = LockAcquire(&tag, lockmode, false, false);
+
+ /*
+ * Now that we have the lock, check for invalidation messages, so that
+ * we will update or flush any stale relcache entry before we try to use
+ * it. We can skip this in the not-uncommon case that we already had
+ * the same type of lock being requested, since then no one else could
+ * have modified the relcache entry in an undesirable way. (In the
+ * case where our own xact modifies the rel, the relcache update happens
+ * via CommandCounterIncrement, not here.)
+ */
+ if (res != LOCKACQUIRE_ALREADY_HELD)
+ AcceptInvalidationMessages();
+}
+
+/*
+ * ConditionalLockRelationOid
+ *
+ * As above, but only lock if we can get the lock without blocking.
+ * Returns TRUE iff the lock was acquired.
+ *
+ * NOTE: we do not currently need conditional versions of all the
+ * LockXXX routines in this file, but they could easily be added if needed.
+ */
+bool
+ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ res = LockAcquire(&tag, lockmode, false, true);
+
+ if (res == LOCKACQUIRE_NOT_AVAIL)
+ return false;
+
+ /*
+ * Now that we have the lock, check for invalidation messages; see
+ * notes in LockRelationOid.
+ */
+ if (res != LOCKACQUIRE_ALREADY_HELD)
+ AcceptInvalidationMessages();
+
+ return true;
+}
+
+/*
+ * UnlockRelationId
+ *
+ * Note: we don't supply UnlockRelationOid since it's normally easy for
+ * callers to provide the LockRelId info from a relcache entry.
+ */
+void
+UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
+
+ LockRelease(&tag, lockmode, false);
+}
+
/*
* LockRelation
+ *
+ * This is a convenience routine for acquiring an additional lock on an
+ * already-open relation. Never try to do "relation_open(foo, NoLock)"
+ * and then lock with this.
*/
void
LockRelation(Relation relation, LOCKMODE lockmode)
@@ -57,31 +158,22 @@ LockRelation(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
+ res = LockAcquire(&tag, lockmode, false, false);
/*
- * Check to see if the relcache entry has been invalidated while we were
- * waiting to lock it. If so, rebuild it, or ereport() trying. Increment
- * the refcount to ensure that RelationFlushRelation will rebuild it and
- * not just delete it. We can skip this if the lock was already held,
- * however.
+ * Now that we have the lock, check for invalidation messages; see
+ * notes in LockRelationOid.
*/
if (res != LOCKACQUIRE_ALREADY_HELD)
- {
- RelationIncrementReferenceCount(relation);
AcceptInvalidationMessages();
- RelationDecrementReferenceCount(relation);
- }
}
/*
* ConditionalLockRelation
*
- * As above, but only lock if we can get the lock without blocking.
- * Returns TRUE iff the lock was acquired.
- *
- * NOTE: we do not currently need conditional versions of all the
- * LockXXX routines in this file, but they could easily be added if needed.
+ * This is a convenience routine for acquiring an additional lock on an
+ * already-open relation. Never try to do "relation_open(foo, NoLock)"
+ * and then lock with this.
*/
bool
ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
@@ -93,30 +185,26 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, true);
+ res = LockAcquire(&tag, lockmode, false, true);
if (res == LOCKACQUIRE_NOT_AVAIL)
return false;
/*
- * Check to see if the relcache entry has been invalidated while we were
- * waiting to lock it. If so, rebuild it, or ereport() trying. Increment
- * the refcount to ensure that RelationFlushRelation will rebuild it and
- * not just delete it. We can skip this if the lock was already held,
- * however.
+ * Now that we have the lock, check for invalidation messages; see
+ * notes in LockRelationOid.
*/
if (res != LOCKACQUIRE_ALREADY_HELD)
- {
- RelationIncrementReferenceCount(relation);
AcceptInvalidationMessages();
- RelationDecrementReferenceCount(relation);
- }
return true;
}
/*
* UnlockRelation
+ *
+ * This is a convenience routine for unlocking a relation without also
+ * closing it.
*/
void
UnlockRelation(Relation relation, LOCKMODE lockmode)
@@ -131,11 +219,11 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
}
/*
- * LockRelationForSession
+ * LockRelationIdForSession
*
* This routine grabs a session-level lock on the target relation. The
* session lock persists across transaction boundaries. It will be removed
- * when UnlockRelationForSession() is called, or if an ereport(ERROR) occurs,
+ * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
* or if the backend exits.
*
* Note that one should also grab a transaction-level lock on the rel
@@ -143,20 +231,20 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
* relcache entry is up to date.
*/
void
-LockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode)
+LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
- (void) LockAcquire(&tag, istemprel, lockmode, true, false);
+ (void) LockAcquire(&tag, lockmode, true, false);
}
/*
- * UnlockRelationForSession
+ * UnlockRelationIdForSession
*/
void
-UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
+UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
{
LOCKTAG tag;
@@ -184,7 +272,7 @@ LockRelationForExtension(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
+ (void) LockAcquire(&tag, lockmode, false, false);
}
/*
@@ -218,7 +306,7 @@ LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.relId,
blkno);
- (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
+ (void) LockAcquire(&tag, lockmode, false, false);
}
/*
@@ -237,8 +325,7 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.relId,
blkno);
- return (LockAcquire(&tag, relation->rd_istemp,
- lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
+ return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
}
/*
@@ -275,7 +362,7 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
+ (void) LockAcquire(&tag, lockmode, false, false);
}
/*
@@ -295,8 +382,7 @@ ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- return (LockAcquire(&tag, relation->rd_istemp,
- lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
+ return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
}
/*
@@ -330,7 +416,7 @@ XactLockTableInsert(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid);
- (void) LockAcquire(&tag, false, ExclusiveLock, false, false);
+ (void) LockAcquire(&tag, ExclusiveLock, false, false);
}
/*
@@ -375,7 +461,7 @@ XactLockTableWait(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid);
- (void) LockAcquire(&tag, false, ShareLock, false, false);
+ (void) LockAcquire(&tag, ShareLock, false, false);
LockRelease(&tag, ShareLock, false);
@@ -403,8 +489,7 @@ ConditionalXactLockTableWait(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid);
- if (LockAcquire(&tag, false,
- ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
+ if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
return false;
LockRelease(&tag, ShareLock, false);
@@ -423,9 +508,7 @@ ConditionalXactLockTableWait(TransactionId xid)
* Obtain a lock on a general object of the current database. Don't use
* this for shared objects (such as tablespaces). It's unwise to apply it
* to relations, also, since a lock taken this way will NOT conflict with
- * LockRelation, and also may be wrongly marked if the relation is temp.
- * (If we ever invent temp objects that aren't tables, we'll want to extend
- * the API of this routine to include an isTempObject flag.)
+ * locks taken via LockRelation and friends.
*/
void
LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
@@ -439,7 +522,7 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
objid,
objsubid);
- (void) LockAcquire(&tag, false, lockmode, false, false);
+ (void) LockAcquire(&tag, lockmode, false, false);
}
/*
@@ -477,7 +560,7 @@ LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
objid,
objsubid);
- (void) LockAcquire(&tag, false, lockmode, false, false);
+ (void) LockAcquire(&tag, lockmode, false, false);
/* Make sure syscaches are up-to-date with any changes we waited for */
AcceptInvalidationMessages();
@@ -500,3 +583,39 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
LockRelease(&tag, lockmode, false);
}
+
+
+/*
+ * LockTagIsTemp
+ * Determine whether a locktag is for a lock on a temporary object
+ *
+ * We need this because 2PC cannot deal with temp objects
+ */
+bool
+LockTagIsTemp(const LOCKTAG *tag)
+{
+ switch (tag->locktag_type)
+ {
+ case LOCKTAG_RELATION:
+ case LOCKTAG_RELATION_EXTEND:
+ case LOCKTAG_PAGE:
+ case LOCKTAG_TUPLE:
+ /* check for lock on a temp relation */
+ /* field1 is dboid, field2 is reloid for all of these */
+ if ((Oid) tag->locktag_field1 == InvalidOid)
+ return false; /* shared, so not temp */
+ if (isTempNamespace(get_rel_namespace((Oid) tag->locktag_field2)))
+ return true;
+ break;
+ case LOCKTAG_TRANSACTION:
+ /* there are no temp transactions */
+ break;
+ case LOCKTAG_OBJECT:
+ /* there are currently no non-table temp objects */
+ break;
+ case LOCKTAG_USERLOCK:
+ /* assume these aren't temp */
+ break;
+ }
+ return false; /* default case */
+}
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index a0bc2869c00..10049d593a0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.169 2006/07/24 16:32:45 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.170 2006/07/31 20:09:05 tgl Exp $
*
* NOTES
* A lock table is a shared memory hash table. When
@@ -36,6 +36,7 @@
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "miscadmin.h"
+#include "storage/lmgr.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/resowner.h"
@@ -449,8 +450,6 @@ ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
*
* Inputs:
* locktag: unique identifier for the lockable object
- * isTempObject: is the lockable object a temporary object? (Under 2PC,
- * such locks cannot be persisted)
* lockmode: lock mode to acquire
* sessionLock: if true, acquire lock for session not current transaction
* dontWait: if true, don't wait to acquire lock
@@ -471,7 +470,6 @@ ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
*/
LockAcquireResult
LockAcquire(const LOCKTAG *locktag,
- bool isTempObject,
LOCKMODE lockmode,
bool sessionLock,
bool dontWait)
@@ -528,7 +526,6 @@ LockAcquire(const LOCKTAG *locktag,
{
locallock->lock = NULL;
locallock->proclock = NULL;
- locallock->isTempObject = isTempObject;
locallock->hashcode = LockTagHashCode(&(localtag.lock));
locallock->nLocks = 0;
locallock->numLockOwners = 0;
@@ -540,8 +537,6 @@ LockAcquire(const LOCKTAG *locktag,
}
else
{
- Assert(locallock->isTempObject == isTempObject);
-
/* Make sure there will be room to remember the lock */
if (locallock->numLockOwners >= locallock->maxLockOwners)
{
@@ -1733,7 +1728,7 @@ AtPrepare_Locks(void)
}
/* Can't handle it if the lock is on a temporary object */
- if (locallock->isTempObject)
+ if (LockTagIsTemp(&locallock->tag.lock))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot PREPARE a transaction that has operated on temporary tables")));
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index f78db61968e..20b83e196a3 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.131 2006/07/14 14:52:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.132 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -904,12 +904,7 @@ CatalogCacheInitializeCache(CatCache *cache)
CatalogCacheInitializeCache_DEBUG1;
- /*
- * Open the relation without locking --- we only need the tupdesc, which
- * we assume will never change ...
- */
- relation = heap_open(cache->cc_reloid, NoLock);
- Assert(RelationIsValid(relation));
+ relation = heap_open(cache->cc_reloid, AccessShareLock);
/*
* switch to the cache context so our allocations do not vanish at the end
@@ -936,7 +931,7 @@ CatalogCacheInitializeCache(CatCache *cache)
*/
MemoryContextSwitchTo(oldcxt);
- heap_close(relation, NoLock);
+ heap_close(relation, AccessShareLock);
CACHE3_elog(DEBUG2, "CatalogCacheInitializeCache: %s, %d keys",
cache->cc_relname, cache->cc_nkeys);
@@ -1012,8 +1007,8 @@ InitCatCachePhase2(CatCache *cache)
{
Relation idesc;
- idesc = index_open(cache->cc_indexoid);
- index_close(idesc);
+ idesc = index_open(cache->cc_indexoid, AccessShareLock);
+ index_close(idesc, AccessShareLock);
}
}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 0fe1f29b251..08697d50366 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.246 2006/07/14 14:52:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.247 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,6 @@
* RelationCacheInitialize - initialize relcache (to empty)
* RelationCacheInitializePhase2 - finish initializing relcache
* RelationIdGetRelation - get a reldesc by relation id
- * RelationIdCacheGetRelation - get a cached reldesc by relid
* RelationClose - close an open relation
*
* NOTES
@@ -34,6 +33,7 @@
#include "access/heapam.h"
#include "access/reloptions.h"
#include "access/xact.h"
+#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_amop.h"
@@ -763,6 +763,10 @@ equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
* recycling the given old relation object. The latter case
* supports rebuilding a relcache entry without invalidating
* pointers to it.
+ *
+ * Returns NULL if no pg_class row could be found for the given relid
+ * (suggesting we are trying to access a just-deleted relation).
+ * Any other error is reported via elog.
* --------------------------------
*/
static Relation
@@ -1387,41 +1391,18 @@ formrdesc(const char *relationName, Oid relationReltype,
* ----------------------------------------------------------------
*/
-/*
- * RelationIdCacheGetRelation
- *
- * Lookup an existing reldesc by OID.
- *
- * Only try to get the reldesc by looking in the cache,
- * do not go to the disk if it's not present.
- *
- * NB: relation ref count is incremented if successful.
- * Caller should eventually decrement count. (Usually,
- * that happens by calling RelationClose().)
- */
-Relation
-RelationIdCacheGetRelation(Oid relationId)
-{
- Relation rd;
-
- RelationIdCacheLookup(relationId, rd);
-
- if (RelationIsValid(rd))
- {
- RelationIncrementReferenceCount(rd);
- /* revalidate nailed index if necessary */
- if (!rd->rd_isvalid)
- RelationReloadClassinfo(rd);
- }
-
- return rd;
-}
-
/*
* RelationIdGetRelation
*
* Lookup a reldesc by OID; make one if not already in cache.
*
+ * Returns NULL if no pg_class row could be found for the given relid
+ * (suggesting we are trying to access a just-deleted relation).
+ * Any other error is reported via elog.
+ *
+ * NB: caller should already have at least AccessShareLock on the
+ * relation ID, else there are nasty race conditions.
+ *
* NB: relation ref count is incremented, or set to 1 if new entry.
* Caller should eventually decrement count. (Usually,
* that happens by calling RelationClose().)
@@ -1432,11 +1413,18 @@ RelationIdGetRelation(Oid relationId)
Relation rd;
/*
- * first try and get a reldesc from the cache
+ * first try to find reldesc in the cache
*/
- rd = RelationIdCacheGetRelation(relationId);
+ RelationIdCacheLookup(relationId, rd);
+
if (RelationIsValid(rd))
+ {
+ RelationIncrementReferenceCount(rd);
+ /* revalidate nailed index if necessary */
+ if (!rd->rd_isvalid)
+ RelationReloadClassinfo(rd);
return rd;
+ }
/*
* no reldesc in the cache, so have RelationBuildDesc() build one and add
@@ -2133,6 +2121,16 @@ RelationBuildLocalRelation(const char *relname,
break;
}
+ /*
+ * check that hardwired list of shared rels matches what's in the
+ * bootstrap .bki file. If you get a failure here during initdb,
+ * you probably need to fix IsSharedRelation() to match whatever
+ * you've done to the set of shared relations.
+ */
+ if (shared_relation != IsSharedRelation(relid))
+ elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
+ relname, relid);
+
/*
* switch to the cache context to create the relcache entry.
*/
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 9cd9162c26b..ddad1745279 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.64 2006/07/13 17:47:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.65 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,6 +17,7 @@
#include "access/relscan.h"
#include "access/sdir.h"
#include "nodes/primnodes.h"
+#include "storage/lock.h"
/*
* Struct for statistics returned by ambuild
@@ -84,9 +85,9 @@ typedef SysScanDescData *SysScanDesc;
/*
* generalized index_ interface routines (in indexam.c)
*/
-extern Relation index_open(Oid relationId);
-extern Relation index_openrv(const RangeVar *relation);
-extern void index_close(Relation relation);
+extern Relation index_open(Oid relationId, LOCKMODE lockmode);
+extern void index_close(Relation relation, LOCKMODE lockmode);
+
extern bool index_insert(Relation indexRelation,
Datum *values, bool *isnull,
ItemPointer heap_t_ctid,
@@ -95,11 +96,9 @@ extern bool index_insert(Relation indexRelation,
extern IndexScanDesc index_beginscan(Relation heapRelation,
Relation indexRelation,
- bool need_index_lock,
Snapshot snapshot,
int nkeys, ScanKey key);
extern IndexScanDesc index_beginscan_multi(Relation indexRelation,
- bool need_index_lock,
Snapshot snapshot,
int nkeys, ScanKey key);
extern void index_rescan(IndexScanDesc scan, ScanKey key);
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index cbe7b0c2442..d32ab6d524e 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.48 2006/07/13 18:01:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.49 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -62,7 +62,6 @@ typedef struct IndexScanDescData
int numberOfKeys; /* number of scan keys */
ScanKey keyData; /* array of scan key descriptors */
bool is_multiscan; /* TRUE = using amgetmulti */
- bool have_lock; /* TRUE = holding AccessShareLock for scan */
/* signaling to index AM about killing index tuples */
bool kill_prior_tuple; /* last-returned tuple is dead */
diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h
index 6136a33f24d..512ea9adbfe 100644
--- a/src/include/catalog/catalog.h
+++ b/src/include/catalog/catalog.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.35 2006/03/05 15:58:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.36 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,6 +31,8 @@ extern bool IsToastNamespace(Oid namespaceId);
extern bool IsReservedName(const char *name);
+extern bool IsSharedRelation(Oid relationId);
+
extern Oid GetNewOid(Relation relation);
extern Oid GetNewOidWithIndex(Relation relation, Relation indexrel);
extern Oid GetNewRelFileNode(Oid reltablespace, bool relisshared,
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 052d2a19cfd..23b0ac9ce4f 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.344 2006/07/31 01:16:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.345 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200607301
+#define CATALOG_VERSION_NO 200607311
#endif
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 048e3e97f7a..7b155bf8289 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.45 2006/07/03 22:45:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.46 2006/07/31 20:09:05 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -51,7 +51,6 @@ CATALOG(pg_am,2601)
bool amoptionalkey; /* can query omit key for the first column? */
bool amindexnulls; /* does AM support NULL index entries? */
bool amstorage; /* can storage type differ from column type? */
- bool amconcurrent; /* does AM support concurrent updates? */
bool amclusterable; /* does AM support cluster command? */
regproc aminsert; /* "insert this tuple" function */
regproc ambeginscan; /* "start new scan" function */
@@ -79,7 +78,7 @@ typedef FormData_pg_am *Form_pg_am;
* compiler constants for pg_am
* ----------------
*/
-#define Natts_pg_am 24
+#define Natts_pg_am 23
#define Anum_pg_am_amname 1
#define Anum_pg_am_amstrategies 2
#define Anum_pg_am_amsupport 3
@@ -89,37 +88,36 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_amoptionalkey 7
#define Anum_pg_am_amindexnulls 8
#define Anum_pg_am_amstorage 9
-#define Anum_pg_am_amconcurrent 10
-#define Anum_pg_am_amclusterable 11
-#define Anum_pg_am_aminsert 12
-#define Anum_pg_am_ambeginscan 13
-#define Anum_pg_am_amgettuple 14
-#define Anum_pg_am_amgetmulti 15
-#define Anum_pg_am_amrescan 16
-#define Anum_pg_am_amendscan 17
-#define Anum_pg_am_ammarkpos 18
-#define Anum_pg_am_amrestrpos 19
-#define Anum_pg_am_ambuild 20
-#define Anum_pg_am_ambulkdelete 21
-#define Anum_pg_am_amvacuumcleanup 22
-#define Anum_pg_am_amcostestimate 23
-#define Anum_pg_am_amoptions 24
+#define Anum_pg_am_amclusterable 10
+#define Anum_pg_am_aminsert 11
+#define Anum_pg_am_ambeginscan 12
+#define Anum_pg_am_amgettuple 13
+#define Anum_pg_am_amgetmulti 14
+#define Anum_pg_am_amrescan 15
+#define Anum_pg_am_amendscan 16
+#define Anum_pg_am_ammarkpos 17
+#define Anum_pg_am_amrestrpos 18
+#define Anum_pg_am_ambuild 19
+#define Anum_pg_am_ambulkdelete 20
+#define Anum_pg_am_amvacuumcleanup 21
+#define Anum_pg_am_amcostestimate 22
+#define Anum_pg_am_amoptions 23
/* ----------------
* initial contents of pg_am
* ----------------
*/
-DATA(insert OID = 403 ( btree 5 1 1 t t t t f t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
+DATA(insert OID = 403 ( btree 5 1 1 t t t t f t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
-DATA(insert OID = 405 ( hash 1 1 0 f f f f f t f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
+DATA(insert OID = 405 ( hash 1 1 0 f f f f f f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
DESCR("hash index access method");
#define HASH_AM_OID 405
-DATA(insert OID = 783 ( gist 100 7 0 f t t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
+DATA(insert OID = 783 ( gist 100 7 0 f t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
-DATA(insert OID = 2742 ( gin 100 4 0 f f f f t t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
+DATA(insert OID = 2742 ( gin 100 4 0 f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h
index c0e86cb80e0..322ae97741c 100644
--- a/src/include/optimizer/plancat.h
+++ b/src/include/optimizer/plancat.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.39 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.40 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include "nodes/relation.h"
-extern void get_relation_info(Oid relationObjectId, RelOptInfo *rel);
+extern void get_relation_info(PlannerInfo *root, Oid relationObjectId, RelOptInfo *rel);
extern bool relation_excluded_by_constraints(RelOptInfo *rel,
RangeTblEntry *rte);
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 1eaede10a0c..d0f9ba2b9c6 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.54 2006/03/05 15:58:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.55 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,13 +21,16 @@
extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
+extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
+extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
+
extern void LockRelation(Relation relation, LOCKMODE lockmode);
extern bool ConditionalLockRelation(Relation relation, LOCKMODE lockmode);
extern void UnlockRelation(Relation relation, LOCKMODE lockmode);
-extern void LockRelationForSession(LockRelId *relid, bool istemprel,
- LOCKMODE lockmode);
-extern void UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode);
+extern void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode);
+extern void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode);
/* Lock a relation for extension */
extern void LockRelationForExtension(Relation relation, LOCKMODE lockmode);
@@ -62,4 +65,7 @@ extern void LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
extern void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
+/* Knowledge about which locktags describe temp objects */
+extern bool LockTagIsTemp(const LOCKTAG *tag);
+
#endif /* LMGR_H */
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 7a2651cd28f..208b4a93ccc 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.96 2006/07/23 23:08:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.97 2006/07/31 20:09:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -349,7 +349,6 @@ typedef struct LOCALLOCK
/* data */
LOCK *lock; /* associated LOCK object in shared mem */
PROCLOCK *proclock; /* associated PROCLOCK object in shmem */
- bool isTempObject; /* true if lock is on a temporary object */
uint32 hashcode; /* copy of LOCKTAG's hash value */
int nLocks; /* total number of times lock is held */
int numLockOwners; /* # of relevant ResourceOwners */
@@ -405,7 +404,6 @@ extern void InitLocks(void);
extern LockMethod GetLocksMethodTable(const LOCK *lock);
extern uint32 LockTagHashCode(const LOCKTAG *locktag);
extern LockAcquireResult LockAcquire(const LOCKTAG *locktag,
- bool isTempObject,
LOCKMODE lockmode,
bool sessionLock,
bool dontWait);
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index b30387a7ef4..aa2b1608c19 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.54 2006/05/04 18:51:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.55 2006/07/31 20:09:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,13 +17,9 @@
#include "utils/rel.h"
/*
- * relation lookup routines
+ * Routines to open (lookup) and close a relcache entry
*/
extern Relation RelationIdGetRelation(Oid relationId);
-
-/* finds an existing cache entry, but won't make a new one */
-extern Relation RelationIdCacheGetRelation(Oid relationId);
-
extern void RelationClose(Relation relation);
/*