Hi, While investigating on some strange "out of shared memory" error reported on the french BBS [1], I noticed that 09adc9a8c09 (adding Robert in Cc) changed ShmemAlloc alignment to CACHELINEALIGN but didn't update any related code that depended on it.
Most of the core code isn't impacted as it doesn't have to reserve any shared memory, but AFAICT pg_prewarm and pg_stat_statements can now slightly underestimate the amount of shared memory they'll use, and similarly for any third party extension that still rely on MAXALIGN alignment. As a consequence those extension can consume a few hundred bytes more than they reserved, which probably will be borrowed from the lock hashtables reserved size that isn't alloced immediately. This can later lead to ShmemAlloc failing when trying to acquire a lock while the hash table is almost full but should still have enough room to store it, which could explain the error reported. PFA a patch that fixes pg_prewarm and pg_stat_statements explicit alignment to CACHELINEALIGN, and also update the alignment in hash_estimate_size() to what I think ShmemInitHash will actually consume. [1] https://forums.postgresql.fr/viewtopic.php?pid=32138#p32138 sorry, it's all in French.
>From 59f4959f3b8f7e69fdbe88a85efaca80b6718a38 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud <julien.rouh...@free.fr> Date: Sat, 27 Feb 2021 15:45:29 +0800 Subject: [PATCH v1] Fix various shared memory computation Oversight in 09adc9a8c09. --- contrib/pg_prewarm/autoprewarm.c | 2 +- contrib/pg_stat_statements/pg_stat_statements.c | 2 +- src/backend/utils/hash/dynahash.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index b3f73ea92d..887e68b288 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -138,7 +138,7 @@ _PG_init(void) EmitWarningsOnPlaceholders("pg_prewarm"); - RequestAddinShmemSpace(MAXALIGN(sizeof(AutoPrewarmSharedState))); + RequestAddinShmemSpace(CACHELINEALIGN(sizeof(AutoPrewarmSharedState))); /* Register autoprewarm worker, if enabled. */ if (autoprewarm) diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 62cccbfa44..4e045ffba7 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -1933,7 +1933,7 @@ pgss_memsize(void) { Size size; - size = MAXALIGN(sizeof(pgssSharedState)); + size = CACHELINEALIGN(sizeof(pgssSharedState)); size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry))); return size; diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index 6546e3c7c7..e532a3825a 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -797,19 +797,19 @@ hash_estimate_size(long num_entries, Size entrysize) nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */ /* fixed control info */ - size = MAXALIGN(sizeof(HASHHDR)); /* but not HTAB, per above */ + size = CACHELINEALIGN(sizeof(HASHHDR)); /* but not HTAB, per above */ /* directory */ size = add_size(size, mul_size(nDirEntries, sizeof(HASHSEGMENT))); /* segments */ size = add_size(size, mul_size(nSegments, - MAXALIGN(DEF_SEGSIZE * sizeof(HASHBUCKET)))); + CACHELINEALIGN(DEF_SEGSIZE * sizeof(HASHBUCKET)))); /* elements --- allocated in groups of choose_nelem_alloc() entries */ elementAllocCnt = choose_nelem_alloc(entrysize); nElementAllocs = (num_entries - 1) / elementAllocCnt + 1; elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize); size = add_size(size, - mul_size(nElementAllocs, - mul_size(elementAllocCnt, elementSize))); + CACHELINEALIGN(Nmul_size(nElementAllocs, + mul_size(elementAllocCnt, elementSize)))); return size; } -- 2.30.1