PostgreSQL Source Code git master
Loading...
Searching...
No Matches
bump.c File Reference
#include "postgres.h"
#include "lib/ilist.h"
#include "port/pg_bitutils.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
#include "utils/memutils_memorychunk.h"
#include "utils/memutils_internal.h"
Include dependency graph for bump.c:

Go to the source code of this file.

Data Structures

struct  BumpContext
 
struct  BumpBlock
 

Macros

#define Bump_BLOCKHDRSZ   MAXALIGN(sizeof(BumpBlock))
 
#define FIRST_BLOCKHDRSZ
 
#define Bump_CHUNKHDRSZ   0
 
#define Bump_CHUNK_FRACTION   8
 
#define KeeperBlock(set)
 
#define IsKeeperBlock(set, blk)   (KeeperBlock(set) == (blk))
 
#define BumpIsValid(set)    ((set) && IsA(set, BumpContext))
 
#define ExternalChunkGetBlock(chunk)    (BumpBlock *) ((char *) chunk - Bump_BLOCKHDRSZ)
 

Typedefs

typedef struct BumpBlock BumpBlock
 
typedef struct BumpContext BumpContext
 

Functions

static void BumpBlockInit (BumpContext *context, BumpBlock *block, Size blksize)
 
static bool BumpBlockIsEmpty (BumpBlock *block)
 
static void BumpBlockMarkEmpty (BumpBlock *block)
 
static Size BumpBlockFreeBytes (BumpBlock *block)
 
static void BumpBlockFree (BumpContext *set, BumpBlock *block)
 
