Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/mmgr/dsa.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * dsa.c
4
 *    Dynamic shared memory areas.
5
 *
6
 * This module provides dynamic shared memory areas which are built on top of
7
 * DSM segments.  While dsm.c allows segments of memory of shared memory to be
8
 * created and shared between backends, it isn't designed to deal with small
9
 * objects.  A DSA area is a shared memory heap usually backed by one or more
10
 * DSM segments which can allocate memory using dsa_allocate() and dsa_free().
11
 * Alternatively, it can be created in pre-existing shared memory, including a
12
 * DSM segment, and then create extra DSM segments as required.  Unlike the
13
 * regular system heap, it deals in pseudo-pointers which must be converted to
14
 * backend-local pointers before they are dereferenced.  These pseudo-pointers
15
 * can however be shared with other backends, and can be used to construct
16
 * shared data structures.
17
 *
18
 * Each DSA area manages a set of DSM segments, adding new segments as
19
 * required and detaching them when they are no longer needed.  Each segment
20
 * contains a number of 4KB pages, a free page manager for tracking
21
 * consecutive runs of free pages, and a page map for tracking the source of
22
 * objects allocated on each page.  Allocation requests above 8KB are handled
23
 * by choosing a segment and finding consecutive free pages in its free page
24
 * manager.  Allocation requests for smaller sizes are handled using pools of
25
 * objects of a selection of sizes.  Each pool consists of a number of 16 page
26
 * (64KB) superblocks allocated in the same way as large objects.  Allocation
27
 * of large objects and new superblocks is serialized by a single LWLock, but
28
 * allocation of small objects from pre-existing superblocks uses one LWLock
29
 * per pool.  Currently there is one pool, and therefore one lock, per size
30
 * class.  Per-core pools to increase concurrency and strategies for reducing
31
 * the resulting fragmentation are areas for future research.  Each superblock
32
 * is managed with a 'span', which tracks the superblock's freelist.  Free
33
 * requests are handled by looking in the page map to find which span an
34
 * address was allocated from, so that small objects can be returned to the
35
 * appropriate free list, and large object pages can be returned directly to
36
 * the free page map.  When allocating, simple heuristics for selecting
37
 * segments and superblocks try to encourage occupied memory to be
38
 * concentrated, increasing the likelihood that whole superblocks can become
39
 * empty and be returned to the free page manager, and whole segments can
40
 * become empty and be returned to the operating system.
41
 *
42
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
43
 * Portions Copyright (c) 1994, Regents of the University of California
44
 *
45
 * IDENTIFICATION
46
 *    src/backend/utils/mmgr/dsa.c
47
 *
48
 *-------------------------------------------------------------------------
49
 */
50
51
#include "postgres.h"
52
53
#include "port/atomics.h"
54
#include "port/pg_bitutils.h"
55
#include "storage/dsm.h"
56
#include "storage/lwlock.h"
57
#include "utils/dsa.h"
58
#include "utils/freepage.h"
59
#include "utils/memutils.h"
60
#include "utils/resowner.h"
61
62
/*
63
 * How many segments to create before we double the segment size.  If this is
64
 * low, then there is likely to be a lot of wasted space in the largest
65
 * segment.  If it is high, then we risk running out of segment slots (see
66
 * dsm.c's limits on total number of segments), or limiting the total size
67
 * an area can manage when using small pointers.
68
 */
69
0
#define DSA_NUM_SEGMENTS_AT_EACH_SIZE 2
70
71
/*
72
 * The maximum number of DSM segments that an area can own, determined by
73
 * the number of bits remaining (but capped at 1024).
74
 */
75
#define DSA_MAX_SEGMENTS \
76
0
  Min(1024, (1 << ((SIZEOF_DSA_POINTER * 8) - DSA_OFFSET_WIDTH)))
77
78
/* The bitmask for extracting the offset from a dsa_pointer. */
79
0
#define DSA_OFFSET_BITMASK (((dsa_pointer) 1 << DSA_OFFSET_WIDTH) - 1)
80
81
/* Number of pages (see FPM_PAGE_SIZE) per regular superblock. */
82
0
#define DSA_PAGES_PER_SUPERBLOCK    16
83
84
/*
85
 * A magic number used as a sanity check for following DSM segments belonging
86
 * to a DSA area (this number will be XORed with the area handle and
87
 * the segment index).
88
 */
89
0
#define DSA_SEGMENT_HEADER_MAGIC 0x0ce26608
90
91
/* Build a dsa_pointer given a segment number and offset. */
92
#define DSA_MAKE_POINTER(segment_number, offset) \
93
0
  (((dsa_pointer) (segment_number) << DSA_OFFSET_WIDTH) | (offset))
94
95
/* Extract the segment number from a dsa_pointer. */
96
0
#define DSA_EXTRACT_SEGMENT_NUMBER(dp) ((dp) >> DSA_OFFSET_WIDTH)
97
98
/* Extract the offset from a dsa_pointer. */
99
0
#define DSA_EXTRACT_OFFSET(dp) ((dp) & DSA_OFFSET_BITMASK)
100
101
/* The type used for index segment indexes (zero based). */
102
typedef size_t dsa_segment_index;
103
104
/* Sentinel value for dsa_segment_index indicating 'none' or 'end'. */
105
0
#define DSA_SEGMENT_INDEX_NONE (~(dsa_segment_index)0)
106
107
/*
108
 * How many bins of segments do we have?  The bins are used to categorize
109
 * segments by their largest contiguous run of free pages.
110
 */
111
0
#define DSA_NUM_SEGMENT_BINS 16
112
113
/*
114
 * What is the lowest bin that holds segments that *might* have n contiguous
115
 * free pages?  There is no point in looking in segments in lower bins; they
116
 * definitely can't service a request for n free pages.
117
 */
118
static inline size_t
119
contiguous_pages_to_segment_bin(size_t n)
120
0
{
121
0
  size_t    bin;
122
123
0
  if (n == 0)
124
0
    bin = 0;
125
0
  else
126
0
    bin = pg_leftmost_one_pos_size_t(n) + 1;
127
128
0
  return Min(bin, DSA_NUM_SEGMENT_BINS - 1);
129
0
}
130
131
/* Macros for access to locks. */
132
0
#define DSA_AREA_LOCK(area) (&area->control->lock)
133
0
#define DSA_SCLASS_LOCK(area, sclass) (&area->control->pools[sclass].lock)
134
135
/*
136
 * The header for an individual segment.  This lives at the start of each DSM
137
 * segment owned by a DSA area including the first segment (where it appears
138
 * as part of the dsa_area_control struct).
139
 */
140
typedef struct
141
{
142
  /* Sanity check magic value. */
143
  uint32    magic;
144
  /* Total number of pages in this segment (excluding metadata area). */
145
  size_t    usable_pages;
146
  /* Total size of this segment in bytes. */
147
  size_t    size;
148
149
  /*
150
   * Index of the segment that precedes this one in the same segment bin, or
151
   * DSA_SEGMENT_INDEX_NONE if this is the first one.
152
   */
153
  dsa_segment_index prev;
154
155
  /*
156
   * Index of the segment that follows this one in the same segment bin, or
157
   * DSA_SEGMENT_INDEX_NONE if this is the last one.
158
   */
159
  dsa_segment_index next;
160
  /* The index of the bin that contains this segment. */
161
  size_t    bin;
162
163
  /*
164
   * A flag raised to indicate that this segment is being returned to the
165
   * operating system and has been unpinned.
166
   */
167
  bool    freed;
168
} dsa_segment_header;
169
170
/*
171
 * Metadata for one superblock.
172
 *
173
 * For most blocks, span objects are stored out-of-line; that is, the span
174
 * object is not stored within the block itself.  But, as an exception, for a
175
 * "span of spans", the span object is stored "inline".  The allocation is
176
 * always exactly one page, and the dsa_area_span object is located at
177
 * the beginning of that page.  The size class is DSA_SCLASS_BLOCK_OF_SPANS,
178
 * and the remaining fields are used just as they would be in an ordinary
179
 * block.  We can't allocate spans out of ordinary superblocks because
180
 * creating an ordinary superblock requires us to be able to allocate a span
181
 * *first*.  Doing it this way avoids that circularity.
182
 */
183
typedef struct
184
{
185
  dsa_pointer pool;     /* Containing pool. */
186
  dsa_pointer prevspan;   /* Previous span. */
187
  dsa_pointer nextspan;   /* Next span. */
188
  dsa_pointer start;      /* Starting address. */
189
  size_t    npages;     /* Length of span in pages. */
190
  uint16    size_class;   /* Size class. */
191
  uint16    ninitialized; /* Maximum number of objects ever allocated. */
192
  uint16    nallocatable; /* Number of objects currently allocatable. */
193
  uint16    firstfree;    /* First object on free list. */
194
  uint16    nmax;     /* Maximum number of objects ever possible. */
195
  uint16    fclass;     /* Current fullness class. */
196
} dsa_area_span;
197
198
/*
199
 * Given a pointer to an object in a span, access the index of the next free
200
 * object in the same span (ie in the span's freelist) as an L-value.
201
 */
202
0
#define NextFreeObjectIndex(object) (* (uint16 *) (object))
203
204
/*
205
 * Small allocations are handled by dividing a single block of memory into
206
 * many small objects of equal size.  The possible allocation sizes are
207
 * defined by the following array.  Larger size classes are spaced more widely
208
 * than smaller size classes.  We fudge the spacing for size classes >1kB to
209
 * avoid space wastage: based on the knowledge that we plan to allocate 64kB
210
 * blocks, we bump the maximum object size up to the largest multiple of
211
 * 8 bytes that still lets us fit the same number of objects into one block.
212
 *
213
 * NB: Because of this fudging, if we were ever to use differently-sized blocks
214
 * for small allocations, these size classes would need to be reworked to be
215
 * optimal for the new size.
216
 *
217
 * NB: The optimal spacing for size classes, as well as the size of the blocks
218
 * out of which small objects are allocated, is not a question that has one
219
 * right answer.  Some allocators (such as tcmalloc) use more closely-spaced
220
 * size classes than we do here, while others (like aset.c) use more
221
 * widely-spaced classes.  Spacing the classes more closely avoids wasting
222
 * memory within individual chunks, but also means a larger number of
223
 * potentially-unfilled blocks.
224
 */
225
static const uint16 dsa_size_classes[] = {
226
  sizeof(dsa_area_span), 0, /* special size classes */
227
  8, 16, 24, 32, 40, 48, 56, 64,  /* 8 classes separated by 8 bytes */
228
  80, 96, 112, 128,     /* 4 classes separated by 16 bytes */
229
  160, 192, 224, 256,     /* 4 classes separated by 32 bytes */
230
  320, 384, 448, 512,     /* 4 classes separated by 64 bytes */
231
  640, 768, 896, 1024,    /* 4 classes separated by 128 bytes */
232
  1280, 1560, 1816, 2048,   /* 4 classes separated by ~256 bytes */
233
  2616, 3120, 3640, 4096,   /* 4 classes separated by ~512 bytes */
234
  5456, 6552, 7280, 8192    /* 4 classes separated by ~1024 bytes */
235
};
236
0
#define DSA_NUM_SIZE_CLASSES        lengthof(dsa_size_classes)
237
238
/* Special size classes. */
239
0
#define DSA_SCLASS_BLOCK_OF_SPANS   0
240
0
#define DSA_SCLASS_SPAN_LARGE     1
241
242
/*
243
 * The following lookup table is used to map the size of small objects
244
 * (less than 1kB) onto the corresponding size class.  To use this table,
245
 * round the size of the object up to the next multiple of 8 bytes, and then
246
 * index into this array.
247
 */
248
static const uint8 dsa_size_class_map[] = {
249
  2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13,
250
  14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17,
251
  18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
252
  20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21,
253
  22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
254
  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
255
  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
256
  25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25
257
};
258
0
#define DSA_SIZE_CLASS_MAP_QUANTUM  8
259
260
/*
261
 * Superblocks are binned by how full they are.  Generally, each fullness
262
 * class corresponds to one quartile, but the block being used for
263
 * allocations is always at the head of the list for fullness class 1,
264
 * regardless of how full it really is.
265
 */
266
0
#define DSA_FULLNESS_CLASSES    4
267
268
/*
269
 * A dsa_area_pool represents a set of objects of a given size class.
270
 *
271
 * Perhaps there should be multiple pools for the same size class for
272
 * contention avoidance, but for now there is just one!
273
 */
274
typedef struct
275
{
276
  /* A lock protecting access to this pool. */
277
  LWLock    lock;
278
  /* A set of linked lists of spans, arranged by fullness. */
279
  dsa_pointer spans[DSA_FULLNESS_CLASSES];
280
  /* Should we pad this out to a cacheline boundary? */
281
} dsa_area_pool;
282
283
/*
284
 * The control block for an area.  This lives in shared memory, at the start of
285
 * the first DSM segment controlled by this area.
286
 */
