mdbx: добавление UUID для идентификации БД.

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2024-07-06 10:46:42 +03:00
parent 319753661a
commit fe31958d46
13 changed files with 246 additions and 72 deletions

View File

@ -826,7 +826,7 @@ macro(libmdbx_setup_libs TARGET MODE)
target_link_libraries(${TARGET} ${MODE} Threads::Threads) target_link_libraries(${TARGET} ${MODE} Threads::Threads)
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") 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) if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_WITHOUT_MSVC_CRT)
target_link_libraries(${TARGET} ${MODE} ntdll_extra) target_link_libraries(${TARGET} ${MODE} ntdll_extra)
endif() endif()

5
mdbx.h
View File

@ -2745,6 +2745,11 @@ struct MDBX_envinfo {
uint64_t uint64_t
fsync; /**< Number of explicit fsync-to-disk operations (not a pages) */ fsync; /**< Number of explicit fsync-to-disk operations (not a pages) */
} mi_pgop_stat; } mi_pgop_stat;
/* GUID of the database DXB file. */
struct {
uint64_t x, y;
} mi_dxbid;
}; };
#ifndef __cplusplus #ifndef __cplusplus
/** \ingroup c_statinfo */ /** \ingroup c_statinfo */

View File

@ -727,6 +727,7 @@ static int env_info_snap(const MDBX_env *env, const MDBX_txn *txn,
troika_t *const troika) { troika_t *const troika) {
const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid); 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_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)) if (unlikely(env->flags & ENV_FATAL_ERROR))
return MDBX_PANIC; 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[0], &meta0->bootid, 16);
memcpy(&out->mi_bootid.meta[1], &meta1->bootid, 16); memcpy(&out->mi_bootid.meta[1], &meta1->bootid, 16);
memcpy(&out->mi_bootid.meta[2], &meta2->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; 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_bootid = offsetof(MDBX_envinfo, mi_bootid);
const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat); 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 && 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; return MDBX_EINVAL;
if (txn) { 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_bootid = offsetof(MDBX_envinfo, mi_bootid);
const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat); 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 && 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; return MDBX_EINVAL;
memset(out, 0, bytes); memset(out, 0, bytes);
@ -993,8 +998,11 @@ __cold int mdbx_preopen_snapinfoW(const wchar_t *pathname, MDBX_envinfo *out,
const unsigned n = 0; const unsigned n = 0;
out->mi_recent_txnid = constmeta_txnid(&header); out->mi_recent_txnid = constmeta_txnid(&header);
out->mi_meta_sign[n] = unaligned_peek_u64(4, &header.sign); 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); memcpy(&out->mi_bootid.meta[n], &header.bootid, 16);
if (likely(bytes > size_before_dxbid))
memcpy(&out->mi_dxbid, &header.dxbid, 16);
}
bailout: bailout:
env_close(&env, false); env_close(&env, false);

View File

@ -1590,13 +1590,23 @@ __cold static int env_chk(MDBX_chk_scope_t *const scope) {
return chk_error_rc(scope, err, "env_info"); return chk_error_rc(scope, err, "env_info");
MDBX_chk_line_t *line = 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) if (chk->envinfo.mi_bootid.current.x | chk->envinfo.mi_bootid.current.y)
line = chk_print(line, "%016" PRIx64 "-%016" PRIx64, line = chk_print(line, "%016" PRIx64 "-%016" PRIx64,
chk->envinfo.mi_bootid.current.x, chk->envinfo.mi_bootid.current.x,
chk->envinfo.mi_bootid.current.y); chk->envinfo.mi_bootid.current.y);
else else
line = chk_puts(line, "unavailable"); line = chk_puts(line, "is unavailable");
chk_line_end(line); chk_line_end(line);
err = osal_filesize(env->lazy_fd, &env->dxb_mmap.filesize); err = osal_filesize(env->lazy_fd, &env->dxb_mmap.filesize);

