diff --git a/CMakeLists.txt b/CMakeLists.txt index d533fa40..00334955 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -826,7 +826,7 @@ macro(libmdbx_setup_libs TARGET MODE) target_link_libraries(${TARGET} ${MODE} Threads::Threads) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(${TARGET} ${MODE} ntdll user32 kernel32 advapi32) + target_link_libraries(${TARGET} ${MODE} ntdll user32 kernel32 advapi32 ole32) if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_WITHOUT_MSVC_CRT) target_link_libraries(${TARGET} ${MODE} ntdll_extra) endif() diff --git a/mdbx.h b/mdbx.h index 1f4c2bc2..8ee45375 100644 --- a/mdbx.h +++ b/mdbx.h @@ -2745,6 +2745,11 @@ struct MDBX_envinfo { uint64_t fsync; /**< Number of explicit fsync-to-disk operations (not a pages) */ } mi_pgop_stat; + + /* GUID of the database DXB file. */ + struct { + uint64_t x, y; + } mi_dxbid; }; #ifndef __cplusplus /** \ingroup c_statinfo */ diff --git a/src/api-env.c b/src/api-env.c index 1e8988b6..ce2d0755 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -727,6 +727,7 @@ static int env_info_snap(const MDBX_env *env, const MDBX_txn *txn, troika_t *const troika) { const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid); const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat); + const size_t size_before_dxbid = offsetof(MDBX_envinfo, mi_dxbid); if (unlikely(env->flags & ENV_FATAL_ERROR)) return MDBX_PANIC; @@ -773,6 +774,8 @@ static int env_info_snap(const MDBX_env *env, const MDBX_txn *txn, memcpy(&out->mi_bootid.meta[0], &meta0->bootid, 16); memcpy(&out->mi_bootid.meta[1], &meta1->bootid, 16); memcpy(&out->mi_bootid.meta[2], &meta2->bootid, 16); + if (likely(bytes > size_before_dxbid)) + memcpy(&out->mi_dxbid, &meta0->dxbid, 16); } const volatile meta_t *txn_meta = head.ptr_v; @@ -895,8 +898,9 @@ __cold int mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid); const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat); + const size_t size_before_dxbid = offsetof(MDBX_envinfo, mi_dxbid); if (unlikely(bytes != sizeof(MDBX_envinfo)) && bytes != size_before_bootid && - bytes != size_before_pgop_stat) + bytes != size_before_pgop_stat && bytes != size_before_dxbid) return MDBX_EINVAL; if (txn) { @@ -938,8 +942,9 @@ __cold int mdbx_preopen_snapinfoW(const wchar_t *pathname, MDBX_envinfo *out, const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid); const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat); + const size_t size_before_dxbid = offsetof(MDBX_envinfo, mi_dxbid); if (unlikely(bytes != sizeof(MDBX_envinfo)) && bytes != size_before_bootid && - bytes != size_before_pgop_stat) + bytes != size_before_pgop_stat && bytes != size_before_dxbid) return MDBX_EINVAL; memset(out, 0, bytes); @@ -993,8 +998,11 @@ __cold int mdbx_preopen_snapinfoW(const wchar_t *pathname, MDBX_envinfo *out, const unsigned n = 0; out->mi_recent_txnid = constmeta_txnid(&header); out->mi_meta_sign[n] = unaligned_peek_u64(4, &header.sign); - if (likely(bytes > size_before_bootid)) + if (likely(bytes > size_before_bootid)) { memcpy(&out->mi_bootid.meta[n], &header.bootid, 16); + if (likely(bytes > size_before_dxbid)) + memcpy(&out->mi_dxbid, &header.dxbid, 16); + } bailout: env_close(&env, false); diff --git a/src/chk.c b/src/chk.c index 1e7cb6dd..88675536 100644 --- a/src/chk.c +++ b/src/chk.c @@ -1590,13 +1590,23 @@ __cold static int env_chk(MDBX_chk_scope_t *const scope) { return chk_error_rc(scope, err, "env_info"); MDBX_chk_line_t *line = - chk_puts(chk_line_begin(scope, MDBX_chk_info), "current boot-id "); + chk_puts(chk_line_begin(scope, MDBX_chk_info - + (1 << MDBX_chk_severity_prio_shift)), + "dxb-id "); + if (chk->envinfo.mi_dxbid.x | chk->envinfo.mi_dxbid.y) + line = chk_print(line, "%016" PRIx64 "-%016" PRIx64, + chk->envinfo.mi_dxbid.x, chk->envinfo.mi_dxbid.y); + else + line = chk_puts(line, "is absent"); + chk_line_end(line); + + line = chk_puts(chk_line_begin(scope, MDBX_chk_info), "current boot-id "); if (chk->envinfo.mi_bootid.current.x | chk->envinfo.mi_bootid.current.y) line = chk_print(line, "%016" PRIx64 "-%016" PRIx64, chk->envinfo.mi_bootid.current.x, chk->envinfo.mi_bootid.current.y); else - line = chk_puts(line, "unavailable"); + line = chk_puts(line, "is unavailable"); chk_line_end(line); err = osal_filesize(env->lazy_fd, &env->dxb_mmap.filesize); diff --git a/src/dxb.c b/src/dxb.c index 9da9c009..401115d9 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -1045,14 +1045,16 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, if ((env->flags & MDBX_RDONLY) == 0 && env->stuck_meta < 0 && (globals.runtime_flags & MDBX_DBG_DONT_UPGRADE) == 0) { - for (int n = 0; n < NUM_METAS; ++n) { + for (unsigned n = 0; n < NUM_METAS; ++n) { meta_t *const meta = METAPAGE(env, n); if (unlikely(unaligned_peek_u64(4, &meta->magic_and_version) != - MDBX_DATA_MAGIC)) { - const txnid_t txnid = constmeta_txnid(meta); + MDBX_DATA_MAGIC) || + (meta->dxbid.x | meta->dxbid.y) == 0) { + const txnid_t txnid = + meta_is_used(&troika, n) ? constmeta_txnid(meta) : 0; NOTICE("%s %s" "meta[%u], txnid %" PRIaTXN, - "updating db-format signature for", + "updating db-format/guid signature for", meta_is_steady(meta) ? "stead-" : "weak-", n, txnid); err = meta_override(env, n, txnid, meta); if (unlikely(err != MDBX_SUCCESS) && diff --git a/src/layout-dxb.h b/src/layout-dxb.h index 06b0e834..78f05aeb 100644 --- a/src/layout-dxb.h +++ b/src/layout-dxb.h @@ -91,15 +91,6 @@ typedef struct geo { }; } geo_t; -typedef union bin128 { - __anonymous_struct_extension__ struct { - uint64_t x, y; - }; - __anonymous_struct_extension__ struct { - uint32_t a, b, c, d; - }; -} bin128_t; - /* Meta page content. * A meta page is the start point for accessing a database snapshot. * Pages 0-2 are meta pages. */ @@ -158,6 +149,9 @@ typedef struct meta { * steady sync point. Zeros mean that no relevant information is available * from the system. */ bin128_t bootid; + + /* GUID базы данных, начиная с v0.13.1 */ + bin128_t dxbid; } meta_t; #pragma pack(1) diff --git a/src/meta.c b/src/meta.c index b7333a0a..ee2a5aef 100644 --- a/src/meta.c +++ b/src/meta.c @@ -332,8 +332,8 @@ int meta_sync(const MDBX_env *env, const meta_ptr_t head) { return rc; } -__cold static page_t *meta_model(const MDBX_env *env, page_t *model, - size_t num) { +__cold static page_t *meta_model(const MDBX_env *env, page_t *model, size_t num, + const bin128_t *guid) { ENSURE(env, is_powerof2(env->ps)); ENSURE(env, env->ps >= MDBX_MIN_PAGESIZE); ENSURE(env, env->ps <= MDBX_MAX_PAGESIZE); @@ -373,6 +373,7 @@ __cold static page_t *meta_model(const MDBX_env *env, page_t *model, model_meta->trees.gc.flags = MDBX_INTEGERKEY; model_meta->trees.gc.root = P_INVALID; model_meta->trees.main.root = P_INVALID; + memcpy(&model_meta->dxbid, guid, sizeof(model_meta->dxbid)); meta_set_txnid(env, model_meta, MIN_TXNID + num); unaligned_poke_u64(4, model_meta->sign, meta_sign_calculate(model_meta)); eASSERT(env, coherency_check_meta(env, model_meta, true)); @@ -380,10 +381,11 @@ __cold static page_t *meta_model(const MDBX_env *env, page_t *model, } __cold meta_t *meta_init_triplet(const MDBX_env *env, void *buffer) { + const bin128_t guid = osal_guid(env); page_t *page0 = (page_t *)buffer; - page_t *page1 = meta_model(env, page0, 0); - page_t *page2 = meta_model(env, page1, 1); - meta_model(env, page2, 2); + page_t *page1 = meta_model(env, page0, 0, &guid); + page_t *page2 = meta_model(env, page1, 1, &guid); + meta_model(env, page2, 2, &guid); return page_meta(page2); } @@ -394,7 +396,8 @@ __cold int __must_check_result meta_override(MDBX_env *env, size_t target, if (unlikely(rc != MDBX_SUCCESS)) return rc; page_t *const page = env->page_auxbuf; - meta_model(env, page, target); + meta_model(env, page, target, + &((target == 0 && shape) ? shape : METAPAGE(env, 0))->dxbid); meta_t *const model = page_meta(page); meta_set_txnid(env, model, txnid); if (txnid) @@ -430,6 +433,12 @@ __cold int __must_check_result meta_override(MDBX_env *env, size_t target, } } } + + if (target == 0 && (model->dxbid.x | model->dxbid.y) == 0) { + const bin128_t guid = osal_guid(env); + memcpy(&model->dxbid, &guid, sizeof(model->dxbid)); + } + meta_sign_as_steady(model); rc = meta_validate(env, model, page, (pgno_t)target, nullptr); if (unlikely(MDBX_IS_ERROR(rc))) diff --git a/src/meta.h b/src/meta.h index 51a8d66f..706061c1 100644 --- a/src/meta.h +++ b/src/meta.h @@ -83,7 +83,12 @@ static inline meta_ptr_t meta_tail(const MDBX_env *env, return r; } +static inline bool meta_is_used(const troika_t *troika, unsigned n) { + return n == troika->recent || n == troika->prefer_steady; +} + static inline bool meta_bootid_match(const meta_t *meta) { + return memcmp(&meta->bootid, &globals.bootid, 16) == 0 && (globals.bootid.x | globals.bootid.y) != 0; } diff --git a/src/osal.c b/src/osal.c index d8d58392..1ae7dcf9 100644 --- a/src/osal.c +++ b/src/osal.c @@ -2931,17 +2931,40 @@ __cold static void bootid_collect(bin128_t *p, const void *s, size_t n) { bootid_shake(p); /* minor non-linear tomfoolery */ - const unsigned z = p->x % 61; + const unsigned z = p->x % 61 + 1; p->y = p->y << z | p->y >> (64 - z); bootid_shake(p); bootid_shake(p); - const unsigned q = p->x % 59; + const unsigned q = p->x % 59 + 1; p->y = p->y << q | p->y >> (64 - q); bootid_shake(p); bootid_shake(p); bootid_shake(p); } +static size_t hamming_weight(size_t v) { + const size_t m1 = (size_t)UINT64_C(0x5555555555555555); + const size_t m2 = (size_t)UINT64_C(0x3333333333333333); + const size_t m4 = (size_t)UINT64_C(0x0f0f0f0f0f0f0f0f); + const size_t h01 = (size_t)UINT64_C(0x0101010101010101); + v -= (v >> 1) & m1; + v = (v & m2) + ((v >> 2) & m2); + v = (v + (v >> 4)) & m4; + return (v * h01) >> (sizeof(v) * 8 - 8); +} + +static inline size_t hw64(uint64_t v) { + size_t r = hamming_weight((size_t)v); + if (sizeof(v) > sizeof(r)) + r += hamming_weight((size_t)(v >> sizeof(r) * 4 >> sizeof(r) * 4)); + return r; +} + +static bool check_uuid(bin128_t uuid) { + size_t hw = hw64(uuid.x) + hw64(uuid.y) + hw64(uuid.x ^ uuid.y); + return (hw >> 6) == 1; +} + #if defined(_WIN32) || defined(_WIN64) __cold static uint64_t windows_systemtime_ms() { @@ -3043,7 +3066,7 @@ bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) { s->y += aligned.y; } else bootid_collect(s, p, n); - return true; + return check_uuid(*s); } if (n) @@ -3051,28 +3074,33 @@ bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) { return false; } +#if defined(__linux__) || defined(__gnu_linux__) +__cold static bool proc_read_uuid(const char *path, bin128_t *target) { + const int fd = open(path, O_RDONLY | O_NOFOLLOW); + if (fd != -1) { + struct statfs fs; + char buf[42]; + const ssize_t len = + (fstatfs(fd, &fs) == 0 && fs.f_type == /* procfs */ 0x9FA0) + ? read(fd, buf, sizeof(buf)) + : -1; + const int err = close(fd); + assert(err == 0); + (void)err; + if (len > 0) + return bootid_parse_uuid(target, buf, len); + } + return false; +} +#endif /* Linux */ + __cold static bin128_t osal_bootid(void) { - bin128_t bin = {{0, 0}}; + bin128_t uuid = {{0, 0}}; bool got_machineid = false, got_boottime = false, got_bootseq = false; #if defined(__linux__) || defined(__gnu_linux__) - { - const int fd = - open("/proc/sys/kernel/random/boot_id", O_RDONLY | O_NOFOLLOW); - if (fd != -1) { - struct statfs fs; - char buf[42]; - const ssize_t len = - (fstatfs(fd, &fs) == 0 && fs.f_type == /* procfs */ 0x9FA0) - ? read(fd, buf, sizeof(buf)) - : -1; - const int err = close(fd); - assert(err == 0); - (void)err; - if (len > 0 && bootid_parse_uuid(&bin, buf, len)) - return bin; - } - } + if (proc_read_uuid("/proc/sys/kernel/random/boot_id", &uuid)) + return uuid; #endif /* Linux */ #if defined(__APPLE__) || defined(__MACH__) @@ -3080,16 +3108,15 @@ __cold static bin128_t osal_bootid(void) { char buf[42]; size_t len = sizeof(buf); if (!sysctlbyname("kern.bootsessionuuid", buf, &len, nullptr, 0) && - bootid_parse_uuid(&bin, buf, len)) - return bin; + bootid_parse_uuid(&uuid, buf, len)) + return uuid; #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \ __MAC_OS_X_VERSION_MIN_REQUIRED > 1050 - uuid_t uuid; + uuid_t hostuuid; struct timespec wait = {0, 1000000000u / 42}; - if (!gethostuuid(uuid, &wait) && - bootid_parse_uuid(&bin, uuid, sizeof(uuid))) - got_machineid = true; + if (!gethostuuid(hostuuid, &wait)) + got_machineid = bootid_parse_uuid(&uuid, hostuuid, sizeof(hostuuid)); #endif /* > 10.5 */ struct timeval boottime; @@ -3127,7 +3154,7 @@ __cold static bin128_t osal_bootid(void) { "MachineGuid", &buf.MachineGuid, &len) == ERROR_SUCCESS && len < sizeof(buf)) - got_machineid = bootid_parse_uuid(&bin, &buf.MachineGuid, len); + got_machineid = bootid_parse_uuid(&uuid, &buf.MachineGuid, len); if (!got_machineid) { /* again, Windows is madness */ @@ -3145,7 +3172,7 @@ __cold static bin128_t osal_bootid(void) { "DigitalProductId", &buf.DigitalProductId, &len) == ERROR_SUCCESS && len > 42 && len < sizeof(buf)) { - bootid_collect(&bin, &buf.DigitalProductId, len); + bootid_collect(&uuid, &buf.DigitalProductId, len); got_machineid = true; } len = sizeof(buf); @@ -3153,7 +3180,7 @@ __cold static bin128_t osal_bootid(void) { "DigitalProductId", &buf.DigitalProductId, &len) == ERROR_SUCCESS && len > 42 && len < sizeof(buf)) { - bootid_collect(&bin, &buf.DigitalProductId, len); + bootid_collect(&uuid, &buf.DigitalProductId, len); got_machineid = true; } len = sizeof(buf); @@ -3161,7 +3188,7 @@ __cold static bin128_t osal_bootid(void) { "DigitalProductId", &buf.DigitalProductId, &len) == ERROR_SUCCESS && len > 42 && len < sizeof(buf)) { - bootid_collect(&bin, &buf.DigitalProductId, len); + bootid_collect(&uuid, &buf.DigitalProductId, len); got_machineid = true; } } @@ -3173,7 +3200,7 @@ __cold static bin128_t osal_bootid(void) { if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BootId", &buf.BootId, &len) == ERROR_SUCCESS && len > 1 && len < sizeof(buf)) { - bootid_collect(&bin, &buf.BootId, len); + bootid_collect(&uuid, &buf.BootId, len); got_bootseq = true; } @@ -3181,7 +3208,7 @@ __cold static bin128_t osal_bootid(void) { if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BaseTime", &buf.BaseTime, &len) == ERROR_SUCCESS && len >= sizeof(buf.BaseTime) && buf.BaseTime) { - bootid_collect(&bin, &buf.BaseTime, len); + bootid_collect(&uuid, &buf.BaseTime, len); got_boottime = true; } @@ -3197,7 +3224,7 @@ __cold static bin128_t osal_bootid(void) { buf.SysTimeOfDayInfoHacked.BootTime.QuadPart - buf.SysTimeOfDayInfoHacked.BootTimeBias; if (UnbiasedBootTime) { - bootid_collect(&bin, &UnbiasedBootTime, sizeof(UnbiasedBootTime)); + bootid_collect(&uuid, &UnbiasedBootTime, sizeof(UnbiasedBootTime)); got_boottime = true; } } @@ -3205,7 +3232,7 @@ __cold static bin128_t osal_bootid(void) { if (!got_boottime) { uint64_t boottime = windows_bootime(); if (boottime) { - bootid_collect(&bin, &boottime, sizeof(boottime)); + bootid_collect(&uuid, &boottime, sizeof(boottime)); got_boottime = true; } } @@ -3223,7 +3250,7 @@ __cold static bin128_t osal_bootid(void) { #endif mib, ARRAY_LENGTH(mib), &buf, &len, nullptr, 0) == 0) - got_machineid = bootid_parse_uuid(&bin, buf, len); + got_machineid = bootid_parse_uuid(&uuid, buf, len); } #endif /* CTL_HW && HW_UUID */ @@ -3238,7 +3265,7 @@ __cold static bin128_t osal_bootid(void) { #endif mib, ARRAY_LENGTH(mib), &buf, &len, nullptr, 0) == 0) - got_machineid = bootid_parse_uuid(&bin, buf, len); + got_machineid = bootid_parse_uuid(&uuid, buf, len); } #endif /* CTL_KERN && KERN_HOSTUUID */ @@ -3247,7 +3274,7 @@ __cold static bin128_t osal_bootid(void) { char buf[42]; size_t len = sizeof(buf); if (sysctlbyname("machdep.dmi.system-uuid", buf, &len, nullptr, 0) == 0) - got_machineid = bootid_parse_uuid(&bin, buf, len); + got_machineid = bootid_parse_uuid(&uuid, buf, len); } #endif /* __NetBSD__ */ @@ -3255,7 +3282,7 @@ __cold static bin128_t osal_bootid(void) { if (!got_machineid) { const int hostid = gethostid(); if (hostid > 0) { - bootid_collect(&bin, &hostid, sizeof(hostid)); + bootid_collect(&uuid, &hostid, sizeof(hostid)); got_machineid = true; } } @@ -3263,8 +3290,8 @@ __cold static bin128_t osal_bootid(void) { if (!got_machineid) { lack: - bin.x = bin.y = 0; - return bin; + uuid.x = uuid.y = 0; + return uuid; } /*--------------------------------------------------------------------------*/ @@ -3281,7 +3308,7 @@ __cold static bin128_t osal_bootid(void) { mib, ARRAY_LENGTH(mib), &boottime, &len, nullptr, 0) == 0 && len == sizeof(boottime) && boottime.tv_sec) { - bootid_collect(&bin, &boottime, len); + bootid_collect(&uuid, &boottime, len); got_boottime = true; } } @@ -3298,11 +3325,11 @@ __cold static bin128_t osal_bootid(void) { switch (kn->data_type) { case KSTAT_DATA_INT32: case KSTAT_DATA_UINT32: - bootid_collect(&bin, &kn->value, sizeof(int32_t)); + bootid_collect(&uuid, &kn->value, sizeof(int32_t)); got_boottime = true; case KSTAT_DATA_INT64: case KSTAT_DATA_UINT64: - bootid_collect(&bin, &kn->value, sizeof(int64_t)); + bootid_collect(&uuid, &kn->value, sizeof(int64_t)); got_boottime = true; } } @@ -3318,12 +3345,12 @@ __cold static bin128_t osal_bootid(void) { const struct utmpx id = {.ut_type = BOOT_TIME}; const struct utmpx *entry = getutxid(&id); if (entry) { - bootid_collect(&bin, entry, sizeof(*entry)); + bootid_collect(&uuid, entry, sizeof(*entry)); got_boottime = true; while (unlikely((entry = getutxid(&id)) != nullptr)) { /* have multiple reboot records, assuming we can distinguish next * bootsession even if RTC is wrong or absent */ - bootid_collect(&bin, entry, sizeof(*entry)); + bootid_collect(&uuid, entry, sizeof(*entry)); got_bootseq = true; } } @@ -3352,7 +3379,7 @@ __cold static bin128_t osal_bootid(void) { goto lack; } - return bin; + return uuid; } __cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages, @@ -3474,6 +3501,100 @@ __cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages, return MDBX_SUCCESS; } +/*----------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include +#endif /* FreeBSD */ + +#if __GLIBC_PREREQ(2, 25) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) || \ + defined(__APPLE__) || __has_include() +#include +#endif /* sys/random.h */ + +MDBX_INTERNAL bin128_t osal_guid(const MDBX_env *env) { + struct { + uint64_t begin, end, cputime; + uintptr_t thread, pid; + const void *x, *y; + bin128_t (*z)(const MDBX_env *env); + } salt; + + salt.begin = osal_monotime(); + bin128_t uuid = {{0, 0}}; + +#if defined(__linux__) || defined(__gnu_linux__) + if (proc_read_uuid("/proc/sys/kernel/random/uuid", &uuid) && check_uuid(uuid)) + return uuid; +#endif /* Linux */ + +#ifdef __FreeBSD__ + STATIC_ASSERT(sizeof(uuid) == sizeof(struct uuid)); + if (uuidgen((struct uuid *)&uuid, 1) == 0 && check_uuid(uuid)) + return uuid; +#endif /* FreeBSD */ + +#if defined(_WIN32) || defined(_WIN64) + if (imports.CoCreateGuid && imports.CoCreateGuid(&uuid) == 0 && + check_uuid(uuid)) + return uuid; + + HCRYPTPROV hCryptProv = 0; + if (CryptAcquireContextW(&hCryptProv, nullptr, nullptr, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + const BOOL ok = + CryptGenRandom(hCryptProv, sizeof(uuid), (unsigned char *)&uuid); + CryptReleaseContext(hCryptProv, 0); + if (ok && check_uuid(uuid)) + return uuid; + } +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_8_0) +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0 + if (CCRandomGenerateBytes(&uuid, sizeof(uuid)) == kCCSuccess && + check_uuid(uuid)) + return uuid; +#endif /* iOS >= 8.x */ +#else + const int fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + const ssize_t len = read(fd, &uuid, sizeof(uuid)); + const int err = close(fd); + assert(err == 0); + (void)err; + if (len == sizeof(uuid) && check_uuid(uuid)) + return uuid; + } +#if (__GLIBC_PREREQ(2, 25) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__)) && \ + !defined(__APPLE__) && !defined(__ANDROID_API__) + if (getrandom(&uuid, sizeof(uuid), 0) == sizeof(uuid) && check_uuid(uuid)) + return uuid; +#elif defined(__OpenBSD__) || (defined(__sun) && defined(__SVR4)) || \ + (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \ + __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if (getentropy(&uuid, sizeof(uuid)) == 0 && check_uuid(uuid)) + return uuid; +#endif /* getrandom() / getentropy() */ +#endif /* !Windows */ + + uuid = globals.bootid; + bootid_collect(&uuid, env, sizeof(*env)); + salt.thread = osal_thread_self(); + salt.pid = osal_getpid(); + salt.x = &salt; + salt.y = env; + salt.z = &osal_guid; + do { + salt.cputime = osal_cputime(nullptr); + salt.end = osal_monotime(); + bootid_collect(&uuid, &salt, sizeof(salt)); + } while (!check_uuid(uuid)); + return uuid; +} + +/*--------------------------------------------------------------------------*/ + void osal_ctor(void) { #if MDBX_HAVE_PWRITEV && defined(_SC_IOV_MAX) osal_iov_max = sysconf(_SC_IOV_MAX); diff --git a/src/osal.h b/src/osal.h index 15831c99..23669cf6 100644 --- a/src/osal.h +++ b/src/osal.h @@ -576,6 +576,17 @@ MDBX_INTERNAL void osal_dtor(void); MDBX_INTERNAL int osal_mb2w(const char *const src, wchar_t **const pdst); #endif /* Windows */ +typedef union bin128 { + __anonymous_struct_extension__ struct { + uint64_t x, y; + }; + __anonymous_struct_extension__ struct { + uint32_t a, b, c, d; + }; +} bin128_t; + +MDBX_INTERNAL bin128_t osal_guid(const MDBX_env *); + /*----------------------------------------------------------------------------*/ MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static inline uint64_t diff --git a/src/txn.c b/src/txn.c index 17845876..c3d32eb5 100644 --- a/src/txn.c +++ b/src/txn.c @@ -839,6 +839,7 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { meta.trees.gc = txn->dbs[FREE_DBI]; meta.trees.main = txn->dbs[MAIN_DBI]; meta.canary = txn->canary; + memcpy(&meta.dxbid, &head.ptr_c->dxbid, sizeof(meta.dxbid)); txnid_t commit_txnid = txn->txnid; #if MDBX_ENABLE_BIGFOOT diff --git a/src/windows-import.c b/src/windows-import.c index 0e702c3e..a401014c 100644 --- a/src/windows-import.c +++ b/src/windows-import.c @@ -147,6 +147,11 @@ void windows_import(void) { if (hAdvapi32dll) { MDBX_IMPORT(hAdvapi32dll, RegGetValueA); } + + const HINSTANCE hOle32dll = GetModuleHandleA("ole32.dll"); + if (hOle32dll) { + MDBX_IMPORT(hOle32dll, CoCreateGuid); + } } #undef MDBX_IMPORT diff --git a/src/windows-import.h b/src/windows-import.h index 7a6c8789..b7c461f9 100644 --- a/src/windows-import.h +++ b/src/windows-import.h @@ -109,6 +109,8 @@ typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); +typedef long(WINAPI *MDBX_CoCreateGuid)(bin128_t *guid); + NTSYSAPI ULONG RtlRandomEx(PULONG Seed); typedef BOOL(WINAPI *MDBX_SetFileIoOverlappedRange)(HANDLE FileHandle, @@ -131,6 +133,7 @@ struct libmdbx_imports { MDBX_GetTickCount64 GetTickCount64; MDBX_RegGetValueA RegGetValueA; MDBX_SetFileIoOverlappedRange SetFileIoOverlappedRange; + MDBX_CoCreateGuid CoCreateGuid; }; MDBX_INTERNAL void windows_import(void);