PostgreSQL Source Code git master
Loading...
Searching...
No Matches
tidstore.c File Reference
#include "postgres.h"
#include "access/tidstore.h"
#include "miscadmin.h"
#include "nodes/bitmapset.h"
#include "storage/lwlock.h"
#include "utils/dsa.h"
#include "lib/radixtree.h"
Include dependency graph for tidstore.c:

Go to the source code of this file.

Data Structures

struct  BlocktableEntry
 
struct  TidStore
 
struct  TidStoreIter
 

Macros

#define WORDNUM(x)   ((x) / BITS_PER_BITMAPWORD)
 
#define BITNUM(x)   ((x) % BITS_PER_BITMAPWORD)
 
#define WORDS_PER_PAGE(n)   ((n) / BITS_PER_BITMAPWORD + 1)
 
#define NUM_FULL_OFFSETS   ((sizeof(uintptr_t) - sizeof(uint8) - sizeof(int8)) / sizeof(OffsetNumber))
 
#define MAX_OFFSET_IN_BITMAP   Min(BITS_PER_BITMAPWORD * PG_INT8_MAX - 1, MaxOffsetNumber)
 
#define MaxBlocktableEntrySize
 
#define RT_PREFIX   local_ts
 
#define RT_SCOPE   static
 
#define RT_DECLARE
 
#define RT_DEFINE
 
#define RT_VALUE_TYPE   BlocktableEntry
 
#define RT_VARLEN_VALUE_SIZE(page)
 
#define RT_RUNTIME_EMBEDDABLE_VALUE
 
#define RT_PREFIX   shared_ts
 
#define RT_SHMEM
 
#define RT_SCOPE   static
 
#define RT_DECLARE
 
#define RT_DEFINE
 
#define RT_VALUE_TYPE   BlocktableEntry
 
#define RT_VARLEN_VALUE_SIZE(page)
 
#define RT_RUNTIME_EMBEDDABLE_VALUE
 
#define TidStoreIsShared(ts)   ((ts)->area != NULL)
 

Typedefs

typedef struct BlocktableEntry BlocktableEntry
 

Functions

TidStoreTidStoreCreateLocal (size_t max_bytes, bool insert_only)
 
TidStoreTidStoreCreateShared (size_t max_bytes, int tranche_id)
 
TidStoreTidStoreAttach (dsa_handle area_handle, dsa_pointer handle)
 
void TidStoreDetach (TidStore *ts)
 
void TidStoreLockExclusive (TidStore *ts)
 
void TidStoreLockShare (TidStore *ts)
 
void TidStoreUnlock (TidStore *ts)
 
void TidStoreDestroy (TidStore *ts)
 
void TidStoreSetBlockOffsets (TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, int num_offsets)
 
bool TidStoreIsMember (TidStore *ts, const ItemPointerData *tid)
 
TidStoreIterTidStoreBeginIterate (TidStore *ts)
 
TidStoreIterResultTidStoreIterateNext (TidStoreIter *iter)
 
void TidStoreEndIterate (TidStoreIter *iter)
 
size_t TidStoreMemoryUsage (TidStore *ts)
 
dsa_areaTidStoreGetDSA (TidStore *ts)
 
dsa_pointer TidStoreGetHandle (TidStore *ts)
 
int TidStoreGetBlockOffsets (TidStoreIterResult *result, OffsetNumber *offsets, int max_offsets)
 

Macro Definition Documentation

◆ BITNUM

#define BITNUM (   x)    ((x) % BITS_PER_BITMAPWORD)

Definition at line 32 of file tidstore.c.

◆ MAX_OFFSET_IN_BITMAP

#define MAX_OFFSET_IN_BITMAP   Min(BITS_PER_BITMAPWORD * PG_INT8_MAX - 1, MaxOffsetNumber)

Definition at line 84 of file tidstore.c.

◆ MaxBlocktableEntrySize

#define MaxBlocktableEntrySize
Value:
uint32 bitmapword
Definition bitmapset.h:44
static int fb(int x)
#define WORDS_PER_PAGE(n)
Definition tidstore.c:35
#define MAX_OFFSET_IN_BITMAP
Definition tidstore.c:84

Definition at line 86 of file tidstore.c.

