Repair some REINDEX problems per recent discussions. The relcache is
authorTom Lane
Wed, 24 Sep 2003 18:54:02 +0000 (18:54 +0000)
committerTom Lane
Wed, 24 Sep 2003 18:54:02 +0000 (18:54 +0000)
now able to cope with assigning new relfilenode values to nailed-in-cache
indexes, so they can be reindexed using the fully crash-safe method.  This
leaves only shared system indexes as special cases.  Remove the 'index
deactivation' code, since it provides no useful protection in the shared-
index case.  Require reindexing of shared indexes to be done in standalone
mode, but remove other restrictions on REINDEX.  -P (IgnoreSystemIndexes)
now prevents using indexes for lookups, but does not disable index updates.
It is therefore safe to allow from PGOPTIONS.  Upshot: reindexing system catalogs
can be done without a standalone backend for all cases except
shared catalogs.

22 files changed:
doc/src/sgml/ref/postgres-ref.sgml
doc/src/sgml/ref/reindex.sgml
src/backend/access/index/genam.c
src/backend/access/transam/xact.c
src/backend/catalog/index.c
src/backend/catalog/pg_largeobject.c
src/backend/commands/functioncmds.c
src/backend/commands/indexcmds.c
src/backend/commands/vacuum.c
src/backend/executor/execUtils.c
src/backend/executor/nodeIndexscan.c
src/backend/storage/ipc/sinval.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/cache/relcache.c
src/backend/utils/cache/syscache.c
src/backend/utils/init/miscinit.c
src/include/catalog/index.h
src/include/miscadmin.h
src/include/utils/errcodes.h
src/include/utils/rel.h
src/include/utils/relcache.h

index b80c9caafac0b55f49cec418849b4b34c4494a4a..279d8875e0ee58881a7c6887f07fd462a33f404c 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -177,9 +177,9 @@ PostgreSQL documentation
       
       
        
-   Ignore system indexes while scanning/updating system tables. The
-   REINDEX command for system tables/indexes
-   requires this option to be used.
+   Ignore system indexes when reading system tables (but still update
+   the indexes when modifying the tables).  This is useful when
+   recovering from damaged system indexes.
        
       
      
index 29b96e462c3b5c7c69fd86f27da4e3d1e85c7a5a..d945112de79dcae79bf0776b930b9346492d4dd0 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -56,43 +56,6 @@ REINDEX { DATABASE | TABLE | INDEX } name
     
    
   
-
-  
-   If you suspect corruption of an index on a user table, you can
-   simply rebuild that index, or all indexes on the table, using
-   REINDEX INDEX or REINDEX
-   TABLE.  Another approach to dealing with a corrupted
-   user-table index is just to drop and recreate it.  This may in fact
-   be preferable if you would like to maintain some semblance of
-   normal operation on the table meanwhile.  REINDEX
-   acquires exclusive lock on the table, while CREATE
-   INDEX only locks out writes not reads of the table.
-  
-
-  
-   Things are more difficult if you need to recover from corruption of
-   an index on a system table.  In this case it's important for the
-   system to not have used any of the suspect indexes itself.
-   (Indeed, in this sort of scenario you may find that server
-   processes are crashing immediately at start-up, due to reliance on
-   the corrupted indexes.)  To recover safely, the server must be shut
-   down and a stand-alone PostgreSQL server
-   must be started instead with the command-line options
-    and .  (These options allow
-   system table modifications and prevent use of system indexes,
-   respectively.)  Then, REINDEX DATABASE,
-   REINDEX TABLE, or REINDEX INDEX can be
-   issued, depending on how much you want to reconstruct.  If in
-   doubt, use REINDEX DATABASE FORCE to force
-   reconstruction of all system indexes in the database.  Then quit
-   the standalone server session and restart the real server.
-  
-
-  
-   See the  reference page for more
-   information about how to interact with the stand-alone server
-   interface.
-  
  
   
  
@@ -104,8 +67,8 @@ REINDEX { DATABASE | TABLE | INDEX } name
     
      
       Recreate all system indexes of a specified database. Indexes on
-      user tables are not included. This form of REINDEX
-      can only be used in stand-alone mode (see above).
+      user tables are not processed.  Also, indexes on shared system
+      catalogs are skipped except in stand-alone mode (see below).
      
     
    
@@ -114,7 +77,8 @@ REINDEX { DATABASE | TABLE | INDEX } name
     TABLE
     
      
-      Recreate all indexes of a specified table.
+      Recreate all indexes of a specified table.  If the table has a
+      secondary TOAST table, that is reindexed as well.
      
     
    
@@ -142,16 +106,93 @@ REINDEX { DATABASE | TABLE | INDEX } name
     FORCE
     
      
-      Force rebuild of system indexes.  Without this key word,
-      REINDEX skips system indexes that are not marked
-      invalid.  FORCE is irrelevant for REINDEX
-      INDEX or when reindexing user indexes.
+      This is an obsolete option; it is ignored if specified.
      
     
    
   
  
 
+  Notes
+
+  
+   If you suspect corruption of an index on a user table, you can
+   simply rebuild that index, or all indexes on the table, using
+   REINDEX INDEX or REINDEX
+   TABLE.  Another approach to dealing with a corrupted
+   user-table index is just to drop and recreate it.  This may in fact
+   be preferable if you would like to maintain some semblance of
+   normal operation on the table meanwhile.  REINDEX
+   acquires exclusive lock on the table, while CREATE
+   INDEX only locks out writes not reads of the table.
+  
+
+  
+   Things are more difficult if you need to recover from corruption of
+   an index on a system table.  In this case it's important for the
+   system to not have used any of the suspect indexes itself.
+   (Indeed, in this sort of scenario you may find that server
+   processes are crashing immediately at start-up, due to reliance on
+   the corrupted indexes.)  To recover safely, the server must be started
+   with the  option, which prevents it from using
+   indexes for system catalog lookups.
+  
+
+  
+   One way to do this is to shut down the postmaster and start a stand-alone
+   PostgreSQL server
+   with the  option included on its command line.
+   Then, REINDEX DATABASE,
+   REINDEX TABLE, or REINDEX INDEX can be
+   issued, depending on how much you want to reconstruct.  If in
+   doubt, use REINDEX DATABASE to select
+   reconstruction of all system indexes in the database.  Then quit
+   the standalone server session and restart the regular server.
+   See the  reference page for more
+   information about how to interact with the stand-alone server
+   interface.
+  
+
+  
+   Alternatively, a regular server session can be started with
+    included in its command line options.
+   The method for doing this varies across clients, but in all
+   libpq-based clients, it is possible to set
+   the PGOPTIONS environment variable to -P
+   before starting the client.  Note that while this method does not
+   require locking out other clients, it may still be wise to prevent
+   other users from connecting to the damaged database until repairs
+   have been completed.
+  
+
+  
+   If corruption is suspected in the indexes of any of the shared
+   system catalogs (pg_database,
+   pg_group, or
+   pg_shadow), then a standalone server
+   must be used to repair it.  REINDEX will not process
+   shared catalogs in multiuser mode.
+  
+
+  
+   For all indexes except the shared system catalogs, REINDEX
+   is crash-safe and transaction-safe.  REINDEX is not
+   crash-safe for shared indexes, which is why this case is disallowed
+   during normal operation.  If a failure occurs while reindexing one
+   of these catalogs in standalone mode, it is important that the failure
+   be rectified and the REINDEX operation redone
+   before attempting to restart the regular server.
+  
+
+  
+   Prior to PostgreSQL 7.4, REINDEX
+   TABLE did not automatically process TOAST tables, and so those had
+   to be reindexed by separate commands.  This is still possible, but
+   redundant.
+  
+
  
   Examples
 
@@ -172,11 +213,15 @@ REINDEX INDEX my_index;
   
 
   
-   Rebuild all system indexes (this will only work in a stand-alone
-   server session):
+   Rebuild all system indexes in a particular database, without trusting them
+   to be valid already:
 
 
-REINDEX DATABASE my_database FORCE;
+$ export PGOPTIONS="-P"
+$ psql broken_db
+...
+broken_db=> REINDEX DATABASE broken_db;
+broken_db=> \q
 
   
  
index eaa0d172e546ca18b9a5b5593a830d54b2b3e42a..a362cd8cfaf6f55d27d5809b79b53722091099a5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.40 2003/08/04 02:39:57 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.41 2003/09/24 18:54:01 tgl Exp $
  *
  * NOTES
  *   many of the old access method routines have been turned into
@@ -184,21 +184,32 @@ systable_beginscan(Relation heapRelation,
                   int nkeys, ScanKey key)
 {
    SysScanDesc sysscan;
+   Relation    irel;
+
+   if (indexOK && !IsIgnoringSystemIndexes())
+   {
+       /* We assume it's a system index, so index_openr is OK */
+       irel = index_openr(indexRelname);
+
+       if (ReindexIsProcessingIndex(RelationGetRelid(irel)))
+       {
+           /* oops, can't use index that's being rebuilt */
+           index_close(irel);
+           irel = NULL;
+       }
+   }
+   else
+       irel = NULL;
 
    sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
 
    sysscan->heap_rel = heapRelation;
+   sysscan->irel = irel;
 
-   if (indexOK &&
-       heapRelation->rd_rel->relhasindex &&
-       !IsIgnoringSystemIndexes())
+   if (irel)
    {
-       Relation    irel;
        int         i;
 
-       /* We assume it's a system index, so index_openr is OK */
-       sysscan->irel = irel = index_openr(indexRelname);
-
        /*
         * Change attribute numbers to be index column numbers.
         *
@@ -210,13 +221,13 @@ systable_beginscan(Relation heapRelation,
            Assert(key[i].sk_attno == irel->rd_index->indkey[i]);
            key[i].sk_attno = i + 1;
        }
+
        sysscan->iscan = index_beginscan(heapRelation, irel, snapshot,
                                         nkeys, key);
        sysscan->scan = NULL;
    }
    else
    {
-       sysscan->irel = NULL;
        sysscan->scan = heap_beginscan(heapRelation, snapshot, nkeys, key);
        sysscan->iscan = NULL;
    }
index e632ae9e1f4f56195f5f3b8f20fd480eb3b52100..e17a3f3c37269b4051a739982cfb27cb2e633cf8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.152 2003/08/08 21:41:28 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.153 2003/09/24 18:54:01 tgl Exp $
  *
  * NOTES
  *     Transaction aborts can now occur two ways:
@@ -834,8 +834,6 @@ StartTransaction(void)
     */
    s->state = TRANS_START;
 
-   SetReindexProcessing(false);
-
    /*
     * generate a new transaction id
     */
@@ -1085,6 +1083,7 @@ AbortTransaction(void)
    AtEOXact_Namespace(false);
    AtEOXact_CatCache(false);
    AtEOXact_Files();
+   SetReindexProcessing(InvalidOid, InvalidOid);
    pgstat_count_xact_rollback();
 
    /*
index 02eba08af41d78c922f708584b097a478d72b40c..ed560fb8915b724b304fe703ceb2eaacaa0981d8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.216 2003/09/23 01:51:09 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.217 2003/09/24 18:54:01 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -76,27 +76,8 @@ static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
                    Oid *classOids,
                    bool primary);
 static Oid IndexGetRelation(Oid indexId);
-static bool activate_index(Oid indexId, bool activate, bool inplace);
 
 
-static bool reindexing = false;
-
-
-bool
-SetReindexProcessing(bool reindexmode)
-{
-   bool        old = reindexing;
-
-   reindexing = reindexmode;
-   return old;
-}
-
-bool
-IsReindexProcessing(void)
-{
-   return reindexing;
-}
-
 /*
  *     ConstructTupleDescriptor
  *
@@ -498,8 +479,6 @@ index_create(Oid heapRelationId,
    Oid         indexoid;
    int         i;
 
-   SetReindexProcessing(false);
-
    /*
     * Only SELECT ... FOR UPDATE are allowed while doing this
     */
@@ -973,46 +952,6 @@ FormIndexDatum(IndexInfo *indexInfo,
 }
 
 
-/* ---------------------------------------------
- *     Indexes of the relation active ?
- *
- * Caller must hold an adequate lock on the relation to ensure the
- * answer won't be changing.
- * ---------------------------------------------
- */
-bool
-IndexesAreActive(Relation heaprel)
-{
-   bool        isactive;
-   Relation    indexRelation;
-   HeapScanDesc scan;
-   ScanKeyData entry;
-
-   if (heaprel->rd_rel->relkind != RELKIND_RELATION &&
-       heaprel->rd_rel->relkind != RELKIND_TOASTVALUE)
-       ereport(ERROR,
-               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                errmsg("relation \"%s\" isn't an indexable relation",
-                       RelationGetRelationName(heaprel))));
-
-   /* If pg_class.relhasindex is set, indexes are active */
-   isactive = heaprel->rd_rel->relhasindex;
-   if (isactive)
-       return isactive;
-
-   /* Otherwise, look to see if there are any indexes */
-   indexRelation = heap_openr(IndexRelationName, AccessShareLock);
-   ScanKeyEntryInitialize(&entry, 0,
-                          Anum_pg_index_indrelid, F_OIDEQ,
-                          ObjectIdGetDatum(RelationGetRelid(heaprel)));
-   scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
-   if (heap_getnext(scan, ForwardScanDirection) == NULL)
-       isactive = true;        /* no indexes, so report "active" */
-   heap_endscan(scan);
-   heap_close(indexRelation, AccessShareLock);
-   return isactive;
-}
-
 /* ----------------
  *     set relhasindex of relation's pg_class entry
  *
@@ -1038,12 +977,13 @@ setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
    HeapScanDesc pg_class_scan = NULL;
 
    /*
-    * Find the tuple to update in pg_class.
+    * Find the tuple to update in pg_class.  In bootstrap mode we can't
+    * use heap_update, so cheat and overwrite the tuple in-place.  In
+    * normal processing, make a copy to scribble on.
     */
    pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
-   if (!IsIgnoringSystemIndexes() &&
-       (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
+   if (!IsBootstrapProcessingMode())
    {
        tuple = SearchSysCacheCopy(RELOID,
                                   ObjectIdGetDatum(relid),
@@ -1064,15 +1004,13 @@ setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
 
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "could not find tuple for relation %u", relid);
+   classtuple = (Form_pg_class) GETSTRUCT(tuple);
+
+   /* Apply required updates */
 
-   /*
-    * Update fields in the pg_class tuple.
-    */
    if (pg_class_scan)
        LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
 
-   classtuple = (Form_pg_class) GETSTRUCT(tuple);
-
    if (classtuple->relhasindex != hasindex)
    {
        classtuple->relhasindex = hasindex;
@@ -1141,80 +1079,48 @@ setNewRelfilenode(Relation relation)
    Relation    pg_class;
    HeapTuple   tuple;
    Form_pg_class rd_rel;
-   HeapScanDesc pg_class_scan = NULL;
-   bool        in_place_upd;
    RelationData workrel;
 
-   Assert(!IsSystemRelation(relation) || IsToastRelation(relation) ||
+   /* Can't change relfilenode for nailed tables (indexes ok though) */
+   Assert(!relation->rd_isnailed ||
           relation->rd_rel->relkind == RELKIND_INDEX);
+   /* Can't change for shared tables or indexes */
+   Assert(!relation->rd_rel->relisshared);
 
    /* Allocate a new relfilenode */
    newrelfilenode = newoid();
 
    /*
-    * Find the RELATION relation tuple for the given relation.
+    * Find the pg_class tuple for the given relation.  This is not used
+    * during bootstrap, so okay to use heap_update always.
     */
    pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
-   in_place_upd = IsIgnoringSystemIndexes();
-
-   if (!in_place_upd)
-   {
-       tuple = SearchSysCacheCopy(RELOID,
-                           ObjectIdGetDatum(RelationGetRelid(relation)),
-                                  0, 0, 0);
-   }
-   else
-   {
-       ScanKeyData key[1];
-
-       ScanKeyEntryInitialize(&key[0], 0,
-                              ObjectIdAttributeNumber,
-                              F_OIDEQ,
-                          ObjectIdGetDatum(RelationGetRelid(relation)));
-
-       pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
-       tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
-   }
-
+   tuple = SearchSysCacheCopy(RELOID,
+                              ObjectIdGetDatum(RelationGetRelid(relation)),
+                              0, 0, 0);
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "could not find tuple for relation %u",
             RelationGetRelid(relation));
    rd_rel = (Form_pg_class) GETSTRUCT(tuple);
 
-   /* schedule unlinking old relfilenode */
-   smgrunlink(DEFAULT_SMGR, relation);
-
    /* create another storage file. Is it a little ugly ? */
+   /* NOTE: any conflict in relfilenode value will be caught here */
    memcpy((char *) &workrel, relation, sizeof(RelationData));
    workrel.rd_fd = -1;
    workrel.rd_node.relNode = newrelfilenode;
    heap_storage_create(&workrel);
    smgrclose(DEFAULT_SMGR, &workrel);
 
+   /* schedule unlinking old relfilenode */
+   smgrunlink(DEFAULT_SMGR, relation);
+
    /* update the pg_class row */
-   if (in_place_upd)
-   {
-       LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
-       rd_rel->relfilenode = newrelfilenode;
-       LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
-       WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
-       BufferSync();
-       /* Send out shared cache inval if necessary */
-       if (!IsBootstrapProcessingMode())
-           CacheInvalidateHeapTuple(pg_class, tuple);
-   }
-   else
-   {
-       rd_rel->relfilenode = newrelfilenode;
-       simple_heap_update(pg_class, &tuple->t_self, tuple);
-       CatalogUpdateIndexes(pg_class, tuple);
-   }
+   rd_rel->relfilenode = newrelfilenode;
+   simple_heap_update(pg_class, &tuple->t_self, tuple);
+   CatalogUpdateIndexes(pg_class, tuple);
 
-   if (!pg_class_scan)
-       heap_freetuple(tuple);
-   else
-       heap_endscan(pg_class_scan);
+   heap_freetuple(tuple);
 
    heap_close(pg_class, RowExclusiveLock);
 
@@ -1264,11 +1170,21 @@ UpdateStats(Oid relid, double reltuples)
    whichRel = relation_open(relid, ShareLock);
 
    /*
-    * Find the RELATION relation tuple for the given relation.
+    * 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 cheat and
+    * overwrite the tuple in-place.
+    *
+    * We also must cheat 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).  In this
+    * case the stats updates will not be WAL-logged and so could be lost
+    * in a crash.  This seems OK considering VACUUM does the same thing.
     */
    pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
-   in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
+   in_place_upd = IsBootstrapProcessingMode() ||
+       ReindexIsProcessingHeap(RelationGetRelid(pg_class));
 
    if (!in_place_upd)
    {
@@ -1291,6 +1207,7 @@ UpdateStats(Oid relid, double reltuples)
 
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "could not find tuple for relation %u", relid);
+   rd_rel = (Form_pg_class) GETSTRUCT(tuple);
 
    /*
     * Figure values to insert.
@@ -1331,18 +1248,12 @@ UpdateStats(Oid relid, double reltuples)
     * also reduces the window wherein concurrent CREATE INDEX commands
     * may conflict.)
     */
-   rd_rel = (Form_pg_class) GETSTRUCT(tuple);
-
    if (rd_rel->relpages != (int32) relpages ||
        rd_rel->reltuples != (float4) reltuples)
    {
        if (in_place_upd)
        {
-           /*
-            * At bootstrap time, we don't need to worry about concurrency
-            * or visibility of changes, so we cheat.  Also cheat if
-            * REINDEX.
-            */
+           /* Bootstrap or reindex case: overwrite fields in place. */
            LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
            rd_rel->relpages = (int32) relpages;
            rd_rel->reltuples = (float4) reltuples;
@@ -1562,10 +1473,13 @@ IndexBuildHeapScan(Relation heapRelation,
                     * should not see any tuples inserted by open
                     * transactions --- unless it's our own transaction.
                     * (Consider INSERT followed by CREATE INDEX within a
-                    * transaction.)
+                    * transaction.)  An exception occurs when reindexing
+                    * a system catalog, because we often release lock on
+                    * system catalogs before committing.
                     */
                    if (!TransactionIdIsCurrentTransactionId(
-                             HeapTupleHeaderGetXmin(heapTuple->t_data)))
+                             HeapTupleHeaderGetXmin(heapTuple->t_data))
+                       && !IsSystemRelation(heapRelation))
                        elog(ERROR, "concurrent insert in progress");
                    indexIt = true;
                    tupleIsAlive = true;
@@ -1577,10 +1491,13 @@ IndexBuildHeapScan(Relation heapRelation,
                     * should not see any tuples deleted by open
                     * transactions --- unless it's our own transaction.
                     * (Consider DELETE followed by CREATE INDEX within a
-                    * transaction.)
+                    * transaction.)  An exception occurs when reindexing
+                    * a system catalog, because we often release lock on
+                    * system catalogs before committing.
                     */
                    if (!TransactionIdIsCurrentTransactionId(
-                             HeapTupleHeaderGetXmax(heapTuple->t_data)))
+                             HeapTupleHeaderGetXmax(heapTuple->t_data))
+                       && !IsSystemRelation(heapRelation))
                        elog(ERROR, "concurrent delete in progress");
                    indexIt = true;
                    tupleIsAlive = false;
@@ -1690,81 +1607,57 @@ IndexGetRelation(Oid indexId)
    return result;
 }
 
-/* ---------------------------------
- * activate_index -- activate/deactivate the specified index.
- *     Note that currently PostgreSQL doesn't hold the
- *     status per index
- * ---------------------------------
- */
-static bool
-activate_index(Oid indexId, bool activate, bool inplace)
-{
-   if (!activate)              /* Currently does nothing */
-       return true;
-   return reindex_index(indexId, false, inplace);
-}
-
-/* --------------------------------
- * reindex_index - This routine is used to recreate an index
- * --------------------------------
+/*
+ * reindex_index - This routine is used to recreate a single index
  */
-bool
-reindex_index(Oid indexId, bool force, bool inplace)
+void
+reindex_index(Oid indexId)
 {
    Relation    iRel,
                heapRelation;
    IndexInfo  *indexInfo;
    Oid         heapId;
-   bool        old;
+   bool        inplace;
 
    /*
     * Open our index relation and get an exclusive lock on it.
     *
-    * Note: doing this before opening the parent heap relation means there's
-    * a possibility for deadlock failure against another xact that is
-    * doing normal accesses to the heap and index.  However, it's not
-    * real clear why you'd be needing to do REINDEX on a table that's in
-    * active use, so I'd rather have the protection of making sure the
-    * index is locked down.
+    * Note: for REINDEX INDEX, doing this before opening the parent heap
+    * relation means there's a possibility for deadlock failure against
+    * another xact that is doing normal accesses to the heap and index.
+    * However, it's not real clear why you'd be wanting to do REINDEX INDEX
+    * on a table that's in active use, so I'd rather have the protection of
+    * making sure the index is locked down.  In the REINDEX TABLE and
+    * REINDEX DATABASE cases, there is no problem because caller already
+    * holds exclusive lock on the parent table.
     */
    iRel = index_open(indexId);
    LockRelation(iRel, AccessExclusiveLock);
 
-   old = SetReindexProcessing(true);
-
    /* Get OID of index's parent table */
    heapId = iRel->rd_index->indrelid;
 
-   /* Open the parent heap relation */
+   /* Open and lock the parent heap relation */
    heapRelation = heap_open(heapId, AccessExclusiveLock);
 
+   SetReindexProcessing(heapId, indexId);
+
    /*
     * If it's a shared index, we must do inplace processing (because we
-    * have no way to update relfilenode in other databases).  Also, if
-    * it's a nailed-in-cache index, we must do inplace processing because
-    * the relcache can't cope with changing its relfilenode.
+    * have no way to update relfilenode in other databases).  Otherwise
+    * we can do it the normal transaction-safe way.
     *
-    * In either of these cases, we are definitely processing a system index,
-    * so we'd better be ignoring system indexes.
+    * Since inplace processing isn't crash-safe, we only allow it in a
+    * standalone backend.  (In the REINDEX TABLE and REINDEX DATABASE cases,
+    * the caller should have detected this.)
     */
-   if (iRel->rd_rel->relisshared)
-   {
-       if (!IsIgnoringSystemIndexes())
-           ereport(ERROR,
-                   (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                  errmsg("the target relation %u is shared", indexId)));
-       inplace = true;
-   }
-#ifndef ENABLE_REINDEX_NAILED_RELATIONS
-   if (iRel->rd_isnailed)
-   {
-       if (!IsIgnoringSystemIndexes())
-           ereport(ERROR,
-                   (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                  errmsg("the target relation %u is nailed", indexId)));
-       inplace = true;
-   }
-#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
+   inplace = iRel->rd_rel->relisshared;
+
+   if (inplace && IsUnderPostmaster)
+       ereport(ERROR,
+               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                errmsg("shared index \"%s\" can only be reindexed in standalone mode",
+                       RelationGetRelationName(iRel))));
 
    /* Fetch info needed for index_build */
    indexInfo = BuildIndexInfo(iRel);
@@ -1797,160 +1690,94 @@ reindex_index(Oid indexId, bool force, bool inplace)
     * index_build will close both the heap and index relations (but not
     * give up the locks we hold on them).  So we're done.
     */
-
-   SetReindexProcessing(old);
-
-   return true;
+   SetReindexProcessing(InvalidOid, InvalidOid);
 }
 
 /*
- * ----------------------------
- * activate_indexes_of_a_table
- * activate/deactivate indexes of the specified table.
+ * reindex_relation - This routine is used to recreate all indexes
+ * of a relation (and its toast relation too, if any).
  *
- * Caller must already hold exclusive lock on the table.
- * ----------------------------
+ * Returns true if any indexes were rebuilt.
  */
 bool
-activate_indexes_of_a_table(Relation heaprel, bool activate)
+reindex_relation(Oid relid)
 {
-   if (IndexesAreActive(heaprel))
-   {
-       if (!activate)
-           setRelhasindex(RelationGetRelid(heaprel), false, false,
-                          InvalidOid);
-       else
-           return false;
-   }
-   else
-   {
-       if (activate)
-           reindex_relation(RelationGetRelid(heaprel), false);
-       else
-           return false;
-   }
-   return true;
-}
-
-/* --------------------------------
- * reindex_relation - This routine is used to recreate indexes
- * of a relation.
- * --------------------------------
- */
-bool
-reindex_relation(Oid relid, bool force)
-{
-   Relation    indexRelation;
-   ScanKeyData entry;
-   HeapScanDesc scan;
-   HeapTuple   indexTuple;
-   bool        old,
-               reindexed;
-   bool        deactivate_needed,
-               overwrite;
    Relation    rel;
-
-   overwrite = deactivate_needed = false;
+   Oid         toast_relid;
+   bool        is_pg_class;
+   bool        result;
+   List       *indexIds,
+              *doneIndexes,
+              *indexId;
 
    /*
     * Ensure to hold an exclusive lock throughout the transaction. The
-    * lock could be less intensive (in the non-overwrite path) but for
-    * now it's AccessExclusiveLock for simplicity.
+    * lock could perhaps be less intensive (in the non-overwrite case)
+    * but for now it's AccessExclusiveLock for simplicity.
     */
    rel = heap_open(relid, AccessExclusiveLock);
 
+   toast_relid = rel->rd_rel->reltoastrelid;
+
    /*
-    * ignore the indexes of the target system relation while processing
-    * reindex.
+    * Get the list of index OIDs for this relation.  (We trust to the
+    * relcache to get this with a sequential scan if ignoring system
+    * indexes.)
     */
-   if (!IsIgnoringSystemIndexes() &&
-       IsSystemRelation(rel) && !IsToastRelation(rel))
-       deactivate_needed = true;
+   indexIds = RelationGetIndexList(rel);
 
    /*
-    * Shared system indexes must be overwritten because it's impossible
-    * to update pg_class tuples of all databases.
+    * reindex_index will attempt to update the pg_class rows for the
+    * relation and index.  If we are processing pg_class itself, we
+    * want to make sure that the updates do not try to insert index
+    * entries into indexes we have not processed yet.  (When we are
+    * trying to recover from corrupted indexes, that could easily
+    * cause a crash.)  We can accomplish this because CatalogUpdateIndexes
+    * will use the relcache's index list to know which indexes to update.
+    * We just force the index list to be only the stuff we've processed.
+    *
+    * It is okay to not insert entries into the indexes we have not
+    * processed yet because all of this is transaction-safe.  If we fail
+    * partway through, the updated rows are dead and it doesn't matter
+    * whether they have index entries.  Also, a new pg_class index will
+    * be created with an entry for its own pg_class row because we do
+    * setNewRelfilenode() before we do index_build().
     */
-   if (rel->rd_rel->relisshared)
+   is_pg_class = (RelationGetRelid(rel) == RelOid_pg_class);
+   doneIndexes = NIL;
+
+   /* Reindex all the indexes. */
+   foreach(indexId, indexIds)
    {
-       if (IsIgnoringSystemIndexes())
-       {
-           overwrite = true;
-           deactivate_needed = true;
-       }
-       else
-           ereport(ERROR,
-                   (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                    errmsg("the target relation %u is shared", relid)));
-   }
+       Oid     indexOid = lfirsto(indexId);
 
-   old = SetReindexProcessing(true);
+       if (is_pg_class)
+           RelationSetIndexList(rel, doneIndexes);
 
-   if (deactivate_needed)
-   {
-       if (IndexesAreActive(rel))
-       {
-           if (!force)
-           {
-               SetReindexProcessing(old);
-               heap_close(rel, NoLock);
-               return false;
-           }
-           activate_indexes_of_a_table(rel, false);
-           CommandCounterIncrement();
-       }
+       reindex_index(indexOid);
+
+       CommandCounterIncrement();
+
+       if (is_pg_class)
+           doneIndexes = lappendo(doneIndexes, indexOid);
    }
 
+   if (is_pg_class)
+       RelationSetIndexList(rel, indexIds);
+
    /*
-    * Continue to hold the lock.
+    * Close rel, but continue to hold the lock.
     */
    heap_close(rel, NoLock);
 
-   indexRelation = heap_openr(IndexRelationName, AccessShareLock);
-   ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
-                          F_OIDEQ, ObjectIdGetDatum(relid));
-   scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
-   reindexed = false;
-   while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-   {
-       Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
-
-       if (activate_index(index->indexrelid, true, overwrite))
-           reindexed = true;
-       else
-       {
-           reindexed = false;
-           break;
-       }
-   }
-   heap_endscan(scan);
-   heap_close(indexRelation, AccessShareLock);
-   if (reindexed)
-   {
-       /*
-        * Ok,we could use the reindexed indexes of the target system
-        * relation now.
-        */
-       if (deactivate_needed)
-       {
-           if (!overwrite && relid == RelOid_pg_class)
-           {
-               /*
-                * For pg_class, relhasindex should be set to true here in
-                * place.
-                */
-               setRelhasindex(relid, true, false, InvalidOid);
-               CommandCounterIncrement();
+   result = (indexIds != NIL);
 
-               /*
-                * However the following setRelhasindex() is needed to
-                * keep consistency with WAL.
-                */
-           }
-           setRelhasindex(relid, true, false, InvalidOid);
-       }
-   }
-   SetReindexProcessing(old);
+   /*
+    * If the relation has a secondary toast rel, reindex that too while we
+    * still hold the lock on the master table.
+    */
+   if (toast_relid != InvalidOid)
+       result |= reindex_relation(toast_relid);
 
-   return reindexed;
+   return result;
 }
index 3bfe0ca23b97ad2ffa765d9524cce432f263c021..850256716995c5b8ff85b252b38756529d70f4f1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.16 2003/08/04 02:39:58 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.17 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -77,32 +77,29 @@ LargeObjectDrop(Oid loid)
 {
    bool        found = false;
    Relation    pg_largeobject;
-   Relation    pg_lo_idx;
    ScanKeyData skey[1];
-   IndexScanDesc sd;
+   SysScanDesc sd;
    HeapTuple   tuple;
 
-   ScanKeyEntryInitialize(&skey[0],
-                          (bits16) 0x0,
-                          (AttrNumber) 1,
+   ScanKeyEntryInitialize(&skey[0], 0x0,
+                          (AttrNumber) Anum_pg_largeobject_loid,
                           (RegProcedure) F_OIDEQ,
                           ObjectIdGetDatum(loid));
 
-   pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock);
-   pg_lo_idx = index_openr(LargeObjectLOidPNIndex);
+   pg_largeobject = heap_openr(LargeObjectRelationName, RowExclusiveLock);
 
-   sd = index_beginscan(pg_largeobject, pg_lo_idx, SnapshotNow, 1, skey);
+   sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndex, true,
+                           SnapshotNow, 1, skey);
 
-   while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
+   while ((tuple = systable_getnext(sd)) != NULL)
    {
        simple_heap_delete(pg_largeobject, &tuple->t_self);
        found = true;
    }
 
-   index_endscan(sd);
+   systable_endscan(sd);
 
-   index_close(pg_lo_idx);
-   heap_close(pg_largeobject, RowShareLock);
+   heap_close(pg_largeobject, RowExclusiveLock);
 
    if (!found)
        ereport(ERROR,
@@ -115,32 +112,29 @@ LargeObjectExists(Oid loid)
 {
    bool        retval = false;
    Relation    pg_largeobject;
-   Relation    pg_lo_idx;
    ScanKeyData skey[1];
-   IndexScanDesc sd;
+   SysScanDesc sd;
    HeapTuple   tuple;
 
    /*
     * See if we can find any tuples belonging to the specified LO
     */
-   ScanKeyEntryInitialize(&skey[0],
-                          (bits16) 0x0,
-                          (AttrNumber) 1,
+   ScanKeyEntryInitialize(&skey[0], 0x0,
+                          (AttrNumber) Anum_pg_largeobject_loid,
                           (RegProcedure) F_OIDEQ,
                           ObjectIdGetDatum(loid));
 
-   pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock);
-   pg_lo_idx = index_openr(LargeObjectLOidPNIndex);
+   pg_largeobject = heap_openr(LargeObjectRelationName, AccessShareLock);
 
-   sd = index_beginscan(pg_largeobject, pg_lo_idx, SnapshotNow, 1, skey);
+   sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndex, true,
+                           SnapshotNow, 1, skey);
 
-   if ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
+   if ((tuple = systable_getnext(sd)) != NULL)
        retval = true;
 
-   index_endscan(sd);
+   systable_endscan(sd);
 
-   index_close(pg_lo_idx);
-   heap_close(pg_largeobject, RowShareLock);
+   heap_close(pg_largeobject, AccessShareLock);
 
    return retval;
 }
index ea5ba1031317e00c5c9d2bea1ce77c500543dee5..328643c171e7a1697a11657b35b37c014e115536 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.34 2003/09/10 19:59:23 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.35 2003/09/24 18:54:01 tgl Exp $
  *
  * DESCRIPTION
  *   These routines take the parse tree and pick out the
@@ -1095,24 +1095,25 @@ DropCast(DropCastStmt *stmt)
 void
 DropCastById(Oid castOid)
 {
-   Relation    relation,
-               index;
+   Relation    relation;
    ScanKeyData scankey;
-   IndexScanDesc scan;
+   SysScanDesc scan;
    HeapTuple   tuple;
 
    relation = heap_openr(CastRelationName, RowExclusiveLock);
-   index = index_openr(CastOidIndex);
 
    ScanKeyEntryInitialize(&scankey, 0x0,
-                          1, F_OIDEQ, ObjectIdGetDatum(castOid));
-   scan = index_beginscan(relation, index, SnapshotNow, 1, &scankey);
-   tuple = index_getnext(scan, ForwardScanDirection);
+                          ObjectIdAttributeNumber,
+                          F_OIDEQ,
+                          ObjectIdGetDatum(castOid));
+   scan = systable_beginscan(relation, CastOidIndex, true,
+                             SnapshotNow, 1, &scankey);
+
+   tuple = systable_getnext(scan);
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "could not find tuple for cast %u", castOid);
    simple_heap_delete(relation, &tuple->t_self);
-   index_endscan(scan);
 
-   index_close(index);
+   systable_endscan(scan);
    heap_close(relation, RowExclusiveLock);
 }
index 4c2221263d7321a3488870c00daf83f0809c63c5..c8ccab8d4e103d8f23f729d6b700f96f553d34e7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.108 2003/09/23 01:51:09 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.109 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -112,14 +112,6 @@ DefineIndex(RangeVar *heapRelation,
    relationId = RelationGetRelid(rel);
    namespaceId = RelationGetNamespace(rel);
 
-   if (!IsBootstrapProcessingMode() &&
-       IsSystemRelation(rel) &&
-       !IndexesAreActive(rel))
-       ereport(ERROR,
-               (errcode(ERRCODE_INDEXES_DEACTIVATED),
-                errmsg("existing indexes are inactive"),
-                errhint("REINDEX the table first.")));
-
    heap_close(rel, NoLock);
 
    /*
@@ -599,10 +591,6 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
 {
    Oid         indOid;
    HeapTuple   tuple;
-   bool        overwrite;
-
-   /* Choose in-place-or-not mode */
-   overwrite = IsIgnoringSystemIndexes();
 
    indOid = RangeVarGetRelid(indexRelation, false);
    tuple = SearchSysCache(RELOID,
@@ -617,37 +605,14 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
                 errmsg("relation \"%s\" is not an index",
                        indexRelation->relname)));
 
