diff options
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 92 |
1 files changed, 57 insertions, 35 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 50ffb0f1b0e..7cd093d2faf 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.215 2005/01/10 20:02:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.215.4.1 2006/01/19 20:28:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1591,11 +1591,13 @@ RelationClose(Relation relation) /* * 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). + * 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. * * 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, @@ -1611,9 +1613,12 @@ RelationReloadClassinfo(Relation relation) HeapTuple pg_class_tuple; Form_pg_class relp; - /* Should be called only for invalidated nailed indexes */ - Assert(relation->rd_isnailed && !relation->rd_isvalid && - relation->rd_rel->relkind == RELKIND_INDEX); + /* Should be called only for invalidated indexes */ + Assert(relation->rd_rel->relkind == RELKIND_INDEX && + !relation->rd_isvalid); + /* Should be closed at smgr level */ + Assert(relation->rd_smgr == NULL); + /* Read the pg_class row */ buildinfo.infotype = INFO_RELID; buildinfo.i.info_id = relation->rd_id; @@ -1625,13 +1630,14 @@ RelationReloadClassinfo(Relation relation) 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", + elog(ERROR, "could not find pg_class tuple for index %u", relation->rd_id); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); - memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE); - /* Now we can recalculate physical address */ - RelationInitPhysicalAddr(relation); + memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE); heap_freetuple(pg_class_tuple); + /* We must recalculate physical address in case it changed */ + RelationInitPhysicalAddr(relation); + /* Make sure targblock is reset in case rel was truncated */ relation->rd_targblock = InvalidBlockNumber; /* Okay, now it's valid again */ relation->rd_isvalid = true; @@ -1687,6 +1693,22 @@ RelationClearRelation(Relation relation, bool rebuild) } /* + * Even non-system indexes should not be blown away if they are open and + * 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. + */ + 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); + return; + } + + /* * Remove relation from hash tables * * Note: we might be reinserting it momentarily, but we must not have it @@ -1999,28 +2021,7 @@ AtEOXact_RelationCache(bool isCommit) int expected_refcnt; /* - * Is it a relation created in the current transaction? - * - * During commit, reset the flag to zero, since we are now out of the - * creating transaction. During abort, simply delete the relcache - * entry --- it isn't interesting any longer. (NOTE: if we have - * forgotten the new-ness of a new relation due to a forced cache - * flush, the entry will get deleted anyway by shared-cache-inval - * processing of the aborted pg_class insertion.) - */ - if (relation->rd_createSubid != InvalidSubTransactionId) - { - if (isCommit) - relation->rd_createSubid = InvalidSubTransactionId; - else - { - RelationClearRelation(relation, false); - continue; - } - } - - /* - * During transaction abort, we must also reset relcache entry ref + * During transaction abort, we must reset relcache entry ref * counts to their normal not-in-a-transaction state. A ref count * may be too high because some routine was exited by ereport() * between incrementing and decrementing the count. @@ -2054,6 +2055,27 @@ AtEOXact_RelationCache(bool isCommit) } /* + * Is it a relation created in the current transaction? + * + * During commit, reset the flag to zero, since we are now out of the + * creating transaction. During abort, simply delete the relcache + * entry --- it isn't interesting any longer. (NOTE: if we have + * forgotten the new-ness of a new relation due to a forced cache + * flush, the entry will get deleted anyway by shared-cache-inval + * processing of the aborted pg_class insertion.) + */ + if (relation->rd_createSubid != InvalidSubTransactionId) + { + if (isCommit) + relation->rd_createSubid = InvalidSubTransactionId; + else + { + RelationClearRelation(relation, false); + continue; + } + } + + /* * Flush any temporary index list. */ if (relation->rd_indexvalid == 2) |