Fix nasty TRUNCATE bug reported by Darrin Ladd. RelationTruncateIndexes
would close and then re-open rel being truncated. Depending on the luck of the draw, the re-opened relcache entry might or might not be at the same physical location as before. Unfortunately, if it wasn't then heap_truncate would crash and burn, because it still had a pointer at the old location. Fix is to open and then close rel in RelationTruncateIndexes, so that rel's refcount never goes to zero until heap_truncate is done.
This commit is contained in:
parent
0ba77c14aa
commit
36786a8150
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.145 2000/09/29 18:21:25 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.146 2000/09/30 18:28:53 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -1064,32 +1064,32 @@ DeleteRelationTuple(Relation rel)
|
||||
* RelationTruncateIndexes - This routine is used to truncate all
|
||||
* indices associated with the heap relation to zero tuples.
|
||||
* The routine will truncate and then reconstruct the indices on
|
||||
* the relation specified by the heapRelation parameter.
|
||||
* the relation specified by the heapId parameter.
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
RelationTruncateIndexes(Relation heapRelation)
|
||||
RelationTruncateIndexes(Oid heapId)
|
||||
{
|
||||
Relation indexRelation,
|
||||
currentIndex;
|
||||
Relation indexRelation;
|
||||
ScanKeyData entry;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple indexTuple,
|
||||
classTuple;
|
||||
IndexInfo *indexInfo;
|
||||
Oid heapId,
|
||||
indexId,
|
||||
accessMethodId;
|
||||
HeapTuple indexTuple;
|
||||
|
||||
heapId = RelationGetRelid(heapRelation);
|
||||
|
||||
/* Scan pg_index to find indexes on heapRelation */
|
||||
/* Scan pg_index to find indexes on specified heap */
|
||||
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
|
||||
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
|
||||
ObjectIdGetDatum(heapId));
|
||||
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
|
||||
|
||||
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
Oid indexId,
|
||||
accessMethodId;
|
||||
IndexInfo *indexInfo;
|
||||
HeapTuple classTuple;
|
||||
Relation heapRelation,
|
||||
currentIndex;
|
||||
|
||||
/*
|
||||
* For each index, fetch info needed for index_build
|
||||
*/
|
||||
@ -1105,10 +1105,16 @@ RelationTruncateIndexes(Relation heapRelation)
|
||||
indexId);
|
||||
accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
|
||||
|
||||
/*
|
||||
* We have to re-open the heap rel each time through this loop
|
||||
* because index_build will close it again. We need grab no lock,
|
||||
* however, because we assume heap_truncate is holding an exclusive
|
||||
* lock on the heap rel.
|
||||
*/
|
||||
heapRelation = heap_open(heapId, NoLock);
|
||||
|
||||
/* Open the index relation */
|
||||
currentIndex = index_open(indexId);
|
||||
if (currentIndex == NULL)
|
||||
elog(ERROR, "RelationTruncateIndexes: can't open index relation");
|
||||
|
||||
/* Obtain exclusive lock on it, just to be sure */
|
||||
LockRelation(currentIndex, AccessExclusiveLock);
|
||||
@ -1127,15 +1133,10 @@ RelationTruncateIndexes(Relation heapRelation)
|
||||
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
|
||||
currentIndex, accessMethodId);
|
||||
index_build(heapRelation, currentIndex, indexInfo, NULL);
|
||||
|
||||
/*
|
||||
* index_build will close both the heap and index relations (but
|
||||
* not give up the locks we hold on them). That's fine for the
|
||||
* index, but we need to open the heap again. We need no new
|
||||
* lock, since this backend still has the exclusive lock grabbed
|
||||
* by heap_truncate.
|
||||
* not give up the locks we hold on them).
|
||||
*/
|
||||
heapRelation = heap_open(heapId, NoLock);
|
||||
}
|
||||
|
||||
/* Complete the scan and close pg_index */
|
||||
@ -1191,17 +1192,12 @@ heap_truncate(char *relname)
|
||||
rel->rd_nblocks = 0;
|
||||
|
||||
/* If this relation has indexes, truncate the indexes too */
|
||||
RelationTruncateIndexes(rel);
|
||||
RelationTruncateIndexes(rid);
|
||||
|
||||
/*
|
||||
* Close the relation, but keep exclusive lock on it until commit.
|
||||
*/
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
* Is this really necessary?
|
||||
*/
|
||||
RelationForgetRelation(rid);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user