diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 8d7b3bf..e1c3c66 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1335,17 +1335,23 @@ include_dir 'conf.d'
- At present, this feature is supported only on Linux. The setting is
- ignored on other systems when set to try.
+ At present, this feature is supported only on Linux and Windows. The
+ setting is ignored on other systems when set to try.
The use of huge pages results in smaller page tables and less CPU time
- spent on memory management, increasing performance. For more details,
+ spent on memory management, increasing performance. For more details on Linux,
see .
+ This feature uses the large-page support on Windows. To use the large-page
+ support, you need to assign Lock page in memory user right to the Windows
+ user account which runs PostgreSQL.
+
+
+
With huge_pages set to try,
the server will try to use huge pages, but fall back to using
normal allocation if that fails. With on, failure
diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index 0ff2c7e..88b195a 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -21,6 +21,7 @@ HANDLE UsedShmemSegID = INVALID_HANDLE_VALUE;
void *UsedShmemSegAddr = NULL;
static Size UsedShmemSegSize = 0;
+static bool EnableLockPagesPrivilege(int elevel);
static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
/*
@@ -103,6 +104,61 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
return true;
}
+/*
+ * EnableLockPagesPrivilege
+ *
+ * Try to acquire SeLockMemoryPrivilege so we can use large pages.
+ */
+static bool
+EnableLockPagesPrivilege(int elevel)
+{
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tp;
+ LUID luid;
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ {
+ ereport(elevel,
+ (errmsg("could not enable Lock pages in memory user right"),
+ errdetail("Failed system call was %s, error code %lu", "OpenProcessToken", GetLastError())));
+ return FALSE;
+ }
+
+ if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
+ {
+ CloseHandle(hToken);
+ ereport(elevel,
+ (errmsg("could not enable Lock pages in memory user right"),
+ errdetail("Failed system call was %s, error code %lu", "LookupPrivilegeValue", GetLastError())));
+ return FALSE;
+ }
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
+ {
+ ereport(elevel,
+ (errmsg("could not enable Lock pages in memory user right"),
+ errdetail("Failed system call was %s, error code %lu", "AdjustTokenPrivileges", GetLastError())));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("could not enable Lock pages in memory user right"),
+ errhint("Assign Lock pages in memory user right to the Windows user account which runs PostgreSQL.")));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ CloseHandle(hToken);
+
+ return TRUE;
+}
/*
* PGSharedMemoryCreate
@@ -127,11 +183,8 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
int i;
DWORD size_high;
DWORD size_low;
-
- if (huge_pages == HUGE_PAGES_ON)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("huge pages not supported on this platform")));
+ SIZE_T largePageSize = 0;
+ DWORD flProtect = PAGE_READWRITE;
/* Room for a header? */
Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
@@ -140,6 +193,34 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
UsedShmemSegAddr = NULL;
+ if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY)
+ {
+ /* Does the processor support large pages? */
+ largePageSize = GetLargePageMinimum();
+ if (largePageSize == 0)
+ {
+ ereport(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("the processor does not support large pages")));
+ ereport(DEBUG1,
+ (errmsg("disabling huge pages")));
+ }
+ else if (!EnableLockPagesPrivilege(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1))
+ {
+ ereport(DEBUG1,
+ (errmsg("disabling huge pages")));
+ }
+ else
+ {
+ /* Huge pages available and privilege enabled, so turn on */
+ flProtect = PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES;
+
+ /* Round size up as appropriate. */
+ if (size % largePageSize != 0)
+ size += largePageSize - (size % largePageSize);
+ }
+ }
+
#ifdef _WIN64
size_high = size >> 32;
#else
@@ -163,7 +244,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */
NULL, /* Default security attrs */
- PAGE_READWRITE, /* Memory is Read/Write */
+ flProtect,
size_high, /* Size Upper 32 Bits */
size_low, /* Size Lower 32 bits */
szShareMem);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 946ba9e..9659000 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3796,7 +3796,7 @@ static struct config_enum ConfigureNamesEnum[] =
{
{"huge_pages", PGC_POSTMASTER, RESOURCES_MEM,
- gettext_noop("Use of huge pages on Linux."),
+ gettext_noop("Use of huge pages on Linux/Windows."),
NULL
},
&huge_pages,