114{
115 /*
116 * MemoryContext for the radix tree when using local memory, NULL for
117 * shared memory
118 */
119 MemoryContext rt_context;
120
121 /* Storage for TIDs. Use either one depending on TidStoreIsShared() */
122 union
123 {
124 local_ts_radix_tree *local;
125 shared_ts_radix_tree *shared;
126 } tree;
127
128 /* DSA area for TidStore if using shared memory */
129 dsa_area *area;
130};
131#define TidStoreIsShared(ts) ((ts)->area != NULL)
132
133/* Iterator for TidStore */
134struct TidStoreIter
135{
136 TidStore *ts;
137
138 /* iterator of radix tree. Use either one depending on TidStoreIsShared() */
139 union
140 {
143 } tree_iter;
144
145 /* output for the caller */
147};
148
149/*
150 * Create a TidStore. The TidStore will live in the memory context that is
151 * CurrentMemoryContext at the time of this call. The TID storage, backed
152 * by a radix tree, will live in its child memory context, rt_context.
153 *
154 * "max_bytes" is not an internally-enforced limit; it is used only as a
155 * hint to cap the memory block size of the memory context for TID storage.
156 * This reduces space wastage due to over-allocation. If the caller wants to
157 * monitor memory usage, it must compare its limit with the value reported
158 * by TidStoreMemoryUsage().
159 */
160TidStore *
161TidStoreCreateLocal(size_t max_bytes, bool insert_only)
162{
163 TidStore *ts;
164 size_t initBlockSize = ALLOCSET_DEFAULT_INITSIZE;
166 size_t maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
167
169
170 /* choose the maxBlockSize to be no larger than 1/16 of max_bytes */
171 while (16 * maxBlockSize > max_bytes)
172 maxBlockSize >>= 1;
173
174 if (maxBlockSize < ALLOCSET_DEFAULT_INITSIZE)
175 maxBlockSize = ALLOCSET_DEFAULT_INITSIZE;
176
177 /* Create a memory context for the TID storage */
178 if (insert_only)
179 {
181 "TID storage",
183 initBlockSize,
184 maxBlockSize);
185 }
186 else
187 {
189 "TID storage",
191 initBlockSize,
192 maxBlockSize);
193 }
194
196
197 return ts;
198}
199
200/*
201 * Similar to TidStoreCreateLocal() but create a shared TidStore on a
202 * DSA area.
203 *
204 * The returned object is allocated in backend-local memory.
205 */
206TidStore *
207TidStoreCreateShared(size_t max_bytes, int tranche_id)
208{
209 TidStore *ts;
210 dsa_area *area;
213
215
216 /*
217 * Choose the initial and maximum DSA segment sizes to be no longer than
218 * 1/8 of max_bytes.
219 */
220 while (8 * dsa_max_size > max_bytes)
221 dsa_max_size >>= 1;
222
225
228
229 area = dsa_create_ext(tranche_id, dsa_init_size, dsa_max_size);
230 ts->tree.shared = shared_ts_create(area, tranche_id);
231 ts->area = area;
232
233 return ts;
234}
235
236/*
237 * Attach to the shared TidStore. 'area_handle' is the DSA handle where
238 * the TidStore is created. 'handle' is the dsa_pointer returned by
239 * TidStoreGetHandle(). The returned object is allocated in backend-local
240 * memory using the CurrentMemoryContext.
241 */
242TidStore *
244{
245 TidStore *ts;
246 dsa_area *area;
247
249 Assert(DsaPointerIsValid(handle));
250
251 /* create per-backend state */
253
254 area = dsa_attach(area_handle);
255
256 /* Find the shared the shared radix tree */
257 ts->tree.shared = shared_ts_attach(area, handle);
258 ts->area = area;
259
260 return ts;
261}
262
263/*
264 * Detach from a TidStore. This also detaches from radix tree and frees
265 * the backend-local resources.
266 */
267void
269{
271
273 dsa_detach(ts->area);
274
275 pfree(ts);
276}
277
278/*
279 * Lock support functions.
280 *
281 * We can use the radix tree's lock for shared TidStore as the data we
282 * need to protect is only the shared radix tree.
283 */
284
285void
287{
288 if (TidStoreIsShared(ts))
290}
291
292void
294{
295 if (TidStoreIsShared(ts))
297}
298
299void
301{
302 if (TidStoreIsShared(ts))
304}
305
306/*
307 * Destroy a TidStore, returning all memory.
308 *
309 * Note that the caller must be certain that no other backend will attempt to
310 * access the TidStore before calling this function. Other backend must
311 * explicitly call TidStoreDetach() to free up backend-local memory associated
312 * with the TidStore. The backend that calls TidStoreDestroy() must not call
313 * TidStoreDetach().
314 */
315void
317{
318 /* Destroy underlying radix tree */
319 if (TidStoreIsShared(ts))
320 {
322 dsa_detach(ts->area);
323 }
324 else
325 {
328 }
329
330 pfree(ts);
331}
332
333/*
334 * Create or replace an entry for the given block and array of offsets.
335 *
336 * NB: This function is designed and optimized for vacuum's heap scanning
337 * phase, so has some limitations:
338 *
339 * - The offset numbers "offsets" must be sorted in ascending order.
340 * - If the block number already exists, the entry will be replaced --
341 * there is no way to add or remove offsets from an entry.
342 */
343void
345 int num_offsets)
346{
347 union
348 {
351 } data;
352 BlocktableEntry *page = (BlocktableEntry *) data.data;
354 int wordnum;
356 int idx = 0;
357
358 Assert(num_offsets > 0);
359
360 /* Check if the given offset numbers are ordered */
361 for (int i = 1; i < num_offsets; i++)
362 Assert(offsets[i] > offsets[i - 1]);
363
364 memset(page, 0, offsetof(BlocktableEntry, words));
365
367 {
368 for (int i = 0; i < num_offsets; i++)
369 {
370 OffsetNumber off = offsets[i];
371
372 /* safety check to ensure we don't overrun bit array bounds */
373 if (off == InvalidOffsetNumber || off > MAX_OFFSET_IN_BITMAP)
374 elog(ERROR, "tuple offset out of range: %u", off);
375
376 page->header.full_offsets[i] = off;
377 }
378
379 page->header.nwords = 0;
380 }
381 else
382 {
384 wordnum <= WORDNUM(offsets[num_offsets - 1]);
386 {
387 word = 0;
388
389 while (idx < num_offsets)
390 {
391 OffsetNumber off = offsets[idx];
392
393 /* safety check to ensure we don't overrun bit array bounds */
394 if (off == InvalidOffsetNumber || off > MAX_OFFSET_IN_BITMAP)
395 elog(ERROR, "tuple offset out of range: %u", off);
396
397 if (off >= next_word_threshold)
398 break;
399
400 word |= ((bitmapword) 1 << BITNUM(off));
401 idx++;
402 }
403
404 /* write out offset bitmap for this wordnum */
405 page->words[wordnum] = word;
406 }
407
408 page->header.nwords = wordnum;
409 Assert(page->header.nwords == WORDS_PER_PAGE(offsets[num_offsets - 1]));
410 }
411
412 if (TidStoreIsShared(ts))
413 shared_ts_set(ts->tree.shared, blkno, page);
414 else
415 local_ts_set(ts->tree.local, blkno, page);
416}
417
418/* Return true if the given TID is present in the TidStore */
419bool
421{
422 int wordnum;
423 int bitnum;
424 BlocktableEntry *page;
427
428 if (TidStoreIsShared(ts))
429 page = shared_ts_find(ts->tree.shared, blk);
430 else
431 page = local_ts_find(ts->tree.local, blk);
432
433 /* no entry for the blk */
434 if (page == NULL)
435 return false;
436
437 if (page->header.nwords == 0)
438 {
439 /* we have offsets in the header */
440 for (int i = 0; i < NUM_FULL_OFFSETS; i++)
441 {
442 if (page->header.full_offsets[i] == off)
443 return true;
444 }
445 return false;
446 }
447 else
448 {
449 wordnum = WORDNUM(off);
450 bitnum = BITNUM(off);
451
452 /* no bitmap for the off */
453 if (wordnum >= page->header.nwords)
454 return false;
455
456 return (page->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0;
457 }
458}
459
460/*
461 * Prepare to iterate through a TidStore.
462 *
463 * The TidStoreIter struct is created in the caller's memory context, and it
464 * will be freed in TidStoreEndIterate.
465 *
466 * The caller is responsible for locking TidStore until the iteration is
467 * finished.
468 */
471{
472 TidStoreIter *iter;
473
475 iter->ts = ts;
476
477 if (TidStoreIsShared(ts))
479 else
481
482 return iter;
483}
484
485
486/*
487 * Return a result that contains the next block number and that can be used to
488 * obtain the set of offsets by calling TidStoreGetBlockOffsets(). The result
489 * is copyable.
490 */
493{
494 uint64 key;
495 BlocktableEntry *page;
496
497 if (TidStoreIsShared(iter->ts))
498 page = shared_ts_iterate_next(iter->tree_iter.shared, &key);
499 else
500 page = local_ts_iterate_next(iter->tree_iter.local, &key);
501
502 if (page == NULL)
503 return NULL;
504
505 iter->output.blkno = key;
506 iter->output.internal_page = page;
507
508 return &(iter->output);
509}
510
511/*
512 * Finish the iteration on TidStore.
513 *
514 * The caller is responsible for releasing any locks.
515 */
516void
518{
519 if (TidStoreIsShared(iter->ts))
521 else
523
524 pfree(iter);
525}
526
527/*
528 * Return the memory usage of TidStore.
529 */
530size_t
532{
533 if (TidStoreIsShared(ts))
535 else
536 return local_ts_memory_usage(ts->tree.local);
537}
538
539/*
540 * Return the DSA area where the TidStore lives.
541 */
542dsa_area *
544{
546
547 return ts->area;
548}
549
552{
554
556}
557
558/*
559 * Given a TidStoreIterResult returned by TidStoreIterateNext(), extract the
560 * offset numbers. Returns the number of offsets filled in, if <=
561 * max_offsets. Otherwise, fills in as much as it can in the given space, and
562 * returns the size of the buffer that would be needed.
563 */
564int
566 OffsetNumber *offsets,
567 int max_offsets)
568{
569 BlocktableEntry *page = result->internal_page;
570 int num_offsets = 0;
571 int wordnum;
572
573 if (page->header.nwords == 0)
574 {
575 /* we have offsets in the header */
576 for (int i = 0; i < NUM_FULL_OFFSETS; i++)
577 {
579 {
581 offsets[num_offsets] = page->header.full_offsets[i];
582 num_offsets++;
583 }
584 }
585 }
586 else
587 {
588 for (wordnum = 0; wordnum < page->header.nwords; wordnum++)
589 {
590 bitmapword w = page->words[wordnum];
591 int off = wordnum * BITS_PER_BITMAPWORD;
592
593 while (w != 0)
594 {
595 if (w & 1)
596 {
598 offsets[num_offsets] = (OffsetNumber) off;
599 num_offsets++;
600 }
601 off++;
602 w >>= 1;
603 }
604 }
605 }
606
607 return num_offsets;
608}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
#define BITS_PER_BITMAPWORD
Definition bitmapset.h:43
uint32 BlockNumber
Definition block.h:31
MemoryContext BumpContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition bump.c:133
#define Assert(condition)
Definition c.h:873
uint64_t uint64
Definition c.h:547
dsa_area * dsa_attach(dsa_handle handle)
Definition dsa.c:510
dsa_area * dsa_create_ext(int tranche_id, size_t init_segment_size, size_t max_segment_size)
Definition dsa.c:421
void dsa_detach(dsa_area *area)
Definition dsa.c:2002
uint64 dsa_pointer
Definition dsa.h:62
#define DSA_MIN_SEGMENT_SIZE
Definition dsa.h:100
dsm_handle dsa_handle
Definition dsa.h:136
#define DSA_DEFAULT_INIT_SEGMENT_SIZE
Definition dsa.h:97
#define DSA_HANDLE_INVALID
Definition dsa.h:139
#define DsaPointerIsValid(x)
Definition dsa.h:106
#define DSA_MAX_SEGMENT_SIZE
Definition dsa.h:103
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc0_object(type)
Definition fe_memutils.h:75
int i
Definition isn.c:77
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
void pfree(void *pointer)
Definition mcxt.c:1616
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_MAXSIZE
Definition memutils.h:159
#define ALLOCSET_DEFAULT_MINSIZE
Definition memutils.h:157
#define ALLOCSET_DEFAULT_INITSIZE
Definition memutils.h:158
#define InvalidOffsetNumber
Definition off.h:26
uint16 OffsetNumber
Definition off.h:24
const void * data
tree
Definition radixtree.h:1828
static void word(struct vars *v, int dir, struct state *lp, struct state *rp)
Definition regcomp.c:1476
bitmapword words[FLEXIBLE_ARRAY_MEMBER]
Definition tidstore.c:76
struct BlocktableEntry::@12 header
OffsetNumber full_offsets[NUM_FULL_OFFSETS]
Definition tidstore.c:63
BlockNumber blkno
Definition tidstore.h:29
void * internal_page
Definition tidstore.h:30
shared_ts_iter * shared
Definition tidstore.c:142
local_ts_iter * local
Definition tidstore.c:143
TidStore * ts
Definition tidstore.c:137
TidStoreIterResult output
Definition tidstore.c:147
union TidStoreIter::@14 tree_iter
dsa_area * area
Definition tidstore.c:130
MemoryContext rt_context
Definition tidstore.c:120
shared_ts_radix_tree * shared
Definition tidstore.c:126
local_ts_radix_tree * local
Definition tidstore.c:125
union TidStore::@13 tree
dsa_area * TidStoreGetDSA(TidStore *ts)
Definition tidstore.c:544
bool TidStoreIsMember(TidStore *ts, const ItemPointerData *tid)
Definition tidstore.c:421
#define NUM_FULL_OFFSETS
Definition tidstore.c:38
#define WORDNUM(x)
Definition tidstore.c:31
TidStoreIter * TidStoreBeginIterate(TidStore *ts)
Definition tidstore.c:471
void TidStoreEndIterate(TidStoreIter *iter)
Definition tidstore.c:518
void TidStoreDetach(TidStore *ts)
Definition tidstore.c:269
TidStoreIterResult * TidStoreIterateNext(TidStoreIter *iter)
Definition tidstore.c:493
void TidStoreLockShare(TidStore *ts)
Definition tidstore.c:294
TidStore * TidStoreCreateLocal(size_t max_bytes, bool insert_only)
Definition tidstore.c:162
void TidStoreDestroy(TidStore *ts)
Definition tidstore.c:317
#define BITNUM(x)
Definition tidstore.c:32
void TidStoreUnlock(TidStore *ts)
Definition tidstore.c:301
#define TidStoreIsShared(ts)
Definition tidstore.c:132
TidStore * TidStoreAttach(dsa_handle area_handle, dsa_pointer handle)
Definition tidstore.c:244
int TidStoreGetBlockOffsets(TidStoreIterResult *result, OffsetNumber *offsets, int max_offsets)
Definition tidstore.c:566
void TidStoreLockExclusive(TidStore *ts)
Definition tidstore.c:287
dsa_pointer TidStoreGetHandle(TidStore *ts)
Definition tidstore.c:552
#define MaxBlocktableEntrySize
Definition tidstore.c:86
void TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, int num_offsets)
Definition tidstore.c:345
size_t TidStoreMemoryUsage(TidStore *ts)
Definition tidstore.c:532
TidStore * TidStoreCreateShared(size_t max_bytes, int tranche_id)
Definition tidstore.c:208

◆ NUM_FULL_OFFSETS

#define NUM_FULL_OFFSETS   ((sizeof(uintptr_t) - sizeof(uint8) - sizeof(int8)) / sizeof(OffsetNumber))

Definition at line 38 of file tidstore.c.

◆ RT_DECLARE [1/2]

#define RT_DECLARE

Definition at line 92 of file tidstore.c.

◆ RT_DECLARE [2/2]

#define RT_DECLARE

Definition at line 92 of file tidstore.c.

◆ RT_DEFINE [1/2]

#define RT_DEFINE

Definition at line 93 of file tidstore.c.

◆ RT_DEFINE [2/2]

#define RT_DEFINE

Definition at line 93 of file tidstore.c.

◆ RT_PREFIX [1/2]

#define RT_PREFIX   local_ts

Definition at line 90 of file tidstore.c.

◆ RT_PREFIX [2/2]

#define RT_PREFIX   shared_ts

Definition at line 90 of file tidstore.c.

◆ RT_RUNTIME_EMBEDDABLE_VALUE [1/2]

#define RT_RUNTIME_EMBEDDABLE_VALUE

Definition at line 98 of file tidstore.c.

◆ RT_RUNTIME_EMBEDDABLE_VALUE [2/2]

#define RT_RUNTIME_EMBEDDABLE_VALUE

