Tweak indexscan machinery to avoid taking an AccessShareLock on an index
authorTom Lane
Sat, 3 Dec 2005 05:51:03 +0000 (05:51 +0000)
committerTom Lane
Sat, 3 Dec 2005 05:51:03 +0000 (05:51 +0000)
if we already have a stronger lock due to the index's table being the
update target table of the query.  Same optimization I applied earlier
at the table level.  There doesn't seem to be much interest in the more
radical idea of not locking indexes at all, so do what we can ...

12 files changed:
src/backend/access/heap/tuptoaster.c
src/backend/access/index/genam.c
src/backend/access/index/indexam.c
src/backend/catalog/catalog.c
src/backend/commands/cluster.c
src/backend/executor/execUtils.c
src/backend/executor/nodeBitmapIndexscan.c
src/backend/executor/nodeIndexscan.c
src/backend/storage/large_object/inv_api.c
src/include/access/genam.h
src/include/access/relscan.h
src/include/executor/executor.h

index 1b762597cbd27e74a1f8a51f5ace668d9eb2f41d..4a1ed4e7edbdd65664e35f440bc0bde0bc6b490c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.56 2005/11/22 18:17:06 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.57 2005/12/03 05:50:59 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1142,8 +1142,8 @@ toast_delete_datum(Relation rel, Datum value)
    /*
     * Find the chunks by index
     */
