mdbx-windows: workaround for Windows10 bugs.

This resolves https://github.com/leo-yuriev/libmdbx/issues/47
This commit is contained in:
Leonid Yuriev 2018-10-20 17:17:31 +03:00
parent c2f850b566
commit 718f997502
3 changed files with 78 additions and 27 deletions

View File

@ -226,12 +226,19 @@ static int suspend_and_append(mdbx_handle_array_t **array,
(*array)->limit = limit * 2; (*array)->limit = limit * 2;
} }
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ThreadId); HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
FALSE, ThreadId);
if (hThread == NULL) if (hThread == NULL)
return GetLastError(); return GetLastError();
if (SuspendThread(hThread) == -1) { if (SuspendThread(hThread) == -1) {
int err = GetLastError();
DWORD ExitCode;
if (err == /* workaround for Win10 UCRT bug */ ERROR_ACCESS_DENIED ||
!GetExitCodeThread(hThread, &ExitCode) || ExitCode != STILL_ACTIVE)
err = MDBX_SUCCESS;
CloseHandle(hThread); CloseHandle(hThread);
return GetLastError(); return err;
} }
(*array)->handles[(*array)->count++] = hThread; (*array)->handles[(*array)->count++] = hThread;
@ -316,9 +323,15 @@ int mdbx_suspend_threads_before_remap(MDBX_env *env,
int mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) { int mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) {
int rc = MDBX_SUCCESS; int rc = MDBX_SUCCESS;
for (unsigned i = 0; i < array->count; ++i) { for (unsigned i = 0; i < array->count; ++i) {
if (ResumeThread(array->handles[i]) == -1) const HANDLE hThread = array->handles[i];
rc = GetLastError(); if (ResumeThread(hThread) == -1) {
CloseHandle(array->handles[i]); const int err = GetLastError();
DWORD ExitCode;
if (err != /* workaround for Win10 UCRT bug */ ERROR_ACCESS_DENIED &&
GetExitCodeThread(hThread, &ExitCode) && ExitCode == STILL_ACTIVE)
rc = err;
}
CloseHandle(hThread);
} }
return rc; return rc;
} }

View File