View File

@ -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 && if ((env->flags & MDBX_RDONLY) == 0 && env->stuck_meta < 0 &&
(globals.runtime_flags & MDBX_DBG_DONT_UPGRADE) == 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); meta_t *const meta = METAPAGE(env, n);
if (unlikely(unaligned_peek_u64(4, &meta->magic_and_version) != if (unlikely(unaligned_peek_u64(4, &meta->magic_and_version) !=
MDBX_DATA_MAGIC)) { MDBX_DATA_MAGIC) ||
const txnid_t txnid = constmeta_txnid(meta); (meta->dxbid.x | meta->dxbid.y) == 0) {
const txnid_t txnid =
meta_is_used(&troika, n) ? constmeta_txnid(meta) : 0;
NOTICE("%s %s" NOTICE("%s %s"
"meta[%u], txnid %" PRIaTXN, "meta[%u], txnid %" PRIaTXN,
"updating db-format signature for", "updating db-format/guid signature for",
meta_is_steady(meta) ? "stead-" : "weak-", n, txnid); meta_is_steady(meta) ? "stead-" : "weak-", n, txnid);
err = meta_override(env, n, txnid, meta); err = meta_override(env, n, txnid, meta);
if (unlikely(err != MDBX_SUCCESS) && if (unlikely(err != MDBX_SUCCESS) &&

View File

@ -91,15 +91,6 @@ typedef struct geo {
}; };
} geo_t; } 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. /* Meta page content.
* A meta page is the start point for accessing a database snapshot. * A meta page is the start point for accessing a database snapshot.
* Pages 0-2 are meta pages. */ * Pages 0-2 are meta pages. */
@ -158,6 +149,9 @@ typedef struct meta {
* steady sync point. Zeros mean that no relevant information is available * steady sync point. Zeros mean that no relevant information is available
* from the system. */ * from the system. */
bin128_t bootid; bin128_t bootid;
/* GUID базы данных, начиная с v0.13.1 */
bin128_t dxbid;
} meta_t; } meta_t;
#pragma pack(1) #pragma pack(1)

View File

@ -332,8 +332,8 @@ int meta_sync(const MDBX_env *env, const meta_ptr_t head) {
return rc; return rc;
} }
__cold static page_t *meta_model(const MDBX_env *env, page_t *model, __cold static page_t *meta_model(const MDBX_env *env, page_t *model, size_t num,
size_t num) { const bin128_t *guid) {
ENSURE(env, is_powerof2(env->ps)); ENSURE(env, is_powerof2(env->ps));
ENSURE(env, env->ps >= MDBX_MIN_PAGESIZE); ENSURE(env, env->ps >= MDBX_MIN_PAGESIZE);
ENSURE(env, env->ps <= MDBX_MAX_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.flags = MDBX_INTEGERKEY;
model_meta->trees.gc.root = P_INVALID; model_meta->trees.gc.root = P_INVALID;
model_meta->trees.main.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); meta_set_txnid(env, model_meta, MIN_TXNID + num);
unaligned_poke_u64(4, model_meta->sign, meta_sign_calculate(model_meta)); unaligned_poke_u64(4, model_meta->sign, meta_sign_calculate(model_meta));
eASSERT(env, coherency_check_meta(env, model_meta, true)); 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) { __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 *page0 = (page_t *)buffer;
page_t *page1 = meta_model(env, page0, 0); page_t *page1 = meta_model(env, page0, 0, &guid);
page_t *page2 = meta_model(env, page1, 1); page_t *page2 = meta_model(env, page1, 1, &guid);
meta_model(env, page2, 2); meta_model(env, page2, 2, &guid);
return page_meta(page2); 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)) if (unlikely(rc != MDBX_SUCCESS))
return rc; return rc;
page_t *const page = env->page_auxbuf; 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_t *const model = page_meta(page);
meta_set_txnid(env, model, txnid); meta_set_txnid(env, model, txnid);
if (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); meta_sign_as_steady(model);
rc = meta_validate(env, model, page, (pgno_t)target, nullptr); rc = meta_validate(env, model, page, (pgno_t)target, nullptr);
if (unlikely(MDBX_IS_ERROR(rc))) if (unlikely(MDBX_IS_ERROR(rc)))