287
typedef struct
288
{
289
  /* The segment header for the first segment. */
290
  dsa_segment_header segment_header;
291
  /* The handle for this area. */
292
  dsa_handle  handle;
293
  /* The handles of the segments owned by this area. */
294
  dsm_handle  segment_handles[DSA_MAX_SEGMENTS];
295
  /* Lists of segments, binned by maximum contiguous run of free pages. */
296
  dsa_segment_index segment_bins[DSA_NUM_SEGMENT_BINS];
297
  /* The object pools for each size class. */
298
  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;
303
  /* The total size of all active segments. */
304
  size_t    total_segment_size;
305
  /* The maximum total size of backing storage we are allowed. */
306
  size_t    max_total_segment_size;
307
  /* Highest used segment index in the history of this area. */
308
  dsa_segment_index high_segment_index;
309
  /* The reference count for this area. */
310
  int     refcnt;
311
  /* A flag indicating that this area has been pinned. */
312
  bool    pinned;
313
  /* The number of times that segments have been freed. */
314
  size_t    freed_segment_counter;
315
  /* The LWLock tranche ID. */
316
  int     lwlock_tranche_id;
317
  /* The general lock (protects everything except object pools). */
318
  LWLock    lock;
319
} dsa_area_control;
320
321
/* Given a pointer to a pool, find a dsa_pointer. */
322
#define DsaAreaPoolToDsaPointer(area, p)  \
323
0
  DSA_MAKE_POINTER(0, (char *) p - (char *) area->control)
324
325
/*
326
 * A dsa_segment_map is stored within the backend-private memory of each
327
 * individual backend.  It holds the base address of the segment within that
328
 * backend, plus the addresses of key objects within the segment.  Those
329
 * could instead be derived from the base address but it's handy to have them
330
 * around.
331
 */
332
typedef struct
333
{
334
  dsm_segment *segment;   /* DSM segment */
335
  char     *mapped_address; /* Address at which segment is mapped */
336
  dsa_segment_header *header; /* Header (same as mapped_address) */
337
  FreePageManager *fpm;   /* Free page manager within segment. */
338
  dsa_pointer *pagemap;   /* Page map within segment. */
339
} dsa_segment_map;
340
341
/*
342
 * Per-backend state for a storage area.  Backends obtain one of these by
343
 * creating an area or attaching to an existing one using a handle.  Each
344
 * process that needs to use an area uses its own object to track where the
345
 * segments are mapped.
346
 */
347
struct dsa_area
348
{
349
  /* Pointer to the control object in shared memory. */
350
  dsa_area_control *control;
351
352
  /*
353
   * All the mappings are owned by this.  The dsa_area itself is not
354
   * directly tracked by the ResourceOwner, but the effect is the same. NULL
355
   * if the attachment has session lifespan, i.e if dsa_pin_mapping() has
356
   * been called.
357
   */
358
  ResourceOwner resowner;
359
360
  /*
361
   * This backend's array of segment maps, ordered by segment index
362
   * corresponding to control->segment_handles.  Some of the area's segments
363
   * may not be mapped in this backend yet, and some slots may have been
364
   * freed and need to be detached; these operations happen on demand.
365
   */
366
  dsa_segment_map segment_maps[DSA_MAX_SEGMENTS];
367
368
  /* The highest segment index this backend has ever mapped. */
369
  dsa_segment_index high_segment_index;
370
371
  /* The last observed freed_segment_counter. */
372
  size_t    freed_segment_counter;
373
};
374
375
0
#define DSA_SPAN_NOTHING_FREE ((uint16) -1)
376
0
#define DSA_SUPERBLOCK_SIZE (DSA_PAGES_PER_SUPERBLOCK * FPM_PAGE_SIZE)
377
378
/* Given a pointer to a segment_map, obtain a segment index number. */
379
#define get_segment_index(area, segment_map_ptr) \
380
0
  (segment_map_ptr - &area->segment_maps[0])
381
382
static void init_span(dsa_area *area, dsa_pointer span_pointer,
383
            dsa_area_pool *pool, dsa_pointer start, size_t npages,
384
            uint16 size_class);
385
static bool transfer_first_span(dsa_area *area, dsa_area_pool *pool,
386
                int fromclass, int toclass);
387
static inline dsa_pointer alloc_object(dsa_area *area, int size_class);
388
static bool ensure_active_superblock(dsa_area *area, dsa_area_pool *pool,
389
                   int size_class);
390
static dsa_segment_map *get_segment_by_index(dsa_area *area,
391
                       dsa_segment_index index);
392
static void destroy_superblock(dsa_area *area, dsa_pointer span_pointer);
393
static void unlink_span(dsa_area *area, dsa_area_span *span);
394
static void add_span_to_fullness_class(dsa_area *area, dsa_area_span *span,
395
                     dsa_pointer span_pointer, int fclass);
396
static void unlink_segment(dsa_area *area, dsa_segment_map *segment_map);
397
static dsa_segment_map *get_best_segment(dsa_area *area, size_t npages);
398
static dsa_segment_map *make_new_segment(dsa_area *area, size_t requested_pages);
399
static dsa_area *create_internal(void *place, size_t size,
400
                 int tranche_id,
401
                 dsm_handle control_handle,
402
                 dsm_segment *control_segment,
403
                 size_t init_segment_size,
404
                 size_t max_segment_size);
405
static dsa_area *attach_internal(void *place, dsm_segment *segment,
406
                 dsa_handle handle);
407
static void check_for_freed_segments(dsa_area *area);
408
static void check_for_freed_segments_locked(dsa_area *area);
409
static void rebin_segment(dsa_area *area, dsa_segment_map *segment_map);
410
411
/*
412
 * Create a new shared area in a new DSM segment.  Further DSM segments will
413
 * be allocated as required to extend the available space.
414
 *
415
 * We can't allocate a LWLock tranche_id within this function, because tranche
416
 * IDs are a scarce resource; there are only 64k available, using low numbers
417
 * when possible matters, and we have no provision for recycling them.  So,
418
 * we require the caller to provide one.
419
 */
420
dsa_area *
421
dsa_create_ext(int tranche_id, size_t init_segment_size, size_t max_segment_size)
422
0
{
423
0
  dsm_segment *segment;
424
0
  dsa_area   *area;
425
426
  /*
427
   * Create the DSM segment that will hold the shared control object and the
428
   * first segment of usable space.
429
   */
430
0
  segment = dsm_create(init_segment_size, 0);
431
432
  /*
433
   * All segments backing this area are pinned, so that DSA can explicitly
434
   * control their lifetime (otherwise a newly created segment belonging to
435
   * this area might be freed when the only backend that happens to have it
436
   * mapped in ends, corrupting the area).
437
   */
438
0
  dsm_pin_segment(segment);
439
440
  /* Create a new DSA area with the control object in this segment. */
441
0
  area = create_internal(dsm_segment_address(segment),
442
0
               init_segment_size,
443
0
               tranche_id,
444
0
               dsm_segment_handle(segment), segment,
445
0
               init_segment_size, max_segment_size);
446
447
  /* Clean up when the control segment detaches. */
448
0
  on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,
449
0
          PointerGetDatum(dsm_segment_address(segment)));
450
451
0
  return area;
452
0
}
453
454
/*
455
 * Create a new shared area in an existing shared memory space, which may be
456
 * either DSM or Postmaster-initialized memory.  DSM segments will be
457
 * allocated as required to extend the available space, though that can be
458
 * prevented with dsa_set_size_limit(area, size) using the same size provided
459
 * to dsa_create_in_place.
460
 *
461
 * Areas created in-place must eventually be released by the backend that
462
 * created them and all backends that attach to them.  This can be done
463
 * explicitly with dsa_release_in_place, or, in the special case that 'place'
464
 * happens to be in a pre-existing DSM segment, by passing in a pointer to the
465
 * segment so that a detach hook can be registered with the containing DSM
466
 * segment.
467
 *
468
 * See dsa_create() for a note about the tranche arguments.
469
 */
470
dsa_area *
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)
474
0
{
475
0
  dsa_area   *area;
476
477
0
  area = create_internal(place, size, tranche_id,
478
0
               DSM_HANDLE_INVALID, NULL,
479
0
               init_segment_size, max_segment_size);
480
481
  /*
482
   * Clean up when the control segment detaches, if a containing DSM segment
483
   * was provided.
484
   */
485
0
  if (segment != NULL)
486
0
    on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,
487
0
            PointerGetDatum(place));
488
489
0
  return area;
490
0
}
491
492
/*
493
 * Obtain a handle that can be passed to other processes so that they can
494
 * attach to the given area.  Cannot be called for areas created with
495
 * dsa_create_in_place.
496
 */
497
dsa_handle
498
dsa_get_handle(dsa_area *area)
499
0
{
500
0
  Assert(area->control->handle != DSA_HANDLE_INVALID);
501
0
  return area->control->handle;
502
0
}
503
504
/*
505
 * Attach to an area given a handle generated (possibly in another process) by
506
 * dsa_get_handle.  The area must have been created with dsa_create (not
507
 * dsa_create_in_place).
508
 */
509
dsa_area *
510
dsa_attach(dsa_handle handle)
511
0
{
512
0
  dsm_segment *segment;
513
0
  dsa_area   *area;
514
515
  /*
516
   * An area handle is really a DSM segment handle for the first segment, so
517
   * we go ahead and attach to that.
518
   */
519
0
  segment = dsm_attach(handle);
520
0
  if (segment == NULL)
521
0
    ereport(ERROR,
522
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
523
0
         errmsg("could not attach to dynamic shared area")));
524
525
0
  area = attach_internal(dsm_segment_address(segment), segment, handle);
526
527
  /* Clean up when the control segment detaches. */
528
0
  on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,
529
0
          PointerGetDatum(dsm_segment_address(segment)));
530
531
0
  return area;
532
0
}
533
534
/*
535
 * Returns whether the area with the given handle was already attached by the
536
 * current process.  The area must have been created with dsa_create (not
537
 * dsa_create_in_place).
538
 */
539
bool
540
dsa_is_attached(dsa_handle handle)
541
0
{
542
  /*
543
   * An area handle is really a DSM segment handle for the first segment, so
544
   * we can just search for that.
545
   */
546
0
  return dsm_find_mapping(handle) != NULL;
547
0
}
548
549
/*
550
 * Attach to an area that was created with dsa_create_in_place.  The caller
551
 * must somehow know the location in memory that was used when the area was
552
 * created, though it may be mapped at a different virtual address in this
553
 * process.
554
 *
555
 * See dsa_create_in_place for note about releasing in-place areas, and the
556
 * optional 'segment' argument which can be provided to allow automatic
557
 * release if the containing memory happens to be a DSM segment.
558
 */
559
dsa_area *
560
dsa_attach_in_place(void *place, dsm_segment *segment)
561
0
{
562
0
  dsa_area   *area;
563
564
0
  area = attach_internal(place, NULL, DSA_HANDLE_INVALID);
565
566
  /*
567
   * Clean up when the control segment detaches, if a containing DSM segment
568
   * was provided.
569
   */
570
0
  if (segment != NULL)
571
0
    on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,
572
0
            PointerGetDatum(place));
573
574
0
  return area;
575
0
}
576
577
/*
578
 * Release a DSA area that was produced by dsa_create_in_place or
579
 * dsa_attach_in_place.  The 'segment' argument is ignored but provides an
580
 * interface suitable for on_dsm_detach, for the convenience of users who want
581
 * to create a DSA segment inside an existing DSM segment and have it
582
 * automatically released when the containing DSM segment is detached.
583
 * 'place' should be the address of the place where the area was created.
584
 *
585
 * This callback is automatically registered for the DSM segment containing
586
 * the control object of in-place areas when a segment is provided to
587
 * dsa_create_in_place or dsa_attach_in_place, and also for all areas created
588
 * with dsa_create.
589
 */
590
void
591
dsa_on_dsm_detach_release_in_place(dsm_segment *segment, Datum place)
592
0
{
593
0
  dsa_release_in_place(DatumGetPointer(place));
594
0
}
595
596
/*
597
 * Release a DSA area that was produced by dsa_create_in_place or
598
 * dsa_attach_in_place.  The 'code' argument is ignored but provides an
599
 * interface suitable for on_shmem_exit or before_shmem_exit, for the
600
 * convenience of users who want to create a DSA segment inside shared memory
601
 * other than a DSM segment and have it automatically release at backend exit.
602
 * 'place' should be the address of the place where the area was created.
603
 */
604
void
605
dsa_on_shmem_exit_release_in_place(int code, Datum place)
606
0
{
607
0
  dsa_release_in_place(DatumGetPointer(place));
608
0
}
609
610
/*
611
 * Release a DSA area that was produced by dsa_create_in_place or
612
 * dsa_attach_in_place.  It is preferable to use one of the 'dsa_on_XXX'
613
 * callbacks so that this is managed automatically, because failure to release
614
 * an area created in-place leaks its segments permanently.
615
 *
616
 * This is also called automatically for areas produced by dsa_create or
617
 * dsa_attach as an implementation detail.
618
 */