Definition at line 98 of file tidstore.c.

◆ RT_SCOPE [1/2]

#define RT_SCOPE   static

Definition at line 91 of file tidstore.c.

◆ RT_SCOPE [2/2]

#define RT_SCOPE   static

Definition at line 91 of file tidstore.c.

◆ RT_SHMEM

#define RT_SHMEM

Definition at line 102 of file tidstore.c.

◆ RT_VALUE_TYPE [1/2]

#define RT_VALUE_TYPE   BlocktableEntry

Definition at line 94 of file tidstore.c.

◆ RT_VALUE_TYPE [2/2]

#define RT_VALUE_TYPE   BlocktableEntry

Definition at line 94 of file tidstore.c.

◆ RT_VARLEN_VALUE_SIZE [1/2]

#define RT_VARLEN_VALUE_SIZE (   page)
Value:
sizeof(bitmapword) * (page)->header.nwords)

Definition at line 95 of file tidstore.c.

◆ RT_VARLEN_VALUE_SIZE [2/2]

#define RT_VARLEN_VALUE_SIZE (   page)
Value:
sizeof(bitmapword) * (page)->header.nwords)

Definition at line 95 of file tidstore.c.

◆ TidStoreIsShared

#define TidStoreIsShared (   ts)    ((ts)->area != NULL)

Definition at line 132 of file tidstore.c.

◆ WORDNUM

#define WORDNUM (   x)    ((x) / BITS_PER_BITMAPWORD)

Definition at line 31 of file tidstore.c.

◆ WORDS_PER_PAGE

#define WORDS_PER_PAGE (   n)    ((n) / BITS_PER_BITMAPWORD + 1)

Definition at line 35 of file tidstore.c.

Typedef Documentation

◆ BlocktableEntry

Function Documentation

◆ TidStoreAttach()

TidStore * TidStoreAttach ( dsa_handle  area_handle,
dsa_pointer  handle 
)

Definition at line 244 of file tidstore.c.

245{
246 TidStore *ts;
247 dsa_area *area;
248
250 Assert(DsaPointerIsValid(handle));
251
252 /* create per-backend state */
254
255 area = dsa_attach(area_handle);
256
257 /* Find the shared the shared radix tree */
258 ts->tree.shared = shared_ts_attach(area, handle);
259 ts->area = area;
260
261 return ts;
262}

References TidStore::area, Assert, dsa_attach(), DSA_HANDLE_INVALID, DsaPointerIsValid, fb(), palloc0_object, TidStore::shared, and TidStore::tree.

Referenced by parallel_vacuum_main().

◆ TidStoreBeginIterate()

TidStoreIter * TidStoreBeginIterate ( TidStore ts)

◆ TidStoreCreateLocal()

TidStore * TidStoreCreateLocal ( size_t  max_bytes,
bool  insert_only 
)

Definition at line 162 of file tidstore.c.

163{
164 TidStore *ts;
165 size_t initBlockSize = ALLOCSET_DEFAULT_INITSIZE;
167 size_t maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
168
170
171 /* choose the maxBlockSize to be no larger than 1/16 of max_bytes */
172 while (16 * maxBlockSize > max_bytes)
173 maxBlockSize >>= 1;
174
175 if (maxBlockSize < ALLOCSET_DEFAULT_INITSIZE)
176 maxBlockSize = ALLOCSET_DEFAULT_INITSIZE;
177
178 /* Create a memory context for the TID storage */
179 if (insert_only)
180 {
182 "TID storage",
184 initBlockSize,
185 maxBlockSize);
186 }
187 else
188 {
190 "TID storage",
192 initBlockSize,
193 maxBlockSize);
194 }
195
197
198 return ts;
199}

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate, BumpContextCreate(), CurrentMemoryContext, fb(), TidStore::local, palloc0_object, TidStore::rt_context, and TidStore::tree.

Referenced by dead_items_alloc(), dead_items_reset(), and test_create().

◆ TidStoreCreateShared()

TidStore * TidStoreCreateShared ( size_t  max_bytes,
int  tranche_id 
)

Definition at line 208 of file tidstore.c.

209{
210 TidStore *ts;
211 dsa_area *area;
214
216
217 /*
218 * Choose the initial and maximum DSA segment sizes to be no longer than
219 * 1/8 of max_bytes.
220 */
221 while (8 * dsa_max_size > max_bytes)
222 dsa_max_size >>= 1;
223
226
229
230 area = dsa_create_ext(tranche_id, dsa_init_size, dsa_max_size);
231 ts->tree.shared = shared_ts_create(area, tranche_id);
232 ts->area = area;
233
234 return ts;
235}

References TidStore::area, dsa_create_ext(), DSA_DEFAULT_INIT_SEGMENT_SIZE, DSA_MAX_SEGMENT_SIZE, DSA_MIN_SEGMENT_SIZE, fb(), palloc0_object, TidStore::shared, and TidStore::tree.

Referenced by parallel_vacuum_init(), parallel_vacuum_reset_dead_items(), and test_create().

◆ TidStoreDestroy()

void TidStoreDestroy ( TidStore ts)

Definition at line 317 of file tidstore.c.

318{
319 /* Destroy underlying radix tree */
320 if (TidStoreIsShared(ts))
321 {
323 dsa_detach(ts->area);
324 }
325 else
326 {
329 }
330
331 pfree(ts);
332}

References TidStore::area, dsa_detach(), fb(), TidStore::local, MemoryContextDelete(), pfree(), TidStore::rt_context, TidStore::shared, TidStoreIsShared, and TidStore::tree.

Referenced by dead_items_reset(), parallel_vacuum_end(), parallel_vacuum_reset_dead_items(), and test_destroy().

