ITS#8324 incremental DB file growth for Windows
authorHoward Chu <hyc@openldap.org>
Mon, 30 Nov 2015 18:46:19 +0000 (18:46 +0000)
committerHoward Chu <hyc@openldap.org>
Mon, 30 Nov 2015 18:46:19 +0000 (18:46 +0000)
libraries/liblmdb/Makefile
libraries/liblmdb/mdb.c

index 098bff5..0d34367 100644 (file)
@@ -24,8 +24,8 @@ W     = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized
 THREADS = -pthread
 OPT = -O2 -g
 CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS)
-LDLIBS =
-SOLIBS =
+LDLIBS = # -lntdll # Windows needs ntdll
+SOLIBS = # -lntdll
 prefix = /usr/local
 mandir = $(prefix)/man
 
index f712115..2e940a1 100644 (file)
 #ifdef _WIN32
 #include <malloc.h>
 #include <windows.h>
+
+/* We use native NT APIs to setup the memory map, so that we can
+ * let the DB file grow incrementally instead of always preallocating
+ * the full size. These APIs are defined in <wdm.h> and <ntifs.h>
+ * but those headers are meant for driver-level development and
+ * conflict with the regular user-level headers, so we explicitly
+ * declare them here. Using these APIs also means we must link to
+ * ntdll.dll, which is not linked by default in user code.
+ */
+NTSTATUS WINAPI
+NtCreateSection(OUT PHANDLE sh, IN ACCESS_MASK acc,
+  IN void * oa OPTIONAL,
+  IN PLARGE_INTEGER ms OPTIONAL,
+  IN ULONG pp, IN ULONG aa, IN HANDLE fh OPTIONAL);
+
+typedef enum _SECTION_INHERIT {
+       ViewShare = 1,
+       ViewUnmap = 2
+} SECTION_INHERIT;
+
+NTSTATUS WINAPI
+NtMapViewOfSection(IN PHANDLE sh, IN HANDLE ph,
+  IN OUT PVOID *addr, IN ULONG_PTR zbits,
+  IN SIZE_T cs, IN OUT PLARGE_INTEGER off OPTIONAL,
+  IN OUT PSIZE_T vs, IN SECTION_INHERIT ih,
+  IN ULONG at, IN ULONG pp);
+
+NTSTATUS WINAPI
+NtClose(HANDLE h);
+
 /** getpid() returns int; MinGW defines pid_t but MinGW64 typedefs it
  *  as int64 which is wrong. MSVC doesn't define it at all, so just
  *  don't use it.
@@ -2293,6 +2323,20 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
                        rc = MDB_MAP_FULL;
                        goto fail;
        }
+#ifdef _WIN32
+       {
+               void *p;
+               p = (MDB_page *)(env->me_map + env->me_psize * pgno);
+               p = VirtualAlloc(p, env->me_psize * num, MEM_COMMIT,
+                       (env->me_flags & MDB_WRITEMAP) ? PAGE_READWRITE:
+                       PAGE_READONLY);
+               if (!p) {
+                       DPUTS("VirtualAlloc failed");
+                       rc = ErrCode();
+                       goto fail;
+               }
+       }
+#endif
 
 search_done:
        if (env->me_flags & MDB_WRITEMAP) {
@@ -3956,42 +4000,26 @@ mdb_env_map(MDB_env *env, void *addr)
        unsigned int flags = env->me_flags;
 #ifdef _WIN32
        int rc;
+       int access = SECTION_MAP_READ;
        HANDLE mh;
-       LONG sizelo, sizehi;
-       size_t msize;
-
-       if (flags & MDB_RDONLY) {
-               /* Don't set explicit map size, use whatever exists */
-               msize = 0;
-               sizelo = 0;
-               sizehi = 0;
-       } else {
-               msize = env->me_mapsize;
-               sizelo = msize & 0xffffffff;
-               sizehi = msize >> 16 >> 16; /* only needed on Win64 */
-
-               /* Windows won't create mappings for zero length files.
-                * and won't map more than the file size.
-                * Just set the maxsize right now.
-                */
-               if (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo
-                       || !SetEndOfFile(env->me_fd)
-                       || SetFilePointer(env->me_fd, 0, NULL, 0) != 0)
-                       return ErrCode();
+       void *map;
+       size_t msize = 0;
+       ULONG pageprot = PAGE_READONLY;
+       if (flags & MDB_WRITEMAP) {
+               access |= SECTION_MAP_WRITE;
+               pageprot = PAGE_READWRITE;
        }
 
-       mh = CreateFileMapping(env->me_fd, NULL, flags & MDB_WRITEMAP ?
-               PAGE_READWRITE : PAGE_READONLY,
-               sizehi, sizelo, NULL);
-       if (!mh)
-               return ErrCode();
-       env->me_map = MapViewOfFileEx(mh, flags & MDB_WRITEMAP ?
-               FILE_MAP_WRITE : FILE_MAP_READ,
-               0, 0, msize, addr);
-       rc = env->me_map ? 0 : ErrCode();
-       CloseHandle(mh);
+       rc = NtCreateSection(&mh, access, NULL, NULL, PAGE_READWRITE, SEC_RESERVE, env->me_fd);
        if (rc)
                return rc;
+       map = addr;
+       msize = env->me_mapsize;
+       rc = NtMapViewOfSection(mh, GetCurrentProcess(), &map, 0, 0, NULL, &msize, ViewUnmap, MEM_RESERVE, pageprot);
+       NtClose(mh);
+       if (rc)
+               return rc;
+       env->me_map = map;
 #else
        int prot = PROT_READ;
        if (flags & MDB_WRITEMAP) {
@@ -4228,6 +4256,17 @@ mdb_env_open2(MDB_env *env)
                        return rc;
                newenv = 0;
        }
+#ifdef _WIN32
+       /* For FIXEDMAP, make sure the file is non-empty before we attempt to map it */
+       if (newenv) {
+               char dummy = 0;
+               rc = WriteFile(env->me_fd, &dummy, 1, NULL, NULL);
+               if (!rc) {
+                       rc = ErrCode();
+                       return rc;
+               }
+       }
+#endif
 
        rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL);
        if (rc)