Commit df3f5dfd authored by Tom Lane's avatar Tom Lane

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.
parent 942a2e94
......@@ -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);
heap_close(pg_class_desc, RowExclusiveLock);
}
ReleaseSysCache(tup);
/* --------------------------------
* 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_close(pg_class_desc, RowExclusiveLock);
}
/* ----------------------------
* heap_truncate
/*
* DeleteAttributeTuples
*
* This routine is used to truncate the data from the
* storage manager of any data within the relation handed
* to this routine.
* ----------------------------
* 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.
*/
void
heap_truncate(Oid rid)
DeleteAttributeTuples(Oid relid)
{
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);
}
Relation attrel;
SysScanDesc scan;
ScanKeyData key[1];
HeapTuple atttup;
/* Grab an appropriate lock on the pg_attribute relation */
attrel = heap_openr(AttributeRelationName, RowExclusiveLock);
/* --------------------------------
* DeleteAttributeTuples
*
* --------------------------------
*/
static void
DeleteAttributeTuples(Relation rel)
{
Relation pg_attribute_desc;
HeapTuple tup;
int2 attnum;
/* Use the index to scan only attributes of the target relation */
ScanKeyEntryInitialize(&key[0], 0x0,
Anum_pg_attribute_attrelid, F_OIDEQ,
ObjectIdGetDatum(relid));
/*
* open pg_attribute
*/
pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
scan = systable_beginscan(attrel, AttributeRelidNumIndex, true,
SnapshotNow, 1, key);
for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
attnum <= rel->rd_att->natts;
attnum++)
/* 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);
}
......@@ -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);
/*
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment