aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/tidstore.c107
-rw-r--r--src/include/access/tidstore.h7
-rw-r--r--src/test/modules/test_tidstore/test_tidstore.c14
3 files changed, 89 insertions, 39 deletions
diff --git a/src/backend/access/common/tidstore.c b/src/backend/access/common/tidstore.c
index f79141590ed..e1a7e824690 100644
--- a/src/backend/access/common/tidstore.c
+++ b/src/backend/access/common/tidstore.c
@@ -7,9 +7,9 @@
* Internally it uses a radix tree as the storage for TIDs. The key is the
* BlockNumber and the value is a bitmap of offsets, BlocktableEntry.
*
- * TidStore can be shared among parallel worker processes by passing DSA area
- * to TidStoreCreate(). Other backends can attach to the shared TidStore by
- * TidStoreAttach().
+ * TidStore can be shared among parallel worker processes by using
+ * TidStoreCreateShared(). Other backends can attach to the shared TidStore
+ * by TidStoreAttach().
*
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -111,15 +111,16 @@ static void tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
/*
* Create a TidStore. The TidStore will live in the memory context that is
* CurrentMemoryContext at the time of this call. The TID storage, backed
- * by a radix tree, will live in its child memory context, rt_context. The
- * TidStore will be limited to (approximately) max_bytes total memory
- * consumption. If the 'area' is non-NULL, the radix tree is created in the
- * DSA area.
+ * by a radix tree, will live in its child memory context, rt_context.
*
- * The returned object is allocated in backend-local memory.
+ * "max_bytes" is not an internally-enforced limit; it is used only as a
+ * hint to cap the memory block size of the memory context for TID storage.
+ * This reduces space wastage due to over-allocation. If the caller wants to
+ * monitor memory usage, it must compare its limit with the value reported
+ * by TidStoreMemoryUsage().
*/
TidStore *
-TidStoreCreate(size_t max_bytes, dsa_area *area, int tranche_id)
+TidStoreCreateLocal(size_t max_bytes)
{
TidStore *ts;
size_t initBlockSize = ALLOCSET_DEFAULT_INITSIZE;
@@ -143,33 +144,74 @@ TidStoreCreate(size_t max_bytes, dsa_area *area, int tranche_id)
initBlockSize,
maxBlockSize);
- if (area != NULL)
- {
- ts->tree.shared = shared_ts_create(ts->rt_context, area,
- tranche_id);
- ts->area = area;
- }
- else
- ts->tree.local = local_ts_create(ts->rt_context);
+ ts->tree.local = local_ts_create(ts->rt_context);
return ts;
}
/*
- * Attach to the shared TidStore using the given handle. The returned object
- * is allocated in backend-local memory using the CurrentMemoryContext.
+ * Similar to TidStoreCreateLocal() but create a shared TidStore on a
+ * DSA area. The TID storage will live in the DSA area, and the memory
+ * context rt_context will have only meta data of the radix tree.
+ *
+ * The returned object is allocated in backend-local memory.
*/
TidStore *
-TidStoreAttach(dsa_area *area, dsa_pointer handle)
+TidStoreCreateShared(size_t max_bytes, int tranche_id)
{
TidStore *ts;
+ dsa_area *area;
+ size_t dsa_init_size = DSA_DEFAULT_INIT_SEGMENT_SIZE;
+ size_t dsa_max_size = DSA_MAX_SEGMENT_SIZE;
- Assert(area != NULL);
+ ts = palloc0(sizeof(TidStore));
+ ts->context = CurrentMemoryContext;
+
+ ts->rt_context = AllocSetContextCreate(CurrentMemoryContext,
+ "TID storage meta data",
+ ALLOCSET_SMALL_SIZES);
+
+ /*
+ * Choose the initial and maximum DSA segment sizes to be no longer than
+ * 1/8 of max_bytes.
+ */
+ while (8 * dsa_max_size > max_bytes)
+ dsa_max_size >>= 1;
+
+ if (dsa_max_size < DSA_MIN_SEGMENT_SIZE)
+ dsa_max_size = DSA_MIN_SEGMENT_SIZE;
+
+ if (dsa_init_size > dsa_max_size)
+ dsa_init_size = dsa_max_size;
+
+ area = dsa_create_ext(tranche_id, dsa_init_size, dsa_max_size);
+ ts->tree.shared = shared_ts_create(ts->rt_context, area,
+ tranche_id);
+ ts->area = area;
+
+ return ts;
+}
+
+/*
+ * Attach to the shared TidStore. 'area_handle' is the DSA handle where
+ * the TidStore is created. 'handle' is the dsa_pointer returned by
+ * TidStoreGetHandle(). The returned object is allocated in backend-local
+ * memory using the CurrentMemoryContext.
+ */
+TidStore *
+TidStoreAttach(dsa_handle area_handle, dsa_pointer handle)
+{
+ TidStore *ts;
+ dsa_area *area;
+
+ Assert(area_handle != DSA_HANDLE_INVALID);
Assert(DsaPointerIsValid(handle));
/* create per-backend state */
ts = palloc0(sizeof(TidStore));
+ area = dsa_attach(area_handle);
+
/* Find the shared the shared radix tree */
ts->tree.shared = shared_ts_attach(area, handle);
ts->area = area;
@@ -178,10 +220,8 @@ TidStoreAttach(dsa_area *area, dsa_pointer handle)
}
/*
- * Detach from a TidStore. This detaches from radix tree and frees the
- * backend-local resources. The radix tree will continue to exist until
- * it is either explicitly destroyed, or the area that backs it is returned
- * to the operating system.
+ * Detach from a TidStore. This also detaches from radix tree and frees
+ * the backend-local resources.
*/
void
TidStoreDetach(TidStore *ts)
@@ -189,6 +229,8 @@ TidStoreDetach(TidStore *ts)
Assert(TidStoreIsShared(ts));
shared_ts_detach(ts->tree.shared);
+ dsa_detach(ts->area);
+
pfree(ts);
}
@@ -234,7 +276,11 @@ TidStoreDestroy(TidStore *ts)
{
/* Destroy underlying radix tree */
if (TidStoreIsShared(ts))
+ {
shared_ts_free(ts->tree.shared);
+
+ dsa_detach(ts->area);
+ }
else
local_ts_free(ts->tree.local);
@@ -420,6 +466,17 @@ TidStoreMemoryUsage(TidStore *ts)
return local_ts_memory_usage(ts->tree.local);
}
+/*
+ * Return the DSA area where the TidStore lives.
+ */
+dsa_area *
+TidStoreGetDSA(TidStore *ts)
+{
+ Assert(TidStoreIsShared(ts));
+
+ return ts->area;
+}
+
dsa_pointer
TidStoreGetHandle(TidStore *ts)
{
diff --git a/src/include/access/tidstore.h b/src/include/access/tidstore.h
index 09f7a9a4745..f05d7487837 100644
--- a/src/include/access/tidstore.h
+++ b/src/include/access/tidstore.h
@@ -29,9 +29,9 @@ typedef struct TidStoreIterResult
OffsetNumber *offsets;
} TidStoreIterResult;
-extern TidStore *TidStoreCreate(size_t max_bytes, dsa_area *area,
- int tranche_id);
-extern TidStore *TidStoreAttach(dsa_area *area, dsa_pointer handle);
+extern TidStore *TidStoreCreateLocal(size_t max_bytes);
+extern TidStore *TidStoreCreateShared(size_t max_bytes, int tranche_id);
+extern TidStore *TidStoreAttach(dsa_handle area_handle, dsa_pointer handle);
extern void TidStoreDetach(TidStore *ts);
extern void TidStoreLockExclusive(TidStore *ts);
extern void TidStoreLockShare(TidStore *ts);
@@ -45,5 +45,6 @@ extern TidStoreIterResult *TidStoreIterateNext(TidStoreIter *iter);
extern void TidStoreEndIterate(TidStoreIter *iter);
extern size_t TidStoreMemoryUsage(TidStore *ts);
extern dsa_pointer TidStoreGetHandle(TidStore *ts);
+extern dsa_area *TidStoreGetDSA(TidStore *ts);
#endif /* TIDSTORE_H */
diff --git a/src/test/modules/test_tidstore/test_tidstore.c b/src/test/modules/test_tidstore/test_tidstore.c
index c74ad2cf8b8..3d4af77dda1 100644
--- a/src/test/modules/test_tidstore/test_tidstore.c
+++ b/src/test/modules/test_tidstore/test_tidstore.c
@@ -34,7 +34,6 @@ PG_FUNCTION_INFO_V1(test_is_full);
PG_FUNCTION_INFO_V1(test_destroy);
static TidStore *tidstore = NULL;
-static dsa_area *dsa = NULL;
static size_t tidstore_empty_size;
/* array for verification of some tests */
@@ -94,7 +93,6 @@ test_create(PG_FUNCTION_ARGS)
size_t array_init_size = 1024;
Assert(tidstore == NULL);
- Assert(dsa == NULL);
/*
* Create the TidStore on TopMemoryContext so that the same process use it
@@ -109,18 +107,16 @@ test_create(PG_FUNCTION_ARGS)
tranche_id = LWLockNewTrancheId();
LWLockRegisterTranche(tranche_id, "test_tidstore");
- dsa = dsa_create(tranche_id);
+ tidstore = TidStoreCreateShared(tidstore_max_size, tranche_id);
/*
* Remain attached until end of backend or explicitly detached so that
* the same process use the tidstore for subsequent tests.
*/
- dsa_pin_mapping(dsa);
-
- tidstore = TidStoreCreate(tidstore_max_size, dsa, tranche_id);
+ dsa_pin_mapping(TidStoreGetDSA(tidstore));
}
else
- tidstore = TidStoreCreate(tidstore_max_size, NULL, 0);
+ tidstore = TidStoreCreateLocal(tidstore_max_size);
tidstore_empty_size = TidStoreMemoryUsage(tidstore);
@@ -309,9 +305,5 @@ test_destroy(PG_FUNCTION_ARGS)
pfree(items.lookup_tids);
pfree(items.iter_tids);
- if (dsa)
- dsa_detach(dsa);
- dsa = NULL;
-
PG_RETURN_VOID();
}