summaryrefslogtreecommitdiff
path: root/plugins/Dbx_mdbx
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2018-01-23 19:05:41 +0300
committerGeorge Hazan <ghazan@miranda.im>2018-01-23 19:05:47 +0300
commit4a54d1481e37dbac6c055e44abc32e8f72b04a15 (patch)
treee81c6ae5e2feefeb7528d7c3ee436f3c8d41d934 /plugins/Dbx_mdbx
parent8b9fe16aec92ab9854d17a64543ece441069ecb6 (diff)
merge with libmdbx
Diffstat (limited to 'plugins/Dbx_mdbx')
-rw-r--r--plugins/Dbx_mdbx/src/libmdbx/src/mdbx.c84
-rw-r--r--plugins/Dbx_mdbx/src/libmdbx/src/osal.c62
2 files changed, 109 insertions, 37 deletions
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(