diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index c151ad829d..9d2d357233 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -709,12 +709,6 @@ CheckAttributeType(const char *attname, } } -/* - * Cap the maximum amount of bytes allocated for InsertPgAttributeTuples() - * slots. - */ -#define MAX_PGATTRIBUTE_INSERT_BYTES 65535 - /* * InsertPgAttributeTuples * Construct and insert a set of tuples in pg_attribute. @@ -750,7 +744,7 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, /* Initialize the number of slots to use */ nslots = Min(tupdesc->natts, - (MAX_PGATTRIBUTE_INSERT_BYTES / sizeof(FormData_pg_attribute))); + (MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_attribute))); slot = palloc(sizeof(TupleTableSlot *) * nslots); for (int i = 0; i < nslots; i++) slot[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple); diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index f263ff13e5..454e569fa9 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -59,10 +59,11 @@ recordMultipleDependencies(const ObjectAddress *depender, { Relation dependDesc; CatalogIndexState indstate; - HeapTuple tup; - int i; - bool nulls[Natts_pg_depend]; - Datum values[Natts_pg_depend]; + TupleTableSlot **slot; + int i, + max_slots, + slot_init_count, + slot_stored_count; if (nreferenced <= 0) return; /* nothing to do */ @@ -76,11 +77,21 @@ recordMultipleDependencies(const ObjectAddress *depender, dependDesc = table_open(DependRelationId, RowExclusiveLock); + /* + * Allocate the slots to use, but delay costly initialization until we + * know that they will be used. + */ + max_slots = Min(nreferenced, + MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_depend)); + slot = palloc(sizeof(TupleTableSlot *) * max_slots); + /* Don't open indexes unless we need to make an update */ indstate = NULL; - memset(nulls, false, sizeof(nulls)); - + /* number of slots currently storing tuples */ + slot_stored_count = 0; + /* number of slots currently initialized */ + slot_init_count = 0; for (i = 0; i < nreferenced; i++, referenced++) { /* @@ -88,38 +99,69 @@ recordMultipleDependencies(const ObjectAddress *depender, * need to record dependencies on it. This saves lots of space in * pg_depend, so it's worth the time taken to check. */ - if (!isObjectPinned(referenced, dependDesc)) + if (isObjectPinned(referenced, dependDesc)) + continue; + + if (slot_init_count < max_slots) { - /* - * Record the Dependency. Note we don't bother to check for - * duplicate dependencies; there's no harm in them. - */ - values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); - values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); - values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); + slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc), + &TTSOpsHeapTuple); + slot_init_count++; + } - values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); - values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); - values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); + ExecClearTuple(slot[slot_stored_count]); - values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); + /* + * Record the dependency. Note we don't bother to check for duplicate + * dependencies; there's no harm in them. + */ + slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); + slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); + slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); + slot[slot_stored_count]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); + slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); + slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); + slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); - tup = heap_form_tuple(dependDesc->rd_att, values, nulls); + memset(slot[slot_stored_count]->tts_isnull, false, + slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool)); + ExecStoreVirtualTuple(slot[slot_stored_count]); + slot_stored_count++; + + /* If slots are full, insert a batch of tuples */ + if (slot_stored_count == max_slots) + { /* fetch index info only when we know we need it */ if (indstate == NULL) indstate = CatalogOpenIndexes(dependDesc); - CatalogTupleInsertWithInfo(dependDesc, tup, indstate); - - heap_freetuple(tup); + CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count, + indstate); + slot_stored_count = 0; } } + /* Insert any tuples left in the buffer */ + if (slot_stored_count > 0) + { + /* fetch index info only when we know we need it */ + if (indstate == NULL) + indstate = CatalogOpenIndexes(dependDesc); + + CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count, + indstate); + } + if (indstate != NULL) CatalogCloseIndexes(indstate); table_close(dependDesc, RowExclusiveLock); + + /* Drop only the number of slots used */ + for (i = 0; i < slot_init_count; i++) + ExecDropSingleTupleTableSlot(slot[i]); + pfree(slot); } /* diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 30b234e90e..3dd7afd343 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -786,12 +786,6 @@ checkSharedDependencies(Oid classId, Oid objectId, } -/* - * Cap the maximum amount of bytes allocated for copyTemplateDependencies() - * slots. - */ -#define MAX_PGSHDEPEND_INSERT_BYTES 65535 - /* * copyTemplateDependencies * @@ -806,21 +800,20 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) ScanKeyData key[1]; SysScanDesc scan; HeapTuple tup; - int slotCount; CatalogIndexState indstate; TupleTableSlot **slot; - int nslots, - max_slots; - bool slot_init = true; + int max_slots, + slot_init_count, + slot_stored_count; sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); sdepDesc = RelationGetDescr(sdepRel); /* - * Allocate the slots to use, but delay initialization until we know that - * they will be used. + * Allocate the slots to use, but delay costly initialization until we + * know that they will be used. */ - max_slots = MAX_PGSHDEPEND_INSERT_BYTES / sizeof(FormData_pg_shdepend); + max_slots = MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_shdepend); slot = palloc(sizeof(TupleTableSlot *) * max_slots); indstate = CatalogOpenIndexes(sdepRel); @@ -834,6 +827,11 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, NULL, 1, key); + /* number of slots currently storing tuples */ + slot_stored_count = 0; + /* number of slots currently initialized */ + slot_init_count = 0; + /* * Copy the entries of the original database, changing the database Id to * that of the new database. Note that because we are not copying rows @@ -841,41 +839,42 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) * copy the ownership dependency of the template database itself; this is * what we want. */ - slotCount = 0; while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_shdepend shdep; - if (slot_init) - slot[slotCount] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple); + if (slot_init_count < max_slots) + { + slot[slot_stored_count] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple); + slot_init_count++; + } - ExecClearTuple(slot[slotCount]); + ExecClearTuple(slot[slot_stored_count]); shdep = (Form_pg_shdepend) GETSTRUCT(tup); - slot[slotCount]->tts_values[Anum_pg_shdepend_dbid] = ObjectIdGetDatum(newDbId); - slot[slotCount]->tts_values[Anum_pg_shdepend_classid] = shdep->classid; - slot[slotCount]->tts_values[Anum_pg_shdepend_objid] = shdep->objid; - slot[slotCount]->tts_values[Anum_pg_shdepend_objsubid] = shdep->objsubid; - slot[slotCount]->tts_values[Anum_pg_shdepend_refclassid] = shdep->refclassid; - slot[slotCount]->tts_values[Anum_pg_shdepend_refobjid] = shdep->refobjid; - slot[slotCount]->tts_values[Anum_pg_shdepend_deptype] = shdep->deptype; + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_dbid] = ObjectIdGetDatum(newDbId); + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid] = shdep->classid; + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid] = shdep->objid; + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid] = shdep->objsubid; + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid] = shdep->refclassid; + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid] = shdep->refobjid; + slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype] = shdep->deptype; - ExecStoreVirtualTuple(slot[slotCount]); - slotCount++; + ExecStoreVirtualTuple(slot[slot_stored_count]); + slot_stored_count++; /* If slots are full, insert a batch of tuples */ - if (slotCount == max_slots) + if (slot_stored_count == max_slots) { - CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slotCount, indstate); - slotCount = 0; - slot_init = false; + CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate); + slot_stored_count = 0; } } /* Insert any tuples left in the buffer */ - if (slotCount > 0) - CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slotCount, indstate); + if (slot_stored_count > 0) + CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate); systable_endscan(scan); @@ -883,8 +882,7 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) table_close(sdepRel, RowExclusiveLock); /* Drop only the number of slots used */ - nslots = slot_init ? slotCount : max_slots; - for (int i = 0; i < nslots; i++) + for (int i = 0; i < slot_init_count; i++) ExecDropSingleTupleTableSlot(slot[i]); pfree(slot); } diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index a7e2a9b26b..d86729dc6c 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -29,6 +29,12 @@ */ typedef struct ResultRelInfo *CatalogIndexState; +/* + * Cap the maximum amount of bytes allocated for multi-inserts with system + * catalogs, limiting the number of slots used. + */ +#define MAX_CATALOG_MULTI_INSERT_BYTES 65535 + /* * indexing.c prototypes */