From df3f5dfd194a837dc430c3a70bfc527b979935b3 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 14 Jul 2002 21:08:08 +0000 Subject: [PATCH] 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. --- src/backend/catalog/heap.c | 341 ++++++++++++++++++------------------ src/backend/catalog/index.c | 45 +---- src/include/catalog/heap.h | 5 +- 3 files changed, 183 insertions(+), 208 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 207090ae70..48f7cae1aa 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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); +} diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 30cef89fef..996fb80a7c 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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); /* diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 5cf87e2631..44c8e13bf6 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -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);