-   if (IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
-       !IsToastClass((Form_pg_class) GETSTRUCT(tuple)))
-   {
-       if (!allowSystemTableMods)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                    errmsg("permission denied: \"%s\" is a system index",
-                           indexRelation->relname),
-                    errhint("Do REINDEX in standalone postgres with -O -P options.")));
-       if (!IsIgnoringSystemIndexes())
-           ereport(ERROR,
-                   (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                    errmsg("permission denied: \"%s\" is a system index",
-                           indexRelation->relname),
-                    errhint("Do REINDEX in standalone postgres with -P -O options.")));
-   }
+   /* Check permissions */
+   if (!pg_class_ownercheck(indOid, GetUserId()))
+       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+                      indexRelation->relname);
 
    ReleaseSysCache(tuple);
 
-   /*
-    * In-place REINDEX within a transaction block is dangerous, because
-    * if the transaction is later rolled back we have no way to undo
-    * truncation of the index's physical file.  Disallow it.
-    */
-   if (overwrite)
-       PreventTransactionChain((void *) indexRelation, "REINDEX");
-
-   if (!reindex_index(indOid, force, overwrite))
-       ereport(WARNING,
-               (errmsg("index \"%s\" wasn't reindexed",
-                       indexRelation->relname)));
+   reindex_index(indOid);
 }
 
 /*
@@ -655,54 +620,62 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
  *     Recreate indexes of a table.
  */
 void
-ReindexTable(RangeVar *relation, bool force)
+ReindexTable(RangeVar *relation, bool force /* currently unused */ )
 {
    Oid         heapOid;
-   char        relkind;
+   HeapTuple   tuple;
 
    heapOid = RangeVarGetRelid(relation, false);
-   relkind = get_rel_relkind(heapOid);
+   tuple = SearchSysCache(RELOID,
+                          ObjectIdGetDatum(heapOid),
+                          0, 0, 0);
+   if (!HeapTupleIsValid(tuple))       /* shouldn't happen */
+       elog(ERROR, "cache lookup failed for relation %u", heapOid);
 
-   if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE)
+   if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION &&
+       ((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_TOASTVALUE)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("relation \"%s\" is not a table",
                        relation->relname)));
 
-   /*
-    * In-place REINDEX within a transaction block is dangerous, because
-    * if the transaction is later rolled back we have no way to undo
-    * truncation of the index's physical file.  Disallow it.
-    *
-    * XXX we assume that in-place reindex will only be done if
-    * IsIgnoringSystemIndexes() is true.
-    */
-   if (IsIgnoringSystemIndexes())
-       PreventTransactionChain((void *) relation, "REINDEX");
+   /* Check permissions */
+   if (!pg_class_ownercheck(heapOid, GetUserId()))
+       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+                      relation->relname);
+
+   /* Can't reindex shared tables except in standalone mode */
+   if (((Form_pg_class) GETSTRUCT(tuple))->relisshared && IsUnderPostmaster)
+       ereport(ERROR,
+               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                errmsg("shared table \"%s\" can only be reindexed in standalone mode",
+                       relation->relname)));
+
+   ReleaseSysCache(tuple);
 
-   if (!reindex_relation(heapOid, force))
+   if (!reindex_relation(heapOid))
        ereport(WARNING,
-               (errmsg("table \"%s\" wasn't reindexed",
+               (errmsg("table \"%s\" has no indexes",
                        relation->relname)));
 }
 
 /*
  * ReindexDatabase
  *     Recreate indexes of a database.
+ *
+ * To reduce the probability of deadlocks, each table is reindexed in a
+ * separate transaction, so we can release the lock on it right away.
  */
 void
-ReindexDatabase(const char *dbname, bool force, bool all)
+ReindexDatabase(const char *dbname, bool force /* currently unused */,
+               bool all)
 {
    Relation    relationRelation;
    HeapScanDesc scan;
    HeapTuple   tuple;
    MemoryContext private_context;
    MemoryContext old;
-   int         relcnt,
-               relalc,
-               i,
-               oncealc = 200;
-   Oid        *relids = (Oid *) NULL;
+   List       *relids = NIL;
 
    AssertArg(dbname);
 
@@ -715,21 +688,12 @@ ReindexDatabase(const char *dbname, bool force, bool all)
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
                       dbname);
 
-   if (!allowSystemTableMods)
-       ereport(ERROR,
-               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                errmsg("REINDEX DATABASE must be done in standalone postgres with -O -P options")));
-   if (!IsIgnoringSystemIndexes())
-       ereport(ERROR,
-               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                errmsg("REINDEX DATABASE must be done in standalone postgres with -P -O options")));
-
    /*
     * We cannot run inside a user transaction block; if we were inside a
     * transaction, then our commit- and start-transaction-command calls
     * would not have the intended effect!
     */
-   PreventTransactionChain((void *) dbname, "REINDEX");
+   PreventTransactionChain((void *) dbname, "REINDEX DATABASE");
 
    /*
     * Create a memory context that will survive forced transaction
@@ -743,55 +707,68 @@ ReindexDatabase(const char *dbname, bool force, bool all)
                                            ALLOCSET_DEFAULT_INITSIZE,
                                            ALLOCSET_DEFAULT_MAXSIZE);
 
+   /*
+    * We always want to reindex pg_class first.  This ensures that if
+    * there is any corruption in pg_class' indexes, they will be fixed
+    * before we process any other tables.  This is critical because
+    * reindexing itself will try to update pg_class.
+    */
+   old = MemoryContextSwitchTo(private_context);
+   relids = lappendo(relids, RelOid_pg_class);
+   MemoryContextSwitchTo(old);
+
    /*
     * Scan pg_class to build a list of the relations we need to reindex.
+    *
+    * We only consider plain relations here (toast rels will be processed
+    * indirectly by reindex_relation).
     */
    relationRelation = heap_openr(RelationRelationName, AccessShareLock);
    scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
-   relcnt = relalc = 0;
    while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
    {
-       char        relkind;
+       Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
+
+       if (classtuple->relkind != RELKIND_RELATION)
+           continue;
 
-       if (!all)
+       if (!all)               /* only system tables? */
        {
-           if (!(IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
-                 !IsToastClass((Form_pg_class) GETSTRUCT(tuple))))
+           if (!IsSystemClass(classtuple))
                continue;
        }
-       relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind;
-       if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE)
+
+       if (IsUnderPostmaster)  /* silently ignore shared tables */
        {
-           old = MemoryContextSwitchTo(private_context);
-           if (relcnt == 0)
-           {
-               relalc = oncealc;
-               relids = palloc(sizeof(Oid) * relalc);
-           }
-           else if (relcnt >= relalc)
-           {
-               relalc *= 2;
-               relids = repalloc(relids, sizeof(Oid) * relalc);
-           }
-           MemoryContextSwitchTo(old);
-           relids[relcnt] = HeapTupleGetOid(tuple);
-           relcnt++;
+           if (classtuple->relisshared)
+               continue;
        }
+
+       if (HeapTupleGetOid(tuple) == RelOid_pg_class)
+           continue;           /* got it already */
+
+       old = MemoryContextSwitchTo(private_context);
+       relids = lappendo(relids, HeapTupleGetOid(tuple));
+       MemoryContextSwitchTo(old);
    }
    heap_endscan(scan);
    heap_close(relationRelation, AccessShareLock);
 
    /* Now reindex each rel in a separate transaction */
    CommitTransactionCommand();
-   for (i = 0; i < relcnt; i++)
+   while (relids)
    {
+       Oid     relid = lfirsto(relids);
+
        StartTransactionCommand();
        SetQuerySnapshot();     /* might be needed for functions in
                                 * indexes */
-       if (reindex_relation(relids[i], force))
+       if (reindex_relation(relid))
            ereport(NOTICE,
-                   (errmsg("relation %u was reindexed", relids[i])));
+                   (errmsg("table \"%s\" was reindexed",
+                           get_rel_name(relid))));
        CommitTransactionCommand();
+       relids = lnext(relids);
    }
    StartTransactionCommand();
 
index f6331e8d214127742d9c07d86656747b135561cd..e626848f12b6bf237d19fdbeef06b4cf35696c2b 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.259 2003/08/04 02:39:58 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.260 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -904,11 +904,6 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
    int         nindexes,
                i;
    VRelStats  *vacrelstats;
-   bool        reindex = false;
-
-   if (IsIgnoringSystemIndexes() &&
-       IsSystemRelation(onerel))
-       reindex = true;
 
    vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
                          &OldestXmin, &FreezeLimit);
@@ -927,27 +922,9 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
 
    /* Now open all indexes of the relation */
    vac_open_indexes(onerel, &nindexes, &Irel);
-   if (!Irel)
-       reindex = false;
-   else if (!RelationGetForm(onerel)->relhasindex)
-       reindex = true;
    if (nindexes > 0)
        vacrelstats->hasindex = true;
 
-#ifdef NOT_USED
-
-   /*
-    * reindex in VACUUM is dangerous under WAL. ifdef out until it
-    * becomes safe.
-    */
-   if (reindex)
-   {
-       vac_close_indexes(nindexes, Irel);
-       Irel = (Relation *) NULL;
-       activate_indexes_of_a_table(onerel, false);
-   }
-#endif   /* NOT_USED */
-
    /* Clean/scan index relation(s) */
    if (Irel != (Relation *) NULL)
    {
@@ -994,11 +971,6 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
        }
    }
 
-#ifdef NOT_USED
-   if (reindex)
-       activate_indexes_of_a_table(onerel, true);
-#endif   /* NOT_USED */
-
    /* update shared free space map with final free space info */
    vac_update_fsm(onerel, &fraged_pages, vacrelstats->rel_pages);
 
index 9c815f84cda6d86fbc2a0651b32dbaaeeadaf1ce..4aa3170daa6a8995019f61df629018a99c205e7e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.103 2003/08/08 21:41:40 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.104 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -647,12 +647,9 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
 
    resultRelInfo->ri_NumIndices = 0;
 
