#include "mdbx.h++" #include #include #include #include #if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L #include #include #endif #if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) #if MDBX_DEBUG || !defined(NDEBUG) #define RELIEF_FACTOR 16 #else #define RELIEF_FACTOR 8 #endif #elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) #define RELIEF_FACTOR 4 #elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul #define RELIEF_FACTOR 2 #else #define RELIEF_FACTOR 1 #endif // static const auto NN = 1000u / RELIEF_FACTOR; #if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L static const auto N = std::min(17u, std::thread::hardware_concurrency()); #else static const auto N = 3u; #endif static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg, unsigned length) noexcept { (void)length; (void)loglevel; fflush(nullptr); std::cout << function << ":" << line << " " << msg; std::cout.flush(); } static char log_buffer[1024]; //-------------------------------------------------------------------------------------------- typedef MDBX_cache_result_t (*get_cached_t)(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, MDBX_cache_entry *entry); static bool check_state(const MDBX_cache_result_t &r, const MDBX_error_t wanna_errcode, const MDBX_cache_status_t wanna_status, unsigned line) { if (r.errcode == wanna_errcode && r.status == wanna_status) return true; std::cerr << "unecpected (at " << line << "): " "err " << r.errcode << " (wanna " << wanna_errcode << "), " "status " << r.status << " (wanna " << wanna_status << ")" << std::endl; return false; } bool case0(mdbx::env env) { get_cached_t get_cached = mdbx_cache_get_SingleThreaded; auto txn = env.start_write(); auto table = txn.create_map("case0", mdbx::key_mode::usual, mdbx::value_mode::single); MDBX_val data; MDBX_cache_entry entry; MDBX_cache_result_t r; bool ok = true; mdbx_cache_init(&entry); r = get_cached(txn, table, mdbx::slice("key"), &data, &entry); ok = check_state(r, MDBX_NOTFOUND, MDBX_CACHE_DIRTY, __LINE__) && ok; txn.commit_embark_read(); r = get_cached(txn, table, mdbx::slice("key"), &data, &entry); ok = check_state(r, MDBX_NOTFOUND, MDBX_CACHE_REFRESHED, __LINE__) && ok; { auto params = mdbx::env::operate_parameters(42); params.options.no_sticky_threads = true; mdbx::env_managed env2(env.get_path(), params); auto txn2 = env2.start_write(); txn2.drop_map("case0"); txn2.commit(); } txn.renew_reading(); r = get_cached(txn, table, mdbx::slice("key"), &data, &entry); ok = check_state(r, MDBX_NOTFOUND, MDBX_CACHE_CONFIRMED, __LINE__) && ok; txn.abort(); txn = env.start_write(); table = txn.create_map("case0", mdbx::key_mode::usual, mdbx::value_mode::single); r = get_cached(txn, table, mdbx::slice("key"), &data, &entry); ok = check_state(r, MDBX_NOTFOUND, MDBX_CACHE_DIRTY, __LINE__) && ok; txn.commit_embark_read(); r = get_cached(txn, table, mdbx::slice("key"), &data, &entry); ok = check_state(r, MDBX_NOTFOUND, MDBX_CACHE_CONFIRMED, __LINE__) && ok; return ok; } //-------------------------------------------------------------------------------------------- int doit() { mdbx::path db_filename = "test-get-cached"; mdbx::env::remove(db_filename); mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(N + 2, 0, mdbx::env::nested_transactions)); bool ok = case0(env); // ok = case1(env) && ok; // ok = case2(env) && ok; if (ok) { std::cout << "OK\n"; return EXIT_SUCCESS; } else { std::cout << "FAIL!\n"; return EXIT_FAILURE; } } int main(int argc, char *argv[]) { (void)argc; (void)argv; mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT | MDBX_DBG_LEGACY_MULTIOPEN, logger_nofmt, log_buffer, sizeof(log_buffer)); try { return doit(); } catch (const std::exception &ex) { std::cerr << "Exception: " << ex.what() << "\n"; return EXIT_FAILURE; } }