◆ TidStoreDetach()

void TidStoreDetach ( TidStore ts)

Definition at line 269 of file tidstore.c.

270{
272
274 dsa_detach(ts->area);
275
276 pfree(ts);
277}

References TidStore::area, Assert, dsa_detach(), fb(), pfree(), TidStore::shared, TidStoreIsShared, and TidStore::tree.

Referenced by parallel_vacuum_main().

◆ TidStoreEndIterate()

void TidStoreEndIterate ( TidStoreIter iter)

◆ TidStoreGetBlockOffsets()

int TidStoreGetBlockOffsets ( TidStoreIterResult result,
OffsetNumber offsets,
int  max_offsets 
)

Definition at line 566 of file tidstore.c.

569{
570 BlocktableEntry *page = result->internal_page;
571 int num_offsets = 0;
572 int wordnum;
573
574 if (page->header.nwords == 0)
575 {
576 /* we have offsets in the header */
577 for (int i = 0; i < NUM_FULL_OFFSETS; i++)
578 {
580 {
582 offsets[num_offsets] = page->header.full_offsets[i];
583 num_offsets++;
584 }
585 }
586 }
587 else
588 {
589 for (wordnum = 0; wordnum < page->header.nwords; wordnum++)
590 {
591 bitmapword w = page->words[wordnum];
592 int off = wordnum * BITS_PER_BITMAPWORD;
593
594 while (w != 0)
595 {
596 if (w & 1)
597 {
599 offsets[num_offsets] = (OffsetNumber) off;
600 num_offsets++;
601 }
602 off++;
603 w >>= 1;
604 }
605 }
606 }
607
608 return num_offsets;
609}

References BITS_PER_BITMAPWORD, fb(), BlocktableEntry::full_offsets, BlocktableEntry::header, i, TidStoreIterResult::internal_page, InvalidOffsetNumber, NUM_FULL_OFFSETS, BlocktableEntry::nwords, and BlocktableEntry::words.

Referenced by check_set_block_offsets(), and lazy_vacuum_heap_rel().

◆ TidStoreGetDSA()

dsa_area * TidStoreGetDSA ( TidStore ts)

Definition at line 544 of file tidstore.c.

545{
547
548 return ts->area;
549}

References TidStore::area, Assert, and TidStoreIsShared.

Referenced by parallel_vacuum_init(), parallel_vacuum_reset_dead_items(), and test_create().

◆ TidStoreGetHandle()

dsa_pointer TidStoreGetHandle ( TidStore ts)

Definition at line 552 of file tidstore.c.

553{
555
557}

References Assert, fb(), TidStore::shared, TidStoreIsShared, and TidStore::tree.

Referenced by parallel_vacuum_init(), and parallel_vacuum_reset_dead_items().

◆ TidStoreIsMember()

bool TidStoreIsMember ( TidStore ts,
const ItemPointerData tid 
)

Definition at line 421 of file tidstore.c.

422{
423 int wordnum;
424 int bitnum;
425 BlocktableEntry *page;
428
429 if (TidStoreIsShared(ts))
430 page = shared_ts_find(ts->tree.shared, blk);
431 else
432 page = local_ts_find(ts->tree.local, blk);
433
434 /* no entry for the blk */
435 if (page == NULL)
436 return false;
437
438 if (page->header.nwords == 0)
439 {
440 /* we have offsets in the header */
441 for (int i = 0; i < NUM_FULL_OFFSETS; i++)
442 {
443 if (page->header.full_offsets[i] == off)
444 return true;
445 }
446 return false;
447 }
448 else
449 {
450 wordnum = WORDNUM(off);
451 bitnum = BITNUM(off);
452
453 /* no bitmap for the off */
454 if (wordnum >= page->header.nwords)
455 return false;
456
457 return (page->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0;
458 }
459}

References BITNUM, fb(), BlocktableEntry::full_offsets, BlocktableEntry::header, i, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), TidStore::local, NUM_FULL_OFFSETS, BlocktableEntry::nwords, TidStore::shared, TidStoreIsShared, TidStore::tree, WORDNUM, and BlocktableEntry::words.

Referenced by check_set_block_offsets(), and vac_tid_reaped().

◆ TidStoreIterateNext()

TidStoreIterResult * TidStoreIterateNext ( TidStoreIter iter)

Definition at line 493 of file tidstore.c.

