Skip to content

Commit b282fa8

Browse files
committed
simplehash: preserve consistency in case of OOM.
Compute size first, then allocate, then update the structure. Previously, an out-of-memory when growing could leave the hashtable in an inconsistent state. Discussion: https://postgr.es/m/20231117201334.eyb542qr5yk4gilq@awork3.anarazel.de Reviewed-by: Andres Freund Reviewed-by: Gurjeet Singh
1 parent a268a51 commit b282fa8

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

src/include/lib/simplehash.h

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@
128128
#define SH_STAT SH_MAKE_NAME(stat)
129129

130130
/* internal helper functions (no externally visible prototypes) */
131-
#define SH_COMPUTE_PARAMETERS SH_MAKE_NAME(compute_parameters)
131+
#define SH_COMPUTE_SIZE SH_MAKE_NAME(compute_size)
132+
#define SH_UPDATE_PARAMETERS SH_MAKE_NAME(update_parameters)
132133
#define SH_NEXT SH_MAKE_NAME(next)
133134
#define SH_PREV SH_MAKE_NAME(prev)
134135
#define SH_DISTANCE_FROM_OPTIMAL SH_MAKE_NAME(distance)
@@ -303,11 +304,11 @@ SH_SCOPE void SH_STAT(SH_TYPE * tb);
303304
#endif
304305

305306
/*
306-
* Compute sizing parameters for hashtable. Called when creating and growing
307-
* the hashtable.
307+
* Compute allocation size for hashtable. Result can be passed to
308+
* SH_UPDATE_PARAMETERS.
308309
*/
309-
static inline void
310-
SH_COMPUTE_PARAMETERS(SH_TYPE * tb, uint64 newsize)
310+
static inline uint64
311+
SH_COMPUTE_SIZE(uint64 newsize)
311312
{
312313
uint64 size;
313314

@@ -325,6 +326,18 @@ SH_COMPUTE_PARAMETERS(SH_TYPE * tb, uint64 newsize)
325326
if (unlikely((((uint64) sizeof(SH_ELEMENT_TYPE)) * size) >= SIZE_MAX / 2))
326327
sh_error("hash table too large");
327328

329+
return size;
330+
}
331+
332+
/*
333+
* Update sizing parameters for hashtable. Called when creating and growing
334+
* the hashtable.
335+
*/
336+
static inline void
337+
SH_UPDATE_PARAMETERS(SH_TYPE * tb, uint64 newsize)
338+
{
339+
uint64 size = SH_COMPUTE_SIZE(newsize);
340+
328341
/* now set size */
329342
tb->size = size;
330343
tb->sizemask = (uint32) (size - 1);
@@ -446,10 +459,11 @@ SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data)
446459
/* increase nelements by fillfactor, want to store nelements elements */
447460
size = Min((double) SH_MAX_SIZE, ((double) nelements) / SH_FILLFACTOR);
448461

449-
SH_COMPUTE_PARAMETERS(tb, size);
462+
size = SH_COMPUTE_SIZE(size);
450463

451-
tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size);
464+
tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * size);
452465

466+
SH_UPDATE_PARAMETERS(tb, size);
453467
return tb;
454468
}
455469

@@ -490,10 +504,15 @@ SH_GROW(SH_TYPE * tb, uint64 newsize)
490504
Assert(oldsize != SH_MAX_SIZE);
491505
Assert(oldsize < newsize);
492506

493-
/* compute parameters for new table */
494-
SH_COMPUTE_PARAMETERS(tb, newsize);
507+
newsize = SH_COMPUTE_SIZE(newsize);
495508

496-
tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size);
509+
tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * newsize);
510+
511+
/*
512+
* Update parameters for new table after allocation succeeds to avoid
513+
* inconsistent state on OOM.
514+
*/
515+
SH_UPDATE_PARAMETERS(tb, newsize);
497516

498517
newdata = tb->data;
499518

@@ -1173,7 +1192,8 @@ SH_STAT(SH_TYPE * tb)
11731192
#undef SH_STAT
11741193

11751194
/* internal function names */
1176-
#undef SH_COMPUTE_PARAMETERS
1195+
#undef SH_COMPUTE_SIZE
1196+
#undef SH_UPDATE_PARAMETERS
11771197
#undef SH_COMPARE_KEYS
11781198
#undef SH_INITIAL_BUCKET
11791199
#undef SH_NEXT

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