MemoryContext BumpContextCreate (MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
 
void BumpReset (MemoryContext context)
 
void BumpDelete (MemoryContext context)
 
static pg_noinline voidBumpAllocLarge (MemoryContext context, Size size, int flags)
 
static voidBumpAllocChunkFromBlock (MemoryContext context, BumpBlock *block, Size size, Size chunk_size)
 
static pg_noinline voidBumpAllocFromNewBlock (MemoryContext context, Size size, int flags, Size chunk_size)
 
voidBumpAlloc (MemoryContext context, Size size, int flags)
 
void BumpFree (void *pointer)
 
voidBumpRealloc (void *pointer, Size size, int flags)
 
MemoryContext BumpGetChunkContext (void *pointer)
 
Size BumpGetChunkSpace (void *pointer)
 
bool BumpIsEmpty (MemoryContext context)
 
void BumpStats (MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
 

Macro Definition Documentation

◆ Bump_BLOCKHDRSZ

#define Bump_BLOCKHDRSZ   MAXALIGN(sizeof(BumpBlock))

Definition at line 48 of file bump.c.

◆ Bump_CHUNK_FRACTION

#define Bump_CHUNK_FRACTION   8

Definition at line 59 of file bump.c.

◆ Bump_CHUNKHDRSZ

#define Bump_CHUNKHDRSZ   0

Definition at line 56 of file bump.c.

◆ BumpIsValid

#define BumpIsValid (   set)     ((set) && IsA(set, BumpContext))

Definition at line 102 of file bump.c.

134{
137 BumpContext *set;
138 BumpBlock *block;
139
140 /* ensure MemoryChunk's size is properly maxaligned */
142 "sizeof(MemoryChunk) is not maxaligned");
143
144 /*
145 * First, validate allocation parameters. Asserts seem sufficient because
146 * nobody varies their parameters at runtime. We somewhat arbitrarily
147 * enforce a minimum 1K block size. We restrict the maximum block size to
148 * MEMORYCHUNK_MAX_BLOCKOFFSET as MemoryChunks are limited to this in
149 * regards to addressing the offset between the chunk and the block that
150 * the chunk is stored on. We would be unable to store the offset between
151 * the chunk and block for any chunks that were beyond
152 * MEMORYCHUNK_MAX_BLOCKOFFSET bytes into the block if the block was to be
153 * larger than this.
154 */
155 Assert(initBlockSize == MAXALIGN(initBlockSize) &&
156 initBlockSize >= 1024);
157 Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
158 maxBlockSize >= initBlockSize &&
159 AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */
160 Assert(minContextSize == 0 ||
162 minContextSize >= 1024 &&
163 minContextSize <= maxBlockSize));
164 Assert(maxBlockSize <= MEMORYCHUNK_MAX_BLOCKOFFSET);
165
166 /* Determine size of initial block */
169 if (minContextSize != 0)
171 else
172 allocSize = Max(allocSize, initBlockSize);
173
174 /*
175 * Allocate the initial block. Unlike other bump.c blocks, it starts with
176 * the context header and its block header follows that.
177 */
178 set = (BumpContext *) malloc(allocSize);
179 if (set == NULL)
180 {
184 errmsg("out of memory"),
185 errdetail("Failed while creating memory context \"%s\".",
186 name)));
187 }
188
189 /*
190 * Avoid writing code that can fail between here and MemoryContextCreate;
191 * we'd leak the header and initial block if we ereport in this stretch.
192 */
193
194 /* See comments about Valgrind interactions in aset.c */
195 VALGRIND_CREATE_MEMPOOL(set, 0, false);
196 /* This vchunk covers the BumpContext and the keeper block header */
198
199 dlist_init(&set->blocks);
200
201 /* Fill in the initial block's block header */
202 block = KeeperBlock(set);
203 /* determine the block size and initialize it */
205 BumpBlockInit(set, block, firstBlockSize);
206
207 /* add it to the doubly-linked list of blocks */
208 dlist_push_head(&set->blocks, &block->node);
209
210 /*
211 * Fill in BumpContext-specific header fields. The Asserts above should
212 * ensure that these all fit inside a uint32.
213 */
214 set->initBlockSize = (uint32) initBlockSize;
215 set->maxBlockSize = (uint32) maxBlockSize;
216 set->nextBlockSize = (uint32) initBlockSize;
217
218 /*
219 * Compute the allocation chunk size limit for this context.
220 *
221 * Limit the maximum size a non-dedicated chunk can be so that we can fit
222 * at least Bump_CHUNK_FRACTION of chunks this big onto the maximum sized
223 * block. We must further limit this value so that it's no more than
224 * MEMORYCHUNK_MAX_VALUE. We're unable to have non-external chunks larger
225 * than that value as we store the chunk size in the MemoryChunk 'value'
226 * field in the call to MemoryChunkSetHdrMask().
227 */
228 set->allocChunkLimit = Min(maxBlockSize, MEMORYCHUNK_MAX_VALUE);
229 while ((Size) (set->allocChunkLimit + Bump_CHUNKHDRSZ) >
230 (Size) ((Size) (maxBlockSize - Bump_BLOCKHDRSZ) / Bump_CHUNK_FRACTION))
231 set->allocChunkLimit >>= 1;
232
233 /* Finally, do the type-independent part of context creation */
235 parent, name);
236
237 ((MemoryContext) set)->mem_allocated = allocSize;
238
239 return (MemoryContext) set;
240}
241
242/*
243 * BumpReset
244 * Frees all memory which is allocated in the given set.
245 *
246 * The code simply frees all the blocks in the context apart from the keeper
247 * block.
248 */
249void
251{
252 BumpContext *set = (BumpContext *) context;
254
255 Assert(BumpIsValid(set));
256
257#ifdef MEMORY_CONTEXT_CHECKING
258 /* Check for corruption and leaks before freeing */
259 BumpCheck(context);
260#endif
261
262 dlist_foreach_modify(miter, &set->blocks)
263 {
264 BumpBlock *block = dlist_container(BumpBlock, node, miter.cur);
265
266 if (IsKeeperBlock(set, block))
267 BumpBlockMarkEmpty(block);
268 else
269 BumpBlockFree(set, block);
270 }
271
272 /*
273 * Instruct Valgrind to throw away all the vchunks associated with this
274 * context, except for the one covering the BumpContext and keeper-block
275 * header. This gets rid of the vchunks for whatever user data is getting
276 * discarded by the context reset.
277 */
279
280 /* Reset block size allocation sequence, too */
281 set->nextBlockSize = set->initBlockSize;
282
283 /* Ensure there is only 1 item in the dlist */
284 Assert(!dlist_is_empty(&set->blocks));
285 Assert(!dlist_has_next(&set->blocks, dlist_head_node(&set->blocks)));
286}
287
288/*
289 * BumpDelete
290 * Free all memory which is allocated in the given context.
291 */
292void
294{
295 /* Reset to release all releasable BumpBlocks */
296 BumpReset(context);
297
298 /* Destroy the vpool -- see notes in aset.c */
300
301 /* And free the context header and keeper block */
302 free(context);
303}
304
305/*
306 * Helper for BumpAlloc() that allocates an entire block for the chunk.
307 *
308 * BumpAlloc()'s comment explains why this is separate.
309 */
311static void *
312BumpAllocLarge(MemoryContext context, Size size, int flags)
313{
314 BumpContext *set = (BumpContext *) context;
315 BumpBlock *block;
316#ifdef MEMORY_CONTEXT_CHECKING
318#endif
319 Size chunk_size;
321 Size blksize;
322
323 /* validate 'size' is within the limits for the given 'flags' */
324 MemoryContextCheckSize(context, size, flags);
325
326#ifdef MEMORY_CONTEXT_CHECKING
327 /* ensure there's always space for the sentinel byte */
328 chunk_size = MAXALIGN(size + 1);
329#else
330 chunk_size = MAXALIGN(size);
331#endif
332
333 required_size = chunk_size + Bump_CHUNKHDRSZ;
334 blksize = required_size + Bump_BLOCKHDRSZ;
335
336 block = (BumpBlock *) malloc(blksize);
337 if (block == NULL)
338 return MemoryContextAllocationFailure(context, size, flags);
339
340 /* Make a vchunk covering the new block's header */
342
343 context->mem_allocated += blksize;
344
345 /* the block is completely full */
346 block->freeptr = block->endptr = ((char *) block) + blksize;
347
348#ifdef MEMORY_CONTEXT_CHECKING
349 /* block with a single (used) chunk */
350 block->context = set;
351
352 chunk = (MemoryChunk *) (((char *) block) + Bump_BLOCKHDRSZ);
353
354 /* mark the MemoryChunk as externally managed */
356
357 chunk->requested_size = size;
358 /* set mark to catch clobber of "unused" space */
359 Assert(size < chunk_size);
361#endif
362#ifdef RANDOMIZE_ALLOCATED_MEMORY
363 /* fill the allocated space with junk */
365#endif
366
367 /*
368 * Add the block to the tail of allocated blocks list. The current block
369 * is left at the head of the list as it may still have space for
370 * non-large allocations.
371 */
372 dlist_push_tail(&set->blocks, &block->node);
373
374#ifdef MEMORY_CONTEXT_CHECKING
375 /* Ensure any padding bytes are marked NOACCESS. */
377 chunk_size - size);
378
379 /* Disallow access to the chunk header. */
381
383#else
384 return (void *) (((char *) block) + Bump_BLOCKHDRSZ);
385#endif
386}
387
388/*
389 * Small helper for allocating a new chunk from a chunk, to avoid duplicating
390 * the code between BumpAlloc() and BumpAllocFromNewBlock().
391 */
392static inline void *
394 Size chunk_size)
395{
396#ifdef MEMORY_CONTEXT_CHECKING
398#else
399 void *ptr;
400#endif
401
402 /* validate we've been given a block with enough free space */
403 Assert(block != NULL);
404 Assert((block->endptr - block->freeptr) >= Bump_CHUNKHDRSZ + chunk_size);
405
406#ifdef MEMORY_CONTEXT_CHECKING
407 chunk = (MemoryChunk *) block->freeptr;
408#else
409 ptr = block->freeptr;
410#endif
411
412 /* point the freeptr beyond this chunk */
413 block->freeptr += (Bump_CHUNKHDRSZ + chunk_size);
414 Assert(block->freeptr <= block->endptr);
415
416#ifdef MEMORY_CONTEXT_CHECKING
417 /* Prepare to initialize the chunk header. */
419
420 MemoryChunkSetHdrMask(chunk, block, chunk_size, MCTX_BUMP_ID);
421 chunk->requested_size = size;
422 /* set mark to catch clobber of "unused" space */
423 Assert(size < chunk_size);
425
426#ifdef RANDOMIZE_ALLOCATED_MEMORY
427 /* fill the allocated space with junk */
429#endif
430
431 /* Ensure any padding bytes are marked NOACCESS. */
433 chunk_size - size);
434
435 /* Disallow access to the chunk header. */
437
439#else
440 return ptr;
441#endif /* MEMORY_CONTEXT_CHECKING */
442}
443
444/*
445 * Helper for BumpAlloc() that allocates a new block and returns a chunk
446 * allocated from it.
447 *
448 * BumpAlloc()'s comment explains why this is separate.
449 */
451static void *
452BumpAllocFromNewBlock(MemoryContext context, Size size, int flags,
453 Size chunk_size)
454{
455 BumpContext *set = (BumpContext *) context;
456 BumpBlock *block;
457 Size blksize;
459
460 /*
461 * The first such block has size initBlockSize, and we double the space in
462 * each succeeding block, but not more than maxBlockSize.
463 */
464 blksize = set->nextBlockSize;
465 set->nextBlockSize <<= 1;
466 if (set->nextBlockSize > set->maxBlockSize)
467 set->nextBlockSize = set->maxBlockSize;
468
469 /* we'll need space for the chunk, chunk hdr and block hdr */
471 /* round the size up to the next power of 2 */
472 if (blksize < required_size)
474
475 block = (BumpBlock *) malloc(blksize);
476
477 if (block == NULL)
478 return MemoryContextAllocationFailure(context, size, flags);
479
480 /* Make a vchunk covering the new block's header */
482
483 context->mem_allocated += blksize;
484
485 /* initialize the new block */
486 BumpBlockInit(set, block, blksize);
487
488 /* add it to the doubly-linked list of blocks */
489 dlist_push_head(&set->blocks, &block->node);
490
491 return BumpAllocChunkFromBlock(context, block, size, chunk_size);
492}
493
494/*
495 * BumpAlloc
496 * Returns a pointer to allocated memory of given size or raises an ERROR
497 * on allocation failure, or returns NULL when flags contains
498 * MCXT_ALLOC_NO_OOM.
499 *
500 * No request may exceed:
501 * MAXALIGN_DOWN(SIZE_MAX) - Bump_BLOCKHDRSZ - Bump_CHUNKHDRSZ
502 * All callers use a much-lower limit.
503 *
504 *
505 * Note: when using valgrind, it doesn't matter how the returned allocation
506 * is marked, as mcxt.c will set it to UNDEFINED.
507 * This function should only contain the most common code paths. Everything
508 * else should be in pg_noinline helper functions, thus avoiding the overhead
509 * of creating a stack frame for the common cases. Allocating memory is often
510 * a bottleneck in many workloads, so avoiding stack frame setup is
511 * worthwhile. Helper functions should always directly return the newly
512 * allocated memory so that we can just return that address directly as a tail
513 * call.
514 */
515void *
516BumpAlloc(MemoryContext context, Size size, int flags)
517{
518 BumpContext *set = (BumpContext *) context;
519 BumpBlock *block;
520 Size chunk_size;
522
523 Assert(BumpIsValid(set));
524
525#ifdef MEMORY_CONTEXT_CHECKING
526 /* ensure there's always space for the sentinel byte */
527 chunk_size = MAXALIGN(size + 1);
528#else
529 chunk_size = MAXALIGN(size);
530#endif
531
532 /*
533 * If requested size exceeds maximum for chunks we hand the request off to
534 * BumpAllocLarge().
535 */
536 if (chunk_size > set->allocChunkLimit)
537 return BumpAllocLarge(context, size, flags);
538
539 required_size = chunk_size + Bump_CHUNKHDRSZ;
540
541 /*
542 * Not an oversized chunk. We try to first make use of the latest block,
543 * but if there's not enough space in it we must allocate a new block.
544 */
545 block = dlist_container(BumpBlock, node, dlist_head_node(&set->blocks));
546
548 return BumpAllocFromNewBlock(context, size, flags, chunk_size);
549
550 /* The current block has space, so just allocate chunk there. */
551 return BumpAllocChunkFromBlock(context, block, size, chunk_size);
552}
553
554/*
555 * BumpBlockInit
556 * Initializes 'block' assuming 'blksize'. Does not update the context's
557 * mem_allocated field.
558 */
559static inline void
560BumpBlockInit(BumpContext *context, BumpBlock *block, Size blksize)
561{
562#ifdef MEMORY_CONTEXT_CHECKING
563 block->context = context;
564#endif
565 block->freeptr = ((char *) block) + Bump_BLOCKHDRSZ;
566 block->endptr = ((char *) block) + blksize;
567
568 /* Mark unallocated space NOACCESS. */
570}
571
572/*
573 * BumpBlockIsEmpty
574 * Returns true iff 'block' contains no chunks
575 */
576static inline bool
578{
579 /* it's empty if the freeptr has not moved */
580 return (block->freeptr == ((char *) block + Bump_BLOCKHDRSZ));
581}
582
583/*
584 * BumpBlockMarkEmpty
585 * Set a block as empty. Does not free the block.
586 */
587static inline void
589{
590#if defined(USE_VALGRIND) || defined(CLOBBER_FREED_MEMORY)
591 char *datastart = ((char *) block) + Bump_BLOCKHDRSZ;
592#endif
593
594#ifdef CLOBBER_FREED_MEMORY
596#else
597 /* wipe_mem() would have done this */
599#endif
600
601 /* Reset the block, but don't return it to malloc */
602 block->freeptr = ((char *) block) + Bump_BLOCKHDRSZ;
603}
604
605/*
606 * BumpBlockFreeBytes
607 * Returns the number of bytes free in 'block'
608 */
609static inline Size
611{
612 return (block->endptr - block->freeptr);
613}
614
615/*
616 * BumpBlockFree
617 * Remove 'block' from 'set' and release the memory consumed by it.
618 */
619static inline void
621{
622 /* Make sure nobody tries to free the keeper block */
623 Assert(!IsKeeperBlock(set, block));
624
625 /* release the block from the list of blocks */
626 dlist_delete(&block->node);
627
628 ((MemoryContext) set)->mem_allocated -= ((char *) block->endptr - (char *) block);
629
630#ifdef CLOBBER_FREED_MEMORY
631 wipe_mem(block, ((char *) block->endptr - (char *) block));
632#endif
633
634 /* As in aset.c, free block-header vchunks explicitly */
635 VALGRIND_MEMPOOL_FREE(set, block);
636
637 free(block);
638}
639
640/*
641 * BumpFree
642 * Unsupported.
643 */
644void
645BumpFree(void *pointer)
646{
647 elog(ERROR, "%s is not supported by the bump memory allocator", "pfree");
648}
649
650/*
651 * BumpRealloc
652 * Unsupported.
653 */
654void *
655BumpRealloc(void *pointer, Size size, int flags)
656{
657 elog(ERROR, "%s is not supported by the bump memory allocator", "realloc");
658 return NULL; /* keep compiler quiet */
659}
660
661/*
662 * BumpGetChunkContext
663 * Unsupported.
664 */
666BumpGetChunkContext(void *pointer)
667{
668 elog(ERROR, "%s is not supported by the bump memory allocator", "GetMemoryChunkContext");
669 return NULL; /* keep compiler quiet */
670}
671
672/*
673 * BumpGetChunkSpace
674 * Unsupported.
675 */
676Size
677BumpGetChunkSpace(void *pointer)
678{
679 elog(ERROR, "%s is not supported by the bump memory allocator", "GetMemoryChunkSpace");
680 return 0; /* keep compiler quiet */
681}
682
683/*
684 * BumpIsEmpty
685 * Is a BumpContext empty of any allocated space?
686 */
687bool
689{
690 BumpContext *set = (BumpContext *) context;
691 dlist_iter iter;
692
693 Assert(BumpIsValid(set));
694
695 dlist_foreach(iter, &set->blocks)
696 {
697 BumpBlock *block = dlist_container(BumpBlock, node, iter.cur);
698
699 if (!BumpBlockIsEmpty(block))
700 return false;
701 }
702
703 return true;
704}
705
706/*
707 * BumpStats
708 * Compute stats about memory consumption of a Bump context.
709 *
710 * printfunc: if not NULL, pass a human-readable stats string to this.
711 * passthru: pass this pointer through to printfunc.
712 * totals: if not NULL, add stats about this context into *totals.
713 * print_to_stderr: print stats to stderr if true, elog otherwise.
714 */
715void
718{
719 BumpContext *set = (BumpContext *) context;
720 Size nblocks = 0;
721 Size totalspace = 0;
722 Size freespace = 0;
723 dlist_iter iter;
724
725 Assert(BumpIsValid(set));
726
727 dlist_foreach(iter, &set->blocks)
728 {
729 BumpBlock *block = dlist_container(BumpBlock, node, iter.cur);
730
731 nblocks++;
732 totalspace += (block->endptr - (char *) block);
733 freespace += (block->endptr - block->freeptr);
734 }
735
736 if (printfunc)
737 {
738 char stats_string[200];
739
741 "%zu total in %zu blocks; %zu free; %zu used",
742 totalspace, nblocks, freespace, totalspace - freespace);
744 }
745
746 if (totals)
747 {
748 totals->nblocks += nblocks;
749 totals->totalspace += totalspace;
750 totals->freespace += freespace;
751 }
752}
753
754
755#ifdef MEMORY_CONTEXT_CHECKING
756
757/*
758 * BumpCheck
759 * Walk through chunks and check consistency of memory.
760 *
761 * NOTE: report errors as WARNING, *not* ERROR or FATAL. Otherwise you'll
762 * find yourself in an infinite loop when trouble occurs, because this
763 * routine will be entered again when elog cleanup tries to release memory!
764 */
765void
767{
768 BumpContext *bump = (BumpContext *) context;
769 const char *name = context->name;
770 dlist_iter iter;
772
773 /* walk all blocks in this context */
774 dlist_foreach(iter, &bump->blocks)
775 {
776 BumpBlock *block = dlist_container(BumpBlock, node, iter.cur);
777 int nchunks;
778 char *ptr;
779 bool has_external_chunk = false;
780
781 if (IsKeeperBlock(bump, block))
782 total_allocated += block->endptr - (char *) bump;
783 else
784 total_allocated += block->endptr - (char *) block;
785
786 /* check block belongs to the correct context */
787 if (block->context != bump)
788 elog(WARNING, "problem in Bump %s: bogus context link in block %p",
789 name, block);
790
791 /* now walk through the chunks and count them */
792 nchunks = 0;
793 ptr = ((char *) block) + Bump_BLOCKHDRSZ;
794
795 while (ptr < block->freeptr)
796 {
797 MemoryChunk *chunk = (MemoryChunk *) ptr;
800
801 /* allow access to the chunk header */
803
805 {
807 chunksize = block->endptr - (char *) MemoryChunkGetPointer(chunk);
808 has_external_chunk = true;
809 }
810 else
811 {
814 }
815
816 /* move to the next chunk */
817 ptr += (chunksize + Bump_CHUNKHDRSZ);
818
819 nchunks += 1;
820
821 /* chunks have both block and context pointers, so check both */
822 if (chunkblock != block)
823 elog(WARNING, "problem in Bump %s: bogus block link in block %p, chunk %p",
824 name, block, chunk);
825 }
826
827 if (has_external_chunk && nchunks > 1)
828 elog(WARNING, "problem in Bump %s: external chunk on non-dedicated block %p",
829 name, block);
830
831 }
832
834}
835
836#endif /* MEMORY_CONTEXT_CHECKING */
static bool BumpBlockIsEmpty(BumpBlock *block)
Definition bump.c:578
#define Bump_CHUNK_FRACTION
Definition bump.c:59
void BumpFree(void *pointer)
Definition bump.c:646
void BumpDelete(MemoryContext context)
Definition bump.c:294
Size BumpGetChunkSpace(void *pointer)
Definition bump.c:678
void BumpStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
Definition bump.c:717
static void BumpBlockFree(BumpContext *set, BumpBlock *block)
Definition bump.c:621
#define KeeperBlock(set)
Definition bump.c:62
static void BumpBlockMarkEmpty(BumpBlock *block)
Definition bump.c:589
#define Bump_CHUNKHDRSZ
Definition bump.c:56
static pg_noinline void * BumpAllocLarge(MemoryContext context, Size size, int flags)
Definition bump.c:313
static void BumpBlockInit(BumpContext *context, BumpBlock *block, Size blksize)
Definition bump.c:561
#define BumpIsValid(set)
Definition bump.c:102
#define Bump_BLOCKHDRSZ
Definition bump.c:48
MemoryContext BumpGetChunkContext(void *pointer)
Definition bump.c:667
#define IsKeeperBlock(set, blk)
Definition bump.c:64
void BumpReset(MemoryContext context)
Definition bump.c:251
static pg_noinline void * BumpAllocFromNewBlock(MemoryContext context, Size size, int flags, Size chunk_size)
Definition bump.c:453
#define FIRST_BLOCKHDRSZ
Definition bump.c:49
bool BumpIsEmpty(MemoryContext context)
Definition bump.c:689
void * BumpRealloc(void *pointer, Size size, int flags)
Definition bump.c:656
static void * BumpAllocChunkFromBlock(MemoryContext context, BumpBlock *block, Size size, Size chunk_size)
Definition bump.c:394
static Size BumpBlockFreeBytes(BumpBlock *block)
Definition bump.c:611
#define ExternalChunkGetBlock(chunk)
Definition bump.c:110
void * BumpAlloc(MemoryContext context, Size size, int flags)
Definition bump.c:517
#define pg_noinline
Definition c.h:295
#define Min(x, y)
Definition c.h:997
#define MAXALIGN(LEN)
Definition c.h:826
#define Max(x, y)
Definition c.h:991
#define Assert(condition)
Definition c.h:873
uint32_t uint32
Definition c.h:546
#define StaticAssertDecl(condition, errmessage)
Definition c.h:942
size_t Size
Definition c.h:619
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define dlist_foreach(iter, lhead)
Definition ilist.h:623
static void dlist_init(dlist_head *head)
Definition ilist.h:314
static bool dlist_has_next(const dlist_head *head, const dlist_node *node)
Definition ilist.h:503
static void dlist_delete(dlist_node *node)
Definition ilist.h:405
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition ilist.h:347
static dlist_node * dlist_head_node(dlist_head *head)
Definition ilist.h:565
#define dlist_foreach_modify(iter, lhead)
Definition ilist.h:640
static bool dlist_is_empty(const dlist_head *head)
Definition ilist.h:336
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition ilist.h:364
#define dlist_container(type, membername, ptr)
Definition ilist.h:593
void MemoryContextCreate(MemoryContext node, NodeTag tag, MemoryContextMethodID method_id, MemoryContext parent, const char *name)
Definition mcxt.c:1149
MemoryContext TopMemoryContext
Definition mcxt.c:166
void MemoryContextStats(MemoryContext context)
Definition mcxt.c:863
void * MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
Definition mcxt.c:1198
#define VALGRIND_DESTROY_MEMPOOL(context)
Definition memdebug.h:25
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition memdebug.h:26
#define VALGRIND_CREATE_MEMPOOL(context, redzones, zeroed)
Definition memdebug.h:24
#define VALGRIND_MEMPOOL_ALLOC(context, addr, size)
Definition memdebug.h:29
#define VALGRIND_MEMPOOL_TRIM(context, addr, size)
Definition memdebug.h:32
#define VALGRIND_MEMPOOL_FREE(context, addr)
Definition memdebug.h:30
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition memdebug.h:27
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
Definition memdebug.h:28
void(* MemoryStatsPrintFunc)(MemoryContext context, void *passthru, const char *stats_string, bool print_to_stderr)
Definition memnodes.h:54
#define AllocHugeSizeIsValid(size)
Definition memutils.h:49
static void MemoryContextCheckSize(MemoryContext context, Size size, int flags)
@ MCTX_BUMP_ID
#define MEMORYCHUNK_MAX_BLOCKOFFSET
#define MEMORYCHUNK_MAX_VALUE
static Size MemoryChunkGetValue(MemoryChunk *chunk)
#define MemoryChunkGetPointer(c)
static bool MemoryChunkIsExternal(MemoryChunk *chunk)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
static void MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk, MemoryContextMethodID methodid)
static void MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, Size value, MemoryContextMethodID methodid)
struct MemoryContextData * MemoryContext
Definition palloc.h:36
#define pg_nextpower2_size_t
#define snprintf
Definition port.h:260
static int fb(int x)
#define free(a)
#define malloc(a)
char * endptr
Definition bump.c:95
char * freeptr
Definition bump.c:94
dlist_node node
Definition bump.c:90
const char * name
Definition memnodes.h:131
dlist_node * cur
Definition ilist.h:179
const char * name

