From 1c174e84c4e8d6a1a9b851b2132e07e5590fefb9 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: Tue, 5 Mar 2024 01:56:04 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx=5Fpreopen=5Fsnapinfo()`=20?= =?UTF-8?q?=D0=B2=20API.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://gitflic.ru/project/erthink/libmdbx/issue/15 --- mdbx.h | 12 ++++++++ src/core.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/main.c++ | 8 +++++ 3 files changed, 103 insertions(+) diff --git a/mdbx.h b/mdbx.h index 1fda47e2..080b2509 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5714,6 +5714,18 @@ LIBMDBX_API int mdbx_env_open_for_recoveryW(MDBX_env *env, * leg(s). */ LIBMDBX_API int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target_meta); +/** \brief FIXME + */ +LIBMDBX_API int mdbx_preopen_snapinfo(const char *pathname, MDBX_envinfo *arg, + size_t bytes); +#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) +/** \copydoc mdbx_preopen_snapinfo() + * \note Available only on Windows. + * \see mdbx_preopen_snapinfo() */ +LIBMDBX_API int mdbx_preopen_snapinfoW(const wchar_t *pathname, + MDBX_envinfo *arg, size_t bytes); +#endif /* Windows */ + /** \brief Флаги/опции для проверки целостности БД. * \see mdbx_env_chk() */ enum MDBX_chk_flags_t { diff --git a/src/core.c b/src/core.c index 666998b4..eb217b0a 100644 --- a/src/core.c +++ b/src/core.c @@ -23396,6 +23396,89 @@ __cold int env_info(const MDBX_env *env, const MDBX_txn *txn, MDBX_envinfo *out, } } +__cold int mdbx_preopen_snapinfo(const char *pathname, MDBX_envinfo *out, + size_t bytes) { +#if defined(_WIN32) || defined(_WIN64) + wchar_t *pathnameW = nullptr; + int rc = osal_mb2w(pathname, &pathnameW); + if (likely(rc == MDBX_SUCCESS)) { + rc = mdbx_preopen_snapinfoW(pathnameW, out, bytes); + osal_free(pathnameW); + } + return rc; +} + +__cold int mdbx_preopen_snapinfoW(const wchar_t *pathname, MDBX_envinfo *out, + size_t bytes) { +#endif /* Windows */ + if (unlikely(!out)) + return MDBX_EINVAL; + + const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid); + const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat); + if (unlikely(bytes != sizeof(MDBX_envinfo)) && bytes != size_before_bootid && + bytes != size_before_pgop_stat) + return MDBX_EINVAL; + + memset(out, 0, bytes); + if (likely(bytes > size_before_bootid)) { + out->mi_bootid.current.x = bootid.x; + out->mi_bootid.current.y = bootid.y; + } + + MDBX_env env; + memset(&env, 0, sizeof(env)); + env.me_pid = osal_getpid(); + const size_t os_psize = osal_syspagesize(); + if (unlikely(!is_powerof2(os_psize) || os_psize < MIN_PAGESIZE)) { + ERROR("unsuitable system pagesize %" PRIuPTR, os_psize); + return MDBX_INCOMPATIBLE; + } + out->mi_sys_pagesize = env.me_os_psize = (unsigned)os_psize; + env.me_flags = MDBX_RDONLY | MDBX_NORDAHEAD | MDBX_ACCEDE | MDBX_VALIDATION; + env.me_stuck_meta = -1; + env.me_lfd = INVALID_HANDLE_VALUE; + env.me_lazy_fd = INVALID_HANDLE_VALUE; + env.me_dsync_fd = INVALID_HANDLE_VALUE; + env.me_fd4meta = INVALID_HANDLE_VALUE; +#if defined(_WIN32) || defined(_WIN64) + env.me_data_lock_event = INVALID_HANDLE_VALUE; + env.me_overlapped_fd = INVALID_HANDLE_VALUE; +#endif /* Windows */ + + int rc = env_handle_pathname(&env, pathname, 0); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + rc = osal_openfile(MDBX_OPEN_DXB_READ, &env, env.me_pathname.dxb, + &env.me_lazy_fd, 0); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + + MDBX_meta header; + rc = read_header(&env, &header, 0, 0); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + + setup_pagesize(&env, header.mm_psize); + out->mi_dxb_pagesize = env.me_psize; + out->mi_geo.lower = pgno2bytes(&env, header.mm_geo.lower); + out->mi_geo.upper = pgno2bytes(&env, header.mm_geo.upper); + out->mi_geo.shrink = pgno2bytes(&env, pv2pages(header.mm_geo.shrink_pv)); + out->mi_geo.grow = pgno2bytes(&env, pv2pages(header.mm_geo.grow_pv)); + out->mi_geo.current = pgno2bytes(&env, header.mm_geo.now); + out->mi_last_pgno = header.mm_geo.next - 1; + + const unsigned n = 0; + out->mi_recent_txnid = constmeta_txnid(&header); + out->mi_meta_sign[n] = unaligned_peek_u64(4, &header.mm_sign); + if (likely(bytes > size_before_bootid)) + memcpy(&out->mi_bootid.meta[n], &header.mm_bootid, 16); + +bailout: + env_close(&env, false); + return rc; +} + __cold int mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_envinfo *arg, size_t bytes) { if (unlikely((env == NULL && txn == NULL) || arg == NULL)) diff --git a/test/main.c++ b/test/main.c++ index 84ab801c..8732f5f7 100644 --- a/test/main.c++ +++ b/test/main.c++ @@ -743,6 +743,14 @@ int main(int argc, char *const argv[]) { log_trace("=== done..."); } + if (!failed) { + MDBX_envinfo info; + int err = + mdbx_preopen_snapinfo(params.pathname_db.c_str(), &info, sizeof(info)); + if (err != MDBX_SUCCESS) + failure_perror("mdbx_preopen_snapinfo()", err); + } + log_notice("RESULT: %s\n", failed ? "Failed" : "Successful"); if (global::config::cleanup_after) { if (failed)