619
void
620
dsa_release_in_place(void *place)
621
0
{
622
0
  dsa_area_control *control = (dsa_area_control *) place;
623
624
0
  LWLockAcquire(&control->lock, LW_EXCLUSIVE);
625
0
  Assert(control->segment_header.magic ==
626
0
       (DSA_SEGMENT_HEADER_MAGIC ^ control->handle ^ 0));
627
0
  Assert(control->refcnt > 0);
628
0
  if (--control->refcnt == 0)
629
0
  {
630
0
    for (dsa_segment_index i = 0; i <= control->high_segment_index; ++i)
631
0
    {
632
0
      dsm_handle  handle;
633
634
0
      handle = control->segment_handles[i];
635
0
      if (handle != DSM_HANDLE_INVALID)
636
0
        dsm_unpin_segment(handle);
637
0
    }
638
0
  }
639
0
  LWLockRelease(&control->lock);
640
0
}
641
642
/*
643
 * Keep a DSA area attached until end of session or explicit detach.
644
 *
645
 * By default, areas are owned by the current resource owner, which means they
646
 * are detached automatically when that scope ends.
647
 */
648
void
649
dsa_pin_mapping(dsa_area *area)
650
0
{
651
0
  if (area->resowner != NULL)
652
0
  {
653
0
    area->resowner = NULL;
654
655
0
    for (dsa_segment_index i = 0; i <= area->high_segment_index; ++i)
656
0
      if (area->segment_maps[i].segment != NULL)
657
0
        dsm_pin_mapping(area->segment_maps[i].segment);
658
0
  }
659
0
}
660
661
/*
662
 * Allocate memory in this storage area.  The return value is a dsa_pointer
663
 * that can be passed to other processes, and converted to a local pointer
664
 * with dsa_get_address.  'flags' is a bitmap which should be constructed
665
 * from the following values:
666
 *
667
 * DSA_ALLOC_HUGE allows allocations >= 1GB.  Otherwise, such allocations
668
 * will result in an ERROR.
669
 *
670
 * DSA_ALLOC_NO_OOM causes this function to return InvalidDsaPointer when
671
 * no memory is available or a size limit established by dsa_set_size_limit
672
 * would be exceeded.  Otherwise, such allocations will result in an ERROR.
673
 *
674
 * DSA_ALLOC_ZERO causes the allocated memory to be zeroed.  Otherwise, the
675
 * contents of newly-allocated memory are indeterminate.
676
 *
677
 * These flags correspond to similarly named flags used by
678
 * MemoryContextAllocExtended().  See also the macros dsa_allocate and
679
 * dsa_allocate0 which expand to a call to this function with commonly used
680
 * flags.
681
 */
682
dsa_pointer
683
dsa_allocate_extended(dsa_area *area, size_t size, int flags)
684
0
{
685
0
  uint16    size_class;
686
0
  dsa_pointer start_pointer;
687
0
  dsa_segment_map *segment_map;
688
0
  dsa_pointer result;
689
690
0
  Assert(size > 0);
691
692
  /* Sanity check on huge individual allocation size. */
693
0
  if (((flags & DSA_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
694
0
    ((flags & DSA_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
695
0
    elog(ERROR, "invalid DSA memory alloc request size %zu", size);
696
697
  /*
698
   * If bigger than the largest size class, just grab a run of pages from
699
   * the free page manager, instead of allocating an object from a pool.
700
   * There will still be a span, but it's a special class of span that
701
   * manages this whole allocation and simply gives all pages back to the
702
   * free page manager when dsa_free is called.
703
   */
704
0
  if (size > dsa_size_classes[lengthof(dsa_size_classes) - 1])
705
0
  {
706
0
    size_t    npages = fpm_size_to_pages(size);
707
0
    size_t    first_page;
708
0
    dsa_pointer span_pointer;
709
0
    dsa_area_pool *pool = &area->control->pools[DSA_SCLASS_SPAN_LARGE];
710
711
    /* Obtain a span object. */
712
0
    span_pointer = alloc_object(area, DSA_SCLASS_BLOCK_OF_SPANS);
713
0
    if (!DsaPointerIsValid(span_pointer))
714
0
    {
715
      /* Raise error unless asked not to. */
716
0
      if ((flags & DSA_ALLOC_NO_OOM) == 0)
717
0
        ereport(ERROR,
718
0
            (errcode(ERRCODE_OUT_OF_MEMORY),
719
0
             errmsg("out of memory"),
720
0
             errdetail("Failed on DSA request of size %zu.",
721
0
                   size)));
722
0
      return InvalidDsaPointer;
723
0
    }
724
725
0
    LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
726
727
    /* Find a segment from which to allocate. */
728
0
    segment_map = get_best_segment(area, npages);
729
0
    if (segment_map == NULL)
730
0
      segment_map = make_new_segment(area, npages);
731
0
    if (segment_map == NULL)
732
0
    {
733
      /* Can't make any more segments: game over. */
734
0
      LWLockRelease(DSA_AREA_LOCK(area));
735
0
      dsa_free(area, span_pointer);
736
737
      /* Raise error unless asked not to. */
738
0
      if ((flags & DSA_ALLOC_NO_OOM) == 0)
739
0
        ereport(ERROR,
740
0
            (errcode(ERRCODE_OUT_OF_MEMORY),
741
0
             errmsg("out of memory"),
742
0
             errdetail("Failed on DSA request of size %zu.",
743
0
                   size)));
744
0
      return InvalidDsaPointer;
745
0
    }
746
747
    /*
748
     * Ask the free page manager for a run of pages.  This should always
749
     * succeed, since both get_best_segment and make_new_segment should
750
     * only return a non-NULL pointer if it actually contains enough
751
     * contiguous freespace.  If it does fail, something in our backend
752
     * private state is out of whack, so use FATAL to kill the process.
753
     */
754
0
    if (!FreePageManagerGet(segment_map->fpm, npages, &first_page))
755
0
      elog(FATAL,
756
0
         "dsa_allocate could not find %zu free pages", npages);
757
0
    LWLockRelease(DSA_AREA_LOCK(area));
758
759
0
    start_pointer = DSA_MAKE_POINTER(get_segment_index(area, segment_map),
760
0
                     first_page * FPM_PAGE_SIZE);
761
762
    /* Initialize span and pagemap. */
763
0
    LWLockAcquire(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE),
764
0
            LW_EXCLUSIVE);
765
0
    init_span(area, span_pointer, pool, start_pointer, npages,
766
0
          DSA_SCLASS_SPAN_LARGE);
767
0
    segment_map->pagemap[first_page] = span_pointer;
768
0
    LWLockRelease(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE));
769
770
    /* Zero-initialize the memory if requested. */
771
0
    if ((flags & DSA_ALLOC_ZERO) != 0)
772
0
      memset(dsa_get_address(area, start_pointer), 0, size);
773
774
0
    return start_pointer;
775
0
  }
776
777
  /* Map allocation to a size class. */
778
0
  if (size < lengthof(dsa_size_class_map) * DSA_SIZE_CLASS_MAP_QUANTUM)
779
0
  {
780
0
    int     mapidx;
781
782
    /* For smaller sizes we have a lookup table... */
783
0
    mapidx = ((size + DSA_SIZE_CLASS_MAP_QUANTUM - 1) /
784
0
          DSA_SIZE_CLASS_MAP_QUANTUM) - 1;
785
0
    size_class = dsa_size_class_map[mapidx];
786
0
  }
787
0
  else
788
0
  {
789
0
    uint16    min;
790
0
    uint16    max;
791
792
    /* ... and for the rest we search by binary chop. */
793
0
    min = dsa_size_class_map[lengthof(dsa_size_class_map) - 1];
794
0
    max = lengthof(dsa_size_classes) - 1;
795
796
0
    while (min < max)
797
0
    {
798
0
      uint16    mid = (min + max) / 2;
799
0
      uint16    class_size = dsa_size_classes[mid];
800
801
0
      if (class_size < size)
802
0
        min = mid + 1;
803
0
      else
804
0
        max = mid;
805
0
    }
806
807
0
    size_class = min;
808
0
  }
809
0
  Assert(size <= dsa_size_classes[size_class]);
810
0
  Assert(size_class == 0 || size > dsa_size_classes[size_class - 1]);
811
812
  /* Attempt to allocate an object from the appropriate pool. */
813
0
  result = alloc_object(area, size_class);
814
815
  /* Check for failure to allocate. */
816
0
  if (!DsaPointerIsValid(result))
817
0
  {
818
    /* Raise error unless asked not to. */
819
0
    if ((flags & DSA_ALLOC_NO_OOM) == 0)
820
0
      ereport(ERROR,
821
0
          (errcode(ERRCODE_OUT_OF_MEMORY),
822
0
           errmsg("out of memory"),
823
0
           errdetail("Failed on DSA request of size %zu.", size)));
824
0
    return InvalidDsaPointer;
825
0
  }
826
827
  /* Zero-initialize the memory if requested. */
828
0
  if ((flags & DSA_ALLOC_ZERO) != 0)
829
0
    memset(dsa_get_address(area, result), 0, size);
830
831
0
  return result;
832
0
}
833
834
/*
835
 * Free memory obtained with dsa_allocate.
836
 */
837
void
838
dsa_free(dsa_area *area, dsa_pointer dp)
839
0
{
840
0
  dsa_segment_map *segment_map;
841
0
  int     pageno;
842
0
  dsa_pointer span_pointer;
843
0
  dsa_area_span *span;
844
0
  char     *superblock;
845
0
  char     *object;
846
0
  size_t    size;
847
0
  int     size_class;
848
849
  /* Make sure we don't have a stale segment in the slot 'dp' refers to. */
850
0
  check_for_freed_segments(area);
851
852
  /* Locate the object, span and pool. */
853
0
  segment_map = get_segment_by_index(area, DSA_EXTRACT_SEGMENT_NUMBER(dp));
854
0
  pageno = DSA_EXTRACT_OFFSET(dp) / FPM_PAGE_SIZE;
855
0
  span_pointer = segment_map->pagemap[pageno];
856
0
  span = dsa_get_address(area, span_pointer);
857
0
  superblock = dsa_get_address(area, span->start);
858
0
  object = dsa_get_address(area, dp);
859
0
  size_class = span->size_class;
860
0
  size = dsa_size_classes[size_class];
861
862
  /*
863
   * Special case for large objects that live in a special span: we return
864
   * those pages directly to the free page manager and free the span.
865
   */
866
0
  if (span->size_class == DSA_SCLASS_SPAN_LARGE)
867
0
  {
868
869
#ifdef CLOBBER_FREED_MEMORY
870
    memset(object, 0x7f, span->npages * FPM_PAGE_SIZE);
871
#endif
872
873
    /* Give pages back to free page manager. */
874
0
    LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
875
0
    FreePageManagerPut(segment_map->fpm,
876
0
               DSA_EXTRACT_OFFSET(span->start) / FPM_PAGE_SIZE,
877
0
               span->npages);
878
879
    /* Move segment to appropriate bin if necessary. */
880
0
    rebin_segment(area, segment_map);
881
0
    LWLockRelease(DSA_AREA_LOCK(area));
882
883
    /* Unlink span. */
884
0
    LWLockAcquire(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE),
885
0
            LW_EXCLUSIVE);
886
0
    unlink_span(area, span);
887
0
    LWLockRelease(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE));
888
    /* Free the span object so it can be reused. */
889
0
    dsa_free(area, span_pointer);
890
0
    return;
891
0
  }
892
893
#ifdef CLOBBER_FREED_MEMORY
894
  memset(object, 0x7f, size);
895
#endif
896
897
0
  LWLockAcquire(DSA_SCLASS_LOCK(area, size_class), LW_EXCLUSIVE);
898
899
  /* Put the object on the span's freelist. */
900
0
  Assert(object >= superblock);
901
0
  Assert(object < superblock + DSA_SUPERBLOCK_SIZE);
902
0
  Assert((object - superblock) % size == 0);
903
0
  NextFreeObjectIndex(object) = span->firstfree;
904
0
  span->firstfree = (object - superblock) / size;
905
0
  ++span->nallocatable;
906
907
  /*
908
   * See if the span needs to moved to a different fullness class, or be
909
   * freed so its pages can be given back to the segment.
910
   */
911
0
  if (span->nallocatable == 1 && span->fclass == DSA_FULLNESS_CLASSES - 1)
912
0
  {
913
    /*
914
     * The block was completely full and is located in the
915
     * highest-numbered fullness class, which is never scanned for free
916
     * chunks.  We must move it to the next-lower fullness class.
917
     */
918
0
    unlink_span(area, span);
919
0
    add_span_to_fullness_class(area, span, span_pointer,
920
0
                   DSA_FULLNESS_CLASSES - 2);
921
922
    /*
923
     * If this is the only span, and there is no active span, then we
924
     * should probably move this span to fullness class 1.  (Otherwise if
925
     * you allocate exactly all the objects in the only span, it moves to
926
     * class 3, then you free them all, it moves to 2, and then is given
927
     * back, leaving no active span).
928
     */
929
0
  }
930
0
  else if (span->nallocatable == span->nmax &&
931
0
       (span->fclass != 1 || span->prevspan != InvalidDsaPointer))
932
0
  {
933
    /*
934
     * This entire block is free, and it's not the active block for this
935
     * size class.  Return the memory to the free page manager. We don't
936
     * do this for the active block to prevent hysteresis: if we
937
     * repeatedly allocate and free the only chunk in the active block, it
938
     * will be very inefficient if we deallocate and reallocate the block
939
     * every time.
940
     */
941
0
    destroy_superblock(area, span_pointer);
942
0
  }
943
944
0
  LWLockRelease(DSA_SCLASS_LOCK(area, size_class));
945
0
}
946
947
/*
948
 * Obtain a backend-local address for a dsa_pointer.  'dp' must point to
949
 * memory allocated by the given area (possibly in another process) that
950
 * hasn't yet been freed.  This may cause a segment to be mapped into the
951
 * current process if required, and may cause freed segments to be unmapped.
952
 */
953
void *
954
dsa_get_address(dsa_area *area, dsa_pointer dp)
955
0
{
956
0
  dsa_segment_index index;
957
0
  size_t    offset;
958
959
  /* Convert InvalidDsaPointer to NULL. */
960
0
  if (!DsaPointerIsValid(dp))
961
0
    return NULL;
962
963
  /* Process any requests to detach from freed segments. */
964
0
  check_for_freed_segments(area);
965
966
  /* Break the dsa_pointer into its components. */
967
0
  index = DSA_EXTRACT_SEGMENT_NUMBER(dp);
968
0
  offset = DSA_EXTRACT_OFFSET(dp);
969
0
  Assert(index < DSA_MAX_SEGMENTS);
970
971
  /* Check if we need to cause this segment to be mapped in. */
972
0
  if (unlikely(area->segment_maps[index].mapped_address == NULL))
973
0
  {
974
    /* Call for effect (we don't need the result). */
975
0
    get_segment_by_index(area, index);
976
0
  }
977
978
0
  return area->segment_maps[index].mapped_address + offset;
979
0
}
980
981
/*
982
 * Pin this area, so that it will continue to exist even if all backends
983
 * detach from it.  In that case, the area can still be reattached to if a
984
 * handle has been recorded somewhere.
985
 */
986
void
987
dsa_pin(dsa_area *area)
988
0
{
989
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
990
0
  if (area->control->pinned)
991
0
  {
992
0
    LWLockRelease(DSA_AREA_LOCK(area));
993
0
    elog(ERROR, "dsa_area already pinned");
994
0
  }
995
0
  area->control->pinned = true;
996
0
  ++area->control->refcnt;
997
0
  LWLockRelease(DSA_AREA_LOCK(area));
998
0
}
999
1000
/*
1001
 * Undo the effects of dsa_pin, so that the given area can be freed when no
1002
 * backends are attached to it.  May be called only if dsa_pin has been
1003
 * called.
1004
 */
1005
void
1006
dsa_unpin(dsa_area *area)
1007
0
{
1008
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
1009
0
  Assert(area->control->refcnt > 1);
1010
0
  if (!area->control->pinned)
1011
0
  {
1012
0
    LWLockRelease(DSA_AREA_LOCK(area));
1013
0
    elog(ERROR, "dsa_area not pinned");
1014
0
  }
1015
0
  area->control->pinned = false;
1016
0
  --area->control->refcnt;
1017
0
  LWLockRelease(DSA_AREA_LOCK(area));
1018
0
}
1019
1020
/*
1021
 * Set the total size limit for this area.  This limit is checked whenever new
1022
 * segments need to be allocated from the operating system.  If the new size
1023
 * limit is already exceeded, this has no immediate effect.
1024
 *
1025
 * Note that the total virtual memory usage may be temporarily larger than
1026
 * this limit when segments have been freed, but not yet detached by all
1027
 * backends that have attached to them.
1028
 */
1029
void
1030
dsa_set_size_limit(dsa_area *area, size_t limit)
1031
0
{
1032
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
1033
0
  area->control->max_total_segment_size = limit;
1034
0
  LWLockRelease(DSA_AREA_LOCK(area));
1035
0
}
1036
1037
/* Return the total size of all active segments */
1038
size_t
1039
dsa_get_total_size(dsa_area *area)
1040
0
{
1041
0
  size_t    size;
1042
1043
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_SHARED);
1044
0
  size = area->control->total_segment_size;
1045
0
  LWLockRelease(DSA_AREA_LOCK(area));
1046
1047
0
  return size;
1048
0
}
1049
1050
/*
1051
 * Same as dsa_get_total_size(), but accepts a DSA handle.  The area must have
1052
 * been created with dsa_create (not dsa_create_in_place).
1053
 */
