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);