diff options
author | George Hazan <ghazan@miranda.im> | 2018-11-25 15:45:50 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2018-11-25 15:45:50 +0300 |
commit | f5e4db1c78db17956920f88cea5e6914ec668e24 (patch) | |
tree | c95b2037ddd70371d3c6b1b9d9264b944618871f | |
parent | bc1277617376426080ca452f63a633c9e255fc4c (diff) |
libmdbx: fix for changing database size
-rw-r--r-- | libs/libmdbx/src/src/mdbx.c | 73 |
1 files changed, 57 insertions, 16 deletions
diff --git a/libs/libmdbx/src/src/mdbx.c b/libs/libmdbx/src/src/mdbx.c index 92e1b5c630..af03bdaa8d 100644 --- a/libs/libmdbx/src/src/mdbx.c +++ b/libs/libmdbx/src/src/mdbx.c @@ -1765,7 +1765,7 @@ static int mdbx_page_loose(MDBX_cursor *mc, MDBX_page *mp) { mdbx_kill_page(txn->mt_env, mp); mp->mp_flags = P_LOOSE | P_DIRTY; VALGRIND_MAKE_MEM_UNDEFINED(mp, PAGEHDRSZ); - VALGRIND_MAKE_MEM_DEFINED(&mp->mp_pgno, sizeof(pgno_t)); + ASAN_UNPOISON_MEMORY_REGION(link, sizeof(*link)); *link = txn->mt_loose_pages; txn->mt_loose_pages = mp; txn->mt_loose_count++; @@ -2246,19 +2246,21 @@ static int mdbx_mapresize(MDBX_env *env, const pgno_t size_pgno, env->me_dxb_mmap.current == env->me_dxb_mmap.filesize) goto bailout; - if ((env->me_flags & MDBX_RDONLY) || limit_bytes != env->me_dxb_mmap.length || - size_bytes < env->me_dxb_mmap.current) { - /* Windows allows only extending a read-write section, but not a - * corresponing mapped view. Therefore in other cases we must suspend - * the local threads for safe remap. */ - array_onstack.limit = ARRAY_LENGTH(array_onstack.handles); - array_onstack.count = 0; - suspended = &array_onstack; - rc = mdbx_suspend_threads_before_remap(env, &suspended); - if (rc != MDBX_SUCCESS) { - mdbx_error("failed suspend-for-remap: errcode %d", rc); - goto bailout; - } + /* 1) Windows allows only extending a read-write section, but not a + * corresponing mapped view. Therefore in other cases we must suspend + * the local threads for safe remap. + * 2) At least on Windows 10 1803 the entire mapped section is unavailable + * for short time during NtExtendSection() or VirtualAlloc() execution. + * + * THEREFORE LOCAL THREADS SUSPENDING IS ALWAYS REQUIRED! + */ + array_onstack.limit = ARRAY_LENGTH(array_onstack.handles); + array_onstack.count = 0; + suspended = &array_onstack; + rc = mdbx_suspend_threads_before_remap(env, &suspended); + if (rc != MDBX_SUCCESS) { + mdbx_error("failed suspend-for-remap: errcode %d", rc); + goto bailout; } #else /* Acquire guard to avoid collision between read and write txns @@ -3347,6 +3349,13 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { } } txn->mt_owner = mdbx_thread_self(); +#if defined(_WIN32) || defined(_WIN64) + if ((txn->mt_flags & MDBX_TXN_RDONLY) != 0 && size > env->me_dbgeo.lower && + env->me_dbgeo.shrink) { + txn->mt_flags |= MDBX_SHRINK_ALLOWED; + mdbx_srwlock_AcquireShared(&env->me_remap_guard); + } +#endif return MDBX_SUCCESS; } bailout: @@ -3514,8 +3523,8 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, if (txn != env->me_txn0) mdbx_free(txn); } else { - mdbx_assert(env, - (txn->mt_flags & ~(MDBX_TXN_RDONLY | MDBX_TXN_WRITEMAP)) == 0); + mdbx_assert(env, (txn->mt_flags & ~(MDBX_TXN_RDONLY | MDBX_TXN_WRITEMAP | + MDBX_SHRINK_ALLOWED)) == 0); txn->mt_signature = MDBX_MT_SIGNATURE; *ret = txn; mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO @@ -3608,6 +3617,10 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) { txn->mt_dbs[FREE_DBI].md_root); if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)) { +#if defined(_WIN32) || defined(_WIN64) + if (txn->mt_flags & MDBX_SHRINK_ALLOWED) + mdbx_srwlock_ReleaseShared(&env->me_remap_guard); +#endif if (txn->mt_ro_reader) { txn->mt_ro_reader->mr_txnid = ~(txnid_t)0; env->me_lck->mti_readers_refresh_flag = true; @@ -5841,6 +5854,34 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, meta.mm_geo.shrink == bytes2pgno(env, env->me_dbgeo.shrink)); if (memcmp(&meta.mm_geo, &head->mm_geo, sizeof(meta.mm_geo))) { + +#if defined(_WIN32) || defined(_WIN64) + /* Was DB shrinking disabled before and now it will be enabled? */ + if (meta.mm_geo.lower < meta.mm_geo.upper && meta.mm_geo.shrink && + !(head->mm_geo.lower < head->mm_geo.upper && head->mm_geo.shrink)) { + rc = mdbx_rdt_lock(env); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + + /* Check if there are any reading threads that do not use the SRWL */ + const mdbx_pid_t CurrentTid = GetCurrentThreadId(); + const MDBX_reader *const begin = env->me_lck->mti_readers; + const MDBX_reader *const end = begin + env->me_lck->mti_numreaders; + for (const MDBX_reader *reader = begin; reader < end; ++reader) { + if (reader->mr_pid == env->me_pid && reader->mr_tid && + reader->mr_tid != CurrentTid) { + /* At least one thread may don't use SRWL */ + rc = MDBX_EPERM; + break; + } + } + + mdbx_rdt_unlock(env); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + } +#endif + if (meta.mm_geo.now != head->mm_geo.now || meta.mm_geo.upper != head->mm_geo.upper) { rc = mdbx_mapresize(env, meta.mm_geo.now, meta.mm_geo.upper); |