1054
size_t
1055
dsa_get_total_size_from_handle(dsa_handle handle)
1056
0
{
1057
0
  size_t    size;
1058
0
  bool    already_attached;
1059
0
  dsm_segment *segment;
1060
0
  dsa_area_control *control;
1061
1062
0
  already_attached = dsa_is_attached(handle);
1063
0
  if (already_attached)
1064
0
    segment = dsm_find_mapping(handle);
1065
0
  else
1066
0
    segment = dsm_attach(handle);
1067
1068
0
  if (segment == NULL)
1069
0
    ereport(ERROR,
1070
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1071
0
         errmsg("could not attach to dynamic shared area")));
1072
1073
0
  control = (dsa_area_control *) dsm_segment_address(segment);
1074
1075
0
  LWLockAcquire(&control->lock, LW_SHARED);
1076
0
  size = control->total_segment_size;
1077
0
  LWLockRelease(&control->lock);
1078
1079
0
  if (!already_attached)
1080
0
    dsm_detach(segment);
1081
1082
0
  return size;
1083
0
}
1084
1085
/*
1086
 * Aggressively free all spare memory in the hope of returning DSM segments to
1087
 * the operating system.
1088
 */
1089
void
1090
dsa_trim(dsa_area *area)
1091
0
{
1092
0
  int     size_class;
1093
1094
  /*
1095
   * Trim in reverse pool order so we get to the spans-of-spans last, just
1096
   * in case any become entirely free while processing all the other pools.
1097
   */
1098
0
  for (size_class = DSA_NUM_SIZE_CLASSES - 1; size_class >= 0; --size_class)
1099
0
  {
1100
0
    dsa_area_pool *pool = &area->control->pools[size_class];
1101
0
    dsa_pointer span_pointer;
1102
1103
0
    if (size_class == DSA_SCLASS_SPAN_LARGE)
1104
0
    {
1105
      /* Large object frees give back segments aggressively already. */
1106
0
      continue;
1107
0
    }
1108
1109
    /*
1110
     * Search fullness class 1 only.  That is where we expect to find an
1111
     * entirely empty superblock (entirely empty superblocks in other
1112
     * fullness classes are returned to the free page map by dsa_free).
1113
     */
1114
0
    LWLockAcquire(DSA_SCLASS_LOCK(area, size_class), LW_EXCLUSIVE);
1115
0
    span_pointer = pool->spans[1];
1116
0
    while (DsaPointerIsValid(span_pointer))
1117
0
    {
1118
0
      dsa_area_span *span = dsa_get_address(area, span_pointer);
1119
0
      dsa_pointer next = span->nextspan;
1120
1121
0
      if (span->nallocatable == span->nmax)
1122
0
        destroy_superblock(area, span_pointer);
1123
1124
0
      span_pointer = next;
1125
0
    }
1126
0
    LWLockRelease(DSA_SCLASS_LOCK(area, size_class));
1127
0
  }
1128
0
}
1129
1130
/*
1131
 * Print out debugging information about the internal state of the shared
1132
 * memory area.
1133
 */
1134
void
1135
dsa_dump(dsa_area *area)
1136
0
{
1137
0
  size_t    i,
1138
0
        j;
1139
1140
  /*
1141
   * Note: This gives an inconsistent snapshot as it acquires and releases
1142
   * individual locks as it goes...
1143
   */
1144
1145
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
1146
0
  check_for_freed_segments_locked(area);
1147
0
  fprintf(stderr, "dsa_area handle %x:\n", area->control->handle);
1148
0
  fprintf(stderr, "  max_total_segment_size: %zu\n",
1149
0
      area->control->max_total_segment_size);
1150
0
  fprintf(stderr, "  total_segment_size: %zu\n",
1151
0
      area->control->total_segment_size);
1152
0
  fprintf(stderr, "  refcnt: %d\n", area->control->refcnt);
1153
0
  fprintf(stderr, "  pinned: %c\n", area->control->pinned ? 't' : 'f');
1154
0
  fprintf(stderr, "  segment bins:\n");
1155
0
  for (i = 0; i < DSA_NUM_SEGMENT_BINS; ++i)
1156
0
  {
1157
0
    if (area->control->segment_bins[i] != DSA_SEGMENT_INDEX_NONE)
1158
0
    {
1159
0
      dsa_segment_index segment_index;
1160
1161
0
      if (i == 0)
1162
0
        fprintf(stderr,
1163
0
            "    segment bin %zu (no contiguous free pages):\n", i);
1164
0
      else
1165
0
        fprintf(stderr,
1166
0
            "    segment bin %zu (at least %d contiguous pages free):\n",
1167
0
            i, 1 << (i - 1));
1168
0
      segment_index = area->control->segment_bins[i];
1169
0
      while (segment_index != DSA_SEGMENT_INDEX_NONE)
1170
0
      {
1171
0
        dsa_segment_map *segment_map;
1172
1173
0
        segment_map =
1174
0
          get_segment_by_index(area, segment_index);
1175
1176
0
        fprintf(stderr,
1177
0
            "      segment index %zu, usable_pages = %zu, "
1178
0
            "contiguous_pages = %zu, mapped at %p\n",
1179
0
            segment_index,
1180
0
            segment_map->header->usable_pages,
1181
0
            fpm_largest(segment_map->fpm),
1182
0
            segment_map->mapped_address);
1183
0
        segment_index = segment_map->header->next;
1184
0
      }
1185
0
    }
1186
0
  }
1187
0
  LWLockRelease(DSA_AREA_LOCK(area));
1188
1189
0
  fprintf(stderr, "  pools:\n");
1190
0
  for (i = 0; i < DSA_NUM_SIZE_CLASSES; ++i)
1191
0
  {
1192
0
    bool    found = false;
1193
1194
0
    LWLockAcquire(DSA_SCLASS_LOCK(area, i), LW_EXCLUSIVE);
1195
0
    for (j = 0; j < DSA_FULLNESS_CLASSES; ++j)
1196
0
      if (DsaPointerIsValid(area->control->pools[i].spans[j]))
1197
0
        found = true;
1198
0
    if (found)
1199
0
    {
1200
0
      if (i == DSA_SCLASS_BLOCK_OF_SPANS)
1201
0
        fprintf(stderr, "    pool for blocks of span objects:\n");
1202
0
      else if (i == DSA_SCLASS_SPAN_LARGE)
1203
0
        fprintf(stderr, "    pool for large object spans:\n");
1204
0
      else
1205
0
        fprintf(stderr,
1206
0
            "    pool for size class %zu (object size %hu bytes):\n",
1207
0
            i, dsa_size_classes[i]);
1208
0
      for (j = 0; j < DSA_FULLNESS_CLASSES; ++j)
1209
0
      {
1210
0
        if (!DsaPointerIsValid(area->control->pools[i].spans[j]))
1211
0
          fprintf(stderr, "      fullness class %zu is empty\n", j);
1212
0
        else
1213
0
        {
1214
0
          dsa_pointer span_pointer = area->control->pools[i].spans[j];
1215
1216
0
          fprintf(stderr, "      fullness class %zu:\n", j);
1217
0
          while (DsaPointerIsValid(span_pointer))
1218
0
          {
1219
0
            dsa_area_span *span;
1220
1221
0
            span = dsa_get_address(area, span_pointer);
1222
0
            fprintf(stderr,
1223
0
                "        span descriptor at "
1224
0
                DSA_POINTER_FORMAT ", superblock at "
1225
0
                DSA_POINTER_FORMAT
1226
0
                ", pages = %zu, objects free = %hu/%hu\n",
1227
0
                span_pointer, span->start, span->npages,
1228
0
                span->nallocatable, span->nmax);
1229
0
            span_pointer = span->nextspan;
1230
0
          }
1231
0
        }
1232
0
      }
1233
0
    }
1234
0
    LWLockRelease(DSA_SCLASS_LOCK(area, i));
1235
0
  }
1236
0
}
1237
1238
/*
1239
 * Return the smallest size that you can successfully provide to
1240
 * dsa_create_in_place.
1241
 */