◆ ExternalChunkGetBlock

#define ExternalChunkGetBlock (   chunk)     (BumpBlock *) ((char *) chunk - Bump_BLOCKHDRSZ)

Definition at line 110 of file bump.c.

◆ FIRST_BLOCKHDRSZ

#define FIRST_BLOCKHDRSZ
Value:

Definition at line 49 of file bump.c.

◆ IsKeeperBlock

#define IsKeeperBlock (   set,
  blk 
)    (KeeperBlock(set) == (blk))

Definition at line 64 of file bump.c.

◆ KeeperBlock

#define KeeperBlock (   set)
Value:
((BumpBlock *) ((char *) (set) + \
MAXALIGN(sizeof(BumpContext))))

Definition at line 62 of file bump.c.

Typedef Documentation

◆ BumpBlock

Definition at line 66 of file bump.c.

◆ BumpContext

Function Documentation

◆ BumpAlloc()

void * BumpAlloc ( MemoryContext  context,
Size  size,
int  flags 
)

Definition at line 517 of file bump.c.

518{
519 BumpContext *set = (BumpContext *) context;
520 BumpBlock *block;
521 Size chunk_size;
523
524 Assert(BumpIsValid(set));
525
526#ifdef MEMORY_CONTEXT_CHECKING
527 /* ensure there's always space for the sentinel byte */
528 chunk_size = MAXALIGN(size + 1);
529#else
530 chunk_size = MAXALIGN(size);
531#endif
532
533 /*
534 * If requested size exceeds maximum for chunks we hand the request off to
535 * BumpAllocLarge().
536 */
537 if (chunk_size > set->allocChunkLimit)
538 return BumpAllocLarge(context, size, flags);
539
540 required_size = chunk_size + Bump_CHUNKHDRSZ;
541
542 /*
543 * Not an oversized chunk. We try to first make use of the latest block,
544 * but if there's not enough space in it we must allocate a new block.
545 */
546 block = dlist_container(BumpBlock, node, dlist_head_node(&set->blocks));
547
549 return BumpAllocFromNewBlock(context, size, flags, chunk_size);
550
551 /* The current block has space, so just allocate chunk there. */
552 return BumpAllocChunkFromBlock(context, block, size, chunk_size);
553}
dlist_head blocks
Definition bump.c:78
uint32 allocChunkLimit
Definition bump.c:76

