Change the relation_open protocol so that we obtain lock on a relation

(table or index) before trying to open its relcache entry.  This fixes
race conditions in which someone else commits a change to the relation's
catalog entries while we are in process of doing relcache load.  Problems
of that ilk have been reported sporadically for years, but it was not
really practical to fix until recently --- for instance, the recent
addition of WAL-log support for in-place updates helped.

Along the way, remove pg_am.amconcurrent: all AMs are now expected to support
concurrent update.
This commit is contained in:
Tom Lane 2006-07-31 20:09:10 +00:00
parent 4cd72b53b9
commit 09d3670df3
40 changed files with 635 additions and 648 deletions

View File

@ -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

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.128 2006/07/27 08:30:41 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.129 2006/07/31 20:08:55 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
@ -401,13 +401,6 @@
<entry>Can index storage data type differ from column data type?</entry>
</row>
<row>
<entry><structfield>amconcurrent</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>Does the access method support concurrent updates?</entry>
</row>
<row>
<entry><structfield>amclusterable</structfield></entry>
<entry><type>bool</type></entry>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.15 2006/07/03 22:45:36 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.16 2006/07/31 20:08:59 tgl Exp $ -->
<chapter id="indexam">
<title>Index Access Method Interface Definition</title>
@ -94,8 +94,7 @@
<para>
Some of the flag columns of <structname>pg_am</structname> have nonobvious
implications. The requirements of <structfield>amcanunique</structfield>
are discussed in <xref linkend="index-unique-checks">, and those of
<structfield>amconcurrent</structfield> in <xref linkend="index-locking">.
are discussed in <xref linkend="index-unique-checks">.
The <structfield>amcanmulticol</structfield> flag asserts that the
access method supports multicolumn indexes, while
<structfield>amoptionalkey</structfield> 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
<structname>pg_am</>.<structfield>amconcurrent</>, it is sufficient to
handle these cases for insertions or deletions performed by the same
backend that's doing the scan. But when <structfield>amconcurrent</> is
true, insertions or deletions from other backends must be handled as well.)
deleted.
</para>
<para>
@ -506,31 +501,16 @@ amrestrpos (IndexScanDesc scan);
<title>Index Locking Considerations</title>
<para>
An index access method can choose whether it supports concurrent updates
of the index by multiple processes. If the method's
<structname>pg_am</>.<structfield>amconcurrent</> flag is true, then
the core <productname>PostgreSQL</productname> system obtains
Index access methods must handle concurrent updates
of the index by multiple processes.
The core <productname>PostgreSQL</productname> system obtains
<literal>AccessShareLock</> on the index during an index scan, and
<literal>RowExclusiveLock</> when updating the index. Since these lock
<literal>RowExclusiveLock</> when updating the index (including plain
<command>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
<literal>REINDEX</>. When <structfield>amconcurrent</> is false,
<productname>PostgreSQL</productname> still obtains
<literal>AccessShareLock</> during index scans, but it obtains
<literal>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.
</para>
<para>
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 <command>UPDATE</>
that uses the index to find the rows to be updated.)
will be taken only during index creation, destruction,
<command>REINDEX</>, or <command>VACUUM FULL</>.
</para>
<para>
@ -567,7 +547,7 @@ amrestrpos (IndexScanDesc scan);
</listitem>
<listitem>
<para>
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
<function>amgettuple</>, and <function>ambulkdelete</> cannot delete
entries from pages that are pinned by other backends. The need
@ -576,11 +556,10 @@ amrestrpos (IndexScanDesc scan);
</listitem>
</itemizedlist>
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 <command>VACUUM</>, and
then to arrive at the corresponding heap entry after that was removed by
<command>VACUUM</>. (With a nonconcurrent index, this is not possible
because of the conflicting index-level locks that will be taken out.)
<command>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 <function>heap_fetch()</>. But what if a

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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.)

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}
/*

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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:

View File

@ -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 "<IDLE>" 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);
}
}

View File

@ -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;

View File

@ -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 */
}

View File

@ -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")));

View File

@ -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);
}
}

View File

@ -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.
*/

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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);
/*