View File

@ -83,7 +83,12 @@ static inline meta_ptr_t meta_tail(const MDBX_env *env,
return r; 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) { static inline bool meta_bootid_match(const meta_t *meta) {
return memcmp(&meta->bootid, &globals.bootid, 16) == 0 && return memcmp(&meta->bootid, &globals.bootid, 16) == 0 &&
(globals.bootid.x | globals.bootid.y) != 0; (globals.bootid.x | globals.bootid.y) != 0;
} }

View File

@ -2931,17 +2931,40 @@ __cold static void bootid_collect(bin128_t *p, const void *s, size_t n) {
bootid_shake(p); bootid_shake(p);
/* minor non-linear tomfoolery */ /* 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); p->y = p->y << z | p->y >> (64 - z);
bootid_shake(p); bootid_shake(p);
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); p->y = p->y << q | p->y >> (64 - q);
bootid_shake(p); bootid_shake(p);
bootid_shake(p); 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) #if defined(_WIN32) || defined(_WIN64)
__cold static uint64_t windows_systemtime_ms() { __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; s->y += aligned.y;
} else } else
bootid_collect(s, p, n); bootid_collect(s, p, n);
return true; return check_uuid(*s);
} }
if (n) if (n)
@ -3051,28 +3074,33 @@ bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
return false; 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) { __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; bool got_machineid = false, got_boottime = false, got_bootseq = false;
#if defined(__linux__) || defined(__gnu_linux__) #if defined(__linux__) || defined(__gnu_linux__)
{ if (proc_read_uuid("/proc/sys/kernel/random/boot_id", &uuid))
const int fd = return uuid;
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;
}
}
#endif /* Linux */ #endif /* Linux */
#if defined(__APPLE__) || defined(__MACH__) #if defined(__APPLE__) || defined(__MACH__)
@ -3080,16 +3108,15 @@ __cold static bin128_t osal_bootid(void) {
char buf[42]; char buf[42];
size_t len = sizeof(buf); size_t len = sizeof(buf);
if (!sysctlbyname("kern.bootsessionuuid", buf, &len, nullptr, 0) && if (!sysctlbyname("kern.bootsessionuuid", buf, &len, nullptr, 0) &&
bootid_parse_uuid(&bin, buf, len)) bootid_parse_uuid(&uuid, buf, len))
return bin; return uuid;
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \ #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
__MAC_OS_X_VERSION_MIN_REQUIRED > 1050 __MAC_OS_X_VERSION_MIN_REQUIRED > 1050
uuid_t uuid; uuid_t hostuuid;
struct timespec wait = {0, 1000000000u / 42}; struct timespec wait = {0, 1000000000u / 42};
if (!gethostuuid(uuid, &wait) && if (!gethostuuid(hostuuid, &wait))
bootid_parse_uuid(&bin, uuid, sizeof(uuid))) got_machineid = bootid_parse_uuid(&uuid, hostuuid, sizeof(hostuuid));
got_machineid = true;
#endif /* > 10.5 */ #endif /* > 10.5 */
struct timeval boottime; struct timeval boottime;
@ -3127,7 +3154,7 @@ __cold static bin128_t osal_bootid(void) {
"MachineGuid", &buf.MachineGuid, "MachineGuid", &buf.MachineGuid,
&len) == ERROR_SUCCESS && &len) == ERROR_SUCCESS &&
len < sizeof(buf)) len < sizeof(buf))
got_machineid = bootid_parse_uuid(&bin, &buf.MachineGuid, len); got_machineid = bootid_parse_uuid(&uuid, &buf.MachineGuid, len);
if (!got_machineid) { if (!got_machineid) {
/* again, Windows is madness */ /* again, Windows is madness */
@ -3145,7 +3172,7 @@ __cold static bin128_t osal_bootid(void) {
"DigitalProductId", &buf.DigitalProductId, "DigitalProductId", &buf.DigitalProductId,
&len) == ERROR_SUCCESS && &len) == ERROR_SUCCESS &&
len > 42 && len < sizeof(buf)) { len > 42 && len < sizeof(buf)) {
bootid_collect(&bin, &buf.DigitalProductId, len); bootid_collect(&uuid, &buf.DigitalProductId, len);
got_machineid = true; got_machineid = true;
} }
len = sizeof(buf); len = sizeof(buf);
@ -3153,7 +3180,7 @@ __cold static bin128_t osal_bootid(void) {
"DigitalProductId", &buf.DigitalProductId, "DigitalProductId", &buf.DigitalProductId,
&len) == ERROR_SUCCESS && &len) == ERROR_SUCCESS &&
len > 42 && len < sizeof(buf)) { len > 42 && len < sizeof(buf)) {
bootid_collect(&bin, &buf.DigitalProductId, len); bootid_collect(&uuid, &buf.DigitalProductId, len);
got_machineid = true; got_machineid = true;
} }
len = sizeof(buf); len = sizeof(buf);
@ -3161,7 +3188,7 @@ __cold static bin128_t osal_bootid(void) {
"DigitalProductId", &buf.DigitalProductId, "DigitalProductId", &buf.DigitalProductId,
&len) == ERROR_SUCCESS && &len) == ERROR_SUCCESS &&
len > 42 && len < sizeof(buf)) { len > 42 && len < sizeof(buf)) {
bootid_collect(&bin, &buf.DigitalProductId, len); bootid_collect(&uuid, &buf.DigitalProductId, len);
got_machineid = true; got_machineid = true;
} }
} }
@ -3173,7 +3200,7 @@ __cold static bin128_t osal_bootid(void) {
if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BootId", if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BootId",
&buf.BootId, &len) == ERROR_SUCCESS && &buf.BootId, &len) == ERROR_SUCCESS &&
len > 1 && len < sizeof(buf)) { len > 1 && len < sizeof(buf)) {
bootid_collect(&bin, &buf.BootId, len); bootid_collect(&uuid, &buf.BootId, len);
got_bootseq = true; got_bootseq = true;
} }
@ -3181,7 +3208,7 @@ __cold static bin128_t osal_bootid(void) {
if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BaseTime", if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_PrefetcherParams, "BaseTime",
&buf.BaseTime, &len) == ERROR_SUCCESS && &buf.BaseTime, &len) == ERROR_SUCCESS &&
len >= sizeof(buf.BaseTime) && buf.BaseTime) { len >= sizeof(buf.BaseTime) && buf.BaseTime) {
bootid_collect(&bin, &buf.BaseTime, len); bootid_collect(&uuid, &buf.BaseTime, len);
got_boottime = true; got_boottime = true;
} }
@ -3197,7 +3224,7 @@ __cold static bin128_t osal_bootid(void) {
buf.SysTimeOfDayInfoHacked.BootTime.QuadPart - buf.SysTimeOfDayInfoHacked.BootTime.QuadPart -
buf.SysTimeOfDayInfoHacked.BootTimeBias; buf.SysTimeOfDayInfoHacked.BootTimeBias;
if (UnbiasedBootTime) { if (UnbiasedBootTime) {
bootid_collect(&bin, &UnbiasedBootTime, sizeof(UnbiasedBootTime)); bootid_collect(&uuid, &UnbiasedBootTime, sizeof(UnbiasedBootTime));
got_boottime = true; got_boottime = true;
} }
} }
@ -3205,7 +3232,7 @@ __cold static bin128_t osal_bootid(void) {
if (!got_boottime) { if (!got_boottime) {
uint64_t boottime = windows_bootime(); uint64_t boottime = windows_bootime();
if (boottime) { if (boottime) {
bootid_collect(&bin, &boottime, sizeof(boottime)); bootid_collect(&uuid, &boottime, sizeof(boottime));
got_boottime = true; got_boottime = true;
} }
} }
@ -3223,7 +3250,7 @@ __cold static bin128_t osal_bootid(void) {
#endif #endif
mib, mib,
ARRAY_LENGTH(mib), &buf, &len, nullptr, 0) == 0) 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 */ #endif /* CTL_HW && HW_UUID */
@ -3238,7 +3265,7 @@ __cold static bin128_t osal_bootid(void) {
#endif #endif
mib, mib,
ARRAY_LENGTH(mib), &buf, &len, nullptr, 0) == 0) 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 */ #endif /* CTL_KERN && KERN_HOSTUUID */
@ -3247,7 +3274,7 @@ __cold static bin128_t osal_bootid(void) {
char buf[42]; char buf[42];
size_t len = sizeof(buf); size_t len = sizeof(buf);
if (sysctlbyname("machdep.dmi.system-uuid", buf, &len, nullptr, 0) == 0) 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__ */ #endif /* __NetBSD__ */
@ -3255,7 +3282,7 @@ __cold static bin128_t osal_bootid(void) {
if (!got_machineid) { if (!got_machineid) {
const int hostid = gethostid(); const int hostid = gethostid();
if (hostid > 0) { if (hostid > 0) {
bootid_collect(&bin, &hostid, sizeof(hostid)); bootid_collect(&uuid, &hostid, sizeof(hostid));
got_machineid = true; got_machineid = true;
} }
} }
@ -3263,8 +3290,8 @@ __cold static bin128_t osal_bootid(void) {
if (!got_machineid) { if (!got_machineid) {
lack: lack:
bin.x = bin.y = 0; uuid.x = uuid.y = 0;
return bin; return uuid;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@ -3281,7 +3308,7 @@ __cold static bin128_t osal_bootid(void) {
mib, mib,
ARRAY_LENGTH(mib), &boottime, &len, nullptr, 0) == 0 && ARRAY_LENGTH(mib), &boottime, &len, nullptr, 0) == 0 &&
len == sizeof(boottime) && boottime.tv_sec) { len == sizeof(boottime) && boottime.tv_sec) {
bootid_collect(&bin, &boottime, len); bootid_collect(&uuid, &boottime, len);
got_boottime = true; got_boottime = true;
} }
} }
@ -3298,11 +3325,11 @@ __cold static bin128_t osal_bootid(void) {
switch (kn->data_type) { switch (kn->data_type) {
case KSTAT_DATA_INT32: case KSTAT_DATA_INT32:
case KSTAT_DATA_UINT32: case KSTAT_DATA_UINT32:
bootid_collect(&bin, &kn->value, sizeof(int32_t)); bootid_collect(&uuid, &kn->value, sizeof(int32_t));
got_boottime = true; got_boottime = true;
case KSTAT_DATA_INT64: case KSTAT_DATA_INT64:
case KSTAT_DATA_UINT64: case KSTAT_DATA_UINT64:
bootid_collect(&bin, &kn->value, sizeof(int64_t)); bootid_collect(&uuid, &kn->value, sizeof(int64_t));
got_boottime = true; 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 id = {.ut_type = BOOT_TIME};
const struct utmpx *entry = getutxid(&id); const struct utmpx *entry = getutxid(&id);
if (entry) { if (entry) {
bootid_collect(&bin, entry, sizeof(*entry)); bootid_collect(&uuid, entry, sizeof(*entry));
got_boottime = true; got_boottime = true;
while (unlikely((entry = getutxid(&id)) != nullptr)) { while (unlikely((entry = getutxid(&id)) != nullptr)) {
/* have multiple reboot records, assuming we can distinguish next /* have multiple reboot records, assuming we can distinguish next
* bootsession even if RTC is wrong or absent */ * bootsession even if RTC is wrong or absent */
bootid_collect(&bin, entry, sizeof(*entry)); bootid_collect(&uuid, entry, sizeof(*entry));
got_bootseq = true; got_bootseq = true;
} }
} }
@ -3352,7 +3379,7 @@ __cold static bin128_t osal_bootid(void) {
goto lack; goto lack;
} }
return bin; return uuid;
} }
__cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages, __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; return MDBX_SUCCESS;
} }
/*----------------------------------------------------------------------------*/
#ifdef __FreeBSD__
#include <sys/uuid.h>
#endif /* FreeBSD */
#if __GLIBC_PREREQ(2, 25) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) || \
defined(__APPLE__) || __has_include(<sys/random.h>)
#include <sys/random.h>
#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) { void osal_ctor(void) {
#if MDBX_HAVE_PWRITEV && defined(_SC_IOV_MAX) #if MDBX_HAVE_PWRITEV && defined(_SC_IOV_MAX)
osal_iov_max = sysconf(_SC_IOV_MAX); osal_iov_max = sysconf(_SC_IOV_MAX);