References BumpContext::allocChunkLimit, Assert, BumpContext::blocks, Bump_CHUNKHDRSZ, BumpAllocChunkFromBlock(), BumpAllocFromNewBlock(), BumpAllocLarge(), BumpBlockFreeBytes(), BumpIsValid, dlist_container, dlist_head_node(), fb(), and MAXALIGN.

◆ BumpAllocChunkFromBlock()

static void * BumpAllocChunkFromBlock ( MemoryContext  context,
BumpBlock block,
Size  size,
Size  chunk_size 
)
inlinestatic

Definition at line 394 of file bump.c.

396{
397#ifdef MEMORY_CONTEXT_CHECKING
399#else
400 void *ptr;
401#endif
402
403 /* validate we've been given a block with enough free space */
404 Assert(block != NULL);
405 Assert((block->endptr - block->freeptr) >= Bump_CHUNKHDRSZ + chunk_size);
406
407#ifdef MEMORY_CONTEXT_CHECKING
408 chunk = (MemoryChunk *) block->freeptr;
409#else
410 ptr = block->freeptr;
411#endif
412
413 /* point the freeptr beyond this chunk */
414 block->freeptr += (Bump_CHUNKHDRSZ + chunk_size);
415 Assert(block->freeptr <= block->endptr);
416
417#ifdef MEMORY_CONTEXT_CHECKING
418 /* Prepare to initialize the chunk header. */
420
421 MemoryChunkSetHdrMask(chunk, block, chunk_size, MCTX_BUMP_ID);
422 chunk->requested_size = size;
423 /* set mark to catch clobber of "unused" space */
424 Assert(size < chunk_size);
426
427#ifdef RANDOMIZE_ALLOCATED_MEMORY
428 /* fill the allocated space with junk */
430#endif
431
432 /* Ensure any padding bytes are marked NOACCESS. */
434 chunk_size - size);
435
436 /* Disallow access to the chunk header. */
438
440#else
441 return ptr;
442#endif /* MEMORY_CONTEXT_CHECKING */
443}

