mdbx-windows: backport - workaround for Windows10 bugs.

This resolves https://github.com/leo-yuriev/libmdbx/issues/47

Change-Id: I6e0d6dfbfec15b68200438b68a2996c357d46b77
This commit is contained in:
Leonid Yuriev 2018-10-20 17:17:31 +03:00
parent 5acf2b126f
commit 08130df595
3 changed files with 80 additions and 27 deletions

View File

@ -196,12 +196,19 @@ static int suspend_and_append(mdbx_handle_array_t **array,
(*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)
return GetLastError();
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);
return GetLastError();
return err;
}
(*array)->handles[(*array)->count++] = hThread;
@ -285,9 +292,15 @@ int mdbx_suspend_threads_before_remap(MDBX_env *env,
int mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) {
int rc = MDBX_SUCCESS;
for (unsigned i = 0; i < array->count; ++i) {
if (ResumeThread(array->handles[i]) == -1)
rc = GetLastError();
CloseHandle(array->handles[i]);
const HANDLE hThread = array->handles[i];
if (ResumeThread(hThread) == -1) {
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;
}

View File

@ -2032,18 +2032,20 @@ bailout:
VALGRIND_CREATE_BLOCK(env->me_map, env->me_mapsize, "mdbx");
}
#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 {
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 (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 {
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) {
env->me_flags |= MDBX_FATAL_ERROR;
if (env->me_txn)
@ -2892,6 +2894,16 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
rc = mdbx_rdt_lock(env);
if (unlikely(MDBX_IS_ERROR(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;
if (unlikely(env->me_live_reader != pid)) {
@ -2990,6 +3002,16 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN));
if (unlikely(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_meta *meta = mdbx_meta_head(env);
@ -3049,8 +3071,11 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
goto bailout;
}
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;
}
}
txn->mt_owner = mdbx_thread_self();
return MDBX_SUCCESS;
@ -3098,6 +3123,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (unlikely(!env || !ret))
return MDBX_EINVAL;
*ret = NULL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDBX_EBADSIGN;
@ -3107,8 +3133,12 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (unlikely(env->me_flags & MDBX_FATAL_ERROR))
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))
return MDBX_EPERM;
#endif /* Windows */
flags &= MDBX_TXN_BEGIN_FLAGS;
flags |= env->me_flags & MDBX_WRITEMAP;
@ -3119,16 +3149,21 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (parent) {
if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EINVAL;
return MDBX_EBADSIGN;
if (unlikely(parent->mt_owner != mdbx_thread_self()))
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 */
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;
}
/* Child txns save MDBX_pgstate and use own copy of cursors */
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
size += tsize = sizeof(MDBX_ntxn);
@ -3204,10 +3239,12 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
rc = mdbx_txn_renew0(txn, flags);
}
if (unlikely(rc)) {
if (unlikely(rc != MDBX_SUCCESS)) {
if (txn != env->me_txn0)
free(txn);
} else {
mdbx_assert(env,
(txn->mt_flags & ~(MDBX_TXN_RDONLY | MDBX_TXN_WRITEMAP)) == 0);
txn->mt_signature = MDBX_MT_SIGNATURE;
*ret = txn;
mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
@ -4400,8 +4437,11 @@ int mdbx_txn_commit(MDBX_txn *txn) {
rc = mdbx_sync_locked(
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;
}
env->me_lck->mti_readers_refresh_flag = false;
end_mode = MDBX_END_COMMITTED | MDBX_END_UPDATE | MDBX_END_EOTDONE;

View File

@ -973,11 +973,11 @@ int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size, size_t limit) {
&ReservedSize, MEM_RESERVE, PAGE_NOACCESS);
if (!NT_SUCCESS(status)) {
ReservedAddress = NULL;
if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 ||
limit == map->length)
if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018)
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;
}
@ -1034,8 +1034,8 @@ retry_mapview:;
if (!NT_SUCCESS(status)) {
if (status == /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 &&
map->address && limit != map->length) {
/* try remap at another base address, but only if the limit is changing */
map->address) {
/* try remap at another base address */
map->address = NULL;
goto retry_mapview;
}