Add GUC parameter "huge_pages_status"
authorMichael Paquier
Thu, 6 Jul 2023 05:42:36 +0000 (14:42 +0900)
committerMichael Paquier
Thu, 6 Jul 2023 05:42:36 +0000 (14:42 +0900)
This is useful to show the allocation state of huge pages when setting
up a server with "huge_pages = try", where allocating huge pages would
be attempted but the server would continue its startup sequence even if
the allocation fails.  The effective status of huge pages is not easily
visible without OS-level tools (or for instance, a lookup at
/proc/N/smaps), and the environments where Postgres runs may not
authorize that.  Like the other GUCs related to huge pages, this works
for Linux and Windows.

This GUC can report as values:
- "on", if huge pages were allocated.
- "off", if huge pages were not allocated.
- "unknown", a special state that could only be seen when using for
example postgres -C because it is only possible to know if the shared
memory allocation worked after we can check for the GUC values, even if
checking a runtime-computed GUC.  This value should never be seen when
querying for the GUC on a running server.  An assertion is added to
check that.

The discussion has also turned around having a new function to grab this
status, but this would have required more tricks for -DEXEC_BACKEND,
something that GUCs already handle.

Noriyoshi Shinoda has initiated the thread that has led to the result of
this commit.

Author: Justin Pryzby
Reviewed-by: Nathan Bossart, Kyotaro Horiguchi, Michael Paquier
Discussion: https://postgr.es/m/TU4PR8401MB1152EBB0D271F827E2E37A01EECC9@TU4PR8401MB1152.NAMPRD84.PROD.OUTLOOK.COM

doc/src/sgml/config.sgml
src/backend/port/sysv_shmem.c
src/backend/port/win32_shmem.c
src/backend/storage/ipc/ipci.c
src/backend/utils/misc/guc_tables.c
src/include/storage/pg_shmem.h
src/test/authentication/t/003_peer.pl
src/test/authentication/t/005_sspi.pl

index 6262cb7bb2f1ae85c20e17de3de6834c10c1899a..c9fa6cd9c76be1c9ff5c6fe61e5a4d3e8b374b96 100644 (file)
@@ -1727,7 +1727,9 @@ include_dir 'conf.d'
         server will try to request huge pages, but fall back to the default if
         that fails. With on, failure to request huge pages
         will prevent the server from starting up. With off,
-        huge pages will not be requested.
+        huge pages will not be requested. The actual state of huge pages is
+        indicated by the server variable
+        .
        
 
        
@@ -10738,6 +10740,25 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
       
      
 
+     
+      huge_pages_status (enum)
+      
+       huge_pages_status configuration parameter
+      
+      
+      
+       
+        Reports the state of huge pages in the current instance:
+        onoff, or
+        unknown (if displayed with
+        postgres -C).
+        This parameter is useful to determine whether allocation of huge pages
+        was successful under huge_pages=try.
+        See  for more information.
+       
+      
+     
+
      
       integer_datetimes (boolean)
       
index eaba244bc9c853fe28a6f03f6487c7c38371b42f..f1eb5a1e208a9358e61eb43df308e94a3417377f 100644 (file)
@@ -627,6 +627,14 @@ CreateAnonymousSegment(Size *size)
    }
 #endif
 