References Assert, Bump_CHUNKHDRSZ, BumpBlock::endptr, fb(), BumpBlock::freeptr, MCTX_BUMP_ID, MemoryChunkGetPointer, MemoryChunkSetHdrMask(), VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MAKE_MEM_UNDEFINED.

Referenced by BumpAlloc(), and BumpAllocFromNewBlock().

◆ BumpAllocFromNewBlock()

static pg_noinline void * BumpAllocFromNewBlock ( MemoryContext  context,
Size  size,
int  flags,
Size  chunk_size 
)
static

Definition at line 453 of file bump.c.

455{
456 BumpContext *set = (BumpContext *) context;
457 BumpBlock *block;
458 Size blksize;
460
461 /*
462 * The first such block has size initBlockSize, and we double the space in
463 * each succeeding block, but not more than maxBlockSize.
464 */
465 blksize = set->nextBlockSize;
466 set->nextBlockSize <<= 1;
467 if (set->nextBlockSize > set->maxBlockSize)
468 set->nextBlockSize = set->maxBlockSize;
469
470 /* we'll need space for the chunk, chunk hdr and block hdr */
472 /* round the size up to the next power of 2 */
473 if (blksize < required_size)
475
476 block = (BumpBlock *) malloc(blksize);
477
478 if (block == NULL)
479 return MemoryContextAllocationFailure(context, size, flags);
480
481 /* Make a vchunk covering the new block's header */
483
484 context->mem_allocated += blksize;
485
486 /* initialize the new block */
487 BumpBlockInit(set, block, blksize);
488
489 /* add it to the doubly-linked list of blocks */
490 dlist_push_head(&set->blocks, &block->node);
491
492 return BumpAllocChunkFromBlock(context, block, size, chunk_size);
493}
uint32 maxBlockSize
Definition bump.c:74
uint32 nextBlockSize
Definition bump.c:75

