Skip to content

Commit 16be2fd

Browse files
committed
Make dsa_allocate interface more like MemoryContextAlloc.
A new function dsa_allocate_extended now takes flags which indicate that huge allocations should be permitted, that out-of-memory conditions should not throw an error, and/or that the returned memory should be zero-filled, just like MemoryContextAllocateExtended. Commit 9acb855, which added dsa_allocate0, was broken because it failed to account for the possibility that dsa_allocate() might return InvalidDsaPointer. This fixes that problem along the way. Thomas Munro, with some comment changes by me. Discussion: http://postgr.es/m/CA+Tgmobt7CcF_uQP2UQwWmu4K9qCHehMJP9_9m1urwP8hbOeHQ@mail.gmail.com
1 parent 1a16af8 commit 16be2fd

File tree

2 files changed

+69
-23
lines changed

2 files changed

+69
-23
lines changed

src/backend/utils/mmgr/dsa.c

+55-21
Original file line numberDiff line numberDiff line change
@@ -642,18 +642,39 @@ dsa_pin_mapping(dsa_area *area)
642642
/*
643643
* Allocate memory in this storage area. The return value is a dsa_pointer
644644
* that can be passed to other processes, and converted to a local pointer
645-
* with dsa_get_address. If no memory is available, returns
646-
* InvalidDsaPointer.
645+
* with dsa_get_address. 'flags' is a bitmap which should be constructed
646+
* from the following values:
647+
*
648+
* DSA_ALLOC_HUGE allows allocations >= 1GB. Otherwise, such allocations
649+
* will result in an ERROR.
650+
*
651+
* DSA_ALLOC_NO_OOM causes this function to return InvalidDsaPointer when
652+
* no memory is available or a size limit establed by set_dsa_size_limit
653+
* would be exceeded. Otherwise, such allocations will result in an ERROR.
654+
*
655+
* DSA_ALLOC_ZERO causes the allocated memory to be zeroed. Otherwise, the
656+
* contents of newly-allocated memory are indeterminate.
657+
*
658+
* These flags correspond to similarly named flags used by
659+
* MemoryContextAllocExtended(). See also the macros dsa_allocate and
660+
* dsa_allocate0 which expand to a call to this function with commonly used
661+
* flags.
647662
*/
648663
dsa_pointer
649-
dsa_allocate(dsa_area *area, Size size)
664+
dsa_allocate_extended(dsa_area *area, Size size, int flags)
650665
{
651666
uint16 size_class;
652667
dsa_pointer start_pointer;
653668
dsa_segment_map *segment_map;
669+
dsa_pointer result;
654670

655671
Assert(size > 0);
656672

673+
/* Sanity check on huge individual allocation size. */
674+
if (((flags & DSA_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
675+
((flags & DSA_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
676+
elog(ERROR, "invalid DSA memory alloc request size %zu", size);
677+
657678
/*
658679
* If bigger than the largest size class, just grab a run of pages from
659680
* the free page manager, instead of allocating an object from a pool.
@@ -684,6 +705,14 @@ dsa_allocate(dsa_area *area, Size size)
684705
/* Can't make any more segments: game over. */
685706
LWLockRelease(DSA_AREA_LOCK(area));
686707
dsa_free(area, span_pointer);
708+
709+
/* Raise error unless asked not to. */
710+
if ((flags & MCXT_ALLOC_NO_OOM) == 0)
711+
ereport(ERROR,
712+
(errcode(ERRCODE_OUT_OF_MEMORY),
713+
errmsg("out of memory"),
714+
errdetail("Failed on DSA request of size %zu.",
715+
size)));
687716
return InvalidDsaPointer;
688717
}
689718

@@ -710,6 +739,10 @@ dsa_allocate(dsa_area *area, Size size)
710739
segment_map->pagemap[first_page] = span_pointer;
711740
LWLockRelease(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE));
712741

742+
/* Zero-initialize the memory if requested. */
743+
if ((flags & DSA_ALLOC_ZERO) != 0)
744+
memset(dsa_get_address(area, start_pointer), 0, size);
745+
713746
return start_pointer;
714747
}
715748

@@ -748,27 +781,28 @@ dsa_allocate(dsa_area *area, Size size)
748781
Assert(size <= dsa_size_classes[size_class]);
749782
Assert(size_class == 0 || size > dsa_size_classes[size_class - 1]);
750783

751-
/*
752-
* Attempt to allocate an object from the appropriate pool. This might
753-
* return InvalidDsaPointer if there's no space available.
754-
*/
755-
return alloc_object(area, size_class);
756-
}
784+
/* Attempt to allocate an object from the appropriate pool. */
785+
result = alloc_object(area, size_class);
757786

758-
/*
759-
* As dsa_allocate, but zeroes the allocated memory.
760-
*/
761-
dsa_pointer
762-
dsa_allocate0(dsa_area *area, Size size)
763-
{
764-
dsa_pointer dp;
765-
char *object;
787+
/* Check for failure to allocate. */
788+
if (!DsaPointerIsValid(result))
789+
{
790+
/* Raise error unless asked not to. */
791+
if ((flags & DSA_ALLOC_NO_OOM) == 0)
792+
{
793+
ereport(ERROR,
794+
(errcode(ERRCODE_OUT_OF_MEMORY),
795+
errmsg("out of memory"),
796+
errdetail("Failed on DSA request of size %zu.", size)));
797+
}
798+
return InvalidDsaPointer;
799+
}
766800

767-
dp = dsa_allocate(area, size);
768-
object = dsa_get_address(area, dp);
769-
memset(object, 0, size);
801+
/* Zero-initialize the memory if requested. */
802+
if ((flags & DSA_ALLOC_ZERO) != 0)
803+
memset(dsa_get_address(area, result), 0, size);
770804

771-
return dp;
805+
return result;
772806
}
773807

774808
/*

src/include/utils/dsa.h

+14-2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,25 @@ typedef pg_atomic_uint64 dsa_pointer_atomic;
7171
#define DSA_POINTER_FORMAT "%016" INT64_MODIFIER "x"
7272
#endif
7373

74+
/* Flags for dsa_allocate_extended. */
75+
#define DSA_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) */
76+
#define DSA_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */
77+
#define DSA_ALLOC_ZERO 0x04 /* zero allocated memory */
78+
7479
/* A sentinel value for dsa_pointer used to indicate failure to allocate. */
7580
#define InvalidDsaPointer ((dsa_pointer) 0)
7681

7782
/* Check if a dsa_pointer value is valid. */
7883
#define DsaPointerIsValid(x) ((x) != InvalidDsaPointer)
7984

85+
/* Allocate uninitialized memory with error on out-of-memory. */
86+
#define dsa_allocate(area, size) \
87+
dsa_allocate_extended(area, size, 0)
88+
89+
/* Allocate zero-initialized memory with error on out-of-memory. */
90+
#define dsa_allocate0(area, size) \
91+
dsa_allocate_extended(area, size, DSA_ALLOC_ZERO)
92+
8093
/*
8194
* The type used for dsa_area handles. dsa_handle values can be shared with
8295
* other processes, so that they can attach to them. This provides a way to
@@ -105,8 +118,7 @@ extern void dsa_unpin(dsa_area *area);
105118
extern void dsa_set_size_limit(dsa_area *area, Size limit);
106119
extern Size dsa_minimum_size(void);
107120
extern dsa_handle dsa_get_handle(dsa_area *area);
108-
extern dsa_pointer dsa_allocate(dsa_area *area, Size size);
109-
extern dsa_pointer dsa_allocate0(dsa_area *area, Size size);
121+
extern dsa_pointer dsa_allocate_extended(dsa_area *area, Size size, int flags);
110122
extern void dsa_free(dsa_area *area, dsa_pointer dp);
111123
extern void *dsa_get_address(dsa_area *area, dsa_pointer dp);
112124
extern void dsa_trim(dsa_area *area);

0 commit comments

Comments
 (0)