*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.157 2007/03/13 00:33:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.158 2007/05/02 21:08:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
+#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relcache.h"
for (ixcnt = 0; ixcnt < snapshot->xcnt; ixcnt++)
XactLockTableWait(snapshot->xip[ixcnt]);
- /* Index can now be marked valid -- update its pg_index entry */
+ /*
+ * Index can now be marked valid -- update its pg_index entry
+ */
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
indexTuple = SearchSysCacheCopy(INDEXRELID,
heap_close(pg_index, RowExclusiveLock);
+ /*
+ * The pg_index update will cause backends (including this one) to update
+ * relcache entries for the index itself, but we should also send a
+ * relcache inval on the parent table to force replanning of cached plans.
+ * Otherwise existing sessions might fail to use the new index where it
+ * would be useful.
+ */
+ CacheInvalidateRelcacheByRelid(heaprelid.relId);
+
/*
* Last thing to do is release the session-level lock on the parent table.
*/
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.79 2007/01/05 22:19:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.80 2007/05/02 21:08:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* KLUGE ALERT: we always send the relcache event with MyDatabaseId,
* even if the rel in question is shared (which we can't easily tell).
* This essentially means that only backends in this same database
- * will react to the relcache flush request. This is in fact
+ * will react to the relcache flush request. This is in fact
* appropriate, since only those backends could see our pg_attribute
- * change anyway. It looks a bit ugly though.
+ * change anyway. It looks a bit ugly though. (In practice, shared
+ * relations can't have schema changes after bootstrap, so we should
+ * never come here for a shared rel anyway.)
*/
databaseId = MyDatabaseId;
}
+ else if (tupleRelId == IndexRelationId)
+ {
+ Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple);
+
+ /*
+ * When a pg_index row is updated, we should send out a relcache inval
+ * for the index relation. As above, we don't know the shared status
+ * of the index, but in practice it doesn't matter since indexes of
+ * shared catalogs can't have such updates.
+ */
+ relationId = indextup->indexrelid;
+ databaseId = MyDatabaseId;
+ }
else
return;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.259 2007/03/29 00:15:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.260 2007/05/02 21:08:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void RelationClearRelation(Relation relation, bool rebuild);
-static void RelationReloadClassinfo(Relation relation);
+static void RelationReloadIndexInfo(Relation relation);
static void RelationFlushRelation(Relation relation);
static bool load_relcache_init_file(void);
static void write_relcache_init_file(void);
RelationIncrementReferenceCount(rd);
/* revalidate nailed index if necessary */
if (!rd->rd_isvalid)
- RelationReloadClassinfo(rd);
+ RelationReloadIndexInfo(rd);
return rd;
}
}
/*
- * RelationReloadClassinfo - reload the pg_class row (only)
+ * RelationReloadIndexInfo - reload minimal information for an open index
*
- * This function is used only for indexes. We currently allow only the
- * pg_class row of an existing index to change (to support changes of
- * owner, tablespace, or relfilenode), not its pg_index row or other
- * subsidiary index schema information. Therefore it's sufficient to do
- * this when we get an SI invalidation. Furthermore, there are cases
- * where it's necessary not to throw away the index information, especially
- * for "nailed" indexes which we are unable to rebuild on-the-fly.
+ * This function is used only for indexes. A relcache inval on an index
+ * can mean that its pg_class or pg_index row changed. There are only
+ * very limited changes that are allowed to an existing index's schema,
+ * so we can update the relcache entry without a complete rebuild; which
+ * is fortunate because we can't rebuild an index entry that is "nailed"
+ * and/or in active use. We support full replacement of the pg_class row,
+ * as well as updates of a few simple fields of the pg_index row.
*
- * We can't necessarily reread the pg_class row right away; we might be
+ * We can't necessarily reread the catalog rows 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_isvalid to false. This routine is called to fix the entry when it
* is next needed.
*/
static void
-RelationReloadClassinfo(Relation relation)
+RelationReloadIndexInfo(Relation relation)
{
bool indexOK;
HeapTuple pg_class_tuple;
if (relation->rd_amcache)
pfree(relation->rd_amcache);
relation->rd_amcache = NULL;
+
+ /*
+ * For a non-system index, there are fields of the pg_index row that are
+ * allowed to change, so re-read that row and update the relcache entry.
+ * Most of the info derived from pg_index (such as support function lookup
+ * info) cannot change, and indeed the whole point of this routine is to
+ * update the relcache entry without clobbering that data; so wholesale
+ * replacement is not appropriate.
+ */
+ if (!IsSystemRelation(relation))
+ {
+ HeapTuple tuple;
+ Form_pg_index index;
+
+ tuple = SearchSysCache(INDEXRELID,
+ ObjectIdGetDatum(RelationGetRelid(relation)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for index %u",
+ RelationGetRelid(relation));
+ index = (Form_pg_index) GETSTRUCT(tuple);
+
+ relation->rd_index->indisvalid = index->indisvalid;
+
+ ReleaseSysCache(tuple);
+ }
+
/* Okay, now it's valid again */
relation->rd_isvalid = true;
}
{
relation->rd_isvalid = false; /* needs to be revalidated */
if (relation->rd_refcnt > 1)
- RelationReloadClassinfo(relation);
+ RelationReloadIndexInfo(relation);
}
return;
}
* have valid index support information. This avoids problems with active
* use of the index support information. As with nailed indexes, we
* re-read the pg_class row to handle possible physical relocation of the
- * index.
+ * index, and we check for pg_index updates too.
*/
if (relation->rd_rel->relkind == RELKIND_INDEX &&
relation->rd_refcnt > 0 &&
relation->rd_indexcxt != NULL)
{
relation->rd_isvalid = false; /* needs to be revalidated */
- RelationReloadClassinfo(relation);
+ RelationReloadIndexInfo(relation);
return;
}