494{
495 uint64 key;
496 BlocktableEntry *page;
497
498 if (TidStoreIsShared(iter->ts))
499 page = shared_ts_iterate_next(iter->tree_iter.shared, &key);
500 else
501 page = local_ts_iterate_next(iter->tree_iter.local, &key);
502
503 if (page == NULL)
504 return NULL;
505
506 iter->output.blkno = key;
507 iter->output.internal_page = page;
508
509 return &(iter->output);
510}

References TidStoreIterResult::blkno, fb(), TidStoreIterResult::internal_page, TidStoreIter::local, TidStoreIter::output, TidStoreIter::shared, TidStoreIsShared, TidStoreIter::tree_iter, and TidStoreIter::ts.

Referenced by check_set_block_offsets(), and vacuum_reap_lp_read_stream_next().

◆ TidStoreLockExclusive()

void TidStoreLockExclusive ( TidStore ts)

Definition at line 287 of file tidstore.c.

288{
289 if (TidStoreIsShared(ts))
291}

References fb(), TidStore::shared, TidStoreIsShared, and TidStore::tree.

Referenced by do_set_block_offsets().

◆ TidStoreLockShare()

void TidStoreLockShare ( TidStore ts)

Definition at line 294 of file tidstore.c.

295{
296 if (TidStoreIsShared(ts))
298}

References fb(), TidStore::shared, TidStoreIsShared, and TidStore::tree.

Referenced by check_set_block_offsets().

◆ TidStoreMemoryUsage()

size_t TidStoreMemoryUsage ( TidStore ts)

◆ TidStoreSetBlockOffsets()

void TidStoreSetBlockOffsets ( TidStore ts,
BlockNumber  blkno,
OffsetNumber offsets,
int  num_offsets 
)

Definition at line 345 of file tidstore.c.

347{
348 union
349 {
352 } data;
353 BlocktableEntry *page = (BlocktableEntry *) data.data;
355 int wordnum;
357 int idx = 0;
358
359 Assert(num_offsets > 0);
360
361 /* Check if the given offset numbers are ordered */
362 for (int i = 1; i < num_offsets; i++)
363 Assert(offsets[i] > offsets[i - 1]);
364
365 memset(page, 0, offsetof(BlocktableEntry, words));
366
368 {
369 for (int i = 0; i < num_offsets; i++)
370 {
371 OffsetNumber off = offsets[i];
372
373 /* safety check to ensure we don't overrun bit array bounds */
374 if (off == InvalidOffsetNumber || off > MAX_OFFSET_IN_BITMAP)
375 elog(ERROR, "tuple offset out of range: %u", off);
376
377 page->header.full_offsets[i] = off;
378 }
379
380 page->header.nwords = 0;
381 }
382 else
383 {
385 wordnum <= WORDNUM(offsets[num_offsets - 1]);
387 {
388 word = 0;
389
390 while (idx < num_offsets)
391 {
392 OffsetNumber off = offsets[idx];
393
394 /* safety check to ensure we don't overrun bit array bounds */
395 if (off == InvalidOffsetNumber || off > MAX_OFFSET_IN_BITMAP)
396 elog(ERROR, "tuple offset out of range: %u", off);
397
398 if (off >= next_word_threshold)
399 break;
400
401 word |= ((bitmapword) 1 << BITNUM(off));
402 idx++;
403 }
404
405 /* write out offset bitmap for this wordnum */
406 page->words[wordnum] = word;
407 }
408
409 page->header.nwords = wordnum;
410 Assert(page->header.nwords == WORDS_PER_PAGE(offsets[num_offsets - 1]));
411 }
412
413 if (TidStoreIsShared(ts))
414 shared_ts_set(ts->tree.shared, blkno, page);
415 else
416 local_ts_set(ts->tree.local, blkno, page);
417}

References Assert, BITNUM, BITS_PER_BITMAPWORD, data, elog, ERROR, fb(), BlocktableEntry::full_offsets, BlocktableEntry::header, i, idx(), InvalidOffsetNumber, TidStore::local, MAX_OFFSET_IN_BITMAP, MaxBlocktableEntrySize, NUM_FULL_OFFSETS, BlocktableEntry::nwords, TidStore::shared, TidStoreIsShared, TidStore::tree, word(), WORDNUM, BlocktableEntry::words, and WORDS_PER_PAGE.

Referenced by dead_items_add(), and do_set_block_offsets().

◆ TidStoreUnlock()

void TidStoreUnlock ( TidStore ts)

Definition at line 301 of file tidstore.c.

302{
303 if (TidStoreIsShared(ts))
305}

References fb(), TidStore::shared, TidStoreIsShared, and TidStore::tree.

Referenced by check_set_block_offsets(), and do_set_block_offsets().