-   /* checks for disabled indexes */
+   /* fast path if no indexes */
    if (!RelationGetForm(resultRelation)->relhasindex)
        return;
-   if (IsIgnoringSystemIndexes() &&
-       IsSystemRelation(resultRelation))
-       return;
 
    /*
     * Get cached list of index OIDs
index f93802269da7ee3c09cdb3034e735210fc5fe1fe..6ab2f0a47bd7f2eaf71b1dd6d7dc1ab1d91278a4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.83 2003/08/22 20:26:43 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.84 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -964,12 +964,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 
    currentRelation = heap_open(reloid, AccessShareLock);
 
-   if (!RelationGetForm(currentRelation)->relhasindex)
-       ereport(ERROR,
-               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                errmsg("indexes of relation %u were deactivated",
-                       reloid)));
-
    indexstate->ss.ss_currentRelation = currentRelation;
    indexstate->ss.ss_currentScanDesc = NULL;   /* no heap scan here */
 
index edd12ed5c84ce3ba156996fbcf40c94925ff2965..366a606684ae1e95e0098a08ff1fb5f732a52a32 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.59 2003/08/04 02:40:03 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.60 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,12 @@ SendSharedInvalidMessage(SharedInvalidationMessage *msg)
 /*
  * ReceiveSharedInvalidMessages
  *     Process shared-cache-invalidation messages waiting for this backend
+ *
+ * NOTE: it is entirely possible for this routine to be invoked recursively
+ * as a consequence of processing inside the invalFunction or resetFunction.
+ * Hence, we must be holding no SI resources when we call them.  The only
+ * bad side-effect is that SIDelExpiredDataEntries might be called extra
+ * times on the way out of a nested call.
  */
 void
 ReceiveSharedInvalidMessages(
index c84d119ad78a9dd96d1e2fce60d2a21572a4a335..e61c866b374b8de8763bb7dcf016948e4319440f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.363 2003/09/14 00:03:32 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.364 2003/09/24 18:54:01 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -2252,9 +2252,12 @@ PostgresMain(int argc, char *argv[], const char *username)
 
                /*
                 * ignore system indexes
+                *
+                * As of PG 7.4 this is safe to allow from the client,
+                * since it only disables reading the system indexes,
+                * not writing them.  Worst case consequence is slowness.
                 */
-               if (secure)     /* XXX safe to allow from client??? */
-                   IgnoreSystemIndexes(true);
+               IgnoreSystemIndexes(true);
                break;
 
            case 'o':
@@ -2658,7 +2661,7 @@ PostgresMain(int argc, char *argv[], const char *username)
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.363 $ $Date: 2003/09/14 00:03:32 $\n");
+       puts("$Revision: 1.364 $ $Date: 2003/09/24 18:54:01 $\n");
    }
 
    /*
index 629751e2f15bf2c76a8d4a2020e8c6d4faca2b9c..356948e12b86429f71f4e96d00730c14abc0f4eb 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.206 2003/09/09 23:22:21 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.207 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -992,11 +992,9 @@ ProcessUtility(Node *parsetree,
                switch (stmt->kind)
                {
                    case OBJECT_INDEX:
-                       CheckRelationOwnership(stmt->relation, false);
                        ReindexIndex(stmt->relation, stmt->force);
                        break;
                    case OBJECT_TABLE:
-                       CheckRelationOwnership(stmt->relation, false);
                        ReindexTable(stmt->relation, stmt->force);
                        break;
                    case OBJECT_DATABASE:
index 592a99faa7d6baf0749f63d3d084866bb7588217..3c4cb46a74f2ab7af8429fddebe36f5496bb21fa 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.188 2003/08/04 02:40:06 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.189 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -279,9 +279,7 @@ static HTAB *OpClassCache = NULL;
 
 static void RelationClearRelation(Relation relation, bool rebuild);
 
-#ifdef ENABLE_REINDEX_NAILED_RELATIONS
 static void RelationReloadClassinfo(Relation relation);
-#endif   /* ENABLE_REINDEX_NAILED_RELATIONS */
 static void RelationFlushRelation(Relation relation);
 static Relation RelationSysNameCacheGetRelation(const char *relationName);
 static bool load_relcache_init_file(void);
@@ -290,7 +288,7 @@ static void write_relcache_init_file(void);
 static void formrdesc(const char *relationName, int natts,
          FormData_pg_attribute *att);
 
-static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
+static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK);
 static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
 static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
                       Relation relation);
@@ -322,7 +320,7 @@ static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
  *     and must eventually be freed with heap_freetuple.
  */
 static HeapTuple
-ScanPgRelation(RelationBuildDescInfo buildinfo)
+ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK)
 {
    HeapTuple   pg_class_tuple;
    Relation    pg_class_desc;
@@ -367,11 +365,12 @@ ScanPgRelation(RelationBuildDescInfo buildinfo)
    /*
     * Open pg_class and fetch a tuple.  Force heap scan if we haven't yet
     * built the critical relcache entries (this includes initdb and
-    * startup without a pg_internal.init file).
+    * startup without a pg_internal.init file).  The caller can also
+    * force a heap scan by setting indexOK == false.
     */
    pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
    pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,
-                                      criticalRelcachesBuilt,
+                                      indexOK && criticalRelcachesBuilt,
                                       SnapshotNow,
                                       nkeys, key);
 
@@ -834,7 +833,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
    /*
     * find the tuple in pg_class corresponding to the given relation id
     */
-   pg_class_tuple = ScanPgRelation(buildinfo);
+   pg_class_tuple = ScanPgRelation(buildinfo, true);
 
    /*
     * if no such tuple exists, return NULL
@@ -875,7 +874,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
     * it could be new too, but it's okay to forget that fact if forced to
     * flush the entry.)
     */
-   relation->rd_isnailed = false;
+   relation->rd_isnailed = 0;
    relation->rd_isnew = false;
    relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
 
