Skip to content

Commit 8ec9438

Browse files
committed
Fix things so that when CREATE INDEX CONCURRENTLY sets pg_index.indisvalid
true at the very end of its processing, the update is broadcast via a shared-cache-inval message for the index; without this, existing backends that already have relcache entries for the index might never see it become valid. Also, force a relcache inval on the index's parent table at the same time, so that any cached plans for that table are re-planned; this ensures that the newly valid index will be used if appropriate. Aside from making C.I.C. behave more reasonably, this is necessary infrastructure for some aspects of the HOT patch. Pavan Deolasee, with a little further stuff from me.
1 parent 229d338 commit 8ec9438

File tree

3 files changed

+75
-21
lines changed

3 files changed

+75
-21
lines changed

src/backend/commands/indexcmds.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.157 2007/03/13 00:33:39 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.158 2007/05/02 21:08:45 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -41,6 +41,7 @@
4141
#include "utils/acl.h"
4242
#include "utils/builtins.h"
4343
#include "utils/fmgroids.h"
44+
#include "utils/inval.h"
4445
#include "utils/lsyscache.h"
4546
#include "utils/memutils.h"
4647
#include "utils/relcache.h"
@@ -514,7 +515,9 @@ DefineIndex(RangeVar *heapRelation,
514515
for (ixcnt = 0; ixcnt < snapshot->xcnt; ixcnt++)
515516
XactLockTableWait(snapshot->xip[ixcnt]);
516517

517-
/* Index can now be marked valid -- update its pg_index entry */
518+
/*
519+
* Index can now be marked valid -- update its pg_index entry
520+
*/
518521
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
519522

520523
indexTuple = SearchSysCacheCopy(INDEXRELID,
@@ -534,6 +537,15 @@ DefineIndex(RangeVar *heapRelation,
534537

535538
heap_close(pg_index, RowExclusiveLock);
536539

540+
/*
541+
* The pg_index update will cause backends (including this one) to update
542+
* relcache entries for the index itself, but we should also send a
543+
* relcache inval on the parent table to force replanning of cached plans.
544+
* Otherwise existing sessions might fail to use the new index where it
545+
* would be useful.
546+
*/
547+
CacheInvalidateRelcacheByRelid(heaprelid.relId);
548+
537549
/*
538550
* Last thing to do is release the session-level lock on the parent table.
539551
*/

src/backend/utils/cache/inval.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
* Portions Copyright (c) 1994, Regents of the University of California
8181
*
8282
* IDENTIFICATION
83-
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.79 2007/01/05 22:19:43 momjian Exp $
83+
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.80 2007/05/02 21:08:46 tgl Exp $
8484
*
8585
*-------------------------------------------------------------------------
8686
*/
@@ -590,12 +590,27 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple)
590590
* KLUGE ALERT: we always send the relcache event with MyDatabaseId,
591591
* even if the rel in question is shared (which we can't easily tell).
592592
* This essentially means that only backends in this same database
593-
* will react to the relcache flush request. This is in fact
593+
* will react to the relcache flush request. This is in fact
594594
* appropriate, since only those backends could see our pg_attribute
595-
* change anyway. It looks a bit ugly though.
595+
* change anyway. It looks a bit ugly though. (In practice, shared
596+
* relations can't have schema changes after bootstrap, so we should
597+
* never come here for a shared rel anyway.)
596598
*/
597599
databaseId = MyDatabaseId;
598600
}
601+
else if (tupleRelId == IndexRelationId)
602+
{
603+
Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple);
604+
605+
/*
606+
* When a pg_index row is updated, we should send out a relcache inval
607+
* for the index relation. As above, we don't know the shared status
608+
* of the index, but in practice it doesn't matter since indexes of
609+
* shared catalogs can't have such updates.
610+
*/
611+
relationId = indextup->indexrelid;
612+
databaseId = MyDatabaseId;
613+
}
599614
else
600615
return;
601616

src/backend/utils/cache/relcache.c

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.259 2007/03/29 00:15:38 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.260 2007/05/02 21:08:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -181,7 +181,7 @@ static HTAB *OpClassCache = NULL;
181181

182182
static void RelationClearRelation(Relation relation, bool rebuild);
183183

184-
static void RelationReloadClassinfo(Relation relation);
184+
static void RelationReloadIndexInfo(Relation relation);
185185
static void RelationFlushRelation(Relation relation);
186186
static bool load_relcache_init_file(void);
187187
static void write_relcache_init_file(void);
@@ -1504,7 +1504,7 @@ RelationIdGetRelation(Oid relationId)
15041504
RelationIncrementReferenceCount(rd);
15051505
/* revalidate nailed index if necessary */
15061506
if (!rd->rd_isvalid)
1507-
RelationReloadClassinfo(rd);
1507+
RelationReloadIndexInfo(rd);
15081508
return rd;
15091509
}
15101510

