From 739bb4f6e84b937a35b1c76d7c90df5c90ac3cbd Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 3 Sep 2024 17:17:33 +0200 Subject: [PATCH v17.1] Add amgettreeheight index AM API routine The only current implementation is for btree where it calls _bt_getrootheight(). Other index types can now also use this to pass information to their amcostestimate routine. Previously, btree was hardcoded and other index types could not hook into the optimizer at this point. Author: Mark Dilger Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com --- contrib/bloom/blutils.c | 1 + doc/src/sgml/indexam.sgml | 16 ++++++++++++++++ src/backend/access/brin/brin.c | 1 + src/backend/access/gin/ginutil.c | 1 + src/backend/access/gist/gist.c | 1 + src/backend/access/hash/hash.c | 1 + src/backend/access/nbtree/nbtree.c | 10 ++++++++++ src/backend/access/spgist/spgutils.c | 1 + src/backend/optimizer/util/plancat.c | 11 +++++------ src/include/access/amapi.h | 8 ++++++++ src/include/access/nbtree.h | 1 + src/test/modules/dummy_index_am/dummy_index_am.c | 1 + 12 files changed, 47 insertions(+), 6 deletions(-) diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 6836129c90d..a29330afcd3 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -137,6 +137,7 @@ blhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = blvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = blcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = bloptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index e3c1539a1e3..dc7d14b60dd 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -146,6 +146,7 @@ Basic API Structure for Indexes amvacuumcleanup_function amvacuumcleanup; amcanreturn_function amcanreturn; /* can be NULL */ amcostestimate_function amcostestimate; + amgettreeheight_function amgettreeheight; /* can be NULL */ amoptions_function amoptions; amproperty_function amproperty; /* can be NULL */ ambuildphasename_function ambuildphasename; /* can be NULL */ @@ -480,6 +481,21 @@ Index Access Method Functions +int +amgettreeheight (Relation rel); + + Compute the height of a tree-shaped index. This information is supplied to + the amcostestimate function in + path->indexinfo->tree_height and can be used to support + the cost estimation. The result is not used anywhere else, so this + function can actually be used to compute any kind of data (that fits into + an integer) about the index that the cost estimation function might want to + know. If the computation is expensive, it could be useful to cache the + result as part of RelationData.rd_amcache. + + + + bytea * amoptions (ArrayType *reloptions, bool validate); diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6467bed604a..94a8bd07017 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -279,6 +279,7 @@ brinhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = brinvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = brincostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = brinoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 5747ae6a4ca..830d67fbc20 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -69,6 +69,7 @@ ginhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = ginvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = gincostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = ginoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index ed4ffa63a77..2d7a0687d4a 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -91,6 +91,7 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = gistvacuumcleanup; amroutine->amcanreturn = gistcanreturn; amroutine->amcostestimate = gistcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = gistoptions; amroutine->amproperty = gistproperty; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 01d06b7c328..a783b9b4e25 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -89,6 +89,7 @@ hashhandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = hashvacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = hashcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = hashoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 686a3206f72..8cfaab949be 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -133,6 +133,7 @@ bthandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = btvacuumcleanup; amroutine->amcanreturn = btcanreturn; amroutine->amcostestimate = btcostestimate; + amroutine->amgettreeheight = btgettreeheight; amroutine->amoptions = btoptions; amroutine->amproperty = btproperty; amroutine->ambuildphasename = btbuildphasename; @@ -1445,3 +1446,12 @@ btcanreturn(Relation index, int attno) { return true; } + +/* + * btgettreeheight() -- Compute tree height for use by btcostestimate(). + */ +int +btgettreeheight(Relation rel) +{ + return _bt_getrootheight(rel); +} diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 76b80146ff0..72b7661971f 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -76,6 +76,7 @@ spghandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = spgvacuumcleanup; amroutine->amcanreturn = spgcanreturn; amroutine->amcostestimate = spgcostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = spgoptions; amroutine->amproperty = spgproperty; amroutine->ambuildphasename = NULL; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 78a3cfafde4..3f3a5dfae6f 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -485,13 +485,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, info->tuples = rel->tuples; } - if (info->relam == BTREE_AM_OID) + /* + * Get tree height while we have the index open + */ + if (amroutine->amgettreeheight) { - /* - * For btrees, get tree height while we have the index - * open - */ - info->tree_height = _bt_getrootheight(indexRelation); + info->tree_height = amroutine->amgettreeheight(indexRelation); } else { diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index f25c9d58a7d..c51de742ea0 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -140,6 +140,13 @@ typedef void (*amcostestimate_function) (struct PlannerInfo *root, double *indexCorrelation, double *indexPages); +/* estimate height of a tree-structured index + * + * XXX This just computes a value that is later used by amcostestimate. This + * API could be expanded to support passing more values if the need arises. + */ +typedef int (*amgettreeheight_function) (Relation rel); + /* parse index reloptions */ typedef bytea *(*amoptions_function) (Datum reloptions, bool validate); @@ -272,6 +279,7 @@ typedef struct IndexAmRoutine amvacuumcleanup_function amvacuumcleanup; amcanreturn_function amcanreturn; /* can be NULL */ amcostestimate_function amcostestimate; + amgettreeheight_function amgettreeheight; /* can be NULL */ amoptions_function amoptions; amproperty_function amproperty; /* can be NULL */ ambuildphasename_function ambuildphasename; /* can be NULL */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 9af9b3ecdcc..d64300fb973 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -1186,6 +1186,7 @@ extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info, extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats); extern bool btcanreturn(Relation index, int attno); +extern int btgettreeheight(Relation rel); /* * prototypes for internal functions in nbtree.c diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c index 0b477116067..2841cf2eb4b 100644 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@ -308,6 +308,7 @@ dihandler(PG_FUNCTION_ARGS) amroutine->amvacuumcleanup = divacuumcleanup; amroutine->amcanreturn = NULL; amroutine->amcostestimate = dicostestimate; + amroutine->amgettreeheight = NULL; amroutine->amoptions = dioptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; -- 2.46.0