@@ -1386,7 +1385,7 @@ formrdesc(const char *relationName,
     * all entries built with this routine are nailed-in-cache; none are
     * for new or temp relations.
     */
-   relation->rd_isnailed = true;
+   relation->rd_isnailed = 1;
    relation->rd_isnew = false;
    relation->rd_istemp = false;
 
@@ -1500,7 +1499,7 @@ formrdesc(const char *relationName,
  *     Lookup an existing reldesc by OID.
  *
  *     Only try to get the reldesc by looking in the cache,
- *     do not go to the disk.
+ *     do not go to the disk if it's not present.
  *
  *     NB: relation ref count is incremented if successful.
  *     Caller should eventually decrement count.  (Usually,
@@ -1514,7 +1513,12 @@ RelationIdCacheGetRelation(Oid relationId)
    RelationIdCacheLookup(relationId, rd);
 
    if (RelationIsValid(rd))
+   {
        RelationIncrementReferenceCount(rd);
+       /* revalidate nailed index if necessary */
+       if (rd->rd_isnailed == 2)
+           RelationReloadClassinfo(rd);
+   }
 
    return rd;
 }
@@ -1538,11 +1542,27 @@ RelationSysNameCacheGetRelation(const char *relationName)
    RelationSysNameCacheLookup(NameStr(name), rd);
 
    if (RelationIsValid(rd))
+   {
        RelationIncrementReferenceCount(rd);
+       /* revalidate nailed index if necessary */
+       if (rd->rd_isnailed == 2)
+           RelationReloadClassinfo(rd);
+   }
 
    return rd;
 }
 
+/*
+ *     RelationNodeCacheGetRelation
+ *
+ *     As above, but lookup by relfilenode.
+ *
+ * NOTE: this must NOT try to revalidate invalidated nailed indexes, since
+ * that could cause us to return an entry with a different relfilenode than
+ * the caller asked for.  Currently this is used only by the buffer manager.
+ * Really the bufmgr's idea of relations should be separated out from the
+ * relcache ...
+ */
 Relation
 RelationNodeCacheGetRelation(RelFileNode rnode)
 {
@@ -1647,39 +1667,60 @@ RelationClose(Relation relation)
 #endif
 }
 
-#ifdef ENABLE_REINDEX_NAILED_RELATIONS
 /*
- * RelationReloadClassinfo
- *
- * This function is especially for nailed relations.
- * relhasindex/relfilenode could be changed even for
- * nailed relations.
+ * RelationReloadClassinfo - reload the pg_class row (only)
+ *
+ * This function is used only for nailed indexes.  Since a REINDEX can
+ * change the relfilenode value for a nailed index, we have to reread
+ * the pg_class row anytime we get an SI invalidation on a nailed index
+ * (without throwing away the whole relcache entry, since we'd be unable
+ * to rebuild it).
+ *
+ * We can't necessarily reread the pg_class row right away; we might be
+ * in a failed transaction when we receive the SI notification.  If so,
+ * RelationClearRelation just marks the entry as invalid by setting
+ * rd_isnailed to 2.  This routine is called to fix the entry when it
+ * is next needed.
  */
 static void
 RelationReloadClassinfo(Relation relation)
 {
    RelationBuildDescInfo buildinfo;
+   bool        indexOK;
    HeapTuple   pg_class_tuple;
    Form_pg_class relp;
 
-   if (!relation->rd_rel)
-       return;
+   /* Should be called only for invalidated nailed indexes */
+   Assert(relation->rd_isnailed == 2 &&
+          relation->rd_rel->relkind == RELKIND_INDEX);
+   /* Read the pg_class row */
    buildinfo.infotype = INFO_RELID;
    buildinfo.i.info_id = relation->rd_id;
-   pg_class_tuple = ScanPgRelation(buildinfo);
+   /*
+    * Don't try to use an indexscan of pg_class_oid_index to reload the
+    * info for pg_class_oid_index ...
+    */
+   indexOK = strcmp(RelationGetRelationName(relation), ClassOidIndex) != 0;
+   pg_class_tuple = ScanPgRelation(buildinfo, indexOK);
    if (!HeapTupleIsValid(pg_class_tuple))
        elog(ERROR, "could not find tuple for system relation %u",
             relation->rd_id);
-   RelationCacheDelete(relation);
    relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
-   memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
-   relation->rd_node.relNode = relp->relfilenode;
-   RelationCacheInsert(relation);
+   if (relation->rd_node.relNode != relp->relfilenode)
+   {
+       /* We have to re-insert the entry into the relcache indexes */
+       RelationCacheDelete(relation);
+       memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
+       relation->rd_node.relNode = relp->relfilenode;
+       RelationCacheInsert(relation);
+   }
    heap_freetuple(pg_class_tuple);
-
-   return;
+   /* Must adjust number of blocks after we know the new relfilenode */
+   relation->rd_targblock = InvalidBlockNumber;
+   RelationUpdateNumberOfBlocks(relation);
+   /* Okay, now it's valid again */
+   relation->rd_isnailed = 1;
 }
-#endif   /* ENABLE_REINDEX_NAILED_RELATIONS */
 
 /*
  * RelationClearRelation
@@ -1712,15 +1753,27 @@ RelationClearRelation(Relation relation, bool rebuild)
     * Never, never ever blow away a nailed-in system relation, because
     * we'd be unable to recover.  However, we must update rd_nblocks and
     * reset rd_targblock, in case we got called because of a relation
-    * cache flush that was triggered by VACUUM.
+    * cache flush that was triggered by VACUUM.  If it's a nailed index,
+    * then we need to re-read the pg_class row to see if its relfilenode
+    * changed.  We can't necessarily do that here, because we might be in
+    * a failed transaction.  We assume it's okay to do it if there are open
+    * references to the relcache entry (cf notes for AtEOXact_RelationCache).
+    * Otherwise just mark the entry as possibly invalid, and it'll be fixed
+    * when next opened.
     */
    if (relation->rd_isnailed)
    {
-       relation->rd_targblock = InvalidBlockNumber;
-       RelationUpdateNumberOfBlocks(relation);
-#ifdef ENABLE_REINDEX_NAILED_RELATIONS
-       RelationReloadClassinfo(relation);
-#endif   /* ENABLE_REINDEX_NAILED_RELATIONS */
+       if (relation->rd_rel->relkind == RELKIND_INDEX)
+       {
+           relation->rd_isnailed = 2;  /* needs to be revalidated */
+           if (relation->rd_refcnt > 1)
+               RelationReloadClassinfo(relation);
+       }
+       else
+       {
+           relation->rd_targblock = InvalidBlockNumber;
+           RelationUpdateNumberOfBlocks(relation);
+       }
        return;
    }
 
@@ -1928,6 +1981,12 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
  *  because (a) during the first pass we won't process any more SI messages,
  *  so hash_seq_search will complete safely; (b) during the second pass we
  *  only hold onto pointers to nondeletable entries.
+ *
+ *  The two-phase approach also makes it easy to ensure that we process
+ *  nailed-in-cache indexes before other nondeletable items, and that we
+ *  process pg_class_oid_index first of all.  In scenarios where a nailed
+ *  index has been given a new relfilenode, we have to detect that update
+ *  before the nailed index is used in reloading any other relcache entry.
  */
 void
 RelationCacheInvalidate(void)
@@ -1935,6 +1994,7 @@ RelationCacheInvalidate(void)
    HASH_SEQ_STATUS status;
    RelIdCacheEnt *idhentry;
    Relation    relation;
+   List       *rebuildFirstList = NIL;
    List       *rebuildList = NIL;
    List       *l;
 
@@ -1954,15 +2014,33 @@ RelationCacheInvalidate(void)
        if (RelationHasReferenceCountZero(relation))
        {
            /* Delete this entry immediately */
+           Assert(!relation->rd_isnailed);
            RelationClearRelation(relation, false);
        }
        else
        {
-           /* Add entry to list of stuff to rebuild in second pass */
-           rebuildList = lcons(relation, rebuildList);
+           /*
+            * Add this entry to list of stuff to rebuild in second pass.
+            * pg_class_oid_index goes on the front of rebuildFirstList,
+            * other nailed indexes on the back, and everything else into
+            * rebuildList (in no particular order).
+            */
+           if (relation->rd_isnailed &&
+               relation->rd_rel->relkind == RELKIND_INDEX)
+           {
+               if (strcmp(RelationGetRelationName(relation),
+                          ClassOidIndex) == 0)
+                   rebuildFirstList = lcons(relation, rebuildFirstList);
+               else
+                   rebuildFirstList = lappend(rebuildFirstList, relation);
+           }
+           else
+               rebuildList = lcons(relation, rebuildList);
        }
    }
 
+   rebuildList = nconc(rebuildFirstList, rebuildList);
+
    /* Phase 2: rebuild the items found to need rebuild in phase 1 */
    foreach(l, rebuildList)
    {
@@ -1976,6 +2054,11 @@ RelationCacheInvalidate(void)
  * AtEOXact_RelationCache
  *
  * Clean up the relcache at transaction commit or abort.
+ *
+ * Note: this must be called *before* processing invalidation messages.
+ * In the case of abort, we don't want to try to rebuild any invalidated
+ * cache entries (since we can't safely do database accesses).  Therefore
+ * we must reset refcnts before handling pending invalidations.
  */
 void
 AtEOXact_RelationCache(bool commit)
@@ -2045,6 +2128,16 @@ AtEOXact_RelationCache(bool commit)
            /* abort case, just reset it quietly */
            RelationSetReferenceCount(relation, expected_refcnt);
        }
+
+       /*
+        * Flush any temporary index list.
+        */
+       if (relation->rd_indexvalid == 2)
+       {
+           freeList(relation->rd_indexlist);
+           relation->rd_indexlist = NIL;
+           relation->rd_indexvalid = 0;
+       }
    }
 }
 
@@ -2101,7 +2194,7 @@ RelationBuildLocalRelation(const char *relname,
     * want it kicked out.  e.g. pg_attribute!!!
     */
    if (nailit)
-       rel->rd_isnailed = true;
+       rel->rd_isnailed = 1;
 
    /*
     * create a new tuple descriptor from the one passed in.  We do this
@@ -2288,7 +2381,7 @@ RelationCacheInitializePhase2(void)
            buildinfo.infotype = INFO_RELNAME; \
            buildinfo.i.info_name = (indname); \
            ird = RelationBuildDesc(buildinfo, NULL); \
-           ird->rd_isnailed = true; \
+           ird->rd_isnailed = 1; \
            RelationSetReferenceCount(ird, 1); \
        } while (0)
 
@@ -2575,7 +2668,7 @@ CheckConstraintFetch(Relation relation)
  * The index list is created only if someone requests it.  We scan pg_index
  * to find relevant indexes, and add the list to the relcache entry so that
  * we won't have to compute it again.  Note that shared cache inval of a
- * relcache entry will delete the old list and set rd_indexfound to false,
+ * relcache entry will delete the old list and set rd_indexvalid to 0,
  * so that we must recompute the index list on next request.  This handles
  * creation or deletion of an index.
  *
@@ -2602,7 +2695,7 @@ RelationGetIndexList(Relation relation)
    MemoryContext oldcxt;
 
    /* Quick exit if we already computed the list. */
-   if (relation->rd_indexfound)
+   if (relation->rd_indexvalid != 0)
        return listCopy(relation->rd_indexlist);
 
    /*
@@ -2638,7 +2731,7 @@ RelationGetIndexList(Relation relation)
    /* Now save a copy of the completed list in the relcache entry. */
    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    relation->rd_indexlist = listCopy(result);
-   relation->rd_indexfound = true;
+   relation->rd_indexvalid = 1;
    MemoryContextSwitchTo(oldcxt);
 
    return result;
@@ -2676,6 +2769,35 @@ insert_ordered_oid(List *list, Oid datum)
    return list;
 }
 