+   /*
+    * Report whether huge pages are in use.  This needs to be tracked before
+    * the second mmap() call if attempting to use huge pages failed
+    * previously.
+    */
+   SetConfigOption("huge_pages_status", (ptr == MAP_FAILED) ? "off" : "on",
+                   PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+
    if (ptr == MAP_FAILED && huge_pages != HUGE_PAGES_ON)
    {
        /*
@@ -737,8 +745,14 @@ PGSharedMemoryCreate(Size size,
        sysvsize = sizeof(PGShmemHeader);
    }
    else
+   {
        sysvsize = size;
 
+       /* huge pages are only available with mmap */
+       SetConfigOption("huge_pages_status", "off",
+                       PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+   }
+
    /*
     * Loop till we find a free IPC key.  Trust CreateDataDirLockFile() to
     * ensure no more than one postmaster per data directory can enter this
index 62e08074770f22f985f2fc5fa40e09e58cee57c0..05494c14a93316a7a2767779c6cd4c22b8de5cc8 100644 (file)
@@ -401,6 +401,11 @@ retry:
    on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));
 
    *shim = hdr;
+
+   /* Report whether huge pages are in use */
+   SetConfigOption("huge_pages_status", (flProtect & SEC_LARGE_PAGES) ?
+                   "on" : "off", PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+
    return hdr;
 }
 
index 8f1ded7338f83944416fd8605c2338a260cec2e8..cc387c00a15d79a74aa71db361b79d4852fa4ae6 100644 (file)
@@ -190,6 +190,13 @@ CreateSharedMemoryAndSemaphores(void)
         */
        seghdr = PGSharedMemoryCreate(size, &shim);
 
+       /*
+        * Make sure that huge pages are never reported as "unknown" while the
+        * server is running.
+        */
+       Assert(strcmp("unknown",
+                     GetConfigOption("huge_pages_status", false, false)) != 0);
+
        InitShmemAccess(seghdr);
 
        /*
index f8ef87d26dcdcbe6fa8eea2065742221a47194a2..59ab630ae40977e4d23c87a715c7ade7a1774312 100644 (file)
@@ -365,6 +365,13 @@ static const struct config_enum_entry huge_pages_options[] = {
    {NULL, 0, false}
 };
 
+static const struct config_enum_entry huge_pages_status_options[] = {
+   {"off", HUGE_PAGES_OFF, false},
+   {"on", HUGE_PAGES_ON, false},
+   {"unknown", HUGE_PAGES_UNKNOWN, false},
+   {NULL, 0, false}
+};
+
 static const struct config_enum_entry recovery_prefetch_options[] = {
    {"off", RECOVERY_PREFETCH_OFF, false},
    {"on", RECOVERY_PREFETCH_ON, false},
@@ -550,6 +557,7 @@ int         ssl_renegotiation_limit;
  */
 int            huge_pages = HUGE_PAGES_TRY;
 int            huge_page_size;
+int            huge_pages_status = HUGE_PAGES_UNKNOWN;
 
 /*
  * These variables are all dummies that don't do anything, except in some
@@ -4876,6 +4884,17 @@ struct config_enum ConfigureNamesEnum[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"huge_pages_status", PGC_INTERNAL, PRESET_OPTIONS,
+           gettext_noop("Indicates the status of huge pages."),
+           NULL,
+           GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+       },
+       &huge_pages_status,
+       HUGE_PAGES_UNKNOWN, huge_pages_status_options,
+       NULL, NULL, NULL
+   },
+
    {
        {"recovery_prefetch", PGC_SIGHUP, WAL_RECOVERY,
            gettext_noop("Prefetch referenced blocks during recovery."),
index 4dd05f156d54712087f0cd0870e437e0ed694310..ba0cdc13c77dd7f5a6c7831cd18c60d272ed9130 100644 (file)
@@ -46,12 +46,13 @@ extern PGDLLIMPORT int shared_memory_type;
 extern PGDLLIMPORT int huge_pages;
 extern PGDLLIMPORT int huge_page_size;
 
-/* Possible values for huge_pages */
+/* Possible values for huge_pages and huge_pages_status */
 typedef enum
 {
    HUGE_PAGES_OFF,
    HUGE_PAGES_ON,
-   HUGE_PAGES_TRY
+   HUGE_PAGES_TRY,             /* only for huge_pages */
+   HUGE_PAGES_UNKNOWN          /* only for huge_pages_status */
 }          HugePagesType;
 
 /* Possible values for shared_memory_type */
index d8e49760726a289a5be2dd43e0de5a75347df678..eacff2b52aa09af792c068f2deff83a036fb5af5 100644 (file)
@@ -100,6 +100,12 @@ my $system_user =
   $node->safe_psql('postgres',
    q(select (string_to_array(SYSTEM_USER, ':'))[2]));
 
+# While on it, check the status of huge pages, that can be either on
+# or off, but never unknown.
+my $huge_pages_status =
+  $node->safe_psql('postgres', q(SHOW huge_pages_status;));
+isnt($huge_pages_status, 'unknown', "check huge_pages_status");
+
 # Tests without the user name map.
 # Failure as connection is attempted with a database role not mapping
 # to an authorized system user.
index 05d81f342293bcd1bcb936a9648d36964a321385..37fd5bc2437351ad969e4a1a5b8109e79325c107 100644 (file)
@@ -21,6 +21,10 @@ $node->init;
 $node->append_conf('postgresql.conf', "log_connections = on\n");
 $node->start;
 
+my $huge_pages_status =
+  $node->safe_psql('postgres', q(SHOW huge_pages_status;));
+isnt($huge_pages_status, 'unknown', "check huge_pages_status");
+
 # SSPI is set up by default.  Make sure it interacts correctly with
 # require_auth.
 $node->connect_ok("require_auth=sspi",