In DeleteAttributeTuples, use a single indexscan instead of the multiple

scans that will most likely be caused by SearchSysCache probes.  Also,
share some code between index deletion and table deletion.
This commit is contained in:
Tom Lane 2002-07-14 21:08:08 +00:00
parent 942a2e94fa
commit df3f5dfd19
3 changed files with 183 additions and 208 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.205 2002/07/12 18:43:13 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.206 2002/07/14 21:08:08 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -66,13 +66,11 @@ static void AddNewRelationTuple(Relation pg_class_desc,
Relation new_rel_desc,
Oid new_rel_oid, Oid new_type_oid,
char relkind, bool relhasoids);
static void DeleteAttributeTuples(Relation rel);
static void DeleteRelationTuple(Relation rel);
static void RelationRemoveInheritance(Relation relation);
static void AddNewRelationType(const char *typeName,
Oid typeNamespace,
Oid new_rel_oid,
Oid new_type_oid);
static void RelationRemoveInheritance(Relation relation);
static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
static void StoreConstraints(Relation rel, TupleDesc tupdesc);
@ -793,193 +791,72 @@ RelationRemoveInheritance(Relation relation)
/*
* DeleteRelationTuple
*
* Remove pg_class row for the given relid.
*
* Note: this is shared by relation deletion and index deletion. It's
* not intended for use anyplace else.
*/
static void
DeleteRelationTuple(Relation rel)
void
DeleteRelationTuple(Oid relid)
{
Relation pg_class_desc;
HeapTuple tup;
/*
* open pg_class
*/
/* Grab an appropriate lock on the pg_class relation */
pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
tup = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(rel->rd_id),
0, 0, 0);
tup = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "Relation \"%s\" does not exist",
RelationGetRelationName(rel));
elog(ERROR, "DeleteRelationTuple: cache lookup failed for relation %u",
relid);
/*
* delete the relation tuple from pg_class, and finish up.
*/
/* delete the relation tuple from pg_class, and finish up */
simple_heap_delete(pg_class_desc, &tup->t_self);
heap_freetuple(tup);
ReleaseSysCache(tup);
heap_close(pg_class_desc, RowExclusiveLock);
}
/* --------------------------------
* 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 heapId parameter.
* --------------------------------
*/
static void
RelationTruncateIndexes(Oid heapId)
{
Relation indexRelation;
ScanKeyData entry;
SysScanDesc scan;
HeapTuple indexTuple;
/* 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 = systable_beginscan(indexRelation, IndexIndrelidIndex, true,
SnapshotNow, 1, &entry);
while (HeapTupleIsValid(indexTuple = systable_getnext(scan)))
{
Form_pg_index indexform = (Form_pg_index) GETSTRUCT(indexTuple);
Oid indexId;
IndexInfo *indexInfo;
Relation heapRelation,
currentIndex;
/*
* For each index, fetch info needed for index_build
*/
indexId = indexform->indexrelid;
indexInfo = BuildIndexInfo(indexform);
/*
* 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);
/* Obtain exclusive lock on it, just to be sure */
LockRelation(currentIndex, AccessExclusiveLock);
/*
* Drop any buffers associated with this index. If they're dirty,
* they're just dropped without bothering to flush to disk.
*/
DropRelationBuffers(currentIndex);
/* Now truncate the actual data and set blocks to zero */
smgrtruncate(DEFAULT_SMGR, currentIndex, 0);
currentIndex->rd_nblocks = 0;
currentIndex->rd_targblock = InvalidBlockNumber;
/* Initialize the index and rebuild */
index_build(heapRelation, currentIndex, indexInfo);
/*
* index_build will close both the heap and index relations (but
* not give up the locks we hold on them).
*/
}
/* Complete the scan and close pg_index */
systable_endscan(scan);
heap_close(indexRelation, AccessShareLock);
}
/* ----------------------------
* heap_truncate
*
* This routine is used to truncate the data from the
* storage manager of any data within the relation handed
* to this routine.
* ----------------------------
*/
void
heap_truncate(Oid rid)
{
Relation rel;
/* Open relation for processing, and grab exclusive access on it. */
rel = heap_open(rid, AccessExclusiveLock);
/*
* TRUNCATE TABLE within a transaction block is dangerous, because if
* the transaction is later rolled back we have no way to undo
* truncation of the relation's physical file. Disallow it except for
* a rel created in the current xact (which would be deleted on abort,
* anyway).
*/
if (IsTransactionBlock() && !rel->rd_myxactonly)
elog(ERROR, "TRUNCATE TABLE cannot run inside a transaction block");
/*
* Release any buffers associated with this relation. If they're
* dirty, they're just dropped without bothering to flush to disk.
*/
DropRelationBuffers(rel);
/* Now truncate the actual data and set blocks to zero */
smgrtruncate(DEFAULT_SMGR, rel, 0);
rel->rd_nblocks = 0;
rel->rd_targblock = InvalidBlockNumber;
/* If this relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rid);
/*
* Close the relation, but keep exclusive lock on it until commit.
*/
heap_close(rel, NoLock);
}
/* --------------------------------
/*
* DeleteAttributeTuples
*
* --------------------------------
* Remove pg_attribute rows for the given relid.
*
* Note: this is shared by relation deletion and index deletion. It's
* not intended for use anyplace else.
*/
static void
DeleteAttributeTuples(Relation rel)
void
DeleteAttributeTuples(Oid relid)
{
Relation pg_attribute_desc;
HeapTuple tup;
int2 attnum;
Relation attrel;
SysScanDesc scan;
ScanKeyData key[1];
HeapTuple atttup;
/*
* open pg_attribute
*/
pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
/* Grab an appropriate lock on the pg_attribute relation */
attrel = heap_openr(AttributeRelationName, RowExclusiveLock);
for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
attnum <= rel->rd_att->natts;
attnum++)
/* Use the index to scan only attributes of the target relation */
ScanKeyEntryInitialize(&key[0], 0x0,
Anum_pg_attribute_attrelid, F_OIDEQ,
ObjectIdGetDatum(relid));
scan = systable_beginscan(attrel, AttributeRelidNumIndex, true,
SnapshotNow, 1, key);
/* Delete all the matching tuples */
while ((atttup = systable_getnext(scan)) != NULL)
{
tup = SearchSysCacheCopy(ATTNUM,
ObjectIdGetDatum(RelationGetRelid(rel)),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tup))
{
simple_heap_delete(pg_attribute_desc, &tup->t_self);
heap_freetuple(tup);
}
simple_heap_delete(attrel, &atttup->t_self);
}
heap_close(pg_attribute_desc, RowExclusiveLock);
/* Clean up after the scan */
systable_endscan(scan);
heap_close(attrel, RowExclusiveLock);
}
/* ----------------------------------------------------------------
@ -1033,14 +910,14 @@ heap_drop_with_catalog(Oid rid)
/*
* delete attribute tuples and associated defaults
*/
DeleteAttributeTuples(rel);
DeleteAttributeTuples(RelationGetRelid(rel));
RemoveDefaults(rel);
/*
* delete relation tuple
*/
DeleteRelationTuple(rel);
DeleteRelationTuple(RelationGetRelid(rel));
/*
* unlink the relation's physical file and finish up.
@ -1734,3 +1611,127 @@ RemoveStatistics(Relation rel)
heap_endscan(scan);
heap_close(pgstatistic, RowExclusiveLock);
}
/*
* RelationTruncateIndexes - 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 heapId parameter.
*/
static void
RelationTruncateIndexes(Oid heapId)
{
Relation indexRelation;
ScanKeyData entry;
SysScanDesc scan;
HeapTuple indexTuple;
/* 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 = systable_beginscan(indexRelation, IndexIndrelidIndex, true,
SnapshotNow, 1, &entry);
while (HeapTupleIsValid(indexTuple = systable_getnext(scan)))
{
Form_pg_index indexform = (Form_pg_index) GETSTRUCT(indexTuple);
Oid indexId;
IndexInfo *indexInfo;
Relation heapRelation,
currentIndex;
/*
* For each index, fetch info needed for index_build
*/
indexId = indexform->indexrelid;
indexInfo = BuildIndexInfo(indexform);
/*
* 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);
/* Obtain exclusive lock on it, just to be sure */
LockRelation(currentIndex, AccessExclusiveLock);
/*
* Drop any buffers associated with this index. If they're dirty,
* they're just dropped without bothering to flush to disk.
*/
DropRelationBuffers(currentIndex);
/* Now truncate the actual data and set blocks to zero */
smgrtruncate(DEFAULT_SMGR, currentIndex, 0);
currentIndex->rd_nblocks = 0;
currentIndex->rd_targblock = InvalidBlockNumber;
/* Initialize the index and rebuild */
index_build(heapRelation, currentIndex, indexInfo);
/*
* index_build will close both the heap and index relations (but
* not give up the locks we hold on them).
*/
}
/* Complete the scan and close pg_index */
systable_endscan(scan);
heap_close(indexRelation, AccessShareLock);
}
/*
* heap_truncate
*
* This routine is used to truncate the data from the
* storage manager of any data within the relation handed
* to this routine.
*/
void
heap_truncate(Oid rid)
{
Relation rel;
/* Open relation for processing, and grab exclusive access on it. */
rel = heap_open(rid, AccessExclusiveLock);
/*
* TRUNCATE TABLE within a transaction block is dangerous, because if
* the transaction is later rolled back we have no way to undo
* truncation of the relation's physical file. Disallow it except for
* a rel created in the current xact (which would be deleted on abort,
* anyway).
*/
if (IsTransactionBlock() && !rel->rd_myxactonly)
elog(ERROR, "TRUNCATE TABLE cannot run inside a transaction block");
/*
* Release any buffers associated with this relation. If they're
* dirty, they're just dropped without bothering to flush to disk.
*/
DropRelationBuffers(rel);
/* Now truncate the actual data and set blocks to zero */
smgrtruncate(DEFAULT_SMGR, rel, 0);
rel->rd_nblocks = 0;
rel->rd_targblock = InvalidBlockNumber;
/* If this relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rid);
/*
* Close the relation, but keep exclusive lock on it until commit.
*/
heap_close(rel, NoLock);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.182 2002/07/12 18:43:13 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.183 2002/07/14 21:08:08 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -789,10 +789,7 @@ index_drop(Oid indexId)
Relation userHeapRelation;
Relation userIndexRelation;
Relation indexRelation;
Relation relationRelation;
Relation attributeRelation;
HeapTuple tuple;
int16 attnum;
int i;
Assert(OidIsValid(indexId));
@ -818,53 +815,27 @@ index_drop(Oid indexId)
/*
* fix RELATION relation
*/
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
/* Remove the pg_class tuple for the index itself */
tuple = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(indexId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "index_drop: cache lookup failed for index %u",
indexId);
simple_heap_delete(relationRelation, &tuple->t_self);
heap_freetuple(tuple);
heap_close(relationRelation, RowExclusiveLock);
DeleteRelationTuple(indexId);
/*
* fix ATTRIBUTE relation
*/
attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
attnum = 1; /* indexes start at 1 */
while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
ObjectIdGetDatum(indexId),
Int16GetDatum(attnum),
0, 0)))
{
simple_heap_delete(attributeRelation, &tuple->t_self);
heap_freetuple(tuple);
attnum++;
}
heap_close(attributeRelation, RowExclusiveLock);
DeleteAttributeTuples(indexId);
/*
* fix INDEX relation
*/
indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(INDEXRELID,
ObjectIdGetDatum(indexId),
0, 0, 0);
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "index_drop: cache lookup failed for index %u",
indexId);
simple_heap_delete(indexRelation, &tuple->t_self);
heap_freetuple(tuple);
ReleaseSysCache(tuple);
heap_close(indexRelation, RowExclusiveLock);
/*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: heap.h,v 1.52 2002/07/12 18:43:19 tgl Exp $
* $Id: heap.h,v 1.53 2002/07/14 21:08:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -61,6 +61,9 @@ extern Node *cookDefault(ParseState *pstate,
extern int RemoveRelConstraints(Relation rel, const char *constrName,
DropBehavior behavior);
extern void DeleteRelationTuple(Oid relid);
extern void DeleteAttributeTuples(Oid relid);
extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno,
bool relhasoids);