Make some minor improvements in memory-context infrastructure.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Oct 2022 15:55:56 +0000 (11:55 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Oct 2022 15:55:56 +0000 (11:55 -0400)
We lack a version of repalloc() that supports MCXT_ALLOC_NO_OOM
semantics, so invent repalloc_extended() with the usual set of
flags.  repalloc_huge() becomes a legacy wrapper for that.

Also, fix dynahash.c so that it can support HASH_ENTER_NULL
requests when using the default palloc-based allocator.
The only reason it didn't do that already was the lack of the
MCXT_ALLOC_NO_OOM option when that code was written, ages ago.

While here, simplify a few overcomplicated tests in mcxt.c.

Discussion: https://postgr.es/m/2982579.1662416866@sss.pgh.pa.us

src/backend/utils/hash/dynahash.c
src/backend/utils/mmgr/mcxt.c
src/include/utils/palloc.h

index 3babde8d704db76c7a785792101df405dca45dc3..4f62958883569e23e7d736f80fbc1f5a9fe3ed5a 100644 (file)
@@ -289,7 +289,8 @@ static void *
 DynaHashAlloc(Size size)
 {
    Assert(MemoryContextIsValid(CurrentDynaHashCxt));
-   return MemoryContextAlloc(CurrentDynaHashCxt, size);
+   return MemoryContextAllocExtended(CurrentDynaHashCxt, size,
+                                     MCXT_ALLOC_NO_OOM);
 }
 
 
@@ -939,9 +940,7 @@ calc_bucket(HASHHDR *hctl, uint32 hash_val)
  *
  * HASH_ENTER will normally ereport a generic "out of memory" error if
  * it is unable to create a new entry.  The HASH_ENTER_NULL operation is
- * the same except it will return NULL if out of memory.  Note that
- * HASH_ENTER_NULL cannot be used with the default palloc-based allocator,
- * since palloc internally ereports on out-of-memory.
+ * the same except it will return NULL if out of memory.
  *
  * If foundPtr isn't NULL, then *foundPtr is set true if we found an
  * existing entry in the table, false otherwise.  This is needed in the
@@ -1084,12 +1083,8 @@ hash_search_with_hash_value(HTAB *hashp,
            }
            return NULL;
 
-       case HASH_ENTER_NULL:
-           /* ENTER_NULL does not work with palloc-based allocator */
-           Assert(hashp->alloc != DynaHashAlloc);
-           /* FALL THRU */
-
        case HASH_ENTER:
+       case HASH_ENTER_NULL:
            /* Return existing element if found, else create one */
            if (currBucket != NULL)
                return (void *) ELEMENTKEY(currBucket);
index b1a3c74830575f452a7be169202c15da93d42ec6..012517be5c5f07c8f52ac0658edbd252c2ab19f3 100644 (file)
@@ -1114,8 +1114,8 @@ MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
    AssertArg(MemoryContextIsValid(context));
    AssertNotInCriticalSection(context);
 
-   if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
-       ((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
+   if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
+         AllocSizeIsValid(size)))
        elog(ERROR, "invalid memory alloc request size %zu", size);
 
    context->isReset = false;
@@ -1269,8 +1269,8 @@ palloc_extended(Size size, int flags)
    AssertArg(MemoryContextIsValid(context));
    AssertNotInCriticalSection(context);
 
-   if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
-       ((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
+   if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
+         AllocSizeIsValid(size)))
        elog(ERROR, "invalid memory alloc request size %zu", size);
 
    context->isReset = false;
@@ -1351,6 +1351,50 @@ repalloc(void *pointer, Size size)
    return ret;
 }
 
+/*
+ * repalloc_extended
+ *     Adjust the size of a previously allocated chunk,
+ *     with HUGE and NO_OOM options.
+ */
+void *
+repalloc_extended(void *pointer, Size size, int flags)
+{
+#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
+   MemoryContext context = GetMemoryChunkContext(pointer);
+#endif
+   void       *ret;
+
+   if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
+         AllocSizeIsValid(size)))
+       elog(ERROR, "invalid memory alloc request size %zu", size);
+
+   AssertNotInCriticalSection(context);
+
+   /* isReset must be false already */
+   Assert(!context->isReset);
+
+   ret = MCXT_METHOD(pointer, realloc) (pointer, size);
+   if (unlikely(ret == NULL))
+   {
+       if ((flags & MCXT_ALLOC_NO_OOM) == 0)
+       {
+           MemoryContext cxt = GetMemoryChunkContext(pointer);
+
+           MemoryContextStats(TopMemoryContext);
+           ereport(ERROR,
+                   (errcode(ERRCODE_OUT_OF_MEMORY),
+                    errmsg("out of memory"),
+                    errdetail("Failed on request of size %zu in memory context \"%s\".",
+                              size, cxt->name)));
+       }
+       return NULL;
+   }
+
+   VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
+
+   return ret;
+}
+
 /*
  * MemoryContextAllocHuge
  *     Allocate (possibly-expansive) space within the specified context.
@@ -1394,35 +1438,8 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
 void *
 repalloc_huge(void *pointer, Size size)
 {
-#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
-   MemoryContext context = GetMemoryChunkContext(pointer);
-#endif
-   void       *ret;
-
-   if (!AllocHugeSizeIsValid(size))
-       elog(ERROR, "invalid memory alloc request size %zu", size);
-
-   AssertNotInCriticalSection(context);
-
-   /* isReset must be false already */
-   Assert(!context->isReset);
-
-   ret = MCXT_METHOD(pointer, realloc) (pointer, size);
-   if (unlikely(ret == NULL))
-   {
-       MemoryContext cxt = GetMemoryChunkContext(pointer);
-
-       MemoryContextStats(TopMemoryContext);
-       ereport(ERROR,
-               (errcode(ERRCODE_OUT_OF_MEMORY),
-                errmsg("out of memory"),
-                errdetail("Failed on request of size %zu in memory context \"%s\".",
-                          size, cxt->name)));
-   }
-
-   VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
-
-   return ret;
+   /* this one seems not worth its own implementation */
+   return repalloc_extended(pointer, size, MCXT_ALLOC_HUGE);
 }
 
 /*
index a0b62aa7b0c7179d7188c0cbd9fd7f33e626032d..8eee0e293857ca839a40487dbd8220c74509293d 100644 (file)
@@ -78,6 +78,8 @@ extern void *palloc(Size size);
 extern void *palloc0(Size size);
 extern void *palloc_extended(Size size, int flags);
 extern pg_nodiscard void *repalloc(void *pointer, Size size);
+extern pg_nodiscard void *repalloc_extended(void *pointer,
+                                           Size size, int flags);
 extern void pfree(void *pointer);
 
 /*