1242
size_t
1243
dsa_minimum_size(void)
1244
0
{
1245
0
  size_t    size;
1246
0
  size_t    pages = 0;
1247
1248
0
  size = MAXALIGN(sizeof(dsa_area_control)) +
1249
0
    MAXALIGN(sizeof(FreePageManager));
1250
1251
  /* Figure out how many pages we need, including the page map... */
1252
0
  while (((size + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE) > pages)
1253
0
  {
1254
0
    ++pages;
1255
0
    size += sizeof(dsa_pointer);
1256
0
  }
1257
1258
0
  return pages * FPM_PAGE_SIZE;
1259
0
}
1260
1261
/*
1262
 * Workhorse function for dsa_create and dsa_create_in_place.
1263
 */
1264
static dsa_area *
1265
create_internal(void *place, size_t size,
1266
        int tranche_id,
1267
        dsm_handle control_handle,
1268
        dsm_segment *control_segment,
1269
        size_t init_segment_size, size_t max_segment_size)
1270
0
{
1271
0
  dsa_area_control *control;
1272
0
  dsa_area   *area;
1273
0
  dsa_segment_map *segment_map;
1274
0
  size_t    usable_pages;
1275
0
  size_t    total_pages;
1276
0
  size_t    metadata_bytes;
1277
1278
  /* Check the initial and maximum block sizes */
1279
0
  Assert(init_segment_size >= DSA_MIN_SEGMENT_SIZE);
1280
0
  Assert(max_segment_size >= init_segment_size);
1281
0
  Assert(max_segment_size <= DSA_MAX_SEGMENT_SIZE);
1282
1283
  /* Sanity check on the space we have to work in. */
1284
0
  if (size < dsa_minimum_size())
1285
0
    elog(ERROR, "dsa_area space must be at least %zu, but %zu provided",
1286
0
       dsa_minimum_size(), size);
1287
1288
  /* Now figure out how much space is usable */
1289
0
  total_pages = size / FPM_PAGE_SIZE;
1290
0
  metadata_bytes =
1291
0
    MAXALIGN(sizeof(dsa_area_control)) +
1292
0
    MAXALIGN(sizeof(FreePageManager)) +
1293
0
    total_pages * sizeof(dsa_pointer);
1294
  /* Add padding up to next page boundary. */
1295
0
  if (metadata_bytes % FPM_PAGE_SIZE != 0)
1296
0
    metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE);
1297
0
  Assert(metadata_bytes <= size);
1298
0
  usable_pages = (size - metadata_bytes) / FPM_PAGE_SIZE;
1299
1300
  /*
1301
   * Initialize the dsa_area_control object located at the start of the
1302
   * space.
1303
   */
1304
0
  control = (dsa_area_control *) place;
1305
0
  memset(place, 0, sizeof(*control));
1306
0
  control->segment_header.magic =
1307
0
    DSA_SEGMENT_HEADER_MAGIC ^ control_handle ^ 0;
1308
0
  control->segment_header.next = DSA_SEGMENT_INDEX_NONE;
1309
0
  control->segment_header.prev = DSA_SEGMENT_INDEX_NONE;
1310
0
  control->segment_header.usable_pages = usable_pages;
1311
0
  control->segment_header.freed = false;
1312
0
  control->segment_header.size = size;
1313
0
  control->handle = control_handle;
1314
0
  control->init_segment_size = init_segment_size;
1315
0
  control->max_segment_size = max_segment_size;
1316
0
  control->max_total_segment_size = (size_t) -1;
1317
0
  control->total_segment_size = size;
1318
0
  control->segment_handles[0] = control_handle;
1319
0
  for (int i = 0; i < DSA_NUM_SEGMENT_BINS; ++i)
1320
0
    control->segment_bins[i] = DSA_SEGMENT_INDEX_NONE;
1321
0
  control->refcnt = 1;
1322
0
  control->lwlock_tranche_id = tranche_id;
1323
1324
  /*
1325
   * Create the dsa_area object that this backend will use to access the
1326
   * area.  Other backends will need to obtain their own dsa_area object by
1327
   * attaching.
1328
   */
1329
0
  area = palloc_object(dsa_area);
1330
0
  area->control = control;
1331
0
  area->resowner = CurrentResourceOwner;
1332
0
  memset(area->segment_maps, 0, sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS);
1333
0
  area->high_segment_index = 0;
1334
0
  area->freed_segment_counter = 0;
1335
0
  LWLockInitialize(&control->lock, control->lwlock_tranche_id);
1336
0
  for (size_t i = 0; i < DSA_NUM_SIZE_CLASSES; ++i)
1337
0
    LWLockInitialize(DSA_SCLASS_LOCK(area, i),
1338
0
             control->lwlock_tranche_id);
1339
1340
  /* Set up the segment map for this process's mapping. */
1341
0
  segment_map = &area->segment_maps[0];
1342
0
  segment_map->segment = control_segment;
1343
0
  segment_map->mapped_address = place;
1344
0
  segment_map->header = (dsa_segment_header *) place;
1345
0
  segment_map->fpm = (FreePageManager *)
1346
0
    (segment_map->mapped_address +
1347
0
     MAXALIGN(sizeof(dsa_area_control)));
1348
0
  segment_map->pagemap = (dsa_pointer *)
1349
0
    (segment_map->mapped_address +
1350
0
     MAXALIGN(sizeof(dsa_area_control)) +
1351
0
     MAXALIGN(sizeof(FreePageManager)));
1352
1353
  /* Set up the free page map. */
1354
0
  FreePageManagerInitialize(segment_map->fpm, segment_map->mapped_address);
1355
  /* There can be 0 usable pages if size is dsa_minimum_size(). */
1356
1357
0
  if (usable_pages > 0)
1358
0
    FreePageManagerPut(segment_map->fpm, metadata_bytes / FPM_PAGE_SIZE,
1359
0
               usable_pages);
1360
1361
  /* Put this segment into the appropriate bin. */
1362
0
  control->segment_bins[contiguous_pages_to_segment_bin(usable_pages)] = 0;
1363
0
  segment_map->header->bin = contiguous_pages_to_segment_bin(usable_pages);
1364
1365
0
  return area;
1366
0
}
1367
1368
/*
1369
 * Workhorse function for dsa_attach and dsa_attach_in_place.
1370
 */
1371
static dsa_area *
1372
attach_internal(void *place, dsm_segment *segment, dsa_handle handle)
1373
0
{
1374
0
  dsa_area_control *control;
1375
0
  dsa_area   *area;
1376
0
  dsa_segment_map *segment_map;
1377
1378
0
  control = (dsa_area_control *) place;
1379
0
  Assert(control->handle == handle);
1380
0
  Assert(control->segment_handles[0] == handle);
1381
0
  Assert(control->segment_header.magic ==
1382
0
       (DSA_SEGMENT_HEADER_MAGIC ^ handle ^ 0));
1383
1384
  /* Build the backend-local area object. */
1385
0
  area = palloc_object(dsa_area);
1386
0
  area->control = control;
1387
0
  area->resowner = CurrentResourceOwner;
1388
0
  memset(&area->segment_maps[0], 0,
1389
0
       sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS);
1390
0
  area->high_segment_index = 0;
1391
1392
  /* Set up the segment map for this process's mapping. */
1393
0
  segment_map = &area->segment_maps[0];
1394
0
  segment_map->segment = segment; /* NULL for in-place */
1395
0
  segment_map->mapped_address = place;
1396
0
  segment_map->header = (dsa_segment_header *) segment_map->mapped_address;
1397
0
  segment_map->fpm = (FreePageManager *)
1398
0
    (segment_map->mapped_address + MAXALIGN(sizeof(dsa_area_control)));
1399
0
  segment_map->pagemap = (dsa_pointer *)
1400
0
    (segment_map->mapped_address + MAXALIGN(sizeof(dsa_area_control)) +
1401
0
     MAXALIGN(sizeof(FreePageManager)));
1402
1403
  /* Bump the reference count. */
1404
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
1405
0
  if (control->refcnt == 0)
1406
0
  {
1407
    /* We can't attach to a DSA area that has already been destroyed. */
1408
0
    ereport(ERROR,
1409
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1410
0
         errmsg("could not attach to dynamic shared area")));
1411
0
  }
1412
0
  ++control->refcnt;
1413
0
  area->freed_segment_counter = area->control->freed_segment_counter;
1414
0
  LWLockRelease(DSA_AREA_LOCK(area));
1415
1416
0
  return area;
1417
0
}
1418
1419
/*
1420
 * Add a new span to fullness class 1 of the indicated pool.
1421
 */
1422
static void
1423
init_span(dsa_area *area,
1424
      dsa_pointer span_pointer,
1425
      dsa_area_pool *pool, dsa_pointer start, size_t npages,
1426
      uint16 size_class)
1427
0
{
1428
0
  dsa_area_span *span = dsa_get_address(area, span_pointer);
1429
0
  size_t    obsize = dsa_size_classes[size_class];
1430
1431
  /*
1432
   * The per-pool lock must be held because we manipulate the span list for
1433
   * this pool.
1434
   */
1435
0
  Assert(LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class)));
1436
1437
  /* Push this span onto the front of the span list for fullness class 1. */
1438
0
  if (DsaPointerIsValid(pool->spans[1]))
1439
0
  {
1440
0
    dsa_area_span *head = (dsa_area_span *)
1441
0
      dsa_get_address(area, pool->spans[1]);
1442
1443
0
    head->prevspan = span_pointer;
1444
0
  }
1445
0
  span->pool = DsaAreaPoolToDsaPointer(area, pool);
1446
0
  span->nextspan = pool->spans[1];
1447
0
  span->prevspan = InvalidDsaPointer;
1448
0
  pool->spans[1] = span_pointer;
1449
1450
0
  span->start = start;
1451
0
  span->npages = npages;
1452
0
  span->size_class = size_class;
1453
0
  span->ninitialized = 0;
1454
0
  if (size_class == DSA_SCLASS_BLOCK_OF_SPANS)
1455
0
  {
1456
    /*
1457
     * A block-of-spans contains its own descriptor, so mark one object as
1458
     * initialized and reduce the count of allocatable objects by one.
1459
     * Doing this here has the side effect of also reducing nmax by one,
1460
     * which is important to make sure we free this object at the correct
1461
     * time.
1462
     */
1463
0
    span->ninitialized = 1;
1464
0
    span->nallocatable = FPM_PAGE_SIZE / obsize - 1;
1465
0
  }
1466
0
  else if (size_class != DSA_SCLASS_SPAN_LARGE)
1467
0
    span->nallocatable = DSA_SUPERBLOCK_SIZE / obsize;
1468
0
  span->firstfree = DSA_SPAN_NOTHING_FREE;
1469
0
  span->nmax = span->nallocatable;
1470
0
  span->fclass = 1;
1471
0
}
1472
1473
/*
1474
 * Transfer the first span in one fullness class to the head of another
1475
 * fullness class.
1476
 */
1477
static bool
1478
transfer_first_span(dsa_area *area,
1479
          dsa_area_pool *pool, int fromclass, int toclass)
1480
0
{
1481
0
  dsa_pointer span_pointer;
1482
0
  dsa_area_span *span;
1483
0
  dsa_area_span *nextspan;
1484
1485
  /* Can't do it if source list is empty. */
1486
0
  span_pointer = pool->spans[fromclass];
1487
0
  if (!DsaPointerIsValid(span_pointer))
1488
0
    return false;
1489
1490
  /* Remove span from head of source list. */
1491
0
  span = dsa_get_address(area, span_pointer);
1492
0
  pool->spans[fromclass] = span->nextspan;
1493
0
  if (DsaPointerIsValid(span->nextspan))
1494
0
  {
1495
0
    nextspan = (dsa_area_span *)
1496
0
      dsa_get_address(area, span->nextspan);
1497
0
    nextspan->prevspan = InvalidDsaPointer;
1498
0
  }
1499
1500
  /* Add span to head of target list. */
1501
0
  span->nextspan = pool->spans[toclass];
1502
0
  pool->spans[toclass] = span_pointer;
1503
0
  if (DsaPointerIsValid(span->nextspan))
1504
0
  {
1505
0
    nextspan = (dsa_area_span *)
1506
0
      dsa_get_address(area, span->nextspan);
1507
0
    nextspan->prevspan = span_pointer;
1508
0
  }
1509
0
  span->fclass = toclass;
1510
1511
0
  return true;
1512
0
}
1513
1514
/*
1515
 * Allocate one object of the requested size class from the given area.
1516
 */
1517
static inline dsa_pointer
1518
alloc_object(dsa_area *area, int size_class)
1519
0
{
1520
0
  dsa_area_pool *pool = &area->control->pools[size_class];
1521
0
  dsa_area_span *span;
1522
0
  dsa_pointer block;
1523
0
  dsa_pointer result;
1524
0
  char     *object;
1525
0
  size_t    size;
1526
1527
  /*
1528
   * Even though ensure_active_superblock can in turn call alloc_object if
1529
   * it needs to allocate a new span, that's always from a different pool,
1530
   * and the order of lock acquisition is always the same, so it's OK that
1531
   * we hold this lock for the duration of this function.
1532
   */
1533
0
  Assert(!LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class)));
1534
0
  LWLockAcquire(DSA_SCLASS_LOCK(area, size_class), LW_EXCLUSIVE);
1535
1536
  /*
1537
   * If there's no active superblock, we must successfully obtain one or
1538
   * fail the request.
1539
   */
1540
0
  if (!DsaPointerIsValid(pool->spans[1]) &&
1541
0
    !ensure_active_superblock(area, pool, size_class))
