0001-WIP-cache-bound-offset-adaptively_v4.patch
application/octet-stream
Filename: 0001-WIP-cache-bound-offset-adaptively_v4.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v4-0001
Subject: cache-bound-offset_v3_modify
| File | + | − |
|---|---|---|
| src/backend/executor/execPartition.c | 125 | 24 |
| src/backend/partitioning/partdesc.c | 2 | 0 |
| src/include/partitioning/partdesc.h | 3 | 0 |
From 7d0bd28f75cf2b26706fe5cc8473aa01950286cb Mon Sep 17 00:00:00 2001
From: "houzj.fnst" <houzj.fnst@cn.fujitsu.com>
Date: Mon, 7 Jun 2021 18:57:14 +0800
Subject: [PATCH] cache-bound-offset_v3_modify
---
src/backend/executor/execPartition.c | 149 ++++++++++++++++++++++-----
src/backend/partitioning/partdesc.c | 2 +
src/include/partitioning/partdesc.h | 3 +
3 files changed, 130 insertions(+), 24 deletions(-)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 606c920b06..122d330a1d 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -150,9 +150,15 @@ typedef struct PartitionDispatchData
PartitionDesc partdesc;
TupleTableSlot *tupslot;
AttrMap *tupmap;
+
+ short ntupinserts;
+ short npartchanges;
+ bool force;
+ bool check_cached;
int indexes[FLEXIBLE_ARRAY_MEMBER];
} PartitionDispatchData;
+#define RECHECK_BOUND_CACHE_THRESHOLD 1000
static ResultRelInfo *ExecInitPartitionInfo(ModifyTableState *mtstate,
EState *estate, PartitionTupleRouting *proute,
@@ -176,7 +182,7 @@ static void FormPartitionKeyDatum(PartitionDispatch pd,
Datum *values,
bool *isnull);
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values,
- bool *isnull);
+ bool *isnull, bool check_cached);
static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
Datum *values,
bool *isnull,
@@ -305,12 +311,23 @@ ExecFindPartition(ModifyTableState *mtstate,
ecxt->ecxt_scantuple = slot;
FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
+ if (dispatch->ntupinserts > RECHECK_BOUND_CACHE_THRESHOLD &&
+ !dispatch->force)
+ {
+ if (dispatch->npartchanges == 0)
+ dispatch->check_cached = true;
+ else
+ dispatch->check_cached = ((dispatch->ntupinserts/dispatch->npartchanges) > 1);
+ dispatch->ntupinserts = dispatch->npartchanges = 0;
+ }
+
/*
* If this partitioned table has no partitions or no partition for
* these values, error out.
*/
if (partdesc->nparts == 0 ||
- (partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
+ (partidx = get_partition_for_tuple(dispatch, values, isnull,
+ dispatch->check_cached)) < 0)
{
char *val_desc;
@@ -1026,6 +1043,12 @@ ExecInitPartitionDispatchInfo(EState *estate,
pd->key = RelationGetPartitionKey(rel);
pd->keystate = NIL;
pd->partdesc = partdesc;
+ pd->ntupinserts = 0;
+ pd->npartchanges = 0;
+ partdesc->cached_bound_offset = -1;
+
+ pd->check_cached = false;
+
if (parent_pd != NULL)
{
TupleDesc tupdesc = RelationGetDescr(rel);
@@ -1236,11 +1259,16 @@ FormPartitionKeyDatum(PartitionDispatch pd,
* Finds partition of relation which accepts the partition key specified
* in values and isnull
*
+ * If check_cached is true, this short-circuits a full-blown search across all
+ * the bounds, instead checking the tuple against the bound whose offset is
+ * cached in pd->partdesc.
+ *
* Return value is index of the partition (>= 0 and < partdesc->nparts) if one
* found or -1 if none found.
*/
static int
-get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
+get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull,
+ bool check_cached)
{
int bound_offset;
int part_index = -1;
@@ -1248,10 +1276,18 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
PartitionDesc partdesc = pd->partdesc;
PartitionBoundInfo boundinfo = partdesc->boundinfo;
+ /*
+ * If the cached bound offset is valid, we check below if the that bound
+ * is satisfied by the new tuple. If it is, there's no need to perform a
+ * search across all bounds.
+ */
+ int cached_off = partdesc->cached_bound_offset;
+
/* Route as appropriate based on partitioning strategy. */
switch (key->strategy)
{
case PARTITION_STRATEGY_HASH:
+ Assert(cached_off < 0);
{
uint64 rowHash;
@@ -1265,6 +1301,7 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
break;
case PARTITION_STRATEGY_LIST:
+ pd->ntupinserts++;
if (isnull[0])
{
if (partition_bound_accepts_nulls(boundinfo))
@@ -1272,14 +1309,37 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
}
else
{
- bool equal = false;
-
- bound_offset = partition_list_bsearch(key->partsupfunc,
- key->partcollation,
- boundinfo,
- values[0], &equal);
- if (bound_offset >= 0 && equal)
- part_index = boundinfo->indexes[bound_offset];
+ if (cached_off >= 0 && check_cached)
+ {
+ Datum bound_datum = boundinfo->datums[cached_off][0];
+ int32 cmpval;
+
+ cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
+ key->partcollation[0],
+ bound_datum,
+ values[0]));
+ if (cmpval == 0)
+ part_index = boundinfo->indexes[cached_off];
+ }
+
+ if (part_index < 0)
+ {
+ bool equal = false;
+
+ bound_offset = partition_list_bsearch(key->partsupfunc,
+ key->partcollation,
+ boundinfo,
+ values[0], &equal);
+ if (bound_offset >= 0 && equal)
+ {
+ part_index = boundinfo->indexes[bound_offset];
+ if (cached_off != bound_offset)
+ {
+ pd->npartchanges++;
+ partdesc->cached_bound_offset = bound_offset;
+ }
+ }
+ }
}
break;
@@ -1289,6 +1349,7 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
range_partkey_has_null = false;
int i;
+ pd->ntupinserts++;
/*
* No range includes NULL, so this will be accepted by the
* default partition if there is one, and otherwise rejected.
@@ -1304,20 +1365,60 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
if (!range_partkey_has_null)
{
- bound_offset = partition_range_datum_bsearch(key->partsupfunc,
- key->partcollation,
- boundinfo,
- key->partnatts,
- values,
- &equal);
+ if (cached_off >= 0 && check_cached)
+ {
+ Datum *bound_datums = boundinfo->datums[cached_off];
+ PartitionRangeDatumKind *bound_kind = boundinfo->kind[cached_off];
+ int32 cmpval;
+
+ /* Check if the value is above the low bound */
+ cmpval = partition_rbound_datum_cmp(key->partsupfunc,
+ key->partcollation,
+ bound_datums,
+ bound_kind,
+ values,
+ key->partnatts);
+ if (cmpval == 0)
+ part_index = boundinfo->indexes[cached_off + 1];
+ else if (cmpval < 0 && cached_off + 1 < boundinfo->ndatums)
+ {
+ /* Check if the value is below the high bound */
+ bound_datums = boundinfo->datums[cached_off + 1];
+ bound_kind = boundinfo->kind[cached_off + 1];
+ cmpval = partition_rbound_datum_cmp(key->partsupfunc,
+ key->partcollation,
+ bound_datums,
+ bound_kind,
+ values,
+ key->partnatts);
+
+ if (cmpval > 0)
+ part_index = boundinfo->indexes[cached_off + 1];
+ }
+ }
- /*
- * The bound at bound_offset is less than or equal to the
- * tuple value, so the bound at offset+1 is the upper
- * bound of the partition we're looking for, if there
- * actually exists one.
- */
- part_index = boundinfo->indexes[bound_offset + 1];
+ if (part_index < 0)
+ {
+ bound_offset = partition_range_datum_bsearch(key->partsupfunc,
+ key->partcollation,
+ boundinfo,
+ key->partnatts,
+ values,
+ &equal);
+
+ /*
+ * The bound at bound_offset is less than or equal to the
+ * tuple value, so the bound at offset+1 is the upper
+ * bound of the partition we're looking for, if there
+ * actually exists one.
+ */
+ part_index = boundinfo->indexes[bound_offset + 1];
+ if (cached_off != bound_offset)
+ {
+ pd->npartchanges++;
+ partdesc->cached_bound_offset = bound_offset;
+ }
+ }
}
}
break;
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index 9a9d6a9643..e6ec01de71 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -285,6 +285,8 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached)
MemoryContextAllocZero(new_pdcxt, sizeof(PartitionDescData));
partdesc->nparts = nparts;
partdesc->detached_exist = detached_exist;
+ partdesc->cached_bound_offset = -1;
+
/* If there are no partitions, the rest of the partdesc can stay zero */
if (nparts > 0)
{
diff --git a/src/include/partitioning/partdesc.h b/src/include/partitioning/partdesc.h
index 0792f48507..9df28ae14f 100644
--- a/src/include/partitioning/partdesc.h
+++ b/src/include/partitioning/partdesc.h
@@ -36,6 +36,9 @@ typedef struct PartitionDescData
* the corresponding 'oids' element belongs to
* a leaf partition or not */
PartitionBoundInfo boundinfo; /* collection of partition bounds */
+ int cached_bound_offset; /* offset of the bound datum most
+ * recently chosen by
+ * get_partition_for_tuple() */
} PartitionDescData;
--
2.18.4