diff -Nacr a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml *** a/doc/src/sgml/config.sgml 2016-09-20 05:17:08.000000000 +0900 --- b/doc/src/sgml/config.sgml 2016-09-26 11:38:01.000000000 +0900 *************** *** 1336,1352 **** ! At present, this feature is supported only on Linux. 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, see . 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 --- 1336,1358 ---- ! 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 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 -Nacr a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c *** a/src/backend/port/win32_shmem.c 2016-09-20 05:17:08.000000000 +0900 --- b/src/backend/port/win32_shmem.c 2016-09-26 11:07:59.000000000 +0900 *************** *** 21,26 **** --- 21,27 ---- void *UsedShmemSegAddr = NULL; static Size UsedShmemSegSize = 0; + static bool EnableLockPagesPrivilege(int elevel); static void pgwin32_SharedMemoryDelete(int status, Datum shmId); /* *************** *** 103,108 **** --- 104,164 ---- 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,137 **** 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"))); /* Room for a header? */ Assert(size > MAXALIGN(sizeof(PGShmemHeader))); --- 183,190 ---- int i; DWORD size_high; DWORD size_low; ! SIZE_T largePageSize = 0; ! DWORD flProtect; /* Room for a header? */ Assert(size > MAXALIGN(sizeof(PGShmemHeader))); *************** *** 140,145 **** --- 193,235 ---- 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"))); + huge_pages = HUGE_PAGES_OFF; + } + } + + if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY) + { + /* Enable Lock pages in memory user right. */ + if (!EnableLockPagesPrivilege(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1)) + { + ereport(DEBUG1, + (errmsg("disabling huge pages"))); + huge_pages = HUGE_PAGES_OFF; + } + } + + if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY) + { + flProtect = PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES; + + /* Round size up as appropriate. */ + if (size % largePageSize != 0) + size += largePageSize - (size % largePageSize); + } + else + flProtect = PAGE_READWRITE; + #ifdef _WIN64 size_high = size >> 32; #else *************** *** 163,169 **** hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */ NULL, /* Default security attrs */ ! PAGE_READWRITE, /* Memory is Read/Write */ size_high, /* Size Upper 32 Bits */ size_low, /* Size Lower 32 bits */ szShareMem); --- 253,259 ---- hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */ NULL, /* Default security attrs */ ! flProtect, size_high, /* Size Upper 32 Bits */ size_low, /* Size Lower 32 bits */ szShareMem); diff -Nacr a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c *** a/src/backend/utils/misc/guc.c 2016-09-20 05:17:08.000000000 +0900 --- b/src/backend/utils/misc/guc.c 2016-09-26 11:10:56.000000000 +0900 *************** *** 3792,3798 **** { {"huge_pages", PGC_POSTMASTER, RESOURCES_MEM, ! gettext_noop("Use of huge pages on Linux."), NULL }, &huge_pages, --- 3792,3798 ---- { {"huge_pages", PGC_POSTMASTER, RESOURCES_MEM, ! gettext_noop("Use of huge pages on Linux/Windows."), NULL }, &huge_pages,