@@ -1579,24 +1579,24 @@ RelationClose(Relation relation)
15791579
}
15801580

15811581
/*
1582-
* RelationReloadClassinfo - reload the pg_class row (only)
1582+
* RelationReloadIndexInfo - reload minimal information for an open index
15831583
*
1584-
* This function is used only for indexes. We currently allow only the
1585-
* pg_class row of an existing index to change (to support changes of
1586-
* owner, tablespace, or relfilenode), not its pg_index row or other
1587-
* subsidiary index schema information. Therefore it's sufficient to do
1588-
* this when we get an SI invalidation. Furthermore, there are cases
1589-
* where it's necessary not to throw away the index information, especially
1590-
* for "nailed" indexes which we are unable to rebuild on-the-fly.
1584+
* This function is used only for indexes. A relcache inval on an index
1585+
* can mean that its pg_class or pg_index row changed. There are only
1586+
* very limited changes that are allowed to an existing index's schema,
1587+
* so we can update the relcache entry without a complete rebuild; which
1588+
* is fortunate because we can't rebuild an index entry that is "nailed"
1589+
* and/or in active use. We support full replacement of the pg_class row,
1590+
* as well as updates of a few simple fields of the pg_index row.
15911591
*
1592-
* We can't necessarily reread the pg_class row right away; we might be
1592+
* We can't necessarily reread the catalog rows right away; we might be
15931593
* in a failed transaction when we receive the SI notification. If so,
15941594
* RelationClearRelation just marks the entry as invalid by setting
15951595
* rd_isvalid to false. This routine is called to fix the entry when it
15961596
* is next needed.
15971597
*/
15981598
static void
1599-
RelationReloadClassinfo(Relation relation)
1599+
RelationReloadIndexInfo(Relation relation)
16001600
{
16011601
bool indexOK;
16021602
HeapTuple pg_class_tuple;
@@ -1635,6 +1635,33 @@ RelationReloadClassinfo(Relation relation)
16351635
if (relation->rd_amcache)
16361636
pfree(relation->rd_amcache);
16371637
relation->rd_amcache = NULL;
1638+
1639+
/*
1640+
* For a non-system index, there are fields of the pg_index row that are
1641+
* allowed to change, so re-read that row and update the relcache entry.
1642+
* Most of the info derived from pg_index (such as support function lookup
1643+
* info) cannot change, and indeed the whole point of this routine is to
1644+
* update the relcache entry without clobbering that data; so wholesale
1645+
* replacement is not appropriate.
1646+
*/
1647+
if (!IsSystemRelation(relation))
1648+
{
1649+
HeapTuple tuple;
1650+
Form_pg_index index;
1651+
1652+
tuple = SearchSysCache(INDEXRELID,
1653+
ObjectIdGetDatum(RelationGetRelid(relation)),
1654+
0, 0, 0);
1655+
if (!HeapTupleIsValid(tuple))
1656+
elog(ERROR, "cache lookup failed for index %u",
1657+
RelationGetRelid(relation));
1658+
index = (Form_pg_index) GETSTRUCT(tuple);
1659+
1660+
relation->rd_index->indisvalid = index->indisvalid;
1661+
1662+
ReleaseSysCache(tuple);
1663+
}
1664+
16381665
/* Okay, now it's valid again */
16391666
relation->rd_isvalid = true;
16401667
}
@@ -1683,7 +1710,7 @@ RelationClearRelation(Relation relation, bool rebuild)
16831710
{
16841711
relation->rd_isvalid = false; /* needs to be revalidated */
16851712
if (relation->rd_refcnt > 1)
1686-
RelationReloadClassinfo(relation);
1713+
RelationReloadIndexInfo(relation);
16871714
}
16881715
return;
16891716
}
@@ -1693,14 +1720,14 @@ RelationClearRelation(Relation relation, bool rebuild)
16931720
* have valid index support information. This avoids problems with active
16941721
* use of the index support information. As with nailed indexes, we
16951722
* re-read the pg_class row to handle possible physical relocation of the
1696-
* index.
1723+
* index, and we check for pg_index updates too.
16971724
*/
16981725
if (relation->rd_rel->relkind == RELKIND_INDEX &&
16991726
relation->rd_refcnt > 0 &&
17001727
relation->rd_indexcxt != NULL)
17011728
{
17021729
relation->rd_isvalid = false; /* needs to be revalidated */
1703-
RelationReloadClassinfo(relation);
1730+
RelationReloadIndexInfo(relation);
17041731
return;
17051732
}
17061733

0 commit comments

Comments
 (0)