Use multi-inserts for pg_ts_config_map

Two locations working on pg_ts_config_map are switched from
CatalogTupleInsert() to a multi-insert approach with tuple slots:
- ALTER TEXT SEARCH CONFIGURATION ADD/ALTER MAPPING when inserting new
entries.  The number of entries to insert is known in advance, so is the
number of slots needed.  Note that CatalogTupleInsertWithInfo() is now
used for the entry updates.
- CREATE TEXT SEARCH CONFIGURATION, where up to ~20-ish records could be
inserted at once.  The number of slots is not known in advance, hence
a slot initialization is delayed until a tuple is stored in it.

Like all the changes of this kind (1ff4161, 63110c6 or e3931d01), an
insert batch is capped at 64kB.

Author: Michael Paquier, Ranier Vilela
Reviewed-by: Kyotaro Horiguchi
Discussion: https://postgr.es/m/Y3M5bovrkTQbAO4W@paquier.xyz
This commit is contained in:
Michael Paquier 2022-11-16 14:32:09 +09:00
parent 36e0358e70
commit 63c833f4bd
1 changed files with 97 additions and 23 deletions

View File

@ -1004,8 +1004,24 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
ScanKeyData skey;
SysScanDesc scan;
HeapTuple maptup;
TupleDesc mapDesc;
TupleTableSlot **slot;
CatalogIndexState indstate;
int max_slots,
slot_init_count,
slot_stored_count;
mapRel = table_open(TSConfigMapRelationId, RowExclusiveLock);
mapDesc = RelationGetDescr(mapRel);
indstate = CatalogOpenIndexes(mapRel);
/*
* Allocate the slots to use, but delay costly initialization until we
* know that they will be used.
*/
max_slots = MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_ts_config_map);
slot = palloc(sizeof(TupleTableSlot *) * max_slots);
ScanKeyInit(&skey,
Anum_pg_ts_config_map_mapcfg,
@ -1015,29 +1031,54 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
NULL, 1, &skey);
/* number of slots currently storing tuples */
slot_stored_count = 0;
/* number of slots currently initialized */
slot_init_count = 0;
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{
Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
HeapTuple newmaptup;
Datum mapvalues[Natts_pg_ts_config_map];
bool mapnulls[Natts_pg_ts_config_map];
memset(mapvalues, 0, sizeof(mapvalues));
memset(mapnulls, false, sizeof(mapnulls));
if (slot_init_count < max_slots)
{
slot[slot_stored_count] = MakeSingleTupleTableSlot(mapDesc,
&TTSOpsHeapTuple);
slot_init_count++;
}
mapvalues[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
mapvalues[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
mapvalues[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
mapvalues[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;
ExecClearTuple(slot[slot_stored_count]);
newmaptup = heap_form_tuple(mapRel->rd_att, mapvalues, mapnulls);
memset(slot[slot_stored_count]->tts_isnull, false,
slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
CatalogTupleInsert(mapRel, newmaptup);
slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;
heap_freetuple(newmaptup);
ExecStoreVirtualTuple(slot[slot_stored_count]);
slot_stored_count++;
/* If slots are full, insert a batch of tuples */
if (slot_stored_count == max_slots)
{
CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count,
indstate);
slot_stored_count = 0;
}
}
/* Insert any tuples left in the buffer */
if (slot_stored_count > 0)
CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count,
indstate);
for (int i = 0; i < slot_init_count; i++)
ExecDropSingleTupleTableSlot(slot[i]);
systable_endscan(scan);
CatalogCloseIndexes(indstate);
}
address = makeConfigurationDependencies(tup, false, mapRel);
@ -1225,6 +1266,7 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
Oid *dictIds;
int ndict;
ListCell *c;
CatalogIndexState indstate;
tsform = (Form_pg_ts_config) GETSTRUCT(tup);
cfgId = tsform->oid;
@ -1275,6 +1317,8 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
i++;
}
indstate = CatalogOpenIndexes(relMap);
if (stmt->replace)
{
/*
@ -1334,7 +1378,7 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
newtup = heap_modify_tuple(maptup,
RelationGetDescr(relMap),
repl_val, repl_null, repl_repl);
CatalogTupleUpdate(relMap, &newtup->t_self, newtup);
CatalogTupleUpdateWithInfo(relMap, &newtup->t_self, newtup, indstate);
}
}
@ -1342,6 +1386,18 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
}
else
{
TupleTableSlot **slot;
int slotCount = 0;
int nslots;
/* Allocate the slots to use and initialize them */
nslots = Min(ntoken * ndict,
MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_ts_config_map));
slot = palloc(sizeof(TupleTableSlot *) * nslots);
for (i = 0; i < nslots; i++)
slot[i] = MakeSingleTupleTableSlot(RelationGetDescr(relMap),
&TTSOpsHeapTuple);
/*
* Insertion of new entries
*/
@ -1349,23 +1405,41 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
{
for (j = 0; j < ndict; j++)
{
Datum values[Natts_pg_ts_config_map];
bool nulls[Natts_pg_ts_config_map];
ExecClearTuple(slot[slotCount]);
memset(nulls, false, sizeof(nulls));
values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgId);
values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(tokens[i]);
values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1);
values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]);
memset(slot[slotCount]->tts_isnull, false,
slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
tup = heap_form_tuple(relMap->rd_att, values, nulls);
CatalogTupleInsert(relMap, tup);
slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgId);
slot[slotCount]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(tokens[i]);
slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1);
slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]);
heap_freetuple(tup);
ExecStoreVirtualTuple(slot[slotCount]);
slotCount++;
/* If slots are full, insert a batch of tuples */
if (slotCount == nslots)
{
CatalogTuplesMultiInsertWithInfo(relMap, slot, slotCount,
indstate);
slotCount = 0;
}
}
}
/* Insert any tuples left in the buffer */
if (slotCount > 0)
CatalogTuplesMultiInsertWithInfo(relMap, slot, slotCount,
indstate);
for (i = 0; i < nslots; i++)
ExecDropSingleTupleTableSlot(slot[i]);
}
/* clean up */
CatalogCloseIndexes(indstate);
EventTriggerCollectAlterTSConfig(stmt, cfgId, dictIds, ndict);
}