v32-0017-tidstore-vacuum-Specify-the-init-and-max-DSA-seg.patch
application/octet-stream
Filename: v32-0017-tidstore-vacuum-Specify-the-init-and-max-DSA-seg.patch
Type: application/octet-stream
Part: 4
Patch
Format: format-patch
Series: patch v32-0017
Subject: tidstore, vacuum: Specify the init and max DSA segment size based on m_w_m
| File | + | − |
|---|---|---|
| src/backend/access/common/tidstore.c | 6 | 26 |
| src/backend/commands/vacuumparallel.c | 17 | 4 |
From 11fda58f829c03d2a7c6476affc61862a078f741 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Mon, 17 Apr 2023 22:27:04 +0900
Subject: [PATCH v32 17/18] tidstore, vacuum: Specify the init and max DSA
segment size based on m_w_m
---
src/backend/access/common/tidstore.c | 32 +++++----------------------
src/backend/commands/vacuumparallel.c | 21 ++++++++++++++----
2 files changed, 23 insertions(+), 30 deletions(-)
diff --git a/src/backend/access/common/tidstore.c b/src/backend/access/common/tidstore.c
index 9360520482..571d15c5c3 100644
--- a/src/backend/access/common/tidstore.c
+++ b/src/backend/access/common/tidstore.c
@@ -180,39 +180,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 +199,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);
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index 8385d375db..17699aa007 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -252,6 +252,8 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes,
Size est_indstats_len;
Size est_shared_len;
Size dsa_minsize = dsa_minimum_size();
+ Size init_segsize;
+ Size max_segsize;
int nindexes_mwm = 0;
int parallel_workers = 0;
int querylen;
@@ -367,12 +369,23 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes,
shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_INDEX_STATS, indstats);
pvs->indstats = indstats;
- /* Prepare DSA space for dead items */
+ /*
+ * Prepare DSA space for dead items.
+ *
+ * Since total DSA size grows while following a geometric series by default,
+ * we specify both the initial DSA segment and maximum DSA segment sizes
+ * based on the memory available for parallel vacuum. Typically, the initial
+ * segment size is 1MB and the maximum segment size is vac_work_mem / 8, and
+ * heap scan stops after allocating 1.125 times more memory than vac_work_mem.
+ */
+ init_segsize = Min(vac_work_mem / 4, (1024 * 1024));
+ max_segsize = Max(vac_work_mem / 8, (8 * 1024 * 1024));
area_space = shm_toc_allocate(pcxt->toc, dsa_minsize);
shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_DEAD_ITEMS, area_space);
- dead_items_dsa = dsa_create_in_place(area_space, dsa_minsize,
- LWTRANCHE_PARALLEL_VACUUM_DSA,
- pcxt->seg);
+ dead_items_dsa = dsa_create_in_place_extended(area_space, dsa_minsize,
+ LWTRANCHE_PARALLEL_VACUUM_DSA,
+ pcxt->seg,
+ init_segsize, max_segsize);
dead_items = TidStoreCreate(vac_work_mem, max_offset, dead_items_dsa);
pvs->dead_items = dead_items;
pvs->dead_items_area = dead_items_dsa;
--
2.31.1