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

Lines changed: 55 additions & 21 deletions
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

Lines changed: 14 additions & 2 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy