From 5cfec7a83205b2ef9a7f9409c742ba047f8bc7a0 Mon Sep 17 00:00:00 2001 From: Leo Yuriev Date: Wed, 31 Jan 2018 15:15:54 +0300 Subject: [PATCH] mdbx: workaround for Windows LockFileEx/WriteFile bug. This resolves https://github.com/leo-yuriev/libmdbx/issues/25 --- src/bits.h | 2 ++ src/lck-windows.c | 12 +++++++++++- src/mdbx.c | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/bits.h b/src/bits.h index 293de7f8..1d39d060 100644 --- a/src/bits.h +++ b/src/bits.h @@ -743,6 +743,8 @@ struct MDBX_env { #if defined(_WIN32) || defined(_WIN64) SRWLOCK me_remap_guard; + /* Workaround for LockFileEx and WriteFile multithread bug */ + CRITICAL_SECTION me_windowsbug_lock; #else mdbx_fastmutex_t me_remap_guard; #endif diff --git a/src/lck-windows.c b/src/lck-windows.c index c7ce8a17..02dc9b46 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -127,16 +127,26 @@ static __inline BOOL funlock(mdbx_filehandle_t fd, uint64_t offset, #define LCK_WHOLE 0, LCK_MAXLEN int mdbx_txn_lock(MDBX_env *env, bool dontwait) { + if (dontwait) { + if (!TryEnterCriticalSection(&env->me_windowsbug_lock)) + return MDBX_BUSY; + } else { + EnterCriticalSection(&env->me_windowsbug_lock); + } + if (flock(env->me_fd, dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT) : (LCK_EXCLUSIVE | LCK_WAITFOR), LCK_BODY)) return MDBX_SUCCESS; int rc = GetLastError(); + LeaveCriticalSection(&env->me_windowsbug_lock); return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY; } void mdbx_txn_unlock(MDBX_env *env) { - if (!funlock(env->me_fd, LCK_BODY)) + int rc = funlock(env->me_fd, LCK_BODY); + LeaveCriticalSection(&env->me_windowsbug_lock); + if (!rc) mdbx_panic("%s failed: errcode %u", mdbx_func_, GetLastError()); } diff --git a/src/mdbx.c b/src/mdbx.c index 60569ca8..f174bc2c 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -4450,6 +4450,7 @@ int __cold mdbx_env_create(MDBX_env **penv) { #if defined(_WIN32) || defined(_WIN64) InitializeSRWLock(&env->me_remap_guard); + InitializeCriticalSection(&env->me_windowsbug_lock); #else rc = mdbx_fastmutex_init(&env->me_remap_guard); if (unlikely(rc != MDBX_SUCCESS)) { @@ -5487,6 +5488,14 @@ int __cold mdbx_env_close_ex(MDBX_env *env, int dont_sync) { mdbx_env_close0(env); mdbx_ensure(env, mdbx_fastmutex_destroy(&env->me_dbi_lock) == MDBX_SUCCESS); +#if defined(_WIN32) || defined(_WIN64) + /* me_remap_guard don't have destructor (Slim Reader/Writer Lock) */ + DeleteCriticalSection(&env->me_windowsbug_lock); +#else + mdbx_ensure(env, + mdbx_fastmutex_destroy(&env->me_remap_guard) == MDBX_SUCCESS); +#endif /* Windows */ + env->me_signature = 0; free(env);