References BumpContext::blocks, Bump_BLOCKHDRSZ, Bump_CHUNKHDRSZ, BumpAllocChunkFromBlock(), BumpBlockInit(), dlist_push_head(), fb(), malloc, BumpContext::maxBlockSize, MemoryContextData::mem_allocated, MemoryContextAllocationFailure(), BumpContext::nextBlockSize, BumpBlock::node, pg_nextpower2_size_t, and VALGRIND_MEMPOOL_ALLOC.

Referenced by BumpAlloc().

◆ BumpAllocLarge()

static pg_noinline void * BumpAllocLarge ( MemoryContext  context,
Size  size,
int  flags 
)
static

Definition at line 313 of file bump.c.

314{
315 BumpContext *set = (BumpContext *) context;
316 BumpBlock *block;
317#ifdef MEMORY_CONTEXT_CHECKING
319#endif
320 Size chunk_size;
322 Size blksize;
323
324 /* validate 'size' is within the limits for the given 'flags' */
325 MemoryContextCheckSize(context, size, flags);
326
327#ifdef MEMORY_CONTEXT_CHECKING
328 /* ensure there's always space for the sentinel byte */
329 chunk_size = MAXALIGN(size + 1);
330#else
331 chunk_size = MAXALIGN(size);
332#endif
333
334 required_size = chunk_size + Bump_CHUNKHDRSZ;
335 blksize = required_size + Bump_BLOCKHDRSZ;
336
337 block = (BumpBlock *) malloc(blksize);
338 if (block == NULL)
339 return MemoryContextAllocationFailure(context, size, flags);
340
341 /* Make a vchunk covering the new block's header */
343
344 context->mem_allocated += blksize;
345
346 /* the block is completely full */
347 block->freeptr = block->endptr = ((char *) block) + blksize;
348
349#ifdef MEMORY_CONTEXT_CHECKING
350 /* block with a single (used) chunk */
351 block->context = set;
352
353 chunk = (MemoryChunk *) (((char *) block) + Bump_BLOCKHDRSZ);
354
355 /* mark the MemoryChunk as externally managed */
357
358 chunk->requested_size = size;
359 /* set mark to catch clobber of "unused" space */
360 Assert(size < chunk_size);
362#endif
363#ifdef RANDOMIZE_ALLOCATED_MEMORY
364 /* fill the allocated space with junk */
366#endif
367
368 /*
369 * Add the block to the tail of allocated blocks list. The current block
370 * is left at the head of the list as it may still have space for
371 * non-large allocations.
372 */
373 dlist_push_tail(&set->blocks, &block->node);
374
375#ifdef MEMORY_CONTEXT_CHECKING
376 /* Ensure any padding bytes are marked NOACCESS. */
378 chunk_size - size);
379
380 /* Disallow access to the chunk header. */
382
384#else
385 return (void *) (((char *) block) + Bump_BLOCKHDRSZ);
386#endif
387}

References Assert, BumpContext::blocks, Bump_BLOCKHDRSZ, Bump_CHUNKHDRSZ, dlist_push_tail(), BumpBlock::endptr, fb(), BumpBlock::freeptr, malloc, MAXALIGN, MCTX_BUMP_ID, MemoryContextData::mem_allocated, MemoryChunkGetPointer, MemoryChunkSetHdrMaskExternal(), MemoryContextAllocationFailure(), MemoryContextCheckSize(), BumpBlock::node, VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MEMPOOL_ALLOC.

Referenced by BumpAlloc().

◆ BumpBlockFree()

static void BumpBlockFree ( BumpContext set,
BumpBlock block 
)
inlinestatic

Definition at line 621 of file bump.c.

622{
623 /* Make sure nobody tries to free the keeper block */
624 Assert(!IsKeeperBlock(set, block));
625
626 /* release the block from the list of blocks */
627 dlist_delete(&block->node);
628
629 ((MemoryContext) set)->mem_allocated -= ((char *) block->endptr - (char *) block);
630
631#ifdef CLOBBER_FREED_MEMORY
632 wipe_mem(block, ((char *) block->endptr - (char *) block));
633#endif
634
635 /* As in aset.c, free block-header vchunks explicitly */
636 VALGRIND_MEMPOOL_FREE(set, block);
637
638 free(block);
639}

