Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ed69cf5

Browse files
committed
Avoid crashing if relcache flush occurs while trying to load data into an
index's support-function cache (in index_getprocinfo). Since none of that data can change for an index that's in active use, it seems sufficient to treat all open indexes the same way we were treating "nailed" system indexes --- that is, just re-read the pg_class row and leave the rest of the relcache entry strictly alone. The pg_class re-read might not be strictly necessary either, but since the reltablespace and relfilenode can change in normal operation it seems safest to do it. (We don't support changing any of the other info about an index at all, at the moment.) Back-patch as far as 8.0. It might be possible to adapt the patch to 7.4, but it would take more work than I care to expend for such a low-probability problem. 7.3 is out of luck for sure.
1 parent 99e0c54 commit ed69cf5

File tree

1 file changed

+34
-13
lines changed

1 file changed

+34
-13
lines changed

src/backend/utils/cache/relcache.c

+34-13
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.236 2006/01/19 00:27:08 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.237 2006/01/19 20:28:43 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1436,11 +1436,13 @@ RelationClose(Relation relation)
14361436
/*
14371437
* RelationReloadClassinfo - reload the pg_class row (only)
14381438
*
1439-
* This function is used only for nailed indexes. Since a REINDEX can
1440-
* change the relfilenode value for a nailed index, we have to reread
1441-
* the pg_class row anytime we get an SI invalidation on a nailed index
1442-
* (without throwing away the whole relcache entry, since we'd be unable
1443-
* to rebuild it).
1439+
* This function is used only for indexes. We currently allow only the
1440+
* pg_class row of an existing index to change (to support changes of
1441+
* owner, tablespace, or relfilenode), not its pg_index row or other
1442+
* subsidiary index schema information. Therefore it's sufficient to do
1443+
* this when we get an SI invalidation. Furthermore, there are cases
1444+
* where it's necessary not to throw away the index information, especially
1445+
* for "nailed" indexes which we are unable to rebuild on-the-fly.
14441446
*
14451447
* We can't necessarily reread the pg_class row right away; we might be
14461448
* in a failed transaction when we receive the SI notification. If so,
@@ -1455,9 +1457,11 @@ RelationReloadClassinfo(Relation relation)
14551457
HeapTuple pg_class_tuple;
14561458
Form_pg_class relp;
14571459

1458-
/* Should be called only for invalidated nailed indexes */
1459-
Assert(relation->rd_isnailed && !relation->rd_isvalid &&
1460-
relation->rd_rel->relkind == RELKIND_INDEX);
1460+
/* Should be called only for invalidated indexes */
1461+
Assert(relation->rd_rel->relkind == RELKIND_INDEX &&
1462+
!relation->rd_isvalid);
1463+
/* Should be closed at smgr level */
1464+
Assert(relation->rd_smgr == NULL);
14611465

14621466
/*
14631467
* Read the pg_class row
@@ -1468,13 +1472,14 @@ RelationReloadClassinfo(Relation relation)
14681472
indexOK = (RelationGetRelid(relation) != ClassOidIndexId);
14691473
pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK);
14701474
if (!HeapTupleIsValid(pg_class_tuple))
1471-
elog(ERROR, "could not find tuple for system relation %u",
1475+
elog(ERROR, "could not find pg_class tuple for index %u",
14721476
RelationGetRelid(relation));
14731477
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1474-
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
1475-
/* Now we can recalculate physical address */
1476-
RelationInitPhysicalAddr(relation);
1478+
memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
14771479
heap_freetuple(pg_class_tuple);
1480+
/* We must recalculate physical address in case it changed */
1481+
RelationInitPhysicalAddr(relation);
1482+
/* Make sure targblock is reset in case rel was truncated */
14781483
relation->rd_targblock = InvalidBlockNumber;
14791484
/* Okay, now it's valid again */
14801485
relation->rd_isvalid = true;
@@ -1529,6 +1534,22 @@ RelationClearRelation(Relation relation, bool rebuild)
15291534
return;
15301535
}
15311536

1537+
/*
1538+
* Even non-system indexes should not be blown away if they are open and
1539+
* have valid index support information. This avoids problems with active
1540+
* use of the index support information. As with nailed indexes, we
1541+
* re-read the pg_class row to handle possible physical relocation of
1542+
* the index.
1543+
*/
1544+
if (relation->rd_rel->relkind == RELKIND_INDEX &&
1545+
relation->rd_refcnt > 0 &&
1546+
relation->rd_indexcxt != NULL)
1547+
{
1548+
relation->rd_isvalid = false; /* needs to be revalidated */
1549+
RelationReloadClassinfo(relation);
1550+
return;
1551+
}
1552+
15321553
/*
15331554
* Remove relation from hash tables
15341555
*

0 commit comments

Comments
 (0)