View File

@ -576,6 +576,17 @@ MDBX_INTERNAL void osal_dtor(void);
MDBX_INTERNAL int osal_mb2w(const char *const src, wchar_t **const pdst); MDBX_INTERNAL int osal_mb2w(const char *const src, wchar_t **const pdst);
#endif /* Windows */ #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 MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static inline uint64_t

View File

@ -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.gc = txn->dbs[FREE_DBI];
meta.trees.main = txn->dbs[MAIN_DBI]; meta.trees.main = txn->dbs[MAIN_DBI];
meta.canary = txn->canary; meta.canary = txn->canary;
memcpy(&meta.dxbid, &head.ptr_c->dxbid, sizeof(meta.dxbid));
txnid_t commit_txnid = txn->txnid; txnid_t commit_txnid = txn->txnid;
#if MDBX_ENABLE_BIGFOOT #if MDBX_ENABLE_BIGFOOT

View File

@ -147,6 +147,11 @@ void windows_import(void) {
if (hAdvapi32dll) { if (hAdvapi32dll) {
MDBX_IMPORT(hAdvapi32dll, RegGetValueA); MDBX_IMPORT(hAdvapi32dll, RegGetValueA);
} }
const HINSTANCE hOle32dll = GetModuleHandleA("ole32.dll");
if (hOle32dll) {
MDBX_IMPORT(hOle32dll, CoCreateGuid);
}
} }
#undef MDBX_IMPORT #undef MDBX_IMPORT

View File

@ -109,6 +109,8 @@ typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
LPDWORD pdwType, PVOID pvData, LPDWORD pdwType, PVOID pvData,
LPDWORD pcbData); LPDWORD pcbData);
typedef long(WINAPI *MDBX_CoCreateGuid)(bin128_t *guid);
NTSYSAPI ULONG RtlRandomEx(PULONG Seed); NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
typedef BOOL(WINAPI *MDBX_SetFileIoOverlappedRange)(HANDLE FileHandle, typedef BOOL(WINAPI *MDBX_SetFileIoOverlappedRange)(HANDLE FileHandle,
@ -131,6 +133,7 @@ struct libmdbx_imports {
MDBX_GetTickCount64 GetTickCount64; MDBX_GetTickCount64 GetTickCount64;
MDBX_RegGetValueA RegGetValueA; MDBX_RegGetValueA RegGetValueA;
MDBX_SetFileIoOverlappedRange SetFileIoOverlappedRange; MDBX_SetFileIoOverlappedRange SetFileIoOverlappedRange;
MDBX_CoCreateGuid CoCreateGuid;
}; };
MDBX_INTERNAL void windows_import(void); MDBX_INTERNAL void windows_import(void);