diff --git a/src/lck-posix.c b/src/lck-posix.c index c1f23b38..5b882b0d 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -91,7 +91,9 @@ static __inline int mdbx_lck_shared(int lfd) { return mdbx_lck_op(lfd, F_SETLKW, F_RDLCK, 0, 1); } -int mdbx_lck_downgrade(MDBX_env *env) { return mdbx_lck_shared(env->me_lfd); } +int mdbx_lck_downgrade(MDBX_env *env, bool complete) { + return complete ? mdbx_lck_shared(env->me_lfd) : MDBX_SUCCESS; +} int mdbx_lck_upgrade(MDBX_env *env) { return mdbx_lck_exclusive(env->me_lfd); } diff --git a/src/lck-windows.c b/src/lck-windows.c index 7bbef4d9..66591db9 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -152,7 +152,7 @@ int mdbx_rdt_lock(MDBX_env *env) { if (env->me_lfd == INVALID_HANDLE_VALUE) return MDBX_SUCCESS; /* readonly database in readonly filesystem */ - /* transite from S-? (used) to S-E (locked), e.g. exlcusive lock upper-part */ + /* transite from S-? (used) to S-E (locked), e.g. exclusive lock upper-part */ if (flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER)) return MDBX_SUCCESS; return GetLastError(); @@ -168,18 +168,18 @@ void mdbx_rdt_unlock(MDBX_env *env) { /*----------------------------------------------------------------------------*/ /* global `initial` lock for lockfile initialization, -* exclusive/shared locking first cacheline */ + * exclusive/shared locking first cacheline */ /* FIXME: locking schema/algo descritpion. ?-? = free S-? = used - E-? + E-? = exclusive-read ?-S ?-E = middle S-S S-E = locked E-S - E-E = exclusive + E-E = exclusive-write */ int mdbx_lck_init(MDBX_env *env) { @@ -187,8 +187,9 @@ int mdbx_lck_init(MDBX_env *env) { return MDBX_SUCCESS; } -/* Seize state as exclusive (E-E and returns MDBX_RESULT_TRUE) -* or used (S-? and returns MDBX_RESULT_FALSE), otherwise returns an error */ +/* Seize state as 'exclusive-write' (E-E and returns MDBX_RESULT_TRUE) + * or as 'used' (S-? and returns MDBX_RESULT_FALSE), otherwise returns an error + */ static int internal_seize_lck(HANDLE lfd) { int rc; assert(lfd != INVALID_HANDLE_VALUE); @@ -202,10 +203,10 @@ static int internal_seize_lck(HANDLE lfd) { return rc; } - /* 3) now on ?-E (middle), try E-E (exclusive) */ + /* 3) now on ?-E (middle), try E-E (exclusive-write) */ mdbx_jitter4testing(false); if (flock(lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) - return MDBX_RESULT_TRUE; /* 4) got E-E (exclusive), done */ + return MDBX_RESULT_TRUE /* 4) got E-E (exclusive-write), done */; /* 5) still on ?-E (middle) */ rc = GetLastError(); @@ -279,32 +280,43 @@ int mdbx_lck_seize(MDBX_env *env) { return rc; } -int mdbx_lck_downgrade(MDBX_env *env) { - /* Transite from exclusive state (E-E) to used (S-?) */ +int mdbx_lck_downgrade(MDBX_env *env, bool complete) { + /* Transite from exclusive state (E-?) to used (S-?) */ assert(env->me_fd != INVALID_HANDLE_VALUE); assert(env->me_lfd != INVALID_HANDLE_VALUE); - /* 1) must be at E-E (exclusive), transite to ?_E (middle) */ + /* 1) must be at E-E (exclusive-write) */ + if (!complete) { + /* transite from E-E to E_? (exclusive-read) */ + if (!funlock(env->me_lfd, LCK_UPPER)) + mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, + "E-E(exclusive-write) >> E-?(exclusive-read)", GetLastError()); + return MDBX_SUCCESS /* 2) now at E-? (exclusive-read), done */; + } + + /* 3) now at E-E (exclusive-write), transite to ?_E (middle) */ if (!funlock(env->me_lfd, LCK_LOWER)) mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, - "E-E(exclusive) >> ?-E(middle)", GetLastError()); + "E-E(exclusive-write) >> ?-E(middle)", GetLastError()); - /* 2) now at ?-E (middle), transite to S-E (locked) */ + /* 4) now at ?-E (middle), transite to S-E (locked) */ if (!flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER)) { - int rc = GetLastError() /* 3) something went wrong, give up */; + int rc = GetLastError() /* 5) something went wrong, give up */; + mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, + "?-E(middle) >> S-E(locked)", rc); return rc; } - /* 4) got S-E (locked), continue transition to S-? (used) */ + /* 6) got S-E (locked), continue transition to S-? (used) */ if (!funlock(env->me_lfd, LCK_UPPER)) mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, "S-E(locked) >> S-?(used)", GetLastError()); - return MDBX_SUCCESS /* 5) now at S-? (used), done */; + return MDBX_SUCCESS /* 7) now at S-? (used), done */; } int mdbx_lck_upgrade(MDBX_env *env) { - /* Transite from locked state (S-E) to exclusive (E-E) */ + /* Transite from locked state (S-E) to exclusive-write (E-E) */ assert(env->me_fd != INVALID_HANDLE_VALUE); assert(env->me_lfd != INVALID_HANDLE_VALUE); @@ -313,10 +325,10 @@ int mdbx_lck_upgrade(MDBX_env *env) { mdbx_panic("%s(%s) failed: errcode %u", mdbx_func_, "S-E(locked) >> ?-E(middle)", GetLastError()); - /* 3) now on ?-E (middle), try E-E (exclusive) */ + /* 3) now on ?-E (middle), try E-E (exclusive-write) */ mdbx_jitter4testing(false); if (flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) - return MDBX_RESULT_TRUE; /* 4) got E-E (exclusive), done */ + return MDBX_RESULT_TRUE; /* 4) got E-E (exclusive-write), done */ /* 5) still on ?-E (middle) */ int rc = GetLastError(); @@ -324,7 +336,7 @@ int mdbx_lck_upgrade(MDBX_env *env) { if (rc != ERROR_SHARING_VIOLATION && rc != ERROR_LOCK_VIOLATION) { /* 6) something went wrong, report but continue */ mdbx_error("%s(%s) failed: errcode %u", mdbx_func_, - "?-E(middle) >> E-E(exclusive)", rc); + "?-E(middle) >> E-E(exclusive-write)", rc); } /* 7) still on ?-E (middle), try restore S-E (locked) */ diff --git a/src/mdbx.c b/src/mdbx.c index 445d948e..3173fe6f 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -4906,11 +4906,14 @@ int __cold mdbx_env_open_ex(MDBX_env *env, const char *path, unsigned flags, if (exclusive == NULL || *exclusive < 2) { /* LY: downgrade lock only if exclusive access not requested. * in case exclusive==1, just leave value as is. */ - rc = mdbx_lck_downgrade(env); - mdbx_debug("lck-downgrade: rc %i ", rc); - if (rc != MDBX_SUCCESS) - goto bailout; + rc = mdbx_lck_downgrade(env, true); + mdbx_debug("lck-downgrade-full: rc %i ", rc); + } else { + rc = mdbx_lck_downgrade(env, false); + mdbx_debug("lck-downgrade-partial: rc %i ", rc); } + if (rc != MDBX_SUCCESS) + goto bailout; } else { if (exclusive) { /* LY: just indicate that is not an exclusive access. */ diff --git a/src/osal.h b/src/osal.h index c35ffa3e..c6cad301 100644 --- a/src/osal.h +++ b/src/osal.h @@ -491,7 +491,7 @@ void mdbx_osal_jitter(bool tiny); int mdbx_lck_init(MDBX_env *env); int mdbx_lck_seize(MDBX_env *env); -int mdbx_lck_downgrade(MDBX_env *env); +int mdbx_lck_downgrade(MDBX_env *env, bool complete); int mdbx_lck_upgrade(MDBX_env *env); void mdbx_lck_destroy(MDBX_env *env);