Here is the proposed patch. This fixes the problems that prevented the
relcache from coping with relfilenode changes for nailed-in-cache
indexes. Accordingly, REINDEX is now crash-safe and transaction-safe
for all cases except reindexing shared system catalogs. That case is
permitted only in a standalone backend (!IsUnderPostmaster). We no
longer require -O to reindex system tables, and since -P now suppresses
only reads not writes of system indexes, it is safe to allow from the
client side. Upshot: reindexing system catalogs can be done without a
standalone backend for all cases except shared catalogs.
regards, tom lane
*** doc/src/sgml/ref/postgres-ref.sgml.orig Thu Sep 18 16:30:15 2003
--- doc/src/sgml/ref/postgres-ref.sgml Mon Sep 22 20:10:32 2003
***************
*** 177,185 ****
<term><option>-P</option></term>
<listitem>
<para>
! Ignore system indexes while scanning/updating system tables. The
! <command>REINDEX</command> command for system tables/indexes
! requires this option to be used.
</para>
</listitem>
</varlistentry>
--- 177,185 ----
<term><option>-P</option></term>
<listitem>
<para>
! 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.
</para>
</listitem>
</varlistentry>
*** doc/src/sgml/ref/reindex.sgml.orig Thu Sep 11 21:47:19 2003
--- doc/src/sgml/ref/reindex.sgml Mon Sep 22 20:23:17 2003
***************
*** 56,98 ****
</listitem>
</itemizedlist>
</para>
-
- <para>
- If you suspect corruption of an index on a user table, you can
- simply rebuild that index, or all indexes on the table, using
- <command>REINDEX INDEX</command> or <command>REINDEX
- TABLE</command>. 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. <command>REINDEX</>
- acquires exclusive lock on the table, while <command>CREATE
- INDEX</> only locks out writes not reads of the table.
- </para>
-
- <para>
- 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 <productname>PostgreSQL</productname> server
- must be started instead with the command-line options
- <option>-O</option> and <option>-P</option>. (These options allow
- system table modifications and prevent use of system indexes,
- respectively.) Then, <command>REINDEX DATABASE</>,
- <command>REINDEX TABLE</>, or <command>REINDEX INDEX</> can be
- issued, depending on how much you want to reconstruct. If in
- doubt, use <command>REINDEX DATABASE FORCE</> to force
- reconstruction of all system indexes in the database. Then quit
- the standalone server session and restart the real server.
- </para>
-
- <para>
- See the <xref linkend="app-postgres"> reference page for more
- information about how to interact with the stand-alone server
- interface.
- </para>
</refsect1>
<refsect1>
--- 56,61 ----
***************
*** 104,111 ****
<listitem>
<para>
Recreate all system indexes of a specified database. Indexes on
! user tables are not included. This form of <command>REINDEX</>
! can only be used in stand-alone mode (see above).
</para>
</listitem>
</varlistentry>
--- 67,74 ----
<listitem>
<para>
Recreate all system indexes of a specified database. Indexes on
! user tables are not processed. Also, indexes on shared system
! catalogs are skipped except in stand-alone mode (see below).
</para>
</listitem>
</varlistentry>
***************
*** 142,151 ****
<term><literal>FORCE</literal></term>
<listitem>
<para>
! Force rebuild of system indexes. Without this key word,
! <command>REINDEX</> skips system indexes that are not marked
! invalid. <literal>FORCE</> is irrelevant for <command>REINDEX
! INDEX</> or when reindexing user indexes.
</para>
</listitem>
</varlistentry>
--- 105,111 ----
<term><literal>FORCE</literal></term>
<listitem>
<para>
! This is an obsolete option; it is ignored if specified.
</para>
</listitem>
</varlistentry>
***************
*** 153,158 ****
--- 113,190 ----
</refsect1>
<refsect1>
+ <title>Notes</title>
+
+ <para>
+ If you suspect corruption of an index on a user table, you can
+ simply rebuild that index, or all indexes on the table, using
+ <command>REINDEX INDEX</command> or <command>REINDEX
+ TABLE</command>. 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. <command>REINDEX</>
+ acquires exclusive lock on the table, while <command>CREATE
+ INDEX</> only locks out writes not reads of the table.
+ </para>
+
+ <para>
+ 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>-P</option> option, which prevents it from using
+ indexes for system catalog lookups.
+ </para>
+
+ <para>
+ One way to do this is to shut down the postmaster and start a stand-alone
+ <productname>PostgreSQL</productname> server
+ with the <option>-P</option> option included on its command line.
+ Then, <command>REINDEX DATABASE</>,
+ <command>REINDEX TABLE</>, or <command>REINDEX INDEX</> can be
+ issued, depending on how much you want to reconstruct. If in
+ doubt, use <command>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 <xref linkend="app-postgres"> reference page for more
+ information about how to interact with the stand-alone server
+ interface.
+ </para>
+
+ <para>
+ Alternatively, a regular server session can be started with
+ <option>-P</option> included in its command line options.
+ The method for doing this varies across clients, but in all
+ <application>libpq</>-based clients, it is possible to set
+ the <envar>PGOPTIONS</envar> environment variable to <literal>-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.
+ </para>
+
+ <para>
+ If corruption is suspected in the indexes of any of the shared
+ system catalogs (<structname>pg_database</structname>,
+ <structname>pg_group</structname>, or
+ <structname>pg_shadow</structname>), then a standalone server
+ must be used to repair it. <command>REINDEX</> will not process
+ shared catalogs in multiuser mode.
+ </para>
+
+ <para>
+ For all indexes except the shared system catalogs, <command>REINDEX</>
+ is crash-safe and transaction-safe. <command>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 before attempting to restart the regular server.
+ </para>
+ </refsect1>
+
+ <refsect1>
<title>Examples</title>
<para>
***************
*** 172,182 ****
</para>
<para>
! Rebuild all system indexes (this will only work in a stand-alone
! server session):
<programlisting>
! REINDEX DATABASE my_database FORCE;
</programlisting>
</para>
</refsect1>
--- 204,218 ----
</para>
<para>
! Rebuild all system indexes in a particular database, without trusting them
! to be valid already:
<programlisting>
! $ <userinput>export PGOPTIONS="-P"</userinput>
! $ <userinput>psql broken_db</userinput>
! ...
! broken_db=> REINDEX DATABASE broken_db;
! broken_db=> \q
</programlisting>
</para>
</refsect1>
*** src/backend/access/index/genam.c.orig Sun Aug 3 23:00:25 2003
--- src/backend/access/index/genam.c Mon Sep 22 17:44:29 2003
***************
*** 184,204 ****
int nkeys, ScanKey key)
{
SysScanDesc sysscan;
sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
sysscan->heap_rel = heapRelation;
! if (indexOK &&
! heapRelation->rd_rel->relhasindex &&
! !IsIgnoringSystemIndexes())
{
- 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.
*
--- 184,215 ----
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 (irel)
{
int i;
/*
* Change attribute numbers to be index column numbers.
*
***************
*** 210,222 ****
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;
}
--- 221,233 ----
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->scan = heap_beginscan(heapRelation, snapshot, nkeys, key);
sysscan->iscan = NULL;
}
*** src/backend/access/transam/xact.c.orig Fri Aug 8 17:47:02 2003
--- src/backend/access/transam/xact.c Mon Sep 22 17:44:36 2003
***************
*** 834,841 ****
*/
s->state = TRANS_START;
- SetReindexProcessing(false);
-
/*
* generate a new transaction id
*/
--- 834,839 ----
***************
*** 1085,1090 ****
--- 1083,1089 ----
AtEOXact_Namespace(false);
AtEOXact_CatCache(false);
AtEOXact_Files();
+ SetReindexProcessing(InvalidOid, InvalidOid);
pgstat_count_xact_rollback();
/*
*** src/backend/catalog/index.c.orig Fri Sep 19 15:57:42 2003
--- src/backend/catalog/index.c Mon Sep 22 19:03:52 2003
***************
*** 78,101 ****
static Oid IndexGetRelation(Oid indexId);
- static bool reindexing = false;
-
-
- bool
- SetReindexProcessing(bool reindexmode)
- {
- bool old = reindexing;
-
- reindexing = reindexmode;
- return old;
- }
-
- bool
- IsReindexProcessing(void)
- {
- return reindexing;
- }
-
/*
* ConstructTupleDescriptor
*
--- 78,83 ----
***************
*** 497,504 ****
Oid indexoid;
int i;
- SetReindexProcessing(false);
-
/*
* Only SELECT ... FOR UPDATE are allowed while doing this
*/
--- 479,484 ----
***************
*** 972,1017 ****
}
- /* ---------------------------------------------
- * 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
*
--- 952,957 ----
***************
*** 1037,1048 ****
HeapScanDesc pg_class_scan = NULL;
/*
! * Find the tuple to update in pg_class.
*/
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
! if (!IsIgnoringSystemIndexes() &&
! (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
{
tuple = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(relid),
--- 977,989 ----
HeapScanDesc pg_class_scan = NULL;
/*
! * 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 (!IsBootstrapProcessingMode())
{
tuple = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(relid),
***************
*** 1063,1077 ****
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for relation %u", relid);
- /*
- * 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;
--- 1004,1016 ----
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for relation %u", relid);
+ classtuple = (Form_pg_class) GETSTRUCT(tuple);
+
+ /* Apply required updates */
if (pg_class_scan)
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
if (classtuple->relhasindex != hasindex)
{
classtuple->relhasindex = hasindex;
***************
*** 1140,1219 ****
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) ||
relation->rd_rel->relkind == RELKIND_INDEX);
/* Allocate a new relfilenode */
newrelfilenode = newoid();
/*
! * Find the RELATION relation tuple for the given relation.
*/
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);
! }
!
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 ? */
memcpy((char *) &workrel, relation, sizeof(RelationData));
workrel.rd_fd = -1;
workrel.rd_node.relNode = newrelfilenode;
heap_storage_create(&workrel);
smgrclose(DEFAULT_SMGR, &workrel);
/* 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);
! }
! if (!pg_class_scan)
! heap_freetuple(tuple);
! else
! heap_endscan(pg_class_scan);
heap_close(pg_class, RowExclusiveLock);
--- 1079,1126 ----
Relation pg_class;
HeapTuple tuple;
Form_pg_class rd_rel;
RelationData workrel;
! /* 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 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);
! 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);
/* 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 */
! rd_rel->relfilenode = newrelfilenode;
! simple_heap_update(pg_class, &tuple->t_self, tuple);
! CatalogUpdateIndexes(pg_class, tuple);
! heap_freetuple(tuple);
heap_close(pg_class, RowExclusiveLock);
***************
*** 1263,1273 ****
whichRel = relation_open(relid, ShareLock);
/*
! * Find the RELATION relation tuple for the given relation.
*/
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
! in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
if (!in_place_upd)
{
--- 1170,1190 ----
whichRel = relation_open(relid, ShareLock);
/*
! * 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 = IsBootstrapProcessingMode() ||
! ReindexIsProcessingHeap(RelationGetRelid(pg_class));
if (!in_place_upd)
{
***************
*** 1290,1295 ****
--- 1207,1213 ----
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for relation %u", relid);
+ rd_rel = (Form_pg_class) GETSTRUCT(tuple);
/*
* Figure values to insert.
***************
*** 1330,1347 ****
* 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.
! */
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
rd_rel->relpages = (int32) relpages;
rd_rel->reltuples = (float4) reltuples;
--- 1248,1259 ----
* also reduces the window wherein concurrent CREATE INDEX commands
* may conflict.)
*/
if (rd_rel->relpages != (int32) relpages ||
rd_rel->reltuples != (float4) reltuples)
{
if (in_place_upd)
{
! /* 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;
***************
*** 1561,1570 ****
* should not see any tuples inserted by open
* transactions --- unless it's our own transaction.
* (Consider INSERT followed by CREATE INDEX within a
! * transaction.)
*/
if (!TransactionIdIsCurrentTransactionId(
! HeapTupleHeaderGetXmin(heapTuple->t_data)))
elog(ERROR, "concurrent insert in progress");
indexIt = true;
tupleIsAlive = true;
--- 1473,1485 ----
* should not see any tuples inserted by open
* transactions --- unless it's our own transaction.
* (Consider INSERT followed by CREATE INDEX within a
! * 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))
! && !IsSystemRelation(heapRelation))
elog(ERROR, "concurrent insert in progress");
indexIt = true;
tupleIsAlive = true;
***************
*** 1576,1585 ****
* should not see any tuples deleted by open
* transactions --- unless it's our own transaction.
* (Consider DELETE followed by CREATE INDEX within a
! * transaction.)
*/
if (!TransactionIdIsCurrentTransactionId(
! HeapTupleHeaderGetXmax(heapTuple->t_data)))
elog(ERROR, "concurrent delete in progress");
indexIt = true;
tupleIsAlive = false;
--- 1491,1503 ----
* should not see any tuples deleted by open
* transactions --- unless it's our own transaction.
* (Consider DELETE followed by CREATE INDEX within a
! * 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))
! && !IsSystemRelation(heapRelation))
elog(ERROR, "concurrent delete in progress");
indexIt = true;
tupleIsAlive = false;
***************
*** 1692,1754 ****
/*
* reindex_index - This routine is used to recreate an index
*/
! bool
! reindex_index(Oid indexId, bool force, bool inplace)
{
Relation iRel,
heapRelation;
IndexInfo *indexInfo;
Oid heapId;
! bool old;
/*
* 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.
*/
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 */
heapRelation = heap_open(heapId, AccessExclusiveLock);
/*
* 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.
*
! * In either of these cases, we are definitely processing a system index,
! * so we'd better be ignoring system indexes. (These checks are just
! * for paranoia's sake --- upstream code should have disallowed reindex
! * in such cases already.)
! */
! if (iRel->rd_rel->relisshared)
! {
! if (!IsIgnoringSystemIndexes())
! elog(ERROR,
! "must be ignoring system indexes to reindex shared index %u",
! indexId);
! inplace = true;
! }
! if (iRel->rd_isnailed)
! {
! if (!IsIgnoringSystemIndexes())
! elog(ERROR,
! "must be ignoring system indexes to reindex nailed index %u",
! indexId);
! inplace = true;
! }
/* Fetch info needed for index_build */
indexInfo = BuildIndexInfo(iRel);
--- 1610,1663 ----
/*
* reindex_index - This routine is used to recreate an index
*/
! void
! reindex_index(Oid indexId)
{
Relation iRel,
heapRelation;
IndexInfo *indexInfo;
Oid heapId;
! bool inplace;
/*
* Open our index relation and get an exclusive lock on it.
*
! * 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);
/* Get OID of index's parent table */
heapId = iRel->rd_index->indrelid;
! /* 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). Otherwise
! * we can do it the normal transaction-safe way.
*
! * 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.)
! */
! 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);
***************
*** 1781,1902 ****
* 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;
! }
!
! #ifdef NOT_USED
! /*
! * activate_indexes_of_a_table
! * activate/deactivate indexes of the specified table.
! *
! * Caller must already hold exclusive lock on the table.
! */
! bool
! activate_indexes_of_a_table(Relation heaprel, bool activate)
! {
! 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;
}
- #endif /* NOT_USED */
/*
* reindex_relation - This routine is used to recreate all indexes
* of a relation.
*/
bool
! reindex_relation(Oid relid, bool force)
{
- Relation indexRelation;
- ScanKeyData entry;
- HeapScanDesc scan;
- HeapTuple indexTuple;
- bool old,
- reindexed;
- bool overwrite;
Relation rel;
!
! overwrite = false;
/*
* 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.
*/
rel = heap_open(relid, AccessExclusiveLock);
/*
! * Should be ignoring system indexes if we are reindexing a system table.
! * (This is elog not ereport because caller should have caught it.)
! */
! if (!IsIgnoringSystemIndexes() &&
! IsSystemRelation(rel) && !IsToastRelation(rel))
! elog(ERROR,
! "must be ignoring system indexes to reindex system table %u",
! relid);
/*
! * Shared system indexes must be overwritten because it's impossible
! * to update pg_class tuples of all databases.
*/
! if (rel->rd_rel->relisshared)
{
! if (!IsIgnoringSystemIndexes()) /* shouldn't happen */
! elog(ERROR,
! "must be ignoring system indexes to reindex shared table %u",
! relid);
! overwrite = true;
! }
! old = SetReindexProcessing(true);
! /*
! * Continue to hold the lock.
! */
! heap_close(rel, NoLock);
! /*
! * Find table's indexes by looking in pg_index (not trusting indexes...)
! */
! 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 (reindex_index(index->indexrelid, false, overwrite))
! reindexed = true;
! else
! {
! reindexed = false;
! break;
! }
}
- heap_endscan(scan);
- heap_close(indexRelation, AccessShareLock);
! SetReindexProcessing(old);
! return reindexed;
}
--- 1690,1770 ----
* 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(InvalidOid, InvalidOid);
}
/*
* reindex_relation - This routine is used to recreate all indexes
* of a relation.
+ *
+ * Returns true if any indexes were rebuilt.
*/
bool
! reindex_relation(Oid relid)
{
Relation rel;
! bool is_pg_class;
! List *indexIds,
! *doneIndexes,
! *indexId;
/*
* Ensure to hold an exclusive lock throughout the transaction. The
! * lock could perhaps be less intensive (in the non-overwrite case)
! * but for now it's AccessExclusiveLock for simplicity.
*/
rel = heap_open(relid, AccessExclusiveLock);
/*
! * 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.)
! */
! indexIds = RelationGetIndexList(rel);
/*
! * 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().
*/
! is_pg_class = (RelationGetRelid(rel) == RelOid_pg_class);
! doneIndexes = NIL;
!
! /* Reindex all the indexes. */
! foreach(indexId, indexIds)
{
! Oid indexOid = lfirsto(indexId);
! if (is_pg_class)
! RelationSetIndexList(rel, doneIndexes);
! reindex_index(indexOid);
! CommandCounterIncrement();
! if (is_pg_class)
! doneIndexes = lappendo(doneIndexes, indexOid);
}
! if (is_pg_class)
! RelationSetIndexList(rel, indexIds);
!
! /*
! * Close rel, but continue to hold the lock.
! */
! heap_close(rel, NoLock);
! return (indexIds != NIL);
}
*** src/backend/commands/indexcmds.c.orig Fri Sep 19 16:07:33 2003
--- src/backend/commands/indexcmds.c Mon Sep 22 18:22:19 2003
***************
*** 112,125 ****
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);
/*
--- 112,117 ----
***************
*** 599,608 ****
{
Oid indOid;
HeapTuple tuple;
- bool overwrite;
-
- /* Choose in-place-or-not mode */
- overwrite = IsIgnoringSystemIndexes();
indOid = RangeVarGetRelid(indexRelation, false);
tuple = SearchSysCache(RELOID,
--- 591,596 ----
***************
*** 617,653 ****
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.")));
! }
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)));
}
/*
--- 605,618 ----
errmsg("relation \"%s\" is not an index",
indexRelation->relname)));
! /* Check permissions */
! if (!pg_class_ownercheck(indOid, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
! indexRelation->relname);
ReleaseSysCache(tuple);
! reindex_index(indOid);
}
/*
***************
*** 655,661 ****
* Recreate indexes of a table.
*/
void
! ReindexTable(RangeVar *relation, bool force)
{
Oid heapOid;
HeapTuple tuple;
--- 620,626 ----
* Recreate indexes of a table.
*/
void
! ReindexTable(RangeVar *relation, bool force /* currently unused */ )
{
Oid heapOid;
HeapTuple tuple;
***************
*** 674,712 ****
errmsg("relation \"%s\" is not a table",
relation->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 table",
! relation->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 table",
! relation->relname),
! errhint("Do REINDEX in standalone postgres with -P -O options.")));
! }
! 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.
! *
! * XXX we assume that in-place reindex will only be done if
! * IsIgnoringSystemIndexes() is true.
! */
! if (IsIgnoringSystemIndexes())
! PreventTransactionChain((void *) relation, "REINDEX");
! if (!reindex_relation(heapOid, force))
ereport(WARNING,
! (errmsg("table \"%s\" wasn't reindexed",
relation->relname)));
}
--- 639,661 ----
errmsg("relation \"%s\" is not a table",
relation->relname)));
! /* 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))
ereport(WARNING,
! (errmsg("table \"%s\" has no indexes",
relation->relname)));
}
***************
*** 715,732 ****
* Recreate indexes of a database.
*/
void
! ReindexDatabase(const char *dbname, bool force, bool all)
{
Relation relationRelation;
HeapScanDesc scan;
HeapTuple tuple;
MemoryContext private_context;
MemoryContext old;
! int relcnt,
! relalc,
! i,
! oncealc = 200;
! Oid *relids = (Oid *) NULL;
AssertArg(dbname);
--- 664,678 ----
* Recreate indexes of a database.
*/
void
! ReindexDatabase(const char *dbname, bool force /* currently unused */,
! bool all)
{
Relation relationRelation;
HeapScanDesc scan;
HeapTuple tuple;
MemoryContext private_context;
MemoryContext old;
! List *relids = NIL;
AssertArg(dbname);
***************
*** 739,759 ****
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");
/*
* Create a memory context that will survive forced transaction
--- 685,696 ----
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
dbname);
/*
* 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 DATABASE");
/*
* Create a memory context that will survive forced transaction
***************
*** 768,821 ****
ALLOCSET_DEFAULT_MAXSIZE);
/*
* Scan pg_class to build a list of the relations we need to reindex.
*/
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
- relcnt = relalc = 0;
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
! char relkind;
! if (!all)
{
! if (!(IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
! !IsToastClass((Form_pg_class) GETSTRUCT(tuple))))
continue;
}
! relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind;
! if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE)
{
! 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++;
}
}
heap_endscan(scan);
heap_close(relationRelation, AccessShareLock);
/* Now reindex each rel in a separate transaction */
CommitTransactionCommand();
! for (i = 0; i < relcnt; i++)
{
StartTransactionCommand();
SetQuerySnapshot(); /* might be needed for functions in
* indexes */
! if (reindex_relation(relids[i], force))
ereport(NOTICE,
! (errmsg("relation %u was reindexed", relids[i])));
CommitTransactionCommand();
}
StartTransactionCommand();
--- 705,769 ----
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.
*/
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
! Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
! if (classtuple->relkind != RELKIND_RELATION &&
! classtuple->relkind != RELKIND_TOASTVALUE)
! continue;
!
! if (!all) /* only system tables? */
{
! if (!(IsSystemClass(classtuple) && !IsToastClass(classtuple)))
continue;
}
!
! if (IsUnderPostmaster) /* silently ignore shared tables */
{
! 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();
! while (relids)
{
+ Oid relid = lfirsto(relids);
+
StartTransactionCommand();
SetQuerySnapshot(); /* might be needed for functions in
* indexes */
! if (reindex_relation(relid))
ereport(NOTICE,
! (errmsg("table \"%s\" was reindexed",
! get_rel_name(relid))));
CommitTransactionCommand();
+ relids = lnext(relids);
}
StartTransactionCommand();
*** src/backend/commands/vacuum.c.orig Sun Aug 3 23:00:32 2003
--- src/backend/commands/vacuum.c Sun Sep 21 16:55:42 2003
***************
*** 904,914 ****
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);
--- 904,909 ----
***************
*** 927,953 ****
/* 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)
{
--- 922,930 ----
***************
*** 993,1003 ****
elog(ERROR, "FlushRelationBuffers returned %d", i);
}
}
-
- #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);
--- 970,975 ----
*** src/backend/executor/execUtils.c.orig Fri Aug 8 17:47:05 2003
--- src/backend/executor/execUtils.c Sun Sep 21 16:55:36 2003
***************
*** 647,657 ****
resultRelInfo->ri_NumIndices = 0;
! /* checks for disabled indexes */
if (!RelationGetForm(resultRelation)->relhasindex)
- return;
- if (IsIgnoringSystemIndexes() &&
- IsSystemRelation(resultRelation))
return;
/*
--- 647,654 ----
resultRelInfo->ri_NumIndices = 0;
! /* fast path if no indexes */
if (!RelationGetForm(resultRelation)->relhasindex)
return;
/*
*** src/backend/executor/nodeIndexscan.c.orig Fri Aug 22 16:26:43 2003
--- src/backend/executor/nodeIndexscan.c Mon Sep 22 18:39:30 2003
***************
*** 964,975 ****
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 */
--- 964,969 ----
*** src/backend/storage/ipc/sinval.c.orig Tue Aug 19 11:39:55 2003
--- src/backend/storage/ipc/sinval.c Sun Sep 21 18:54:08 2003
***************
*** 73,78 ****
--- 73,84 ----
/*
* 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(
*** src/backend/tcop/postgres.c.orig Sat Sep 13 20:03:32 2003
--- src/backend/tcop/postgres.c Mon Sep 22 19:30:50 2003
***************
*** 2252,2260 ****
/*
* ignore system indexes
*/
! if (secure) /* XXX safe to allow from client??? */
! IgnoreSystemIndexes(true);
break;
case 'o':
--- 2252,2263 ----
/*
* 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.
*/
! IgnoreSystemIndexes(true);
break;
case 'o':
*** src/backend/tcop/utility.c.orig Wed Sep 10 11:16:08 2003
--- src/backend/tcop/utility.c Mon Sep 22 18:16:18 2003
***************
*** 992,1002 ****
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:
--- 992,1000 ----
*** src/backend/utils/cache/relcache.c.orig Sun Aug 3 23:01:06 2003
--- src/backend/utils/cache/relcache.c Mon Sep 22 14:32:08 2003
***************
*** 279,287 ****
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);
--- 279,285 ----
***************
*** 290,296 ****
static void formrdesc(const char *relationName, int natts,
FormData_pg_attribute *att);
! static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
Relation relation);
--- 288,294 ----
static void formrdesc(const char *relationName, int natts,
FormData_pg_attribute *att);
! static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK);
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
Relation relation);
***************
*** 322,328 ****
* and must eventually be freed with heap_freetuple.
*/
static HeapTuple
! ScanPgRelation(RelationBuildDescInfo buildinfo)
{
HeapTuple pg_class_tuple;
Relation pg_class_desc;
--- 320,326 ----
* and must eventually be freed with heap_freetuple.
*/
static HeapTuple
! ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK)
{
HeapTuple pg_class_tuple;
Relation pg_class_desc;
***************
*** 367,377 ****
/*
* 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).
*/
pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,
! criticalRelcachesBuilt,
SnapshotNow,
nkeys, key);
--- 365,376 ----
/*
* 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). 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,
! indexOK && criticalRelcachesBuilt,
SnapshotNow,
nkeys, key);
***************
*** 834,840 ****
/*
* find the tuple in pg_class corresponding to the given relation id
*/
! pg_class_tuple = ScanPgRelation(buildinfo);
/*
* if no such tuple exists, return NULL
--- 833,839 ----
/*
* find the tuple in pg_class corresponding to the given relation id
*/
! pg_class_tuple = ScanPgRelation(buildinfo, true);
/*
* if no such tuple exists, return NULL
***************
*** 875,881 ****
* 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_isnew = false;
relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
--- 874,880 ----
* it could be new too, but it's okay to forget that fact if forced to
* flush the entry.)
*/
! relation->rd_isnailed = 0;
relation->rd_isnew = false;
relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
***************
*** 1386,1392 ****
* all entries built with this routine are nailed-in-cache; none are
* for new or temp relations.
*/
! relation->rd_isnailed = true;
relation->rd_isnew = false;
relation->rd_istemp = false;
--- 1385,1391 ----
* all entries built with this routine are nailed-in-cache; none are
* for new or temp relations.
*/
! relation->rd_isnailed = 1;
relation->rd_isnew = false;
relation->rd_istemp = false;
***************
*** 1500,1506 ****
* Lookup an existing reldesc by OID.
*
* Only try to get the reldesc by looking in the cache,
! * do not go to the disk.
*
* NB: relation ref count is incremented if successful.
* Caller should eventually decrement count. (Usually,
--- 1499,1505 ----
* Lookup an existing reldesc by OID.
*
* Only try to get the reldesc by looking in the cache,
! * do not go to the disk if it's not present.
*
* NB: relation ref count is incremented if successful.
* Caller should eventually decrement count. (Usually,
***************
*** 1514,1520 ****
--- 1513,1524 ----
RelationIdCacheLookup(relationId, rd);
if (RelationIsValid(rd))
+ {
RelationIncrementReferenceCount(rd);
+ /* revalidate nailed index if necessary */
+ if (rd->rd_isnailed == 2)
+ RelationReloadClassinfo(rd);
+ }
return rd;
}
***************
*** 1538,1548 ****
--- 1542,1568 ----
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,1685 ****
#endif
}
- #ifdef ENABLE_REINDEX_NAILED_RELATIONS
/*
! * RelationReloadClassinfo
*
! * This function is especially for nailed relations.
! * relhasindex/relfilenode could be changed even for
! * nailed relations.
*/
static void
RelationReloadClassinfo(Relation relation)
{
RelationBuildDescInfo buildinfo;
HeapTuple pg_class_tuple;
Form_pg_class relp;
! if (!relation->rd_rel)
! return;
buildinfo.infotype = INFO_RELID;
buildinfo.i.info_id = relation->rd_id;
! pg_class_tuple = ScanPgRelation(buildinfo);
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);
heap_freetuple(pg_class_tuple);
!
! return;
}
- #endif /* ENABLE_REINDEX_NAILED_RELATIONS */
/*
* RelationClearRelation
--- 1667,1726 ----
#endif
}
/*
! * 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;
! /* 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;
! /*
! * 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);
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
! 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);
! /* 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;
}
/*
* RelationClearRelation
***************
*** 1712,1726 ****
* 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.
*/
if (relation->rd_isnailed)
{
! relation->rd_targblock = InvalidBlockNumber;
! RelationUpdateNumberOfBlocks(relation);
! #ifdef ENABLE_REINDEX_NAILED_RELATIONS
! RelationReloadClassinfo(relation);
! #endif /* ENABLE_REINDEX_NAILED_RELATIONS */
return;
}
--- 1753,1779 ----
* 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. 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)
{
! 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,1933 ****
--- 1981,1992 ----
* 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,1940 ****
--- 1994,2000 ----
HASH_SEQ_STATUS status;
RelIdCacheEnt *idhentry;
Relation relation;
+ List *rebuildFirstList = NIL;
List *rebuildList = NIL;
List *l;
***************
*** 1954,1968 ****
if (RelationHasReferenceCountZero(relation))
{
/* Delete this entry immediately */
RelationClearRelation(relation, false);
}
else
{
! /* Add entry to list of stuff to rebuild in second pass */
! rebuildList = lcons(relation, rebuildList);
}
}
/* Phase 2: rebuild the items found to need rebuild in phase 1 */
foreach(l, rebuildList)
{
--- 2014,2046 ----
if (RelationHasReferenceCountZero(relation))
{
/* Delete this entry immediately */
+ Assert(!relation->rd_isnailed);
RelationClearRelation(relation, false);
}
else
{
! /*
! * 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,1981 ****
--- 2054,2064 ----
* 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,2050 ****
--- 2128,2143 ----
/* 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,2107 ****
* want it kicked out. e.g. pg_attribute!!!
*/
if (nailit)
! rel->rd_isnailed = true;
/*
* create a new tuple descriptor from the one passed in. We do this
--- 2194,2200 ----
* want it kicked out. e.g. pg_attribute!!!
*/
if (nailit)
! rel->rd_isnailed = 1;
/*
* create a new tuple descriptor from the one passed in. We do this
***************
*** 2288,2294 ****
buildinfo.infotype = INFO_RELNAME; \
buildinfo.i.info_name = (indname); \
ird = RelationBuildDesc(buildinfo, NULL); \
! ird->rd_isnailed = true; \
RelationSetReferenceCount(ird, 1); \
} while (0)
--- 2381,2387 ----
buildinfo.infotype = INFO_RELNAME; \
buildinfo.i.info_name = (indname); \
ird = RelationBuildDesc(buildinfo, NULL); \
! ird->rd_isnailed = 1; \
RelationSetReferenceCount(ird, 1); \
} while (0)
***************
*** 2575,2581 ****
* 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,
* so that we must recompute the index list on next request. This handles
* creation or deletion of an index.
*
--- 2668,2674 ----
* 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_indexvalid to 0,
* so that we must recompute the index list on next request. This handles
* creation or deletion of an index.
*
***************
*** 2602,2608 ****
MemoryContext oldcxt;
/* Quick exit if we already computed the list. */
! if (relation->rd_indexfound)
return listCopy(relation->rd_indexlist);
/*
--- 2695,2701 ----
MemoryContext oldcxt;
/* Quick exit if we already computed the list. */
! if (relation->rd_indexvalid != 0)
return listCopy(relation->rd_indexlist);
/*
***************
*** 2638,2644 ****
/* Now save a copy of the completed list in the relcache entry. */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
relation->rd_indexlist = listCopy(result);
! relation->rd_indexfound = true;
MemoryContextSwitchTo(oldcxt);
return result;
--- 2731,2737 ----
/* Now save a copy of the completed list in the relcache entry. */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
relation->rd_indexlist = listCopy(result);
! relation->rd_indexvalid = 1;
MemoryContextSwitchTo(oldcxt);
return result;
***************
*** 2677,2682 ****
--- 2770,2804 ----
}
/*
+ * 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
*
* We cache the result of transforming pg_index.indexprs into a node tree.
***************
*** 3087,3093 ****
RelationSetReferenceCount(rel, 1);
else
RelationSetReferenceCount(rel, 0);
! rel->rd_indexfound = false;
rel->rd_indexlist = NIL;
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
--- 3209,3215 ----
RelationSetReferenceCount(rel, 1);
else
RelationSetReferenceCount(rel, 0);
! rel->rd_indexvalid = 0;
rel->rd_indexlist = NIL;
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
*** src/backend/utils/cache/syscache.c.orig Sun Aug 3 23:01:06 2003
--- src/backend/utils/cache/syscache.c Sun Sep 21 16:55:31 2003
***************
*** 436,452 ****
}}
};
! static CatCache *SysCache[
! lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
-
-
- bool
- IsCacheInitialized(void)
- {
- return CacheInitialized;
- }
/*
--- 436,444 ----
}}
};
! static CatCache *SysCache[lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
/*
*** src/backend/utils/init/miscinit.c.orig Mon Aug 4 00:03:10 2003
--- src/backend/utils/init/miscinit.c Mon Sep 22 17:44:19 2003
***************
*** 51,56 ****
--- 51,61 ----
/* ----------------------------------------------------------------
* 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,80 ****
* True if ignoring system indexes.
*/
bool
! IsIgnoringSystemIndexes()
{
return isIgnoringSystemIndexes;
}
/*
* IgnoreSystemIndexes
! * Set true or false whether PostgreSQL ignores system indexes.
! *
*/
void
IgnoreSystemIndexes(bool mode)
{
isIgnoringSystemIndexes = mode;
}
/* ----------------------------------------------------------------
--- 66,131 ----
* True if ignoring system indexes.
*/
bool
! IsIgnoringSystemIndexes(void)
{
return isIgnoringSystemIndexes;
}
/*
* IgnoreSystemIndexes
! * Set true or false whether PostgreSQL ignores system indexes.
*/
void
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;
}
/* ----------------------------------------------------------------
*** src/include/catalog/index.h.orig Sun Aug 3 23:01:28 2003
--- src/include/catalog/index.h Sun Sep 21 19:25:22 2003
***************
*** 51,65 ****
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);
--- 51,62 ----
char *nullv);
extern void UpdateStats(Oid relid, double reltuples);
!
extern void setRelhasindex(Oid relid, bool hasindex,
bool isprimary, Oid reltoastidxid);
extern void setNewRelfilenode(Relation relation);
extern void index_build(Relation heapRelation, Relation indexRelation,
IndexInfo *indexInfo);
***************
*** 69,77 ****
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);
#endif /* INDEX_H */
--- 66,72 ----
IndexBuildCallback callback,
void *callback_state);
! extern void reindex_index(Oid indexId);
! extern bool reindex_relation(Oid relid);
#endif /* INDEX_H */
*** src/include/miscadmin.h.orig Tue Aug 26 11:38:25 2003
--- src/include/miscadmin.h Mon Sep 22 17:44:14 2003
***************
*** 296,313 ****
extern void BaseInit(void);
/* in utils/init/miscinit.c */
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 */
--- 296,312 ----
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);
#endif /* MISCADMIN_H */
*** src/include/utils/errcodes.h.orig Tue Aug 26 17:15:27 2003
--- src/include/utils/errcodes.h Mon Sep 22 18:40:53 2003
***************
*** 281,287 ****
/* 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) */
--- 281,286 ----
*** src/include/utils/rel.h.orig Sun Aug 3 23:01:45 2003
--- src/include/utils/rel.h Mon Sep 22 13:34:07 2003
***************
*** 119,126 ****
* 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 */
Form_pg_class rd_rel; /* RELATION tuple */
TupleDesc rd_att; /* tuple descriptor */
Oid rd_id; /* relation's object id */
--- 119,128 ----
* it is possible for new-ness to be "forgotten" (eg, after CLUSTER).
*/
bool rd_istemp; /* rel uses the local buffer mgr */
! 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 */
*** src/include/utils/relcache.h.orig Sun Aug 3 23:01:45 2003
--- src/include/utils/relcache.h Sun Sep 21 19:25:15 2003
***************
*** 35,40 ****
--- 35,42 ----
extern List *RelationGetIndexExpressions(Relation relation);
extern List *RelationGetIndexPredicate(Relation relation);
+ extern void RelationSetIndexList(Relation relation, List *indexIds);
+
extern void RelationInitIndexAccessInfo(Relation relation);
/*