From 48a56d1d0525b6f4cab7e677dbe419b2c6646edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 4 Dec 2022 18:10:54 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D0=B7=D0=B0=D0=BF=D1=80=D0=B5=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B7=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20`MDBX=5FWRITEMAP`=20=D0=BC=D0=B5=D0=B6=D0=B4=D1=83=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D1=81=D1=81=D0=B0=D0=BC=D0=B8=20?= =?UTF-8?q?=D0=B2=20=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=D0=B0=D1=85=20=D1=81=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D0=BE=D0=B9/?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B2=D0=BE=D0=B9=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D0=B8=D1=81=D1=8C=D1=8E.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ранее упущенный не очевидный момент: При работе БД в режимах не-синхронной/отложенной фиксации на диске, все процессы-писатели должны иметь одинаковый режим MDBX_WRITEMAP. В противном случае, сброс на диск следует выполнять дважды: сначала msync(), затем fdatasync(). При этом msync() не обязан отрабатывать в процессах без MDBX_WRITEMAP, так как файл в память отображен только для чтения. Поэтому, в общем случае, различия по MDBX_WRITEMAP не позволяют выполнить фиксацию данных на диск, после их изменения в другом процессе. В режиме MDBX_UTTERLY_NOSYNC позволять совместную работу с MDBX_WRITEMAP также не следует, поскольку никакой процесс (в том числе последний) не может гарантированно сбросить данные на диск, а следовательно не должен помечать какую-либо транзакцию как steady. В результате, требуется либо запретить совместную работу процессам с разным MDBX_WRITEMAP в режиме отложенной записи, либо отслеживать такое смешивание и блокировать steady-пометки - что контрпродуктивно. --- src/core.c | 73 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/src/core.c b/src/core.c index a01c18cd..30de3226 100644 --- a/src/core.c +++ b/src/core.c @@ -14328,12 +14328,6 @@ __cold int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, } osal_fseek(env->me_lfd, safe_parking_lot_offset); - const MDBX_env_flags_t rigorous_flags = - MDBX_SAFE_NOSYNC | MDBX_DEPRECATED_MAPASYNC; - const MDBX_env_flags_t mode_flags = rigorous_flags | MDBX_NOMETASYNC | - MDBX_LIFORECLAIM | - MDBX_DEPRECATED_COALESCE | MDBX_NORDAHEAD; - eASSERT(env, env->me_dsync_fd == INVALID_HANDLE_VALUE); if (!(flags & (MDBX_RDONLY | MDBX_SAFE_NOSYNC | MDBX_DEPRECATED_MAPASYNC))) { rc = osal_openfile(MDBX_OPEN_DXB_DSYNC, env, env_pathname.dxb, @@ -14345,11 +14339,19 @@ __cold int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, } } + const MDBX_env_flags_t lazy_flags = + MDBX_SAFE_NOSYNC | MDBX_UTTERLY_NOSYNC | MDBX_NOMETASYNC; + const MDBX_env_flags_t mode_flags = lazy_flags | MDBX_LIFORECLAIM | + MDBX_NORDAHEAD | MDBX_RDONLY | + MDBX_WRITEMAP; + MDBX_lockinfo *const lck = env->me_lck_mmap.lck; if (lck && lck_rc != MDBX_RESULT_TRUE && (env->me_flags & MDBX_RDONLY) == 0) { - while (atomic_load32(&lck->mti_envmode, mo_AcquireRelease) == MDBX_RDONLY) { + MDBX_env_flags_t snap_flags; + while ((snap_flags = atomic_load32(&lck->mti_envmode, mo_AcquireRelease)) == + MDBX_RDONLY) { if (atomic_cas32(&lck->mti_envmode, MDBX_RDONLY, - env->me_flags & mode_flags)) { + (snap_flags = (env->me_flags & mode_flags)))) { /* The case: * - let's assume that for some reason the DB file is smaller * than it should be according to the geometry, @@ -14368,15 +14370,44 @@ __cold int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, if (env->me_flags & MDBX_ACCEDE) { /* Pickup current mode-flags (MDBX_LIFORECLAIM, MDBX_NORDAHEAD, etc). */ - const unsigned diff = - (lck->mti_envmode.weak ^ env->me_flags) & mode_flags; - NOTICE("accede mode-flags: 0x%X, 0x%X -> 0x%X", diff, env->me_flags, - env->me_flags ^ diff); + const MDBX_env_flags_t diff = + (snap_flags ^ env->me_flags) & + ((snap_flags & lazy_flags) ? mode_flags + : mode_flags & ~MDBX_WRITEMAP); env->me_flags ^= diff; + NOTICE("accede mode-flags: 0x%X, 0x%X -> 0x%X", diff, + env->me_flags ^ diff, env->me_flags); } - if ((lck->mti_envmode.weak ^ env->me_flags) & rigorous_flags) { - ERROR("%s", "current mode/flags incompatible with requested"); + /* Ранее упущенный не очевидный момент: При работе БД в режимах + * не-синхронной/отложенной фиксации на диске, все процессы-писатели должны + * иметь одинаковый режим MDBX_WRITEMAP. + * + * В противном случае, сброс на диск следует выполнять дважды: сначала + * msync(), затем fdatasync(). При этом msync() не обязан отрабатывать + * в процессах без MDBX_WRITEMAP, так как файл в память отображен только + * для чтения. Поэтому, в общем случае, различия по MDBX_WRITEMAP не + * позволяют выполнить фиксацию данных на диск, после их изменения в другом + * процессе. + * + * В режиме MDBX_UTTERLY_NOSYNC позволять совместную работу с MDBX_WRITEMAP + * также не следует, поскольку никакой процесс (в том числе последний) не + * может гарантированно сбросить данные на диск, а следовательно не должен + * помечать какую-либо транзакцию как steady. + * + * В результате, требуется либо запретить совместную работу процессам с + * разным MDBX_WRITEMAP в режиме отложенной записи, либо отслеживать такое + * смешивание и блокировать steady-пометки - что контрпродуктивно. */ + const MDBX_env_flags_t rigorous_flags = + (snap_flags & lazy_flags) + ? MDBX_SAFE_NOSYNC | MDBX_UTTERLY_NOSYNC | MDBX_WRITEMAP + : MDBX_SAFE_NOSYNC | MDBX_UTTERLY_NOSYNC; + const MDBX_env_flags_t rigorous_diff = + (snap_flags ^ env->me_flags) & rigorous_flags; + if (rigorous_diff) { + ERROR("current mode/flags 0x%X incompatible with requested 0x%X, " + "rigorous diff 0x%X", + env->me_flags, snap_flags, rigorous_diff); rc = MDBX_INCOMPATIBLE; goto bailout; } @@ -14397,11 +14428,14 @@ __cold int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, } DEBUG("opened dbenv %p", (void *)env); + if (!lck || lck_rc == MDBX_RESULT_TRUE) { + env->me_lck->mti_envmode.weak = env->me_flags & mode_flags; + env->me_lck->mti_meta_sync_txnid.weak = + (uint32_t)recent_committed_txnid(env); + env->me_lck->mti_reader_check_timestamp.weak = osal_monotime(); + } if (lck) { if (lck_rc == MDBX_RESULT_TRUE) { - lck->mti_envmode.weak = env->me_flags & (mode_flags | MDBX_RDONLY); - lck->mti_meta_sync_txnid.weak = (uint32_t)recent_committed_txnid(env); - lck->mti_reader_check_timestamp.weak = osal_monotime(); rc = osal_lck_downgrade(env); DEBUG("lck-downgrade-%s: rc %i", (env->me_flags & MDBX_EXCLUSIVE) ? "partial" : "full", rc); @@ -14420,11 +14454,6 @@ __cold int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, goto bailout; env->me_flags |= MDBX_ENV_TXKEY; } - } else { - env->me_lck->mti_envmode.weak = env->me_flags & (mode_flags | MDBX_RDONLY); - env->me_lck->mti_meta_sync_txnid.weak = - (uint32_t)recent_committed_txnid(env); - env->me_lck->mti_reader_check_timestamp.weak = osal_monotime(); } if ((flags & MDBX_RDONLY) == 0) {