From e86e43b93fb901aacd8d2b69aa53ad896c5b5e1c Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Wed, 8 Mar 2023 15:08:58 +0900 Subject: [PATCH v31 11/14] Remove the max memory deduction from TidStore. --- src/backend/access/common/tidstore.c | 43 +++++++--------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/backend/access/common/tidstore.c b/src/backend/access/common/tidstore.c index 9360520482..ee73759648 100644 --- a/src/backend/access/common/tidstore.c +++ b/src/backend/access/common/tidstore.c @@ -82,6 +82,7 @@ typedef uint64 offsetbm; #define RT_SCOPE static #define RT_DECLARE #define RT_DEFINE +#define RT_MEASURE_MEMORY_USAGE #define RT_VALUE_TYPE tidkey #include "lib/radixtree.h" @@ -90,6 +91,7 @@ typedef uint64 offsetbm; #define RT_SCOPE static #define RT_DECLARE #define RT_DEFINE +#define RT_MEASURE_MEMORY_USAGE #define RT_VALUE_TYPE tidkey #include "lib/radixtree.h" @@ -180,39 +182,15 @@ TidStoreCreate(size_t max_bytes, int max_off, dsa_area *area) ts = palloc0(sizeof(TidStore)); - /* - * Create the radix tree for the main storage. - * - * Memory consumption depends on the number of stored tids, but also on the - * distribution of them, how the radix tree stores, and the memory management - * that backed the radix tree. The maximum bytes that a TidStore can - * use is specified by the max_bytes in TidStoreCreate(). We want the total - * amount of memory consumption by a TidStore not to exceed the max_bytes. - * - * In local TidStore cases, the radix tree uses slab allocators for each kind - * of node class. The most memory consuming case while adding Tids associated - * with one page (i.e. during TidStoreSetBlockOffsets()) is that we allocate a new - * slab block for a new radix tree node, which is approximately 70kB. Therefore, - * we deduct 70kB from the max_bytes. - * - * In shared cases, DSA allocates the memory segments big enough to follow - * a geometric series that approximately doubles the total DSA size (see - * make_new_segment() in dsa.c). We simulated the how DSA increases segment - * size and the simulation revealed, the 75% threshold for the maximum bytes - * perfectly works in case where the max_bytes is a power-of-2, and the 60% - * threshold works for other cases. - */ if (area != NULL) { dsa_pointer dp; - float ratio = ((max_bytes & (max_bytes - 1)) == 0) ? 0.75 : 0.6; ts->tree.shared = shared_rt_create(CurrentMemoryContext, area, LWTRANCHE_SHARED_TIDSTORE); dp = dsa_allocate0(area, sizeof(TidStoreControl)); ts->control = (TidStoreControl *) dsa_get_address(area, dp); - ts->control->max_bytes = (size_t) (max_bytes * ratio); ts->area = area; ts->control->magic = TIDSTORE_MAGIC; @@ -223,11 +201,15 @@ TidStoreCreate(size_t max_bytes, int max_off, dsa_area *area) else { ts->tree.local = local_rt_create(CurrentMemoryContext); - ts->control = (TidStoreControl *) palloc0(sizeof(TidStoreControl)); - ts->control->max_bytes = max_bytes - (70 * 1024); } + /* + * max_bytes is forced to be at least 64KB, the current minimum valid value + * for the work_mem GUC. + */ + ts->control->max_bytes = Max(64 * 1024L, max_bytes); + ts->control->max_off = max_off; ts->control->max_off_nbits = pg_ceil_log2_32(max_off); @@ -331,14 +313,8 @@ TidStoreReset(TidStore *ts) LWLockAcquire(&ts->control->lock, LW_EXCLUSIVE); - /* - * Free the radix tree and return allocated DSA segments to - * the operating system. - */ - shared_rt_free(ts->tree.shared); - dsa_trim(ts->area); - /* Recreate the radix tree */ + shared_rt_free(ts->tree.shared); ts->tree.shared = shared_rt_create(CurrentMemoryContext, ts->area, LWTRANCHE_SHARED_TIDSTORE); @@ -352,6 +328,7 @@ TidStoreReset(TidStore *ts) } else { + /* Recreate the radix tree */ local_rt_free(ts->tree.local); ts->tree.local = local_rt_create(CurrentMemoryContext); -- 2.31.1