References Assert, dlist_delete(), BumpBlock::endptr, fb(), free, IsKeeperBlock, BumpBlock::node, and VALGRIND_MEMPOOL_FREE.

Referenced by BumpReset().

◆ BumpBlockFreeBytes()

static Size BumpBlockFreeBytes ( BumpBlock block)
inlinestatic

Definition at line 611 of file bump.c.

612{
613 return (block->endptr - block->freeptr);
614}

References BumpBlock::endptr, and BumpBlock::freeptr.

Referenced by BumpAlloc().

◆ BumpBlockInit()

static void BumpBlockInit ( BumpContext context,
BumpBlock block,
Size  blksize 
)
inlinestatic

Definition at line 561 of file bump.c.

562{
563#ifdef MEMORY_CONTEXT_CHECKING
564 block->context = context;
565#endif
566 block->freeptr = ((char *) block) + Bump_BLOCKHDRSZ;
567 block->endptr = ((char *) block) + blksize;
568
569 /* Mark unallocated space NOACCESS. */
571}

References Bump_BLOCKHDRSZ, BumpBlock::endptr, BumpBlock::freeptr, and VALGRIND_MAKE_MEM_NOACCESS.

Referenced by BumpAllocFromNewBlock(), and BumpContextCreate().

◆ BumpBlockIsEmpty()

static bool BumpBlockIsEmpty ( BumpBlock block)
inlinestatic

Definition at line 578 of file bump.c.

579{
580 /* it's empty if the freeptr has not moved */
581 return (block->freeptr == ((char *) block + Bump_BLOCKHDRSZ));
582}

References Bump_BLOCKHDRSZ, and BumpBlock::freeptr.

Referenced by BumpIsEmpty().

◆ BumpBlockMarkEmpty()

static void BumpBlockMarkEmpty ( BumpBlock block)
inlinestatic

Definition at line 589 of file bump.c.

590{
591#if defined(USE_VALGRIND) || defined(CLOBBER_FREED_MEMORY)
592 char *datastart = ((char *) block) + Bump_BLOCKHDRSZ;
593#endif
594
595#ifdef CLOBBER_FREED_MEMORY
597#else
598 /* wipe_mem() would have done this */
600#endif
601
602 /* Reset the block, but don't return it to malloc */
603 block->freeptr = ((char *) block) + Bump_BLOCKHDRSZ;
604}

References Bump_BLOCKHDRSZ, fb(), BumpBlock::freeptr, and VALGRIND_MAKE_MEM_NOACCESS.

Referenced by BumpReset().

◆ BumpContextCreate()

MemoryContext BumpContextCreate ( MemoryContext  parent,
const char name,
Size  minContextSize,
Size  initBlockSize,
Size  maxBlockSize 
)

Definition at line 133 of file bump.c.

135{
138 BumpContext *set;
139 BumpBlock *block;
140
141 /* ensure MemoryChunk's size is properly maxaligned */
143 "sizeof(MemoryChunk) is not maxaligned");
144
145 /*
146 * First, validate allocation parameters. Asserts seem sufficient because
147 * nobody varies their parameters at runtime. We somewhat arbitrarily
148 * enforce a minimum 1K block size. We restrict the maximum block size to
149 * MEMORYCHUNK_MAX_BLOCKOFFSET as MemoryChunks are limited to this in
150 * regards to addressing the offset between the chunk and the block that
151 * the chunk is stored on. We would be unable to store the offset between
152 * the chunk and block for any chunks that were beyond
153 * MEMORYCHUNK_MAX_BLOCKOFFSET bytes into the block if the block was to be
154 * larger than this.
155 */
156 Assert(initBlockSize == MAXALIGN(initBlockSize) &&
157 initBlockSize >= 1024);
158 Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
159 maxBlockSize >= initBlockSize &&
160 AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */
161 Assert(minContextSize == 0 ||
163 minContextSize >= 1024 &&
164 minContextSize <= maxBlockSize));
165 Assert(maxBlockSize <= MEMORYCHUNK_MAX_BLOCKOFFSET);
166
167 /* Determine size of initial block */
170 if (minContextSize != 0)
172 else
173 allocSize = Max(allocSize, initBlockSize);
174
175 /*
176 * Allocate the initial block. Unlike other bump.c blocks, it starts with
177 * the context header and its block header follows that.
178 */
179 set = (BumpContext *) malloc(allocSize);
180 if (set == NULL)
181 {
185 errmsg("out of memory"),
186 errdetail("Failed while creating memory context \"%s\".",
187 name)));
188 }
189
190 /*
191 * Avoid writing code that can fail between here and MemoryContextCreate;
192 * we'd leak the header and initial block if we ereport in this stretch.
193 */
194
195 /* See comments about Valgrind interactions in aset.c */
196 VALGRIND_CREATE_MEMPOOL(set, 0, false);
197 /* This vchunk covers the BumpContext and the keeper block header */
199
200 dlist_init(&set->blocks);
201
202 /* Fill in the initial block's block header */
203 block = KeeperBlock(set);
204 /* determine the block size and initialize it */
206 BumpBlockInit(set, block, firstBlockSize);
207
208 /* add it to the doubly-linked list of blocks */
209 dlist_push_head(&set->blocks, &block->node);
210
211 /*
212 * Fill in BumpContext-specific header fields. The Asserts above should
213 * ensure that these all fit inside a uint32.
214 */
215 set->initBlockSize = (uint32) initBlockSize;
216 set->maxBlockSize = (uint32) maxBlockSize;
217 set->nextBlockSize = (uint32) initBlockSize;
218
219 /*
220 * Compute the allocation chunk size limit for this context.
221 *
222 * Limit the maximum size a non-dedicated chunk can be so that we can fit
223 * at least Bump_CHUNK_FRACTION of chunks this big onto the maximum sized
224 * block. We must further limit this value so that it's no more than
225 * MEMORYCHUNK_MAX_VALUE. We're unable to have non-external chunks larger
226 * than that value as we store the chunk size in the MemoryChunk 'value'
227 * field in the call to MemoryChunkSetHdrMask().
228 */
229 set->allocChunkLimit = Min(maxBlockSize, MEMORYCHUNK_MAX_VALUE);
230 while ((Size) (set->allocChunkLimit + Bump_CHUNKHDRSZ) >
231 (Size) ((Size) (maxBlockSize - Bump_BLOCKHDRSZ) / Bump_CHUNK_FRACTION))
232 set->allocChunkLimit >>= 1;
233
234 /* Finally, do the type-independent part of context creation */
236 parent, name);
237
238 ((MemoryContext) set)->mem_allocated = allocSize;
239
240 return (MemoryContext) set;
241}
uint32 initBlockSize
Definition bump.c:73

