]> granicus.if.org Git - postgresql/commitdiff
Change the relation_open protocol so that we obtain lock on a relation
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 31 Jul 2006 20:09:10 +0000 (20:09 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 31 Jul 2006 20:09:10 +0000 (20:09 +0000)
(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.

40 files changed:
contrib/userlock/user_locks.c
doc/src/sgml/catalogs.sgml
doc/src/sgml/indexam.sgml
src/backend/access/gin/ginvacuum.c
src/backend/access/gist/gistvacuum.c
src/backend/access/heap/heapam.c
src/backend/access/heap/tuptoaster.c
src/backend/access/index/genam.c
src/backend/access/index/indexam.c
src/backend/bootstrap/bootstrap.c
src/backend/catalog/catalog.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/commands/cluster.c
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/commands/typecmds.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/executor/execUtils.c
src/backend/executor/nodeBitmapIndexscan.c
src/backend/executor/nodeIndexscan.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/relnode.c
src/backend/postmaster/autovacuum.c
src/backend/storage/large_object/inv_api.c
src/backend/storage/lmgr/lmgr.c
src/backend/storage/lmgr/lock.c
src/backend/utils/cache/catcache.c
src/backend/utils/cache/relcache.c
src/include/access/genam.h
src/include/access/relscan.h
src/include/catalog/catalog.h
src/include/catalog/catversion.h
src/include/catalog/pg_am.h
src/include/optimizer/plancat.h
src/include/storage/lmgr.h
src/include/storage/lock.h
src/include/utils/relcache.h

index c27dc253d832216605ee00b9f61d39c9b15b8762..394a4fe190696cac0d0c3a507cd8d58af17aa4c7 100644 (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
index dfb6348e1d633b26e7c4706f96b6030730c39df0..80ed7d829bcf200781bff36d46ac34f8e00301e3 100644 (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
  -->
       <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>
index 7febd0c90723ee7ce9b440b66591adaef246dc56..1afa120766e0101bea285eb6e4bb4430c9c76753 100644 (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
index c6551939a204efafb4845e79280fbe832677ac53..2bc80a26433cf0f00028e531ddfb8d7ce9310c0d 100644 (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);
 }
 
index e3bff5147c24e03752499a56fe4438f494142e40..37b5631b281d546b3b643d8bb643370321334962 100644 (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);
 }
 
index 91460410bf9229fb4e48649800693f40837f77c9..f29407e8e5df1f4ab2b9e3e468d8a7ebbba2a0f2 100644 (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);
 
-       /* The relcache does all the real work... */
-       r = RelationIdGetRelation(relationId);
-
-       if (!RelationIsValid(r))
-               elog(ERROR, "could not open relation with OID %u", relationId);
-
+       /* Get the lock before trying to open the relcache entry */
        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))));
+                       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
-                       LockRelation(r, lockmode);
+                       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);
+
        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
+        * 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);
 }
 
 
index 11adf165c45be37eb5d2c5ac10f92170c7bd29d0..43ca366f0a6e5c9434656ea89f28981e48ab1760 100644 (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;
index 399386c856705550fe50584355393d7851bbf48b..347d2b5365a9d77e65760005623bef008e42f48a 100644 (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);
index 900b34263d863b781c3eb77f8fd27e6d4d516168..2663876f49452b7f49cc1574d7e9911e1ddc0f9b 100644 (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,33 +263,18 @@ 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);
+       GET_REL_PROCEDURE(ambeginscan);
 
        /*
-        * LockRelation can clean rd_aminfo structure, so fill procedure after
-        * LockRelation
+        * We hold a reference count to the relcache entry throughout the scan.
         */
-
-       GET_REL_PROCEDURE(ambeginscan);
+       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 */
index 9399b6d052bbb38b0fcd8504c4d75760be0f001c..08189bf07b23622001130cbc620a3ba4ce3a0030 100644 (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);
        }
 }
index a7b50df950d37d28b81b5870b17efb2c3f3a2b52..5d99acafc95c207ac6a243a3d3bb4c4a86ec89d2 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 #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));
index 361f68008772fe6968240985b9af73498ee4ae00..922a0cebf71518d5c9d4cd1aa6926ce76bbbe806 100644 (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.
index 092c9dcda1048fa4aa7df7bd642b0f5821cb1b06..0da209ff21600a9e5b6a31a15c193adf819f5947 100644 (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:
+       pg_class = heap_open(RelationRelationId, RowExclusiveLock);
 
-       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);
 }
 
index e16afa0559d7e67ec8e0b9c5c9a6a9945bea49c2..f0cbaefd60efb9be48b2ce81ffeb641c5650dd29 100644 (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);
 }
