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 * 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 * INTERFACE ROUTINES
@ -66,13 +66,11 @@ static void AddNewRelationTuple(Relation pg_class_desc,
Relation new_rel_desc, Relation new_rel_desc,
Oid new_rel_oid, Oid new_type_oid, Oid new_rel_oid, Oid new_type_oid,
char relkind, bool relhasoids); 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, static void AddNewRelationType(const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid new_rel_oid, Oid new_rel_oid,
Oid new_type_oid); Oid new_type_oid);
static void RelationRemoveInheritance(Relation relation);
static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin); static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin); static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
static void StoreConstraints(Relation rel, TupleDesc tupdesc); static void StoreConstraints(Relation rel, TupleDesc tupdesc);
@ -793,193 +791,72 @@ RelationRemoveInheritance(Relation relation)
/* /*
* DeleteRelationTuple * 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 void
DeleteRelationTuple(Relation rel) DeleteRelationTuple(Oid relid)
{ {
Relation pg_class_desc; Relation pg_class_desc;
HeapTuple tup; HeapTuple tup;
/* /* Grab an appropriate lock on the pg_class relation */
* open pg_class
*/
pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock); pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
tup = SearchSysCacheCopy(RELOID, tup = SearchSysCache(RELOID,
ObjectIdGetDatum(rel->rd_id), ObjectIdGetDatum(relid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "Relation \"%s\" does not exist", elog(ERROR, "DeleteRelationTuple: cache lookup failed for relation %u",
RelationGetRelationName(rel)); 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); simple_heap_delete(pg_class_desc, &tup->t_self);
heap_freetuple(tup);
ReleaseSysCache(tup);
heap_close(pg_class_desc, RowExclusiveLock); 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 * 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 void
DeleteAttributeTuples(Relation rel) DeleteAttributeTuples(Oid relid)
{ {
Relation pg_attribute_desc; Relation attrel;
HeapTuple tup; SysScanDesc scan;
int2 attnum; ScanKeyData key[1];
HeapTuple atttup;
/* /* Grab an appropriate lock on the pg_attribute relation */
* open pg_attribute attrel = heap_openr(AttributeRelationName, RowExclusiveLock);
*/
pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
for (attnum = FirstLowInvalidHeapAttributeNumber + 1; /* Use the index to scan only attributes of the target relation */
attnum <= rel->rd_att->natts; ScanKeyEntryInitialize(&key[0], 0x0,
attnum++) 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, simple_heap_delete(attrel, &atttup->t_self);
ObjectIdGetDatum(RelationGetRelid(rel)),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tup))
{
simple_heap_delete(pg_attribute_desc, &tup->t_self);
heap_freetuple(tup);
}
} }
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 * delete attribute tuples and associated defaults
*/ */
DeleteAttributeTuples(rel); DeleteAttributeTuples(RelationGetRelid(rel));
RemoveDefaults(rel); RemoveDefaults(rel);
/* /*
* delete relation tuple * delete relation tuple
*/ */
DeleteRelationTuple(rel); DeleteRelationTuple(RelationGetRelid(rel));
/* /*
* unlink the relation's physical file and finish up. * unlink the relation's physical file and finish up.
@ -1734,3 +1611,127 @@ RemoveStatistics(Relation rel)
heap_endscan(scan); heap_endscan(scan);
heap_close(pgstatistic, RowExclusiveLock); 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 * 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 * INTERFACE ROUTINES
@ -789,10 +789,7 @@ index_drop(Oid indexId)
Relation userHeapRelation; Relation userHeapRelation;
Relation userIndexRelation; Relation userIndexRelation;
Relation indexRelation; Relation indexRelation;
Relation relationRelation;
Relation attributeRelation;
HeapTuple tuple; HeapTuple tuple;
int16 attnum;
int i; int i;
Assert(OidIsValid(indexId)); Assert(OidIsValid(indexId));
@ -818,45 +815,18 @@ index_drop(Oid indexId)
/* /*
* fix RELATION relation * fix RELATION relation
*/ */
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock); DeleteRelationTuple(indexId);
/* 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);
/* /*
* fix ATTRIBUTE relation * fix ATTRIBUTE relation
*/ */
attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock); DeleteAttributeTuples(indexId);
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);
/* /*
* fix INDEX relation * fix INDEX relation
*/ */
indexRelation = heap_openr(IndexRelationName, RowExclusiveLock); indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(INDEXRELID, tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexId), ObjectIdGetDatum(indexId),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
@ -864,7 +834,8 @@ index_drop(Oid indexId)
indexId); indexId);
simple_heap_delete(indexRelation, &tuple->t_self); simple_heap_delete(indexRelation, &tuple->t_self);
heap_freetuple(tuple);
ReleaseSysCache(tuple);
heap_close(indexRelation, RowExclusiveLock); heap_close(indexRelation, RowExclusiveLock);
/* /*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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, extern int RemoveRelConstraints(Relation rel, const char *constrName,
DropBehavior behavior); DropBehavior behavior);
extern void DeleteRelationTuple(Oid relid);
extern void DeleteAttributeTuples(Oid relid);
extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno,
bool relhasoids); bool relhasoids);