References BumpContext::allocChunkLimit, AllocHugeSizeIsValid, Assert, BumpContext::blocks, Bump_BLOCKHDRSZ, Bump_CHUNK_FRACTION, Bump_CHUNKHDRSZ, BumpBlockInit(), dlist_init(), dlist_push_head(), ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), FIRST_BLOCKHDRSZ, BumpContext::initBlockSize, KeeperBlock, malloc, Max, MAXALIGN, BumpContext::maxBlockSize, MCTX_BUMP_ID, MEMORYCHUNK_MAX_BLOCKOFFSET, MEMORYCHUNK_MAX_VALUE, MemoryContextCreate(), MemoryContextStats(), Min, name, BumpContext::nextBlockSize, BumpBlock::node, StaticAssertDecl, TopMemoryContext, VALGRIND_CREATE_MEMPOOL, and VALGRIND_MEMPOOL_ALLOC.

Referenced by ExecInitRecursiveUnion(), ExecInitSetOp(), ExecInitSubPlan(), hash_create_memory(), TidStoreCreateLocal(), and tuplesort_begin_batch().

◆ BumpDelete()

void BumpDelete ( MemoryContext  context)

Definition at line 294 of file bump.c.

295{
296 /* Reset to release all releasable BumpBlocks */
297 BumpReset(context);
298
299 /* Destroy the vpool -- see notes in aset.c */
301
302 /* And free the context header and keeper block */
303 free(context);
304}

References BumpReset(), free, and VALGRIND_DESTROY_MEMPOOL.

◆ BumpFree()

void BumpFree ( void pointer)

Definition at line 646 of file bump.c.

647{
648 elog(ERROR, "%s is not supported by the bump memory allocator", "pfree");
649}

References elog, and ERROR.

◆ BumpGetChunkContext()

MemoryContext BumpGetChunkContext ( void pointer)

Definition at line 667 of file bump.c.

668{
669 elog(ERROR, "%s is not supported by the bump memory allocator", "GetMemoryChunkContext");
670 return NULL; /* keep compiler quiet */
671}

References elog, ERROR, and fb().

◆ BumpGetChunkSpace()

Size BumpGetChunkSpace ( void pointer)

Definition at line 678 of file bump.c.

679{
680 elog(ERROR, "%s is not supported by the bump memory allocator", "GetMemoryChunkSpace");
681 return 0; /* keep compiler quiet */
682}

References elog, and ERROR.

◆ BumpIsEmpty()

bool BumpIsEmpty ( MemoryContext  context)

Definition at line 689 of file bump.c.

690{
691 BumpContext *set = (BumpContext *) context;
692 dlist_iter iter;
693
694 Assert(BumpIsValid(set));
695
696 dlist_foreach(iter, &set->blocks)
697 {
698 BumpBlock *block = dlist_container(BumpBlock, node, iter.cur);
699
700 if (!BumpBlockIsEmpty(block))
701 return false;
702 }
703
704 return true;
705}

References Assert, BumpContext::blocks, BumpBlockIsEmpty(), BumpIsValid, dlist_iter::cur, dlist_container, and dlist_foreach.

◆ BumpRealloc()

void * BumpRealloc ( void pointer,
Size  size,
int  flags 
)

Definition at line 656 of file bump.c.

657{
658 elog(ERROR, "%s is not supported by the bump memory allocator", "realloc");
659 return NULL; /* keep compiler quiet */
660}

References elog, ERROR, and fb().

◆ BumpReset()

void BumpReset ( MemoryContext  context)

Definition at line 251 of file bump.c.

252{
253 BumpContext *set = (BumpContext *) context;
255
256 Assert(BumpIsValid(set));
257
258#ifdef MEMORY_CONTEXT_CHECKING
259 /* Check for corruption and leaks before freeing */
260 BumpCheck(context);
261#endif
262
264 {
265 BumpBlock *block = dlist_container(BumpBlock, node, miter.cur);
266
267 if (IsKeeperBlock(set, block))
268 BumpBlockMarkEmpty(block);
269 else
270 BumpBlockFree(set, block);
271 }
272
273 /*
274 * Instruct Valgrind to throw away all the vchunks associated with this
275 * context, except for the one covering the BumpContext and keeper-block
276 * header. This gets rid of the vchunks for whatever user data is getting
277 * discarded by the context reset.
278 */
280
281 /* Reset block size allocation sequence, too */
282 set->nextBlockSize = set->initBlockSize;
283
284 /* Ensure there is only 1 item in the dlist */
287}

References Assert, BumpContext::blocks, BumpBlockFree(), BumpBlockMarkEmpty(), BumpIsValid, dlist_container, dlist_foreach_modify, dlist_has_next(), dlist_head_node(), dlist_is_empty(), fb(), FIRST_BLOCKHDRSZ, BumpContext::initBlockSize, IsKeeperBlock, BumpContext::nextBlockSize, and VALGRIND_MEMPOOL_TRIM.

Referenced by BumpDelete().

◆ BumpStats()

void BumpStats ( MemoryContext  context,
MemoryStatsPrintFunc  printfunc,
void passthru,
MemoryContextCounters totals,
bool  print_to_stderr 
)

Definition at line 717 of file bump.c.

719{
720 BumpContext *set = (BumpContext *) context;
721 Size nblocks = 0;
722 Size totalspace = 0;
723 Size freespace = 0;
724 dlist_iter iter;
725
726 Assert(BumpIsValid(set));
727
728 dlist_foreach(iter, &set->blocks)
729 {
730 BumpBlock *block = dlist_container(BumpBlock, node, iter.cur);
731
732 nblocks++;
733 totalspace += (block->endptr - (char *) block);
734 freespace += (block->endptr - block->freeptr);
735 }
736
737 if (printfunc)
738 {
739 char stats_string[200];
740
742 "%zu total in %zu blocks; %zu free; %zu used",
743 totalspace, nblocks, freespace, totalspace - freespace);
745 }
746
747 if (totals)
748 {
749 totals->nblocks += nblocks;
750 totals->totalspace += totalspace;
751 totals->freespace += freespace;
752 }
753}

References Assert, BumpContext::blocks, BumpIsValid, dlist_iter::cur, dlist_container, dlist_foreach, BumpBlock::endptr, fb(), BumpBlock::freeptr, and snprintf.