@ -2295,18 +2295,20 @@ bailout:
VALGRIND_CREATE_BLOCK(env->me_map, env->me_mapsize, "mdbx"); VALGRIND_CREATE_BLOCK(env->me_map, env->me_mapsize, "mdbx");
} }
#endif #endif
} else if (rc != MDBX_RESULT_TRUE) {
mdbx_error("failed resize datafile/mapping: "
"present %" PRIuPTR " -> %" PRIuPTR ", "
"limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d",
env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper, limit_bytes,
rc);
} else { } else {
mdbx_notice("unable resize datafile/mapping: " if (rc != MDBX_RESULT_TRUE) {
"present %" PRIuPTR " -> %" PRIuPTR ", " mdbx_error("failed resize datafile/mapping: "
"limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d", "present %" PRIuPTR " -> %" PRIuPTR ", "
env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper, limit_bytes, "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d",
rc); env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper,
limit_bytes, rc);
} else {
mdbx_notice("unable resize datafile/mapping: "
"present %" PRIuPTR " -> %" PRIuPTR ", "
"limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d",
env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper,
limit_bytes, rc);
}
if (!env->me_dxb_mmap.address) { if (!env->me_dxb_mmap.address) {
env->me_flags |= MDBX_FATAL_ERROR; env->me_flags |= MDBX_FATAL_ERROR;
if (env->me_txn) if (env->me_txn)
@ -3161,6 +3163,16 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
rc = mdbx_rdt_lock(env); rc = mdbx_rdt_lock(env);
if (unlikely(MDBX_IS_ERROR(rc))) if (unlikely(MDBX_IS_ERROR(rc)))
return rc; return rc;
if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) {
mdbx_rdt_unlock(env);
return MDBX_PANIC;
}
#if defined(_WIN32) || defined(_WIN64)
if (unlikely(!env->me_map)) {
mdbx_rdt_unlock(env);
return MDBX_EPERM;
}
#endif /* Windows */
rc = MDBX_SUCCESS; rc = MDBX_SUCCESS;
if (unlikely(env->me_live_reader != env->me_pid)) { if (unlikely(env->me_live_reader != env->me_pid)) {
@ -3259,6 +3271,16 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN)); rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN));
if (unlikely(rc)) if (unlikely(rc))
return rc; return rc;
if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) {
mdbx_txn_unlock(env);
return MDBX_PANIC;
}
#if defined(_WIN32) || defined(_WIN64)
if (unlikely(!env->me_map)) {
mdbx_txn_unlock(env);
return MDBX_EPERM;
}
#endif /* Windows */
mdbx_jitter4testing(false); mdbx_jitter4testing(false);
MDBX_meta *meta = mdbx_meta_head(env); MDBX_meta *meta = mdbx_meta_head(env);
@ -3318,8 +3340,11 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
goto bailout; goto bailout;
} }
rc = mdbx_mapresize(env, txn->mt_end_pgno, upper_pgno); rc = mdbx_mapresize(env, txn->mt_end_pgno, upper_pgno);
if (rc != MDBX_SUCCESS) if (rc != MDBX_SUCCESS) {
if (rc == MDBX_RESULT_TRUE)
rc = MDBX_MAP_RESIZED;
goto bailout; goto bailout;
}
} }
txn->mt_owner = mdbx_thread_self(); txn->mt_owner = mdbx_thread_self();
return MDBX_SUCCESS; return MDBX_SUCCESS;
@ -3367,6 +3392,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (unlikely(!env || !ret)) if (unlikely(!env || !ret))
return MDBX_EINVAL; return MDBX_EINVAL;
*ret = NULL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE)) if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDBX_EBADSIGN; return MDBX_EBADSIGN;
@ -3376,8 +3402,12 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) if (unlikely(env->me_flags & MDBX_FATAL_ERROR))
return MDBX_PANIC; return MDBX_PANIC;
#if !defined(_WIN32) && !defined(_WIN64)
/* Don't check env->me_map until lock to avoid race with re-mapping for
* shrinking */
if (unlikely(!env->me_map)) if (unlikely(!env->me_map))
return MDBX_EPERM; return MDBX_EPERM;
#endif /* Windows */
flags &= MDBX_TXN_BEGIN_FLAGS; flags &= MDBX_TXN_BEGIN_FLAGS;
flags |= env->me_flags & MDBX_WRITEMAP; flags |= env->me_flags & MDBX_WRITEMAP;
@ -3388,16 +3418,21 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (parent) { if (parent) {
if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE)) if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EINVAL; return MDBX_EBADSIGN;
if (unlikely(parent->mt_owner != mdbx_thread_self())) if (unlikely(parent->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH; return MDBX_THREAD_MISMATCH;
#if defined(_WIN32) || defined(_WIN64)
if (unlikely(!env->me_map))
return MDBX_EPERM;
#endif /* Windows */
/* Nested transactions: Max 1 child, write txns only, no writemap */ /* Nested transactions: Max 1 child, write txns only, no writemap */
flags |= parent->mt_flags; flags |= parent->mt_flags;
if (unlikely(flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED))) { if (unlikely(flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED)))
return (parent->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EINVAL : MDBX_BAD_TXN; return (parent->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EINVAL : MDBX_BAD_TXN;
}
/* Child txns save MDBX_pgstate and use own copy of cursors */ /* Child txns save MDBX_pgstate and use own copy of cursors */
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1); size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
size += tsize = sizeof(MDBX_ntxn); size += tsize = sizeof(MDBX_ntxn);
@ -3475,10 +3510,11 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
rc = mdbx_txn_renew0(txn, flags); rc = mdbx_txn_renew0(txn, flags);
} }
if (unlikely(rc)) { if (unlikely(rc != MDBX_SUCCESS)) {
if (txn != env->me_txn0) if (txn != env->me_txn0)
mdbx_free(txn); mdbx_free(txn);
} else { } else {
mdbx_assert(env, (txn->mt_flags & ~MDBX_RDONLY) == 0);
txn->mt_signature = MDBX_MT_SIGNATURE; txn->mt_signature = MDBX_MT_SIGNATURE;
*ret = txn; *ret = txn;
mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
@ -4859,8 +4895,10 @@ int mdbx_txn_commit(MDBX_txn *txn) {
rc = mdbx_sync_locked( rc = mdbx_sync_locked(
env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, &meta); env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, &meta);
} }
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS)) {
env->me_flags |= MDBX_FATAL_ERROR;
goto fail; goto fail;
}
if (likely(env->me_lck)) if (likely(env->me_lck))
env->me_lck->mti_readers_refresh_flag = false; env->me_lck->mti_readers_refresh_flag = false;

View File

@ -1071,11 +1071,11 @@ int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size, size_t limit) {
&ReservedSize, MEM_RESERVE, PAGE_NOACCESS); &ReservedSize, MEM_RESERVE, PAGE_NOACCESS);
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
ReservedAddress = NULL; ReservedAddress = NULL;
if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 || if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018)
limit == map->length)
goto bailout_ntstatus /* no way to recovery */; goto bailout_ntstatus /* no way to recovery */;
/* assume we can change base address if mapping size changed */ /* assume we can change base address if mapping size changed or prev address
* couldn't be used */
map->address = NULL; map->address = NULL;
} }
@ -1132,8 +1132,8 @@ retry_mapview:;
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
if (status == /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 && if (status == /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 &&
map->address && limit != map->length) { map->address) {
/* try remap at another base address, but only if the limit is changing */ /* try remap at another base address */
map->address = NULL; map->address = NULL;
goto retry_mapview; goto retry_mapview;
} }