-   toastscan = index_beginscan(toastrel, toastidx, SnapshotToast,
-                               1, &toastkey);
+   toastscan = index_beginscan(toastrel, toastidx, true,
+                               SnapshotToast, 1, &toastkey);
    while ((toasttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
    {
        /*
@@ -1219,8 +1219,8 @@ toast_fetch_datum(varattrib *attr)
     */
    nextidx = 0;
 
-   toastscan = index_beginscan(toastrel, toastidx, SnapshotToast,
-                               1, &toastkey);
+   toastscan = index_beginscan(toastrel, toastidx, true,
+                               SnapshotToast, 1, &toastkey);
    while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
    {
        /*
@@ -1394,8 +1394,8 @@ 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, SnapshotToast,
-                               nscankeys, toastkey);
+   toastscan = index_beginscan(toastrel, toastidx, true,
+                               SnapshotToast, nscankeys, toastkey);
    while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
    {
        /*
index d32a9f9db9edd0a407f3de81855099a7e47a97cb..6ca2fe594bff453b7c972743f24d3834a1d5f74a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.51 2005/11/22 18:17:06 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.52 2005/12/03 05:51:00 tgl Exp $
  *
  * NOTES
  *   many of the old access method routines have been turned into
@@ -86,7 +86,8 @@ RelationGetIndexScan(Relation indexRelation,
    else
        scan->keyData = NULL;
 
-   scan->is_multiscan = false; /* caller may change this */
+   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 */
    scan->keys_are_unique = false;      /* may be set by index AM */
@@ -211,8 +212,8 @@ systable_beginscan(Relation heapRelation,
            key[i].sk_attno = i + 1;
        }
 
-       sysscan->iscan = index_beginscan(heapRelation, irel, snapshot,
-                                        nkeys, key);
+       sysscan->iscan = index_beginscan(heapRelation, irel, true,
+                                        snapshot, nkeys, key);
        sysscan->scan = NULL;
    }
    else
index bd2e3bdd06e2925a6b015a469593b43c0fe31791..c1e61ff2bda32f883247c4e3a1f18ec6033cb23e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.86 2005/10/15 02:49:09 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.87 2005/12/03 05:51:00 tgl Exp $
  *
  * INTERFACE ROUTINES
  *     index_open      - open an index relation by relation OID
@@ -111,6 +111,7 @@ do { \
 } while(0)
 
 static IndexScanDesc index_beginscan_internal(Relation indexRelation,
+                        bool need_index_lock,
                         int nkeys, ScanKey key);
 
 
@@ -229,16 +230,23 @@ index_insert(Relation indexRelation,
  * 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.
  */
 IndexScanDesc
 index_beginscan(Relation heapRelation,
                Relation indexRelation,
+               bool need_index_lock,
                Snapshot snapshot,
                int nkeys, ScanKey key)
 {
    IndexScanDesc scan;
 
-   scan = index_beginscan_internal(indexRelation, nkeys, key);
+   scan = index_beginscan_internal(indexRelation, need_index_lock,
+                                   nkeys, key);
 
    /*
     * Save additional parameters into the scandesc.  Everything else was set
@@ -259,12 +267,14 @@ 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, nkeys, key);
+   scan = index_beginscan_internal(indexRelation, need_index_lock,
+                                   nkeys, key);
 
    /*
     * Save additional parameters into the scandesc.  Everything else was set
@@ -281,6 +291,7 @@ index_beginscan_multi(Relation indexRelation,
  */
 static IndexScanDesc
 index_beginscan_internal(Relation indexRelation,
+                        bool need_index_lock,
                         int nkeys, ScanKey key)
 {
    IndexScanDesc scan;
@@ -291,13 +302,15 @@ index_beginscan_internal(Relation indexRelation,
    RelationIncrementReferenceCount(indexRelation);
 
    /*
-    * Acquire AccessShareLock for the duration of the scan
+    * 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...
     */
-   LockRelation(indexRelation, AccessShareLock);
+   if (need_index_lock)
+       LockRelation(indexRelation, AccessShareLock);
 
    /*
     * LockRelation can clean rd_aminfo structure, so fill procedure after
@@ -315,6 +328,9 @@ 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;
 }
 
@@ -380,7 +396,8 @@ index_endscan(IndexScanDesc scan)
 
    /* Release index lock and refcount acquired by index_beginscan */
 
-   UnlockRelation(scan->indexRelation, AccessShareLock);
+   if (scan->have_lock)
+       UnlockRelation(scan->indexRelation, AccessShareLock);
 
    RelationDecrementReferenceCount(scan->indexRelation);
 
index 69313ea86a2e1816b7d6c24d2a1ccf5352b0ab7b..b63a75495982872fb96ba5bd35ec9fdc07600bfe 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.64 2005/10/15 02:49:12 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.65 2005/12/03 05:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -309,7 +309,8 @@ GetNewOidWithIndex(Relation relation, Relation indexrel)
                    ObjectIdGetDatum(newOid));
 
        /* see notes above about using SnapshotDirty */
-       scan = index_beginscan(relation, indexrel, SnapshotDirty, 1, &key);
+       scan = index_beginscan(relation, indexrel, true,
+                              SnapshotDirty, 1, &key);
 
        collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));
 
index 671c8bf091ebc7e6bb9e1913675e92d6069f210e..e97cc83669f4a242f978a3458b5f73e4408dc601 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.142 2005/11/22 18:17:08 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.143 2005/12/03 05:51:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -643,7 +643,8 @@ 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, SnapshotNow, 0, (ScanKey) NULL);
+   scan = index_beginscan(OldHeap, OldIndex, true,
+                          SnapshotNow, 0, (ScanKey) NULL);
 
    while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)
    {
index c814b971472d689ced80175199e32a523c27ad11..500ff0f4f27ab4d15045eb4f64721d4f425091cd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.130 2005/12/02 20:03:40 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.131 2005/12/03 05:51:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -693,6 +693,28 @@ ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
  * ----------------------------------------------------------------
  */
 
+/* ----------------------------------------------------------------
+ *     ExecRelationIsTargetRelation
+ *
+ *     Detect whether a relation (identified by rangetable index)
+ *     is one of the target relations of the query.
+ * ----------------------------------------------------------------
+ */
+bool
+ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
+{
+   ResultRelInfo *resultRelInfos;
+   int         i;
+
+   resultRelInfos = estate->es_result_relations;
+   for (i = 0; i < estate->es_num_result_relations; i++)
+   {
+       if (resultRelInfos[i].ri_RangeTableIndex == scanrelid)
+           return true;
+   }
+   return false;
+}
+
 /* ----------------------------------------------------------------
  *     ExecOpenScanRelation
  *
index 4217de395228bcb0baa9f0d9e6682fe0805075c1..114de29ba8e0864d286a83e8839a57b900d74e6d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.13 2005/12/02 20:03:40 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.14 2005/12/03 05:51:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -214,6 +214,7 @@ BitmapIndexScanState *
 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
 {
    BitmapIndexScanState *indexstate;
+   bool        relistarget;
 
    /*
     * create state structure
@@ -294,13 +295,19 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
    indexstate->ss.ss_currentScanDesc = NULL;
 
    /*
-    * open the index relation and initialize relation and scan descriptors.
+    * Open the index relation and initialize relation and scan descriptors.
     * Note we acquire no locks here; the index machinery does its own locks
-    * and unlocks.
+    * 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.
     */
    indexstate->biss_RelationDesc = index_open(node->indexid);
+   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 4beecfbd57f8dc8a00ffcc24c46864694afe38a2..94495b4bc711678383403430ba797bfe0b1aab1e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.108 2005/12/02 20:03:40 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.109 2005/12/03 05:51:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -461,6 +461,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 {
    IndexScanState *indexstate;
    Relation    currentRelation;
+   bool        relistarget;
 
    /*
     * create state structure
@@ -557,14 +558,19 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
    ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
 
    /*
-    * open the index relation and initialize relation and scan descriptors.
+    * Open the index relation and initialize relation and scan descriptors.
     * 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!)
+    * 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.
     */
    indexstate->iss_RelationDesc = index_open(node->indexid);
+   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 74409f3cd0aed2858a0e2c8d68942955dc3d01b6..f6d4cf804574fa92ded3d8ac0a0380775a750117 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.113 2005/10/15 02:49:26 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.114 2005/12/03 05:51:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -299,7 +299,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(obj_desc->id));
 
-   sd = index_beginscan(lo_heap_r, lo_index_r,
+   sd = index_beginscan(lo_heap_r, lo_index_r, true,
                         obj_desc->snapshot, 1, skey);
 
    /*
@@ -410,7 +410,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
                BTGreaterEqualStrategyNumber, F_INT4GE,
                Int32GetDatum(pageno));
 
-   sd = index_beginscan(lo_heap_r, lo_index_r,
+   sd = index_beginscan(lo_heap_r, lo_index_r, true,
                         obj_desc->snapshot, 2, skey);
 
    while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
@@ -526,7 +526,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
                BTGreaterEqualStrategyNumber, F_INT4GE,
                Int32GetDatum(pageno));
 
-   sd = index_beginscan(lo_heap_r, lo_index_r,
+   sd = index_beginscan(lo_heap_r, lo_index_r, false /* got lock */,
                         obj_desc->snapshot, 2, skey);
 
    oldtuple = NULL;
index acae7277a012eec37c4e551d036c15e222475509..7dc33d3138cc766f86fb56f7e0e802df1f4b3f4a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.53 2005/10/15 02:49:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.54 2005/12/03 05:51:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -79,9 +79,11 @@ 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 c0b7c92cd53dd7ff1ab115091c16fac21a4e4225..dd6336ca269e09d5b6c7e4986a66b608b54d4120 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.42 2005/11/26 03:03:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.43 2005/12/03 05:51:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,6 +61,7 @@ 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 f1d4e37c419ec4212894c4bb493e467edbfcfb27..facb10a2e25929420b9af75cf775455665fbf3b7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.122 2005/12/02 20:03:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.123 2005/12/03 05:51:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -230,6 +230,8 @@ extern void ExecAssignScanType(ScanState *scanstate,
                   TupleDesc tupDesc, bool shouldFree);
 extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
 
+extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
+
 extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid);
 extern void ExecCloseScanRelation(Relation scanrel);