Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Reset reindex-in-progress state before reverifying an exclusion constraint.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 6 Jun 2011 02:30:04 +0000 (22:30 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 6 Jun 2011 02:31:05 +0000 (22:31 -0400)
This avoids an Assert failure when we try to use ordinary index fetches
while checking for exclusion conflicts.  Per report from Noah Misch.

No need for back-patch because the Assert wasn't there before 9.1.

src/backend/catalog/index.c
src/test/regress/input/constraints.source
src/test/regress/output/constraints.source

index 53b4c3c59bf78cacf8def18ac4d46940a3a29b71..1b39e1683c709ab866de16ccd199ef92ed2db8ec 100644 (file)
@@ -115,6 +115,7 @@ static void validate_index_heapscan(Relation heapRelation,
                        Snapshot snapshot,
                        v_i_state *state);
 static Oid IndexGetRelation(Oid indexId);
+static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid);
 static void SetReindexProcessing(Oid heapOid, Oid indexOid);
 static void ResetReindexProcessing(void);
 static void SetReindexPending(List *indexes);
@@ -1747,8 +1748,8 @@ index_build(Relation heapRelation,
     * created it, or truncated twice in a subsequent transaction, the
     * relfilenode won't change, and nothing needs to be done here.
     */
-   if (heapRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED
-       && !smgrexists(indexRelation->rd_smgr, INIT_FORKNUM))
+   if (heapRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
+       !smgrexists(indexRelation->rd_smgr, INIT_FORKNUM))
    {
        RegProcedure ambuildempty = indexRelation->rd_am->ambuildempty;
 
@@ -1757,19 +1758,6 @@ index_build(Relation heapRelation,
        OidFunctionCall1(ambuildempty, PointerGetDatum(indexRelation));
    }
 
-   /*
-    * If it's for an exclusion constraint, make a second pass over the heap
-    * to verify that the constraint is satisfied.
-    */
-   if (indexInfo->ii_ExclusionOps != NULL)
-       IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
-
-   /* Roll back any GUC changes executed by index functions */
-   AtEOXact_GUC(false, save_nestlevel);
-
-   /* Restore userid and security context */
-   SetUserIdAndSecContext(save_userid, save_sec_context);
-
    /*
     * If we found any potentially broken HOT chains, mark the index as not
     * being usable until the current transaction is below the event horizon.
@@ -1824,8 +1812,23 @@ index_build(Relation heapRelation,
                       InvalidOid,
                       stats->index_tuples);
 
-   /* Make the updated versions visible */
+   /* Make the updated catalog row versions visible */
    CommandCounterIncrement();
+
+   /*
+    * If it's for an exclusion constraint, make a second pass over the heap
+    * to verify that the constraint is satisfied.  We must not do this until
+    * the index is fully valid.  (Broken HOT chains shouldn't matter, though;
+    * see comments for IndexCheckExclusion.)
+    */
+   if (indexInfo->ii_ExclusionOps != NULL)
+       IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
+
+   /* Roll back any GUC changes executed by index functions */
+   AtEOXact_GUC(false, save_nestlevel);
+
+   /* Restore userid and security context */
+   SetUserIdAndSecContext(save_userid, save_sec_context);
 }
 
 
@@ -2269,6 +2272,15 @@ IndexCheckExclusion(Relation heapRelation,
    EState     *estate;
    ExprContext *econtext;
 
+   /*
+    * If we are reindexing the target index, mark it as no longer being
+    * reindexed, to forestall an Assert in index_beginscan when we try to
+    * use the index for probes.  This is OK because the index is now
+    * fully valid.
+    */
+   if (ReindexIsCurrentlyProcessingIndex(RelationGetRelid(indexRelation)))
+       ResetReindexProcessing();
+
    /*
     * Need an EState for evaluation of index expressions and partial-index
     * predicates.  Also a slot to hold the current tuple.
@@ -2989,8 +3001,8 @@ reindex_relation(Oid relid, int flags)
 
            CommandCounterIncrement();
 
-           if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
-               RemoveReindexPending(indexOid);
+           /* Index should no longer be in the pending list */
+           Assert(!ReindexIsProcessingIndex(indexOid));
 
            if (is_pg_class)
                doneIndexes = lappend_oid(doneIndexes, indexOid);
@@ -3030,7 +3042,9 @@ reindex_relation(Oid relid, int flags)
  *     System index reindexing support
  *
  * When we are busy reindexing a system index, this code provides support
- * for preventing catalog lookups from using that index.
+ * for preventing catalog lookups from using that index.  We also make use
+ * of this to catch attempted uses of user indexes during reindexing of
+ * those indexes.
  * ----------------------------------------------------------------
  */
 
@@ -3048,6 +3062,16 @@ ReindexIsProcessingHeap(Oid heapOid)
    return heapOid == currentlyReindexedHeap;
 }
 
+/*
+ * ReindexIsCurrentlyProcessingIndex
+ *     True if index specified by OID is currently being reindexed.
+ */
+static bool
+ReindexIsCurrentlyProcessingIndex(Oid indexOid)
+{
+   return indexOid == currentlyReindexedIndex;
+}
+
 /*
  * ReindexIsProcessingIndex
  *     True if index specified by OID is currently being reindexed,
@@ -3075,6 +3099,8 @@ SetReindexProcessing(Oid heapOid, Oid indexOid)
        elog(ERROR, "cannot reindex while reindexing");
    currentlyReindexedHeap = heapOid;
    currentlyReindexedIndex = indexOid;
+   /* Index is no longer "pending" reindex. */
+   RemoveReindexPending(indexOid);
 }
 
 /*
index 0d278212c02a4801cd0919b4c2a134b448a2ac42..b84d51e9e5216f8e5899f6bb10d87e12a78e4dc1 100644 (file)
@@ -397,6 +397,9 @@ INSERT INTO circles VALUES('<(20,20), 10>', '<(10,10), 5>');
 ALTER TABLE circles ADD EXCLUDE USING gist
   (c1 WITH &&, (c2::circle) WITH &&);
 
+-- try reindexing an existing constraint
+REINDEX INDEX circles_c1_c2_excl;
+
 DROP TABLE circles;
 
 -- Check deferred exclusion constraint
index d164b90af78e5cb818803e1f1bbadb90fe87c05a..e2f2939931580e1796fc3fde7f4cebf25553d02e 100644 (file)
@@ -543,6 +543,8 @@ ALTER TABLE circles ADD EXCLUDE USING gist
 NOTICE:  ALTER TABLE / ADD EXCLUDE will create implicit index "circles_c1_c2_excl1" for table "circles"
 ERROR:  could not create exclusion constraint "circles_c1_c2_excl1"
 DETAIL:  Key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>) conflicts with key (c1, (c2::circle))=(<(0,0),5>, <(0,0),4>).
+-- try reindexing an existing constraint
+REINDEX INDEX circles_c1_c2_excl;
 DROP TABLE circles;
 -- Check deferred exclusion constraint
 CREATE TABLE deferred_excl (