index a3b35a640eac97874a39a152c7c529186f6286c8..6154a4ed3da20e9ad253f49f17d187193e55a6f3 100644 (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;
index 53382ff3d470308d9373ef53215a884ece1b3f81..3b408b411a6acd9d1c26743f019262cb6724ea5d 100644 (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,
index 158e783c57558a30ce9aea7d0f296bfe2d5c23de..13e7cab721b86555ba14239fbcc833dcc1b1917f 100644 (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
index 1304e6868131c7ba347a0d72d4054c42ca1c33bd..6dfa6296d5abe66f7bc79d080cf4cf7eeb0b30b4 100644 (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.)
index eb0fce72edb5d70104a63ffb21aafd2f54b2e969..c21be2f4788e4b67b82925b12a8d3f9e0aa19de2 100644 (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);
 }
index d2727c4a4708166e0c2d6ffae8cba3357b1e4a1e..2202e7b7e9ace65a97d831a791557b9ee7c88d0c 100644 (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;
 
index 11f2ae20f5e9bfe4085b355c249ab9ebbdb2b91c..c879de3bbc173f3a8cdcb839836a6aca3b825a5b 100644 (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);
        }
 
        /*
index 7555b5a22ca4e7776fce208acf2edfb6e1954c30..6a0303cddd12b7539466945a5c8c53d510622e4c 100644 (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);
index 02f83667a45b1023f165ed43d1b5d56fd0ac67b2..84ee56beb0ff6a22b1bcf9d7152b64bc41e1f98e 100644 (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);
index ff453336a1614a92a560a0f434783e4cad6247db..bafe1b66731e4bb8805efed25962d4da02d68a98 100644 (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);
                }
index d20a8154612c39cd985b3988316d000b0d0ba87f..8d06254a9f40553adfee6574552f540330491913 100644 (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:
index 90d47b09dcc3557f7f84f92fa4f73697e05873e2..25a19b2b24b8062ea6d81e5f606f6b9639c49f20 100644 (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);
                }
        }
 
index fd6ae5abc327215d1ac246affe16ccccc64c2084..582eabdb2adcaad43314230b5bd84a0391b1eb4e 100644 (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;
index 8e99d4be48f759afc73394bdbbff81d24c0ff572..ad7ee3e6013621aaf528e0e3f7b0adefc801cdb4 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 #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 */
+}
index a0bc2869c00c746b40e226b6768ef8d986cbb336..10049d593a0772f5ab06e60ce7b3a820782a45db 100644 (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")));
index f78db61968e28d53578f53037ebf0a27ed61353b..20b83e196a342dee107ef281d33cc066299e6ddf 100644 (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);
        }
 }
 
index 0fe1f29b2515433e1c84b0a66ba8da1173212d17..08697d503667c6cc5956f0891288da101b7f1399 100644 (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
@@ -1388,22 +1392,29 @@ formrdesc(const char *relationName, Oid relationReltype,
  */
 
 /*
- *             RelationIdCacheGetRelation
+ *             RelationIdGetRelation
  *
- *             Lookup an existing reldesc by OID.
+ *             Lookup a reldesc by OID; make one if not already in cache.
  *
- *             Only try to get the reldesc by looking in the cache,
- *             do not go to the disk if it's not present.
+ *             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: relation ref count is incremented if successful.
+ *             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().)
  */
 Relation
-RelationIdCacheGetRelation(Oid relationId)
+RelationIdGetRelation(Oid relationId)
 {
        Relation        rd;
 
+       /*
+        * first try to find reldesc in the cache
+        */
        RelationIdCacheLookup(relationId, rd);
 
        if (RelationIsValid(rd))
@@ -1412,31 +1423,8 @@ RelationIdCacheGetRelation(Oid relationId)
                /* 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.
- *
- *             NB: relation ref count is incremented, or set to 1 if new entry.
- *             Caller should eventually decrement count.  (Usually,
- *             that happens by calling RelationClose().)
- */
-Relation
-RelationIdGetRelation(Oid relationId)
-{
-       Relation        rd;
-
-       /*
-        * first try and get a reldesc from the cache
-        */
-       rd = RelationIdCacheGetRelation(relationId);
-       if (RelationIsValid(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.
         */
index 9cd9162c26b1a071aec42a96f1f8668d0db19666..ddad1745279f03f04730c5f16751799aee14373a 100644 (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);
index cbe7b0c2442c2227e5ef8f1d7662c8df61dc4af2..d32ab6d524e0836e2af3381ab64b4d32d11890c3 100644 (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 */
index 6136a33f24d2561a664c2c867b606ecac6eda886..512ea9adbfe9ee786c0832c33e1426a914706ed7 100644 (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,
index 052d2a19cfd7c10f9159cc7d532650639172dcc0..23b0ac9ce4fb1320666a9f15ba3d67fef741e541 100644 (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
index 048e3e97f7a7f897418b4e6350af7d9962c8c8b2..7b155bf8289802414e1e920cddc5f5511266b428 100644 (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 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 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 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 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
 
index c0e86cb80e02fb31adfd5313f8aae920887dbd9e..322ae97741cf5fba468d2dd771aa2363fa5457b1 100644 (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);
index 1eaede10a0cfa6cb46980ade2b63b31f81d377ef..d0f9ba2b9c646748a66e6749501405cb611ef7d2 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
index 7a2651cd28f32d5760fecbee63c9e3f42b006464..208b4a93ccc6fac824e6d76f381aa9db83dd4b92 100644 (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);
index b30387a7ef48ae314981a86a5691017715f8d4c0..aa2b1608c19d951875ffd576aa316c8d6fb6bc40 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 #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);
 
 /*