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 @@ ...@@ -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, ...@@ -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) ...@@ -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);
heap_close(pg_class_desc, RowExclusiveLock); 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 * DeleteAttributeTuples
* *
* This routine is used to truncate the data from the * Remove pg_attribute rows for the given relid.
* storage manager of any data within the relation handed *
* to this routine. * Note: this is shared by relation deletion and index deletion. It's
* ---------------------------- * not intended for use anyplace else.
*/ */
void void
heap_truncate(Oid rid) DeleteAttributeTuples(Oid relid)
{ {
Relation rel; Relation attrel;
SysScanDesc scan;
/* Open relation for processing, and grab exclusive access on it. */ ScanKeyData key[1];
HeapTuple atttup;
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);
}
/* Grab an appropriate lock on the pg_attribute relation */
attrel = heap_openr(AttributeRelationName, RowExclusiveLock);
/* -------------------------------- /* Use the index to scan only attributes of the target relation */
* DeleteAttributeTuples ScanKeyEntryInitialize(&key[0], 0x0,
* Anum_pg_attribute_attrelid, F_OIDEQ,
* -------------------------------- ObjectIdGetDatum(relid));
*/
static void
DeleteAttributeTuples(Relation rel)
{
Relation pg_attribute_desc;
HeapTuple tup;
int2 attnum;
/* scan = systable_beginscan(attrel, AttributeRelidNumIndex, true,
* open pg_attribute SnapshotNow, 1, key);
*/
pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
for (attnum = FirstLowInvalidHeapAttributeNumber + 1; /* Delete all the matching tuples */
attnum <= rel->rd_att->natts; while ((atttup = systable_getnext(scan)) != NULL)
attnum++)
{ {
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) ...@@ -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) ...@@ -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);
}
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -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,53 +815,27 @@ index_drop(Oid indexId) ...@@ -818,53 +815,27 @@ 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))
elog(ERROR, "index_drop: cache lookup failed for index %u", elog(ERROR, "index_drop: cache lookup failed for index %u",
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);
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -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, ...@@ -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);
......
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