+/*
+ * RelationSetIndexList -- externally force the index list contents
+ *
+ * This is used to temporarily override what we think the set of valid
+ * indexes is.  The forcing will be valid only until transaction commit
+ * or abort.
+ *
+ * This should only be applied to nailed relations, because in a non-nailed
+ * relation the hacked index list could be lost at any time due to SI
+ * messages.  In practice it is only used on pg_class (see REINDEX).
+ *
+ * It is up to the caller to make sure the given list is correctly ordered.
+ */
+void
+RelationSetIndexList(Relation relation, List *indexIds)
+{
+   MemoryContext oldcxt;
+
+   Assert(relation->rd_isnailed == 1);
+   /* Copy the list into the cache context (could fail for lack of mem) */
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+   indexIds = listCopy(indexIds);
+   MemoryContextSwitchTo(oldcxt);
+   /* Okay to replace old list */
+   freeList(relation->rd_indexlist);
+   relation->rd_indexlist = indexIds;
+   relation->rd_indexvalid = 2;        /* mark list as forced */
+}
+
 /*
  * RelationGetIndexExpressions -- get the index expressions for an index
  *
@@ -3087,7 +3209,7 @@ load_relcache_init_file(void)
            RelationSetReferenceCount(rel, 1);
        else
            RelationSetReferenceCount(rel, 0);
-       rel->rd_indexfound = false;
+       rel->rd_indexvalid = 0;
        rel->rd_indexlist = NIL;
        MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
 
index aa89bb817879d12092bd603e61973b764729ccda..9b250eef62ec3c52a0d277a15bbf613b572a017e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.90 2003/08/04 02:40:06 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.91 2003/09/24 18:54:01 tgl Exp $
  *
  * NOTES
  *   These routines allow the parser/planner/executor to perform
@@ -436,19 +436,11 @@ static const struct cachedesc cacheinfo[] = {
    }}
 };
 
-static CatCache *SysCache[
-                         lengthof(cacheinfo)];
+static CatCache *SysCache[lengthof(cacheinfo)];
 static int SysCacheSize = lengthof(cacheinfo);
 static bool CacheInitialized = false;
 
 
-bool
-IsCacheInitialized(void)
-{
-   return CacheInitialized;
-}
-
-
 /*
  * InitCatalogCache - initialize the caches
  *
index 9f19d1187ba8b652e0f320404435c5f5b7ced141..22baac3706f6e4f2ae21afdda46578235509386f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.113 2003/08/04 04:03:10 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.114 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,11 @@ static char socketLockFile[MAXPGPATH];
 
 /* ----------------------------------------------------------------
  *     ignoring system indexes support stuff
+ *
+ * NOTE: "ignoring system indexes" means we do not use the system indexes
+ * for lookups (either in hardwired catalog accesses or in planner-generated
+ * plans).  We do, however, still update the indexes when a catalog
+ * modification is made.
  * ----------------------------------------------------------------
  */
 
@@ -61,15 +66,14 @@ static bool isIgnoringSystemIndexes = false;
  *     True if ignoring system indexes.
  */
 bool
-IsIgnoringSystemIndexes()
+IsIgnoringSystemIndexes(void)
 {
    return isIgnoringSystemIndexes;
 }
 
 /*
  * IgnoreSystemIndexes
- * Set true or false whether PostgreSQL ignores system indexes.
- *
+ *     Set true or false whether PostgreSQL ignores system indexes.
  */
 void
 IgnoreSystemIndexes(bool mode)
@@ -77,6 +81,53 @@ IgnoreSystemIndexes(bool mode)
    isIgnoringSystemIndexes = mode;
 }
 
+/* ----------------------------------------------------------------
+ *     system index reindexing support
+ *
+ * When we are busy reindexing a system index, this code provides support
+ * for preventing catalog lookups from using that index.
+ * ----------------------------------------------------------------
+ */
+
+static Oid currentlyReindexedHeap = InvalidOid;
+static Oid currentlyReindexedIndex = InvalidOid;
+
+/*
+ * ReindexIsProcessingHeap
+ *     True if heap specified by OID is currently being reindexed.
+ */
+bool
+ReindexIsProcessingHeap(Oid heapOid)
+{
+   return heapOid == currentlyReindexedHeap;
+}
+
+/*
+ * ReindexIsProcessingIndex
+ *     True if index specified by OID is currently being reindexed.
+ */
+bool
+ReindexIsProcessingIndex(Oid indexOid)
+{
+   return indexOid == currentlyReindexedIndex;
+}
+
+/*
+ * SetReindexProcessing
+ *     Set flag that specified heap/index are being reindexed.
+ *     Pass InvalidOid to indicate that reindexing is not active.
+ */
+void
+SetReindexProcessing(Oid heapOid, Oid indexOid)
+{
+   /* Args should be both, or neither, InvalidOid */
+   Assert((heapOid == InvalidOid) == (indexOid == InvalidOid));
+   /* Reindexing is not re-entrant. */
+   Assert(indexOid == InvalidOid || currentlyReindexedIndex == InvalidOid);
+   currentlyReindexedHeap = heapOid;
+   currentlyReindexedIndex = indexOid;
+}
+
 /* ----------------------------------------------------------------
  *             database path / name support stuff
  * ----------------------------------------------------------------
index e3ee98a7c38d5fad33417f477caeccf7879196c8..2a45c290b92ee8044b968c525c238da1ffe7d83d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: index.h,v 1.52 2003/08/04 02:40:10 momjian Exp $
+ * $Id: index.h,v 1.53 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,15 +51,12 @@ extern void FormIndexDatum(IndexInfo *indexInfo,
               char *nullv);
 
 extern void UpdateStats(Oid relid, double reltuples);
-extern bool IndexesAreActive(Relation heaprel);
+
 extern void setRelhasindex(Oid relid, bool hasindex,
               bool isprimary, Oid reltoastidxid);
 
 extern void setNewRelfilenode(Relation relation);
 
-extern bool SetReindexProcessing(bool processing);
-extern bool IsReindexProcessing(void);
-
 extern void index_build(Relation heapRelation, Relation indexRelation,
            IndexInfo *indexInfo);
 
@@ -69,9 +66,7 @@ extern double IndexBuildHeapScan(Relation heapRelation,
                   IndexBuildCallback callback,
                   void *callback_state);
 
-extern bool activate_indexes_of_a_table(Relation heaprel, bool activate);
-
-extern bool reindex_index(Oid indexId, bool force, bool inplace);
-extern bool reindex_relation(Oid relid, bool force);
+extern void reindex_index(Oid indexId);
+extern bool reindex_relation(Oid relid);
 
 #endif   /* INDEX_H */
index d5d6d85c62a9c0168bd6fdf2c7e558544e25e73f..1c1c1d3451934ce10719a3387b98e09348adfe60 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.133 2003/08/26 15:38:25 tgl Exp $
+ * $Id: miscadmin.h,v 1.134 2003/09/24 18:54:01 tgl Exp $
  *
  * NOTES
  *   some of the information in this file should be moved to
@@ -296,18 +296,17 @@ extern void InitPostgres(const char *dbname, const char *username);
 extern void BaseInit(void);
 
 /* in utils/init/miscinit.c */
+extern void IgnoreSystemIndexes(bool mode);
+extern bool IsIgnoringSystemIndexes(void);
+extern void SetReindexProcessing(Oid heapOid, Oid indexOid);
+extern bool ReindexIsProcessingHeap(Oid heapOid);
+extern bool ReindexIsProcessingIndex(Oid indexOid);
 extern void CreateDataDirLockFile(const char *datadir, bool amPostmaster);
 extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
 extern void TouchSocketLockFile(void);
 extern void RecordSharedMemoryInLockFile(unsigned long id1,
                             unsigned long id2);
-
 extern void ValidatePgVersion(const char *path);
 extern void process_preload_libraries(char *preload_libraries_string);
 
-/* these externs do not belong here... */
-extern void IgnoreSystemIndexes(bool mode);
-extern bool IsIgnoringSystemIndexes(void);
-extern bool IsCacheInitialized(void);
-
 #endif   /* MISCADMIN_H */
index 13e42cf1b9d87ff59ab746baad5fb3680e734324..fa1cd254a4f56b8423947eeaa9f9e8028708057f 100644 (file)
@@ -11,7 +11,7 @@
  *
  * Copyright (c) 2003, PostgreSQL Global Development Group
  *
- * $Id: errcodes.h,v 1.5 2003/08/26 21:15:27 tgl Exp $
+ * $Id: errcodes.h,v 1.6 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /* Class 55 - Object Not In Prerequisite State (class borrowed from DB2) */
 #define ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE   MAKE_SQLSTATE('5','5', '0','0','0')
 #define ERRCODE_OBJECT_IN_USE              MAKE_SQLSTATE('5','5', '0','0','6')
-#define ERRCODE_INDEXES_DEACTIVATED            MAKE_SQLSTATE('5','5', 'P','0','1')
 #define ERRCODE_CANT_CHANGE_RUNTIME_PARAM  MAKE_SQLSTATE('5','5', 'P','0','2')
 
 /* Class 57 - Operator Intervention (class borrowed from DB2) */
index 0971abf000ada59c28b3ed915eb358fb26d4f384..377822afc692636929f29d9c52a78f2eeda64dfa 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.67 2003/08/04 02:40:15 momjian Exp $
+ * $Id: rel.h,v 1.68 2003/09/24 18:54:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,8 +119,10 @@ typedef struct RelationData
     * it is possible for new-ness to be "forgotten" (eg, after CLUSTER).
     */
    bool        rd_istemp;      /* rel uses the local buffer mgr */
-   bool        rd_isnailed;    /* rel is nailed in cache */
-   bool        rd_indexfound;  /* true if rd_indexlist is valid */
+   char        rd_isnailed;    /* rel is nailed in cache: 0 = no, 1 = yes,
+                                * 2 = yes but possibly invalid */
+   char        rd_indexvalid;  /* state of rd_indexlist: 0 = not valid,
+                                * 1 = valid, 2 = temporarily forced */
    Form_pg_class rd_rel;       /* RELATION tuple */
    TupleDesc   rd_att;         /* tuple descriptor */
    Oid         rd_id;          /* relation's object id */
index 5d08e9b0256a191e556eabfb1bf6a0a12cd54d56..61e09c38461f9053e308f08696294aae5f720db0 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relcache.h,v 1.36 2003/08/04 02:40:15 momjian Exp $
+ * $Id: relcache.h,v 1.37 2003/09/24 18:54:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,8 @@ extern List *RelationGetIndexList(Relation relation);
 extern List *RelationGetIndexExpressions(Relation relation);
 extern List *RelationGetIndexPredicate(Relation relation);
 
+extern void RelationSetIndexList(Relation relation, List *indexIds);
+
 extern void RelationInitIndexAccessInfo(Relation relation);
 
 /*