Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bb952c8

Browse files
Allow specifying initial and maximum segment sizes for DSA.
Previously, the DSA segment size always started with 1MB and grew up to DSA_MAX_SEGMENT_SIZE. It was inconvenient in certain scenarios, such as when the caller desired a soft constraint on the total DSA segment size, limiting it to less than 1MB. This commit introduces the capability to specify the initial and maximum DSA segment sizes when creating a DSA area, providing more flexibility and control over memory usage. Reviewed-by: John Naylor, Tomas Vondra Discussion: https://postgr.es/m/CAD21AoAYGGC1ePjVX0H%2Bpp9rH%3D9vuPK19nNOiu12NprdV5TVJA%40mail.gmail.com
1 parent 1f42337 commit bb952c8

File tree

2 files changed

+71
-38
lines changed

2 files changed

+71
-38
lines changed

src/backend/utils/mmgr/dsa.c

+29-34
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,6 @@
5959
#include "utils/memutils.h"
6060
#include "utils/resowner.h"
6161

62-
/*
63-
* The size of the initial DSM segment that backs a dsa_area created by
64-
* dsa_create. After creating some number of segments of this size we'll
65-
* double this size, and so on. Larger segments may be created if necessary
66-
* to satisfy large requests.
67-
*/
68-
#define DSA_INITIAL_SEGMENT_SIZE ((size_t) (1 * 1024 * 1024))
69-
7062
/*
7163
* How many segments to create before we double the segment size. If this is
7264
* low, then there is likely to be a lot of wasted space in the largest
@@ -76,17 +68,6 @@
7668
*/
7769
#define DSA_NUM_SEGMENTS_AT_EACH_SIZE 2
7870

79-
/*
80-
* The number of bits used to represent the offset part of a dsa_pointer.
81-
* This controls the maximum size of a segment, the maximum possible
82-
* allocation size and also the maximum number of segments per area.
83-
*/
84-
#if SIZEOF_DSA_POINTER == 4
85-
#define DSA_OFFSET_WIDTH 27 /* 32 segments of size up to 128MB */
86-
#else
87-
#define DSA_OFFSET_WIDTH 40 /* 1024 segments of size up to 1TB */
88-
#endif
89-
9071
/*
9172
* The maximum number of DSM segments that an area can own, determined by
9273
* the number of bits remaining (but capped at 1024).
@@ -97,9 +78,6 @@
9778
/* The bitmask for extracting the offset from a dsa_pointer. */
9879
#define DSA_OFFSET_BITMASK (((dsa_pointer) 1 << DSA_OFFSET_WIDTH) - 1)
9980

100-
/* The maximum size of a DSM segment. */
101-
#define DSA_MAX_SEGMENT_SIZE ((size_t) 1 << DSA_OFFSET_WIDTH)
102-
10381
/* Number of pages (see FPM_PAGE_SIZE) per regular superblock. */
10482
#define DSA_PAGES_PER_SUPERBLOCK 16
10583

@@ -318,6 +296,10 @@ typedef struct
318296
dsa_segment_index segment_bins[DSA_NUM_SEGMENT_BINS];
319297
/* The object pools for each size class. */
320298
dsa_area_pool pools[DSA_NUM_SIZE_CLASSES];
299+
/* initial allocation segment size */
300+
size_t init_segment_size;
301+
/* maximum allocation segment size */
302+
size_t max_segment_size;
321303
/* The total size of all active segments. */
322304
size_t total_segment_size;
323305
/* The maximum total size of backing storage we are allowed. */
@@ -417,7 +399,9 @@ static dsa_segment_map *make_new_segment(dsa_area *area, size_t requested_pages)
417399
static dsa_area *create_internal(void *place, size_t size,
418400
int tranche_id,
419401
dsm_handle control_handle,
420-
dsm_segment *control_segment);
402+
dsm_segment *control_segment,
403+
size_t init_segment_size,
404+
size_t max_segment_size);
421405
static dsa_area *attach_internal(void *place, dsm_segment *segment,
422406
dsa_handle handle);
423407
static void check_for_freed_segments(dsa_area *area);
@@ -434,7 +418,7 @@ static void rebin_segment(dsa_area *area, dsa_segment_map *segment_map);
434418
* we require the caller to provide one.
435419
*/
436420
dsa_area *
437-
dsa_create(int tranche_id)
421+
dsa_create_ext(int tranche_id, size_t init_segment_size, size_t max_segment_size)
438422
{
439423
dsm_segment *segment;
440424
dsa_area *area;
@@ -443,7 +427,7 @@ dsa_create(int tranche_id)
443427
* Create the DSM segment that will hold the shared control object and the
444428
* first segment of usable space.
445429
*/
446-
segment = dsm_create(DSA_INITIAL_SEGMENT_SIZE, 0);
430+
segment = dsm_create(init_segment_size, 0);
447431

448432
/*
449433
* All segments backing this area are pinned, so that DSA can explicitly
@@ -455,9 +439,10 @@ dsa_create(int tranche_id)
455439

456440
/* Create a new DSA area with the control object in this segment. */
457441
area = create_internal(dsm_segment_address(segment),
458-
DSA_INITIAL_SEGMENT_SIZE,
442+
init_segment_size,
459443
tranche_id,
460-
dsm_segment_handle(segment), segment);
444+
dsm_segment_handle(segment), segment,
445+
init_segment_size, max_segment_size);
461446

