From a2bdbc97dc2f1d9e7a512d45bef68846bb22a722 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Wed, 20 May 2020 13:31:04 +0300 Subject: [PATCH] mdbx: truncate clk-file when DB closed in sync-state. Change-Id: I2e2438606118e3aa3fa9d60811fea99994403d32 --- src/lck-posix.c | 4 +- src/lck-windows.c | 101 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/lck-posix.c b/src/lck-posix.c index 6b6127bd..9038739f 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -477,8 +477,10 @@ MDBX_INTERNAL_FUNC int __cold mdbx_lck_destroy(MDBX_env *env, mdbx_assert(env, rc == 0); if (rc == 0) { + const bool synced = env->me_lck_mmap.lck->mti_unsynced_pages == 0; mdbx_munmap(&env->me_lck_mmap); - rc = ftruncate(env->me_lfd, 0) ? errno : 0; + if (synced) + rc = ftruncate(env->me_lfd, 0) ? errno : 0; } mdbx_jitter4testing(false); diff --git a/src/lck-windows.c b/src/lck-windows.c index cb9fc1d7..8ec4659a 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -344,13 +344,6 @@ mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) { * i.e. free/shared/exclusive x free/shared/exclusive == 9. * Only 6 states of FSM are used, which 2 of ones are transitive. * - * The mdbx_lck_seize() moves the locking-FSM from the initial free/unlocked - * state to the "exclusive write" (and returns MDBX_RESULT_TRUE) if possible, - * or to the "used" (and returns MDBX_RESULT_FALSE). - * - * The mdbx_lck_downgrade() moves the locking-FSM from "exclusive write" - * state to the "used" (i.e. shared) state. - * * States: * ?-? = free, i.e. unlocked * S-? = used, i.e. shared lock @@ -361,6 +354,16 @@ mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) { * S-E = locked (transitive state) * E-S * E-E = exclusive-write, i.e. exclusive due (re)initialization + * + * The mdbx_lck_seize() moves the locking-FSM from the initial free/unlocked + * state to the "exclusive write" (and returns MDBX_RESULT_TRUE) if possible, + * or to the "used" (and returns MDBX_RESULT_FALSE). + * + * The mdbx_lck_downgrade() moves the locking-FSM from "exclusive write" + * state to the "used" (i.e. shared) state. + * + * The mdbx_lck_upgrade() moves the locking-FSM from "used" (i.e. shared) + * state to the "exclusive write" state. */ static void lck_unlock(MDBX_env *env) { @@ -406,30 +409,6 @@ static void lck_unlock(MDBX_env *env) { } } -MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env, - MDBX_env *inprocess_neighbor, - int global_uniqueness_flag) { - (void)env; - (void)inprocess_neighbor; - (void)global_uniqueness_flag; - return MDBX_SUCCESS; -} - -MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env, - MDBX_env *inprocess_neighbor) { - (void)inprocess_neighbor; - - /* LY: should unmap before releasing the locks to avoid race condition and - * STATUS_USER_MAPPED_FILE/ERROR_USER_MAPPED_FILE */ - if (env->me_map) - mdbx_munmap(&env->me_dxb_mmap); - if (env->me_lck) - mdbx_munmap(&env->me_lck_mmap); - - lck_unlock(env); - return MDBX_SUCCESS; -} - /* Seize state as 'exclusive-write' (E-E and returns MDBX_RESULT_TRUE) * or as 'used' (S-? and returns MDBX_RESULT_FALSE). * Oherwise returns an error. */ @@ -553,6 +532,66 @@ MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) { return MDBX_SUCCESS /* 5) now at S-? (used), done */; } +MDBX_INTERNAL_FUNC int mdbx_lck_upgrade(MDBX_env *env) { + /* Transite from used state (S-?) to exclusive-write (E-E) */ + assert(env->me_lfd != INVALID_HANDLE_VALUE); + + if (env->me_flags & MDBX_EXCLUSIVE) + return MDBX_SUCCESS /* nope since files were must be opened non-shareable */ + ; + + int rc; + /* 1) now on S-? (used), try S-E (locked) */ + mdbx_jitter4testing(false); + if (!flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_UPPER)) { + rc = GetLastError() /* 2) something went wrong, give up */; + mdbx_verbose("%s, err %u", "S-?(used) >> S-E(locked)", rc); + return rc; + } + + /* 3) now on S-E (locked), transite to ?-E (middle) */ + if (!funlock(env->me_lfd, LCK_LOWER)) + mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> ?-E(middle)", + GetLastError()); + + /* 4) now on ?-E (middle), try E-E (exclusive-write) */ + mdbx_jitter4testing(false); + if (!flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) { + rc = GetLastError() /* 5) something went wrong, give up */; + mdbx_verbose("%s, err %u", "?-E(middle) >> E-E(exclusive-write)", rc); + return rc; + } + + return MDBX_SUCCESS /* 6) now at E-E (exclusive-write), done */; +} + +MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env, + MDBX_env *inprocess_neighbor, + int global_uniqueness_flag) { + (void)env; + (void)inprocess_neighbor; + (void)global_uniqueness_flag; + return MDBX_SUCCESS; +} + +MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env, + MDBX_env *inprocess_neighbor) { + /* LY: should unmap before releasing the locks to avoid race condition and + * STATUS_USER_MAPPED_FILE/ERROR_USER_MAPPED_FILE */ + if (env->me_map) + mdbx_munmap(&env->me_dxb_mmap); + if (env->me_lck) { + const bool synced = env->me_lck_mmap.lck->mti_unsynced_pages == 0; + mdbx_munmap(&env->me_lck_mmap); + if (synced && !inprocess_neighbor && env->me_lfd != INVALID_HANDLE_VALUE && + mdbx_lck_upgrade(env) == MDBX_SUCCESS) + /* this will fail if LCK is used/mmapped by other process(es) */ + mdbx_ftruncate(env->me_lfd, 0); + } + lck_unlock(env); + return MDBX_SUCCESS; +} + /*----------------------------------------------------------------------------*/ /* reader checking (by pid) */