From 4a54d1481e37dbac6c055e44abc32e8f72b04a15 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 23 Jan 2018 19:05:41 +0300 Subject: merge with libmdbx --- plugins/Dbx_mdbx/src/libmdbx/src/mdbx.c | 84 +++++++++++++++++++++------------ plugins/Dbx_mdbx/src/libmdbx/src/osal.c | 62 +++++++++++++++++++++--- 2 files changed, 109 insertions(+), 37 deletions(-) (limited to 'plugins/Dbx_mdbx') diff --git a/plugins/Dbx_mdbx/src/libmdbx/src/mdbx.c b/plugins/Dbx_mdbx/src/libmdbx/src/mdbx.c index 2eafad6155..fd8c9a9bc7 100644 --- a/plugins/Dbx_mdbx/src/libmdbx/src/mdbx.c +++ b/plugins/Dbx_mdbx/src/libmdbx/src/mdbx.c @@ -2775,12 +2775,16 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1); size += tsize = sizeof(MDBX_ntxn); } else if (flags & MDBX_RDONLY) { + if (env->me_txn0 && unlikely(env->me_txn0->mt_owner == mdbx_thread_self())) + return MDBX_BUSY; size = env->me_maxdbs * (sizeof(MDBX_db) + 1); size += tsize = sizeof(MDBX_txn); } else { /* Reuse preallocated write txn. However, do not touch it until * mdbx_txn_renew0() succeeds, since it currently may be active. */ txn = env->me_txn0; + if (unlikely(txn->mt_owner == mdbx_thread_self())) + return MDBX_BUSY; goto renew; } if (unlikely((txn = calloc(1, size)) == NULL)) { @@ -3954,30 +3958,6 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) { continue; } - /* LY: check mapsize limits */ - const uint64_t mapsize_min = - page.mp_meta.mm_geo.lower * (uint64_t)page.mp_meta.mm_psize; - const uint64_t mapsize_max = - page.mp_meta.mm_geo.upper * (uint64_t)page.mp_meta.mm_psize; - STATIC_ASSERT(MAX_MAPSIZE < SSIZE_MAX - MAX_PAGESIZE); - STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE); - if (mapsize_min < MIN_MAPSIZE || mapsize_max > MAX_MAPSIZE) { - mdbx_notice("meta[%u] has invalid min-mapsize (%" PRIu64 "), skip it", - meta_number, mapsize_min); - rc = MDBX_VERSION_MISMATCH; - continue; - } - - STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE); - if (mapsize_max > MAX_MAPSIZE || - MAX_PAGENO < mdbx_roundup2((size_t)mapsize_max, env->me_os_psize) / - (uint64_t)page.mp_meta.mm_psize) { - mdbx_notice("meta[%u] has too large max-mapsize (%" PRIu64 "), skip it", - meta_number, mapsize_max); - rc = MDBX_TOO_LARGE; - continue; - } - /* LY: check end_pgno */ if (page.mp_meta.mm_geo.now < page.mp_meta.mm_geo.lower || page.mp_meta.mm_geo.now > page.mp_meta.mm_geo.upper) { @@ -3996,6 +3976,43 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) { continue; } + /* LY: check mapsize limits */ + const uint64_t mapsize_min = + page.mp_meta.mm_geo.lower * (uint64_t)page.mp_meta.mm_psize; + STATIC_ASSERT(MAX_MAPSIZE < SSIZE_MAX - MAX_PAGESIZE); + STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE); + if (mapsize_min < MIN_MAPSIZE || mapsize_min > MAX_MAPSIZE) { + mdbx_notice("meta[%u] has invalid min-mapsize (%" PRIu64 "), skip it", + meta_number, mapsize_min); + rc = MDBX_VERSION_MISMATCH; + continue; + } + + const uint64_t mapsize_max = + page.mp_meta.mm_geo.upper * (uint64_t)page.mp_meta.mm_psize; + STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE); + if (mapsize_max > MAX_MAPSIZE || + MAX_PAGENO < mdbx_roundup2((size_t)mapsize_max, env->me_os_psize) / + (uint64_t)page.mp_meta.mm_psize) { + const uint64_t used_bytes = + page.mp_meta.mm_geo.next * (uint64_t)page.mp_meta.mm_psize; + if (page.mp_meta.mm_geo.next - 1 > MAX_PAGENO || + used_bytes > MAX_MAPSIZE) { + mdbx_notice("meta[%u] has too large max-mapsize (%" PRIu64 "), skip it", + meta_number, mapsize_max); + rc = MDBX_TOO_LARGE; + continue; + } + + /* allow to open large DB from a 32-bit environment */ + mdbx_notice("meta[%u] has too large max-mapsize (%" PRIu64 "), " + "but size of used space still acceptable (%" PRIu64 ")", + meta_number, mapsize_max, used_bytes); + page.mp_meta.mm_geo.upper = (pgno_t)(MAX_MAPSIZE / page.mp_meta.mm_psize); + if (page.mp_meta.mm_geo.now > page.mp_meta.mm_geo.upper) + page.mp_meta.mm_geo.now = page.mp_meta.mm_geo.upper; + } + if (page.mp_meta.mm_geo.next > page.mp_meta.mm_geo.now) { mdbx_notice("meta[%u] next-pageno (%" PRIaPGNO ") is beyond end-pgno (%" PRIaPGNO "), skip it", @@ -4649,7 +4666,7 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, goto bailout; } size_upper -= env->me_os_psize; - if ((size_t)size_upper > (size_t)size_lower) + if ((size_t)size_upper < (size_t)size_lower) size_lower = size_upper; } mdbx_assert(env, (size_upper - size_lower) % env->me_os_psize == 0); @@ -4834,6 +4851,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) { meta.mm_txnid_a, mdbx_durable_str(&meta)); mdbx_setup_pagesize(env, meta.mm_psize); + const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next); if ((env->me_flags & MDBX_RDONLY) /* readonly */ || lck_rc != MDBX_RESULT_TRUE /* not exclusive */) { /* use present params from db */ @@ -4849,9 +4867,6 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) { } } else if (env->me_dbgeo.now) { /* silently growth to last used page */ - const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next); - if (env->me_dbgeo.lower < used_bytes) - env->me_dbgeo.lower = used_bytes; if (env->me_dbgeo.now < used_bytes) env->me_dbgeo.now = used_bytes; if (env->me_dbgeo.upper < used_bytes) @@ -4916,7 +4931,6 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) { const size_t expected_bytes = mdbx_roundup2(pgno2bytes(env, meta.mm_geo.now), env->me_os_psize); - const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next); mdbx_ensure(env, expected_bytes >= used_bytes); if (filesize_before_mmap != expected_bytes) { if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) { @@ -8082,7 +8096,10 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) { return MDBX_EBADSIGN; if (unlikely(txn->mt_owner != mdbx_thread_self())) - return MDBX_THREAD_MISMATCH; + return txn->mt_owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN; + + if (unlikely(txn->mt_flags & (MDBX_TXN_FINISHED | MDBX_TXN_ERROR))) + return MDBX_BAD_TXN; if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE && mc->mc_signature != MDBX_MC_READY4CLOSE)) @@ -8180,7 +8197,12 @@ void mdbx_cursor_close(MDBX_cursor *mc) { MDBX_txn *mdbx_cursor_txn(MDBX_cursor *mc) { if (unlikely(!mc || mc->mc_signature != MDBX_MC_SIGNATURE)) return NULL; - return mc->mc_txn; + MDBX_txn *txn = mc->mc_txn; + if (unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE)) + return NULL; + if (unlikely(txn->mt_flags & MDBX_TXN_FINISHED)) + return NULL; + return txn; } MDBX_dbi mdbx_cursor_dbi(MDBX_cursor *mc) { diff --git a/plugins/Dbx_mdbx/src/libmdbx/src/osal.c b/plugins/Dbx_mdbx/src/libmdbx/src/osal.c index fa6fe279da..af0b88ce88 100644 --- a/plugins/Dbx_mdbx/src/libmdbx/src/osal.c +++ b/plugins/Dbx_mdbx/src/libmdbx/src/osal.c @@ -99,12 +99,12 @@ extern NTSTATUS NTAPI NtUnmapViewOfSection(IN HANDLE ProcessHandle, extern NTSTATUS NTAPI NtClose(HANDLE Handle); extern NTSTATUS NTAPI NtAllocateVirtualMemory( - IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG ZeroBits, - IN OUT PULONG RegionSize, IN ULONG AllocationType, IN ULONG Protect); + IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG_PTR ZeroBits, + IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect); extern NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN PVOID *BaseAddress, - IN OUT PULONG RegionSize, + IN OUT PSIZE_T RegionSize, IN ULONG FreeType); #ifndef FILE_PROVIDER_CURRENT_VERSION @@ -870,7 +870,7 @@ int mdbx_mmap(int flags, mdbx_mmap_t *map, size_t size, size_t limit) { if (rc == MDBX_SUCCESS) map->filesize = size; /* ignore error, because Windows unable shrink file - * that already mapped (by another process) */; + * that already mapped (by another process) */ } LARGE_INTEGER SectionSize; @@ -931,6 +931,12 @@ int mdbx_munmap(mdbx_mmap_t *map) { NTSTATUS rc = NtUnmapViewOfSection(GetCurrentProcess(), map->address); if (!NT_SUCCESS(rc)) ntstatus2errcode(rc); + + if (map->filesize != map->current && + mdbx_filesize(map->fd, &map->filesize) == MDBX_SUCCESS && + map->filesize != map->current) + (void)mdbx_ftruncate(map->fd, map->current); + map->length = 0; map->current = 0; map->address = nullptr; @@ -961,8 +967,23 @@ int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size, size_t limit) { return ntstatus2errcode(status); } + if (limit > map->length) { + /* check ability of address space for growth before umnap */ + PVOID BaseAddress = (PBYTE)map->address + map->length; + SIZE_T RegionSize = limit - map->length; + status = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0, + &RegionSize, MEM_RESERVE, PAGE_NOACCESS); + if (!NT_SUCCESS(status)) + return ntstatus2errcode(status); + + status = NtFreeVirtualMemory(GetCurrentProcess(), &BaseAddress, &RegionSize, + MEM_RELEASE); + if (!NT_SUCCESS(status)) + return ntstatus2errcode(status); + } + /* Windows unable: - * - shrinking a mapped file; + * - shrink a mapped file; * - change size of mapped view; * - extend read-only mapping; * Therefore we should unmap/map entire section. */ @@ -971,6 +992,8 @@ int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size, size_t limit) { return ntstatus2errcode(status); status = NtClose(map->section); map->section = NULL; + PVOID ReservedAddress = NULL; + SIZE_T ReservedSize = limit; if (!NT_SUCCESS(status)) { bailout_ntstatus: @@ -978,9 +1001,27 @@ int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size, size_t limit) { bailout: map->address = NULL; map->current = map->length = 0; + if (ReservedAddress) + (void)NtFreeVirtualMemory(GetCurrentProcess(), &ReservedAddress, + &ReservedSize, MEM_RELEASE); return err; } + /* resizing of the file may take a while, + * therefore we reserve address space to avoid occupy it by other threads */ + ReservedAddress = map->address; + status = NtAllocateVirtualMemory(GetCurrentProcess(), &ReservedAddress, 0, + &ReservedSize, MEM_RESERVE, PAGE_NOACCESS); + if (!NT_SUCCESS(status)) { + ReservedAddress = NULL; + if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 || + limit == map->length) + goto bailout_ntstatus /* no way to recovery */; + + /* assume we can change base address if mapping size changed */ + map->address = NULL; + } + retry_file_and_section: err = mdbx_filesize(map->fd, &map->filesize); if (err != MDBX_SUCCESS) @@ -991,7 +1032,7 @@ retry_file_and_section: if (err == MDBX_SUCCESS) map->filesize = size; /* ignore error, because Windows unable shrink file - * that already mapped (by another process) */; + * that already mapped (by another process) */ } SectionSize.QuadPart = size; @@ -1010,6 +1051,15 @@ retry_file_and_section: if (!NT_SUCCESS(status)) goto bailout_ntstatus; + if (ReservedAddress) { + /* release reserved address space */ + status = NtFreeVirtualMemory(GetCurrentProcess(), &ReservedAddress, + &ReservedSize, MEM_RELEASE); + ReservedAddress = NULL; + if (!NT_SUCCESS(status)) + goto bailout_ntstatus; + } + retry_mapview:; SIZE_T ViewSize = (flags & MDBX_RDONLY) ? size : limit; status = NtMapViewOfSection( -- cgit v1.2.3