462447
/* Clean up when the control segment detaches. */
463448
on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,
@@ -483,13 +468,15 @@ dsa_create(int tranche_id)
483468
* See dsa_create() for a note about the tranche arguments.
484469
*/
485470
dsa_area *
486-
dsa_create_in_place(void *place, size_t size,
487-
int tranche_id, dsm_segment *segment)
471+
dsa_create_in_place_ext(void *place, size_t size,
472+
int tranche_id, dsm_segment *segment,
473+
size_t init_segment_size, size_t max_segment_size)
488474
{
489475
dsa_area *area;
490476

491477
area = create_internal(place, size, tranche_id,
492-
DSM_HANDLE_INVALID, NULL);
478+
DSM_HANDLE_INVALID, NULL,
479+
init_segment_size, max_segment_size);
493480

494481
/*
495482
* Clean up when the control segment detaches, if a containing DSM segment
@@ -1231,7 +1218,8 @@ static dsa_area *
12311218
create_internal(void *place, size_t size,
12321219
int tranche_id,
12331220
dsm_handle control_handle,
1234-
dsm_segment *control_segment)
1221+
dsm_segment *control_segment,
1222+
size_t init_segment_size, size_t max_segment_size)
12351223
{
12361224
dsa_area_control *control;
12371225
dsa_area *area;
@@ -1241,6 +1229,11 @@ create_internal(void *place, size_t size,
12411229
size_t metadata_bytes;
12421230
int i;
12431231

1232+
/* Check the initial and maximum block sizes */
1233+
Assert(init_segment_size >= DSA_MIN_SEGMENT_SIZE);
1234+
Assert(max_segment_size >= init_segment_size);
1235+
Assert(max_segment_size <= DSA_MAX_SEGMENT_SIZE);
1236+
12441237
/* Sanity check on the space we have to work in. */
12451238
if (size < dsa_minimum_size())
12461239
elog(ERROR, "dsa_area space must be at least %zu, but %zu provided",
@@ -1270,8 +1263,10 @@ create_internal(void *place, size_t size,
12701263
control->segment_header.prev = DSA_SEGMENT_INDEX_NONE;
12711264
control->segment_header.usable_pages = usable_pages;
12721265
control->segment_header.freed = false;
1273-
control->segment_header.size = DSA_INITIAL_SEGMENT_SIZE;
1266+
control->segment_header.size = size;
12741267
control->handle = control_handle;
1268+
control->init_segment_size = init_segment_size;
1269+
control->max_segment_size = max_segment_size;
12751270
control->max_total_segment_size = (size_t) -1;
12761271
control->total_segment_size = size;
12771272
control->segment_handles[0] = control_handle;
@@ -2127,9 +2122,9 @@ make_new_segment(dsa_area *area, size_t requested_pages)
21272122
* move to huge pages in the future. Then we work back to the number of
21282123
* pages we can fit.
21292124
*/
2130-
total_size = DSA_INITIAL_SEGMENT_SIZE *
2125+
total_size = area->control->init_segment_size *
21312126
((size_t) 1 << (new_index / DSA_NUM_SEGMENTS_AT_EACH_SIZE));
2132-
total_size = Min(total_size, DSA_MAX_SEGMENT_SIZE);
2127+
total_size = Min(total_size, area->control->max_segment_size);
21332128
total_size = Min(total_size,
21342129
area->control->max_total_segment_size -
21352130
area->control->total_segment_size);

src/include/utils/dsa.h

+42-4
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ typedef pg_atomic_uint64 dsa_pointer_atomic;
7777
/* A sentinel value for dsa_pointer used to indicate failure to allocate. */
7878
#define InvalidDsaPointer ((dsa_pointer) 0)
7979

80+
/*
81+
* The number of bits used to represent the offset part of a dsa_pointer.
82+
* This controls the maximum size of a segment, the maximum possible
83+
* allocation size and also the maximum number of segments per area.
84+
*/
85+
#if SIZEOF_DSA_POINTER == 4
86+
#define DSA_OFFSET_WIDTH 27 /* 32 segments of size up to 128MB */
87+
#else
88+
#define DSA_OFFSET_WIDTH 40 /* 1024 segments of size up to 1TB */
89+
#endif
90+
91+
/*
92+
* The default size of the initial DSM segment that backs a dsa_area created
93+
* by dsa_create. After creating some number of segments of the initial size
94+
* we'll double this size, and so on. Larger segments may be created if
95+
* necessary to satisfy large requests.
96+
*/
97+
#define DSA_DEFAULT_INIT_SEGMENT_SIZE ((size_t) (1 * 1024 * 1024))
98+
99+
/* The minimum size of a DSM segment. */
100+
#define DSA_MIN_SEGMENT_SIZE ((size_t) (256 * 1024L))
101+
102+
/* The maximum size of a DSM segment. */
103+
#define DSA_MAX_SEGMENT_SIZE ((size_t) 1 << DSA_OFFSET_WIDTH)
104+
80105
/* Check if a dsa_pointer value is valid. */
81106
#define DsaPointerIsValid(x) ((x) != InvalidDsaPointer)
82107

@@ -88,6 +113,17 @@ typedef pg_atomic_uint64 dsa_pointer_atomic;
88113
#define dsa_allocate0(area, size) \
89114
dsa_allocate_extended(area, size, DSA_ALLOC_ZERO)
90115

116+
/* Create dsa_area with default segment sizes */
117+
#define dsa_create(tranch_id) \
118+
dsa_create_ext(tranch_id, DSA_DEFAULT_INIT_SEGMENT_SIZE, \
119+
DSA_MAX_SEGMENT_SIZE)
120+
121+
/* Create dsa_area with default segment sizes in an existing share memory space */
122+
#define dsa_create_in_place(place, size, tranch_id, segment) \
123+
dsa_create_in_place_ext(place, size, tranch_id, segment, \
124+
DSA_DEFAULT_INIT_SEGMENT_SIZE, \
125+
DSA_MAX_SEGMENT_SIZE)
126+
91127
/*
92128
* The type used for dsa_area handles. dsa_handle values can be shared with
93129
* other processes, so that they can attach to them. This provides a way to
@@ -102,10 +138,12 @@ typedef dsm_handle dsa_handle;
102138
/* Sentinel value to use for invalid dsa_handles. */
103139
#define DSA_HANDLE_INVALID ((dsa_handle) DSM_HANDLE_INVALID)
104140

105-
106-
extern dsa_area *dsa_create(int tranche_id);
107-
extern dsa_area *dsa_create_in_place(void *place, size_t size,
108-
int tranche_id, dsm_segment *segment);
141+
extern dsa_area *dsa_create_ext(int tranche_id, size_t init_segment_size,
142+
size_t max_segment_size);
143+
extern dsa_area *dsa_create_in_place_ext(void *place, size_t size,
144+
int tranche_id, dsm_segment *segment,
145+
size_t init_segment_size,
146+
size_t max_segment_size);
109147
extern dsa_area *dsa_attach(dsa_handle handle);
110148
extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment);
111149
extern void dsa_release_in_place(void *place);

0 commit comments

Comments
 (0)