1542
0
  {
1543
0
    result = InvalidDsaPointer;
1544
0
  }
1545
0
  else
1546
0
  {
1547
    /*
1548
     * There should be a block in fullness class 1 at this point, and it
1549
     * should never be completely full.  Thus we can either pop an object
1550
     * from the free list or, failing that, initialize a new object.
1551
     */
1552
0
    Assert(DsaPointerIsValid(pool->spans[1]));
1553
0
    span = (dsa_area_span *)
1554
0
      dsa_get_address(area, pool->spans[1]);
1555
0
    Assert(span->nallocatable > 0);
1556
0
    block = span->start;
1557
0
    Assert(size_class < DSA_NUM_SIZE_CLASSES);
1558
0
    size = dsa_size_classes[size_class];
1559
0
    if (span->firstfree != DSA_SPAN_NOTHING_FREE)
1560
0
    {
1561
0
      result = block + span->firstfree * size;
1562
0
      object = dsa_get_address(area, result);
1563
0
      span->firstfree = NextFreeObjectIndex(object);
1564
0
    }
1565
0
    else
1566
0
    {
1567
0
      result = block + span->ninitialized * size;
1568
0
      ++span->ninitialized;
1569
0
    }
1570
0
    --span->nallocatable;
1571
1572
    /* If it's now full, move it to the highest-numbered fullness class. */
1573
0
    if (span->nallocatable == 0)
1574
0
      transfer_first_span(area, pool, 1, DSA_FULLNESS_CLASSES - 1);
1575
0
  }
1576
1577
0
  Assert(LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class)));
1578
0
  LWLockRelease(DSA_SCLASS_LOCK(area, size_class));
1579
1580
0
  return result;
1581
0
}
1582
1583
/*
1584
 * Ensure an active (i.e. fullness class 1) superblock, unless all existing
1585
 * superblocks are completely full and no more can be allocated.
1586
 *
1587
 * Fullness classes K of 0..N are loosely intended to represent blocks whose
1588
 * utilization percentage is at least K/N, but we only enforce this rigorously
1589
 * for the highest-numbered fullness class, which always contains exactly
1590
 * those blocks that are completely full.  It's otherwise acceptable for a
1591
 * block to be in a higher-numbered fullness class than the one to which it
1592
 * logically belongs.  In addition, the active block, which is always the
1593
 * first block in fullness class 1, is permitted to have a higher allocation
1594
 * percentage than would normally be allowable for that fullness class; we
1595
 * don't move it until it's completely full, and then it goes to the
1596
 * highest-numbered fullness class.
1597
 *
1598
 * It might seem odd that the active block is the head of fullness class 1
1599
 * rather than fullness class 0, but experience with other allocators has
1600
 * shown that it's usually better to allocate from a block that's moderately
1601
 * full rather than one that's nearly empty.  Insofar as is reasonably
1602
 * possible, we want to avoid performing new allocations in a block that would
1603
 * otherwise become empty soon.
1604
 */
1605
static bool
1606
ensure_active_superblock(dsa_area *area, dsa_area_pool *pool,
1607
             int size_class)
1608
0
{
1609
0
  dsa_pointer span_pointer;
1610
0
  dsa_pointer start_pointer;
1611
0
  size_t    obsize = dsa_size_classes[size_class];
1612
0
  size_t    nmax;
1613
0
  int     fclass;
1614
0
  size_t    npages = 1;
1615
0
  size_t    first_page;
1616
0
  size_t    i;
1617
0
  dsa_segment_map *segment_map;
1618
1619
0
  Assert(LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class)));
1620
1621
  /*
1622
   * Compute the number of objects that will fit in a block of this size
1623
   * class.  Span-of-spans blocks are just a single page, and the first
1624
   * object isn't available for use because it describes the block-of-spans
1625
   * itself.
1626
   */
1627
0
  if (size_class == DSA_SCLASS_BLOCK_OF_SPANS)
1628
0
    nmax = FPM_PAGE_SIZE / obsize - 1;
1629
0
  else
1630
0
    nmax = DSA_SUPERBLOCK_SIZE / obsize;
1631
1632
  /*
1633
   * If fullness class 1 is empty, try to find a span to put in it by
1634
   * scanning higher-numbered fullness classes (excluding the last one,
1635
   * whose blocks are certain to all be completely full).
1636
   */
1637
0
  for (fclass = 2; fclass < DSA_FULLNESS_CLASSES - 1; ++fclass)
1638
0
  {
1639
0
    span_pointer = pool->spans[fclass];
1640
1641
0
    while (DsaPointerIsValid(span_pointer))
1642
0
    {
1643
0
      int     tfclass;
1644
0
      dsa_area_span *span;
1645
0
      dsa_area_span *nextspan;
1646
0
      dsa_area_span *prevspan;
1647
0
      dsa_pointer next_span_pointer;
1648
1649
0
      span = (dsa_area_span *)
1650
0
        dsa_get_address(area, span_pointer);
1651
0
      next_span_pointer = span->nextspan;
1652
1653
      /* Figure out what fullness class should contain this span. */
1654
0
      tfclass = (nmax - span->nallocatable)
1655
0
        * (DSA_FULLNESS_CLASSES - 1) / nmax;
1656
1657
      /* Look up next span. */
1658
0
      if (DsaPointerIsValid(span->nextspan))
1659
0
        nextspan = (dsa_area_span *)
1660
0
          dsa_get_address(area, span->nextspan);
1661
0
      else
1662
0
        nextspan = NULL;
1663
1664
      /*
1665
       * If utilization has dropped enough that this now belongs in some
1666
       * other fullness class, move it there.
1667
       */
1668
0
      if (tfclass < fclass)
1669
0
      {
1670
        /* Remove from the current fullness class list. */
1671
0
        if (pool->spans[fclass] == span_pointer)
1672
0
        {
1673
          /* It was the head; remove it. */
1674
0
          Assert(!DsaPointerIsValid(span->prevspan));
1675
0
          pool->spans[fclass] = span->nextspan;
1676
0
          if (nextspan != NULL)
1677
0
            nextspan->prevspan = InvalidDsaPointer;
1678
0
        }
1679
0
        else
1680
0
        {
1681
          /* It was not the head. */
1682
0
          Assert(DsaPointerIsValid(span->prevspan));
1683
0
          prevspan = (dsa_area_span *)
1684
0
            dsa_get_address(area, span->prevspan);
1685
0
          prevspan->nextspan = span->nextspan;
1686
0
        }
1687
0
        if (nextspan != NULL)
1688
0
          nextspan->prevspan = span->prevspan;
1689
1690
        /* Push onto the head of the new fullness class list. */
1691
0
        span->nextspan = pool->spans[tfclass];
1692
0
        pool->spans[tfclass] = span_pointer;
1693
0
        span->prevspan = InvalidDsaPointer;
1694
0
        if (DsaPointerIsValid(span->nextspan))
1695
0
        {
1696
0
          nextspan = (dsa_area_span *)
1697
0
            dsa_get_address(area, span->nextspan);
1698
0
          nextspan->prevspan = span_pointer;
1699
0
        }
1700
0
        span->fclass = tfclass;
1701
0
      }
1702
1703
      /* Advance to next span on list. */
1704
0
      span_pointer = next_span_pointer;
1705
0
    }
1706
1707
    /* Stop now if we found a suitable block. */
1708
0
    if (DsaPointerIsValid(pool->spans[1]))
1709
0
      return true;
1710
0
  }
1711
1712
  /*
1713
   * If there are no blocks that properly belong in fullness class 1, pick
1714
   * one from some other fullness class and move it there anyway, so that we
1715
   * have an allocation target.  Our last choice is to transfer a block
1716
   * that's almost empty (and might become completely empty soon if left
1717
   * alone), but even that is better than failing, which is what we must do
1718
   * if there are no blocks at all with freespace.
1719
   */
1720
0
  Assert(!DsaPointerIsValid(pool->spans[1]));
1721
0
  for (fclass = 2; fclass < DSA_FULLNESS_CLASSES - 1; ++fclass)
1722
0
    if (transfer_first_span(area, pool, fclass, 1))
1723
0
      return true;
1724
0
  if (!DsaPointerIsValid(pool->spans[1]) &&
1725
0
    transfer_first_span(area, pool, 0, 1))
1726
0
    return true;
1727
1728
  /*
1729
   * We failed to find an existing span with free objects, so we need to
1730
   * allocate a new superblock and construct a new span to manage it.
1731
   *
1732
   * First, get a dsa_area_span object to describe the new superblock block
1733
   * ... unless this allocation is for a dsa_area_span object, in which case
1734
   * that's surely not going to work.  We handle that case by storing the
1735
   * span describing a block-of-spans inline.
1736
   */
1737
0
  if (size_class != DSA_SCLASS_BLOCK_OF_SPANS)
1738
0
  {
1739
0
    span_pointer = alloc_object(area, DSA_SCLASS_BLOCK_OF_SPANS);
1740
0
    if (!DsaPointerIsValid(span_pointer))
1741
0
      return false;
1742
0
    npages = DSA_PAGES_PER_SUPERBLOCK;
1743
0
  }
1744
1745
  /* Find or create a segment and allocate the superblock. */
1746
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
1747
0
  segment_map = get_best_segment(area, npages);
1748
0
  if (segment_map == NULL)
1749
0
  {
1750
0
    segment_map = make_new_segment(area, npages);
1751
0
    if (segment_map == NULL)
1752
0
    {
1753
0
      LWLockRelease(DSA_AREA_LOCK(area));
1754
0
      return false;
1755
0
    }
1756
0
  }
1757
1758
  /*
1759
   * This shouldn't happen: get_best_segment() or make_new_segment()
1760
   * promised that we can successfully allocate npages.
1761
   */
1762
0
  if (!FreePageManagerGet(segment_map->fpm, npages, &first_page))
1763
0
    elog(FATAL,
1764
0
       "dsa_allocate could not find %zu free pages for superblock",
1765
0
       npages);
1766
0
  LWLockRelease(DSA_AREA_LOCK(area));
1767
1768
  /* Compute the start of the superblock. */
1769
0
  start_pointer =
1770
0
    DSA_MAKE_POINTER(get_segment_index(area, segment_map),
1771
0
             first_page * FPM_PAGE_SIZE);
1772
1773
  /*
1774
   * If this is a block-of-spans, carve the descriptor right out of the
1775
   * allocated space.
1776
   */
1777
0
  if (size_class == DSA_SCLASS_BLOCK_OF_SPANS)
1778
0
  {
1779
    /*
1780
     * We have a pointer into the segment.  We need to build a dsa_pointer
1781
     * from the segment index and offset into the segment.
1782
     */
1783
0
    span_pointer = start_pointer;
1784
0
  }
1785
1786
  /* Initialize span and pagemap. */
1787
0
  init_span(area, span_pointer, pool, start_pointer, npages, size_class);
1788
0
  for (i = 0; i < npages; ++i)
1789
0
    segment_map->pagemap[first_page + i] = span_pointer;
1790
1791
0
  return true;
1792
0
}
1793
1794
/*
1795
 * Return the segment map corresponding to a given segment index, mapping the
1796
 * segment in if necessary.  For internal segment book-keeping, this is called
1797
 * with the area lock held.  It is also called by dsa_free and dsa_get_address
1798
 * without any locking, relying on the fact they have a known live segment
1799
 * index and they always call check_for_freed_segments to ensures that any
1800
 * freed segment occupying the same slot is detached first.
1801
 */
1802
static dsa_segment_map *
1803
get_segment_by_index(dsa_area *area, dsa_segment_index index)
1804
0
{
1805
0
  if (unlikely(area->segment_maps[index].mapped_address == NULL))
1806
0
  {
1807
0
    dsm_handle  handle;
1808
0
    dsm_segment *segment;
1809
0
    dsa_segment_map *segment_map;
1810
0
    ResourceOwner oldowner;
1811
1812
    /*
1813
     * If we are reached by dsa_free or dsa_get_address, there must be at
1814
     * least one object allocated in the referenced segment.  Otherwise,
1815
     * their caller has a double-free or access-after-free bug, which we
1816
     * have no hope of detecting.  So we know it's safe to access this
1817
     * array slot without holding a lock; it won't change underneath us.
1818
     * Furthermore, we know that we can see the latest contents of the
1819
     * slot, as explained in check_for_freed_segments, which those
1820
     * functions call before arriving here.
1821
     */
1822
0
    handle = area->control->segment_handles[index];
1823
1824
    /* It's an error to try to access an unused slot. */
1825
0
    if (handle == DSM_HANDLE_INVALID)
1826
0
      elog(ERROR,
1827
0
         "dsa_area could not attach to a segment that has been freed");
1828
1829
0
    oldowner = CurrentResourceOwner;
1830
0
    CurrentResourceOwner = area->resowner;
1831
0
    segment = dsm_attach(handle);
1832
0
    CurrentResourceOwner = oldowner;
1833
0
    if (segment == NULL)
1834
0
      elog(ERROR, "dsa_area could not attach to segment");
1835
0
    segment_map = &area->segment_maps[index];
1836
0
    segment_map->segment = segment;
1837
0
    segment_map->mapped_address = dsm_segment_address(segment);
1838
0
    segment_map->header =
1839
0
      (dsa_segment_header *) segment_map->mapped_address;
1840
0
    segment_map->fpm = (FreePageManager *)
1841
0
      (segment_map->mapped_address +
1842
0
       MAXALIGN(sizeof(dsa_segment_header)));
1843
0
    segment_map->pagemap = (dsa_pointer *)
1844
0
      (segment_map->mapped_address +
1845
0
       MAXALIGN(sizeof(dsa_segment_header)) +
1846
0
       MAXALIGN(sizeof(FreePageManager)));
1847
1848
    /* Remember the highest index this backend has ever mapped. */
1849
0
    if (area->high_segment_index < index)
1850
0
      area->high_segment_index = index;
1851
1852
0
    Assert(segment_map->header->magic ==
1853
0
         (DSA_SEGMENT_HEADER_MAGIC ^ area->control->handle ^ index));
1854
0
  }
1855
1856
  /*
1857
   * Callers of dsa_get_address() and dsa_free() don't hold the area lock,
1858
   * but it's a bug in the calling code and undefined behavior if the
1859
   * address is not live (ie if the segment might possibly have been freed,
1860
   * they're trying to use a dangling pointer).
1861
   *
1862
   * For dsa.c code that holds the area lock to manipulate segment_bins
1863
   * lists, it would be a bug if we ever reach a freed segment here.  After
1864
   * it's marked as freed, the only thing any backend should do with it is
1865
   * unmap it, and it should always have done that in
1866
   * check_for_freed_segments_locked() before arriving here to resolve an
1867
   * index to a segment_map.
1868
   *
1869
   * Either way we can assert that we aren't returning a freed segment.
1870
   */
1871
0
  Assert(!area->segment_maps[index].header->freed);
1872
1873
0
  return &area->segment_maps[index];
1874
0
}
1875
1876
/*
1877
 * Return a superblock to the free page manager.  If the underlying segment
1878
 * has become entirely free, then return it to the operating system.
1879
 *
1880
 * The appropriate pool lock must be held.
1881
 */
1882
static void
1883
destroy_superblock(dsa_area *area, dsa_pointer span_pointer)
1884
0
{
1885
0
  dsa_area_span *span = dsa_get_address(area, span_pointer);
1886
0
  int     size_class = span->size_class;
1887
0
  dsa_segment_map *segment_map;
1888
1889
1890
  /* Remove it from its fullness class list. */
1891
0
  unlink_span(area, span);
1892
1893
  /*
1894
   * Note: Here we acquire the area lock while we already hold a per-pool
1895
   * lock.  We never hold the area lock and then take a pool lock, or we
1896
   * could deadlock.
1897
   */
1898
0
  LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
1899
0
  check_for_freed_segments_locked(area);
1900
0
  segment_map =
1901
0
    get_segment_by_index(area, DSA_EXTRACT_SEGMENT_NUMBER(span->start));
1902
0
  FreePageManagerPut(segment_map->fpm,
1903
0
             DSA_EXTRACT_OFFSET(span->start) / FPM_PAGE_SIZE,
1904
0
             span->npages);
1905
  /* Check if the segment is now entirely free. */
1906
0
  if (fpm_largest(segment_map->fpm) == segment_map->header->usable_pages)
1907
0
  {
1908
0
    dsa_segment_index index = get_segment_index(area, segment_map);
1909
1910
    /* If it's not the segment with extra control data, free it. */
1911
0
    if (index != 0)
1912
0
    {
1913
      /*
1914
       * Give it back to the OS, and allow other backends to detect that
1915
       * they need to detach.
1916
       */
1917
0
      unlink_segment(area, segment_map);
1918
0
      segment_map->header->freed = true;
1919
0
      Assert(area->control->total_segment_size >=
1920
0
           segment_map->header->size);
1921
0
      area->control->total_segment_size -=
1922
0
        segment_map->header->size;
1923
0
      dsm_unpin_segment(dsm_segment_handle(segment_map->segment));
1924
0
      dsm_detach(segment_map->segment);
1925
0
      area->control->segment_handles[index] = DSM_HANDLE_INVALID;
1926
0
      ++area->control->freed_segment_counter;
1927
0
      segment_map->segment = NULL;
1928
0
      segment_map->header = NULL;
1929
0
      segment_map->mapped_address = NULL;
1930
0
    }
1931
0
  }
1932
1933
  /* Move segment to appropriate bin if necessary. */
1934
0
  if (segment_map->header != NULL)
1935
0
    rebin_segment(area, segment_map);
1936
1937
0
  LWLockRelease(DSA_AREA_LOCK(area));
1938
1939
  /*
1940
   * Span-of-spans blocks store the span which describes them within the
1941
   * block itself, so freeing the storage implicitly frees the descriptor
1942
   * also.  If this is a block of any other type, we need to separately free
1943
   * the span object also.  This recursive call to dsa_free will acquire the
1944
   * span pool's lock.  We can't deadlock because the acquisition order is
1945
   * always some other pool and then the span pool.
1946
   */
1947
0
  if (size_class != DSA_SCLASS_BLOCK_OF_SPANS)
1948
0
    dsa_free(area, span_pointer);
1949
0
}
1950
1951
static void
1952
unlink_span(dsa_area *area, dsa_area_span *span)
1953
0
{
1954
0
  if (DsaPointerIsValid(span->nextspan))
1955
0
  {
1956
0
    dsa_area_span *next = dsa_get_address(area, span->nextspan);
1957
1958
0
    next->prevspan = span->prevspan;
1959
0
  }
1960
0
  if (DsaPointerIsValid(span->prevspan))
1961
0
  {
1962
0
    dsa_area_span *prev = dsa_get_address(area, span->prevspan);
1963
1964
0
    prev->nextspan = span->nextspan;
1965
0
  }
1966
0
  else
1967
0
  {
1968
0
    dsa_area_pool *pool = dsa_get_address(area, span->pool);
1969
1970
0
    pool->spans[span->fclass] = span->nextspan;
1971
0
  }
1972
0
}
1973
1974
static void
1975
add_span_to_fullness_class(dsa_area *area, dsa_area_span *span,
1976
               dsa_pointer span_pointer,
1977
               int fclass)
1978
0
{
1979
0
  dsa_area_pool *pool = dsa_get_address(area, span->pool);
1980
1981
0
  if (DsaPointerIsValid(pool->spans[fclass]))
1982
0
  {
1983
0
    dsa_area_span *head = dsa_get_address(area,
1984
0
                        pool->spans[fclass]);
1985
1986
0
    head->prevspan = span_pointer;
1987
0
  }
1988
0
  span->prevspan = InvalidDsaPointer;
1989
0
  span->nextspan = pool->spans[fclass];
1990
0
  pool->spans[fclass] = span_pointer;
1991
0
  span->fclass = fclass;
1992
0
}
1993
1994
/*
1995
 * Detach from an area that was either created or attached to by this process.
1996
 */
1997
void
1998
dsa_detach(dsa_area *area)
1999
0
{
2000
  /* Detach from all segments. */
2001
0
  for (dsa_segment_index i = 0; i <= area->high_segment_index; ++i)
2002
0
    if (area->segment_maps[i].segment != NULL)
2003
0
      dsm_detach(area->segment_maps[i].segment);
2004
2005
  /*
2006
   * Note that 'detaching' (= detaching from DSM segments) doesn't include
2007
   * 'releasing' (= adjusting the reference count).  It would be nice to
2008
   * combine these operations, but client code might never get around to
2009
   * calling dsa_detach because of an error path, and a detach hook on any
2010
   * particular segment is too late to detach other segments in the area
2011
   * without risking a 'leak' warning in the non-error path.
2012
   */
2013
2014
  /* Free the backend-local area object. */
2015
0
  pfree(area);
2016
0
}
2017
2018
/*
2019
 * Unlink a segment from the bin that contains it.
2020
 */
2021
static void
2022
unlink_segment(dsa_area *area, dsa_segment_map *segment_map)
2023
0
{
2024
0
  if (segment_map->header->prev != DSA_SEGMENT_INDEX_NONE)
2025
0
  {
2026
0
    dsa_segment_map *prev;
2027
2028
0
    prev = get_segment_by_index(area, segment_map->header->prev);
2029
0
    prev->header->next = segment_map->header->next;
2030
0
  }
2031
0
  else
2032
0
  {
2033
0
    Assert(area->control->segment_bins[segment_map->header->bin] ==
2034
0
         get_segment_index(area, segment_map));
2035
0
    area->control->segment_bins[segment_map->header->bin] =
2036
0
      segment_map->header->next;
2037
0
  }
2038
0
  if (segment_map->header->next != DSA_SEGMENT_INDEX_NONE)
2039
0
  {
2040
0
    dsa_segment_map *next;
2041
2042
0
    next = get_segment_by_index(area, segment_map->header->next);
2043
0
    next->header->prev = segment_map->header->prev;
2044
0
  }
2045
0
}
2046
2047
/*
2048
 * Find a segment that could satisfy a request for 'npages' of contiguous
2049
 * memory, or return NULL if none can be found.  This may involve attaching to
2050
 * segments that weren't previously attached so that we can query their free
2051
 * pages map.
2052
 */
2053
static dsa_segment_map *
2054
get_best_segment(dsa_area *area, size_t npages)
2055
0
{
2056
0
  size_t    bin;
2057
2058
0
  Assert(LWLockHeldByMe(DSA_AREA_LOCK(area)));
2059
0
  check_for_freed_segments_locked(area);
2060
2061
  /*
2062
   * Start searching from the first bin that *might* have enough contiguous
2063
   * pages.
2064
   */
2065
0
  for (bin = contiguous_pages_to_segment_bin(npages);
2066
0
     bin < DSA_NUM_SEGMENT_BINS;
2067
0
     ++bin)
2068
0
  {
2069
    /*
2070
     * The minimum contiguous size that any segment in this bin should
2071
     * have.  We'll re-bin if we see segments with fewer.
2072
     */
2073
0
    size_t    threshold = (size_t) 1 << (bin - 1);
2074
0
    dsa_segment_index segment_index;
2075
2076
    /* Search this bin for a segment with enough contiguous space. */
2077
0
    segment_index = area->control->segment_bins[bin];
2078
0
    while (segment_index != DSA_SEGMENT_INDEX_NONE)
2079
0
    {
2080
0
      dsa_segment_map *segment_map;
2081
0
      dsa_segment_index next_segment_index;
2082
0
      size_t    contiguous_pages;
2083
2084
0
      segment_map = get_segment_by_index(area, segment_index);
2085
0
      next_segment_index = segment_map->header->next;
2086
0
      contiguous_pages = fpm_largest(segment_map->fpm);
2087
2088
      /* Not enough for the request, still enough for this bin. */
2089
0
      if (contiguous_pages >= threshold && contiguous_pages < npages)
2090
0
      {
2091
0
        segment_index = next_segment_index;
2092
0
        continue;
2093
0
      }
2094
2095
      /* Re-bin it if it's no longer in the appropriate bin. */
2096
0
      if (contiguous_pages < threshold)
2097
0
      {
2098
0
        rebin_segment(area, segment_map);
2099
2100
        /*
2101
         * But fall through to see if it's enough to satisfy this
2102
         * request anyway....
2103
         */
2104
0
      }
2105
2106
      /* Check if we are done. */
2107
0
      if (contiguous_pages >= npages)
2108
0
        return segment_map;
2109
2110
      /* Continue searching the same bin. */
2111
0
      segment_index = next_segment_index;
2112
0
    }
2113
0
  }
2114
2115
  /* Not found. */
2116
0
  return NULL;
2117
0
}
2118
2119
/*
2120
 * Create a new segment that can handle at least requested_pages.  Returns
2121
 * NULL if the requested total size limit or maximum allowed number of
2122
 * segments would be exceeded.
2123
 */
2124
static dsa_segment_map *
2125
make_new_segment(dsa_area *area, size_t requested_pages)
2126
0
{
2127
0
  dsa_segment_index new_index;
2128
0
  size_t    metadata_bytes;
2129
0
  size_t    total_size;
2130
0
  size_t    total_pages;
2131
0
  size_t    usable_pages;
2132
0
  dsa_segment_map *segment_map;
2133
0
  dsm_segment *segment;
2134
0
  ResourceOwner oldowner;
2135
2136
0
  Assert(LWLockHeldByMe(DSA_AREA_LOCK(area)));
2137
2138
  /* Find a segment slot that is not in use (linearly for now). */
2139
0
  for (new_index = 1; new_index < DSA_MAX_SEGMENTS; ++new_index)
2140
0
  {
2141
0
    if (area->control->segment_handles[new_index] == DSM_HANDLE_INVALID)
2142
0
      break;
2143
0
  }
2144
0
  if (new_index == DSA_MAX_SEGMENTS)
2145
0
    return NULL;
2146
2147
  /*
2148
   * If the total size limit is already exceeded, then we exit early and
2149
   * avoid arithmetic wraparound in the unsigned expressions below.
2150
   */
2151
0
  if (area->control->total_segment_size >=
2152
0
    area->control->max_total_segment_size)
2153
0
    return NULL;
2154
2155
  /*
2156
   * The size should be at least as big as requested, and at least big
2157
   * enough to follow a geometric series that approximately doubles the
2158
   * total storage each time we create a new segment.  We use geometric
2159
   * growth because the underlying DSM system isn't designed for large
2160
   * numbers of segments (otherwise we might even consider just using one
2161
   * DSM segment for each large allocation and for each superblock, and then
2162
   * we wouldn't need to use FreePageManager).
2163
   *
2164
   * We decide on a total segment size first, so that we produce tidy
2165
   * power-of-two sized segments.  This is a good property to have if we
2166
   * move to huge pages in the future.  Then we work back to the number of
2167
   * pages we can fit.
2168
   */
2169
0
  total_size = area->control->init_segment_size *
2170
0
    ((size_t) 1 << (new_index / DSA_NUM_SEGMENTS_AT_EACH_SIZE));
2171
0
  total_size = Min(total_size, area->control->max_segment_size);
2172
0
  total_size = Min(total_size,
2173
0
           area->control->max_total_segment_size -
2174
0
           area->control->total_segment_size);
2175
2176
0
  total_pages = total_size / FPM_PAGE_SIZE;
2177
0
  metadata_bytes =
2178
0
    MAXALIGN(sizeof(dsa_segment_header)) +
2179
0
    MAXALIGN(sizeof(FreePageManager)) +
2180
0
    sizeof(dsa_pointer) * total_pages;
2181
2182
  /* Add padding up to next page boundary. */
2183
0
  if (metadata_bytes % FPM_PAGE_SIZE != 0)
2184
0
    metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE);
2185
0
  if (total_size <= metadata_bytes)
2186
0
    return NULL;
2187
0
  usable_pages = (total_size - metadata_bytes) / FPM_PAGE_SIZE;
2188
0
  Assert(metadata_bytes + usable_pages * FPM_PAGE_SIZE <= total_size);
2189
2190
  /* See if that is enough... */
2191
0
  if (requested_pages > usable_pages)
2192
0
  {
2193
0
    size_t    total_requested_pages PG_USED_FOR_ASSERTS_ONLY;
2194
2195
    /*
2196
     * We'll make an odd-sized segment, working forward from the requested
2197
     * number of pages.
2198
     */
2199
0
    usable_pages = requested_pages;
2200
0
    metadata_bytes =
2201
0
      MAXALIGN(sizeof(dsa_segment_header)) +
2202
0
      MAXALIGN(sizeof(FreePageManager)) +
2203
0
      usable_pages * sizeof(dsa_pointer);
2204
2205
    /*
2206
     * We must also account for pagemap entries needed to cover the
2207
     * metadata pages themselves.  The pagemap must track all pages in the
2208
     * segment, including the pages occupied by metadata.
2209
     *
2210
     * This formula uses integer ceiling division to compute the exact
2211
     * number of additional entries needed.  The divisor (FPM_PAGE_SIZE -
2212
     * sizeof(dsa_pointer)) accounts for the fact that each metadata page
2213
     * consumes one pagemap entry of sizeof(dsa_pointer) bytes, leaving
2214
     * only (FPM_PAGE_SIZE - sizeof(dsa_pointer)) net bytes per metadata
2215
     * page.
2216
     */
2217
0
    metadata_bytes +=
2218
0
      ((metadata_bytes + (FPM_PAGE_SIZE - sizeof(dsa_pointer)) - 1) /
2219
0
       (FPM_PAGE_SIZE - sizeof(dsa_pointer))) *
2220
0
      sizeof(dsa_pointer);
2221
2222
    /* Add padding up to next page boundary. */
2223
0
    if (metadata_bytes % FPM_PAGE_SIZE != 0)
2224
0
      metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE);
2225
0
    total_size = metadata_bytes + usable_pages * FPM_PAGE_SIZE;
2226
0
    total_requested_pages = total_size / FPM_PAGE_SIZE;
2227
2228
    /*
2229
     * Verify that we allocated enough pagemap entries for metadata and
2230
     * usable pages.  This reverse-engineers the new calculation of
2231
     * "metadata_bytes" done based on the new "requested_pages" for an
2232
     * odd-sized segment.
2233
     */
2234
0
    Assert((metadata_bytes - MAXALIGN(sizeof(dsa_segment_header)) -
2235
0
        MAXALIGN(sizeof(FreePageManager))) / sizeof(dsa_pointer) >= total_requested_pages);
2236
2237
    /* Is that too large for dsa_pointer's addressing scheme? */
2238
0
    if (total_size > DSA_MAX_SEGMENT_SIZE)
2239
0
      return NULL;
2240
2241
    /* Would that exceed the limit? */
2242
0
    if (total_size > area->control->max_total_segment_size -
2243
0
      area->control->total_segment_size)
2244
0
      return NULL;
2245
0
  }
2246
2247
  /* Create the segment. */
2248
0
  oldowner = CurrentResourceOwner;
2249
0
  CurrentResourceOwner = area->resowner;
2250
0
  segment = dsm_create(total_size, 0);
2251
0
  CurrentResourceOwner = oldowner;
2252
0
  if (segment == NULL)
2253
0
    return NULL;
2254
0
  dsm_pin_segment(segment);
2255
2256
  /* Store the handle in shared memory to be found by index. */
2257
0
  area->control->segment_handles[new_index] =
2258
0
    dsm_segment_handle(segment);
2259
  /* Track the highest segment index in the history of the area. */
2260
0
  if (area->control->high_segment_index < new_index)
2261
0
    area->control->high_segment_index = new_index;
2262
  /* Track the highest segment index this backend has ever mapped. */
2263
0
  if (area->high_segment_index < new_index)
2264
0
    area->high_segment_index = new_index;
2265
  /* Track total size of all segments. */
2266
0
  area->control->total_segment_size += total_size;
2267
0
  Assert(area->control->total_segment_size <=
2268
0
       area->control->max_total_segment_size);
2269
2270
  /* Build a segment map for this segment in this backend. */
2271
0
  segment_map = &area->segment_maps[new_index];
2272
0
  segment_map->segment = segment;
2273
0
  segment_map->mapped_address = dsm_segment_address(segment);
2274
0
  segment_map->header = (dsa_segment_header *) segment_map->mapped_address;
2275
0
  segment_map->fpm = (FreePageManager *)
2276
0
    (segment_map->mapped_address +
2277
0
     MAXALIGN(sizeof(dsa_segment_header)));
2278
0
  segment_map->pagemap = (dsa_pointer *)
2279
0
    (segment_map->mapped_address +
2280
0
     MAXALIGN(sizeof(dsa_segment_header)) +
2281
0
     MAXALIGN(sizeof(FreePageManager)));
2282
2283
  /* Set up the free page map. */
2284
0
  FreePageManagerInitialize(segment_map->fpm, segment_map->mapped_address);
2285
0
  FreePageManagerPut(segment_map->fpm, metadata_bytes / FPM_PAGE_SIZE,
2286
0
             usable_pages);
2287
2288
  /* Set up the segment header and put it in the appropriate bin. */
2289
0
  segment_map->header->magic =
2290
0
    DSA_SEGMENT_HEADER_MAGIC ^ area->control->handle ^ new_index;
2291
0
  segment_map->header->usable_pages = usable_pages;
2292
0
  segment_map->header->size = total_size;
2293
0
  segment_map->header->bin = contiguous_pages_to_segment_bin(usable_pages);
2294
0
  segment_map->header->prev = DSA_SEGMENT_INDEX_NONE;
2295
0
  segment_map->header->next =
2296
0
    area->control->segment_bins[segment_map->header->bin];
2297
0
  segment_map->header->freed = false;
2298
0
  area->control->segment_bins[segment_map->header->bin] = new_index;
2299
0
  if (segment_map->header->next != DSA_SEGMENT_INDEX_NONE)
2300
0
  {
2301
0
    dsa_segment_map *next =
2302
0
      get_segment_by_index(area, segment_map->header->next);
2303
2304
0
    Assert(next->header->bin == segment_map->header->bin);
2305
0
    next->header->prev = new_index;
2306
0
  }
2307
2308
0
  return segment_map;
2309
0
}
2310
2311
/*
2312
 * Check if any segments have been freed by destroy_superblock, so we can
2313
 * detach from them in this backend.  This function is called by
2314
 * dsa_get_address and dsa_free to make sure that a dsa_pointer they have
2315
 * received can be resolved to the correct segment.
2316
 *
2317
 * The danger we want to defend against is that there could be an old segment
2318
 * mapped into a given slot in this backend, and the dsa_pointer they have
2319
 * might refer to some new segment in the same slot.  So those functions must
2320
 * be sure to process all instructions to detach from a freed segment that had
2321
 * been generated by the time this process received the dsa_pointer, before
2322
 * they call get_segment_by_index.
2323
 */
2324
static void
2325
check_for_freed_segments(dsa_area *area)
2326
0
{
2327
0
  size_t    freed_segment_counter;
2328
2329
  /*
2330
   * Any other process that has freed a segment has incremented
2331
   * freed_segment_counter while holding an LWLock, and that must precede
2332
   * any backend creating a new segment in the same slot while holding an
2333
   * LWLock, and that must precede the creation of any dsa_pointer pointing
2334
   * into the new segment which might reach us here, and the caller must
2335
   * have sent the dsa_pointer to this process using appropriate memory
2336
   * synchronization (some kind of locking or atomic primitive or system
2337
   * call).  So all we need to do on the reading side is ask for the load of
2338
   * freed_segment_counter to follow the caller's load of the dsa_pointer it
2339
   * has, and we can be sure to detect any segments that had been freed as
2340
   * of the time that the dsa_pointer reached this process.
2341
   */
2342
0
  pg_read_barrier();
2343
0
  freed_segment_counter = area->control->freed_segment_counter;
2344
0
  if (unlikely(area->freed_segment_counter != freed_segment_counter))
2345
0
  {
2346
    /* Check all currently mapped segments to find what's been freed. */
2347
0
    LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE);
2348
0
    check_for_freed_segments_locked(area);
2349
0
    LWLockRelease(DSA_AREA_LOCK(area));
2350
0
  }
2351
0
}
2352
2353
/*
2354
 * Workhorse for check_for_freed_segments(), and also used directly in path
2355
 * where the area lock is already held.  This should be called after acquiring
2356
 * the lock but before looking up any segment by index number, to make sure we
2357
 * unmap any stale segments that might have previously had the same index as a
2358
 * current segment.
2359
 */
2360
static void
2361
check_for_freed_segments_locked(dsa_area *area)
2362
0
{
2363
0
  size_t    freed_segment_counter;
2364
2365
0
  Assert(LWLockHeldByMe(DSA_AREA_LOCK(area)));
2366
0
  freed_segment_counter = area->control->freed_segment_counter;
2367
0
  if (unlikely(area->freed_segment_counter != freed_segment_counter))
2368
0
  {
2369
0
    for (dsa_segment_index i = 0; i <= area->high_segment_index; ++i)
2370
0
    {
2371
0
      if (area->segment_maps[i].header != NULL &&
2372
0
        area->segment_maps[i].header->freed)
2373
0
      {
2374
0
        dsm_detach(area->segment_maps[i].segment);
2375
0
        area->segment_maps[i].segment = NULL;
2376
0
        area->segment_maps[i].header = NULL;
2377
0
        area->segment_maps[i].mapped_address = NULL;
2378
0
      }
2379
0
    }
2380
0
    area->freed_segment_counter = freed_segment_counter;
2381
0
  }
2382
0
}
2383
2384
/*
2385
 * Re-bin segment if it's no longer in the appropriate bin.
2386
 */
2387
static void
2388
rebin_segment(dsa_area *area, dsa_segment_map *segment_map)
2389
0
{
2390
0
  size_t    new_bin;
2391
0
  dsa_segment_index segment_index;
2392
2393
0
  new_bin = contiguous_pages_to_segment_bin(fpm_largest(segment_map->fpm));
2394
0
  if (segment_map->header->bin == new_bin)
2395
0
    return;
2396
2397
  /* Remove it from its current bin. */
2398
0
  unlink_segment(area, segment_map);
2399
2400
  /* Push it onto the front of its new bin. */
2401
0
  segment_index = get_segment_index(area, segment_map);
2402
0
  segment_map->header->prev = DSA_SEGMENT_INDEX_NONE;
2403
0
  segment_map->header->next = area->control->segment_bins[new_bin];
2404
0
  segment_map->header->bin = new_bin;
2405
0
  area->control->segment_bins[new_bin] = segment_index;
2406
0
  if (segment_map->header->next != DSA_SEGMENT_INDEX_NONE)
2407
0
  {
2408
0
    dsa_segment_map *next;
2409
2410
0
    next = get_segment_by_index(area, segment_map->header->next);
2411
    Assert(next->header->bin == new_bin);
2412
0
    next->header->prev = segment_index;
2413
0
  }
2414
0
}