pg.ddx.io  pgsql-bugs@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Heikki Linnakangas <hlinnaka@iki.fi>
To: pgsql-hackers <pgsql-hackers@postgresql.org>
Subject: Re: DSA_ALLOC_NO_OOM doesn't work
Date: Tue, 13 Feb 2024 16:23:20 +0200
Message-ID: <6030bdec-0de1-4da2-b0b3-335007eae97f@iki.fi> (raw)
In-Reply-To: <5efa4a5e-2b8b-42dd-80ed-f920718cf5c0@iki.fi>
References: <5efa4a5e-2b8b-42dd-80ed-f920718cf5c0@iki.fi>

(moving to pgsql-hackers)

On 29/01/2024 14:06, Heikki Linnakangas wrote:
> If you call dsa_allocate_extended(DSA_ALLOC_NO_OOM), it will still
> ereport an error if you run out of space (originally reported at [0]).
> 
> Attached patch adds code to test_dsa.c to demonstrate that:
> 
> postgres=# select test_dsa_basic();
> ERROR:  could not resize shared memory segment "/PostgreSQL.1312700148"
> to 1075843072 bytes: No space left on device
> 
> [0] https://github.com/pgvector/pgvector/issues/434#issuecomment-1912744489

I wrote the attached patch to address this, in a fairly straightforward 
or naive way. The problem was that even though dsa_allocate() had code 
to check the return value of dsm_create(), and return NULL instead of 
ereport(ERROR) if the DSA_ALLOC_NO_OOM was set, dsm_create() does not in 
fact return NULL on OOM. To fix, I added a DSM_CREATE_NO_OOM option to 
dsm_create(), and I also had to punch that through to dsm_impl_op().

This is a little unpolished, but if we want to backpatch something 
narrow now, this would probably be the right approach.

However, I must say that the dsm_impl_op() interface is absolutely 
insane. It's like someone looked at ioctl() and thought, "hey that's a 
great idea!". It mixes all different operations like creating or 
destroying a DSM segment together into one function call, and the return 
value is just a boolean, even though the function could fail for many 
different reasons, and the callers do in fact care about the reason. In 
a more natural interface, the different operations would have very 
different function signatures.

I think we must refactor that. It might be best to leave this 
DSA_ALLOC_NO_OOM bug unfixed in backpatches, and fix it on top of the 
refactorings on master only. Later, we can backpatch the refactorings 
too if we're comfortable with it; extensions shouldn't be using the 
dsm_impl_op() interface directly.

(I skimmed through the thread where the DSM code was added, but didn't 
see any mention of why dsm_impl_op() signature is like that: 
https://www.postgresql.org/message-id/CA%2BTgmoaDqDUgt%3D4Zs_QPOnBt%3DEstEaVNP%2B5t%2Bm%3DFPNWshiPR3...)

-- 
Heikki Linnakangas
Neon (https://neon.tech)

Attachments: download all (2 files, .tar.gz)

0001-Add-test.patch (text/x-patch, 1.0K) download From b60f877ad67e70b60915b2b25d0dbae6972c3536 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas <heikki.linnakangas@iki.fi> Date: Tue, 13 Feb 2024 14:22:10 +0200 Subject: [PATCH 1/2] Add test Discussion: https://www.postgresql.org/message-id/5efa4a5e-2b8b-42dd-80ed-f920718cf5c0@iki.fi --- src/test/modules/test_dsa/test_dsa.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/modules/test_dsa/test_dsa.c b/src/test/modules/test_dsa/test_dsa.c index 844316dec2b..f37eb57e99d 100644 --- a/src/test/modules/test_dsa/test_dsa.c +++ b/src/test/modules/test_dsa/test_dsa.c @@ -51,6 +51,19 @@ test_dsa_basic(PG_FUNCTION_ARGS) for (int i = 0; i < 100; i++) { dsa_free(a, p[i]); + p[i] = InvalidDsaPointer; + } + + for (int i = 0; i < 100; i++) + p[i] = dsa_allocate_extended(a, 1024*1024*1024, DSA_ALLOC_NO_OOM | DSA_ALLOC_HUGE); + + for (int i = 0; i < 100; i++) + { + if (p[i] != InvalidDsaPointer) + { + dsa_free(a, p[i]); + p[i] = InvalidDsaPointer; + } } dsa_detach(a); -- 2.39.2
0002-Fix-DSA_ALLOC_NO_OOM.patch (text/x-patch, 19.2K) download From fb20d55111d726dca247b2111a175f30d412e35a Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas <heikki.linnakangas@iki.fi> Date: Tue, 13 Feb 2024 15:52:48 +0200 Subject: [PATCH 2/2] Fix DSA_ALLOC_NO_OOM --- src/backend/access/common/session.c | 2 +- src/backend/access/transam/parallel.c | 2 +- src/backend/storage/ipc/dsm.c | 43 +++++++++----- src/backend/storage/ipc/dsm_impl.c | 84 ++++++++++++++++++++------- src/backend/utils/mmgr/dsa.c | 2 +- src/include/storage/dsm.h | 1 + src/include/storage/dsm_impl.h | 4 +- 7 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/backend/access/common/session.c b/src/backend/access/common/session.c index 3f2256f4915..5d4fe6dbb7a 100644 --- a/src/backend/access/common/session.c +++ b/src/backend/access/common/session.c @@ -102,7 +102,7 @@ GetSessionDsmHandle(void) /* Set up segment and TOC. */ size = shm_toc_estimate(&estimator); - seg = dsm_create(size, DSM_CREATE_NULL_IF_MAXSEGMENTS); + seg = dsm_create(size, DSM_CREATE_NULL_IF_MAXSEGMENTS | DSM_CREATE_NO_OOM); if (seg == NULL) { MemoryContextSwitchTo(old_context); diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 849a03e4b65..df1e5e7145d 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -312,7 +312,7 @@ InitializeParallelDSM(ParallelContext *pcxt) */ segsize = shm_toc_estimate(&pcxt->estimator); if (pcxt->nworkers > 0) - pcxt->seg = dsm_create(segsize, DSM_CREATE_NULL_IF_MAXSEGMENTS); + pcxt->seg = dsm_create(segsize, DSM_CREATE_NULL_IF_MAXSEGMENTS | DSM_CREATE_NO_OOM); if (pcxt->seg != NULL) pcxt->toc = shm_toc_create(PARALLEL_MAGIC, dsm_segment_address(pcxt->seg), diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c index 6b12108dd10..2d2596fbe2d 100644 --- a/src/backend/storage/ipc/dsm.c +++ b/src/backend/storage/ipc/dsm.c @@ -214,7 +214,7 @@ dsm_postmaster_startup(PGShmemHeader *shim) continue; if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize, &dsm_control_impl_private, &dsm_control_address, - &dsm_control_mapped_size, ERROR)) + &dsm_control_mapped_size, ERROR, 0)) break; } dsm_control = dsm_control_address; @@ -255,7 +255,7 @@ dsm_cleanup_using_control_segment(dsm_handle old_control_handle) * out quietly. */ if (!dsm_impl_op(DSM_OP_ATTACH, old_control_handle, 0, &impl_private, - &mapped_address, &mapped_size, DEBUG1)) + &mapped_address, &mapped_size, DEBUG1, 0)) return; /* @@ -266,7 +266,7 @@ dsm_cleanup_using_control_segment(dsm_handle old_control_handle) if (!dsm_control_segment_sane(old_control, mapped_size)) { dsm_impl_op(DSM_OP_DETACH, old_control_handle, 0, &impl_private, - &mapped_address, &mapped_size, LOG); + &mapped_address, &mapped_size, LOG, 0); return; } @@ -296,7 +296,7 @@ dsm_cleanup_using_control_segment(dsm_handle old_control_handle) /* Destroy the referenced segment. */ dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private, - &junk_mapped_address, &junk_mapped_size, LOG); + &junk_mapped_address, &junk_mapped_size, LOG, 0); } /* Destroy the old control segment, too. */ @@ -304,7 +304,7 @@ dsm_cleanup_using_control_segment(dsm_handle old_control_handle) "cleaning up dynamic shared memory control segment with ID %u", old_control_handle); dsm_impl_op(DSM_OP_DESTROY, old_control_handle, 0, &impl_private, - &mapped_address, &mapped_size, LOG); + &mapped_address, &mapped_size, LOG, 0); } /* @@ -400,7 +400,7 @@ dsm_postmaster_shutdown(int code, Datum arg) /* Destroy the segment. */ dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private, - &junk_mapped_address, &junk_mapped_size, LOG); + &junk_mapped_address, &junk_mapped_size, LOG, 0); } /* Remove the control segment itself. */ @@ -410,7 +410,7 @@ dsm_postmaster_shutdown(int code, Datum arg) dsm_control_address = dsm_control; dsm_impl_op(DSM_OP_DESTROY, dsm_control_handle, 0, &dsm_control_impl_private, &dsm_control_address, - &dsm_control_mapped_size, LOG); + &dsm_control_mapped_size, LOG, 0); dsm_control = dsm_control_address; shim->dsm_control = 0; } @@ -512,6 +512,8 @@ dsm_shmem_init(void) * remains attached until explicitly detached or the session ends. * Creating with a NULL CurrentResourceOwner is equivalent to creating * with a non-NULL CurrentResourceOwner and then calling dsm_pin_mapping. + * + * XXX: explain flags */ dsm_segment * dsm_create(Size size, int flags) @@ -569,14 +571,25 @@ dsm_create(Size size, int flags) LWLockRelease(DynamicSharedMemoryControlLock); for (;;) { + int impl_flags = ((flags & DSM_CREATE_NO_OOM) != 0) ? DSM_OP_CREATE_NO_OOM : 0; + Assert(seg->mapped_address == NULL && seg->mapped_size == 0); /* Use even numbers only */ seg->handle = pg_prng_uint32(&pg_global_prng_state) << 1; if (seg->handle == DSM_HANDLE_INVALID) /* Reserve sentinel */ continue; + errno = 0; if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private, - &seg->mapped_address, &seg->mapped_size, ERROR)) + &seg->mapped_address, &seg->mapped_size, ERROR, impl_flags)) break; + if ((flags & DSM_CREATE_NO_OOM) != 0 && (errno == ENOMEM || errno == ENOSPC)) + { + if (seg->resowner != NULL) + ResourceOwnerForgetDSM(seg->resowner, seg); + dlist_delete(&seg->node); + pfree(seg); + return NULL; + } } LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); } @@ -614,13 +627,13 @@ dsm_create(Size size, int flags) LWLockRelease(DynamicSharedMemoryControlLock); if (!using_main_dsm_region) dsm_impl_op(DSM_OP_DESTROY, seg->handle, 0, &seg->impl_private, - &seg->mapped_address, &seg->mapped_size, WARNING); + &seg->mapped_address, &seg->mapped_size, WARNING, 0); if (seg->resowner != NULL) ResourceOwnerForgetDSM(seg->resowner, seg); dlist_delete(&seg->node); pfree(seg); - if ((flags & DSM_CREATE_NULL_IF_MAXSEGMENTS) != 0) + if ((flags & (DSM_CREATE_NULL_IF_MAXSEGMENTS | DSM_CREATE_NO_OOM)) != 0) return NULL; ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), @@ -744,7 +757,7 @@ dsm_attach(dsm_handle h) /* Here's where we actually try to map the segment. */ if (!is_main_region_dsm_handle(seg->handle)) dsm_impl_op(DSM_OP_ATTACH, seg->handle, 0, &seg->impl_private, - &seg->mapped_address, &seg->mapped_size, ERROR); + &seg->mapped_address, &seg->mapped_size, ERROR, 0); return seg; } @@ -788,7 +801,7 @@ dsm_detach_all(void) if (control_address != NULL) dsm_impl_op(DSM_OP_DETACH, dsm_control_handle, 0, &dsm_control_impl_private, &control_address, - &dsm_control_mapped_size, ERROR); + &dsm_control_mapped_size, ERROR, 0); } /* @@ -841,7 +854,7 @@ dsm_detach(dsm_segment *seg) { if (!is_main_region_dsm_handle(seg->handle)) dsm_impl_op(DSM_OP_DETACH, seg->handle, 0, &seg->impl_private, - &seg->mapped_address, &seg->mapped_size, WARNING); + &seg->mapped_address, &seg->mapped_size, WARNING, 0); seg->impl_private = NULL; seg->mapped_address = NULL; seg->mapped_size = 0; @@ -883,7 +896,7 @@ dsm_detach(dsm_segment *seg) */ if (is_main_region_dsm_handle(seg->handle) || dsm_impl_op(DSM_OP_DESTROY, seg->handle, 0, &seg->impl_private, - &seg->mapped_address, &seg->mapped_size, WARNING)) + &seg->mapped_address, &seg->mapped_size, WARNING, 0)) { LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); if (is_main_region_dsm_handle(seg->handle)) @@ -1055,7 +1068,7 @@ dsm_unpin_segment(dsm_handle handle) */ if (is_main_region_dsm_handle(handle) || dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private, - &junk_mapped_address, &junk_mapped_size, WARNING)) + &junk_mapped_address, &junk_mapped_size, WARNING, 0)) { LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); if (is_main_region_dsm_handle(handle)) diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index 03aa47a1049..693caf8a64b 100644 --- a/src/backend/storage/ipc/dsm_impl.c +++ b/src/backend/storage/ipc/dsm_impl.c @@ -72,23 +72,23 @@ #ifdef USE_DSM_POSIX static bool dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, - Size *mapped_size, int elevel); + Size *mapped_size, int elevel, int flags); static int dsm_impl_posix_resize(int fd, off_t size); #endif #ifdef USE_DSM_SYSV static bool dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, - Size *mapped_size, int elevel); + Size *mapped_size, int elevel, int flags); #endif #ifdef USE_DSM_WINDOWS static bool dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, - Size *mapped_size, int elevel); + Size *mapped_size, int elevel, int flags); #endif #ifdef USE_DSM_MMAP static bool dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, - Size *mapped_size, int elevel); + Size *mapped_size, int elevel, int flags); #endif static int errcode_for_dynamic_shared_memory(void); @@ -153,38 +153,45 @@ int min_dynamic_shared_memory; * a message should first be logged at the specified elevel, except in the * case where DSM_OP_CREATE experiences a name collision, which should * silently return false. + * + * If op is DSM_OP_CREATE and the DSM_OP_CREATE_NO_OOM flag is set, returns + * false on a failure caused by running out of memory or disk space, + * regardless of elevel. That can be distinguished from a name collision by + * checking if 'errno' is ENOSPC or ENOMEM. *----- */ bool dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, - int elevel) + int elevel, int flags) { Assert(op == DSM_OP_CREATE || request_size == 0); Assert((op != DSM_OP_CREATE && op != DSM_OP_ATTACH) || (*mapped_address == NULL && *mapped_size == 0)); + Assert((op == DSM_OP_CREATE && (flags & ~DSM_OP_CREATE_NO_OOM) == 0) || + flags == 0); switch (dynamic_shared_memory_type) { #ifdef USE_DSM_POSIX case DSM_IMPL_POSIX: return dsm_impl_posix(op, handle, request_size, impl_private, - mapped_address, mapped_size, elevel); + mapped_address, mapped_size, elevel, flags); #endif #ifdef USE_DSM_SYSV case DSM_IMPL_SYSV: return dsm_impl_sysv(op, handle, request_size, impl_private, - mapped_address, mapped_size, elevel); + mapped_address, mapped_size, elevel, flags); #endif #ifdef USE_DSM_WINDOWS case DSM_IMPL_WINDOWS: return dsm_impl_windows(op, handle, request_size, impl_private, - mapped_address, mapped_size, elevel); + mapped_address, mapped_size, elevel, flags); #endif #ifdef USE_DSM_MMAP case DSM_IMPL_MMAP: return dsm_impl_mmap(op, handle, request_size, impl_private, - mapped_address, mapped_size, elevel); + mapped_address, mapped_size, elevel, flags); #endif default: elog(ERROR, "unexpected dynamic shared memory type: %d", @@ -211,10 +218,10 @@ dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size, static bool dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, - int elevel) + int elevel, int flags) { char name[64]; - int flags; + int open_flags; int fd; char *address; @@ -255,10 +262,13 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, */ ReserveExternalFD(); - flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0); - if ((fd = shm_open(name, flags, PG_FILE_MODE_OWNER)) == -1) + open_flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0); + if ((fd = shm_open(name, open_flags, PG_FILE_MODE_OWNER)) == -1) { ReleaseExternalFD(); + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; if (op == DSM_OP_ATTACH || errno != EEXIST) ereport(elevel, (errcode_for_dynamic_shared_memory(), @@ -304,6 +314,9 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, shm_unlink(name); errno = save_errno; + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m", @@ -326,6 +339,9 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, shm_unlink(name); errno = save_errno; + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not map shared memory segment \"%s\": %m", @@ -422,7 +438,7 @@ dsm_impl_posix_resize(int fd, off_t size) static bool dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, - int elevel) + int elevel, int flags) { key_t key; int ident; @@ -484,13 +500,14 @@ dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, } else { - int flags = IPCProtection; + int ipc_flags = IPCProtection; size_t segsize; /* * Allocate the memory BEFORE acquiring the resource, so that we don't * leak the resource if memory allocation fails. */ + // FIXME: NO_OOM ident_cache = MemoryContextAlloc(TopMemoryContext, sizeof(int)); /* @@ -502,16 +519,20 @@ dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, if (op == DSM_OP_CREATE) { - flags |= IPC_CREAT | IPC_EXCL; + ipc_flags |= IPC_CREAT | IPC_EXCL; segsize = request_size; } - if ((ident = shmget(key, segsize, flags)) == -1) + if ((ident = shmget(key, segsize, ipc_flags)) == -1) { + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; if (op == DSM_OP_ATTACH || errno != EEXIST) { int save_errno = errno; + // FIXME: do we leak 'ident_cache' otherwise? pfree(ident_cache); errno = save_errno; ereport(elevel, @@ -579,6 +600,9 @@ dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, shmctl(ident, IPC_RMID, NULL); errno = save_errno; + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not map shared memory segment \"%s\": %m", @@ -609,7 +633,7 @@ dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, static bool dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, - Size *mapped_size, int elevel) + Size *mapped_size, int elevel, int flags) { char *address; HANDLE hmap; @@ -702,6 +726,10 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, if (!hmap) { _dosmaperr(errcode); + + if ((flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not create shared memory segment \"%s\": %m", @@ -738,6 +766,9 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, CloseHandle(hmap); errno = save_errno; + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not map shared memory segment \"%s\": %m", @@ -791,10 +822,10 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, static bool dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, - int elevel) + int elevel, int flags) { char name[64]; - int flags; + int open_flags; int fd; char *address; @@ -827,9 +858,12 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, } /* Create new segment or open an existing one for attach. */ - flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0); - if ((fd = OpenTransientFile(name, flags)) == -1) + open_flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0); + if ((fd = OpenTransientFile(name, open_flags)) == -1) { + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; if (op == DSM_OP_ATTACH || errno != EEXIST) ereport(elevel, (errcode_for_dynamic_shared_memory(), @@ -906,6 +940,9 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, unlink(name); errno = save_errno ? save_errno : ENOSPC; + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m", @@ -928,6 +965,9 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, unlink(name); errno = save_errno; + if (op == DSM_OP_CREATE && (flags & DSM_OP_CREATE_NO_OOM) != 0 && + (errno == ENOMEM || errno == ENOSPC)) + return false; ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not map shared memory segment \"%s\": %m", diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c index a6b728ba9ff..29b6f975be7 100644 --- a/src/backend/utils/mmgr/dsa.c +++ b/src/backend/utils/mmgr/dsa.c @@ -2164,7 +2164,7 @@ make_new_segment(dsa_area *area, size_t requested_pages) /* Create the segment. */ oldowner = CurrentResourceOwner; CurrentResourceOwner = area->resowner; - segment = dsm_create(total_size, 0); + segment = dsm_create(total_size, DSM_CREATE_NULL_IF_MAXSEGMENTS | DSM_CREATE_NO_OOM); CurrentResourceOwner = oldowner; if (segment == NULL) return NULL; diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h index 1a22b32df1a..7e2ec8fc560 100644 --- a/src/include/storage/dsm.h +++ b/src/include/storage/dsm.h @@ -18,6 +18,7 @@ typedef struct dsm_segment dsm_segment; #define DSM_CREATE_NULL_IF_MAXSEGMENTS 0x0001 +#define DSM_CREATE_NO_OOM 0x0002 /* Startup and shutdown functions. */ struct PGShmemHeader; /* avoid including pg_shmem.h */ diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h index 882269603da..2097876f756 100644 --- a/src/include/storage/dsm_impl.h +++ b/src/include/storage/dsm_impl.h @@ -66,10 +66,12 @@ typedef enum DSM_OP_DESTROY, } dsm_op; +#define DSM_OP_CREATE_NO_OOM 0x01 + /* Create, attach to, detach from, resize, or destroy a segment. */ extern bool dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, - int elevel); + int elevel, int flags); /* Implementation-dependent actions required to keep segment until shutdown. */ extern void dsm_impl_pin_segment(dsm_handle handle, void *impl_private, -- 2.39.2

view thread (9+ messages)  latest in thread

Message-ID: <6030bdec-0de1-4da2-b0b3-335007eae97f@iki.fi>
Permalink:  ../6030bdec-0de1-4da2-b0b3-335007eae97f@iki.fi/
Also on:    postgresql.org/message-id/6030bdec-0de1-4da2-b0b3-335007eae97f@iki.fi

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-bugs@postgresql.org
  Cc: hlinnaka@iki.fi, pgsql-hackers@postgresql.org
  Subject: Re: DSA_ALLOC_NO_OOM doesn't work
  In-Reply-To: <6030bdec-0de1-4da2-b0b3-335007eae97f@iki.fi>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox