diff --git a/3rdparty/crc32c_adler/crc32c_adler.c b/3rdparty/crc32c_adler/crc32c_adler.c
index 72542222b5430ee0feafa0544f7c9dd72eb0966b..ce23887e4fd1ad28466fd57f84ca559d8a4b6523 100755
--- a/3rdparty/crc32c_adler/crc32c_adler.c
+++ b/3rdparty/crc32c_adler/crc32c_adler.c
@@ -499,7 +499,7 @@ uint32_t crc32c(uint32_t crc, const void *buf, size_t len)
 {
 #if defined(__x86_64__)                 /* @RRL: to compile for ARM */
     return crc32c_hw_support() ? crc32c_hw(crc, buf, len) : crc32c_sw(crc, buf, len);
-#elif
+#else
     return crc32c_sw(crc, buf, len);
 #endif
 }
diff --git a/3rdparty/cuttdb/CMakeLists.txt b/3rdparty/cuttdb/CMakeLists.txt
deleted file mode 100755
index 2fb2bf49fcd21fd80fb7fa7f79a133ffcb2775fc..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/CMakeLists.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-project(dap_cuttdb C)
-
-add_definitions ("-D_GNU_SOURCE")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
-
-file(GLOB cuttdb_src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.c)
-file(GLOB cuttdb_h RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.h)
-list(APPEND cuttdb_src ${cuttdb_h})
-
-# the server part ain't ported, and thus not built, so are tests.
-list(FILTER cuttdb_src EXCLUDE REGEX "ae_")
-list(FILTER cuttdb_src EXCLUDE REGEX "server.")
-list(FILTER cuttdb_src EXCLUDE REGEX "dump.")
-list(FILTER cuttdb_src EXCLUDE REGEX "builddb.")
-list(FILTER cuttdb_src EXCLUDE REGEX "test_mt.")
-
-if(UNIX)
-   list(FILTER cuttdb_src EXCLUDE REGEX "mman.")
-endif()
-
-add_library(${PROJECT_NAME} STATIC ${cuttdb_src})
-set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
-set_target_properties(${PROJECT_NAME} PROPERTIES COMPILER_LANGUAGE C)
-target_include_directories(${PROJECT_NAME} INTERFACE src)
-target_compile_options(${PROJECT_NAME} PRIVATE -Wno-sign-compare)
diff --git a/3rdparty/cuttdb/src/ae_epoll.c b/3rdparty/cuttdb/src/ae_epoll.c
deleted file mode 100644
index ff8591d86c3d7962c1b01e6ad51b09144ba74f04..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/ae_epoll.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Linux epoll(2) based ae.c module
- * Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
- * Released under the BSD license. See the COPYING file for more info. */
-
-#include <sys/epoll.h>
-#include <errno.h>
-
-typedef struct aeApiState {
-    int epfd;
-    struct epoll_event events[AE_SETSIZE];
-} aeApiState;
-
-static int aeApiCreate(EventLoop *eventLoop) {
-    aeApiState *state = malloc(sizeof(aeApiState));
-
-    if (!state) return -1;
-    state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */
-    if (state->epfd == -1) return -1;
-    eventLoop->apidata = state;
-    return 0;
-}
-
-/*
-    be not referenced anywhere
-static void aeApiFree(EventLoop *eventLoop) {
-    aeApiState *state = eventLoop->apidata;
-
-    close(state->epfd);
-    free(state);
-}
-*/
-
-static int aeApiAddEvent(EventLoop *eventLoop, int fd, int mask) {
-    aeApiState *state = eventLoop->apidata;
-    struct epoll_event ee;
-    ee.events = EPOLLONESHOT;
-    if (mask & AE_READABLE) ee.events |= EPOLLIN;
-    if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
-    ee.data.u64 = 0; /* avoid valgrind warning */
-    ee.data.fd = fd;
-    if (epoll_ctl(state->epfd, EPOLL_CTL_ADD,fd,&ee) == -1 && errno != EEXIST) {
-        fprintf(stderr, "epoll_ctl(%d,%d) failed: %d\n", EPOLL_CTL_ADD,fd,errno);
-        return -1;
-    }
-    return 0;
-}
-
-static int aeApiUpdateEvent(EventLoop *eventLoop, int fd, int mask) {
-    aeApiState *state = eventLoop->apidata;
-    struct epoll_event ee;
-    ee.events = EPOLLONESHOT;
-    if (mask & AE_READABLE) ee.events |= EPOLLIN;
-    if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
-    ee.data.u64 = 0; /* avoid valgrind warning */
-    ee.data.fd = fd;
-    if (epoll_ctl(state->epfd, EPOLL_CTL_MOD,fd,&ee) == -1) {
-        fprintf(stderr, "epoll_ctl(%d,%d) failed: %d\n", EPOLL_CTL_ADD,fd,errno);
-        return -1;
-    }
-    return 0;
-}
-
-static int aeApiDelEvent(EventLoop *eventLoop, int fd) {
-    aeApiState *state = eventLoop->apidata;
-    struct epoll_event ee;
-
-    ee.events = 0;
-    ee.data.u64 = 0; /* avoid valgrind warning */
-    ee.data.fd = fd;
-    /* Note, Kernel < 2.6.9 requires a non null event pointer even for
-     * EPOLL_CTL_DEL. */
-    if ( epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee) == -1 
-            && errno != ENOENT && errno != EBADF) {
-        fprintf(stderr, "epoll_ctl(%d,%d) failed: %d\n", EPOLL_CTL_DEL,fd,errno);
-        return -1;
-    }
-    return 0;
-}
-
-int aeApiPoll(EventLoop *eventLoop, struct timeval *tvp) {
-    aeApiState *state = eventLoop->apidata;
-    int retval, numevents = 0;
-
-    retval = epoll_wait(state->epfd,state->events,AE_SETSIZE,
-            tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
-    if (retval > 0) {
-        int j;
-
-        numevents = retval;
-        for (j = 0; j < numevents; j++) {
-            int mask = 0;
-            struct epoll_event *e = state->events+j;
-
-            if (e->events & EPOLLIN) mask |= AE_READABLE;
-            if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
-            eventLoop->fired[j] = e->data.fd;
-        }
-    }
-    return numevents;
-}
-
-
-/*
-    be not referenced anywhere
-static char *aeApiName(void) {
-    return "epoll";
-}
-*/
-
diff --git a/3rdparty/cuttdb/src/ae_kqueue.c b/3rdparty/cuttdb/src/ae_kqueue.c
deleted file mode 100644
index cd80a57be2d19d485f2a2ce3485b42494ba43640..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/ae_kqueue.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Kqueue(2)-based ae.c module
- * Copyright (C) 2009 Harish Mallipeddi - harish.mallipeddi@gmail.com
- * Released under the BSD license. See the COPYING file for more info. */
-
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-
-typedef struct aeApiState {
-    int kqfd;
-    struct kevent events[AE_SETSIZE];
-} aeApiState;
-
-static int aeApiCreate(EventLoop *eventLoop) {
-    aeApiState *state = malloc(sizeof(aeApiState));
-
-    if (!state) return -1;
-    state->kqfd = kqueue();
-    if (state->kqfd == -1) return -1;
-    eventLoop->apidata = state;
-    
-    return 0;    
-}
-
-static void aeApiFree(EventLoop *eventLoop) {
-    aeApiState *state = eventLoop->apidata;
-
-    close(state->kqfd);
-    free(state);
-}
-
-static int aeApiAddEvent(EventLoop *eventLoop, int fd, int mask) {
-    aeApiState *state = eventLoop->apidata;
-    struct kevent ke;
-    
-    if (mask & AE_READABLE) {
-        EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
-        if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1;
-    }
-    if (mask & AE_WRITABLE) {
-        EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
-        if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1;
-    }
-    return 0;
-}
-
-static int aeApiUpdateEvent(EventLoop *eventLoop, int fd, int mask) {
-    return aeApiAddEvent(eventLoop, fd, mask);
-}
-
-static int aeApiDelEvent(EventLoop *eventLoop, int fd) {
-    aeApiState *state = eventLoop->apidata;
-    struct kevent ke;
-
-    EV_SET(&ke, fd, EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
-    kevent(state->kqfd, &ke, 1, NULL, 0, NULL);
-    return 0;
-}
-
-static int aeApiPoll(EventLoop *eventLoop, struct timeval *tvp) {
-    aeApiState *state = eventLoop->apidata;
-    int retval, numevents = 0;
-
-    if (tvp != NULL) {
-        struct timespec timeout;
-        timeout.tv_sec = tvp->tv_sec;
-        timeout.tv_nsec = tvp->tv_usec * 1000;
-        retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, &timeout);
-    } else {
-        retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, NULL);
-    }    
-
-    if (retval > 0) {
-        int j;
-        
-        numevents = retval;
-        for(j = 0; j < numevents; j++) {
-            int mask = 0;
-            struct kevent *e = state->events+j;
-            
-            if (e->filter == EVFILT_READ) mask |= AE_READABLE;
-            if (e->filter == EVFILT_WRITE) mask |= AE_WRITABLE;
-            eventLoop->fired[j] = e->ident; 
-        }
-    }
-    return numevents;
-}
-
-static char *aeApiName(void) {
-    return "kqueue";
-}
diff --git a/3rdparty/cuttdb/src/ae_select.c b/3rdparty/cuttdb/src/ae_select.c
deleted file mode 100644
index 1e5d3ae91aa886a4b086ff07c28b9e10045ea292..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/ae_select.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Select()-based ae.c module
- * Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
- * Released under the BSD license. See the COPYING file for more info. */
-
-#include <string.h>
-
-typedef struct aeApiState {
-    fd_set rfds, wfds;
-    /* We need to have a copy of the fd sets as it's not safe to reuse
-     * FD sets after select(). */
-    fd_set _rfds, _wfds;
-} aeApiState;
-
-static int aeApiCreate(EventLoop *eventLoop) {
-    aeApiState *state = malloc(sizeof(aeApiState));
-
-    if (!state) return -1;
-    FD_ZERO(&state->rfds);
-    FD_ZERO(&state->wfds);
-    eventLoop->apidata = state;
-    return 0;
-}
-
-static void aeApiFree(EventLoop *eventLoop) {
-    free(eventLoop->apidata);
-}
-
-static int aeApiAddEvent(EventLoop *eventLoop, int fd, int mask) {
-    aeApiState *state = eventLoop->apidata;
-
-    if (mask & AE_READABLE) FD_SET(fd,&state->rfds);
-    if (mask & AE_WRITABLE) FD_SET(fd,&state->wfds);
-    return 0;
-}
-
-static void aeApiDelEvent(EventLoop *eventLoop, int fd, int mask) {
-    aeApiState *state = eventLoop->apidata;
-
-    if (mask & AE_READABLE) FD_CLR(fd,&state->rfds);
-    if (mask & AE_WRITABLE) FD_CLR(fd,&state->wfds);
-}
-
-static int aeApiPoll(EventLoop *eventLoop, struct timeval *tvp) {
-    aeApiState *state = eventLoop->apidata;
-    int retval, j, numevents = 0;
-
-    memcpy(&state->_rfds,&state->rfds,sizeof(fd_set));
-    memcpy(&state->_wfds,&state->wfds,sizeof(fd_set));
-
-    retval = select(eventLoop->maxfd+1,
-                &state->_rfds,&state->_wfds,NULL,tvp);
-    if (retval > 0) {
-        for (j = 0; j <= eventLoop->maxfd; j++) {
-            int mask = 0;
-            aeFileEvent *fe = &eventLoop->events[j];
-
-            if (fe->mask == AE_NONE) continue;
-            if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds))
-                mask |= AE_READABLE;
-            if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds))
-                mask |= AE_WRITABLE;
-            eventLoop->fired[numevents].fd = j;
-            eventLoop->fired[numevents].mask = mask;
-            numevents++;
-        }
-    }
-    return numevents;
-}
-
-static char *aeApiName(void) {
-    return "select";
-}
diff --git a/3rdparty/cuttdb/src/cdb_bgtask.c b/3rdparty/cuttdb/src/cdb_bgtask.c
deleted file mode 100644
index d12bd26e6c3b35e61e97aab1f2be49b10ea9cd80..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_bgtask.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cdb_bgtask.h"
-#include <stdlib.h>
-#include <errno.h>
-#include <signal.h>
-
-/* where thread begins */
-static void *_cdb_bgtask_func(void *arg);
-
-
-CDBBGTASK *cdb_bgtask_new()
-{
-    CDBBGTASK *bt = (CDBBGTASK *)malloc(sizeof(CDBBGTASK));
-
-    bt->tnum = 0;
-    bt->run = 0;
-    bt->tid = 0;
-    pthread_cond_init(&bt->scond, NULL);
-    pthread_mutex_init(&bt->smutex, NULL);
-    return bt;
-}
-
-
-/* add a task into task list, must called before the thread run */
-int cdb_bgtask_add(CDBBGTASK *bt, TASKFUNC func, void *arg, int intval)
-{
-    TASK *task = &bt->tasks[bt->tnum];
-
-    if (bt->tid || bt->tnum > MAXTASKNUM)
-        return -1;
-
-    task->arg = arg;
-    task->func = func;
-    task->intval = intval;
-    task->ltime = time(NULL);
-    bt->tnum++;
-    return 0;
-}
-
-
-static void *_cdb_bgtask_func(void *arg)
-{
-    CDBBGTASK *bt = (CDBBGTASK *)arg;
-#ifndef _WIN32
-    /* block all signals coming into current thread */
-    sigset_t smask;
-    sigfillset(&smask);
-    pthread_sigmask(SIG_BLOCK, &smask, NULL);
-#endif
-    /* loop */
-    while(bt->run) {
-        time_t now = time(NULL);
-        struct timespec timeout;
-        int l_cond_rc;
-
-        /* check should run some tasks every 1 second */
-        timeout.tv_sec = now + 1;
-        timeout.tv_nsec = 0;
-
-        /* iterate and run the tasks */
-        for(int i = 0; i < bt->tnum; i++) {
-            TASK *task = &bt->tasks[i];
-            if (now >= task->ltime + task->intval) {
-                task->func(task->arg);
-                task->ltime = now;
-            }
-        }
-        pthread_mutex_lock(&bt->smutex);
-        l_cond_rc = pthread_cond_timedwait(&bt->scond, &bt->smutex, &timeout);
-        pthread_mutex_unlock(&bt->smutex);
-    }
-
-    return NULL;
-}
-
-
-/* create a thread for tasks */
-void cdb_bgtask_start(CDBBGTASK *bt)
-{
-    if (bt->run)
-        return;
-
-    bt->run = 1;
-    pthread_create(&bt->tid, NULL, _cdb_bgtask_func, bt);
-    return;
-}
-
-
-/* wait for the task thread exits */
-void cdb_bgtask_stop(CDBBGTASK *bt)
-{
-    if (bt->run) {
-        void **ret = NULL;
-        bt->run = 0;
-        pthread_cond_signal(&bt->scond);
-        pthread_join(bt->tid, ret);
-    }
-
-    bt->tnum = 0;
-}
-
-
-void cdb_bgtask_destroy(CDBBGTASK *bt)
-{
-    cdb_bgtask_stop(bt);
-    pthread_cond_destroy(&bt->scond);
-    pthread_mutex_destroy(&bt->smutex);
-    free(bt);
-}
-
-
-
-
diff --git a/3rdparty/cuttdb/src/cdb_bgtask.h b/3rdparty/cuttdb/src/cdb_bgtask.h
deleted file mode 100644
index 6dee1b992d21bac8a496e7f8f89431c570b9358a..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_bgtask.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_BGTASK_H_
-#define _CDB_BGTASK_H_
-#include <time.h>
-#include <pthread.h>
-
-
-/* 16 tasks at most in a task thread */
-#define MAXTASKNUM 16
-
-typedef void (*TASKFUNC)(void *);
-
-/* struct for timer task */
-typedef struct {
-    /* task function */
-    TASKFUNC func;
-    /* task argument */
-    void *arg;
-    /* task run interval(seconds) */
-    int intval;
-    /* time of last run */
-    time_t ltime;
-} TASK;
-
-/* struct for a background task manager */
-typedef struct CDBBGTASK
-{
-    TASK tasks[MAXTASKNUM];
-    /* number of tasks */
-    int tnum;
-    /* is running? */
-    int run;
-    pthread_t tid;
-    /* for wait the thread exit */
-    pthread_mutex_t smutex;
-    pthread_cond_t scond;
-} CDBBGTASK;
-
-
-
-CDBBGTASK *cdb_bgtask_new();
-int cdb_bgtask_add(CDBBGTASK *task, TASKFUNC func, void *arg, int intval);
-void cdb_bgtask_start(CDBBGTASK *bt);
-void cdb_bgtask_stop(CDBBGTASK *task);
-void cdb_bgtask_destroy(CDBBGTASK *task);
-
-
-#endif
diff --git a/3rdparty/cuttdb/src/cdb_bloomfilter.c b/3rdparty/cuttdb/src/cdb_bloomfilter.c
deleted file mode 100644
index ebf5e2d3e8b508a20985b76bd6a1e974a89c9daf..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_bloomfilter.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cdb_bloomfilter.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define CDBBFHASHNUM 16
-#define CDBBFSPLITPOW 6
-
-static uint64_t BFSEEDS[CDBBFHASHNUM] = {217636919,290182597,386910137,515880193,
-                                        687840301,917120411,1222827239,1610612741,
-                                        3300450239,3300450259,3300450281,3300450289,
-                                        3221225473ul,4294967291ul,163227661,122420729,};
-
-struct CDBBLOOMFILTER
-{
-    uint8_t *bitmap[1<<CDBBFSPLITPOW];
-    uint64_t rnum;
-    uint64_t size;
-    int hnum;
-    int ratio;
-};
-
-
-CDBBLOOMFILTER *cdb_bf_new(uint64_t rnum, uint64_t size)
-{
-    CDBBLOOMFILTER *bf = (CDBBLOOMFILTER *)malloc(sizeof(CDBBLOOMFILTER));
-    bf->rnum = 0;
-    bf->size = size;
-    /* number of hash should be 0.7 * ratio */
-    bf->hnum = size * 8 * 7 / (rnum * 10);
-    /* number of hash is limit in [1, 16] */
-    if (bf->hnum > CDBBFHASHNUM)
-        bf->hnum = CDBBFHASHNUM;
-    if (bf->hnum == 0)
-        bf->hnum = 1;
-    /* avoid malloc too much memory once */
-    for(int i = 0; i < (1 << CDBBFSPLITPOW); i++) {
-        bf->bitmap[i] = (uint8_t*)malloc(size >> CDBBFSPLITPOW);
-        memset(bf->bitmap[i], 0, size >> CDBBFSPLITPOW);
-    }
-    return bf;
-}
-
-
-void cdb_bf_set(CDBBLOOMFILTER *bf, void *key, int ksize)
-{
-    uint8_t *src = (uint8_t *)key, *end = src + ksize;
-    uint64_t hval[CDBBFHASHNUM] = {0};
-
-    for(;src < end; src++) 
-        for(int i = 0; i < bf->hnum; i++) 
-            hval[i] = hval[i] * BFSEEDS[i] + *src;
-
-    for(int i = 0; i < bf->hnum; i++) {
-        uint64_t p = (hval[i] >> CDBBFSPLITPOW) % ((bf->size >> CDBBFSPLITPOW) << 3);
-        uint8_t *bitmap = bf->bitmap[hval[i] & ((1<<CDBBFSPLITPOW) - 1)];
-        bitmap[p >> 3] |= (1 << (p & 0x07));
-    }
-
-    bf->rnum++;
-}
-
-
-bool cdb_bf_exist(CDBBLOOMFILTER *bf, void *key, int ksize)
-{
-    uint8_t *src = (uint8_t *)key, *end = src + ksize;
-    uint64_t hval[CDBBFHASHNUM] = {0};
-    int exist = 0;
-
-    for(;src < end; src++) 
-        for(int i = 0; i < bf->hnum; i++) 
-            hval[i] = hval[i] * BFSEEDS[i] + *src;
-
-    for(int i = 0; i < bf->hnum; i++) {
-        uint64_t p = (hval[i] >> CDBBFSPLITPOW) % ((bf->size >> CDBBFSPLITPOW) << 3);
-        uint8_t *bitmap = bf->bitmap[hval[i] & ((1<<CDBBFSPLITPOW) - 1)];
-        if (bitmap[p >> 3] & (1 << (p & 0x07)))
-            exist++;
-        else 
-            break;
-    }
-
-    return (exist == bf->hnum);
-}
-
-void cdb_bf_clean(CDBBLOOMFILTER *bf)
-{
-    for(int i = 0; i < (1 << CDBBFSPLITPOW); i++) 
-        memset(bf->bitmap[i], 0, bf->size >> CDBBFSPLITPOW);
-
-    bf->rnum = 0;
-}
-
-
-void cdb_bf_destroy(CDBBLOOMFILTER *bf)
-{
-    for(int i = 0; i < (1 << CDBBFSPLITPOW); i++) 
-        free(bf->bitmap[i]);
-    free(bf);
-}
-
-
-#ifdef _UT_CDBBF_
-#include <stdio.h>
-#include <stdlib.h>
-#include "cdb_bloomfilter.h"
-
-int main(int argc, char *argv[])
-{
-    int size = 1048576;
-    int rnum = 1048576;
-    if (argc > 1)
-        rnum = atoi(argv[1]);
-    if (argc > 2)
-        size = atoi(argv[2]);
-
-    CDBBLOOMFILTER *bf = cdb_bf_new(rnum, size);
-    for(int i = 0; i < rnum; i++) {
-        int j = 2 * i;
-        cdb_bf_set(bf, &j, 4);
-    }
-
-    int exist = 0;
-    for(int i = 0; i < rnum; i++) {
-        int j = 2 * i;
-        if (cdb_bf_exist(bf, &j, 4))
-            exist++;
-    }
-    printf("right positive: %.2f%%%%\n", (float)exist/(float)rnum*10000);
-
-    exist = 0;
-    for(int i = 0; i < rnum * 2; i++) {
-        int j = 2 * i + 1;
-        if (cdb_bf_exist(bf, &j, 4))
-            exist++;
-    }
-
-    printf("false positive: %.2f%%%%  %d/%d\n", (float)exist/(float)rnum*5000, exist, rnum * 2);
-    printf("element num: %d\n", bf->rnum);
-    cdb_bf_destroy(bf);
-    return 0;
-}
-#endif
-
diff --git a/3rdparty/cuttdb/src/cdb_bloomfilter.h b/3rdparty/cuttdb/src/cdb_bloomfilter.h
deleted file mode 100644
index 6ccdab1fccc1d92d843f072046550741a5cdaf37..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_bloomfilter.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-/*
-Bloom Filter is currently not used in cuttdb
-*/
-#ifndef _CDB_BLOOMFILTER_H_
-#define _CDB_BLOOMFILTER_H_
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef struct CDBBLOOMFILTER CDBBLOOMFILTER;
-
-#define CDBBFRATIO 8
-
-CDBBLOOMFILTER *cdb_bf_new(uint64_t rnum, uint64_t size);
-void cdb_bf_set(CDBBLOOMFILTER *bf, void *key, int ksize);
-bool cdb_bf_exist(CDBBLOOMFILTER *bf, void *key, int ksize);
-void cdb_bf_clean(CDBBLOOMFILTER *bf);
-void cdb_bf_destroy(CDBBLOOMFILTER *bf);
-
-#endif
diff --git a/3rdparty/cuttdb/src/cdb_builddb.c b/3rdparty/cuttdb/src/cdb_builddb.c
deleted file mode 100644
index fc5f18dc68c9dbd78de89441d88ada791a8b97a5..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_builddb.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-#include "cuttdb.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <time.h>
-
-int main(int argc, char *argv[])
-{
-    CDB *db = cdb_new();
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s db_path [hsize = 2000000]\n", argv[0]);
-        return 0;
-    }
-        
-    /* 1TB memory limit(unlimited) */
-    cdb_option(db, argc >= 3? atoi(argv[2]):2000000 , 0, 1048576);
-    cdb_seterrcb(db, cdb_deferrorcb, NULL);
-    if (cdb_open(db, argv[1], CDB_CREAT | CDB_PAGEWARMUP) < 0) {
-        return -1;
-    }
-    char *buf = NULL;
-    long count = 0;
-
-    size_t size, size2;
-    while((size = getline(&buf, &size2, stdin)) != -1) {
-        /* remove the delimiter*/
-        buf[--size] = '\0';
-        int klen = -1;
-        int vlen = -1;
-        uint32_t expire = 0;
-        int parsenum = 0;
-        for(int i = 0; i < size; i++) {
-            if (buf[i] == '\t') {
-                if (klen == -1)
-                    klen = i;
-                else {
-                    vlen = i - klen - 1;
-                    parsenum = 1;
-                }
-            } else if (buf[i] >= '0' && buf[i] <= '9' && parsenum) {
-                expire = expire * 10 + buf[i] - '0';
-            }
-        }
-
-        if (klen > 0 && vlen > 0) {
-            cdb_set2(db, buf, klen, buf + klen + 1, vlen,
-                    CDB_OVERWRITE, expire > 0? expire - time(NULL): 0);
-            count++;
-        }
-        free(buf);
-        buf = NULL;
-    }
-    cdb_destroy(db);
-    fprintf(stderr, "imported %ld records\n", count);
-    return 0;
-}
-
-
diff --git a/3rdparty/cuttdb/src/cdb_core.c b/3rdparty/cuttdb/src/cdb_core.c
deleted file mode 100644
index 75aabebe36dd7a12e0101d14a2229e0824d4ee64..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_core.c
+++ /dev/null
@@ -1,1457 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cuttdb.h"
-#include "cdb_crc64.h"
-#include "cdb_types.h"
-#include "cdb_hashtable.h"
-#include "cdb_bloomfilter.h"
-#include "cdb_lock.h"
-#include "cdb_bgtask.h"
-#include "cdb_errno.h"
-#include "cdb_vio.h"
-#include "cdb_core.h"
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <pthread.h>
-
-static void _cdb_pageout(CDB *db);
-static void _cdb_defparam(CDB *db);
-static void _cdb_recout(CDB *db);
-static uint32_t _pagehash(const void *key, int len);
-static void _cdb_flushdpagetask(void *arg);
-static void _cdb_timerreset(struct timespec *ts);
-static uint32_t _cdb_timermicrosec(struct timespec *ts);
-static void _cdb_pagewarmup(CDB *db, bool loadbf);
-
-
-/* it isn't necessary to rehash bid in hash table cache */
-static uint32_t _pagehash(const void *key, int len)
-{
-    uint32_t tst = 0;
-    if (len < tst)
-        return 0;
-    (void) len;
-    return *(uint32_t*)key;
-}
-
-
-/* used to get the duration of a procedure */
-static void _cdb_timerreset(struct timespec *ts)
-{
-    clock_gettime(CLOCK_MONOTONIC, ts);
-}
-
-
-static uint32_t _cdb_timermicrosec(struct timespec *ts)
-{
-    struct timespec ts2;
-    uint32_t diff;
-    clock_gettime(CLOCK_MONOTONIC, &ts2);
-    diff = (ts2.tv_sec - ts->tv_sec) * 1000000;
-    diff += ts2.tv_nsec / 1000;
-    diff -= ts->tv_nsec / 1000;
-    return diff;
-}
-
-
-/* reset the parameters */
-static void _cdb_defparam(CDB *db)
-{
-    db->rnum = 0;
-    db->bfsize = 0;
-    db->rclimit = 128 * MB;
-    db->pclimit = 1024 * MB;
-    db->hsize = 1000000; 
-    db->rcache = db->pcache = db->dpcache = NULL;
-    db->bf = NULL;
-    db->opened = false;
-    db->vio = NULL;
-    db->mtable = NULL;
-    db->oid = 0;
-    db->roid = 0;
-    db->errcbarg = NULL;
-    db->errcb = NULL;
-    db->areadsize = 4 * KB;
-    return;
-}
-
-
-/* flush all dirty pages */
-void cdb_flushalldpage(CDB *db)
-{
-    if (db->dpcache) {
-        while (db->dpcache->num) {
-            CDBHTITEM *item = cdb_ht_poptail(db->dpcache);    
-            uint32_t bid = *(uint32_t*)cdb_ht_itemkey(db->dpcache, item);
-            FOFF off;
-            db->vio->wpage(db->vio, (CDBPAGE*)cdb_ht_itemval(db->dpcache, item), &off);
-            db->mtable[bid] = off;
-            free(item);
-        } 
-
-        db->roid = db->oid; 
-        db->vio->cleanpoint(db->vio);
-    }
-}
-
-
-/* flush oldest dirty index page to disk, it runs in another thread and triggered by timer */
-static void _cdb_flushdpagetask(void *arg)
-{
-    CDB *db = (CDB *)arg;
-    CDBHTITEM *item;
-    CDBPAGE *page;
-    time_t now = time(NULL);
-    bool cleandcache = false;
-    uint32_t bid;
-
-    if (!db->dpcache)
-        /* no dirty page cache */
-        return;
-
-    /* if there isn't too much dirty page and some time passed since last clean,
-     write out all dirty pages to make a recovery point(oid) */
-    if (db->dpcache->num < 1024 && now > db->ndpltime + 120)
-        cleandcache = true;
-        
-    while(db->dpcache->num) {
-        FOFF off;
-        cdb_lock_lock(db->dpclock);
-        item = cdb_ht_gettail(db->dpcache);
-        /* no item in dpcache after lock */
-        if (item == NULL) {
-            cdb_lock_unlock(db->dpclock);
-            return;
-        }
-        page = (CDBPAGE *)cdb_ht_itemval(db->dpcache, item);
-        /* bid = page->bid; also OK */
-        bid = *(uint32_t*)cdb_ht_itemkey(db->dpcache, item);
-        /* been dirty for too long? */
-        if (now > page->mtime + DPAGETIMEOUT || cleandcache) {
-            if (cdb_lock_trylock(db->mlock[page->bid % MLOCKNUM])) {
-                /* avoid dead lock, since dpclock is holding */
-                cdb_lock_unlock(db->dpclock);
-                return;
-            }
-            /* remove it from dpcache */
-            cdb_ht_poptail(db->dpcache);
-            cdb_lock_unlock(db->dpclock);
-
-            /* write to disk */
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            db->vio->wpage(db->vio, page, &off);
-            db->wcount++;
-            db->wtime += _cdb_timermicrosec(&ts);
-            db->mtable[bid] = off;
-
-            /* move the clean page into pcache */
-            cdb_lock_lock(db->pclock);
-            cdb_ht_insert(db->pcache, item);
-            cdb_lock_unlock(db->pclock);
-            cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-        } else {
-            /* tail in dpcache isn't expired */
-            cdb_lock_unlock(db->dpclock);
-            return;
-        }
-    }
-
-    if (db->dpcache->num == 0 && cleandcache)
-        db->ndpltime = now;
-
-    if (cleandcache) {
-        /* clean succeed if goes here, remember the recovery point */
-        /* it's not necessary to lock */
-        db->roid = db->oid; 
-        db->vio->cleanpoint(db->vio);
-    }
-}
-
-
-/* fill the index page cache, and set the bloomfilter if necessary */
-static void _cdb_pagewarmup(CDB *db, bool loadbf)
-{
-    char sbuf[SBUFSIZE];
-    void *it = db->vio->pageitfirst(db->vio, 0);
-
-    if (it == NULL)
-        return;
-
-    for(;;) {
-        CDBPAGE *page = (CDBPAGE *)sbuf;
-        if (db->vio->pageitnext(db->vio, &page, it) < 0)
-            break;
-
-        /* the page is the newest one because its offset matches the one in main table */
-        if (OFFEQ(page->ooff, db->mtable[page->bid])) {
-            if (loadbf) {
-                /* iterate key hashes in page, set to the filter */
-                cdb_lock_lock(db->bflock);
-                for(uint32_t i = 0; i < page->num; i++) {
-                    uint64_t hash = (page->bid << 24) | (page->items[i].hash.i2 << 8)
-                        | (page->items[i].hash.i1);
-                    /* bloom filter use the combined record hash as key */
-                    cdb_bf_set(db->bf, &hash, SI8);
-                }
-                cdb_lock_unlock(db->bflock);
-            }
-
-            /* set the page to pcache if it doesn't exceed the limit size */
-            if (db->pcache && db->pcache->size < db->pclimit) {
-                cdb_lock_lock(db->pclock);
-                cdb_ht_insert2(db->pcache, &page->bid, SI4, page, MPAGESIZE(page));
-                cdb_lock_unlock(db->pclock);
-            }
-        }
-        /* the page may not be still in stack */
-        if (page != (CDBPAGE *)sbuf)
-            free(page);
-
-        if (!loadbf && (db->pcache && db->pcache->size > db->pclimit))
-            break;
-    }
-
-    db->vio->pageitdestroy(db->vio, it);
-}
-
-
-/* generate an incremental global operation id */
-uint64_t cdb_genoid(CDB *db)
-{
-    uint64_t oid;
-    cdb_lock_lock(db->oidlock);
-    oid = db->oid++;
-    cdb_lock_unlock(db->oidlock);
-    return oid;
-}
-
-
-/* get a new record iterator */
-void *cdb_iterate_new(CDB *db, uint64_t oid)
-{
-    return db->vio->recitfirst(db->vio, oid);
-}
-
-
-
-/* iterate the database by callback */
-uint64_t cdb_iterate(CDB *db, CDB_ITERCALLBACK itcb, void *arg, void *iter)
-{
-    char sbuf[SBUFSIZE];
-    uint64_t cnt = 0;
-
-    if (iter == NULL)
-        return cnt;
-    for(;;) {
-        /* the rec is a copy from file, may in stack or allocated in heap */
-        CDBREC *rec = (CDBREC *)sbuf;
-        bool ret = true;
-        if (db->vio->recitnext(db->vio, &rec, iter) < 0) 
-            break;
-        
-        if (cdb_checkoff(db, CDBHASH64(rec->key, rec->ksize), rec->ooff, CDB_NOTLOCKED)) {
-            ret = itcb(arg, rec->key, rec->ksize, rec->val, rec->vsize, rec->expire, rec->oid);
-            cnt++;
-        }
-        if (rec != (CDBREC *)sbuf)
-            free(rec);
-        if (!ret) 
-            break;
-    }
-    return cnt;
-}
-
-
-
-/* destroy the iterator */
-void cdb_iterate_destroy(CDB *db, void *iter)
-{
-    db->vio->recitdestroy(db->vio, iter);
-}
-
-
-/* difficult to implement */
-/*
-static void _cdb_rcachewarmup(CDB *db)
-{
-}
-*/
-
-
-CDB *cdb_new()
-{
-    CDB *db;
-    db = (CDB *)malloc(sizeof(CDB));
-    /* I assume all operation in this layer is 'fast', so no mutex used here */
-    for(int i = 0; i < MLOCKNUM; i++) 
-        db->mlock[i] = cdb_lock_new(CDB_LOCKMUTEX);
-    db->dpclock = cdb_lock_new(CDB_LOCKMUTEX);
-    db->pclock = cdb_lock_new(CDB_LOCKMUTEX);
-    db->rclock = cdb_lock_new(CDB_LOCKMUTEX);
-    db->stlock = cdb_lock_new(CDB_LOCKMUTEX);
-    db->oidlock = cdb_lock_new(CDB_LOCKMUTEX);
-    db->bflock = cdb_lock_new(CDB_LOCKMUTEX);
-    db->bgtask = cdb_bgtask_new();
-    /* every thread should has its own errno */
-    db->errkey = (pthread_key_t *)malloc(sizeof(pthread_key_t));
-    pthread_key_create(db->errkey, NULL);
-    /* set default parameter */
-    _cdb_defparam(db);
-    return db;
-}
-
-
-int cdb_option(CDB *db, int bnum, int rcacheMB, int pcacheMB)
-{
-    /* too small bnum is not allowed */
-    db->hsize = bnum > 4096? bnum : 4096;
-
-    if (rcacheMB >= 0)
-        db->rclimit = (uint64_t)rcacheMB * MB;
-    if (pcacheMB >= 0)
-        db->pclimit = (uint64_t)pcacheMB * MB;
-    return 0;
-}
-
-
-void cdb_option_bloomfilter(CDB *db, uint64_t size)
-{
-    db->bfsize = size;
-}
-
-void cdb_option_areadsize(CDB *db, uint32_t size)
-{
-    db->areadsize = size;
-    if (db->areadsize < 1 * KB)
-        db->areadsize = 1 * KB;
-
-    if (db->areadsize > SBUFSIZE - (sizeof(CDBREC) - RECHSIZE)) 
-        db->areadsize = SBUFSIZE - (sizeof(CDBREC) - RECHSIZE);
-}
-
-int cdb_open(CDB *db, const char *file_name, int mode)
-{
-    /* if will become into a hash table when file_name == CDB_MEMDB */
-    int memdb = (strcmp(file_name, CDB_MEMDB) == 0);
-
-    if (db->rclimit)
-        /* record cache is enabled */
-        db->rcache = cdb_ht_new(true, NULL);
-    else if (memdb) {
-        /* record cache is disabled, but in MEMDB mode */
-        cdb_seterrno(db, CDB_MEMDBNOCACHE, __FILE__, __LINE__);
-        goto ERRRET;
-    }
-
-    if (db->pclimit && !memdb) {
-        /* page cache enabled. page cache is meaningless under MEMDB  mode */
-        db->dpcache = cdb_ht_new(true, _pagehash);
-        db->pcache = cdb_ht_new(true, _pagehash);
-    }
-
-
-    if (!memdb) {
-        if (db->bfsize) {
-            /* bloom filter enabled */
-            db->bf = cdb_bf_new(db->bfsize, db->bfsize);
-        }
-        /* now only one storage format is supported */
-        db->vio = cdb_vio_new(CDBVIOAPND2);
-        db->vio->db = db;
-        if (db->vio->open(db->vio, file_name, mode) < 0)
-            goto ERRRET;
-        if (db->vio->rhead(db->vio) < 0) {
-            db->mtable = (FOFF*)malloc(sizeof(FOFF) * db->hsize);
-            memset(db->mtable, 0, sizeof(FOFF) * db->hsize);
-        }
-        /* dirty index page would be swap to disk by timer control */
-        cdb_bgtask_add(db->bgtask, _cdb_flushdpagetask, db, 1);
-        db->ndpltime = time(NULL);
-        /* start background task thread */
-        cdb_bgtask_start(db->bgtask);
-    } else {
-        /* no persistent storage under MEMDB mode */
-        db->vio = NULL;
-        db->bgtask = NULL;
-        db->mtable = NULL;
-    }
-
-    if (db->bf || ((mode & CDB_PAGEWARMUP) && db->pcache)) {
-        /* fill the bloom filter if it is enabled, and fill the page cache */
-        _cdb_pagewarmup(db, !!db->bf);
-    }
-
-    /* reset the statistic info */
-    cdb_stat(db, NULL);
-    db->opened = true;
-    return 0;
-
-ERRRET:
-    if (db->rcache)
-        cdb_ht_destroy(db->rcache);
-    if (db->pcache)
-        cdb_ht_destroy(db->pcache);
-    if (db->dpcache)
-        cdb_ht_destroy(db->dpcache);
-    if (db->bf)
-        cdb_bf_destroy(db->bf);
-    cdb_bgtask_stop(db->bgtask);
-    _cdb_defparam(db);
-    return -1;
-}
-
-
-/* check if the page cache size exceed the limit. clean oldest page if necessary */
-static void _cdb_pageout(CDB *db)
-{
-    while (PCOVERFLOW(db)) {
-        if (db->pcache->num) {
-            /* clean page cache is prior */
-            cdb_lock_lock(db->pclock);
-            cdb_ht_removetail(db->pcache);
-            cdb_lock_unlock(db->pclock);
-        } else if (db->dpcache->num) {
-            CDBHTITEM *item;
-            uint32_t bid;
-            FOFF off;
-            cdb_lock_lock(db->dpclock);
-            item = cdb_ht_gettail(db->dpcache);    
-            if (item == NULL) {
-                cdb_lock_unlock(db->dpclock);
-                break;
-            }
-
-            bid = *(uint32_t*)cdb_ht_itemkey(db->dpcache, item);
-            /* must lock the main table inside the dpclock protection */
-            if (cdb_lock_trylock(db->mlock[bid % MLOCKNUM]) < 0) {
-                /* avoid dead lock since dpclock is holding */
-                cdb_lock_unlock(db->dpclock);
-                /* do nothing this time */
-                break;
-            }
-            cdb_ht_poptail(db->dpcache);
-            cdb_lock_unlock(db->dpclock);
-
-            /* write out dirty page */
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            db->vio->wpage(db->vio, (CDBPAGE*)cdb_ht_itemval(db->dpcache, item), &off);
-            db->wcount++;
-            db->wtime += _cdb_timermicrosec(&ts);
-            db->mtable[bid] = off;
-            cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-            free(item);
-        }
-    }
-}
-
-
-/* check if the record cache size exceed the limit. clean oldest record if necessary */
-static void _cdb_recout(CDB *db)
-{
-    while (RCOVERFLOW(db)) {
-        cdb_lock_lock(db->rclock);
-        if (db->rcache->num)
-            cdb_ht_removetail(db->rcache);
-        cdb_lock_unlock(db->rclock);
-    }
-}
-
-
-/* get all offsets from index(page) by key, even if only one of them at most is valid.
- Others are due to the hash collision */
-int cdb_getoff(CDB *db, uint64_t hash, FOFF **offs, int locked) 
-{
-    char sbuf[SBUFSIZE];
-    CDBPAGE *page = NULL;
-    int rnum;
-    bool incache = true;
-    uint32_t bid = (hash >> 24) % db->hsize;
-    PHASH phash;
-
-    phash.i1 = hash & 0xff;
-    phash.i2 = (hash >> 8) & 0xffff;
-
-    if (db->bf) {
-        uint64_t bfkey = (bid << 24) | (hash & 0xffffff);
-        /* check the key-hash in bloom filter? return now if not exist */
-        cdb_lock_lock(db->bflock);
-        if (!cdb_bf_exist(db->bf, &bfkey, SI8)) {
-            cdb_lock_unlock(db->bflock);
-            return 0;
-        }
-        cdb_lock_unlock(db->bflock);
-    }
-
-    if (locked == CDB_NOTLOCKED) cdb_lock_lock(db->mlock[bid % MLOCKNUM]);
-    /* page exists in clean page cache? */
-    if (db->pcache) {
-        cdb_lock_lock(db->pclock);
-        page = cdb_ht_get2(db->pcache, &bid, SI4, true);
-        cdb_lock_unlock(db->pclock);
-    }
-
-    /* not in pcache, exists in dirty page cache? */
-    if (page == NULL && db->dpcache) {
-        cdb_lock_lock(db->dpclock);
-        page = cdb_ht_get2(db->dpcache, &bid, SI4, true);
-        cdb_lock_unlock(db->dpclock);
-    }
-
-    if (page == NULL) {
-        /* not in dpcache either, read from disk */
-        incache = false;
-        db->pcmiss++;
-        /* page stays in stack by default */
-        page = (CDBPAGE *)sbuf;
-        if (OFFNOTNULL(db->mtable[bid])) {
-            /* page offset not null in main table */
-            int ret;
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            ret = db->vio->rpage(db->vio, &page, db->mtable[bid]);
-            db->rcount++;
-            db->rtime += _cdb_timermicrosec(&ts);
-
-            /* read page error, return */
-            if (ret < 0) {
-                if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-                if (page != (CDBPAGE *)sbuf)
-                    free(page);
-                return -1;
-            }
-        } else {
-            /* no page in this bucket */
-            page->cap = page->num = 0;
-            page->osize = 0;
-            OFFZERO(page->ooff);
-        }
-    } else {
-        db->pchit++;
-    }
-
-    rnum = 0;
-    for(uint32_t i = 0; i < page->num; i++) {
-        /* compare every hash in the page */
-        if (PHASHEQ(page->items[i].hash, phash)) {
-            (*offs)[rnum] = page->items[i].off;
-            /* result offset list stays in stack by default. Allocate one in heap if 
-            it exceeds the limit */
-            if (++rnum == SFOFFNUM) {
-                /* very little possibility goes here */
-                FOFF *tmp = (FOFF*)malloc((page->num - i + SFOFFNUM + 1) * sizeof(FOFF));
-                memcpy(tmp, *offs, SFOFFNUM * sizeof(FOFF));
-                *offs = tmp;
-            } 
-        }
-    }
-
-    if (!incache) {
-        /* set into clean page cache if not exists before */
-        if (db->pcache) {
-            cdb_lock_lock(db->pclock);
-            cdb_ht_insert2(db->pcache, &bid, SI4, page, MPAGESIZE(page));
-            cdb_lock_unlock(db->pclock);
-        }
-        /* if page now points to heap memory, free it */
-        if (page != (CDBPAGE *)sbuf) {
-            free(page);
-        }
-    }
-    if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-
-    /* check page cache overflow */
-    if (PCOVERFLOW(db))
-        _cdb_pageout(db);
-
-    return rnum;
-}
-
-
-/* replace a specified record's offset, may be used at disk space recycling 
- off indicates its previous offset, noff is the new offset. return negative if not found */
-int cdb_replaceoff(CDB *db, uint64_t hash, FOFF off, FOFF noff, int locked)
-{
-    char sbuf[SBUFSIZE];
-    CDBPAGE *page = NULL;
-    CDBHTITEM *pitem = NULL;
-    bool indpcache = false;
-    uint32_t bid = (hash >> 24) % db->hsize;
-    PHASH phash;
-    bool found = false;
-
-    phash.i1 = hash & 0xff;
-    phash.i2 = (hash >> 8) & 0xffff;
-
-    if (locked == CDB_NOTLOCKED) cdb_lock_lock(db->mlock[bid % MLOCKNUM]);
-    if (db->pcache) {
-        /* in clean page cache, since it would be modified, it should be deleted from pcache */
-        cdb_lock_lock(db->pclock);
-        pitem = cdb_ht_del(db->pcache, &bid, SI4);
-        cdb_lock_unlock(db->pclock);
-        if (pitem)
-            page = (CDBPAGE *)cdb_ht_itemval(db->pcache, pitem);
-    }
-    if (page == NULL && db->dpcache) {
-        /* not in pcache, but in dirty page cache */
-        cdb_lock_lock(db->dpclock);
-        page = cdb_ht_get2(db->dpcache, &bid, SI4, true);
-        cdb_lock_unlock(db->dpclock);
-        if (page)
-            indpcache = true;
-    }
-    if (page == NULL) {
-        /* not exists either, read from disk */
-        db->pcmiss++;
-        page = (CDBPAGE *)sbuf;
-        if (OFFNOTNULL(db->mtable[bid])) {
-            int ret;
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            ret = db->vio->rpage(db->vio, &page, db->mtable[bid]);
-            db->rcount++;
-            db->rtime += _cdb_timermicrosec(&ts);
-            
-            if (ret < 0) {
-                if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-                if (page != (CDBPAGE *)sbuf)
-                    free(page);
-                return -1;
-            }
-        } else {
-            /* nullified the empty page */
-            page->cap = page->num = 0;
-            page->osize = 0;
-            OFFZERO(page->ooff);
-        }
-    } else {
-        db->pchit++;
-    }
-
-    /* check and modify */
-    for(uint32_t i = 0; i < page->num; i++) {
-        if (PHASHEQ(page->items[i].hash, phash)
-            && OFFEQ(page->items[i].off, off)) {
-                page->items[i].off = noff;
-                found = true;
-                break;
-        }
-    }
-
-    if (db->dpcache && !indpcache) {
-        /* if page already dirty in cache, need not do anything */
-        /* dirty page cache is enabled but not exists before */
-        if (pitem) {
-            /* pitem not NULL indicates it belongs to pcache */
-            if (found) {
-                /* modified page */
-                cdb_lock_lock(db->dpclock);
-                cdb_ht_insert(db->dpcache, pitem);
-                cdb_lock_unlock(db->dpclock);
-            } else {
-                /* got from pcache, but not modified */
-                cdb_lock_lock(db->pclock);
-                cdb_ht_insert(db->pcache, pitem);
-                cdb_lock_unlock(db->pclock);
-            }
-            /* page belongs to memory in 'cache', must not free */
-        } else if (page != NULL) {
-            /* page read from disk, but not in cache */
-            cdb_lock_lock(db->dpclock);
-            cdb_ht_insert2(db->dpcache, &bid, SI4, page, MPAGESIZE(page));
-            cdb_lock_unlock(db->dpclock);
-            /* the 'page' won't be use anymore */
-            if (page != (CDBPAGE *)sbuf) 
-                free(page);
-        }
-    } else if (!db->dpcache){
-        /* no page cache. Write out dirty page immediately */
-        FOFF poff;
-        struct timespec ts;
-        _cdb_timerreset(&ts);
-        db->vio->wpage(db->vio, page, &poff);
-        db->wcount++;
-        db->wtime += _cdb_timermicrosec(&ts);
-
-        db->mtable[bid] = poff;
-        if (page != (CDBPAGE *)sbuf) 
-                free(page);
-    }
-    if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-
-    /* check page cache overflow */
-    if (PCOVERFLOW(db))
-        _cdb_pageout(db);
-
-    return 0;
-}
-
-
-/* insert/delete a key-offset pair from index page */
-int cdb_updatepage(CDB *db, uint64_t hash, FOFF off, int opt, int locked)
-{
-    char sbuf[SBUFSIZE], sbuf2[SBUFSIZE];
-    CDBPAGE *page = NULL, *npage = NULL;
-    CDBHTITEM *pitem = NULL, *nitem = NULL;
-    CDBHASHTABLE *tmpcache = NULL;
-    CDBLOCK *tmpclock = NULL;
-    int npsize = 0;
-    uint32_t bid = (hash >> 24) % db->hsize;
-    PHASH phash;
-
-    phash.i1 = hash & 0xff;
-    phash.i2 = (hash >> 8) & 0xffff;
-
-    if (locked == CDB_NOTLOCKED) cdb_lock_lock(db->mlock[bid % MLOCKNUM]);
-    /* firstly, try move the page out of the cache if possible, 
-    it assumes that the page would be modified(pair exists) */
-    if (db->pcache) {
-        /* try clean page cache */
-        cdb_lock_lock(db->pclock);
-        pitem = cdb_ht_del(db->pcache, &bid, SI4);
-        cdb_lock_unlock(db->pclock);
-        if (pitem) {
-            page = (CDBPAGE *)cdb_ht_itemval(db->pcache, pitem);
-            tmpcache = db->pcache;
-            tmpclock = db->pclock;
-        }
-    }
-    if (page == NULL && db->dpcache) {
-        /* try dirty page cache */
-        cdb_lock_lock(db->dpclock);
-        pitem = cdb_ht_del(db->dpcache, &bid, SI4);
-        cdb_lock_unlock(db->dpclock);
-        if (pitem) {
-            page = (CDBPAGE *)cdb_ht_itemval(db->dpcache, pitem);
-            tmpcache = db->dpcache;
-            tmpclock = db->dpclock;
-        }
-    }
-
-    if (page == NULL) {
-        db->pcmiss++;
-        page = (CDBPAGE *)sbuf;
-        /* doesn't exist in cache, read from disk */
-        if (OFFNOTNULL(db->mtable[bid])) {
-            int ret;
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            ret = db->vio->rpage(db->vio, &page, db->mtable[bid]);
-            db->rcount++;
-            db->rtime += _cdb_timermicrosec(&ts);
-
-            if (ret < 0) {
-                if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-                if (page != (CDBPAGE *)sbuf)
-                    free(page);
-                return -1;
-            }
-        } else {
-            page->cap = 0;
-            page->num = 0;
-            page->osize = 0;
-            OFFZERO(page->ooff);
-        }
-    } else {
-        db->pchit++;
-    }
-
-    npsize = MPAGESIZE(page);
-
-    if (opt == CDB_PAGEDELETEOFF)
-    ;//    npsize = MPAGESIZE(page) - sizeof(PITEM);
-    /* do not malloc new page on deletion */
-
-    else if (opt == CDB_PAGEINSERTOFF && page->cap == page->num) {
-    /* get a new page, from dirty page cache if possible */
-        npsize = MPAGESIZE(page) + CDB_PAGEINCR * sizeof(PITEM);
-        if (db->dpcache) {
-            nitem = cdb_ht_newitem(db->dpcache, SI4, npsize);
-            *(uint32_t*)cdb_ht_itemkey(db->dpcache, nitem) = bid;
-            npage = (CDBPAGE *)cdb_ht_itemval(db->dpcache, nitem);
-        } else {
-            /* no dpcache, use stack if size fits */
-            if (npsize > SBUFSIZE) 
-                npage = (CDBPAGE *)malloc(npsize);
-            else
-                npage = (CDBPAGE *)sbuf2;
-        }
-
-        /* initialize the new page */
-    
-        npage->bid = bid;
-        npage->oid = cdb_genoid(db);
-        npage->osize = page->osize;
-        npage->ooff = page->ooff;
-        npage->mtime = time(NULL);
-        npage->cap = page->cap + CDB_PAGEINCR;
-        npage->num = page->num;
-        memcpy(npage->items, page->items, page->num * sizeof(PITEM)); 
-        /* old page got from cache */
-        if (pitem)
-            free(pitem);
-        /* old page read from disk, if in stack? */
-        else if (page != (CDBPAGE *)sbuf)
-            free(page);
-
-        page = npage;
-        pitem = nitem;
-    }
-
-    uint32_t onum = page->num;
-
-    if (opt == CDB_PAGEDELETEOFF) {
-        bool found = false;
-        for(uint32_t i = 0; i < page->num; i++) {
-            if (!found) {
-                if (PHASHEQ(page->items[i].hash, phash)
-                    && OFFEQ(page->items[i].off, off))
-                {
-                    found = true;
-                    /* records num is consistant with index */
-                    cdb_lock_lock(db->stlock);
-                    db->rnum--;
-                    cdb_lock_unlock(db->stlock);
-                }
-            }
-            if (found && i + 1 < page->num)
-                page->items[i] = page->items[i+1];
-        }
-        if (found)
-            page->num--;
-    } else if (opt == CDB_PAGEINSERTOFF) {
-        bool found = false;
-        /* check already exist? */
-        for(uint32_t i = 0; i < page->num; i++) {
-            if (PHASHEQ(page->items[i].hash, phash)
-                && OFFEQ(page->items[i].off, off)) {
-                /* avoid exceptional deduplicated item */
-                found = true;
-                break;
-            }
-        }
-
-        /* append to the tail */
-        if (!found) {
-            page->items[page->num].hash = phash;
-            page->items[page->num].off = off;
-            page->num++;
-            /* records num is consistant with index */
-            cdb_lock_lock(db->stlock);
-            db->rnum++;
-            cdb_lock_unlock(db->stlock);
-            if (db->bf) {
-                uint64_t bfkey = (((hash >> 24) % db->hsize) << 24) | (hash & 0xffffff);
-                cdb_lock_lock(db->bflock);
-                cdb_bf_set(db->bf, &bfkey, SI8);
-                cdb_lock_unlock(db->bflock);
-            }
-        }
-    }
-
-    if (page->num == onum) {
-        /* nothing done */
-        if (pitem) {
-            /* insert the item back to the cache where it belongs */
-            cdb_lock_lock(tmpclock);
-            cdb_ht_insert(tmpcache, pitem);
-            cdb_lock_unlock(tmpclock);
-        } else {
-            if (page != (CDBPAGE *)sbuf2
-                    && page != (CDBPAGE *)sbuf)
-                free(page);
-        }
-        if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-        return -1;
-    } else {
-        if (pitem) {
-            cdb_lock_lock(db->dpclock);
-            cdb_ht_insert(db->dpcache, pitem);
-            cdb_lock_unlock(db->dpclock);
-        } else {
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            db->vio->wpage(db->vio, page, &off);
-            db->wcount++;
-            db->wtime += _cdb_timermicrosec(&ts);
-
-            db->mtable[bid] = off;
-            if (page != (CDBPAGE *)sbuf2
-                    && page != (CDBPAGE *)sbuf)
-                free(page);
-        }
-    }
-
-    if (locked == CDB_NOTLOCKED) cdb_lock_unlock(db->mlock[bid % MLOCKNUM]);
-
-    /* check page cache overflow */
-    if (PCOVERFLOW(db))
-        _cdb_pageout(db);
-
-    return 0;
-}
-
-
-/* check if an record with specified key-offset exists in index */
-bool cdb_checkoff(CDB *db, uint64_t hash, FOFF off, int locked)
-{
-    FOFF soffs[SFOFFNUM];
-    FOFF *soff = (FOFF *)soffs;
-    int dupnum;
-    int ret = false;
-
-    /* get all possible offsets */
-    dupnum = cdb_getoff(db, hash, &soff, locked);
-    for(int i = 0; i < dupnum; i++) {
-        if (OFFEQ(soff[i], off)) {
-            ret = true;
-            break;
-        }
-    }
-
-    if (soff != (FOFF *)soffs) {
-        free(soff);
-    }
-
-    return ret;
-}
-
-
-/* wrapper and simplified of set operation */
-int cdb_set(CDB *db, const char *key, int ksize, const char *val, int vsize)
-{
-    return cdb_set2(db, key, ksize, val, vsize, CDB_OVERWRITE, 0);
-}
-
-
-int cdb_set2(CDB *db, const char *key, int ksize, const char *val, int vsize, int opt, int expire)
-{
-    CDBREC rec;
-    FOFF ooff, noff;
-    uint32_t now = time(NULL);
-    uint64_t hash;
-    uint32_t lockid;
-    bool expired = false;
- 
-    if (db->vio == NULL) {
-        /* if it is a memdb, just operate on the record cache and return */
-        cdb_lock_lock(db->rclock);
-        cdb_ht_insert2(db->rcache, key, ksize, val, vsize);
-        cdb_lock_unlock(db->rclock);
-        if (RCOVERFLOW(db))
-            _cdb_recout(db);
-        return 0;
-    }
-
-    hash = CDBHASH64(key, ksize);
-    lockid = (hash >> 24) % db->hsize % MLOCKNUM;
-    OFFZERO(rec.ooff);
-    OFFZERO(ooff);
-    rec.osize = 0;
-    rec.key = (char*)key;
-    rec.val = (char*)val;
-    rec.ksize = ksize;
-    rec.vsize = vsize;
-    rec.oid = cdb_genoid(db);
-    rec.expire = expire? now + expire : 0;
-        
-    cdb_lock_lock(db->mlock[lockid]);
-    cdb_lock_lock(db->rclock);
-    if (db->rcache) {
-        /* if record already exists, get its old meta info */
-        int item_vsize;
-        char *cval;
-        uint32_t old_expire = 0;
-        cval = cdb_ht_get(db->rcache, key, ksize, &item_vsize, false);
-        if (cval) {
-            /* record already exists */
-            ooff = rec.ooff = *(FOFF*)cval;
-            rec.osize = item_vsize - SFOFF - SI4;
-            old_expire = *(uint32_t*)(cval + SFOFF); 
-        }
-        if (old_expire && old_expire <= now)
-            /* once exist but expired? */
-            expired = true;
-    }
-    cdb_lock_unlock(db->rclock);
-
-    if (OFFNULL(ooff)) {
-        FOFF soffs[SFOFFNUM];
-        FOFF *soff = soffs;
-        char sbuf[SBUFSIZE];
-        CDBREC *rrec = (CDBREC*)sbuf;
-        
-        int retnum;
-        if ((retnum = cdb_getoff(db, hash, &soff, CDB_LOCKED)) < 0) {
-            cdb_lock_unlock(db->mlock[lockid]);
-            return -1;
-        }
-            
-        for(int i = 0; i < retnum; i++) {
-            /* check for duplicate records/older version*/
-            int cret;
-            if (rrec != (CDBREC*)sbuf) {
-                free(rrec);
-                rrec = (CDBREC*)sbuf;
-            }
-            
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            cret = db->vio->rrec(db->vio, &rrec, soff[i], false);
-            db->rcount++;
-            db->rtime += _cdb_timermicrosec(&ts);
-            
-            if (cret < 0)
-                continue;
-                
-            if ((uint32_t) ksize == rrec->ksize && memcmp(rrec->key, key, ksize) == 0) {
-                /* got its old meta info */
-                rec.osize = rrec->osize;
-                rec.ooff = rrec->ooff;
-                ooff = rec.ooff;
-                if (rrec->expire <= now)
-                    expired = true;
-                break;
-            }
-        }
-        if (soff != soffs)
-            free(soff);
-        if (rrec != (CDBREC*)sbuf) 
-            free(rrec);
-    }
-    
-    if (OFFNOTNULL(ooff) && !expired) {
-        /* record already exists*/
-        if (opt & CDB_INSERTIFNOEXIST) {
-            cdb_lock_unlock(db->mlock[lockid]);
-            cdb_seterrno(db, CDB_EXIST, __FILE__, __LINE__);
-            return -2;
-        }
-    } else {
-        if (opt & CDB_INSERTIFEXIST) {
-            cdb_lock_unlock(db->mlock[lockid]);
-            cdb_seterrno(db, CDB_NOTFOUND, __FILE__, __LINE__);
-            return -3;
-        }
-    }
-    
-    struct timespec ts;
-    _cdb_timerreset(&ts);
-    if (db->vio->wrec(db->vio, &rec, &noff) < 0) {
-        cdb_lock_unlock(db->mlock[lockid]);
-        return -1;
-    }
-    db->wcount++;
-    db->wtime += _cdb_timermicrosec(&ts);
-    
-    if (OFFNOTNULL(ooff)) {
-        cdb_replaceoff(db, hash, ooff, noff, CDB_LOCKED);
-    } else {
-        cdb_updatepage(db, hash, noff, CDB_PAGEINSERTOFF, CDB_LOCKED);
-    }
-    
-    if (db->rcache) {
-        if ((opt & CDB_INSERTCACHE) == CDB_INSERTCACHE) {
-            char *cval;
-            CDBHTITEM *item = cdb_ht_newitem(db->rcache, ksize, vsize + SI4 + SFOFF);
-            memcpy(cdb_ht_itemkey(db->rcache, item), key, ksize);
-            cval = cdb_ht_itemval(db->rcache, item);
-            memcpy(cval + SI4 + SFOFF, val, vsize);
-            *(FOFF*)(cval) = rec.ooff;
-            *(uint32_t*)(cval + SFOFF) = rec.expire;
-            cdb_lock_lock(db->rclock);
-            cdb_ht_insert(db->rcache, item);
-            cdb_lock_unlock(db->rclock);
-        }
-    } 
-    cdb_lock_unlock(db->mlock[lockid]);
-    
-    if (RCOVERFLOW(db))
-        _cdb_recout(db);
-
-    cdb_seterrno(db, CDB_SUCCESS, __FILE__, __LINE__);
-    return 0;
-}
-
-
-int cdb_is(CDB *db, const char *key, int ksize)
-{
-    FOFF soffs[SFOFFNUM];
-    FOFF *offs;
-    int dupnum, ret = -3;
-    uint64_t hash;
-    //uint32_t now = time(NULL);
-    uint32_t lockid;
-
-    if (db->rcache) {
-        char *cval;
-        cdb_lock_lock(db->rclock);
-        cval = cdb_ht_get(db->rcache, key, ksize, 0, true);
-        if (cval) {
-            db->rchit++;
-            cdb_lock_unlock(db->rclock);
-            return 0;
-        } else {
-            db->rcmiss++;
-            if (db->vio == NULL) {
-                cdb_lock_unlock(db->rclock);
-                return -3;
-            }
-        }
-        cdb_lock_unlock(db->rclock);
-    }
-
-    offs = soffs;
-    hash = CDBHASH64(key, ksize);
-    lockid = (hash >> 24) % db->hsize % MLOCKNUM;
-    cdb_lock_lock(db->mlock[lockid]);
-    dupnum = cdb_getoff(db, hash, &offs, CDB_LOCKED);
-    if (dupnum <= 0) {
-        cdb_lock_unlock(db->mlock[lockid]);
-        return -1;
-    }
-    else
-        ret = 0;
-    cdb_lock_unlock(db->mlock[lockid]);
-
-    if (RCOVERFLOW(db))
-        _cdb_recout(db);
-
-    if (offs != soffs)
-        free(offs);
-
-    if (ret < 0)
-        cdb_seterrno(db, CDB_NOTFOUND, __FILE__, __LINE__);
-    else {
-        db->rcmiss++;
-        cdb_seterrno(db, CDB_SUCCESS, __FILE__, __LINE__);
-    }
-    return ret;
-}
-
-
-int cdb_get(CDB *db, const char *key, int ksize, void **val, int *vsize)
-{
-    char sbuf[SBUFSIZE];
-    CDBREC *rec = (CDBREC *)sbuf;
-    FOFF soffs[SFOFFNUM];
-    FOFF *offs;
-    int dupnum, ret = -3;
-    uint64_t hash;
-    uint32_t now = time(NULL);
-    uint32_t lockid;
-
-    *vsize = 0;
-    *val = NULL;
-    cdb_lock_lock(db->rclock);
-    if (db->rcache) {
-        char *cval;
-        cval = cdb_ht_get(db->rcache, key, ksize, vsize, true);
-        if (cval) {
-            db->rchit++;
-            if (db->vio) {
-                (*vsize) -= SI4 + SFOFF;
-                if (*(uint32_t*)(cval + SFOFF)
-                    && *(uint32_t*)(cval + SFOFF) <= now) {
-                    cdb_lock_unlock(db->rclock);
-                    /* not found no not report error now */
-                    //cdb_seterrno(db, CDB_NOTFOUND, __FILE__, __LINE__);
-                    return -3;
-                }
-                cval = (void*)(cval + SI4 + SFOFF);
-            }
-            *val = malloc(*vsize);
-            memcpy(*val, cval, *vsize);
-            cdb_lock_unlock(db->rclock);
-            return 0;
-        } else {
-            db->rcmiss++;
-            if (db->vio == NULL) {
-                cdb_lock_unlock(db->rclock);
-                return -3;
-            }
-        }
-    }
-    cdb_lock_unlock(db->rclock);
-
-    offs = soffs;
-    hash = CDBHASH64(key, ksize);
-    lockid = (hash >> 24) % db->hsize % MLOCKNUM;
-    cdb_lock_lock(db->mlock[lockid]);
-    dupnum = cdb_getoff(db, hash, &offs, CDB_LOCKED);
-    if (dupnum < 0) {
-        cdb_lock_unlock(db->mlock[lockid]);
-        return -1;
-    }
-
-    for(int i = 0; i < dupnum; i++) {
-        int cret;
-        if (rec != (CDBREC*)sbuf) {
-            free(rec);
-            rec = (CDBREC*)sbuf;
-        }
-
-        struct timespec ts;
-        _cdb_timerreset(&ts);
-        cret = db->vio->rrec(db->vio, &rec, offs[i], true);
-        db->rcount++;
-        db->rtime += _cdb_timermicrosec(&ts);
-
-        if (cret < 0)
-            continue;
-
-        if ((uint32_t) ksize == rec->ksize && memcmp(rec->key, key, ksize) == 0) {
-            if (rec->expire && rec->expire <= now) {
-                break;
-            }
-            *vsize = rec->vsize;
-            *val = malloc(*vsize);
-            memcpy(*val, rec->val, *vsize);
-            ret = 0;
-            break;
-        } 
-    }
-
-    if (ret == 0 && db->rcache) {
-        char *cval;
-        CDBHTITEM *item = cdb_ht_newitem(db->rcache, ksize, *vsize + SI4 + SFOFF);
-        memcpy(cdb_ht_itemkey(db->rcache, item), key, ksize);
-        cval = cdb_ht_itemval(db->rcache, item);
-        memcpy(cval + SI4 + SFOFF, *val, *vsize);
-        *(FOFF*)(cval) = rec->ooff;
-        *(uint32_t*)(cval + SFOFF) = rec->expire;
-        cdb_lock_lock(db->rclock);
-        cdb_ht_insert(db->rcache, item);
-        cdb_lock_unlock(db->rclock);
-    }
-    cdb_lock_unlock(db->mlock[lockid]);
-    
-    if (RCOVERFLOW(db))
-        _cdb_recout(db);
-            
-    if (offs != soffs)
-        free(offs);
-        
-    if (rec != (CDBREC*)sbuf) 
-        free(rec);
-
-    if (ret < 0)
-        cdb_seterrno(db, CDB_NOTFOUND, __FILE__, __LINE__);
-    else {
-        db->rcmiss++;
-        cdb_seterrno(db, CDB_SUCCESS, __FILE__, __LINE__);
-    }
-    return ret;
-}
-
-
-void cdb_free_val(void **val)
-{
-    if (*val) 
-        free(*val);
-    *val = NULL;
-}
-
-
-int cdb_del(CDB *db, const char *key, int ksize)
-{
-    FOFF ooff;
-    CDBREC rec;
-    uint32_t lockid;
-    uint64_t hash;
-    
-    OFFZERO(rec.ooff);
-    OFFZERO(ooff);
-    rec.osize = 0;
-    rec.key = (char*)key;
-    rec.ksize = ksize;
-    rec.val = NULL;
-    rec.vsize = 0;
-    
-    if (db->vio == NULL) {
-        /* if it is a memdb, just operate on the record cache and return */
-        cdb_lock_lock(db->rclock);
-        cdb_ht_del2(db->rcache, key, ksize);
-        cdb_lock_unlock(db->rclock);
-        if (RCOVERFLOW(db))
-            _cdb_recout(db);
-        return 0;
-    }
-    
-    hash = CDBHASH64(key, ksize);
-    lockid = (hash >> 24) % db->hsize % MLOCKNUM;
-    cdb_lock_lock(db->mlock[lockid]);
-    if (db->rcache) {
-        /* if record already exists, get its old meta info */
-        CDBHTITEM *item;
-        cdb_lock_lock(db->rclock);
-        item = cdb_ht_del(db->rcache, key, ksize);
-        cdb_lock_unlock(db->rclock);
-        if (item) {
-            char *cval = cdb_ht_itemval(db->rcache, item);
-            ooff = rec.ooff = *(FOFF*)cval;
-            rec.osize = item->vsize - SFOFF - SI4;
-            rec.expire = *(uint32_t*)(cval + SFOFF);
-            free(item);
-        }
-    }
-    
-    if (OFFNULL(ooff)) {
-        FOFF soffs[SFOFFNUM];
-        FOFF *soff = soffs;
-        char sbuf[SBUFSIZE];
-        CDBREC *rrec = (CDBREC*)sbuf;
-        
-        int retnum;
-        if ((retnum = cdb_getoff(db, hash, &soff, CDB_LOCKED)) < 0) {
-            cdb_lock_unlock(db->mlock[lockid]);
-            return -1;
-        }
-            
-        for(int i = 0; i < retnum; i++) {
-            /* check for duplicate records/older version*/
-            int cret;
-            if (rrec != (CDBREC*)sbuf) {
-                free(rrec);
-                rrec = (CDBREC*)sbuf;
-            }
-            
-            struct timespec ts;
-            _cdb_timerreset(&ts);
-            cret = db->vio->rrec(db->vio, &rrec, soff[i], false);
-            db->rcount++;
-            db->rtime += _cdb_timermicrosec(&ts);
-            
-            if (cret < 0)
-                continue;
-                
-            if ((uint32_t) ksize == rrec->ksize && memcmp(rrec->key, key, ksize) == 0) {
-                /* got its old meta info */
-                rec.osize = rrec->osize;
-                rec.ooff = rrec->ooff;
-                ooff = rec.ooff;
-                break;
-            }
-        }
-        if (soff != soffs)
-            free(soff);
-        if (rrec != (CDBREC*)sbuf) 
-            free(rrec);
-    }
-    
-    if (OFFNOTNULL(ooff)) {
-        cdb_updatepage(db, hash, ooff, CDB_PAGEDELETEOFF, CDB_LOCKED);
-        cdb_lock_unlock(db->mlock[lockid]);
-        
-        struct timespec ts;
-        _cdb_timerreset(&ts);
-        db->vio->drec(db->vio, &rec, ooff);
-        //if ( < 0)
-          // return -1;  succeed or not doesn't matter
-        db->wcount++;
-        db->wtime += _cdb_timermicrosec(&ts);
-        cdb_seterrno(db, CDB_SUCCESS, __FILE__, __LINE__);
-        return 0;
-    } else {
-        cdb_lock_unlock(db->mlock[lockid]);
-        cdb_seterrno(db, CDB_NOTFOUND, __FILE__, __LINE__);
-        return -3;
-    }
-}
-
-
-void cdb_stat(CDB *db, CDBSTAT *stat)
-{
-    if (stat == NULL) {
-        db->rchit = db->rcmiss = 0;
-        db->pchit = db->pcmiss = 0;
-        db->rcount = db->rtime = 0;
-        db->wcount = db->wtime = 0;
-    } else {
-        stat->rnum = db->rnum;
-        stat->rcnum = db->rcache? db->rcache->num : 0;
-        stat->pnum = db->hsize;
-        stat->pcnum = (db->pcache? db->pcache->num : 0) 
-            + (db->dpcache? db->dpcache->num : 0);
-        stat->rchit = db->rchit;
-        stat->rcmiss = db->rcmiss;
-        stat->pchit = db->pchit;
-        stat->pcmiss = db->pcmiss;
-        stat->rlatcy = db->rcount ? db->rtime / db->rcount : 0;
-        stat->wlatcy = db->wcount ? db->wtime / db->wcount : 0;
-    }
-}
-
-
-int cdb_close(CDB *db)
-{
-    if (!db->opened)
-        return -1;
-
-    if (db->bgtask)
-        cdb_bgtask_stop(db->bgtask);
-    if (db->rcache)
-        cdb_ht_destroy(db->rcache);
-    if (db->pcache)
-        cdb_ht_destroy(db->pcache);
-    if (db->dpcache) {
-        cdb_flushalldpage(db);
-        cdb_ht_destroy(db->dpcache);
-    }
-
-    if (db->vio) {
-        db->vio->whead(db->vio);
-        db->vio->close(db->vio);
-        cdb_vio_destroy(db->vio);
-    }
-    if (db->mtable)
-        free(db->mtable);
-    db->opened = false;
-    _cdb_defparam(db);
-    return 0;
-}
-
-
-void cdb_deferrorcb(void *arg, int errno, const char *file, int line)
-{
-    (void) arg;
-    fprintf(stderr, "DBERR: [%s:%d] %d - %s\n", file, line, errno, cdb_errmsg(errno));
-}
-
-
-int cdb_destroy(CDB *db)
-{
-    if (db->opened)
-        cdb_close(db);
-    for(int i = 0; i < MLOCKNUM; i++)
-        cdb_lock_destory(db->mlock[i]);
-    cdb_lock_destory(db->dpclock);
-    cdb_lock_destory(db->pclock);
-    cdb_lock_destory(db->rclock);
-    cdb_lock_destory(db->stlock);
-    cdb_lock_destory(db->oidlock);
-    cdb_lock_destory(db->bflock);
-    cdb_bgtask_destroy(db->bgtask);
-    pthread_key_delete(*(pthread_key_t*)db->errkey);
-    free(db->errkey);
-    free(db);
-    return 0;
-}
-
-
-
diff --git a/3rdparty/cuttdb/src/cdb_core.h b/3rdparty/cuttdb/src/cdb_core.h
deleted file mode 100644
index bcd4ad9a6bef0d43993781f3707ed0f44935cae2..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_core.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_CORE_H_
-#define _CDB_CORE_H_
-#include "cuttdb.h"
-#include "cdb_types.h"
-#include "cdb_hashtable.h"
-#include "cdb_bloomfilter.h"
-#include "cdb_lock.h"
-#include "cdb_vio.h"
-#include "cdb_bgtask.h"
-#include <stdint.h>
-#include <stdbool.h>
-
-
-enum {
-    CDB_PAGEDELETEOFF = 0,
-    CDB_PAGEINSERTOFF = 1,
-};
-
-/* the DB object */
-struct CDB
-{
-    /* size limit for record cache */
-    uint64_t rclimit;
-    /* size limit for index page cache */
-    uint64_t pclimit;
-    /* size of bloom filter */
-    uint64_t bfsize;
-    /* record number in db */
-    uint64_t rnum;
-    /* always increment operation id */
-    uint64_t oid;
-    /* recovery point oid */
-    uint64_t roid;
-    /* hash table size */
-    uint32_t hsize;
-    /* last timestamp of no dirty page state */
-    uint32_t ndpltime;
-    /* currently the database opened or not */
-    bool opened;
-    /* the size for a disk seek&read, should not greater than SBUFSIZE */
-    uint32_t areadsize;
-
-    /* record cache */
-    CDBHASHTABLE *rcache;
-    /* (clean) index page cache */
-    CDBHASHTABLE *pcache;
-    /* dirty index page cache */
-    CDBHASHTABLE *dpcache;
-    /* Bloom Filter */
-    CDBBLOOMFILTER *bf;
-
-    /* lock for rcache */
-    CDBLOCK *rclock;
-    /* lock for pcache */
-    CDBLOCK *pclock;
-    /* lock for dpcache */
-    CDBLOCK *dpclock;
-    /* lock for hash table operation, split to MLOCKNUM groups */
-    CDBLOCK *mlock[MLOCKNUM];
-    /* lock for statistic */
-    CDBLOCK *stlock;
-    /* lock for operation id */
-    CDBLOCK *oidlock;
-    /* lock for bloom filter */
-    CDBLOCK *bflock;
-    /* background tasks in another thread */
-    CDBBGTASK *bgtask;
-
-    /* main hash table, contains 'hsize' elements */
-    FOFF *mtable;
-    /* disk i/o layer object */
-    CDBVIO *vio;
-
-    /* callback function when error occurs */
-    CDB_ERRCALLBACK errcb;
-    /* argument for callback function */
-    void *errcbarg;
-    /* key to get error code in current thread */
-    void *errkey;
-
-    /* statistics below, this fields have no lock protection */
-    /* record cache hit/miss */
-    uint64_t rchit;
-    uint64_t rcmiss;
-    /* page cache hit/miss */
-    uint64_t pchit;
-    uint64_t pcmiss;
-    /* cumulative disk read time */
-    uint64_t rtime;
-    /* number of disk read operation */
-    uint64_t rcount;
-    /* cumulative disk write time */
-    uint64_t wtime;
-    /* number of disk write operation */
-    uint64_t wcount;
-};
-
-
-bool cdb_checkoff(CDB *db, uint64_t hash, FOFF off, int locked);
-int cdb_getoff(CDB *db, uint64_t hash, FOFF **offs, int locked);
-int cdb_replaceoff(CDB *db, uint64_t hash, FOFF off, FOFF noff, int locked);
-int cdb_updatepage(CDB *db, uint64_t hash, FOFF off, int opt, int locked);
-void cdb_flushalldpage(CDB *db);
-uint64_t cdb_genoid(CDB *db);
-
-#endif
-
diff --git a/3rdparty/cuttdb/src/cdb_crc64.c b/3rdparty/cuttdb/src/cdb_crc64.c
deleted file mode 100644
index 6c72eb73fb3b8aaf774cd0e87479fc0fe82c580b..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_crc64.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-/**************************************************************
-* *
-* Fichier : crc64.c *
-* Fonction pour calculer le CRC64 *
-* *
-**************************************************************/
-#include "cdb_crc64.h"
-
-
-#define CONST64(n) (n##ULL)
-static uint64_t CRC64_Table[256] =
-{
-    CONST64(0x0000000000000000), CONST64(0x42f0e1eba9ea3693),
-    CONST64(0x85e1c3d753d46d26), CONST64(0xc711223cfa3e5bb5),
-    CONST64(0x493366450e42ecdf), CONST64(0x0bc387aea7a8da4c),
-    CONST64(0xccd2a5925d9681f9), CONST64(0x8e224479f47cb76a),
-    CONST64(0x9266cc8a1c85d9be), CONST64(0xd0962d61b56fef2d),
-    CONST64(0x17870f5d4f51b498), CONST64(0x5577eeb6e6bb820b),
-    CONST64(0xdb55aacf12c73561), CONST64(0x99a54b24bb2d03f2),
-    CONST64(0x5eb4691841135847), CONST64(0x1c4488f3e8f96ed4),
-    CONST64(0x663d78ff90e185ef), CONST64(0x24cd9914390bb37c),
-    CONST64(0xe3dcbb28c335e8c9), CONST64(0xa12c5ac36adfde5a),
-    CONST64(0x2f0e1eba9ea36930), CONST64(0x6dfeff5137495fa3),
-    CONST64(0xaaefdd6dcd770416), CONST64(0xe81f3c86649d3285),
-    CONST64(0xf45bb4758c645c51), CONST64(0xb6ab559e258e6ac2),
-    CONST64(0x71ba77a2dfb03177), CONST64(0x334a9649765a07e4),
-    CONST64(0xbd68d2308226b08e), CONST64(0xff9833db2bcc861d),
-    CONST64(0x388911e7d1f2dda8), CONST64(0x7a79f00c7818eb3b),
-    CONST64(0xcc7af1ff21c30bde), CONST64(0x8e8a101488293d4d),
-    CONST64(0x499b3228721766f8), CONST64(0x0b6bd3c3dbfd506b),
-    CONST64(0x854997ba2f81e701), CONST64(0xc7b97651866bd192),
-    CONST64(0x00a8546d7c558a27), CONST64(0x4258b586d5bfbcb4),
-    CONST64(0x5e1c3d753d46d260), CONST64(0x1cecdc9e94ace4f3),
-    CONST64(0xdbfdfea26e92bf46), CONST64(0x990d1f49c77889d5),
-    CONST64(0x172f5b3033043ebf), CONST64(0x55dfbadb9aee082c),
-    CONST64(0x92ce98e760d05399), CONST64(0xd03e790cc93a650a),
-    CONST64(0xaa478900b1228e31), CONST64(0xe8b768eb18c8b8a2),
-    CONST64(0x2fa64ad7e2f6e317), CONST64(0x6d56ab3c4b1cd584),
-    CONST64(0xe374ef45bf6062ee), CONST64(0xa1840eae168a547d),
-    CONST64(0x66952c92ecb40fc8), CONST64(0x2465cd79455e395b),
-    CONST64(0x3821458aada7578f), CONST64(0x7ad1a461044d611c),
-    CONST64(0xbdc0865dfe733aa9), CONST64(0xff3067b657990c3a),
-    CONST64(0x711223cfa3e5bb50), CONST64(0x33e2c2240a0f8dc3),
-    CONST64(0xf4f3e018f031d676), CONST64(0xb60301f359dbe0e5),
-    CONST64(0xda050215ea6c212f), CONST64(0x98f5e3fe438617bc),
-    CONST64(0x5fe4c1c2b9b84c09), CONST64(0x1d14202910527a9a),
-    CONST64(0x93366450e42ecdf0), CONST64(0xd1c685bb4dc4fb63),
-    CONST64(0x16d7a787b7faa0d6), CONST64(0x5427466c1e109645),
-    CONST64(0x4863ce9ff6e9f891), CONST64(0x0a932f745f03ce02),
-    CONST64(0xcd820d48a53d95b7), CONST64(0x8f72eca30cd7a324),
-    CONST64(0x0150a8daf8ab144e), CONST64(0x43a04931514122dd),
-    CONST64(0x84b16b0dab7f7968), CONST64(0xc6418ae602954ffb),
-    CONST64(0xbc387aea7a8da4c0), CONST64(0xfec89b01d3679253),
-    CONST64(0x39d9b93d2959c9e6), CONST64(0x7b2958d680b3ff75),
-    CONST64(0xf50b1caf74cf481f), CONST64(0xb7fbfd44dd257e8c),
-    CONST64(0x70eadf78271b2539), CONST64(0x321a3e938ef113aa),
-    CONST64(0x2e5eb66066087d7e), CONST64(0x6cae578bcfe24bed),
-    CONST64(0xabbf75b735dc1058), CONST64(0xe94f945c9c3626cb),
-    CONST64(0x676dd025684a91a1), CONST64(0x259d31cec1a0a732),
-    CONST64(0xe28c13f23b9efc87), CONST64(0xa07cf2199274ca14),
-    CONST64(0x167ff3eacbaf2af1), CONST64(0x548f120162451c62),
-    CONST64(0x939e303d987b47d7), CONST64(0xd16ed1d631917144),
-    CONST64(0x5f4c95afc5edc62e), CONST64(0x1dbc74446c07f0bd),
-    CONST64(0xdaad56789639ab08), CONST64(0x985db7933fd39d9b),
-    CONST64(0x84193f60d72af34f), CONST64(0xc6e9de8b7ec0c5dc),
-    CONST64(0x01f8fcb784fe9e69), CONST64(0x43081d5c2d14a8fa),
-    CONST64(0xcd2a5925d9681f90), CONST64(0x8fdab8ce70822903),
-    CONST64(0x48cb9af28abc72b6), CONST64(0x0a3b7b1923564425),
-    CONST64(0x70428b155b4eaf1e), CONST64(0x32b26afef2a4998d),
-    CONST64(0xf5a348c2089ac238), CONST64(0xb753a929a170f4ab),
-    CONST64(0x3971ed50550c43c1), CONST64(0x7b810cbbfce67552),
-    CONST64(0xbc902e8706d82ee7), CONST64(0xfe60cf6caf321874),
-    CONST64(0xe224479f47cb76a0), CONST64(0xa0d4a674ee214033),
-    CONST64(0x67c58448141f1b86), CONST64(0x253565a3bdf52d15),
-    CONST64(0xab1721da49899a7f), CONST64(0xe9e7c031e063acec),
-    CONST64(0x2ef6e20d1a5df759), CONST64(0x6c0603e6b3b7c1ca),
-    CONST64(0xf6fae5c07d3274cd), CONST64(0xb40a042bd4d8425e),
-    CONST64(0x731b26172ee619eb), CONST64(0x31ebc7fc870c2f78),
-    CONST64(0xbfc9838573709812), CONST64(0xfd39626eda9aae81),
-    CONST64(0x3a28405220a4f534), CONST64(0x78d8a1b9894ec3a7),
-    CONST64(0x649c294a61b7ad73), CONST64(0x266cc8a1c85d9be0),
-    CONST64(0xe17dea9d3263c055), CONST64(0xa38d0b769b89f6c6),
-    CONST64(0x2daf4f0f6ff541ac), CONST64(0x6f5faee4c61f773f),
-    CONST64(0xa84e8cd83c212c8a), CONST64(0xeabe6d3395cb1a19),
-    CONST64(0x90c79d3fedd3f122), CONST64(0xd2377cd44439c7b1),
-    CONST64(0x15265ee8be079c04), CONST64(0x57d6bf0317edaa97),
-    CONST64(0xd9f4fb7ae3911dfd), CONST64(0x9b041a914a7b2b6e),
-    CONST64(0x5c1538adb04570db), CONST64(0x1ee5d94619af4648),
-    CONST64(0x02a151b5f156289c), CONST64(0x4051b05e58bc1e0f),
-    CONST64(0x87409262a28245ba), CONST64(0xc5b073890b687329),
-    CONST64(0x4b9237f0ff14c443), CONST64(0x0962d61b56fef2d0),
-    CONST64(0xce73f427acc0a965), CONST64(0x8c8315cc052a9ff6),
-    CONST64(0x3a80143f5cf17f13), CONST64(0x7870f5d4f51b4980),
-    CONST64(0xbf61d7e80f251235), CONST64(0xfd913603a6cf24a6),
-    CONST64(0x73b3727a52b393cc), CONST64(0x31439391fb59a55f),
-    CONST64(0xf652b1ad0167feea), CONST64(0xb4a25046a88dc879),
-    CONST64(0xa8e6d8b54074a6ad), CONST64(0xea16395ee99e903e),
-    CONST64(0x2d071b6213a0cb8b), CONST64(0x6ff7fa89ba4afd18),
-    CONST64(0xe1d5bef04e364a72), CONST64(0xa3255f1be7dc7ce1),
-    CONST64(0x64347d271de22754), CONST64(0x26c49cccb40811c7),
-    CONST64(0x5cbd6cc0cc10fafc), CONST64(0x1e4d8d2b65facc6f),
-    CONST64(0xd95caf179fc497da), CONST64(0x9bac4efc362ea149),
-    CONST64(0x158e0a85c2521623), CONST64(0x577eeb6e6bb820b0),
-    CONST64(0x906fc95291867b05), CONST64(0xd29f28b9386c4d96),
-    CONST64(0xcedba04ad0952342), CONST64(0x8c2b41a1797f15d1),
-    CONST64(0x4b3a639d83414e64), CONST64(0x09ca82762aab78f7),
-    CONST64(0x87e8c60fded7cf9d), CONST64(0xc51827e4773df90e),
-    CONST64(0x020905d88d03a2bb), CONST64(0x40f9e43324e99428),
-    CONST64(0x2cffe7d5975e55e2), CONST64(0x6e0f063e3eb46371),
-    CONST64(0xa91e2402c48a38c4), CONST64(0xebeec5e96d600e57),
-    CONST64(0x65cc8190991cb93d), CONST64(0x273c607b30f68fae),
-    CONST64(0xe02d4247cac8d41b), CONST64(0xa2dda3ac6322e288),
-    CONST64(0xbe992b5f8bdb8c5c), CONST64(0xfc69cab42231bacf),
-    CONST64(0x3b78e888d80fe17a), CONST64(0x7988096371e5d7e9),
-    CONST64(0xf7aa4d1a85996083), CONST64(0xb55aacf12c735610),
-    CONST64(0x724b8ecdd64d0da5), CONST64(0x30bb6f267fa73b36),
-    CONST64(0x4ac29f2a07bfd00d), CONST64(0x08327ec1ae55e69e),
-    CONST64(0xcf235cfd546bbd2b), CONST64(0x8dd3bd16fd818bb8),
-    CONST64(0x03f1f96f09fd3cd2), CONST64(0x41011884a0170a41),
-    CONST64(0x86103ab85a2951f4), CONST64(0xc4e0db53f3c36767),
-    CONST64(0xd8a453a01b3a09b3), CONST64(0x9a54b24bb2d03f20),
-    CONST64(0x5d45907748ee6495), CONST64(0x1fb5719ce1045206),
-    CONST64(0x919735e51578e56c), CONST64(0xd367d40ebc92d3ff),
-    CONST64(0x1476f63246ac884a), CONST64(0x568617d9ef46bed9),
-    CONST64(0xe085162ab69d5e3c), CONST64(0xa275f7c11f7768af),
-    CONST64(0x6564d5fde549331a), CONST64(0x279434164ca30589),
-    CONST64(0xa9b6706fb8dfb2e3), CONST64(0xeb46918411358470),
-    CONST64(0x2c57b3b8eb0bdfc5), CONST64(0x6ea7525342e1e956),
-    CONST64(0x72e3daa0aa188782), CONST64(0x30133b4b03f2b111),
-    CONST64(0xf7021977f9cceaa4), CONST64(0xb5f2f89c5026dc37),
-    CONST64(0x3bd0bce5a45a6b5d), CONST64(0x79205d0e0db05dce),
-    CONST64(0xbe317f32f78e067b), CONST64(0xfcc19ed95e6430e8),
-    CONST64(0x86b86ed5267cdbd3), CONST64(0xc4488f3e8f96ed40),
-    CONST64(0x0359ad0275a8b6f5), CONST64(0x41a94ce9dc428066),
-    CONST64(0xcf8b0890283e370c), CONST64(0x8d7be97b81d4019f),
-    CONST64(0x4a6acb477bea5a2a), CONST64(0x089a2aacd2006cb9),
-    CONST64(0x14dea25f3af9026d), CONST64(0x562e43b4931334fe),
-    CONST64(0x913f6188692d6f4b), CONST64(0xd3cf8063c0c759d8),
-    CONST64(0x5dedc41a34bbeeb2), CONST64(0x1f1d25f19d51d821),
-    CONST64(0xd80c07cd676f8394), CONST64(0x9afce626ce85b507)
-};
-
-
-uint64_t cdb_crc64(const void *buf, uint32_t len)
-{
-    uint32_t i;
-    uint64_t crc = 0xFFFFFFFFFFFFFFFF;
-    uint8_t *cbuf = (uint8_t *)buf;
-
-    for (i = 0; i < len; i++) {
-        crc = CRC64_Table[(uint8_t)(crc >> 56) ^ *cbuf++] ^ (crc << 8);
-    }
-    return crc;
-} 
-
diff --git a/3rdparty/cuttdb/src/cdb_crc64.h b/3rdparty/cuttdb/src/cdb_crc64.h
deleted file mode 100644
index 50744fc844afe84cdcef8ddba5f6cff81ae5599a..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_crc64.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_CRC64_H_
-#define _CDB_CRC64_H_
-#include <stdint.h>
-
-uint64_t cdb_crc64(const void *buf, uint32_t len);
-
-#endif
diff --git a/3rdparty/cuttdb/src/cdb_dumpdb.c b/3rdparty/cuttdb/src/cdb_dumpdb.c
deleted file mode 100644
index 99cddbb5355cb44d235ef08b27234a7199c2fe67..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_dumpdb.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-#include "cuttdb.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-
-bool itcb(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid)
-{
-#define SBUFSIZE 4096
-    char buf[SBUFSIZE];
-    char *kvbuf = buf;
-    if (ksize + vsize + 2 > SBUFSIZE)
-        kvbuf = (char*)malloc(ksize + vsize + 2);
-    memcpy(kvbuf, key, ksize);
-    kvbuf[ksize] = '\t';
-    memcpy(kvbuf + ksize + 1, val, vsize);
-    kvbuf[ksize + vsize + 1] = '\0';
-    printf("%s\t%u\n", kvbuf, expire);
-    if (kvbuf != buf)
-        free(kvbuf);
-    return true;
-}
-
-int main(int argc, char *argv[])
-{
-    /* 1TB */
-    int cache_limit = 1048576;
-
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s dbpath [cachelimit(MB)].... \n", argv[0]);
-        return -1;
-    }
-    if (argc > 2) {
-        cache_limit = atoi(argv[2]);
-    }
-    
-    CDB *db = cdb_new();
-    cdb_option(db, 0, 0, cache_limit);
-    if (cdb_open(db, argv[1], CDB_PAGEWARMUP) < 0) {
-        fprintf(stderr, "Database open error, unable to recovery\n");
-        return -1;
-    }
-    void *it = cdb_iterate_new(db, 0);
-    cdb_iterate(db, itcb, NULL, it);
-    cdb_iterate_destroy(db, it);
-    cdb_destroy(db);
-}
-
-
-
-
-
diff --git a/3rdparty/cuttdb/src/cdb_dumpraw.c b/3rdparty/cuttdb/src/cdb_dumpraw.c
deleted file mode 100644
index 53bbe11c6e7bec1723c97fb951b63468889d555a..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_dumpraw.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <stdint.h>
-
-#define SI4 4
-#define SI8 8
-
-/* data record */
-typedef struct {
-    /* disk store starts at following field */
-    uint32_t magic;
-    uint32_t ksize;
-    uint32_t vsize;
-    uint32_t expire;
-    uint64_t oid;
-    char buf[0];
-} __attribute__((packed)) CDBREC;
-
-/* real size of a record header when stored on disk */
-#define RECHSIZE (SI4 * 4 + SI8)
-/* real size of a record when stored on disk */
-#define RECSIZE(r) (RECHSIZE + (r)->ksize + (r)->vsize)
-
-#define FILEMETASIZE 64
-#define ALIGNBYTES 16
-#define RECMAGIC 0x19871022
-#define DELRECMAGIC 0x19871023
-#define FILEMAGICHEADER "CuTtDbFiLePaRtIaL"
-#define FILEMAGICLEN (strlen(FILEMAGICHEADER))
-#define OFFALIGNED(off) (((off) & (ALIGNBYTES - 1))? ((off) | (ALIGNBYTES - 1)) + 1: off)
-
-
-
-void process(const char *filename)
-{
-#define SBUFSIZE 4096
-    int fd = open(filename, O_RDONLY, 0644);
-    char buf[SBUFSIZE];
-    if (fd < 0)
-        fprintf(stderr, "%s Open failed\n", filename);
-
-    long filesize = lseek(fd, 0, SEEK_END);
-    long pos = FILEMETASIZE;
-    char *map = (char*)mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
-    if (memcmp(map, FILEMAGICHEADER, FILEMAGICLEN)) {
-        fprintf(stderr, "%s is not a cuttdb file\n", filename);
-        close(fd);
-        return;
-    }
-
-    while(pos < filesize) {
-        char *kvbuf = buf;
-        CDBREC *rec = (CDBREC*)&map[pos];
-        if (rec->magic != RECMAGIC && rec->magic != DELRECMAGIC) {
-            pos += ALIGNBYTES;
-            continue;
-        }
-
-        pos += OFFALIGNED(RECSIZE(rec));
-        if (rec->magic != RECMAGIC)
-            continue;
-        
-        if (rec->ksize + rec->vsize + 2 > SBUFSIZE) {
-            kvbuf = (char*)malloc(rec->ksize + rec->vsize + 2);
-        }
-        memcpy(kvbuf, rec->buf, rec->ksize);
-        kvbuf[rec->ksize] = '\t';
-        memcpy(kvbuf + rec->ksize + 1, rec->buf + rec->ksize, rec->vsize);
-        kvbuf[rec->ksize + rec->vsize + 1] = '\0';
-        printf("%s\t%u\n", kvbuf, rec->expire);
-        if (kvbuf != buf)
-            free(kvbuf);
-    }
-
-    munmap(map, filesize);
-    close(fd);
-}
-
-
-
-
-int main(int argc, char *argv[])
-{
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s dat########.cdb dat########.cdb .... \n", argv[0]);
-        return 0;
-    }
-    for(int i = 1; i < argc; i++)
-        process(argv[i]);
-    return 0;
-}
-
-
-
-
diff --git a/3rdparty/cuttdb/src/cdb_errno.c b/3rdparty/cuttdb/src/cdb_errno.c
deleted file mode 100644
index 0e9765acce186a2a0dc3c83260e6c10d884b613a..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_errno.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cuttdb.h"
-#include "cdb_errno.h"
-#include "cdb_types.h"
-#include "cdb_core.h"
-#include <pthread.h>
-
-
-int cdb_errno(CDB *db)
-{
-    return (size_t)pthread_getspecific(*(pthread_key_t*)db->errkey);
-}
-
-const char *cdb_errmsg(int ecode)
-{
-    switch(ecode) {
-        case CDB_SUCCESS:
-            return "Success";
-        case CDB_NOTFOUND:
-            return "Key Not Found";
-        case CDB_EXIST:
-            return "Item Already Exists";
-        case CDB_DIRNOEXIST:
-            return "Path Open Failed";
-        case CDB_OPENERR:
-            return "File Open Failed";
-        case CDB_PIDEXIST:
-            return "Opened By Another Process";
-        case CDB_DATAERRDAT:
-            return "Data File Content Error";
-        case CDB_DATAERRIDX:
-            return "Index File Content Error";
-        case CDB_WRITEERR:
-            return "Write To File Error";
-        case CDB_READERR:
-            return "Read From File Error";
-        case CDB_NOFID:
-            return "Internal File Lost";
-        case CDB_INTERNALERR:
-            return "Internal Error";
-        case CDB_DATAERRMETA:
-            return "File Header Error";
-        case CDB_MEMDBNOCACHE:
-            return "MemDB Mode With Zero Record Cache Size";
-        default:
-            return "Error For Errno";
-    }
-}
-
-
-void cdb_seterrcb(CDB *db, CDB_ERRCALLBACK errcb, void *arg)
-{
-    db->errcb = errcb;
-    db->errcbarg = arg;
-}
-
-
-void cdb_seterrno(CDB *db, int ecode, const char *source, int line)
-{
-    pthread_setspecific(*(pthread_key_t*)db->errkey, (void*)(size_t)ecode);
-    if (ecode != CDB_SUCCESS && db->errcb) {
-        db->errcb(db->errcbarg, ecode, source, line);
-    }
-}
diff --git a/3rdparty/cuttdb/src/cdb_errno.h b/3rdparty/cuttdb/src/cdb_errno.h
deleted file mode 100644
index f274819de73b2133d2648aa6490ea8f5cf66b41c..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_errno.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_ERRNO_H_
-#define _CDB_ERRNO_H_
-
-void cdb_seterrno(CDB *db, int ecode, const char *source, int line);
-
-#endif
-
diff --git a/3rdparty/cuttdb/src/cdb_hashtable.c b/3rdparty/cuttdb/src/cdb_hashtable.c
deleted file mode 100644
index 00d1a640c7657ddc8569c8071d14b90c7e736504..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_hashtable.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cdb_hashtable.h"
-#include <stdlib.h>
-#include <string.h>
-
-/*
-#define LRUPREV(i) (*(CDBHTITEM**)&((i)->buf[0]))
-#define LRUNEXT(i) (*(CDBHTITEM**)&((i)->buf[sizeof(void*)]))
-*/
-
-#define LRUPREV(i) ((i)->lruptr[0])
-#define LRUNEXT(i) ((i)->lruptr[1])
-
-static uint32_t MurmurHash1( const void * key, int len)
-{
-    const unsigned int m = 0xc6a4a793;
-    const int r = 16;
-    unsigned int h = 0x19900917 ^ (len * m);
-    const unsigned char * data = (const unsigned char *)key;
-
-    while(len >= 4)
-    {
-        unsigned int k = *(unsigned int *)data;
-        h += k; h *= m; h ^= h >> 16;
-        data += 4; len -= 4;
-    }
-
-    switch(len)
-    {
-    case 3:
-        h += data[2] << 16;
-    case 2:
-        h += data[1] << 8;
-    case 1:
-        h += data[0];
-        h *= m;
-        h ^= h >> r;
-    };
-
-    h *= m; h ^= h >> 10;
-    h *= m; h ^= h >> 17;
-    return h;
-} 
-
-void *cdb_ht_itemkey(CDBHASHTABLE *ht, CDBHTITEM *item)
-{
-    return (void *)(item->buf + ht->lru * 2 * sizeof(void*));
-}
-
-void *cdb_ht_itemval(CDBHASHTABLE *ht, CDBHTITEM *item)
-{
-    return (void *)(item->buf + ht->lru * 2 * sizeof(void*) + item->ksize);
-}
-
-CDBHASHTABLE *cdb_ht_new(bool lru, CDBHASHFUNC hashfunc)
-{
-    CDBHASHTABLE *ht;
-
-    ht = (CDBHASHTABLE*)malloc(sizeof(CDBHASHTABLE));
-    ht->hash = NULL;
-    ht->lru = lru;
-    ht->num = ht->size = 0;
-    ht->tail = ht->head = NULL;
-    for(uint32_t i = 0; i < (1<<CDBHTBNUMPOW); i++) {
-        CDBHTBUCKET *bucket = &(ht->buckets[i]);
-        bucket->bnum = 2;
-        uint32_t lsize = sizeof(CDBHTITEM *) * bucket->bnum;
-        bucket->rnum = 0;
-        bucket->items = (CDBHTITEM **)malloc(lsize);
-        ht->size += lsize;
-        memset(bucket->items, 0, lsize);
-    }
-    ht->hash = hashfunc;
-    if (ht->hash == NULL)
-        ht->hash = MurmurHash1;
-
-    ht->size += sizeof(CDBHASHTABLE);
-
-    return ht;
-}
-
-CDBHTITEM *cdb_ht_newitem(CDBHASHTABLE *ht, int ksize, int vsize)
-{
-    CDBHTITEM *item;
-    int hsize;
-
-    if (ht->lru)
-        hsize = sizeof(CDBHTITEM) + 2 * sizeof(void*);
-    else
-        hsize = sizeof(CDBHTITEM);
-
-    item = (CDBHTITEM*)malloc(hsize + ksize + vsize);
-    item->ksize = ksize;
-    item->vsize = vsize;
-    if (ht->lru) {
-        LRUPREV(item) = NULL;
-        LRUNEXT(item) = NULL;
-    }
-    return item;
-}
-
-
-
-
-void cdb_ht_insert(CDBHASHTABLE *ht, CDBHTITEM *item)
-{
-    uint32_t bid, hid;
-    CDBHTBUCKET *bucket;
-
-    item->hash = ht->hash(cdb_ht_itemkey(ht, item), item->ksize);
-    bid = item->hash & ((1<<CDBHTBNUMPOW)-1);
-    bucket = &(ht->buckets[bid]);
-    hid = (item->hash >> CDBHTBNUMPOW) & (bucket->bnum-1);
-
-    if (bucket->rnum > bucket->bnum * 2) {
-        CDBHTITEM **ilist;
-        uint32_t exp = 2;
-        if (bucket->bnum < 512) 
-            exp = 4;
-        int listsize = (bucket->bnum * exp) * sizeof(CDBHTITEM*);
-        ilist = (CDBHTITEM**)malloc(listsize);
-        memset(ilist, 0, listsize);
-        for(uint32_t i = 0; i < bucket->bnum; i++) {
-            CDBHTITEM *curitem = bucket->items[i];
-            while(curitem != NULL) {
-                CDBHTITEM *nextitem = curitem->hnext;
-                uint32_t hid = (curitem->hash>>CDBHTBNUMPOW)
-                    & (bucket->bnum * exp - 1);
-                curitem->hnext = ilist[hid];
-                ilist[hid] = curitem;
-                curitem = nextitem;
-            }
-        }
-        free(bucket->items);
-        bucket->items = ilist;
-        ht->size += listsize - bucket->bnum * sizeof(CDBHTITEM *);
-        bucket->bnum *= exp;
-        hid = (item->hash >> CDBHTBNUMPOW) & (bucket->bnum - 1);
-    }
-
-    {
-        CDBHTITEM *curitem = bucket->items[hid];
-        CDBHTITEM *preitem = NULL;
-        while(curitem != NULL) {
-            if (curitem->hash == item->hash
-                && curitem->ksize == item->ksize
-                && memcmp(cdb_ht_itemkey(ht, curitem),
-                cdb_ht_itemkey(ht, item) ,curitem->ksize) == 0) {
-                    CDBHTITEM *tmp;
-                    if (ht->lru) {
-                        if (LRUPREV(curitem))
-                            LRUNEXT(LRUPREV(curitem)) = LRUNEXT(curitem);
-                        if (LRUNEXT(curitem))
-                            LRUPREV(LRUNEXT(curitem)) = LRUPREV(curitem);
-                        if (ht->head == curitem)
-                            ht->head = LRUNEXT(curitem);
-                        if (ht->tail == curitem) 
-                            ht->tail = LRUPREV(curitem);
-                    }
-                    if (preitem)
-                        preitem->hnext = curitem->hnext;
-                    else
-                        bucket->items[hid] = curitem->hnext;
-                    tmp = curitem->hnext;
-                    ht->size -= sizeof(CDBHTITEM) + curitem->ksize + curitem->vsize
-                        + (ht->lru > 0) * sizeof(CDBHTITEM*) * 2;
-                    ht->num--;
-                    bucket->rnum--;
-                    free(curitem);
-                    curitem = tmp;
-                    break;
-            }
-            preitem = curitem;
-            curitem = curitem->hnext;
-        }
-    }
-
-    item->hnext = bucket->items[hid];
-    bucket->items[hid] = item;
-
-    if (ht->lru) {
-        if (ht->head) LRUPREV(ht->head) = item;
-        LRUPREV(item) = NULL;
-        LRUNEXT(item) = ht->head;
-        ht->head = item;
-        if (ht->tail == NULL)
-            ht->tail = item;
-    }
-
-    bucket->rnum++;
-    ht->num++;
-    ht->size += sizeof(CDBHTITEM) + item->ksize + item->vsize
-        + ht->lru * sizeof(CDBHTITEM*) * 2;
-}
-
-
-void *cdb_ht_insert2(CDBHASHTABLE *ht, const void *key, int ksize, const void *val, int vsize)
-{
-    CDBHTITEM *item;
-
-    item = cdb_ht_newitem(ht, ksize, vsize);
-    memcpy(cdb_ht_itemkey(ht, item), key, ksize);
-    memcpy(cdb_ht_itemval(ht, item), val, vsize);
-    cdb_ht_insert(ht, item);
-    return cdb_ht_itemval(ht, item);
-}
-
-void *cdb_ht_get(CDBHASHTABLE *ht, const void *key, int ksize, int *vsize, bool mtf)
-{
-    CDBHTITEM *res;
-
-    res = cdb_ht_get3(ht, key, ksize, mtf);
-    if (res) {
-        if(vsize)
-            *vsize = res->vsize;
-        return cdb_ht_itemval(ht, res);
-    } else { 
-        if(vsize)
-            *vsize = 0;
-        return NULL;
-    }
-}
-
-
-void *cdb_ht_get2(CDBHASHTABLE *ht, const void *key, int ksize, bool mtf)
-{
-    CDBHTITEM *res;
-
-    res = cdb_ht_get3(ht, key, ksize, mtf);
-    if (res)
-        return cdb_ht_itemval(ht, res);
-    else
-        return NULL;
-}
-
-
-CDBHTITEM *cdb_ht_get3(CDBHASHTABLE *ht, const void *key, int ksize, bool mtf)
-{
-    uint32_t hash, bid, hid;
-    CDBHTBUCKET *bucket;
-    CDBHTITEM *curitem;
-
-    hash = ht->hash(key, ksize);
-    bid = hash & ((1<<CDBHTBNUMPOW)-1);
-    bucket = &(ht->buckets[bid]);
-    hid = (hash >> CDBHTBNUMPOW) & (bucket->bnum - 1);
-
-    curitem = bucket->items[hid];
-    while (curitem != NULL) {
-        if (curitem->hash == hash
-            && curitem->ksize == ksize
-            && memcmp(cdb_ht_itemkey(ht, curitem), key , ksize) == 0) {
-                if (ht->lru && mtf && ht->head != curitem) {
-                    if (LRUPREV(curitem))
-                        LRUNEXT(LRUPREV(curitem)) = LRUNEXT(curitem);
-                    if (LRUNEXT(curitem))
-                        LRUPREV(LRUNEXT(curitem)) = LRUPREV(curitem);             
-                    if (ht->tail == curitem) 
-                        ht->tail = LRUPREV(curitem);
-
-                    LRUNEXT(curitem) = ht->head;
-                    LRUPREV(ht->head) = curitem;
-                    ht->head = curitem;
-                    LRUPREV(curitem) = NULL;
-                }
-                return curitem;
-        }
-        curitem = curitem->hnext;
-    }
-    return NULL;
-}
-
-
-bool cdb_ht_exist(CDBHASHTABLE *ht, const void *key, int ksize)
-{
-    int vsize;
-    return (cdb_ht_get(ht, key, ksize, &vsize, false) != NULL);
-}
-
-
-int cdb_ht_del2(CDBHASHTABLE *ht, const void *key, int ksize)
-{
-    CDBHTITEM *res = NULL;
-    res = cdb_ht_del(ht, key, ksize);
-    if (res) {
-        free(res);
-        return 0;
-    }
-    return -1;
-}
-
-
-CDBHTITEM *cdb_ht_del(CDBHASHTABLE *ht, const void *key, int ksize)
-{
-    uint32_t hash, bid, hid;
-    CDBHTBUCKET *bucket;
-    CDBHTITEM *curitem, *preitem;
-    CDBHTITEM *res = NULL;
-
-    hash = ht->hash(key, ksize);
-    bid = hash & ((1<<CDBHTBNUMPOW)-1);
-    bucket = &(ht->buckets[bid]);
-    hid = (hash >> CDBHTBNUMPOW) & (bucket->bnum - 1);
-
-    curitem = bucket->items[hid];
-    preitem = NULL;
-    while(curitem != NULL) {
-        if (curitem->hash == hash
-            && curitem->ksize == ksize
-            && memcmp(cdb_ht_itemkey(ht, curitem),
-            key, ksize) == 0) {
-            if (ht->lru) {
-                if (LRUPREV(curitem))
-                    LRUNEXT(LRUPREV(curitem)) = LRUNEXT(curitem);
-                if (LRUNEXT(curitem))
-                    LRUPREV(LRUNEXT(curitem)) = LRUPREV(curitem);
-                if (ht->head == curitem)
-                    ht->head = LRUNEXT(curitem);
-                if (ht->tail == curitem) 
-                    ht->tail = LRUPREV(curitem);
-            }
-            if (preitem)
-                preitem->hnext = curitem->hnext;
-            else
-                bucket->items[hid] = curitem->hnext;
-            ht->size -= sizeof(CDBHTITEM) + curitem->ksize + curitem->vsize
-                + (ht->lru > 0) * sizeof(CDBHTITEM*) * 2;
-            ht->num--;
-            bucket->rnum--;
-            res = curitem;
-            curitem = curitem->hnext;
-            break;
-        }
-        preitem = curitem;
-        curitem = curitem->hnext;
-    }
-
-    return res;
-}
-
-
-void cdb_ht_removetail(CDBHASHTABLE *ht)
-{
-    CDBHTITEM *item;
-
-    item = cdb_ht_poptail(ht);
-    if (item)
-        free(item);
-    return;
-}
-
-
-CDBHTITEM *cdb_ht_gettail(CDBHASHTABLE *ht)
-{
-    return ht->tail;
-}
-
-
-CDBHTITEM *cdb_ht_poptail(CDBHASHTABLE *ht)
-{
-    CDBHTITEM *item = ht->tail, *curitem, *preitem;;
-    CDBHTBUCKET *bucket;
-    uint32_t bid, hid;
-
-    if (!(ht->lru) || item == NULL)
-        return NULL;
-
-    bid = item->hash & ((1<<CDBHTBNUMPOW)-1);
-    bucket = &(ht->buckets[bid]);
-    hid = (item->hash >> CDBHTBNUMPOW) & (bucket->bnum - 1);
-
-    curitem = bucket->items[hid];
-    preitem = NULL;
-    while (curitem != NULL) {
-        if (curitem->hash == item->hash
-            && curitem->ksize == item->ksize
-            && memcmp(cdb_ht_itemkey(ht, curitem),
-            cdb_ht_itemkey(ht, item), item->ksize) == 0) {
-                if (preitem) {
-                    preitem->hnext = curitem->hnext;
-                } else {
-                    bucket->items[hid] = curitem->hnext;
-                }
-                break;   
-        }
-        preitem = curitem;
-        curitem = curitem->hnext;
-    }
-
-    if (LRUPREV(item))
-        LRUNEXT(LRUPREV(item)) = NULL;
-    if (ht->head == item)
-        ht->head = NULL;
-    ht->tail = LRUPREV(item);
-    bucket->rnum--;
-    ht->num--;
-    ht->size -= sizeof(CDBHTITEM) + item->ksize + item->vsize
-        + sizeof(CDBHTITEM*) * 2;
-    return item;
-}
-
-void cdb_ht_clean(CDBHASHTABLE *ht)
-{
-    for(uint32_t i = 0; i < (1<<CDBHTBNUMPOW); i++) {
-        CDBHTBUCKET *bucket = &(ht->buckets[i]);
-        for(uint32_t j = 0; j < bucket->bnum; j++) {
-            CDBHTITEM *curitem = bucket->items[j];
-            while(curitem != NULL) {
-                CDBHTITEM *tmp = curitem->hnext;
-                free(curitem);
-                curitem = tmp;
-            }
-            bucket->items[j] = NULL;
-        }
-        bucket->rnum = 0;
-    }
-    ht->num = 0;
-}
-
-
-void cdb_ht_destroy(CDBHASHTABLE *ht)
-{
-    if (ht->lru) {
-        CDBHTITEM *curitem = ht->head;
-        while(curitem) {
-            CDBHTITEM *nextitem = LRUNEXT(curitem);
-            free(curitem);
-            curitem = nextitem;
-        }
-    }
-
-    for(uint32_t i = 0; i < (1<<CDBHTBNUMPOW); i++) {
-        CDBHTBUCKET *bucket = &(ht->buckets[i]);
-
-        for(uint32_t j = 0; j < bucket->bnum && (!ht->lru); j++) {
-            CDBHTITEM *curitem = bucket->items[j];
-            while(curitem != NULL) {
-                CDBHTITEM *tmp = curitem->hnext;
-                free(curitem);
-                curitem = tmp;
-            }
-        }
-        free(bucket->items);
-    }
-    free(ht);
-}
-
-
-CDBHTITEM *cdb_ht_iterbegin(CDBHASHTABLE *ht)
-{
-    for(uint32_t i = 0; i < (1<<CDBHTBNUMPOW); i++) {
-        CDBHTBUCKET *bucket = &(ht->buckets[i]);
-        if (!bucket->rnum)
-            continue;
-        for(uint32_t j = 0; j < bucket->bnum; j++)
-            if (bucket->items[j])
-                return bucket->items[j];
-    }
-
-    return NULL;
-}
-
-
-CDBHTITEM *cdb_ht_iternext(CDBHASHTABLE *ht, CDBHTITEM *cur)
-{
-    if (cur == NULL)
-        return NULL;
-
-    if (cur->hnext)
-        return cur->hnext;
-
-    uint32_t bid = cur->hash & ((1<<CDBHTBNUMPOW)-1);
-    CDBHTBUCKET *bucket = &(ht->buckets[bid]);
-    uint32_t hid = (cur->hash >> CDBHTBNUMPOW) & (bucket->bnum - 1);
-
-    for(uint32_t i = hid + 1; i < bucket->bnum; i++) {
-        if (bucket->items[i])
-            return bucket->items[i];
-    }
-
-    for(uint32_t i = bid + 1; i < (1<<CDBHTBNUMPOW); i++) {
-        CDBHTBUCKET *bucket = &(ht->buckets[i]);
-        if (!bucket->rnum)
-            continue;
-        for(uint32_t  j = 0; j < bucket->bnum; j++)
-            if (bucket->items[j])
-                return bucket->items[j];
-    }
-
-    return NULL;
-}
-
-
-#ifdef _UT_
-#include <stdio.h>
-#include <time.h>
-int main(int argc, char *argv[])
-{
-    CDBHASHTABLE *ht;
-    long k, v;
-    ht = cdb_ht_new(true, NULL);
-    for(int i = 0; i < 1000; i++) {
-        k = i;
-        v = i * 1000;
-        cdb_ht_insert2(ht, &k, sizeof(long), &v, sizeof(long));
-    }
-
-    srand(time(NULL));
-
-    for(int i = 0; i < 1000; i++) {
-        long *v, k = rand() % 1000;
-        int vsize;
-        v = (long*)cdb_ht_get(ht, &k, sizeof(long), &vsize, true);
-        printf("get: %ld -> %ld (%d)\n", k, *v, vsize);
-    }
-
-    printf("total size: %d  num: %d\n", ht->size, ht->num);
-
-    CDBHTITEM *item;
-    item = cdb_ht_poptail(ht);
-    printf("tail:  %ld - %ld\n", *(long*)cdb_ht_itemkey(ht, item), *(long*)cdb_ht_itemval(ht, item));
-    free(item);
-    item = cdb_ht_poptail(ht);
-    printf("tail:  %ld - %ld\n", *(long*)cdb_ht_itemkey(ht, item), *(long*)cdb_ht_itemval(ht, item));
-    free(item);
-}
-#endif
diff --git a/3rdparty/cuttdb/src/cdb_hashtable.h b/3rdparty/cuttdb/src/cdb_hashtable.h
deleted file mode 100644
index 1f35b376dae7dd7618c24500dc729ab71577ad45..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_hashtable.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_HASHTABLE_H_
-#define _CDB_HASHTABLE_H_
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-typedef uint32_t (*CDBHASHFUNC)(const void *, int);
-
-/* default 1<<8 level-1 buckets, which makes the table expanding more smoothly */
-#define CDBHTBNUMPOW 8
-
-
-typedef struct CDBHTITEM
-{
-    int ksize;
-    int vsize;
-    uint32_t hash;
-    /* next element with the same hash */
-    struct CDBHTITEM *hnext;
-    /* if LRU is true, the first several bytes are two pointers of prev/next element */
-    struct CDBHTITEM *lruptr[0];
-    char buf[0];
-} __attribute__((packed)) CDBHTITEM;
-
-
-typedef struct {
-    /* array for items */
-    CDBHTITEM **items;
-    /* number of allocated slots in the bucket */
-    uint32_t bnum;
-    /* number of items exist in the bucket */
-    uint32_t rnum;
-} CDBHTBUCKET;
-
-
-typedef struct CDBHASHTABLE {
-    /* is in LRU mode? */
-    bool lru;
-    /* user specified hash function */
-    CDBHASHFUNC hash;
-    /* fixed number for level-1 buckets */
-    CDBHTBUCKET buckets[1<<CDBHTBNUMPOW];
-    /* memory usage */
-    uint64_t size;
-    /* number of items */
-    uint64_t num;
-    /* in LRU mode, the newest item */
-    CDBHTITEM *head;
-    /* in LRU mode, the oldest item */
-    CDBHTITEM *tail;
-} CDBHASHTABLE;
-
-
-/* get the pointer of key in current item */
-/* #define cdb_ht_itemkey(ht, item) (item->buf + ht->lru * 2 * sizeof(void*)) */
-void *cdb_ht_itemkey(CDBHASHTABLE *ht, CDBHTITEM *item);
-
-/* get the pointer of value in current item */
-/* #define cdb_ht_itemval(ht, item) (item->buf + ht->lru * 2 * sizeof(void*) + item->ksize) */
-void *cdb_ht_itemval(CDBHASHTABLE *ht, CDBHTITEM *item);
-
-/* create an hashtable, it can be a simple hashtable or with LeastRecentUse
-   The LRU mode needs extra two pointer space for every element
-   hash function can by specified by user */
-CDBHASHTABLE *cdb_ht_new(bool lru, CDBHASHFUNC hashfunc);
-
-/* clean and free the hastable */
-void cdb_ht_destroy(CDBHASHTABLE *ht);
-
-/* allocate a new item with specified size, but do not insert it into table */
-CDBHTITEM *cdb_ht_newitem(CDBHASHTABLE *ht, int ksize, int vsize);
-
-/* insert an item which already exists into table */
-void cdb_ht_insert(CDBHASHTABLE *ht, CDBHTITEM *item);
-
-/* allocate and insert an item into table by key and value, return the pointer of value in table */
-void *cdb_ht_insert2(CDBHASHTABLE *ht, const void *key, int ksize, const void *val, int vsize);
-
-/* get the value of an item and its size in table, move the item to front if mtf == true */
-void *cdb_ht_get(CDBHASHTABLE *ht, const void *key, int ksize, int *vsize, bool mtf);
-
-/* get the value of an item, assume the size is known, move the item to front if mtf == true */
-void *cdb_ht_get2(CDBHASHTABLE *ht, const void *key, int ksize, bool mtf);
-
-/* get the pointer of an item, it hasn't been copied */
-CDBHTITEM *cdb_ht_get3(CDBHASHTABLE *ht, const void *key, int ksize, bool mtf);
-
-/* check if an item with the key exists */
-bool cdb_ht_exist(CDBHASHTABLE *ht, const void *key, int ksize);
-
-/* delete and free an item from table by its key */
-int cdb_ht_del2(CDBHASHTABLE *ht, const void *key, int ksize);
-
-/* return and delete an item from table, the item should be freed by user */
-CDBHTITEM *cdb_ht_del(CDBHASHTABLE *ht, const void *key, int ksize);
-
-/* delete and free the last item in table */
-void cdb_ht_removetail(CDBHASHTABLE *ht);
-
-/* return last item in table, do not delete nor free */
-CDBHTITEM *cdb_ht_gettail(CDBHASHTABLE *ht);
-
-/* return last item in table, delete but should be freed by user */
-CDBHTITEM *cdb_ht_poptail(CDBHASHTABLE *ht);
-
-/* clean and free all elements in the table*/
-void cdb_ht_clean(CDBHASHTABLE *ht);
-
-/* iterate the table by get the front one firstly */
-CDBHTITEM *cdb_ht_iterbegin(CDBHASHTABLE *ht);
-
-/* get the next item of current element */
-CDBHTITEM *cdb_ht_iternext(CDBHASHTABLE *ht, CDBHTITEM *cur);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
-
diff --git a/3rdparty/cuttdb/src/cdb_lock.c b/3rdparty/cuttdb/src/cdb_lock.c
deleted file mode 100644
index 92aab58be4ec916aaa1037e48b62f641176ee9c6..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_lock.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cdb_lock.h"
-#include <stdlib.h>
-#include <pthread.h>
-#include <sched.h>
-
-
-CDBLOCK *cdb_lock_new(int ltype)
-{
-    CDBLOCK *lock = NULL;
-#ifndef DAP_OS_DARWIN
-    if (ltype == CDB_LOCKSPIN) {
-        lock = (CDBLOCK *)malloc(sizeof(CDBLOCK) + sizeof(pthread_spinlock_t));
-        pthread_spin_init((pthread_spinlock_t*)&lock->lock, PTHREAD_PROCESS_PRIVATE);
-    } else
-#endif
-    if (ltype == CDB_LOCKMUTEX) {
-        lock = (CDBLOCK *)malloc(sizeof(CDBLOCK) + sizeof(pthread_mutex_t));
-        pthread_mutex_init((pthread_mutex_t*)&lock->lock, NULL);
-    }
-    if( lock)
-        lock->ltype = ltype;
-
-    return lock;
-}
-
-
-void cdb_lock_lock(CDBLOCK *lock)
-{
-#ifndef DAP_OS_DARWIN
-    if (lock->ltype == CDB_LOCKSPIN)
-        pthread_spin_lock((pthread_spinlock_t*)&lock->lock);
-    else
-#endif
-        if (lock->ltype == CDB_LOCKMUTEX)
-            pthread_mutex_lock((pthread_mutex_t*)&lock->lock);
-}
-
-
-void cdb_lock_unlock(CDBLOCK *lock)
-{
-#ifndef DAP_OS_DARWIN
-    if (lock->ltype == CDB_LOCKSPIN)
-        pthread_spin_unlock((pthread_spinlock_t*)&lock->lock);
-    else
-#endif
-        if (lock->ltype == CDB_LOCKMUTEX)
-        pthread_mutex_unlock((pthread_mutex_t*)&lock->lock);
-}
-
-
-void cdb_lock_destory(CDBLOCK *lock)
-{
-#ifndef DAP_OS_DARWIN
-    if (lock->ltype == CDB_LOCKSPIN)
-        pthread_spin_destroy((pthread_spinlock_t*)&lock->lock);
-    else
-#endif
-        if (lock->ltype == CDB_LOCKMUTEX)
-            pthread_mutex_destroy((pthread_mutex_t*)&lock->lock);
-
-    free(lock);
-}
-
-
-int cdb_lock_trylock(CDBLOCK *lock)
-{
-#ifndef DAP_OS_DARWIN
-    if (lock->ltype == CDB_LOCKSPIN)
-        return pthread_spin_trylock((pthread_spinlock_t*)&lock->lock);
-    else
-#endif
-        if (lock->ltype == CDB_LOCKMUTEX)
-            return pthread_mutex_trylock((pthread_mutex_t*)&lock->lock);
-    return 0;
-}
-
diff --git a/3rdparty/cuttdb/src/cdb_lock.h b/3rdparty/cuttdb/src/cdb_lock.h
deleted file mode 100644
index bbd13098603bc0e0048d9e752b646ea7fea7d53a..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_lock.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_LOCK_H_
-#define _CDB_LOCK_H_
-
-
-enum {
-    /* spinlock */
-#ifndef DAP_OS_DARWIN
-    CDB_LOCKSPIN,
-#endif
-    /* mutex, which may cause OS context switch, mainly used in where Disk IO happens */
-    CDB_LOCKMUTEX,
-};
-
-/* may be used to indicated whether the area is protected */
-enum {
-    CDB_LOCKED,
-    CDB_NOTLOCKED,
-};
-
-typedef struct CDBLOCK
-{
-    int ltype;
-    char lock[0];
-} CDBLOCK;
-
-
-CDBLOCK *cdb_lock_new(int ltype);
-void cdb_lock_lock(CDBLOCK *lock);
-void cdb_lock_unlock(CDBLOCK *lock);
-void cdb_lock_destory(CDBLOCK *lock);
-int cdb_lock_trylock(CDBLOCK *lock);
-
-
-
-#endif
-
diff --git a/3rdparty/cuttdb/src/cdb_types.h b/3rdparty/cuttdb/src/cdb_types.h
deleted file mode 100644
index c32676d1bbc16ddef0b39c44b91df51cead61ba9..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_types.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_TYPES_H_
-#define _CDB_TYPES_H_
-#include <stdint.h>
-
-#define KB 1024
-#define MB 1048576
-#define CDBMIN(a, b) ((a)<(b)?(a):(b))
-#define CDBMAX(a, b) ((a)>(b)?(a):(b))
-
-#define SI8 8
-#define SI4 4
-/* space reserved in stack for i/o, avoid some malloc/free */
-#define SBUFSIZE (64 * KB)
-
-/* a default disk read size for index page, 3KB is enough(a page with 300 items) */
-#define PAGEAREADSIZE (3 * KB)
-
-/* reserved in stack for matched items in a hash index page */
-#define SFOFFNUM 8
-
-/* a valid virtual offset */
-#define OFFNOTNULL(o) (((o).i4)||((o).i2))
-/* a null virtual offset */
-#define OFFNULL(o) (((o).i4==0)&&((o).i2==0))
-/* nullify an offset  */
-#define OFFZERO(o) do{(o).i4=0;(o).i2=0;}while(0)
-/* offset is equal ? */
-#define OFFEQ(a,b) (((a).i4==(b).i4)&&((a).i2==(b).i2))
-/* hash in page is equal ? */
-#define PHASHEQ(a,b) (((a).i2==(b).i2)&&((a).i1==(b).i1))
-/* page size increment */
-#define CDB_PAGEINCR 4
-
-
-/* if page cache size exceeds the limit */
-#define PCOVERFLOW(db) ( (db) && (db)->dpcache && (db)->pcache && (db)->dpcache->size + (db)->pcache->size > (db)->pclimit)
-/* if record cache size exceeds the limit */
-#define RCOVERFLOW(db) ((db) && (db)->rcache && (db)->rcache->size > (db)->rclimit)
-
-/* timeout for a dirty index page stays since last modify */
-#define DPAGETIMEOUT 40
-/* operation on main table are isolated by these locks */
-#define MLOCKNUM 256
-
-#define CDBHASH64(a, b) cdb_crc64(a, b) 
-
-/* all virtual offsets are 48-bits */
-typedef struct FOFF
-{
-    uint32_t i4;
-    uint16_t i2;
-} __attribute__((packed)) FOFF;
-
-
-
-#define SFOFF (sizeof(FOFF))
-
-
-/* all hash value in index page are 24-bits 
-    range 0..16M guarantee very low collision 
-    with less than a hundred records in a page */
-typedef struct PHASH
-{
-    uint16_t i2;
-    uint8_t i1;
-} __attribute__((packed)) PHASH;
-
-
-/* an item in index page contains a hash and an offset */
-typedef struct PITEM
-{
-    FOFF off;
-    PHASH hash;
-} __attribute__((packed)) PITEM;
-
-
-/* data record */
-typedef struct CDBREC{
-    /* where the data come from */
-    FOFF ooff;
-    uint32_t osize;
-
-    /* access convenient*/
-    void *key;
-    void *val;
-
-    /* disk store starts at following field */
-    uint32_t magic;
-    uint32_t ksize;
-    uint32_t vsize;
-    uint32_t expire;
-    uint64_t oid;
-    char buf[0];
-} __attribute__((packed)) CDBREC;
-
-/* real size of a record header when stored on disk */
-#define RECHSIZE (SI4 * 4 + SI8)
-/* real size of a record when stored on disk */
-#define RECSIZE(r) (RECHSIZE + (r)->ksize + (r)->vsize)
-
-
-/* index page */
-typedef struct CDBPAGE{
-    FOFF ooff;
-    uint32_t osize;
-    uint32_t cap;
-
-    union {
-        /* what it be on disk */
-        uint32_t magic;
-        /* what it be in memory */
-        uint32_t mtime;
-    };
-    /* which bucket it belongs to */
-    uint32_t bid;
-    uint32_t num;
-    uint64_t oid;
-    PITEM items[0];
-} __attribute__((packed)) CDBPAGE;
-
-/* real size of a page header when stored on disk */
-#define PAGEHSIZE (SI4 * 3 + SI8)
-/* real size of a page when stored on disk */
-#define PAGESIZE(p) (PAGEHSIZE + sizeof(PITEM) * (p)->num)
-/* in-memory size of an record structure */
-#define MPAGESIZE(p) (sizeof(CDBPAGE) + sizeof(PITEM) * (p)->cap)
-
-#endif
-
diff --git a/3rdparty/cuttdb/src/cdb_vio.c b/3rdparty/cuttdb/src/cdb_vio.c
deleted file mode 100644
index c0da6d1572812cbda4afe795cf24e25a733e375b..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_vio.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cdb_vio.h"
-#include "cdb_types.h"
-#include "vio_apnd2.h"
-#include "stdlib.h"
-
-
-CDBVIO *cdb_vio_new(int type)
-{
-    CDBVIO *res;
-    res = (CDBVIO *)malloc(sizeof(CDBVIO));
-    switch(type) {
-        case CDBVIOAPND2:
-            vio_apnd2_init(res);
-            break;
-        default:
-            vio_apnd2_init(res);
-            break;
-    }
-    return res;
-}
-
-int cdb_vio_destroy(CDBVIO *vio)
-{
-    free(vio);
-    return 0;
-}
-
diff --git a/3rdparty/cuttdb/src/cdb_vio.h b/3rdparty/cuttdb/src/cdb_vio.h
deleted file mode 100644
index 5c6e7e205813f11d84d45f0fa8916cff1edc3bbe..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cdb_vio.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CDB_VIO_H_
-#define _CDB_VIO_H_
-#include "cdb_types.h"
-#include "cuttdb.h"
-#include <stdint.h>
-#include <stdbool.h>
-
-enum {
-    /* obsoleted */
-    CDBVIOAPPEND,
-    /* append only format storage */
-    CDBVIOAPND2,
-};
-
-typedef struct CDBVIO CDBVIO;
-
-/* write a record, returns virtual offset at 3rd parameter */
-typedef int (*VIOWRITEREC)(CDBVIO*, CDBREC*, FOFF*);
-/* delete a record, pass in the current offset at 3rd parameter */
-typedef int (*VIODELETEREC)(CDBVIO*, CDBREC*, FOFF);
-/* read a record, 2nd parameter default points to stack buffer, if its real size
-greater than the stack buffer size, it will be changed to points to a space in heap, 
-the last parameter decides whether read the whole record or just read key for comparsion */
-typedef int (*VIOREADREC)(CDBVIO*, CDBREC**, FOFF, bool);
-/* close the storage */
-typedef int (*VIOCLOSE)(CDBVIO*);
-/* open the storage, pass in the storage path and open mode */
-typedef int (*VIOOPEN)(CDBVIO*, const char*, int);
-/* write an index page, return its virtual offset at 3rd parameter */
-typedef int (*VIOWRITEPAGE)(CDBVIO*, CDBPAGE *, FOFF*);
-/* read an index page, 2nd parameter default points to stack buffer, if its real size
-greater than the stack buffer size, it will be changed to points to a space in heap */
-typedef int (*VIOREADPAGE)(CDBVIO*, CDBPAGE **, FOFF);
-/* make the storage do an sync operation */
-typedef int (*VIOSYNC)(CDBVIO*);
-/* write db header, which contains main-index */
-typedef int (*VIOWRITEHEAD)(CDBVIO*);
-/* read db header, which contains main-index */
-typedef int (*VIOREADHEAD)(CDBVIO*);
-/* tell that no dirty page exists */
-typedef void (*VIOCLEANPOINT)(CDBVIO*);
-/* get the record/page iterator at oid */
-typedef void* (*VIOITFIRST)(CDBVIO *, uint64_t oid);
-/* get the next index page by iterator */
-typedef int (*VIOPAGEITNEXT)(CDBVIO *, CDBPAGE **, void *);
-/* get the next record by iterator */
-typedef int (*VIORECITNEXT)(CDBVIO *, CDBREC **, void *);
-/* destroy and free the iterator */
-typedef void (*VIOITDESTROY)(CDBVIO *, void *);
-
-struct CDBVIO 
-{
-    VIOOPEN open;
-    VIOCLOSE close;
-
-    VIOWRITEREC wrec;
-    VIODELETEREC drec;
-    VIOREADREC rrec;
-
-    VIOWRITEPAGE wpage;
-    VIOREADPAGE rpage;
-
-    VIOSYNC sync;
-    VIOWRITEHEAD whead;
-    VIOREADHEAD rhead;
-    
-    VIOCLEANPOINT cleanpoint;
-
-    VIOITFIRST pageitfirst;
-    VIOPAGEITNEXT pageitnext;
-    VIOITDESTROY pageitdestroy;
-
-    VIOITFIRST recitfirst;
-    VIORECITNEXT recitnext;
-    VIOITDESTROY recitdestroy;
-
-    CDB *db;
-    void *iometa;
-};
-
-
-CDBVIO *cdb_vio_new(int type);
-int cdb_vio_destroy(CDBVIO *vio);
-
-
-#endif
diff --git a/3rdparty/cuttdb/src/cuttdb-server.c b/3rdparty/cuttdb/src/cuttdb-server.c
deleted file mode 100644
index 9b09a2863a28eeb88b74eebd1f23ebf6f6bfaa71..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cuttdb-server.c
+++ /dev/null
@@ -1,2152 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   The server&network part of CuttDB is based on Beansdb:
- *
- *   http://beansdb.googlecode.com
- *
- *   Beansdb is most based on Memcachedb and Memcached:
- *
- *   http://memcachedb.org/
- *   http://danga.com/memcached/
- *
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cuttdb-server.h"
-#include "cuttdb.h"
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <signal.h>
-#include <sys/resource.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-/* need this to get IOV_MAX on some platforms. */
-#ifndef __need_IOV_MAX
-#define __need_IOV_MAX
-#endif
-#include <pwd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-#include <limits.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-
-#ifdef HAVE_READPROC
-#include <proc/readproc.h>
-#endif
-
-#ifdef HAVE_MALLOC_H
-/* OpenBSD has a malloc.h, but warns to use stdlib.h instead */
-#ifndef __OpenBSD__
-#include <malloc.h>
-#endif
-#endif
-
-/* FreeBSD 4.x doesn't have IOV_MAX exposed. */
-#ifndef IOV_MAX
-#if defined(__FreeBSD__) || defined(__APPLE__)
-# define IOV_MAX 1024
-#endif
-#endif
-
-#ifndef IOV_MAX
-# define IOV_MAX 1024
-#endif
-
-#ifndef CLOCK_MONOTONIC
-#include "clock_gettime_stub.c"
-#endif
-
-/*
- * forward declarations
- */
-static int new_socket(struct addrinfo *ai);
-static int server_socket(const int port, const bool is_udp);
-static int try_read_command(conn *c);
-static int try_read_network(conn *c);
-
-/* stats */
-static void stats_reset(void);
-static void stats_init(void);
-
-/* defaults */
-static void settings_init(void);
-
-/* event handling, network IO */
-static void conn_close(conn *c);
-static void conn_init(void);
-static bool update_event(conn *c, const int new_flags);
-int delete_event(int fd);
-static void complete_nread(conn *c);
-static void process_command(conn *c, char *command);
-static int transmit(conn *c);
-static int ensure_iov_space(conn *c);
-static int add_iov(conn *c, const void *buf, int len);
-static int add_msghdr(conn *c);
-static void conn_free(conn *c);
-
-
-static size_t item_make_header(const uint8_t nkey, const int flags, const int nbytes,
-                     char *suffix, uint8_t *nsuffix);
-static int item_free(item *it);
-static item *item_get(char *key, size_t nkey);
-static item *item_alloc1(char *key, const size_t nkey, const int flags, const int nbytes);
-
-/** exported globals **/
-struct stats stats;
-struct settings settings;
-
-CDB *db = NULL;
-FILE   *access_log = NULL;
-int daemon_quit = 0;
-
-/** file scope variables **/
-static int stub_fd = 0;
-
-#define TRANSMIT_COMPLETE   0
-#define TRANSMIT_INCOMPLETE 1
-#define TRANSMIT_SOFT_ERROR 2
-#define TRANSMIT_HARD_ERROR 3
-
-
-void item_init(void) {
-    /*freeitemtotal = INIT_ITEM_FREELIST_LENGTH;
-    freeitemcurr  = 0;
-
-    freeitem = (item **)malloc( sizeof(item *) * freeitemtotal );
-    if (freeitem == NULL) {
-        perror("malloc()");
-    }*/
-    return;
-}
-
-static size_t item_make_header(const uint8_t nkey, const int flags, const int nbytes,
-                     char *suffix, uint8_t *nsuffix) {
-    /* suffix is defined at 40 chars elsewhere.. */
-    *nsuffix = (uint8_t) snprintf(suffix, 40, " %d %d\r\n", flags, nbytes - 2);
-    return sizeof(item) + nkey + *nsuffix + nbytes;
-}
-
-static int item_free(item *it)
-{
-    free(it);
-    return 0;
-}
-
-static item *item_get(char *key, size_t nkey)
-{
-    item *it = NULL;
-    int vlen;
-    uint32_t flag;
-    void *value;
-    int ret = cdb_get(db, key, nkey, &value, &vlen);
-    flag = 0;
-    if (ret == 0){
-        it = item_alloc1(key, nkey, flag, vlen + 2);
-        if (it){
-            memcpy(ITEM_data(it), value, vlen);
-            memcpy(ITEM_data(it) + vlen, "\r\n", 2);
-        }
-        cdb_free_val(&value);
-    }
-    return it;
-
-}
-
-static item *item_alloc1(char *key, const size_t nkey, const int flags, const int nbytes)
-{
-    uint8_t nsuffix;
-    item *it;
-    char suffix[40];
-    size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix);
-
-    it = (item *)malloc(ntotal);
-    if (it == NULL){
-        return NULL;
-    }
-    memset(it, 0, ntotal);
-
-    it->nkey = nkey;
-    it->nbytes = nbytes;
-    strcpy(ITEM_key(it), key);
-    memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);
-    it->nsuffix = nsuffix;
-    return it;
-}
-
-
-static void stats_init(void) {
-    stats.curr_conns = stats.total_conns = stats.conn_structs = 0;
-    stats.get_cmds = stats.set_cmds = stats.delete_cmds = 0;
-    stats.slow_cmds = stats.get_hits = stats.get_misses = 0;
-    stats.bytes_read = stats.bytes_written = 0;
-
-    /* make the time we started always be 2 seconds before we really
-       did, so time(0) - time.started is never zero.  if so, things
-       like 'settings.oldest_live' which act as booleans as well as
-       values are now false in boolean context... */
-    stats.started = time(0) - 2;
-}
-
-static void stats_reset(void) {
-    STATS_LOCK();
-    stats.total_conns = 0;
-    stats.get_cmds = stats.set_cmds = stats.delete_cmds = 0;
-    stats.slow_cmds = stats.get_hits = stats.get_misses = 0;
-    stats.bytes_read = stats.bytes_written = 0;
-    STATS_UNLOCK();
-}
-
-static void settings_init(void) {
-    settings.port = 8964;
-    /* By default this string should be NULL for getaddrinfo() */
-    settings.inter = NULL;
-    settings.item_buf_size = 4 * 1024;     /* default is 4KB */
-    settings.maxconns = 1024;         /* to limit connections-related memory to about 5MB */
-    settings.verbose = 0;
-    settings.num_threads = 16;
-    settings.flush_period = 1;  // 1 secs
-    settings.slow_cmd_time = 0.1; // 100ms
-}
-
-/*
- * Adds a message header to a connection.
- *
- * Returns 0 on success, -1 on out-of-memory.
- */
-static int add_msghdr(conn *c)
-{
-    struct msghdr *msg;
-
-    assert(c != NULL);
-
-    if (c->msgsize == c->msgused) {
-        msg = realloc(c->msglist, c->msgsize * 2 * sizeof(struct msghdr));
-        if (! msg)
-            return -1;
-        c->msglist = msg;
-        c->msgsize *= 2;
-    }
-
-    msg = c->msglist + c->msgused;
-
-    /* this wipes msg_iovlen, msg_control, msg_controllen, and
-       msg_flags, the last 3 of which aren't defined on solaris: */
-    memset(msg, 0, sizeof(struct msghdr));
-
-    msg->msg_iov = &c->iov[c->iovused];
-
-    c->msgbytes = 0;
-    c->msgused++;
-
-    return 0;
-}
-
-
-/*
- * Free list management for connections.
- */
-
-static conn **freeconns;
-static int freetotal;
-static int freecurr;
-
-
-static void conn_init(void) {
-    freetotal = 200;
-    freecurr = 0;
-    if ((freeconns = (conn **)malloc(sizeof(conn *) * freetotal)) == NULL) {
-        fprintf(stderr, "malloc()\n");
-    }
-    return;
-}
-
-/*
- * Returns a connection from the freelist, if any. Should call this using
- * conn_from_freelist() for thread safety.
- */
-conn *do_conn_from_freelist() {
-    conn *c;
-
-    if (freecurr > 0) {
-        c = freeconns[--freecurr];
-    } else {
-        c = NULL;
-    }
-
-    return c;
-}
-
-/*
- * Adds a connection to the freelist. 0 = success. Should call this using
- * conn_add_to_freelist() for thread safety.
- */
-bool do_conn_add_to_freelist(conn *c) {
-    if (freecurr < freetotal) {
-        freeconns[freecurr++] = c;
-        return false;
-    } else {
-        /* try to enlarge free connections array */
-        conn **new_freeconns = realloc(freeconns, sizeof(conn *) * freetotal * 2);
-        if (new_freeconns) {
-            freetotal *= 2;
-            freeconns = new_freeconns;
-            freeconns[freecurr++] = c;
-            return false;
-        }
-    }
-    return true;
-}
-
-conn *conn_new(const int sfd, const int init_state, const int read_buffer_size) {
-    conn *c = conn_from_freelist();
-
-    if (NULL == c) {
-        if (!(c = (conn *)calloc(1, sizeof(conn)))) {
-            fprintf(stderr, "calloc()\n");
-            return NULL;
-        }
-        c->rbuf = c->wbuf = 0;
-        c->ilist = 0;
-        c->iov = 0;
-        c->msglist = 0;
-
-        c->rsize = read_buffer_size;
-        c->wsize = DATA_BUFFER_SIZE;
-        c->isize = ITEM_LIST_INITIAL;
-        c->iovsize = IOV_LIST_INITIAL;
-        c->msgsize = MSG_LIST_INITIAL;
-
-        c->rbuf = (char *)malloc((size_t)c->rsize);
-        c->wbuf = (char *)malloc((size_t)c->wsize);
-        c->ilist = (item **)malloc(sizeof(item *) * c->isize);
-        c->iov = (struct iovec *)malloc(sizeof(struct iovec) * c->iovsize);
-        c->msglist = (struct msghdr *)malloc(sizeof(struct msghdr) * c->msgsize);
-
-        if (c->rbuf == 0 || c->wbuf == 0 || c->ilist == 0 || c->iov == 0 ||
-                c->msglist == 0) {
-            conn_free(c);
-            fprintf(stderr, "malloc()\n");
-            return NULL;
-        }
-
-        STATS_LOCK();
-        stats.conn_structs++;
-        STATS_UNLOCK();
-    }
-
-    if (settings.verbose > 1) {
-        if (init_state == conn_listening)
-            fprintf(stderr, "<%d server listening\n", sfd);
-        else
-            fprintf(stderr, "<%d new client connection\n", sfd);
-    }
-
-    c->sfd = sfd;
-    c->state = init_state;
-    c->rlbytes = 0;
-    c->rbytes = c->wbytes = 0;
-    c->wcurr = c->wbuf;
-    c->rcurr = c->rbuf;
-    c->ritem = 0;
-    c->icurr = c->ilist;
-    c->ileft = 0;
-    c->iovused = 0;
-    c->msgcurr = 0;
-    c->msgused = 0;
-
-    c->write_and_go = conn_read;
-    c->write_and_free = 0;
-    c->item = 0;
-    c->noreply = false;
-    
-    update_event(c, AE_READABLE);
-    if (add_event(sfd, AE_READABLE, c) == -1) {
-        if (conn_add_to_freelist(c)) {
-            conn_free(c);
-        }
-        perror("event_add");
-        return NULL;
-    }
-
-    STATS_LOCK();
-    stats.curr_conns++;
-    stats.total_conns++;
-    STATS_UNLOCK();
-
-    return c;
-}
-
-static void conn_cleanup(conn *c) {
-    assert(c != NULL);
-
-    if (c->item) {
-        item_free(c->item);
-        c->item = 0;
-    }
-
-    if (c->ileft != 0) {
-        for (; c->ileft > 0; c->ileft--,c->icurr++) {
-            item_free(*(c->icurr));
-        }
-    }
-
-    if (c->write_and_free) {
-        free(c->write_and_free);
-        c->write_and_free = 0;
-    }
-}
-
-/*
- * Frees a connection.
- */
-void conn_free(conn *c) {
-    if (c) {
-        if (c->msglist)
-            free(c->msglist);
-        if (c->rbuf)
-            free(c->rbuf);
-        if (c->wbuf)
-            free(c->wbuf);
-        if (c->ilist)
-            free(c->ilist);
-        if (c->iov)
-            free(c->iov);
-        free(c);
-    }
-}
-
-static void conn_close(conn *c) {
-    assert(c != NULL);
-
-    if (settings.verbose > 1)
-        fprintf(stderr, "<%d connection closed.\n", c->sfd);
-
-    delete_event(c->sfd);
-    close(c->sfd);
-    c->sfd = -1;
-    update_event(c, 0);
-    conn_cleanup(c);
-
-    /* if the connection has big buffers, just free it */
-    if (c->rsize > READ_BUFFER_HIGHWAT || conn_add_to_freelist(c)) {
-        conn_free(c);
-    }
-
-    STATS_LOCK();
-    stats.curr_conns--;
-    STATS_UNLOCK();
-
-    return;
-}
-
-
-/*
- * Shrinks a connection's buffers if they're too big.  This prevents
- * periodic large "get" requests from permanently chewing lots of server
- * memory.
- *
- * This should only be called in between requests since it can wipe output
- * buffers!
- */
-static void conn_shrink(conn *c) {
-    assert(c != NULL);
-
-    if (c->rsize > READ_BUFFER_HIGHWAT && c->rbytes < DATA_BUFFER_SIZE) {
-        char *newbuf;
-
-        if (c->rcurr != c->rbuf)
-            memmove(c->rbuf, c->rcurr, (size_t)c->rbytes);
-
-        newbuf = (char *)realloc((void *)c->rbuf, DATA_BUFFER_SIZE);
-
-        if (newbuf) {
-            c->rbuf = newbuf;
-            c->rsize = DATA_BUFFER_SIZE;
-        }
-        /* TODO check other branch... */
-        c->rcurr = c->rbuf;
-    }
-
-    if (c->isize > ITEM_LIST_HIGHWAT) {
-        item **newbuf = (item**) realloc((void *)c->ilist, ITEM_LIST_INITIAL * sizeof(c->ilist[0]));
-        if (newbuf) {
-            c->ilist = newbuf;
-            c->isize = ITEM_LIST_INITIAL;
-        }
-    /* TODO check error condition? */
-    }
-
-    if (c->msgsize > MSG_LIST_HIGHWAT) {
-        struct msghdr *newbuf = (struct msghdr *) realloc((void *)c->msglist, MSG_LIST_INITIAL * sizeof(c->msglist[0]));
-        if (newbuf) {
-            c->msglist = newbuf;
-            c->msgsize = MSG_LIST_INITIAL;
-        }
-    /* TODO check error condition? */
-    }
-
-    if (c->iovsize > IOV_LIST_HIGHWAT) {
-        struct iovec *newbuf = (struct iovec *) realloc((void *)c->iov, IOV_LIST_INITIAL * sizeof(c->iov[0]));
-        if (newbuf) {
-            c->iov = newbuf;
-            c->iovsize = IOV_LIST_INITIAL;
-        }
-    /* TODO check return value */
-    }
-}
-
-/*
- * Sets a connection's current state in the state machine. Any special
- * processing that needs to happen on certain state transitions can
- * happen here.
- */
-static void conn_set_state(conn *c, int state) {
-    assert(c != NULL);
-
-    if (state != c->state) {
-        if (state == conn_read) {
-            conn_shrink(c);
-        }
-        c->state = state;
-    }
-}
-
-
-/*
- * Ensures that there is room for another struct iovec in a connection's
- * iov list.
- *
- * Returns 0 on success, -1 on out-of-memory.
- */
-static int ensure_iov_space(conn *c) {
-    assert(c != NULL);
-
-    if (c->iovused >= c->iovsize) {
-        int i, iovnum;
-        struct iovec *new_iov = (struct iovec *)realloc(c->iov,
-                                (c->iovsize * 2) * sizeof(struct iovec));
-        if (! new_iov)
-            return -1;
-        c->iov = new_iov;
-        c->iovsize *= 2;
-
-        /* Point all the msghdr structures at the new list. */
-        for (i = 0, iovnum = 0; i < c->msgused; i++) {
-            c->msglist[i].msg_iov = &c->iov[iovnum];
-            iovnum += c->msglist[i].msg_iovlen;
-        }
-    }
-
-    return 0;
-}
-
-
-/*
- * Adds data to the list of pending data that will be written out to a
- * connection.
- *
- * Returns 0 on success, -1 on out-of-memory.
- */
-
-static int add_iov(conn *c, const void *buf, int len) {
-    struct msghdr *m;
-    int leftover;
-    bool limit_to_mtu;
-
-    assert(c != NULL);
-
-    do {
-        m = &c->msglist[c->msgused - 1];
-
-        /*
-         * Limit the first payloads of TCP replies, to
-         * MAX_PAYLOAD_SIZE bytes.
-         */
-        limit_to_mtu = (1 == c->msgused);
-
-        /* We may need to start a new msghdr if this one is full. */
-        if (m->msg_iovlen == IOV_MAX ||
-            (limit_to_mtu && c->msgbytes >= MAX_PAYLOAD_SIZE)) {
-            add_msghdr(c);
-            m = &c->msglist[c->msgused - 1];
-        }
-
-        if (ensure_iov_space(c) != 0)
-            return -1;
-
-        /* If the fragment is too big to fit in the datagram, split it up */
-        if (limit_to_mtu && len + c->msgbytes > MAX_PAYLOAD_SIZE) {
-            leftover = len + c->msgbytes - MAX_PAYLOAD_SIZE;
-            len -= leftover;
-        } else {
-            leftover = 0;
-        }
-
-        m = &c->msglist[c->msgused - 1];
-        m->msg_iov[m->msg_iovlen].iov_base = (void *)buf;
-        m->msg_iov[m->msg_iovlen].iov_len = len;
-
-        c->msgbytes += len;
-        c->iovused++;
-        m->msg_iovlen++;
-
-        buf = ((char *)buf) + len;
-        len = leftover;
-    } while (leftover > 0);
-
-    return 0;
-}
-
-
-static void out_string(conn *c, const char *str) {
-    size_t len;
-
-    assert(c != NULL);
-
-    if (c->noreply) {
-        if (settings.verbose > 1)
-            fprintf(stderr, ">%d %s\n", c->sfd, str);
-        c->noreply = false;
-        conn_set_state(c, conn_read);
-        return;
-    }    
-
-    len = strlen(str);
-    if ((len + 2) > c->wsize) {
-        /* ought to be always enough. just fail for simplicity */
-        str = "SERVER_ERROR output line too long";
-        len = strlen(str);
-    }
-
-    memcpy(c->wbuf, str, len);
-    memcpy(c->wbuf + len, "\r\n", 2);
-    c->wbytes = len + 2;
-    c->wcurr = c->wbuf;
-
-    conn_set_state(c, conn_write);
-    c->write_and_go = conn_read;
-    return;
-}
-
-/*
- * we get here after reading the value in set/add/replace commands. The command
- * has been stored in c->item_comm, and the item is ready in c->item.
- */
-
-static void complete_nread(conn *c) {
-    assert(c != NULL);
-
-    item *it = c->item;
-    int comm = c->item_comm;
-    int ret;
-
-    STATS_LOCK();
-    stats.set_cmds++;
-    STATS_UNLOCK();
-
-    if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
-        out_string(c, "CLIENT_ERROR bad data chunk");
-    } else {
-      ret = store_item(it, comm);
-      if (ret == 0)
-          out_string(c, "STORED");
-      else if(ret == -2)
-          out_string(c, "EXISTS");
-      else if(ret == -3)
-          out_string(c, "NOT_FOUND");
-      else
-          out_string(c, "NOT_STORED");
-    }
-
-    item_free(c->item);
-    c->item = 0;
-}
-
-/*
- * Stores an item in the cache according to the semantics of one of the set
- * commands. In threaded mode, this is protected by the cache lock.
- *
- * Returns true if the item was stored.
- */
-int store_item(item *it, int comm) {
-    char *key = ITEM_key(it);
-
-    switch (comm) {
-    case NREAD_SET:
-        return cdb_set2(db, key, it->nkey, ITEM_data(it), it->nbytes - 2, CDB_INSERTCACHE | CDB_OVERWRITE, it->expire);
-    case NREAD_ADD:
-        return cdb_set2(db, key, it->nkey, ITEM_data(it), it->nbytes - 2, CDB_INSERTCACHE | CDB_INSERTIFNOEXIST, it->expire);
-    case NREAD_REPLACE:
-        return cdb_set2(db, key, it->nkey, ITEM_data(it), it->nbytes - 2, CDB_INSERTCACHE | CDB_INSERTIFEXIST, it->expire);
-    }
-    return 0;
-}
-
-/*
- * adds a delta value to a numeric item.
- */
-/*
-
-int add_delta(char *key, size_t nkey, int64_t delta, char *buf);
-int add_delta(char* key, size_t nkey, int64_t delta, char *buf) {
-    uint64_t value = hs_incr(db, key, delta);
-    snprintf(buf, INCR_MAX_STORAGE_LEN, "%llu", (unsigned long long)value);
-    return 0;
-}
-*/
-
-typedef struct token_s {
-    char *value;
-    size_t length;
-} token_t;
-
-#define COMMAND_TOKEN 0
-#define SUBCOMMAND_TOKEN 1
-#define KEY_TOKEN 1
-#define KEY_MAX_LENGTH 250
-
-#define MAX_TOKENS 8
-
-/*
- * Tokenize the command string by replacing whitespace with '\0' and update
- * the token array tokens with pointer to start of each token and length.
- * Returns total number of tokens.  The last valid token is the terminal
- * token (value points to the first unprocessed character of the string and
- * length zero).
- *
- * Usage example:
- *
- *  while(tokenize_command(command, ncommand, tokens, max_tokens) > 0) {
- *      for(int ix = 0; tokens[ix].length != 0; ix++) {
- *          ...
- *      }
- *      ncommand = tokens[ix].value - command;
- *      command  = tokens[ix].value;
- *   }
- */
-static size_t tokenize_command(char *command, token_t *tokens, const size_t max_tokens) {
-    char *s, *e;
-    size_t ntokens = 0;
-
-    assert(command != NULL && tokens != NULL && max_tokens > 1);
-
-    for (s = e = command; ntokens < max_tokens - 1; ++e) {
-        if (*e == ' ') {
-            if (s != e) {
-                tokens[ntokens].value = s;
-                tokens[ntokens].length = e - s;
-                ntokens++;
-                *e = '\0';
-            }
-            s = e + 1;
-        }
-        else if (*e == '\0') {
-            if (s != e) {
-                tokens[ntokens].value = s;
-                tokens[ntokens].length = e - s;
-                ntokens++;
-            }
-
-            break; /* string end */
-        }
-    }
-
-    /*
-     * If we scanned the whole string, the terminal value pointer is null,
-     * otherwise it is the first unprocessed character.
-     */
-    tokens[ntokens].value =  *e == '\0' ? NULL : e;
-    tokens[ntokens].length = 0;
-    ntokens++;
-
-    return ntokens;
-}
-
-static inline bool set_noreply_maybe(conn *c, token_t *tokens, size_t ntokens)
-{
-    int noreply_index = ntokens - 2;
-
-    /*
-      NOTE: this function is not the first place where we are going to
-      send the reply.  We could send it instead from process_command()
-      if the request line has wrong number of tokens.  However parsing
-      malformed line for "noreply" option is not reliable anyway, so
-      it can't be helped.
-    */
-    if (tokens[noreply_index].value
-        && strcmp(tokens[noreply_index].value, "noreply") == 0) {
-        c->noreply = true;
-    }
-    return c->noreply;
-}
-
-static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
-    time_t now = time(0);
-    char *command;
-    char *subcommand;
-
-    assert(c != NULL);
-
-    if(ntokens < 2) {
-        out_string(c, "CLIENT_ERROR bad command line");
-        return;
-    }
-
-    command = tokens[COMMAND_TOKEN].value;
-
-    if (ntokens == 2 && strcmp(command, "stats") == 0) {
-        char temp[1024];
-        pid_t pid = getpid();
-        uint64_t total = 0, curr = 0;
-        CDBSTAT db_stat;
-        cdb_stat(db, &db_stat);
-        total = db_stat.rnum;
-        char *pos = temp;
-
-#ifndef WIN32
-        struct rusage usage;
-        getrusage(RUSAGE_SELF, &usage);
-#endif /* !WIN32 */
-
-        STATS_LOCK();
-        pos += sprintf(pos, "STAT pid %ld\r\n", (long)pid);
-        pos += sprintf(pos, "STAT uptime %"PRIuS"\r\n", now - stats.started);
-        pos += sprintf(pos, "STAT time %"PRIuS"\r\n", now);
-        pos += sprintf(pos, "STAT version " VERSION "\r\n");
-        pos += sprintf(pos, "STAT pointer_size %"PRIuS"\r\n", 8 * sizeof(void *));
-#ifndef WIN32
-        pos += sprintf(pos, "STAT rusage_user %ld.%06ld\r\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
-        pos += sprintf(pos, "STAT rusage_system %ld.%06ld\r\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
-        pos += sprintf(pos, "STAT rusage_minflt %"PRIu64"\r\n", usage.ru_minflt);
-        pos += sprintf(pos, "STAT rusage_majflt %"PRIu64"\r\n", usage.ru_majflt);
-        pos += sprintf(pos, "STAT rusage_nswap %"PRIu64"\r\n", usage.ru_nswap);
-        pos += sprintf(pos, "STAT rusage_inblock %"PRIu64"\r\n", usage.ru_inblock);
-        pos += sprintf(pos, "STAT rusage_oublock %"PRIu64"\r\n", usage.ru_oublock);
-        pos += sprintf(pos, "STAT rusage_nvcsw %"PRIu64"\r\n", usage.ru_nvcsw);
-        pos += sprintf(pos, "STAT rusage_nivcsw %"PRIu64"\r\n", usage.ru_nivcsw);
-#endif /* !WIN32 */
-#ifdef HAVE_READPROC
-        proc_t p;
-        get_proc_stats(getpid(), &p);
-        pos += sprintf(pos, "STAT rusage_maxrss %"PRIu64"\r\n", p.vm_rss);
-#endif
-        pos += sprintf(pos, "STAT item_buf_size %"PRIuS"\r\n", settings.item_buf_size);
-        pos += sprintf(pos, "STAT curr_connections %"PRIu32"\r\n", stats.curr_conns - 1); /* ignore listening conn */
-        pos += sprintf(pos, "STAT total_connections %"PRIu32"\r\n", stats.total_conns);
-        pos += sprintf(pos, "STAT connection_structures %"PRIu32"\r\n", stats.conn_structs);
-        pos += sprintf(pos, "STAT cmd_get %"PRIu64"\r\n", stats.get_cmds);
-        pos += sprintf(pos, "STAT cmd_set %"PRIu64"\r\n", stats.set_cmds);
-        pos += sprintf(pos, "STAT cmd_delete %"PRIu64"\r\n", stats.delete_cmds);
-        pos += sprintf(pos, "STAT slow_cmd %"PRIu64"\r\n", stats.slow_cmds);
-        pos += sprintf(pos, "STAT get_hits %"PRIu64"\r\n", stats.get_hits);
-        pos += sprintf(pos, "STAT get_misses %"PRIu64"\r\n", stats.get_misses);
-        pos += sprintf(pos, "STAT curr_items %"PRIu64"\r\n", curr); 
-        pos += sprintf(pos, "STAT total_items %"PRIu64"\r\n", total); 
-        pos += sprintf(pos, "STAT bytes_read %"PRIu64"\r\n", stats.bytes_read);
-        pos += sprintf(pos, "STAT bytes_written %"PRIu64"\r\n", stats.bytes_written);
-        pos += sprintf(pos, "STAT threads %d\r\n", settings.num_threads);
-        pos += sprintf(pos, "STAT records_in_cache %lu\r\n", db_stat.rcnum);
-        pos += sprintf(pos, "STAT pages_total %lu\r\n", db_stat.pnum);
-        pos += sprintf(pos, "STAT pages_in_cache %lu\r\n", db_stat.pcnum);
-        pos += sprintf(pos, "STAT record_cache_hits %lu\r\n", db_stat.rchit);
-        pos += sprintf(pos, "STAT record_cache_misses %lu\r\n", db_stat.rcmiss);
-        pos += sprintf(pos, "STAT page_cache_hits %lu\r\n", db_stat.pchit);
-        pos += sprintf(pos, "STAT page_cache_misses %lu\r\n", db_stat.pcmiss);
-        pos += sprintf(pos, "STAT read_latency_avg  %u\r\n", db_stat.rlatcy);
-        pos += sprintf(pos, "STAT write_latency_avg %u\r\n", db_stat.wlatcy);
-        pos += sprintf(pos, "END");
-        STATS_UNLOCK();
-        out_string(c, temp);
-        return;
-    }
-
-    subcommand = tokens[SUBCOMMAND_TOKEN].value;
-
-    if (strcmp(subcommand, "reset") == 0) {
-        stats_reset();
-        out_string(c, "RESET");
-        return;
-    }
-
-    out_string(c, "ERROR");
-}
-
-/* ntokens is overwritten here... shrug.. */
-static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens) {
-    char *key;
-    size_t nkey;
-    int i = 0;
-    item *it = NULL;
-    token_t *key_token = &tokens[KEY_TOKEN];
-    int stats_get_cmds   = 0;
-    int stats_get_hits   = 0;
-    int stats_get_misses = 0;
-    assert(c != NULL);
-
-    do {
-        while(key_token->length != 0) {
-
-            key = key_token->value;
-            nkey = key_token->length;
-
-            if(nkey > KEY_MAX_LENGTH) {
-                STATS_LOCK();
-                stats.get_cmds   += stats_get_cmds;
-                stats.get_hits   += stats_get_hits;
-                stats.get_misses += stats_get_misses;
-                STATS_UNLOCK();
-                out_string(c, "CLIENT_ERROR bad command line format");
-                return;
-            }
-
-            stats_get_cmds++;
-            
-            it = item_get(key, nkey);
-
-            if (it) {
-                if (i >= c->isize) {
-                    item **new_list = realloc(c->ilist, sizeof(item *) * c->isize * 2);
-                    if (new_list) {
-                        c->isize *= 2;
-                        c->ilist = new_list;
-                    } else { 
-                        item_free(it);
-                        it = NULL;
-                        break;
-                    }
-                }
-
-                /*
-                 * Construct the response. Each hit adds three elements to the
-                 * outgoing data list:
-                 *   "VALUE "
-                 *   key
-                 *   " " + flags + " " + data length + "\r\n" + data (with \r\n)
-                 */
-
-                if (add_iov(c, "VALUE ", 6) != 0 ||
-                   add_iov(c, ITEM_key(it), it->nkey) != 0 ||
-                   add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0)
-                   {
-                       item_free(it);
-                       it = NULL;
-                       break;
-                   }
-
-                if (settings.verbose > 1)
-                    fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it));
-
-                stats_get_hits++;
-                *(c->ilist + i) = it;
-                i++;
-
-            } else {
-                stats_get_misses++;
-            }
-
-            key_token++;
-        }
-
-        /*
-         * If the command string hasn't been fully processed, get the next set
-         * of tokens.
-         */
-        if(key_token->value != NULL) {
-            ntokens = tokenize_command(key_token->value, tokens, MAX_TOKENS);
-            key_token = tokens;
-        }
-
-    } while(key_token->value != NULL);
-
-    c->icurr = c->ilist;
-    c->ileft = i;
-
-    if (settings.verbose > 1)
-        fprintf(stderr, ">%d END\n", c->sfd);
-
-    /*
-        If the loop was terminated because of out-of-memory, it is not
-        reliable to add END\r\n to the buffer, because it might not end
-        in \r\n. So we send SERVER_ERROR instead.
-    */
-    if (key_token->value != NULL || add_iov(c, "END\r\n", 5) != 0) {
-        out_string(c, "SERVER_ERROR out of memory writing get response");
-    }
-    else {
-        conn_set_state(c, conn_mwrite);
-        c->msgcurr = 0;
-    }
-
-    STATS_LOCK();
-    stats.get_cmds   += stats_get_cmds;
-    stats.get_hits   += stats_get_hits;
-    stats.get_misses += stats_get_misses;
-    STATS_UNLOCK();
-
-    return;
-}
-
-static void process_update_command(conn *c, token_t *tokens, const size_t ntokens, int comm) {
-    char *key;
-    size_t nkey;
-    int flags;
-    time_t exptime;
-    int vlen;
-    item *it = NULL;
-
-    assert(c != NULL);
-
-    set_noreply_maybe(c, tokens, ntokens);
-
-    if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
-        out_string(c, "CLIENT_ERROR bad command line format");
-        return;
-    }
-
-    key = tokens[KEY_TOKEN].value;
-    nkey = tokens[KEY_TOKEN].length;
-
-    flags = strtoul(tokens[2].value, NULL, 10);
-    exptime = strtol(tokens[3].value, NULL, 10);
-    vlen = strtol(tokens[4].value, NULL, 10);
-
-    if(errno == ERANGE || ((flags == 0 || exptime == 0) && errno == EINVAL)
-       || vlen < 0) {
-        out_string(c, "CLIENT_ERROR bad command line format");
-        return;
-    }
-
-    it = item_alloc1(key, nkey, flags, vlen+2);
-    it->expire = exptime;
-    it->flag = flags;
-
-    if (it == NULL) {
-        out_string(c, "SERVER_ERROR out of memory storing object");
-        /* swallow the data line */
-        c->write_and_go = conn_swallow;
-        c->sbytes = vlen + 2;
-        return;
-    }
-
-    c->item = it;
-    c->ritem = ITEM_data(it);
-    c->rlbytes = it->nbytes;
-    c->item_comm = comm;
-    conn_set_state(c, conn_nread);
-}
-
-bool safe_strtoull(const char *str, uint64_t *out) {
-    assert(out != NULL);
-    errno = 0;
-    *out = 0;
-    char *endptr;
-    unsigned long long ull = strtoull(str, &endptr, 10);
-    if (errno == ERANGE)
-        return false;
-    if (isspace(*endptr) || (*endptr == '\0' && endptr != str)) {
-        *out = ull;
-        return true;
-    }
-    return false;
-}
-
-/*
-
-
-static void process_arithmetic_command(conn *c, token_t *tokens, const size_t ntokens, const bool incr) {
-    char temp[INCR_MAX_STORAGE_LEN];
-    uint64_t delta;
-    char *key;
-    size_t nkey;
-
-    assert(c != NULL);
-
-    set_noreply_maybe(c, tokens, ntokens);
- 
-    STATS_LOCK();
-    stats.set_cmds++;
-    STATS_UNLOCK();
-
-    if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
-        out_string(c, "CLIENT_ERROR bad command line format");
-        return;
-    }
-
-    key = tokens[KEY_TOKEN].value;
-    nkey = tokens[KEY_TOKEN].length;
-
-    if (!safe_strtoull(tokens[2].value, &delta)) {
-        out_string(c, "CLIENT_ERROR invalid numeric delta argument");
-        return;
-    }
-    
-    switch(add_delta(key, nkey, delta, temp)) {
-    case 0:
-        out_string(c, temp);
-        break;
-//    case NON_NUMERIC:
-//        out_string(c, "CLIENT_ERROR cannot increment or decrement non-numeric value");
-//        break;
-//    case EOM:
-//        out_string(c, "SERVER_ERROR out of memory");
-//        break;
-    }
-}
-*/
-
-
-static void process_delete_command(conn *c, token_t *tokens, const size_t ntokens) {
-    char *key;
-    size_t nkey;
-    assert(c != NULL);
-    
-    set_noreply_maybe(c, tokens, ntokens);
-    
-    STATS_LOCK();
-    stats.delete_cmds++;
-    STATS_UNLOCK();
-
-    key = tokens[KEY_TOKEN].value;
-    nkey = tokens[KEY_TOKEN].length;
-    if(nkey > KEY_MAX_LENGTH) {
-        out_string(c, "CLIENT_ERROR bad command line format");
-        return;
-    }
-
-    switch (cdb_del(db, key, nkey)) {
-    case 0:
-        out_string(c, "DELETED");
-        break;
-    case -3:
-        out_string(c, "NOT_FOUND");
-        break;
-//    case -1:
-//        out_string(c, "SERVER_ERROR while delete a item");
-//        break;
-//    default:
-//        out_string(c, "SERVER_ERROR nothing to do");
-    }
-    return;
-}
-
-static void process_verbosity_command(conn *c, token_t *tokens, const size_t ntokens) {
-    unsigned int level;
-
-    assert(c != NULL);
-    
-    set_noreply_maybe(c, tokens, ntokens);
-
-    level = strtoul(tokens[1].value, NULL, 10);
-    if(errno == ERANGE) {
-        out_string(c, "CLIENT_ERROR bad command line format");
-        return;
-    }
-    settings.verbose = level > MAX_VERBOSITY_LEVEL ? MAX_VERBOSITY_LEVEL : level;
-    out_string(c, "OK");
-    return;
-}
-
-static void process_command(conn *c, char *command) {
-
-    token_t tokens[MAX_TOKENS];
-    size_t ntokens;
-    int comm;
-    struct timespec start, end;
-
-    assert(c != NULL);
-
-    if (settings.verbose > 1)
-        fprintf(stderr, "<%d %s\n", c->sfd, command);
-
-    /*
-     * for commands set/add/replace, we build an item and read the data
-     * directly into it, then continue in nread_complete().
-     */
-
-    c->msgcurr = 0;
-    c->msgused = 0;
-    c->iovused = 0;
-    if (add_msghdr(c) != 0) {
-        out_string(c, "SERVER_ERROR out of memory preparing response");
-        return;
-    }
-
-    clock_gettime(CLOCK_MONOTONIC, &start);          
-
-    ntokens = tokenize_command(command, tokens, MAX_TOKENS);
-    if (ntokens >= 3 &&
-        (strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) ) {
-
-        process_get_command(c, tokens, ntokens);
-
-    } else if ((ntokens == 6 || ntokens == 7) &&
-                ((strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || 
-                 (strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
-                 (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) {
-
-        process_update_command(c, tokens, ntokens, comm);
-
-//    } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) {
-
-//            process_arithmetic_command(c, tokens, ntokens, 1);
-
-    } else if (ntokens >= 3 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) {
-
-        process_delete_command(c, tokens, ntokens);
-
-    } else if (ntokens >= 2 && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == 0)) {
-
-        process_stat(c, tokens, ntokens);
-
-    } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "version") == 0)) {
-
-        out_string(c, "VERSION " VERSION);
-
-    } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "quit") == 0)) {
-
-        conn_set_state(c, conn_closing);
-
-    } else if (ntokens == 3 && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) {
-
-        process_verbosity_command(c, tokens, ntokens);
-    
-/*    } else if (ntokens >= 2 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) {
-
-        set_noreply_maybe(c, tokens, ntokens);
-
-        int limit = 10000;
-        if (ntokens == (c->noreply ? 4 : 3)) {
-            limit = strtol(tokens[1].value, NULL, 10);
-            if(errno == ERANGE) {
-                out_string(c, "CLIENT_ERROR bad command line format");
-                return;
-            }
-        }
-        
-        hs_optimize(db, limit);
-        out_string(c, "OK");
-        return;
-*/
-    } else {
-        out_string(c, "ERROR");
-        return;
-    }
-    
-    clock_gettime(CLOCK_MONOTONIC, &end);
-    float secs = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
-    if (secs > settings.slow_cmd_time) {
-        STATS_LOCK();
-        stats.slow_cmds ++;
-        STATS_UNLOCK();
-    }
-
-    // access logging
-    if (NULL != access_log && ntokens >= 3) {
-        char now[255];
-        time_t t = time(NULL);
-        strftime(now, 200, "%Y-%m-%d %H:%M:%S", localtime(&t));
-        struct sockaddr_storage addr;
-        socklen_t addrlen = sizeof(addr);
-        getpeername(c->sfd, (struct sockaddr*)&addr, &addrlen);
-        char host[NI_MAXHOST], serv[NI_MAXSERV];
-        getnameinfo((struct sockaddr*)&addr, addrlen,  host, sizeof(host), serv, sizeof(serv), 
-                NI_NUMERICSERV);
-        fprintf(access_log, "%s %s:%s %s %s %.3f\n", now, host, serv, 
-                command, tokens[1].value, secs*1000);
-    }
-
-    return;
-}
-
-/*
- * if we have a complete line in the buffer, process it.
- */
-static int try_read_command(conn *c) {
-    char *el, *cont;
-
-    assert(c != NULL);
-    assert(c->rcurr <= (c->rbuf + c->rsize));
-
-    if (c->rbytes == 0)
-        return 0;
-    el = memchr(c->rcurr, '\n', c->rbytes);
-    if (!el)
-        return 0;
-    cont = el + 1;
-    if ((el - c->rcurr) > 1 && *(el - 1) == '\r') {
-        el--;
-    }
-    *el = '\0';
-
-    assert(cont <= (c->rcurr + c->rbytes));
-
-    process_command(c, c->rcurr);
-
-    c->rbytes -= (cont - c->rcurr);
-    c->rcurr = cont;
-
-    assert(c->rcurr <= (c->rbuf + c->rsize));
-
-    return 1;
-}
-
-/*
- * read from network as much as we can, handle buffer overflow and connection
- * close.
- * before reading, move the remaining incomplete fragment of a command
- * (if any) to the beginning of the buffer.
- * return 0 if there's nothing to read on the first read.
- */
-static int try_read_network(conn *c) {
-    int gotdata = 0;
-    int res;
-
-    assert(c != NULL);
-
-    if (c->rcurr != c->rbuf) {
-        if (c->rbytes != 0) /* otherwise there's nothing to copy */
-            memmove(c->rbuf, c->rcurr, c->rbytes);
-        c->rcurr = c->rbuf;
-    }
-
-    while (1) {
-        if (c->rbytes >= c->rsize) {
-            char *new_rbuf = realloc(c->rbuf, c->rsize * 2);
-            if (!new_rbuf) {
-                if (settings.verbose > 0)
-                    fprintf(stderr, "Couldn't realloc input buffer\n");
-                c->rbytes = 0; /* ignore what we read */
-                out_string(c, "SERVER_ERROR out of memory reading request");
-                c->write_and_go = conn_closing;
-                return 1;
-            }
-            c->rcurr = c->rbuf = new_rbuf;
-            c->rsize *= 2;
-        }
-
-
-        int avail = c->rsize - c->rbytes;
-        res = read(c->sfd, c->rbuf + c->rbytes, avail);
-        if (res > 0) {
-            STATS_LOCK();
-            stats.bytes_read += res;
-            STATS_UNLOCK();
-            gotdata = 1;
-            c->rbytes += res;
-            if (res == avail) {
-                continue;
-            } else {
-                break;
-            }
-        }
-        if (res == 0) {
-            /* connection closed */
-            conn_set_state(c, conn_closing);
-            return 1;
-        }
-        if (res == -1) {
-            if (errno == EAGAIN || errno == EWOULDBLOCK) break;
-            /* Should close on unhandled errors. */
-            conn_set_state(c, conn_closing);
-            return 1;
-        }
-    }
-    return gotdata;
-}
-
-static bool update_event(conn *c, const int new_flags) {
-    c->ev_flags = new_flags;
-    return true;
-}
-
-/*
- * Transmit the next chunk of data from our list of msgbuf structures.
- *
- * Returns:
- *   TRANSMIT_COMPLETE   All done writing.
- *   TRANSMIT_INCOMPLETE More data remaining to write.
- *   TRANSMIT_SOFT_ERROR Can't write any more right now.
- *   TRANSMIT_HARD_ERROR Can't write (c->state is set to conn_closing)
- */
-static int transmit(conn *c) {
-    assert(c != NULL);
-
-    if (c->msgcurr < c->msgused &&
-            c->msglist[c->msgcurr].msg_iovlen == 0) {
-        /* Finished writing the current msg; advance to the next. */
-        c->msgcurr++;
-    }
-    if (c->msgcurr < c->msgused) {
-        ssize_t res;
-        struct msghdr *m = &c->msglist[c->msgcurr];
-
-        res = sendmsg(c->sfd, m, 0);
-        if (res > 0) {
-            STATS_LOCK();
-            stats.bytes_written += res;
-            STATS_UNLOCK();
-
-            /* We've written some of the data. Remove the completed
-               iovec entries from the list of pending writes. */
-            while (m->msg_iovlen > 0 && res >= m->msg_iov->iov_len) {
-                res -= m->msg_iov->iov_len;
-                m->msg_iovlen--;
-                m->msg_iov++;
-            }
-
-            /* Might have written just part of the last iovec entry;
-               adjust it so the next write will do the rest. */
-            if (res > 0) {
-                m->msg_iov->iov_base += res;
-                m->msg_iov->iov_len -= res;
-            }
-            return TRANSMIT_INCOMPLETE;
-        }
-        if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
-            update_event(c, AE_WRITABLE);
-            return TRANSMIT_SOFT_ERROR;
-        }
-        /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
-           we have a real error, on which we close the connection */
-        if (settings.verbose > 0)
-            perror("Failed to write, and not due to blocking");
-
-        conn_set_state(c, conn_closing);
-        return TRANSMIT_HARD_ERROR;
-    } else {
-        return TRANSMIT_COMPLETE;
-    }
-}
-
-void drive_machine(conn *c) {
-    bool stop = false;
-    int sfd, flags = 1;
-    socklen_t addrlen;
-    struct sockaddr_storage addr;
-    int res;
-
-    assert(c != NULL);
-
-    while (!stop) {
-
-        switch(c->state) {
-        case conn_listening:
-            addrlen = sizeof(addr);
-            if ((sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen)) == -1) {
-                stop = true;
-                if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                    /* these are transient, so don't log anything */
-                } else if (errno == EMFILE) {
-                    if (settings.verbose > 0)
-                        fprintf(stderr, "Too many open connections\n");
-                    if (stub_fd > 0){
-                        close(stub_fd);
-                        if ((sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen)) != -1) {
-                            close(sfd);
-                            stub_fd = open("/dev/null", O_RDONLY);
-                            stop = false;
-                        }else{
-                            if (settings.verbose > 0)
-                                fprintf(stderr, "Too many open connections 2\n");
-                        }
-                    }
-                } else {
-                    perror("accept()");
-                }
-                if (stop) break;
-            }
-            if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
-                fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
-                perror("setting O_NONBLOCK");
-                close(sfd);
-                break;
-            }
-            if (NULL == conn_new(sfd, conn_read, DATA_BUFFER_SIZE)) { 
-                if (settings.verbose > 0) {
-                    fprintf(stderr, "Can't listen for events on fd %d\n", sfd);
-                }
-                close(sfd);
-            }
-            break;
-
-        case conn_read:
-            if (try_read_command(c) != 0) {
-                continue;
-            }
-            if (try_read_network(c) != 0) {
-                continue;
-            }
-            /* we have no command line and no data to read from network */
-            update_event(c, AE_READABLE);
-            stop = true;
-            break;
-
-        case conn_nread:
-            /* we are reading rlbytes into ritem; */
-            if (c->rlbytes == 0) {
-                complete_nread(c);
-                break;
-            }
-            /* first check if we have leftovers in the conn_read buffer */
-            if (c->rbytes > 0) {
-                int tocopy = c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes;
-                memcpy(c->ritem, c->rcurr, tocopy);
-                c->ritem += tocopy;
-                c->rlbytes -= tocopy;
-                c->rcurr += tocopy;
-                c->rbytes -= tocopy;
-                break;
-            }
-
-            /*  now try reading from the socket */
-            res = read(c->sfd, c->ritem, c->rlbytes);
-            if (res > 0) {
-                STATS_LOCK();
-                stats.bytes_read += res;
-                STATS_UNLOCK();
-                c->ritem += res;
-                c->rlbytes -= res;
-                break;
-            }
-            if (res == 0) { /* end of stream */
-                conn_set_state(c, conn_closing);
-                break;
-            }
-            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
-                update_event(c, AE_READABLE);
-                stop = true;
-                break;
-            }
-            /* otherwise we have a real error, on which we close the connection */
-            if (settings.verbose > 0)
-                fprintf(stderr, "Failed to read, and not due to blocking\n");
-            conn_set_state(c, conn_closing);
-            break;
-
-        case conn_swallow:
-            /* we are reading sbytes and throwing them away */
-            if (c->sbytes == 0) {
-                conn_set_state(c, conn_read);
-                break;
-            }
-
-            /* first check if we have leftovers in the conn_read buffer */
-            if (c->rbytes > 0) {
-                int tocopy = c->rbytes > c->sbytes ? c->sbytes : c->rbytes;
-                c->sbytes -= tocopy;
-                c->rcurr += tocopy;
-                c->rbytes -= tocopy;
-                break;
-            }
-
-            /*  now try reading from the socket */
-            res = read(c->sfd, c->rbuf, c->rsize > c->sbytes ? c->sbytes : c->rsize);
-            if (res > 0) {
-                STATS_LOCK();
-                stats.bytes_read += res;
-                STATS_UNLOCK();
-                c->sbytes -= res;
-                break;
-            }
-            if (res == 0) { /* end of stream */
-                conn_set_state(c, conn_closing);
-                break;
-            }
-            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
-                update_event(c, AE_READABLE);
-                stop = true;
-                break;
-            }
-            /* otherwise we have a real error, on which we close the connection */
-            if (settings.verbose > 0)
-                fprintf(stderr, "Failed to read, and not due to blocking\n");
-            conn_set_state(c, conn_closing);
-            break;
-
-        case conn_write:
-            /*
-             * We want to write out a simple response. If we haven't already,
-             * assemble it into a msgbuf list (this will be a single-entry
-             * list for TCP or a two-entry list for UDP).
-             */
-            if (c->iovused == 0) {
-                if (add_iov(c, c->wcurr, c->wbytes) != 0) {
-                    if (settings.verbose > 0)
-                        fprintf(stderr, "Couldn't build response\n");
-                    conn_set_state(c, conn_closing);
-                    break;
-                }
-            }
-
-            /* fall through... */
-
-        case conn_mwrite:
-            switch (transmit(c)) {
-            case TRANSMIT_COMPLETE:
-                if (c->state == conn_mwrite) {
-                    while (c->ileft > 0) {
-                        item *it = *(c->icurr);
-                        item_free(it);
-                        c->icurr++;
-                        c->ileft--;
-                    }
-                    conn_set_state(c, conn_read);
-                } else if (c->state == conn_write) {
-                    if (c->write_and_free) {
-                        free(c->write_and_free);
-                        c->write_and_free = 0;
-                    }
-                    conn_set_state(c, c->write_and_go);
-                } else {
-                    if (settings.verbose > 0)
-                        fprintf(stderr, "Unexpected state %d\n", c->state);
-                    conn_set_state(c, conn_closing);
-                }
-                break;
-
-            case TRANSMIT_INCOMPLETE:
-            case TRANSMIT_HARD_ERROR:
-                break;                   /* Continue in state machine. */
-
-            case TRANSMIT_SOFT_ERROR:
-                stop = true;
-                break;
-            }
-            break;
-
-        case conn_closing:
-            conn_close(c);
-            stop = true;
-            break;
-        }
-    }
-
-    return;
-}
-
-static int new_socket(struct addrinfo *ai) {
-    int sfd;
-    int flags;
-
-    if ((sfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) {
-        perror("socket()");
-        return -1;
-    }
-
-    if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
-        fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
-        perror("setting O_NONBLOCK");
-        close(sfd);
-        return -1;
-    }
-    return sfd;
-}
-
-static int server_socket(const int port, const bool is_udp) {
-    int sfd;
-    struct linger ling = {0, 0};
-    struct addrinfo *ai;
-    struct addrinfo *next;
-    struct addrinfo hints;
-    char port_buf[NI_MAXSERV];
-    int error;
-    int success = 0;
-
-    int flags =1;
-
-    /*
-     * the memset call clears nonstandard fields in some impementations
-     * that otherwise mess things up.
-     */
-    memset(&hints, 0, sizeof (hints));
-    hints.ai_flags = AI_PASSIVE|AI_ADDRCONFIG;
-    hints.ai_family = AF_UNSPEC;
-    hints.ai_protocol = IPPROTO_TCP;
-    hints.ai_socktype = SOCK_STREAM;
-
-    snprintf(port_buf, NI_MAXSERV, "%d", port);
-    error= getaddrinfo(settings.inter, port_buf, &hints, &ai);
-    if (error != 0) {
-      if (error != EAI_SYSTEM)
-        fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
-      else
-        perror("getaddrinfo()");
-
-      return 1;
-    }
-
-    for (next= ai; next; next= next->ai_next) {
-        conn *listen_conn_add;
-        if ((sfd = new_socket(next)) == -1) {
-            freeaddrinfo(ai);
-            return 1;
-        }
-
-        setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
-        setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
-        setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
-        setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
-
-        if (bind(sfd, next->ai_addr, next->ai_addrlen) == -1) {
-            if (errno != EADDRINUSE) {
-                perror("bind()");
-                close(sfd);
-                freeaddrinfo(ai);
-                return 1;
-            }
-            close(sfd);
-            continue;
-        } else {
-          success++;
-          if (listen(sfd, 1024) == -1) {
-              perror("listen()");
-              close(sfd);
-              freeaddrinfo(ai);
-              return 1;
-          }
-      }
-
-      if (!(listen_conn_add = conn_new(sfd, conn_listening, 1))) {
-          fprintf(stderr, "failed to create listening connection\n");
-          exit(EXIT_FAILURE);
-      }
-    }
-
-    freeaddrinfo(ai);
-
-    /* Return zero iff we detected no errors in starting up connections */
-    return success == 0;
-}
-
-static void usage(void) {
-    printf(PACKAGE " " VERSION "\n");
-    printf("-p <num>      TCP port number to listen on (default: 8964)\n"
-           "-l <ip_addr>  interface to listen on, default is INDRR_ANY\n"
-           "-d            run as a daemon\n"
-           "-P <num>      page cache limit(MB), default 256(MB)\n"
-           "-r <num>      record cache limit(MB), default 256(MB)\n"
-           "-R <num>      bytes for a disk read operation, must be between[1024,65535), recommend to be larger than most small records, default is 4096(Bytes)\n"
-           "-L <file>     log file\n"
-           "-u <username> assume identity of <username> (only when run as root)\n"
-           "-c <num>      max simultaneous connections, default is 1024\n"
-           "-t <num>      number of threads to use, default 16\n"
-           "-H <dir>      home of database, default is 'testdb', keep sure the directory exists\n"
-           "-s <num>      slow command time limit, in ms, default is 100ms\n"
-           "-n            main hash table size, recommend to be 1%% - 10%% of maximum record num, default is 1000000\n"
-           "-v            verbose (print errors/warnings while in event loop)\n"
-           "-vv           very verbose (also print client commands/reponses)\n"
-           "-h            print this help and exit\n"
-           "-i            print license info\n"
-           );
-
-    return;
-}
-
-static void usage_license(void) {
-    printf(PACKAGE " " VERSION "\n\n");
-    printf(
-    "Copyright (c) 2012, Siyuan Fu. <fusiyuan2010@gmail.com>\n"
-    "All rights reserved.\n"
-    "\n"
-    "\n"
-    "This product includes software developed by Douban Inc.\n"
-    "\n"
-    "[ Beansdb ]\n"
-    "\n"
-    "Copyright (c) 2009, Douban Inc. <http://www.douban.com/>\n"
-    "All rights reserved.\n"
-    "\n"
-    "Redistribution and use in source and binary forms, with or without\n"
-    "modification, are permitted provided that the following conditions are\n"
-    "met:\n"
-    "\n"
-    "    * Redistributions of source code must retain the above copyright\n"
-    "notice, this list of conditions and the following disclaimer.\n"
-    "\n"
-    "    * Redistributions in binary form must reproduce the above\n"
-    "copyright notice, this list of conditions and the following disclaimer\n"
-    "in the documentation and/or other materials provided with the\n"
-    "distribution.\n"
-    "\n"
-    "    * Neither the name of the Douban Inc. nor the names of its\n"
-    "contributors may be used to endorse or promote products derived from\n"
-    "this software without specific prior written permission.\n"
-    "\n"
-    "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-    "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-    "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-    "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-    "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-    "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-    "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-    "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-    "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-    "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-    "\n"
-    "\n"
-    "This product includes software developed by Douban Inc.\n"
-    "\n"
-    "[ memcachedb ]\n"
-    "\n"
-    "Copyright (c) 2008, Steve Chu. <stvchu@gmail.com>\n"
-    "All rights reserved.\n"
-    "\n"
-    "Redistribution and use in source and binary forms, with or without\n"
-    "modification, are permitted provided that the following conditions are\n"
-    "met:\n"
-    "\n"
-    "    * Redistributions of source code must retain the above copyright\n"
-    "notice, this list of conditions and the following disclaimer.\n"
-    "\n"
-    "    * Redistributions in binary form must reproduce the above\n"
-    "copyright notice, this list of conditions and the following disclaimer\n"
-    "in the documentation and/or other materials provided with the\n"
-    "distribution.\n"
-    "\n"
-    "    * Neither the name of the Danga Interactive nor the names of its\n"
-    "contributors may be used to endorse or promote products derived from\n"
-    "this software without specific prior written permission.\n"
-    "\n"
-    "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-    "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-    "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-    "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-    "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-    "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-    "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-    "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-    "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-    "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-    "\n"
-    "\n"
-    "This product includes software developed by Danga Interactive, Inc.\n"
-    "\n"
-    "[ memcached ]\n"
-    "\n"
-    "Copyright (c) 2003, Danga Interactive, Inc. <http://www.danga.com/>\n"
-    "All rights reserved.\n"
-    "\n"
-    "Redistribution and use in source and binary forms, with or without\n"
-    "modification, are permitted provided that the following conditions are\n"
-    "met:\n"
-    "\n"
-    "    * Redistributions of source code must retain the above copyright\n"
-    "notice, this list of conditions and the following disclaimer.\n"
-    "\n"
-    "    * Redistributions in binary form must reproduce the above\n"
-    "copyright notice, this list of conditions and the following disclaimer\n"
-    "in the documentation and/or other materials provided with the\n"
-    "distribution.\n"
-    "\n"
-    "    * Neither the name of the Danga Interactive nor the names of its\n"
-    "contributors may be used to endorse or promote products derived from\n"
-    "this software without specific prior written permission.\n"
-    "\n"
-    "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-    "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-    "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-    "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-    "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-    "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-    "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-    "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-    "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-    "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-    "\n"
-    "\n"
-    "This product includes software developed by Niels Provos.\n"
-    "\n"
-    "[ libevent ]\n"
-    "\n"
-    "Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>\n"
-    "All rights reserved.\n"
-    "\n"
-    "Redistribution and use in source and binary forms, with or without\n"
-    "modification, are permitted provided that the following conditions\n"
-    "are met:\n"
-    "1. Redistributions of source code must retain the above copyright\n"
-    "   notice, this list of conditions and the following disclaimer.\n"
-    "2. Redistributions in binary form must reproduce the above copyright\n"
-    "   notice, this list of conditions and the following disclaimer in the\n"
-    "   documentation and/or other materials provided with the distribution.\n"
-    "3. All advertising materials mentioning features or use of this software\n"
-    "   must display the following acknowledgement:\n"
-    "      This product includes software developed by Niels Provos.\n"
-    "4. The name of the author may not be used to endorse or promote products\n"
-    "   derived from this software without specific prior written permission.\n"
-    "\n"
-    "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
-    "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
-    "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"
-    "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
-    "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"
-    "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-    "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-    "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n"
-    "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-    );
-
-    return;
-}
-
-
-/* for safely exit, make sure to do checkpoint*/
-static void sig_handler(const int sig)
-{
-    if (sig != SIGTERM && sig != SIGQUIT && sig != SIGINT) {
-        return;
-    }
-    if (daemon_quit == 1){
-        return;
-    }
-    daemon_quit = 1;
-    fprintf(stderr, "Signal(%d) received, try to exit daemon gracefully..\n", sig);
-}
-
-
-int main (int argc, char **argv) {
-    int c;
-    //struct in_addr addr;
-    char *dbhome = "testdb";
-    bool daemonize = false;
-    char *username = NULL;
-    FILE *log_file = NULL;
-    struct passwd *pw;
-    struct sigaction sa;
-    struct rlimit rlim;
-    int rcache = 256, pcache = 256;
-    /* recommend for 100,000,000 records*/
-    int db_hsize = 1000000; 
-    int areadsize = 4096;
-
-    /* init settings */
-    settings_init();
-
-    /* set stderr non-buffering (for running under, say, daemontools) */
-    setbuf(stderr, NULL);
-
-    /* process arguments */
-    while ((c = getopt(argc, argv, "a:p:c:hivl:dr:u:P:L:t:b:H:s:n:R:")) != -1) {
-        switch (c) {
-        case 'a':
-            if (strcmp(optarg, "-") == 0) {
-                access_log = stdout;
-            }else{
-                access_log = fopen(optarg, "a");
-                if (NULL == access_log) {
-                    fprintf(stderr, "open access_log %s failed\n", optarg);
-                    exit(1);
-                }
-            }
-            break;
-        case 'p':
-            settings.port = atoi(optarg);
-            break;
-        case 'c':
-            settings.maxconns = atoi(optarg);
-            break;
-        case 'h':
-            usage();
-            exit(EXIT_SUCCESS);
-        case 'i':
-            usage_license();
-            exit(EXIT_SUCCESS);
-        case 'v':
-            settings.verbose++;
-            break;
-        case 'l':
-            settings.inter= strdup(optarg);
-            break;
-        case 'd':
-            daemonize = true;
-            break;
-        case 'r':
-            rcache = atoi(optarg);
-            break;
-        case 'R':
-            areadsize = atoi(optarg);
-            break;
-        case 'u':
-            username = optarg;
-            break;
-        case 'P':
-            pcache = atoi(optarg);
-            break;
-        case 'L':
-            if ((log_file = fopen(optarg, "a")) != NULL){
-                setlinebuf(log_file);
-                fclose(stdout);
-                fclose(stderr);
-                stdout = stderr = log_file;
-            }else{
-                fprintf(stderr, "open log file %s failed\n", optarg);
-            }
-            break;
-        case 't':
-            settings.num_threads = atoi(optarg);
-            if (settings.num_threads == 0) {
-                fprintf(stderr, "Number of threads must be greater than 0\n");
-                exit(EXIT_FAILURE);
-            }
-            break;
-        case 'b':
-            settings.item_buf_size = atoi(optarg);
-            if(settings.item_buf_size < 512){
-                fprintf(stderr, "item buf size must be larger than 512 bytes\n");
-                exit(EXIT_FAILURE);
-            } 
-            if(settings.item_buf_size > 256 * 1024){
-                fprintf(stderr, "Warning: item buffer size(-b) larger than 256KB may cause performance issue\n");
-            } 
-            break;
-        case 'H':
-            dbhome = optarg;
-            break;
-        case 's':
-            settings.slow_cmd_time = atoi(optarg) / 1000.0;
-            break;
-        case 'n':
-            db_hsize = atoi(optarg);
-            break;
-        default:
-            fprintf(stderr, "Illegal argument \"%c\"\n", c);
-            exit(EXIT_FAILURE);
-        }
-    }
-
-    /*
-     * If needed, increase rlimits to allow as many connections
-     * as needed.
-     */
-
-    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
-        fprintf(stderr, "failed to getrlimit number of files\n");
-        exit(EXIT_FAILURE);
-    } else {
-        int maxfiles = settings.maxconns;
-        if (rlim.rlim_cur < maxfiles)
-            rlim.rlim_cur = maxfiles + 3;
-        if (rlim.rlim_max < rlim.rlim_cur)
-            rlim.rlim_max = rlim.rlim_cur;
-        if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
-            fprintf(stderr, "failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.\n");
-            exit(EXIT_FAILURE);
-        }
-    }
-
-    /* daemonize if requested */
-    /* if we want to ensure our ability to dump core, don't chdir to / */
-    if (daemonize) {
-        int res;
-        res = daemon(1, settings.verbose || log_file);
-        if (res == -1) {
-            fprintf(stderr, "failed to daemon() in order to daemonize\n");
-            return 1;
-        }
-    }
-
-    /* lose root privileges if we have them */
-    if (getuid() == 0 || geteuid() == 0) {
-        if (username == 0 || *username == '\0') {
-            fprintf(stderr, "can't run as root without the -u switch\n");
-            return 1;
-        }
-        if ((pw = getpwnam(username)) == 0) {
-            fprintf(stderr, "can't find the user %s to switch to\n", username);
-            return 1;
-        }
-        if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
-            fprintf(stderr, "failed to assume identity of user %s\n", username);
-            return 1;
-        }
-    }
-    
-    /* initialize other stuff */
-    item_init();
-    stats_init();
-    conn_init();
-
-    /*
-     * ignore SIGPIPE signals; we can use errno==EPIPE if we
-     * need that information
-     */
-    sa.sa_handler = SIG_IGN;
-    sa.sa_flags = 0;
-    if (sigemptyset(&sa.sa_mask) == -1 ||
-        sigaction(SIGPIPE, &sa, 0) == -1) {
-        perror("failed to ignore SIGPIPE; sigaction");
-        exit(EXIT_FAILURE);
-    }
-
-    /* open db */
-    db = cdb_new();
-    cdb_option(db, db_hsize, rcache, pcache);
-    cdb_option_areadsize(db, areadsize);
-
-    if (cdb_open(db, dbhome, CDB_CREAT | CDB_PAGEWARMUP) < 0) {
-        fprintf(stderr, "failed to open db %s\n", dbhome);
-        exit(1);
-    }
-
-    if ((stub_fd = open("/dev/null", O_RDONLY)) == -1) {
-        perror("open stub file failed");
-        exit(1);
-    }
-    thread_init(settings.num_threads);
-    
-    /* create the listening socket, bind it, and init */
-    if (server_socket(settings.port, false)) {
-        fprintf(stderr, "failed to listen\n");
-        exit(EXIT_FAILURE);
-    }
-
-    /* register signal callback */
-    if (signal(SIGTERM, sig_handler) == SIG_ERR)
-        fprintf(stderr, "can not catch SIGTERM\n");
-    if (signal(SIGQUIT, sig_handler) == SIG_ERR)
-        fprintf(stderr, "can not catch SIGQUIT\n");
-    if (signal(SIGINT,  sig_handler) == SIG_ERR)
-        fprintf(stderr, "can not catch SIGINT\n");
-
-    /* enter the event loop */
-    printf("all ready.\n");
-    loop_run(settings.num_threads);
-
-    /* wait other thread to ends */
-    fprintf(stderr, "waiting for close ... \n");
-    cdb_destroy(db);
-    fprintf(stderr, "done.\n");
-
-    if (log_file) {
-        fclose(log_file);
-    }
-
-    return 0;
-}
-
diff --git a/3rdparty/cuttdb/src/cuttdb-server.h b/3rdparty/cuttdb/src/cuttdb-server.h
deleted file mode 100644
index 90cc9b6271683c058dfacd007fad43ffef239c55..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cuttdb-server.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- *  Beansdb - A high available distributed key-value storage system:
- *
- *      http://beansdb.googlecode.com
- *
- *  The source code of Beansdb is most based on Memcachedb and Memcached:
- *
- *      http://memcachedb.org/
- *      http://danga.com/memcached/
- *
- *  Copyright 2009 Douban Inc.  All rights reserved.
- *
- *  Use and distribution licensed under the BSD license.  See
- *  the LICENSE file for full text.
- *
- *  Authors:
- *      Davies Liu <davies.liu@gmail.com>
- *
- */
- 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-#define DATA_BUFFER_SIZE 2048
-#define MAX_PAYLOAD_SIZE 1400
-#define MAX_SENDBUF_SIZE (256 * 1024 * 1024)
-/* I'm told the max legnth of a 64-bit num converted to string is 20 bytes.
- * Plus a few for spaces, \r\n, \0 */
-#define SUFFIX_SIZE 24
-#define INCR_MAX_STORAGE_LEN 24
-
-/** Initial size of list of items being returned by "get". */
-#define ITEM_LIST_INITIAL 200
-
-/** Initial size of the sendmsg() scatter/gather array. */
-#define IOV_LIST_INITIAL 400
-
-/** Initial number of sendmsg() argument structures to allocate. */
-#define MSG_LIST_INITIAL 10
-
-/** High water marks for buffer shrinking */
-#define READ_BUFFER_HIGHWAT 8192
-#define ITEM_LIST_HIGHWAT 400
-#define IOV_LIST_HIGHWAT 600
-#define MSG_LIST_HIGHWAT 100
-
-#define MAX_REP_PRIORITY 1000000
-#define MAX_REP_ACK_POLICY 6
-#define MAX_REP_NSITES 1000
-
-
-#define RGET_MAX_ITEMS 100
-#define PACKAGE "CuttDB"
-#define VERSION "0.1.0"
-
-/* Get a consistent bool type */
-#include <stdbool.h>
-
-#if HAVE_STDINT_H
-# include <stdint.h>
-#else
- typedef unsigned char             uint8_t;
-#endif
-
-/* unistd.h is here */
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-/* 64-bit Portable printf */
-/* printf macros for size_t, in the style of inttypes.h */
-#ifdef _LP64
-#define __PRIS_PREFIX "z"
-#else
-#define __PRIS_PREFIX
-#endif
-
-#define AE_SETSIZE (1024*60)    /* Max number of fd supported */
-
-#define AE_OK 0
-#define AE_ERR -1
-
-#define AE_NONE 0
-#define AE_READABLE 1
-#define AE_WRITABLE 2
-
-/* Use these macros after a % in a printf format string
-   to get correct 32/64 bit behavior, like this:
-   size_t size = records.size();
-   printf("%"PRIuS"\n", size); */
-
-#define PRIdS __PRIS_PREFIX "d"
-#define PRIxS __PRIS_PREFIX "x"
-#define PRIuS __PRIS_PREFIX "u"
-#define PRIXS __PRIS_PREFIX "X"
-#define PRIoS __PRIS_PREFIX "o"
-
-struct stats {
-    uint32_t      curr_conns;
-    uint32_t      total_conns;
-    uint32_t      conn_structs;
-    uint64_t      get_cmds;
-    uint64_t      set_cmds;
-    uint64_t      delete_cmds;
-    uint64_t      slow_cmds;
-    uint64_t      get_hits;
-    uint64_t      get_misses;
-    time_t        started;          /* when the process was started */
-    uint64_t      bytes_read;
-    uint64_t      bytes_written;
-};
-
-#define MAX_VERBOSITY_LEVEL 2
-
-struct settings {
-    size_t item_buf_size;
-    int maxconns;
-    int port;
-    char *inter;
-    int verbose;
-    float slow_cmd_time;
-    int flush_period;
-    int flush_limit;
-    int num_threads;        /* number of libevent threads to run */
-};
-
-extern struct stats stats;
-extern struct settings settings;
-
-typedef struct _stritem {
-    int             expire;        /* expire time */
-    uint32_t        flag;        /* flag of item */
-    int             nbytes;     /* size of data */
-    uint8_t         nsuffix;    /* length of flags-and-length string */
-    uint8_t         nkey;       /* key length, w/terminating null and padding */
-    void * end[];
-    /* then null-terminated key */
-    /* then " flags length\r\n" (no terminating null) */
-    /* then data with terminating \r\n (no terminating null; it's binary!) */
-} item;
-
-#define ITEM_key(item) ((char*)&((item)->end[0]))
-
-/* warning: don't use these macros with a function, as it evals its arg twice */
-#define ITEM_suffix(item) ((char*) &((item)->end[0]) + (item)->nkey + 1)
-#define ITEM_data(item) ((char*) &((item)->end[0]) + (item)->nkey + 1 + (item)->nsuffix)
-#define ITEM_ntotal(item) (sizeof(struct _stritem) + (item)->nkey + 1 + (item)->nsuffix + (item)->nbytes)
-
-enum conn_states {
-    conn_listening,  /** the socket which listens for connections */
-    conn_read,       /** reading in a command line */
-    conn_write,      /** writing out a simple response */
-    conn_nread,      /** reading in a fixed number of bytes */
-    conn_swallow,    /** swallowing unnecessary bytes w/o storing */
-    conn_closing,    /** closing this connection */
-    conn_mwrite,     /** writing out many items sequentially */
-};
-
-#define NREAD_ADD 1
-#define NREAD_SET 2
-#define NREAD_REPLACE 3
-#define NREAD_APPEND 4
-#define NREAD_PREPEND 5
-
-typedef struct conn conn;
-struct conn {
-    int    sfd;
-    int    state;
-    short  ev_flags;
-
-    char   *rbuf;   /** buffer to read commands into */
-    char   *rcurr;  /** but if we parsed some already, this is where we stopped */
-    int    rsize;   /** total allocated size of rbuf */
-    int    rbytes;  /** how much data, starting from rcur, do we have unparsed */
-
-    char   *wbuf;
-    char   *wcurr;
-    int    wsize;
-    int    wbytes;
-    int    write_and_go; /** which state to go into after finishing current write */
-    void   *write_and_free; /** free this memory after finishing writing */
-    bool   noreply;   /* True if the reply should not be sent. */
-
-    char   *ritem;  /** when we read in an item's value, it goes here */
-    int    rlbytes;
-
-    /* data for the nread state */
-
-    /**
-     * item is used to hold an item structure created after reading the command
-     * line of set/add/replace commands, but before we finished reading the actual
-     * data. The data is read into ITEM_data(item) to avoid extra copying.
-     */
-
-    void   *item;     /* for commands set/add/replace  */
-    int    item_comm; /* which one is it: set/add/replace */
-
-    /* data for the swallow state */
-    int    sbytes;    /* how many bytes to swallow */
-
-    /* data for the mwrite state */
-    struct iovec *iov;
-    int    iovsize;   /* number of elements allocated in iov[] */
-    int    iovused;   /* number of elements used in iov[] */
-
-    struct msghdr *msglist;
-    int    msgsize;   /* number of elements allocated in msglist[] */
-    int    msgused;   /* number of elements used in msglist[] */
-    int    msgcurr;   /* element in msglist[] being transmitted now */
-    int    msgbytes;  /* number of bytes in current msg */
-
-    item   **ilist;   /* list of items to write out */
-    int    isize;
-    item   **icurr;
-    int    ileft;
-
-    conn   *next;     /* Used for generating a list of conn structures */
-};
-
-/*
- * Functions
- */
-
-/* item management */
-/*
-void item_init(void);
-item *do_item_from_freelist(void);
-int do_item_add_to_freelist(item *it);
-item *item_alloc1(char *key, const size_t nkey, const int flags, const int nbytes);
-int item_free(item *it);
-item *item_get(char *key, size_t nkey);
-*/
-
-/* conn management */
-conn *do_conn_from_freelist();
-bool do_conn_add_to_freelist(conn *c);
-conn *conn_new(const int sfd, const int init_state, const int read_buffer_size);
-
-int store_item(item *item, int comm);
-
-void thread_init(int nthreads);
-int add_event(int fd, int mask, conn *c);
-void loop_run(int nthreads);
-
-void drive_machine(conn *c);
-
-/* Lock wrappers for cache functions that are called from main loop. */
-conn *mt_conn_from_freelist(void);
-bool mt_conn_add_to_freelist(conn *c);
-item *mt_item_from_freelist(void);
-int mt_item_add_to_freelist(item *it);
-void  mt_stats_lock(void);
-void  mt_stats_unlock(void);
-
-#define conn_from_freelist()        mt_conn_from_freelist()
-#define conn_add_to_freelist(x)     mt_conn_add_to_freelist(x)
-#define item_from_freelist()        mt_item_from_freelist()
-#define item_add_to_freelist(x)     mt_item_add_to_freelist(x)
-#define STATS_LOCK()                mt_stats_lock()
-#define STATS_UNLOCK()              mt_stats_unlock()
-
-extern int daemon_quit;
-
diff --git a/3rdparty/cuttdb/src/cuttdb.c b/3rdparty/cuttdb/src/cuttdb.c
deleted file mode 100644
index 74e342623a5308fd4275868263eaac87c1c726e7..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cuttdb.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "cuttdb.h"
-#include "cdb_types.h"
-#include "cdb_vio.h"
-
-
-/* nothing here */
diff --git a/3rdparty/cuttdb/src/cuttdb.h b/3rdparty/cuttdb/src/cuttdb.h
deleted file mode 100644
index 1814028f51f0ebd8300adc9e2eb34ae684e7218e..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/cuttdb.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _CUTTDB_H_
-#define _CUTTDB_H_
-#include <stdint.h>
-#include <stdbool.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-typedef struct CDB CDB;
-typedef void (*CDB_ERRCALLBACK)(void *, int, const char *, int);
-typedef bool (*CDB_ITERCALLBACK)(void *, const char *, int, const char *, int, uint32_t, uint64_t);
-
-/* performance statistical information of an database instance */
-typedef struct {
-    /* number of records in db */
-    uint64_t rnum;
-    /* number of records in cache */
-    uint64_t rcnum;
-    /* number of pages in db */
-    uint64_t pnum;
-    /* number of pages in cache */
-    uint64_t pcnum;
-    /* cache hit of record cache */
-    uint64_t rchit;
-    /* cache miss of record cache */
-    uint64_t rcmiss;
-    /* cache hit of page cache */
-    uint64_t pchit;
-    /* cache miss of page cache */
-    uint64_t pcmiss;
-    /* average disk read latency */
-    uint32_t rlatcy;
-    /* average disk write latency */
-    uint32_t wlatcy;
-} CDBSTAT;
-
-/* options to open a database*/
-enum {
-    /* create an database if not exist */
-    CDB_CREAT = 0x1,
-    /* clean the database if already exist */
-    CDB_TRUNC = 0x2,
-    /* fill the cache when start up */
-    CDB_PAGEWARMUP = 0x4,
-};
-
-/* error codes */
-enum {
-    CDB_SUCCESS = 0,
-    CDB_NOTFOUND,
-    CDB_EXIST,
-    CDB_DIRNOEXIST,
-    CDB_OPENERR,
-    CDB_PIDEXIST,
-    CDB_DATAERRDAT,
-    CDB_DATAERRIDX,
-    CDB_WRITEERR,
-    CDB_READERR,
-    CDB_NOFID,
-    CDB_INTERNALERR,
-    CDB_DATAERRMETA,
-    CDB_MEMDBNOCACHE,
-};
-
-/* record insertion options */
-enum {
-    CDB_OVERWRITE = 0,
-    CDB_INSERTIFEXIST = 0x1,
-    CDB_INSERTIFNOEXIST = 0x2,
-    CDB_INSERTCACHE = 0x8,
-};
-
-/* if database path is CDB_MEMDB, records are never written to disk, they stay in cache only */
-#define CDB_MEMDB ":memory:"
-
-/*
- WARNING: 
-
- the library has auxiliary thread, which means do fork() after open a database will cause
- unpredictable situation.
-*/
-
-/* create an cuttdb object, which should be freed by cdb_destory() */
-CDB *cdb_new();
-
-/* cdb_option() must be called before cdb_open()
-
- the second parameter 'hsize' indicates the size of main hash table, which can't be
- modified after the database be created. To get better performance, it is suggest to
- set the 'hsize' to 10% - 1% of the total number of records. The default value 1 million
- should be proper for about 100 million records. Too large or small of the value would
- lead to drop in speed or waste of memory
-
- the third parameter 'rcacheMB' indicates the size limit of record cache (measured by 
- MegaBytes), every record in cache would have about 40 bytes overhead. 
-
- the fourth parameter 'pcacheMB' indicates the size limit of index page cache (measured 
- by MegaBytes). If a record is not in record cache, it will be read by only 1 disk seek
- with enough page cache, or it have to make an extra disk seek to load the page. 
- cuttdb will use about {10 * number of records} bytes to cache all index pages, which 
- ensures fastest 'set' operation.
-
- the default parameter is (_db, 1000000, 128, 1024)
-
- return 0 if success, or -1 at failure. */
-int cdb_option(CDB *db, int hsize, int rcacheMB, int pcacheMB);
-
-/* Enable bloomfilter, size should be the estimated number of records in database 
- must be called before cdb_open(),
- The value is 100000 at minimum. Memory cost of bloomfilter is size/8 bytes */
-void cdb_option_bloomfilter(CDB *db, uint64_t size);
-
-/* this is an advanced parameter. It is the size for cuttdb making a read from disk.
- CuttDB do not know the record size even if the index is in memory,
- so at least a read with default size will performed while in cdb_get().
- The value is recommended to be larger than the size of most records in database,
- unless the records are mostly larger than tens of KB.
- If the value is much larger than recommended, it will be a waste of computing. 
- The value can only be 65536 at maximum, 1024 at minimum */
-void cdb_option_areadsize(CDB *db, uint32_t size);
-
-/* open an database, 'file' should be an existing directory, or CDB_MEMDB for temporary store,
-   'mode' should be combination of CDB_CREAT / CDB_TRUNC / CDB_PAGEWARMUP 
-   CDB_PAGEWARMUP means to warm up page cache while opening 
-   If there is a file called 'force_recovery' in the data directory, even if it might be made by 'touch force_recovery',
-   a force recovery will happen to rebuild the index (be aware that some deleted records would reappear after this)
- */
-int cdb_open(CDB *db, const char *file, int mode);
-
-
-/* simplified cdb_set2, insert a record with CDB_OVERWRITE and never expire */
-int cdb_set(CDB *db, const char *key, int ksize, const char *val, int vsize);
-
-/* set a record by 'key' and 'value', 
-   opt could be bit combination of CDB_INSERTCACHE and one in {CDB_INSERTIFEXIST, CDB_INSERTNOEXIST,
-   CDB_OVERWRITE}
-   expire is the time for the record be valid, measured by second. 0 means never expire.
-   return 0 if success, or -1 at failure. */
-int cdb_set2(CDB *db, const char *key, int ksize, const char *val, int vsize, int opt, int expire);
-
-
-int cdb_is(CDB *db, const char *key, int ksize);
-
-/* get an record by 'key', the value will be allocated and passed out by 'val', its size is
-   'vsize'.  return 0 if success, or -1 at failure. */
-int cdb_get(CDB *db, const char *key, int ksize, void **val, int *vsize);
-
-
-/* the val got by cdb_get should be freed by this for safety.
-   If there is more than one memory allocator */
-void cdb_free_val(void **val);
-
-
-/* delete an record by 'key'. However ,the space of the record would not be recycled. 
-   'vsize'.  return 0 if success, or -1 at failure. */
-int cdb_del(CDB *db, const char *key, int ksize);
-
-
-/* create a new iterator begins at given operation id */
-void *cdb_iterate_new(CDB *db, uint64_t oid);
-
-/* iterate through the database with a callback, the function would stop if callback returned false
-   The callback should accept key, ksize, value, vsize, expire time, oid
-   Returns the number of records have been visited */
-uint64_t cdb_iterate(CDB *db, CDB_ITERCALLBACK itcb, void *arg, void *iter);
-
-/* destroy the iterator */
-void cdb_iterate_destroy(CDB *db, void *iter);
-
-/* get the current statistic information of db. 'stat' should be the struct already allocated.
-   if 'stat' is NULL, the statistic will be reset to zero. */
-void cdb_stat(CDB *db, CDBSTAT *stat);
-
-
-/* close the database. IT MUST BE CALLED BEFORE PROGRAM EXITS TO ENSURE DATA COMPLETION */
-int cdb_close(CDB *db);
-
-
-/* close the database if it opened, and free the object */
-int cdb_destroy(CDB *db);
-
-
-/* get last error number in current thread */
-int cdb_errno(CDB *db);
-
-
-/* get the description of an error number */
-const char *cdb_errmsg(int ecode);
-
-
-/* set callback when error happened, 'cdb_deferrorcb' is optional, which shows the error to stderr */
-void cdb_seterrcb(CDB *db, CDB_ERRCALLBACK errcb, void *arg);
-
-/* a possible error callback */
-void cdb_deferrorcb(void *arg, int errno, const char *file, int line);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
diff --git a/3rdparty/cuttdb/src/mman.c b/3rdparty/cuttdb/src/mman.c
deleted file mode 100644
index ea5d358adc7768acd227507d7ac9e7853823729d..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/mman.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * mman-win32 library
- * https://code.google.com/p/mman-win32/
- * reinterpreted by Konstantin Papizh <konstantin.papizh@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- */
-
-#include <windows.h>
-#include <errno.h>
-#include <stdio.h>
-#include "mman.h"
-
-static DWORD __map_mmap_prot_page(const int prot) {
-    DWORD protect = 0;
-    
-    if (prot == PROT_NONE)
-        return protect;
-        
-    if ((prot & PROT_EXEC) != 0) {
-        protect = ((prot & PROT_WRITE) != 0) ? 
-                    PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
-    } else {
-        protect = ((prot & PROT_WRITE) != 0) ?
-                    PAGE_READWRITE : PAGE_READONLY;
-    }
-    return protect;
-}
-
-static DWORD __map_mmap_prot_file(const int prot) {
-
-    DWORD desiredAccess = 0;
-    if (prot == PROT_NONE)
-        return desiredAccess;
-        
-    if ((prot & PROT_READ) != 0)
-        desiredAccess |= FILE_MAP_READ;
-    if ((prot & PROT_WRITE) != 0)
-        desiredAccess |= FILE_MAP_WRITE;
-    if ((prot & PROT_EXEC) != 0)
-        desiredAccess |= FILE_MAP_EXECUTE;
-    
-    return desiredAccess;
-}
-
-void* mmap(void *addr, size_t len, int prot, int flags, int fildes, offset_t off)
-{
-    HANDLE fm, h;
-    void *map = MAP_FAILED;
-
-    const DWORD dwFileOffsetLow = (sizeof(offset_t) <= sizeof(DWORD)) ?
-                    (DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
-    const DWORD dwFileOffsetHigh = (sizeof(offset_t) <= sizeof(DWORD)) ?
-                    (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFF00000000L);
-    const DWORD protect = __map_mmap_prot_page(prot);
-    const DWORD desiredAccess = __map_mmap_prot_file(prot);
-
-    const offset_t maxSize = off + (offset_t)len;
-
-    const DWORD dwMaxSizeLow = (sizeof(offset_t) <= sizeof(DWORD)) ?
-                    (DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
-    const DWORD dwMaxSizeHigh = (sizeof(offset_t) <= sizeof(DWORD)) ?
-                    (DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFF00000000L);
-    _set_errno(0);
-    
-    if (len == 0 || prot == PROT_EXEC) {
-        _set_errno(EINVAL);
-        return MAP_FAILED;
-    }
-    
-    h = ((flags & MAP_ANONYMOUS) == 0) ? 
-                    (HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
-
-    if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE) {
-        _set_errno(EBADF);
-        return MAP_FAILED;
-    }
-
-    fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
-
-    if (fm == NULL) {
-        int a = errno;
-        _set_errno(GetLastError());
-        a = errno;
-        printf("%d", a);
-        return MAP_FAILED;
-    }
-  
-    if ((flags & MAP_FIXED) == 0) {
-        map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
-    }
-    else {
-        map = MapViewOfFileEx(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len, addr);
-    }
-    CloseHandle(fm);
-
-    if (map == NULL) {
-        _set_errno(GetLastError());
-        return MAP_FAILED;
-    }
-    return map;
-}
-
-int munmap(void *addr, size_t len) {
-    if (UnmapViewOfFile(addr))
-        return 0;
-        
-    _set_errno(GetLastError());
-    return -1;
-}
-
-int _mprotect(void *addr, size_t len, int prot) {
-    DWORD newProtect = __map_mmap_prot_page(prot);
-    DWORD oldProtect = 0;
-    
-    if (VirtualProtect(addr, len, newProtect, &oldProtect))
-        return 0;
-    _set_errno(GetLastError());
-    return -1;
-}
-
-int msync(void *addr, size_t len, int flags) {
-    if (FlushViewOfFile(addr, len))
-        return 0;
-    _set_errno(GetLastError());
-    return -1;
-}
-
-int mlock(const void *addr, size_t len) {
-    if (VirtualLock((LPVOID)addr, len))
-        return 0;
-    _set_errno(GetLastError());
-    return -1;
-}
-
-int munlock(const void *addr, size_t len) {
-    if (VirtualUnlock((LPVOID)addr, len))
-        return 0;
-    _set_errno(GetLastError());
-    return -1;
-}
-
-ssize_t pread(int fd, void *buf, unsigned long count, offset_t offset) {
-    unsigned long len = 0;
-
-    OVERLAPPED overlapped;
-    memset(&overlapped, 0, sizeof(OVERLAPPED));
-    overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
-    overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
-
-    HANDLE file = (HANDLE)_get_osfhandle(fd);
-    if ((!ReadFile(file, buf, count, &len, &overlapped)) && GetLastError() != ERROR_HANDLE_EOF) {
-        _set_errno(GetLastError());
-        return -1;
-    }
-    return len;
-}
-
-ssize_t pwrite(int fd, const void *buf, unsigned long count, offset_t offset) {
-    long unsigned int len = 0;
-
-    OVERLAPPED overlapped;
-    memset(&overlapped, 0, sizeof(OVERLAPPED));
-    overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
-    overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
-
-    HANDLE file = (HANDLE)_get_osfhandle(fd);
-    if (!WriteFile(file, buf, count, &len, &overlapped)) {
-        _set_errno(GetLastError());
-        return -1;
-    }
-    return len;
-}
diff --git a/3rdparty/cuttdb/src/mman.h b/3rdparty/cuttdb/src/mman.h
deleted file mode 100644
index 7367f3d4cfa4a37ff423e6202cfb4d79d6058c8e..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/mman.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _MMAN_H_
-#define _MMAN_H_
-
-#include <_mingw.h>
-#include <stdint.h>
-#include <io.h>
-
-#if defined(_WIN64)
-typedef int64_t offset_t;
-#else
-typedef uint32_t offset_t;
-#endif
-
-#include <sys/types.h>
-#include <stdbool.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PROT_NONE       0
-#define PROT_READ       1
-#define PROT_WRITE      2
-#define PROT_EXEC       4
-
-#define MAP_FILE        0
-#define MAP_SHARED      1
-#define MAP_PRIVATE     2
-#define MAP_TYPE        0xf
-#define MAP_FIXED       0x10
-#define MAP_ANONYMOUS   0x20
-#define MAP_ANON        MAP_ANONYMOUS
-
-#define MAP_FAILED      ((void *)-1)
-
-#define MS_ASYNC        1
-#define MS_SYNC         2
-#define MS_INVALIDATE   4
-
-#define fdatasync(fd) _commit(fd)
-
-void*   mmap(void *addr, size_t len, int prot, int flags, int fildes, offset_t offset);
-int     munmap(void *addr, size_t len);
-int     _mprotect(void *addr, size_t len, int prot);
-int     msync(void *addr, size_t len, int flags);
-int     mlock(const void *addr, size_t len);
-int     munlock(const void *addr, size_t len);
-
-ssize_t pread(int fd, void *buf, unsigned long count, offset_t offset);
-ssize_t pwrite(int fd, const void *buf, unsigned long count, offset_t offset);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*  _MMAN_H_ */
diff --git a/3rdparty/cuttdb/src/server-thread.c b/3rdparty/cuttdb/src/server-thread.c
deleted file mode 100644
index c7a05c30319e63a177178ab43a84bc7b5435fb11..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/server-thread.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   The server&network part of CuttDB is based on Beansdb:
- *
- *   http://beansdb.googlecode.com
- *
- *   Beansdb is most based on Memcachedb and Memcached:
- *
- *   http://memcachedb.org/
- *   http://danga.com/memcached/
- *
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-#include "cuttdb-server.h"
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include <pthread.h>
-
-typedef struct EventLoop {
-//    int   maxfd;
-    conn* conns[AE_SETSIZE];
-    int   fired[AE_SETSIZE];
-    int   nready;
-    void *apidata;
-} EventLoop;
-
-/* Lock for connection freelist */
-static pthread_mutex_t conn_lock;
-
-/* Lock for item buffer freelist */
-static pthread_mutex_t ibuffer_lock;
-
-static EventLoop loop;
-static pthread_mutex_t leader;
-
-/*
- * Pulls a conn structure from the freelist, if one is available.
- */
-conn *mt_conn_from_freelist() {
-    conn *c;
-    pthread_mutex_lock(&conn_lock);
-    c = do_conn_from_freelist();
-    pthread_mutex_unlock(&conn_lock);
-    return c;
-}
-
-/*
- * Adds a conn structure to the freelist.
- *
- * Returns 0 on success, 1 if the structure couldn't be added.
- */
-bool mt_conn_add_to_freelist(conn *c) {
-    bool result;
-
-    pthread_mutex_lock(&conn_lock);
-    result = do_conn_add_to_freelist(c);
-    pthread_mutex_unlock(&conn_lock);
-
-    return result;
-}
-
-
-/******************************* GLOBAL STATS ******************************/
-
-void mt_stats_lock() {
-}
-
-void mt_stats_unlock() {
-}
-
-/* Include the best multiplexing layer supported by this system.
- * The following should be ordered by performances, descending. */
-#ifdef HAVE_EPOLL
-#include "ae_epoll.c"
-#else
-    #ifdef HAVE_KQUEUE
-    #include "ae_kqueue.c"
-    #else
-    #include "ae_select.c"
-    #endif
-#endif
-
-/*
- * Initializes the thread subsystem, creating various worker threads.
- *
- * nthreads  Number of event handler threads to spawn
- */
-void thread_init(int nthreads) {
-    pthread_mutex_init(&ibuffer_lock, NULL);
-    pthread_mutex_init(&conn_lock, NULL);
-    pthread_mutex_init(&leader, NULL);
-    
-    memset(&loop, 0, sizeof(loop));
-    if (aeApiCreate(&loop) == -1) {
-        exit(1);
-    }
-}
-
-int add_event(int fd, int mask, conn *c)
-{
-    if (fd >= AE_SETSIZE) {
-        fprintf(stderr, "fd is too large: %d\n", fd);
-        return AE_ERR;
-    }
-    assert(loop.conns[fd] == NULL);
-    loop.conns[fd] = c;
-    if (aeApiAddEvent(&loop, fd, mask) == -1){
-        loop.conns[fd] = NULL;
-        return AE_ERR;
-    }
-//    if (fd > loop.maxfd)
-//        loop.maxfd = fd;
-    return AE_OK;
-}
-
-int update_event(int fd, int mask, conn *c)
-{
-    loop.conns[fd] = c;
-    if (aeApiUpdateEvent(&loop, fd, mask) == -1){
-        loop.conns[fd] = NULL;
-        return AE_ERR;
-    }
-    return AE_OK;
-}
-
-int delete_event(int fd)
-{
-    if (fd >= AE_SETSIZE) return -1;
-    if (loop.conns[fd] == NULL) return 0;
-    if (aeApiDelEvent(&loop, fd) == -1)
-        return -1;
-    loop.conns[fd] = NULL;
-    return 0;
-}
-
-static void *worker_main(void *arg) {
-    pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
-    
-    struct timeval tv = {1, 0};
-    while (!daemon_quit) {
-        pthread_mutex_lock(&leader);
-
-AGAIN:
-        while(loop.nready == 0 && daemon_quit == 0)
-            loop.nready = aeApiPoll(&loop, &tv);
-        if (daemon_quit) {
-            pthread_mutex_unlock(&leader);
-            break;
-        }
-       
-        loop.nready --;
-        int fd = loop.fired[loop.nready];
-        conn *c = loop.conns[fd];
-        if (c == NULL){
-            fprintf(stderr, "Bug: conn %d should not be NULL\n", fd);
-            close(fd);
-            goto AGAIN;
-        }
-        loop.conns[fd] = NULL; 
-        pthread_mutex_unlock(&leader);
-        
-        drive_machine(c);
-        if (c->ev_flags > 0) {
-            update_event(fd, c->ev_flags, c);
-        }
-    }
-    return NULL; 
-}
-
-void loop_run(int nthread)
-{
-    int i, ret;
-    pthread_attr_t  attr;
-    pthread_attr_init(&attr);
-    pthread_t* tids = malloc(sizeof(pthread_t) * nthread);
-    
-    for (i=0; i<nthread - 1; i++) {
-        if ((ret = pthread_create(tids + i, &attr, worker_main, NULL)) != 0) {
-            fprintf(stderr, "Can't create thread: %s\n",
-                    strerror(ret));
-            exit(1);
-        }
-    }
-    
-    worker_main(NULL);
-    
-    // wait workers to stop
-    for (i=0; i<nthread - 1; i++) {
-        (void) pthread_join(tids[i], NULL);
-    }
-    free(tids);
-}
-
diff --git a/3rdparty/cuttdb/src/test_mt.c b/3rdparty/cuttdb/src/test_mt.c
deleted file mode 100644
index de4d383731a4a66bc2e690f40dfc742ec022073e..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/test_mt.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#include <pthread.h>
-#include "cuttdb.h"
-
-
-CDB *db;
-
-enum {
-    SETOP,
-    GETOP,
-    DELOP,
-};
-
-#if 1
-static int prob_table1[8] = {SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, DELOP, GETOP};
-static int prob_table2[8] = {SETOP, SETOP, SETOP, SETOP, SETOP, DELOP, DELOP, GETOP};
-static int prob_table3[8] = {SETOP, SETOP, SETOP, DELOP, DELOP, DELOP, DELOP, GETOP};
-#else
-static int prob_table1[8] = {SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, GETOP};
-static int prob_table2[8] = {SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, GETOP};
-static int prob_table3[8] = {SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, SETOP, GETOP};
-#endif
-int *optable = NULL;
-
-
-long get_rand() 
-{
-    return (long)rand() * RAND_MAX + rand();
-}
-
-
-void *test_thread(void *arg)
-{
-    char key[64];
-    char value[128];
-    void *v;
-    int knum = *(int*)arg;
-    while(1) {
-        int krand = get_rand() % knum;
-        int ksize = snprintf(key, 64, "%ld%ld%ld", krand, krand, krand);
-        int vsize = snprintf(value, 128, "%ld%ld%ld%ld%d%ld%ld%ld%ld",
-                krand, krand, krand, krand, krand, krand, krand, krand);
-        int op = optable[rand() & 0x07];
-        int expire = 600 + 20 * (rand() % 1000);
-        switch(op) {
-            case SETOP:
-                if (cdb_set2(db, key, ksize, value, vsize, CDB_OVERWRITE | CDB_INSERTCACHE, expire) < 0)
-                    printf("ERROR! %s:%d\n", __FILE__, __LINE__);
-                break;
-            case GETOP:
-                if (cdb_get(db, key, ksize, &v, &vsize) == -1)
-                    printf("ERROR! %s:%d\n", __FILE__, __LINE__);
-                if (v)
-                    cdb_free_val(&v);
-                break;
-            case DELOP:
-                if (cdb_del(db, key, ksize) == -1)
-                    printf("ERROR! %s:%d\n", __FILE__, __LINE__);
-                break;
-            default:
-                break;
-        }
-    }
-}
-
-
-
-int main(int argc, char *argv[])
-{
-    int thread_num = 2;
-    int record_num = 10000000;
-    char *db_path = NULL;
-    printf("Usage: %s db_path [record_num] [thread_num]\n", argv[0]);
-    if (argc >= 2)
-        db_path = argv[1];
-    else
-        return -1;
-
-    if (argc >= 3)
-        record_num = atoi(argv[2]);
-    if (argc >= 4)
-        thread_num = atoi(argv[3]);
-
-    record_num = record_num < 100? 100: record_num;
-    thread_num = thread_num < 1? 1: thread_num;
-    srand(time(NULL));
-
-    db = cdb_new();
-    cdb_option(db, record_num / 100, 0, 1024000);
-    if (cdb_open(db, db_path, CDB_CREAT | CDB_TRUNC) < 0) {
-        printf("DB Open err\n");
-        return -1;
-    }
-
-
-    optable = prob_table1;
-    pthread_t threads[thread_num];
-    for(int i = 0; i < thread_num; i++) {
-        pthread_create(&threads[i], NULL, test_thread, &record_num);
-    }
-
-    int clear_interval = 0;
-    while(1) {
-        CDBSTAT st;
-        cdb_stat(db, &st);
-        printf("rnum: %lu, rcnum: %lu, pnum: %lu, pcnum %lu, rlatcy: %u  wlatcy: %u"
-                " rh/m: %lu/%lu ph/m: %lu/%lu\n",
-                st.rnum, st.rcnum, st.pnum, st.pcnum, st.rlatcy, st.wlatcy,
-                st.rchit, st.rcmiss, st.pchit, st.pcmiss);
-        if (++clear_interval % 20 == 0)
-            cdb_stat(db, NULL);
-
-        if (st.rnum > 0.7 * record_num)
-            optable = prob_table2;
-        if (st.rnum > 0.9 * record_num)
-            optable = prob_table3;
-
-        if (st.rnum < 0.8 * record_num)
-            optable = prob_table2;
-
-        if (st.rnum < 0.6 * record_num)
-            optable = prob_table1;
-        fflush(stdout);
-        sleep(1);
-    }
-    
-    return 0;
-}
-
-
-
diff --git a/3rdparty/cuttdb/src/vio_apnd2.c b/3rdparty/cuttdb/src/vio_apnd2.c
deleted file mode 100644
index 68dc326df18ab8409520da20a7285989bdd09377..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/vio_apnd2.c
+++ /dev/null
@@ -1,2644 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license.
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#include "vio_apnd2.h"
-#include "cdb_hashtable.h"
-#include "cdb_bgtask.h"
-#include "cdb_lock.h"
-#include "cuttdb.h"
-#include "cdb_core.h"
-#include "cdb_errno.h"
-#include "cdb_types.h"
-#include "cdb_crc64.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/stat.h>
-#ifdef _WIN32
-#include "mman.h"
-#else
-#include <sys/mman.h>
-#endif
-#include <fcntl.h>
-#include <unistd.h>
-#include <dirent.h>
-
-/* record magic bytes */
-#define RECMAGIC 0x19871022
-/* obsoleted, but appeared in some code */
-#define DELRECMAGIC 0x19871023
-#define PAGEMAGIC 0x19890604
-
-/* data buffered before pwrite to disk */
-#define IOBUFSIZE (2 * MB)
-/* structure of deletion buffer differs from the others, buffered DELBUFMAX records at most */
-#define DELBUFMAX 10000
-
-/* index(page) file size limit */
-#define FIDXMAXSIZE (16 * MB)
-/* data file size limit */
-#define FDATMAXSIZE (128 * MB)
-/* all meta information are regulated to fix size */
-#define FILEMETASIZE 64
-/* the file opened simultaneously limit, managed by LRU */
-#define MAXFD 16384
-#define MAX_PATH_LEN 255
-
-#define FILEMAGICHEADER "CuTtDbFiLePaRtIaL"
-#define FILEMAGICLEN (strlen(FILEMAGICHEADER))
-/* page or data records are stored at aligned offset */
-#define ALIGNBYTES 16
-
-/* virtual offset(48bits) transform into real offset(fid,offset) */
-#define VOFF2ROFF(off, fid, roff) do{fid = (off).i4 >> 8; \
-    roff = ((off).i4 & 0xff) << 16; roff = (roff | (off).i2) * ALIGNBYTES;}while(0)
-
-/* real offset transform into virtual offset */
-#define ROFF2VOFF(fid, roff, off) do{(off).i4 = fid << 8; \
-    (off).i4 |= (roff / ALIGNBYTES) >> 16; (off).i2 = (roff / ALIGNBYTES) & 0xffff;} while(0)
-
-/* align to a integer offset */
-#define OFFALIGNED(off) ((((off)-1) | (ALIGNBYTES - 1)) + 1)
-
-/* used in fd LRU-cached, distinguish index or data files' fd */
-#define VFIDIDX(fid) (fid * 2)
-#define VFIDDAT(fid) (fid * 2 + 1)
-
-/* how often write out buffered data */
-#define FLUSHTIMEOUT 5
-/* how often to check if index file needs space recycle */
-#define RCYLEPAGEINTERVAL 60
-/* how often to check if data file needs space recycle */
-#define RCYLEDATAINTERVAL 120
-/* data file space recycle check interval factor (seconds per data file/128MB)*/
-#define DATARCYLECHECKFACTOR 1800
-
-
-/* three type of file */
-enum {
-    /* random value */
-    VIOAPND2_INDEX = 0x97,
-    VIOAPND2_DATA = 0x98,
-    VIOAPND2_DELLOG = 0x99,
-};
-
-
-/* where the record comes from when calling writerec */
-enum {
-    VIOAPND2_RECEXTERNAL = 0,
-    VIOAPND2_RECINTERNAL = 1,
-};
-
-
-/* a file is writing or full? */
-enum {
-    VIOAPND2_WRITING = 0,
-    VIOAPND2_FULL = 1,
-};
-
-/* signature in the header file, indicates it's open or be safety closed */
-enum {
-    /* any number doens't matter */
-    VIOAPND2_SIGOPEN = 2,
-    VIOAPND2_SIGCLOSED = 3,
-};
-
-
-/* buffer for IO */
-typedef struct {
-    uint32_t limit;
-    uint32_t off;
-    uint32_t pos;
-    uint32_t fid;
-    uint64_t oid;
-    int fd;
-    char buf[IOBUFSIZE];
-} VIOAPND2IOBUF;
-
-
-/* file information for every file */
-typedef struct VIOAPND2FINFO {
-    /* fid */
-    uint32_t fid;
-    /* first oid */
-    uint64_t oidf;
-    /* last oid */
-    uint64_t oidl;
-
-    /* next file */
-    struct VIOAPND2FINFO *fnext;
-    /* prev file */
-    struct VIOAPND2FINFO *fprev;
-
-    uint32_t fsize;
-    /* junk space */
-    uint32_t rcyled;
-    /* nearest expire time */
-    uint32_t nexpire;
-    /* last time for recycle check */
-    uint32_t lcktime;
-    /* index page file or data file? */
-    uint8_t ftype;
-    /* writing or full? */
-    uint8_t fstatus;
-    /* ref count, avoid unlink failure */
-    uint32_t ref;
-    /* whether unlink the file after dereference */
-    bool unlink;
-} VIOAPND2FINFO;
-
-
-typedef struct {
-    /* a new db? */
-    bool create;
-    /* fd number limit */
-    int maxfds;
-    /* opened files' fds cache */
-    CDBHASHTABLE *fdcache;
-
-    /* number of data file */
-    uint32_t dfnum;
-    /* number of index file */
-    uint32_t ifnum;
-
-    /* Buffers */
-    VIOAPND2IOBUF dbuf;
-    VIOAPND2IOBUF ibuf;
-    FOFF delbuf[DELBUFMAX];
-    int delbufpos;
-
-    /* db path */
-    char *filepath;
-
-
-    /* file information of index files */
-    CDBHASHTABLE *idxmeta;
-    VIOAPND2FINFO *idxfhead;
-    VIOAPND2FINFO *idxftail;
-    /* file information of data files */
-    CDBHASHTABLE *datmeta;
-    VIOAPND2FINFO *datfhead;
-    VIOAPND2FINFO *datftail;
-
-    /* fd for db header */
-    int hfd;
-    /* fd for files meta header */
-    int mfd;
-    /* fd for deletion log */
-    int dfd;
-
-    /* lock for all I/O operation */
-    CDBLOCK *lock;
-
-    int idxitfid;
-    uint32_t idxitoff;
-    char *idxmmap;
-
-} VIOAPND2;
-
-
-/* iterator for index/data */
-typedef struct {
-    /* current open fd */
-    int fd;
-    /* current offset in file*/
-    uint32_t off;
-    /* current operation id */
-    uint64_t oid;
-    /* current file size*/
-    uint64_t fsize;
-    /* mapped of file */
-    char *mmap;
-    /* reference of filemeta struct */
-    VIOAPND2FINFO *finfo;
-} VIOAPND2ITOR;
-
-
-static int _vio_apnd2_open(CDBVIO *vio, const char *filepath, int flags);
-static int _vio_apnd2_checkpid(CDBVIO *vio);
-static int _vio_apnd2_write(CDBVIO *vio, int fd, void *buf, uint32_t size, bool aligned);
-static int _vio_apnd2_read(CDBVIO *vio, int fd, void *buf, uint32_t size, uint64_t off);
-static int _vio_apnd2_readmeta(CDBVIO *vio, bool overwrite);
-static int _vio_apnd2_writemeta(CDBVIO *vio);
-static int _vio_apnd2_close(CDBVIO *vio);
-static int _vio_apnd2_writerec(CDBVIO *vio, CDBREC *rec, FOFF *off, int ptrtype);
-static int _vio_apnd2_writerecexternal(CDBVIO *vio, CDBREC *rec, FOFF *off);
-static int _vio_apnd2_writerecinternal(CDBVIO *vio, CDBREC *rec, FOFF *off);
-static int _vio_apnd2_deleterec(CDBVIO *vio, CDBREC *rec, FOFF off);
-static int _vio_apnd2_readrec(CDBVIO *vio, CDBREC** rec, FOFF off, bool readval);
-static int _vio_apnd2_writepage(CDBVIO *vio, CDBPAGE *page, FOFF *off);
-static int _vio_apnd2_readpage(CDBVIO *vio, CDBPAGE **page, FOFF off);
-static int _vio_apnd2_sync(CDBVIO *vio);
-static int _vio_apnd2_writehead2(CDBVIO *vio);
-static int _vio_apnd2_writehead(CDBVIO *vio, bool wtable);
-static int _vio_apnd2_readhead2(CDBVIO *vio);
-static int _vio_apnd2_readhead(CDBVIO *vio, bool rtable);
-static int _vio_apnd2_writefmeta(CDBVIO *vio, int fd, VIOAPND2FINFO *finfo);
-static int _vio_apnd2_readfmeta(CDBVIO *vio, int fd, VIOAPND2FINFO *finfo);
-static int _vio_apnd2_flushbuf(CDBVIO *vio, int dtype);
-static void _vio_apnd2_flushtask(void *arg);
-static void _vio_apnd2_rcyledataspacetask(void *arg);
-static void _vio_apnd2_fixcachepageooff(CDB *db, uint32_t bit, FOFF off);
-static void _vio_apnd2_rcylepagespacetask(void *arg);
-static int _vio_apnd2_shiftnew(CDBVIO *vio, int dtype);
-static int _vio_apnd2_recovery(CDBVIO *vio, bool force);
-static void _vio_apnd2_unlink(CDBVIO *vio, VIOAPND2FINFO *finfo, int dtype);
-static VIOAPND2FINFO* _vio_apnd2_fileiternext(CDBVIO *vio, int dtype, uint64_t oid);
-static int _vio_apnd2_iterfirst(CDBVIO *vio, VIOAPND2ITOR *it, int dtype, int64_t oid);
-static int _vio_apnd2_iterfree(CDBVIO *vio, int dtype, VIOAPND2ITOR *it);
-static int _vio_apnd2_pageiternext(CDBVIO *vio, CDBPAGE **page, void *iter);
-static int _vio_apnd2_reciternext(CDBVIO *vio, CDBREC **rec, void *iter);
-static void* _vio_apnd2_reciterfirst(CDBVIO *vio, uint64_t oid);
-static void* _vio_apnd2_pageiterfirst(CDBVIO *vio, uint64_t oid);
-static void _vio_apnd2_reciterdestory(CDBVIO *vio, void *iter);
-static void _vio_apnd2_pageiterdestory(CDBVIO *vio, void *iter);
-static void _vio_apnd2_cleanpoint(CDBVIO *vio);
-static int _vio_apnd2_cmpfuncsreorder(const void *p1, const void *p2);
-static int _vio_apnd2_checkopensig(CDBVIO *vio);
-static int _vio_apnd2_setopensig(CDBVIO *vio, int sig);
-static int _vio_apnd2_rcyledatafile(CDBVIO *vio, VIOAPND2FINFO *finfo, bool rcyle);
-
-
-/* hook the io methods */
-void vio_apnd2_init(CDBVIO *vio)
-{
-    vio->close = _vio_apnd2_close;
-    vio->open = _vio_apnd2_open;
-    vio->rpage = _vio_apnd2_readpage;
-    vio->wpage = _vio_apnd2_writepage;
-    vio->rrec = _vio_apnd2_readrec;
-    vio->drec = _vio_apnd2_deleterec;
-    vio->wrec = _vio_apnd2_writerecexternal;
-    vio->sync = _vio_apnd2_sync;
-    vio->rhead = _vio_apnd2_readhead2;
-    vio->whead = _vio_apnd2_writehead2;
-    vio->cleanpoint = _vio_apnd2_cleanpoint;
-    vio->pageitfirst = _vio_apnd2_pageiterfirst;
-    vio->pageitnext = _vio_apnd2_pageiternext;
-    vio->pageitdestroy = _vio_apnd2_pageiterdestory;
-    vio->recitfirst = _vio_apnd2_reciterfirst;
-    vio->recitnext = _vio_apnd2_reciternext;
-    vio->recitdestroy = _vio_apnd2_reciterdestory;
-}
-
-/* the hash table used in VIOAPND2 need not rehash, just use the key id is OK */
-static uint32_t _directhash(const void *key, int size)
-{
-    (void) size;
-    return *(uint32_t*)key;
-}
-
-
-/* allocate a new VIOAPND2 object, called when open db */
-static void _vio_apnd2_new(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)malloc(sizeof(VIOAPND2));
-
-    myio->dfnum = myio->ifnum = 0;
-
-    myio->dbuf.fid = 0;
-    myio->dbuf.pos = 0;
-    myio->dbuf.off = 0;
-    myio->dbuf.oid = 0;
-    memset(myio->dbuf.buf, 0, IOBUFSIZE);
-    myio->idxfhead = NULL;
-    myio->idxftail = NULL;
-
-    myio->ibuf.fid = 0;
-    myio->ibuf.pos = 0;
-    myio->ibuf.off = 0;
-    myio->ibuf.oid = 0;
-    memset(myio->ibuf.buf, 0, IOBUFSIZE);
-    myio->datfhead = NULL;
-    myio->datftail = NULL;
-
-    myio->delbufpos = 0;
-
-    myio->ifnum = 0;
-    myio->dfnum = 0;
-
-    myio->mfd = -1;
-    myio->hfd = -1;
-    myio->dfd = -1;
-
-    myio->fdcache = cdb_ht_new(true, _directhash);
-    /* the following two are look-up table, need not LRU */
-    myio->idxmeta = cdb_ht_new(false, _directhash);
-    myio->datmeta = cdb_ht_new(false, _directhash);
-
-    myio->lock = cdb_lock_new(CDB_LOCKMUTEX);
-
-    myio->create = true;
-    myio->maxfds = MAXFD;
-    myio->filepath = NULL;
-
-    vio->iometa = myio;
-}
-
-
-/* free a VIOAPND2 object, called when close db */
-static void _vio_apnd2_destroy(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    cdb_ht_destroy(myio->fdcache);
-    cdb_ht_destroy(myio->idxmeta);
-    cdb_ht_destroy(myio->datmeta);
-    cdb_lock_destory(myio->lock);
-    if (myio->filepath)
-        free(myio->filepath);
-    free(myio);
-    vio->iometa = NULL;
-}
-
-/* check if another process has already open the current db */
-static int _vio_apnd2_checkpid(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    struct stat st;
-    char filename[MAX_PATH_LEN] = {0};
-    char syspidpath[MAX_PATH_LEN] = {0};
-    snprintf(filename, MAX_PATH_LEN, "%s/pid.cdb", myio->filepath);
-
-    if (stat(filename, &st) == 0) {
-        /* pid file exist */
-        FILE *f = fopen(filename, "rt");
-        int pid = -1;
-        if (f == NULL) {
-            cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-            return -1;
-        }
-
-        int ret = fscanf(f, "%d", &pid);
-        fclose(f);
-        if (ret == 1 ) {
-            /* check if the process still alive */
-            snprintf(syspidpath, MAX_PATH_LEN, "/proc/%d", pid);
-            if (stat(syspidpath, &st) == 0) {
-                cdb_seterrno(vio->db, CDB_PIDEXIST, __FILE__, __LINE__);
-                return -1;
-            }
-        }
-    }
-
-    /* pid file non-exist or obsoleted */
-    FILE *f = fopen(filename, "wt");
-    if (f == NULL) {
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        return -1;
-    }
-    fprintf(f, "%d\n", getpid());
-    fclose(f);
-    return 0;
-}
-
-/* open an db by path and mode */
-static int _vio_apnd2_open(CDBVIO *vio, const char *filepath, int flags)
-{
-    int rflags = O_RDWR;
-    char filename[MAX_PATH_LEN] = {0};
-    int fsize;
-    int sigstatus;
-    VIOAPND2 *myio;
-
-    _vio_apnd2_new(vio);
-    myio = (VIOAPND2 *)vio->iometa;
-    myio->filepath = strdup(filepath);
-
-    if (flags & CDB_CREAT)
-        rflags |= O_CREAT;
-    if (flags & CDB_TRUNC)
-        rflags |= O_TRUNC;
-
-    if (/*_vio_apnd2_checkpid(vio) <*/ 0) {
-        goto ERRRET;
-    }
-
-    snprintf(filename, MAX_PATH_LEN, "%s/mainindex.cdb", myio->filepath);
-    myio->hfd = open(filename, rflags, 0644);
-    if (myio->hfd < 0 && errno == ENOENT && (rflags & O_CREAT)) {
-        /* try to create, but path not exists */
-        cdb_seterrno(vio->db, CDB_DIRNOEXIST, __FILE__, __LINE__);
-        goto ERRRET;
-    } else if (myio->hfd < 0) {
-        /* other open error */
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        goto ERRRET;
-    }
-
-    fsize = lseek(myio->hfd, 0, SEEK_END);
-    if (fsize) {
-        myio->create = false;
-        sigstatus = _vio_apnd2_checkopensig(vio);
-        if (sigstatus < 0) {
-            /* main table read error */
-            cdb_seterrno(vio->db, CDB_READERR, __FILE__, __LINE__);
-            goto ERRRET;
-        }
-    } else {
-        sigstatus = VIOAPND2_SIGCLOSED;
-    }
-
-    /* */
-    struct stat st;
-    snprintf(filename, MAX_PATH_LEN, "%s/force_recovery", myio->filepath);
-    if (stat(filename, &st) == 0) {
-        /* special file exist, force recovery to fix the database */
-        _vio_apnd2_recovery(vio, true);
-        unlink(filename);
-    }  else if (sigstatus == VIOAPND2_SIGOPEN) {
-        /* didn't properly closed last time */
-        _vio_apnd2_recovery(vio, false);
-    } else if (sigstatus != VIOAPND2_SIGCLOSED) {
-        cdb_seterrno(vio->db, CDB_DATAERRMETA, __FILE__, __LINE__);
-        goto ERRRET;
-    }
-
-    if (_vio_apnd2_setopensig(vio, VIOAPND2_SIGOPEN) < 0) {
-        cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-        goto ERRRET;
-    }
-
-    snprintf(filename, MAX_PATH_LEN, "%s/mainmeta.cdb", myio->filepath);
-    myio->mfd = open(filename, rflags, 0644);
-    if (myio->mfd < 0) {
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        goto ERRRET;
-    }
-
-    fsize = lseek(myio->mfd, 0, SEEK_END);
-    if (fsize) {
-        /* exist database */
-        _vio_apnd2_readmeta(vio, false);
-
-        /* open current data file and index file for buffer */
-        snprintf(filename, MAX_PATH_LEN, "%s/idx%08d.cdb", myio->filepath, myio->ibuf.fid);
-        myio->ibuf.fd = open(filename, rflags, 0644);
-        myio->ibuf.limit = CDBMIN(IOBUFSIZE, FIDXMAXSIZE - myio->ibuf.off);
-        myio->ibuf.pos = 0;
-
-        snprintf(filename, MAX_PATH_LEN, "%s/dat%08d.cdb", myio->filepath, myio->dbuf.fid);
-        myio->dbuf.fd = open(filename, rflags, 0644);
-        myio->dbuf.limit = CDBMIN(IOBUFSIZE, FDATMAXSIZE - myio->dbuf.off);
-        myio->dbuf.pos = 0;
-    } else {
-        /* new database */
-        myio->create = true;
-        /* remember the bnum */
-        _vio_apnd2_writehead(vio, false);
-        _vio_apnd2_shiftnew(vio, VIOAPND2_INDEX);
-        _vio_apnd2_shiftnew(vio, VIOAPND2_DATA);
-    }
-
-    snprintf(filename, MAX_PATH_LEN, "%s/dellog.cdb", myio->filepath);
-    myio->dfd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
-    if (myio->dfd < 0) {
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        goto ERRRET;
-    }
-
-    /* set background tasks, flush buffer and recycle space */
-    cdb_bgtask_add(vio->db->bgtask, _vio_apnd2_flushtask, vio, FLUSHTIMEOUT);
-    cdb_bgtask_add(vio->db->bgtask, _vio_apnd2_rcylepagespacetask, vio, RCYLEPAGEINTERVAL);
-    cdb_bgtask_add(vio->db->bgtask, _vio_apnd2_rcyledataspacetask, vio, RCYLEDATAINTERVAL);
-    return 0;
-
-ERRRET:
-    if (myio->mfd > 0)
-        close(myio->mfd);
-    if (myio->hfd > 0)
-        close(myio->hfd);
-    if (myio->dfd > 0)
-        close(myio->dfd);
-    _vio_apnd2_destroy(vio);
-    return -1;
-}
-
-
-/* task for flush buffer */
-static void _vio_apnd2_flushtask(void *arg)
-{
-    CDBVIO *vio = (CDBVIO *)arg;
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    cdb_lock_lock(myio->lock);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_DELLOG);
-    cdb_lock_unlock(myio->lock);
-}
-
-
-/* read information for db files, 'overwrite' indicates recovery */
-static int _vio_apnd2_readmeta(CDBVIO *vio, bool overwrite)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    char buf[FILEMETASIZE];
-    char *hbuf;
-    int hbufsize;
-    int pos = 0;
-
-    if (pread(myio->mfd, buf, FILEMETASIZE, 0) != FILEMETASIZE) {
-        if (overwrite)
-            return 0;
-        cdb_seterrno(vio->db, CDB_READERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    if (memcmp(buf, FILEMAGICHEADER, FILEMAGICLEN) != 0) {
-        cdb_seterrno(vio->db, CDB_DATAERRMETA, __FILE__, __LINE__);
-        return -1;
-    }
-
-    pos += FILEMAGICLEN;
-    cdb_lock_lock(myio->lock);
-    if (!overwrite)
-        myio->ibuf.off = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    myio->ibuf.limit = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    if (!overwrite)
-        myio->dbuf.off = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    myio->dbuf.limit = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    if (!overwrite)
-        myio->ifnum = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    if (!overwrite)
-        myio->dfnum = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    if (!overwrite)
-        myio->ibuf.fid = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    if (!overwrite)
-        myio->dbuf.fid = *(uint32_t*)(buf + pos);
-    pos += SI4;
-
-    hbufsize = (SI4 + SI4 + SI4 + SI8 + SI8 + 1 + 1) * myio->ifnum;
-    hbufsize += (SI4 + SI4 + SI4 + SI4 + SI8 + SI8 + 1 + 1) * myio->dfnum;
-    hbuf = (char*)malloc(hbufsize);
-    pos = 0;
-
-    if (pread(myio->mfd, hbuf, hbufsize, FILEMETASIZE) != hbufsize) {
-        cdb_lock_unlock(myio->lock);
-        free(hbuf);
-        if (overwrite)
-            return 0;
-        cdb_seterrno(vio->db, CDB_READERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    for(uint32_t i = 0; i < myio->ifnum; i++) {
-        VIOAPND2FINFO finfo, *finfo2;
-        finfo.fid = *(uint32_t*)(hbuf + pos);
-        pos += SI4;
-        finfo.fsize = *(uint32_t*)(hbuf + pos);
-        pos += SI4;
-        finfo.rcyled = *(uint32_t*)(hbuf + pos);
-        pos += SI4;;
-        finfo.oidf = *(uint64_t*)(hbuf + pos);
-        pos += SI8;
-        finfo.oidl = *(uint64_t*)(hbuf + pos);
-        pos += SI8;
-        finfo.fstatus = *(uint8_t*)(hbuf + pos);
-        pos += 1;
-        finfo.ftype = *(uint8_t*)(hbuf + pos);
-        pos += 1;
-        finfo.ref = 0;
-        finfo.unlink = false;
-        if (overwrite) {
-            /* in recovery mode only fix 'recycled size' */
-            /* But do nothing with index files */
-            continue;
-        }
-        finfo2 = (VIOAPND2FINFO *)cdb_ht_insert2(myio->idxmeta, &finfo.fid, SI4, &finfo, sizeof(finfo));
-        if (myio->idxfhead) {
-            finfo2->fprev = myio->idxftail;
-            myio->idxftail->fnext = finfo2;
-            finfo2->fnext = NULL;
-            myio->idxftail = finfo2;
-        } else {
-            myio->idxfhead = myio->idxftail = finfo2;
-            finfo2->fprev = finfo2->fnext = NULL;
-        }
-    }
-
-    for(uint32_t i = 0; i < myio->dfnum; i++) {
-        VIOAPND2FINFO finfo, *finfo2;
-        finfo.fid = *(uint32_t*)(hbuf + pos);
-        pos += SI4;
-        finfo.fsize = *(uint32_t*)(hbuf + pos);
-        pos += SI4;
-        finfo.rcyled = *(uint32_t*)(hbuf + pos);
-        pos += SI4;
-        finfo.nexpire = *(uint32_t*)(hbuf + pos);
-        pos += SI4;
-        finfo.oidf = *(uint64_t*)(hbuf + pos);
-        pos += SI8;
-        finfo.oidl = *(uint64_t*)(hbuf + pos);
-        pos += SI8;
-        finfo.fstatus = *(uint8_t*)(hbuf + pos);
-        pos += 1;
-        finfo.ftype = *(uint8_t*)(hbuf + pos);
-        pos += 1;
-        finfo.ref = 0;
-        finfo.unlink = false;
-        finfo.lcktime = time(NULL);
-        if (overwrite) {
-            /* in recovery mode only fix 'recycled size' */
-            finfo2 = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &finfo.fid, SI4, false);
-            if (finfo2) {
-                finfo2->rcyled = finfo.rcyled;
-                finfo2->nexpire = finfo.nexpire;
-            }
-            continue;
-        }
-        finfo2 = (VIOAPND2FINFO *)cdb_ht_insert2(myio->datmeta, &finfo.fid, SI4, &finfo, sizeof(finfo));
-        if (myio->datfhead) {
-            finfo2->fprev = myio->datftail;
-            myio->datftail->fnext = finfo2;
-            finfo2->fnext = NULL;
-            myio->datftail = finfo2;
-        } else {
-            myio->datfhead = myio->datftail = finfo2;
-            finfo2->fprev = finfo2->fnext = NULL;
-        }
-    }
-    cdb_lock_unlock(myio->lock);
-    free(hbuf);
-
-    return 0;
-}
-
-
-/* flush i/o buffer */
-static int _vio_apnd2_flushbuf(CDBVIO *vio, int dtype)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    VIOAPND2FINFO *finfo;
-    VIOAPND2IOBUF *iobuf;
-    CDBHASHTABLE *ht;
-    uint32_t *fid;
-    uint32_t fsizemax;
-
-    /* link to the proper operation object */
-    if (dtype == VIOAPND2_INDEX) {
-        iobuf = &myio->ibuf;
-        ht = myio->idxmeta;
-        fsizemax = FIDXMAXSIZE;
-    } else if (dtype == VIOAPND2_DATA) {
-        iobuf = &myio->dbuf;
-        ht = myio->datmeta;
-        fsizemax = FDATMAXSIZE;
-    } else if (dtype == VIOAPND2_DELLOG) {
-        /* buffer for deletion is special */
-        if (myio->delbufpos == 0)
-            return 0;
-        if ( (size_t) write(myio->dfd, myio->delbuf, sizeof(FOFF) * (size_t) myio->delbufpos)
-                != sizeof(FOFF) * (size_t) myio->delbufpos) {
-            cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-            return -1;
-        }
-        myio->delbufpos = 0;
-        return 0;
-    } else {
-        cdb_seterrno(vio->db, CDB_INTERNALERR, __FILE__, __LINE__);
-        return -1;
-    }
-    fid = &iobuf->fid;
-
-    /* get information from table */
-    finfo = (VIOAPND2FINFO *)cdb_ht_get2(ht, fid, SI4, false);
-    if (finfo == NULL) {
-        cdb_seterrno(vio->db, CDB_INTERNALERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    /* write out if buffered */
-    if (iobuf->pos > 0) {
-        if (pwrite(iobuf->fd, iobuf->buf, iobuf->pos, iobuf->off) != iobuf->pos) {
-            if (ftruncate(iobuf->fd, iobuf->off) < 0)
-                cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-            return -1;
-        }
-    }
-
-    /* mark the operation id */
-    finfo->oidl = iobuf->oid;
-
-    /* reset the buffer information */
-    iobuf->pos = 0;
-    iobuf->off = lseek(iobuf->fd, 0, SEEK_END);
-    /* fix file size info whenever possible */
-    finfo->fsize = iobuf->off;
-    iobuf->off = OFFALIGNED(iobuf->off);
-
-    /* current writing file nearly full? open a new one */
-    if (iobuf->off > fsizemax - 16 * KB) {
-        finfo->fstatus = VIOAPND2_FULL;
-        _vio_apnd2_writefmeta(vio, iobuf->fd, finfo);
-        close(iobuf->fd);
-        _vio_apnd2_shiftnew(vio, dtype);
-    } else
-        iobuf->limit = CDBMIN(IOBUFSIZE, fsizemax - iobuf->off) ;
-
-    return 0;
-}
-
-/* create a new file for buffer and writing */
-static int _vio_apnd2_shiftnew(CDBVIO *vio, int dtype)
-{
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    VIOAPND2IOBUF *iobuf;
-    CDBHASHTABLE *ht;
-    uint32_t *fnum;
-    uint32_t tryiter, curfid;
-    char filename[MAX_PATH_LEN];
-    char ipfx[] = "idx";
-    char dpfx[] = "dat";
-    char *pfx;
-
-    /* link to proper object by dtype */
-    if (dtype == VIOAPND2_INDEX) {
-        iobuf = &myio->ibuf;
-        ht = myio->idxmeta;
-        fnum = &myio->ifnum;
-        pfx = ipfx;
-    } else if (dtype == VIOAPND2_DATA) {
-        iobuf = &myio->dbuf;
-        ht = myio->datmeta;
-        fnum = &myio->dfnum;
-        pfx = dpfx;
-    } else {
-        cdb_seterrno(vio->db, CDB_INTERNALERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    curfid = iobuf->fid;
-
-    /* reset invalid buffer, prevent for misuse */
-    iobuf->fd = -1;
-    iobuf->fid = 0xffffff;
-    iobuf->limit = iobuf->pos = iobuf->off = 0xffffffff;
-
-    /* find a valid fid, try 16M times at most */
-    tryiter = 0;
-    while(cdb_ht_exist(ht, &curfid, SI4)) {
-        curfid++;
-        tryiter++;
-        if (tryiter == 0xffffff) {
-            cdb_seterrno(vio->db, CDB_NOFID, __FILE__, __LINE__);
-            return -1;
-        }
-        if (curfid == 0xffffff)
-            curfid = 0;
-    }
-
-    /* open new file */
-    snprintf(filename, MAX_PATH_LEN, "%s/%s%08d.cdb", myio->filepath, pfx, curfid);
-    iobuf->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
-    if (iobuf->fd < 0) {
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        return -1;
-    }
-    iobuf->limit = IOBUFSIZE;
-    iobuf->fid = curfid;
-    iobuf->off = FILEMETASIZE;
-    iobuf->pos = 0;
-
-    /* set meta information for new file */
-    VIOAPND2FINFO finfo, *finfo2;
-    finfo.fsize = lseek(iobuf->fd, 0, SEEK_END);
-    finfo.oidf = iobuf->oid;
-    finfo.oidl = iobuf->oid;
-    finfo.rcyled = 0;
-    finfo.lcktime = time(NULL);
-    finfo.fstatus = VIOAPND2_WRITING;
-    finfo.ftype = dtype;
-    finfo.fid = curfid;
-    finfo.unlink = false;
-    finfo.nexpire = 0xffffffff;
-    finfo.ref = 0;
-    /* meta information also be written to disk immediately */
-    if (_vio_apnd2_writefmeta(vio, iobuf->fd, &finfo) < 0) {
-        close(iobuf->fd);
-        iobuf->fd = -1;
-        iobuf->fid = 0xffffff;
-        iobuf->limit = iobuf->pos = iobuf->off = 0xffffffff;
-        return -1;
-    }
-    (*fnum)++;
-    finfo2 = cdb_ht_insert2(ht, &curfid, SI4, &finfo, sizeof(VIOAPND2FINFO));
-    if (dtype == VIOAPND2_INDEX) {
-        if (myio->idxfhead) {
-            finfo2->fprev = myio->idxftail;
-            myio->idxftail->fnext = finfo2;
-            finfo2->fnext = NULL;
-            myio->idxftail = finfo2;
-        } else {
-            myio->idxfhead = myio->idxftail = finfo2;
-            finfo2->fprev = finfo2->fnext = NULL;
-        }
-    } else if (dtype == VIOAPND2_DATA) {
-        if (myio->datfhead) {
-            finfo2->fprev = myio->datftail;
-            myio->datftail->fnext = finfo2;
-            finfo2->fnext = NULL;
-            myio->datftail = finfo2;
-        } else {
-            myio->datfhead = myio->datftail = finfo2;
-            finfo2->fprev = finfo2->fnext = NULL;
-        }
-    }
-
-    return 0;
-}
-
-
-/* write a single file's meta information */
-static int _vio_apnd2_writefmeta(CDBVIO *vio, int fd, VIOAPND2FINFO *finfo)
-{
-    char buf[FILEMETASIZE];
-    int pos = 0;
-
-    memset(buf, 'X', FILEMETASIZE);
-    memcpy(buf, FILEMAGICHEADER, FILEMAGICLEN);
-    pos += FILEMAGICLEN;
-    *(uint64_t*)(buf + pos) = finfo->oidf;
-    pos += SI8;
-    *(uint64_t*)(buf + pos) = finfo->oidl;
-    pos += SI8;
-    *(uint32_t*)(buf + pos) = finfo->fsize;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = finfo->fid;
-    pos += SI4;
-    *(uint8_t*)(buf + pos) = finfo->fstatus;
-    pos++;
-    *(uint8_t*)(buf + pos) = finfo->ftype;
-    pos++;
-
-    if (pwrite(fd, buf, FILEMETASIZE, 0) != FILEMETASIZE) {
-        cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-        return -1;
-    }
-    return 0;
-}
-
-/* read a single file's meta information */
-static int _vio_apnd2_readfmeta(CDBVIO *vio, int fd, VIOAPND2FINFO *finfo)
-{
-    char buf[FILEMETASIZE];
-    int pos = 0;
-
-    memset(buf, 'X', FILEMETASIZE);
-    if (pread(fd, buf, FILEMETASIZE, 0) != FILEMETASIZE) {
-        cdb_seterrno(vio->db, CDB_READERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    if (memcmp(buf, FILEMAGICHEADER, FILEMAGICLEN)) {
-        cdb_seterrno(vio->db, CDB_DATAERRMETA, __FILE__, __LINE__);
-        return -1;
-    }
-
-    pos += FILEMAGICLEN;
-    finfo->oidf = *(uint64_t*)(buf + pos);
-    pos += SI8;
-    finfo->oidl = *(uint64_t*)(buf + pos);
-    pos += SI8;
-    finfo->fsize = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    finfo->fid = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    finfo->fstatus = *(uint8_t*)(buf + pos);
-    pos++;
-    finfo->ftype  = *(uint8_t*)(buf + pos);
-    pos++;
-    return 0;
-}
-
-
-/* write to disk directly instead of using buffer(Only Appends) */
-static int _vio_apnd2_write(CDBVIO *vio, int fd, void *buf, uint32_t size, bool aligned)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    uint32_t off;
-
-    if (size == 0)
-        return 0;
-
-    off = lseek(fd, 0, SEEK_END);
-    if (aligned)
-        off = OFFALIGNED(off);
-    if (pwrite(fd, buf, size, off) != size) {
-        /* to avoid compile warning */
-        if (ftruncate(myio->ibuf.fd, off) < 0)
-            cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    return size;
-}
-
-
-/* read from disk; if data has not been written, read from buffer */
-static int _vio_apnd2_read(CDBVIO *vio, int fd, void *buf, uint32_t size, uint64_t off)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    int ret;
-
-    /* in buffer? */
-    if (fd == myio->dbuf.fd && off >= myio->dbuf.off) {
-        uint64_t boff = off - myio->dbuf.off;
-        ret = CDBMIN(size, myio->dbuf.pos - boff);
-        memcpy(buf, myio->dbuf.buf + boff, ret);
-    } else if (fd == myio->ibuf.fd && off >= myio->ibuf.off) {
-        uint64_t boff = off - myio->ibuf.off;
-        ret = CDBMIN(size, myio->ibuf.pos - boff);
-        memcpy(buf, myio->ibuf.buf + boff, ret);
-    } else {
-        /* not in buffer */
-        ret = pread(fd, buf, size, off);
-        if (ret < 0) {
-            cdb_seterrno(vio->db, CDB_READERR, __FILE__, __LINE__);
-            return -1;
-        }
-    }
-    return ret;
-}
-
-
-/* write all files meta information into a file */
-static int _vio_apnd2_writemeta(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    char buf[FILEMETASIZE];
-    char *hbuf;
-    int hbufsize;
-    int pos = 0;
-
-    memset(buf, 'X', FILEMETASIZE);
-    memcpy(buf, FILEMAGICHEADER, FILEMAGICLEN);
-    pos += FILEMAGICLEN;
-    cdb_lock_lock(myio->lock);
-    *(uint32_t*)(buf + pos) = myio->ibuf.off;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->ibuf.limit;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->dbuf.off;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->dbuf.limit;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->ifnum;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->dfnum;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->ibuf.fid;
-    pos += SI4;
-    *(uint32_t*)(buf + pos) = myio->dbuf.fid;
-    pos += SI4;
-
-    hbufsize = (SI4 + SI4 + SI4 + SI8 + SI8 + 1 + 1) * myio->ifnum;
-    hbufsize += (SI4 + SI4 + SI4 + SI4 + SI8 + SI8 + 1 + 1) * myio->dfnum;
-    hbuf = (char*)malloc(hbufsize);
-    memset(hbuf, 'X', hbufsize);
-    pos = 0;
-    /* iterate all the index files order by oid */
-    VIOAPND2FINFO *finfo = myio->idxfhead;
-    while(finfo != NULL) {
-        *(uint32_t*)(hbuf + pos) = finfo->fid;
-        pos += 4;
-        *(uint32_t*)(hbuf + pos) = finfo->fsize;
-        pos += 4;
-        *(uint32_t*)(hbuf + pos) = finfo->rcyled;
-        pos += 4;
-        *(uint64_t*)(hbuf + pos) = finfo->oidf;
-        pos += 8;
-        *(uint64_t*)(hbuf + pos) = finfo->oidl;
-        pos += 8;
-        *(uint8_t*)(hbuf + pos) = finfo->fstatus;
-        pos += 1;
-        *(uint8_t*)(hbuf + pos) = finfo->ftype;
-        pos += 1;
-        finfo = finfo->fnext;
-    }
-
-    /* iterate all the data files order by oid */
-    finfo = myio->datfhead;
-    while(finfo != NULL) {
-        *(uint32_t*)(hbuf + pos) = finfo->fid;
-        pos += 4;
-        *(uint32_t*)(hbuf + pos) = finfo->fsize;
-        pos += 4;
-        *(uint32_t*)(hbuf + pos) = finfo->rcyled;
-        pos += 4;
-        *(uint32_t*)(hbuf + pos) = finfo->nexpire;
-        pos += 4;
-        *(uint64_t*)(hbuf + pos) = finfo->oidf;
-        pos += 8;
-        *(uint64_t*)(hbuf + pos) = finfo->oidl;
-        pos += 8;
-        *(uint8_t*)(hbuf + pos) = finfo->fstatus;
-        pos += 1;
-        *(uint8_t*)(hbuf + pos) = finfo->ftype;
-        pos += 1;
-        finfo = finfo->fnext;
-    }
-    cdb_lock_unlock(myio->lock);
-
-    if (pwrite(myio->mfd, buf, FILEMETASIZE, 0) != FILEMETASIZE) {
-        cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-        free(hbuf);
-        return -1;
-    }
-
-    if (pwrite(myio->mfd, hbuf, hbufsize, FILEMETASIZE) != hbufsize) {
-        cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-        free(hbuf);
-        return -1;
-    }
-    free(hbuf);
-
-    return 0;
-}
-
-
-/* close db */
-static int _vio_apnd2_close(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDBHTITEM *item;
-    char filename[MAX_PATH_LEN] = {0};
-    VIOAPND2FINFO *finfo;
-
-    /* flush buffer */
-    _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-    finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->idxmeta, &myio->ibuf.fid, SI4, false);
-    if (finfo)
-        _vio_apnd2_writefmeta(vio, myio->ibuf.fd, finfo);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-    finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &myio->dbuf.fid, SI4, false);
-    if (finfo)
-        _vio_apnd2_writefmeta(vio, myio->dbuf.fd, finfo);
-
-    /* iterate and close the fd cache */
-    item = cdb_ht_iterbegin(myio->fdcache);
-    while(item != NULL) {
-        close(*(int*)cdb_ht_itemval(myio->fdcache, item));
-        item = cdb_ht_iternext(myio->fdcache, item);
-    }
-
-    if (myio->dbuf.fd > 0)
-        close(myio->dbuf.fd);
-    if (myio->ibuf.fd > 0)
-        close(myio->ibuf.fd);
-
-    /* rewrite the metafile */
-    _vio_apnd2_writemeta(vio);
-    /* close all open files */
-    snprintf(filename, MAX_PATH_LEN, "%s/pid.cdb", myio->filepath);
-    unlink(filename);
-    /* dellog only be useful for recovery of database unsafety close */
-    snprintf(filename, MAX_PATH_LEN, "%s/dellog.cdb", myio->filepath);
-    unlink(filename);
-    _vio_apnd2_setopensig(vio, VIOAPND2_SIGCLOSED);
-    if (myio->hfd > 0)
-        close(myio->hfd);
-    if (myio->mfd > 0)
-        close(myio->mfd);
-    if (myio->dfd > 0)
-        close(myio->dfd);
-    _vio_apnd2_destroy(vio);
-    return 0;
-}
-
-
-/* open a file, and remember its fd. The function runs under lock protection */
-static int _vio_apnd2_loadfd(CDBVIO *vio, uint32_t fid, int dtype)
-{
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    int fd;
-    char filename[MAX_PATH_LEN];
-    char ipfx[] = "idx";
-    char dpfx[] = "dat";
-    char *pfx;
-    uint32_t vfid;
-
-    if (dtype == VIOAPND2_INDEX) {
-        pfx = ipfx;
-        vfid = VFIDIDX(fid);
-    } else if (dtype == VIOAPND2_DATA) {
-        pfx = dpfx;
-        vfid = VFIDDAT(fid);
-    } else {
-        cdb_seterrno(vio->db, CDB_INTERNALERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    snprintf(filename, MAX_PATH_LEN, "%s/%s%08d.cdb", myio->filepath, pfx, fid);
-    fd = open(filename, O_RDONLY, 0644);
-    if (fd < 0) {
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    /* cache the fd, close the oldest file not touched */
-    cdb_ht_insert2(myio->fdcache, &vfid, SI4, &fd, sizeof(int));
-    while(myio->fdcache->num > (uint32_t) myio->maxfds) {
-        CDBHTITEM *item = cdb_ht_poptail(myio->fdcache);
-        close(*(int*)cdb_ht_itemval(myio->fdcache, item));
-        free(item);
-    }
-
-    return fd;
-}
-
-/* read a index page */
-static int _vio_apnd2_readpage(CDBVIO *vio, CDBPAGE **page, FOFF off)
-{
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    int ret, fd;
-    uint32_t psize;
-    uint32_t fid, roff;
-    uint32_t fixbufsize = SBUFSIZE - (sizeof(CDBPAGE) - PAGEHSIZE);
-    uint32_t areadsize = PAGEAREADSIZE; //vio->db->areadsize;
-
-    VOFF2ROFF(off, fid, roff);
-    /* avoid dirty memory */
-    (*page)->magic = 0;
-
-    cdb_lock_lock(myio->lock);
-    if (fid == myio->ibuf.fid)
-        /* read from current writing file? */
-        fd = myio->ibuf.fd;
-    else {
-        /* old index file */
-        int vfid, *fdret;
-        vfid = VFIDIDX(fid);
-        /* in cache? */
-        fdret = cdb_ht_get2(myio->fdcache, &vfid, sizeof(vfid), true);
-        if (fdret == NULL) {
-            fd = _vio_apnd2_loadfd(vio, fid, VIOAPND2_INDEX);
-            if (fd < 0) {
-                cdb_lock_unlock(myio->lock);
-                return -1;
-            }
-        } else
-            fd = *fdret;
-    }
-
-    /* NOTICE: the data on disk actually starts at 'magic' field in structure */
-    ret = _vio_apnd2_read(vio, fd, &(*page)->magic, areadsize, roff);
-    if (ret <= 0) {
-        cdb_lock_unlock(myio->lock);
-        return -1;
-    }
-
-    if ((*page)->magic != PAGEMAGIC) {
-        cdb_lock_unlock(myio->lock);
-        cdb_seterrno(vio->db, CDB_DATAERRIDX, __FILE__, __LINE__);
-        return -1;
-    }
-
-    psize = PAGESIZE(*page);
-    if ((uint32_t) ret < areadsize && (uint32_t) ret < psize) {
-        cdb_lock_unlock(myio->lock);
-        cdb_seterrno(vio->db, CDB_DATAERRIDX, __FILE__, __LINE__);
-        return ret;
-    } else if (psize > areadsize) {
-        /* need another read operation since the page is a large than default read size */
-        if (psize > fixbufsize) {
-            /* record is larger the stack size */
-            CDBPAGE *npage = (CDBPAGE *)malloc(sizeof(CDBPAGE) + (*page)->num * sizeof(PITEM));
-            memcpy(&npage->magic, &(*page)->magic, areadsize);
-            *page = npage;
-        }
-
-        ret = _vio_apnd2_read(vio, fd, (char*)&(*page)->magic + areadsize,
-            psize - areadsize, roff + areadsize);
-        if ((uint32_t) ret < psize - areadsize) {
-            cdb_lock_unlock(myio->lock);
-            cdb_seterrno(vio->db, CDB_DATAERRIDX, __FILE__, __LINE__);
-            return -1;
-        }
-    }
-
-    cdb_lock_unlock(myio->lock);
-
-    /* remember where i got the page, calculate into junk space if page is discarded */
-    (*page)->osize = OFFALIGNED(psize);
-    (*page)->ooff = off;
-    (*page)->cap = (*page)->num;
-    return 0;
-}
-
-/* read a data record */
-static int _vio_apnd2_readrec(CDBVIO *vio, CDBREC** rec, FOFF off, bool readval)
-{
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    int ret, fd;
-    uint32_t rsize;
-    uint32_t fid, roff;
-    /* the 'rec' is hoped to be fit in stack, the actually size is a little smaller */
-    /* because some fields in CDBREC structure are not on disk */
-    uint32_t fixbufsize = SBUFSIZE - (sizeof(CDBREC) - RECHSIZE);
-    uint32_t areadsize = vio->db->areadsize;
-
-    VOFF2ROFF(off, fid, roff);
-    /* avoid dirty memory */
-    (*rec)->magic = 0;
-
-    cdb_lock_lock(myio->lock);
-    if (fid == myio->dbuf.fid)
-        /* read from current writing file? */
-        fd = myio->dbuf.fd;
-    else {
-        /* read from old data file */
-        int vfid, *fdret;
-        vfid = VFIDDAT(fid);
-        fdret = cdb_ht_get2(myio->fdcache, &vfid, sizeof(vfid), true);
-        if (fdret == NULL) {
-            fd = _vio_apnd2_loadfd(vio, fid, VIOAPND2_DATA);
-            if (fd < 0) {
-                cdb_lock_unlock(myio->lock);
-                return -1;
-            }
-        } else
-            fd = *fdret;
-    }
-
-    /* NOTICE: the data on disk actually starts at 'magic' field in structure */
-    ret = _vio_apnd2_read(vio, fd, &(*rec)->magic, areadsize, roff);
-    if (ret <= 0) {
-        cdb_lock_unlock(myio->lock);
-        return -1;
-    }
-
-    if ((*rec)->magic != RECMAGIC) {
-        cdb_lock_unlock(myio->lock);
-        cdb_seterrno(vio->db, CDB_DATAERRDAT, __FILE__, __LINE__);
-        return -1;
-    }
-
-    uint32_t ovsize = (*rec)->vsize;
-    if (!readval)
-        /* read key only */
-        (*rec)->vsize = 0;
-    rsize = RECSIZE(*rec);
-
-    if ((uint32_t) ret < areadsize && (uint32_t) ret < rsize) {
-        cdb_lock_unlock(myio->lock);
-        cdb_seterrno(vio->db, CDB_DATAERRDAT, __FILE__, __LINE__);
-        return -1;
-    } else if (rsize > areadsize) {
-        /* need another read */
-        if (rsize > fixbufsize) {
-            /* record is larger the stack size */
-            CDBREC *nrec = (CDBREC *)malloc(sizeof(CDBREC)+(*rec)->ksize+(*rec)->vsize);
-            memcpy(&nrec->magic, &(*rec)->magic, areadsize);
-            *rec = nrec;
-        }
-        ret = _vio_apnd2_read(vio, fd, (char*)&(*rec)->magic + areadsize,
-            rsize - areadsize, roff + areadsize);
-        if ((uint32_t) ret != rsize - areadsize) {
-            cdb_lock_unlock(myio->lock);
-            cdb_seterrno(vio->db, CDB_DATAERRDAT, __FILE__, __LINE__);
-            return -1;
-        }
-    }
-    cdb_lock_unlock(myio->lock);
-
-    /* fix pointer */
-    (*rec)->key = (*rec)->buf;
-    (*rec)->val = (*rec)->buf + (*rec)->ksize;
-
-    /* even if didn't read the value, still keep the complete (old) size */
-    if (!readval)
-        (*rec)->osize = OFFALIGNED(rsize + ovsize);
-    else
-        (*rec)->osize = OFFALIGNED(rsize);
-
-    (*rec)->ooff = off;
-    return 0;
-}
-
-
-/* write a index page, return the written virtual offset */
-static int _vio_apnd2_writepage(CDBVIO *vio, CDBPAGE *page, FOFF *off)
-{
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    VIOAPND2FINFO *finfo;
-    uint32_t psize = PAGESIZE(page);
-    uint32_t fid, roff;
-    uint32_t ofid;
-
-    page->magic = PAGEMAGIC;
-    page->oid = cdb_genoid(vio->db);
-
-    cdb_lock_lock(myio->lock);
-    /* buffer ready? */
-    if (myio->ibuf.fd < 0) {
-        if (_vio_apnd2_shiftnew(vio, VIOAPND2_INDEX) < 0) {
-            cdb_lock_unlock(myio->lock);
-            return -1;
-        }
-    }
-
-    /* if it was modified from existing page, remember the wasted space */
-    if (OFFNOTNULL(page->ooff)) {
-        VOFF2ROFF(page->ooff, ofid, roff);
-        finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->idxmeta, &ofid, SI4, false);
-        if (finfo)
-            finfo->rcyled += page->osize;
-    }
-
-    if (psize > myio->ibuf.limit) {
-        /* page too large  */
-        _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-        fid = myio->ibuf.fid;
-        roff = myio->ibuf.off;
-        _vio_apnd2_write(vio, myio->ibuf.fd, &page->magic, psize, true);
-        myio->ibuf.oid = page->oid;
-        _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-        cdb_lock_unlock(myio->lock);
-
-        /* remember last wrote offset */
-        ROFF2VOFF(fid, roff, *off);
-        page->ooff = *off;
-        page->osize = OFFALIGNED(psize);
-        return 0;
-    } else if (psize + myio->ibuf.pos > myio->ibuf.limit)
-        /* buffer is full */
-        _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-
-    /* copy to buffer */
-    fid = myio->ibuf.fid;
-    roff = myio->ibuf.off + myio->ibuf.pos;
-    memcpy(myio->ibuf.buf + myio->ibuf.pos, &page->magic, psize);
-    myio->ibuf.pos += psize;
-    myio->ibuf.pos = OFFALIGNED(myio->ibuf.pos);
-    myio->ibuf.oid = page->oid;
-    cdb_lock_unlock(myio->lock);
-    ROFF2VOFF(fid, roff, *off);
-
-    /* remember last wrote offset */
-    page->ooff = *off;
-    page->osize = OFFALIGNED(psize);
-    return 0;
-}
-
-
-/* delete a record */
-static int _vio_apnd2_deleterec(CDBVIO *vio, CDBREC *rec, FOFF off)
-{
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    uint32_t ofid, roff;
-
-    cdb_lock_lock(myio->lock);
-    myio->delbuf[myio->delbufpos] = off;
-    if (++myio->delbufpos == DELBUFMAX) {
-        if (_vio_apnd2_flushbuf(vio, VIOAPND2_DELLOG) < 0)
-            return -1;
-    }
-
-    /* it is an deleted record, remember the space to be recycled */
-    VOFF2ROFF(off, ofid, roff);
-    if (OFFNOTNULL(rec->ooff)) {
-        VIOAPND2FINFO *finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &ofid, SI4, false);
-        if (finfo) {
-            finfo->rcyled += rec->osize;
-        }
-    }
-    cdb_lock_unlock(myio->lock);
-    return 0;
-}
-
-
-
-/* write a data record, return the written virtual offset */
-static int _vio_apnd2_writerec(CDBVIO *vio, CDBREC *rec, FOFF *off, int ptrtype) {
-    VIOAPND2 *myio = (VIOAPND2*)vio->iometa;
-    uint32_t rsize = RECSIZE(rec);
-    uint32_t fid, roff, ofid;
-    if (ptrtype == VIOAPND2_RECEXTERNAL)
-        rec->magic = RECMAGIC;
-
-    /* oid always are increment, even if it is a record moved from an old data file */
-    rec->oid = cdb_genoid(vio->db);
-    cdb_lock_lock(myio->lock);
-    /* buffer ready? */
-    if (myio->dbuf.fd < 0) {
-        if (_vio_apnd2_shiftnew(vio, VIOAPND2_DATA) < 0) {
-            cdb_lock_unlock(myio->lock);
-            return -1;
-        }
-    }
-    /* it is an overwritten record, remember the space to be recycled */
-    if (OFFNOTNULL(rec->ooff)) {
-        VOFF2ROFF(rec->ooff, ofid, roff);
-        VIOAPND2FINFO *finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &ofid, SI4, false);
-        if (finfo)
-            finfo->rcyled += rec->osize;
-    }
-    if (rsize > myio->dbuf.limit) {
-        /* record too large */
-        _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-        fid = myio->dbuf.fid;
-        roff = myio->dbuf.off;
-        _vio_apnd2_write(vio, myio->dbuf.fd, &rec->magic, RECHSIZE, true);
-        if (ptrtype == VIOAPND2_RECINTERNAL)
-            _vio_apnd2_write(vio, myio->dbuf.fd, rec->buf, rec->ksize + rec->vsize, false);
-        else {
-            _vio_apnd2_write(vio, myio->dbuf.fd, rec->key, rec->ksize, false);
-            _vio_apnd2_write(vio, myio->dbuf.fd, rec->val, rec->vsize, false);
-        }
-        /* reset the buffer */
-        myio->dbuf.oid = rec->oid;
-        _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-        if (rec->expire) {
-            VIOAPND2FINFO *finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &fid, SI4, false);
-            if (finfo) {
-                if (finfo->nexpire == 0) {
-                    finfo->lcktime = time(NULL);
-                    finfo->nexpire = rec->expire;
-                } else if (finfo->nexpire > rec->expire) {
-                    finfo->nexpire = rec->expire;
-                }
-            }
-        }
-        cdb_lock_unlock(myio->lock);
-        ROFF2VOFF(fid, roff, *off);
-        return 0;
-    } else if (rsize + myio->dbuf.pos > myio->dbuf.limit)
-        /* buffer is full */
-        _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-    /* copy to buffer */
-    fid = myio->dbuf.fid;
-    roff = myio->dbuf.off + myio->dbuf.pos;
-    memcpy(myio->dbuf.buf + myio->dbuf.pos, &rec->magic, RECHSIZE);
-    myio->dbuf.pos += RECHSIZE;
-    if (ptrtype == VIOAPND2_RECINTERNAL) {
-        memcpy(myio->dbuf.buf + myio->dbuf.pos, rec->buf, rec->ksize + rec->vsize);
-        myio->dbuf.pos += rec->ksize + rec->vsize;
-    } else {
-        memcpy(myio->dbuf.buf + myio->dbuf.pos, rec->key, rec->ksize);
-        myio->dbuf.pos += rec->ksize;
-        memcpy(myio->dbuf.buf + myio->dbuf.pos, rec->val, rec->vsize);
-        myio->dbuf.pos += rec->vsize;
-    }
-    myio->dbuf.pos = OFFALIGNED(myio->dbuf.pos);
-    myio->dbuf.oid = rec->oid;
-    if (rec->expire) {
-        VIOAPND2FINFO *finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &fid, SI4, false);
-        if (finfo) {
-            if (finfo->nexpire == 0) {
-                finfo->lcktime = time(NULL);
-                finfo->nexpire = rec->expire;
-            } else if (finfo->nexpire > rec->expire) {
-                finfo->nexpire = rec->expire;
-            }
-        }
-    }
-    ROFF2VOFF(fid, roff, *off);
-    cdb_lock_unlock(myio->lock);
-    rec->osize = rsize;
-    rec->ooff = *off;
-    return 0;
-}
-
-static int _vio_apnd2_writerecexternal(CDBVIO *vio, CDBREC *rec, FOFF *off)
-{
-    return _vio_apnd2_writerec(vio, rec, off, VIOAPND2_RECEXTERNAL);
-}
-
-static int _vio_apnd2_writerecinternal(CDBVIO *vio, CDBREC *rec, FOFF *off)
-{
-    return _vio_apnd2_writerec(vio, rec, off, VIOAPND2_RECINTERNAL);
-}
-
-
-/* flush buffers, and sync data to disk from OS cache */
-static int _vio_apnd2_sync(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    cdb_lock_lock(myio->lock);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-    if (myio->dbuf.fd > 0)
-        fdatasync(myio->dbuf.fd);
-    if (myio->ibuf.fd > 0)
-        fdatasync(myio->ibuf.fd);
-
-    _vio_apnd2_writehead(vio, false);
-    cdb_lock_unlock(myio->lock);
-    return 0;
-}
-
-
-/* write db information and main index table into a single file */
-static int _vio_apnd2_writehead(CDBVIO *vio, bool wtable)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDB *db = vio->db;
-    char buf[FILEMETASIZE];
-    int pos = 0;
-
-    memset(buf, 'X', FILEMETASIZE);
-    memcpy(buf, FILEMAGICHEADER, FILEMAGICLEN);
-    pos += FILEMAGICLEN;
-    *(uint32_t*)(buf + pos) = db->hsize;
-    pos += SI4;
-    *(uint64_t*)(buf + pos) = db->oid;
-    pos += SI8;
-    *(uint64_t*)(buf + pos) = db->roid;
-    pos += SI8;
-    *(uint64_t*)(buf + pos) = db->rnum;
-    pos += SI8;
-    *(uint32_t*)(buf + pos) = VIOAPND2_SIGOPEN;
-    pos += SI4;
-
-    if (pwrite(myio->hfd, buf, FILEMETASIZE, 0) != FILEMETASIZE) {
-        cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    if (wtable && (size_t) pwrite(myio->hfd, db->mtable, sizeof(FOFF) * db->hsize, FILEMETASIZE)
-        != sizeof(FOFF) * db->hsize) {
-            cdb_seterrno(vio->db, CDB_WRITEERR, __FILE__, __LINE__);
-            return -1;
-    }
-    return 0;
-}
-
-
-/* wrapped for upper layer */
-static int _vio_apnd2_writehead2(CDBVIO *vio)
-{
-    return _vio_apnd2_writehead(vio, true);
-}
-
-
-/* read db information and main index table from a single file */
-static int _vio_apnd2_readhead(CDBVIO *vio, bool rtable)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDB *db = vio->db;
-    char buf[FILEMETASIZE];
-    int pos = 0;
-
-    if (myio->create) {
-        /* the db is just created, allocate a empty main index table for db */
-        db->mtable = (FOFF *)malloc(sizeof(FOFF) * db->hsize);
-        memset(db->mtable, 0, sizeof(FOFF) * db->hsize);
-        _vio_apnd2_writehead(vio, false);
-        return 0;
-    }
-
-    if (pread(myio->hfd, buf, FILEMETASIZE, 0) != FILEMETASIZE) {
-        cdb_seterrno(db, CDB_READERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    if (memcmp(buf, FILEMAGICHEADER, FILEMAGICLEN)) {
-        cdb_seterrno(db, CDB_DATAERRMETA, __FILE__, __LINE__);
-        return -1;
-    }
-
-    pos += FILEMAGICLEN;
-    db->hsize = *(uint32_t*)(buf + pos);
-    pos += SI4;
-    db->oid = *(uint64_t*)(buf + pos);
-    pos += SI8;
-    db->roid = *(uint64_t*)(buf + pos);
-    pos += SI8;
-    db->rnum = *(uint64_t*)(buf + pos);
-    pos += SI8;
-    /* 4 bytes reserved for open status */
-    pos += SI4;
-
-    if (!rtable)
-        return 0;
-
-    if (db->mtable)
-        free(db->mtable);
-    db->mtable = (FOFF *)malloc(sizeof(FOFF) * db->hsize);
-    if ( (size_t) pread(myio->hfd, db->mtable, sizeof(FOFF) * db->hsize, FILEMETASIZE) !=
-        sizeof(FOFF) * db->hsize) {
-            free(db->mtable);
-            cdb_seterrno(db, CDB_READERR, __FILE__, __LINE__);
-            return -1;
-    }
-    return 0;
-}
-
-
-/* wrapped for upper layer */
-static int _vio_apnd2_readhead2(CDBVIO *vio)
-{
-    return _vio_apnd2_readhead(vio, true);
-}
-
-
-/* check if some dat file has too large junk space */
-static void _vio_apnd2_rcyledataspacetask(void *arg)
-{
-    CDBVIO *vio = (CDBVIO *)arg;
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDBHTITEM *item;
-    uint32_t now = time(NULL);
-    uint32_t posblexpnum = 0;
-    cdb_lock_lock(myio->lock);
-    item = cdb_ht_iterbegin(myio->datmeta);
-    while(item != NULL) {
-        VIOAPND2FINFO *finfo = (VIOAPND2FINFO*)cdb_ht_itemval(myio->datmeta, item);
-        if (finfo->nexpire && finfo->nexpire <= now)
-            posblexpnum++;
-        item = cdb_ht_iternext(myio->datmeta, item);
-    }
-
-    item = cdb_ht_iterbegin(myio->datmeta);
-    while(item != NULL) {
-        VIOAPND2FINFO *finfo = (VIOAPND2FINFO*)cdb_ht_itemval(myio->datmeta, item);
-        uint32_t fid = finfo->fid;
-        /* rcyled space size is inaccurate */
-        if (finfo->rcyled * 2 < finfo->fsize
-            /* no data file possibly has expire record */
-            && (posblexpnum == 0
-            /* long enough time passed since last check on this file */
-            || finfo->lcktime + posblexpnum * DATARCYLECHECKFACTOR > now
-            /* check the data file most recent expire record */
-            || finfo->nexpire > now
-            /* no expire record */
-            || finfo->nexpire == 0)) {
-            item = cdb_ht_iternext(myio->datmeta, item);
-            continue;
-        }
-
-        /* do not work on the writing file or file to be deleted */
-        if (finfo->fstatus != VIOAPND2_FULL || finfo->unlink) {
-            item = cdb_ht_iternext(myio->datmeta, item);
-            continue;
-        }
-
-        /* have to iterate and calculate recycle space */
-        finfo->ref++;
-        /* operation on this file should not in lock protection */
-        cdb_lock_unlock(myio->lock);
-
-        if (finfo->rcyled * 2 < finfo->fsize) {
-            _vio_apnd2_rcyledatafile(vio, finfo, false);
-            finfo->lcktime = now;
-        }
-
-        if (finfo->rcyled * 2 >= finfo->fsize) {
-            _vio_apnd2_rcyledatafile(vio, finfo, true);
-        }
-
-        cdb_lock_lock(myio->lock);
-        finfo->ref--;
-        if (finfo->ref == 0 && finfo->unlink) {
-            /* unlink the file */
-            _vio_apnd2_unlink(vio, finfo, VIOAPND2_DATA);
-            cdb_ht_del2(myio->datmeta, &fid, SI4);
-        }
-        item = cdb_ht_iterbegin(myio->datmeta);
-    }
-    cdb_lock_unlock(myio->lock);
-}
-
-/* only be called in _vio_apnd2_rcylepagespacetask; when a page is moved into a new
-  index file, its ooff should be changed, also its copy in cache should be updated */
-static void _vio_apnd2_fixcachepageooff(CDB *db, uint32_t bid, FOFF off)
-{
-    CDBPAGE *page = NULL;
-
-    if (db->pcache) {
-        cdb_lock_lock(db->pclock);
-        page = cdb_ht_get2(db->pcache, &bid, SI4, true);
-        cdb_lock_unlock(db->pclock);
-    }
-
-    /* not in pcache, exists in dirty page cache? */
-    if (page == NULL && db->dpcache) {
-        cdb_lock_lock(db->dpclock);
-        page = cdb_ht_get2(db->dpcache, &bid, SI4, true);
-        cdb_lock_unlock(db->dpclock);
-    }
-
-    if (page)
-        page->ooff = off;
-}
-
-/* check if some index file has too large junk space */
-static void _vio_apnd2_rcylepagespacetask(void *arg)
-{
-    CDBVIO *vio = (CDBVIO *)arg;
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDBHTITEM *item;
-
-    cdb_lock_lock(myio->lock);
-    item = cdb_ht_iterbegin(myio->idxmeta);
-    while(item != NULL) {
-        VIOAPND2FINFO *finfo = (VIOAPND2FINFO*)cdb_ht_itemval(myio->idxmeta, item);
-        uint32_t fid = finfo->fid;
-
-        /* do not work on the writing file or file to be deleted */
-        if (finfo->fstatus != VIOAPND2_FULL || finfo->unlink) {
-            item = cdb_ht_iternext(myio->idxmeta, item);
-            continue;
-        }
-
-        /* junk space too large? */
-        if (finfo->rcyled * 2 > finfo->fsize) {
-            int fd;
-            char filename[MAX_PATH_LEN];
-            snprintf(filename, MAX_PATH_LEN, "%s/idx%08d.cdb", myio->filepath, fid);
-            fd = open(filename, O_RDONLY, 0644);
-            if (fd < 0) {
-                cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-                item = cdb_ht_iternext(myio->idxmeta, item);
-                continue;
-            }
-            finfo->ref++;
-            /* I/O should not block the lock */
-            cdb_lock_unlock(myio->lock);
-
-            uint32_t fsize = lseek(fd, 0, SEEK_END);
-            uint32_t pos = FILEMETASIZE;
-            char *map = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
-            while(pos < fsize) {
-                CDBPAGE *page = (CDBPAGE *)&map[pos-(sizeof(CDBPAGE) - PAGEHSIZE)];
-                FOFF off;
-
-                if (page->magic != PAGEMAGIC) {
-                    pos += ALIGNBYTES;
-                    continue;
-                }
-
-                ROFF2VOFF(fid, pos, off);
-                page->ooff = off;
-                page->osize = OFFALIGNED(PAGESIZE(page));
-                if (OFFEQ(vio->db->mtable[page->bid], off)) {
-                    FOFF noff;
-                    _vio_apnd2_writepage(vio, page, &noff);
-                    /* lock and double check */
-                    cdb_lock_lock(vio->db->mlock[page->bid % MLOCKNUM]);
-                    if (OFFEQ(vio->db->mtable[page->bid], off)) {
-                        vio->db->mtable[page->bid] = noff;
-                        _vio_apnd2_fixcachepageooff(vio->db, page->bid, noff);
-                    }
-                    cdb_lock_unlock(vio->db->mlock[page->bid % MLOCKNUM]);
-                }
-                pos += OFFALIGNED(PAGESIZE(page));
-            }
-            munmap(map, fsize);
-            close(fd);
-
-            cdb_lock_lock(myio->lock);
-            /* drop information for the file */
-            finfo->ref--;
-            finfo->unlink = true;
-            if (finfo->ref == 0) {
-                /* unlink the file */
-                _vio_apnd2_unlink(vio, finfo, VIOAPND2_INDEX);
-                cdb_ht_del2(myio->idxmeta, &fid, SI4);
-            }
-            /* reset the iterator */
-            item = cdb_ht_iterbegin(myio->idxmeta);
-            continue;
-        }
-        item = cdb_ht_iternext(myio->idxmeta, item);
-    }
-    cdb_lock_unlock(myio->lock);
-}
-
-
-/* unlink a file and remove fd from fdcache. The function runs under lock protection */
-static void _vio_apnd2_unlink(CDBVIO *vio, VIOAPND2FINFO *finfo, int dtype)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    char filename[MAX_PATH_LEN];
-    char ipfx[] = "idx";
-    char dpfx[] = "dat";
-    char *pfx;
-    uint32_t *fnum;
-    uint32_t vfid, fid = finfo->fid;
-    VIOAPND2FINFO **fhead, **ftail;
-    CDBHTITEM *fditem = NULL;
-
-    if (dtype == VIOAPND2_INDEX) {
-        pfx = ipfx;
-        vfid = VFIDIDX(fid);
-        fnum = &myio->ifnum;
-        fhead = &myio->idxfhead;
-        ftail = &myio->idxftail;
-    } else if (dtype == VIOAPND2_DATA) {
-        pfx = dpfx;
-        vfid = VFIDDAT(fid);
-        fnum = &myio->dfnum;
-        fhead = &myio->datfhead;
-        ftail = &myio->datftail;
-    } else
-        return;
-
-    snprintf(filename, MAX_PATH_LEN, "%s/%s%08d.cdb", myio->filepath, pfx, fid);
-    fditem = cdb_ht_del(myio->fdcache, &vfid, SI4);
-    if (fditem != NULL) {
-        close(*(int*)cdb_ht_itemval(myio->fdcache, fditem));
-        free(fditem);
-    }
-    (*fnum)--;
-    unlink(filename);
-
-    /* fix linked list of data/index files after remove a finfo from meta table */
-    if (finfo->fprev)
-        finfo->fprev->fnext = finfo->fnext;
-    if (finfo->fnext)
-        finfo->fnext->fprev = finfo->fprev;
-    if (*fhead == finfo)
-        *fhead = finfo->fnext;
-    if (*ftail == finfo)
-        *ftail = finfo->fprev;
-}
-
-
-/* only be used for sorting files at recovery */
-typedef struct {
-    uint32_t fid;
-    uint64_t oidf;
-} VIOAPND2SREORDER;
-
-
-static int _vio_apnd2_cmpfuncsreorder(const void *p1, const void *p2)
-{
-    VIOAPND2SREORDER *s1, *s2;
-    s1 = (VIOAPND2SREORDER *)p1;
-    s2 = (VIOAPND2SREORDER *)p2;
-    return s1->oidf - s2->oidf;
-}
-
-
-/* recovery the database if it was not close properly
- * or force recovery from roid = 0
- * the procedure runs with no lock protection */
-static int _vio_apnd2_recovery(CDBVIO *vio, bool force)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDB *db = vio->db;
-    char filename[MAX_PATH_LEN];
-    struct dirent *filelist;
-    VIOAPND2SREORDER *idxorders;
-    int idxpos, idxlimit;
-    VIOAPND2SREORDER *datorders;
-    int datpos, datlimit;
-    uint32_t imaxfid = 0, dmaxfid = 0;
-    bool gotmindex = false;
-
-
-    idxpos = datpos = 0;
-    idxlimit = datlimit = 256;
-    idxorders = (VIOAPND2SREORDER *)malloc(idxlimit * sizeof(VIOAPND2SREORDER));
-    datorders = (VIOAPND2SREORDER *)malloc(datlimit * sizeof(VIOAPND2SREORDER));
-    DIR *dir = opendir(myio->filepath);
-    myio->dfnum = myio->ifnum = 0;
-    myio->datfhead = myio->datftail = myio->idxfhead = myio->idxftail = NULL;
-    /* special value to mark if found current writing file */
-    myio->ibuf.fid = myio->dbuf.fid = -1;
-    for (filelist = readdir(dir); filelist; filelist = readdir(dir)) {
-        // Check file name/type
-        const char *cstr = filelist->d_name;
-        if (strncmp(cstr + strlen(cstr) - 4, ".cdb", 4) != 0)
-            /* not a cuttdb file*/
-            continue;
-        if (strcmp(cstr, "dellog.cdb") == 0) {
-            snprintf(filename, MAX_PATH_LEN, "%s/%s", myio->filepath, cstr);
-            myio->dfd = open(filename, O_RDONLY, 0644);
-        } else if (strcmp(cstr, "mainindex.cdb") == 0) {
-            gotmindex = true;
-//            snprintf(filename, MAX_PATH_LEN, "%s/%s", myio->filepath, cstr);
-//            myio->hfd = open(filename, O_RDONLY, 0644);
-//            if (_vio_apnd2_readhead(vio, false) < 0 || db->hsize == 0) {
-//                goto ERRRET;
-//            }
-//            db->mtable = (FOFF *)malloc(sizeof(FOFF) * db->hsize);
-//            gotmindex = true;
-//            memset(db->mtable, 0, sizeof(FOFF) * db->hsize);
-        } else if (strcmp(cstr, "mainmeta.cdb") == 0) {
-            snprintf(filename, MAX_PATH_LEN, "%s/%s", myio->filepath, cstr);
-            myio->mfd = open(filename, O_RDWR, 0644);
-            if (myio->mfd < 0) {
-                cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-                continue;
-            }
-        } else if (strlen(cstr) == 15
-            && (strncmp(cstr, "dat", 3) == 0 || strncmp(cstr, "idx", 3) == 0)) {
-            VIOAPND2FINFO finfo;
-            uint64_t fsize = 0;
-
-            snprintf(filename, MAX_PATH_LEN, "%s/%s", myio->filepath, cstr);
-            int fd = open(filename, O_RDWR, 0644);
-            if (fd < 0) {
-                cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-                continue;
-            }
-            if (_vio_apnd2_readfmeta(vio, fd, &finfo) < 0) {
-                close(fd);
-                continue;
-            }
-            fsize = lseek(fd, 0, SEEK_END);
-            finfo.rcyled = 0;
-            finfo.ref = 0;
-            finfo.unlink = false;
-            finfo.fprev = finfo.fnext = NULL;
-            if (finfo.ftype == VIOAPND2_INDEX) {
-                if (force) {
-                    /* delete all index file and rebuild them if force to recovery */
-                    close(fd);
-                    unlink(filename);
-                } else {
-                    cdb_ht_insert2(myio->idxmeta, &finfo.fid, SI4, &finfo, sizeof(VIOAPND2FINFO));
-                    idxorders[idxpos].fid = finfo.fid;
-                    idxorders[idxpos].oidf = finfo.oidf;
-                    if (++idxpos == idxlimit) {
-                        VIOAPND2SREORDER *tmp = (VIOAPND2SREORDER *)malloc(idxlimit * 2 * sizeof(VIOAPND2SREORDER));
-                        memcpy(tmp, idxorders, idxlimit * sizeof(VIOAPND2SREORDER));
-                        idxlimit *= 2;
-                        free(idxorders);
-                        idxorders = tmp;
-                    }
-                    if(finfo.fstatus == VIOAPND2_WRITING) {
-                        myio->ibuf.fid = finfo.fid;
-                        myio->ibuf.off = OFFALIGNED(fsize);
-                        myio->ibuf.pos = 0;
-                        myio->ibuf.fd = fd;
-                    } else
-                        close(fd);
-                    if (finfo.fid > imaxfid)
-                        imaxfid = finfo.fid;
-                    myio->ifnum++;
-                }
-            } else if (finfo.ftype == VIOAPND2_DATA) {
-                /* no information about nearest expire record time, make a fake one(non zero) */
-                finfo.nexpire = finfo.lcktime = time(NULL);
-                cdb_ht_insert2(myio->datmeta, &finfo.fid, SI4, &finfo, sizeof(VIOAPND2FINFO));
-                datorders[datpos].fid = finfo.fid;
-                datorders[datpos].oidf = finfo.oidf;
-                if (++datpos == datlimit) {
-                    VIOAPND2SREORDER *tmp = (VIOAPND2SREORDER *)malloc(datlimit * 2 * sizeof(VIOAPND2SREORDER));
-                    memcpy(tmp, datorders, datlimit * sizeof(VIOAPND2SREORDER));
-                    datlimit *= 2;
-                    free(datorders);
-                    datorders = tmp;
-                }
-                if (finfo.fstatus == VIOAPND2_WRITING) {
-                    myio->dbuf.fid = finfo.fid;
-                    myio->dbuf.off = OFFALIGNED(fsize);
-                    myio->dbuf.pos = 0;
-                    myio->dbuf.fd = fd;
-                } else
-                    close(fd);
-                if (finfo.fid > dmaxfid)
-                    dmaxfid = finfo.fid;
-                myio->dfnum++;
-            } else
-                close(fd);
-        } /* end of else */
-    } /* end of for */
-
-
-    /* fix recycled size */
-    _vio_apnd2_readmeta(vio, true);
-    closedir(dir);
-
-    if (!gotmindex) {
-        /* recovery failed */
-        /* return */
-        goto ERRRET;
-    } else {
-        if (_vio_apnd2_readhead(vio, false) < 0)
-            goto ERRRET;
-    }
-
-    if (myio->mfd < 0) {
-        snprintf(filename, MAX_PATH_LEN, "%s/mainmeta.cdb", myio->filepath);
-        myio->mfd = open(filename, O_RDWR | O_CREAT, 0644);
-        if (myio->mfd < 0) {
-            cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-            goto ERRRET;
-        }
-    }
-
-    /* index file complele broken, replay all records to build the index */
-    if (myio->ifnum == 0 || force)
-        db->roid = 0;
-    /* re-count records num */
-    db->rnum = 0;
-
-    /* fix index/data file meta relation */
-    qsort(datorders, datpos, sizeof(VIOAPND2SREORDER), _vio_apnd2_cmpfuncsreorder);
-    qsort(idxorders, idxpos, sizeof(VIOAPND2SREORDER), _vio_apnd2_cmpfuncsreorder);
-
-    VIOAPND2FINFO *lfinfo = NULL;
-    for(int i = 0; i < datpos; i++) {
-        VIOAPND2FINFO *cfinfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &datorders[i].fid, SI4, false);
-        if (cfinfo == NULL)
-            continue;
-        if (lfinfo)
-            lfinfo->fnext = cfinfo;
-        else {
-            myio->datfhead = cfinfo;
-        }
-        cfinfo->fprev = lfinfo;
-        lfinfo = cfinfo;
-    }
-    myio->datftail = lfinfo;
-    if (lfinfo)
-        lfinfo->fnext = NULL;
-    lfinfo = NULL;
-    for(int i = 0; i < idxpos; i++) {
-        VIOAPND2FINFO *cfinfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->idxmeta, &idxorders[i].fid, SI4, false);
-        if (cfinfo == NULL)
-            continue;
-        if (lfinfo)
-            lfinfo->fnext = cfinfo;
-        else {
-            myio->idxfhead = cfinfo;
-        }
-        cfinfo->fprev = lfinfo;
-        lfinfo = cfinfo;
-    }
-    myio->idxftail = lfinfo;
-    if (lfinfo)
-        lfinfo->fnext = NULL;
-    lfinfo = NULL;
-
-    if (myio->ibuf.fid == (uint32_t) -1) {
-        myio->ibuf.fid = 0;
-        _vio_apnd2_shiftnew(vio, VIOAPND2_INDEX);
-    }
-    if (myio->dbuf.fid == (uint32_t) -1) {
-        myio->dbuf.fid = 0;
-        _vio_apnd2_shiftnew(vio, VIOAPND2_DATA);
-    }
-
-    /* fix offsets in main index table */
-    db->mtable = (FOFF *)malloc(db->hsize * sizeof(FOFF));
-    memset(db->mtable, 0, db->hsize * sizeof(FOFF));
-    void *it = _vio_apnd2_pageiterfirst(vio, 0);
-    if (it) {
-        char sbuf[SBUFSIZE];
-        CDBPAGE *page = (CDBPAGE *)sbuf;
-        /* need not use iterator since don't care about contents in page */
-        /* I'm just lazy, cpu time is cheap */
-        while(_vio_apnd2_pageiternext(vio, &page, it) == 0) {
-            if (OFFNOTNULL(db->mtable[page->bid])) {
-                /* recalculate the space to be recycled */
-                uint32_t ofid, roff;
-                char sbuf[SBUFSIZE];
-                CDBPAGE *opage = (CDBPAGE *)sbuf;
-                _vio_apnd2_readpage(vio, &opage, db->mtable[page->bid]);
-                if (OFFNOTNULL(opage->ooff)) {
-                    VOFF2ROFF(opage->ooff, ofid, roff);
-                    VIOAPND2FINFO *finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->idxmeta, &ofid, SI4, false);
-                    if (finfo)
-                        finfo->rcyled += opage->osize;
-                }
-                /* fix impaction of old page */
-                db->rnum -= opage->num;
-                if (opage != (CDBPAGE *)sbuf)
-                    free(opage);
-            }
-            db->mtable[page->bid] = page->ooff;
-            db->rnum += page->num;
-            if (page != (CDBPAGE *)sbuf) {
-                free(page);
-                page = (CDBPAGE *)sbuf;
-            }
-        }
-        _vio_apnd2_pageiterdestory(vio, it);
-    }
-
-    /* like what was did just now */
-    it = _vio_apnd2_reciterfirst(vio, db->roid);
-    if (it) {
-        char sbuf[SBUFSIZE];
-        CDBREC *rec = (CDBREC *)sbuf;
-        while(_vio_apnd2_reciternext(vio, &rec, it) == 0) {
-            FOFF soffs[SFOFFNUM];
-            FOFF *soff = soffs, ooff;
-            char sbuf2[SBUFSIZE];
-            OFFZERO(ooff);
-            CDBREC *rrec = (CDBREC*)sbuf2;
-            uint64_t hash = CDBHASH64(rec->buf, rec->ksize);
-
-            /* check record with duplicate key(old version/overwritten maybe */
-            int retnum = cdb_getoff(db, hash, &soff, CDB_NOTLOCKED);
-            for(int i = 0; i < retnum; i++) {
-                if (rrec != (CDBREC*)sbuf2) {
-                    free(rrec);
-                    rrec = (CDBREC*)sbuf2;
-                }
-
-                int cret = _vio_apnd2_readrec(db->vio, &rrec, soff[i], false);
-                if (cret < 0)
-                    continue;
-
-                if (rec->ksize == rrec->ksize && memcmp(rrec->key, rec->key, rec->ksize) == 0) {
-                    ooff = rrec->ooff;
-                    break;
-                }
-            }
-            if (soff != soffs)
-                free(soff);
-            if (rrec != (CDBREC*)sbuf2)
-                free(rrec);
-
-            if (OFFNOTNULL(ooff))
-                /* replace offset in index */
-                cdb_replaceoff(db, hash, ooff, rec->ooff, CDB_NOTLOCKED);
-            else
-                cdb_updatepage(vio->db, hash, rec->ooff, CDB_PAGEINSERTOFF, CDB_NOTLOCKED);
-
-            if (rec->oid > db->oid)
-                db->oid = rec->oid;
-            if (rec != (CDBREC *)sbuf) {
-                free(rec);
-                rec = (CDBREC *)sbuf;
-            }
-        }
-        _vio_apnd2_reciterdestory(vio, it);
-    }
-
-    /* replay deletion logs */
-    FOFF delitems[1024];
-    for(; myio->dfd > 0;) {
-        int ret = read(myio->dfd, delitems, 1024 * sizeof(FOFF));
-        if (ret > 0) {
-            for(uint32_t j = 0; j * sizeof(FOFF) < (uint32_t) ret; j++) {
-                char sbuf[SBUFSIZE];
-                uint32_t ofid, roff;
-                CDBREC *rec = (CDBREC *)sbuf;
-                if (_vio_apnd2_readrec(vio, &rec, delitems[j], false) < 0)
-                    continue;
-                if (cdb_updatepage(db, CDBHASH64(rec->key, rec->ksize),
-                                   delitems[j], CDB_PAGEDELETEOFF, CDB_NOTLOCKED) == 0)
-                VOFF2ROFF(delitems[j], ofid, roff);
-                VIOAPND2FINFO *finfo = (VIOAPND2FINFO *)cdb_ht_get2(myio->datmeta, &ofid, SI4, false);
-                if (finfo)
-                    finfo->rcyled += rec->osize;
-                if (rec != (CDBREC *)sbuf)
-                    free(rec);
-            }
-        } else {
-            close(myio->dfd);
-            myio->dfd = -1;
-        }
-    }
-
-    cdb_flushalldpage(db);
-    _vio_apnd2_writemeta(vio);
-    _vio_apnd2_writehead(vio, true);
-    cdb_ht_clean(myio->idxmeta);
-    cdb_ht_clean(myio->datmeta);
-    free(idxorders);
-    free(datorders);
-    /* mfd / dfd will be opened again after this function, but hfd won't be */
-    myio->datfhead = myio->datftail = myio->idxfhead = myio->idxftail = NULL;
-    if (myio->ibuf.fd > 0)
-        close(myio->ibuf.fd);
-    if (myio->dbuf.fd > 0)
-        close(myio->dbuf.fd);
-    if (myio->mfd > 0)
-        close(myio->mfd);
-    if (myio->dfd > 0)
-        close(myio->dfd);
-    return 0;
-
-ERRRET:
-    closedir(dir);
-    if (myio->hfd > 0)
-        close(myio->hfd);
-    if (myio->mfd > 0)
-        close(myio->mfd);
-    if (myio->dfd > 0)
-        close(myio->dfd);
-    free(datorders);
-    free(idxorders);
-    return -1;
-}
-
-
-static VIOAPND2FINFO* _vio_apnd2_fileiternext(CDBVIO *vio, int dtype, uint64_t oid)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    uint64_t foid = (uint64_t)-1;
-    CDBHTITEM *item;
-    CDBHASHTABLE *ht;
-    VIOAPND2FINFO *finfo = NULL;
-
-    if (dtype == VIOAPND2_INDEX)
-        ht = myio->idxmeta;
-    else if (dtype == VIOAPND2_DATA)
-        ht = myio->datmeta;
-    else
-        return NULL;
-
-    cdb_lock_lock(myio->lock);
-    item = cdb_ht_iterbegin(ht);
-    while(item) {
-        VIOAPND2FINFO *tfinfo = (VIOAPND2FINFO *)cdb_ht_itemval(ht, item);
-        if (tfinfo->oidf < foid && tfinfo->oidf >= oid) {
-            foid = tfinfo->oidf;
-            finfo = tfinfo;
-        }
-        item = cdb_ht_iternext(ht, item);
-    }
-    if (finfo)
-        finfo->ref++;
-    cdb_lock_unlock(myio->lock);
-    return finfo;
-}
-
-static int _vio_apnd2_iterfirst(CDBVIO *vio, VIOAPND2ITOR *it, int dtype, int64_t oid)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    CDBHASHTABLE *tmpcache;
-    char filename[MAX_PATH_LEN];
-    char ipfx[] = "idx";
-    char dpfx[] = "dat";
-    char *pfx;
-
-    if (dtype == VIOAPND2_INDEX) {
-        pfx = ipfx;
-        tmpcache = myio->idxmeta;
-    } else if (dtype == VIOAPND2_DATA) {
-        pfx = dpfx;
-        tmpcache = myio->datmeta;
-    } else
-        return -1;
-
-    if (it->finfo == NULL)
-        it->finfo = _vio_apnd2_fileiternext(vio, dtype, oid);
-    if (it->finfo == NULL) {
-        return -1;
-    }
-
-    snprintf(filename, MAX_PATH_LEN, "%s/%s%08d.cdb", myio->filepath, pfx, it->finfo->fid);
-    it->fd = open(filename, O_RDONLY, 0644);
-    if (it->fd < 0) {
-        cdb_lock_lock(myio->lock);
-        it->finfo->ref--;
-        if (it->finfo->ref == 0 && it->finfo->unlink) {
-            /* unlink the file */
-            _vio_apnd2_unlink(vio, it->finfo, dtype);
-            cdb_ht_del2(tmpcache, &it->finfo->fid, SI4);
-        }
-        cdb_lock_unlock(myio->lock);
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    it->fsize = lseek(it->fd, 0, SEEK_END);
-    it->mmap = mmap(NULL, it->fsize, PROT_READ, MAP_PRIVATE, it->fd, 0);
-    it->off = FILEMETASIZE;
-    it->oid = oid;
-
-    while(it->off < it->fsize) {
-        if (dtype == VIOAPND2_INDEX) {
-            CDBPAGE *page = (CDBPAGE *)(it->mmap + it->off -(sizeof(CDBPAGE) - PAGEHSIZE));
-            if (page->magic != PAGEMAGIC) {
-                it->off += ALIGNBYTES;
-                continue;
-            }
-            if (page->oid >= (uint64_t) oid)
-                break;
-            it->off += OFFALIGNED(PAGESIZE(page));
-        } else if (dtype == VIOAPND2_DATA) {
-            CDBREC *rec = (CDBREC *)(it->mmap + it->off -(sizeof(CDBREC) - RECHSIZE));
-            if (rec->magic != RECMAGIC && rec->magic != DELRECMAGIC) {
-                it->off += ALIGNBYTES;
-                continue;
-            }
-            if (rec->oid >= (uint64_t) oid)
-                break;
-            it->off += OFFALIGNED(RECSIZE(rec));
-        }
-    }
-
-    if (it->off >= it->fsize) {
-        munmap(it->mmap, it->fsize);
-        close(it->fd);
-        cdb_lock_lock(myio->lock);
-        it->finfo->ref--;
-        if (it->finfo->ref == 0 && it->finfo->unlink) {
-            /* unlink the file */
-            _vio_apnd2_unlink(vio, it->finfo, dtype);
-            cdb_ht_del2(tmpcache, &it->finfo->fid, SI4);
-        }
-        cdb_lock_unlock(myio->lock);
-        return -1;
-    }
-    return 0;
-}
-
-
-static int _vio_apnd2_pageiternext(CDBVIO *vio, CDBPAGE **page, void *iter)
-{
-    VIOAPND2ITOR *it = (VIOAPND2ITOR *)iter;
-    CDBPAGE *cpage;
-    uint32_t fixbufsize = SBUFSIZE - (sizeof(CDBPAGE) - PAGEHSIZE);
-
-    for(;;) {
-        if (it->off >= it->fsize) {
-            it->oid = CDBMAX(it->oid, it->finfo->oidl);
-            _vio_apnd2_iterfree(vio, VIOAPND2_INDEX, it);
-            if (_vio_apnd2_iterfirst(vio, it, VIOAPND2_INDEX, it->oid) < 0)
-                return -1;
-        }
-        cpage = (CDBPAGE *)(it->mmap + it->off -(sizeof(CDBPAGE) - PAGEHSIZE));
-        if (cpage->magic != PAGEMAGIC) {
-            it->off += ALIGNBYTES;
-            continue;
-        }
-        if (PAGESIZE(cpage) <= fixbufsize)
-            memcpy(&(*page)->magic, &cpage->magic, PAGESIZE(cpage));
-        else {
-            *page = (CDBPAGE *)malloc(sizeof(CDBPAGE) + (*page)->num * sizeof(PITEM));
-            memcpy(&(*page)->magic, &cpage->magic, PAGESIZE(cpage));
-        }
-        (*page)->osize = PAGESIZE(cpage);
-        (*page)->cap = (*page)->num;
-        ROFF2VOFF(it->finfo->fid, it->off, (*page)->ooff);
-        /* set iterator to next one */
-        it->oid = (*page)->oid + 1;
-        it->off += OFFALIGNED(PAGESIZE(cpage));
-        return 0;
-    }
-    return -1;
-}
-
-static int _vio_apnd2_reciternext(CDBVIO *vio, CDBREC **rec, void *iter)
-{
-    VIOAPND2ITOR *it = (VIOAPND2ITOR *)iter;
-    CDBREC *crec;
-    uint32_t fixbufsize = SBUFSIZE - (sizeof(CDBREC) - RECHSIZE);
-
-    for(;;) {
-        if (it->off >= it->fsize) {
-            it->oid = CDBMAX(it->oid, it->finfo->oidl);
-            _vio_apnd2_iterfree(vio, VIOAPND2_DATA, it);
-            if (_vio_apnd2_iterfirst(vio, it, VIOAPND2_DATA, it->oid) < 0)
-                return -1;
-        }
-        crec = (CDBREC *)(it->mmap + it->off -(sizeof(CDBREC) - RECHSIZE));
-        if (crec->magic != RECMAGIC && crec->magic != DELRECMAGIC) {
-            it->off += ALIGNBYTES;
-            continue;
-        }
-        if (RECSIZE(crec) <= fixbufsize)
-            memcpy(&(*rec)->magic, &crec->magic, RECSIZE(crec));
-        else {
-            *rec = (CDBREC *)malloc(sizeof(CDBREC) + crec->ksize + crec->vsize);
-            memcpy(&(*rec)->magic, &crec->magic, RECSIZE(crec));
-        }
-
-        (*rec)->osize = RECSIZE(crec);
-        (*rec)->expire = crec->expire;
-        ROFF2VOFF(it->finfo->fid, it->off, (*rec)->ooff);
-        (*rec)->key = (*rec)->buf;
-        (*rec)->val = (*rec)->buf + (*rec)->ksize;
-
-        /* set iterator to next one */
-        it->oid = (*rec)->oid + 1;
-        it->off += OFFALIGNED(RECSIZE(crec));
-        return 0;
-    }
-    return -1;
-}
-
-
-static int _vio_apnd2_iterfree(CDBVIO *vio, int dtype, VIOAPND2ITOR *it)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    if (it->mmap) {
-        munmap(it->mmap, it->fsize);
-        close(it->fd);
-        cdb_lock_lock(myio->lock);
-        it->finfo->ref--;
-        if (it->finfo->ref == 0 && it->finfo->unlink) {
-            /* unlink the file */
-            VIOAPND2FINFO *tfinfo;
-            it->finfo->fnext->fprev = it->finfo->fprev;
-            it->finfo->fprev->fnext = it->finfo->fnext;
-            tfinfo = it->finfo;
-            it->finfo = it->finfo->fnext;
-            _vio_apnd2_unlink(vio, tfinfo, dtype);
-            if (dtype == VIOAPND2_INDEX)
-                cdb_ht_del2(myio->idxmeta, &tfinfo->fid, SI4);
-            else if (dtype == VIOAPND2_DATA)
-                cdb_ht_del2(myio->datmeta, &tfinfo->fid, SI4);
-        } else
-            it->finfo = it->finfo->fnext;
-        if (it->finfo)
-            it->finfo->ref++;
-        cdb_lock_unlock(myio->lock);
-        it->mmap = NULL;
-    }
-    return 0;
-}
-
-
-static void* _vio_apnd2_reciterfirst(CDBVIO *vio, uint64_t oid)
-{
-    VIOAPND2ITOR *it = (VIOAPND2ITOR *)malloc(sizeof(VIOAPND2ITOR));
-
-    /* iterator won't get to buffered data */
-    _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-    it->mmap = NULL;
-    it->finfo = NULL;
-    if (_vio_apnd2_iterfirst(vio, it, VIOAPND2_DATA, oid) < 0) {
-        free(it);
-        return NULL;
-    }
-    return (void*)it;
-}
-
-
-static void _vio_apnd2_reciterdestory(CDBVIO *vio, void *iter)
-{
-    if (iter) {
-        _vio_apnd2_iterfree(vio, VIOAPND2_DATA, (VIOAPND2ITOR *)iter);
-        free(iter);
-    }
-}
-
-static void* _vio_apnd2_pageiterfirst(CDBVIO *vio, uint64_t oid)
-{
-    VIOAPND2ITOR *it = (VIOAPND2ITOR *)malloc(sizeof(VIOAPND2ITOR));
-
-    /* iterator won't get to buffered data */
-    _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-    it->mmap = NULL;
-    it->finfo = NULL;
-    if (_vio_apnd2_iterfirst(vio, it, VIOAPND2_INDEX, oid) < 0) {
-        free(it);
-        return NULL;
-    }
-    return (void*)it;
-}
-
-
-static void _vio_apnd2_pageiterdestory(CDBVIO *vio, void *iter)
-{
-    if (iter) {
-        _vio_apnd2_iterfree(vio, VIOAPND2_INDEX, (VIOAPND2ITOR *)iter);
-        free(iter);
-    }
-}
-
-static int _vio_apnd2_rcyledatafile(CDBVIO *vio, VIOAPND2FINFO *finfo, bool rcyle)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    int fd;
-    char filename[MAX_PATH_LEN];
-    uint32_t nexpire = 0xffffffff;
-
-    snprintf(filename, MAX_PATH_LEN, "%s/dat%08d.cdb", myio->filepath, finfo->fid);
-    fd = open(filename, O_RDONLY, 0644);
-    if (fd < 0) {
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-        return -1;
-    }
-
-    uint32_t frsize = 0, fsize = lseek(fd, 0, SEEK_END);
-    uint32_t pos = FILEMETASIZE;
-    char *map = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
-    uint32_t now = time(NULL);
-    while(pos < fsize) {
-        CDBREC *rec = (CDBREC *)&map[pos-(sizeof(CDBREC) - RECHSIZE)];
-        FOFF off;
-        uint64_t hash;
-
-        if (rec->magic != RECMAGIC && rec->magic != DELRECMAGIC) {
-            pos += ALIGNBYTES;
-            continue;
-        }
-
-        ROFF2VOFF(finfo->fid, pos, off);
-        hash = CDBHASH64(rec->buf, rec->ksize);
-        if (cdb_checkoff(vio->db, hash, off, CDB_NOTLOCKED)
-        /* not expired */
-        && (rec->expire > now || rec->expire == 0)) {
-            /* nearest expire record in current file */
-            if (rec->expire && rec->expire < nexpire)
-                nexpire = rec->expire;
-
-            /* record exist in index, skip */
-            if (rcyle) {
-                FOFF noff;
-                rec->ooff = off;
-                rec->osize = OFFALIGNED(RECSIZE(rec));
-                _vio_apnd2_writerecinternal(vio, rec, &noff);
-                cdb_replaceoff(vio->db, hash, off, noff, CDB_NOTLOCKED);
-            }
-        } else {
-            if (rcyle && rec->expire && rec->expire < now) {
-                /* expired record, delete from index page */
-                cdb_updatepage(vio->db, hash, off, CDB_PAGEDELETEOFF, CDB_NOTLOCKED);
-            }
-            frsize += OFFALIGNED(RECSIZE(rec));
-        }
-        pos += OFFALIGNED(RECSIZE(rec));
-    }
-    munmap(map, fsize);
-    close(fd);
-    cdb_lock_lock(myio->lock);
-    /* fix metainfo about nearest expire time in current data file */
-    if (nexpire == 0xffffffff)
-        finfo->nexpire = 0;
-    else
-        finfo->nexpire = nexpire;
-    finfo->rcyled = frsize;
-    if (rcyle) {
-        /* unlink */
-        finfo->unlink = true;
-    }
-    cdb_lock_unlock(myio->lock);
-    return 0;
-}
-
-
-static void _vio_apnd2_cleanpoint(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    char filename[MAX_PATH_LEN];
-
-    cdb_lock_lock(myio->lock);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_DATA);
-    _vio_apnd2_flushbuf(vio, VIOAPND2_INDEX);
-    _vio_apnd2_writehead(vio, false);
-    if (myio->dfd > 0)
-        close(myio->dfd);
-    snprintf(filename, MAX_PATH_LEN, "%s/dellog.cdb", myio->filepath);
-    /* clean the previous deletion log */
-    myio->dfd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-    /* open failed, whom to tell? */
-    if (myio->dfd < 0)
-        cdb_seterrno(vio->db, CDB_OPENERR, __FILE__, __LINE__);
-    cdb_lock_unlock(myio->lock);
-}
-
-
-static int _vio_apnd2_checkopensig(CDBVIO *vio)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    int pos = 0;
-    uint32_t ret;
-
-    if (myio->hfd < 0)
-        return -1;
-
-    pos += FILEMAGICLEN;
-    pos += SI4;
-    pos += SI8;
-    pos += SI8;
-    pos += SI8;
-    if (pread(myio->hfd, &ret, SI4, pos) != SI4)
-        return -1;
-
-    return ret;
-}
-
-
-static int _vio_apnd2_setopensig(CDBVIO *vio, int sig)
-{
-    VIOAPND2 *myio = (VIOAPND2 *)vio->iometa;
-    int pos = 0;
-    uint32_t val = sig;
-    if (myio->hfd < 0)
-        return -1;
-
-    pos += FILEMAGICLEN;
-    pos += SI4;
-    pos += SI8;
-    pos += SI8;
-    pos += SI8;
-    if (pwrite(myio->hfd, &val, SI4, pos) != SI4)
-        return -1;
-    return 0;
-}
-
-
diff --git a/3rdparty/cuttdb/src/vio_apnd2.h b/3rdparty/cuttdb/src/vio_apnd2.h
deleted file mode 100644
index cb47a7dbd18a0f40ad1f9a571b35b94feaeff6d5..0000000000000000000000000000000000000000
--- a/3rdparty/cuttdb/src/vio_apnd2.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- *   CuttDB - a fast key-value storage engine
- *
- *
- *   http://code.google.com/p/cuttdb/
- *   
- *   Copyright (c) 2012, Siyuan Fu.  All rights reserved.
- *   Use and distribution licensed under the BSD license. 
- *   See the LICENSE file for full text
- *
- *   Author: Siyuan Fu <fusiyuan2010@gmail.com>
- *
- */
-
-
-#ifndef _VIO_APND2_H_
-#define _VIO_APND2_H_
-#include "cdb_vio.h"
-
-
-void vio_apnd2_init(CDBVIO *vio);
-
-#endif
diff --git a/3rdparty/libmdbx/CMakeLists.txt b/3rdparty/libmdbx/CMakeLists.txt
deleted file mode 100644
index 2ddc192beefc7e7f982fee08096f389ddcbc3fbf..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/CMakeLists.txt
+++ /dev/null
@@ -1,943 +0,0 @@
-##
-##  Copyright 2020-2022 Leonid Yuriev <leo@yuriev.ru>
-##  and other libmdbx authors: please see AUTHORS file.
-##  All rights reserved.
-##
-##  Redistribution and use in source and binary forms, with or without
-##  modification, are permitted only as authorized by the OpenLDAP
-##  Public License.
-##
-##  A copy of this license is available in the file LICENSE in the
-##  top-level directory of the distribution or, alternatively, at
-##  <http://www.OpenLDAP.org/license.html>.
-##
-
-##
-##  libmdbx = { Revised and extended descendant of Symas LMDB. }
-##  Please see README.md at https://gitflic.ru/project/erthink/libmdbx
-##
-##  Libmdbx is superior to LMDB in terms of features and reliability,
-##  not inferior in performance. libmdbx works on Linux, FreeBSD, MacOS X
-##  and other systems compliant with POSIX.1-2008, but also support Windows
-##  as a complementary platform.
-##
-##  The next version is under active non-public development and will be
-##  released as MithrilDB and libmithrildb for libraries & packages.
-##  Admittedly mythical Mithril is resembling silver but being stronger and
-##  lighter than steel. Therefore MithrilDB is rightly relevant name.
-##
-##  MithrilDB will be radically different from libmdbx by the new database
-##  format and API based on C++17, as well as the Apache 2.0 License.
-##  The goal of this revolution is to provide a clearer and robust API,
-##  add more features and new valuable properties of database.
-##
-##  The Future will (be) Positive. Всё будет хорошо.
-##
-
-if(CMAKE_VERSION VERSION_LESS 3.12)
-  cmake_minimum_required(VERSION 3.8.2)
-else()
-  cmake_minimum_required(VERSION 3.12)
-endif()
-
-cmake_policy(PUSH)
-cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
-if(NOT CMAKE_VERSION VERSION_LESS 3.15)
-  cmake_policy(SET CMP0091 NEW)
-endif()
-if(NOT CMAKE_VERSION VERSION_LESS 3.13)
-  cmake_policy(SET CMP0077 NEW)
-endif()
-if(NOT CMAKE_VERSION VERSION_LESS 3.12)
-  cmake_policy(SET CMP0075 NEW)
-endif()
-if(NOT CMAKE_VERSION VERSION_LESS 3.9)
-  cmake_policy(SET CMP0069 NEW)
-  include(CheckIPOSupported)
-  check_ipo_supported(RESULT CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE)
-else()
-  set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE FALSE)
-endif()
-
-if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/core.c" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/alloy.c" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/version.c.in" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/man1" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/mdbx_chk.c" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/mdbx.c++")
-  set(MDBX_AMALGAMATED_SOURCE FALSE)
-  find_program(GIT git)
-  if(NOT GIT)
-    message(SEND_ERROR "Git command-line tool not found")
-  endif()
-  set(MDBX_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
-elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION.txt" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx.c" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx.c++" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/man1" AND
-    EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx_chk.c")
-  set(MDBX_AMALGAMATED_SOURCE TRUE)
-  set(MDBX_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
-else()
-  message(FATAL_ERROR "\n"
-    "Please don't use tarballs nor zips which are automatically provided by Github!  "
-    "These archives do not contain version information and thus are unfit to build libmdbx.  "
-    "You can vote for ability of disabling auto-creation such unsuitable archives at https://github.community/t/disable-tarball\n"
-    "Instead of above, just clone the git repository, either download a tarball or zip with the properly amalgamated source core.  "
-    "For embedding libmdbx use a git-submodule or the amalgamated source code.\n"
-    "Please, avoid using any other techniques.")
-endif()
-
-if(DEFINED PROJECT_NAME)
-  option(MDBX_FORCE_BUILD_AS_MAIN_PROJECT "Force libmdbx to full control build options even it added as a subdirectory to your project." OFF)
-endif()
-
-if(DEFINED PROJECT_NAME AND NOT MDBX_FORCE_BUILD_AS_MAIN_PROJECT)
-  set(SUBPROJECT ON)
-  set(NOT_SUBPROJECT OFF)
-  if(NOT MDBX_AMALGAMATED_SOURCE AND NOT DEFINED BUILD_TESTING)
-    set(BUILD_TESTING OFF)
-  endif()
-  enable_language(C)
-else()
-  set(SUBPROJECT OFF)
-  set(NOT_SUBPROJECT ON)
-  project(libmdbx C)
-  if(NOT MDBX_AMALGAMATED_SOURCE AND NOT DEFINED BUILD_TESTING)
-    set(BUILD_TESTING ON)
-  endif()
-endif()
-
-if(NOT MDBX_AMALGAMATED_SOURCE)
-  include(CTest)
-  option(MDBX_ENABLE_TESTS "Build libmdbx tests." ${BUILD_TESTING})
-elseif(DEFINED MDBX_ENABLE_TESTS AND MDBX_ENABLE_TESTS)
-  message(WARNING "MDBX_ENABLE_TESTS=${MDBX_ENABLE_TESTS}: But amalgamated source code don't includes tests.")
-  set(MDBX_ENABLE_TESTS OFF)
-endif()
-
-# Try to find a C++ compiler unless sure that this is unnecessary.
-if (NOT CMAKE_CXX_COMPILER_LOADED)
-  include(CheckLanguage)
-  if(NOT DEFINED MDBX_BUILD_CXX OR MDBX_BUILD_CXX
-      OR (NOT MDBX_AMALGAMATED_SOURCE AND (NOT DEFINED MDBX_ENABLE_TESTS OR MDBX_ENABLE_TESTS)))
-    check_language(CXX)
-    if(CMAKE_CXX_COMPILER)
-      enable_language(CXX)
-    endif()
-  endif()
-else()
-  enable_language(CXX)
-endif()
-
-# Set default build type to Release. This is to ease a User's life.
-if(NOT CMAKE_BUILD_TYPE)
-  set(CMAKE_BUILD_TYPE Release CACHE STRING
-    "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
-    FORCE)
-endif()
-string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPERCASE)
-
-if(NOT_SUBPROJECT AND (CMAKE_CROSSCOMPILING OR IOS))
-  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
-endif()
-
-if(NOT "$ENV{TEAMCITY_PROCESS_FLOW_ID}" STREQUAL "")
-  set(CI TEAMCITY)
-  message(STATUS "TeamCity CI")
-elseif(NOT "$ENV{TRAVIS}" STREQUAL "")
-  set(CI TRAVIS)
-  message(STATUS "Travis CI")
-elseif(NOT "$ENV{CIRCLECI}" STREQUAL "")
-  set(CI CIRCLE)
-  message(STATUS "Circle CI")
-elseif(NOT "$ENV{APPVEYOR}" STREQUAL "")
-  set(CI APPVEYOR)
-  message(STATUS "AppVeyor CI")
-elseif(NOT "$ENV{CI}" STREQUAL "")
-  set(CI "$ENV{CI}")
-  message(STATUS "Other CI (${CI})")
-else()
-  message(STATUS "Assume No any CI environment")
-  unset(CI)
-endif()
-
-# output all mdbx-related targets in single directory
-if(NOT DEFINED MDBX_OUTPUT_DIR)
-  set(MDBX_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
-endif()
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
-set(CMAKE_PDB_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
-
-include(CheckFunctionExists)
-include(FindPackageMessage)
-include(GNUInstallDirs)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION LESS 1900)
-  message(SEND_ERROR "MSVC compiler ${MSVC_VERSION} is too old for building MDBX."
-    " At least 'Microsoft Visual Studio 2015' is required.")
-endif()
-
-set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
-set(THREADS_PREFER_PTHREAD_FLAG TRUE)
-find_package(Threads REQUIRED)
-
-include(cmake/utils.cmake)
-include(cmake/compiler.cmake)
-include(cmake/profile.cmake)
-
-# Workaround for `-pthread` toolchain/cmake bug
-if(NOT APPLE AND NOT MSVC
-    AND CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_THREAD_LIBS_INIT
-    AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG))
-  check_compiler_flag("-pthread" CC_HAS_PTHREAD)
-  if(CC_HAS_PTHREAD AND NOT CMAKE_EXE_LINKER_FLAGS MATCHES "-pthread")
-    message(STATUS "Force add -pthread for linker flags to avoid troubles")
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
-    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread")
-    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pthread")
-  endif()
-endif()
-
-CHECK_FUNCTION_EXISTS(pow NOT_NEED_LIBM)
-if(NOT_NEED_LIBM)
-  set(LIB_MATH "")
-else()
-  set(CMAKE_REQUIRED_LIBRARIES m)
-  CHECK_FUNCTION_EXISTS(pow HAVE_LIBM)
-  if(HAVE_LIBM)
-    set(LIB_MATH m)
-  else()
-    message(FATAL_ERROR "No libm found for math support")
-  endif()
-endif()
-
-if(SUBPROJECT)
-  if(NOT DEFINED BUILD_SHARED_LIBS)
-    option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" OFF)
-  endif()
-  if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
-    option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON)
-  endif()
-else()
-  option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" ON)
-  option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON)
-  if (CC_HAS_ARCH_NATIVE)
-    option(BUILD_FOR_NATIVE_CPU "Generate code for the compiling machine CPU" OFF)
-  endif()
-
-  if(CMAKE_CONFIGURATION_TYPES OR NOT CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
-    set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT ON)
-  else()
-    set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT OFF)
-  endif()
-
-  if(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE
-      OR GCC_LTO_AVAILABLE OR MSVC_LTO_AVAILABLE OR
-      (CLANG_LTO_AVAILABLE AND
-        ((DEFINED MDBX_ENABLE_TESTS AND NOT MDBX_ENABLE_TESTS)
-        OR NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)))
-    option(INTERPROCEDURAL_OPTIMIZATION "Enable interprocedural/LTO optimization" ${INTERPROCEDURAL_OPTIMIZATION_DEFAULT})
-  else()
-    set(INTERPROCEDURAL_OPTIMIZATION OFF)
-  endif()
-
-  if(INTERPROCEDURAL_OPTIMIZATION)
-    if(GCC_LTO_AVAILABLE)
-      set(LTO_ENABLED TRUE)
-      set(CMAKE_AR ${CMAKE_GCC_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE)
-      set(CMAKE_NM ${CMAKE_GCC_NM} CACHE PATH "Path to nm program with LTO-plugin" FORCE)
-      set(CMAKE_RANLIB ${CMAKE_GCC_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE)
-      message(STATUS "MDBX indulge Link-Time Optimization by GCC")
-    elseif(CLANG_LTO_AVAILABLE)
-      set(LTO_ENABLED TRUE)
-      set(CMAKE_AR ${CMAKE_CLANG_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE)
-      set(CMAKE_NM ${CMAKE_CLANG_NM} CACHE PATH "Path to nm program with LTO-plugin" FORCE)
-      set(CMAKE_RANLIB ${CMAKE_CLANG_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE)
-      message(STATUS "MDBX indulge Link-Time Optimization by CLANG")
-    elseif(MSVC_LTO_AVAILABLE)
-      set(LTO_ENABLED TRUE)
-      message(STATUS "MDBX indulge Link-Time Optimization by MSVC")
-    elseif(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE)
-      message(STATUS "MDBX indulge Interprocedural Optimization by CMake")
-      set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
-      set(LTO_ENABLED TRUE)
-    else()
-      message(WARNING "Unable to engage interprocedural/LTO optimization.")
-    endif()
-  else()
-    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE)
-    set(LTO_ENABLED FALSE)
-  endif()
-
-  if(NOT MDBX_AMALGAMATED_SOURCE)
-    find_program(VALGRIND valgrind)
-    if(VALGRIND)
-      # LY: cmake is ugly and nasty.
-      #      - therefore memcheck-options should be defined before including ctest;
-      #      - otherwise ctest may ignore it.
-      set(MEMORYCHECK_SUPPRESSIONS_FILE
-        "${CMAKE_CURRENT_SOURCE_DIR}/test/valgrind_suppress.txt"
-        CACHE FILEPATH "Suppressions file for Valgrind" FORCE)
-      set(MEMORYCHECK_COMMAND_OPTIONS
-        "--trace-children=yes --leak-check=full --track-origins=yes --error-exitcode=42 --error-markers=@ --errors-for-leak-kinds=definite --fair-sched=yes --suppressions=${MEMORYCHECK_SUPPRESSIONS_FILE}"
-        CACHE STRING "Valgrind options" FORCE)
-      set(VALGRIND_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS}" CACHE STRING "Valgrind options" FORCE)
-    endif()
-
-    # Enable 'make tags' target.
-    find_program(CTAGS ctags)
-    if(CTAGS)
-      add_custom_target(tags COMMAND ${CTAGS} -R -f tags
-        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-      add_custom_target(ctags DEPENDS tags)
-    endif(CTAGS)
-
-    if(UNIX)
-      find_program(CLANG_FORMAT
-        NAMES clang-format-13 clang-format)
-      if(CLANG_FORMAT)
-        execute_process(COMMAND ${CLANG_FORMAT} "--version" OUTPUT_VARIABLE clang_format_version_info)
-        string(REGEX MATCH "version ([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" clang_format_version_info CLANG_FORMAT_VERSION)
-        if(clang_format_version_info AND NOT CLANG_FORMAT_VERSION VERSION_LESS 13.0)
-          # Enable 'make reformat' target.
-          add_custom_target(reformat
-            VERBATIM
-            COMMAND
-            git ls-files |
-            grep -E \\.\(c|cxx|cc|cpp|h|hxx|hpp\)\(\\.in\)?\$ |
-            xargs ${CLANG_FORMAT} -i --style=file
-            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
-        endif()
-      endif()
-    endif()
-
-    if(NOT "${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
-      add_custom_target(distclean)
-      add_custom_command(TARGET distclean
-        COMMAND ${CMAKE_COMMAND} -E remove_directory "${PROJECT_BINARY_DIR}"
-        COMMENT "Removing the build directory and its content")
-    elseif(IS_DIRECTORY .git AND GIT)
-      add_custom_target(distclean)
-      add_custom_command(TARGET distclean
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        COMMAND ${GIT} submodule foreach --recursive git clean -f -X -d
-        COMMAND ${GIT} clean -f -X -d
-        COMMENT "Removing all build files from the source directory")
-    endif()
-  endif(NOT MDBX_AMALGAMATED_SOURCE)
-
-  setup_compile_flags()
-endif(SUBPROJECT)
-
-list(FIND CMAKE_C_COMPILE_FEATURES c_std_11 HAS_C11)
-list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11)
-list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14)
-list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 HAS_CXX17)
-list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 HAS_CXX20)
-list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_23 HAS_CXX23)
-if(NOT DEFINED MDBX_CXX_STANDARD)
-  if(DEFINED ENV{CMAKE_CXX_STANDARD})
-    set(CMAKE_CXX_STANDARD $ENV{CMAKE_CXX_STANDARD})
-  endif()
-  if(DEFINED CMAKE_CXX_STANDARD)
-    set(MDBX_CXX_STANDARD ${CMAKE_CXX_STANDARD})
-  elseif(NOT HAS_CXX23 LESS 0
-      AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12))
-    set(MDBX_CXX_STANDARD 23)
-  elseif(NOT HAS_CXX20 LESS 0
-      AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10))
-    set(MDBX_CXX_STANDARD 20)
-  elseif(NOT HAS_CXX17 LESS 0
-      AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5))
-    set(MDBX_CXX_STANDARD 17)
-  elseif(NOT HAS_CXX14 LESS 0)
-    set(MDBX_CXX_STANDARD 14)
-  elseif(NOT HAS_CXX11 LESS 0)
-    set(MDBX_CXX_STANDARD 11)
-  else()
-    set(MDBX_CXX_STANDARD 98)
-  endif()
-endif()
-if(NOT DEFINED MDBX_C_STANDARD)
-  # MSVC >= 19.28 (Microsoft Visual Studio 16.8) is mad!
-  #               It unable process Windows SDK headers in the C11 mode!
-  if(MSVC AND MSVC_VERSION GREATER 1927 AND NOT MSVC_VERSION GREATER 1929)
-    set(MDBX_C_STANDARD 99)
-    set(C_FALLBACK_11 OFF)
-    set(C_FALLBACK_GNU11 OFF)
-  elseif(HAS_C11 LESS 0 AND NOT C_FALLBACK_GNU11 AND NOT C_FALLBACK_11)
-    set(MDBX_C_STANDARD 99)
-  else()
-    set(MDBX_C_STANDARD 11)
-  endif()
-endif()
-
-if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND EXISTS "${MDBX_SOURCE_DIR}/ntdll.def")
-  if(MSVC)
-    if(NOT MSVC_LIB_EXE)
-      # Find lib.exe
-      get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME)
-      string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME})
-      find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE})
-    endif()
-    if(MSVC_LIB_EXE)
-      message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}")
-      set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.lib")
-      add_custom_command(OUTPUT "${MDBX_NTDLL_EXTRA_IMPLIB}"
-        COMMENT "Create extra-import-library for ntdll.dll"
-        MAIN_DEPENDENCY "${MDBX_SOURCE_DIR}/ntdll.def"
-        COMMAND ${MSVC_LIB_EXE} /def:"${MDBX_SOURCE_DIR}/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}" ${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
-    else()
-      message(WARNING "MSVC's lib tool not found")
-    endif()
-  elseif(MINGW OR MINGW64)
-    if(NOT DLLTOOL)
-      # Find dlltool
-      get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME)
-      string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME})
-      find_program(DLLTOOL NAMES ${DLLTOOL_NAME})
-    endif()
-    if(DLLTOOL)
-      message(STATUS "Found dlltool: ${DLLTOOL}")
-      set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a")
-      add_custom_command(OUTPUT "${MDBX_NTDLL_EXTRA_IMPLIB}"
-        COMMENT "Create extra-import-library for ntdll.dll"
-        MAIN_DEPENDENCY "${MDBX_SOURCE_DIR}/ntdll.def"
-        COMMAND ${DLLTOOL} -d "${MDBX_SOURCE_DIR}/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}")
-    else()
-      message(WARNING "dlltool not found")
-    endif()
-  endif()
-
-  if(MDBX_NTDLL_EXTRA_IMPLIB)
-    # LY: Sometimes CMake requires a nightmarish magic for simple things.
-    # 1) create a target out of the library compilation result
-    add_custom_target(ntdll_extra_target DEPENDS "${MDBX_NTDLL_EXTRA_IMPLIB}")
-    # 2) create an library target out of the library compilation result
-    add_library(ntdll_extra STATIC IMPORTED GLOBAL)
-    add_dependencies(ntdll_extra ntdll_extra_target)
-    # 3) specify where the library is (and where to find the headers)
-    set_target_properties(ntdll_extra
-      PROPERTIES
-      IMPORTED_LOCATION "${MDBX_NTDLL_EXTRA_IMPLIB}")
-  endif()
-endif()
-
-################################################################################
-################################################################################
-#
-#           ####   #####    #####     #     ####   #    #   ####
-#          #    #  #    #     #       #    #    #  ##   #  #
-#          #    #  #    #     #       #    #    #  # #  #   ####
-#          #    #  #####      #       #    #    #  #  # #       #
-#          #    #  #          #       #    #    #  #   ##  #    #
-#           ####   #          #       #     ####   #    #   ####
-#
-
-set(MDBX_BUILD_OPTIONS ENABLE_UBSAN ENABLE_ASAN MDBX_USE_VALGRIND ENABLE_GPROF ENABLE_GCOV)
-macro(add_mdbx_option NAME DESCRIPTION DEFAULT)
-  list(APPEND MDBX_BUILD_OPTIONS ${NAME})
-  if(NOT ${DEFAULT} STREQUAL "AUTO")
-    option(${NAME} "${DESCRIPTION}" ${DEFAULT})
-  elseif(NOT DEFINED ${NAME})
-    set(${NAME}_AUTO ON)
-  endif()
-endmacro()
-
-if(IOS)
-  set(MDBX_BUILD_TOOLS_DEFAULT OFF)
-  if(NOT_SUBPROJECT)
-    cmake_policy(SET CMP0006 OLD)
-    set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO")
-  endif()
-else()
-  set(MDBX_BUILD_TOOLS_DEFAULT ON)
-endif()
-
-add_mdbx_option(MDBX_INSTALL_STATIC "Build and install libmdbx for static linking" OFF)
-add_mdbx_option(MDBX_BUILD_SHARED_LIBRARY "Build libmdbx as shared library (DLL)" ${BUILD_SHARED_LIBS})
-add_mdbx_option(MDBX_BUILD_TOOLS "Build MDBX tools (mdbx_chk/stat/dump/load/copy)" ${MDBX_BUILD_TOOLS_DEFAULT})
-CMAKE_DEPENDENT_OPTION(MDBX_INSTALL_MANPAGES "Install man-pages for MDBX tools (mdbx_chk/stat/dump/load/copy)" ON MDBX_BUILD_TOOLS OFF)
-add_mdbx_option(MDBX_TXN_CHECKOWNER "Checking transaction matches the calling thread inside libmdbx's API" ON)
-add_mdbx_option(MDBX_ENV_CHECKPID "Paranoid checking PID inside libmdbx's API" AUTO)
-mark_as_advanced(MDBX_ENV_CHECKPID)
-if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
-  add_mdbx_option(MDBX_DISABLE_GNU_SOURCE "Don't use GNU/Linux libc extensions" OFF)
-  mark_as_advanced(MDBX_DISABLE_GNU_SOURCE)
-endif()
-if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR IOS)
-  add_mdbx_option(MDBX_OSX_SPEED_INSTEADOF_DURABILITY "Disable use fcntl(F_FULLFSYNC) in favor of speed" OFF)
-  mark_as_advanced(MDBX_OSX_SPEED_INSTEADOF_DURABILITY)
-endif()
-if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
-  if(MDBX_NTDLL_EXTRA_IMPLIB)
-    add_mdbx_option(MDBX_WITHOUT_MSVC_CRT "Avoid dependence from MSVC CRT and use ntdll.dll instead" OFF)
-  endif()
-else()
-  add_mdbx_option(MDBX_USE_OFDLOCKS "Use Open file description locks (aka OFD locks, non-POSIX)" AUTO)
-  mark_as_advanced(MDBX_USE_OFDLOCKS)
-endif()
-add_mdbx_option(MDBX_LOCKING "Locking method (Win32=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO)
-mark_as_advanced(MDBX_LOCKING)
-add_mdbx_option(MDBX_TRUST_RTC "Does a system have battery-backed Real-Time Clock or just a fake" AUTO)
-mark_as_advanced(MDBX_TRUST_RTC)
-option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF)
-option(MDBX_DISABLE_PAGECHECKS "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF)
-
-if(NOT MDBX_AMALGAMATED_SOURCE)
-  if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
-    set(MDBX_ALLOY_BUILD_DEFAULT OFF)
-  else()
-    set(MDBX_ALLOY_BUILD_DEFAULT ON)
-  endif()
-  add_mdbx_option(MDBX_ALLOY_BUILD "Build MDBX library through single/alloyed object file" ${MDBX_ALLOY_BUILD_DEFAULT})
-endif()
-
-if((MDBX_BUILD_TOOLS OR MDBX_ENABLE_TESTS) AND MDBX_BUILD_SHARED_LIBRARY)
-  add_mdbx_option(MDBX_LINK_TOOLS_NONSTATIC "Link MDBX tools with non-static libmdbx" OFF)
-else()
-  unset(MDBX_LINK_TOOLS_NONSTATIC CACHE)
-endif()
-
-if(CMAKE_CXX_COMPILER_LOADED AND MDBX_CXX_STANDARD GREATER_EQUAL 11 AND MDBX_CXX_STANDARD LESS 83)
-  if(NOT MDBX_AMALGAMATED_SOURCE)
-    option(MDBX_ENABLE_TESTS "Build MDBX tests" ${BUILD_TESTING})
-  endif()
-  if(NOT MDBX_WITHOUT_MSVC_CRT
-      AND NOT (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
-      AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.9)
-      AND NOT (MSVC AND MSVC_VERSION LESS 1900))
-    option(MDBX_BUILD_CXX "Build C++ portion" ON)
-  else()
-    set(MDBX_BUILD_CXX FALSE)
-  endif()
-else()
-  set(MDBX_BUILD_CXX FALSE)
-  set(MDBX_ENABLE_TESTS FALSE)
-endif()
-
-################################################################################
-################################################################################
-
-if(MDBX_BUILD_CXX AND NOT CMAKE_CXX_COMPILER_LOADED)
-  message(FATAL_ERROR "MDBX_BUILD_CXX=${MDBX_BUILD_CXX}: The C++ compiler is required to build the C++API.")
-endif()
-
-if(MDBX_BUILD_CXX)
-  # determine library for C++ std::filesystem
-  probe_libcxx_filesystem()
-endif()
-
-# Get version
-fetch_version(MDBX "${CMAKE_CURRENT_SOURCE_DIR}" FALSE)
-message(STATUS "libmdbx version is ${MDBX_VERSION}")
-
-# sources list
-set(LIBMDBX_PUBLIC_HEADERS mdbx.h)
-set(LIBMDBX_SOURCES mdbx.h "${CMAKE_CURRENT_BINARY_DIR}/config.h")
-if(MDBX_AMALGAMATED_SOURCE)
-  list(APPEND LIBMDBX_SOURCES mdbx.c)
-else()
-  # generate version file
-  configure_file("${MDBX_SOURCE_DIR}/version.c.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/version.c" ESCAPE_QUOTES)
-  file(SHA256 "${CMAKE_CURRENT_BINARY_DIR}/version.c" MDBX_SOURCERY_DIGEST)
-  string(MAKE_C_IDENTIFIER "${MDBX_GIT_DESCRIBE}" MDBX_SOURCERY_SUFFIX)
-  set(MDBX_BUILD_SOURCERY "${MDBX_SOURCERY_DIGEST}_${MDBX_SOURCERY_SUFFIX}")
-
-  if(MDBX_ALLOY_BUILD)
-    list(APPEND LIBMDBX_SOURCES "${MDBX_SOURCE_DIR}/alloy.c")
-    include_directories("${MDBX_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
-  else()
-    list(APPEND LIBMDBX_SOURCES
-      "${CMAKE_CURRENT_BINARY_DIR}/version.c"
-      "${MDBX_SOURCE_DIR}/options.h" "${MDBX_SOURCE_DIR}/defs.h"
-      "${MDBX_SOURCE_DIR}/internals.h" "${MDBX_SOURCE_DIR}/osal.h"
-      "${MDBX_SOURCE_DIR}/core.c" "${MDBX_SOURCE_DIR}/osal.c"
-      "${MDBX_SOURCE_DIR}/lck-posix.c" "${MDBX_SOURCE_DIR}/lck-windows.c")
-    include_directories("${MDBX_SOURCE_DIR}")
-  endif()
-endif(MDBX_AMALGAMATED_SOURCE)
-if(MDBX_BUILD_CXX)
-  message(STATUS "Use C${MDBX_C_STANDARD} and C++${MDBX_CXX_STANDARD} for libmdbx")
-  list(APPEND LIBMDBX_PUBLIC_HEADERS mdbx.h++)
-  list(APPEND LIBMDBX_SOURCES "${MDBX_SOURCE_DIR}/mdbx.c++" mdbx.h++)
-else()
-  message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx but C++ portion is disabled")
-endif()
-
-if(SUBPROJECT AND MSVC)
-  if(MSVC_VERSION LESS 1900)
-    message(FATAL_ERROR "At least \"Microsoft C/C++ Compiler\" version 19.0.24234.1 (Visual Studio 2015 Update 3) is required.")
-  endif()
-  add_compile_options("/utf-8")
-endif()
-
-macro(target_setup_options TARGET)
-  if(DEFINED INTERPROCEDURAL_OPTIMIZATION)
-    set_target_properties(${TARGET} PROPERTIES
-      INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>)
-  endif()
-  if(NOT C_FALLBACK_GNU11 AND NOT C_FALLBACK_11)
-    set_target_properties(${TARGET} PROPERTIES
-      C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON)
-  endif()
-  if(MDBX_BUILD_CXX)
-    set_target_properties(${TARGET} PROPERTIES
-      CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
-    if(MSVC AND NOT MSVC_VERSION LESS 1910)
-      target_compile_options(${TARGET} INTERFACE "/Zc:__cplusplus")
-    endif()
-  endif()
-  if(CC_HAS_FASTMATH
-      AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10))
-    target_compile_options(${TARGET} PRIVATE "-ffast-math")
-  endif()
-  if(CC_HAS_VISIBILITY)
-    target_compile_options(${TARGET} PRIVATE "-fvisibility=hidden")
-  endif()
-  if(BUILD_FOR_NATIVE_CPU AND CC_HAS_ARCH_NATIVE)
-    target_compile_options(${TARGET} PRIVATE "-march=native")
-  endif()
-endmacro()
-
-macro(libmdbx_setup_libs TARGET MODE)
-  target_link_libraries(${TARGET} ${MODE} Threads::Threads)
-  if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
-    target_link_libraries(${TARGET} ${MODE} ntdll advapi32)
-    if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_WITHOUT_MSVC_CRT)
-      target_link_libraries(${TARGET} ${MODE} ntdll_extra)
-    endif()
-  elseif(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Solaris")
-    target_link_libraries(${TARGET} ${MODE} kstat)
-  elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
-    target_link_libraries(${TARGET} ${MODE} log)
-  endif()
-  if(LIBCXX_FILESYSTEM AND MDBX_BUILD_CXX)
-    if(CMAKE_COMPILER_IS_ELBRUSCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1.25.23
-        AND NOT CMAKE_VERSION VERSION_LESS 3.13)
-      target_link_options(${TARGET} PUBLIC "-Wl,--allow-multiple-definition")
-    endif()
-    target_link_libraries(${TARGET} PUBLIC ${LIBCXX_FILESYSTEM})
-  endif()
-endmacro()
-
-# build static library
-if(MDBX_INSTALL_STATIC)
-  add_library(mdbx-static STATIC ${LIBMDBX_SOURCES})
-else()
-  add_library(mdbx-static STATIC EXCLUDE_FROM_ALL ${LIBMDBX_SOURCES})
-endif()
-set_target_properties(mdbx-static PROPERTIES PUBLIC_HEADER "${LIBMDBX_PUBLIC_HEADERS}")
-target_compile_definitions(mdbx-static PRIVATE MDBX_BUILD_SHARED_LIBRARY=0)
-target_setup_options(mdbx-static)
-libmdbx_setup_libs(mdbx-static INTERFACE)
-if(MDBX_BUILD_SHARED_LIBRARY)
-  set_target_properties(mdbx-static PROPERTIES OUTPUT_NAME mdbx-static)
-else()
-  set_target_properties(mdbx-static PROPERTIES OUTPUT_NAME mdbx)
-endif()
-target_include_directories(mdbx-static INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
-
-################################################################################
-
-# build shared library
-if(MDBX_BUILD_SHARED_LIBRARY)
-  add_library(mdbx SHARED ${LIBMDBX_SOURCES})
-  set_target_properties(mdbx PROPERTIES PUBLIC_HEADER "${LIBMDBX_PUBLIC_HEADERS}")
-  target_compile_definitions(mdbx PRIVATE LIBMDBX_EXPORTS MDBX_BUILD_SHARED_LIBRARY=1 INTERFACE LIBMDBX_IMPORTS)
-  target_setup_options(mdbx)
-  libmdbx_setup_libs(mdbx PRIVATE)
-  if(MSVC)
-    if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_WITHOUT_MSVC_CRT)
-      set_property(TARGET mdbx PROPERTY LINKER_FLAGS "/NODEFAULTLIB")
-    else()
-      set_property(TARGET mdbx PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
-    endif()
-  endif()
-  if(CC_HAS_VISIBILITY AND (LTO_ENABLED OR INTERPROCEDURAL_OPTIMIZATION))
-    set_target_properties(mdbx PROPERTIES LINK_FLAGS "-fvisibility=hidden")
-  endif()
-  list(APPEND MDBX_BUILD_FLAGS ${CMAKE_SHARED_LINKER_FLAGS})
-  target_include_directories(mdbx INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
-endif()
-
-if(MDBX_BUILD_SHARED_LIBRARY AND MDBX_LINK_TOOLS_NONSTATIC)
-  set(TOOL_MDBX_LIB mdbx)
-
-  # use, i.e. don't skip the full RPATH for the build tree
-  set(CMAKE_SKIP_BUILD_RPATH FALSE)
-
-  # when building, don't use the install RPATH already (but later on when installing)
-  set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
-
-  # add the automatically determined parts of the RPATH
-  # which point to directories outside the build tree to the install RPATH
-  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
-
-  # the RPATH to be used when installing, but only if it's not a system directory
-  list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
-  if(isSystemDir EQUAL -1)
-    if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
-      set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
-    else()
-      set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib")
-    endif()
-  endif()
-else()
-  set(TOOL_MDBX_LIB mdbx-static)
-endif()
-
-# build mdbx-tools
-if(MDBX_BUILD_TOOLS)
-  if(NOT MDBX_AMALGAMATED_SOURCE AND ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
-    set(WINGETOPT_SRC ${MDBX_SOURCE_DIR}/wingetopt.c ${MDBX_SOURCE_DIR}/wingetopt.h)
-  else()
-    set(WINGETOPT_SRC "")
-  endif()
-
-  foreach(TOOL mdbx_chk mdbx_copy mdbx_stat mdbx_dump mdbx_load mdbx_drop)
-    add_executable(${TOOL} mdbx.h ${MDBX_SOURCE_DIR}/${TOOL}.c ${WINGETOPT_SRC})
-    if(NOT C_FALLBACK_GNU11 AND NOT C_FALLBACK_11)
-      set_target_properties(${TOOL} PROPERTIES
-        C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON)
-    endif()
-    target_setup_options(${TOOL})
-    target_link_libraries(${TOOL} ${TOOL_MDBX_LIB})
-  endforeach()
-  if(LIB_MATH)
-    target_link_libraries(mdbx_chk ${LIB_MATH})
-    target_link_libraries(mdbx_stat ${LIB_MATH})
-  endif()
-endif()
-
-################################################################################
-
-# mdbx-shared-lib installation
-if(NOT DEFINED MDBX_DLL_INSTALL_DESTINATION)
-  if(WIN32)
-    set(MDBX_DLL_INSTALL_DESTINATION ${CMAKE_INSTALL_BINDIR})
-  else()
-    set(MDBX_DLL_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR})
-  endif()
-endif()
-if(MDBX_BUILD_SHARED_LIBRARY)
-  if(CMAKE_VERSION VERSION_LESS 3.12)
-    install(TARGETS mdbx EXPORT libmdbx
-      LIBRARY DESTINATION ${MDBX_DLL_INSTALL_DESTINATION} COMPONENT runtime
-      OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
-      INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
-  else()
-    install(TARGETS mdbx EXPORT libmdbx
-      LIBRARY DESTINATION ${MDBX_DLL_INSTALL_DESTINATION} COMPONENT runtime
-      NAMELINK_COMPONENT devel
-      OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
-      INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
-  endif()
-endif(MDBX_BUILD_SHARED_LIBRARY)
-
-# mdbx-tools installation
-if(MDBX_BUILD_TOOLS)
-  if(NOT DEFINED MDBX_TOOLS_INSTALL_DESTINATION)
-    set(MDBX_TOOLS_INSTALL_DESTINATION ${CMAKE_INSTALL_BINDIR})
-  endif()
-  install(
-    TARGETS
-    mdbx_chk
-    mdbx_stat
-    mdbx_copy
-    mdbx_dump
-    mdbx_load
-    mdbx_drop
-    RUNTIME
-    DESTINATION ${MDBX_TOOLS_INSTALL_DESTINATION}
-    COMPONENT runtime)
-  if(MDBX_INSTALL_MANPAGES)
-    if(NOT DEFINED MDBX_MAN_INSTALL_DESTINATION)
-      set(MDBX_MAN_INSTALL_DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
-    endif()
-    install(
-      FILES
-      "${MDBX_SOURCE_DIR}/man1/mdbx_chk.1"
-      "${MDBX_SOURCE_DIR}/man1/mdbx_stat.1"
-      "${MDBX_SOURCE_DIR}/man1/mdbx_copy.1"
-      "${MDBX_SOURCE_DIR}/man1/mdbx_dump.1"
-      "${MDBX_SOURCE_DIR}/man1/mdbx_load.1"
-      "${MDBX_SOURCE_DIR}/man1/mdbx_drop.1"
-      DESTINATION ${MDBX_MAN_INSTALL_DESTINATION}
-      COMPONENT doc)
-  endif()
-endif(MDBX_BUILD_TOOLS)
-
-# mdbx-static-lib installation
-if(MDBX_INSTALL_STATIC)
-  if(CMAKE_VERSION VERSION_LESS 3.12)
-    install(TARGETS mdbx-static EXPORT libmdbx
-      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
-      INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
-  else()
-    install(TARGETS mdbx-static EXPORT libmdbx
-      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      NAMELINK_COMPONENT devel
-      OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
-      PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
-      INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
-  endif()
-endif(MDBX_INSTALL_STATIC)
-
-################################################################################
-
-# collect options & build info
-if(NOT DEFINED MDBX_BUILD_TIMESTAMP)
-  string(TIMESTAMP MDBX_BUILD_TIMESTAMP UTC)
-endif()
-set(MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS})
-if(MDBX_BUILD_CXX)
-  set(MDBX_BUILD_FLAGS ${CMAKE_CXX_FLAGS})
-endif()
-
-# append cmake's build-type flags and defines
-if(NOT CMAKE_CONFIGURATION_TYPES)
-  list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}})
-  if(MDBX_BUILD_CXX)
-    list(APPEND MDBX_BUILD_FLAGS ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}})
-  endif()
-endif()
-
-# choice target to fetch definitions and options
-if(MDBX_BUILD_SHARED_LIBRARY)
-  set(target4fetch mdbx)
-else()
-  set(target4fetch mdbx-static)
-endif()
-
-# get definitions
-get_target_property(defs_list ${target4fetch} COMPILE_DEFINITIONS)
-if(defs_list)
-  list(APPEND MDBX_BUILD_FLAGS ${defs_list})
-endif()
-
-# get target compile options
-get_target_property(options_list ${target4fetch} COMPILE_OPTIONS)
-if(options_list)
-  list(APPEND MDBX_BUILD_FLAGS ${options_list})
-endif()
-
-list(REMOVE_DUPLICATES MDBX_BUILD_FLAGS)
-string(REPLACE ";" " " MDBX_BUILD_FLAGS "${MDBX_BUILD_FLAGS}")
-if(CMAKE_CONFIGURATION_TYPES)
-  # add dynamic part via per-configuration define
-  message(STATUS "MDBX Compile Flags: ${MDBX_BUILD_FLAGS} <AND CONFIGURATION DEPENDENT>")
-  add_definitions(-DMDBX_BUILD_FLAGS_CONFIG="$<$<CONFIG:Debug>:${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_DEFINES_DEBUG}>$<$<CONFIG:Release>:${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_DEFINES_RELEASE}>$<$<CONFIG:RelWithDebInfo>:${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_DEFINES_RELWITHDEBINFO}>$<$<CONFIG:MinSizeRel>:${CMAKE_C_FLAGS_MINSIZEREL} ${CMAKE_C_DEFINES_MINSIZEREL}>")
-else()
-  message(STATUS "MDBX Compile Flags: ${MDBX_BUILD_FLAGS}")
-endif()
-
-# get compiler info
-execute_process(COMMAND sh -c "${CMAKE_C_COMPILER} --version | head -1"
-  OUTPUT_VARIABLE MDBX_BUILD_COMPILER
-  OUTPUT_STRIP_TRAILING_WHITESPACE
-  ERROR_QUIET
-  RESULT_VARIABLE rc)
-if(rc OR NOT MDBX_BUILD_COMPILER)
-  string(STRIP "${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}" MDBX_BUILD_COMPILER)
-endif()
-
-# make a build-target triplet
-if(CMAKE_C_COMPILER_TARGET)
-  set(MDBX_BUILD_TARGET "${CMAKE_C_COMPILER_TARGET}")
-else()
-  if(CMAKE_C_COMPILER_ARCHITECTURE_ID)
-    string(STRIP "${CMAKE_C_COMPILER_ARCHITECTURE_ID}" MDBX_BUILD_TARGET)
-  elseif(CMAKE_GENERATOR_PLATFORM AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL CMAKE_SYSTEM_NAME)
-    string(STRIP "${CMAKE_GENERATOR_PLATFORM}" MDBX_BUILD_TARGET)
-  elseif(CMAKE_SYSTEM_ARCH)
-    string(STRIP "${CMAKE_SYSTEM_ARCH}" MDBX_BUILD_TARGET)
-  elseif(CMAKE_LIBRARY_ARCHITECTURE)
-    string(STRIP "${CMAKE_LIBRARY_ARCHITECTURE}" MDBX_BUILD_TARGET)
-  elseif(CMAKE_SYSTEM_PROCESSOR)
-    string(STRIP "${CMAKE_SYSTEM_PROCESSOR}" MDBX_BUILD_TARGET)
-  else()
-    set(MDBX_BUILD_TARGET "unknown")
-  endif()
-  if(CMAKE_C_COMPILER_ABI
-      AND NOT (CMAKE_C_COMPILER_ABI MATCHES ".*${MDBX_BUILD_TARGET}.*" OR MDBX_BUILD_TARGET MATCHES ".*${CMAKE_C_COMPILER_ABI}.*"))
-    string(APPEND MDBX_BUILD_TARGET "-${CMAKE_C_COMPILER_ABI}")
-  endif()
-  if(CMAKE_C_PLATFORM_ID
-      AND NOT (CMAKE_SYSTEM_NAME
-        AND (CMAKE_C_PLATFORM_ID MATCHES ".*${CMAKE_SYSTEM_NAME}.*" OR CMAKE_SYSTEM_NAME MATCHES ".*${CMAKE_C_PLATFORM_ID}.*"))
-      AND NOT (CMAKE_C_PLATFORM_ID MATCHES ".*${CMAKE_C_PLATFORM_ID}.*" OR MDBX_BUILD_TARGET MATCHES ".*${CMAKE_C_PLATFORM_ID}.*"))
-    string(APPEND MDBX_BUILD_TARGET "-${CMAKE_C_COMPILER_ABI}")
-  endif()
-  if(CMAKE_SYSTEM_NAME)
-    string(APPEND MDBX_BUILD_TARGET "-${CMAKE_SYSTEM_NAME}")
-  endif()
-endif()
-
-# provide build-type
-if(CMAKE_CONFIGURATION_TYPES)
-  # via per-configuration define
-  add_definitions(-DMDBX_BUILD_TYPE="$<CONFIG>")
-  set(MDBX_BUILD_TYPE "<CONFIGURATION DEPENDENT>")
-else()
-  set(MDBX_BUILD_TYPE ${CMAKE_BUILD_TYPE})
-endif()
-
-# options
-set(options VERSION C_COMPILER CXX_COMPILER MDBX_BUILD_TARGET MDBX_BUILD_TYPE ${MDBX_BUILD_OPTIONS})
-foreach(item IN LISTS options)
-  if(DEFINED ${item})
-    set(value "${${item}}")
-  elseif(DEFINED MDBX_${item})
-    set(item MDBX_${item})
-    set(value "${${item}}")
-  elseif(DEFINED CMAKE_${item})
-    set(item CMAKE_${item})
-    set(value "${${item}}")
-  else()
-    set(value "AUTO (not pre-defined explicitly)")
-  endif()
-  message(STATUS "${item}: ${value}")
-endforeach(item)
-
-# provide config.h for library build info
-configure_file("${MDBX_SOURCE_DIR}/config.h.in"
-  "${CMAKE_CURRENT_BINARY_DIR}/config.h" ESCAPE_QUOTES)
-add_definitions(-DMDBX_CONFIG_H="${CMAKE_CURRENT_BINARY_DIR}/config.h")
-
-################################################################################
-
-if(NOT MDBX_AMALGAMATED_SOURCE AND MDBX_ENABLE_TESTS)
-  if(NOT CMAKE_CXX_COMPILER_LOADED)
-    message(FATAL_ERROR "MDBX_ENABLE_TESTS=${MDBX_ENABLE_TESTS}: The C++ compiler is required to build the tests.")
-  endif()
-  add_subdirectory(test)
-endif()
-
-################################################################################
-
-set(PACKAGE "libmdbx")
-set(CPACK_PACKAGE_VERSION_MAJOR ${MDBX_VERSION_MAJOR})
-set(CPACK_PACKAGE_VERSION_MINOR ${MDBX_VERSION_MINOR})
-set(CPACK_PACKAGE_VERSION_PATCH ${MDBX_VERSION_RELEASE})
-set(CPACK_PACKAGE_VERSION_COMMIT ${MDBX_VERSION_REVISION})
-set(PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}.${CPACK_PACKAGE_VERSION_COMMIT}")
-message(STATUS "libmdbx package version is ${PACKAGE_VERSION}")
-
-cmake_policy(POP)
diff --git a/3rdparty/libmdbx/ChangeLog.md b/3rdparty/libmdbx/ChangeLog.md
deleted file mode 100644
index f677fed8d9822d262f63df2d8f2fe49b40df40c3..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/ChangeLog.md
+++ /dev/null
@@ -1,777 +0,0 @@
-ChangeLog
----------
-
-### TODO
-
- - [Engage an "overlapped I/O" on Windows](todo4recovery://erased_by_github/libmdbx/issues/224).
- - [Simple careful mode for working with corrupted DB](todo4recovery://erased_by_github/libmdbx/issues/223).
- - [Move most of `mdbx_chk` functional to the library API](todo4recovery://erased_by_github/libmdbx/issues/204).
- - [Replace SRW-lock on Windows to allow shrink DB with `MDBX_NOTLS` option](todo4recovery://erased_by_github/libmdbx/issues/210).
- - [More flexible support of asynchronous runtime/framework(s)](todo4recovery://erased_by_github/libmdbx/issues/200).
- - [Migration guide from LMDB to MDBX](todo4recovery://erased_by_github/libmdbx/issues/199).
- - [Get rid of dirty-pages list in MDBX_WRITEMAP mode](todo4recovery://erased_by_github/libmdbx/issues/193).
- - [Large/Overflow pages accounting for dirty-room](todo4recovery://erased_by_github/libmdbx/issues/192).
- - [Support for RAW devices](todo4recovery://erased_by_github/libmdbx/issues/124).
- - [Support MessagePack for Keys & Values](todo4recovery://erased_by_github/libmdbx/issues/115).
- - [Engage new terminology](todo4recovery://erased_by_github/libmdbx/issues/137).
- - Packages for [Astra Linux](https://astralinux.ru/), [ALT Linux](https://www.altlinux.org/), [ROSA Linux](https://www.rosalinux.ru/), etc.
-
-
-## v0.11.7 at 2022-04-22
-
-The stable risen release after the Github's intentional malicious disaster.
-
-#### We have migrated to a reliable trusted infrastructure
-The origin for now is at [GitFlic](https://gitflic.ru/project/erthink/libmdbx)
-since on 2022-04-15 the Github administration, without any warning nor
-explanation, deleted _libmdbx_ along with a lot of other projects,
-simultaneously blocking access for many developers.
-For the same reason ~~Github~~ is blacklisted forever.
-
-GitFlic already support Russian and English languages, plan to support more,
-including 和 中文. You are welcome!
-
-New:
-
- - Added the `tools-static` make target to build statically linked MDBX tools.
- - Support for Microsoft Visual Studio 2022.
- - Support build by MinGW' make from command line without CMake.
- - Added `mdbx::filesystem` C++ API namespace that corresponds to `std::filesystem` or `std::experimental::filesystem`.
- - Created [website](https://libmdbx.website.yandexcloud.net/) for online auto-generated documentation.
- - Used `todo4recovery://erased_by_github/` for dead (or temporarily lost) resources deleted by ~~Github~~.
- - Added `--loglevel=` command-line option to the `mdbx_test` tool.
- - Added few fast smoke-like tests into CMake builds.
-
-Fixes:
-
- - Fixed a race between starting a transaction and creating a DBI descriptor that could lead to `SIGSEGV` in the cursor tracking code.
- - Clarified description of `MDBX_EPERM` error returned from `mdbx_env_set_geometry()`.
- - Fixed non-promoting the parent transaction to be dirty in case the undo of the geometry update failed during abortion of a nested transaction.
- - Resolved linking issues with `libstdc++fs`/`libc++fs`/`libc++experimental` for C++ `std::filesystem` or `std::experimental::filesystem` for legacy compilers.
- - Added workaround for GNU Make 3.81 and earlier.
- - Added workaround for Elbrus/LCC 1.25 compiler bug of class inline `static constexpr` member field.
- - [Fixed](https://github.com/ledgerwatch/erigon/issues/3874) minor assertion regression (only debug builds were affected).
- - Fixed detection of `C++20` concepts accessibility.
- - Fixed detection of Clang's LTO availability for Android.
- - Fixed build for ARM/ARM64 by MSVC.
- - Fixed non-x86 Windows builds with `MDBX_WITHOUT_MSVC_CRT=ON` and `MDBX_BUILD_SHARED_LIBRARY=ON`.
-
-Minors:
-
- - Resolve minor MSVC warnings: avoid `/INCREMENTAL[:YES]` with `/LTCG`, `/W4` with `/W3`, the `C5105` warning.
- - Switched to using `MDBX_EPERM` instead of `MDBX_RESULT_TRUE' to indicate that the geometry cannot be updated.
- - Added `NULL` checking during memory allocation inside `mdbx_chk`.
- - Resolved all warnings from MinGW while used without CMake.
- - Added inheretable `target_include_directories()` to `CMakeLists.txt` for easy integration.
- - Added build-time checks and paranoid runtime assertions for the `off_t` arguments of `fcntl()` which are used for locking.
- - Added `-Wno-lto-type-mismatch` to avoid false-positive warnings from old GCC during LTO-enabled builds.
- - Added checking for TID (system thread id) to avoid hang on 32-bit Bionic/Android  within `pthread_mutex_lock()`.
- - Reworked `MDBX_BUILD_TARGET` of CMake builds.
- - Added `CMAKE_HOST_ARCH` and `CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET`.
-
-
-## v0.11.6 at 2022-03-24
-
-The stable release with the complete workaround for an incoherence flaw of Linux unified page/buffer cache.
-Nonetheless the cause for this trouble may be an issue of Intel CPU cache/MESI.
-See [issue#269](todo4recovery://erased_by_github/libmdbx/issues/269) for more information.
-
-Acknowledgements:
-
- - [David Bouyssié](https://github.com/david-bouyssie) for [Scala bindings](https://github.com/david-bouyssie/mdbx4s).
- - [Michelangelo Riccobene](https://github.com/mriccobene) for reporting and testing.
-
-Fixes:
-
- - [Added complete workaround](todo4recovery://erased_by_github/libmdbx/issues/269) for an incoherence flaw of Linux unified page/buffer cache.
- - [Fixed](todo4recovery://erased_by_github/libmdbx/issues/272) cursor reusing for read-only transactions.
- - Fixed copy&paste typo inside `mdbx::cursor::find_multivalue()`.
-
-Minors:
-
- - Minor refine C++ API for convenience.
- - Minor internals refines.
- - Added `lib-static` and `lib-shared` targets for make.
- - Added minor workaround for AppleClang 13.3 bug.
- - Clarified error messages of a signature/version mismatch.
-
-
-## v0.11.5 at 2022-02-23
-
-The release with the temporary hotfix for a flaw of Linux unified page/buffer cache.
-See [issue#269](todo4recovery://erased_by_github/libmdbx/issues/269) for more information.
-
-Acknowledgements:
-
- - [Simon Leier](https://github.com/leisim) for reporting and testing.
- - [Kai Wetlesen](https://github.com/kaiwetlesen) for [RPMs](http://copr.fedorainfracloud.org/coprs/kwetlesen/libmdbx/).
- - [Tullio Canepa](https://github.com/canepat) for reporting C++ API issue and contributing.
-
-Fixes:
-
- - [Added hotfix](todo4recovery://erased_by_github/libmdbx/issues/269) for a flaw of Linux unified page/buffer cache.
- - [Fixed/Reworked](todo4recovery://erased_by_github/libmdbx/pull/270) move-assignment operators for "managed" classes of C++ API.
- - Fixed potential `SIGSEGV` while open DB with overrided non-default page size.
- - [Made](todo4recovery://erased_by_github/libmdbx/issues/267) `mdbx_env_open()` idempotence in failure cases.
- - Refined/Fixed pages reservation inside `mdbx_update_gc()` to avoid non-reclamation in a rare cases.
- - Fixed typo in a retained space calculation for the hsr-callback.
-
-Minors:
-
- - Reworked functions for meta-pages, split-off non-volatile.
- - Disentangled C11-atomic fences/barriers and pure-functions (with `__attribute__((__pure__))`) to avoid compiler misoptimization.
- - Fixed hypotetic unaligned access to 64-bit dwords on ARM with `__ARM_FEATURE_UNALIGNED` defined.
- - Reasonable paranoia that makes clarity for code readers.
- - Minor fixes Doxygen references, comments, descriptions, etc.
-
-
-## v0.11.4 at 2022-02-02
-
-The stable release with fixes for large and huge databases sized of 4..128 TiB.
-
-Acknowledgements:
-
- - [Ledgerwatch](https://github.com/ledgerwatch), [Binance](https://github.com/binance-chain) and [Positive Technologies](https://www.ptsecurity.com/) teams for reporting, assistance in investigation and testing.
- - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation.
- - [Kris Zyp](https://github.com/kriszyp) for [Deno](https://deno.land/) support.
-
-New features, extensions and improvements:
-
- - Added treating the `UINT64_MAX` value as maximum for given option inside `mdbx_env_set_option()`.
- - Added `to_hex/to_base58/to_base64::output(std::ostream&)` overloads without using temporary string objects as buffers.
- - Added `--geometry-jitter=YES|no` option to the test framework.
- - Added support for [Deno](https://deno.land/) support by [Kris Zyp](https://github.com/kriszyp).
-
-Fixes:
-
- - Fixed handling `MDBX_opt_rp_augment_limit` for GC's records from huge transactions (Erigon/Akula/Ethereum).
- - [Fixed](todo4recovery://erased_by_github/libmdbx/issues/258) build on Android (avoid including `sys/sem.h`).
- - [Fixed](todo4recovery://erased_by_github/libmdbx/pull/261) missing copy assignment operator for `mdbx::move_result`.
- - Fixed missing `&` for `std::ostream &operator<<()` overloads.
- - Fixed unexpected `EXDEV` (Cross-device link) error from `mdbx_env_copy()`.
- - Fixed base64 encoding/decoding bugs in auxillary C++ API.
- - Fixed overflow of `pgno_t` during checking PNL on 64-bit platforms.
- - [Fixed](todo4recovery://erased_by_github/libmdbx/issues/260) excessive PNL checking after sort for spilling.
- - Reworked checking `MAX_PAGENO` and DB upper-size geometry limit.
- - [Fixed](todo4recovery://erased_by_github/libmdbx/issues/265) build for some combinations of versions of  MSVC and Windows SDK.
-
-Minors:
-
- - Added workaround for CLANG bug [D79919/PR42445](https://reviews.llvm.org/D79919).
- - Fixed build test on Android (using `pthread_barrier_t` stub).
- - Disabled C++20 concepts for CLANG < 14 on Android.
- - Fixed minor `unused parameter` warning.
- - Added CI for Android.
- - Refine/cleanup internal logging.
- - Refined line splitting inside hex/base58/base64 encoding to avoid `\n` at the end.
- - Added workaround for modern libstdc++ with CLANG < 4.x
- - Relaxed txn-check rules for auxiliary functions.
- - Clarified a comments and descriptions, etc.
- - Using the `-fno-semantic interposition` option to reduce the overhead to calling self own public functions.
-
-
-## v0.11.3 at 2021-12-31
-
-Acknowledgements:
-
- - [gcxfd <i@rmw.link>](https://github.com/gcxfd) for reporting, contributing and testing.
- - [장세연 (Чан Се Ен)](https://github.com/sasgas) for reporting and testing.
- - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation.
-
-New features, extensions and improvements:
-
- - [Added](todo4recovery://erased_by_github/libmdbx/issues/236) `mdbx_cursor_get_batch()`.
- - [Added](todo4recovery://erased_by_github/libmdbx/issues/250) `MDBX_SET_UPPERBOUND`.
- - C++ API is finalized now.
- - The GC update stage has been [significantly speeded](todo4recovery://erased_by_github/libmdbx/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem).
-
-Fixes:
-
- - Disabled C++20 concepts for stupid AppleClang 13.x
- - Fixed internal collision of `MDBX_SHRINK_ALLOWED` with `MDBX_ACCEDE`.
-
-Minors:
-
- - Fixed returning `MDBX_RESULT_TRUE` (unexpected -1) from `mdbx_env_set_option()`.
- - Added `mdbx_env_get_syncbytes()` and `mdbx_env_get_syncperiod()`.
- - [Clarified](todo4recovery://erased_by_github/libmdbx/pull/249) description of `MDBX_INTEGERKEY`.
- - Reworked/simplified `mdbx_env_sync_internal()`.
- - [Fixed](todo4recovery://erased_by_github/libmdbx/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases.
- - Avoiding extra looping inside `mdbx_env_info_ex()`.
- - Explicitly enabled core dumps from stochastic tests scripts on Linux.
- - [Fixed](todo4recovery://erased_by_github/libmdbx/issues/253) `mdbx_override_meta()` to avoid false-positive assertions.
- - For compatibility reverted returning `MDBX_ENODATA`for some cases.
-
-
-## v0.11.2 at 2021-12-02
-
-Acknowledgements:
-
- - [장세연 (Чан Се Ен)](https://github.com/sasgas) for contributing to C++ API.
- - [Alain Picard](https://github.com/castortech) for [Java bindings](https://github.com/castortech/mdbxjni).
- - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
- - [Kris Zyp](https://github.com/kriszyp) for reporting and testing.
- - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs).
-
-Fixes:
-
- - [Fixed compilation](todo4recovery://erased_by_github/libmdbx/pull/239) with `devtoolset-9` on CentOS/RHEL 7.
- - [Fixed unexpected `MDBX_PROBLEM` error](todo4recovery://erased_by_github/libmdbx/issues/242) because of update an obsolete meta-page.
- - [Fixed returning `MDBX_NOTFOUND` error](todo4recovery://erased_by_github/libmdbx/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation.
- - [Fixed compilation](todo4recovery://erased_by_github/libmdbx/issues/245) without kernel/libc-devel headers.
-
-Minors:
-
- - Fixed `constexpr`-related macros for legacy compilers.
- - Allowed to define 'CMAKE_CXX_STANDARD` using an environment variable.
- - Simplified collection statistics of page operation .
- - Added `MDBX_FORCE_BUILD_AS_MAIN_PROJECT` cmake option.
- - Remove unneeded `#undef P_DIRTY`.
-
-
-## v0.11.1 at 2021-10-23
-
-### Backward compatibility break:
-
-The database format signature has been changed to prevent
-forward-interoperability with an previous releases, which may lead to a
-[false positive diagnosis of database corruption](todo4recovery://erased_by_github/libmdbx/issues/238)
-due to flaws of an old library versions.
-
-This change is mostly invisible:
-
- - previously versions are unable to read/write a new DBs;
- - but the new release is able to handle an old DBs and will silently upgrade ones.
-
-Acknowledgements:
-
- - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
-
-
-## v0.10.5 at 2021-10-13 (obsolete, please use v0.11.1)
-
-Unfortunately, the `v0.10.5` accidentally comes not full-compatible with previous releases:
-
- - `v0.10.5` can read/processing DBs created by previous releases, i.e. the backward-compatibility is provided;
- - however, previous releases may lead to false-corrupted state with DB that was touched by `v0.10.5`, i.e. the forward-compatibility is broken for `v0.10.4` and earlier.
-
-This cannot be fixed, as it requires fixing past versions, which as a result we will just get a current version.
-Therefore, it is recommended to use `v0.11.1` instead of `v0.10.5`.
-
-Acknowledgements:
-
- - [Noel Kuntze](https://github.com/Thermi) for immediately bug reporting.
-
-Fixes:
-
- - Fixed unaligned access regression after the `#pragma pack` fix for modern compilers.
- - Added UBSAN-test to CI to avoid a regression(s) similar to lately fixed.
- - Fixed possibility of meta-pages clashing after manually turn to a particular meta-page using `mdbx_chk` utility.
-
-Minors:
-
- - Refined handling of weak or invalid meta-pages while a DB opening.
- - Refined providing information for the `@MAIN` and `@GC` sub-databases of a last committed modification transaction's ID.
-
-
-## v0.10.4 at 2021-10-10
-
-Acknowledgements:
-
- - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs).
- - [Andrew Ashikhmin](https://github.com/yperbasis) for contributing to C++ API.
-
-Fixes:
-
- - Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru)).
- - Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](todo4recovery://erased_by_github/libmdbx/issues/235).
- - Fixed `noexcept` for potentially throwing `txn::put()` of C++ API.
-
-Minors:
-
- - Added stochastic test script for checking small transactions cases.
- - Removed extra transaction commit/restart inside test framework.
- - In debugging builds fixed a too small (single page) by default DB shrink threshold.
-
-
-## v0.10.3 at 2021-08-27
-
-Acknowledgements:
-
- - [Francisco Vallarino](https://github.com/fjvallarino) for [Haskell bindings for libmdbx](https://hackage.haskell.org/package/libmdbx).
- - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
- - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for contributing.
-
-Extensions and improvements:
-
- - Added `cursor::erase()` overloads for `key` and for `key-value`.
- - Resolve minor Coverity Scan issues (no fixes but some hint/comment were added).
- - Resolve minor UndefinedBehaviorSanitizer issues (no fixes but some workaround were added).
-
-Fixes:
-
- - Always setup `madvise` while opening DB (fixes todo4recovery://erased_by_github/libmdbx/issues/231).
- - Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages.
-
-Minors:
-
- - Fixed getting revision number from middle of history during amalgamation (GNU Makefile).
- - Fixed search GCC tools for LTO (CMake scripts).
- - Fixed/reorder dirs list for search CLANG tools for LTO (CMake scripts).
- - Fixed/workarounds for CLANG < 9.x
- - Fixed CMake warning about compatibility with 3.8.2
-
-
-## v0.10.2 at 2021-07-26
-
-Acknowledgements:
-
- - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
- - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for reporting bugs.
- - [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs.
- - [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx).
- - [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store).
- - [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](todo4recovery://erased_by_github/libmdbx/commits/python-bindings).
-
-New features, extensions and improvements:
-
- - [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](todo4recovery://erased_by_github/libmdbx/issues/201).
- - Added options support for `long-stochastic` script.
- - Avoided `MDBX_TXN_FULL` error for large transactions when possible.
- - The `MDBX_READERS_LIMIT` increased to `32767`.
- - Raise `MDBX_TOO_LARGE` under Valgrind/ASAN if being opened DB is 100 larger than RAM (to avoid hangs and OOM).
- - Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck.
- - Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures.
- - `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc).
- - Added more checks for [rare/fuzzing corruption cases](todo4recovery://erased_by_github/libmdbx/issues/217).
-
-Backward compatibility break:
-
- - Use file `VERSION.txt` for version information instead of `VERSION` to avoid collision with `#include <version>`.
- - Rename `slice::from/to_FOO_bytes()` to `slice::envisage_from/to_FOO_length()'.
- - Rename `MDBX_TEST_EXTRA` make's variable to `MDBX_SMOKE_EXTRA`.
- - Some details of the C++ API have been changed for subsequent freezing.
-
-Fixes:
-
- - Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors.
- - Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](todo4recovery://erased_by_github/libmdbx/issues/203).
- - Fixed [log a warning during a new DB creation](todo4recovery://erased_by_github/libmdbx/issues/205).
- - Fixed [false-negative `mdbx_cursor_eof()` result](todo4recovery://erased_by_github/libmdbx/issues/207).
- - Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](todo4recovery://erased_by_github/libmdbx/issues/208).
- - Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](todo4recovery://erased_by_github/libmdbx/issues/209).
- - Fixed [C++ Buffer issue with `std::string` and alignment](todo4recovery://erased_by_github/libmdbx/issues/191).
- - Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap.
- - Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`.
- - Fixed [using bad meta-pages if DB was partially/recoverable corrupted](todo4recovery://erased_by_github/libmdbx/issues/217).
- - Fixed extra `noexcept` for `buffer::&assign_reference()`.
- - Fixed `bootid` generation on Windows for case of change system' time.
- - Fixed [test framework keygen-related issue](todo4recovery://erased_by_github/libmdbx/issues/127).
-
-
-## v0.10.1 at 2021-06-01
-
-Acknowledgements:
-
- - [Alexey Akhunov](https://github.com/AlexeyAkhunov) and [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting and testing.
- - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for bug reporting and testing related to WSL2.
-
-New features:
-
- - Added `-p` option to `mdbx_stat` utility for printing page operations statistic.
- - Added explicit checking for and warning about using unfit github's archives.
- - Added fallback from [OFD locking](https://bit.ly/3yFRtYC) to legacy non-OFD POSIX file locks on an `EINVAL` error.
- - Added [Plan 9](https://en.wikipedia.org/wiki/9P_(protocol)) network file system to the whitelist for an ability to open a DB in exclusive mode.
- - Support for opening from WSL2 environment a DB hosted on Windows drive and mounted via [DrvFs](https://docs.microsoft.com/it-it/archive/blogs/wsl/wsl-file-system-support#drvfs) (i.e by Plan 9 noted above).
-
-Fixes:
-
- - Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library.
- - Fixed confusing/messy errors when build library from unfit github's archives (todo4recovery://erased_by_github/libmdbx/issues/197).
- - Fixed `#​e​l​s​i​f` typo.
- - Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (todo4recovery://erased_by_github/libmdbx/issues/195).
- - Re-Fixed WSL1/WSL2 detection with distinguishing (todo4recovery://erased_by_github/libmdbx/issues/97).
-
-
-## v0.10.0 at 2021-05-09
-
-Acknowledgements:
-
- - [Mahlon E. Smith](https://github.com/mahlonsmith) for [Ruby bindings](https://rubygems.org/gems/mdbx/).
- - [Alex Sharov](https://github.com/AskAlexSharov) for [mdbx-go](https://github.com/torquem-ch/mdbx-go), bug reporting and testing.
- - [Artem Vorotnikov](https://github.com/vorot93) for bug reporting and PR.
- - [Paolo Rebuffo](https://www.linkedin.com/in/paolo-rebuffo-8255766/), [Alexey Akhunov](https://github.com/AlexeyAkhunov) and Mark Grosberg for donations.
- - [Noel Kuntze](https://github.com/Thermi) for preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings)
-
-New features:
-
- - Added `mdbx_env_set_option()` and `mdbx_env_get_option()` for controls
-   various runtime options for an environment (announce of this feature  was missed in a previous news).
- - Added `MDBX_DISABLE_PAGECHECKS` build option to disable some checks to reduce an overhead
-   and detection probability of database corruption to a values closer to the LMDB.
-   The `MDBX_DISABLE_PAGECHECKS=1` provides a performance boost of about 10% in CRUD scenarios,
-   and conjointly with the `MDBX_ENV_CHECKPID=0` and `MDBX_TXN_CHECKOWNER=0` options can yield
-   up to 30% more performance compared to LMDB.
- - Using float point (exponential quantized) representation for internal 16-bit values
-   of grow step and shrink threshold when huge ones (todo4recovery://erased_by_github/libmdbx/issues/166).
-   To minimize the impact on compatibility, only the odd values inside the upper half
-   of the range (i.e. 32769..65533) are used for the new representation.
- - Added the `mdbx_drop` similar to LMDB command-line tool to purge or delete (sub)database(s).
- - [Ruby bindings](https://rubygems.org/gems/mdbx/) is available now by [Mahlon E. Smith](https://github.com/mahlonsmith).
- - Added `MDBX_ENABLE_MADVISE` build option which controls the use of POSIX `madvise()` hints and friends.
- - The internal node sizes were refined, resulting in a reduction in large/overflow pages in some use cases
-   and a slight increase in limits for a keys size to ≈½ of page size.
- - Added to `mdbx_chk` output number of keys/items on pages.
- - Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (todo4recovery://erased_by_github/libmdbx/pull/180).
- - Major rework page splitting (af9b7b560505684249b76730997f9e00614b8113) for
-     - An "auto-appending" feature upon insertion for both ascending and
-       descending key sequences. As a result, the optimality of page filling
-       increases significantly (more densely, less slackness) while
-       inserting ordered sequences of keys,
-     - A "splitting at middle" to make page tree more balanced on average.
- - Added `mdbx_get_sysraminfo()` to the API.
- - Added guessing a reasonable maximum DB size for the default upper limit of geometry (todo4recovery://erased_by_github/libmdbx/issues/183).
- - Major rework internal labeling of a dirty pages (958fd5b9479f52f2124ab7e83c6b18b04b0e7dda) for
-   a "transparent spilling" feature with the gist to make a dirty pages
-   be ready to spilling (writing to a disk) without further altering ones.
-   Thus in the `MDBX_WRITEMAP` mode the OS kernel able to oust dirty pages
-   to DB file without further penalty during transaction commit.
-   As a result, page swapping and I/O could be significantly reduced during extra large transactions and/or lack of memory.
- - Minimized reading leaf-pages during dropping subDB(s) and nested trees.
- - Major rework a spilling of dirty pages to support [LRU](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))
-   policy and prioritization for a large/overflow pages.
- - Statistics of page operations (split, merge, copy, spill, etc) now available through `mdbx_env_info_ex()`.
- - Auto-setup limit for length of dirty pages list (`MDBX_opt_txn_dp_limit` option).
- - Support `make options` to list available build options.
- - Support `make help` to list available make targets.
- - Silently `make`'s build by default.
- - Preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) is available now
-   by [Noel Kuntze](https://github.com/Thermi) (todo4recovery://erased_by_github/libmdbx/issues/147).
-
-Backward compatibility break:
-
- - The `MDBX_AVOID_CRT` build option was renamed to `MDBX_WITHOUT_MSVC_CRT`.
-   This option is only relevant when building for Windows.
- - The `mdbx_env_stat()` always, and `mdbx_env_stat_ex()` when called with the zeroed transaction parameter,
-   now internally start temporary read transaction and thus may returns `MDBX_BAD_RSLOT` error.
-   So, just never use deprecated `mdbx_env_stat()' and call `mdbx_env_stat_ex()` with transaction parameter.
- - The build option `MDBX_CONFIG_MANUAL_TLS_CALLBACK` was removed and now just a non-zero value of
-   the `MDBX_MANUAL_MODULE_HANDLER` macro indicates the requirement to manually call `mdbx_module_handler()`
-   when loading libraries and applications uses statically linked libmdbx on an obsolete Windows versions.
-
-Fixes:
-
- - Fixed performance regression due non-optimal C11 atomics usage (todo4recovery://erased_by_github/libmdbx/issues/160).
- - Fixed "reincarnation" of subDB after it deletion (todo4recovery://erased_by_github/libmdbx/issues/168).
- - Fixed (disallowing) implicit subDB deletion via operations on `@MAIN`'s DBI-handle.
- - Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (todo4recovery://erased_by_github/libmdbx/issues/171).
- - Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (todo4recovery://erased_by_github/libmdbx/issues/170).
- - Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((todo4recovery://erased_by_github/libmdbx/issues/179).
- - Fixed an unreasonably huge default upper limit for DB geometry (todo4recovery://erased_by_github/libmdbx/issues/183).
- - Fixed `constexpr` specifier for the `slice::invalid()`.
- - Fixed (no)readahead auto-handling (todo4recovery://erased_by_github/libmdbx/issues/164).
- - Fixed non-alloy build for Windows.
- - Switched to using Heap-functions instead of LocalAlloc/LocalFree on Windows.
- - Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (todo4recovery://erased_by_github/libmdbx/issues/190).
- - Fixed building by GCC 4.8.5 (added workaround for a preprocessor's bug).
- - Fixed building C++ part for iOS <= 13.0 (unavailability of  `std::filesystem::path`).
- - Fixed building for Windows target versions prior to Windows Vista (`WIN32_WINNT < 0x0600`).
- - Fixed building by MinGW for Windows (todo4recovery://erased_by_github/libmdbx/issues/155).
-
-
-## v0.9.3 at 2021-02-02
-
-Acknowledgements:
-
- - [Mahlon E. Smith](http://www.martini.nu/) for [FreeBSD port of libmdbx](https://svnweb.freebsd.org/ports/head/databases/mdbx/).
- - [장세연](http://www.castis.com) for bug fixing and PR.
- - [Clément Renault](https://github.com/Kerollmops/heed) for [Heed](https://github.com/Kerollmops/heed) fully typed Rust wrapper.
- - [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting.
- - [Noel Kuntze](https://github.com/Thermi) for bug reporting.
-
-Removed options and features:
-
- - Drop `MDBX_HUGE_TRANSACTIONS` build-option (now no longer required).
-
-New features:
-
- - Package for FreeBSD is available now by Mahlon E. Smith.
- - New API functions to get/set various options (todo4recovery://erased_by_github/libmdbx/issues/128):
-    - the maximum number of named databases for the environment;
-    - the maximum number of threads/reader slots;
-    - threshold (since the last unsteady commit) to force flush the data buffers to disk;
-    - relative period (since the last unsteady commit) to force flush the data buffers to disk;
-    - limit to grow a list of reclaimed/recycled page's numbers for finding a sequence of contiguous pages for large data items;
-    - limit to grow a cache of dirty pages for reuse in the current transaction;
-    - limit of a pre-allocated memory items for dirty pages;
-    - limit of dirty pages for a write transaction;
-    - initial allocation size for dirty pages list of a write transaction;
-    - maximal part of the dirty pages may be spilled when necessary;
-    - minimal part of the dirty pages should be spilled when necessary;
-    - how much of the parent transaction dirty pages will be spilled while start each child transaction;
- - Unlimited/Dynamic size of retired and dirty page lists (todo4recovery://erased_by_github/libmdbx/issues/123).
- - Added `-p` option (purge subDB before loading) to `mdbx_load` tool.
- - Reworked spilling of large transaction and committing of nested transactions:
-    - page spilling code reworked to avoid the flaws and bugs inherited from LMDB;
-    - limit for number of dirty pages now is controllable at runtime;
-    - a spilled pages, including overflow/large pages, now can be reused and refunded/compactified in nested transactions;
-    - more effective refunding/compactification especially for the loosed page cache.
- - Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options.
- - Added `mdbx_default_pagesize()` function.
- - Better support architectures with a weak/relaxed memory consistency model (ARM, AARCH64, PPC, MIPS, RISC-V, etc) by means [C11 atomics](https://en.cppreference.com/w/c/atomic).
- - Speed up page number lists and dirty page lists (todo4recovery://erased_by_github/libmdbx/issues/132).
- - Added `LIBMDBX_NO_EXPORTS_LEGACY_API` build option.
-
-Fixes:
-
- - Fixed missing cleanup (null assigned) in the C++ commit/abort (todo4recovery://erased_by_github/libmdbx/pull/143).
- - Fixed `mdbx_realloc()` for case of nullptr and `MDBX_WITHOUT_MSVC_CRT=ON` for Windows.
- - Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (todo4recovery://erased_by_github/libmdbx/issues/146).
- - Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (todo4recovery://erased_by_github/libmdbx/issues/153).
- - Fixed minor/potential memory leak during page flushing and unspilling.
- - Fixed handling states of cursors's and subDBs's for nested transactions.
- - Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit.
- - Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (todo4recovery://erased_by_github/libmdbx/issues/153).
- - Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (todo4recovery://erased_by_github/libmdbx/issues/123).
- - Fixed auto-recovery (`weak->steady` with the same boot-id) when Database size at last weak checkpoint is large than at last steady checkpoint.
- - Fixed operation on systems with unusual small/large page size, including PowerPC (todo4recovery://erased_by_github/libmdbx/issues/157).
-
-
-## v0.9.2 at 2020-11-27
-
-Acknowledgements:
-
- - Jens Alfke (Mobile Architect at [Couchbase](https://www.couchbase.com/)) for [NimDBX](https://github.com/snej/nimdbx).
- - Clément Renault (CTO at [MeiliSearch](https://www.meilisearch.com/)) for [mdbx-rs](https://github.com/Kerollmops/mdbx-rs).
- - Alex Sharov (Go-Lang Teach Lead at [TurboGeth/Ethereum](https://ethereum.org/)) for an extreme test cases and bug reporting.
- - George Hazan (CTO at [Miranda NG](https://www.miranda-ng.org/)) for bug reporting.
- - [Positive Technologies](https://www.ptsecurity.com/) for funding and [The Standoff](https://standoff365.com/).
-
-Added features:
-
- - Provided package for [buildroot](https://buildroot.org/).
- - Binding for Nim is [available](https://github.com/snej/nimdbx) now by Jens Alfke.
- - Added `mdbx_env_delete()` for deletion an environment files in a proper and multiprocess-safe way.
- - Added `mdbx_txn_commit_ex()` with collecting latency information.
- - Fast completion pure nested transactions.
- - Added `LIBMDBX_INLINE_API` macro and inline versions of some API functions.
- - Added `mdbx_cursor_copy()` function.
- - Extended tests for checking cursor tracking.
- - Added `MDBX_SET_LOWERBOUND` operation for `mdbx_cursor_get()`.
-
-Fixes:
-
- - Fixed missing installation of `mdbx.h++`.
- - Fixed use of obsolete `__noreturn`.
- - Fixed use of `yield` instruction on ARM if unsupported.
- - Added pthread workaround for buggy toolchain/cmake/buildroot.
- - Fixed use of `pthread_yield()` for non-GLIBC.
- - Fixed use of `RegGetValueA()` on Windows 2000/XP.
- - Fixed use of `GetTickCount64()` on Windows 2000/XP.
- - Fixed opening DB on a network shares (in the exclusive mode).
- - Fixed copy&paste typos.
- - Fixed minor false-positive GCC warning.
- - Added workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK.
- - Fixed cursor state after multimap/dupsort repeated deletes (todo4recovery://erased_by_github/libmdbx/issues/121).
- - Added `SIGPIPE` suppression for internal thread during `mdbx_env_copy()`.
- - Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (todo4recovery://erased_by_github/libmdbx/issues/131).
- - Fixed spilled pages checking (todo4recovery://erased_by_github/libmdbx/issues/126).
- - Fixed `mdbx_load` for 'plain text' and without `-s name` cases (todo4recovery://erased_by_github/libmdbx/issues/136).
- - Fixed save/restore/commit of cursors for nested transactions.
- - Fixed cursors state in rare/special cases (move next beyond end-of-data, after deletion and so on).
- - Added workaround for MSVC 19.28 (Visual Studio 16.8) (but may still hang during compilation).
- - Fixed paranoidal Clang C++ UB for bitwise operations with flags defined by enums.
- - Fixed large pages checking (for compatibility and to avoid false-positive errors from `mdbx_chk`).
- - Added workaround for Wine (https://github.com/miranda-ng/miranda-ng/issues/1209).
- - Fixed `ERROR_NOT_SUPPORTED` while opening DB by UNC pathnames (https://github.com/miranda-ng/miranda-ng/issues/2627).
- - Added handling `EXCEPTION_POSSIBLE_DEADLOCK` condition for Windows.
-
-
-## v0.9.1 2020-09-30
-
-Added features:
-
- - Preliminary C++ API with support for C++17 polymorphic allocators.
- - [Online C++ API reference](https://erased_by_github_and_to_be_restored.todo/libmdbx/) by Doxygen.
- - Quick reference for Insert/Update/Delete operations.
- - Explicit `MDBX_SYNC_DURABLE` to sync modes for API clarity.
- - Explicit `MDBX_ALLDUPS` and `MDBX_UPSERT` for API clarity.
- - Support for read transactions preparation (`MDBX_TXN_RDONLY_PREPARE` flag).
- - Support for cursor preparation/(pre)allocation and reusing (`mdbx_cursor_create()` and `mdbx_cursor_bind()` functions).
- - Support for checking database using specified meta-page (see `mdbx_chk -h`).
- - Support for turn to the specific meta-page after checking (see `mdbx_chk -h`).
- - Support for explicit reader threads (de)registration.
- - The `mdbx_txn_break()` function to explicitly mark a transaction as broken.
- - Improved handling of corrupted databases by `mdbx_chk` utility and `mdbx_walk_tree()` function.
- - Improved DB corruption detection by checking parent-page-txnid.
- - Improved opening large DB (> 4Gb) from 32-bit code.
- - Provided `pure-function` and `const-function` attributes to C API.
- - Support for user-settable context for transactions & cursors.
- - Revised API and documentation related to Handle-Slow-Readers callback feature.
-
-Deprecated functions and flags:
-
- - For clarity and API simplification the `MDBX_MAPASYNC` flag is deprecated.
-   Just use `MDBX_SAFE_NOSYNC` or `MDBX_UTTERLY_NOSYNC` instead of it.
- - `MDBX_oom_func`, `mdbx_env_set_oomfunc()` and `mdbx_env_get_oomfunc()`
-   replaced with `MDBX_hsr_func`, `mdbx_env_get_hsr` and `mdbx_env_get_hsr()`.
-
-Fixes:
-
- - Fix `mdbx_strerror()` for `MDBX_BUSY` error (no error description is returned).
- - Fix update internal meta-geo information in read-only mode (`EACCESS` or `EBADFD` error).
- - Fix `mdbx_page_get()` null-defer when DB corrupted (crash by `SIGSEGV`).
- - Fix `mdbx_env_open()` for re-opening after non-fatal errors (`mdbx_chk` unexpected failures).
- - Workaround for MSVC 19.27 `static_assert()` bug.
- - Doxygen descriptions and refinement.
- - Update Valgrind's suppressions.
- - Workaround to avoid infinite loop of 'nested' testcase on MIPS under QEMU.
- - Fix a lot of typos & spelling (Thanks to Josh Soref for PR).
- - Fix `getopt()` messages for Windows (Thanks to Andrey Sporaw for reporting).
- - Fix MSVC compiler version requirements (Thanks to Andrey Sporaw for reporting).
- - Workarounds for QEMU's bugs to run tests for cross-builded library under QEMU.
- - Now C++ compiler optional for building by CMake.
-
-
-## v0.9.0 2020-07-31 (not a release, but API changes)
-
-Added features:
-
- - [Online C API reference](https://erased_by_github_and_to_be_restored.todo/libmdbx/) by Doxygen.
- - Separated enums for environment, sub-databases, transactions, copying and data-update flags.
-
-Deprecated functions and flags:
-
- - Usage of custom comparators and the `mdbx_dbi_open_ex()` are deprecated, since such databases couldn't be checked by the `mdbx_chk` utility.
-   Please use the value-to-key functions to provide keys that are compatible with the built-in libmdbx comparators.
-
-
-## v0.8.2 2020-07-06
-- Added support multi-opening the same DB in a process with SysV locking (BSD).
-- Fixed warnings & minors for LCC compiler (E2K).
-- Enabled to simultaneously open the same database from processes with and without the `MDBX_WRITEMAP` option.
-- Added key-to-value, `mdbx_get_keycmp()` and `mdbx_get_datacmp()` functions (helpful to avoid using custom comparators).
-- Added `ENABLE_UBSAN` CMake option to enabling the UndefinedBehaviorSanitizer from GCC/CLANG.
-- Workaround for [CLANG bug](https://bugs.llvm.org/show_bug.cgi?id=43275).
-- Returning `MDBX_CORRUPTED` in case all meta-pages are weak and no other error.
-- Refined mode bits while auto-creating LCK-file.
-- Avoids unnecessary database file re-mapping in case geometry changed by another process(es).
-  From the user's point of view, the `MDBX_UNABLE_EXTEND_MAPSIZE` error will now be returned less frequently and only when using the DB in the current process really requires it to be reopened.
-- Remapping on-the-fly and of the database file was implemented.
-  Now remapping with a change of address is performed automatically if there are no dependent readers in the current process.
-
-
-## v0.8.1 2020-06-12
-- Minor change versioning. The last number in the version now means the number of commits since last release/tag.
-- Provide ChangeLog file.
-- Fix for using libmdbx as a C-only sub-project with CMake.
-- Fix `mdbx_env_set_geometry()` for case it is called from an opened environment outside of a write transaction.
-- Add support for huge transactions and `MDBX_HUGE_TRANSACTIONS` build-option (default `OFF`).
-- Refine LTO (link time optimization) for clang.
-- Force enabling exceptions handling for MSVC (`/EHsc` option).
-
-
-## v0.8.0 2020-06-05
-- Support for Android/Bionic.
-- Support for iOS.
-- Auto-handling `MDBX_NOSUBDIR` while opening for any existing database.
-- Engage github-actions to make release-assets.
-- Clarify API description.
-- Extended keygen-cases in stochastic test.
-- Fix fetching of first/lower key from LEAF2-page during page merge.
-- Fix missing comma in array of error messages.
-- Fix div-by-zero while copy-with-compaction for non-resizable environments.
-- Fixes & enhancements for custom-comparators.
-- Fix `MDBX_WITHOUT_MSVC_CRT` option and missing `ntdll.def`.
-- Fix `mdbx_env_close()` to work correctly called concurrently from several threads.
-- Fix null-deref in an ASAN-enabled builds while opening the environment with error and/or read-only.
-- Fix AddressSanitizer errors after closing the environment.
-- Fix/workaround to avoid GCC 10.x pedantic warnings.
-- Fix using `ENODATA` for FreeBSD.
-- Avoid invalidation of DBI-handle(s) when it just closes.
-- Avoid using `pwritev()` for single-writes (up to 10% speedup for some kernels & scenarios).
-- Avoiding `MDBX_UTTERLY_NOSYNC` as result of flags merge.
-- Add `mdbx_dbi_dupsort_depthmask()` function.
-- Add `MDBX_CP_FORCE_RESIZEABLE` option.
-- Add deprecated `MDBX_MAP_RESIZED` for compatibility.
-- Add `MDBX_BUILD_TOOLS` option (default `ON`).
-- Refine `mdbx_dbi_open_ex()` to safe concurrently opening the same handle from different threads.
-- Truncate clk-file during environment closing. So a zero-length lck-file indicates that the environment was closed properly.
-- Refine `mdbx_update_gc()` for huge transactions with small sizes of database page.
-- Extends dump/load to support all MDBX attributes.
-- Avoid upsertion the same key-value data, fix related assertions.
-- Rework min/max length checking for keys & values.
-- Checking the order of keys on all pages during checking.
-- Support `CFLAGS_EXTRA` make-option for convenience.
-- Preserve the last txnid while copying with compactification.
-- Auto-reset running transaction in mdbx_txn_renew().
-- Automatically abort errored transaction in mdbx_txn_commit().
-- Auto-choose page size for large databases.
-- Rearrange source files, rework build, options-support by CMake.
-- Crutch for WSL1 (Windows subsystem for Linux).
-- Refine install/uninstall targets.
-- Support for Valgrind 3.14 and later.
-- Add check-analyzer check-ubsan check-asan check-leak targets to Makefile.
-- Minor fix/workaround to avoid UBSAN traps for `memcpy(ptr, NULL, 0)`.
-- Avoid some GCC-analyzer false-positive warnings.
-
-
-## v0.7.0 2020-03-18
-- Workarounds for Wine (Windows compatibility layer for Linux).
-- `MDBX_MAP_RESIZED` renamed to `MDBX_UNABLE_EXTEND_MAPSIZE`.
-- Clarify API description, fix typos.
-- Speedup runtime checks in debug/checked builds.
-- Added checking for read/write transactions overlapping for the same thread, added `MDBX_TXN_OVERLAPPING` error and `MDBX_DBG_LEGACY_OVERLAP` option.
-- Added `mdbx_key_from_jsonInteger()`, `mdbx_key_from_double()`, `mdbx_key_from_float()`, `mdbx_key_from_int64()` and `mdbx_key_from_int32()` functions. See `mdbx.h` for description.
-- Fix compatibility (use zero for invalid DBI).
-- Refine/clarify error messages.
-- Avoids extra error messages "bad txn" from mdbx_chk when DB is corrupted.
-
-
-## v0.6.0 2020-01-21
-- Fix `mdbx_load` utility for custom comparators.
-- Fix checks related to `MDBX_APPEND` flag inside `mdbx_cursor_put()`.
-- Refine/fix dbi_bind() internals.
-- Refine/fix handling `STATUS_CONFLICTING_ADDRESSES`.
-- Rework `MDBX_DBG_DUMP` option to avoid disk I/O performance degradation.
-- Add built-in help to test tool.
-- Fix `mdbx_env_set_geometry()` for large page size.
-- Fix env_set_geometry() for large pagesize.
-- Clarify API description & comments, fix typos.
-
-
-## v0.5.0 2019-12-31
-- Fix returning MDBX_RESULT_TRUE from page_alloc().
-- Fix false-positive ASAN issue.
-- Fix assertion for `MDBX_NOTLS` option.
-- Rework `MADV_DONTNEED` threshold.
-- Fix `mdbx_chk` utility for don't checking some numbers if walking on the B-tree was disabled.
-- Use page's mp_txnid for basic integrity checking.
-- Add `MDBX_FORCE_ASSERTIONS` built-time option.
-- Rework `MDBX_DBG_DUMP` to avoid performance degradation.
-- Rename `MDBX_NOSYNC` to `MDBX_SAFE_NOSYNC` for clarity.
-- Interpret `ERROR_ACCESS_DENIED` from `OpenProcess()` as 'process exists'.
-- Avoid using `FILE_FLAG_NO_BUFFERING` for compatibility with small database pages.
-- Added install section for CMake.
-
-
-## v0.4.0 2019-12-02
-- Support for Mac OSX, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, OpenSolaris, OpenIndiana (AIX and HP-UX pending).
-- Use bootid for decisions of rollback.
-- Counting retired pages and extended transaction info.
-- Add `MDBX_ACCEDE` flag for database opening.
-- Using OFD-locks and tracking for in-process multi-opening.
-- Hot backup into pipe.
-- Support for cmake & amalgamated sources.
-- Fastest internal sort implementation.
-- New internal dirty-list implementation with lazy sorting.
-- Support for lazy-sync-to-disk with polling.
-- Extended key length.
-- Last update transaction number for each sub-database.
-- Automatic read ahead enabling/disabling.
-- More auto-compactification.
-- Using -fsanitize=undefined and -Wpedantic options.
-- Rework page merging.
-- Nested transactions.
-- API description.
-- Checking for non-local filesystems to avoid DB corruption.
diff --git a/3rdparty/libmdbx/GNUmakefile b/3rdparty/libmdbx/GNUmakefile
deleted file mode 100644
index d6b9fc7a7cf14a26ce72e8c1f8f54d404c603173..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/GNUmakefile
+++ /dev/null
@@ -1,375 +0,0 @@
-# This makefile is for GNU Make 3.80 or above, and nowadays provided
-# just for compatibility and preservation of traditions.
-#
-# Please use CMake in case of any difficulties or
-# problems with this old-school's magic.
-#
-################################################################################
-#
-# Basic internal definitios. For a customizable variables and options see below.
-#
-$(info // The GNU Make $(MAKE_VERSION))
-SHELL         := $(shell env bash -c 'echo $$BASH')
-MAKE_VERx3    := $(shell printf "%3s%3s%3s" $(subst ., ,$(MAKE_VERSION)))
-make_lt_3_81  := $(shell expr "$(MAKE_VERx3)" "<" "  3 81")
-ifneq ($(make_lt_3_81),0)
-$(error Please use GNU Make 3.81 or above)
-endif
-make_ge_4_1   := $(shell expr "$(MAKE_VERx3)" ">=" "  4  1")
-SRC_PROBE_C   := $(shell [ -f mdbx.c ] && echo mdbx.c || echo src/osal.c)
-SRC_PROBE_CXX := $(shell [ -f mdbx.c++ ] && echo mdbx.c++ || echo src/mdbx.c++)
-UNAME         := $(shell uname -s 2>/dev/null || echo Unknown)
-
-define cxx_filesystem_probe
-  int main(int argc, const char*argv[]) {
-    mdbx::filesystem::path probe(argv[0]);
-    if (argc != 1) throw mdbx::filesystem::filesystem_error(std::string("fake"), std::error_code());
-    return mdbx::filesystem::is_directory(probe.relative_path());
-  }
-endef
-#
-################################################################################
-#
-# Use `make options` to list the available libmdbx build options.
-#
-# Note that the defaults should already be correct for most platforms;
-# you should not need to change any of these. Read their descriptions
-# in README and source code (see src/options.h) if you do.
-#
-
-# install sandbox
-DESTDIR ?=
-INSTALL ?= install
-# install prefixes (inside sandbox)
-prefix  ?= /usr/local
-mandir  ?= $(prefix)/man
-# lib/bin suffix for multiarch/biarch, e.g. '.x86_64'
-suffix  ?=
-
-# toolchain
-CC      ?= gcc
-CXX     ?= g++
-CFLAGS_EXTRA ?=
-LD      ?= ld
-
-# build options
-MDBX_BUILD_OPTIONS ?=-DNDEBUG=1
-MDBX_BUILD_TIMESTAMP ?=$(shell date +%Y-%m-%dT%H:%M:%S%z)
-
-# probe and compose common compiler flags with variable expansion trick (seems this work two times per session for GNU Make 3.81)
-CFLAGS       ?= $(strip $(eval CFLAGS := -std=gnu11 -O2 -g -Wall -Werror -Wextra -Wpedantic -ffunction-sections -fPIC -fvisibility=hidden -pthread -Wno-error=attributes $$(shell for opt in -fno-semantic-interposition -Wno-unused-command-line-argument -Wno-tautological-compare; do [ -z "$$$$($(CC) '-DMDBX_BUILD_FLAGS="probe"' $$$${opt} -c $(SRC_PROBE_C) -o /dev/null >/dev/null 2>&1 || echo failed)" ] && echo "$$$${opt} "; done)$(CFLAGS_EXTRA))$(CFLAGS))
-
-# choosing C++ standard with variable expansion trick (seems this work two times per session for GNU Make 3.81)
-CXXSTD       ?= $(eval CXXSTD := $$(shell for std in gnu++23 c++23 gnu++2b c++2b gnu++20 c++20 gnu++2a c++2a gnu++17 c++17 gnu++1z c++1z gnu++14 c++14 gnu++1y c++1y gnu+11 c++11 gnu++0x c++0x; do $(CXX) -std=$$$${std} -c $(SRC_PROBE_CXX) -o /dev/null 2>probe4std-$$$${std}.err >/dev/null && echo "-std=$$$${std}" && exit; done))$(CXXSTD)
-CXXFLAGS     ?= $(strip $(CXXSTD) $(filter-out -std=gnu11,$(CFLAGS)))
-
-# libraries and options for linking
-EXE_LDFLAGS  ?= -pthread
-ifneq ($(make_ge_4_1),1)
-# don't use variable expansion trick as workaround for bugs of GNU Make before 4.1
-LIBS         ?= $(shell $(uname2libs))
-LDFLAGS      ?= $(shell $(uname2ldflags))
-LIB_STDCXXFS ?= $(shell echo '$(cxx_filesystem_probe)' | cat mdbx.h++ - | sed $$'1s/\xef\xbb\xbf//' | $(CXX) -x c++ $(CXXFLAGS) -Wno-error - -Wl,--allow-multiple-definition -lstdc++fs $(LIBS) $(LDFLAGS) $(EXE_LDFLAGS) -o /dev/null 2>probe4lstdfs.err >/dev/null && echo '-Wl,--allow-multiple-definition -lstdc++fs')
-else
-# using variable expansion trick to avoid repeaded probes
-LIBS         ?= $(eval LIBS := $$(shell $$(uname2libs)))$(LIBS)
-LDFLAGS      ?= $(eval LDFLAGS := $$(shell $$(uname2ldflags)))$(LDFLAGS)
-LIB_STDCXXFS ?= $(eval LIB_STDCXXFS := $$(shell echo '$$(cxx_filesystem_probe)' | cat mdbx.h++ - | sed $$$$'1s/\xef\xbb\xbf//' | $(CXX) -x c++ $(CXXFLAGS) -Wno-error - -Wl,--allow-multiple-definition -lstdc++fs $(LIBS) $(LDFLAGS) $(EXE_LDFLAGS) -o /dev/null 2>probe4lstdfs.err >/dev/null && echo '-Wl,--allow-multiple-definition -lstdc++fs'))$(LIB_STDCXXFS)
-endif
-
-################################################################################
-
-define uname2sosuffix
-  case "$(UNAME)" in
-    Darwin*|Mach*) echo dylib;;
-    CYGWIN*|MINGW*|MSYS*|Windows*) echo dll;;
-    *) echo so;;
-  esac
-endef
-
-define uname2ldflags
-  case "$(UNAME)" in
-    CYGWIN*|MINGW*|MSYS*|Windows*)
-      echo '-Wl,--gc-sections,-O1';
-      ;;
-    *)
-      $(LD) --help 2>/dev/null | grep -q -- --gc-sections && echo '-Wl,--gc-sections,-z,relro,-O1';
-      $(LD) --help 2>/dev/null | grep -q -- -dead_strip && echo '-Wl,-dead_strip';
-      ;;
-  esac
-endef
-
-# TIP: try add the'-Wl, --no-as-needed,-lrt' for ability to built with modern glibc, but then use with the old.
-define uname2libs
-  case "$(UNAME)" in
-    CYGWIN*|MINGW*|MSYS*|Windows*)
-      echo '-lm -lntdll -lwinmm';
-      ;;
-    *SunOS*|*Solaris*)
-      echo '-lm -lkstat -lrt';
-      ;;
-    *Darwin*|OpenBSD*)
-      echo '-lm';
-      ;;
-    *)
-      echo '-lm -lrt';
-      ;;
-  esac
-endef
-
-SO_SUFFIX  := $(shell $(uname2sosuffix))
-HEADERS    := mdbx.h mdbx.h++
-LIBRARIES  := libmdbx.a libmdbx.$(SO_SUFFIX)
-TOOLS      := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk mdbx_drop
-MANPAGES   := mdbx_stat.1 mdbx_copy.1 mdbx_dump.1 mdbx_load.1 mdbx_chk.1 mdbx_drop.1
-TIP        := // TIP:
-
-.PHONY: all help options lib libs tools clean install uninstall check_buildflags_tag tools-static
-.PHONY: install-strip install-no-strip strip libmdbx mdbx show-options lib-static lib-shared
-
-ifeq ("$(origin V)", "command line")
-  MDBX_BUILD_VERBOSE := $(V)
-endif
-ifndef MDBX_BUILD_VERBOSE
-  MDBX_BUILD_VERBOSE := 0
-endif
-
-ifeq ($(MDBX_BUILD_VERBOSE),1)
-  QUIET :=
-  HUSH :=
-  $(info $(TIP) Use `make V=0` for quiet.)
-else
-  QUIET := @
-  HUSH := >/dev/null
-  $(info $(TIP) Use `make V=1` for verbose.)
-endif
-
-all: show-options $(LIBRARIES) $(TOOLS)
-
-help:
-	@echo "  make all                 - build libraries and tools"
-	@echo "  make help                - print this help"
-	@echo "  make options             - list build options"
-	@echo "  make lib                 - build libraries, also lib-static and lib-shared"
-	@echo "  make tools               - build the tools"
-	@echo "  make tools-static        - build the tools with statically linking with system libraries and compiler runtime"
-	@echo "  make clean               "
-	@echo "  make install             "
-	@echo "  make uninstall           "
-	@echo ""
-	@echo "  make strip               - strip debug symbols from binaries"
-	@echo "  make install-no-strip    - install explicitly without strip"
-	@echo "  make install-strip       - install explicitly with strip"
-	@echo ""
-	@echo "  make bench               - run ioarena-benchmark"
-	@echo "  make bench-couple        - run ioarena-benchmark for mdbx and lmdb"
-	@echo "  make bench-triplet       - run ioarena-benchmark for mdbx, lmdb, sqlite3"
-	@echo "  make bench-quartet       - run ioarena-benchmark for mdbx, lmdb, rocksdb, wiredtiger"
-	@echo "  make bench-clean         - remove temp database(s) after benchmark"
-
-show-options:
-	@echo "  MDBX_BUILD_OPTIONS   = $(MDBX_BUILD_OPTIONS)"
-	@echo "  MDBX_BUILD_TIMESTAMP = $(MDBX_BUILD_TIMESTAMP)"
-	@echo '$(TIP) Use `make options` to listing available build options.'
-	@echo "  CC       =`which $(CC)` | `$(CC) --version | head -1`"
-	@echo "  CFLAGS   =$(CFLAGS)"
-	@echo "  CXXFLAGS =$(CXXFLAGS)"
-	@echo "  LDFLAGS  =$(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) $(EXE_LDFLAGS)"
-	@echo '$(TIP) Use `make help` to listing available targets.'
-
-options:
-	@echo "  INSTALL      =$(INSTALL)"
-	@echo "  DESTDIR      =$(DESTDIR)"
-	@echo "  prefix       =$(prefix)"
-	@echo "  mandir       =$(mandir)"
-	@echo "  suffix       =$(suffix)"
-	@echo ""
-	@echo "  CC           =$(CC)"
-	@echo "  CFLAGS_EXTRA =$(CFLAGS_EXTRA)"
-	@echo "  CFLAGS       =$(CFLAGS)"
-	@echo "  CXX          =$(CXX)"
-	@echo "  CXXSTD       =$(CXXSTD)"
-	@echo "  CXXFLAGS     =$(CXXFLAGS)"
-	@echo ""
-	@echo "  LD           =$(LD)"
-	@echo "  LDFLAGS      =$(LDFLAGS)"
-	@echo "  EXE_LDFLAGS  =$(EXE_LDFLAGS)"
-	@echo "  LIBS         =$(LIBS)"
-	@echo ""
-	@echo "  MDBX_BUILD_OPTIONS   = $(MDBX_BUILD_OPTIONS)"
-	@echo "  MDBX_BUILD_TIMESTAMP = $(MDBX_BUILD_TIMESTAMP)"
-	@echo ""
-	@echo "## Assortment items for MDBX_BUILD_OPTIONS:"
-	@echo "##   Note that the defaults should already be correct for most platforms;"
-	@echo "##   you should not need to change any of these. Read their descriptions"
-	@echo "##   in README and source code (see mdbx.c) if you do."
-	@grep -h '#ifndef MDBX_' mdbx.c | grep -v BUILD | uniq | sed 's/#ifndef /  /'
-
-lib libs libmdbx mdbx: libmdbx.a libmdbx.$(SO_SUFFIX)
-
-tools: $(TOOLS)
-tools-static: $(addsuffix .static,$(TOOLS)) $(addsuffix .static-lto,$(TOOLS))
-
-strip: all
-	@echo '  STRIP libmdbx.$(SO_SUFFIX) $(TOOLS)'
-	$(TRACE )strip libmdbx.$(SO_SUFFIX) $(TOOLS)
-
-clean:
-	@echo '  REMOVE ...'
-	$(QUIET)rm -rf $(TOOLS) mdbx_test @* *.[ao] *.[ls]o *.$(SO_SUFFIX) *.dSYM *~ tmp.db/* \
-		*.gcov *.log *.err src/*.o test/*.o mdbx_example dist \
-		config.h src/config.h src/version.c *.tar* buildflags.tag \
-		mdbx_*.static mdbx_*.static-lto
-
-MDBX_BUILD_FLAGS =$(strip $(MDBX_BUILD_OPTIONS) $(CXXSTD) $(CFLAGS) $(LDFLAGS) $(LIBS))
-check_buildflags_tag:
-	$(QUIET)if [ "$(MDBX_BUILD_FLAGS)" != "$$(cat buildflags.tag 2>&1)" ]; then \
-		echo -n "  CLEAN for build with specified flags..." && \
-		$(MAKE) IOARENA=false CXXSTD= -s clean >/dev/null && echo " Ok" && \
-		echo '$(MDBX_BUILD_FLAGS)' > buildflags.tag; \
-	fi
-
-buildflags.tag: check_buildflags_tag
-
-lib-static libmdbx.a: mdbx-static.o mdbx++-static.o
-	@echo '  AR $@'
-	$(QUIET)$(AR) rcs $@ $? $(HUSH)
-
-lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o mdbx++-dylib.o
-	@echo '  LD $@'
-	$(QUIET)$(CXX) $(CXXFLAGS) $^ -pthread -shared $(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) -o $@
-
-
-################################################################################
-# Amalgamated source code, i.e. distributed after `make dist`
-MAN_SRCDIR := man1/
-
-config.h: buildflags.tag mdbx.c $(lastword $(MAKEFILE_LIST))
-	@echo '  MAKE $@'
-	$(QUIET)(echo '#define MDBX_BUILD_TIMESTAMP "$(MDBX_BUILD_TIMESTAMP)"' \
-	&& echo "#define MDBX_BUILD_FLAGS \"$$(cat buildflags.tag)\"" \
-	&& echo '#define MDBX_BUILD_COMPILER "$(shell (LC_ALL=C $(CC) --version || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
-	&& echo '#define MDBX_BUILD_TARGET "$(shell set -o pipefail; (LC_ALL=C $(CC) -v 2>&1 | grep -i '^Target:' | cut -d ' ' -f 2- || (LC_ALL=C $(CC) --version | grep -qi e2k && echo E2K) || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
-	) >$@
-
-mdbx-dylib.o: config.h mdbx.c mdbx.h $(lastword $(MAKEFILE_LIST))
-	@echo '  CC $@'
-	$(QUIET)$(CC) $(CFLAGS) $(MDBX_BUILD_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c mdbx.c -o $@
-
-mdbx-static.o: config.h mdbx.c mdbx.h $(lastword $(MAKEFILE_LIST))
-	@echo '  CC $@'
-	$(QUIET)$(CC) $(CFLAGS) $(MDBX_BUILD_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c mdbx.c -o $@
-
-mdbx++-dylib.o: config.h mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
-	@echo '  CC $@'
-	$(QUIET)$(CXX) $(CXXFLAGS) $(MDBX_BUILD_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c mdbx.c++ -o $@
-
-mdbx++-static.o: config.h mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
-	@echo '  CC $@'
-	$(QUIET)$(CXX) $(CXXFLAGS) $(MDBX_BUILD_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c mdbx.c++ -o $@
-
-mdbx_%:	mdbx_%.c mdbx-static.o
-	@echo '  CC+LD $@'
-	$(QUIET)$(CC) $(CFLAGS) $(MDBX_BUILD_OPTIONS) '-DMDBX_CONFIG_H="config.h"' $^ $(EXE_LDFLAGS) $(LIBS) -o $@
-
-mdbx_%.static: mdbx_%.c mdbx-static.o
-	@echo '  CC+LD $@'
-	$(QUIET)$(CC) $(CFLAGS) $(MDBX_BUILD_OPTIONS) '-DMDBX_CONFIG_H="config.h"' $^ $(EXE_LDFLAGS) -static -Wl,--strip-all -o $@
-
-mdbx_%.static-lto: mdbx_%.c config.h mdbx.c mdbx.h
-	@echo '  CC+LD $@'
-	$(QUIET)$(CC) $(CFLAGS) -Os -flto $(MDBX_BUILD_OPTIONS) '-DLIBMDBX_API=' '-DMDBX_CONFIG_H="config.h"' \
-		$< mdbx.c $(EXE_LDFLAGS) $(LIBS) -static -Wl,--strip-all -o $@
-
-
-install: $(LIBRARIES) $(TOOLS) $(HEADERS)
-	@echo '  INSTALLING...'
-	$(QUIET)mkdir -p $(DESTDIR)$(prefix)/bin$(suffix) && \
-		$(INSTALL) -p $(EXE_INSTALL_FLAGS) $(TOOLS) $(DESTDIR)$(prefix)/bin$(suffix)/ && \
-	mkdir -p $(DESTDIR)$(prefix)/lib$(suffix)/ && \
-		$(INSTALL) -p $(EXE_INSTALL_FLAGS) $(filter-out libmdbx.a,$(LIBRARIES)) $(DESTDIR)$(prefix)/lib$(suffix)/ && \
-	mkdir -p $(DESTDIR)$(prefix)/lib$(suffix)/ && \
-		$(INSTALL) -p libmdbx.a $(DESTDIR)$(prefix)/lib$(suffix)/ && \
-	mkdir -p $(DESTDIR)$(prefix)/include/ && \
-		$(INSTALL) -p -m 444 $(HEADERS) $(DESTDIR)$(prefix)/include/ && \
-	mkdir -p $(DESTDIR)$(mandir)/man1/ && \
-		$(INSTALL) -p -m 444 $(addprefix $(MAN_SRCDIR), $(MANPAGES)) $(DESTDIR)$(mandir)/man1/
-
-install-strip: EXE_INSTALL_FLAGS = -s
-install-strip: install
-
-install-no-strip: EXE_INSTALL_FLAGS =
-install-no-strip: install
-
-uninstall:
-	@echo '  UNINSTALLING/REMOVE...'
-	$(QUIET)rm -f $(addprefix $(DESTDIR)$(prefix)/bin$(suffix)/,$(TOOLS)) \
-		$(addprefix $(DESTDIR)$(prefix)/lib$(suffix)/,$(LIBRARIES)) \
-		$(addprefix $(DESTDIR)$(prefix)/include/,$(HEADERS)) \
-		$(addprefix $(DESTDIR)$(mandir)/man1/,$(MANPAGES))
-
-################################################################################
-# Benchmarking by ioarena
-
-ifeq ($(origin IOARENA),undefined)
-IOARENA := $(shell \
-  (test -x ../ioarena/@BUILD/src/ioarena && echo ../ioarena/@BUILD/src/ioarena) || \
-  (test -x ../../@BUILD/src/ioarena && echo ../../@BUILD/src/ioarena) || \
-  (test -x ../../src/ioarena && echo ../../src/ioarena) || which ioarena 2>&- || \
-  (echo false && echo '$(TIP) Clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring directory for availability of benchmarking.' >&2))
-endif
-NN	?= 25000000
-BENCH_CRUD_MODE ?= nosync
-
-bench-clean:
-	@echo '  REMOVE bench-*.txt _ioarena/*'
-	$(QUIET)rm -rf bench-*.txt _ioarena/*
-
-re-bench: bench-clean bench
-
-ifeq ($(or $(IOARENA),false),false)
-bench bench-quartet bench-triplet bench-couple:
-	$(QUIET)echo 'The `ioarena` benchmark is required.' >&2 && \
-	echo 'Please clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring `ioarena` directory.' >&2 && \
-	false
-
-else
-
-.PHONY: bench bench-clean bench-couple re-bench bench-quartet bench-triplet
-
-define bench-rule
-bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST))
-	@echo '  RUNNING ioarena for $1/$2...'
-	$(QUIET)LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \
-		$(IOARENA) -D $(1) -B crud -m $(BENCH_CRUD_MODE) -n $(2) \
-		| tee $$@ | grep throughput && \
-	LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \
-		$(IOARENA) -D $(1) -B get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \
-		| tee -a $$@ | grep throughput \
-	|| mv -f $$@ $$@.error
-
-endef
-
-$(eval $(call bench-rule,mdbx,$(NN),libmdbx.$(SO_SUFFIX)))
-
-$(eval $(call bench-rule,sophia,$(NN)))
-$(eval $(call bench-rule,leveldb,$(NN)))
-$(eval $(call bench-rule,rocksdb,$(NN)))
-$(eval $(call bench-rule,wiredtiger,$(NN)))
-$(eval $(call bench-rule,forestdb,$(NN)))
-$(eval $(call bench-rule,lmdb,$(NN)))
-$(eval $(call bench-rule,nessdb,$(NN)))
-$(eval $(call bench-rule,sqlite3,$(NN)))
-$(eval $(call bench-rule,ejdb,$(NN)))
-$(eval $(call bench-rule,vedisdb,$(NN)))
-$(eval $(call bench-rule,dummy,$(NN)))
-bench: bench-mdbx_$(NN).txt
-bench-quartet: bench-mdbx_$(NN).txt bench-lmdb_$(NN).txt bench-rocksdb_$(NN).txt bench-wiredtiger_$(NN).txt
-bench-triplet: bench-mdbx_$(NN).txt bench-lmdb_$(NN).txt bench-sqlite3_$(NN).txt
-bench-couple: bench-mdbx_$(NN).txt bench-lmdb_$(NN).txt
-
-# $(eval $(call bench-rule,debug,10))
-# .PHONY: bench-debug
-# bench-debug: bench-debug_10.txt
-
-endif
diff --git a/3rdparty/libmdbx/LICENSE b/3rdparty/libmdbx/LICENSE
deleted file mode 100644
index 05ad7571e448b9d83ead5d4691274d9484574714..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/LICENSE
+++ /dev/null
@@ -1,47 +0,0 @@
-The OpenLDAP Public License
-  Version 2.8, 17 August 2003
-
-Redistribution and use of this software and associated documentation
-("Software"), with or without modification, are permitted provided
-that the following conditions are met:
-
-1. Redistributions in source form must retain copyright statements
-   and notices,
-
-2. Redistributions in binary form must reproduce applicable copyright
-   statements and notices, this list of conditions, and the following
-   disclaimer in the documentation and/or other materials provided
-   with the distribution, and
-
-3. Redistributions must contain a verbatim copy of this document.
-
-The OpenLDAP Foundation may revise this license from time to time.
-Each revision is distinguished by a version number.  You may use
-this Software under terms of this license revision or under the
-terms of any subsequent revision of the license.
-
-THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT
-SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
-OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-The names of the authors and copyright holders must not be used in
-advertising or otherwise to promote the sale, use or other dealing
-in this Software without specific, written prior permission.  Title
-to copyright in this Software shall at all times remain with copyright
-holders.
-
-OpenLDAP is a registered trademark of the OpenLDAP Foundation.
-
-Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
-California, USA.  All Rights Reserved.  Permission to copy and
-distribute verbatim copies of this document is granted.
diff --git a/3rdparty/libmdbx/README.md b/3rdparty/libmdbx/README.md
deleted file mode 100644
index b27fadb211a231b7f5f9106aac68afa34cafe184..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/README.md
+++ /dev/null
@@ -1,760 +0,0 @@
-<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
-
-### The origin has been migrated to [GitFlic](https://gitflic.ru/project/erthink/libmdbx)
-since on 2022-04-15 the Github administration, without any warning
-nor explanation, deleted _libmdbx_ along with a lot of other projects,
-simultaneously blocking access for many developers.
-For the same reason ~~Github~~ is blacklisted forever.
-
-GitFlic's developers plan to support other languages,
-including English 和 中文, in the near future.
-
-### Основной репозиторий перемещен на [GitFlic](https://gitflic.ru/project/erthink/libmdbx)
-так как 15 апреля 2022 администрация Github без предупреждения и
-объяснения причин удалила _libmdbx_ вместе с массой других проектов,
-одновременно заблокировав доступ многим разработчикам.
-По этой же причине ~~Github~~ навсегда занесен в черный список.
-
---------------------------------------------------------------------------------
-
-*The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет хорошо.*
-
-> Please refer to the online [documentation](https://libmdbx.website.yandexcloud.net)
-> with [`C` API description](https://libmdbx.website.yandexcloud.net/group__c__api.html)
-> and pay attention to the [`C++` API](https://gitflic.ru/project/erthink/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1).
-
-> Questions, feedback and suggestions are welcome to the [Telegram' group](https://t.me/libmdbx).
-
-> For NEWS take a look to the [ChangeLog](https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
-
-
-libmdbx
-========
-
-<!-- section-begin overview -->
-
-_libmdbx_ is an extremely fast, compact, powerful, embedded, transactional
-[key-value database](https://en.wikipedia.org/wiki/Key-value_database),
-with [permissive license](https://gitflic.ru/project/erthink/libmdbx/blob?file=LICENSE).
-_libmdbx_ has a specific set of properties and capabilities,
-focused on creating unique lightweight solutions.
-
-1. Allows **a swarm of multi-threaded processes to
-[ACID](https://en.wikipedia.org/wiki/ACID)ly read and update** several
-key-value [maps](https://en.wikipedia.org/wiki/Associative_array) and
-[multimaps](https://en.wikipedia.org/wiki/Multimap) in a locally-shared
-database.
-
-2. Provides **extraordinary performance**, minimal overhead through
-[Memory-Mapping](https://en.wikipedia.org/wiki/Memory-mapped_file) and
-`Olog(N)` operations costs by virtue of [B+
-tree](https://en.wikipedia.org/wiki/B%2B_tree).
-
-3. Requires **no maintenance and no crash recovery** since it doesn't use
-[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging), but that might
-be a caveat for write-intensive workloads with durability requirements.
-
-4. **Compact and friendly for fully embedding**. Only ≈25KLOC of `C11`,
-≈64K x86 binary code of core, no internal threads neither server process(es),
-but implements a simplified variant of the [Berkeley
-DB](https://en.wikipedia.org/wiki/Berkeley_DB) and
-[dbm](https://en.wikipedia.org/wiki/DBM_(computing)) API.
-
-5. Enforces [serializability](https://en.wikipedia.org/wiki/Serializability) for
-writers just by single
-[mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) and affords
-[wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom)
-for parallel readers without atomic/interlocked operations, while
-**writing and reading transactions do not block each other**.
-
-6. **Guarantee data integrity** after crash unless this was explicitly
-neglected in favour of write performance.
-
-7. Supports Linux, Windows, MacOS, Android, iOS, FreeBSD, DragonFly, Solaris,
-OpenSolaris, OpenIndiana, NetBSD, OpenBSD and other systems compliant with
-**POSIX.1-2008**.
-
-<!-- section-end -->
-
-Historically, _libmdbx_ is a deeply revised and extended descendant of the amazing
-[Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
-_libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb).
-
-<!-- section-begin mithril -->
-
-The next version is under active non-public development from scratch and will be
-released as **MithrilDB** and `libmithrildb` for libraries & packages.
-Admittedly mythical [Mithril](https://en.wikipedia.org/wiki/Mithril) is
-resembling silver but being stronger and lighter than steel. Therefore
-_MithrilDB_ is a rightly relevant name.
-
-   > _MithrilDB_ will be radically different from _libmdbx_ by the new
-   > database format and API based on C++17, as well as the [Apache 2.0
-   > License](https://www.apache.org/licenses/LICENSE-2.0). The goal of this
-   > revolution is to provide a clearer and robust API, add more features and
-   > new valuable properties of the database.
-
-<!-- section-end -->
-
------
-
-## Table of Contents
-- [Characteristics](#characteristics)
-    - [Features](#features)
-    - [Limitations](#limitations)
-    - [Gotchas](#gotchas)
-    - [Comparison with other databases](#comparison-with-other-databases)
-    - [Improvements beyond LMDB](#improvements-beyond-lmdb)
-    - [History & Acknowledgments](#history)
-- [Usage](#usage)
-    - [Building and Testing](#building-and-testing)
-    - [API description](#api-description)
-    - [Bindings](#bindings)
-- [Performance comparison](#performance-comparison)
-    - [Integral performance](#integral-performance)
-    - [Read scalability](#read-scalability)
-    - [Sync-write mode](#sync-write-mode)
-    - [Lazy-write mode](#lazy-write-mode)
-    - [Async-write mode](#async-write-mode)
-    - [Cost comparison](#cost-comparison)
-
-# Characteristics
-
-<!-- section-begin characteristics -->
-
-## Features
-
-- Key-value data model, keys are always sorted.
-
-- Fully [ACID](https://en.wikipedia.org/wiki/ACID)-compliant, through to
-[MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control)
-and [CoW](https://en.wikipedia.org/wiki/Copy-on-write).
-
-- Multiple key-value sub-databases within a single datafile.
-
-- Range lookups, including range query estimation.
-
-- Efficient support for short fixed length keys, including native 32/64-bit integers.
-
-- Ultra-efficient support for [multimaps](https://en.wikipedia.org/wiki/Multimap). Multi-values sorted, searchable and iterable. Keys stored without duplication.
-
-- Data is [memory-mapped](https://en.wikipedia.org/wiki/Memory-mapped_file) and accessible directly/zero-copy. Traversal of database records is extremely-fast.
-
-- Transactions for readers and writers, ones do not block others.
-
-- Writes are strongly serialized. No transaction conflicts nor deadlocks.
-
-- Readers are [non-blocking](https://en.wikipedia.org/wiki/Non-blocking_algorithm), notwithstanding [snapshot isolation](https://en.wikipedia.org/wiki/Snapshot_isolation).
-
-- Nested write transactions.
-
-- Reads scale linearly across CPUs.
-
-- Continuous zero-overhead database compactification.
-
-- Automatic on-the-fly database size adjustment.
-
-- Customizable database page size.
-
-- `Olog(N)` cost of lookup, insert, update, and delete operations by virtue of [B+ tree characteristics](https://en.wikipedia.org/wiki/B%2B_tree#Characteristics).
-
-- Online hot backup.
-
-- Append operation for efficient bulk insertion of pre-sorted data.
-
-- No [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) nor any
-transaction journal. No crash recovery needed. No maintenance is required.
-
-- No internal cache and/or memory management, all done by basic OS services.
-
-## Limitations
-
-- **Page size**: a power of 2, minimum `256` (mostly for testing), maximum `65536` bytes, default `4096` bytes.
-- **Key size**: minimum `0`, maximum ≈½ pagesize (`2022` bytes for default 4K pagesize, `32742` bytes for 64K pagesize).
-- **Value size**: minimum `0`, maximum `2146435072` (`0x7FF00000`) bytes for maps, ≈½ pagesize for multimaps (`2022` bytes for default 4K pagesize, `32742` bytes for 64K pagesize).
-- **Write transaction size**: up to `1327217884` pages (`4.944272` TiB for default 4K pagesize, `79.108351` TiB for 64K pagesize).
-- **Database size**: up to `2147483648` pages (≈`8.0` TiB for default 4K pagesize, ≈`128.0` TiB for 64K pagesize).
-- **Maximum sub-databases**: `32765`.
-
-## Gotchas
-
-1. There cannot be more than one writer at a time, i.e. no more than one write transaction at a time.
-
-2. _libmdbx_ is based on [B+ tree](https://en.wikipedia.org/wiki/B%2B_tree), so access to database pages is mostly random.
-Thus SSDs provide a significant performance boost over spinning disks for large databases.
-
-3. _libmdbx_ uses [shadow paging](https://en.wikipedia.org/wiki/Shadow_paging) instead of [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging).
-Thus syncing data to disk might be a bottleneck for write intensive workload.
-
-4. _libmdbx_ uses [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write) for [snapshot isolation](https://en.wikipedia.org/wiki/Snapshot_isolation) during updates,
-but read transactions prevents recycling an old retired/freed pages, since it read ones. Thus altering of data during a parallel
-long-lived read operation will increase the process work set, may exhaust entire free database space,
-the database can grow quickly, and result in performance degradation.
-Try to avoid long running read transactions.
-
-5. _libmdbx_ is extraordinarily fast and provides minimal overhead for data access,
-so you should reconsider using brute force techniques and double check your code.
-On the one hand, in the case of _libmdbx_, a simple linear search may be more profitable than complex indexes.
-On the other hand, if you make something suboptimally, you can notice detrimentally only on sufficiently large data.
-
-## Comparison with other databases
-For now please refer to [chapter of "BoltDB comparison with other
-databases"](https://github.com/coreos/bbolt#comparison-with-other-databases)
-which is also (mostly) applicable to _libmdbx_.
-
-<!-- section-end -->
-
-<!-- section-begin improvements -->
-
-Improvements beyond LMDB
-========================
-
-_libmdbx_ is superior to legendary _[LMDB](https://symas.com/lmdb/)_ in
-terms of features and reliability, not inferior in performance. In
-comparison to _LMDB_, _libmdbx_ make things "just work" perfectly and
-out-of-the-box, not silently and catastrophically break down. The list
-below is pruned down to the improvements most notable and obvious from
-the user's point of view.
-
-## Added Features
-
-1. Keys could be more than 2 times longer than _LMDB_.
-
-    > For DB with default page size _libmdbx_ support keys up to 2022 bytes
-    > and up to 32742 bytes for 64K page size. _LMDB_ allows key size up to
-    > 511 bytes and may silently loses data with large values.
-
-2. Up to 30% faster than _LMDB_ in [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) benchmarks.
-
-    > Benchmarks of the in-[tmpfs](https://en.wikipedia.org/wiki/Tmpfs) scenarios,
-    > that tests the speed of the engine itself, showned that _libmdbx_ 10-20% faster than _LMDB_,
-    > and up to 30% faster when _libmdbx_ compiled with specific build options
-    > which downgrades several runtime checks to be match with LMDB behaviour.
-    >
-    > These and other results could be easily reproduced with [ioArena](https://github.com/pmwkaa/ioarena) just by `make bench-quartet` command,
-    > including comparisons with [RockDB](https://en.wikipedia.org/wiki/RocksDB)
-    > and [WiredTiger](https://en.wikipedia.org/wiki/WiredTiger).
-
-3. Automatic on-the-fly database size adjustment, both increment and reduction.
-
-    > _libmdbx_ manages the database size according to parameters specified
-    > by `mdbx_env_set_geometry()` function,
-    > ones include the growth step and the truncation threshold.
-    >
-    > Unfortunately, on-the-fly database size adjustment doesn't work under [Wine](https://en.wikipedia.org/wiki/Wine_(software))
-    > due to its internal limitations and unimplemented functions, i.e. the `MDBX_UNABLE_EXTEND_MAPSIZE` error will be returned.
-
-4. Automatic continuous zero-overhead database compactification.
-
-    > During each commit _libmdbx_ merges a freeing pages which adjacent with the unallocated area
-    > at the end of file, and then truncates unused space when a lot enough of.
-
-5. The same database format for 32- and 64-bit builds.
-
-    > _libmdbx_ database format depends only on the [endianness](https://en.wikipedia.org/wiki/Endianness) but not on the [bitness](https://en.wiktionary.org/wiki/bitness).
-
-6. LIFO policy for Garbage Collection recycling. This can significantly increase write performance due write-back disk cache up to several times in a best case scenario.
-
-    > LIFO means that for reuse will be taken the latest becomes unused pages.
-    > Therefore the loop of database pages circulation becomes as short as possible.
-    > In other words, the set of pages, that are (over)written in memory and on disk during a series of write transactions, will be as small as possible.
-    > Thus creates ideal conditions for the battery-backed or flash-backed disk cache efficiency.
-
-7. Fast estimation of range query result volume, i.e. how many items can
-be found between a `KEY1` and a `KEY2`. This is a prerequisite for build
-and/or optimize query execution plans.
-
-    > _libmdbx_ performs a rough estimate based on common B-tree pages of the paths from root to corresponding keys.
-
-8. `mdbx_chk` utility for database integrity check.
-Since version 0.9.1, the utility supports checking the database using any of the three meta pages and the ability to switch to it.
-
-9. Support for opening databases in the exclusive mode, including on a network share.
-
-10. Zero-length for keys and values.
-
-11. Ability to determine whether the particular data is on a dirty page
-or not, that allows to avoid copy-out before updates.
-
-12. Extended information of whole-database, sub-databases, transactions, readers enumeration.
-
-    > _libmdbx_ provides a lot of information, including dirty and leftover pages
-    > for a write transaction, reading lag and holdover space for read transactions.
-
-13. Extended update and delete operations.
-
-    > _libmdbx_ allows one _at once_ with getting previous value
-    > and addressing the particular item from multi-value with the same key.
-
-14. Useful runtime options for tuning engine to application's requirements and use cases specific.
-
-15. Automated steady sync-to-disk upon several thresholds and/or timeout via cheap polling.
-
-16. Sequence generation and three persistent 64-bit markers.
-
-17. Handle-Slow-Readers callback to resolve a database full/overflow issues due to long-lived read transaction(s).
-
-18. Ability to determine whether the cursor is pointed to a key-value
-pair, to the first, to the last, or not set to anything.
-
-
-## Other fixes and specifics
-
-1. Fixed more than 10 significant errors, in particular: page leaks,
-wrong sub-database statistics, segfault in several conditions,
-nonoptimal page merge strategy, updating an existing record with
-a change in data size (including for multimap), etc.
-
-2. All cursors can be reused and should be closed explicitly,
-regardless ones were opened within a write or read transaction.
-
-3. Opening database handles are spared from race conditions and
-pre-opening is not needed.
-
-4. Returning `MDBX_EMULTIVAL` error in case of ambiguous update or delete.
-
-5. Guarantee of database integrity even in asynchronous unordered write-to-disk mode.
-
-    > _libmdbx_ propose additional trade-off by `MDBX_SAFE_NOSYNC` with append-like manner for updates,
-    > that avoids database corruption after a system crash contrary to LMDB.
-    > Nevertheless, the `MDBX_UTTERLY_NOSYNC` mode is available to match LMDB's behaviour for `MDB_NOSYNC`.
-
-6. On **MacOS & iOS** the `fcntl(F_FULLFSYNC)` syscall is used _by
-default_ to synchronize data with the disk, as this is [the only way to
-guarantee data
-durability](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html)
-in case of power failure. Unfortunately, in scenarios with high write
-intensity, the use of `F_FULLFSYNC` significantly degrades performance
-compared to LMDB, where the `fsync()` syscall is used. Therefore,
-_libmdbx_ allows you to override this behavior by defining the
-`MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` option while build the library.
-
-7. On **Windows** the `LockFileEx()` syscall is used for locking, since
-it allows place the database on network drives, and provides protection
-against incompetent user actions (aka
-[poka-yoke](https://en.wikipedia.org/wiki/Poka-yoke)). Therefore
-_libmdbx_ may be a little lag in performance tests from LMDB where the
-named mutexes are used.
-
-<!-- section-end -->
-<!-- section-begin history -->
-
-# History
-
-Historically, _libmdbx_ is a deeply revised and extended descendant of the
-[Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
-At first the development was carried out within the
-[ReOpenLDAP](todo4recovery://erased_by_github/ReOpenLDAP) project. About a
-year later _libmdbx_ was separated into a standalone project, which was
-[presented at Highload++ 2015
-conference](http://www.highload.ru/2015/abstracts/1831.html).
-
-Since 2017 _libmdbx_ is used in [Fast Positive Tables](https://gitflic.ru/project/erthink/libfpta),
-and development is funded by [Positive Technologies](https://www.ptsecurity.com).
-
-On 2022-04-15 the Github administration, without any warning nor
-explanation, deleted _libmdbx_ along with a lot of other projects,
-simultaneously blocking access for many developers. Therefore on
-2022-04-21 we have migrated to a reliable trusted infrastructure.
-The origin for now is at [GitFlic](https://gitflic.ru/project/erthink/libmdbx)
-with backup at [ABF by ROSA Лаб](https://abf.io/erthink/libmdbx).
-For the same reason ~~Github~~ is blacklisted forever.
-
-## Acknowledgments
-Howard Chu <hyc@openldap.org> is the author of LMDB, from which
-originated the _libmdbx_ in 2015.
-
-Martin Hedenfalk <martin@bzero.se> is the author of `btree.c` code, which
-was used to begin development of LMDB.
-
-<!-- section-end -->
-
---------------------------------------------------------------------------------
-
-Usage
-=====
-
-<!-- section-begin usage -->
-
-Currently, libmdbx is only available in a
-[source code](https://en.wikipedia.org/wiki/Source_code) form.
-Packages support for common Linux distributions is planned in the future,
-since release the version 1.0.
-
-## Source code embedding
-
-_libmdbx_ provides two official ways for integration in source code form:
-
-1. Using the amalgamated source code.
-
-    > The amalgamated source code includes all files required to build and
-    > use _libmdbx_, but not for testing _libmdbx_ itself.
-
-2. Adding the complete original source code as a `git submodule`.
-
-    > This allows you to build as _libmdbx_ and testing tool.
-    >  On the other hand, this way requires you to pull git tags, and use C++11 compiler for test tool.
-
-_**Please, avoid using any other techniques.**_ Otherwise, at least
-don't ask for support and don't name such chimeras `libmdbx`.
-
-The amalgamated source code could be created from the original clone of git
-repository on Linux by executing `make dist`. As a result, the desired
-set of files will be formed in the `dist` subdirectory.
-
-
-## Building and Testing
-
-Both amalgamated and original source code provides build through the use
-[CMake](https://cmake.org/) or [GNU
-Make](https://www.gnu.org/software/make/) with
-[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). All build ways
-are completely traditional and have minimal prerequirements like
-`build-essential`, i.e. the non-obsolete C/C++ compiler and a
-[SDK](https://en.wikipedia.org/wiki/Software_development_kit) for the
-target platform. Obviously you need building tools itself, i.e. `git`,
-`cmake` or GNU `make` with `bash`. For your convenience, `make help`
-and `make options` are also available for listing existing targets
-and build options respectively.
-
-The only significant specificity is that git' tags are required
-to build from complete (not amalgamated) source codes.
-Executing **`git fetch --tags --force --prune`** is enough to get ones,
-and `--unshallow` or `--update-shallow` is required for shallow cloned case.
-
-So just using CMake or GNU Make in your habitual manner and feel free to
-fill an issue or make pull request in the case something will be
-unexpected or broken down.
-
-### Testing
-The amalgamated source code does not contain any tests for or several reasons.
-Please read [the explanation](todo4recovery://erased_by_github/libmdbx/issues/214#issuecomment-870717981) and don't ask to alter this.
-So for testing _libmdbx_ itself you need a full source code, i.e. the clone of a git repository, there is no option.
-
-The full source code of _libmdbx_ has a [`test` subdirectory](https://gitflic.ru/project/erthink/libmdbx/tree/master/test) with minimalistic test "framework".
-Actually yonder is a source code of the `mdbx_test` – console utility which has a set of command-line options that allow construct and run a reasonable enough test scenarios.
-This test utility is intended for _libmdbx_'s developers for testing library itself, but not for use by users.
-Therefore, only basic information is provided:
-
-   - There are few CRUD-based test cases (hill, TTL, nested, append, jitter, etc),
-     which can be combined to test the concurrent operations within shared database in a multi-processes environment.
-     This is the `basic` test scenario.
-   - The `Makefile` provide several self-described targets for testing: `smoke`, `test`, `check`, `memcheck`, `test-valgrind`,
-     `test-asan`, `test-leak`, `test-ubsan`, `cross-gcc`, `cross-qemu`, `gcc-analyzer`, `smoke-fault`, `smoke-singleprocess`,
-     `test-singleprocess`, 'long-test'. Please run `make --help` if doubt.
-   - In addition to the `mdbx_test` utility, there is the script [`long_stochastic.sh`](https://gitflic.ru/project/erthink/libmdbx/blob/master/test/long_stochastic.sh),
-     which calls `mdbx_test` by going through set of modes and options, with gradually increasing the number of operations and the size of transactions.
-     This script is used for mostly of all automatic testing, including `Makefile` targets and Continuous Integration.
-   - Brief information of available command-line options is available by `--help`.
-     However, you should dive into source code to get all, there is no option.
-
-Anyway, no matter how thoroughly the _libmdbx_ is tested, you should rely only on your own tests for a few reasons:
-
-1. Mostly of all use cases are unique.
-   So it is no warranty that your use case was properly tested, even the _libmdbx_'s tests engages stochastic approach.
-2. If there are problems, then your test on the one hand will help to verify whether you are using _libmdbx_ correctly,
-   on the other hand it will allow to reproduce the problem and insure against regression in a future.
-3. Actually you should rely on than you checked by yourself or take a risk.
-
-
-### Common important details
-
-#### Build reproducibility
-By default _libmdbx_ track build time via `MDBX_BUILD_TIMESTAMP` build option and macro.
-So for a [reproducible builds](https://en.wikipedia.org/wiki/Reproducible_builds) you should predefine/override it to known fixed string value.
-For instance:
-
- - for reproducible build with make: `make MDBX_BUILD_TIMESTAMP=unknown ` ...
- - or during configure by CMake: `cmake -DMDBX_BUILD_TIMESTAMP:STRING=unknown ` ...
-
-Of course, in addition to this, your toolchain must ensure the reproducibility of builds.
-For more information please refer to [reproducible-builds.org](https://reproducible-builds.org/).
-
-#### Containers
-There are no special traits nor quirks if you use libmdbx ONLY inside the single container.
-But in a cross-container cases or with a host-container(s) mix the two major things MUST be
-guaranteed:
-
-1. Coherence of memory mapping content and unified page cache inside OS kernel for host and all container(s) operated with a DB.
-Basically this means must be only a single physical copy of each memory mapped DB' page in the system memory.
-
-2. Uniqueness of [PID](https://en.wikipedia.org/wiki/Process_identifier) values and/or a common space for ones:
-    - for POSIX systems: PID uniqueness for all processes operated with a DB.
-      I.e. the `--pid=host` is required for run DB-aware processes inside Docker,
-      either without host interaction a `--pid=container:<name|id>` with the same name/id.
-    - for non-POSIX (i.e. Windows) systems: inter-visibility of processes handles.
-      I.e. the `OpenProcess(SYNCHRONIZE, ..., PID)` must return reasonable error,
-      including `ERROR_ACCESS_DENIED`,
-      but not the `ERROR_INVALID_PARAMETER` as for an invalid/non-existent PID.
-
-#### DSO/DLL unloading and destructors of Thread-Local-Storage objects
-When building _libmdbx_ as a shared library or use static _libmdbx_ as a
-part of another dynamic library, it is advisable to make sure that your
-system ensures the correctness of the call destructors of
-Thread-Local-Storage objects when unloading dynamic libraries.
-
-If this is not the case, then unloading a dynamic-link library with
-_libmdbx_ code inside, can result in either a resource leak or a crash
-due to calling destructors from an already unloaded DSO/DLL object. The
-problem can only manifest in a multithreaded application, which makes
-the unloading of shared dynamic libraries with _libmdbx_ code inside,
-after using _libmdbx_. It is known that TLS-destructors are properly
-maintained in the following cases:
-
-- On all modern versions of Windows (Windows 7 and later).
-
-- On systems with the
-[`__cxa_thread_atexit_impl()`](https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables)
-function in the standard C library, including systems with GNU libc
-version 2.18 and later.
-
-- On systems with libpthread/ntpl from GNU libc with bug fixes
-[#21031](https://sourceware.org/bugzilla/show_bug.cgi?id=21031) and
-[#21032](https://sourceware.org/bugzilla/show_bug.cgi?id=21032), or
-where there are no similar bugs in the pthreads implementation.
-
-### Linux and other platforms with GNU Make
-To build the library it is enough to execute `make all` in the directory
-of source code, and `make check` to execute the basic tests.
-
-If the `make` installed on the system is not GNU Make, there will be a
-lot of errors from make when trying to build. In this case, perhaps you
-should use `gmake` instead of `make`, or even `gnu-make`, etc.
-
-### FreeBSD and related platforms
-As a rule on BSD and it derivatives the default is to use Berkeley Make and
-[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is not installed.
-
-So you need to install the required components: GNU Make, Bash, C and C++
-compilers compatible with GCC or CLANG. After that, to build the
-library, it is enough to execute `gmake all` (or `make all`) in the
-directory with source code, and `gmake check` (or `make check`) to run
-the basic tests.
-
-### Windows
-For build _libmdbx_ on Windows the _original_ CMake and [Microsoft Visual
-Studio 2019](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio) are
-recommended. Please use the recent versions of CMake, Visual Studio and Windows
-SDK to avoid troubles with C11 support and `alignas()` feature.
-
-For build by MinGW the 10.2 or recent version coupled with a modern CMake are required.
-So it is recommended to use [chocolatey](https://chocolatey.org/) to install and/or update the ones.
-
-Another ways to build is potentially possible but not supported and will not.
-The `CMakeLists.txt` or `GNUMakefile` scripts will probably need to be modified accordingly.
-Using other methods do not forget to add the `ntdll.lib` to linking.
-
-It should be noted that in _libmdbx_ was efforts to avoid
-runtime dependencies from CRT and other MSVC libraries.
-For this is enough to pass the `-DMDBX_WITHOUT_MSVC_CRT:BOOL=ON` option
-during configure by CMake.
-
-An example of running a basic test script can be found in the
-[CI-script](appveyor.yml) for [AppVeyor](https://www.appveyor.com/). To
-run the [long stochastic test scenario](test/long_stochastic.sh),
-[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is required, and
-such testing is recommended with placing the test data on the
-[RAM-disk](https://en.wikipedia.org/wiki/RAM_drive).
-
-### Windows Subsystem for Linux
-_libmdbx_ could be used in [WSL2](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux#WSL_2)
-but NOT in [WSL1](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux#WSL_1) environment.
-This is a consequence of the fundamental shortcomings of _WSL1_ and cannot be fixed.
-To avoid data loss, _libmdbx_ returns the `ENOLCK` (37, "No record locks available")
-error when opening the database in a _WSL1_ environment.
-
-### MacOS
-Current [native build tools](https://en.wikipedia.org/wiki/Xcode) for
-MacOS include GNU Make, CLANG and an outdated version of Bash.
-Therefore, to build the library, it is enough to run `make all` in the
-directory with source code, and run `make check` to execute the base
-tests. If something goes wrong, it is recommended to install
-[Homebrew](https://brew.sh/) and try again.
-
-To run the [long stochastic test scenario](test/long_stochastic.sh), you
-will need to install the current (not outdated) version of
-[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). To do this, we
-recommend that you install [Homebrew](https://brew.sh/) and then execute
-`brew install bash`.
-
-### Android
-We recommend using CMake to build _libmdbx_ for Android.
-Please refer to the [official guide](https://developer.android.com/studio/projects/add-native-code).
-
-### iOS
-To build _libmdbx_ for iOS, we recommend using CMake with the
-["toolchain file"](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html)
-from the [ios-cmake](https://github.com/leetal/ios-cmake) project.
-
-<!-- section-end -->
-
-## API description
-
-Please refer to the online [_libmdbx_ API reference](https://libmdbx.website.yandexcloud.net/docs)
-and/or see the [mdbx.h++](mdbx.h%2B%2B) and [mdbx.h](mdbx.h) headers.
-
-<!-- section-begin bindings -->
-
-Bindings
-========
-
-| Runtime |  Repo  | Author |
-| ------- | ------ | ------ |
-| Scala   | [mdbx4s](https://github.com/david-bouyssie/mdbx4s) | [David Bouyssié](https://github.com/david-bouyssie) |
-| Haskell | [libmdbx-hs](https://hackage.haskell.org/package/libmdbx) | [Francisco Vallarino](https://github.com/fjvallarino) |
-| NodeJS, [Deno](https://deno.land/) | [lmdbx-js](https://github.com/kriszyp/lmdbx-js) | [Kris Zyp](https://github.com/kriszyp/)
-| NodeJS  | [node-mdbx](https://www.npmjs.com/package/node-mdbx/) | [Сергей Федотов](mailto:sergey.fedotov@corp.mail.ru) |
-| Ruby    | [ruby-mdbx](https://rubygems.org/gems/mdbx/)          | [Mahlon E. Smith](https://github.com/mahlonsmith) |
-| Go      | [mdbx-go](https://github.com/torquem-ch/mdbx-go)      | [Alex Sharov](https://github.com/AskAlexSharov) |
-| [Nim](https://en.wikipedia.org/wiki/Nim_(programming_language)) | [NimDBX](https://github.com/snej/nimdbx) | [Jens Alfke](https://github.com/snej)
-| Rust    | [libmdbx-rs](https://github.com/vorot93/libmdbx-rs)   | [Artem Vorotnikov](https://github.com/vorot93) |
-| Rust    | [mdbx](https://crates.io/crates/mdbx)                 | [gcxfd](https://github.com/gcxfd) |
-| Java    | [mdbxjni](https://github.com/castortech/mdbxjni)      | [Castor Technologies](https://castortech.com/) |
-| Python (draft)  | [python-bindings](todo4recovery://erased_by_github/libmdbx/commits/python-bindings) branch | [Noel Kuntze](https://github.com/Thermi)
-| .NET (obsolete) | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) |
-
-<!-- section-end -->
-
---------------------------------------------------------------------------------
-
-<!-- section-begin performance -->
-
-Performance comparison
-======================
-
-All benchmarks were done in 2015 by [IOArena](https://github.com/pmwkaa/ioarena)
-and multiple [scripts](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015)
-runs on Lenovo Carbon-2 laptop, i7-4600U 2.1 GHz (2 physical cores, 4 HyperThreading cores), 8 Gb RAM,
-SSD SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Gb.
-
-## Integral performance
-
-Here showed sum of performance metrics in 3 benchmarks:
-
- - Read/Search on the machine with 4 logical CPUs in HyperThreading mode (i.e. actually 2 physical CPU cores);
-
- - Transactions with [CRUD](https://en.wikipedia.org/wiki/CRUD)
- operations in sync-write mode (fdatasync is called after each
- transaction);
-
- - Transactions with [CRUD](https://en.wikipedia.org/wiki/CRUD)
- operations in lazy-write mode (moment to sync data to persistent storage
- is decided by OS).
-
-*Reasons why asynchronous mode isn't benchmarked here:*
-
-  1. It doesn't make sense as it has to be done with DB engines, oriented
-  for keeping data in memory e.g. [Tarantool](https://tarantool.io/),
-  [Redis](https://redis.io/)), etc.
-
-  2. Performance gap is too high to compare in any meaningful way.
-
-![Comparison #1: Integral Performance](https://libmdbx.website.yandexcloud.net/img/perf-slide-1.png)
-
---------------------------------------------------------------------------------
-
-## Read Scalability
-
-Summary performance with concurrent read/search queries in 1-2-4-8
-threads on the machine with 4 logical CPUs in HyperThreading mode (i.e. actually 2 physical CPU cores).
-
-![Comparison #2: Read Scalability](https://libmdbx.website.yandexcloud.net/img/perf-slide-2.png)
-
---------------------------------------------------------------------------------
-
-## Sync-write mode
-
- - Linear scale on left and dark rectangles mean arithmetic mean
- transactions per second;
-
- - Logarithmic scale on right is in seconds and yellow intervals mean
- execution time of transactions. Each interval shows minimal and maximum
- execution time, cross marks standard deviation.
-
-**10,000 transactions in sync-write mode**. In case of a crash all data
-is consistent and conforms to the last successful transaction. The
-[fdatasync](https://linux.die.net/man/2/fdatasync) syscall is used after
-each write transaction in this mode.
-
-In the benchmark each transaction contains combined CRUD operations (2
-inserts, 1 read, 1 update, 1 delete). Benchmark starts on an empty database
-and after full run the database contains 10,000 small key-value records.
-
-![Comparison #3: Sync-write mode](https://libmdbx.website.yandexcloud.net/img/perf-slide-3.png)
-
---------------------------------------------------------------------------------
-
-## Lazy-write mode
-
- - Linear scale on left and dark rectangles mean arithmetic mean of
- thousands transactions per second;
-
- - Logarithmic scale on right in seconds and yellow intervals mean
- execution time of transactions. Each interval shows minimal and maximum
- execution time, cross marks standard deviation.
-
-**100,000 transactions in lazy-write mode**. In case of a crash all data
-is consistent and conforms to the one of last successful transactions, but
-transactions after it will be lost. Other DB engines use
-[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) or transaction
-journal for that, which in turn depends on order of operations in the
-journaled filesystem. _libmdbx_ doesn't use WAL and hands I/O operations
-to filesystem and OS kernel (mmap).
-
-In the benchmark each transaction contains combined CRUD operations (2
-inserts, 1 read, 1 update, 1 delete). Benchmark starts on an empty database
-and after full run the database contains 100,000 small key-value
-records.
-
-
-![Comparison #4: Lazy-write mode](https://libmdbx.website.yandexcloud.net/img/perf-slide-4.png)
-
---------------------------------------------------------------------------------
-
-## Async-write mode
-
- - Linear scale on left and dark rectangles mean arithmetic mean of
- thousands transactions per second;
-
- - Logarithmic scale on right in seconds and yellow intervals mean
- execution time of transactions. Each interval shows minimal and maximum
- execution time, cross marks standard deviation.
-
-**1,000,000 transactions in async-write mode**.
-In case of a crash all data is consistent and conforms to the one of last successful transactions,
-but lost transaction count is much higher than in
-lazy-write mode. All DB engines in this mode do as little writes as
-possible on persistent storage. _libmdbx_ uses
-[msync(MS_ASYNC)](https://linux.die.net/man/2/msync) in this mode.
-
-In the benchmark each transaction contains combined CRUD operations (2
-inserts, 1 read, 1 update, 1 delete). Benchmark starts on an empty database
-and after full run the database contains 10,000 small key-value records.
-
-![Comparison #5: Async-write mode](https://libmdbx.website.yandexcloud.net/img/perf-slide-5.png)
-
---------------------------------------------------------------------------------
-
-## Cost comparison
-
-Summary of used resources during lazy-write mode benchmarks:
-
- - Read and write IOPs;
-
- - Sum of user CPU time and sys CPU time;
-
- - Used space on persistent storage after the test and closed DB, but not
- waiting for the end of all internal housekeeping operations (LSM
- compactification, etc).
-
-_ForestDB_ is excluded because benchmark showed it's resource
-consumption for each resource (CPU, IOPs) much higher than other engines
-which prevents to meaningfully compare it with them.
-
-All benchmark data is gathered by
-[getrusage()](http://man7.org/linux/man-pages/man2/getrusage.2.html)
-syscall and by scanning the data directory.
-
-![Comparison #6: Cost comparison](https://libmdbx.website.yandexcloud.net/img/perf-slide-6.png)
-
-<!-- section-end -->
diff --git a/3rdparty/libmdbx/VERSION.txt b/3rdparty/libmdbx/VERSION.txt
deleted file mode 100644
index a9da9632c3d3a984f84670e0e4d1458e18896c49..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/VERSION.txt
+++ /dev/null
@@ -1 +0,0 @@
-0.11.7.0
diff --git a/3rdparty/libmdbx/cmake/compiler.cmake b/3rdparty/libmdbx/cmake/compiler.cmake
deleted file mode 100644
index 17c468b7395273f43a5bfd8e413ad1329fb3aa80..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/cmake/compiler.cmake
+++ /dev/null
@@ -1,1023 +0,0 @@
-##  Copyright (c) 2012-2022 Leonid Yuriev <leo@yuriev.ru>.
-##
-##  Licensed under the Apache License, Version 2.0 (the "License");
-##  you may not use this file except in compliance with the License.
-##  You may obtain a copy of the License at
-##
-##      http://www.apache.org/licenses/LICENSE-2.0
-##
-##  Unless required by applicable law or agreed to in writing, software
-##  distributed under the License is distributed on an "AS IS" BASIS,
-##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-##  See the License for the specific language governing permissions and
-##  limitations under the License.
-##
-
-if(CMAKE_VERSION VERSION_LESS 3.12)
-  cmake_minimum_required(VERSION 3.8.2)
-else()
-  cmake_minimum_required(VERSION 3.12)
-endif()
-
-cmake_policy(PUSH)
-cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
-
-if(CMAKE_VERSION MATCHES ".*MSVC.*" AND CMAKE_VERSION VERSION_LESS 3.16)
-  message(FATAL_ERROR "CMake from MSVC kit is unfit! "
-    "Please use MSVC2019 with modern CMake the original CMake from https://cmake.org/download/")
-endif()
-
-if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED))
-  message(FATAL_ERROR "This module required C or C++ to be enabled")
-endif()
-
-if(CMAKE_CXX_COMPILER_LOADED)
-  include(CheckCXXSourceRuns)
-  include(CheckCXXSourceCompiles)
-  include(CheckCXXCompilerFlag)
-endif()
-if(CMAKE_C_COMPILER_LOADED)
-  include(CheckCSourceRuns)
-  include(CheckCSourceCompiles)
-  include(CheckCCompilerFlag)
-endif()
-include(CMakeDependentOption)
-include(CheckLibraryExists)
-include(CheckIncludeFiles)
-
-# Check if the same compile family is used for both C and CXX
-if(CMAKE_C_COMPILER_LOADED AND CMAKE_CXX_COMPILER_LOADED AND
-    NOT (CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID))
-  message(WARNING "CMAKE_C_COMPILER_ID (${CMAKE_C_COMPILER_ID}) is different "
-    "from CMAKE_CXX_COMPILER_ID (${CMAKE_CXX_COMPILER_ID}). "
-    "The final binary may be unusable.")
-endif()
-
-if(CMAKE_CXX_COMPILER_LOADED)
-  set(CMAKE_PRIMARY_LANG "CXX")
-else()
-  set(CMAKE_PRIMARY_LANG "C")
-endif()
-
-macro(check_compiler_flag flag variable)
-  if(CMAKE_CXX_COMPILER_LOADED)
-    check_cxx_compiler_flag(${flag} ${variable})
-  else()
-    check_c_compiler_flag(${flag} ${variable})
-  endif()
-endmacro(check_compiler_flag)
-
-# We support building with Clang and gcc. First check
-# what we're using for build.
-if(CMAKE_C_COMPILER_LOADED AND CMAKE_C_COMPILER_ID MATCHES ".*[Cc][Ll][Aa][Nn][Gg].*")
-  set(CMAKE_COMPILER_IS_CLANG  ON)
-  set(CMAKE_COMPILER_IS_GNUCC  OFF)
-endif()
-if(CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXX_COMPILER_ID MATCHES ".*[Cc][Ll][Aa][Nn][Gg].*")
-  set(CMAKE_COMPILER_IS_CLANG  ON)
-  set(CMAKE_COMPILER_IS_GNUCXX OFF)
-endif()
-
-if(CMAKE_C_COMPILER_LOADED)
-  # Check for Elbrus lcc
-  execute_process(COMMAND ${CMAKE_C_COMPILER} --version
-    OUTPUT_VARIABLE tmp_lcc_probe_version
-    RESULT_VARIABLE tmp_lcc_probe_result ERROR_QUIET)
-  if(tmp_lcc_probe_result EQUAL 0)
-    string(FIND "${tmp_lcc_probe_version}" "lcc:" tmp_lcc_marker)
-    string(FIND "${tmp_lcc_probe_version}" ":e2k-" tmp_e2k_marker)
-    if(tmp_lcc_marker GREATER -1 AND tmp_e2k_marker GREATER tmp_lcc_marker)
-      execute_process(COMMAND ${CMAKE_C_COMPILER} -print-version
-        OUTPUT_VARIABLE CMAKE_C_COMPILER_VERSION
-        RESULT_VARIABLE tmp_lcc_probe_result
-        OUTPUT_STRIP_TRAILING_WHITESPACE)
-      set(CMAKE_COMPILER_IS_ELBRUSC ON)
-      set(CMAKE_C_COMPILER_ID "Elbrus")
-      message(STATUS "Detected Elbrus C compiler ${CMAKE_C_COMPILER_VERSION}")
-    else()
-      set(CMAKE_COMPILER_IS_ELBRUSC OFF)
-    endif()
-    unset(tmp_lcc_marker)
-    unset(tmp_e2k_marker)
-  endif()
-  unset(tmp_lcc_probe_version)
-  unset(tmp_lcc_probe_result)
-endif()
-
-if(CMAKE_CXX_COMPILER_LOADED)
-  # Check for Elbrus l++
-  execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version
-    OUTPUT_VARIABLE tmp_lxx_probe_version
-    RESULT_VARIABLE tmp_lxx_probe_result ERROR_QUIET)
-  if(tmp_lxx_probe_result EQUAL 0)
-    string(FIND "${tmp_lxx_probe_version}" "lcc:" tmp_lcc_marker)
-    string(FIND "${tmp_lxx_probe_version}" ":e2k-" tmp_e2k_marker)
-    if(tmp_lcc_marker GREATER -1 AND tmp_e2k_marker GREATER tmp_lcc_marker)
-      execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-version
-        OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION
-        RESULT_VARIABLE tmp_lxx_probe_result
-        OUTPUT_STRIP_TRAILING_WHITESPACE)
-      set(CMAKE_COMPILER_IS_ELBRUSCXX ON)
-      set(CMAKE_CXX_COMPILER_ID "Elbrus")
-      message(STATUS "Detected Elbrus C++ compiler ${CMAKE_CXX_COMPILER_VERSION}")
-    else()
-      set(CMAKE_COMPILER_IS_ELBRUSCXX OFF)
-    endif()
-    unset(tmp_lcc_marker)
-    unset(tmp_e2k_marker)
-  endif()
-  unset(tmp_lxx_probe_version)
-  unset(tmp_lxx_probe_result)
-endif()
-
-# Hard coding the compiler version is ugly from cmake POV, but
-# at least gives user a friendly error message. The most critical
-# demand for C++ compiler is support of C++11 lambdas, added
-# only in version 4.5 https://gcc.gnu.org/projects/cxx0x.html
-if(CMAKE_COMPILER_IS_GNUCC)
-  if(CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5
-      AND NOT CMAKE_COMPILER_IS_ELBRUSC)
-    message(FATAL_ERROR "
-      Your GCC version is ${CMAKE_C_COMPILER_VERSION}, please update")
-  endif()
-endif()
-if(CMAKE_COMPILER_IS_GNUCXX)
-  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5
-      AND NOT CMAKE_COMPILER_IS_ELBRUSCXX)
-    message(FATAL_ERROR "
-      Your G++ version is ${CMAKE_CXX_COMPILER_VERSION}, please update")
-  endif()
-endif()
-
-if(CMAKE_CL_64)
-  set(MSVC64 1)
-endif()
-if(WIN32 AND CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG})
-  execute_process(COMMAND ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} -dumpmachine
-    OUTPUT_VARIABLE __GCC_TARGET_MACHINE
-    OUTPUT_STRIP_TRAILING_WHITESPACE)
-  if(__GCC_TARGET_MACHINE MATCHES "amd64|x86_64|AMD64")
-    set(MINGW64 1)
-  endif()
-  unset(__GCC_TARGET_MACHINE)
-endif()
-
-if(NOT DEFINED IOS)
-  if(APPLE AND (CMAKE_SYSTEM_NAME STREQUAL "iOS"
-      OR DEFINED CMAKE_IOS_DEVELOPER_ROOT
-      OR DEFINED IOS_PLATFORM OR DEFINED IOS_ARCH))
-    set(IOS TRUE)
-  else()
-    set(IOS FALSE)
-  endif()
-endif()
-
-if(NOT DEFINED CMAKE_TARGET_BITNESS)
-  if (CMAKE_SIZEOF_VOID_P LESS 4)
-    set(CMAKE_TARGET_BITNESS 16)
-  elseif (CMAKE_SIZEOF_VOID_P LESS 8)
-    set(CMAKE_TARGET_BITNESS 32)
-  else()
-    set(CMAKE_TARGET_BITNESS 64)
-  endif()
-endif()
-
-if(NOT CMAKE_SYSTEM_ARCH)
-  if(CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ARCHITECTURE_ID)
-    set(CMAKE_SYSTEM_ARCH "${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ARCHITECTURE_ID}")
-  elseif(CMAKE_ANDROID_ARCH_ABI)
-    set(CMAKE_SYSTEM_ARCH "${CMAKE_ANDROID_ARCH_ABI}")
-  elseif(CMAKE_COMPILER_IS_ELBRUSC OR CMAKE_COMPILER_IS_ELBRUSCXX
-      OR CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ID STREQUAL "LCC"
-      OR CMAKE_SYSTEM_PROCESSOR MATCHES "e2k.*|E2K.*|elbrus.*|ELBRUS.*")
-    set(E2K TRUE)
-    set(CMAKE_SYSTEM_ARCH "Elbrus")
-  elseif(MSVC64 OR MINGW64 OR MINGW OR (MSVC AND NOT CMAKE_CROSSCOMPILING))
-    if(CMAKE_TARGET_BITNESS EQUAL 64)
-      set(X86_64 TRUE)
-      set(CMAKE_SYSTEM_ARCH "x86_64")
-    else()
-      set(X86_32 TRUE)
-      set(CMAKE_SYSTEM_ARCH "x86")
-    endif()
-  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|[xXiI]86_64.*|AMD64.*|[iI][3-6]86.*|[xXiI]86.*")
-    if(CMAKE_TARGET_BITNESS EQUAL 64)
-      set(X86_64 TRUE)
-      set(CMAKE_SYSTEM_ARCH "x86_64")
-    else()
-      set(X86_32 TRUE)
-      set(CMAKE_SYSTEM_ARCH "x86")
-    endif()
-  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch.*|AARCH.*|arm.*|ARM.*)")
-    if(CMAKE_TARGET_BITNESS EQUAL 64)
-      set(AARCH64 TRUE)
-      set(CMAKE_SYSTEM_ARCH "ARM64")
-    else()
-      set(ARM32 TRUE)
-      set(CMAKE_SYSTEM_ARCH "ARM")
-    endif()
-  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc).*")
-    if(CMAKE_TARGET_BITNESS EQUAL 64)
-      set(PPC64 TRUE)
-      set(CMAKE_SYSTEM_ARCH "PPC64")
-    else()
-      set(PPC32 TRUE)
-      set(CMAKE_SYSTEM_ARCH "PPC")
-    endif()
-  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(mips|MIPS).*")
-    if(CMAKE_TARGET_BITNESS EQUAL 64)
-      set(MIPS64 TRUE)
-      set(CMAKE_SYSTEM_ARCH "MIPS64")
-    else()
-      set(MIPS32 TRUE)
-      set(CMAKE_SYSTEM_ARCH "MIPS")
-    endif()
-  endif()
-endif()
-if(CMAKE_C_COMPILER_LOADED AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID)
-  set(CMAKE_C_COMPILER_ARCHITECTURE_ID "${CMAKE_SYSTEM_ARCH}")
-endif()
-if(CMAKE_CXX_COMPILER_LOADED AND NOT CMAKE_CXX_COMPILER_ARCHITECTURE_ID)
-  set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID "${CMAKE_SYSTEM_ARCH}")
-endif()
-
-if(NOT CMAKE_HOST_ARCH)
-  if(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE)
-    set(CMAKE_HOST_ARCH "${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "e2k.*|E2K.*|elbrus.*|ELBRUS.*")
-    set(CMAKE_HOST_ARCH "Elbrus")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "amd64.*|[xXiI]86_64.*|AMD64.*")
-    set(CMAKE_HOST_ARCH "x86_64")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "[iI][3-6]86.*|[xXiI]86.*")
-    set(CMAKE_HOST_ARCH "x86")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|ARM64.*)")
-    set(CMAKE_HOST_ARCH "ARM64")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "^(arm.*|ARM.*)")
-    set(CMAKE_HOST_ARCH "ARM")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "^(powerpc|ppc)64.*")
-    set(CMAKE_HOST_ARCH "PPC64")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "^(powerpc|ppc).*")
-    set(CMAKE_HOST_ARCH "PPC")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "^(mips|MIPS)64.*")
-    set(CMAKE_HOST_ARCH "MIPS64")
-  elseif(CMAKE_HOST_PROCESSOR MATCHES "^(mips|MIPS).*")
-    set(CMAKE_HOST_ARCH "MIPS")
-  else()
-    set(CMAKE_HOST_ARCH "${CMAKE_HOST_SYSTEM_PROCESSOR}")
-  endif()
-endif()
-
-if(NOT DEFINED CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET)
-  if(CMAKE_CROSSCOMPILING AND CMAKE_CROSSCOMPILING_EMULATOR)
-    set(CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET TRUE)
-  elseif(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR)
-    set(CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET FALSE)
-  elseif(CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME
-      AND ((CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_PROCESSOR)
-      OR (CMAKE_SYSTEM_ARCH STREQUAL CMAKE_HOST_ARCH)
-      OR (WIN32 AND CMAKE_HOST_WIN32 AND X86_32 AND CMAKE_HOST_ARCH STREQUAL "x86_64")))
-    set(CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET TRUE)
-    message(STATUS
-      "Assume СAN RUN A BUILT EXECUTABLES,"
-      " since host (${CMAKE_HOST_SYSTEM_NAME}-${CMAKE_HOST_ARCH})"
-      " match target (${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_ARCH})")
-  else()
-    if(CMAKE_C_COMPILER_LOADED)
-      include(CheckCSourceRuns)
-      check_c_source_runs("int main(void) { return 0; }" CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET)
-    elseif(CMAKE_CXX_COMPILER_LOADED)
-      include(CheckCXXSourceRuns)
-      check_cxx_source_runs("int main(void) { return 0; }" CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET)
-    endif()
-    if(NOT CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET)
-      message(STATUS "Force CMAKE_CROSSCOMPILING to TRUE")
-      set(CMAKE_CROSSCOMPILING TRUE)
-    endif()
-  endif()
-endif()
-
-if(MSVC)
-  check_compiler_flag("/WX" CC_HAS_WERROR)
-else()
-  #
-  # GCC started to warn for unused result starting from 4.2, and
-  # this is when it introduced -Wno-unused-result
-  # GCC can also be built on top of llvm runtime (on mac).
-  check_compiler_flag("-Wno-unknown-pragmas" CC_HAS_WNO_UNKNOWN_PRAGMAS)
-  check_compiler_flag("-Wextra" CC_HAS_WEXTRA)
-  check_compiler_flag("-Werror" CC_HAS_WERROR)
-  check_compiler_flag("-fexceptions" CC_HAS_FEXCEPTIONS)
-  check_compiler_flag("-fno-semantic-interposition" CC_HAS_FNO_SEMANTIC_INTERPOSITION)
-  if(CMAKE_CXX_COMPILER_LOADED)
-    check_cxx_compiler_flag("-fcxx-exceptions" CC_HAS_FCXX_EXCEPTIONS)
-  endif()
-  check_compiler_flag("-funwind-tables" CC_HAS_FUNWIND_TABLES)
-  check_compiler_flag("-fno-omit-frame-pointer" CC_HAS_FNO_OMIT_FRAME_POINTER)
-  check_compiler_flag("-fno-common" CC_HAS_FNO_COMMON)
-  check_compiler_flag("-ggdb" CC_HAS_GGDB)
-  check_compiler_flag("-fvisibility=hidden" CC_HAS_VISIBILITY)
-  check_compiler_flag("-march=native" CC_HAS_ARCH_NATIVE)
-  check_compiler_flag("-Og" CC_HAS_DEBUG_FRIENDLY_OPTIMIZATION)
-  check_compiler_flag("-Wall" CC_HAS_WALL)
-  check_compiler_flag("-Ominimal" CC_HAS_OMINIMAL)
-  check_compiler_flag("-ffunction-sections -fdata-sections" CC_HAS_SECTIONS)
-  check_compiler_flag("-ffast-math" CC_HAS_FASTMATH)
-  check_compiler_flag("-Wno-attributes" CC_HAS_WNO_ATTRIBUTES)
-
-  # Check for an omp support
-  set(CMAKE_REQUIRED_FLAGS "-fopenmp -Werror")
-  if(CMAKE_CXX_COMPILER_LOADED)
-    check_cxx_source_compiles("int main(void) {
-      #pragma omp parallel
-      return 0;
-      }" HAVE_OPENMP)
-  else()
-    check_c_source_compiles("int main(void) {
-      #pragma omp parallel
-      return 0;
-      }" HAVE_OPENMP)
-  endif()
-  set(CMAKE_REQUIRED_FLAGS "")
-endif()
-
-# Crutch for old C++ compilers and/or CMake to enabling C++11
-if(CMAKE_CXX_COMPILER_LOADED)
-  list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11)
-  if(HAS_CXX11 LESS 0)
-    check_cxx_compiler_flag("-std=gnu++11" CXX_FALLBACK_GNU11)
-    if(NOT CXX_FALLBACK_GNU11)
-      check_cxx_compiler_flag("-std=c++11" CXX_FALLBACK_11)
-    endif()
-  endif()
-endif()
-
-# Crutch for mad C compilers and/or CMake to enabling C11
-if(CMAKE_C_COMPILER_LOADED)
-  list(FIND CMAKE_C_COMPILE_FEATURES c_std_11 HAS_C11)
-  if(HAS_C11 LESS 0)
-    if (MSVC)
-      check_c_compiler_flag("/std:c11" C_FALLBACK_11)
-    else()
-      check_c_compiler_flag("-std=gnu11" C_FALLBACK_GNU11)
-      if(NOT C_FALLBACK_GNU11)
-        check_c_compiler_flag("-std=c11" C_FALLBACK_11)
-      endif()
-    endif()
-  endif()
-endif()
-
-# Check for LTO support by GCC
-if(CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG} AND NOT CMAKE_COMPILER_IS_ELBRUSC AND NOT CMAKE_COMPILER_IS_ELBRUSCXX)
-  unset(gcc_collect)
-  unset(gcc_lto_wrapper)
-
-  if(NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 4.7)
-    execute_process(COMMAND ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} -v
-      OUTPUT_VARIABLE gcc_info_v ERROR_VARIABLE gcc_info_v)
-
-    string(REGEX MATCH "^(.+\nCOLLECT_GCC=)([^ \n]+)(\n.+)$" gcc_collect_valid ${gcc_info_v})
-    if(gcc_collect_valid)
-      string(REGEX REPLACE "^(.+\nCOLLECT_GCC=)([^ \n]+)(\n.+)$" "\\2" gcc_collect ${gcc_info_v})
-    endif()
-
-    string(REGEX MATCH "^(.+\nCOLLECT_LTO_WRAPPER=)([^ \n]+/lto-wrapper)(\n.+)$" gcc_lto_wrapper_valid ${gcc_info_v})
-    if(gcc_lto_wrapper_valid)
-      string(REGEX REPLACE "^(.+\nCOLLECT_LTO_WRAPPER=)([^ \n]+/lto-wrapper)(\n.+)$" "\\2" gcc_lto_wrapper ${gcc_info_v})
-    endif()
-
-    set(gcc_suffix "")
-    if(gcc_collect_valid AND gcc_collect)
-      string(REGEX MATCH "^(.*(cc|\\+\\+))(-.+)$" gcc_suffix_valid ${gcc_collect})
-      if(gcc_suffix_valid)
-        string(REGEX REPLACE "^(.*(cc|\\+\\+))(-.+)$" "\\3" gcc_suffix ${gcc_collect})
-      endif()
-    endif()
-
-    get_filename_component(gcc_dir ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} DIRECTORY)
-    if(NOT CMAKE_GCC_AR)
-      find_program(CMAKE_GCC_AR NAMES "gcc${gcc_suffix}-ar" "gcc-ar${gcc_suffix}" PATHS "${gcc_dir}" NO_DEFAULT_PATH)
-    endif()
-    if(NOT CMAKE_GCC_NM)
-      find_program(CMAKE_GCC_NM NAMES "gcc${gcc_suffix}-nm" "gcc-nm${gcc_suffix}" PATHS "${gcc_dir}" NO_DEFAULT_PATH)
-    endif()
-    if(NOT CMAKE_GCC_RANLIB)
-      find_program(CMAKE_GCC_RANLIB NAMES "gcc${gcc_suffix}-ranlib" "gcc-ranlib${gcc_suffix}" PATHS "${gcc_dir}" NO_DEFAULT_PATH)
-    endif()
-
-    unset(gcc_dir)
-    unset(gcc_suffix_valid)
-    unset(gcc_suffix)
-    unset(gcc_lto_wrapper_valid)
-    unset(gcc_collect_valid)
-    unset(gcc_collect)
-    unset(gcc_info_v)
-  endif()
-
-  if(CMAKE_GCC_AR AND CMAKE_GCC_NM AND CMAKE_GCC_RANLIB AND gcc_lto_wrapper)
-    message(STATUS "Found GCC's LTO toolset: ${gcc_lto_wrapper}, ${CMAKE_GCC_AR}, ${CMAKE_GCC_RANLIB}")
-    set(GCC_LTO_CFLAGS "-flto -fno-fat-lto-objects -fuse-linker-plugin")
-    set(GCC_LTO_AVAILABLE TRUE)
-    message(STATUS "Link-Time Optimization by GCC is available")
-  else()
-    set(GCC_LTO_AVAILABLE FALSE)
-    message(STATUS "Link-Time Optimization by GCC is NOT available")
-  endif()
-  unset(gcc_lto_wrapper)
-endif()
-
-# check for LTO by MSVC
-if(MSVC AND NOT CMAKE_COMPILER_IS_CLANG)
-  if(NOT MSVC_VERSION LESS 1600)
-    set(MSVC_LTO_AVAILABLE TRUE)
-    message(STATUS "Link-Time Optimization by MSVC is available")
-  else()
-    set(MSVC_LTO_AVAILABLE FALSE)
-    message(STATUS "Link-Time Optimization by MSVC is NOT available")
-  endif()
-endif()
-
-# Check for LTO support by CLANG
-if(CMAKE_COMPILER_IS_CLANG)
-  if(NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 3.5)
-    execute_process(COMMAND ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} -print-search-dirs
-      OUTPUT_VARIABLE clang_search_dirs RESULT_VARIABLE clang_probe_result ERROR_QUIET)
-
-    unset(clang_bindirs)
-    unset(clang_bindirs_x)
-    unset(clang_libdirs)
-    unset(clang_libdirs_x)
-    if(clang_probe_result EQUAL 0)
-      string(REGEX MATCH "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" regexp_valid ${clang_search_dirs})
-      if(regexp_valid)
-        string(REGEX REPLACE "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs})
-        string(REPLACE ":" ";" list "${list}")
-        foreach(dir IN LISTS list)
-          get_filename_component(dir "${dir}" REALPATH)
-          if(dir MATCHES ".*llvm.*" OR dir MATCHES ".*clang.*")
-            list(APPEND clang_bindirs "${dir}")
-          else()
-            list(APPEND clang_bindirs_x "${dir}")
-          endif()
-        endforeach()
-        list(APPEND clang_bindirs "${clang_bindirs_x}")
-        list(REMOVE_DUPLICATES clang_bindirs)
-      endif()
-      string(REGEX MATCH "(^|\n.*)(.*libraries: =)([^\n]+)((\n.*)|$)" regexp_valid ${clang_search_dirs})
-      if(regexp_valid)
-        string(REGEX REPLACE "(^|\n.*)(.*libraries: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs})
-        string(REPLACE ":" ";" list "${list}")
-        foreach(dir IN LISTS list)
-          get_filename_component(dir "${dir}" REALPATH)
-          if(dir MATCHES ".*llvm.*" OR dir MATCHES ".*clang.*")
-            list(APPEND clang_libdirs "${dir}")
-          else()
-            list(APPEND clang_libdirs_x "${dir}")
-          endif()
-        endforeach()
-        list(APPEND clang_libdirs "${clang_libdirs_x}")
-        list(REMOVE_DUPLICATES clang_libdirs)
-      endif()
-    else()
-      get_filename_component(clang_bindirs ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} DIRECTORY)
-      if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
-        set(clang_libdirs ${clang_bindirs})
-      else()
-        get_filename_component(clang_libdirs "${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER}/../lib" REALPATH)
-      endif()
-    endif()
-
-    if(clang_bindirs AND clang_libdirs)
-      message(STATUS "Found CLANG/LLVM directories: ${clang_bindirs}, ${clang_libdirs}")
-    else()
-      message(STATUS "Could NOT find CLANG/LLVM directories (bin and/or lib).")
-    endif()
-
-    if(NOT CMAKE_CLANG_LD AND clang_bindirs)
-      find_program(CMAKE_CLANG_LD NAMES lld-link ld.lld "ld${CMAKE_TARGET_BITNESS}.lld" lld llvm-link llvm-ld PATHS ${clang_bindirs} NO_DEFAULT_PATH)
-    endif()
-    if(NOT CMAKE_CLANG_AR AND clang_bindirs)
-      find_program(CMAKE_CLANG_AR NAMES llvm-ar ar PATHS ${clang_bindirs} NO_DEFAULT_PATH)
-    endif()
-    if(NOT CMAKE_CLANG_NM AND clang_bindirs)
-      find_program(CMAKE_CLANG_NM NAMES llvm-nm nm PATHS ${clang_bindirs} NO_DEFAULT_PATH)
-    endif()
-    if(NOT CMAKE_CLANG_RANLIB AND clang_bindirs)
-      find_program(CMAKE_CLANG_RANLIB NAMES llvm-ranlib ranlib PATHS ${clang_bindirs} NO_DEFAULT_PATH)
-    endif()
-
-    set(clang_lto_plugin_name "LLVMgold${CMAKE_SHARED_LIBRARY_SUFFIX}")
-    if(NOT CMAKE_LD_GOLD AND clang_bindirs)
-      find_program(CMAKE_LD_GOLD NAMES ld.gold PATHS ${clang_bindirs})
-    endif()
-    if(NOT CLANG_LTO_PLUGIN AND clang_libdirs)
-      find_file(CLANG_LTO_PLUGIN ${clang_lto_plugin_name} PATHS ${clang_libdirs} NO_DEFAULT_PATH)
-    endif()
-
-    if(CLANG_LTO_PLUGIN)
-      message(STATUS "Found CLANG/LLVM's plugin for LTO: ${CLANG_LTO_PLUGIN}")
-    else()
-      message(STATUS "Could NOT find CLANG/LLVM's plugin (${clang_lto_plugin_name}) for LTO.")
-    endif()
-
-    if(CMAKE_CLANG_LD)
-      message(STATUS "Found CLANG/LLVM's linker for LTO: ${CMAKE_CLANG_LD}")
-    else()
-      message(STATUS "Could NOT find CLANG/LLVM's linker (lld, llvm-ld, llvm-link) for LTO.")
-    endif()
-
-    if(CMAKE_CLANG_AR AND CMAKE_CLANG_RANLIB AND CMAKE_CLANG_NM)
-      message(STATUS "Found CLANG/LLVM's binutils for LTO: ${CMAKE_CLANG_AR}, ${CMAKE_CLANG_RANLIB}, ${CMAKE_CLANG_NM}")
-    else()
-      message(STATUS "Could NOT find CLANG/LLVM's binutils (ar, ranlib, nm) for LTO.")
-    endif()
-
-    unset(clang_lto_plugin_name)
-    unset(clang_libdir)
-    unset(clang_bindir_valid)
-    unset(clang_bindir)
-    unset(clang_search_dirs)
-  endif()
-
-  if(CMAKE_CLANG_AR AND CMAKE_CLANG_NM AND CMAKE_CLANG_RANLIB
-      AND ((CLANG_LTO_PLUGIN AND CMAKE_LD_GOLD)
-        OR (CMAKE_CLANG_LD
-          AND NOT (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"
-            AND CMAKE_SYSTEM_NAME STREQUAL "Linux"))
-        OR APPLE))
-    if(ANDROID AND CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 12)
-      set(CLANG_LTO_AVAILABLE FALSE)
-      message(STATUS "Link-Time Optimization by CLANG/LLVM is available but unusable due https://reviews.llvm.org/D79919")
-    else()
-      set(CLANG_LTO_AVAILABLE TRUE)
-      message(STATUS "Link-Time Optimization by CLANG/LLVM is available")
-    endif()
-  elseif(CMAKE_TOOLCHAIN_FILE AND NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 7.0)
-    set(CLANG_LTO_AVAILABLE TRUE)
-    if(NOT CMAKE_CLANG_LD)
-      set(CMAKE_CLANG_LD ${CMAKE_LINKER})
-    endif()
-    if(NOT CMAKE_CLANG_AR)
-      set(CMAKE_CLANG_AR ${CMAKE_AR})
-    endif()
-    if(NOT CMAKE_CLANG_NM)
-      set(CMAKE_CLANG_NM ${CMAKE_NM})
-    endif()
-    if(NOT CMAKE_CLANG_RANLIB)
-      set(CMAKE_CLANG_RANLIB ${CMAKE_RANLIB})
-    endif()
-    message(STATUS "Assume Link-Time Optimization by CLANG/LLVM is available via ${CMAKE_TOOLCHAIN_FILE}")
-  else()
-    set(CLANG_LTO_AVAILABLE FALSE)
-    message(STATUS "Link-Time Optimization by CLANG/LLVM is NOT available")
-  endif()
-endif()
-
-# Perform build type specific configuration.
-option(ENABLE_BACKTRACE "Enable output of fiber backtrace information in 'show
-  fiber' administrative command. Only works on x86 architectures, if compiled
-  with gcc. If GNU binutils and binutils-dev libraries are installed, backtrace
-  is output with resolved function (symbol) names. Otherwise only frame
-  addresses are printed." OFF)
-
-set(HAVE_BFD FALSE)
-if(ENABLE_BACKTRACE)
-  if(NOT (X86_32 OR X86_64) OR NOT CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG})
-    # We only know this option to work with gcc
-    message(FATAL_ERROR "ENABLE_BACKTRACE option is set but the system
-      is not x86 based (${CMAKE_SYSTEM_PROCESSOR}) or the compiler
-      is not GNU GCC (${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER}).")
-  endif()
-  # Use GNU bfd if present.
-  find_library(BFD_LIBRARY NAMES libbfd.a)
-  if(BFD_LIBRARY)
-    check_library_exists(${BFD_LIBRARY} bfd_init "" HAVE_BFD_LIB)
-  endif()
-  find_library(IBERTY_LIBRARY NAMES libiberty.a)
-  if(IBERTY_LIBRARY)
-    check_library_exists(${IBERTY_LIBRARY} cplus_demangle "" HAVE_IBERTY_LIB)
-  endif()
-  set(CMAKE_REQUIRED_DEFINITIONS -DPACKAGE=${PACKAGE} -DPACKAGE_VERSION=${PACKAGE_VERSION})
-  check_include_files(bfd.h HAVE_BFD_H)
-  set(CMAKE_REQUIRED_DEFINITIONS)
-  find_package(ZLIB)
-  if(HAVE_BFD_LIB AND HAVE_BFD_H AND HAVE_IBERTY_LIB AND ZLIB_FOUND)
-    set(HAVE_BFD ON)
-    set(BFD_LIBRARIES ${BFD_LIBRARY} ${IBERTY_LIBRARY} ${ZLIB_LIBRARIES})
-    find_package_message(BFD_LIBRARIES "Found libbfd and dependencies"
-      ${BFD_LIBRARIES})
-    if(TARGET_OS_FREEBSD AND NOT TARGET_OS_DEBIAN_FREEBSD)
-      set(BFD_LIBRARIES ${BFD_LIBRARIES} iconv)
-    endif()
-  endif()
-endif()
-
-macro(setup_compile_flags)
-  # save initial C/CXX flags
-  if(NOT INITIAL_CMAKE_FLAGS_SAVED)
-    if(CMAKE_CXX_COMPILER_LOADED)
-      set(INITIAL_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
-    endif()
-    if(CMAKE_C_COMPILER_LOADED)
-      set(INITIAL_CMAKE_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
-    endif()
-    set(INITIAL_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
-    set(INITIAL_CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
-    set(INITIAL_CMAKE_STATIC_LINKER_FLAGS ${CMAKE_STATIC_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
-    set(INITIAL_CMAKE_MODULE_LINKER_FLAGS ${CMAKE_MODULE_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
-    set(INITIAL_CMAKE_FLAGS_SAVED TRUE CACHE INTERNAL "State of initial CMake's flags" FORCE)
-  endif()
-
-  # reset C/CXX flags
-  if(CMAKE_CXX_COMPILER_LOADED)
-    set(CXX_FLAGS ${INITIAL_CMAKE_CXX_FLAGS})
-    # Crutch for old C++ compilers and/or CMake to enabling C++11
-    if(CXX_FALLBACK_GNU11)
-      add_compile_flags("CXX" "-std=gnu++11")
-    elseif(CXX_FALLBACK_11)
-      add_compile_flags("CXX" "-std=c++11")
-    endif()
-  endif()
-  if(CMAKE_C_COMPILER_LOADED)
-    set(C_FLAGS ${INITIAL_CMAKE_C_FLAGS})
-    # Crutch for mad C compilers and/or CMake to enabling C11
-    if(C_FALLBACK_GNU11)
-      add_compile_flags("C" "-std=gnu11")
-    elseif(C_FALLBACK_11)
-      if(MSVC)
-        add_compile_flags("C" "/std:c11")
-      else()
-        add_compile_flags("C" "-std=c11")
-      endif()
-    endif()
-  endif()
-  set(EXE_LINKER_FLAGS ${INITIAL_CMAKE_EXE_LINKER_FLAGS})
-  set(SHARED_LINKER_FLAGS ${INITIAL_CMAKE_SHARED_LINKER_FLAGS})
-  set(STATIC_LINKER_FLAGS ${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
-  set(MODULE_LINKER_FLAGS ${INITIAL_CMAKE_MODULE_LINKER_FLAGS})
-
-  if(CC_HAS_FEXCEPTIONS)
-    add_compile_flags("C;CXX" "-fexceptions")
-  endif()
-  if(CC_HAS_FCXX_EXCEPTIONS)
-    add_compile_flags("CXX" "-fcxx-exceptions" "-frtti")
-  endif()
-  if(CC_HAS_FNO_SEMANTIC_INTERPOSITION AND NOT CMAKE_COMPILER_IS_CLANG)
-    add_compile_flags("C;CXX" "-fno-semantic-interposition")
-  endif()
-  if(MSVC)
-    # checks for /EHa or /clr options exists,
-    # i.e. is enabled structured async WinNT exceptions
-    string(REGEX MATCH "^(.* )*[-/]EHc*a( .*)*$" msvc_async_eh_enabled "${CXX_FLAGS}" "${C_FLAGS}")
-    string(REGEX MATCH "^(.* )*[-/]clr( .*)*$" msvc_clr_enabled "${CXX_FLAGS}" "${C_FLAGS}")
-    # remote any /EH? options
-    string(REGEX REPLACE "( *[-/]-*EH[csa]+ *)+" "" CXX_FLAGS "${CXX_FLAGS}")
-    string(REGEX REPLACE "( *[-/]-*EH[csa]+ *)+" "" C_FLAGS "${C_FLAGS}")
-    if (msvc_clr_enabled STREQUAL "")
-      if(NOT msvc_async_eh_enabled STREQUAL "")
-        add_compile_flags("C;CXX" "/EHa")
-      else()
-        add_compile_flags("C;CXX" "/EHsc")
-      endif()
-    endif()
-  endif(MSVC)
-
-  if(CC_HAS_WNO_ATTRIBUTES AND CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG}
-      AND CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 9)
-    # GCC < 9.x generates false-positive warnings for optimization attributes
-    add_compile_flags("C;CXX" "-Wno-attributes")
-    if(LTO_ENABLED)
-      add_compile_flags("C;CXX" "-Wno-lto-type-mismatch")
-    endif()
-  endif()
-
-  # In C a global variable without a storage specifier (static/extern) and
-  # without an initialiser is called a ’tentative definition’. The
-  # language permits multiple tentative definitions in the single
-  # translation unit; i.e. int foo; int foo; is perfectly ok. GNU
-  # toolchain goes even further, allowing multiple tentative definitions
-  # in *different* translation units. Internally, variables introduced via
-  # tentative definitions are implemented as ‘common’ symbols. Linker
-  # permits multiple definitions if they are common symbols, and it picks
-  # one arbitrarily for inclusion in the binary being linked.
-  #
-  # -fno-common forces GNU toolchain to behave in a more
-  # standard-conformant way in respect to tentative definitions and it
-  # prevents common symbols generation. Since we are a cross-platform
-  # project it really makes sense. There are toolchains that don’t
-  # implement GNU style handling of the tentative definitions and there
-  # are platforms lacking proper support for common symbols (osx).
-  if(CC_HAS_FNO_COMMON)
-    add_compile_flags("C;CXX" "-fno-common")
-  endif()
-
-  if(CC_HAS_GGDB)
-    add_compile_flags("C;CXX" "-ggdb")
-  endif()
-
-  if(CC_HAS_WNO_UNKNOWN_PRAGMAS AND NOT HAVE_OPENMP)
-    add_compile_flags("C;CXX" "-Wno-unknown-pragmas")
-  endif()
-
-  if(CC_HAS_SECTIONS)
-    add_compile_flags("C;CXX" "-ffunction-sections" "-fdata-sections")
-  elseif(MSVC)
-    add_compile_flags("C;CXX" "/Gy")
-  endif()
-
-  # We must set -fno-omit-frame-pointer here, since we rely
-  # on frame pointer when getting a backtrace, and it must
-  # be used consistently across all object files.
-  # The same reasoning applies to -fno-stack-protector switch.
-  if(ENABLE_BACKTRACE)
-    if(CC_HAS_FNO_OMIT_FRAME_POINTER)
-      add_compile_flags("C;CXX" "-fno-omit-frame-pointer")
-    endif()
-  endif()
-
-  if(MSVC)
-    if(MSVC_VERSION LESS 1900)
-      message(FATAL_ERROR "At least \"Microsoft C/C++ Compiler\" version 19.0.24234.1 (Visual Studio 2015 Update 3) is required.")
-    endif()
-    if(NOT MSVC_VERSION LESS 1910)
-      add_compile_flags("CXX" "/Zc:__cplusplus")
-    endif()
-    remove_compile_flag("C;CXX" "/W3")
-    add_compile_flags("C;CXX" "/W4 /utf-8")
-  else()
-    if(CC_HAS_WALL)
-      add_compile_flags("C;CXX" "-Wall")
-    endif()
-    if(CC_HAS_WEXTRA)
-      add_compile_flags("C;CXX" "-Wextra")
-    endif()
-  endif()
-
-  add_definitions("-D__STDC_FORMAT_MACROS=1")
-  add_definitions("-D__STDC_LIMIT_MACROS=1")
-  add_definitions("-D__STDC_CONSTANT_MACROS=1")
-  add_definitions("-D_HAS_EXCEPTIONS=1")
-
-  # Only add -Werror if it's a debug build, done by developers.
-  # Release builds should not cause extra trouble.
-  if(CC_HAS_WERROR AND (CI OR CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
-    if(MSVC)
-      add_compile_flags("C;CXX" "/WX")
-    elseif(CMAKE_COMPILER_IS_CLANG)
-      if(NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 6)
-        add_compile_flags("C;CXX" "-Werror")
-      endif()
-    elseif(CMAKE_COMPILER_IS_GNUCC)
-      if(NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 6)
-        add_compile_flags("C;CXX" "-Werror")
-      endif()
-    else()
-      add_compile_flags("C;CXX" "-Werror")
-    endif()
-  endif()
-
-
-  if(CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG}
-      AND CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 5)
-    # G++ bug. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31488
-    add_compile_flags("CXX" "-Wno-invalid-offsetof")
-  endif()
-  if(MINGW)
-    # Disable junk MINGW's warnings that issued due to incompatibilities
-    # and shortcomings of MINGW,
-    # since the code is checked by builds with GCC, CLANG and MSVC.
-    add_compile_flags("C;CXX" "-Wno-format-extra-args" "-Wno-format" "-Wno-cast-function-type" "-Wno-implicit-fallthrough")
-  endif()
-
-  if(ENABLE_ASAN)
-    add_compile_flags("C;CXX" "-fsanitize=address")
-  endif()
-
-  if(ENABLE_UBSAN)
-    add_compile_flags("C;CXX" "-fsanitize=undefined" "-fsanitize-undefined-trap-on-error")
-  endif()
-
-  if(ENABLE_GCOV)
-    if(NOT HAVE_GCOV)
-      message(FATAL_ERROR
-        "ENABLE_GCOV option requested but gcov library is not found")
-    endif()
-
-    add_compile_flags("C;CXX" "-fprofile-arcs" "-ftest-coverage")
-    set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
-    set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
-    set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
-    # add_library(gcov SHARED IMPORTED)
-  endif()
-
-  if(ENABLE_GPROF)
-    add_compile_flags("C;CXX" "-pg")
-  endif()
-
-  if(CMAKE_COMPILER_IS_GNUCC AND LTO_ENABLED)
-    add_compile_flags("C;CXX" ${GCC_LTO_CFLAGS})
-    set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} ${GCC_LTO_CFLAGS} -fverbose-asm -fwhole-program")
-    set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} ${GCC_LTO_CFLAGS} -fverbose-asm")
-    set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} ${GCC_LTO_CFLAGS} -fverbose-asm")
-    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
-      # Pass the same optimization flags to the linker
-      set(compile_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}}")
-      set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} ${compile_flags}")
-      set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} ${compile_flags}")
-      set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} ${compile_flags}")
-      unset(compile_flags)
-    else()
-      add_compile_flags("CXX" "-flto-odr-type-merging")
-    endif()
-  endif()
-
-  if(MSVC AND NOT CMAKE_COMPILER_IS_CLANG AND LTO_ENABLED)
-    add_compile_flags("C;CXX" "/GL")
-    foreach(linkmode IN ITEMS EXE SHARED STATIC MODULE)
-      set(${linkmode}_LINKER_FLAGS "${${linkmode}_LINKER_FLAGS} /LTCG")
-      string(REGEX REPLACE "^(.*)(/INCREMENTAL)(:YES)?(:NO)?( ?.*)$" "\\1\\2:NO\\5" ${linkmode}_LINKER_FLAGS "${${linkmode}_LINKER_FLAGS}")
-      string(STRIP "${${linkmode}_LINKER_FLAGS}" ${linkmode}_LINKER_FLAGS)
-      foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES ITEMS Release MinSizeRel RelWithDebInfo Debug)
-        string(TOUPPER "${config}" config_uppercase)
-        if(DEFINED "CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase}")
-          string(REGEX REPLACE "^(.*)(/INCREMENTAL)(:YES)?(:NO)?( ?.*)$" "\\1\\2:NO\\5" altered_flags "${CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase}}")
-          string(STRIP "${altered_flags}" altered_flags)
-          if(NOT "${altered_flags}" STREQUAL "${CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase}}")
-            set(CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase} "${altered_flags}" CACHE STRING "Altered: '/INCREMENTAL' removed for LTO" FORCE)
-          endif()
-        endif()
-      endforeach(config)
-    endforeach(linkmode)
-    unset(linkmode)
-
-    foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES ITEMS Release MinSizeRel RelWithDebInfo)
-      foreach(lang IN ITEMS C CXX)
-        string(TOUPPER "${config}" config_uppercase)
-        if(DEFINED "CMAKE_${lang}_FLAGS_${config_uppercase}")
-          string(REPLACE "/O2" "/Ox" altered_flags "${CMAKE_${lang}_FLAGS_${config_uppercase}}")
-          if(NOT "${altered_flags}" STREQUAL "${CMAKE_${lang}_FLAGS_${config_uppercase}}")
-            set(CMAKE_${lang}_FLAGS_${config_uppercase} "${altered_flags}" CACHE STRING "Altered: '/O2' replaced by '/Ox' for LTO" FORCE)
-          endif()
-        endif()
-        unset(config_uppercase)
-      endforeach(lang)
-    endforeach(config)
-    unset(altered_flags)
-    unset(lang)
-    unset(config)
-  endif()
-
-  if(CMAKE_COMPILER_IS_CLANG AND OSX_ARCHITECTURES)
-    set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} -Wl,-keep_dwarf_unwind")
-    set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} -Wl,-keep_dwarf_unwind")
-    set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} -Wl,-keep_dwarf_unwind")
-  endif()
-
-  if(CMAKE_COMPILER_IS_CLANG AND LTO_ENABLED)
-    if(CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 3.9)
-      set(CLANG_LTO_FLAG "-flto")
-    else()
-      set(CLANG_LTO_FLAG "-flto=thin")
-    endif()
-    add_compile_flags("C;CXX" ${CLANG_LTO_FLAG})
-    if(NOT MSVC)
-      set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} ${CLANG_LTO_FLAG} -fverbose-asm -fwhole-program")
-      set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} ${CLANG_LTO_FLAG} -fverbose-asm")
-      set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} ${CLANG_LTO_FLAG} -fverbose-asm")
-    endif()
-  endif()
-
-  # push C/CXX flags into the cache
-  if(CMAKE_CXX_COMPILER_LOADED)
-    set(CMAKE_CXX_FLAGS ${CXX_FLAGS} CACHE STRING "Flags used by the C++ compiler during all build types" FORCE)
-    unset(CXX_FLAGS)
-  endif()
-  if(CMAKE_C_COMPILER_LOADED)
-    set(CMAKE_C_FLAGS ${C_FLAGS} CACHE STRING "Flags used by the C compiler during all build types" FORCE)
-    unset(C_FLAGS)
-  endif()
-  set(CMAKE_EXE_LINKER_FLAGS ${EXE_LINKER_FLAGS} CACHE STRING "Flags used by the linker" FORCE)
-  set(CMAKE_SHARED_LINKER_FLAGS ${SHARED_LINKER_FLAGS} CACHE STRING "Flags used by the linker during the creation of dll's" FORCE)
-  set(CMAKE_STATIC_LINKER_FLAGS ${STATIC_LINKER_FLAGS} CACHE STRING "Flags used by the linker during the creation of static libraries" FORCE)
-  set(CMAKE_MODULE_LINKER_FLAGS ${MODULE_LINKER_FLAGS} CACHE STRING "Flags used by the linker during the creation of modules" FORCE)
-  unset(EXE_LINKER_FLAGS)
-  unset(SHARED_LINKER_FLAGS)
-  unset(STATIC_LINKER_FLAGS)
-  unset(MODULE_LINKER_FLAGS)
-endmacro(setup_compile_flags)
-
-macro(probe_libcxx_filesystem)
-  if(CMAKE_CXX_COMPILER_LOADED AND NOT DEFINED LIBCXX_FILESYSTEM)
-    list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11)
-    if(NOT HAS_CXX11 LESS 0)
-      include(CMakePushCheckState)
-      include(CheckCXXSourceCompiles)
-      cmake_push_check_state()
-      set(stdfs_probe_save_libraries ${CMAKE_REQUIRED_LIBRARIES})
-      set(stdfs_probe_save_flags ${CMAKE_REQUIRED_FLAGS})
-      set(stdfs_probe_save_link_options ${CMAKE_REQUIRED_LINK_OPTIONS})
-      unset(stdfs_probe_clear_cxx_standard)
-      if(NOT DEFINED CMAKE_CXX_STANDARD)
-        list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14)
-        list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 HAS_CXX17)
-        if(NOT HAS_CXX17 LESS 0
-            AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5))
-          set(CMAKE_CXX_STANDARD 17)
-        elseif(NOT HAS_CXX14 LESS 0)
-          set(CMAKE_CXX_STANDARD 14)
-        else()
-          set(CMAKE_CXX_STANDARD 11)
-        endif()
-        set(stdfs_probe_clear_cxx_standard ON)
-      endif()
-      if(CMAKE_COMPILER_IS_ELBRUSCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1.25.23)
-        if(CMAKE_VERSION VERSION_LESS 3.14)
-          set(CMAKE_REQUIRED_FLAGS ${stdfs_probe_save_flags} "-Wl,--allow-multiple-definition")
-        else()
-          set(CMAKE_REQUIRED_LINK_OPTIONS ${stdfs_probe_save_link_options} "-Wl,--allow-multiple-definition")
-        endif()
-      endif()
-
-      set(stdfs_probe_code [[
-        #if defined(__SIZEOF_INT128__) && !defined(__GLIBCXX_TYPE_INT_N_0) && defined(__clang__) && __clang_major__ < 4
-        #define __GLIBCXX_BITSIZE_INT_N_0 128
-        #define __GLIBCXX_TYPE_INT_N_0 __int128
-        #endif
-
-        #ifndef __has_include
-        #define __has_include(header) (0)
-        #endif
-        #if __has_include(<version>)
-        #include <version>
-        #endif
-        #include <cstdlib>
-        #include <string>
-        #if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
-        #include <string_view>
-        #endif
-
-        #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
-        #include <filesystem>
-        #else
-        #include <experimental/filesystem>
-        #endif
-
-        #if (defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && (!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || __IPHONE_OS_VERSION_MIN_REQUIRED >= 130100))
-        namespace fs = ::std::filesystem;
-        #elif defined(__cpp_lib_experimental_filesystem) && __cpp_lib_experimental_filesystem >= 201406L
-        namespace fs = ::std::experimental::filesystem;
-        #endif
-
-        int main(int argc, const char*argv[]) {
-          fs::path probe(argv[0]);
-          if (argc != 1) throw fs::filesystem_error(std::string("fake"), std::error_code());
-          return fs::is_directory(probe.relative_path());
-        }
-        ]])
-      set(LIBCXX_FILESYSTEM "")
-
-      check_cxx_source_compiles("${stdfs_probe_code}" LIBCXX_FILESYSTEM_none)
-      if(LIBCXX_FILESYSTEM_none)
-        message(STATUS "No linking with additional library needed for std::filesystem")
-      else()
-        set(CMAKE_REQUIRED_LIBRARIES ${stdfs_probe_save_libraries} "stdc++fs")
-        check_cxx_source_compiles("${stdfs_probe_code}" LIBCXX_FILESYSTEM_stdcxxfs)
-        if(LIBCXX_FILESYSTEM_stdcxxfs)
-          set(LIBCXX_FILESYSTEM "stdc++fs")
-          message(STATUS "Linking with ${LIBCXX_FILESYSTEM} is required for std::filesystem")
-        else()
-          set(CMAKE_REQUIRED_LIBRARIES ${stdfs_probe_save_libraries} "c++fs")
-          check_cxx_source_compiles("${stdfs_probe_code}" LIBCXX_FILESYSTEM_cxxfs)
-          if(LIBCXX_FILESYSTEM_cxxfs)
-            set(LIBCXX_FILESYSTEM "c++fs")
-            message(STATUS "Linking with ${LIBCXX_FILESYSTEM} is required for std::filesystem")
-          else()
-            set(CMAKE_REQUIRED_LIBRARIES ${stdfs_probe_save_libraries} "c++experimental")
-            check_cxx_source_compiles("${stdfs_probe_code}" LIBCXX_FILESYSTEM_cxxexperimental)
-            if(LIBCXX_FILESYSTEM_cxxexperimental)
-              set(LIBCXX_FILESYSTEM "c++experimental")
-              message(STATUS "Linking with ${LIBCXX_FILESYSTEM} is required for std::filesystem")
-            else()
-              message(STATUS "No support for std::filesystem")
-            endif()
-          endif()
-        endif()
-      endif()
-
-      set(CMAKE_REQUIRED_LINK_OPTIONS ${stdfs_probe_save_link_options})
-      set(CMAKE_REQUIRED_FLAGS ${stdfs_probe_save_flags})
-      set(CMAKE_REQUIRED_LIBRARIES ${stdfs_probe_save_libraries})
-      if(stdfs_probe_clear_cxx_standard)
-        unset(CMAKE_CXX_STANDARD)
-      endif()
-      unset(stdfs_probe_clear_cxx_standard)
-      unset(stdfs_probe_save_link_options)
-      unset(stdfs_probe_save_flags)
-      unset(stdfs_probe_save_libraries)
-      unset(stdfs_probe_code)
-      unset(stdfs_probe_rc)
-      cmake_pop_check_state()
-    endif()
-  endif()
-endmacro(probe_libcxx_filesystem)
-
-cmake_policy(POP)
diff --git a/3rdparty/libmdbx/cmake/profile.cmake b/3rdparty/libmdbx/cmake/profile.cmake
deleted file mode 100644
index 6fe9c8217fa5b054cc402a70b136ebc1f1f24e2b..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/cmake/profile.cmake
+++ /dev/null
@@ -1,53 +0,0 @@
-##  Copyright (c) 2012-2022 Leonid Yuriev <leo@yuriev.ru>.
-##
-##  Licensed under the Apache License, Version 2.0 (the "License");
-##  you may not use this file except in compliance with the License.
-##  You may obtain a copy of the License at
-##
-##      http://www.apache.org/licenses/LICENSE-2.0
-##
-##  Unless required by applicable law or agreed to in writing, software
-##  distributed under the License is distributed on an "AS IS" BASIS,
-##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-##  See the License for the specific language governing permissions and
-##  limitations under the License.
-##
-
-if(CMAKE_VERSION VERSION_LESS 3.12)
-  cmake_minimum_required(VERSION 3.8.2)
-else()
-  cmake_minimum_required(VERSION 3.12)
-endif()
-
-cmake_policy(PUSH)
-cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
-
-include(CheckLibraryExists)
-check_library_exists(gcov __gcov_flush "" HAVE_GCOV)
-
-option(ENABLE_GCOV
-  "Enable integration with gcov, a code coverage program" OFF)
-
-option(ENABLE_GPROF
-  "Enable integration with gprof, a performance analyzing tool" OFF)
-
-if(CMAKE_CXX_COMPILER_LOADED)
-  include(CheckIncludeFileCXX)
-  check_include_file_cxx(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
-else()
-  include(CheckIncludeFile)
-  check_include_file(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
-endif()
-
-option(MDBX_USE_VALGRIND "Enable integration with valgrind, a memory analyzing tool" OFF)
-if(MDBX_USE_VALGRIND AND NOT HAVE_VALGRIND_MEMCHECK_H)
-  message(FATAL_ERROR "MDBX_USE_VALGRIND option is set but valgrind/memcheck.h is not found")
-endif()
-
-option(ENABLE_ASAN
-  "Enable AddressSanitizer, a fast memory error detector based on compiler instrumentation" OFF)
-
-option(ENABLE_UBSAN
-  "Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector based on compiler instrumentation" OFF)
-
-cmake_policy(POP)
diff --git a/3rdparty/libmdbx/cmake/utils.cmake b/3rdparty/libmdbx/cmake/utils.cmake
deleted file mode 100644
index a461cc27d1ba0b57bb9564c107f790fad886abfe..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/cmake/utils.cmake
+++ /dev/null
@@ -1,284 +0,0 @@
-##  Copyright (c) 2012-2022 Leonid Yuriev <leo@yuriev.ru>.
-##
-##  Licensed under the Apache License, Version 2.0 (the "License");
-##  you may not use this file except in compliance with the License.
-##  You may obtain a copy of the License at
-##
-##      http://www.apache.org/licenses/LICENSE-2.0
-##
-##  Unless required by applicable law or agreed to in writing, software
-##  distributed under the License is distributed on an "AS IS" BASIS,
-##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-##  See the License for the specific language governing permissions and
-##  limitations under the License.
-##
-
-if(CMAKE_VERSION VERSION_LESS 3.12)
-  cmake_minimum_required(VERSION 3.8.2)
-else()
-  cmake_minimum_required(VERSION 3.12)
-endif()
-
-cmake_policy(PUSH)
-cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
-
-macro(add_compile_flags languages)
-  foreach(_lang ${languages})
-    string(REPLACE ";" " " _flags "${ARGN}")
-    if(CMAKE_CXX_COMPILER_LOADED AND _lang STREQUAL "CXX")
-      set("${_lang}_FLAGS" "${${_lang}_FLAGS} ${_flags}")
-    endif()
-    if(CMAKE_C_COMPILER_LOADED AND _lang STREQUAL "C")
-      set("${_lang}_FLAGS" "${${_lang}_FLAGS} ${_flags}")
-    endif()
-  endforeach()
-  unset(_lang)
-  unset(_flags)
-endmacro(add_compile_flags)
-
-macro(remove_flag varname flag)
-  string(REGEX REPLACE "^(.*)( ${flag} )(.*)$" "\\1 \\3" ${varname} ${${varname}})
-  string(REGEX REPLACE "^((.+ )*)(${flag})(( .+)*)$" "\\1\\4" ${varname} ${${varname}})
-endmacro(remove_flag)
-
-macro(remove_compile_flag languages flag)
-  foreach(_lang ${languages})
-    if(CMAKE_CXX_COMPILER_LOADED AND _lang STREQUAL "CXX")
-      remove_flag(${_lang}_FLAGS ${flag})
-    endif()
-    if(CMAKE_C_COMPILER_LOADED AND _lang STREQUAL "C")
-      remove_flag(${_lang}_FLAGS ${flag})
-    endif()
-  endforeach()
-  unset(_lang)
-endmacro(remove_compile_flag)
-
-macro(set_source_files_compile_flags)
-  foreach(file ${ARGN})
-    get_filename_component(_file_ext ${file} EXT)
-    set(_lang "")
-    if("${_file_ext}" STREQUAL ".m")
-      set(_lang OBJC)
-      # CMake believes that Objective C is a flavor of C++, not C,
-      # and uses g++ compiler for .m files.
-      # LANGUAGE property forces CMake to use CC for ${file}
-      set_source_files_properties(${file} PROPERTIES LANGUAGE C)
-    elseif("${_file_ext}" STREQUAL ".mm")
-      set(_lang OBJCXX)
-    endif()
-
-    if(_lang)
-      get_source_file_property(_flags ${file} COMPILE_FLAGS)
-      if("${_flags}" STREQUAL "NOTFOUND")
-        set(_flags "${CMAKE_${_lang}_FLAGS}")
-      else()
-        set(_flags "${_flags} ${CMAKE_${_lang}_FLAGS}")
-      endif()
-      # message(STATUS "Set (${file} ${_flags}")
-      set_source_files_properties(${file} PROPERTIES COMPILE_FLAGS
-        "${_flags}")
-    endif()
-  endforeach()
-  unset(_file_ext)
-  unset(_lang)
-endmacro(set_source_files_compile_flags)
-
-macro(fetch_version name source_root_directory parent_scope)
-  set(${name}_VERSION "")
-  set(${name}_GIT_DESCRIBE "")
-  set(${name}_GIT_TIMESTAMP "")
-  set(${name}_GIT_TREE "")
-  set(${name}_GIT_COMMIT "")
-  set(${name}_GIT_REVISION 0)
-  set(${name}_GIT_VERSION "")
-  if(GIT AND EXISTS "${source_root_directory}/.git")
-    execute_process(COMMAND ${GIT} show --no-patch --format=%cI HEAD
-      OUTPUT_VARIABLE ${name}_GIT_TIMESTAMP
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      WORKING_DIRECTORY ${source_root_directory}
-      RESULT_VARIABLE rc)
-    if(rc OR "${name}_GIT_TIMESTAMP" STREQUAL "%cI")
-      execute_process(COMMAND ${GIT} show --no-patch --format=%ci HEAD
-        OUTPUT_VARIABLE ${name}_GIT_TIMESTAMP
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${source_root_directory}
-        RESULT_VARIABLE rc)
-      if(rc OR "${name}_GIT_TIMESTAMP" STREQUAL "%ci")
-        message(FATAL_ERROR "Please install latest version of git (`show --no-patch --format=%cI HEAD` failed)")
-      endif()
-    endif()
-
-    execute_process(COMMAND ${GIT} show --no-patch --format=%T HEAD
-      OUTPUT_VARIABLE ${name}_GIT_TREE
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      WORKING_DIRECTORY ${source_root_directory}
-      RESULT_VARIABLE rc)
-    if(rc OR "${name}_GIT_TREE" STREQUAL "")
-      message(FATAL_ERROR "Please install latest version of git (`show --no-patch --format=%T HEAD` failed)")
-    endif()
-
-    execute_process(COMMAND ${GIT} show --no-patch --format=%H HEAD
-      OUTPUT_VARIABLE ${name}_GIT_COMMIT
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      WORKING_DIRECTORY ${source_root_directory}
-      RESULT_VARIABLE rc)
-    if(rc OR "${name}_GIT_COMMIT" STREQUAL "")
-      message(FATAL_ERROR "Please install latest version of git (`show --no-patch --format=%H HEAD` failed)")
-    endif()
-
-    execute_process(COMMAND ${GIT} rev-list --tags --count
-      OUTPUT_VARIABLE tag_count
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      WORKING_DIRECTORY ${source_root_directory}
-      RESULT_VARIABLE rc)
-    if(rc)
-      message(FATAL_ERROR "Please install latest version of git (`git rev-list --tags --count` failed)")
-    endif()
-
-    if(tag_count EQUAL 0)
-      execute_process(COMMAND ${GIT} rev-list --all --count
-        OUTPUT_VARIABLE whole_count
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${source_root_directory}
-        RESULT_VARIABLE rc)
-      if(rc)
-        message(FATAL_ERROR "Please install latest version of git (`git rev-list --all --count` failed)")
-      endif()
-      if(whole_count GREATER 42)
-        message(FATAL_ERROR "Please fetch tags (no any tags for ${whole_count} commits)")
-      endif()
-      set(${name}_GIT_VERSION "0;0;0")
-      execute_process(COMMAND ${GIT} rev-list --count --all --no-merges
-        OUTPUT_VARIABLE ${name}_GIT_REVISION
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${source_root_directory}
-        RESULT_VARIABLE rc)
-      if(rc OR "${name}_GIT_REVISION" STREQUAL "")
-        message(FATAL_ERROR "Please install latest version of git (`rev-list --count --all --no-merges` failed)")
-      endif()
-    else(tag_count EQUAL 0)
-      execute_process(COMMAND ${GIT} describe --tags --long --dirty=-dirty "--match=v[0-9]*"
-        OUTPUT_VARIABLE ${name}_GIT_DESCRIBE
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${source_root_directory}
-        RESULT_VARIABLE rc)
-      if(rc OR "${name}_GIT_DESCRIBE" STREQUAL "")
-        if(_whole_count GREATER 42)
-          message(FATAL_ERROR "Please fetch tags (`describe --tags --long --dirty --match=v[0-9]*` failed)")
-        else()
-          execute_process(COMMAND ${GIT} describe --all --long --dirty=-dirty
-            OUTPUT_VARIABLE ${name}_GIT_DESCRIBE
-            OUTPUT_STRIP_TRAILING_WHITESPACE
-            WORKING_DIRECTORY ${source_root_directory}
-            RESULT_VARIABLE rc)
-          if(rc OR "${name}_GIT_DESCRIBE" STREQUAL "")
-            message(FATAL_ERROR "Please install latest version of git (`git rev-list --tags --count` and/or `git rev-list --all --count` failed)")
-          endif()
-        endif()
-      endif()
-
-      execute_process(COMMAND ${GIT} describe --tags --abbrev=0 "--match=v[0-9]*"
-        OUTPUT_VARIABLE last_release_tag
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${source_root_directory}
-        RESULT_VARIABLE rc)
-      if(rc)
-        message(FATAL_ERROR "Please install latest version of git (`describe --tags --abbrev=0 --match=v[0-9]*` failed)")
-      endif()
-      if (last_release_tag)
-        set(git_revlist_arg "${last_release_tag}..HEAD")
-      else()
-        execute_process(COMMAND ${GIT} tag --sort=-version:refname
-          OUTPUT_VARIABLE tag_list
-          OUTPUT_STRIP_TRAILING_WHITESPACE
-          WORKING_DIRECTORY ${source_root_directory}
-          RESULT_VARIABLE rc)
-        if(rc)
-          message(FATAL_ERROR "Please install latest version of git (`tag --sort=-version:refname` failed)")
-        endif()
-        string(REGEX REPLACE "\n" ";" tag_list "${tag_list}")
-        set(git_revlist_arg "HEAD")
-        foreach(tag IN LISTS tag_list)
-          if(NOT last_release_tag)
-            string(REGEX MATCH "^v[0-9]+(\.[0-9]+)+" last_release_tag "${tag}")
-            set(git_revlist_arg "${tag}..HEAD")
-          endif()
-        endforeach(tag)
-      endif()
-      execute_process(COMMAND ${GIT} rev-list --count "${git_revlist_arg}"
-        OUTPUT_VARIABLE ${name}_GIT_REVISION
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        WORKING_DIRECTORY ${source_root_directory}
-        RESULT_VARIABLE rc)
-      if(rc OR "${name}_GIT_REVISION" STREQUAL "")
-        message(FATAL_ERROR "Please install latest version of git (`rev-list --count ${git_revlist_arg}` failed)")
-      endif()
-
-      string(REGEX MATCH "^(v)?([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" git_version_valid "${${name}_GIT_DESCRIBE}")
-      if(git_version_valid)
-        string(REGEX REPLACE "^(v)?([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" "\\2;\\3;\\4" ${name}_GIT_VERSION ${${name}_GIT_DESCRIBE})
-      else()
-        string(REGEX MATCH "^(v)?([0-9]+)\\.([0-9]+)(.*)?" git_version_valid "${${name}_GIT_DESCRIBE}")
-        if(git_version_valid)
-          string(REGEX REPLACE "^(v)?([0-9]+)\\.([0-9]+)(.*)?" "\\2;\\3;0" ${name}_GIT_VERSION ${${name}_GIT_DESCRIBE})
-        else()
-          message(AUTHOR_WARNING "Bad ${name} version \"${${name}_GIT_DESCRIBE}\"; falling back to 0.0.0 (have you made an initial release?)")
-          set(${name}_GIT_VERSION "0;0;0")
-        endif()
-      endif()
-    endif(tag_count EQUAL 0)
-  endif()
-
-  if(NOT ${name}_GIT_VERSION OR NOT ${name}_GIT_TIMESTAMP OR ${name}_GIT_REVISION STREQUAL "")
-    if(GIT AND EXISTS "${source_root_directory}/.git")
-      message(WARNING "Unable to retrieve ${name} version from git.")
-    endif()
-    set(${name}_GIT_VERSION "0;0;0;0")
-    set(${name}_GIT_TIMESTAMP "")
-    set(${name}_GIT_REVISION 0)
-
-    # Try to get version from VERSION file
-    set(version_file "${source_root_directory}/VERSION.txt")
-    if(NOT EXISTS "${version_file}")
-      set(version_file "${source_root_directory}/VERSION")
-    endif()
-    if(EXISTS "${version_file}")
-      file(STRINGS "${version_file}" ${name}_VERSION LIMIT_COUNT 1 LIMIT_INPUT 42)
-    endif()
-
-    if(NOT ${name}_VERSION)
-      message(WARNING "Unable to retrieve ${name} version from \"${version_file}\" file.")
-      set(${name}_VERSION_LIST ${${name}_GIT_VERSION})
-      string(REPLACE ";" "." ${name}_VERSION "${${name}_GIT_VERSION}")
-    else()
-      string(REPLACE "." ";" ${name}_VERSION_LIST ${${name}_VERSION})
-    endif()
-
-  else()
-    list(APPEND ${name}_GIT_VERSION ${${name}_GIT_REVISION})
-    set(${name}_VERSION_LIST ${${name}_GIT_VERSION})
-    string(REPLACE ";" "." ${name}_VERSION "${${name}_GIT_VERSION}")
-  endif()
-
-  list(GET ${name}_VERSION_LIST 0 "${name}_VERSION_MAJOR")
-  list(GET ${name}_VERSION_LIST 1 "${name}_VERSION_MINOR")
-  list(GET ${name}_VERSION_LIST 2 "${name}_VERSION_RELEASE")
-  list(GET ${name}_VERSION_LIST 3 "${name}_VERSION_REVISION")
-
-  if(${parent_scope})
-    set(${name}_VERSION_MAJOR "${${name}_VERSION_MAJOR}" PARENT_SCOPE)
-    set(${name}_VERSION_MINOR "${${name}_VERSION_MINOR}" PARENT_SCOPE)
-    set(${name}_VERSION_RELEASE "${${name}_VERSION_RELEASE}" PARENT_SCOPE)
-    set(${name}_VERSION_REVISION "${${name}_VERSION_REVISION}" PARENT_SCOPE)
-    set(${name}_VERSION "${${name}_VERSION}" PARENT_SCOPE)
-
-    set(${name}_GIT_DESCRIBE "${${name}_GIT_DESCRIBE}" PARENT_SCOPE)
-    set(${name}_GIT_TIMESTAMP "${${name}_GIT_TIMESTAMP}" PARENT_SCOPE)
-    set(${name}_GIT_TREE "${${name}_GIT_TREE}" PARENT_SCOPE)
-    set(${name}_GIT_COMMIT "${${name}_GIT_COMMIT}" PARENT_SCOPE)
-    set(${name}_GIT_REVISION "${${name}_GIT_REVISION}" PARENT_SCOPE)
-    set(${name}_GIT_VERSION "${${name}_GIT_VERSION}" PARENT_SCOPE)
-  endif()
-endmacro(fetch_version)
-
-cmake_policy(POP)
diff --git a/3rdparty/libmdbx/config.h b/3rdparty/libmdbx/config.h
deleted file mode 100644
index b8983250d7e7eccd96e832d50ebb0aca5ad225d2..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/config.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This is CMake-template for libmdbx's config.h
- ******************************************************************************/
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-/* #undef LTO_ENABLED */
-/* #undef MDBX_USE_VALGRIND */
-/* #undef ENABLE_GPROF */
-/* #undef ENABLE_GCOV */
-/* #undef ENABLE_ASAN */
-/* #undef ENABLE_UBSAN */
-#define MDBX_FORCE_ASSERTIONS 0
-
-/* Common */
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_ENV_CHECKPID_AUTO
-#ifndef MDBX_ENV_CHECKPID_AUTO
-#define MDBX_ENV_CHECKPID 0
-#endif
-#define MDBX_LOCKING_AUTO
-#ifndef MDBX_LOCKING_AUTO
-/* #undef MDBX_LOCKING */
-#endif
-#define MDBX_TRUST_RTC_AUTO
-#ifndef MDBX_TRUST_RTC_AUTO
-#define MDBX_TRUST_RTC 0
-#endif
-#define MDBX_DISABLE_PAGECHECKS 0
-
-/* Windows */
-#define MDBX_WITHOUT_MSVC_CRT 0
-
-/* MacOS & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY 0
-
-/* POSIX */
-#define MDBX_DISABLE_GNU_SOURCE 0
-#define MDBX_USE_OFDLOCKS_AUTO
-#ifndef MDBX_USE_OFDLOCKS_AUTO
-#define MDBX_USE_OFDLOCKS 0
-#endif
-
-/* Build Info */
-#ifndef MDBX_BUILD_TIMESTAMP
-#define MDBX_BUILD_TIMESTAMP "2022-11-07T16:21:48Z"
-#endif
-#ifndef MDBX_BUILD_TARGET
-#define MDBX_BUILD_TARGET "x86_64-ELF-Linux"
-#endif
-#ifndef MDBX_BUILD_TYPE
-#define MDBX_BUILD_TYPE "Debug"
-#endif
-#ifndef MDBX_BUILD_COMPILER
-#define MDBX_BUILD_COMPILER "gcc (Debian 10.2.1-6) 10.2.1 20210110"
-#endif
-#ifndef MDBX_BUILD_FLAGS
-#define MDBX_BUILD_FLAGS "-g MDBX_BUILD_SHARED_LIBRARY=0 -ffast-math -fvisibility=hidden"
-#endif
-/* #undef MDBX_BUILD_SOURCERY */
-
-/* *INDENT-ON* */
-/* clang-format on */
diff --git a/3rdparty/libmdbx/config.h.in b/3rdparty/libmdbx/config.h.in
deleted file mode 100644
index 7959699a302dbcf5422ead3a7c19d9faa49a8cff..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/config.h.in
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This is CMake-template for libmdbx's config.h
- ******************************************************************************/
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#cmakedefine LTO_ENABLED
-#cmakedefine MDBX_USE_VALGRIND
-#cmakedefine ENABLE_GPROF
-#cmakedefine ENABLE_GCOV
-#cmakedefine ENABLE_ASAN
-#cmakedefine ENABLE_UBSAN
-#cmakedefine01 MDBX_FORCE_ASSERTIONS
-
-/* Common */
-#cmakedefine01 MDBX_TXN_CHECKOWNER
-#cmakedefine MDBX_ENV_CHECKPID_AUTO
-#ifndef MDBX_ENV_CHECKPID_AUTO
-#cmakedefine01 MDBX_ENV_CHECKPID
-#endif
-#cmakedefine MDBX_LOCKING_AUTO
-#ifndef MDBX_LOCKING_AUTO
-#cmakedefine MDBX_LOCKING @MDBX_LOCKING@
-#endif
-#cmakedefine MDBX_TRUST_RTC_AUTO
-#ifndef MDBX_TRUST_RTC_AUTO
-#cmakedefine01 MDBX_TRUST_RTC
-#endif
-#cmakedefine01 MDBX_DISABLE_PAGECHECKS
-
-/* Windows */
-#cmakedefine01 MDBX_WITHOUT_MSVC_CRT
-
-/* MacOS & iOS */
-#cmakedefine01 MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-
-/* POSIX */
-#cmakedefine01 MDBX_DISABLE_GNU_SOURCE
-#cmakedefine MDBX_USE_OFDLOCKS_AUTO
-#ifndef MDBX_USE_OFDLOCKS_AUTO
-#cmakedefine01 MDBX_USE_OFDLOCKS
-#endif
-
-/* Build Info */
-#ifndef MDBX_BUILD_TIMESTAMP
-#cmakedefine MDBX_BUILD_TIMESTAMP "@MDBX_BUILD_TIMESTAMP@"
-#endif
-#ifndef MDBX_BUILD_TARGET
-#cmakedefine MDBX_BUILD_TARGET "@MDBX_BUILD_TARGET@"
-#endif
-#ifndef MDBX_BUILD_TYPE
-#cmakedefine MDBX_BUILD_TYPE "@MDBX_BUILD_TYPE@"
-#endif
-#ifndef MDBX_BUILD_COMPILER
-#cmakedefine MDBX_BUILD_COMPILER "@MDBX_BUILD_COMPILER@"
-#endif
-#ifndef MDBX_BUILD_FLAGS
-#cmakedefine MDBX_BUILD_FLAGS "@MDBX_BUILD_FLAGS@"
-#endif
-#cmakedefine MDBX_BUILD_SOURCERY @MDBX_BUILD_SOURCERY@
-
-/* *INDENT-ON* */
-/* clang-format on */
diff --git a/3rdparty/libmdbx/man1/mdbx_chk.1 b/3rdparty/libmdbx/man1/mdbx_chk.1
deleted file mode 100644
index a4e335d930534958bc29786c850d5086d6bcbfb4..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/man1/mdbx_chk.1
+++ /dev/null
@@ -1,99 +0,0 @@
-.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
-.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.TH MDBX_CHK 1 "2022-04-22" "MDBX 0.11.7"
-.SH NAME
-mdbx_chk \- MDBX checking tool
-.SH SYNOPSIS
-.B mdbx_chk
-[\c
-.BR \-V ]
-[\c
-.BR \-v [ v [ v ]]]
-[\c
-.BR \-n ]
-[\c
-.BR \-q ]
-[\c
-.BR \-c ]
-[\c
-.BR \-w ]
-[\c
-.BR \-d ]
-[\c
-.BR \-i ]
-[\c
-.BI \-s \ subdb\fR]
-.BR \ dbpath
-.SH DESCRIPTION
-The
-.B mdbx_chk
-utility intended to check an MDBX database file.
-.SH OPTIONS
-.TP
-.BR \-V
-Write the library version number to the standard output, and exit.
-.TP
-.BR \-v
-Produce verbose output, including summarize space and page usage statistics.
-If \fB\-vv\fP is given, be more verbose, show summarized B-tree info
-and space allocation.
-If \fB\-vvv\fP is given, be more verbose, include summarized statistics
-of leaf B-tree pages.
-If \fB\-vvvv\fP is given, be even more verbose, show info of each page
-during B-tree traversal and basic info of each GC record.
-If \fB\-vvvvv\fP is given, turn maximal verbosity, display the full list
-of page IDs in the GC records and size of each key-value pair of database(s).
-.TP
-.BR \-q
-Be quiet; do not output anything even if an error was detected.
-.TP
-.BR \-c
-Force using cooperative mode while opening environment, i.e. don't try to open
-in exclusive/monopolistic mode. Only exclusive/monopolistic mode allow complete
-check, including full check of all meta-pages and actual size of database file.
-.TP
-.BR \-w
-Open environment in read-write mode and lock for writing while checking.
-This could be impossible if environment already used by another process(s)
-in an incompatible read-write mode. This allow rollback to last steady commit
-(in case environment was not closed properly) and then check transaction IDs
-of meta-pages. Otherwise, without \fB\-w\fP option environment will be
-opened in read-only mode.
-.TP
-.BR \-d
-Disable page-by-page traversal of B-tree. In this case, without B-tree
-traversal, it is unable to check for lost-unused pages nor for double-used
-pages.
-.TP
-.BR \-i
-Ignore wrong order errors, which will likely false-positive if custom
-comparator(s) was used.
-.TP
-.BR \-s \ subdb
-Verify and show info only for a specific subdatabase.
-.TP
-.BR \-0 | \-1 | \-2
-Using specific meta-page 0, or 2 for checking.
-.TP
-.BR \-t
-Turn to a specified meta-page on successful check.
-.TP
-.BR \-T
-Turn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!
-.TP
-.BR \-n
-Open MDBX environment(s) which do not use subdirectories.
-This is legacy option. For now MDBX handles this automatically.
-
-.SH DIAGNOSTICS
-Exit status is zero if no errors occur. Errors result in a non-zero exit status
-and a diagnostic message being written to standard error
-if no quiet mode was requested.
-.SH "SEE ALSO"
-.BR mdbx_stat (1),
-.BR mdbx_copy (1),
-.BR mdbx_dump (1),
-.BR mdbx_load (1)
-.BR mdbx_drop (1)
-.SH AUTHOR
-Leonid Yuriev <https://gitflic.ru/user/erthink>
diff --git a/3rdparty/libmdbx/man1/mdbx_copy.1 b/3rdparty/libmdbx/man1/mdbx_copy.1
deleted file mode 100644
index e06347f6fb0972bf270215789139b087f5ee7d42..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/man1/mdbx_copy.1
+++ /dev/null
@@ -1,68 +0,0 @@
-.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
-.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
-.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
-.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.TH MDBX_COPY 1 "2022-04-22" "MDBX 0.11.7"
-.SH NAME
-mdbx_copy \- MDBX environment copy tool
-.SH SYNOPSIS
-.B mdbx_copy
-[\c
-.BR \-V ]
-[\c
-.BR \-q ]
-[\c
-.BR \-c ]
-[\c
-.BR \-n ]
-.B src_path
-[\c
-.BR dest_path ]
-.SH DESCRIPTION
-The
-.B mdbx_copy
-utility copies an MDBX environment. The environment can
-be copied regardless of whether it is currently in use.
-No lockfile is created, since it gets recreated at need.
-
-If
-.I dest_path
-is specified it must be the path of an empty directory
-for storing the backup. Otherwise, the backup will be
-written to stdout.
-
-.SH OPTIONS
-.TP
-.BR \-V
-Write the library version number to the standard output, and exit.
-.TP
-.BR \-q
-Be quiet.
-.TP
-.BR \-c
-Compact while copying. Only current data pages will be copied; freed
-or unused pages will be omitted from the copy. This option will
-slow down the backup process as it is more CPU-intensive.
-Currently it fails if the environment has suffered a page leak.
-.TP
-.BR \-n
-Open MDBX environment(s) which do not use subdirectories.
-This is legacy option. For now MDBX handles this automatically.
-
-.SH DIAGNOSTICS
-Exit status is zero if no errors occur.
-Errors result in a non-zero exit status and
-a diagnostic message being written to standard error.
-.SH CAVEATS
-This utility can trigger significant file size growth if run
-in parallel with write transactions, because pages which they
-free during copying cannot be reused until the copy is done.
-.SH "SEE ALSO"
-.BR mdbx_dump (1),
-.BR mdbx_chk (1),
-.BR mdbx_stat (1),
-.BR mdbx_load (1)
-.BR mdbx_drop (1)
-.SH AUTHOR
-Howard Chu of Symas Corporation <http://www.symas.com>,
-Leonid Yuriev <https://gitflic.ru/user/erthink>
diff --git a/3rdparty/libmdbx/man1/mdbx_drop.1 b/3rdparty/libmdbx/man1/mdbx_drop.1
deleted file mode 100644
index b9577fcafa8f3b090436424886804efc6d9ffad0..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/man1/mdbx_drop.1
+++ /dev/null
@@ -1,48 +0,0 @@
-.\" Copyright 2021-2022 Leonid Yuriev <leo@yuriev.ru>.
-.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
-.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.TH MDBX_DROP 1 "2022-04-22" "MDBX 0.11.7"
-.SH NAME
-mdbx_drop \- MDBX database delete tool
-.SH SYNOPSIS
-.B mdbx_drop
-[\c
-.BR \-V ]
-[\c
-.BR \-d ]
-[\c
-.BI \-s \ subdb\fR]
-[\c
-.BR \-n ]
-.BR \ dbpath
-.SH DESCRIPTION
-The
-.B mdbx_drop
-utility empties or deletes a database in the specified
-environment.
-.SH OPTIONS
-.TP
-.BR \-V
-Write the library version number to the standard output, and exit.
-.TP
-.BR \-d
-Delete the specified database, don't just empty it.
-.TP
-.BR \-s \ subdb
-Operate on a specific subdatabase. If no database is specified, only the main database is dropped.
-.TP
-.BR \-n
-Dump an MDBX database which does not use subdirectories.
-This is legacy option. For now MDBX handles this automatically.
-
-.SH DIAGNOSTICS
-Exit status is zero if no errors occur.
-Errors result in a non-zero exit status and
-a diagnostic message being written to standard error.
-.SH "SEE ALSO"
-.BR mdbx_load (1),
-.BR mdbx_copy (1),
-.BR mdbx_chk (1),
-.BR mdbx_stat (1)
-.SH AUTHOR
-Howard Chu of Symas Corporation <http://www.symas.com>
diff --git a/3rdparty/libmdbx/man1/mdbx_dump.1 b/3rdparty/libmdbx/man1/mdbx_dump.1
deleted file mode 100644
index 469f13b65fb0ba83ecadb060388e5f3afa9dbb3d..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/man1/mdbx_dump.1
+++ /dev/null
@@ -1,94 +0,0 @@
-.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
-.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
-.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
-.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.TH MDBX_DUMP 1 "2022-04-22" "MDBX 0.11.7"
-.SH NAME
-mdbx_dump \- MDBX environment export tool
-.SH SYNOPSIS
-.B mdbx_dump
-[\c
-.BR \-V ]
-[\c
-.BR \-q ]
-[\c
-.BI \-f \ file\fR]
-[\c
-.BR \-l ]
-[\c
-.BR \-p ]
-[\c
-.BR \-a \ |
-.BI \-s \ subdb\fR]
-[\c
-.BR \-r ]
-[\c
-.BR \-n ]
-.BR \ dbpath
-.SH DESCRIPTION
-The
-.B mdbx_dump
-utility reads a database and writes its contents to the
-standard output using a portable flat-text format
-understood by the
-.BR mdbx_load (1)
-utility.
-.SH OPTIONS
-.TP
-.BR \-V
-Write the library version number to the standard output, and exit.
-.TP
-.BR \-q
-Be quiet.
-.TP
-.BR \-f \ file
-Write to the specified file instead of to the standard output.
-.TP
-.BR \-l
-List the databases stored in the environment. Just the
-names will be listed, no data will be output.
-.TP
-.BR \-p
-If characters in either the key or data items are printing characters (as
-defined by isprint(3)), output them directly. This option permits users to
-use standard text editors and tools to modify the contents of databases.
-
-Note: different systems may have different notions about what characters
-are considered printing characters, and databases dumped in this manner may
-be less portable to external systems.
-.TP
-.BR \-a
-Dump all of the subdatabases in the environment.
-.TP
-.BR \-s \ subdb
-Dump a specific subdatabase. If no database is specified, only the main database is dumped.
-.TP
-.BR \-r
-Rescure mode. Ignore some errors to dump corrupted DB.
-.TP
-.BR \-n
-Dump an MDBX database which does not use subdirectories.
-This is legacy option. For now MDBX handles this automatically.
-
-.SH DIAGNOSTICS
-Exit status is zero if no errors occur.
-Errors result in a non-zero exit status and
-a diagnostic message being written to standard error.
-
-Dumping and reloading databases that use user-defined comparison functions
-will result in new databases that use the default comparison functions.
-\fBIn this case it is quite likely that the reloaded database will be
-damaged beyond repair permitting neither record storage nor retrieval.\fP
-
-The only available workaround is to modify the source for the
-.BR mdbx_load (1)
-utility to load the database using the correct comparison functions.
-.SH "SEE ALSO"
-.BR mdbx_load (1),
-.BR mdbx_copy (1),
-.BR mdbx_chk (1),
-.BR mdbx_stat (1)
-.BR mdbx_drop (1)
-.SH AUTHOR
-Howard Chu of Symas Corporation <http://www.symas.com>,
-Leonid Yuriev <https://gitflic.ru/user/erthink>
diff --git a/3rdparty/libmdbx/man1/mdbx_load.1 b/3rdparty/libmdbx/man1/mdbx_load.1
deleted file mode 100644
index 850d4d1c0ee48cbdd4771f2a027fd165b0cb1ef6..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/man1/mdbx_load.1
+++ /dev/null
@@ -1,105 +0,0 @@
-.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
-.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
-.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
-.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.TH MDBX_LOAD 1 "2022-04-22" "MDBX 0.11.7"
-.SH NAME
-mdbx_load \- MDBX environment import tool
-.SH SYNOPSIS
-.B mdbx_load
-[\c
-.BR \-V ]
-[\c
-.BR \-q ]
-[\c
-.BR \-a ]
-[\c
-.BI \-f \ file\fR]
-[\c
-.BI \-s \ subdb\fR]
-[\c
-.BR \-N ]
-[\c
-.BR \-T ]
-[\c
-.BR \-r ]
-[\c
-.BR \-n ]
-.BR \ dbpath
-.SH DESCRIPTION
-The
-.B mdbx_load
-utility reads from the standard input and loads it into the
-MDBX environment
-.BR dbpath .
-
-The input to
-.B mdbx_load
-must be in the output format specified by the
-.BR mdbx_dump (1)
-utility or as specified by the
-.B -T
-option below.
-
-A simple escape mechanism, where newline and backslash (\\) characters are special, is
-applied to the text input. Newline characters are interpreted as record separators.
-Backslash characters in the text will be interpreted in one of two ways: If the backslash
-character precedes another backslash character, the pair will be interpreted as a literal
-backslash. If the backslash character precedes any other character, the two characters
-following the backslash will be interpreted as a hexadecimal specification of a single
-character; for example, \\0a is a newline character in the ASCII character set.
-
-For this reason, any backslash or newline characters that naturally occur in the text
-input must be escaped to avoid misinterpretation by
-.BR mdbx_load .
-
-.SH OPTIONS
-.TP
-.BR \-V
-Write the library version number to the standard output, and exit.
-.TP
-.BR \-q
-Be quiet.
-.TP
-.BR \-a
-Append all records in the order they appear in the input. The input is assumed to already be
-in correctly sorted order and no sorting or checking for redundant values will be performed.
-This option must be used to reload data that was produced by running
-.B mdbx_dump
-on a database that uses custom compare functions.
-.TP
-.BR \-f \ file
-Read from the specified file instead of from the standard input.
-.TP
-.BR \-s \ subdb
-Load a specific subdatabase. If no database is specified, data is loaded into the main database.
-.TP
-.BR \-N
-Don't overwrite existing records when loading into an already existing database; just skip them.
-.TP
-.BR \-T
-Load data from simple text files. The input must be paired lines of text, where the first
-line of the pair is the key item, and the second line of the pair is its corresponding
-data item.
-.TP
-.BR \-r
-Rescure mode. Ignore errors to load corrupted DB dump.
-.TP
-.BR \-n
-Load an MDBX database which does not use subdirectories.
-This is legacy option. For now MDBX handles this automatically.
-
-.SH DIAGNOSTICS
-Exit status is zero if no errors occur.
-Errors result in a non-zero exit status and
-a diagnostic message being written to standard error.
-
-.SH "SEE ALSO"
-.BR mdbx_dump (1),
-.BR mdbx_chk (1),
-.BR mdbx_stat (1),
-.BR mdbx_copy (1)
-.BR mdbx_drop (1)
-.SH AUTHOR
-Howard Chu of Symas Corporation <http://www.symas.com>,
-Leonid Yuriev <https://gitflic.ru/user/erthink>
diff --git a/3rdparty/libmdbx/man1/mdbx_stat.1 b/3rdparty/libmdbx/man1/mdbx_stat.1
deleted file mode 100644
index 8055d6e1dd7c08b39a8e6f1cab52089bf22d9cec..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/man1/mdbx_stat.1
+++ /dev/null
@@ -1,86 +0,0 @@
-.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
-.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
-.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
-.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.TH MDBX_STAT 1 "2022-04-22" "MDBX 0.11.7"
-.SH NAME
-mdbx_stat \- MDBX environment status tool
-.SH SYNOPSIS
-.B mdbx_stat
-[\c
-.BR \-V ]
-[\c
-.BR \-q ]
-[\c
-.BR \-p ]
-[\c
-.BR \-e ]
-[\c
-.BR \-f [ f [ f ]]]
-[\c
-.BR \-r [ r ]]
-[\c
-.BR \-a \ |
-.BI \-s \ subdb\fR]
-.BR \ dbpath
-[\c
-.BR \-n ]
-.SH DESCRIPTION
-The
-.B mdbx_stat
-utility displays the status of an MDBX environment.
-.SH OPTIONS
-.TP
-.BR \-V
-Write the library version number to the standard output, and exit.
-.TP
-.BR \-q
-Be quiet.
-.TP
-.BR \-p
-Display overall statistics of page operations of all (running, completed
-and aborted) transactions in the current multi-process session (since the
-first process opened the database after everyone had previously closed it).
-.TP
-.BR \-e
-Display information about the database environment.
-.TP
-.BR \-f
-Display information about the environment GC.
-If \fB\-ff\fP is given, summarize each GC/freelist entry.
-If \fB\-fff\fP is given, display the full list of page IDs in the GC/freelist.
-.TP
-.BR \-r
-Display information about the environment reader table.
-Shows the process ID, thread ID, and transaction ID for each active
-reader slot. The process ID and transaction ID are in decimal, the
-thread ID is in hexadecimal. The transaction ID is displayed as "-"
-if the reader does not currently have a read transaction open.
-If \fB\-rr\fP is given, check for stale entries in the reader
-table and clear them. The reader table will be printed again
-after the check is performed.
-.TP
-.BR \-a
-Display the status of all of the subdatabases in the environment.
-.TP
-.BR \-s \ subdb
-Display the status of a specific subdatabase.
-.TP
-.BR \-n
-Display the status of an MDBX database which does not use subdirectories.
-This is legacy option. For now MDBX handles this automatically
-for existing databases, but may be required while creating new.
-
-.SH DIAGNOSTICS
-Exit status is zero if no errors occur.
-Errors result in a non-zero exit status and
-a diagnostic message being written to standard error.
-.SH "SEE ALSO"
-.BR mdbx_chk (1),
-.BR mdbx_copy (1),
-.BR mdbx_dump (1),
-.BR mdbx_load (1)
-.BR mdbx_drop (1)
-.SH AUTHOR
-Howard Chu of Symas Corporation <http://www.symas.com>,
-Leonid Yuriev <https://gitflic.ru/user/erthink>
diff --git a/3rdparty/libmdbx/mdbx.c b/3rdparty/libmdbx/mdbx.c
deleted file mode 100644
index a6db608ee4d17cc4a67e0cc44342f5658c34f42a..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx.c
+++ /dev/null
@@ -1,30924 +0,0 @@
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define xMDBX_ALLOY 1
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * This code is derived from "LMDB engine" written by
- * Howard Chu (Symas Corporation), which itself derived from btree.c
- * written by Martin Hedenfalk.
- *
- * ---
- *
- * Portions Copyright 2011-2015 Howard Chu, Symas Corp. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- *
- * ---
- *
- * Portions Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-
-/*------------------------------------------------------------------------------
- * Internal inline functions */
-
-MDBX_NOTHROW_CONST_FUNCTION static unsigned branchless_abs(int value) {
-  assert(value > INT_MIN);
-  const unsigned expanded_sign =
-      (unsigned)(value >> (sizeof(value) * CHAR_BIT - 1));
-  return ((unsigned)value + expanded_sign) ^ expanded_sign;
-}
-
-/* Pack/Unpack 16-bit values for Grow step & Shrink threshold */
-MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t me2v(unsigned m,
-                                                        unsigned e) {
-  assert(m < 2048 && e < 8);
-  return (pgno_t)(32768 + ((m + 1) << (e + 8)));
-}
-
-MDBX_NOTHROW_CONST_FUNCTION static __inline uint16_t v2me(size_t v,
-                                                          unsigned e) {
-  assert(v > (e ? me2v(2047, e - 1) : 32768));
-  assert(v <= me2v(2047, e));
-  size_t m = (v - 32768 + ((size_t)1 << (e + 8)) - 1) >> (e + 8);
-  m -= m > 0;
-  assert(m < 2048 && e < 8);
-  // f e d c b a 9 8 7 6 5 4 3 2 1 0
-  // 1 e e e m m m m m m m m m m m 1
-  const uint16_t pv = (uint16_t)(0x8001 + (e << 12) + (m << 1));
-  assert(pv != 65535);
-  return pv;
-}
-
-/* Convert 16-bit packed (exponential quantized) value to number of pages */
-MDBX_NOTHROW_CONST_FUNCTION static pgno_t pv2pages(uint16_t pv) {
-  if ((pv & 0x8001) != 0x8001)
-    return pv;
-  if (pv == 65535)
-    return 65536;
-  // f e d c b a 9 8 7 6 5 4 3 2 1 0
-  // 1 e e e m m m m m m m m m m m 1
-  return me2v((pv >> 1) & 2047, (pv >> 12) & 7);
-}
-
-/* Convert number of pages to 16-bit packed (exponential quantized) value */
-MDBX_NOTHROW_CONST_FUNCTION static uint16_t pages2pv(size_t pages) {
-  if (pages < 32769 || (pages < 65536 && (pages & 1) == 0))
-    return (uint16_t)pages;
-  if (pages <= me2v(2047, 0))
-    return v2me(pages, 0);
-  if (pages <= me2v(2047, 1))
-    return v2me(pages, 1);
-  if (pages <= me2v(2047, 2))
-    return v2me(pages, 2);
-  if (pages <= me2v(2047, 3))
-    return v2me(pages, 3);
-  if (pages <= me2v(2047, 4))
-    return v2me(pages, 4);
-  if (pages <= me2v(2047, 5))
-    return v2me(pages, 5);
-  if (pages <= me2v(2047, 6))
-    return v2me(pages, 6);
-  return (pages < me2v(2046, 7)) ? v2me(pages, 7) : 65533;
-}
-
-/*------------------------------------------------------------------------------
- * Unaligned access */
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline unsigned
-field_alignment(unsigned alignment_baseline, size_t field_offset) {
-  unsigned merge = alignment_baseline | (unsigned)field_offset;
-  return merge & -(int)merge;
-}
-
-/* read-thunk for UB-sanitizer */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint8_t
-peek_u8(const uint8_t *const __restrict ptr) {
-  return *ptr;
-}
-
-/* write-thunk for UB-sanitizer */
-static __always_inline void poke_u8(uint8_t *const __restrict ptr,
-                                    const uint8_t v) {
-  *ptr = v;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint16_t
-unaligned_peek_u16(const unsigned expected_alignment, const void *const ptr) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  if (MDBX_UNALIGNED_OK >= 2 || (expected_alignment % sizeof(uint16_t)) == 0)
-    return *(const uint16_t *)ptr;
-  else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    return *(const __unaligned uint16_t *)ptr;
-#else
-    uint16_t v;
-    memcpy(&v, ptr, sizeof(v));
-    return v;
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-static __always_inline void
-unaligned_poke_u16(const unsigned expected_alignment,
-                   void *const __restrict ptr, const uint16_t v) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  if (MDBX_UNALIGNED_OK >= 2 || (expected_alignment % sizeof(v)) == 0)
-    *(uint16_t *)ptr = v;
-  else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    *((uint16_t __unaligned *)ptr) = v;
-#else
-    memcpy(ptr, &v, sizeof(v));
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint32_t unaligned_peek_u32(
-    const unsigned expected_alignment, const void *const __restrict ptr) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  if (MDBX_UNALIGNED_OK >= 4 || (expected_alignment % sizeof(uint32_t)) == 0)
-    return *(const uint32_t *)ptr;
-  else if ((expected_alignment % sizeof(uint16_t)) == 0) {
-    const uint16_t lo =
-        ((const uint16_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__];
-    const uint16_t hi =
-        ((const uint16_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__];
-    return lo | (uint32_t)hi << 16;
-  } else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    return *(const __unaligned uint32_t *)ptr;
-#else
-    uint32_t v;
-    memcpy(&v, ptr, sizeof(v));
-    return v;
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-static __always_inline void
-unaligned_poke_u32(const unsigned expected_alignment,
-                   void *const __restrict ptr, const uint32_t v) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  if (MDBX_UNALIGNED_OK >= 4 || (expected_alignment % sizeof(v)) == 0)
-    *(uint32_t *)ptr = v;
-  else if ((expected_alignment % sizeof(uint16_t)) == 0) {
-    ((uint16_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__] = (uint16_t)v;
-    ((uint16_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__] =
-        (uint16_t)(v >> 16);
-  } else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    *((uint32_t __unaligned *)ptr) = v;
-#else
-    memcpy(ptr, &v, sizeof(v));
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint64_t unaligned_peek_u64(
-    const unsigned expected_alignment, const void *const __restrict ptr) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  if (MDBX_UNALIGNED_OK >= 8 || (expected_alignment % sizeof(uint64_t)) == 0)
-    return *(const uint64_t *)ptr;
-  else if ((expected_alignment % sizeof(uint32_t)) == 0) {
-    const uint32_t lo =
-        ((const uint32_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__];
-    const uint32_t hi =
-        ((const uint32_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__];
-    return lo | (uint64_t)hi << 32;
-  } else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    return *(const __unaligned uint64_t *)ptr;
-#else
-    uint64_t v;
-    memcpy(&v, ptr, sizeof(v));
-    return v;
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-static __always_inline uint64_t
-unaligned_peek_u64_volatile(const unsigned expected_alignment,
-                            volatile const void *const __restrict ptr) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  assert(expected_alignment % sizeof(uint32_t) == 0);
-  if (MDBX_UNALIGNED_OK >= 8 || (expected_alignment % sizeof(uint64_t)) == 0)
-    return *(volatile const uint64_t *)ptr;
-  else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    return *(volatile const __unaligned uint64_t *)ptr;
-#else
-    const uint32_t lo = ((volatile const uint32_t *)
-                             ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__];
-    const uint32_t hi = ((volatile const uint32_t *)
-                             ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__];
-    return lo | (uint64_t)hi << 32;
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-static __always_inline void
-unaligned_poke_u64(const unsigned expected_alignment,
-                   void *const __restrict ptr, const uint64_t v) {
-  assert((uintptr_t)ptr % expected_alignment == 0);
-  if (MDBX_UNALIGNED_OK >= 8 || (expected_alignment % sizeof(v)) == 0)
-    *(uint64_t *)ptr = v;
-  else if ((expected_alignment % sizeof(uint32_t)) == 0) {
-    ((uint32_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__] = (uint32_t)v;
-    ((uint32_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__] =
-        (uint32_t)(v >> 32);
-  } else {
-#if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) ||            \
-    defined(_M_X64) || defined(_M_IA64)
-    *((uint64_t __unaligned *)ptr) = v;
-#else
-    memcpy(ptr, &v, sizeof(v));
-#endif /* _MSC_VER || __unaligned */
-  }
-}
-
-#define UNALIGNED_PEEK_8(ptr, struct, field)                                   \
-  peek_u8((const uint8_t *)(ptr) + offsetof(struct, field))
-#define UNALIGNED_POKE_8(ptr, struct, field, value)                            \
-  poke_u8((uint8_t *)(ptr) + offsetof(struct, field), value)
-
-#define UNALIGNED_PEEK_16(ptr, struct, field)                                  \
-  unaligned_peek_u16(1, (const char *)(ptr) + offsetof(struct, field))
-#define UNALIGNED_POKE_16(ptr, struct, field, value)                           \
-  unaligned_poke_u16(1, (char *)(ptr) + offsetof(struct, field), value)
-
-#define UNALIGNED_PEEK_32(ptr, struct, field)                                  \
-  unaligned_peek_u32(1, (const char *)(ptr) + offsetof(struct, field))
-#define UNALIGNED_POKE_32(ptr, struct, field, value)                           \
-  unaligned_poke_u32(1, (char *)(ptr) + offsetof(struct, field), value)
-
-#define UNALIGNED_PEEK_64(ptr, struct, field)                                  \
-  unaligned_peek_u64(1, (const char *)(ptr) + offsetof(struct, field))
-#define UNALIGNED_POKE_64(ptr, struct, field, value)                           \
-  unaligned_poke_u64(1, (char *)(ptr) + offsetof(struct, field), value)
-
-/* Get the page number pointed to by a branch node */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline pgno_t
-node_pgno(const MDBX_node *const __restrict node) {
-  pgno_t pgno = UNALIGNED_PEEK_32(node, MDBX_node, mn_pgno32);
-  if (sizeof(pgno) > 4)
-    pgno |= ((uint64_t)UNALIGNED_PEEK_8(node, MDBX_node, mn_extra)) << 32;
-  return pgno;
-}
-
-/* Set the page number in a branch node */
-static __always_inline void node_set_pgno(MDBX_node *const __restrict node,
-                                          pgno_t pgno) {
-  assert(pgno >= MIN_PAGENO && pgno <= MAX_PAGENO);
-
-  UNALIGNED_POKE_32(node, MDBX_node, mn_pgno32, (uint32_t)pgno);
-  if (sizeof(pgno) > 4)
-    UNALIGNED_POKE_8(node, MDBX_node, mn_extra,
-                     (uint8_t)((uint64_t)pgno >> 32));
-}
-
-/* Get the size of the data in a leaf node */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
-node_ds(const MDBX_node *const __restrict node) {
-  return UNALIGNED_PEEK_32(node, MDBX_node, mn_dsize);
-}
-
-/* Set the size of the data for a leaf node */
-static __always_inline void node_set_ds(MDBX_node *const __restrict node,
-                                        size_t size) {
-  assert(size < INT_MAX);
-  UNALIGNED_POKE_32(node, MDBX_node, mn_dsize, (uint32_t)size);
-}
-
-/* The size of a key in a node */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
-node_ks(const MDBX_node *const __restrict node) {
-  return UNALIGNED_PEEK_16(node, MDBX_node, mn_ksize);
-}
-
-/* Set the size of the key for a leaf node */
-static __always_inline void node_set_ks(MDBX_node *const __restrict node,
-                                        size_t size) {
-  assert(size < INT16_MAX);
-  UNALIGNED_POKE_16(node, MDBX_node, mn_ksize, (uint16_t)size);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint8_t
-node_flags(const MDBX_node *const __restrict node) {
-  return UNALIGNED_PEEK_8(node, MDBX_node, mn_flags);
-}
-
-static __always_inline void node_set_flags(MDBX_node *const __restrict node,
-                                           uint8_t flags) {
-  UNALIGNED_POKE_8(node, MDBX_node, mn_flags, flags);
-}
-
-/* Size of the node header, excluding dynamic data at the end */
-#define NODESIZE offsetof(MDBX_node, mn_data)
-
-/* Address of the key for the node */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline void *
-node_key(const MDBX_node *const __restrict node) {
-  return (char *)node + NODESIZE;
-}
-
-/* Address of the data for a node */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline void *
-node_data(const MDBX_node *const __restrict node) {
-  return (char *)node_key(node) + node_ks(node);
-}
-
-/* Size of a node in a leaf page with a given key and data.
- * This is node header plus key plus data size. */
-MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-node_size_len(const size_t key_len, const size_t value_len) {
-  return NODESIZE + EVEN(key_len + value_len);
-}
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
-node_size(const MDBX_val *key, const MDBX_val *value) {
-  return node_size_len(key ? key->iov_len : 0, value ? value->iov_len : 0);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline pgno_t
-peek_pgno(const void *const __restrict ptr) {
-  if (sizeof(pgno_t) == sizeof(uint32_t))
-    return (pgno_t)unaligned_peek_u32(1, ptr);
-  else if (sizeof(pgno_t) == sizeof(uint64_t))
-    return (pgno_t)unaligned_peek_u64(1, ptr);
-  else {
-    pgno_t pgno;
-    memcpy(&pgno, ptr, sizeof(pgno));
-    return pgno;
-  }
-}
-
-static __always_inline void poke_pgno(void *const __restrict ptr,
-                                      const pgno_t pgno) {
-  if (sizeof(pgno) == sizeof(uint32_t))
-    unaligned_poke_u32(1, ptr, pgno);
-  else if (sizeof(pgno) == sizeof(uint64_t))
-    unaligned_poke_u64(1, ptr, pgno);
-  else
-    memcpy(ptr, &pgno, sizeof(pgno));
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline pgno_t
-node_largedata_pgno(const MDBX_node *const __restrict node) {
-  assert(node_flags(node) & F_BIGDATA);
-  return peek_pgno(node_data(node));
-}
-
-/*------------------------------------------------------------------------------
- * Nodes, Keys & Values length limitation factors:
- *
- * BRANCH_NODE_MAX
- *   Branch-page must contain at least two nodes, within each a key and a child
- *   page number. But page can't be splitted if it contains less that 4 keys,
- *   i.e. a page should not overflow before adding the fourth key. Therefore,
- *   at least 3 branch-node should fit in the single branch-page. Further, the
- *   first node of a branch-page doesn't contain a key, i.e. the first node
- *   is always require space just for itself. Thus:
- *       PAGEROOM = pagesize - page_hdr_len;
- *       BRANCH_NODE_MAX = even_floor(
- *         (PAGEROOM - sizeof(indx_t) - NODESIZE) / (3 - 1) - sizeof(indx_t));
- *       KEYLEN_MAX = BRANCH_NODE_MAX - node_hdr_len;
- *
- * LEAF_NODE_MAX
- *   Leaf-node must fit into single leaf-page, where a value could be placed on
- *   a large/overflow page. However, may require to insert a nearly page-sized
- *   node between two large nodes are already fill-up a page. In this case the
- *   page must be splitted to two if some pair of nodes fits on one page, or
- *   otherwise the page should be splitted to the THREE with a single node
- *   per each of ones. Such 1-into-3 page splitting is costly and complex since
- *   requires TWO insertion into the parent page, that could lead to split it
- *   and so on up to the root. Therefore double-splitting is avoided here and
- *   the maximum node size is half of a leaf page space:
- *       LEAF_NODE_MAX = even_floor(PAGEROOM / 2 - sizeof(indx_t));
- *       DATALEN_NO_OVERFLOW = LEAF_NODE_MAX - KEYLEN_MAX;
- *
- *  - SubDatabase-node must fit into one leaf-page:
- *       SUBDB_NAME_MAX = LEAF_NODE_MAX - node_hdr_len - sizeof(MDBX_db);
- *
- *  - Dupsort values itself are a keys in a dupsort-subdb and couldn't be longer
- *    than the KEYLEN_MAX. But dupsort node must not great than LEAF_NODE_MAX,
- *    since dupsort value couldn't be placed on a large/overflow page:
- *       DUPSORT_DATALEN_MAX = min(KEYLEN_MAX,
- *                                 max(DATALEN_NO_OVERFLOW, sizeof(MDBX_db));
- */
-
-#define PAGEROOM(pagesize) ((pagesize)-PAGEHDRSZ)
-#define EVEN_FLOOR(n) ((n) & ~(size_t)1)
-#define BRANCH_NODE_MAX(pagesize)                                              \
-  (EVEN_FLOOR((PAGEROOM(pagesize) - sizeof(indx_t) - NODESIZE) / (3 - 1) -     \
-              sizeof(indx_t)))
-#define LEAF_NODE_MAX(pagesize)                                                \
-  (EVEN_FLOOR(PAGEROOM(pagesize) / 2) - sizeof(indx_t))
-#define MAX_GC1OVPAGE(pagesize) (PAGEROOM(pagesize) / sizeof(pgno_t) - 1)
-
-static __inline unsigned keysize_max(size_t pagesize, MDBX_db_flags_t flags) {
-  assert(pagesize >= MIN_PAGESIZE && pagesize <= MAX_PAGESIZE &&
-         is_powerof2(pagesize));
-  STATIC_ASSERT(BRANCH_NODE_MAX(MIN_PAGESIZE) - NODESIZE >= 8);
-  if (flags & MDBX_INTEGERKEY)
-    return 8 /* sizeof(uint64_t) */;
-
-  const intptr_t max_branch_key = BRANCH_NODE_MAX(pagesize) - NODESIZE;
-  STATIC_ASSERT(LEAF_NODE_MAX(MIN_PAGESIZE) - NODESIZE -
-                    /* sizeof(uint64) as a key */ 8 >
-                sizeof(MDBX_db));
-  if (flags &
-      (MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_REVERSEDUP | MDBX_INTEGERDUP)) {
-    const intptr_t max_dupsort_leaf_key =
-        LEAF_NODE_MAX(pagesize) - NODESIZE - sizeof(MDBX_db);
-    return (max_branch_key < max_dupsort_leaf_key)
-               ? (unsigned)max_branch_key
-               : (unsigned)max_dupsort_leaf_key;
-  }
-  return (unsigned)max_branch_key;
-}
-
-static __inline size_t valsize_max(size_t pagesize, MDBX_db_flags_t flags) {
-  assert(pagesize >= MIN_PAGESIZE && pagesize <= MAX_PAGESIZE &&
-         is_powerof2(pagesize));
-
-  if (flags & MDBX_INTEGERDUP)
-    return 8 /* sizeof(uint64_t) */;
-
-  if (flags & (MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_REVERSEDUP))
-    return keysize_max(pagesize, 0);
-
-  const unsigned page_ln2 = log2n_powerof2(pagesize);
-  const size_t hard = 0x7FF00000ul;
-  const size_t hard_pages = hard >> page_ln2;
-  STATIC_ASSERT(MDBX_PGL_LIMIT <= MAX_PAGENO);
-  const size_t pages_limit = MDBX_PGL_LIMIT / 4;
-  const size_t limit =
-      (hard_pages < pages_limit) ? hard : (pages_limit << page_ln2);
-  return (limit < MAX_MAPSIZE / 2) ? limit : MAX_MAPSIZE / 2;
-}
-
-__cold int mdbx_env_get_maxkeysize(const MDBX_env *env) {
-  return mdbx_env_get_maxkeysize_ex(env, MDBX_DUPSORT);
-}
-
-__cold int mdbx_env_get_maxkeysize_ex(const MDBX_env *env,
-                                      MDBX_db_flags_t flags) {
-  if (unlikely(!env || env->me_signature.weak != MDBX_ME_SIGNATURE))
-    return -1;
-
-  return (int)mdbx_limits_keysize_max((intptr_t)env->me_psize, flags);
-}
-
-size_t mdbx_default_pagesize(void) {
-  size_t pagesize = mdbx_syspagesize();
-  mdbx_ensure(nullptr, is_powerof2(pagesize));
-  pagesize = (pagesize >= MIN_PAGESIZE) ? pagesize : MIN_PAGESIZE;
-  pagesize = (pagesize <= MAX_PAGESIZE) ? pagesize : MAX_PAGESIZE;
-  return pagesize;
-}
-
-__cold intptr_t mdbx_limits_keysize_max(intptr_t pagesize,
-                                        MDBX_db_flags_t flags) {
-  if (pagesize < 1)
-    pagesize = (intptr_t)mdbx_default_pagesize();
-  if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
-               pagesize > (intptr_t)MAX_PAGESIZE ||
-               !is_powerof2((size_t)pagesize)))
-    return -1;
-
-  return keysize_max(pagesize, flags);
-}
-
-__cold int mdbx_env_get_maxvalsize_ex(const MDBX_env *env,
-                                      MDBX_db_flags_t flags) {
-  if (unlikely(!env || env->me_signature.weak != MDBX_ME_SIGNATURE))
-    return -1;
-
-  return (int)mdbx_limits_valsize_max((intptr_t)env->me_psize, flags);
-}
-
-__cold intptr_t mdbx_limits_valsize_max(intptr_t pagesize,
-                                        MDBX_db_flags_t flags) {
-  if (pagesize < 1)
-    pagesize = (intptr_t)mdbx_default_pagesize();
-  if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
-               pagesize > (intptr_t)MAX_PAGESIZE ||
-               !is_powerof2((size_t)pagesize)))
-    return -1;
-
-  return valsize_max(pagesize, flags);
-}
-
-/* Calculate the size of a leaf node.
- *
- * The size depends on the environment's page size; if a data item
- * is too large it will be put onto an overflow page and the node
- * size will only include the key and not the data. Sizes are always
- * rounded up to an even number of bytes, to guarantee 2-byte alignment
- * of the MDBX_node headers. */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
-leaf_size(const MDBX_env *env, const MDBX_val *key, const MDBX_val *data) {
-  size_t node_bytes = node_size(key, data);
-  if (node_bytes > env->me_leaf_nodemax) {
-    /* put on overflow page */
-    node_bytes = node_size_len(key->iov_len, 0) + sizeof(pgno_t);
-  }
-
-  return node_bytes + sizeof(indx_t);
-}
-
-/* Calculate the size of a branch node.
- *
- * The size should depend on the environment's page size but since
- * we currently don't support spilling large keys onto overflow
- * pages, it's simply the size of the MDBX_node header plus the
- * size of the key. Sizes are always rounded up to an even number
- * of bytes, to guarantee 2-byte alignment of the MDBX_node headers.
- *
- * [in] env The environment handle.
- * [in] key The key for the node.
- *
- * Returns The number of bytes needed to store the node. */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
-branch_size(const MDBX_env *env, const MDBX_val *key) {
-  /* Size of a node in a branch page with a given key.
-   * This is just the node header plus the key, there is no data. */
-  size_t node_bytes = node_size(key, nullptr);
-  if (unlikely(node_bytes > env->me_leaf_nodemax)) {
-    /* put on overflow page */
-    /* not implemented */
-    mdbx_assert_fail(env, "INDXSIZE(key) <= env->me_nodemax", __func__,
-                     __LINE__);
-    node_bytes = node_size(key, nullptr) + sizeof(pgno_t);
-  }
-
-  return node_bytes + sizeof(indx_t);
-}
-
-MDBX_NOTHROW_CONST_FUNCTION static __always_inline uint16_t
-flags_db2sub(uint16_t db_flags) {
-  uint16_t sub_flags = db_flags & MDBX_DUPFIXED;
-
-  /* MDBX_INTEGERDUP => MDBX_INTEGERKEY */
-#define SHIFT_INTEGERDUP_TO_INTEGERKEY 2
-  STATIC_ASSERT((MDBX_INTEGERDUP >> SHIFT_INTEGERDUP_TO_INTEGERKEY) ==
-                MDBX_INTEGERKEY);
-  sub_flags |= (db_flags & MDBX_INTEGERDUP) >> SHIFT_INTEGERDUP_TO_INTEGERKEY;
-
-  /* MDBX_REVERSEDUP => MDBX_REVERSEKEY */
-#define SHIFT_REVERSEDUP_TO_REVERSEKEY 5
-  STATIC_ASSERT((MDBX_REVERSEDUP >> SHIFT_REVERSEDUP_TO_REVERSEKEY) ==
-                MDBX_REVERSEKEY);
-  sub_flags |= (db_flags & MDBX_REVERSEDUP) >> SHIFT_REVERSEDUP_TO_REVERSEKEY;
-
-  return sub_flags;
-}
-
-/*----------------------------------------------------------------------------*/
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline size_t
-pgno2bytes(const MDBX_env *env, pgno_t pgno) {
-  mdbx_assert(env, (1u << env->me_psize2log) == env->me_psize);
-  return ((size_t)pgno) << env->me_psize2log;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline MDBX_page *
-pgno2page(const MDBX_env *env, pgno_t pgno) {
-  return (MDBX_page *)(env->me_map + pgno2bytes(env, pgno));
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline pgno_t
-bytes2pgno(const MDBX_env *env, size_t bytes) {
-  mdbx_assert(env, (env->me_psize >> env->me_psize2log) == 1);
-  return (pgno_t)(bytes >> env->me_psize2log);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static size_t
-pgno_align2os_bytes(const MDBX_env *env, pgno_t pgno) {
-  return ceil_powerof2(pgno2bytes(env, pgno), env->me_os_psize);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static pgno_t pgno_align2os_pgno(const MDBX_env *env,
-                                                            pgno_t pgno) {
-  return bytes2pgno(env, pgno_align2os_bytes(env, pgno));
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static size_t
-bytes_align2os_bytes(const MDBX_env *env, size_t bytes) {
-  return ceil_powerof2(ceil_powerof2(bytes, env->me_psize), env->me_os_psize);
-}
-
-/* Address of first usable data byte in a page, after the header */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline void *
-page_data(const MDBX_page *mp) {
-  return (char *)mp + PAGEHDRSZ;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline const MDBX_page *
-data_page(const void *data) {
-  return container_of(data, MDBX_page, mp_ptrs);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline MDBX_meta *
-page_meta(MDBX_page *mp) {
-  return (MDBX_meta *)page_data(mp);
-}
-
-/* Number of nodes on a page */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline unsigned
-page_numkeys(const MDBX_page *mp) {
-  return mp->mp_lower >> 1;
-}
-
-/* The amount of space remaining in the page */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline unsigned
-page_room(const MDBX_page *mp) {
-  return mp->mp_upper - mp->mp_lower;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline unsigned
-page_space(const MDBX_env *env) {
-  STATIC_ASSERT(PAGEHDRSZ % 2 == 0);
-  return env->me_psize - PAGEHDRSZ;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline unsigned
-page_used(const MDBX_env *env, const MDBX_page *mp) {
-  return page_space(env) - page_room(mp);
-}
-
-/* The percentage of space used in the page, in a percents. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static __inline double
-page_fill(const MDBX_env *env, const MDBX_page *mp) {
-  return page_used(env, mp) * 100.0 / page_space(env);
-}
-
-/* The number of overflow pages needed to store the given size. */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline pgno_t
-number_of_ovpages(const MDBX_env *env, size_t bytes) {
-  return bytes2pgno(env, PAGEHDRSZ - 1 + bytes) + 1;
-}
-
-__cold static int MDBX_PRINTF_ARGS(2, 3)
-    bad_page(const MDBX_page *mp, const char *fmt, ...) {
-  if (mdbx_log_enabled(MDBX_LOG_ERROR)) {
-    static const MDBX_page *prev;
-    if (prev != mp) {
-      prev = mp;
-      const char *type;
-      switch (mp->mp_flags & (P_BRANCH | P_LEAF | P_OVERFLOW | P_META |
-                              P_LEAF2 | P_BAD | P_SUBP)) {
-      case P_BRANCH:
-        type = "branch";
-        break;
-      case P_LEAF:
-        type = "leaf";
-        break;
-      case P_LEAF | P_SUBP:
-        type = "subleaf";
-        break;
-      case P_LEAF | P_LEAF2:
-        type = "dupfixed-leaf";
-        break;
-      case P_LEAF | P_LEAF2 | P_SUBP:
-        type = "dupfixed-subleaf";
-        break;
-      case P_OVERFLOW:
-        type = "large";
-        break;
-      default:
-        type = "broken";
-      }
-      mdbx_debug_log(MDBX_LOG_ERROR, "badpage", 0,
-                     "corrupted %s-page #%u, mod-txnid %" PRIaTXN "\n", type,
-                     mp->mp_pgno, mp->mp_txnid);
-    }
-
-    va_list args;
-    va_start(args, fmt);
-    mdbx_debug_log_va(MDBX_LOG_ERROR, "badpage", 0, fmt, args);
-    va_end(args);
-  }
-  return MDBX_CORRUPTED;
-}
-
-/* Address of node i in page p */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline MDBX_node *
-page_node(const MDBX_page *mp, unsigned i) {
-  assert((mp->mp_flags & (P_LEAF2 | P_OVERFLOW | P_META)) == 0);
-  assert(page_numkeys(mp) > (unsigned)(i));
-  assert(mp->mp_ptrs[i] % 2 == 0);
-  return (MDBX_node *)((char *)mp + mp->mp_ptrs[i] + PAGEHDRSZ);
-}
-
-/* The address of a key in a LEAF2 page.
- * LEAF2 pages are used for MDBX_DUPFIXED sorted-duplicate sub-DBs.
- * There are no node headers, keys are stored contiguously. */
-MDBX_NOTHROW_PURE_FUNCTION static __always_inline void *
-page_leaf2key(const MDBX_page *mp, unsigned i, size_t keysize) {
-  assert((mp->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_META)) ==
-         (P_LEAF | P_LEAF2));
-  assert(mp->mp_leaf2_ksize == keysize);
-  (void)keysize;
-  return (char *)mp + PAGEHDRSZ + (i * mp->mp_leaf2_ksize);
-}
-
-/* Set the node's key into keyptr. */
-static __always_inline void get_key(const MDBX_node *node, MDBX_val *keyptr) {
-  keyptr->iov_len = node_ks(node);
-  keyptr->iov_base = node_key(node);
-}
-
-/* Set the node's key into keyptr, if requested. */
-static __always_inline void
-get_key_optional(const MDBX_node *node, MDBX_val *keyptr /* __may_null */) {
-  if (keyptr)
-    get_key(node, keyptr);
-}
-
-/*------------------------------------------------------------------------------
- * Workaround for mmaped-lookahead-cross-page-boundary bug
- * in an obsolete versions of Elbrus's libc and kernels. */
-#if defined(__e2k__) && defined(MDBX_E2K_MLHCPB_WORKAROUND) &&                 \
-    MDBX_E2K_MLHCPB_WORKAROUND
-int __hot mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
-                                         size_t n) {
-  if (unlikely(n > 42
-               /* LY: align followed access if reasonable possible */
-               && (((uintptr_t)s1) & 7) != 0 &&
-               (((uintptr_t)s1) & 7) == (((uintptr_t)s2) & 7))) {
-    if (((uintptr_t)s1) & 1) {
-      const int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
-      if (diff)
-        return diff;
-      s1 = (char *)s1 + 1;
-      s2 = (char *)s2 + 1;
-      n -= 1;
-    }
-
-    if (((uintptr_t)s1) & 2) {
-      const uint16_t a = *(uint16_t *)s1;
-      const uint16_t b = *(uint16_t *)s2;
-      if (likely(a != b))
-        return (__builtin_bswap16(a) > __builtin_bswap16(b)) ? 1 : -1;
-      s1 = (char *)s1 + 2;
-      s2 = (char *)s2 + 2;
-      n -= 2;
-    }
-
-    if (((uintptr_t)s1) & 4) {
-      const uint32_t a = *(uint32_t *)s1;
-      const uint32_t b = *(uint32_t *)s2;
-      if (likely(a != b))
-        return (__builtin_bswap32(a) > __builtin_bswap32(b)) ? 1 : -1;
-      s1 = (char *)s1 + 4;
-      s2 = (char *)s2 + 4;
-      n -= 4;
-    }
-  }
-
-  while (n >= 8) {
-    const uint64_t a = *(uint64_t *)s1;
-    const uint64_t b = *(uint64_t *)s2;
-    if (likely(a != b))
-      return (__builtin_bswap64(a) > __builtin_bswap64(b)) ? 1 : -1;
-    s1 = (char *)s1 + 8;
-    s2 = (char *)s2 + 8;
-    n -= 8;
-  }
-
-  if (n & 4) {
-    const uint32_t a = *(uint32_t *)s1;
-    const uint32_t b = *(uint32_t *)s2;
-    if (likely(a != b))
-      return (__builtin_bswap32(a) > __builtin_bswap32(b)) ? 1 : -1;
-    s1 = (char *)s1 + 4;
-    s2 = (char *)s2 + 4;
-  }
-
-  if (n & 2) {
-    const uint16_t a = *(uint16_t *)s1;
-    const uint16_t b = *(uint16_t *)s2;
-    if (likely(a != b))
-      return (__builtin_bswap16(a) > __builtin_bswap16(b)) ? 1 : -1;
-    s1 = (char *)s1 + 2;
-    s2 = (char *)s2 + 2;
-  }
-
-  return (n & 1) ? *(uint8_t *)s1 - *(uint8_t *)s2 : 0;
-}
-
-int __hot mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2) {
-  while (true) {
-    int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
-    if (likely(diff != 0) || *s1 == '\0')
-      return diff;
-    s1 += 1;
-    s2 += 1;
-  }
-}
-
-int __hot mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
-                                          size_t n) {
-  while (n > 0) {
-    int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
-    if (likely(diff != 0) || *s1 == '\0')
-      return diff;
-    s1 += 1;
-    s2 += 1;
-    n -= 1;
-  }
-  return 0;
-}
-
-size_t __hot mdbx_e2k_strlen_bug_workaround(const char *s) {
-  size_t n = 0;
-  while (*s) {
-    s += 1;
-    n += 1;
-  }
-  return n;
-}
-
-size_t __hot mdbx_e2k_strnlen_bug_workaround(const char *s, size_t maxlen) {
-  size_t n = 0;
-  while (maxlen > n && *s) {
-    s += 1;
-    n += 1;
-  }
-  return n;
-}
-#endif /* MDBX_E2K_MLHCPB_WORKAROUND */
-
-/*------------------------------------------------------------------------------
- * safe read/write volatile 64-bit fields on 32-bit architectures. */
-
-MDBX_MAYBE_UNUSED static __always_inline uint64_t
-atomic_store64(MDBX_atomic_uint64_t *p, const uint64_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8);
-#if MDBX_64BIT_ATOMIC
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint64_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint64_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-#else  /* !MDBX_64BIT_ATOMIC */
-  mdbx_compiler_barrier();
-  atomic_store32(&p->low, (uint32_t)value, mo_Relaxed);
-  mdbx_jitter4testing(true);
-  atomic_store32(&p->high, (uint32_t)(value >> 32), order);
-  mdbx_jitter4testing(true);
-#endif /* !MDBX_64BIT_ATOMIC */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static
-#if MDBX_64BIT_ATOMIC
-    __always_inline
-#endif /* MDBX_64BIT_ATOMIC */
-        uint64_t
-        atomic_load64(const MDBX_atomic_uint64_t *p,
-                      enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8);
-#if MDBX_64BIT_ATOMIC
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint64_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint64_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint64_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-#else  /* !MDBX_64BIT_ATOMIC */
-  mdbx_compiler_barrier();
-  uint64_t value = (uint64_t)atomic_load32(&p->high, order) << 32;
-  mdbx_jitter4testing(true);
-  value |= atomic_load32(&p->low, (order == mo_Relaxed) ? mo_Relaxed
-                                                        : mo_AcquireRelease);
-  mdbx_jitter4testing(true);
-  for (;;) {
-    mdbx_compiler_barrier();
-    uint64_t again = (uint64_t)atomic_load32(&p->high, order) << 32;
-    mdbx_jitter4testing(true);
-    again |= atomic_load32(&p->low, (order == mo_Relaxed) ? mo_Relaxed
-                                                          : mo_AcquireRelease);
-    mdbx_jitter4testing(true);
-    if (likely(value == again))
-      return value;
-    value = again;
-  }
-#endif /* !MDBX_64BIT_ATOMIC */
-}
-
-static __always_inline void atomic_yield(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  YieldProcessor();
-#elif defined(__ia32__) || defined(__e2k__)
-  __builtin_ia32_pause();
-#elif defined(__ia64__)
-#if defined(__HP_cc__) || defined(__HP_aCC__)
-  _Asm_hint(_HINT_PAUSE);
-#else
-  __asm__ __volatile__("hint @pause");
-#endif
-#elif defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH > 6) ||       \
-    defined(__ARM_ARCH_6K__)
-#ifdef __CC_ARM
-  __yield();
-#else
-  __asm__ __volatile__("yield");
-#endif
-#elif (defined(__mips64) || defined(__mips64__)) && defined(__mips_isa_rev) && \
-    __mips_isa_rev >= 2
-  __asm__ __volatile__("pause");
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-  __asm__ __volatile__(".word 0x00000140");
-#elif defined(__linux__) || defined(__gnu_linux__) || defined(_UNIX03_SOURCE)
-  sched_yield();
-#elif (defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 1)) || defined(_OPEN_THREADS)
-  pthread_yield();
-#endif
-}
-
-#if MDBX_64BIT_CAS
-static __always_inline bool atomic_cas64(MDBX_atomic_uint64_t *p, uint64_t c,
-                                         uint64_t v) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  STATIC_ASSERT(sizeof(long long) >= sizeof(uint64_t));
-#ifdef ATOMIC_LLONG_LOCK_FREE
-  STATIC_ASSERT(ATOMIC_LLONG_LOCK_FREE > 0);
-#if ATOMIC_LLONG_LOCK_FREE < 2
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint64_t, p)));
-#endif /* ATOMIC_LLONG_LOCK_FREE < 2 */
-#else  /* defined(ATOMIC_LLONG_LOCK_FREE) */
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint64_t, p)));
-#endif
-  return atomic_compare_exchange_strong(MDBX_c11a_rw(uint64_t, p), &c, v);
-#elif defined(__GNUC__) || defined(__clang__)
-  return __sync_bool_compare_and_swap(&p->weak, c, v);
-#elif defined(_MSC_VER)
-  return c == (uint64_t)_InterlockedCompareExchange64(
-                  (volatile __int64 *)&p->weak, v, c);
-#elif defined(__APPLE__)
-  return OSAtomicCompareAndSwap64Barrier(c, v, &p->weak);
-#else
-#error FIXME: Unsupported compiler
-#endif
-}
-#endif /* MDBX_64BIT_CAS */
-
-static __always_inline bool atomic_cas32(MDBX_atomic_uint32_t *p, uint32_t c,
-                                         uint32_t v) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t));
-#ifdef ATOMIC_INT_LOCK_FREE
-  STATIC_ASSERT(ATOMIC_INT_LOCK_FREE > 0);
-#if ATOMIC_INT_LOCK_FREE < 2
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-#endif
-#else
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-#endif
-  return atomic_compare_exchange_strong(MDBX_c11a_rw(uint32_t, p), &c, v);
-#elif defined(__GNUC__) || defined(__clang__)
-  return __sync_bool_compare_and_swap(&p->weak, c, v);
-#elif defined(_MSC_VER)
-  STATIC_ASSERT(sizeof(volatile long) == sizeof(volatile uint32_t));
-  return c ==
-         (uint32_t)_InterlockedCompareExchange((volatile long *)&p->weak, v, c);
-#elif defined(__APPLE__)
-  return OSAtomicCompareAndSwap32Barrier(c, v, &p->weak);
-#else
-#error FIXME: Unsupported compiler
-#endif
-}
-
-static __always_inline uint32_t atomic_add32(MDBX_atomic_uint32_t *p,
-                                             uint32_t v) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t));
-#ifdef ATOMIC_INT_LOCK_FREE
-  STATIC_ASSERT(ATOMIC_INT_LOCK_FREE > 0);
-#if ATOMIC_INT_LOCK_FREE < 2
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-#endif
-#else
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-#endif
-  return atomic_fetch_add(MDBX_c11a_rw(uint32_t, p), v);
-#elif defined(__GNUC__) || defined(__clang__)
-  return __sync_fetch_and_add(&p->weak, v);
-#elif defined(_MSC_VER)
-  STATIC_ASSERT(sizeof(volatile long) == sizeof(volatile uint32_t));
-  return (uint32_t)_InterlockedExchangeAdd((volatile long *)&p->weak, v);
-#elif defined(__APPLE__)
-  return OSAtomicAdd32Barrier(v, &p->weak);
-#else
-#error FIXME: Unsupported compiler
-#endif
-}
-
-#define atomic_sub32(p, v) atomic_add32(p, 0 - (v))
-
-static __always_inline uint64_t safe64_txnid_next(uint64_t txnid) {
-  txnid += xMDBX_TXNID_STEP;
-#if !MDBX_64BIT_CAS
-  /* avoid overflow of low-part in safe64_reset() */
-  txnid += (UINT32_MAX == (uint32_t)txnid);
-#endif
-  return txnid;
-}
-
-static __always_inline void safe64_reset(MDBX_atomic_uint64_t *p,
-                                         bool single_writer) {
-#if !MDBX_64BIT_CAS
-  if (!single_writer) {
-    STATIC_ASSERT(xMDBX_TXNID_STEP > 1);
-    /* it is safe to increment low-part to avoid ABA, since xMDBX_TXNID_STEP > 1
-     * and overflow was preserved in safe64_txnid_next() */
-    atomic_add32(&p->low, 1) /* avoid ABA in safe64_reset_compare() */;
-    atomic_store32(
-        &p->high, UINT32_MAX,
-        mo_Relaxed) /* atomically make >= SAFE64_INVALID_THRESHOLD */;
-    atomic_add32(&p->low, 1) /* avoid ABA in safe64_reset_compare() */;
-  } else
-#endif /* !MDBX_64BIT_CAS */
-#if MDBX_64BIT_ATOMIC
-    /* atomically make value >= SAFE64_INVALID_THRESHOLD by 64-bit operation */
-    atomic_store64(p, UINT64_MAX,
-                   single_writer ? mo_AcquireRelease
-                                 : mo_SequentialConsistency);
-#else
-  /* atomically make value >= SAFE64_INVALID_THRESHOLD by 32-bit operation */
-  atomic_store32(&p->high, UINT32_MAX,
-                 single_writer ? mo_AcquireRelease : mo_SequentialConsistency);
-#endif /* MDBX_64BIT_ATOMIC */
-  assert(p->weak >= SAFE64_INVALID_THRESHOLD);
-  mdbx_jitter4testing(true);
-}
-
-static __always_inline bool safe64_reset_compare(MDBX_atomic_uint64_t *p,
-                                                 txnid_t compare) {
-  /* LY: This function is used to reset `mr_txnid` from hsr-handler in case
-   *     the asynchronously cancellation of read transaction. Therefore,
-   *     there may be a collision between the cleanup performed here and
-   *     asynchronous termination and restarting of the read transaction
-   *     in another proces/thread. In general we MUST NOT reset the `mr_txnid`
-   *     if a new transaction was started (i.e. if `mr_txnid` was changed). */
-#if MDBX_64BIT_CAS
-  bool rc = atomic_cas64(p, compare, UINT64_MAX);
-#else
-  /* LY: There is no gold ratio here since shared mutex is too costly,
-   *     in such way we must acquire/release it for every update of mr_txnid,
-   *     i.e. twice for each read transaction). */
-  bool rc = false;
-  if (likely(atomic_load32(&p->low, mo_AcquireRelease) == (uint32_t)compare &&
-             atomic_cas32(&p->high, (uint32_t)(compare >> 32), UINT32_MAX))) {
-    if (unlikely(atomic_load32(&p->low, mo_AcquireRelease) !=
-                 (uint32_t)compare))
-      atomic_cas32(&p->high, UINT32_MAX, (uint32_t)(compare >> 32));
-    else
-      rc = true;
-  }
-#endif /* MDBX_64BIT_CAS */
-  mdbx_jitter4testing(true);
-  return rc;
-}
-
-static __always_inline void safe64_write(MDBX_atomic_uint64_t *p,
-                                         const uint64_t v) {
-  assert(p->weak >= SAFE64_INVALID_THRESHOLD);
-#if MDBX_64BIT_ATOMIC
-  atomic_store64(p, v, mo_AcquireRelease);
-#else  /* MDBX_64BIT_ATOMIC */
-  mdbx_compiler_barrier();
-  /* update low-part but still value >= SAFE64_INVALID_THRESHOLD */
-  atomic_store32(&p->low, (uint32_t)v, mo_Relaxed);
-  assert(p->weak >= SAFE64_INVALID_THRESHOLD);
-  mdbx_jitter4testing(true);
-  /* update high-part from SAFE64_INVALID_THRESHOLD to actual value */
-  atomic_store32(&p->high, (uint32_t)(v >> 32), mo_AcquireRelease);
-#endif /* MDBX_64BIT_ATOMIC */
-  assert(p->weak == v);
-  mdbx_jitter4testing(true);
-}
-
-static __always_inline uint64_t safe64_read(const MDBX_atomic_uint64_t *p) {
-  mdbx_jitter4testing(true);
-  uint64_t v = atomic_load64(p, mo_AcquireRelease);
-  mdbx_jitter4testing(true);
-  return v;
-}
-
-#if 0 /* unused for now */
-MDBX_MAYBE_UNUSED static __always_inline bool safe64_is_valid(uint64_t v) {
-#if MDBX_WORDBITS >= 64
-  return v < SAFE64_INVALID_THRESHOLD;
-#else
-  return (v >> 32) != UINT32_MAX;
-#endif /* MDBX_WORDBITS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline bool
- safe64_is_valid_ptr(const MDBX_atomic_uint64_t *p) {
-#if MDBX_64BIT_ATOMIC
-  return atomic_load64(p, mo_AcquireRelease) < SAFE64_INVALID_THRESHOLD;
-#else
-  return atomic_load32(&p->high, mo_AcquireRelease) != UINT32_MAX;
-#endif /* MDBX_64BIT_ATOMIC */
-}
-#endif /* unused for now */
-
-/* non-atomic write with safety for reading a half-updated value */
-static __always_inline void safe64_update(MDBX_atomic_uint64_t *p,
-                                          const uint64_t v) {
-#if MDBX_64BIT_ATOMIC
-  atomic_store64(p, v, mo_Relaxed);
-#else
-  safe64_reset(p, true);
-  safe64_write(p, v);
-#endif /* MDBX_64BIT_ATOMIC */
-}
-
-/* non-atomic increment with safety for reading a half-updated value */
-MDBX_MAYBE_UNUSED static
-#if MDBX_64BIT_ATOMIC
-    __always_inline
-#endif /* MDBX_64BIT_ATOMIC */
-    void
-    safe64_inc(MDBX_atomic_uint64_t *p, const uint64_t v) {
-  assert(v > 0);
-  safe64_update(p, atomic_load64(p, mo_Relaxed) + v);
-}
-
-/*----------------------------------------------------------------------------*/
-/* rthc (tls keys and destructors) */
-
-typedef struct rthc_entry_t {
-  MDBX_reader *begin;
-  MDBX_reader *end;
-  mdbx_thread_key_t thr_tls_key;
-  bool key_valid;
-} rthc_entry_t;
-
-#if MDBX_DEBUG
-#define RTHC_INITIAL_LIMIT 1
-#else
-#define RTHC_INITIAL_LIMIT 16
-#endif
-
-static bin128_t bootid;
-
-#if defined(_WIN32) || defined(_WIN64)
-static CRITICAL_SECTION rthc_critical_section;
-static CRITICAL_SECTION lcklist_critical_section;
-#else
-int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj, void *dso_symbol)
-    __attribute__((__weak__));
-#ifdef __APPLE__ /* FIXME: Thread-Local Storage destructors & DSO-unloading */
-int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj,
-                             void *dso_symbol) {
-  (void)dtor;
-  (void)obj;
-  (void)dso_symbol;
-  return -1;
-}
-#endif           /* __APPLE__ */
-
-static pthread_mutex_t lcklist_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t rthc_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t rthc_cond = PTHREAD_COND_INITIALIZER;
-static mdbx_thread_key_t rthc_key;
-static MDBX_atomic_uint32_t rthc_pending;
-
-__cold static void workaround_glibc_bug21031(void) {
-  /* Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=21031
-   *
-   * Due race between pthread_key_delete() and __nptl_deallocate_tsd()
-   * The destructor(s) of thread-local-storage object(s) may be running
-   * in another thread(s) and be blocked or not finished yet.
-   * In such case we get a SEGFAULT after unload this library DSO.
-   *
-   * So just by yielding a few timeslices we give a chance
-   * to such destructor(s) for completion and avoids segfault. */
-  sched_yield();
-  sched_yield();
-  sched_yield();
-}
-#endif
-
-static unsigned rthc_count, rthc_limit;
-static rthc_entry_t *rthc_table;
-static rthc_entry_t rthc_table_static[RTHC_INITIAL_LIMIT];
-
-static __inline void rthc_lock(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  EnterCriticalSection(&rthc_critical_section);
-#else
-  mdbx_ensure(nullptr, mdbx_pthread_mutex_lock(&rthc_mutex) == 0);
-#endif
-}
-
-static __inline void rthc_unlock(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  LeaveCriticalSection(&rthc_critical_section);
-#else
-  mdbx_ensure(nullptr, pthread_mutex_unlock(&rthc_mutex) == 0);
-#endif
-}
-
-static __inline int thread_key_create(mdbx_thread_key_t *key) {
-  int rc;
-#if defined(_WIN32) || defined(_WIN64)
-  *key = TlsAlloc();
-  rc = (*key != TLS_OUT_OF_INDEXES) ? MDBX_SUCCESS : GetLastError();
-#else
-  rc = pthread_key_create(key, nullptr);
-#endif
-  mdbx_trace("&key = %p, value %" PRIuPTR ", rc %d",
-             __Wpedantic_format_voidptr(key), (uintptr_t)*key, rc);
-  return rc;
-}
-
-static __inline void thread_key_delete(mdbx_thread_key_t key) {
-  mdbx_trace("key = %" PRIuPTR, (uintptr_t)key);
-#if defined(_WIN32) || defined(_WIN64)
-  mdbx_ensure(nullptr, TlsFree(key));
-#else
-  mdbx_ensure(nullptr, pthread_key_delete(key) == 0);
-  workaround_glibc_bug21031();
-#endif
-}
-
-static __inline void *thread_rthc_get(mdbx_thread_key_t key) {
-#if defined(_WIN32) || defined(_WIN64)
-  return TlsGetValue(key);
-#else
-  return pthread_getspecific(key);
-#endif
-}
-
-static void thread_rthc_set(mdbx_thread_key_t key, const void *value) {
-#if defined(_WIN32) || defined(_WIN64)
-  mdbx_ensure(nullptr, TlsSetValue(key, (void *)value));
-#else
-#define MDBX_THREAD_RTHC_ZERO 0
-#define MDBX_THREAD_RTHC_REGISTERED 1
-#define MDBX_THREAD_RTHC_COUNTED 2
-  static __thread char thread_registration_state;
-  if (value && unlikely(thread_registration_state == MDBX_THREAD_RTHC_ZERO)) {
-    thread_registration_state = MDBX_THREAD_RTHC_REGISTERED;
-    mdbx_trace("thread registered 0x%" PRIxPTR, mdbx_thread_self());
-    if (&__cxa_thread_atexit_impl == nullptr ||
-        __cxa_thread_atexit_impl(mdbx_rthc_thread_dtor,
-                                 &thread_registration_state,
-                                 (void *)&mdbx_version /* dso_anchor */)) {
-      mdbx_ensure(nullptr, pthread_setspecific(
-                               rthc_key, &thread_registration_state) == 0);
-      thread_registration_state = MDBX_THREAD_RTHC_COUNTED;
-      const unsigned count_before = atomic_add32(&rthc_pending, 1);
-      mdbx_ensure(nullptr, count_before < INT_MAX);
-      mdbx_trace("fallback to pthreads' tsd, key %" PRIuPTR ", count %u",
-                 (uintptr_t)rthc_key, count_before);
-      (void)count_before;
-    }
-  }
-  mdbx_ensure(nullptr, pthread_setspecific(key, value) == 0);
-#endif
-}
-
-__cold void mdbx_rthc_global_init(void) {
-  rthc_limit = RTHC_INITIAL_LIMIT;
-  rthc_table = rthc_table_static;
-#if defined(_WIN32) || defined(_WIN64)
-  InitializeCriticalSection(&rthc_critical_section);
-  InitializeCriticalSection(&lcklist_critical_section);
-#else
-  mdbx_ensure(nullptr,
-              pthread_key_create(&rthc_key, mdbx_rthc_thread_dtor) == 0);
-  mdbx_trace("pid %d, &mdbx_rthc_key = %p, value 0x%x", mdbx_getpid(),
-             __Wpedantic_format_voidptr(&rthc_key), (unsigned)rthc_key);
-#endif
-  /* checking time conversion, this also avoids racing on 32-bit architectures
-   * during writing calculated 64-bit ratio(s) into memory. */
-  uint32_t proba = UINT32_MAX;
-  while (true) {
-    unsigned time_conversion_checkup =
-        mdbx_osal_monotime_to_16dot16(mdbx_osal_16dot16_to_monotime(proba));
-    unsigned one_more = (proba < UINT32_MAX) ? proba + 1 : proba;
-    unsigned one_less = (proba > 0) ? proba - 1 : proba;
-    mdbx_ensure(nullptr, time_conversion_checkup >= one_less &&
-                             time_conversion_checkup <= one_more);
-    if (proba == 0)
-      break;
-    proba >>= 1;
-  }
-
-  bootid = mdbx_osal_bootid();
-#if 0 /* debug */
-  for (unsigned i = 0; i < 65536; ++i) {
-    size_t pages = pv2pages(i);
-    unsigned x = pages2pv(pages);
-    size_t xp = pv2pages(x);
-    if (!(x == i || (x % 2 == 0 && x < 65536)) || pages != xp)
-      printf("%u => %zu => %u => %zu\n", i, pages, x, xp);
-    assert(pages == xp);
-  }
-  fflush(stdout);
-#endif
-}
-
-/* dtor called for thread, i.e. for all mdbx's environment objects */
-__cold void mdbx_rthc_thread_dtor(void *ptr) {
-  rthc_lock();
-  mdbx_trace(">> pid %d, thread 0x%" PRIxPTR ", rthc %p", mdbx_getpid(),
-             mdbx_thread_self(), ptr);
-
-  const uint32_t self_pid = mdbx_getpid();
-  for (unsigned i = 0; i < rthc_count; ++i) {
-    if (!rthc_table[i].key_valid)
-      continue;
-    const mdbx_thread_key_t key = rthc_table[i].thr_tls_key;
-    MDBX_reader *const rthc = thread_rthc_get(key);
-    if (rthc < rthc_table[i].begin || rthc >= rthc_table[i].end)
-      continue;
-#if !defined(_WIN32) && !defined(_WIN64)
-    if (pthread_setspecific(key, nullptr) != 0) {
-      mdbx_trace("== thread 0x%" PRIxPTR
-                 ", rthc %p: ignore race with tsd-key deletion",
-                 mdbx_thread_self(), ptr);
-      continue /* ignore race with tsd-key deletion by mdbx_env_close() */;
-    }
-#endif
-
-    mdbx_trace("== thread 0x%" PRIxPTR
-               ", rthc %p, [%i], %p ... %p (%+i), rtch-pid %i, "
-               "current-pid %i",
-               mdbx_thread_self(), __Wpedantic_format_voidptr(rthc), i,
-               __Wpedantic_format_voidptr(rthc_table[i].begin),
-               __Wpedantic_format_voidptr(rthc_table[i].end),
-               (int)(rthc - rthc_table[i].begin), rthc->mr_pid.weak, self_pid);
-    if (atomic_load32(&rthc->mr_pid, mo_Relaxed) == self_pid) {
-      mdbx_trace("==== thread 0x%" PRIxPTR ", rthc %p, cleanup",
-                 mdbx_thread_self(), __Wpedantic_format_voidptr(rthc));
-      atomic_store32(&rthc->mr_pid, 0, mo_AcquireRelease);
-    }
-  }
-
-#if defined(_WIN32) || defined(_WIN64)
-  mdbx_trace("<< thread 0x%" PRIxPTR ", rthc %p", mdbx_thread_self(), ptr);
-  rthc_unlock();
-#else
-  const char self_registration = *(volatile char *)ptr;
-  *(volatile char *)ptr = MDBX_THREAD_RTHC_ZERO;
-  mdbx_trace("== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %d",
-             mdbx_thread_self(), ptr, mdbx_getpid(), self_registration);
-  if (self_registration == MDBX_THREAD_RTHC_COUNTED)
-    mdbx_ensure(nullptr, atomic_sub32(&rthc_pending, 1) > 0);
-
-  if (atomic_load32(&rthc_pending, mo_AcquireRelease) == 0) {
-    mdbx_trace("== thread 0x%" PRIxPTR ", rthc %p, pid %d, wake",
-               mdbx_thread_self(), ptr, mdbx_getpid());
-    mdbx_ensure(nullptr, pthread_cond_broadcast(&rthc_cond) == 0);
-  }
-
-  mdbx_trace("<< thread 0x%" PRIxPTR ", rthc %p", mdbx_thread_self(), ptr);
-  /* Allow tail call optimization, i.e. gcc should generate the jmp instruction
-   * instead of a call for pthread_mutex_unlock() and therefore CPU could not
-   * return to current DSO's code section, which may be unloaded immediately
-   * after the mutex got released. */
-  pthread_mutex_unlock(&rthc_mutex);
-#endif
-}
-
-__cold void mdbx_rthc_global_dtor(void) {
-  mdbx_trace(">> pid %d", mdbx_getpid());
-
-  rthc_lock();
-#if !defined(_WIN32) && !defined(_WIN64)
-  char *rthc = pthread_getspecific(rthc_key);
-  mdbx_trace(
-      "== thread 0x%" PRIxPTR ", rthc %p, pid %d, self-status %d, left %d",
-      mdbx_thread_self(), __Wpedantic_format_voidptr(rthc), mdbx_getpid(),
-      rthc ? *rthc : -1, atomic_load32(&rthc_pending, mo_Relaxed));
-  if (rthc) {
-    const char self_registration = *rthc;
-    *rthc = MDBX_THREAD_RTHC_ZERO;
-    if (self_registration == MDBX_THREAD_RTHC_COUNTED)
-      mdbx_ensure(nullptr, atomic_sub32(&rthc_pending, 1) > 0);
-  }
-
-  struct timespec abstime;
-  mdbx_ensure(nullptr, clock_gettime(CLOCK_REALTIME, &abstime) == 0);
-  abstime.tv_nsec += 1000000000l / 10;
-  if (abstime.tv_nsec >= 1000000000l) {
-    abstime.tv_nsec -= 1000000000l;
-    abstime.tv_sec += 1;
-  }
-#if MDBX_DEBUG > 0
-  abstime.tv_sec += 600;
-#endif
-
-  for (unsigned left;
-       (left = atomic_load32(&rthc_pending, mo_AcquireRelease)) > 0;) {
-    mdbx_trace("pid %d, pending %u, wait for...", mdbx_getpid(), left);
-    const int rc = pthread_cond_timedwait(&rthc_cond, &rthc_mutex, &abstime);
-    if (rc && rc != EINTR)
-      break;
-  }
-  thread_key_delete(rthc_key);
-#endif
-
-  const uint32_t self_pid = mdbx_getpid();
-  for (unsigned i = 0; i < rthc_count; ++i) {
-    if (!rthc_table[i].key_valid)
-      continue;
-    const mdbx_thread_key_t key = rthc_table[i].thr_tls_key;
-    thread_key_delete(key);
-    for (MDBX_reader *rthc = rthc_table[i].begin; rthc < rthc_table[i].end;
-         ++rthc) {
-      mdbx_trace(
-          "== [%i] = key %" PRIuPTR ", %p ... %p, rthc %p (%+i), "
-          "rthc-pid %i, current-pid %i",
-          i, (uintptr_t)key, __Wpedantic_format_voidptr(rthc_table[i].begin),
-          __Wpedantic_format_voidptr(rthc_table[i].end),
-          __Wpedantic_format_voidptr(rthc), (int)(rthc - rthc_table[i].begin),
-          rthc->mr_pid.weak, self_pid);
-      if (atomic_load32(&rthc->mr_pid, mo_Relaxed) == self_pid) {
-        atomic_store32(&rthc->mr_pid, 0, mo_AcquireRelease);
-        mdbx_trace("== cleanup %p", __Wpedantic_format_voidptr(rthc));
-      }
-    }
-  }
-
-  rthc_limit = rthc_count = 0;
-  if (rthc_table != rthc_table_static)
-    mdbx_free(rthc_table);
-  rthc_table = nullptr;
-  rthc_unlock();
-
-#if defined(_WIN32) || defined(_WIN64)
-  DeleteCriticalSection(&lcklist_critical_section);
-  DeleteCriticalSection(&rthc_critical_section);
-#else
-  /* LY: yielding a few timeslices to give a more chance
-   * to racing destructor(s) for completion. */
-  workaround_glibc_bug21031();
-#endif
-
-  mdbx_trace("<< pid %d\n", mdbx_getpid());
-}
-
-__cold int mdbx_rthc_alloc(mdbx_thread_key_t *key, MDBX_reader *begin,
-                           MDBX_reader *end) {
-  int rc;
-  if (key) {
-#ifndef NDEBUG
-    *key = (mdbx_thread_key_t)0xBADBADBAD;
-#endif /* NDEBUG */
-    rc = thread_key_create(key);
-    if (rc != MDBX_SUCCESS)
-      return rc;
-  }
-
-  rthc_lock();
-  const mdbx_thread_key_t new_key = key ? *key : 0;
-  mdbx_trace(">> key %" PRIuPTR ", rthc_count %u, rthc_limit %u",
-             (uintptr_t)new_key, rthc_count, rthc_limit);
-  if (rthc_count == rthc_limit) {
-    rthc_entry_t *new_table =
-        mdbx_realloc((rthc_table == rthc_table_static) ? nullptr : rthc_table,
-                     sizeof(rthc_entry_t) * rthc_limit * 2);
-    if (new_table == nullptr) {
-      rc = MDBX_ENOMEM;
-      goto bailout;
-    }
-    if (rthc_table == rthc_table_static)
-      memcpy(new_table, rthc_table_static, sizeof(rthc_table_static));
-    rthc_table = new_table;
-    rthc_limit *= 2;
-  }
-  mdbx_trace("== [%i] = key %" PRIuPTR ", %p ... %p", rthc_count,
-             (uintptr_t)new_key, __Wpedantic_format_voidptr(begin),
-             __Wpedantic_format_voidptr(end));
-  rthc_table[rthc_count].key_valid = key ? true : false;
-  rthc_table[rthc_count].thr_tls_key = key ? new_key : 0;
-  rthc_table[rthc_count].begin = begin;
-  rthc_table[rthc_count].end = end;
-  ++rthc_count;
-  mdbx_trace("<< key %" PRIuPTR ", rthc_count %u, rthc_limit %u",
-             (uintptr_t)new_key, rthc_count, rthc_limit);
-  rthc_unlock();
-  return MDBX_SUCCESS;
-
-bailout:
-  if (key)
-    thread_key_delete(*key);
-  rthc_unlock();
-  return rc;
-}
-
-__cold void mdbx_rthc_remove(const mdbx_thread_key_t key) {
-  thread_key_delete(key);
-  rthc_lock();
-  mdbx_trace(">> key %zu, rthc_count %u, rthc_limit %u", (size_t)key,
-             rthc_count, rthc_limit);
-
-  for (unsigned i = 0; i < rthc_count; ++i) {
-    if (rthc_table[i].key_valid && key == rthc_table[i].thr_tls_key) {
-      const uint32_t self_pid = mdbx_getpid();
-      mdbx_trace("== [%i], %p ...%p, current-pid %d", i,
-                 __Wpedantic_format_voidptr(rthc_table[i].begin),
-                 __Wpedantic_format_voidptr(rthc_table[i].end), self_pid);
-
-      for (MDBX_reader *rthc = rthc_table[i].begin; rthc < rthc_table[i].end;
-           ++rthc) {
-        if (atomic_load32(&rthc->mr_pid, mo_Relaxed) == self_pid) {
-          atomic_store32(&rthc->mr_pid, 0, mo_AcquireRelease);
-          mdbx_trace("== cleanup %p", __Wpedantic_format_voidptr(rthc));
-        }
-      }
-      if (--rthc_count > 0)
-        rthc_table[i] = rthc_table[rthc_count];
-      else if (rthc_table != rthc_table_static) {
-        mdbx_free(rthc_table);
-        rthc_table = rthc_table_static;
-        rthc_limit = RTHC_INITIAL_LIMIT;
-      }
-      break;
-    }
-  }
-
-  mdbx_trace("<< key %zu, rthc_count %u, rthc_limit %u", (size_t)key,
-             rthc_count, rthc_limit);
-  rthc_unlock();
-}
-
-//------------------------------------------------------------------------------
-
-#define RTHC_ENVLIST_END ((MDBX_env *)((uintptr_t)50459))
-static MDBX_env *inprocess_lcklist_head = RTHC_ENVLIST_END;
-
-static __inline void lcklist_lock(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  EnterCriticalSection(&lcklist_critical_section);
-#else
-  mdbx_ensure(nullptr, mdbx_pthread_mutex_lock(&lcklist_mutex) == 0);
-#endif
-}
-
-static __inline void lcklist_unlock(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  LeaveCriticalSection(&lcklist_critical_section);
-#else
-  mdbx_ensure(nullptr, pthread_mutex_unlock(&lcklist_mutex) == 0);
-#endif
-}
-
-MDBX_NOTHROW_CONST_FUNCTION static uint64_t rrxmrrxmsx_0(uint64_t v) {
-  /* Pelle Evensen's mixer, https://bit.ly/2HOfynt */
-  v ^= (v << 39 | v >> 25) ^ (v << 14 | v >> 50);
-  v *= UINT64_C(0xA24BAED4963EE407);
-  v ^= (v << 40 | v >> 24) ^ (v << 15 | v >> 49);
-  v *= UINT64_C(0x9FB21C651E98DF25);
-  return v ^ v >> 28;
-}
-
-static int uniq_peek(const mdbx_mmap_t *pending, mdbx_mmap_t *scan) {
-  int rc;
-  uint64_t bait;
-  MDBX_lockinfo *const pending_lck = pending->lck;
-  MDBX_lockinfo *const scan_lck = scan->lck;
-  if (pending_lck) {
-    bait = atomic_load64(&pending_lck->mti_bait_uniqueness, mo_AcquireRelease);
-    rc = MDBX_SUCCESS;
-  } else {
-    bait = 0 /* hush MSVC warning */;
-    rc = mdbx_msync(scan, 0, sizeof(MDBX_lockinfo), MDBX_SYNC_DATA);
-    if (rc == MDBX_SUCCESS)
-      rc = mdbx_pread(pending->fd, &bait, sizeof(scan_lck->mti_bait_uniqueness),
-                      offsetof(MDBX_lockinfo, mti_bait_uniqueness));
-  }
-  if (likely(rc == MDBX_SUCCESS) &&
-      bait == atomic_load64(&scan_lck->mti_bait_uniqueness, mo_AcquireRelease))
-    rc = MDBX_RESULT_TRUE;
-
-  mdbx_trace("uniq-peek: %s, bait 0x%016" PRIx64 ",%s rc %d",
-             pending_lck ? "mem" : "file", bait,
-             (rc == MDBX_RESULT_TRUE) ? " found," : (rc ? " FAILED," : ""), rc);
-  return rc;
-}
-
-static int uniq_poke(const mdbx_mmap_t *pending, mdbx_mmap_t *scan,
-                     uint64_t *abra) {
-  if (*abra == 0) {
-    const uintptr_t tid = mdbx_thread_self();
-    uintptr_t uit = 0;
-    memcpy(&uit, &tid, (sizeof(tid) < sizeof(uit)) ? sizeof(tid) : sizeof(uit));
-    *abra =
-        rrxmrrxmsx_0(mdbx_osal_monotime() + UINT64_C(5873865991930747) * uit);
-  }
-  const uint64_t cadabra =
-      rrxmrrxmsx_0(*abra + UINT64_C(7680760450171793) * (unsigned)mdbx_getpid())
-          << 24 |
-      *abra >> 40;
-  MDBX_lockinfo *const scan_lck = scan->lck;
-  atomic_store64(&scan_lck->mti_bait_uniqueness, cadabra,
-                 mo_SequentialConsistency);
-  *abra = *abra * UINT64_C(6364136223846793005) + 1;
-  return uniq_peek(pending, scan);
-}
-
-__cold static int uniq_check(const mdbx_mmap_t *pending, MDBX_env **found) {
-  *found = nullptr;
-  uint64_t salt = 0;
-  for (MDBX_env *scan = inprocess_lcklist_head; scan != RTHC_ENVLIST_END;
-       scan = scan->me_lcklist_next) {
-    MDBX_lockinfo *const scan_lck = scan->me_lck_mmap.lck;
-    int err = atomic_load64(&scan_lck->mti_bait_uniqueness, mo_AcquireRelease)
-                  ? uniq_peek(pending, &scan->me_lck_mmap)
-                  : uniq_poke(pending, &scan->me_lck_mmap, &salt);
-    if (err == MDBX_ENODATA) {
-      uint64_t length;
-      if (likely(mdbx_filesize(pending->fd, &length) == MDBX_SUCCESS &&
-                 length == 0)) {
-        /* LY: skip checking since LCK-file is empty, i.e. just created. */
-        mdbx_debug("uniq-probe: %s", "unique (new/empty lck)");
-        return MDBX_RESULT_TRUE;
-      }
-    }
-    if (err == MDBX_RESULT_TRUE)
-      err = uniq_poke(pending, &scan->me_lck_mmap, &salt);
-    if (err == MDBX_RESULT_TRUE) {
-      (void)mdbx_msync(&scan->me_lck_mmap, 0, sizeof(MDBX_lockinfo),
-                       MDBX_SYNC_NONE);
-      err = uniq_poke(pending, &scan->me_lck_mmap, &salt);
-    }
-    if (err == MDBX_RESULT_TRUE) {
-      err = uniq_poke(pending, &scan->me_lck_mmap, &salt);
-      *found = scan;
-      mdbx_debug("uniq-probe: found %p", __Wpedantic_format_voidptr(*found));
-      return MDBX_RESULT_FALSE;
-    }
-    if (unlikely(err != MDBX_SUCCESS)) {
-      mdbx_debug("uniq-probe: failed rc %d", err);
-      return err;
-    }
-  }
-
-  mdbx_debug("uniq-probe: %s", "unique");
-  return MDBX_RESULT_TRUE;
-}
-
-static int lcklist_detach_locked(MDBX_env *env) {
-  MDBX_env *inprocess_neighbor = nullptr;
-  int rc = MDBX_SUCCESS;
-  if (env->me_lcklist_next != nullptr) {
-    mdbx_ensure(env, env->me_lcklist_next != nullptr);
-    mdbx_ensure(env, inprocess_lcklist_head != RTHC_ENVLIST_END);
-    for (MDBX_env **ptr = &inprocess_lcklist_head; *ptr != RTHC_ENVLIST_END;
-         ptr = &(*ptr)->me_lcklist_next) {
-      if (*ptr == env) {
-        *ptr = env->me_lcklist_next;
-        env->me_lcklist_next = nullptr;
-        break;
-      }
-    }
-    mdbx_ensure(env, env->me_lcklist_next == nullptr);
-  }
-
-  rc = likely(mdbx_getpid() == env->me_pid)
-           ? uniq_check(&env->me_lck_mmap, &inprocess_neighbor)
-           : MDBX_PANIC;
-  if (!inprocess_neighbor && env->me_live_reader)
-    (void)mdbx_rpid_clear(env);
-  if (!MDBX_IS_ERROR(rc))
-    rc = mdbx_lck_destroy(env, inprocess_neighbor);
-  return rc;
-}
-
-/*------------------------------------------------------------------------------
- * LY: State of the art quicksort-based sorting, with internal stack
- * and network-sort for small chunks.
- * Thanks to John M. Gamble for the http://pages.ripco.net/~jgamble/nw.html */
-
-#define SORT_CMP_SWAP(TYPE, CMP, a, b)                                         \
-  do {                                                                         \
-    const TYPE swap_tmp = (a);                                                 \
-    const bool swap_cmp = CMP(swap_tmp, b);                                    \
-    (a) = swap_cmp ? swap_tmp : b;                                             \
-    (b) = swap_cmp ? b : swap_tmp;                                             \
-  } while (0)
-
-//  3 comparators, 3 parallel operations
-//  o-----^--^--o
-//        |  |
-//  o--^--|--v--o
-//     |  |
-//  o--v--v-----o
-//
-//  [[1,2]]
-//  [[0,2]]
-//  [[0,1]]
-#define SORT_NETWORK_3(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-  } while (0)
-
-//  5 comparators, 3 parallel operations
-//  o--^--^--------o
-//     |  |
-//  o--v--|--^--^--o
-//        |  |  |
-//  o--^--v--|--v--o
-//     |     |
-//  o--v-----v-----o
-//
-//  [[0,1],[2,3]]
-//  [[0,2],[1,3]]
-//  [[1,2]]
-#define SORT_NETWORK_4(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-  } while (0)
-
-//  9 comparators, 5 parallel operations
-//  o--^--^-----^-----------o
-//     |  |     |
-//  o--|--|--^--v-----^--^--o
-//     |  |  |        |  |
-//  o--|--v--|--^--^--|--v--o
-//     |     |  |  |  |
-//  o--|-----v--|--v--|--^--o
-//     |        |     |  |
-//  o--v--------v-----v--v--o
-//
-//  [[0,4],[1,3]]
-//  [[0,2]]
-//  [[2,4],[0,1]]
-//  [[2,3],[1,4]]
-//  [[1,2],[3,4]]
-#define SORT_NETWORK_5(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-  } while (0)
-
-//  12 comparators, 6 parallel operations
-//  o-----^--^--^-----------------o
-//        |  |  |
-//  o--^--|--v--|--^--------^-----o
-//     |  |     |  |        |
-//  o--v--v-----|--|--^--^--|--^--o
-//              |  |  |  |  |  |
-//  o-----^--^--v--|--|--|--v--v--o
-//        |  |     |  |  |
-//  o--^--|--v-----v--|--v--------o
-//     |  |           |
-//  o--v--v-----------v-----------o
-//
-//  [[1,2],[4,5]]
-//  [[0,2],[3,5]]
-//  [[0,1],[3,4],[2,5]]
-//  [[0,3],[1,4]]
-//  [[2,4],[1,3]]
-//  [[2,3]]
-#define SORT_NETWORK_6(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-  } while (0)
-
-//  16 comparators, 6 parallel operations
-//  o--^--------^-----^-----------------o
-//     |        |     |
-//  o--|--^-----|--^--v--------^--^-----o
-//     |  |     |  |           |  |
-//  o--|--|--^--v--|--^-----^--|--v-----o
-//     |  |  |     |  |     |  |
-//  o--|--|--|-----v--|--^--v--|--^--^--o
-//     |  |  |        |  |     |  |  |
-//  o--v--|--|--^-----v--|--^--v--|--v--o
-//        |  |  |        |  |     |
-//  o-----v--|--|--------v--v-----|--^--o
-//           |  |                 |  |
-//  o--------v--v-----------------v--v--o
-//
-//  [[0,4],[1,5],[2,6]]
-//  [[0,2],[1,3],[4,6]]
-//  [[2,4],[3,5],[0,1]]
-//  [[2,3],[4,5]]
-//  [[1,4],[3,6]]
-//  [[1,2],[3,4],[5,6]]
-#define SORT_NETWORK_7(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-  } while (0)
-
-//  19 comparators, 6 parallel operations
-//  o--^--------^-----^-----------------o
-//     |        |     |
-//  o--|--^-----|--^--v--------^--^-----o
-//     |  |     |  |           |  |
-//  o--|--|--^--v--|--^-----^--|--v-----o
-//     |  |  |     |  |     |  |
-//  o--|--|--|--^--v--|--^--v--|--^--^--o
-//     |  |  |  |     |  |     |  |  |
-//  o--v--|--|--|--^--v--|--^--v--|--v--o
-//        |  |  |  |     |  |     |
-//  o-----v--|--|--|--^--v--v-----|--^--o
-//           |  |  |  |           |  |
-//  o--------v--|--v--|--^--------v--v--o
-//              |     |  |
-//  o-----------v-----v--v--------------o
-//
-//  [[0,4],[1,5],[2,6],[3,7]]
-//  [[0,2],[1,3],[4,6],[5,7]]
-//  [[2,4],[3,5],[0,1],[6,7]]
-//  [[2,3],[4,5]]
-//  [[1,4],[3,6]]
-//  [[1,2],[3,4],[5,6]]
-#define SORT_NETWORK_8(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-  } while (0)
-
-//  25 comparators, 9 parallel operations
-//  o--^-----^--^-----^-----------------------------------o
-//     |     |  |     |
-//  o--v--^--v--|-----|--^-----^-----------^--------------o
-//        |     |     |  |     |           |
-//  o-----v-----|-----|--|-----|--^-----^--|--^-----^--^--o
-//              |     |  |     |  |     |  |  |     |  |
-//  o--^-----^--v--^--v--|-----|--|-----|--v--|-----|--v--o
-//     |     |     |     |     |  |     |     |     |
-//  o--v--^--v-----|-----v--^--v--|-----|-----|--^--v-----o
-//        |        |        |     |     |     |  |
-//  o-----v--------|--------|-----v--^--v--^--|--|--^-----o
-//                 |        |        |     |  |  |  |
-//  o--^-----^-----v--------|--------|-----|--v--v--v-----o
-//     |     |              |        |     |
-//  o--v--^--v--------------v--------|-----v--------------o
-//        |                          |
-//  o-----v--------------------------v--------------------o
-//
-//  [[0,1],[3,4],[6,7]]
-//  [[1,2],[4,5],[7,8]]
-//  [[0,1],[3,4],[6,7],[2,5]]
-//  [[0,3],[1,4],[5,8]]
-//  [[3,6],[4,7],[2,5]]
-//  [[0,3],[1,4],[5,7],[2,6]]
-//  [[1,3],[4,6]]
-//  [[2,4],[5,6]]
-//  [[2,3]]
-#define SORT_NETWORK_9(TYPE, CMP, begin)                                       \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-  } while (0)
-
-//  29 comparators, 9 parallel operations
-//  o--------------^-----^--^--^-----------------------o
-//                 |     |  |  |
-//  o-----------^--|--^--|--|--v--^--------^-----------o
-//              |  |  |  |  |     |        |
-//  o--------^--|--|--|--|--v--^--v-----^--|--^--------o
-//           |  |  |  |  |     |        |  |  |
-//  o-----^--|--|--|--|--v--^--|-----^--|--v--v--^-----o
-//        |  |  |  |  |     |  |     |  |        |
-//  o--^--|--|--|--|--v-----|--v--^--|--|--^-----v--^--o
-//     |  |  |  |  |        |     |  |  |  |        |
-//  o--|--|--|--|--v--^-----|--^--|--v--v--|-----^--v--o
-//     |  |  |  |     |     |  |  |        |     |
-//  o--|--|--|--v--^--|-----v--|--v--^-----|--^--v-----o
-//     |  |  |     |  |        |     |     |  |
-//  o--|--|--v-----|--|--^-----v--^--|-----v--v--------o
-//     |  |        |  |  |        |  |
-//  o--|--v--------|--v--|--^-----v--v-----------------o
-//     |           |     |  |
-//  o--v-----------v-----v--v--------------------------o
-//
-//  [[4,9],[3,8],[2,7],[1,6],[0,5]]
-//  [[1,4],[6,9],[0,3],[5,8]]
-//  [[0,2],[3,6],[7,9]]
-//  [[0,1],[2,4],[5,7],[8,9]]
-//  [[1,2],[4,6],[7,8],[3,5]]
-//  [[2,5],[6,8],[1,3],[4,7]]
-//  [[2,3],[6,7]]
-//  [[3,4],[5,6]]
-//  [[4,5]]
-#define SORT_NETWORK_10(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-  } while (0)
-
-//  35 comparators, 9 parallel operations
-//  o--^-----^-----------------^--------^--------------------o
-//     |     |                 |        |
-//  o--v--^--|--^--^--------^--|--------|--^-----------------o
-//        |  |  |  |        |  |        |  |
-//  o--^--|--v--v--|-----^--|--|--------|--|-----^--^--------o
-//     |  |        |     |  |  |        |  |     |  |
-//  o--v--v--------|-----|--|--|--^-----|--|--^--v--|--^--^--o
-//                 |     |  |  |  |     |  |  |     |  |  |
-//  o--^-----^-----|-----|--|--v--|--^--v--v--|-----v--|--v--o
-//     |     |     |     |  |     |  |        |        |
-//  o--v--^--|--^--v--^--|--v-----|--|--------|--------v--^--o
-//        |  |  |     |  |        |  |        |           |
-//  o--^--|--v--v--^--|--v--^-----|--|--------|--------^--v--o
-//     |  |        |  |     |     |  |        |        |
-//  o--v--v--------|--|-----|-----v--|--^-----|-----^--|--^--o
-//                 |  |     |        |  |     |     |  |  |
-//  o--^--^--------|--|-----|--------v--|-----v--^--|--v--v--o
-//     |  |        |  |     |           |        |  |
-//  o--v--|--^-----|--v-----|-----------|--------v--v--------o
-//        |  |     |        |           |
-//  o-----v--v-----v--------v-----------v--------------------o
-//
-//  [[0,1],[2,3],[4,5],[6,7],[8,9]]
-//  [[1,3],[5,7],[0,2],[4,6],[8,10]]
-//  [[1,2],[5,6],[9,10],[0,4],[3,7]]
-//  [[1,5],[6,10],[4,8]]
-//  [[5,9],[2,6],[0,4],[3,8]]
-//  [[1,5],[6,10],[2,3],[8,9]]
-//  [[1,4],[7,10],[3,5],[6,8]]
-//  [[2,4],[7,9],[5,6]]
-//  [[3,4],[7,8]]
-#define SORT_NETWORK_11(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-  } while (0)
-
-//  39 comparators, parallel operations
-//  o--^-----^-----------------^--------^--------------------o
-//     |     |                 |        |
-//  o--v--^--|--^--^--------^--|--------|--^-----------------o
-//        |  |  |  |        |  |        |  |
-//  o--^--|--v--v--|-----^--|--|--------|--|-----^--^--------o
-//     |  |        |     |  |  |        |  |     |  |
-//  o--v--v--------|-----|--|--|--^-----|--|--^--v--|--^--^--o
-//                 |     |  |  |  |     |  |  |     |  |  |
-//  o--^-----^-----|-----|--|--v--|--^--v--v--|-----v--|--v--o
-//     |     |     |     |  |     |  |        |        |
-//  o--v--^--|--^--v--^--|--v-----|--|--------|--------v--^--o
-//        |  |  |     |  |        |  |        |           |
-//  o--^--|--v--v--^--|--v--^-----|--|--------|--------^--v--o
-//     |  |        |  |     |     |  |        |        |
-//  o--v--v--------|--|-----|--^--v--|--^--^--|-----^--|--^--o
-//                 |  |     |  |     |  |  |  |     |  |  |
-//  o--^-----^-----|--|-----|--|-----v--|--|--v--^--|--v--v--o
-//     |     |     |  |     |  |        |  |     |  |
-//  o--v--^--|--^--|--v-----|--|--------|--|-----v--v--------o
-//        |  |  |  |        |  |        |  |
-//  o--^--|--v--v--v--------v--|--------|--v-----------------o
-//     |  |                    |        |
-//  o--v--v--------------------v--------v--------------------o
-//
-//  [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11]]
-//  [[1,3],[5,7],[9,11],[0,2],[4,6],[8,10]]
-//  [[1,2],[5,6],[9,10],[0,4],[7,11]]
-//  [[1,5],[6,10],[3,7],[4,8]]
-//  [[5,9],[2,6],[0,4],[7,11],[3,8]]
-//  [[1,5],[6,10],[2,3],[8,9]]
-//  [[1,4],[7,10],[3,5],[6,8]]
-//  [[2,4],[7,9],[5,6]]
-//  [[3,4],[7,8]]
-#define SORT_NETWORK_12(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[11]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-  } while (0)
-
-//  45 comparators, 10 parallel operations
-//  o--------^--^-----^-----------------------------^-----------------o
-//           |  |     |                             |
-//  o--^-----|--v-----|-----^--------------^-----^--|-----^-----------o
-//     |     |        |     |              |     |  |     |
-//  o--|-----|--^--^--v-----|--------------|--^--|--|--^--v--^--------o
-//     |     |  |  |        |              |  |  |  |  |     |
-//  o--|--^--|--|--v-----^--|--------^-----|--|--v--|--|--^--v-----^--o
-//     |  |  |  |        |  |        |     |  |     |  |  |        |
-//  o--|--v--|--|--^-----|--v-----^--v-----|--|--^--|--|--|--^--^--v--o
-//     |     |  |  |     |        |        |  |  |  |  |  |  |  |
-//  o--|--^--|--|--|--^--|--------|-----^--|--|--|--v--v--v--|--v--^--o
-//     |  |  |  |  |  |  |        |     |  |  |  |           |     |
-//  o--|--|--|--v--v--|--|--^-----|--^--v--|--v--|--^--------v--^--v--o
-//     |  |  |        |  |  |     |  |     |     |  |           |
-//  o--v--|--|-----^--|--v--|--^--|--|-----v-----v--|--^--------v-----o
-//        |  |     |  |     |  |  |  |              |  |
-//  o-----v--|--^--|--|-----|--v--|--|--^-----^-----v--v--^-----------o
-//           |  |  |  |     |     |  |  |     |           |
-//  o--^-----|--|--|--v-----|-----v--|--v--^--|--^--------v-----------o
-//     |     |  |  |        |        |     |  |  |
-//  o--|-----|--|--|--^-----|--------v--^--|--v--v--------------------o
-//     |     |  |  |  |     |           |  |
-//  o--v-----|--v--|--v-----|--^--------v--v--------------------------o
-//           |     |        |  |
-//  o--------v-----v--------v--v--------------------------------------o
-//
-//  [[1,7],[9,11],[3,4],[5,8],[0,12],[2,6]]
-//  [[0,1],[2,3],[4,6],[8,11],[7,12],[5,9]]
-//  [[0,2],[3,7],[10,11],[1,4],[6,12]]
-//  [[7,8],[11,12],[4,9],[6,10]]
-//  [[3,4],[5,6],[8,9],[10,11],[1,7]]
-//  [[2,6],[9,11],[1,3],[4,7],[8,10],[0,5]]
-//  [[2,5],[6,8],[9,10]]
-//  [[1,2],[3,5],[7,8],[4,6]]
-//  [[2,3],[4,5],[6,7],[8,9]]
-//  [[3,4],[5,6]]
-#define SORT_NETWORK_13(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[11]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[11]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-  } while (0)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-//  51 comparators, 10 parallel operations
-//  o--^--^-----^-----------^-----------------------------------------------------------o
-//     |  |     |           |
-//  o--v--|--^--|--^--------|--^-----^-----------------------^--------------------------o
-//        |  |  |  |        |  |     |                       |
-//  o--^--v--|--|--|--^-----|--|--^--v-----------------------|--^--^--------------------o
-//     |     |  |  |  |     |  |  |                          |  |  |
-//  o--v-----v--|--|--|--^--|--|--|--^--------------^--------|--|--|--^--^--^-----------o
-//              |  |  |  |  |  |  |  |              |        |  |  |  |  |  |
-//  o--^--^-----v--|--|--|--|--|--|--|--^-----------|-----^--v--|--v--|--|--v-----------o
-//     |  |        |  |  |  |  |  |  |  |           |     |     |     |  |
-//  o--v--|--^-----v--|--|--|--|--|--|--|--^--^-----|-----|-----|--^--|--v-----^--------o
-//        |  |        |  |  |  |  |  |  |  |  |     |     |     |  |  |        |
-//  o--^--v--|--------v--|--|--|--|--|--|--|--|--^--|-----|-----|--v--|-----^--v-----^--o
-//     |     |           |  |  |  |  |  |  |  |  |  |     |     |     |     |        |
-//  o--v-----v-----------v--|--|--|--|--|--|--|--|--|--^--|--^--|-----|--^--|--^--^--v--o
-//                          |  |  |  |  |  |  |  |  |  |  |  |  |     |  |  |  |  |
-//  o--^--^-----^-----------v--|--|--|--|--|--|--|--|--|--v--|--v-----v--|--v--|--v--^--o
-//     |  |     |              |  |  |  |  |  |  |  |  |     |           |     |     |
-//  o--v--|--^--|--^-----------v--|--|--|--|--|--v--|--|-----|--^--------|-----v--^--v--o
-//        |  |  |  |              |  |  |  |  |     |  |     |  |        |        |
-//  o--^--v--|--|--|--------------v--|--|--|--v-----|--|-----|--v--------|--^-----v-----o
-//     |     |  |  |                 |  |  |        |  |     |           |  |
-//  o--v-----v--|--|-----------------v--|--|--------|--v-----|--^--------|--|--^--------o
-//              |  |                    |  |        |        |  |        |  |  |
-//  o--^--------v--|--------------------v--|--------v--------|--|--------v--v--v--------o
-//     |           |                       |                 |  |
-//  o--v-----------v-----------------------v-----------------v--v-----------------------o
-//
-//  [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13]]
-//  [[0,2],[4,6],[8,10],[1,3],[5,7],[9,11]]
-//  [[0,4],[8,12],[1,5],[9,13],[2,6],[3,7]]
-//  [[0,8],[1,9],[2,10],[3,11],[4,12],[5,13]]
-//  [[5,10],[6,9],[3,12],[7,11],[1,2],[4,8]]
-//  [[1,4],[7,13],[2,8],[5,6],[9,10]]
-//  [[2,4],[11,13],[3,8],[7,12]]
-//  [[6,8],[10,12],[3,5],[7,9]]
-//  [[3,4],[5,6],[7,8],[9,10],[11,12]]
-//  [[6,7],[8,9]]
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#define SORT_NETWORK_14(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[11]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[12], begin[13]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[13]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-  } while (0)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-//  56 comparators, 10 parallel operations
-//  o--^--^-----^-----------^--------------------------------------------------------------o
-//     |  |     |           |
-//  o--v--|--^--|--^--------|--^-----^--------------------------^--------------------------o
-//        |  |  |  |        |  |     |                          |
-//  o--^--v--|--|--|--^-----|--|--^--v--------------------------|--^--^--------------------o
-//     |     |  |  |  |     |  |  |                             |  |  |
-//  o--v-----v--|--|--|--^--|--|--|--^-----------------^--------|--|--|--^--^--^-----------o
-//              |  |  |  |  |  |  |  |                 |        |  |  |  |  |  |
-//  o--^--^-----v--|--|--|--|--|--|--|--^--------------|-----^--v--|--v--|--|--v-----------o
-//     |  |        |  |  |  |  |  |  |  |              |     |     |     |  |
-//  o--v--|--^-----v--|--|--|--|--|--|--|--^-----^-----|-----|-----|--^--|--v-----^--------o
-//        |  |        |  |  |  |  |  |  |  |     |     |     |     |  |  |        |
-//  o--^--v--|--------v--|--|--|--|--|--|--|--^--|--^--|-----|-----|--v--|-----^--v-----^--o
-//     |     |           |  |  |  |  |  |  |  |  |  |  |     |     |     |     |        |
-//  o--v-----v-----------v--|--|--|--|--|--|--|--|--|--|--^--|--^--|-----|--^--|--^--^--v--o
-//                          |  |  |  |  |  |  |  |  |  |  |  |  |  |     |  |  |  |  |
-//  o--^--^-----^-----------v--|--|--|--|--|--|--|--|--|--|--v--|--v-----v--|--v--|--v--^--o
-//     |  |     |              |  |  |  |  |  |  |  |  |  |     |           |     |     |
-//  o--v--|--^--|--^-----------v--|--|--|--|--|--|--v--|--|-----|--^--------|-----v--^--v--o
-//        |  |  |  |              |  |  |  |  |  |     |  |     |  |        |        |
-//  o--^--v--|--|--|--^-----------v--|--|--|--|--v-----|--|-----|--v--------|--^-----v-----o
-//     |     |  |  |  |              |  |  |  |        |  |     |           |  |
-//  o--v-----v--|--|--|--------------v--|--|--|--------|--v-----|--^--^-----|--|--^--------o
-//              |  |  |                 |  |  |        |        |  |  |     |  |  |
-//  o--^--^-----v--|--|-----------------v--|--|--------v--------|--|--|-----v--v--v--------o
-//     |  |        |  |                    |  |                 |  |  |
-//  o--v--|--------v--|--------------------v--|--^--------------v--|--v--------------------o
-//        |           |                       |  |                 |
-//  o-----v-----------v-----------------------v--v-----------------v-----------------------o
-//
-//  [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13]]
-//  [[0,2],[4,6],[8,10],[12,14],[1,3],[5,7],[9,11]]
-//  [[0,4],[8,12],[1,5],[9,13],[2,6],[10,14],[3,7]]
-//  [[0,8],[1,9],[2,10],[3,11],[4,12],[5,13],[6,14]]
-//  [[5,10],[6,9],[3,12],[13,14],[7,11],[1,2],[4,8]]
-//  [[1,4],[7,13],[2,8],[11,14],[5,6],[9,10]]
-//  [[2,4],[11,13],[3,8],[7,12]]
-//  [[6,8],[10,12],[3,5],[7,9]]
-//  [[3,4],[5,6],[7,8],[9,10],[11,12]]
-//  [[6,7],[8,9]]
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#define SORT_NETWORK_15(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[11]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[12], begin[13]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[12], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[14]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[13], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[13]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-  } while (0)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-//  60 comparators, 10 parallel operations
-//  o--^--^-----^-----------^-----------------------------------------------------------------o
-//     |  |     |           |
-//  o--v--|--^--|--^--------|--^-----^-----------------------------^--------------------------o
-//        |  |  |  |        |  |     |                             |
-//  o--^--v--|--|--|--^-----|--|--^--v-----------------------------|--^--^--------------------o
-//     |     |  |  |  |     |  |  |                                |  |  |
-//  o--v-----v--|--|--|--^--|--|--|--^--------------------^--------|--|--|--^--^--^-----------o
-//              |  |  |  |  |  |  |  |                    |        |  |  |  |  |  |
-//  o--^--^-----v--|--|--|--|--|--|--|--^-----------------|-----^--v--|--v--|--|--v-----------o
-//     |  |        |  |  |  |  |  |  |  |                 |     |     |     |  |
-//  o--v--|--^-----v--|--|--|--|--|--|--|--^--------^-----|-----|-----|--^--|--v-----^--------o
-//        |  |        |  |  |  |  |  |  |  |        |     |     |     |  |  |        |
-//  o--^--v--|--------v--|--|--|--|--|--|--|--^-----|--^--|-----|-----|--v--|-----^--v-----^--o
-//     |     |           |  |  |  |  |  |  |  |     |  |  |     |     |     |     |        |
-//  o--v-----v-----------v--|--|--|--|--|--|--|--^--|--|--|--^--|--^--|-----|--^--|--^--^--v--o
-//                          |  |  |  |  |  |  |  |  |  |  |  |  |  |  |     |  |  |  |  |
-//  o--^--^-----^-----------v--|--|--|--|--|--|--|--|--|--|--|--v--|--v-----v--|--v--|--v--^--o
-//     |  |     |              |  |  |  |  |  |  |  |  |  |  |     |           |     |     |
-//  o--v--|--^--|--^-----------v--|--|--|--|--|--|--|--v--|--|-----|--^--------|-----v--^--v--o
-//        |  |  |  |              |  |  |  |  |  |  |     |  |     |  |        |        |
-//  o--^--v--|--|--|--^-----------v--|--|--|--|--|--v-----|--|-----|--v--------|--^-----v-----o
-//     |     |  |  |  |              |  |  |  |  |        |  |     |           |  |
-//  o--v-----v--|--|--|--^-----------v--|--|--|--|--------|--v-----|--^--^-----|--|--^--------o
-//              |  |  |  |              |  |  |  |        |        |  |  |     |  |  |
-//  o--^--^-----v--|--|--|--------------v--|--|--|--------v--------|--|--|-----v--v--v--------o
-//     |  |        |  |  |                 |  |  |                 |  |  |
-//  o--v--|--^-----v--|--|-----------------v--|--|--^--------------v--|--v--------------------o
-//        |  |        |  |                    |  |  |                 |
-//  o--^--v--|--------v--|--------------------v--|--v-----------------v-----------------------o
-//     |     |           |                       |
-//  o--v-----v-----------v-----------------------v--------------------------------------------o
-//
-//  [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13],[14,15]]
-//  [[0,2],[4,6],[8,10],[12,14],[1,3],[5,7],[9,11],[13,15]]
-//  [[0,4],[8,12],[1,5],[9,13],[2,6],[10,14],[3,7],[11,15]]
-//  [[0,8],[1,9],[2,10],[3,11],[4,12],[5,13],[6,14],[7,15]]
-//  [[5,10],[6,9],[3,12],[13,14],[7,11],[1,2],[4,8]]
-//  [[1,4],[7,13],[2,8],[11,14],[5,6],[9,10]]
-//  [[2,4],[11,13],[3,8],[7,12]]
-//  [[6,8],[10,12],[3,5],[7,9]]
-//  [[3,4],[5,6],[7,8],[9,10],[11,12]]
-//  [[6,7],[8,9]]
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#define SORT_NETWORK_16(TYPE, CMP, begin)                                      \
-  do {                                                                         \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[11]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[12], begin[13]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[14], begin[15]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[12], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[13], begin[15]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[15]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[14]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[15]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[13], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[11]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[13]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[14]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[13]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[12]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[10], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[9]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[10]);                             \
-    SORT_CMP_SWAP(TYPE, CMP, begin[11], begin[12]);                            \
-    SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]);                              \
-    SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]);                              \
-  } while (0)
-
-#define SORT_INNER(TYPE, CMP, begin, end, len)                                 \
-  switch (len) {                                                               \
-  default:                                                                     \
-    __unreachable();                                                           \
-  case 0:                                                                      \
-  case 1:                                                                      \
-    break;                                                                     \
-  case 2:                                                                      \
-    SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]);                              \
-    break;                                                                     \
-  case 3:                                                                      \
-    SORT_NETWORK_3(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 4:                                                                      \
-    SORT_NETWORK_4(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 5:                                                                      \
-    SORT_NETWORK_5(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 6:                                                                      \
-    SORT_NETWORK_6(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 7:                                                                      \
-    SORT_NETWORK_7(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 8:                                                                      \
-    SORT_NETWORK_8(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 9:                                                                      \
-    SORT_NETWORK_9(TYPE, CMP, begin);                                          \
-    break;                                                                     \
-  case 10:                                                                     \
-    SORT_NETWORK_10(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  case 11:                                                                     \
-    SORT_NETWORK_11(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  case 12:                                                                     \
-    SORT_NETWORK_12(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  case 13:                                                                     \
-    SORT_NETWORK_13(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  case 14:                                                                     \
-    SORT_NETWORK_14(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  case 15:                                                                     \
-    SORT_NETWORK_15(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  case 16:                                                                     \
-    SORT_NETWORK_16(TYPE, CMP, begin);                                         \
-    break;                                                                     \
-  }
-
-#define SORT_SWAP(TYPE, a, b)                                                  \
-  do {                                                                         \
-    const TYPE swap_tmp = (a);                                                 \
-    (a) = (b);                                                                 \
-    (b) = swap_tmp;                                                            \
-  } while (0)
-
-#define SORT_PUSH(low, high)                                                   \
-  do {                                                                         \
-    top->lo = (low);                                                           \
-    top->hi = (high);                                                          \
-    ++top;                                                                     \
-  } while (0)
-
-#define SORT_POP(low, high)                                                    \
-  do {                                                                         \
-    --top;                                                                     \
-    low = top->lo;                                                             \
-    high = top->hi;                                                            \
-  } while (0)
-
-#define SORT_IMPL(NAME, EXPECT_LOW_CARDINALITY_OR_PRESORTED, TYPE, CMP)        \
-                                                                               \
-  static __inline bool NAME##_is_sorted(const TYPE *first, const TYPE *last) { \
-    while (++first <= last)                                                    \
-      if (CMP(first[0], first[-1]))                                            \
-        return false;                                                          \
-    return true;                                                               \
-  }                                                                            \
-                                                                               \
-  typedef struct {                                                             \
-    TYPE *lo, *hi;                                                             \
-  } NAME##_stack;                                                              \
-                                                                               \
-  static __hot void NAME(TYPE *const begin, TYPE *const end) {                 \
-    NAME##_stack stack[sizeof(unsigned) * CHAR_BIT], *top = stack;             \
-                                                                               \
-    TYPE *hi = end - 1;                                                        \
-    TYPE *lo = begin;                                                          \
-    while (true) {                                                             \
-      const ptrdiff_t len = hi - lo;                                           \
-      if (len < 16) {                                                          \
-        SORT_INNER(TYPE, CMP, lo, hi + 1, len + 1);                            \
-        if (unlikely(top == stack))                                            \
-          break;                                                               \
-        SORT_POP(lo, hi);                                                      \
-        continue;                                                              \
-      }                                                                        \
-                                                                               \
-      TYPE *mid = lo + (len >> 1);                                             \
-      SORT_CMP_SWAP(TYPE, CMP, *lo, *mid);                                     \
-      SORT_CMP_SWAP(TYPE, CMP, *mid, *hi);                                     \
-      SORT_CMP_SWAP(TYPE, CMP, *lo, *mid);                                     \
-                                                                               \
-      TYPE *right = hi - 1;                                                    \
-      TYPE *left = lo + 1;                                                     \
-      while (1) {                                                              \
-        while (CMP(*left, *mid))                                               \
-          ++left;                                                              \
-        while (CMP(*mid, *right))                                              \
-          --right;                                                             \
-        if (unlikely(left > right)) {                                          \
-          if (EXPECT_LOW_CARDINALITY_OR_PRESORTED) {                           \
-            if (NAME##_is_sorted(lo, right))                                   \
-              lo = right + 1;                                                  \
-            if (NAME##_is_sorted(left, hi))                                    \
-              hi = left;                                                       \
-          }                                                                    \
-          break;                                                               \
-        }                                                                      \
-        SORT_SWAP(TYPE, *left, *right);                                        \
-        mid = (mid == left) ? right : (mid == right) ? left : mid;             \
-        ++left;                                                                \
-        --right;                                                               \
-      }                                                                        \
-                                                                               \
-      if (right - lo > hi - left) {                                            \
-        SORT_PUSH(lo, right);                                                  \
-        lo = left;                                                             \
-      } else {                                                                 \
-        SORT_PUSH(left, hi);                                                   \
-        hi = right;                                                            \
-      }                                                                        \
-    }                                                                          \
-                                                                               \
-    if (mdbx_audit_enabled()) {                                                \
-      for (TYPE *scan = begin + 1; scan < end; ++scan)                         \
-        assert(CMP(scan[-1], scan[0]));                                        \
-    }                                                                          \
-  }
-
-/*------------------------------------------------------------------------------
- * LY: radix sort for large chunks */
-
-#define RADIXSORT_IMPL(NAME, TYPE, EXTRACT_KEY, BUFFER_PREALLOCATED, END_GAP)  \
-                                                                               \
-  __hot static bool NAME##_radixsort(TYPE *const begin,                        \
-                                     const unsigned length) {                  \
-    TYPE *tmp;                                                                 \
-    if (BUFFER_PREALLOCATED) {                                                 \
-      tmp = begin + length + END_GAP;                                          \
-      /* memset(tmp, 0xDeadBeef, sizeof(TYPE) * length); */                    \
-    } else {                                                                   \
-      tmp = mdbx_malloc(sizeof(TYPE) * length);                                \
-      if (unlikely(!tmp))                                                      \
-        return false;                                                          \
-    }                                                                          \
-                                                                               \
-    unsigned key_shift = 0, key_diff_mask;                                     \
-    do {                                                                       \
-      struct {                                                                 \
-        unsigned a[256], b[256];                                               \
-      } counters;                                                              \
-      memset(&counters, 0, sizeof(counters));                                  \
-                                                                               \
-      key_diff_mask = 0;                                                       \
-      unsigned prev_key = EXTRACT_KEY(begin) >> key_shift;                     \
-      TYPE *r = begin, *end = begin + length;                                  \
-      do {                                                                     \
-        const unsigned key = EXTRACT_KEY(r) >> key_shift;                      \
-        counters.a[key & 255]++;                                               \
-        counters.b[(key >> 8) & 255]++;                                        \
-        key_diff_mask |= prev_key ^ key;                                       \
-        prev_key = key;                                                        \
-      } while (++r != end);                                                    \
-                                                                               \
-      unsigned ta = 0, tb = 0;                                                 \
-      for (unsigned i = 0; i < 256; ++i) {                                     \
-        const unsigned ia = counters.a[i];                                     \
-        counters.a[i] = ta;                                                    \
-        ta += ia;                                                              \
-        const unsigned ib = counters.b[i];                                     \
-        counters.b[i] = tb;                                                    \
-        tb += ib;                                                              \
-      }                                                                        \
-                                                                               \
-      r = begin;                                                               \
-      do {                                                                     \
-        const unsigned key = EXTRACT_KEY(r) >> key_shift;                      \
-        tmp[counters.a[key & 255]++] = *r;                                     \
-      } while (++r != end);                                                    \
-                                                                               \
-      if (unlikely(key_diff_mask < 256)) {                                     \
-        memcpy(begin, tmp, (char *)end - (char *)begin);                       \
-        break;                                                                 \
-      }                                                                        \
-      end = (r = tmp) + length;                                                \
-      do {                                                                     \
-        const unsigned key = EXTRACT_KEY(r) >> key_shift;                      \
-        begin[counters.b[(key >> 8) & 255]++] = *r;                            \
-      } while (++r != end);                                                    \
-                                                                               \
-      key_shift += 16;                                                         \
-    } while (key_diff_mask >> 16);                                             \
-                                                                               \
-    if (!(BUFFER_PREALLOCATED))                                                \
-      mdbx_free(tmp);                                                          \
-    return true;                                                               \
-  }
-
-/*------------------------------------------------------------------------------
- * LY: Binary search */
-
-#define SEARCH_IMPL(NAME, TYPE_LIST, TYPE_ARG, CMP)                            \
-  static __always_inline const TYPE_LIST *NAME(                                \
-      const TYPE_LIST *first, unsigned length, const TYPE_ARG item) {          \
-    const TYPE_LIST *const begin = first, *const end = begin + length;         \
-                                                                               \
-    while (length > 3) {                                                       \
-      const unsigned whole = length;                                           \
-      length >>= 1;                                                            \
-      const TYPE_LIST *const middle = first + length;                          \
-      const unsigned left = whole - length - 1;                                \
-      const bool cmp = CMP(*middle, item);                                     \
-      length = cmp ? left : length;                                            \
-      first = cmp ? middle + 1 : first;                                        \
-    }                                                                          \
-                                                                               \
-    switch (length) {                                                          \
-    case 3:                                                                    \
-      if (!CMP(*first, item))                                                  \
-        break;                                                                 \
-      ++first;                                                                 \
-      __fallthrough /* fall through */;                                        \
-    case 2:                                                                    \
-      if (!CMP(*first, item))                                                  \
-        break;                                                                 \
-      ++first;                                                                 \
-      __fallthrough /* fall through */;                                        \
-    case 1:                                                                    \
-      if (!CMP(*first, item))                                                  \
-        break;                                                                 \
-      ++first;                                                                 \
-      __fallthrough /* fall through */;                                        \
-    case 0:                                                                    \
-      break;                                                                   \
-    default:                                                                   \
-      __unreachable();                                                         \
-    }                                                                          \
-                                                                               \
-    if (mdbx_audit_enabled()) {                                                \
-      for (const TYPE_LIST *scan = begin; scan < first; ++scan)                \
-        assert(CMP(*scan, item));                                              \
-      for (const TYPE_LIST *scan = first; scan < end; ++scan)                  \
-        assert(!CMP(*scan, item));                                             \
-      (void)begin, (void)end;                                                  \
-    }                                                                          \
-                                                                               \
-    return first;                                                              \
-  }
-
-/*----------------------------------------------------------------------------*/
-
-static __always_inline size_t pnl2bytes(size_t size) {
-  assert(size > 0 && size <= MDBX_PGL_LIMIT);
-#if MDBX_PNL_PREALLOC_FOR_RADIXSORT
-  size += size;
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-  STATIC_ASSERT(MDBX_ASSUME_MALLOC_OVERHEAD +
-                    (MDBX_PGL_LIMIT * (MDBX_PNL_PREALLOC_FOR_RADIXSORT + 1) +
-                     MDBX_PNL_GRANULATE + 2) *
-                        sizeof(pgno_t) <
-                SIZE_MAX / 4 * 3);
-  size_t bytes =
-      ceil_powerof2(MDBX_ASSUME_MALLOC_OVERHEAD + sizeof(pgno_t) * (size + 2),
-                    MDBX_PNL_GRANULATE * sizeof(pgno_t)) -
-      MDBX_ASSUME_MALLOC_OVERHEAD;
-  return bytes;
-}
-
-static __always_inline pgno_t bytes2pnl(const size_t bytes) {
-  size_t size = bytes / sizeof(pgno_t);
-  assert(size > 2 && size <= MDBX_PGL_LIMIT + /* alignment gap */ 65536);
-  size -= 2;
-#if MDBX_PNL_PREALLOC_FOR_RADIXSORT
-  size >>= 1;
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-  return (pgno_t)size;
-}
-
-static MDBX_PNL mdbx_pnl_alloc(size_t size) {
-  size_t bytes = pnl2bytes(size);
-  MDBX_PNL pl = mdbx_malloc(bytes);
-  if (likely(pl)) {
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-    bytes = malloc_usable_size(pl);
-#endif /* malloc_usable_size */
-    pl[0] = bytes2pnl(bytes);
-    assert(pl[0] >= size);
-    pl[1] = 0;
-    pl += 1;
-  }
-  return pl;
-}
-
-static void mdbx_pnl_free(MDBX_PNL pl) {
-  if (likely(pl))
-    mdbx_free(pl - 1);
-}
-
-/* Shrink the PNL to the default size if it has grown larger */
-static void mdbx_pnl_shrink(MDBX_PNL *ppl) {
-  assert(bytes2pnl(pnl2bytes(MDBX_PNL_INITIAL)) >= MDBX_PNL_INITIAL &&
-         bytes2pnl(pnl2bytes(MDBX_PNL_INITIAL)) < MDBX_PNL_INITIAL * 3 / 2);
-  assert(MDBX_PNL_SIZE(*ppl) <= MDBX_PGL_LIMIT &&
-         MDBX_PNL_ALLOCLEN(*ppl) >= MDBX_PNL_SIZE(*ppl));
-  MDBX_PNL_SIZE(*ppl) = 0;
-  if (unlikely(MDBX_PNL_ALLOCLEN(*ppl) >
-               MDBX_PNL_INITIAL * 2 - MDBX_CACHELINE_SIZE / sizeof(pgno_t))) {
-    size_t bytes = pnl2bytes(MDBX_PNL_INITIAL);
-    MDBX_PNL pl = mdbx_realloc(*ppl - 1, bytes);
-    if (likely(pl)) {
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-      bytes = malloc_usable_size(pl);
-#endif /* malloc_usable_size */
-      *pl = bytes2pnl(bytes);
-      *ppl = pl + 1;
-    }
-  }
-}
-
-/* Grow the PNL to the size growed to at least given size */
-static int mdbx_pnl_reserve(MDBX_PNL *ppl, const size_t wanna) {
-  const size_t allocated = MDBX_PNL_ALLOCLEN(*ppl);
-  assert(MDBX_PNL_SIZE(*ppl) <= MDBX_PGL_LIMIT &&
-         MDBX_PNL_ALLOCLEN(*ppl) >= MDBX_PNL_SIZE(*ppl));
-  if (likely(allocated >= wanna))
-    return MDBX_SUCCESS;
-
-  if (unlikely(wanna > /* paranoia */ MDBX_PGL_LIMIT)) {
-    mdbx_error("PNL too long (%zu > %zu)", wanna, (size_t)MDBX_PGL_LIMIT);
-    return MDBX_TXN_FULL;
-  }
-
-  const size_t size = (wanna + wanna - allocated < MDBX_PGL_LIMIT)
-                          ? wanna + wanna - allocated
-                          : MDBX_PGL_LIMIT;
-  size_t bytes = pnl2bytes(size);
-  MDBX_PNL pl = mdbx_realloc(*ppl - 1, bytes);
-  if (likely(pl)) {
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-    bytes = malloc_usable_size(pl);
-#endif /* malloc_usable_size */
-    *pl = bytes2pnl(bytes);
-    assert(*pl >= wanna);
-    *ppl = pl + 1;
-    return MDBX_SUCCESS;
-  }
-  return MDBX_ENOMEM;
-}
-
-/* Make room for num additional elements in an PNL */
-static __always_inline int __must_check_result mdbx_pnl_need(MDBX_PNL *ppl,
-                                                             size_t num) {
-  assert(MDBX_PNL_SIZE(*ppl) <= MDBX_PGL_LIMIT &&
-         MDBX_PNL_ALLOCLEN(*ppl) >= MDBX_PNL_SIZE(*ppl));
-  assert(num <= MDBX_PGL_LIMIT);
-  const size_t wanna = MDBX_PNL_SIZE(*ppl) + num;
-  return likely(MDBX_PNL_ALLOCLEN(*ppl) >= wanna)
-             ? MDBX_SUCCESS
-             : mdbx_pnl_reserve(ppl, wanna);
-}
-
-static __always_inline void mdbx_pnl_xappend(MDBX_PNL pl, pgno_t pgno) {
-  assert(MDBX_PNL_SIZE(pl) < MDBX_PNL_ALLOCLEN(pl));
-  if (mdbx_audit_enabled()) {
-    for (unsigned i = MDBX_PNL_SIZE(pl); i > 0; --i)
-      assert(pgno != pl[i]);
-  }
-  MDBX_PNL_SIZE(pl) += 1;
-  MDBX_PNL_LAST(pl) = pgno;
-}
-
-/* Append an pgno range onto an unsorted PNL */
-__always_inline static int __must_check_result
-mdbx_pnl_append_range(bool spilled, MDBX_PNL *ppl, pgno_t pgno, unsigned n) {
-  assert(n > 0);
-  int rc = mdbx_pnl_need(ppl, n);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  const MDBX_PNL pnl = *ppl;
-#if MDBX_PNL_ASCENDING
-  unsigned w = MDBX_PNL_SIZE(pnl);
-  do {
-    pnl[++w] = pgno;
-    pgno += spilled ? 2 : 1;
-  } while (--n);
-  MDBX_PNL_SIZE(pnl) = w;
-#else
-  unsigned w = MDBX_PNL_SIZE(pnl) + n;
-  MDBX_PNL_SIZE(pnl) = w;
-  do {
-    pnl[w--] = pgno;
-    pgno += spilled ? 2 : 1;
-  } while (--n);
-#endif
-
-  return MDBX_SUCCESS;
-}
-
-/* Append an pgno range into the sorted PNL */
-static __hot int __must_check_result mdbx_pnl_insert_range(MDBX_PNL *ppl,
-                                                           pgno_t pgno,
-                                                           unsigned n) {
-  assert(n > 0);
-  int rc = mdbx_pnl_need(ppl, n);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  const MDBX_PNL pnl = *ppl;
-  unsigned r = MDBX_PNL_SIZE(pnl), w = r + n;
-  MDBX_PNL_SIZE(pnl) = w;
-  while (r && MDBX_PNL_DISORDERED(pnl[r], pgno))
-    pnl[w--] = pnl[r--];
-
-  for (pgno_t fill = MDBX_PNL_ASCENDING ? pgno + n : pgno; w > r; --w)
-    pnl[w] = MDBX_PNL_ASCENDING ? --fill : fill++;
-
-  return MDBX_SUCCESS;
-}
-
-static bool mdbx_pnl_check(const MDBX_PNL pl, const size_t limit) {
-  assert(limit >= MIN_PAGENO - MDBX_ENABLE_REFUND);
-  if (likely(MDBX_PNL_SIZE(pl))) {
-    assert(MDBX_PNL_LEAST(pl) >= MIN_PAGENO);
-    assert(MDBX_PNL_MOST(pl) < limit);
-    assert(MDBX_PNL_SIZE(pl) <= MDBX_PGL_LIMIT);
-    if (unlikely(MDBX_PNL_SIZE(pl) > MDBX_PGL_LIMIT))
-      return false;
-    if (unlikely(MDBX_PNL_LEAST(pl) < MIN_PAGENO))
-      return false;
-    if (unlikely(MDBX_PNL_MOST(pl) >= limit))
-      return false;
-    if (mdbx_audit_enabled()) {
-      for (const pgno_t *scan = &MDBX_PNL_LAST(pl); --scan > pl;) {
-        assert(MDBX_PNL_ORDERED(scan[0], scan[1]));
-        if (unlikely(!MDBX_PNL_ORDERED(scan[0], scan[1])))
-          return false;
-      }
-    }
-  }
-  return true;
-}
-
-static __always_inline bool mdbx_pnl_check4assert(const MDBX_PNL pl,
-                                                  const size_t limit) {
-  if (unlikely(pl == nullptr))
-    return true;
-  assert(MDBX_PNL_ALLOCLEN(pl) >= MDBX_PNL_SIZE(pl));
-  if (unlikely(MDBX_PNL_ALLOCLEN(pl) < MDBX_PNL_SIZE(pl)))
-    return false;
-  return mdbx_pnl_check(pl, limit);
-}
-
-/* Merge an PNL onto an PNL. The destination PNL must be big enough */
-static void __hot mdbx_pnl_xmerge(MDBX_PNL dst, const MDBX_PNL src) {
-  assert(mdbx_pnl_check4assert(dst, MAX_PAGENO + 1));
-  assert(mdbx_pnl_check(src, MAX_PAGENO + 1));
-  const size_t total = MDBX_PNL_SIZE(dst) + MDBX_PNL_SIZE(src);
-  assert(MDBX_PNL_ALLOCLEN(dst) >= total);
-  pgno_t *w = dst + total;
-  pgno_t *d = dst + MDBX_PNL_SIZE(dst);
-  const pgno_t *s = src + MDBX_PNL_SIZE(src);
-  dst[0] = /* detent for scan below */ (MDBX_PNL_ASCENDING ? 0 : ~(pgno_t)0);
-  while (s > src) {
-    while (MDBX_PNL_ORDERED(*s, *d))
-      *w-- = *d--;
-    *w-- = *s--;
-  }
-  MDBX_PNL_SIZE(dst) = (pgno_t)total;
-  assert(mdbx_pnl_check4assert(dst, MAX_PAGENO + 1));
-}
-
-static void mdbx_spill_remove(MDBX_txn *txn, unsigned idx, unsigned npages) {
-  mdbx_tassert(txn, idx > 0 && idx <= MDBX_PNL_SIZE(txn->tw.spill_pages) &&
-                        txn->tw.spill_least_removed > 0);
-  txn->tw.spill_least_removed =
-      (idx < txn->tw.spill_least_removed) ? idx : txn->tw.spill_least_removed;
-  txn->tw.spill_pages[idx] |= 1;
-  MDBX_PNL_SIZE(txn->tw.spill_pages) -=
-      (idx == MDBX_PNL_SIZE(txn->tw.spill_pages));
-
-  while (unlikely(npages > 1)) {
-    const pgno_t pgno = (txn->tw.spill_pages[idx] >> 1) + 1;
-    if (MDBX_PNL_ASCENDING) {
-      if (++idx > MDBX_PNL_SIZE(txn->tw.spill_pages) ||
-          (txn->tw.spill_pages[idx] >> 1) != pgno)
-        return;
-    } else {
-      if (--idx < 1 || (txn->tw.spill_pages[idx] >> 1) != pgno)
-        return;
-      txn->tw.spill_least_removed = (idx < txn->tw.spill_least_removed)
-                                        ? idx
-                                        : txn->tw.spill_least_removed;
-    }
-    txn->tw.spill_pages[idx] |= 1;
-    MDBX_PNL_SIZE(txn->tw.spill_pages) -=
-        (idx == MDBX_PNL_SIZE(txn->tw.spill_pages));
-    --npages;
-  }
-}
-
-static MDBX_PNL mdbx_spill_purge(MDBX_txn *txn) {
-  mdbx_tassert(txn, txn->tw.spill_least_removed > 0);
-  const MDBX_PNL sl = txn->tw.spill_pages;
-  if (txn->tw.spill_least_removed != INT_MAX) {
-    unsigned len = MDBX_PNL_SIZE(sl), r, w;
-    for (w = r = txn->tw.spill_least_removed; r <= len; ++r) {
-      sl[w] = sl[r];
-      w += 1 - (sl[r] & 1);
-    }
-    for (size_t i = 1; i < w; ++i)
-      mdbx_tassert(txn, (sl[i] & 1) == 0);
-    MDBX_PNL_SIZE(sl) = w - 1;
-    txn->tw.spill_least_removed = INT_MAX;
-  } else {
-    for (size_t i = 1; i <= MDBX_PNL_SIZE(sl); ++i)
-      mdbx_tassert(txn, (sl[i] & 1) == 0);
-  }
-  return sl;
-}
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_EXTRACT_KEY(ptr) (*(ptr))
-#else
-#define MDBX_PNL_EXTRACT_KEY(ptr) (P_INVALID - *(ptr))
-#endif
-RADIXSORT_IMPL(pgno, pgno_t, MDBX_PNL_EXTRACT_KEY,
-               MDBX_PNL_PREALLOC_FOR_RADIXSORT, 0)
-
-SORT_IMPL(pgno_sort, false, pgno_t, MDBX_PNL_ORDERED)
-
-static __hot void mdbx_pnl_sort_nochk(MDBX_PNL pnl) {
-  if (likely(MDBX_PNL_SIZE(pnl) < MDBX_RADIXSORT_THRESHOLD) ||
-      unlikely(!pgno_radixsort(&MDBX_PNL_FIRST(pnl), MDBX_PNL_SIZE(pnl))))
-    pgno_sort(MDBX_PNL_BEGIN(pnl), MDBX_PNL_END(pnl));
-}
-
-static __inline void mdbx_pnl_sort(MDBX_PNL pnl, size_t limit4check) {
-  mdbx_pnl_sort_nochk(pnl);
-  assert(mdbx_pnl_check(pnl, limit4check));
-  (void)limit4check;
-}
-
-/* Search for an pgno in an PNL.
- * Returns The index of the first item greater than or equal to pgno. */
-SEARCH_IMPL(pgno_bsearch, pgno_t, pgno_t, MDBX_PNL_ORDERED)
-
-static __hot unsigned mdbx_pnl_search_nochk(const MDBX_PNL pnl, pgno_t pgno) {
-  const pgno_t *begin = MDBX_PNL_BEGIN(pnl);
-  const pgno_t *it = pgno_bsearch(begin, MDBX_PNL_SIZE(pnl), pgno);
-  const pgno_t *end = begin + MDBX_PNL_SIZE(pnl);
-  assert(it >= begin && it <= end);
-  if (it != begin)
-    assert(MDBX_PNL_ORDERED(it[-1], pgno));
-  if (it != end)
-    assert(!MDBX_PNL_ORDERED(it[0], pgno));
-  return (unsigned)(it - begin + 1);
-}
-
-static __inline unsigned mdbx_pnl_search(const MDBX_PNL pnl, pgno_t pgno,
-                                         size_t limit) {
-  assert(mdbx_pnl_check4assert(pnl, limit));
-  assert(pgno < limit);
-  (void)limit;
-  return mdbx_pnl_search_nochk(pnl, pgno);
-}
-
-static __inline unsigned mdbx_search_spilled(const MDBX_txn *txn, pgno_t pgno) {
-  const MDBX_PNL pnl = txn->tw.spill_pages;
-  if (likely(!pnl))
-    return 0;
-  pgno <<= 1;
-  unsigned n = mdbx_pnl_search(pnl, pgno, (size_t)(MAX_PAGENO + 1) << 1);
-  return (n <= MDBX_PNL_SIZE(pnl) && pnl[n] == pgno) ? n : 0;
-}
-
-static __inline bool mdbx_intersect_spilled(const MDBX_txn *txn, pgno_t pgno,
-                                            unsigned npages) {
-  const MDBX_PNL pnl = txn->tw.spill_pages;
-  if (likely(!pnl))
-    return false;
-  const unsigned len = MDBX_PNL_SIZE(pnl);
-  if (mdbx_log_enabled(MDBX_LOG_EXTRA)) {
-    mdbx_debug_extra("PNL len %u [", len);
-    for (unsigned i = 1; i <= len; ++i)
-      mdbx_debug_extra_print(" %li", (pnl[i] & 1) ? -(long)(pnl[i] >> 1)
-                                                  : (long)(pnl[i] >> 1));
-    mdbx_debug_extra_print("%s\n", "]");
-  }
-  const pgno_t spilled_range_begin = pgno << 1;
-  const pgno_t spilled_range_last = ((pgno + npages) << 1) - 1;
-#if MDBX_PNL_ASCENDING
-  const unsigned n =
-      mdbx_pnl_search(pnl, spilled_range_begin, (size_t)(MAX_PAGENO + 1) << 1);
-  assert(n && (n == MDBX_PNL_SIZE(pnl) + 1 || spilled_range_begin <= pnl[n]));
-  const bool rc = n <= MDBX_PNL_SIZE(pnl) && pnl[n] <= spilled_range_last;
-#else
-  const unsigned n =
-      mdbx_pnl_search(pnl, spilled_range_last, (size_t)(MAX_PAGENO + 1) << 1);
-  assert(n && (n == MDBX_PNL_SIZE(pnl) + 1 || spilled_range_last >= pnl[n]));
-  const bool rc = n <= MDBX_PNL_SIZE(pnl) && pnl[n] >= spilled_range_begin;
-#endif
-  if (mdbx_assert_enabled()) {
-    bool check = false;
-    for (unsigned i = 0; i < npages; ++i)
-      check |= mdbx_search_spilled(txn, pgno + i) != 0;
-    assert(check == rc);
-  }
-  return rc;
-}
-
-/*----------------------------------------------------------------------------*/
-
-static __always_inline size_t txl2bytes(const size_t size) {
-  assert(size > 0 && size <= MDBX_TXL_MAX * 2);
-  size_t bytes =
-      ceil_powerof2(MDBX_ASSUME_MALLOC_OVERHEAD + sizeof(txnid_t) * (size + 2),
-                    MDBX_TXL_GRANULATE * sizeof(txnid_t)) -
-      MDBX_ASSUME_MALLOC_OVERHEAD;
-  return bytes;
-}
-
-static __always_inline size_t bytes2txl(const size_t bytes) {
-  size_t size = bytes / sizeof(txnid_t);
-  assert(size > 2 && size <= MDBX_TXL_MAX * 2);
-  return size - 2;
-}
-
-static MDBX_TXL mdbx_txl_alloc(void) {
-  size_t bytes = txl2bytes(MDBX_TXL_INITIAL);
-  MDBX_TXL tl = mdbx_malloc(bytes);
-  if (likely(tl)) {
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-    bytes = malloc_usable_size(tl);
-#endif /* malloc_usable_size */
-    tl[0] = bytes2txl(bytes);
-    assert(tl[0] >= MDBX_TXL_INITIAL);
-    tl[1] = 0;
-    tl += 1;
-  }
-  return tl;
-}
-
-static void mdbx_txl_free(MDBX_TXL tl) {
-  if (likely(tl))
-    mdbx_free(tl - 1);
-}
-
-static int mdbx_txl_reserve(MDBX_TXL *ptl, const size_t wanna) {
-  const size_t allocated = (size_t)MDBX_PNL_ALLOCLEN(*ptl);
-  assert(MDBX_PNL_SIZE(*ptl) <= MDBX_TXL_MAX &&
-         MDBX_PNL_ALLOCLEN(*ptl) >= MDBX_PNL_SIZE(*ptl));
-  if (likely(allocated >= wanna))
-    return MDBX_SUCCESS;
-
-  if (unlikely(wanna > /* paranoia */ MDBX_TXL_MAX)) {
-    mdbx_error("TXL too long (%zu > %zu)", wanna, (size_t)MDBX_TXL_MAX);
-    return MDBX_TXN_FULL;
-  }
-
-  const size_t size = (wanna + wanna - allocated < MDBX_TXL_MAX)
-                          ? wanna + wanna - allocated
-                          : MDBX_TXL_MAX;
-  size_t bytes = txl2bytes(size);
-  MDBX_TXL tl = mdbx_realloc(*ptl - 1, bytes);
-  if (likely(tl)) {
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-    bytes = malloc_usable_size(tl);
-#endif /* malloc_usable_size */
-    *tl = bytes2txl(bytes);
-    assert(*tl >= wanna);
-    *ptl = tl + 1;
-    return MDBX_SUCCESS;
-  }
-  return MDBX_ENOMEM;
-}
-
-static __always_inline int __must_check_result mdbx_txl_need(MDBX_TXL *ptl,
-                                                             size_t num) {
-  assert(MDBX_PNL_SIZE(*ptl) <= MDBX_TXL_MAX &&
-         MDBX_PNL_ALLOCLEN(*ptl) >= MDBX_PNL_SIZE(*ptl));
-  assert(num <= MDBX_PGL_LIMIT);
-  const size_t wanna = (size_t)MDBX_PNL_SIZE(*ptl) + num;
-  return likely(MDBX_PNL_ALLOCLEN(*ptl) >= wanna)
-             ? MDBX_SUCCESS
-             : mdbx_txl_reserve(ptl, wanna);
-}
-
-static __always_inline void mdbx_txl_xappend(MDBX_TXL tl, txnid_t id) {
-  assert(MDBX_PNL_SIZE(tl) < MDBX_PNL_ALLOCLEN(tl));
-  MDBX_PNL_SIZE(tl) += 1;
-  MDBX_PNL_LAST(tl) = id;
-}
-
-#define TXNID_SORT_CMP(first, last) ((first) > (last))
-SORT_IMPL(txnid_sort, false, txnid_t, TXNID_SORT_CMP)
-static void mdbx_txl_sort(MDBX_TXL tl) {
-  txnid_sort(MDBX_PNL_BEGIN(tl), MDBX_PNL_END(tl));
-}
-
-static int __must_check_result mdbx_txl_append(MDBX_TXL *ptl, txnid_t id) {
-  if (unlikely(MDBX_PNL_SIZE(*ptl) == MDBX_PNL_ALLOCLEN(*ptl))) {
-    int rc = mdbx_txl_need(ptl, MDBX_TXL_GRANULATE);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-  mdbx_txl_xappend(*ptl, id);
-  return MDBX_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------*/
-
-#define MDBX_DPL_UNSORTED_BACKLOG 16
-#define MDBX_DPL_GAP_FOR_MERGESORT MDBX_DPL_UNSORTED_BACKLOG
-#define MDBX_DPL_GAP_FOR_EDGING 2
-#define MDBX_DPL_RESERVE_GAP                                                   \
-  (MDBX_DPL_GAP_FOR_MERGESORT + MDBX_DPL_GAP_FOR_EDGING)
-
-static __always_inline size_t dpl2bytes(ptrdiff_t size) {
-  assert(size > CURSOR_STACK && (size_t)size <= MDBX_PGL_LIMIT);
-#if MDBX_DPL_PREALLOC_FOR_RADIXSORT
-  size += size;
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-  STATIC_ASSERT(MDBX_ASSUME_MALLOC_OVERHEAD + sizeof(MDBX_dpl) +
-                    (MDBX_PGL_LIMIT * (MDBX_DPL_PREALLOC_FOR_RADIXSORT + 1) +
-                     MDBX_DPL_RESERVE_GAP) *
-                        sizeof(MDBX_dp) +
-                    MDBX_PNL_GRANULATE * sizeof(void *) * 2 <
-                SIZE_MAX / 4 * 3);
-  size_t bytes =
-      ceil_powerof2(MDBX_ASSUME_MALLOC_OVERHEAD + sizeof(MDBX_dpl) +
-                        ((size_t)size + MDBX_DPL_RESERVE_GAP) * sizeof(MDBX_dp),
-                    MDBX_PNL_GRANULATE * sizeof(void *) * 2) -
-      MDBX_ASSUME_MALLOC_OVERHEAD;
-  return bytes;
-}
-
-static __always_inline unsigned bytes2dpl(const ptrdiff_t bytes) {
-  size_t size = (bytes - sizeof(MDBX_dpl)) / sizeof(MDBX_dp);
-  assert(size > CURSOR_STACK + MDBX_DPL_RESERVE_GAP &&
-         size <= MDBX_PGL_LIMIT + MDBX_PNL_GRANULATE);
-  size -= MDBX_DPL_RESERVE_GAP;
-#if MDBX_DPL_PREALLOC_FOR_RADIXSORT
-  size >>= 1;
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-  return (unsigned)size;
-}
-
-static __always_inline unsigned dpl_setlen(MDBX_dpl *dl, unsigned len) {
-  static const MDBX_page dpl_stub_pageE = {
-      {0}, 0, P_BAD, {0}, /* pgno */ ~(pgno_t)0};
-  assert(dpl_stub_pageE.mp_flags == P_BAD &&
-         dpl_stub_pageE.mp_pgno == P_INVALID);
-  dl->length = len;
-  dl->items[len + 1].ptr = (MDBX_page *)&dpl_stub_pageE;
-  dl->items[len + 1].pgno = P_INVALID;
-  dl->items[len + 1].extra = 0;
-  return len;
-}
-
-static __always_inline void dpl_clear(MDBX_dpl *dl) {
-  static const MDBX_page dpl_stub_pageB = {{0}, 0, P_BAD, {0}, /* pgno */ 0};
-  assert(dpl_stub_pageB.mp_flags == P_BAD && dpl_stub_pageB.mp_pgno == 0);
-  dl->sorted = dpl_setlen(dl, 0);
-  dl->items[0].ptr = (MDBX_page *)&dpl_stub_pageB;
-  dl->items[0].pgno = 0;
-  dl->items[0].extra = 0;
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-}
-
-static void mdbx_dpl_free(MDBX_txn *txn) {
-  if (likely(txn->tw.dirtylist)) {
-    mdbx_free(txn->tw.dirtylist);
-    txn->tw.dirtylist = NULL;
-  }
-}
-
-static MDBX_dpl *mdbx_dpl_reserve(MDBX_txn *txn, size_t size) {
-  size_t bytes = dpl2bytes((size < MDBX_PGL_LIMIT) ? size : MDBX_PGL_LIMIT);
-  MDBX_dpl *const dl = mdbx_realloc(txn->tw.dirtylist, bytes);
-  if (likely(dl)) {
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-    bytes = malloc_usable_size(dl);
-#endif /* malloc_usable_size */
-    dl->detent = bytes2dpl(bytes);
-    mdbx_tassert(txn, txn->tw.dirtylist == NULL || dl->length <= dl->detent);
-    txn->tw.dirtylist = dl;
-  }
-  return dl;
-}
-
-static int mdbx_dpl_alloc(MDBX_txn *txn) {
-  mdbx_tassert(txn, (txn->mt_flags & MDBX_TXN_RDONLY) == 0);
-  const int wanna = (txn->mt_env->me_options.dp_initial < txn->mt_geo.upper)
-                        ? txn->mt_env->me_options.dp_initial
-                        : txn->mt_geo.upper;
-  if (txn->tw.dirtylist) {
-    dpl_clear(txn->tw.dirtylist);
-    const int realloc_threshold = 64;
-    if (likely(
-            !((int)(txn->tw.dirtylist->detent - wanna) > realloc_threshold ||
-              (int)(txn->tw.dirtylist->detent - wanna) < -realloc_threshold)))
-      return MDBX_SUCCESS;
-  }
-  if (unlikely(!mdbx_dpl_reserve(txn, wanna)))
-    return MDBX_ENOMEM;
-  dpl_clear(txn->tw.dirtylist);
-  return MDBX_SUCCESS;
-}
-
-#define MDBX_DPL_EXTRACT_KEY(ptr) ((ptr)->pgno)
-RADIXSORT_IMPL(dpl, MDBX_dp, MDBX_DPL_EXTRACT_KEY,
-               MDBX_DPL_PREALLOC_FOR_RADIXSORT, 1)
-
-#define DP_SORT_CMP(first, last) ((first).pgno < (last).pgno)
-SORT_IMPL(dp_sort, false, MDBX_dp, DP_SORT_CMP)
-
-__hot __noinline static MDBX_dpl *mdbx_dpl_sort_slowpath(const MDBX_txn *txn) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  const unsigned unsorted = dl->length - dl->sorted;
-  if (likely(unsorted < MDBX_RADIXSORT_THRESHOLD) ||
-      unlikely(!dpl_radixsort(dl->items + 1, dl->length))) {
-    if (dl->sorted > unsorted / 4 + 4 &&
-        (MDBX_DPL_PREALLOC_FOR_RADIXSORT ||
-         dl->length + unsorted < dl->detent + MDBX_DPL_GAP_FOR_MERGESORT)) {
-      MDBX_dp *const sorted_begin = dl->items + 1;
-      MDBX_dp *const sorted_end = sorted_begin + dl->sorted;
-      MDBX_dp *const end =
-          dl->items + (MDBX_DPL_PREALLOC_FOR_RADIXSORT
-                           ? dl->length + dl->length + 1
-                           : dl->detent + MDBX_DPL_RESERVE_GAP);
-      MDBX_dp *const tmp = end - unsorted;
-      assert(dl->items + dl->length + 1 < tmp);
-      /* copy unsorted to the end of allocated space and sort it */
-      memcpy(tmp, sorted_end, unsorted * sizeof(MDBX_dp));
-      dp_sort(tmp, tmp + unsorted);
-      /* merge two parts from end to begin */
-      MDBX_dp *w = dl->items + dl->length;
-      MDBX_dp *l = dl->items + dl->sorted;
-      MDBX_dp *r = end - 1;
-      do {
-        const bool cmp = l->pgno > r->pgno;
-        *w = cmp ? *l : *r;
-        l -= cmp;
-        r += cmp - 1;
-      } while (likely(--w > l));
-      assert(r == tmp - 1);
-      assert(dl->items[0].pgno == 0 &&
-             dl->items[dl->length + 1].pgno == P_INVALID);
-      if (mdbx_assert_enabled())
-        for (unsigned i = 0; i <= dl->length; ++i)
-          assert(dl->items[i].pgno < dl->items[i + 1].pgno);
-    } else {
-      dp_sort(dl->items + 1, dl->items + dl->length + 1);
-      assert(dl->items[0].pgno == 0 &&
-             dl->items[dl->length + 1].pgno == P_INVALID);
-    }
-  } else {
-    assert(dl->items[0].pgno == 0 &&
-           dl->items[dl->length + 1].pgno == P_INVALID);
-  }
-  dl->sorted = dl->length;
-  return dl;
-}
-
-static __always_inline MDBX_dpl *mdbx_dpl_sort(const MDBX_txn *txn) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  assert(dl->length <= MDBX_PGL_LIMIT);
-  assert(dl->sorted <= dl->length);
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  return likely(dl->sorted == dl->length) ? dl : mdbx_dpl_sort_slowpath(txn);
-}
-
-/* Returns the index of the first dirty-page whose pgno
- * member is greater than or equal to id. */
-#define DP_SEARCH_CMP(dp, id) ((dp).pgno < (id))
-SEARCH_IMPL(dp_bsearch, MDBX_dp, pgno_t, DP_SEARCH_CMP)
-
-static unsigned __hot mdbx_dpl_search(const MDBX_txn *txn, pgno_t pgno) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  if (mdbx_audit_enabled()) {
-    for (const MDBX_dp *ptr = dl->items + dl->sorted; --ptr > dl->items;) {
-      assert(ptr[0].pgno < ptr[1].pgno);
-      assert(ptr[0].pgno >= NUM_METAS);
-    }
-  }
-
-  switch (dl->length - dl->sorted) {
-  default:
-    /* sort a whole */
-    mdbx_dpl_sort_slowpath(txn);
-    break;
-  case 0:
-    /* whole sorted cases */
-    break;
-
-#define LINEAR_SEARCH_CASE(N)                                                  \
-  case N:                                                                      \
-    if (dl->items[dl->length - N + 1].pgno == pgno)                            \
-      return dl->length - N + 1;                                               \
-    __fallthrough
-
-    /* try linear search until the threshold */
-    LINEAR_SEARCH_CASE(16); /* fall through */
-    LINEAR_SEARCH_CASE(15); /* fall through */
-    LINEAR_SEARCH_CASE(14); /* fall through */
-    LINEAR_SEARCH_CASE(13); /* fall through */
-    LINEAR_SEARCH_CASE(12); /* fall through */
-    LINEAR_SEARCH_CASE(11); /* fall through */
-    LINEAR_SEARCH_CASE(10); /* fall through */
-    LINEAR_SEARCH_CASE(9);  /* fall through */
-    LINEAR_SEARCH_CASE(8);  /* fall through */
-    LINEAR_SEARCH_CASE(7);  /* fall through */
-    LINEAR_SEARCH_CASE(6);  /* fall through */
-    LINEAR_SEARCH_CASE(5);  /* fall through */
-    LINEAR_SEARCH_CASE(4);  /* fall through */
-    LINEAR_SEARCH_CASE(3);  /* fall through */
-    LINEAR_SEARCH_CASE(2);  /* fall through */
-  case 1:
-    if (dl->items[dl->length].pgno == pgno)
-      return dl->length;
-    /* continue bsearch on the sorted part */
-    break;
-  }
-  return (unsigned)(dp_bsearch(dl->items + 1, dl->sorted, pgno) - dl->items);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __inline unsigned
-dpl_npages(const MDBX_dpl *dl, unsigned i) {
-  assert(0 <= (int)i && i <= dl->length);
-  unsigned n = likely(!dl->items[i].multi) ? 1 : dl->items[i].ptr->mp_pages;
-  assert(n == (IS_OVERFLOW(dl->items[i].ptr) ? dl->items[i].ptr->mp_pages : 1));
-  return n;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static __inline unsigned
-dpl_endpgno(const MDBX_dpl *dl, unsigned i) {
-  return dpl_npages(dl, i) + dl->items[i].pgno;
-}
-
-static __inline bool mdbx_dpl_intersect(const MDBX_txn *txn, pgno_t pgno,
-                                        unsigned npages) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  assert(dl->sorted == dl->length);
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  unsigned const n = mdbx_dpl_search(txn, pgno);
-  assert(n >= 1 && n <= dl->length + 1);
-  assert(pgno <= dl->items[n].pgno);
-  assert(pgno > dl->items[n - 1].pgno);
-  const bool rc =
-      /* intersection with founded */ pgno + npages > dl->items[n].pgno ||
-      /* intersection with prev */ dpl_endpgno(dl, n - 1) > pgno;
-  if (mdbx_assert_enabled()) {
-    bool check = false;
-    for (unsigned i = 1; i <= dl->length; ++i) {
-      const MDBX_page *const dp = dl->items[i].ptr;
-      if (!(dp->mp_pgno /* begin */ >= /* end */ pgno + npages ||
-            dpl_endpgno(dl, i) /* end */ <= /* begin */ pgno))
-        check |= true;
-    }
-    assert(check == rc);
-  }
-  return rc;
-}
-
-static __always_inline unsigned mdbx_dpl_exist(MDBX_txn *txn, pgno_t pgno) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  unsigned i = mdbx_dpl_search(txn, pgno);
-  assert((int)i > 0);
-  return (dl->items[i].pgno == pgno) ? i : 0;
-}
-
-MDBX_MAYBE_UNUSED static const MDBX_page *debug_dpl_find(const MDBX_txn *txn,
-                                                         const pgno_t pgno) {
-  const MDBX_dpl *dl = txn->tw.dirtylist;
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  for (unsigned i = dl->length; i > dl->sorted; --i)
-    if (dl->items[i].pgno == pgno)
-      return dl->items[i].ptr;
-
-  if (dl->sorted) {
-    const unsigned i =
-        (unsigned)(dp_bsearch(dl->items + 1, dl->sorted, pgno) - dl->items);
-    if (dl->items[i].pgno == pgno)
-      return dl->items[i].ptr;
-  }
-  return nullptr;
-}
-
-static void mdbx_dpl_remove(const MDBX_txn *txn, unsigned i) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  assert((int)i > 0 && i <= dl->length);
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  dl->sorted -= dl->sorted >= i;
-  dl->length -= 1;
-  memmove(dl->items + i, dl->items + i + 1,
-          (dl->length - i + 2) * sizeof(dl->items[0]));
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-}
-
-static __always_inline int __must_check_result
-mdbx_dpl_append(MDBX_txn *txn, pgno_t pgno, MDBX_page *page, unsigned npages) {
-  MDBX_dpl *dl = txn->tw.dirtylist;
-  assert(dl->length <= MDBX_PGL_LIMIT + MDBX_PNL_GRANULATE);
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  if (mdbx_audit_enabled()) {
-    for (unsigned i = dl->length; i > 0; --i) {
-      assert(dl->items[i].pgno != pgno);
-      if (unlikely(dl->items[i].pgno == pgno)) {
-        mdbx_error("Page %u already exist in the DPL at %u", pgno, i);
-        return MDBX_PROBLEM;
-      }
-    }
-  }
-
-  const unsigned length = dl->length + 1;
-  const unsigned sorted =
-      (dl->sorted == dl->length && dl->items[dl->length].pgno < pgno)
-          ? length
-          : dl->sorted;
-
-  if (unlikely(dl->length == dl->detent)) {
-    if (unlikely(dl->detent >= MDBX_PGL_LIMIT)) {
-      mdbx_error("DPL is full (MDBX_PGL_LIMIT %zu)", MDBX_PGL_LIMIT);
-      return MDBX_TXN_FULL;
-    }
-    const size_t size = (dl->detent < MDBX_PNL_INITIAL * 42)
-                            ? dl->detent + dl->detent
-                            : dl->detent + dl->detent / 2;
-    dl = mdbx_dpl_reserve(txn, size);
-    if (unlikely(!dl))
-      return MDBX_ENOMEM;
-    mdbx_tassert(txn, dl->length < dl->detent);
-  }
-
-  /* copy the stub beyond the end */
-  dl->items[length + 1] = dl->items[length];
-  /* append page */
-  dl->items[length].ptr = page;
-  dl->items[length].pgno = pgno;
-  dl->items[length].multi = npages > 1;
-  dl->items[length].lru = txn->tw.dirtylru++;
-  dl->length = length;
-  dl->sorted = sorted;
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  return MDBX_SUCCESS;
-}
-
-static __inline uint32_t mdbx_dpl_age(const MDBX_txn *txn, unsigned i) {
-  const MDBX_dpl *dl = txn->tw.dirtylist;
-  assert((int)i > 0 && i <= dl->length);
-  /* overflow could be here */
-  return (txn->tw.dirtylru - dl->items[i].lru) & UINT32_C(0x7fffFFFF);
-}
-
-/*----------------------------------------------------------------------------*/
-
-uint8_t mdbx_runtime_flags = MDBX_RUNTIME_FLAGS_INIT;
-uint8_t mdbx_loglevel = MDBX_LOG_FATAL;
-MDBX_debug_func *mdbx_debug_logger;
-
-static __must_check_result __inline int mdbx_page_retire(MDBX_cursor *mc,
-                                                         MDBX_page *mp);
-
-static int __must_check_result mdbx_page_dirty(MDBX_txn *txn, MDBX_page *mp,
-                                               unsigned npages);
-struct page_result {
-  MDBX_page *page;
-  int err;
-};
-
-static struct page_result mdbx_page_alloc(MDBX_cursor *mc, const pgno_t num,
-                                          int flags);
-static txnid_t mdbx_kick_longlived_readers(MDBX_env *env,
-                                           const txnid_t laggard);
-
-static struct page_result mdbx_page_new(MDBX_cursor *mc, const unsigned flags,
-                                        const unsigned npages);
-static int mdbx_page_touch(MDBX_cursor *mc);
-static int mdbx_cursor_touch(MDBX_cursor *mc);
-static int mdbx_touch_dbi(MDBX_cursor *mc);
-
-#define MDBX_END_NAMES                                                         \
-  {                                                                            \
-    "committed", "empty-commit", "abort", "reset", "reset-tmp", "fail-begin",  \
-        "fail-beginchild"                                                      \
-  }
-enum {
-  /* mdbx_txn_end operation number, for logging */
-  MDBX_END_COMMITTED,
-  MDBX_END_PURE_COMMIT,
-  MDBX_END_ABORT,
-  MDBX_END_RESET,
-  MDBX_END_RESET_TMP,
-  MDBX_END_FAIL_BEGIN,
-  MDBX_END_FAIL_BEGINCHILD
-};
-#define MDBX_END_OPMASK 0x0F  /* mask for mdbx_txn_end() operation number */
-#define MDBX_END_UPDATE 0x10  /* update env state (DBIs) */
-#define MDBX_END_FREE 0x20    /* free txn unless it is MDBX_env.me_txn0 */
-#define MDBX_END_EOTDONE 0x40 /* txn's cursors already closed */
-#define MDBX_END_SLOT 0x80    /* release any reader slot if MDBX_NOTLS */
-static int mdbx_txn_end(MDBX_txn *txn, const unsigned mode);
-
-__hot static struct page_result __must_check_result
-mdbx_page_get_ex(MDBX_cursor *const mc, const pgno_t pgno, txnid_t front);
-static __always_inline int __must_check_result mdbx_page_get(MDBX_cursor *mc,
-                                                             pgno_t pgno,
-                                                             MDBX_page **mp,
-                                                             txnid_t front) {
-
-  struct page_result ret = mdbx_page_get_ex(mc, pgno, front);
-  *mp = ret.page;
-  return ret.err;
-}
-
-static int __must_check_result mdbx_page_search_root(MDBX_cursor *mc,
-                                                     const MDBX_val *key,
-                                                     int flags);
-
-#define MDBX_PS_MODIFY 1
-#define MDBX_PS_ROOTONLY 2
-#define MDBX_PS_FIRST 4
-#define MDBX_PS_LAST 8
-static int __must_check_result mdbx_page_search(MDBX_cursor *mc,
-                                                const MDBX_val *key, int flags);
-static int __must_check_result mdbx_page_merge(MDBX_cursor *csrc,
-                                               MDBX_cursor *cdst);
-
-#define MDBX_SPLIT_REPLACE MDBX_APPENDDUP /* newkey is not new */
-static int __must_check_result mdbx_page_split(MDBX_cursor *mc,
-                                               const MDBX_val *const newkey,
-                                               MDBX_val *const newdata,
-                                               pgno_t newpgno, unsigned nflags);
-
-static bool meta_checktxnid(const MDBX_env *env, const MDBX_meta *meta,
-                            bool report);
-static int __must_check_result mdbx_validate_meta_copy(MDBX_env *env,
-                                                       const MDBX_meta *meta,
-                                                       MDBX_meta *dest);
-static int __must_check_result mdbx_override_meta(MDBX_env *env,
-                                                  unsigned target,
-                                                  txnid_t txnid,
-                                                  const MDBX_meta *shape);
-static int __must_check_result mdbx_read_header(MDBX_env *env, MDBX_meta *meta,
-                                                const int lck_exclusive,
-                                                const mdbx_mode_t mode_bits);
-static int __must_check_result mdbx_sync_locked(MDBX_env *env, unsigned flags,
-                                                MDBX_meta *const pending);
-static int mdbx_env_close0(MDBX_env *env);
-
-struct node_result {
-  MDBX_node *node;
-  bool exact;
-};
-
-static struct node_result mdbx_node_search(MDBX_cursor *mc,
-                                           const MDBX_val *key);
-
-static int __must_check_result mdbx_node_add_branch(MDBX_cursor *mc,
-                                                    unsigned indx,
-                                                    const MDBX_val *key,
-                                                    pgno_t pgno);
-static int __must_check_result mdbx_node_add_leaf(MDBX_cursor *mc,
-                                                  unsigned indx,
-                                                  const MDBX_val *key,
-                                                  MDBX_val *data,
-                                                  unsigned flags);
-static int __must_check_result mdbx_node_add_leaf2(MDBX_cursor *mc,
-                                                   unsigned indx,
-                                                   const MDBX_val *key);
-
-static void mdbx_node_del(MDBX_cursor *mc, size_t ksize);
-static void mdbx_node_shrink(MDBX_page *mp, unsigned indx);
-static int __must_check_result mdbx_node_move(MDBX_cursor *csrc,
-                                              MDBX_cursor *cdst, bool fromleft);
-static int __must_check_result mdbx_node_read(MDBX_cursor *mc,
-                                              const MDBX_node *leaf,
-                                              MDBX_val *data,
-                                              const txnid_t front);
-static int __must_check_result mdbx_rebalance(MDBX_cursor *mc);
-static int __must_check_result mdbx_update_key(MDBX_cursor *mc,
-                                               const MDBX_val *key);
-
-static void mdbx_cursor_pop(MDBX_cursor *mc);
-static int __must_check_result mdbx_cursor_push(MDBX_cursor *mc, MDBX_page *mp);
-
-static int __must_check_result mdbx_audit_ex(MDBX_txn *txn,
-                                             unsigned retired_stored,
-                                             bool dont_filter_gc);
-
-static int __must_check_result mdbx_page_check(MDBX_cursor *const mc,
-                                               const MDBX_page *const mp,
-                                               unsigned options);
-static int __must_check_result mdbx_cursor_check(MDBX_cursor *mc,
-                                                 unsigned options);
-static int __must_check_result mdbx_cursor_del0(MDBX_cursor *mc);
-static int __must_check_result mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi,
-                                         const MDBX_val *key,
-                                         const MDBX_val *data, unsigned flags);
-#define SIBLING_LEFT 0
-#define SIBLING_RIGHT 2
-static int __must_check_result mdbx_cursor_sibling(MDBX_cursor *mc, int dir);
-static int __must_check_result mdbx_cursor_next(MDBX_cursor *mc, MDBX_val *key,
-                                                MDBX_val *data,
-                                                MDBX_cursor_op op);
-static int __must_check_result mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key,
-                                                MDBX_val *data,
-                                                MDBX_cursor_op op);
-struct cursor_set_result {
-  int err;
-  bool exact;
-};
-
-static struct cursor_set_result mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key,
-                                                MDBX_val *data,
-                                                MDBX_cursor_op op);
-static int __must_check_result mdbx_cursor_first(MDBX_cursor *mc, MDBX_val *key,
-                                                 MDBX_val *data);
-static int __must_check_result mdbx_cursor_last(MDBX_cursor *mc, MDBX_val *key,
-                                                MDBX_val *data);
-
-static int __must_check_result mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn,
-                                                MDBX_dbi dbi);
-static int __must_check_result mdbx_xcursor_init0(MDBX_cursor *mc);
-static int __must_check_result mdbx_xcursor_init1(MDBX_cursor *mc,
-                                                  MDBX_node *node,
-                                                  const MDBX_page *mp);
-static int __must_check_result mdbx_xcursor_init2(MDBX_cursor *mc,
-                                                  MDBX_xcursor *src_mx,
-                                                  bool new_dupdata);
-static void cursor_copy(const MDBX_cursor *csrc, MDBX_cursor *cdst);
-
-static int __must_check_result mdbx_drop_tree(MDBX_cursor *mc,
-                                              const bool may_have_subDBs);
-static int __must_check_result mdbx_fetch_sdb(MDBX_txn *txn, MDBX_dbi dbi);
-static int __must_check_result mdbx_setup_dbx(MDBX_dbx *const dbx,
-                                              const MDBX_db *const db,
-                                              const unsigned pagesize);
-
-static MDBX_cmp_func cmp_lexical, cmp_reverse, cmp_int_align4, cmp_int_align2,
-    cmp_int_unaligned, cmp_lenfast;
-
-static __inline MDBX_cmp_func *get_default_keycmp(unsigned flags);
-static __inline MDBX_cmp_func *get_default_datacmp(unsigned flags);
-
-__cold const char *mdbx_liberr2str(int errnum) {
-  /* Table of descriptions for MDBX errors */
-  static const char *const tbl[] = {
-      "MDBX_KEYEXIST: Key/data pair already exists",
-      "MDBX_NOTFOUND: No matching key/data pair found",
-      "MDBX_PAGE_NOTFOUND: Requested page not found",
-      "MDBX_CORRUPTED: Database is corrupted",
-      "MDBX_PANIC: Environment had fatal error",
-      "MDBX_VERSION_MISMATCH: DB version mismatch libmdbx",
-      "MDBX_INVALID: File is not an MDBX file",
-      "MDBX_MAP_FULL: Environment mapsize limit reached",
-      "MDBX_DBS_FULL: Too many DBI-handles (maxdbs reached)",
-      "MDBX_READERS_FULL: Too many readers (maxreaders reached)",
-      NULL /* MDBX_TLS_FULL (-30789): unused in MDBX */,
-      "MDBX_TXN_FULL: Transaction has too many dirty pages,"
-      " i.e transaction is too big",
-      "MDBX_CURSOR_FULL: Cursor stack limit reachedn - this usually indicates"
-      " corruption, i.e branch-pages loop",
-      "MDBX_PAGE_FULL: Internal error - Page has no more space",
-      "MDBX_UNABLE_EXTEND_MAPSIZE: Database engine was unable to extend"
-      " mapping, e.g. since address space is unavailable or busy,"
-      " or Operation system not supported such operations",
-      "MDBX_INCOMPATIBLE: Environment or database is not compatible"
-      " with the requested operation or the specified flags",
-      "MDBX_BAD_RSLOT: Invalid reuse of reader locktable slot,"
-      " e.g. read-transaction already run for current thread",
-      "MDBX_BAD_TXN: Transaction is not valid for requested operation,"
-      " e.g. had errored and be must aborted, has a child, or is invalid",
-      "MDBX_BAD_VALSIZE: Invalid size or alignment of key or data"
-      " for target database, either invalid subDB name",
-      "MDBX_BAD_DBI: The specified DBI-handle is invalid"
-      " or changed by another thread/transaction",
-      "MDBX_PROBLEM: Unexpected internal error, transaction should be aborted",
-      "MDBX_BUSY: Another write transaction is running,"
-      " or environment is already used while opening with MDBX_EXCLUSIVE flag",
-  };
-
-  if (errnum >= MDBX_KEYEXIST && errnum <= MDBX_BUSY) {
-    int i = errnum - MDBX_KEYEXIST;
-    return tbl[i];
-  }
-
-  switch (errnum) {
-  case MDBX_SUCCESS:
-    return "MDBX_SUCCESS: Successful";
-  case MDBX_EMULTIVAL:
-    return "MDBX_EMULTIVAL: The specified key has"
-           " more than one associated value";
-  case MDBX_EBADSIGN:
-    return "MDBX_EBADSIGN: Wrong signature of a runtime object(s),"
-           " e.g. memory corruption or double-free";
-  case MDBX_WANNA_RECOVERY:
-    return "MDBX_WANNA_RECOVERY: Database should be recovered,"
-           " but this could NOT be done automatically for now"
-           " since it opened in read-only mode";
-  case MDBX_EKEYMISMATCH:
-    return "MDBX_EKEYMISMATCH: The given key value is mismatched to the"
-           " current cursor position";
-  case MDBX_TOO_LARGE:
-    return "MDBX_TOO_LARGE: Database is too large for current system,"
-           " e.g. could NOT be mapped into RAM";
-  case MDBX_THREAD_MISMATCH:
-    return "MDBX_THREAD_MISMATCH: A thread has attempted to use a not"
-           " owned object, e.g. a transaction that started by another thread";
-  case MDBX_TXN_OVERLAPPING:
-    return "MDBX_TXN_OVERLAPPING: Overlapping read and write transactions for"
-           " the current thread";
-  default:
-    return NULL;
-  }
-}
-
-__cold const char *mdbx_strerror_r(int errnum, char *buf, size_t buflen) {
-  const char *msg = mdbx_liberr2str(errnum);
-  if (!msg && buflen > 0 && buflen < INT_MAX) {
-#if defined(_WIN32) || defined(_WIN64)
-    const DWORD size = FormatMessageA(
-        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
-        errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen,
-        NULL);
-    return size ? buf : "FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM) failed";
-#elif defined(_GNU_SOURCE) && defined(__GLIBC__)
-    /* GNU-specific */
-    if (errnum > 0)
-      msg = strerror_r(errnum, buf, buflen);
-#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
-    /* XSI-compliant */
-    if (errnum > 0 && strerror_r(errnum, buf, buflen) == 0)
-      msg = buf;
-#else
-    if (errnum > 0) {
-      msg = strerror(errnum);
-      if (msg) {
-        strncpy(buf, msg, buflen);
-        msg = buf;
-      }
-    }
-#endif
-    if (!msg) {
-      (void)snprintf(buf, buflen, "error %d", errnum);
-      msg = buf;
-    }
-    buf[buflen - 1] = '\0';
-  }
-  return msg;
-}
-
-__cold const char *mdbx_strerror(int errnum) {
-#if defined(_WIN32) || defined(_WIN64)
-  static char buf[1024];
-  return mdbx_strerror_r(errnum, buf, sizeof(buf));
-#else
-  const char *msg = mdbx_liberr2str(errnum);
-  if (!msg) {
-    if (errnum > 0)
-      msg = strerror(errnum);
-    if (!msg) {
-      static char buf[32];
-      (void)snprintf(buf, sizeof(buf) - 1, "error %d", errnum);
-      msg = buf;
-    }
-  }
-  return msg;
-#endif
-}
-
-#if defined(_WIN32) || defined(_WIN64) /* Bit of madness for Windows */
-const char *mdbx_strerror_r_ANSI2OEM(int errnum, char *buf, size_t buflen) {
-  const char *msg = mdbx_liberr2str(errnum);
-  if (!msg && buflen > 0 && buflen < INT_MAX) {
-    const DWORD size = FormatMessageA(
-        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
-        errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen,
-        NULL);
-    if (!size)
-      msg = "FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM) failed";
-    else if (!CharToOemBuffA(buf, buf, size))
-      msg = "CharToOemBuffA() failed";
-    else
-      msg = buf;
-  }
-  return msg;
-}
-
-const char *mdbx_strerror_ANSI2OEM(int errnum) {
-  static char buf[1024];
-  return mdbx_strerror_r_ANSI2OEM(errnum, buf, sizeof(buf));
-}
-#endif /* Bit of madness for Windows */
-
-__cold void mdbx_debug_log_va(int level, const char *function, int line,
-                              const char *fmt, va_list args) {
-  if (mdbx_debug_logger)
-    mdbx_debug_logger(level, function, line, fmt, args);
-  else {
-#if defined(_WIN32) || defined(_WIN64)
-    if (IsDebuggerPresent()) {
-      int prefix_len = 0;
-      char *prefix = nullptr;
-      if (function && line > 0)
-        prefix_len = mdbx_asprintf(&prefix, "%s:%d ", function, line);
-      else if (function)
-        prefix_len = mdbx_asprintf(&prefix, "%s: ", function);
-      else if (line > 0)
-        prefix_len = mdbx_asprintf(&prefix, "%d: ", line);
-      if (prefix_len > 0 && prefix) {
-        OutputDebugStringA(prefix);
-        mdbx_free(prefix);
-      }
-      char *msg = nullptr;
-      int msg_len = mdbx_vasprintf(&msg, fmt, args);
-      if (msg_len > 0 && msg) {
-        OutputDebugStringA(msg);
-        mdbx_free(msg);
-      }
-    }
-#else
-    if (function && line > 0)
-      fprintf(stderr, "%s:%d ", function, line);
-    else if (function)
-      fprintf(stderr, "%s: ", function);
-    else if (line > 0)
-      fprintf(stderr, "%d: ", line);
-    vfprintf(stderr, fmt, args);
-    fflush(stderr);
-#endif
-  }
-}
-
-__cold void mdbx_debug_log(int level, const char *function, int line,
-                           const char *fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  mdbx_debug_log_va(level, function, line, fmt, args);
-  va_end(args);
-}
-
-/* Dump a key in ascii or hexadecimal. */
-const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
-                          const size_t bufsize) {
-  if (!key)
-    return "<null>";
-  if (!key->iov_len)
-    return "<empty>";
-  if (!buf || bufsize < 4)
-    return nullptr;
-
-  bool is_ascii = true;
-  const uint8_t *const data = key->iov_base;
-  for (unsigned i = 0; i < key->iov_len; i++)
-    if (data[i] < ' ' || data[i] > '~') {
-      is_ascii = false;
-      break;
-    }
-
-  if (is_ascii) {
-    int len =
-        snprintf(buf, bufsize, "%.*s",
-                 (key->iov_len > INT_MAX) ? INT_MAX : (int)key->iov_len, data);
-    assert(len > 0 && (unsigned)len < bufsize);
-    (void)len;
-  } else {
-    char *const detent = buf + bufsize - 2;
-    char *ptr = buf;
-    *ptr++ = '<';
-    for (unsigned i = 0; i < key->iov_len; i++) {
-      const ptrdiff_t left = detent - ptr;
-      assert(left > 0);
-      int len = snprintf(ptr, left, "%02x", data[i]);
-      if (len < 0 || len >= left)
-        break;
-      ptr += len;
-    }
-    if (ptr < detent) {
-      ptr[0] = '>';
-      ptr[1] = '\0';
-    }
-  }
-  return buf;
-}
-
-/*------------------------------------------------------------------------------
- LY: debug stuff */
-
-static const char *mdbx_leafnode_type(MDBX_node *n) {
-  static const char *const tp[2][2] = {{"", ": DB"},
-                                       {": sub-page", ": sub-DB"}};
-  return F_ISSET(node_flags(n), F_BIGDATA)
-             ? ": overflow page"
-             : tp[F_ISSET(node_flags(n), F_DUPDATA)]
-                 [F_ISSET(node_flags(n), F_SUBDATA)];
-}
-
-/* Display all the keys in the page. */
-MDBX_MAYBE_UNUSED static void mdbx_page_list(MDBX_page *mp) {
-  pgno_t pgno = mp->mp_pgno;
-  const char *type;
-  MDBX_node *node;
-  unsigned i, nkeys, nsize, total = 0;
-  MDBX_val key;
-  DKBUF;
-
-  switch (mp->mp_flags &
-          (P_BRANCH | P_LEAF | P_LEAF2 | P_META | P_OVERFLOW | P_SUBP)) {
-  case P_BRANCH:
-    type = "Branch page";
-    break;
-  case P_LEAF:
-    type = "Leaf page";
-    break;
-  case P_LEAF | P_SUBP:
-    type = "Leaf sub-page";
-    break;
-  case P_LEAF | P_LEAF2:
-    type = "Leaf2 page";
-    break;
-  case P_LEAF | P_LEAF2 | P_SUBP:
-    type = "Leaf2 sub-page";
-    break;
-  case P_OVERFLOW:
-    mdbx_verbose("Overflow page %" PRIaPGNO " pages %u\n", pgno, mp->mp_pages);
-    return;
-  case P_META:
-    mdbx_verbose("Meta-page %" PRIaPGNO " txnid %" PRIu64 "\n", pgno,
-                 unaligned_peek_u64(4, page_meta(mp)->mm_txnid_a));
-    return;
-  default:
-    mdbx_verbose("Bad page %" PRIaPGNO " flags 0x%X\n", pgno, mp->mp_flags);
-    return;
-  }
-
-  nkeys = page_numkeys(mp);
-  mdbx_verbose("%s %" PRIaPGNO " numkeys %u\n", type, pgno, nkeys);
-
-  for (i = 0; i < nkeys; i++) {
-    if (IS_LEAF2(mp)) { /* LEAF2 pages have no mp_ptrs[] or node headers */
-      key.iov_len = nsize = mp->mp_leaf2_ksize;
-      key.iov_base = page_leaf2key(mp, i, nsize);
-      total += nsize;
-      mdbx_verbose("key %u: nsize %u, %s\n", i, nsize, DKEY(&key));
-      continue;
-    }
-    node = page_node(mp, i);
-    key.iov_len = node_ks(node);
-    key.iov_base = node->mn_data;
-    nsize = (unsigned)(NODESIZE + key.iov_len);
-    if (IS_BRANCH(mp)) {
-      mdbx_verbose("key %u: page %" PRIaPGNO ", %s\n", i, node_pgno(node),
-                   DKEY(&key));
-      total += nsize;
-    } else {
-      if (F_ISSET(node_flags(node), F_BIGDATA))
-        nsize += sizeof(pgno_t);
-      else
-        nsize += (unsigned)node_ds(node);
-      total += nsize;
-      nsize += sizeof(indx_t);
-      mdbx_verbose("key %u: nsize %u, %s%s\n", i, nsize, DKEY(&key),
-                   mdbx_leafnode_type(node));
-    }
-    total = EVEN(total);
-  }
-  mdbx_verbose("Total: header %u + contents %u + unused %u\n",
-               IS_LEAF2(mp) ? PAGEHDRSZ : PAGEHDRSZ + mp->mp_lower, total,
-               page_room(mp));
-}
-
-/*----------------------------------------------------------------------------*/
-
-/* Check if there is an initialized xcursor, so XCURSOR_REFRESH() is proper */
-#define XCURSOR_INITED(mc)                                                     \
-  ((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
-
-/* Update sub-page pointer, if any, in mc->mc_xcursor.
- * Needed when the node which contains the sub-page may have moved.
- * Called with mp = mc->mc_pg[mc->mc_top], ki = mc->mc_ki[mc->mc_top]. */
-#define XCURSOR_REFRESH(mc, mp, ki)                                            \
-  do {                                                                         \
-    MDBX_page *xr_pg = (mp);                                                   \
-    MDBX_node *xr_node = page_node(xr_pg, ki);                                 \
-    if ((node_flags(xr_node) & (F_DUPDATA | F_SUBDATA)) == F_DUPDATA)          \
-      (mc)->mc_xcursor->mx_cursor.mc_pg[0] = node_data(xr_node);               \
-  } while (0)
-
-MDBX_MAYBE_UNUSED static bool cursor_is_tracked(const MDBX_cursor *mc) {
-  for (MDBX_cursor *scan = mc->mc_txn->mt_cursors[mc->mc_dbi]; scan;
-       scan = scan->mc_next)
-    if (mc == ((mc->mc_flags & C_SUB) ? &scan->mc_xcursor->mx_cursor : scan))
-      return true;
-  return false;
-}
-
-/* Perform act while tracking temporary cursor mn */
-#define WITH_CURSOR_TRACKING(mn, act)                                          \
-  do {                                                                         \
-    mdbx_cassert(&(mn),                                                        \
-                 mn.mc_txn->mt_cursors != NULL /* must be not rdonly txt */);  \
-    mdbx_cassert(&(mn), !cursor_is_tracked(&(mn)));                            \
-    MDBX_cursor mc_dummy;                                                      \
-    MDBX_cursor **tracking_head = &(mn).mc_txn->mt_cursors[mn.mc_dbi];         \
-    MDBX_cursor *tracked = &(mn);                                              \
-    if ((mn).mc_flags & C_SUB) {                                               \
-      mc_dummy.mc_flags = C_INITIALIZED;                                       \
-      mc_dummy.mc_top = 0;                                                     \
-      mc_dummy.mc_snum = 0;                                                    \
-      mc_dummy.mc_xcursor = (MDBX_xcursor *)&(mn);                             \
-      tracked = &mc_dummy;                                                     \
-    }                                                                          \
-    tracked->mc_next = *tracking_head;                                         \
-    *tracking_head = tracked;                                                  \
-    { act; }                                                                   \
-    *tracking_head = tracked->mc_next;                                         \
-  } while (0)
-
-int mdbx_cmp(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
-             const MDBX_val *b) {
-  mdbx_assert(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
-  return txn->mt_dbxs[dbi].md_cmp(a, b);
-}
-
-int mdbx_dcmp(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
-              const MDBX_val *b) {
-  mdbx_assert(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
-  return txn->mt_dbxs[dbi].md_dcmp(a, b);
-}
-
-/* Allocate memory for a page.
- * Re-use old malloc'ed pages first for singletons, otherwise just malloc.
- * Set MDBX_TXN_ERROR on failure. */
-static MDBX_page *mdbx_page_malloc(MDBX_txn *txn, unsigned num) {
-  MDBX_env *env = txn->mt_env;
-  MDBX_page *np = env->me_dp_reserve;
-  size_t size = env->me_psize;
-  if (likely(num == 1 && np)) {
-    mdbx_assert(env, env->me_dp_reserve_len > 0);
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(np, size);
-    VALGRIND_MEMPOOL_ALLOC(env, np, size);
-    VALGRIND_MAKE_MEM_DEFINED(&np->mp_next, sizeof(np->mp_next));
-    env->me_dp_reserve = np->mp_next;
-    env->me_dp_reserve_len -= 1;
-  } else {
-    size = pgno2bytes(env, num);
-    np = mdbx_malloc(size);
-    if (unlikely(!np)) {
-      txn->mt_flags |= MDBX_TXN_ERROR;
-      return np;
-    }
-    VALGRIND_MEMPOOL_ALLOC(env, np, size);
-  }
-
-  if ((env->me_flags & MDBX_NOMEMINIT) == 0) {
-    /* For a single page alloc, we init everything after the page header.
-     * For multi-page, we init the final page; if the caller needed that
-     * many pages they will be filling in at least up to the last page. */
-    size_t skip = PAGEHDRSZ;
-    if (num > 1)
-      skip += pgno2bytes(env, num - 1);
-    memset((char *)np + skip, 0, size - skip);
-  }
-#if MDBX_DEBUG
-  np->mp_pgno = 0;
-#endif
-  VALGRIND_MAKE_MEM_UNDEFINED(np, size);
-  np->mp_flags = 0;
-  np->mp_pages = num;
-  return np;
-}
-
-/* Free a shadow dirty page */
-static void mdbx_dpage_free(MDBX_env *env, MDBX_page *dp, unsigned npages) {
-  VALGRIND_MAKE_MEM_UNDEFINED(dp, pgno2bytes(env, npages));
-  MDBX_ASAN_UNPOISON_MEMORY_REGION(dp, pgno2bytes(env, npages));
-  if (MDBX_DEBUG != 0 || unlikely(env->me_flags & MDBX_PAGEPERTURB))
-    memset(dp, -1, pgno2bytes(env, npages));
-  if (npages == 1 &&
-      env->me_dp_reserve_len < env->me_options.dp_reserve_limit) {
-    MDBX_ASAN_POISON_MEMORY_REGION((char *)dp + sizeof(dp->mp_next),
-                                   pgno2bytes(env, npages) -
-                                       sizeof(dp->mp_next));
-    dp->mp_next = env->me_dp_reserve;
-    VALGRIND_MEMPOOL_FREE(env, dp);
-    env->me_dp_reserve = dp;
-    env->me_dp_reserve_len += 1;
-  } else {
-    /* large pages just get freed directly */
-    VALGRIND_MEMPOOL_FREE(env, dp);
-    mdbx_free(dp);
-  }
-}
-
-/* Return all dirty pages to dpage list */
-static void mdbx_dlist_free(MDBX_txn *txn) {
-  MDBX_env *env = txn->mt_env;
-  MDBX_dpl *const dl = txn->tw.dirtylist;
-
-  for (unsigned i = 1; i <= dl->length; i++) {
-    MDBX_page *dp = dl->items[i].ptr;
-    mdbx_dpage_free(env, dp, dpl_npages(dl, i));
-  }
-
-  dpl_clear(dl);
-}
-
-static __always_inline MDBX_db *mdbx_outer_db(MDBX_cursor *mc) {
-  mdbx_cassert(mc, (mc->mc_flags & C_SUB) != 0);
-  MDBX_xcursor *mx = container_of(mc->mc_db, MDBX_xcursor, mx_db);
-  MDBX_cursor_couple *couple = container_of(mx, MDBX_cursor_couple, inner);
-  mdbx_cassert(mc, mc->mc_db == &couple->outer.mc_xcursor->mx_db);
-  mdbx_cassert(mc, mc->mc_dbx == &couple->outer.mc_xcursor->mx_dbx);
-  return couple->outer.mc_db;
-}
-
-MDBX_MAYBE_UNUSED __cold static bool mdbx_dirtylist_check(MDBX_txn *txn) {
-  const MDBX_dpl *const dl = txn->tw.dirtylist;
-  assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
-  mdbx_tassert(txn, txn->tw.dirtyroom + dl->length ==
-                        (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                        : txn->mt_env->me_options.dp_limit));
-
-  if (!mdbx_audit_enabled())
-    return true;
-
-  unsigned loose = 0;
-  for (unsigned i = dl->length; i > 0; --i) {
-    const MDBX_page *const dp = dl->items[i].ptr;
-    if (!dp)
-      continue;
-
-    mdbx_tassert(txn, dp->mp_pgno == dl->items[i].pgno);
-    if (unlikely(dp->mp_pgno != dl->items[i].pgno))
-      return false;
-
-    const uint32_t age = mdbx_dpl_age(txn, i);
-    mdbx_tassert(txn, age < UINT32_MAX / 3);
-    if (unlikely(age > UINT32_MAX / 3))
-      return false;
-
-    mdbx_tassert(txn, dp->mp_flags == P_LOOSE || IS_MODIFIABLE(txn, dp));
-    if (dp->mp_flags == P_LOOSE) {
-      loose += 1;
-    } else if (unlikely(!IS_MODIFIABLE(txn, dp)))
-      return false;
-
-    const unsigned num = dpl_npages(dl, i);
-    mdbx_tassert(txn, txn->mt_next_pgno >= dp->mp_pgno + num);
-    if (unlikely(txn->mt_next_pgno < dp->mp_pgno + num))
-      return false;
-
-    if (i < dl->sorted) {
-      mdbx_tassert(txn, dl->items[i + 1].pgno >= dp->mp_pgno + num);
-      if (unlikely(dl->items[i + 1].pgno < dp->mp_pgno + num))
-        return false;
-    }
-
-    const unsigned rpa = mdbx_pnl_search(txn->tw.reclaimed_pglist, dp->mp_pgno,
-                                         txn->mt_next_pgno);
-    mdbx_tassert(txn, rpa > MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) ||
-                          txn->tw.reclaimed_pglist[rpa] != dp->mp_pgno);
-    if (rpa <= MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) &&
-        unlikely(txn->tw.reclaimed_pglist[rpa] == dp->mp_pgno))
-      return false;
-    if (num > 1) {
-      const unsigned rpb = mdbx_pnl_search(
-          txn->tw.reclaimed_pglist, dp->mp_pgno + num - 1, txn->mt_next_pgno);
-      mdbx_tassert(txn, rpa == rpb);
-      if (unlikely(rpa != rpb))
-        return false;
-    }
-  }
-
-  mdbx_tassert(txn, loose == txn->tw.loose_count);
-  if (unlikely(loose != txn->tw.loose_count))
-    return false;
-
-  for (unsigned i = 1; i <= MDBX_PNL_SIZE(txn->tw.retired_pages); ++i) {
-    const MDBX_page *const dp = debug_dpl_find(txn, txn->tw.retired_pages[i]);
-    mdbx_tassert(txn, !dp);
-    if (unlikely(dp))
-      return false;
-  }
-
-  return true;
-}
-
-#if MDBX_ENABLE_REFUND
-static void mdbx_refund_reclaimed(MDBX_txn *txn) {
-  /* Scanning in descend order */
-  pgno_t next_pgno = txn->mt_next_pgno;
-  const MDBX_PNL pnl = txn->tw.reclaimed_pglist;
-  mdbx_tassert(txn, MDBX_PNL_SIZE(pnl) && MDBX_PNL_MOST(pnl) == next_pgno - 1);
-#if MDBX_PNL_ASCENDING
-  unsigned i = MDBX_PNL_SIZE(pnl);
-  mdbx_tassert(txn, pnl[i] == next_pgno - 1);
-  while (--next_pgno, --i > 0 && pnl[i] == next_pgno - 1)
-    ;
-  MDBX_PNL_SIZE(pnl) = i;
-#else
-  unsigned i = 1;
-  mdbx_tassert(txn, pnl[i] == next_pgno - 1);
-  unsigned len = MDBX_PNL_SIZE(pnl);
-  while (--next_pgno, ++i <= len && pnl[i] == next_pgno - 1)
-    ;
-  MDBX_PNL_SIZE(pnl) = len -= i - 1;
-  for (unsigned move = 0; move < len; ++move)
-    pnl[1 + move] = pnl[i + move];
-#endif
-  mdbx_verbose("refunded %" PRIaPGNO " pages: %" PRIaPGNO " -> %" PRIaPGNO,
-               txn->mt_next_pgno - next_pgno, txn->mt_next_pgno, next_pgno);
-  txn->mt_next_pgno = next_pgno;
-  mdbx_tassert(txn, mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                          txn->mt_next_pgno - 1));
-}
-
-static void mdbx_refund_loose(MDBX_txn *txn) {
-  mdbx_tassert(txn, txn->tw.loose_pages != nullptr);
-  mdbx_tassert(txn, txn->tw.loose_count > 0);
-
-  MDBX_dpl *const dl = txn->tw.dirtylist;
-  mdbx_tassert(txn, dl->length >= txn->tw.loose_count);
-
-  pgno_t onstack[MDBX_CACHELINE_SIZE * 8 / sizeof(pgno_t)];
-  MDBX_PNL suitable = onstack;
-
-  if (dl->length - dl->sorted > txn->tw.loose_count) {
-    /* Dirty list is useless since unsorted. */
-    if (bytes2pnl(sizeof(onstack)) < txn->tw.loose_count) {
-      suitable = mdbx_pnl_alloc(txn->tw.loose_count);
-      if (unlikely(!suitable))
-        return /* this is not a reason for transaction fail */;
-    }
-
-    /* Collect loose-pages which may be refunded. */
-    mdbx_tassert(txn, txn->mt_next_pgno >= MIN_PAGENO + txn->tw.loose_count);
-    pgno_t most = MIN_PAGENO;
-    unsigned w = 0;
-    for (const MDBX_page *lp = txn->tw.loose_pages; lp; lp = lp->mp_next) {
-      mdbx_tassert(txn, lp->mp_flags == P_LOOSE);
-      mdbx_tassert(txn, txn->mt_next_pgno > lp->mp_pgno);
-      if (likely(txn->mt_next_pgno - txn->tw.loose_count <= lp->mp_pgno)) {
-        mdbx_tassert(txn,
-                     w < ((suitable == onstack) ? bytes2pnl(sizeof(onstack))
-                                                : MDBX_PNL_ALLOCLEN(suitable)));
-        suitable[++w] = lp->mp_pgno;
-        most = (lp->mp_pgno > most) ? lp->mp_pgno : most;
-      }
-    }
-
-    if (most + 1 == txn->mt_next_pgno) {
-      /* Sort suitable list and refund pages at the tail. */
-      MDBX_PNL_SIZE(suitable) = w;
-      mdbx_pnl_sort(suitable, MAX_PAGENO + 1);
-
-      /* Scanning in descend order */
-      const int step = MDBX_PNL_ASCENDING ? -1 : 1;
-      const int begin = MDBX_PNL_ASCENDING ? MDBX_PNL_SIZE(suitable) : 1;
-      const int end = MDBX_PNL_ASCENDING ? 0 : MDBX_PNL_SIZE(suitable) + 1;
-      mdbx_tassert(txn, suitable[begin] >= suitable[end - step]);
-      mdbx_tassert(txn, most == suitable[begin]);
-
-      for (int i = begin + step; i != end; i += step) {
-        if (suitable[i] != most - 1)
-          break;
-        most -= 1;
-      }
-      const unsigned refunded = txn->mt_next_pgno - most;
-      mdbx_debug("refund-suitable %u pages %" PRIaPGNO " -> %" PRIaPGNO,
-                 refunded, most, txn->mt_next_pgno);
-      txn->tw.loose_count -= refunded;
-      txn->tw.dirtyroom += refunded;
-      assert(txn->tw.dirtyroom <= txn->mt_env->me_options.dp_limit);
-      txn->mt_next_pgno = most;
-
-      /* Filter-out dirty list */
-      unsigned r = 0;
-      w = 0;
-      if (dl->sorted) {
-        do {
-          if (dl->items[++r].pgno < most) {
-            if (++w != r)
-              dl->items[w] = dl->items[r];
-          }
-        } while (r < dl->sorted);
-        dl->sorted = w;
-      }
-      while (r < dl->length) {
-        if (dl->items[++r].pgno < most) {
-          if (++w != r)
-            dl->items[w] = dl->items[r];
-        }
-      }
-      dpl_setlen(dl, w);
-      mdbx_tassert(txn,
-                   txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                       (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                       : txn->mt_env->me_options.dp_limit));
-
-      goto unlink_loose;
-    }
-  } else {
-    /* Dirtylist is mostly sorted, just refund loose pages at the end. */
-    mdbx_dpl_sort(txn);
-    mdbx_tassert(txn, dl->length < 2 ||
-                          dl->items[1].pgno < dl->items[dl->length].pgno);
-    mdbx_tassert(txn, dl->sorted == dl->length);
-
-    /* Scan dirtylist tail-forward and cutoff suitable pages. */
-    unsigned n;
-    for (n = dl->length; dl->items[n].pgno == txn->mt_next_pgno - 1 &&
-                         dl->items[n].ptr->mp_flags == P_LOOSE;
-         --n) {
-      mdbx_tassert(txn, n > 0);
-      MDBX_page *dp = dl->items[n].ptr;
-      mdbx_debug("refund-sorted page %" PRIaPGNO, dp->mp_pgno);
-      mdbx_tassert(txn, dp->mp_pgno == dl->items[n].pgno);
-      txn->mt_next_pgno -= 1;
-    }
-    dpl_setlen(dl, n);
-
-    if (dl->sorted != dl->length) {
-      const unsigned refunded = dl->sorted - dl->length;
-      dl->sorted = dl->length;
-      txn->tw.loose_count -= refunded;
-      txn->tw.dirtyroom += refunded;
-      mdbx_tassert(txn,
-                   txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                       (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                       : txn->mt_env->me_options.dp_limit));
-
-      /* Filter-out loose chain & dispose refunded pages. */
-    unlink_loose:
-      for (MDBX_page **link = &txn->tw.loose_pages; *link;) {
-        MDBX_page *dp = *link;
-        mdbx_tassert(txn, dp->mp_flags == P_LOOSE);
-        if (txn->mt_next_pgno > dp->mp_pgno) {
-          link = &dp->mp_next;
-        } else {
-          *link = dp->mp_next;
-          if ((txn->mt_flags & MDBX_WRITEMAP) == 0)
-            mdbx_dpage_free(txn->mt_env, dp, 1);
-        }
-      }
-    }
-  }
-
-  mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-  if (suitable != onstack)
-    mdbx_pnl_free(suitable);
-  txn->tw.loose_refund_wl = txn->mt_next_pgno;
-}
-
-static bool mdbx_refund(MDBX_txn *txn) {
-  const pgno_t before = txn->mt_next_pgno;
-
-  if (txn->tw.loose_pages && txn->tw.loose_refund_wl > txn->mt_next_pgno)
-    mdbx_refund_loose(txn);
-
-  while (true) {
-    if (MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) == 0 ||
-        MDBX_PNL_MOST(txn->tw.reclaimed_pglist) != txn->mt_next_pgno - 1)
-      break;
-
-    mdbx_refund_reclaimed(txn);
-    if (!txn->tw.loose_pages || txn->tw.loose_refund_wl <= txn->mt_next_pgno)
-      break;
-
-    const pgno_t memo = txn->mt_next_pgno;
-    mdbx_refund_loose(txn);
-    if (memo == txn->mt_next_pgno)
-      break;
-  }
-
-  if (before == txn->mt_next_pgno)
-    return false;
-
-  if (txn->tw.spill_pages)
-    /* Squash deleted pagenums if we refunded any */
-    mdbx_spill_purge(txn);
-
-  return true;
-}
-#else  /* MDBX_ENABLE_REFUND */
-static __inline bool mdbx_refund(MDBX_txn *txn) {
-  (void)txn;
-  /* No online auto-compactification. */
-  return false;
-}
-#endif /* MDBX_ENABLE_REFUND */
-
-__cold static void mdbx_kill_page(MDBX_txn *txn, MDBX_page *mp, pgno_t pgno,
-                                  unsigned npages) {
-  MDBX_env *const env = txn->mt_env;
-  mdbx_debug("kill %u page(s) %" PRIaPGNO, npages, pgno);
-  mdbx_assert(env, pgno >= NUM_METAS && npages);
-  if (!IS_FROZEN(txn, mp)) {
-    const size_t bytes = pgno2bytes(env, npages);
-    memset(mp, -1, bytes);
-    mp->mp_pgno = pgno;
-    if ((env->me_flags & MDBX_WRITEMAP) == 0)
-      mdbx_pwrite(env->me_lazy_fd, mp, bytes, pgno2bytes(env, pgno));
-  } else {
-    struct iovec iov[MDBX_COMMIT_PAGES];
-    iov[0].iov_len = env->me_psize;
-    iov[0].iov_base = (char *)env->me_pbuf + env->me_psize;
-    size_t iov_off = pgno2bytes(env, pgno);
-    unsigned n = 1;
-    while (--npages) {
-      iov[n] = iov[0];
-      if (++n == MDBX_COMMIT_PAGES) {
-        mdbx_pwritev(env->me_lazy_fd, iov, MDBX_COMMIT_PAGES, iov_off,
-                     pgno2bytes(env, MDBX_COMMIT_PAGES));
-        iov_off += pgno2bytes(env, MDBX_COMMIT_PAGES);
-        n = 0;
-      }
-    }
-    mdbx_pwritev(env->me_lazy_fd, iov, n, iov_off, pgno2bytes(env, n));
-  }
-}
-
-/* Remove page from dirty list */
-static __inline void mdbx_page_wash(MDBX_txn *txn, const unsigned di,
-                                    MDBX_page *const mp,
-                                    const unsigned npages) {
-  mdbx_tassert(txn, di && di <= txn->tw.dirtylist->length &&
-                        txn->tw.dirtylist->items[di].ptr == mp);
-  mdbx_dpl_remove(txn, di);
-  txn->tw.dirtyroom++;
-  mdbx_tassert(txn, txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                        (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                        : txn->mt_env->me_options.dp_limit));
-  mp->mp_txnid = INVALID_TXNID;
-  mp->mp_flags = 0xFFFF;
-  VALGRIND_MAKE_MEM_UNDEFINED(mp, PAGEHDRSZ);
-  if (txn->mt_flags & MDBX_WRITEMAP) {
-    VALGRIND_MAKE_MEM_NOACCESS(page_data(mp),
-                               pgno2bytes(txn->mt_env, npages) - PAGEHDRSZ);
-    MDBX_ASAN_POISON_MEMORY_REGION(page_data(mp),
-                                   pgno2bytes(txn->mt_env, npages) - PAGEHDRSZ);
-  } else
-    mdbx_dpage_free(txn->mt_env, mp, npages);
-}
-
-static __inline txnid_t pp_txnid4chk(const MDBX_page *mp, const MDBX_txn *txn) {
-  (void)txn;
-#if MDBX_DISABLE_PAGECHECKS
-  (void)mp;
-  return 0;
-#else
-  return /* maybe zero in legacy DB */ mp->mp_txnid;
-#endif /* !MDBX_DISABLE_PAGECHECKS */
-}
-
-/* Retire, loosen or free a single page.
- *
- * For dirty pages, saves single pages to a list for future reuse in this same
- * txn. It has been pulled from the GC and already resides on the dirty list,
- * but has been deleted. Use these pages first before pulling again from the GC.
- *
- * If the page wasn't dirtied in this txn, just add it
- * to this txn's free list. */
-static int mdbx_page_retire_ex(MDBX_cursor *mc, const pgno_t pgno,
-                               MDBX_page *mp /* maybe null */,
-                               int pagetype /* maybe unknown/zero */) {
-  int rc;
-  MDBX_txn *const txn = mc->mc_txn;
-  mdbx_tassert(txn, !mp || (mp->mp_pgno == pgno && PAGETYPE(mp) == pagetype));
-
-  /* During deleting entire subtrees, it is reasonable and possible to avoid
-   * reading leaf pages, i.e. significantly reduce hard page-faults & IOPs:
-   *  - mp is null, i.e. the page has not yet been read;
-   *  - pagetype is known and the P_LEAF bit is set;
-   *  - we can determine the page status via scanning the lists
-   *    of dirty and spilled pages.
-   *
-   *  On the other hand, this could be suboptimal for WRITEMAP mode, since
-   *  requires support the list of dirty pages and avoid explicit spilling.
-   *  So for flexibility and avoid extra internal dependencies we just
-   *  fallback to reading if dirty list was not allocated yet. */
-  unsigned di = 0, si = 0, npages = 1;
-  bool is_frozen = false, is_spilled = false, is_shadowed = false;
-  if (unlikely(!mp)) {
-    if (mdbx_assert_enabled() && pagetype) {
-      MDBX_page *check;
-      rc = mdbx_page_get(mc, pgno, &check, txn->mt_front);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-      mdbx_tassert(txn, (PAGETYPE(check) & ~P_LEAF2) == (pagetype & ~P_FROZEN));
-      mdbx_tassert(txn, !(pagetype & P_FROZEN) || IS_FROZEN(txn, check));
-    }
-    if (pagetype & P_FROZEN) {
-      is_frozen = true;
-      if (mdbx_assert_enabled()) {
-        for (MDBX_txn *scan = txn; scan; scan = scan->mt_parent) {
-          mdbx_tassert(txn, !mdbx_search_spilled(scan, pgno));
-          mdbx_tassert(txn, !scan->tw.dirtylist || !debug_dpl_find(scan, pgno));
-        }
-      }
-      goto status_done;
-    } else if (pagetype && txn->tw.dirtylist) {
-      if ((di = mdbx_dpl_exist(txn, pgno)) != 0) {
-        mp = txn->tw.dirtylist->items[di].ptr;
-        mdbx_tassert(txn, IS_MODIFIABLE(txn, mp));
-        goto status_done;
-      }
-      if ((si = mdbx_search_spilled(txn, pgno)) != 0) {
-        is_spilled = true;
-        goto status_done;
-      }
-      for (MDBX_txn *parent = txn->mt_parent; parent;
-           parent = parent->mt_parent) {
-        if (mdbx_dpl_exist(parent, pgno)) {
-          is_shadowed = true;
-          goto status_done;
-        }
-        if (mdbx_search_spilled(parent, pgno)) {
-          is_spilled = true;
-          goto status_done;
-        }
-      }
-      is_frozen = true;
-      goto status_done;
-    }
-
-    rc = mdbx_page_get(mc, pgno, &mp, txn->mt_front);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    mdbx_tassert(txn, !pagetype || PAGETYPE(mp) == pagetype);
-    pagetype = PAGETYPE(mp);
-  }
-
-  is_frozen = IS_FROZEN(txn, mp);
-  if (!is_frozen) {
-    const bool is_dirty = IS_MODIFIABLE(txn, mp);
-    is_spilled = IS_SPILLED(txn, mp) && !(txn->mt_flags & MDBX_WRITEMAP);
-    is_shadowed = IS_SHADOWED(txn, mp);
-    if (is_dirty) {
-      mdbx_tassert(txn, !is_spilled);
-      mdbx_tassert(txn, !mdbx_search_spilled(txn, pgno));
-      mdbx_tassert(txn, debug_dpl_find(txn, pgno) == mp || txn->mt_parent ||
-                            (txn->mt_flags & MDBX_WRITEMAP));
-    } else {
-      mdbx_tassert(txn, !debug_dpl_find(txn, pgno));
-    }
-
-    di = is_dirty ? mdbx_dpl_exist(txn, pgno) : 0;
-    si = is_spilled ? mdbx_search_spilled(txn, pgno) : 0;
-    mdbx_tassert(txn, !is_dirty || di || (txn->mt_flags & MDBX_WRITEMAP));
-  } else {
-    mdbx_tassert(txn, !IS_MODIFIABLE(txn, mp));
-    mdbx_tassert(txn, !IS_SPILLED(txn, mp));
-    mdbx_tassert(txn, !IS_SHADOWED(txn, mp));
-  }
-
-status_done:
-  if (likely((pagetype & P_OVERFLOW) == 0)) {
-    STATIC_ASSERT(P_BRANCH == 1);
-    const bool is_branch = pagetype & P_BRANCH;
-    if (unlikely(mc->mc_flags & C_SUB)) {
-      MDBX_db *outer = mdbx_outer_db(mc);
-      mdbx_cassert(mc, !is_branch || outer->md_branch_pages > 0);
-      outer->md_branch_pages -= is_branch;
-      mdbx_cassert(mc, is_branch || outer->md_leaf_pages > 0);
-      outer->md_leaf_pages -= 1 - is_branch;
-    }
-    mdbx_cassert(mc, !is_branch || mc->mc_db->md_branch_pages > 0);
-    mc->mc_db->md_branch_pages -= is_branch;
-    mdbx_cassert(mc, (pagetype & P_LEAF) == 0 || mc->mc_db->md_leaf_pages > 0);
-    mc->mc_db->md_leaf_pages -= (pagetype & P_LEAF) != 0;
-  } else {
-    npages = mp->mp_pages;
-    mdbx_cassert(mc, mc->mc_db->md_overflow_pages >= npages);
-    mc->mc_db->md_overflow_pages -= npages;
-  }
-
-  if (is_frozen) {
-  retire:
-    mdbx_debug("retire %u page %" PRIaPGNO, npages, pgno);
-    rc = mdbx_pnl_append_range(false, &txn->tw.retired_pages, pgno, npages);
-    mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-    return rc;
-  }
-
-  /* Возврат страниц в нераспределенный "хвост" БД.
-   * Содержимое страниц не уничтожается, а для вложенных транзакций граница
-   * нераспределенного "хвоста" БД сдвигается только при их коммите. */
-  if (MDBX_ENABLE_REFUND && unlikely(pgno + npages == txn->mt_next_pgno)) {
-    const char *kind = nullptr;
-    if (di) {
-      /* Страница испачкана в этой транзакции, но до этого могла быть
-       * аллоцирована, испачкана и пролита в одной из родительских транзакций.
-       * Её МОЖНО вытолкнуть в нераспределенный хвост. */
-      kind = "dirty";
-      /* Remove from dirty list */
-      mdbx_page_wash(txn, di, mp, npages);
-    } else if (si) {
-      /* Страница пролита в этой транзакции, т.е. она аллоцирована
-       * и запачкана в этой или одной из родительских транзакций.
-       * Её МОЖНО вытолкнуть в нераспределенный хвост. */
-      kind = "spilled";
-      mdbx_spill_remove(txn, si, npages);
-    } else if ((txn->mt_flags & MDBX_WRITEMAP)) {
-      kind = "writemap";
-      mdbx_tassert(txn, mp && IS_MODIFIABLE(txn, mp));
-    } else {
-      /* Страница аллоцирована, запачкана и возможно пролита в одной
-       * из родительских транзакций.
-       * Её МОЖНО вытолкнуть в нераспределенный хвост. */
-      kind = "parent's";
-      if (mdbx_assert_enabled() && mp) {
-        kind = nullptr;
-        for (MDBX_txn *parent = txn->mt_parent; parent;
-             parent = parent->mt_parent) {
-          if (mdbx_search_spilled(parent, pgno)) {
-            kind = "parent-spilled";
-            mdbx_tassert(txn, is_spilled);
-            break;
-          }
-          if (mp == debug_dpl_find(parent, pgno)) {
-            kind = "parent-dirty";
-            mdbx_tassert(txn, !is_spilled);
-            break;
-          }
-        }
-        mdbx_tassert(txn, kind != nullptr);
-      }
-      mdbx_tassert(txn,
-                   is_spilled || is_shadowed || (mp && IS_SHADOWED(txn, mp)));
-    }
-    mdbx_debug("refunded %u %s page %" PRIaPGNO, npages, kind, pgno);
-    txn->mt_next_pgno = pgno;
-    mdbx_refund(txn);
-    return MDBX_SUCCESS;
-  }
-
-  if (di) {
-    /* Dirty page from this transaction */
-    /* If suitable we can reuse it through loose list */
-    if (likely(npages == 1 &&
-               txn->tw.loose_count < txn->mt_env->me_options.dp_loose_limit &&
-               (!MDBX_ENABLE_REFUND ||
-                /* skip pages near to the end in favor of compactification */
-                txn->mt_next_pgno >
-                    pgno + txn->mt_env->me_options.dp_loose_limit ||
-                txn->mt_next_pgno <= txn->mt_env->me_options.dp_loose_limit))) {
-      mdbx_debug("loosen dirty page %" PRIaPGNO, pgno);
-      mp->mp_flags = P_LOOSE;
-      mp->mp_next = txn->tw.loose_pages;
-      txn->tw.loose_pages = mp;
-      txn->tw.loose_count++;
-#if MDBX_ENABLE_REFUND
-      txn->tw.loose_refund_wl = (pgno + 2 > txn->tw.loose_refund_wl)
-                                    ? pgno + 2
-                                    : txn->tw.loose_refund_wl;
-#endif /* MDBX_ENABLE_REFUND */
-      if (MDBX_DEBUG != 0 || unlikely(txn->mt_env->me_flags & MDBX_PAGEPERTURB))
-        memset(page_data(mp), -1, txn->mt_env->me_psize - PAGEHDRSZ);
-      VALGRIND_MAKE_MEM_NOACCESS(page_data(mp),
-                                 txn->mt_env->me_psize - PAGEHDRSZ);
-      MDBX_ASAN_POISON_MEMORY_REGION(page_data(mp),
-                                     txn->mt_env->me_psize - PAGEHDRSZ);
-      return MDBX_SUCCESS;
-    }
-
-#if !MDBX_DEBUG && !defined(MDBX_USE_VALGRIND) && !defined(__SANITIZE_ADDRESS__)
-    if (unlikely(txn->mt_env->me_flags & MDBX_PAGEPERTURB))
-#endif
-    {
-      /* Страница могла быть изменена в одной из родительских транзакций,
-       * в том числе, позже выгружена и затем снова загружена и изменена.
-       * В обоих случаях её нельзя затирать на диске и помечать недоступной
-       * в asan и/или valgrind */
-      for (MDBX_txn *parent = txn->mt_parent;
-           parent && (parent->mt_flags & MDBX_TXN_SPILLS);
-           parent = parent->mt_parent) {
-        if (mdbx_intersect_spilled(parent, pgno, npages))
-          goto skip_invalidate;
-        if (mdbx_dpl_intersect(parent, pgno, npages))
-          goto skip_invalidate;
-      }
-
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-      if (MDBX_DEBUG != 0 || unlikely(txn->mt_env->me_flags & MDBX_PAGEPERTURB))
-#endif
-        mdbx_kill_page(txn, mp, pgno, npages);
-      if (!(txn->mt_flags & MDBX_WRITEMAP)) {
-        VALGRIND_MAKE_MEM_NOACCESS(page_data(pgno2page(txn->mt_env, pgno)),
-                                   pgno2bytes(txn->mt_env, npages) - PAGEHDRSZ);
-        MDBX_ASAN_POISON_MEMORY_REGION(page_data(pgno2page(txn->mt_env, pgno)),
-                                       pgno2bytes(txn->mt_env, npages) -
-                                           PAGEHDRSZ);
-      }
-    }
-  skip_invalidate:
-    /* Remove from dirty list */
-    mdbx_page_wash(txn, di, mp, npages);
-
-  reclaim:
-    mdbx_debug("reclaim %u %s page %" PRIaPGNO, npages, "dirty", pgno);
-    rc = mdbx_pnl_insert_range(&txn->tw.reclaimed_pglist, pgno, npages);
-    mdbx_tassert(txn,
-                 mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                       txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-    mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-    return rc;
-  }
-
-  if (si) {
-    /* Page ws spilled in this txn */
-    mdbx_spill_remove(txn, si, npages);
-    /* Страница могла быть выделена и затем пролита в этой транзакции,
-     * тогда её необходимо поместить в reclaimed-список.
-     * Либо она могла быть выделена в одной из родительских транзакций и затем
-     * пролита в этой транзакции, тогда её необходимо поместить в
-     * retired-список для последующей фильтрации при коммите. */
-    for (MDBX_txn *parent = txn->mt_parent; parent;
-         parent = parent->mt_parent) {
-      if (mdbx_dpl_exist(parent, pgno))
-        goto retire;
-    }
-    /* Страница точно была выделена в этой транзакции
-     * и теперь может быть использована повторно. */
-    goto reclaim;
-  }
-
-  if (is_shadowed) {
-    /* Dirty page MUST BE a clone from (one of) parent transaction(s). */
-    if (mdbx_assert_enabled()) {
-      const MDBX_page *parent_dp = nullptr;
-      /* Check parent(s)'s dirty lists. */
-      for (MDBX_txn *parent = txn->mt_parent; parent && !parent_dp;
-           parent = parent->mt_parent) {
-        mdbx_tassert(txn, !mdbx_search_spilled(parent, pgno));
-        parent_dp = debug_dpl_find(parent, pgno);
-      }
-      mdbx_tassert(txn, parent_dp && (!mp || parent_dp == mp));
-    }
-    /* Страница была выделена в родительской транзакции и теперь может быть
-     * использована повторно, но только внутри этой транзакции, либо дочерних.
-     */
-    goto reclaim;
-  }
-
-  /* Страница может входить в доступный читателям MVCC-снимок, либо же она
-   * могла быть выделена, а затем пролита в одной из родительских
-   * транзакций. Поэтому пока помещаем её в retired-список, который будет
-   * фильтроваться относительно dirty- и spilled-списков родительских
-   * транзакций при коммите дочерних транзакций, либо же будет записан
-   * в GC в неизменном виде. */
-  goto retire;
-}
-
-static __inline int mdbx_page_retire(MDBX_cursor *mc, MDBX_page *mp) {
-  return mdbx_page_retire_ex(mc, mp->mp_pgno, mp, PAGETYPE(mp));
-}
-
-struct mdbx_iov_ctx {
-  unsigned iov_items;
-  size_t iov_bytes;
-  size_t iov_off;
-  pgno_t flush_begin;
-  pgno_t flush_end;
-  struct iovec iov[MDBX_COMMIT_PAGES];
-};
-
-static __inline void mdbx_iov_init(MDBX_txn *const txn,
-                                   struct mdbx_iov_ctx *ctx) {
-  ctx->flush_begin = MAX_PAGENO;
-  ctx->flush_end = MIN_PAGENO;
-  ctx->iov_items = 0;
-  ctx->iov_bytes = 0;
-  ctx->iov_off = 0;
-  (void)txn;
-}
-
-static __inline void mdbx_iov_done(MDBX_txn *const txn,
-                                   struct mdbx_iov_ctx *ctx) {
-  mdbx_tassert(txn, ctx->iov_items == 0);
-#if defined(__linux__) || defined(__gnu_linux__)
-  MDBX_env *const env = txn->mt_env;
-  if (!(txn->mt_flags & MDBX_WRITEMAP) &&
-      mdbx_linux_kernel_version < 0x02060b00)
-    /* Linux kernels older than version 2.6.11 ignore the addr and nbytes
-     * arguments, making this function fairly expensive. Therefore, the
-     * whole cache is always flushed. */
-    mdbx_flush_incoherent_mmap(
-        env->me_map + pgno2bytes(env, ctx->flush_begin),
-        pgno2bytes(env, ctx->flush_end - ctx->flush_begin), env->me_os_psize);
-#endif /* Linux */
-}
-
-static int mdbx_iov_write(MDBX_txn *const txn, struct mdbx_iov_ctx *ctx) {
-  mdbx_tassert(txn, !(txn->mt_flags & MDBX_WRITEMAP));
-  mdbx_tassert(txn, ctx->iov_items > 0);
-
-  MDBX_env *const env = txn->mt_env;
-  int rc;
-  if (likely(ctx->iov_items == 1)) {
-    mdbx_assert(env, ctx->iov_bytes == (size_t)ctx->iov[0].iov_len);
-    rc = mdbx_pwrite(env->me_lazy_fd, ctx->iov[0].iov_base, ctx->iov[0].iov_len,
-                     ctx->iov_off);
-  } else {
-    rc = mdbx_pwritev(env->me_lazy_fd, ctx->iov, ctx->iov_items, ctx->iov_off,
-                      ctx->iov_bytes);
-  }
-
-  if (unlikely(rc != MDBX_SUCCESS))
-    mdbx_error("Write error: %s", mdbx_strerror(rc));
-  else {
-    VALGRIND_MAKE_MEM_DEFINED(txn->mt_env->me_map + ctx->iov_off,
-                              ctx->iov_bytes);
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(txn->mt_env->me_map + ctx->iov_off,
-                                     ctx->iov_bytes);
-  }
-
-  unsigned iov_items = ctx->iov_items;
-#if MDBX_ENABLE_PGOP_STAT
-  txn->mt_env->me_lck->mti_pgop_stat.wops.weak += iov_items;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  ctx->iov_items = 0;
-  ctx->iov_bytes = 0;
-
-  uint64_t timestamp = 0;
-  for (unsigned i = 0; i < iov_items; i++) {
-    MDBX_page *wp = (MDBX_page *)ctx->iov[i].iov_base;
-    const MDBX_page *rp = pgno2page(txn->mt_env, wp->mp_pgno);
-    /* check with timeout as the workaround
-     * for todo4recovery://erased_by_github/libmdbx/issues/269 */
-    while (likely(rc == MDBX_SUCCESS) &&
-           unlikely(memcmp(wp, rp, ctx->iov[i].iov_len) != 0)) {
-      if (!timestamp) {
-        timestamp = mdbx_osal_monotime();
-        mdbx_iov_done(txn, ctx);
-        mdbx_warning(
-            "catch delayed/non-arrived page %" PRIaPGNO " %s", wp->mp_pgno,
-            "(workaround for incoherent flaw of unified page/buffer cache)");
-      } else if (unlikely(mdbx_osal_monotime() - timestamp > 65536 / 10)) {
-        mdbx_error(
-            "bailout waiting for %" PRIaPGNO " page arrival %s", wp->mp_pgno,
-            "(workaround for incoherent flaw of unified page/buffer cache)");
-        rc = MDBX_CORRUPTED;
-      }
-#if defined(_WIN32) || defined(_WIN64)
-      SwitchToThread();
-#elif defined(__linux__) || defined(__gnu_linux__) || defined(_UNIX03_SOURCE)
-      sched_yield();
-#elif (defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 1)) || defined(_OPEN_THREADS)
-      pthread_yield();
-#else
-      usleep(42);
-#endif
-    }
-    mdbx_dpage_free(env, wp, bytes2pgno(env, ctx->iov[i].iov_len));
-  }
-  return rc;
-}
-
-static int iov_page(MDBX_txn *txn, struct mdbx_iov_ctx *ctx, MDBX_page *dp,
-                    unsigned npages) {
-  MDBX_env *const env = txn->mt_env;
-  mdbx_tassert(txn,
-               dp->mp_pgno >= MIN_PAGENO && dp->mp_pgno < txn->mt_next_pgno);
-  mdbx_tassert(txn, IS_MODIFIABLE(txn, dp));
-  mdbx_tassert(txn,
-               !(dp->mp_flags & ~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW)));
-
-  ctx->flush_begin =
-      (ctx->flush_begin < dp->mp_pgno) ? ctx->flush_begin : dp->mp_pgno;
-  ctx->flush_end = (ctx->flush_end > dp->mp_pgno + npages)
-                       ? ctx->flush_end
-                       : dp->mp_pgno + npages;
-  env->me_lck->mti_unsynced_pages.weak += npages;
-
-  if (IS_SHADOWED(txn, dp)) {
-    mdbx_tassert(txn, !(txn->mt_flags & MDBX_WRITEMAP));
-    dp->mp_txnid = txn->mt_txnid;
-    mdbx_tassert(txn, IS_SPILLED(txn, dp));
-    const size_t size = pgno2bytes(env, npages);
-    if (ctx->iov_off + ctx->iov_bytes != pgno2bytes(env, dp->mp_pgno) ||
-        ctx->iov_items == ARRAY_LENGTH(ctx->iov) ||
-        ctx->iov_bytes + size > MAX_WRITE) {
-      if (ctx->iov_items) {
-        int err = mdbx_iov_write(txn, ctx);
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-#if defined(__linux__) || defined(__gnu_linux__)
-        if (mdbx_linux_kernel_version >= 0x02060b00)
-        /* Linux kernels older than version 2.6.11 ignore the addr and nbytes
-         * arguments, making this function fairly expensive. Therefore, the
-         * whole cache is always flushed. */
-#endif /* Linux */
-          mdbx_flush_incoherent_mmap(env->me_map + ctx->iov_off, ctx->iov_bytes,
-                                     env->me_os_psize);
-      }
-      ctx->iov_off = pgno2bytes(env, dp->mp_pgno);
-    }
-    ctx->iov[ctx->iov_items].iov_base = (void *)dp;
-    ctx->iov[ctx->iov_items].iov_len = size;
-    ctx->iov_items += 1;
-    ctx->iov_bytes += size;
-  } else {
-    mdbx_tassert(txn, txn->mt_flags & MDBX_WRITEMAP);
-  }
-  return MDBX_SUCCESS;
-}
-
-static int spill_page(MDBX_txn *txn, struct mdbx_iov_ctx *ctx, MDBX_page *dp,
-                      unsigned npages) {
-  mdbx_tassert(txn, !(txn->mt_flags & MDBX_WRITEMAP));
-  pgno_t pgno = dp->mp_pgno;
-  int err = iov_page(txn, ctx, dp, npages);
-  if (likely(err == MDBX_SUCCESS)) {
-    err = mdbx_pnl_append_range(true, &txn->tw.spill_pages, pgno << 1, npages);
-#if MDBX_ENABLE_PGOP_STAT
-    if (likely(err == MDBX_SUCCESS))
-      txn->mt_env->me_lck->mti_pgop_stat.spill.weak += npages;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  }
-  return err;
-}
-
-/* Set unspillable LRU-label for dirty pages watched by txn.
- * Returns the number of pages marked as unspillable. */
-static unsigned mdbx_cursor_keep(MDBX_txn *txn, MDBX_cursor *mc) {
-  unsigned keep = 0;
-  while (mc->mc_flags & C_INITIALIZED) {
-    for (unsigned i = 0; i < mc->mc_snum; ++i) {
-      const MDBX_page *mp = mc->mc_pg[i];
-      if (IS_MODIFIABLE(txn, mp) && !IS_SUBP(mp)) {
-        unsigned const n = mdbx_dpl_search(txn, mp->mp_pgno);
-        if (txn->tw.dirtylist->items[n].pgno == mp->mp_pgno &&
-            mdbx_dpl_age(txn, n)) {
-          txn->tw.dirtylist->items[n].lru = txn->tw.dirtylru;
-          ++keep;
-        }
-      }
-    }
-    if (!mc->mc_xcursor)
-      break;
-    mc = &mc->mc_xcursor->mx_cursor;
-  }
-  return keep;
-}
-
-static unsigned mdbx_txn_keep(MDBX_txn *txn, MDBX_cursor *m0) {
-  unsigned keep = m0 ? mdbx_cursor_keep(txn, m0) : 0;
-  for (unsigned i = FREE_DBI; i < txn->mt_numdbs; ++i)
-    if (F_ISSET(txn->mt_dbistate[i], DBI_DIRTY | DBI_VALID) &&
-        txn->mt_dbs[i].md_root != P_INVALID)
-      for (MDBX_cursor *mc = txn->mt_cursors[i]; mc; mc = mc->mc_next)
-        if (mc != m0)
-          keep += mdbx_cursor_keep(txn, mc);
-  return keep;
-}
-
-/* Returns the spilling priority (0..255) for a dirty page:
- *      0 = should be spilled;
- *    ...
- *  > 255 = must not be spilled. */
-static unsigned spill_prio(const MDBX_txn *txn, const unsigned i,
-                           const uint32_t reciprocal) {
-  MDBX_dpl *const dl = txn->tw.dirtylist;
-  const uint32_t age = mdbx_dpl_age(txn, i);
-  const unsigned npages = dpl_npages(dl, i);
-  const pgno_t pgno = dl->items[i].pgno;
-  if (age == 0) {
-    mdbx_debug("skip %s %u page %" PRIaPGNO, "keep", npages, pgno);
-    return 256;
-  }
-
-  MDBX_page *const dp = dl->items[i].ptr;
-  if (dp->mp_flags & (P_LOOSE | P_SPILLED)) {
-    mdbx_debug("skip %s %u page %" PRIaPGNO,
-               (dp->mp_flags & P_LOOSE)   ? "loose"
-               : (dp->mp_flags & P_LOOSE) ? "loose"
-                                          : "parent-spilled",
-               npages, pgno);
-    return 256;
-  }
-
-  /* Can't spill twice,
-   * make sure it's not already in a parent's spill list(s). */
-  MDBX_txn *parent = txn->mt_parent;
-  if (parent && (parent->mt_flags & MDBX_TXN_SPILLS)) {
-    do
-      if (mdbx_intersect_spilled(parent, pgno, npages)) {
-        mdbx_debug("skip-2 parent-spilled %u page %" PRIaPGNO, npages, pgno);
-        dp->mp_flags |= P_SPILLED;
-        return 256;
-      }
-    while ((parent = parent->mt_parent) != nullptr);
-  }
-
-  mdbx_tassert(txn, age * (uint64_t)reciprocal < UINT32_MAX);
-  unsigned prio = age * reciprocal >> 24;
-  mdbx_tassert(txn, prio < 256);
-  if (likely(npages == 1))
-    return prio = 256 - prio;
-
-  /* make a large/overflow pages be likely to spill */
-  uint32_t factor = npages | npages >> 1;
-  factor |= factor >> 2;
-  factor |= factor >> 4;
-  factor |= factor >> 8;
-  factor |= factor >> 16;
-  factor = prio * log2n_powerof2(factor + 1) + /* golden ratio */ 157;
-  factor = (factor < 256) ? 255 - factor : 0;
-  mdbx_tassert(txn, factor < 256 && factor < (256 - prio));
-  return prio = factor;
-}
-
-/* Spill pages from the dirty list back to disk.
- * This is intended to prevent running into MDBX_TXN_FULL situations,
- * but note that they may still occur in a few cases:
- *
- * 1) our estimate of the txn size could be too small. Currently this
- *  seems unlikely, except with a large number of MDBX_MULTIPLE items.
- *
- * 2) child txns may run out of space if their parents dirtied a
- *  lot of pages and never spilled them. TODO: we probably should do
- *  a preemptive spill during mdbx_txn_begin() of a child txn, if
- *  the parent's dirtyroom is below a given threshold.
- *
- * Otherwise, if not using nested txns, it is expected that apps will
- * not run into MDBX_TXN_FULL any more. The pages are flushed to disk
- * the same way as for a txn commit, e.g. their dirty status is cleared.
- * If the txn never references them again, they can be left alone.
- * If the txn only reads them, they can be used without any fuss.
- * If the txn writes them again, they can be dirtied immediately without
- * going thru all of the work of mdbx_page_touch(). Such references are
- * handled by mdbx_page_unspill().
- *
- * Also note, we never spill DB root pages, nor pages of active cursors,
- * because we'll need these back again soon anyway. And in nested txns,
- * we can't spill a page in a child txn if it was already spilled in a
- * parent txn. That would alter the parent txns' data even though
- * the child hasn't committed yet, and we'd have no way to undo it if
- * the child aborted. */
-static int mdbx_txn_spill(MDBX_txn *const txn, MDBX_cursor *const m0,
-                          const unsigned need) {
-#if xMDBX_DEBUG_SPILLING != 1
-  /* production mode */
-  if (likely(txn->tw.dirtyroom + txn->tw.loose_count >= need))
-    return MDBX_SUCCESS;
-  unsigned wanna_spill = need - txn->tw.dirtyroom;
-#else
-  /* debug mode: spill at least one page if xMDBX_DEBUG_SPILLING == 1 */
-  unsigned wanna_spill =
-      (need > txn->tw.dirtyroom) ? need - txn->tw.dirtyroom : 1;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  const unsigned dirty = txn->tw.dirtylist->length;
-  const unsigned spill_min =
-      txn->mt_env->me_options.spill_min_denominator
-          ? dirty / txn->mt_env->me_options.spill_min_denominator
-          : 0;
-  const unsigned spill_max =
-      dirty - (txn->mt_env->me_options.spill_max_denominator
-                   ? dirty / txn->mt_env->me_options.spill_max_denominator
-                   : 0);
-  wanna_spill = (wanna_spill > spill_min) ? wanna_spill : spill_min;
-  wanna_spill = (wanna_spill < spill_max) ? wanna_spill : spill_max;
-  if (!wanna_spill)
-    return MDBX_SUCCESS;
-
-  mdbx_notice("spilling %u dirty-entries (have %u dirty-room, need %u)",
-              wanna_spill, txn->tw.dirtyroom, need);
-  mdbx_tassert(txn, txn->tw.dirtylist->length >= wanna_spill);
-
-  struct mdbx_iov_ctx ctx;
-  mdbx_iov_init(txn, &ctx);
-  int rc = MDBX_SUCCESS;
-  if (txn->mt_flags & MDBX_WRITEMAP) {
-    MDBX_dpl *const dl = txn->tw.dirtylist;
-    const unsigned span = dl->length - txn->tw.loose_count;
-    txn->tw.dirtyroom += span;
-    unsigned r, w;
-    for (w = 0, r = 1; r <= dl->length; ++r) {
-      MDBX_page *dp = dl->items[r].ptr;
-      if (dp->mp_flags & P_LOOSE)
-        dl->items[++w] = dl->items[r];
-      else if (!MDBX_FAKE_SPILL_WRITEMAP) {
-        rc = iov_page(txn, &ctx, dp, dpl_npages(dl, r));
-        mdbx_tassert(txn, rc == MDBX_SUCCESS);
-      }
-    }
-
-    mdbx_tassert(txn, span == r - 1 - w && w == txn->tw.loose_count);
-    dl->sorted = (dl->sorted == dl->length) ? w : 0;
-    dpl_setlen(dl, w);
-    mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-
-    if (!MDBX_FAKE_SPILL_WRITEMAP && ctx.flush_end > ctx.flush_begin) {
-      MDBX_env *const env = txn->mt_env;
-#if MDBX_ENABLE_PGOP_STAT
-      env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-      rc = mdbx_msync(&env->me_dxb_mmap,
-                      pgno_align2os_bytes(env, ctx.flush_begin),
-                      pgno_align2os_bytes(env, ctx.flush_end - ctx.flush_begin),
-                      MDBX_SYNC_NONE);
-    }
-    return rc;
-  }
-
-  mdbx_tassert(txn, !(txn->mt_flags & MDBX_WRITEMAP));
-  if (!txn->tw.spill_pages) {
-    txn->tw.spill_least_removed = INT_MAX;
-    txn->tw.spill_pages = mdbx_pnl_alloc(wanna_spill);
-    if (unlikely(!txn->tw.spill_pages)) {
-      rc = MDBX_ENOMEM;
-    bailout:
-      txn->mt_flags |= MDBX_TXN_ERROR;
-      return rc;
-    }
-  } else {
-    /* purge deleted slots */
-    mdbx_spill_purge(txn);
-    rc = mdbx_pnl_reserve(&txn->tw.spill_pages, wanna_spill);
-    (void)rc /* ignore since the resulting list may be shorter
-     and mdbx_pnl_append() will increase pnl on demand */
-        ;
-  }
-
-  /* Сортируем чтобы запись на диск была полее последовательна */
-  MDBX_dpl *const dl = mdbx_dpl_sort(txn);
-
-  /* Preserve pages which may soon be dirtied again */
-  const unsigned unspillable = mdbx_txn_keep(txn, m0);
-  if (unspillable + txn->tw.loose_count >= dl->length) {
-#if xMDBX_DEBUG_SPILLING == 1 /* avoid false failure in debug mode  */
-    if (likely(txn->tw.dirtyroom + txn->tw.loose_count >= need))
-      return MDBX_SUCCESS;
-#endif /* xMDBX_DEBUG_SPILLING */
-    mdbx_error("all %u dirty pages are unspillable  since referenced "
-               "by a cursor(s), use fewer cursors or increase "
-               "MDBX_opt_txn_dp_limit",
-               unspillable);
-    goto done;
-  }
-
-  /* Подзадача: Вытолкнуть часть страниц на диск в соответствии с LRU,
-   * но при этом учесть важные поправки:
-   *  - лучше выталкивать старые large/overflow страницы, так будет освобождено
-   *    больше памяти, а также так как они (в текущем понимании) гораздо реже
-   *    повторно изменяются;
-   *  - при прочих равных лучше выталкивать смежные страницы, так будет
-   *    меньше I/O операций;
-   *  - желательно потратить на это меньше времени чем std::partial_sort_copy;
-   *
-   * Решение:
-   *  - Квантуем весь диапазон lru-меток до 256 значений и задействуем один
-   *    проход 8-битного radix-sort. В результате получаем 256 уровней
-   *    "свежести", в том числе значение lru-метки, старее которой страницы
-   *    должны быть выгружены;
-   *  - Двигаемся последовательно в сторону увеличения номеров страниц
-   *    и выталкиваем страницы с lru-меткой старее отсекающего значения,
-   *    пока не вытолкнем достаточно;
-   *  - Встречая страницы смежные с выталкиваемыми для уменьшения кол-ва
-   *    I/O операций выталкиваем и их, если они попадают в первую половину
-   *    между выталкиваемыми и самыми свежими lru-метками;
-   *  - дополнительно при сортировке умышленно старим large/overflow страницы,
-   *    тем самым повышая их шансы на выталкивание. */
-
-  /* get min/max of LRU-labels */
-  uint32_t age_max = 0;
-  for (unsigned i = 1; i <= dl->length; ++i) {
-    const uint32_t age = mdbx_dpl_age(txn, i);
-    age_max = (age_max >= age) ? age_max : age;
-  }
-
-  mdbx_verbose("lru-head %u, age-max %u", txn->tw.dirtylru, age_max);
-
-  /* half of 8-bit radix-sort */
-  unsigned radix_counters[256], spillable = 0, spilled = 0;
-  memset(&radix_counters, 0, sizeof(radix_counters));
-  const uint32_t reciprocal = (UINT32_C(255) << 24) / (age_max + 1);
-  for (unsigned i = 1; i <= dl->length; ++i) {
-    unsigned prio = spill_prio(txn, i, reciprocal);
-    if (prio < 256) {
-      radix_counters[prio] += 1;
-      spillable += 1;
-    }
-  }
-
-  if (likely(spillable > 0)) {
-    unsigned prio2spill = 0, prio2adjacent = 128, amount = radix_counters[0];
-    for (unsigned i = 1; i < 256; i++) {
-      if (amount < wanna_spill) {
-        prio2spill = i;
-        prio2adjacent = i + (257 - i) / 2;
-        amount += radix_counters[i];
-      } else if (amount + amount < spillable + wanna_spill
-                 /* РАВНОЗНАЧНО: amount - wanna_spill < spillable - amount */) {
-        prio2adjacent = i;
-        amount += radix_counters[i];
-      } else
-        break;
-    }
-
-    mdbx_verbose("prio2spill %u, prio2adjacent %u, amount %u, spillable %u, "
-                 "wanna_spill %u",
-                 prio2spill, prio2adjacent, amount, spillable, wanna_spill);
-    mdbx_tassert(txn, prio2spill < prio2adjacent && prio2adjacent <= 256);
-
-    unsigned prev_prio = 256;
-    unsigned r, w, prio;
-    for (w = 0, r = 1; r <= dl->length && spilled < wanna_spill;
-         prev_prio = prio, ++r) {
-      prio = spill_prio(txn, r, reciprocal);
-      MDBX_page *const dp = dl->items[r].ptr;
-      if (prio < prio2adjacent) {
-        const pgno_t pgno = dl->items[r].pgno;
-        const unsigned npages = dpl_npages(dl, r);
-        if (prio <= prio2spill) {
-          if (prev_prio < prio2adjacent && prev_prio > prio2spill &&
-              dpl_endpgno(dl, r - 1) == pgno) {
-            mdbx_debug("co-spill %u prev-adjacent page %" PRIaPGNO
-                       " (age %d, prio %u)",
-                       dpl_npages(dl, w), dl->items[r - 1].pgno,
-                       mdbx_dpl_age(txn, r - 1), prev_prio);
-            --w;
-            rc = spill_page(txn, &ctx, dl->items[r - 1].ptr,
-                            dpl_npages(dl, r - 1));
-            if (unlikely(rc != MDBX_SUCCESS))
-              break;
-            ++spilled;
-          }
-
-          mdbx_debug("spill %u page %" PRIaPGNO " (age %d, prio %u)", npages,
-                     dp->mp_pgno, mdbx_dpl_age(txn, r), prio);
-          rc = spill_page(txn, &ctx, dp, npages);
-          if (unlikely(rc != MDBX_SUCCESS))
-            break;
-          ++spilled;
-          continue;
-        }
-
-        if (prev_prio <= prio2spill && dpl_endpgno(dl, r - 1) == pgno) {
-          mdbx_debug("co-spill %u next-adjacent page %" PRIaPGNO
-                     " (age %d, prio %u)",
-                     npages, dp->mp_pgno, mdbx_dpl_age(txn, r), prio);
-          rc = spill_page(txn, &ctx, dp, npages);
-          if (unlikely(rc != MDBX_SUCCESS))
-            break;
-          prio = prev_prio /* to continue co-spilling next adjacent pages */;
-          ++spilled;
-          continue;
-        }
-      }
-      dl->items[++w] = dl->items[r];
-    }
-
-    mdbx_tassert(txn, spillable == 0 || spilled > 0);
-
-    while (r <= dl->length)
-      dl->items[++w] = dl->items[r++];
-    mdbx_tassert(txn, r - 1 - w == spilled);
-
-    dl->sorted = dpl_setlen(dl, w);
-    txn->tw.dirtyroom += spilled;
-    mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-
-    if (ctx.iov_items)
-      rc = mdbx_iov_write(txn, &ctx);
-
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-
-    mdbx_pnl_sort(txn->tw.spill_pages, (size_t)txn->mt_next_pgno << 1);
-    txn->mt_flags |= MDBX_TXN_SPILLS;
-    mdbx_notice("spilled %u dirty-entries, now have %u dirty-room", spilled,
-                txn->tw.dirtyroom);
-    mdbx_iov_done(txn, &ctx);
-  } else {
-    mdbx_tassert(txn, ctx.iov_items == 0 && rc == MDBX_SUCCESS);
-    for (unsigned i = 1; i <= dl->length; ++i) {
-      MDBX_page *dp = dl->items[i].ptr;
-      mdbx_notice(
-          "dirtylist[%u]: pgno %u, npages %u, flags 0x%04X, age %u, prio %u", i,
-          dp->mp_pgno, dpl_npages(dl, i), dp->mp_flags, mdbx_dpl_age(txn, i),
-          spill_prio(txn, i, reciprocal));
-    }
-  }
-
-#if xMDBX_DEBUG_SPILLING == 2
-  if (txn->tw.loose_count + txn->tw.dirtyroom <= need / 2 + 1)
-    mdbx_error("dirty-list length: before %u, after %u, parent %i, loose %u; "
-               "needed %u, spillable %u; "
-               "spilled %u dirty-entries, now have %u dirty-room",
-               dl->length + spilled, dl->length,
-               (txn->mt_parent && txn->mt_parent->tw.dirtylist)
-                   ? (int)txn->mt_parent->tw.dirtylist->length
-                   : -1,
-               txn->tw.loose_count, need, spillable, spilled,
-               txn->tw.dirtyroom);
-  mdbx_ensure(txn->mt_env, txn->tw.loose_count + txn->tw.dirtyroom > need / 2);
-#endif /* xMDBX_DEBUG_SPILLING */
-
-done:
-  return likely(txn->tw.dirtyroom + txn->tw.loose_count >
-                ((need > CURSOR_STACK) ? CURSOR_STACK : need))
-             ? MDBX_SUCCESS
-             : MDBX_TXN_FULL;
-}
-
-static int mdbx_cursor_spill(MDBX_cursor *mc, const MDBX_val *key,
-                             const MDBX_val *data) {
-  MDBX_txn *txn = mc->mc_txn;
-  /* Estimate how much space this operation will take: */
-  /* 1) Max b-tree height, reasonable enough with including dups' sub-tree */
-  unsigned need = CURSOR_STACK + 3;
-  /* 2) GC/FreeDB for any payload */
-  if (mc->mc_dbi > FREE_DBI) {
-    need += txn->mt_dbs[FREE_DBI].md_depth + 3;
-    /* 3) Named DBs also dirty the main DB */
-    if (mc->mc_dbi > MAIN_DBI)
-      need += txn->mt_dbs[MAIN_DBI].md_depth + 3;
-  }
-#if xMDBX_DEBUG_SPILLING != 2
-  /* production mode */
-  /* 4) Double the page chain estimation
-   * for extensively splitting, rebalance and merging */
-  need += need;
-  /* 5) Factor the key+data which to be put in */
-  need += bytes2pgno(txn->mt_env, node_size(key, data)) + 1;
-#else
-  /* debug mode */
-  (void)key;
-  (void)data;
-  mc->mc_txn->mt_env->debug_dirtied_est = ++need;
-  mc->mc_txn->mt_env->debug_dirtied_act = 0;
-#endif /* xMDBX_DEBUG_SPILLING == 2 */
-
-  return mdbx_txn_spill(txn, mc, need);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static bool meta_bootid_match(const MDBX_meta *meta) {
-  return memcmp(&meta->mm_bootid, &bootid, 16) == 0 &&
-         (bootid.x | bootid.y) != 0;
-}
-
-static bool meta_weak_acceptable(const MDBX_env *env, const MDBX_meta *meta,
-                                 const int lck_exclusive) {
-  return lck_exclusive
-             ? /* exclusive lock */ meta_bootid_match(meta)
-             : /* db already opened */ env->me_lck_mmap.lck &&
-                   (env->me_lck_mmap.lck->mti_envmode.weak & MDBX_RDONLY) == 0;
-}
-
-#define METAPAGE(env, n) page_meta(pgno2page(env, n))
-#define METAPAGE_END(env) METAPAGE(env, NUM_METAS)
-
-MDBX_NOTHROW_PURE_FUNCTION static __inline txnid_t
-constmeta_txnid(const MDBX_env *env, const MDBX_meta *meta) {
-  mdbx_memory_fence(mo_AcquireRelease, false);
-  txnid_t a = unaligned_peek_u64(4, &meta->mm_txnid_a);
-  txnid_t b = unaligned_peek_u64(4, &meta->mm_txnid_b);
-  mdbx_assert(env, a == b);
-  (void)env;
-  return (a == b) ? a : 0;
-}
-
-static __inline txnid_t meta_txnid(const MDBX_env *env,
-                                   volatile const MDBX_meta *meta) {
-  (void)env;
-  mdbx_memory_fence(mo_AcquireRelease, false);
-  txnid_t a = unaligned_peek_u64_volatile(4, &meta->mm_txnid_a);
-  txnid_t b = unaligned_peek_u64_volatile(4, &meta->mm_txnid_b);
-  return (a == b) ? a : 0;
-}
-
-static __inline void meta_update_begin(const MDBX_env *env, MDBX_meta *meta,
-                                       txnid_t txnid) {
-  mdbx_assert(env, meta >= METAPAGE(env, 0) && meta < METAPAGE_END(env));
-  mdbx_assert(env, unaligned_peek_u64(4, meta->mm_txnid_a) < txnid &&
-                       unaligned_peek_u64(4, meta->mm_txnid_b) < txnid);
-  (void)env;
-  unaligned_poke_u64(4, meta->mm_txnid_b, 0);
-  mdbx_memory_fence(mo_AcquireRelease, true);
-  unaligned_poke_u64(4, meta->mm_txnid_a, txnid);
-}
-
-static __inline void meta_update_end(const MDBX_env *env, MDBX_meta *meta,
-                                     txnid_t txnid) {
-  mdbx_assert(env, meta >= METAPAGE(env, 0) && meta < METAPAGE_END(env));
-  mdbx_assert(env, unaligned_peek_u64(4, meta->mm_txnid_a) == txnid);
-  mdbx_assert(env, unaligned_peek_u64(4, meta->mm_txnid_b) < txnid);
-  (void)env;
-  mdbx_jitter4testing(true);
-  memcpy(&meta->mm_bootid, &bootid, 16);
-  unaligned_poke_u64(4, meta->mm_txnid_b, txnid);
-  mdbx_memory_fence(mo_AcquireRelease, true);
-}
-
-static __inline void meta_set_txnid(const MDBX_env *env, MDBX_meta *meta,
-                                    const txnid_t txnid) {
-  mdbx_assert(env, !env->me_map || meta < METAPAGE(env, 0) ||
-                       meta >= METAPAGE_END(env));
-  (void)env;
-  /* update inconsistently since this function used ONLY for filling meta-image
-   * for writing, but not the actual meta-page */
-  memcpy(&meta->mm_bootid, &bootid, 16);
-  unaligned_poke_u64(4, meta->mm_txnid_a, txnid);
-  unaligned_poke_u64(4, meta->mm_txnid_b, txnid);
-}
-
-static __inline uint64_t meta_sign(const MDBX_meta *meta) {
-  uint64_t sign = MDBX_DATASIGN_NONE;
-#if 0 /* TODO */
-  sign = hippeus_hash64(...);
-#else
-  (void)meta;
-#endif
-  /* LY: newer returns MDBX_DATASIGN_NONE or MDBX_DATASIGN_WEAK */
-  return (sign > MDBX_DATASIGN_WEAK) ? sign : ~sign;
-}
-
-enum meta_choise_mode { prefer_last, prefer_steady };
-
-static __inline bool meta_ot(const enum meta_choise_mode mode,
-                             const MDBX_env *env, volatile const MDBX_meta *a,
-                             volatile const MDBX_meta *b) {
-  mdbx_jitter4testing(true);
-  const txnid_t txnid_a = meta_txnid(env, a);
-  mdbx_jitter4testing(true);
-  const txnid_t txnid_b = meta_txnid(env, b);
-  mdbx_jitter4testing(true);
-  const bool is_stead_b = META_IS_STEADY(b);
-
-  if (mode == prefer_steady) {
-    mdbx_jitter4testing(true);
-    const bool is_stead_a = META_IS_STEADY(a);
-    if (is_stead_a != is_stead_b)
-      return is_stead_b;
-  } else {
-    mdbx_assert(env, mode == prefer_last);
-  }
-  if (txnid_a == txnid_b)
-    return is_stead_b;
-  return txnid_a < txnid_b;
-}
-
-static bool meta_eq(const MDBX_env *env, volatile const MDBX_meta *a,
-                    volatile const MDBX_meta *b) {
-  mdbx_jitter4testing(true);
-  const txnid_t txnid = meta_txnid(env, a);
-  if (!txnid || txnid != meta_txnid(env, b))
-    return false;
-
-  mdbx_jitter4testing(true);
-  if (META_IS_STEADY(a) != META_IS_STEADY(b))
-    return false;
-
-  mdbx_jitter4testing(true);
-  return true;
-}
-
-static int meta_eq_mask(const MDBX_env *env) {
-  volatile const MDBX_meta *m0 = METAPAGE(env, 0);
-  volatile const MDBX_meta *m1 = METAPAGE(env, 1);
-  volatile const MDBX_meta *m2 = METAPAGE(env, 2);
-
-  int rc = meta_eq(env, m0, m1) ? 1 : 0;
-  if (meta_eq(env, m1, m2))
-    rc += 2;
-  if (meta_eq(env, m2, m0))
-    rc += 4;
-  return rc;
-}
-
-static __inline volatile const MDBX_meta *
-meta_recent(const enum meta_choise_mode mode, const MDBX_env *env,
-            volatile const MDBX_meta *a, volatile const MDBX_meta *b) {
-  const bool a_older_that_b = meta_ot(mode, env, a, b);
-  mdbx_assert(env, !meta_eq(env, a, b));
-  return a_older_that_b ? b : a;
-}
-
-static const MDBX_meta *meta_ancient_prefer_weak(const MDBX_env *env,
-                                                 const MDBX_meta *a,
-                                                 const MDBX_meta *b) {
-  const bool a_older_that_b = meta_ot(prefer_steady, env, a, b);
-  mdbx_assert(env, !meta_eq(env, a, b));
-  return a_older_that_b ? a : b;
-}
-
-static __inline volatile const MDBX_meta *
-meta_mostrecent(const enum meta_choise_mode mode, const MDBX_env *env) {
-  volatile const MDBX_meta *m0 = METAPAGE(env, 0);
-  volatile const MDBX_meta *m1 = METAPAGE(env, 1);
-  volatile const MDBX_meta *m2 = METAPAGE(env, 2);
-
-  volatile const MDBX_meta *head = meta_recent(mode, env, m0, m1);
-  head = meta_recent(mode, env, head, m2);
-  return head;
-}
-
-static volatile const MDBX_meta *meta_prefer_steady(const MDBX_env *env) {
-  return meta_mostrecent(prefer_steady, env);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static const MDBX_meta *
-constmeta_prefer_steady(const MDBX_env *env) {
-  return (const MDBX_meta *)meta_mostrecent(prefer_steady, env);
-}
-
-static volatile const MDBX_meta *meta_prefer_last(const MDBX_env *env) {
-  return meta_mostrecent(prefer_last, env);
-}
-
-MDBX_NOTHROW_PURE_FUNCTION static const MDBX_meta *
-constmeta_prefer_last(const MDBX_env *env) {
-  return (const MDBX_meta *)meta_mostrecent(prefer_last, env);
-}
-
-static txnid_t mdbx_recent_committed_txnid(const MDBX_env *env) {
-  while (true) {
-    volatile const MDBX_meta *head = meta_prefer_last(env);
-    const txnid_t recent = meta_txnid(env, head);
-    mdbx_compiler_barrier();
-    if (likely(head == meta_prefer_last(env) &&
-               recent == meta_txnid(env, head)))
-      return recent;
-  }
-}
-
-static txnid_t mdbx_recent_steady_txnid(const MDBX_env *env) {
-  while (true) {
-    volatile const MDBX_meta *head = meta_prefer_steady(env);
-    const txnid_t recent = meta_txnid(env, head);
-    mdbx_compiler_barrier();
-    if (likely(head == meta_prefer_steady(env) &&
-               recent == meta_txnid(env, head)))
-      return recent;
-  }
-}
-
-static const char *mdbx_durable_str(volatile const MDBX_meta *const meta) {
-  if (META_IS_STEADY(meta))
-    return (unaligned_peek_u64_volatile(4, meta->mm_datasync_sign) ==
-            meta_sign((const MDBX_meta *)meta))
-               ? "Steady"
-               : "Tainted";
-  return "Weak";
-}
-
-/*----------------------------------------------------------------------------*/
-
-/* Find oldest txnid still referenced. */
-static txnid_t mdbx_find_oldest(const MDBX_txn *txn) {
-  mdbx_tassert(txn, (txn->mt_flags & MDBX_TXN_RDONLY) == 0);
-  MDBX_env *env = txn->mt_env;
-  const txnid_t edge = mdbx_recent_steady_txnid(env);
-  mdbx_tassert(txn, edge <= txn->mt_txnid);
-
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (unlikely(lck == NULL /* exclusive mode */))
-    return atomic_store64(&lck->mti_oldest_reader, edge, mo_Relaxed);
-
-  const txnid_t last_oldest =
-      atomic_load64(&lck->mti_oldest_reader, mo_AcquireRelease);
-  mdbx_tassert(txn, edge >= last_oldest);
-  if (likely(last_oldest == edge))
-    return edge;
-
-  const uint32_t nothing_changed = MDBX_STRING_TETRAD("None");
-  const uint32_t snap_readers_refresh_flag =
-      atomic_load32(&lck->mti_readers_refresh_flag, mo_AcquireRelease);
-  mdbx_jitter4testing(false);
-  if (snap_readers_refresh_flag == nothing_changed)
-    return last_oldest;
-
-  txnid_t oldest = edge;
-  atomic_store32(&lck->mti_readers_refresh_flag, nothing_changed, mo_Relaxed);
-  const unsigned snap_nreaders =
-      atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-  for (unsigned i = 0; i < snap_nreaders; ++i) {
-    if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease)) {
-      /* mdbx_jitter4testing(true); */
-      const txnid_t snap = safe64_read(&lck->mti_readers[i].mr_txnid);
-      if (oldest > snap && last_oldest <= /* ignore pending updates */ snap) {
-        oldest = snap;
-        if (oldest == last_oldest)
-          return oldest;
-      }
-    }
-  }
-
-  if (oldest != last_oldest) {
-    mdbx_verbose("update oldest %" PRIaTXN " -> %" PRIaTXN, last_oldest,
-                 oldest);
-    mdbx_tassert(txn, oldest >= lck->mti_oldest_reader.weak);
-    atomic_store64(&lck->mti_oldest_reader, oldest, mo_Relaxed);
-  }
-  return oldest;
-}
-
-/* Find largest mvcc-snapshot still referenced. */
-__cold static pgno_t mdbx_find_largest(MDBX_env *env, pgno_t largest) {
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (likely(lck != NULL /* exclusive mode */)) {
-    const unsigned snap_nreaders =
-        atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-    for (unsigned i = 0; i < snap_nreaders; ++i) {
-    retry:
-      if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease)) {
-        /* mdbx_jitter4testing(true); */
-        const pgno_t snap_pages = atomic_load32(
-            &lck->mti_readers[i].mr_snapshot_pages_used, mo_Relaxed);
-        const txnid_t snap_txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
-        if (unlikely(
-                snap_pages !=
-                    atomic_load32(&lck->mti_readers[i].mr_snapshot_pages_used,
-                                  mo_AcquireRelease) ||
-                snap_txnid != safe64_read(&lck->mti_readers[i].mr_txnid)))
-          goto retry;
-        if (largest < snap_pages &&
-            atomic_load64(&lck->mti_oldest_reader, mo_AcquireRelease) <=
-                /* ignore pending updates */ snap_txnid &&
-            snap_txnid <= env->me_txn0->mt_txnid)
-          largest = snap_pages;
-      }
-    }
-  }
-
-  return largest;
-}
-
-/* Add a page to the txn's dirty list */
-static int __must_check_result mdbx_page_dirty(MDBX_txn *txn, MDBX_page *mp,
-                                               unsigned npages) {
-#if xMDBX_DEBUG_SPILLING == 2
-  txn->mt_env->debug_dirtied_act += 1;
-  mdbx_ensure(txn->mt_env,
-              txn->mt_env->debug_dirtied_act < txn->mt_env->debug_dirtied_est);
-  mdbx_ensure(txn->mt_env, txn->tw.dirtyroom + txn->tw.loose_count > 0);
-#endif /* xMDBX_DEBUG_SPILLING == 2 */
-
-  int rc;
-  mp->mp_txnid = txn->mt_front;
-  if (unlikely(txn->tw.dirtyroom == 0)) {
-    if (txn->tw.loose_count) {
-      MDBX_page *loose = txn->tw.loose_pages;
-      mdbx_debug("purge-and-reclaim loose page %" PRIaPGNO, loose->mp_pgno);
-      rc = mdbx_pnl_insert_range(&txn->tw.reclaimed_pglist, loose->mp_pgno, 1);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-      unsigned di = mdbx_dpl_search(txn, loose->mp_pgno);
-      mdbx_tassert(txn, txn->tw.dirtylist->items[di].ptr == loose);
-      mdbx_dpl_remove(txn, di);
-      txn->tw.loose_pages = loose->mp_next;
-      txn->tw.loose_count--;
-      txn->tw.dirtyroom++;
-      if (!(txn->mt_flags & MDBX_WRITEMAP))
-        mdbx_dpage_free(txn->mt_env, loose, 1);
-    } else {
-      mdbx_error("Dirtyroom is depleted, DPL length %u",
-                 txn->tw.dirtylist->length);
-      if (!(txn->mt_flags & MDBX_WRITEMAP))
-        mdbx_dpage_free(txn->mt_env, mp, npages);
-      return MDBX_TXN_FULL;
-    }
-  }
-
-  rc = mdbx_dpl_append(txn, mp->mp_pgno, mp, npages);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-  bailout:
-    txn->mt_flags |= MDBX_TXN_ERROR;
-    return rc;
-  }
-  txn->tw.dirtyroom--;
-  mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-  return MDBX_SUCCESS;
-}
-
-#if !(defined(_WIN32) || defined(_WIN64))
-MDBX_MAYBE_UNUSED static __always_inline int ignore_enosys(int err) {
-#ifdef ENOSYS
-  if (err == ENOSYS)
-    return MDBX_RESULT_TRUE;
-#endif /* ENOSYS */
-#ifdef ENOIMPL
-  if (err == ENOIMPL)
-    return MDBX_RESULT_TRUE;
-#endif /* ENOIMPL */
-#ifdef ENOTSUP
-  if (err == ENOTSUP)
-    return MDBX_RESULT_TRUE;
-#endif /* ENOTSUP */
-#ifdef ENOSUPP
-  if (err == ENOSUPP)
-    return MDBX_RESULT_TRUE;
-#endif /* ENOSUPP */
-#ifdef EOPNOTSUPP
-  if (err == EOPNOTSUPP)
-    return MDBX_RESULT_TRUE;
-#endif /* EOPNOTSUPP */
-  if (err == EAGAIN)
-    return MDBX_RESULT_TRUE;
-  return err;
-}
-#endif /* defined(_WIN32) || defined(_WIN64) */
-
-#if MDBX_ENABLE_MADVISE
-/* Turn on/off readahead. It's harmful when the DB is larger than RAM. */
-__cold static int mdbx_set_readahead(MDBX_env *env, const pgno_t edge,
-                                     const bool enable,
-                                     const bool force_whole) {
-  mdbx_assert(env, edge >= NUM_METAS && edge <= MAX_PAGENO + 1);
-  mdbx_assert(env, (enable & 1) == (enable != 0));
-  const bool toggle = force_whole ||
-                      ((enable ^ env->me_lck->mti_readahead_anchor) & 1) ||
-                      !env->me_lck->mti_readahead_anchor;
-  const pgno_t prev_edge = env->me_lck->mti_readahead_anchor >> 1;
-  const size_t limit = env->me_dxb_mmap.limit;
-  size_t offset =
-      toggle ? 0
-             : pgno_align2os_bytes(env, (prev_edge < edge) ? prev_edge : edge);
-  offset = (offset < limit) ? offset : limit;
-
-  size_t length =
-      pgno_align2os_bytes(env, (prev_edge < edge) ? edge : prev_edge);
-  length = (length < limit) ? length : limit;
-  length -= offset;
-
-  mdbx_assert(env, 0 <= (intptr_t)length);
-  if (length == 0)
-    return MDBX_SUCCESS;
-
-  mdbx_notice("readahead %s %u..%u", enable ? "ON" : "OFF",
-              bytes2pgno(env, offset), bytes2pgno(env, offset + length));
-
-#if defined(F_RDAHEAD)
-  if (toggle && unlikely(fcntl(env->me_lazy_fd, F_RDAHEAD, enable) == -1))
-    return errno;
-#endif /* F_RDAHEAD */
-
-  int err;
-  if (enable) {
-#if defined(MADV_NORMAL)
-    err = madvise(env->me_map + offset, length, MADV_NORMAL)
-              ? ignore_enosys(errno)
-              : MDBX_SUCCESS;
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(POSIX_MADV_NORMAL)
-    err = ignore_enosys(
-        posix_madvise(env->me_map + offset, length, POSIX_MADV_NORMAL));
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(POSIX_FADV_NORMAL) && defined(POSIX_FADV_WILLNEED)
-    err = ignore_enosys(
-        posix_fadvise(env->me_lazy_fd, offset, length, POSIX_FADV_NORMAL));
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(_WIN32) || defined(_WIN64)
-    /* no madvise on Windows */
-#else
-#warning "FIXME"
-#endif
-    if (toggle) {
-      /* NOTE: Seems there is a bug in the Mach/Darwin/OSX kernel,
-       * because MADV_WILLNEED with offset != 0 may cause SIGBUS
-       * on following access to the hinted region.
-       * 19.6.0 Darwin Kernel Version 19.6.0: Tue Jan 12 22:13:05 PST 2021;
-       * root:xnu-6153.141.16~1/RELEASE_X86_64 x86_64 */
-#if defined(F_RDADVISE)
-      struct radvisory hint;
-      hint.ra_offset = offset;
-      hint.ra_count = length;
-      (void)/* Ignore ENOTTY for DB on the ram-disk and so on */ fcntl(
-          env->me_lazy_fd, F_RDADVISE, &hint);
-#elif defined(MADV_WILLNEED)
-      err = madvise(env->me_map + offset, length, MADV_WILLNEED)
-                ? ignore_enosys(errno)
-                : MDBX_SUCCESS;
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-#elif defined(POSIX_MADV_WILLNEED)
-      err = ignore_enosys(
-          posix_madvise(env->me_map + offset, length, POSIX_MADV_WILLNEED));
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-#elif defined(_WIN32) || defined(_WIN64)
-      if (mdbx_PrefetchVirtualMemory) {
-        WIN32_MEMORY_RANGE_ENTRY hint;
-        hint.VirtualAddress = env->me_map + offset;
-        hint.NumberOfBytes = length;
-        (void)mdbx_PrefetchVirtualMemory(GetCurrentProcess(), 1, &hint, 0);
-      }
-#elif defined(POSIX_FADV_WILLNEED)
-      err = ignore_enosys(
-          posix_fadvise(env->me_lazy_fd, offset, length, POSIX_FADV_WILLNEED));
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-#else
-#warning "FIXME"
-#endif
-    }
-  } else {
-#if defined(MADV_RANDOM)
-    err = madvise(env->me_map + offset, length, MADV_RANDOM)
-              ? ignore_enosys(errno)
-              : MDBX_SUCCESS;
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(POSIX_MADV_RANDOM)
-    err = ignore_enosys(
-        posix_madvise(env->me_map + offset, length, POSIX_MADV_RANDOM));
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(POSIX_FADV_RANDOM)
-    err = ignore_enosys(
-        posix_fadvise(env->me_lazy_fd, offset, length, POSIX_FADV_RANDOM));
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(_WIN32) || defined(_WIN64)
-    /* no madvise on Windows */
-#else
-#warning "FIXME"
-#endif /* MADV_RANDOM */
-  }
-
-  env->me_lck->mti_readahead_anchor = (enable & 1) + (edge << 1);
-  err = MDBX_SUCCESS;
-  return err;
-}
-#endif /* MDBX_ENABLE_MADVISE */
-
-__cold static int mdbx_mapresize(MDBX_env *env, const pgno_t used_pgno,
-                                 const pgno_t size_pgno,
-                                 const pgno_t limit_pgno, const bool implicit) {
-  const size_t limit_bytes = pgno_align2os_bytes(env, limit_pgno);
-  const size_t size_bytes = pgno_align2os_bytes(env, size_pgno);
-  const size_t prev_size = env->me_dxb_mmap.current;
-  const size_t prev_limit = env->me_dxb_mmap.limit;
-#if MDBX_ENABLE_MADVISE || defined(MDBX_USE_VALGRIND)
-  const void *const prev_addr = env->me_map;
-#endif /* MDBX_ENABLE_MADVISE || MDBX_USE_VALGRIND */
-
-  mdbx_verbose("resize datafile/mapping: "
-               "present %" PRIuPTR " -> %" PRIuPTR ", "
-               "limit %" PRIuPTR " -> %" PRIuPTR,
-               prev_size, size_bytes, prev_limit, limit_bytes);
-
-  mdbx_assert(env, limit_bytes >= size_bytes);
-  mdbx_assert(env, bytes2pgno(env, size_bytes) >= size_pgno);
-  mdbx_assert(env, bytes2pgno(env, limit_bytes) >= limit_pgno);
-
-  unsigned mresize_flags =
-      env->me_flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_UTTERLY_NOSYNC);
-#if defined(_WIN32) || defined(_WIN64)
-  /* Acquire guard in exclusive mode for:
-   *   - to avoid collision between read and write txns around env->me_dbgeo;
-   *   - to avoid attachment of new reading threads (see mdbx_rdt_lock); */
-  mdbx_srwlock_AcquireExclusive(&env->me_remap_guard);
-  mdbx_handle_array_t *suspended = NULL;
-  mdbx_handle_array_t array_onstack;
-  int rc = MDBX_SUCCESS;
-  if (limit_bytes == env->me_dxb_mmap.limit &&
-      size_bytes == env->me_dxb_mmap.current &&
-      size_bytes == env->me_dxb_mmap.filesize)
-    goto bailout;
-
-  if ((env->me_flags & MDBX_NOTLS) == 0) {
-    /* 1) Windows allows only extending a read-write section, but not a
-     *    corresponding 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.
-     * 3) Under Wine runtime environment on Linux a section extending is not
-     *    supported.
-     *
-     * 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;
-    }
-    mresize_flags |= implicit ? MDBX_MRESIZE_MAY_UNMAP
-                              : MDBX_MRESIZE_MAY_UNMAP | MDBX_MRESIZE_MAY_MOVE;
-  }
-#else  /* Windows */
-  /* Acquire guard to avoid collision between read and write txns
-   * around env->me_dbgeo */
-  int rc = mdbx_fastmutex_acquire(&env->me_remap_guard);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  if (limit_bytes == env->me_dxb_mmap.limit &&
-      size_bytes == env->me_dxb_mmap.current)
-    goto bailout;
-
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (limit_bytes != env->me_dxb_mmap.limit && !(env->me_flags & MDBX_NOTLS) &&
-      lck && !implicit) {
-    int err = mdbx_rdt_lock(env) /* lock readers table until remap done */;
-    if (unlikely(MDBX_IS_ERROR(err))) {
-      rc = err;
-      goto bailout;
-    }
-
-    /* looking for readers from this process */
-    const unsigned snap_nreaders =
-        atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-    mdbx_assert(env, !implicit);
-    mresize_flags |= MDBX_MRESIZE_MAY_UNMAP | MDBX_MRESIZE_MAY_MOVE;
-    for (unsigned i = 0; i < snap_nreaders; ++i) {
-      if (lck->mti_readers[i].mr_pid.weak == env->me_pid &&
-          lck->mti_readers[i].mr_tid.weak != mdbx_thread_self()) {
-        /* the base address of the mapping can't be changed since
-         * the other reader thread from this process exists. */
-        mdbx_rdt_unlock(env);
-        mresize_flags &= ~(MDBX_MRESIZE_MAY_UNMAP | MDBX_MRESIZE_MAY_MOVE);
-        break;
-      }
-    }
-  }
-#endif /* ! Windows */
-
-  if ((env->me_flags & MDBX_WRITEMAP) && env->me_lck->mti_unsynced_pages.weak) {
-#if MDBX_ENABLE_PGOP_STAT
-    env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    rc = mdbx_msync(&env->me_dxb_mmap, 0, pgno_align2os_bytes(env, used_pgno),
-                    MDBX_SYNC_NONE);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-  }
-
-#if MDBX_ENABLE_MADVISE
-  if (size_bytes < prev_size) {
-    mdbx_notice("resize-MADV_%s %u..%u",
-                (env->me_flags & MDBX_WRITEMAP) ? "REMOVE" : "DONTNEED",
-                size_pgno, bytes2pgno(env, prev_size));
-    rc = MDBX_RESULT_TRUE;
-#if defined(MADV_REMOVE)
-    if (env->me_flags & MDBX_WRITEMAP)
-      rc =
-          madvise(env->me_map + size_bytes, prev_size - size_bytes, MADV_REMOVE)
-              ? ignore_enosys(errno)
-              : MDBX_SUCCESS;
-#endif /* MADV_REMOVE */
-#if defined(MADV_DONTNEED)
-    if (rc == MDBX_RESULT_TRUE)
-      rc = madvise(env->me_map + size_bytes, prev_size - size_bytes,
-                   MADV_DONTNEED)
-               ? ignore_enosys(errno)
-               : MDBX_SUCCESS;
-#elif defined(POSIX_MADV_DONTNEED)
-    if (rc == MDBX_RESULT_TRUE)
-      rc = ignore_enosys(posix_madvise(env->me_map + size_bytes,
-                                       prev_size - size_bytes,
-                                       POSIX_MADV_DONTNEED));
-#elif defined(POSIX_FADV_DONTNEED)
-    if (rc == MDBX_RESULT_TRUE)
-      rc = ignore_enosys(posix_fadvise(env->me_lazy_fd, size_bytes,
-                                       prev_size - size_bytes,
-                                       POSIX_FADV_DONTNEED));
-#endif /* MADV_DONTNEED */
-    if (unlikely(MDBX_IS_ERROR(rc)))
-      goto bailout;
-    if (env->me_lck->mti_discarded_tail.weak > size_pgno)
-      env->me_lck->mti_discarded_tail.weak = size_pgno;
-  }
-#endif /* MDBX_ENABLE_MADVISE */
-
-  rc = mdbx_mresize(mresize_flags, &env->me_dxb_mmap, size_bytes, limit_bytes);
-
-#if MDBX_ENABLE_MADVISE
-  if (rc == MDBX_SUCCESS) {
-    env->me_lck->mti_discarded_tail.weak = size_pgno;
-    const bool readahead =
-        !(env->me_flags & MDBX_NORDAHEAD) &&
-        mdbx_is_readahead_reasonable(size_bytes, -(intptr_t)prev_size);
-    const bool force = limit_bytes != prev_limit ||
-                       env->me_dxb_mmap.address != prev_addr
-#if defined(_WIN32) || defined(_WIN64)
-                       || prev_size > size_bytes
-#endif /* Windows */
-        ;
-    rc = mdbx_set_readahead(env, size_pgno, readahead, force);
-  }
-#endif /* MDBX_ENABLE_MADVISE */
-
-bailout:
-  if (rc == MDBX_SUCCESS) {
-    mdbx_assert(env, size_bytes == env->me_dxb_mmap.current);
-    mdbx_assert(env, size_bytes <= env->me_dxb_mmap.filesize);
-    mdbx_assert(env, limit_bytes == env->me_dxb_mmap.limit);
-#ifdef MDBX_USE_VALGRIND
-    if (prev_limit != env->me_dxb_mmap.limit || prev_addr != env->me_map) {
-      VALGRIND_DISCARD(env->me_valgrind_handle);
-      env->me_valgrind_handle = 0;
-      if (env->me_dxb_mmap.limit)
-        env->me_valgrind_handle =
-            VALGRIND_CREATE_BLOCK(env->me_map, env->me_dxb_mmap.limit, "mdbx");
-    }
-#endif /* MDBX_USE_VALGRIND */
-  } else {
-    if (rc != MDBX_UNABLE_EXTEND_MAPSIZE && rc != MDBX_EPERM) {
-      mdbx_error("failed resize datafile/mapping: "
-                 "present %" PRIuPTR " -> %" PRIuPTR ", "
-                 "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d",
-                 prev_size, size_bytes, prev_limit, limit_bytes, rc);
-    } else {
-      mdbx_warning("unable resize datafile/mapping: "
-                   "present %" PRIuPTR " -> %" PRIuPTR ", "
-                   "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d",
-                   prev_size, size_bytes, prev_limit, limit_bytes, rc);
-    }
-    if (!env->me_dxb_mmap.address) {
-      env->me_flags |= MDBX_FATAL_ERROR;
-      if (env->me_txn)
-        env->me_txn->mt_flags |= MDBX_TXN_ERROR;
-      rc = MDBX_PANIC;
-    }
-  }
-
-#if defined(_WIN32) || defined(_WIN64)
-  int err = MDBX_SUCCESS;
-  mdbx_srwlock_ReleaseExclusive(&env->me_remap_guard);
-  if (suspended) {
-    err = mdbx_resume_threads_after_remap(suspended);
-    if (suspended != &array_onstack)
-      mdbx_free(suspended);
-  }
-#else
-  if (env->me_lck_mmap.lck &&
-      (mresize_flags & (MDBX_MRESIZE_MAY_UNMAP | MDBX_MRESIZE_MAY_MOVE)) != 0)
-    mdbx_rdt_unlock(env);
-  int err = mdbx_fastmutex_release(&env->me_remap_guard);
-#endif /* Windows */
-  if (err != MDBX_SUCCESS) {
-    mdbx_fatal("failed resume-after-remap: errcode %d", err);
-    return MDBX_PANIC;
-  }
-  return rc;
-}
-
-__cold static int mdbx_mapresize_implicit(MDBX_env *env, const pgno_t used_pgno,
-                                          const pgno_t size_pgno,
-                                          const pgno_t limit_pgno) {
-  const pgno_t mapped_pgno = bytes2pgno(env, env->me_dxb_mmap.limit);
-  mdbx_assert(env, mapped_pgno >= used_pgno);
-  return mdbx_mapresize(
-      env, used_pgno, size_pgno,
-      (size_pgno > mapped_pgno)
-          ? limit_pgno
-          : /* The actual mapsize may be less since the geo.upper may be changed
-               by other process. So, avoids remapping until it necessary. */
-          mapped_pgno,
-      true);
-}
-
-static int mdbx_meta_unsteady(MDBX_env *env, const txnid_t last_steady,
-                              MDBX_meta *const meta, mdbx_filehandle_t fd) {
-  const uint64_t wipe = MDBX_DATASIGN_NONE;
-  if (unlikely(META_IS_STEADY(meta)) &&
-      constmeta_txnid(env, meta) <= last_steady) {
-    mdbx_warning("wipe txn #%" PRIaTXN ", meta %" PRIaPGNO, last_steady,
-                 data_page(meta)->mp_pgno);
-    if (env->me_flags & MDBX_WRITEMAP)
-      unaligned_poke_u64(4, meta->mm_datasync_sign, wipe);
-    else
-      return mdbx_pwrite(fd, &wipe, sizeof(meta->mm_datasync_sign),
-                         (uint8_t *)&meta->mm_datasync_sign - env->me_map);
-    if (constmeta_txnid(env, meta) == last_steady)
-      mdbx_assert(env, meta_checktxnid(env, meta, true));
-  }
-  return MDBX_SUCCESS;
-}
-
-__cold static int mdbx_wipe_steady(MDBX_env *env, const txnid_t last_steady) {
-#if MDBX_ENABLE_PGOP_STAT
-  env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  const mdbx_filehandle_t fd = (env->me_dsync_fd != INVALID_HANDLE_VALUE)
-                                   ? env->me_dsync_fd
-                                   : env->me_lazy_fd;
-  int err = mdbx_meta_unsteady(env, last_steady, METAPAGE(env, 0), fd);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-  err = mdbx_meta_unsteady(env, last_steady, METAPAGE(env, 1), fd);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-  err = mdbx_meta_unsteady(env, last_steady, METAPAGE(env, 2), fd);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  if (env->me_flags & MDBX_WRITEMAP) {
-    mdbx_flush_incoherent_cpu_writeback();
-    err = mdbx_msync(&env->me_dxb_mmap, 0, pgno_align2os_bytes(env, NUM_METAS),
-                     MDBX_SYNC_DATA);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-  } else {
-    if (fd == env->me_lazy_fd) {
-#if MDBX_USE_SYNCFILERANGE
-      static bool syncfilerange_unavailable;
-      if (!syncfilerange_unavailable &&
-          sync_file_range(env->me_lazy_fd, 0, pgno2bytes(env, NUM_METAS),
-                          SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER)) {
-        err = errno;
-        if (ignore_enosys(err) == MDBX_RESULT_TRUE)
-          syncfilerange_unavailable = true;
-      }
-      if (syncfilerange_unavailable)
-#endif /* MDBX_USE_SYNCFILERANGE */
-        err = mdbx_fsync(env->me_lazy_fd, MDBX_SYNC_DATA);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-    }
-    mdbx_flush_incoherent_mmap(env->me_map, pgno2bytes(env, NUM_METAS),
-                               env->me_os_psize);
-  }
-
-  /* force oldest refresh */
-  atomic_store32(&env->me_lck->mti_readers_refresh_flag, true, mo_Relaxed);
-  return MDBX_SUCCESS;
-}
-
-/* Allocate page numbers and memory for writing.  Maintain mt_last_reclaimed,
- * mt_reclaimed_pglist and mt_next_pgno.  Set MDBX_TXN_ERROR on failure.
- *
- * If there are free pages available from older transactions, they
- * are re-used first. Otherwise allocate a new page at mt_next_pgno.
- * Do not modify the GC, just merge GC records into mt_reclaimed_pglist
- * and move mt_last_reclaimed to say which records were consumed.  Only this
- * function can create mt_reclaimed_pglist and move
- * mt_last_reclaimed/mt_next_pgno.
- *
- * [in] mc    cursor A cursor handle identifying the transaction and
- *            database for which we are allocating.
- * [in] num   the number of pages to allocate.
- *
- * Returns 0 on success, non-zero on failure.*/
-
-#define MDBX_ALLOC_CACHE 1
-#define MDBX_ALLOC_GC 2
-#define MDBX_ALLOC_NEW 4
-#define MDBX_ALLOC_SLOT 8
-#define MDBX_ALLOC_FAKE 16
-#define MDBX_ALLOC_ALL (MDBX_ALLOC_CACHE | MDBX_ALLOC_GC | MDBX_ALLOC_NEW)
-
-__hot static struct page_result mdbx_page_alloc(MDBX_cursor *mc,
-                                                const pgno_t num, int flags) {
-  struct page_result ret;
-  MDBX_txn *const txn = mc->mc_txn;
-  MDBX_env *const env = txn->mt_env;
-  mdbx_assert(env, num == 0 || !(flags & MDBX_ALLOC_SLOT));
-  mdbx_assert(env, num > 0 || !(flags & MDBX_ALLOC_NEW));
-
-  const unsigned coalesce_threshold =
-      env->me_maxgc_ov1page - env->me_maxgc_ov1page / 4;
-  if (likely(flags & MDBX_ALLOC_GC)) {
-    flags |= env->me_flags & (MDBX_COALESCE | MDBX_LIFORECLAIM);
-    if (MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) > coalesce_threshold)
-      flags &= ~MDBX_COALESCE;
-    if (unlikely(
-            /* If mc is updating the GC, then the retired-list cannot play
-               catch-up with itself by growing while trying to save it. */
-            (mc->mc_flags & C_RECLAIMING) ||
-            /* avoid (recursive) search inside empty tree and while tree is
-               updating, todo4recovery://erased_by_github/libmdbx/issues/31 */
-            txn->mt_dbs[FREE_DBI].md_entries == 0 ||
-            /* If our dirty list is already full, we can't touch GC */
-            (txn->tw.dirtyroom < txn->mt_dbs[FREE_DBI].md_depth &&
-             !(txn->mt_dbistate[FREE_DBI] & DBI_DIRTY))))
-      flags &= ~(MDBX_ALLOC_GC | MDBX_COALESCE);
-  }
-
-  if (likely(num == 1 && (flags & MDBX_ALLOC_CACHE) != 0)) {
-    /* If there are any loose pages, just use them */
-    mdbx_assert(env, (flags & MDBX_ALLOC_SLOT) == 0);
-    if (likely(txn->tw.loose_pages)) {
-#if MDBX_ENABLE_REFUND
-      if (txn->tw.loose_refund_wl > txn->mt_next_pgno) {
-        mdbx_refund(txn);
-        if (unlikely(!txn->tw.loose_pages))
-          goto no_loose;
-      }
-#endif /* MDBX_ENABLE_REFUND */
-
-      ret.page = txn->tw.loose_pages;
-      txn->tw.loose_pages = ret.page->mp_next;
-      txn->tw.loose_count--;
-      mdbx_debug_extra("db %d use loose page %" PRIaPGNO, DDBI(mc),
-                       ret.page->mp_pgno);
-      mdbx_tassert(txn, ret.page->mp_pgno < txn->mt_next_pgno);
-      mdbx_ensure(env, ret.page->mp_pgno >= NUM_METAS);
-      VALGRIND_MAKE_MEM_UNDEFINED(page_data(ret.page), page_space(txn->mt_env));
-      MDBX_ASAN_UNPOISON_MEMORY_REGION(page_data(ret.page),
-                                       page_space(txn->mt_env));
-      ret.page->mp_txnid = txn->mt_front;
-      ret.err = MDBX_SUCCESS;
-      return ret;
-    }
-  }
-#if MDBX_ENABLE_REFUND
-no_loose:
-#endif /* MDBX_ENABLE_REFUND */
-
-  mdbx_tassert(txn,
-               mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                     txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-  pgno_t pgno, *re_list = txn->tw.reclaimed_pglist;
-  unsigned range_begin = 0, re_len = MDBX_PNL_SIZE(re_list);
-  txnid_t oldest = 0, last = 0;
-
-  while (true) { /* hsr-kick retry loop */
-    MDBX_cursor_couple recur;
-    for (MDBX_cursor_op op = MDBX_FIRST;;
-         op = (flags & MDBX_LIFORECLAIM) ? MDBX_PREV : MDBX_NEXT) {
-      MDBX_val key, data;
-
-      /* Seek a big enough contiguous page range.
-       * Prefer pages with lower pgno. */
-      mdbx_tassert(txn, mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                              txn->mt_next_pgno));
-      if (!(flags & (MDBX_COALESCE | MDBX_ALLOC_SLOT)) && re_len >= num) {
-        mdbx_tassert(txn, MDBX_PNL_LAST(re_list) < txn->mt_next_pgno &&
-                              MDBX_PNL_FIRST(re_list) < txn->mt_next_pgno);
-        range_begin = MDBX_PNL_ASCENDING ? 1 : re_len;
-        pgno = MDBX_PNL_LEAST(re_list);
-        if (likely(num == 1))
-          goto done;
-
-        const unsigned wanna_range = num - 1;
-#if MDBX_PNL_ASCENDING
-        mdbx_tassert(txn, pgno == re_list[1] && range_begin == 1);
-        while (true) {
-          unsigned range_end = range_begin + wanna_range;
-          if (re_list[range_end] - pgno == wanna_range)
-            goto done;
-          if (range_end == re_len)
-            break;
-          pgno = re_list[++range_begin];
-        }
-#else
-        mdbx_tassert(txn, pgno == re_list[re_len] && range_begin == re_len);
-        while (true) {
-          if (re_list[range_begin - wanna_range] - pgno == wanna_range)
-            goto done;
-          if (range_begin == wanna_range)
-            break;
-          pgno = re_list[--range_begin];
-        }
-#endif /* MDBX_PNL sort-order */
-      }
-
-      if (op == MDBX_FIRST) { /* 1st iteration, setup cursor, etc */
-        if (unlikely(!(flags & MDBX_ALLOC_GC)))
-          break /* reclaiming is prohibited for now */;
-
-        /* Prepare to fetch more and coalesce */
-        oldest = (flags & MDBX_LIFORECLAIM)
-                     ? mdbx_find_oldest(txn)
-                     : atomic_load64(&env->me_lck->mti_oldest_reader,
-                                     mo_AcquireRelease);
-        ret.err = mdbx_cursor_init(&recur.outer, txn, FREE_DBI);
-        if (unlikely(ret.err != MDBX_SUCCESS))
-          goto fail;
-        if (flags & MDBX_LIFORECLAIM) {
-          /* Begin from oldest reader if any */
-          if (oldest > MIN_TXNID) {
-            last = oldest - 1;
-            op = MDBX_SET_RANGE;
-          }
-        } else if (txn->tw.last_reclaimed) {
-          /* Continue lookup from txn->tw.last_reclaimed to oldest reader */
-          last = txn->tw.last_reclaimed;
-          op = MDBX_SET_RANGE;
-        }
-
-        key.iov_base = &last;
-        key.iov_len = sizeof(last);
-      }
-
-      if (!(flags & MDBX_LIFORECLAIM)) {
-        /* Do not try fetch more if the record will be too recent */
-        if (op != MDBX_FIRST && ++last >= oldest) {
-          oldest = mdbx_find_oldest(txn);
-          if (oldest <= last)
-            break;
-        }
-      }
-
-      ret.err = mdbx_cursor_get(&recur.outer, &key, NULL, op);
-      if (ret.err == MDBX_NOTFOUND && (flags & MDBX_LIFORECLAIM)) {
-        if (op == MDBX_SET_RANGE)
-          continue;
-        txnid_t snap = mdbx_find_oldest(txn);
-        if (oldest < snap) {
-          oldest = snap;
-          last = oldest - 1;
-          key.iov_base = &last;
-          key.iov_len = sizeof(last);
-          op = MDBX_SET_RANGE;
-          ret.err = mdbx_cursor_get(&recur.outer, &key, NULL, op);
-        }
-      }
-      if (unlikely(ret.err)) {
-        if (ret.err == MDBX_NOTFOUND)
-          break;
-        goto fail;
-      }
-
-      if (!MDBX_DISABLE_PAGECHECKS &&
-          unlikely(key.iov_len != sizeof(txnid_t))) {
-        ret.err = MDBX_CORRUPTED;
-        goto fail;
-      }
-      last = unaligned_peek_u64(4, key.iov_base);
-      if (!MDBX_DISABLE_PAGECHECKS &&
-          unlikely(last < MIN_TXNID || last > MAX_TXNID)) {
-        ret.err = MDBX_CORRUPTED;
-        goto fail;
-      }
-      if (oldest <= last) {
-        oldest = mdbx_find_oldest(txn);
-        if (oldest <= last) {
-          if (flags & MDBX_LIFORECLAIM)
-            continue;
-          break;
-        }
-      }
-
-      if (flags & MDBX_LIFORECLAIM) {
-        /* skip IDs of records that already reclaimed */
-        if (txn->tw.lifo_reclaimed) {
-          size_t i;
-          for (i = (size_t)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed); i > 0; --i)
-            if (txn->tw.lifo_reclaimed[i] == last)
-              break;
-          if (i)
-            continue;
-        }
-      }
-
-      /* Reading next GC record */
-      MDBX_page *const mp = recur.outer.mc_pg[recur.outer.mc_top];
-      if (unlikely((ret.err = mdbx_node_read(
-                        &recur.outer,
-                        page_node(mp, recur.outer.mc_ki[recur.outer.mc_top]),
-                        &data, pp_txnid4chk(mp, txn))) != MDBX_SUCCESS))
-        goto fail;
-
-      if ((flags & MDBX_LIFORECLAIM) && !txn->tw.lifo_reclaimed) {
-        txn->tw.lifo_reclaimed = mdbx_txl_alloc();
-        if (unlikely(!txn->tw.lifo_reclaimed)) {
-          ret.err = MDBX_ENOMEM;
-          goto fail;
-        }
-      }
-
-      /* Append PNL from GC record to tw.reclaimed_pglist */
-      mdbx_cassert(mc, (mc->mc_flags & C_GCFREEZE) == 0);
-      pgno_t *gc_pnl = (pgno_t *)data.iov_base;
-      mdbx_tassert(txn, data.iov_len >= MDBX_PNL_SIZEOF(gc_pnl));
-      if (unlikely(data.iov_len < MDBX_PNL_SIZEOF(gc_pnl) ||
-                   !mdbx_pnl_check(gc_pnl, txn->mt_next_pgno))) {
-        ret.err = MDBX_CORRUPTED;
-        goto fail;
-      }
-      const unsigned gc_len = MDBX_PNL_SIZE(gc_pnl);
-      if (unlikely(/* list is too long already */ MDBX_PNL_SIZE(
-                       txn->tw.reclaimed_pglist) >=
-                   env->me_options.rp_augment_limit) &&
-          ((/* not a slot-request from gc-update */
-            (flags & MDBX_ALLOC_SLOT) == 0 &&
-            /* have enough unallocated space */ txn->mt_geo.upper >=
-                txn->mt_next_pgno + (size_t)num) ||
-           gc_len + MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) >=
-               MDBX_PGL_LIMIT)) {
-        /* Stop reclaiming to avoid overflow the page list.
-         * This is a rare case while search for a continuously multi-page region
-         * in a large database.
-         * todo4recovery://erased_by_github/libmdbx/issues/123 */
-        mdbx_notice("stop reclaiming to avoid PNL overflow: %u (current) + %u "
-                    "(chunk) -> %u",
-                    MDBX_PNL_SIZE(txn->tw.reclaimed_pglist), gc_len,
-                    gc_len + MDBX_PNL_SIZE(txn->tw.reclaimed_pglist));
-        flags &= ~(MDBX_ALLOC_GC | MDBX_COALESCE);
-        break;
-      }
-      ret.err = mdbx_pnl_need(&txn->tw.reclaimed_pglist, gc_len);
-      if (unlikely(ret.err != MDBX_SUCCESS))
-        goto fail;
-      re_list = txn->tw.reclaimed_pglist;
-
-      /* Remember ID of GC record */
-      if (flags & MDBX_LIFORECLAIM) {
-        ret.err = mdbx_txl_append(&txn->tw.lifo_reclaimed, last);
-        if (unlikely(ret.err != MDBX_SUCCESS))
-          goto fail;
-      }
-      txn->tw.last_reclaimed = last;
-
-      if (mdbx_log_enabled(MDBX_LOG_EXTRA)) {
-        mdbx_debug_extra("PNL read txn %" PRIaTXN " root %" PRIaPGNO
-                         " num %u, PNL",
-                         last, txn->mt_dbs[FREE_DBI].md_root, gc_len);
-        for (unsigned i = gc_len; i; i--)
-          mdbx_debug_extra_print(" %" PRIaPGNO, gc_pnl[i]);
-        mdbx_debug_extra_print("%s\n", ".");
-      }
-
-      /* Merge in descending sorted order */
-      const unsigned prev_re_len = MDBX_PNL_SIZE(re_list);
-      mdbx_pnl_xmerge(re_list, gc_pnl);
-      /* re-check to avoid duplicates */
-      if (!MDBX_DISABLE_PAGECHECKS &&
-          unlikely(!mdbx_pnl_check(re_list, txn->mt_next_pgno))) {
-        ret.err = MDBX_CORRUPTED;
-        goto fail;
-      }
-      mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-
-      re_len = MDBX_PNL_SIZE(re_list);
-      mdbx_tassert(txn, re_len == 0 || re_list[re_len] < txn->mt_next_pgno);
-      if (MDBX_ENABLE_REFUND && re_len &&
-          unlikely(MDBX_PNL_MOST(re_list) == txn->mt_next_pgno - 1)) {
-        /* Refund suitable pages into "unallocated" space */
-        mdbx_refund(txn);
-        re_list = txn->tw.reclaimed_pglist;
-        re_len = MDBX_PNL_SIZE(re_list);
-      }
-
-      /* Done for a kick-reclaim mode, actually no page needed */
-      if (unlikely(flags & MDBX_ALLOC_SLOT)) {
-        mdbx_debug("early-return NULL-page for %s mode", "MDBX_ALLOC_SLOT");
-        ret.err = MDBX_SUCCESS;
-        ret.page = NULL;
-        return ret;
-      }
-
-      /* Don't try to coalesce too much. */
-      if (flags & MDBX_COALESCE) {
-        if (re_len /* current size */ > coalesce_threshold ||
-            (re_len > prev_re_len &&
-             re_len - prev_re_len /* delta from prev */ >=
-                 coalesce_threshold / 2)) {
-          mdbx_trace("clear %s %s", "MDBX_COALESCE", "since got threshold");
-          flags &= ~MDBX_COALESCE;
-        }
-      }
-    }
-
-    if (F_ISSET(flags, MDBX_COALESCE | MDBX_ALLOC_GC)) {
-      mdbx_debug_extra("clear %s and continue", "MDBX_COALESCE");
-      flags &= ~MDBX_COALESCE;
-      continue;
-    }
-
-    /* There is no suitable pages in the GC and to be able to allocate
-     * we should CHOICE one of:
-     *  - make a new steady checkpoint if reclaiming was stopped by
-     *    the last steady-sync, or wipe it in the MDBX_UTTERLY_NOSYNC mode;
-     *  - kick lagging reader(s) if reclaiming was stopped by ones of it.
-     *  - extend the database file. */
-
-    /* Will use new pages from the map if nothing is suitable in the GC. */
-    range_begin = 0;
-    pgno = txn->mt_next_pgno;
-    const size_t next = (size_t)pgno + num;
-
-    if (flags & MDBX_ALLOC_GC) {
-      const MDBX_meta *const head = constmeta_prefer_last(env);
-      const MDBX_meta *const steady = constmeta_prefer_steady(env);
-      /* does reclaiming stopped at the last steady point? */
-      if (head != steady && META_IS_STEADY(steady) &&
-          oldest == constmeta_txnid(env, steady)) {
-        mdbx_debug("gc-kick-steady: head %" PRIaTXN "-%s, tail %" PRIaTXN
-                   "-%s, oldest %" PRIaTXN,
-                   constmeta_txnid(env, head), mdbx_durable_str(head),
-                   constmeta_txnid(env, steady), mdbx_durable_str(steady),
-                   oldest);
-        ret.err = MDBX_RESULT_TRUE;
-        const pgno_t autosync_threshold =
-            atomic_load32(&env->me_lck->mti_autosync_threshold, mo_Relaxed);
-        const uint64_t autosync_period =
-            atomic_load64(&env->me_lck->mti_autosync_period, mo_Relaxed);
-        /* wipe the last steady-point if one of:
-         *  - UTTERLY_NOSYNC mode AND auto-sync threshold is NOT specified
-         *  - UTTERLY_NOSYNC mode AND free space at steady-point is exhausted
-         * otherwise, make a new steady-point if one of:
-         *  - auto-sync threshold is specified and reached;
-         *  - upper limit of database size is reached;
-         *  - database is full (with the current file size)
-         *       AND auto-sync threshold it NOT specified */
-        if (F_ISSET(env->me_flags, MDBX_UTTERLY_NOSYNC) &&
-            ((autosync_threshold | autosync_period) == 0 ||
-             next >= steady->mm_geo.now)) {
-          /* wipe steady checkpoint in MDBX_UTTERLY_NOSYNC mode
-           * without any auto-sync threshold(s). */
-          ret.err = mdbx_wipe_steady(env, oldest);
-          mdbx_debug("gc-wipe-steady, rc %d", ret.err);
-          mdbx_assert(env, steady != meta_prefer_steady(env));
-        } else if ((flags & MDBX_ALLOC_NEW) == 0 ||
-                   (autosync_threshold &&
-                    atomic_load32(&env->me_lck->mti_unsynced_pages,
-                                  mo_Relaxed) >= autosync_threshold) ||
-                   (autosync_period &&
-                    mdbx_osal_monotime() -
-                            atomic_load64(&env->me_lck->mti_sync_timestamp,
-                                          mo_Relaxed) >=
-                        autosync_period) ||
-                   next >= txn->mt_geo.upper ||
-                   (next >= txn->mt_end_pgno &&
-                    (autosync_threshold | autosync_period) == 0)) {
-          /* make steady checkpoint. */
-          MDBX_meta meta = *head;
-          ret.err = mdbx_sync_locked(env, env->me_flags & MDBX_WRITEMAP, &meta);
-          mdbx_debug("gc-make-steady, rc %d", ret.err);
-          mdbx_assert(env, steady != meta_prefer_steady(env));
-        }
-        if (ret.err == MDBX_SUCCESS) {
-          if (mdbx_find_oldest(txn) > oldest)
-            continue;
-          /* it is reasonable check/kick lagging reader(s) here,
-           * since we made a new steady point or wipe the last. */
-          if (oldest < txn->mt_txnid - xMDBX_TXNID_STEP &&
-              mdbx_kick_longlived_readers(env, oldest) > oldest)
-            continue;
-        } else if (unlikely(ret.err != MDBX_RESULT_TRUE))
-          goto fail;
-      }
-    }
-
-    /* don't kick lagging reader(s) if is enough unallocated space
-     * at the end of database file. */
-    if ((flags & MDBX_ALLOC_NEW) && next <= txn->mt_end_pgno)
-      goto done;
-    if ((flags & MDBX_ALLOC_GC) && oldest < txn->mt_txnid - xMDBX_TXNID_STEP &&
-        mdbx_kick_longlived_readers(env, oldest) > oldest)
-      continue;
-
-    ret.err = MDBX_NOTFOUND;
-    if (flags & MDBX_ALLOC_NEW) {
-      ret.err = MDBX_MAP_FULL;
-      if (next < txn->mt_geo.upper && txn->mt_geo.grow_pv) {
-        mdbx_assert(env, next > txn->mt_end_pgno);
-        const pgno_t grow_step = pv2pages(txn->mt_geo.grow_pv);
-        size_t aligned = pgno_align2os_pgno(
-            env, (pgno_t)(next + grow_step - next % grow_step));
-
-        if (aligned > txn->mt_geo.upper)
-          aligned = txn->mt_geo.upper;
-        mdbx_assert(env, aligned > txn->mt_end_pgno);
-
-        mdbx_verbose("try growth datafile to %zu pages (+%zu)", aligned,
-                     aligned - txn->mt_end_pgno);
-        ret.err = mdbx_mapresize_implicit(env, txn->mt_next_pgno,
-                                          (pgno_t)aligned, txn->mt_geo.upper);
-        if (ret.err == MDBX_SUCCESS) {
-          env->me_txn->mt_end_pgno = (pgno_t)aligned;
-          goto done;
-        }
-
-        mdbx_error("unable growth datafile to %zu pages (+%zu), errcode %d",
-                   aligned, aligned - txn->mt_end_pgno, ret.err);
-      } else {
-        mdbx_notice("gc-alloc: next %zu > upper %" PRIaPGNO, next,
-                    txn->mt_geo.upper);
-      }
-    }
-
-  fail:
-    mdbx_assert(env,
-                mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                      txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-    if (likely(!(flags & MDBX_ALLOC_FAKE)))
-      txn->mt_flags |= MDBX_TXN_ERROR;
-    if (num != 1 || ret.err != MDBX_NOTFOUND)
-      mdbx_notice("alloc %u pages failed, flags 0x%x, errcode %d", num, flags,
-                  ret.err);
-    else
-      mdbx_trace("alloc %u pages failed, flags 0x%x, errcode %d", num, flags,
-                 ret.err);
-    mdbx_assert(env, ret.err != MDBX_SUCCESS);
-    ret.page = NULL;
-    return ret;
-  }
-
-done:
-  mdbx_assert(env, !(flags & MDBX_ALLOC_SLOT));
-  mdbx_ensure(env, pgno >= NUM_METAS);
-  if (unlikely(flags & MDBX_ALLOC_FAKE)) {
-    mdbx_debug("return NULL-page for %u pages of %s mode", num,
-               "MDBX_ALLOC_FAKE");
-    ret.page = NULL;
-    ret.err = MDBX_SUCCESS;
-    return ret;
-  }
-
-  if (env->me_flags & MDBX_WRITEMAP) {
-    ret.page = pgno2page(env, pgno);
-    /* LY: reset no-access flag from mdbx_page_loose() */
-    VALGRIND_MAKE_MEM_UNDEFINED(ret.page, pgno2bytes(env, num));
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(ret.page, pgno2bytes(env, num));
-  } else {
-    ret.page = mdbx_page_malloc(txn, num);
-    if (unlikely(!ret.page)) {
-      ret.err = MDBX_ENOMEM;
-      goto fail;
-    }
-  }
-
-  if (range_begin) {
-    mdbx_cassert(mc, (mc->mc_flags & C_GCFREEZE) == 0);
-    mdbx_tassert(txn, pgno < txn->mt_next_pgno);
-    mdbx_tassert(txn, pgno == re_list[range_begin]);
-    /* Cutoff allocated pages from tw.reclaimed_pglist */
-#if MDBX_PNL_ASCENDING
-    for (unsigned i = range_begin + num; i <= re_len;)
-      re_list[range_begin++] = re_list[i++];
-    MDBX_PNL_SIZE(re_list) = re_len = range_begin - 1;
-#else
-    MDBX_PNL_SIZE(re_list) = re_len -= num;
-    for (unsigned i = range_begin - num; i < re_len;)
-      re_list[++i] = re_list[++range_begin];
-#endif
-    mdbx_tassert(txn,
-                 mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                       txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-  } else {
-    txn->mt_next_pgno = pgno + num;
-    mdbx_assert(env, txn->mt_next_pgno <= txn->mt_end_pgno);
-  }
-
-  if (unlikely(env->me_flags & MDBX_PAGEPERTURB))
-    memset(ret.page, -1, pgno2bytes(env, num));
-  VALGRIND_MAKE_MEM_UNDEFINED(ret.page, pgno2bytes(env, num));
-
-  ret.page->mp_pgno = pgno;
-  ret.page->mp_leaf2_ksize = 0;
-  ret.page->mp_flags = 0;
-  if ((mdbx_assert_enabled() || mdbx_audit_enabled()) && num > 1) {
-    ret.page->mp_pages = num;
-    ret.page->mp_flags = P_OVERFLOW;
-  }
-  ret.err = mdbx_page_dirty(txn, ret.page, num);
-  if (unlikely(ret.err != MDBX_SUCCESS))
-    goto fail;
-
-  mdbx_tassert(txn,
-               mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                     txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-  return ret;
-}
-
-/* Copy the used portions of a non-overflow page. */
-__hot static void mdbx_page_copy(MDBX_page *dst, const MDBX_page *src,
-                                 size_t psize) {
-  STATIC_ASSERT(UINT16_MAX > MAX_PAGESIZE - PAGEHDRSZ);
-  STATIC_ASSERT(MIN_PAGESIZE > PAGEHDRSZ + NODESIZE * 4);
-  if ((src->mp_flags & (P_LEAF2 | P_OVERFLOW)) == 0) {
-    size_t upper = src->mp_upper, lower = src->mp_lower, unused = upper - lower;
-
-    /* If page isn't full, just copy the used portion. Adjust
-     * alignment so memcpy may copy words instead of bytes. */
-    if (unused >= MDBX_CACHELINE_SIZE * 2) {
-      lower = ceil_powerof2(lower + PAGEHDRSZ, sizeof(void *));
-      upper = floor_powerof2(upper + PAGEHDRSZ, sizeof(void *));
-      memcpy(dst, src, lower);
-      dst = (void *)((char *)dst + upper);
-      src = (void *)((char *)src + upper);
-      psize -= upper;
-    }
-  }
-  memcpy(dst, src, psize);
-}
-
-/* Pull a page off the txn's spill list, if present.
- *
- * If a page being referenced was spilled to disk in this txn, bring
- * it back and make it dirty/writable again. */
-static struct page_result __must_check_result
-mdbx_page_unspill(MDBX_txn *const txn, const MDBX_page *const mp) {
-  mdbx_verbose("unspill page %" PRIaPGNO, mp->mp_pgno);
-  mdbx_tassert(txn, (txn->mt_flags & MDBX_WRITEMAP) == 0);
-  mdbx_tassert(txn, IS_SPILLED(txn, mp));
-  const MDBX_txn *scan = txn;
-  struct page_result ret;
-  do {
-    mdbx_tassert(txn, (scan->mt_flags & MDBX_TXN_SPILLS) != 0);
-    const unsigned si = mdbx_search_spilled(scan, mp->mp_pgno);
-    if (!si)
-      continue;
-    const unsigned npages = IS_OVERFLOW(mp) ? mp->mp_pages : 1;
-    ret.page = mdbx_page_malloc(txn, npages);
-    if (unlikely(!ret.page)) {
-      ret.err = MDBX_ENOMEM;
-      return ret;
-    }
-    mdbx_page_copy(ret.page, mp, pgno2bytes(txn->mt_env, npages));
-    if (scan == txn) {
-      /* If in current txn, this page is no longer spilled.
-       * If it happens to be the last page, truncate the spill list.
-       * Otherwise mark it as deleted by setting the LSB. */
-      mdbx_spill_remove(txn, si, npages);
-    } /* otherwise, if belonging to a parent txn, the
-       * page remains spilled until child commits */
-
-    ret.err = mdbx_page_dirty(txn, ret.page, npages);
-    if (unlikely(ret.err != MDBX_SUCCESS))
-      return ret;
-#if MDBX_ENABLE_PGOP_STAT
-    txn->mt_env->me_lck->mti_pgop_stat.unspill.weak += npages;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    ret.page->mp_flags |= (scan == txn) ? 0 : P_SPILLED;
-    ret.err = MDBX_SUCCESS;
-    return ret;
-  } while (likely((scan = scan->mt_parent) != nullptr &&
-                  (scan->mt_flags & MDBX_TXN_SPILLS) != 0));
-  mdbx_error("Page %" PRIaPGNO " mod-txnid %" PRIaTXN
-             " not found in the spill-list(s), current txn %" PRIaTXN
-             " front %" PRIaTXN ", root txn %" PRIaTXN " front %" PRIaTXN,
-             mp->mp_pgno, mp->mp_txnid, txn->mt_txnid, txn->mt_front,
-             txn->mt_env->me_txn0->mt_txnid, txn->mt_env->me_txn0->mt_front);
-  ret.err = MDBX_PROBLEM;
-  ret.page = NULL;
-  return ret;
-}
-
-/* Touch a page: make it dirty and re-insert into tree with updated pgno.
- * Set MDBX_TXN_ERROR on failure.
- *
- * [in] mc  cursor pointing to the page to be touched
- *
- * Returns 0 on success, non-zero on failure. */
-__hot static int mdbx_page_touch(MDBX_cursor *mc) {
-  const MDBX_page *const mp = mc->mc_pg[mc->mc_top];
-  MDBX_page *np;
-  MDBX_txn *txn = mc->mc_txn;
-  int rc;
-
-  if (mdbx_assert_enabled()) {
-    if (mc->mc_flags & C_SUB) {
-      MDBX_xcursor *mx = container_of(mc->mc_db, MDBX_xcursor, mx_db);
-      MDBX_cursor_couple *couple = container_of(mx, MDBX_cursor_couple, inner);
-      mdbx_tassert(txn, mc->mc_db == &couple->outer.mc_xcursor->mx_db);
-      mdbx_tassert(txn, mc->mc_dbx == &couple->outer.mc_xcursor->mx_dbx);
-      mdbx_tassert(txn, *couple->outer.mc_dbistate & DBI_DIRTY);
-    } else {
-      mdbx_tassert(txn, *mc->mc_dbistate & DBI_DIRTY);
-    }
-    mdbx_tassert(txn, mc->mc_txn->mt_flags & MDBX_TXN_DIRTY);
-    mdbx_tassert(txn, !IS_OVERFLOW(mp));
-    mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-  }
-
-  if (IS_MODIFIABLE(txn, mp) || IS_SUBP(mp))
-    return MDBX_SUCCESS;
-
-  if (IS_FROZEN(txn, mp)) {
-    /* CoW the page */
-    rc = mdbx_pnl_need(&txn->tw.retired_pages, 1);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-    const struct page_result par = mdbx_page_alloc(mc, 1, MDBX_ALLOC_ALL);
-    rc = par.err;
-    np = par.page;
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-
-    const pgno_t pgno = np->mp_pgno;
-    mdbx_debug("touched db %d page %" PRIaPGNO " -> %" PRIaPGNO, DDBI(mc),
-               mp->mp_pgno, pgno);
-    mdbx_tassert(txn, mp->mp_pgno != pgno);
-    mdbx_pnl_xappend(txn->tw.retired_pages, mp->mp_pgno);
-    /* Update the parent page, if any, to point to the new page */
-    if (mc->mc_top) {
-      MDBX_page *parent = mc->mc_pg[mc->mc_top - 1];
-      MDBX_node *node = page_node(parent, mc->mc_ki[mc->mc_top - 1]);
-      node_set_pgno(node, pgno);
-    } else {
-      mc->mc_db->md_root = pgno;
-    }
-
-#if MDBX_ENABLE_PGOP_STAT
-    txn->mt_env->me_lck->mti_pgop_stat.cow.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    mdbx_page_copy(np, mp, txn->mt_env->me_psize);
-    np->mp_pgno = pgno;
-    np->mp_txnid = txn->mt_front;
-  } else if (IS_SPILLED(txn, mp)) {
-    struct page_result pur = mdbx_page_unspill(txn, mp);
-    np = pur.page;
-    rc = pur.err;
-    if (likely(rc == MDBX_SUCCESS)) {
-      mdbx_tassert(txn, np != nullptr);
-      goto done;
-    }
-    goto fail;
-  } else {
-    if (unlikely(!txn->mt_parent)) {
-      mdbx_error("Unexpected not frozen/modifiable/spilled but shadowed %s "
-                 "page %" PRIaPGNO " mod-txnid %" PRIaTXN ","
-                 " without parent transaction, current txn %" PRIaTXN
-                 " front %" PRIaTXN,
-                 IS_BRANCH(mp) ? "branch" : "leaf", mp->mp_pgno, mp->mp_txnid,
-                 mc->mc_txn->mt_txnid, mc->mc_txn->mt_front);
-      rc = MDBX_PROBLEM;
-      goto fail;
-    }
-
-    mdbx_debug("clone db %d page %" PRIaPGNO, DDBI(mc), mp->mp_pgno);
-    mdbx_tassert(txn, txn->tw.dirtylist->length <=
-                          MDBX_PGL_LIMIT + MDBX_PNL_GRANULATE);
-    /* No - copy it */
-    np = mdbx_page_malloc(txn, 1);
-    if (unlikely(!np)) {
-      rc = MDBX_ENOMEM;
-      goto fail;
-    }
-    mdbx_page_copy(np, mp, txn->mt_env->me_psize);
-
-    /* insert a clone of parent's dirty page, so don't touch dirtyroom */
-    rc = mdbx_page_dirty(txn, np, 1);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-
-#if MDBX_ENABLE_PGOP_STAT
-    txn->mt_env->me_lck->mti_pgop_stat.clone.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  }
-
-done:
-  /* Adjust cursors pointing to mp */
-  mc->mc_pg[mc->mc_top] = np;
-  MDBX_cursor *m2 = txn->mt_cursors[mc->mc_dbi];
-  if (mc->mc_flags & C_SUB) {
-    for (; m2; m2 = m2->mc_next) {
-      MDBX_cursor *m3 = &m2->mc_xcursor->mx_cursor;
-      if (m3->mc_snum < mc->mc_snum)
-        continue;
-      if (m3->mc_pg[mc->mc_top] == mp)
-        m3->mc_pg[mc->mc_top] = np;
-    }
-  } else {
-    for (; m2; m2 = m2->mc_next) {
-      if (m2->mc_snum < mc->mc_snum)
-        continue;
-      if (m2 == mc)
-        continue;
-      if (m2->mc_pg[mc->mc_top] == mp) {
-        m2->mc_pg[mc->mc_top] = np;
-        if (XCURSOR_INITED(m2) && IS_LEAF(np))
-          XCURSOR_REFRESH(m2, np, m2->mc_ki[mc->mc_top]);
-      }
-    }
-  }
-  return MDBX_SUCCESS;
-
-fail:
-  txn->mt_flags |= MDBX_TXN_ERROR;
-  return rc;
-}
-
-__cold static int mdbx_env_sync_internal(MDBX_env *env, bool force,
-                                         bool nonblock) {
-  bool locked = false;
-  int rc = MDBX_RESULT_TRUE /* means "nothing to sync" */;
-
-retry:;
-  unsigned flags = env->me_flags & ~(MDBX_NOMETASYNC | MDBX_SHRINK_ALLOWED);
-  if (unlikely((flags & (MDBX_RDONLY | MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE)) !=
-               MDBX_ENV_ACTIVE)) {
-    rc = MDBX_EACCESS;
-    if (!(flags & MDBX_ENV_ACTIVE))
-      rc = MDBX_EPERM;
-    if (flags & MDBX_FATAL_ERROR)
-      rc = MDBX_PANIC;
-    goto bailout;
-  }
-
-  const pgno_t unsynced_pages =
-      atomic_load32(&env->me_lck->mti_unsynced_pages, mo_Relaxed);
-  volatile const MDBX_meta *head = meta_prefer_last(env);
-  const txnid_t head_txnid = meta_txnid(env, head);
-  const uint32_t synched_meta_txnid_u32 =
-      atomic_load32(&env->me_lck->mti_meta_sync_txnid, mo_Relaxed);
-  if (unsynced_pages == 0 && synched_meta_txnid_u32 == (uint32_t)head_txnid &&
-      META_IS_STEADY(head))
-    goto bailout;
-
-  const pgno_t autosync_threshold =
-      atomic_load32(&env->me_lck->mti_autosync_threshold, mo_Relaxed);
-  const uint64_t autosync_period =
-      atomic_load64(&env->me_lck->mti_autosync_period, mo_Relaxed);
-  if (force || (autosync_threshold && unsynced_pages >= autosync_threshold) ||
-      (autosync_period &&
-       mdbx_osal_monotime() -
-               atomic_load64(&env->me_lck->mti_sync_timestamp, mo_Relaxed) >=
-           autosync_period))
-    flags &= MDBX_WRITEMAP /* clear flags for full steady sync */;
-
-  const bool inside_txn = (env->me_txn0->mt_owner == mdbx_thread_self());
-  if (!inside_txn) {
-    if (!locked) {
-      int err;
-      unsigned wops = 0;
-      /* pre-sync to avoid latency for writer */
-      if (unsynced_pages > /* FIXME: define threshold */ 16 &&
-          (flags & MDBX_SAFE_NOSYNC) == 0) {
-        mdbx_assert(env, ((flags ^ env->me_flags) & MDBX_WRITEMAP) == 0);
-        if (flags & MDBX_WRITEMAP) {
-          /* Acquire guard to avoid collision with remap */
-#if defined(_WIN32) || defined(_WIN64)
-          mdbx_srwlock_AcquireShared(&env->me_remap_guard);
-#else
-          err = mdbx_fastmutex_acquire(&env->me_remap_guard);
-          if (unlikely(err != MDBX_SUCCESS))
-            return err;
-#endif
-          const size_t usedbytes = pgno_align2os_bytes(env, head->mm_geo.next);
-          err = mdbx_msync(&env->me_dxb_mmap, 0, usedbytes, MDBX_SYNC_DATA);
-#if defined(_WIN32) || defined(_WIN64)
-          mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
-#else
-          int unlock_err = mdbx_fastmutex_release(&env->me_remap_guard);
-          if (unlikely(unlock_err != MDBX_SUCCESS) && err == MDBX_SUCCESS)
-            err = unlock_err;
-#endif
-        } else
-          err = mdbx_fsync(env->me_lazy_fd, MDBX_SYNC_DATA);
-
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-
-        /* pre-sync done */
-        wops = 1;
-        rc = MDBX_SUCCESS /* means "some data was synced" */;
-      }
-
-      err = mdbx_txn_lock(env, nonblock);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-
-      locked = true;
-#if MDBX_ENABLE_PGOP_STAT
-      env->me_lck->mti_pgop_stat.wops.weak += wops;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-      goto retry;
-    }
-    env->me_txn0->mt_txnid = head_txnid;
-    mdbx_assert(env, head_txnid == meta_txnid(env, head));
-    mdbx_assert(env, head_txnid == mdbx_recent_committed_txnid(env));
-    mdbx_find_oldest(env->me_txn0);
-    flags |= MDBX_SHRINK_ALLOWED;
-  }
-
-  mdbx_assert(env, inside_txn || locked);
-  mdbx_assert(env, !inside_txn || (flags & MDBX_SHRINK_ALLOWED) == 0);
-
-  if (!META_IS_STEADY(head) ||
-      ((flags & MDBX_SAFE_NOSYNC) == 0 && unsynced_pages)) {
-    mdbx_debug("meta-head %" PRIaPGNO ", %s, sync_pending %" PRIaPGNO,
-               data_page((const void *)head)->mp_pgno, mdbx_durable_str(head),
-               unsynced_pages);
-    MDBX_meta meta = *head;
-    rc = mdbx_sync_locked(env, flags, &meta);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-  }
-
-  /* LY: sync meta-pages if MDBX_NOMETASYNC enabled
-   *     and someone was not synced above. */
-  if (atomic_load32(&env->me_lck->mti_meta_sync_txnid, mo_Relaxed) !=
-      (uint32_t)head_txnid) {
-#if MDBX_ENABLE_PGOP_STAT
-    env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    rc = (flags & MDBX_WRITEMAP)
-             ? mdbx_msync(&env->me_dxb_mmap, 0,
-                          pgno_align2os_bytes(env, NUM_METAS),
-                          MDBX_SYNC_DATA | MDBX_SYNC_IODQ)
-             : mdbx_fsync(env->me_lazy_fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-    if (likely(rc == MDBX_SUCCESS))
-      atomic_store32(&env->me_lck->mti_meta_sync_txnid, (uint32_t)head_txnid,
-                     mo_Relaxed);
-  }
-
-bailout:
-  if (locked)
-    mdbx_txn_unlock(env);
-  return rc;
-}
-
-static __inline int check_env(const MDBX_env *env, const bool wanna_active) {
-  if (unlikely(!env))
-    return MDBX_EINVAL;
-
-  if (unlikely(env->me_signature.weak != MDBX_ME_SIGNATURE))
-    return MDBX_EBADSIGN;
-
-#if MDBX_ENV_CHECKPID
-  if (unlikely(env->me_pid != mdbx_getpid())) {
-    ((MDBX_env *)env)->me_flags |= MDBX_FATAL_ERROR;
-    return MDBX_PANIC;
-  }
-#endif /* MDBX_ENV_CHECKPID */
-
-  if (unlikely(env->me_flags & MDBX_FATAL_ERROR))
-    return MDBX_PANIC;
-
-  if (wanna_active) {
-    if (unlikely((env->me_flags & MDBX_ENV_ACTIVE) == 0))
-      return MDBX_EPERM;
-    mdbx_assert(env, env->me_map != nullptr);
-  }
-
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_env_sync_internal(env, force, nonblock);
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold int mdbx_env_sync(MDBX_env *env) { return __inline_mdbx_env_sync(env); }
-
-__cold int mdbx_env_sync_poll(MDBX_env *env) {
-  return __inline_mdbx_env_sync_poll(env);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-/* Back up parent txn's cursors, then grab the originals for tracking */
-static int mdbx_cursor_shadow(MDBX_txn *parent, MDBX_txn *nested) {
-  for (int i = parent->mt_numdbs; --i >= 0;) {
-    nested->mt_cursors[i] = NULL;
-    MDBX_cursor *mc = parent->mt_cursors[i];
-    if (mc != NULL) {
-      size_t size = mc->mc_xcursor ? sizeof(MDBX_cursor) + sizeof(MDBX_xcursor)
-                                   : sizeof(MDBX_cursor);
-      for (MDBX_cursor *bk; mc; mc = bk->mc_next) {
-        bk = mc;
-        if (mc->mc_signature != MDBX_MC_LIVE)
-          continue;
-        bk = mdbx_malloc(size);
-        if (unlikely(!bk))
-          return MDBX_ENOMEM;
-#if MDBX_DEBUG
-        memset(bk, 0xCD, size);
-        VALGRIND_MAKE_MEM_UNDEFINED(bk, size);
-#endif /* MDBX_DEBUG */
-        *bk = *mc;
-        mc->mc_backup = bk;
-        /* Kill pointers into src to reduce abuse: The
-         * user may not use mc until dst ends. But we need a valid
-         * txn pointer here for cursor fixups to keep working. */
-        mc->mc_txn = nested;
-        mc->mc_db = &nested->mt_dbs[i];
-        mc->mc_dbistate = &nested->mt_dbistate[i];
-        MDBX_xcursor *mx = mc->mc_xcursor;
-        if (mx != NULL) {
-          *(MDBX_xcursor *)(bk + 1) = *mx;
-          mx->mx_cursor.mc_txn = nested;
-        }
-        mc->mc_next = nested->mt_cursors[i];
-        nested->mt_cursors[i] = mc;
-      }
-    }
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Close this txn's cursors, give parent txn's cursors back to parent.
- *
- * [in] txn     the transaction handle.
- * [in] merge   true to keep changes to parent cursors, false to revert.
- *
- * Returns 0 on success, non-zero on failure. */
-static void mdbx_cursors_eot(MDBX_txn *txn, const bool merge) {
-  for (int i = txn->mt_numdbs; --i >= 0;) {
-    MDBX_cursor *next, *mc = txn->mt_cursors[i];
-    if (!mc)
-      continue;
-    txn->mt_cursors[i] = NULL;
-    do {
-      const unsigned stage = mc->mc_signature;
-      MDBX_cursor *bk = mc->mc_backup;
-      next = mc->mc_next;
-      mdbx_ensure(txn->mt_env,
-                  stage == MDBX_MC_LIVE || (stage == MDBX_MC_WAIT4EOT && bk));
-      mdbx_cassert(mc, mc->mc_dbi == (unsigned)i);
-      if (bk) {
-        MDBX_xcursor *mx = mc->mc_xcursor;
-        mdbx_cassert(mc, mx == bk->mc_xcursor);
-        mdbx_tassert(txn, txn->mt_parent != NULL);
-        mdbx_ensure(txn->mt_env, bk->mc_signature == MDBX_MC_LIVE);
-        if (stage == MDBX_MC_WAIT4EOT /* Cursor was closed by user */)
-          mc->mc_signature = stage /* Promote closed state to parent txn */;
-        else if (merge) {
-          /* Restore pointers to parent txn */
-          mc->mc_next = bk->mc_next;
-          mc->mc_backup = bk->mc_backup;
-          mc->mc_txn = bk->mc_txn;
-          mc->mc_db = bk->mc_db;
-          mc->mc_dbistate = bk->mc_dbistate;
-          if (mx) {
-            if (mx != bk->mc_xcursor) {
-              *bk->mc_xcursor = *mx;
-              mx = bk->mc_xcursor;
-            }
-            mx->mx_cursor.mc_txn = bk->mc_txn;
-          }
-        } else {
-          /* Restore from backup, i.e. rollback/abort nested txn */
-          *mc = *bk;
-          if (mx)
-            *mx = *(MDBX_xcursor *)(bk + 1);
-        }
-        bk->mc_signature = 0;
-        mdbx_free(bk);
-      } else {
-        mdbx_ensure(txn->mt_env, stage == MDBX_MC_LIVE);
-        mc->mc_signature = MDBX_MC_READY4CLOSE /* Cursor may be reused */;
-        mc->mc_flags = 0 /* reset C_UNTRACK */;
-      }
-    } while ((mc = next) != NULL);
-  }
-}
-
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-/* Find largest mvcc-snapshot still referenced by this process. */
-static pgno_t mdbx_find_largest_this(MDBX_env *env, pgno_t largest) {
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (likely(lck != NULL /* exclusive mode */)) {
-    const unsigned snap_nreaders =
-        atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-    for (unsigned i = 0; i < snap_nreaders; ++i) {
-    retry:
-      if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease) ==
-          env->me_pid) {
-        /* mdbx_jitter4testing(true); */
-        const pgno_t snap_pages = atomic_load32(
-            &lck->mti_readers[i].mr_snapshot_pages_used, mo_Relaxed);
-        const txnid_t snap_txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
-        if (unlikely(
-                snap_pages !=
-                    atomic_load32(&lck->mti_readers[i].mr_snapshot_pages_used,
-                                  mo_AcquireRelease) ||
-                snap_txnid != safe64_read(&lck->mti_readers[i].mr_txnid)))
-          goto retry;
-        if (largest < snap_pages &&
-            atomic_load64(&lck->mti_oldest_reader, mo_AcquireRelease) <=
-                /* ignore pending updates */ snap_txnid &&
-            snap_txnid <= MAX_TXNID)
-          largest = snap_pages;
-      }
-    }
-  }
-  return largest;
-}
-
-static void mdbx_txn_valgrind(MDBX_env *env, MDBX_txn *txn) {
-#if !defined(__SANITIZE_ADDRESS__)
-  if (!RUNNING_ON_VALGRIND)
-    return;
-#endif
-
-  if (txn) { /* transaction start */
-    if (env->me_poison_edge < txn->mt_next_pgno)
-      env->me_poison_edge = txn->mt_next_pgno;
-    VALGRIND_MAKE_MEM_DEFINED(env->me_map, pgno2bytes(env, txn->mt_next_pgno));
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(env->me_map,
-                                     pgno2bytes(env, txn->mt_next_pgno));
-    /* don't touch more, it should be already poisoned */
-  } else { /* transaction end */
-    bool should_unlock = false;
-    pgno_t last = MAX_PAGENO + 1;
-    if (env->me_txn0 && env->me_txn0->mt_owner == mdbx_thread_self()) {
-      /* inside write-txn */
-      const MDBX_meta *head = constmeta_prefer_last(env);
-      last = head->mm_geo.next;
-    } else if (env->me_flags & MDBX_RDONLY) {
-      /* read-only mode, no write-txn, no wlock mutex */
-      last = NUM_METAS;
-    } else if (mdbx_txn_lock(env, true) == MDBX_SUCCESS) {
-      /* no write-txn */
-      last = NUM_METAS;
-      should_unlock = true;
-    } else {
-      /* write txn is running, therefore shouldn't poison any memory range */
-      return;
-    }
-
-    last = mdbx_find_largest_this(env, last);
-    const pgno_t edge = env->me_poison_edge;
-    if (edge > last) {
-      mdbx_assert(env, last >= NUM_METAS);
-      env->me_poison_edge = last;
-      VALGRIND_MAKE_MEM_NOACCESS(env->me_map + pgno2bytes(env, last),
-                                 pgno2bytes(env, edge - last));
-      MDBX_ASAN_POISON_MEMORY_REGION(env->me_map + pgno2bytes(env, last),
-                                     pgno2bytes(env, edge - last));
-    }
-    if (should_unlock)
-      mdbx_txn_unlock(env);
-  }
-}
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-typedef struct {
-  int err;
-  MDBX_reader *rslot;
-} bind_rslot_result;
-
-static bind_rslot_result bind_rslot(MDBX_env *env, const uintptr_t tid) {
-  mdbx_assert(env, env->me_lck_mmap.lck);
-  mdbx_assert(env, env->me_lck->mti_magic_and_version == MDBX_LOCK_MAGIC);
-  mdbx_assert(env, env->me_lck->mti_os_and_format == MDBX_LOCK_FORMAT);
-
-  bind_rslot_result result = {mdbx_rdt_lock(env), nullptr};
-  if (unlikely(MDBX_IS_ERROR(result.err)))
-    return result;
-  if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) {
-    mdbx_rdt_unlock(env);
-    result.err = MDBX_PANIC;
-    return result;
-  }
-  if (unlikely(!env->me_map)) {
-    mdbx_rdt_unlock(env);
-    result.err = MDBX_EPERM;
-    return result;
-  }
-
-  if (unlikely(env->me_live_reader != env->me_pid)) {
-    result.err = mdbx_rpid_set(env);
-    if (unlikely(result.err != MDBX_SUCCESS)) {
-      mdbx_rdt_unlock(env);
-      return result;
-    }
-    env->me_live_reader = env->me_pid;
-  }
-
-  result.err = MDBX_SUCCESS;
-  unsigned slot, nreaders;
-  while (1) {
-    nreaders = atomic_load32(&env->me_lck->mti_numreaders, mo_Relaxed);
-    for (slot = 0; slot < nreaders; slot++)
-      if (atomic_load32(&env->me_lck->mti_readers[slot].mr_pid, mo_Relaxed) ==
-          0)
-        break;
-
-    if (likely(slot < env->me_maxreaders))
-      break;
-
-    result.err = mdbx_cleanup_dead_readers(env, true, NULL);
-    if (result.err != MDBX_RESULT_TRUE) {
-      mdbx_rdt_unlock(env);
-      result.err =
-          (result.err == MDBX_SUCCESS) ? MDBX_READERS_FULL : result.err;
-      return result;
-    }
-  }
-
-  result.rslot = &env->me_lck->mti_readers[slot];
-  /* Claim the reader slot, carefully since other code
-   * uses the reader table un-mutexed: First reset the
-   * slot, next publish it in lck->mti_numreaders.  After
-   * that, it is safe for mdbx_env_close() to touch it.
-   * When it will be closed, we can finally claim it. */
-  atomic_store32(&result.rslot->mr_pid, 0, mo_Relaxed);
-  safe64_reset(&result.rslot->mr_txnid, true);
-  if (slot == nreaders)
-    atomic_store32(&env->me_lck->mti_numreaders, ++nreaders, mo_Relaxed);
-  atomic_store64(&result.rslot->mr_tid, (env->me_flags & MDBX_NOTLS) ? 0 : tid,
-                 mo_Relaxed);
-  atomic_store32(&result.rslot->mr_pid, env->me_pid, mo_Relaxed);
-  mdbx_rdt_unlock(env);
-
-  if (likely(env->me_flags & MDBX_ENV_TXKEY)) {
-    mdbx_assert(env, env->me_live_reader == env->me_pid);
-    thread_rthc_set(env->me_txkey, result.rslot);
-  }
-  return result;
-}
-
-__cold int mdbx_thread_register(const MDBX_env *env) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!env->me_lck_mmap.lck))
-    return (env->me_flags & MDBX_EXCLUSIVE) ? MDBX_EINVAL : MDBX_EPERM;
-
-  if (unlikely((env->me_flags & MDBX_ENV_TXKEY) == 0)) {
-    mdbx_assert(env, !env->me_lck_mmap.lck || (env->me_flags & MDBX_NOTLS));
-    return MDBX_EINVAL /* MDBX_NOTLS mode */;
-  }
-
-  mdbx_assert(env, (env->me_flags & (MDBX_NOTLS | MDBX_ENV_TXKEY |
-                                     MDBX_EXCLUSIVE)) == MDBX_ENV_TXKEY);
-  MDBX_reader *r = thread_rthc_get(env->me_txkey);
-  if (unlikely(r != NULL)) {
-    mdbx_assert(env, r->mr_pid.weak == env->me_pid);
-    mdbx_assert(env, r->mr_tid.weak == mdbx_thread_self());
-    if (unlikely(r->mr_pid.weak != env->me_pid))
-      return MDBX_BAD_RSLOT;
-    return MDBX_RESULT_TRUE /* already registered */;
-  }
-
-  const uintptr_t tid = mdbx_thread_self();
-  if (env->me_txn0 && unlikely(env->me_txn0->mt_owner == tid))
-    return MDBX_TXN_OVERLAPPING;
-  return bind_rslot((MDBX_env *)env, tid).err;
-}
-
-__cold int mdbx_thread_unregister(const MDBX_env *env) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!env->me_lck_mmap.lck))
-    return MDBX_RESULT_TRUE;
-
-  if (unlikely((env->me_flags & MDBX_ENV_TXKEY) == 0)) {
-    mdbx_assert(env, !env->me_lck_mmap.lck || (env->me_flags & MDBX_NOTLS));
-    return MDBX_RESULT_TRUE /* MDBX_NOTLS mode */;
-  }
-
-  mdbx_assert(env, (env->me_flags & (MDBX_NOTLS | MDBX_ENV_TXKEY |
-                                     MDBX_EXCLUSIVE)) == MDBX_ENV_TXKEY);
-  MDBX_reader *r = thread_rthc_get(env->me_txkey);
-  if (unlikely(r == NULL))
-    return MDBX_RESULT_TRUE /* not registered */;
-
-  mdbx_assert(env, r->mr_pid.weak == env->me_pid);
-  mdbx_assert(env, r->mr_tid.weak == mdbx_thread_self());
-  if (unlikely(r->mr_pid.weak != env->me_pid ||
-               r->mr_tid.weak != mdbx_thread_self()))
-    return MDBX_BAD_RSLOT;
-
-  if (unlikely(r->mr_txnid.weak < SAFE64_INVALID_THRESHOLD))
-    return MDBX_BUSY /* transaction is still active */;
-
-  atomic_store32(&r->mr_pid, 0, mo_Relaxed);
-  atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
-                 mo_AcquireRelease);
-  thread_rthc_set(env->me_txkey, nullptr);
-  return MDBX_SUCCESS;
-}
-
-/* check against todo4recovery://erased_by_github/libmdbx/issues/269 */
-static bool meta_checktxnid(const MDBX_env *env, const MDBX_meta *meta,
-                            bool report) {
-  const txnid_t meta_txnid = constmeta_txnid(env, meta);
-  const txnid_t freedb_mod_txnid = meta->mm_dbs[FREE_DBI].md_mod_txnid;
-  const txnid_t maindb_mod_txnid = meta->mm_dbs[MAIN_DBI].md_mod_txnid;
-
-  const pgno_t freedb_root_pgno = meta->mm_dbs[FREE_DBI].md_root;
-  const MDBX_page *freedb_root = (env->me_map && freedb_root_pgno != P_INVALID)
-                                     ? pgno2page(env, freedb_root_pgno)
-                                     : nullptr;
-
-  const pgno_t maindb_root_pgno = meta->mm_dbs[MAIN_DBI].md_root;
-  const MDBX_page *maindb_root = (env->me_map && maindb_root_pgno != P_INVALID)
-                                     ? pgno2page(env, maindb_root_pgno)
-                                     : nullptr;
-
-  const uint64_t magic_and_version =
-      unaligned_peek_u64(4, &meta->mm_magic_and_version);
-  bool ok = true;
-  if (unlikely(meta_txnid < freedb_mod_txnid ||
-               (!freedb_mod_txnid && freedb_root &&
-                likely(magic_and_version == MDBX_DATA_MAGIC)))) {
-    if (report)
-      mdbx_warning(
-          "catch invalid %sdb_mod_txnid %" PRIaTXN " for meta_txnid %" PRIaTXN
-          " %s",
-          "free", freedb_mod_txnid, meta_txnid,
-          "(workaround for incoherent flaw of unified page/buffer cache)");
-    ok = false;
-  }
-  if (unlikely(meta_txnid < maindb_mod_txnid ||
-               (!maindb_mod_txnid && maindb_root &&
-                likely(magic_and_version == MDBX_DATA_MAGIC)))) {
-    if (report)
-      mdbx_warning(
-          "catch invalid %sdb_mod_txnid %" PRIaTXN " for meta_txnid %" PRIaTXN
-          " %s",
-          "main", maindb_mod_txnid, meta_txnid,
-          "(workaround for incoherent flaw of unified page/buffer cache)");
-    ok = false;
-  }
-  if (likely(freedb_root && freedb_mod_txnid)) {
-    VALGRIND_MAKE_MEM_DEFINED(freedb_root, sizeof(freedb_root->mp_txnid));
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(freedb_root,
-                                     sizeof(freedb_root->mp_txnid));
-    const txnid_t root_txnid = freedb_root->mp_txnid;
-    if (unlikely(root_txnid != freedb_mod_txnid)) {
-      if (report)
-        mdbx_warning(
-            "catch invalid root_page_txnid %" PRIaTXN
-            " for %sdb_mod_txnid %" PRIaTXN " %s",
-            root_txnid, "free", maindb_mod_txnid,
-            "(workaround for incoherent flaw of unified page/buffer cache)");
-      ok = false;
-    }
-  }
-  if (likely(maindb_root && maindb_mod_txnid)) {
-    VALGRIND_MAKE_MEM_DEFINED(maindb_root, sizeof(maindb_root->mp_txnid));
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(maindb_root,
-                                     sizeof(maindb_root->mp_txnid));
-    const txnid_t root_txnid = maindb_root->mp_txnid;
-    if (unlikely(root_txnid != maindb_mod_txnid)) {
-      if (report)
-        mdbx_warning(
-            "catch invalid root_page_txnid %" PRIaTXN
-            " for %sdb_mod_txnid %" PRIaTXN " %s",
-            root_txnid, "main", maindb_mod_txnid,
-            "(workaround for incoherent flaw of unified page/buffer cache)");
-      ok = false;
-    }
-  }
-  return ok;
-}
-
-/* check with timeout as the workaround
- * for todo4recovery://erased_by_github/libmdbx/issues/269 */
-static int meta_waittxnid(const MDBX_env *env, const MDBX_meta *meta,
-                          uint64_t *timestamp) {
-  if (likely(meta_checktxnid(env, (const MDBX_meta *)meta, !*timestamp)))
-    return MDBX_SUCCESS;
-
-  if (!*timestamp)
-    *timestamp = mdbx_osal_monotime();
-  else if (unlikely(mdbx_osal_monotime() - *timestamp > 65536 / 10)) {
-    mdbx_error("bailout waiting for valid snapshot %s",
-               "(workaround for incoherent flaw of unified page/buffer cache)");
-    return MDBX_CORRUPTED;
-  }
-
-#if defined(_WIN32) || defined(_WIN64)
-  SwitchToThread();
-#elif defined(__linux__) || defined(__gnu_linux__) || defined(_UNIX03_SOURCE)
-  sched_yield();
-#elif (defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 1)) || defined(_OPEN_THREADS)
-  pthread_yield();
-#else
-  usleep(42);
-#endif
-  return MDBX_RESULT_TRUE;
-}
-
-/* Common code for mdbx_txn_begin() and mdbx_txn_renew(). */
-static int mdbx_txn_renew0(MDBX_txn *txn, const unsigned flags) {
-  MDBX_env *env = txn->mt_env;
-  int rc;
-
-#if MDBX_ENV_CHECKPID
-  if (unlikely(env->me_pid != mdbx_getpid())) {
-    env->me_flags |= MDBX_FATAL_ERROR;
-    return MDBX_PANIC;
-  }
-#endif /* MDBX_ENV_CHECKPID */
-
-  STATIC_ASSERT(sizeof(MDBX_reader) == 32);
-#if MDBX_LOCKING > 0
-  STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_wlock) % MDBX_CACHELINE_SIZE == 0);
-  STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_rlock) % MDBX_CACHELINE_SIZE == 0);
-#else
-  STATIC_ASSERT(
-      offsetof(MDBX_lockinfo, mti_oldest_reader) % MDBX_CACHELINE_SIZE == 0);
-  STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_numreaders) % MDBX_CACHELINE_SIZE ==
-                0);
-#endif /* MDBX_LOCKING */
-  STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_readers) % MDBX_CACHELINE_SIZE ==
-                0);
-
-  const uintptr_t tid = mdbx_thread_self();
-  if (flags & MDBX_TXN_RDONLY) {
-    mdbx_assert(env, (flags & ~(MDBX_TXN_RO_BEGIN_FLAGS | MDBX_WRITEMAP)) == 0);
-    txn->mt_flags =
-        MDBX_TXN_RDONLY | (env->me_flags & (MDBX_NOTLS | MDBX_WRITEMAP));
-    MDBX_reader *r = txn->to.reader;
-    STATIC_ASSERT(sizeof(uintptr_t) <= sizeof(r->mr_tid));
-    if (likely(env->me_flags & MDBX_ENV_TXKEY)) {
-      mdbx_assert(env, !(env->me_flags & MDBX_NOTLS));
-      r = thread_rthc_get(env->me_txkey);
-      if (likely(r)) {
-        if (unlikely(!r->mr_pid.weak) &&
-            (mdbx_runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN)) {
-          thread_rthc_set(env->me_txkey, nullptr);
-          r = nullptr;
-        } else {
-          mdbx_assert(env, r->mr_pid.weak == env->me_pid);
-          mdbx_assert(env, r->mr_tid.weak == mdbx_thread_self());
-        }
-      }
-    } else {
-      mdbx_assert(env, !env->me_lck_mmap.lck || (env->me_flags & MDBX_NOTLS));
-    }
-
-    if (likely(r)) {
-      if (unlikely(r->mr_pid.weak != env->me_pid ||
-                   r->mr_txnid.weak < SAFE64_INVALID_THRESHOLD))
-        return MDBX_BAD_RSLOT;
-    } else if (env->me_lck_mmap.lck) {
-      bind_rslot_result brs = bind_rslot(env, tid);
-      if (unlikely(brs.err != MDBX_SUCCESS))
-        return brs.err;
-      r = brs.rslot;
-    }
-    txn->to.reader = r;
-    if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY)) {
-      mdbx_assert(env, txn->mt_txnid == 0);
-      mdbx_assert(env, txn->mt_owner == 0);
-      mdbx_assert(env, txn->mt_numdbs == 0);
-      if (likely(r)) {
-        mdbx_assert(env, r->mr_snapshot_pages_used.weak == 0);
-        mdbx_assert(env, r->mr_txnid.weak >= SAFE64_INVALID_THRESHOLD);
-        atomic_store32(&r->mr_snapshot_pages_used, 0, mo_Relaxed);
-      }
-      txn->mt_flags = MDBX_TXN_RDONLY | MDBX_TXN_FINISHED;
-      return MDBX_SUCCESS;
-    }
-
-    /* Seek & fetch the last meta */
-    if (likely(/* not recovery mode */ env->me_stuck_meta < 0)) {
-      uint64_t timestamp = 0;
-      while (1) {
-        volatile const MDBX_meta *const meta = meta_prefer_last(env);
-        mdbx_jitter4testing(false);
-        const txnid_t snap = meta_txnid(env, meta);
-        mdbx_jitter4testing(false);
-        if (likely(r)) {
-          safe64_reset(&r->mr_txnid, false);
-          atomic_store32(&r->mr_snapshot_pages_used, meta->mm_geo.next,
-                         mo_Relaxed);
-          atomic_store64(&r->mr_snapshot_pages_retired,
-                         unaligned_peek_u64_volatile(4, meta->mm_pages_retired),
-                         mo_Relaxed);
-          safe64_write(&r->mr_txnid, snap);
-          mdbx_jitter4testing(false);
-          mdbx_assert(env, r->mr_pid.weak == mdbx_getpid());
-          mdbx_assert(
-              env, r->mr_tid.weak ==
-                       ((env->me_flags & MDBX_NOTLS) ? 0 : mdbx_thread_self()));
-          mdbx_assert(env, r->mr_txnid.weak == snap);
-          atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
-                         mo_AcquireRelease);
-        } else {
-          /* exclusive mode without lck */
-        }
-        mdbx_jitter4testing(true);
-
-        /* Snap the state from current meta-head */
-        txn->mt_txnid = snap;
-        txn->mt_geo = meta->mm_geo;
-        STATIC_ASSERT(CORE_DBS == 2);
-        txn->mt_dbs[0] = meta->mm_dbs[0];
-        txn->mt_dbs[1] = meta->mm_dbs[1];
-        txn->mt_canary = meta->mm_canary;
-
-        /* LY: Retry on a race, ITS#7970.
-         * The barrier is not needed here since C11-atomics are used,
-         * but it is reasonable paranoia to avoid compiler misoptimization
-         * and makes clarity for code readers. */
-        mdbx_compiler_barrier();
-        if (likely(meta == meta_prefer_last(env) &&
-                   snap == meta_txnid(env, meta) &&
-                   snap >= atomic_load64(&env->me_lck->mti_oldest_reader,
-                                         mo_AcquireRelease))) {
-          /* workaround for todo4recovery://erased_by_github/libmdbx/issues/269
-           */
-          rc = meta_waittxnid(env, (const MDBX_meta *)meta, &timestamp);
-          mdbx_jitter4testing(false);
-          if (likely(rc == MDBX_SUCCESS))
-            break;
-          if (likely(rc == MDBX_RESULT_TRUE))
-            continue;
-          goto bailout;
-        }
-      }
-    } else {
-      /* r/o recovery mode */
-      MDBX_meta *const meta = METAPAGE(env, env->me_stuck_meta);
-      txn->mt_txnid = constmeta_txnid(env, meta);
-      txn->mt_geo = meta->mm_geo;
-      memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDBX_db));
-      txn->mt_canary = meta->mm_canary;
-      if (likely(r)) {
-        atomic_store32(&r->mr_snapshot_pages_used, meta->mm_geo.next,
-                       mo_Relaxed);
-        atomic_store64(&r->mr_snapshot_pages_retired,
-                       unaligned_peek_u64(4, meta->mm_pages_retired),
-                       mo_Relaxed);
-        atomic_store64(&r->mr_txnid, txn->mt_txnid, mo_Relaxed);
-        mdbx_jitter4testing(false);
-        mdbx_assert(env, r->mr_pid.weak == mdbx_getpid());
-        mdbx_assert(
-            env, r->mr_tid.weak ==
-                     ((env->me_flags & MDBX_NOTLS) ? 0 : mdbx_thread_self()));
-        mdbx_assert(env, r->mr_txnid.weak == txn->mt_txnid);
-        atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
-                       mo_Relaxed);
-      }
-    }
-
-    if (unlikely(txn->mt_txnid < MIN_TXNID || txn->mt_txnid > MAX_TXNID)) {
-      mdbx_error("%s", "environment corrupted by died writer, must shutdown!");
-      rc = MDBX_CORRUPTED;
-      goto bailout;
-    }
-    mdbx_assert(env, txn->mt_txnid >= env->me_lck->mti_oldest_reader.weak);
-    txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
-    mdbx_ensure(env, txn->mt_txnid >=
-                         /* paranoia is appropriate here */ env->me_lck
-                             ->mti_oldest_reader.weak);
-    txn->mt_numdbs = env->me_numdbs;
-  } else {
-    mdbx_assert(env, (flags & ~(MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_SPILLS |
-                                MDBX_WRITEMAP)) == 0);
-    if (unlikely(txn->mt_owner == tid ||
-                 /* not recovery mode */ env->me_stuck_meta >= 0))
-      return MDBX_BUSY;
-    MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-    if (lck && (env->me_flags & MDBX_NOTLS) == 0 &&
-        (mdbx_runtime_flags & MDBX_DBG_LEGACY_OVERLAP) == 0) {
-      const unsigned snap_nreaders =
-          atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-      for (unsigned i = 0; i < snap_nreaders; ++i) {
-        if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_Relaxed) ==
-                env->me_pid &&
-            unlikely(atomic_load64(&lck->mti_readers[i].mr_tid, mo_Relaxed) ==
-                     tid)) {
-          const txnid_t txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
-          if (txnid >= MIN_TXNID && txnid <= MAX_TXNID)
-            return MDBX_TXN_OVERLAPPING;
-        }
-      }
-    }
-
-    /* Not yet touching txn == env->me_txn0, it may be active */
-    mdbx_jitter4testing(false);
-    rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TXN_TRY));
-    if (unlikely(rc))
-      return rc;
-    if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) {
-      mdbx_txn_unlock(env);
-      return MDBX_PANIC;
-    }
-#if defined(_WIN32) || defined(_WIN64)
-    if (unlikely(!env->me_map)) {
-      mdbx_txn_unlock(env);
-      return MDBX_EPERM;
-    }
-#endif /* Windows */
-
-    mdbx_jitter4testing(false);
-    const MDBX_meta *meta = constmeta_prefer_last(env);
-    uint64_t timestamp = 0;
-    while (
-        "workaround for todo4recovery://erased_by_github/libmdbx/issues/269") {
-      rc = meta_waittxnid(env, (const MDBX_meta *)meta, &timestamp);
-      if (likely(rc == MDBX_SUCCESS))
-        break;
-      if (unlikely(rc != MDBX_RESULT_TRUE))
-        goto bailout;
-    }
-    mdbx_jitter4testing(false);
-    txn->mt_canary = meta->mm_canary;
-    const txnid_t snap = constmeta_txnid(env, meta);
-    txn->mt_txnid = safe64_txnid_next(snap);
-    if (unlikely(txn->mt_txnid > MAX_TXNID)) {
-      rc = MDBX_TXN_FULL;
-      mdbx_error("txnid overflow, raise %d", rc);
-      goto bailout;
-    }
-
-    txn->mt_flags = flags;
-    txn->mt_child = NULL;
-    txn->tw.loose_pages = NULL;
-    txn->tw.loose_count = 0;
-#if MDBX_ENABLE_REFUND
-    txn->tw.loose_refund_wl = 0;
-#endif /* MDBX_ENABLE_REFUND */
-    MDBX_PNL_SIZE(txn->tw.retired_pages) = 0;
-    txn->tw.spill_pages = NULL;
-    txn->tw.spill_least_removed = 0;
-    txn->tw.last_reclaimed = 0;
-    if (txn->tw.lifo_reclaimed)
-      MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) = 0;
-    env->me_txn = txn;
-    txn->mt_numdbs = env->me_numdbs;
-    memcpy(txn->mt_dbiseqs, env->me_dbiseqs, txn->mt_numdbs * sizeof(unsigned));
-    /* Copy the DB info and flags */
-    memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDBX_db));
-    /* Moved to here to avoid a data race in read TXNs */
-    txn->mt_geo = meta->mm_geo;
-
-    rc = mdbx_dpl_alloc(txn);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-    txn->tw.dirtyroom = txn->mt_env->me_options.dp_limit;
-    txn->tw.dirtylru = MDBX_DEBUG ? ~42u : 0;
-  }
-
-  /* Setup db info */
-  mdbx_compiler_barrier();
-  memset(txn->mt_cursors, 0, sizeof(MDBX_cursor *) * txn->mt_numdbs);
-  for (unsigned i = CORE_DBS; i < txn->mt_numdbs; i++) {
-    const unsigned db_flags = env->me_dbflags[i];
-    txn->mt_dbs[i].md_flags = db_flags & DB_PERSISTENT_FLAGS;
-    txn->mt_dbistate[i] =
-        (db_flags & DB_VALID) ? DBI_VALID | DBI_USRVALID | DBI_STALE : 0;
-  }
-  txn->mt_dbistate[MAIN_DBI] = DBI_VALID | DBI_USRVALID;
-  txn->mt_dbistate[FREE_DBI] = DBI_VALID;
-  txn->mt_front =
-      txn->mt_txnid + ((flags & (MDBX_WRITEMAP | MDBX_RDONLY)) == 0);
-
-  if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) {
-    mdbx_warning("%s", "environment had fatal error, must shutdown!");
-    rc = MDBX_PANIC;
-  } else {
-    const size_t size =
-        pgno2bytes(env, (txn->mt_flags & MDBX_TXN_RDONLY) ? txn->mt_next_pgno
-                                                          : txn->mt_end_pgno);
-    if (unlikely(size > env->me_dxb_mmap.limit)) {
-      if (txn->mt_geo.upper > MAX_PAGENO + 1 ||
-          bytes2pgno(env, pgno2bytes(env, txn->mt_geo.upper)) !=
-              txn->mt_geo.upper) {
-        rc = MDBX_UNABLE_EXTEND_MAPSIZE;
-        goto bailout;
-      }
-      rc = mdbx_mapresize(env, txn->mt_next_pgno, txn->mt_end_pgno,
-                          txn->mt_geo.upper,
-                          (txn->mt_flags & MDBX_TXN_RDONLY) ? true : false);
-      if (rc != MDBX_SUCCESS)
-        goto bailout;
-    }
-    if (txn->mt_flags & MDBX_TXN_RDONLY) {
-#if defined(_WIN32) || defined(_WIN64)
-      if (((size > env->me_dbgeo.lower && env->me_dbgeo.shrink) ||
-           (mdbx_RunningUnderWine() &&
-            /* under Wine acquisition of remap_guard is always required,
-             * since Wine don't support section extending,
-             * i.e. in both cases unmap+map are required. */
-            size < env->me_dbgeo.upper && env->me_dbgeo.grow)) &&
-          /* avoid recursive use SRW */ (txn->mt_flags & MDBX_NOTLS) == 0) {
-        txn->mt_flags |= MDBX_SHRINK_ALLOWED;
-        mdbx_srwlock_AcquireShared(&env->me_remap_guard);
-      }
-#endif /* Windows */
-    } else {
-      env->me_dxb_mmap.current = size;
-      env->me_dxb_mmap.filesize =
-          (env->me_dxb_mmap.filesize < size) ? size : env->me_dxb_mmap.filesize;
-    }
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-    mdbx_txn_valgrind(env, txn);
-#endif
-    txn->mt_owner = tid;
-    return MDBX_SUCCESS;
-  }
-bailout:
-  mdbx_tassert(txn, rc != MDBX_SUCCESS);
-  mdbx_txn_end(txn, MDBX_END_SLOT | MDBX_END_FAIL_BEGIN);
-  return rc;
-}
-
-static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) {
-  if (unlikely(!txn))
-    return MDBX_EINVAL;
-
-  if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
-    return MDBX_EBADSIGN;
-
-  if (unlikely(txn->mt_flags & bad_bits))
-    return MDBX_BAD_TXN;
-
-#if MDBX_TXN_CHECKOWNER
-  if ((txn->mt_flags & MDBX_NOTLS) == 0 &&
-      unlikely(txn->mt_owner != mdbx_thread_self()))
-    return txn->mt_owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN;
-#endif /* MDBX_TXN_CHECKOWNER */
-
-  if (unlikely(!txn->mt_env->me_map))
-    return MDBX_EPERM;
-
-  return MDBX_SUCCESS;
-}
-
-static __always_inline int check_txn_rw(const MDBX_txn *txn, int bad_bits) {
-  int err = check_txn(txn, bad_bits);
-  if (unlikely(err))
-    return err;
-
-  if (unlikely(F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
-    return MDBX_EACCESS;
-
-  return MDBX_SUCCESS;
-}
-
-int mdbx_txn_renew(MDBX_txn *txn) {
-  if (unlikely(!txn))
-    return MDBX_EINVAL;
-
-  if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
-    return MDBX_EBADSIGN;
-
-  if (unlikely((txn->mt_flags & MDBX_TXN_RDONLY) == 0))
-    return MDBX_EINVAL;
-
-  int rc;
-  if (unlikely(txn->mt_owner != 0 || !(txn->mt_flags & MDBX_TXN_FINISHED))) {
-    rc = mdbx_txn_reset(txn);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  rc = mdbx_txn_renew0(txn, MDBX_TXN_RDONLY);
-  if (rc == MDBX_SUCCESS) {
-    txn->mt_owner = mdbx_thread_self();
-    mdbx_debug("renew txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
-               "/%" PRIaPGNO,
-               txn->mt_txnid, (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w',
-               (void *)txn, (void *)txn->mt_env, txn->mt_dbs[MAIN_DBI].md_root,
-               txn->mt_dbs[FREE_DBI].md_root);
-  }
-  return rc;
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags,
-                   MDBX_txn **ret) {
-  return __inline_mdbx_txn_begin(env, parent, flags, ret);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx) {
-  int rc = check_txn(txn, MDBX_TXN_FINISHED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  txn->mt_userctx = ctx;
-  return MDBX_SUCCESS;
-}
-
-void *mdbx_txn_get_userctx(const MDBX_txn *txn) {
-  return check_txn(txn, MDBX_TXN_FINISHED) ? nullptr : txn->mt_userctx;
-}
-
-int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags,
-                      MDBX_txn **ret, void *context) {
-  MDBX_txn *txn;
-  unsigned size, tsize;
-
-  if (unlikely(!ret))
-    return MDBX_EINVAL;
-  *ret = NULL;
-
-  if (unlikely((flags & ~MDBX_TXN_RW_BEGIN_FLAGS) &&
-               (flags & ~MDBX_TXN_RO_BEGIN_FLAGS)))
-    return MDBX_EINVAL;
-
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(env->me_flags & MDBX_RDONLY &
-               ~flags)) /* write txn in RDONLY env */
-    return MDBX_EACCESS;
-
-  flags |= env->me_flags & MDBX_WRITEMAP;
-
-  if (parent) {
-    /* Nested transactions: Max 1 child, write txns only, no writemap */
-    rc = check_txn_rw(parent,
-                      MDBX_TXN_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-
-    if (env->me_options.spill_parent4child_denominator) {
-      /* Spill dirty-pages of parent to provide dirtyroom for child txn */
-      rc = mdbx_txn_spill(parent, nullptr,
-                          parent->tw.dirtylist->length /
-                              env->me_options.spill_parent4child_denominator);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-    }
-    mdbx_tassert(parent, mdbx_audit_ex(parent, 0, false) == 0);
-
-    flags |= parent->mt_flags & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_SPILLS);
-  } else if (flags & MDBX_TXN_RDONLY) {
-    if (env->me_txn0 &&
-        unlikely(env->me_txn0->mt_owner == mdbx_thread_self()) &&
-        (mdbx_runtime_flags & MDBX_DBG_LEGACY_OVERLAP) == 0)
-      return MDBX_TXN_OVERLAPPING;
-  } else {
-    /* Reuse preallocated write txn. However, do not touch it until
-     * mdbx_txn_renew0() succeeds, since it currently may be active. */
-    txn = env->me_txn0;
-    goto renew;
-  }
-
-  size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
-  size += tsize = sizeof(MDBX_txn);
-  if (unlikely((txn = mdbx_malloc(size)) == NULL)) {
-    mdbx_debug("calloc: %s", "failed");
-    return MDBX_ENOMEM;
-  }
-#if MDBX_DEBUG
-  memset(txn, 0xCD, size);
-  VALGRIND_MAKE_MEM_UNDEFINED(txn, size);
-#endif /* MDBX_DEBUG */
-  memset(txn, 0, tsize);
-  txn->mt_dbxs = env->me_dbxs; /* static */
-  txn->mt_dbs = (MDBX_db *)((char *)txn + tsize);
-  txn->mt_cursors = (MDBX_cursor **)(txn->mt_dbs + env->me_maxdbs);
-  txn->mt_dbistate = (uint8_t *)txn + size - env->me_maxdbs;
-  txn->mt_flags = flags;
-  txn->mt_env = env;
-
-  if (parent) {
-    mdbx_tassert(parent, mdbx_dirtylist_check(parent));
-    txn->mt_dbiseqs = parent->mt_dbiseqs;
-    txn->mt_geo = parent->mt_geo;
-    rc = mdbx_dpl_alloc(txn);
-    if (likely(rc == MDBX_SUCCESS)) {
-      const unsigned len =
-          MDBX_PNL_SIZE(parent->tw.reclaimed_pglist) + parent->tw.loose_count;
-      txn->tw.reclaimed_pglist =
-          mdbx_pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL);
-      if (unlikely(!txn->tw.reclaimed_pglist))
-        rc = MDBX_ENOMEM;
-    }
-    if (unlikely(rc != MDBX_SUCCESS)) {
-    nested_failed:
-      mdbx_pnl_free(txn->tw.reclaimed_pglist);
-      mdbx_dpl_free(txn);
-      mdbx_free(txn);
-      return rc;
-    }
-
-    /* Move loose pages to reclaimed list */
-    if (parent->tw.loose_count) {
-      do {
-        MDBX_page *lp = parent->tw.loose_pages;
-        const unsigned di = mdbx_dpl_exist(parent, lp->mp_pgno);
-        mdbx_tassert(parent, di && parent->tw.dirtylist->items[di].ptr == lp);
-        mdbx_tassert(parent, lp->mp_flags == P_LOOSE);
-        rc =
-            mdbx_pnl_insert_range(&parent->tw.reclaimed_pglist, lp->mp_pgno, 1);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto nested_failed;
-        parent->tw.loose_pages = lp->mp_next;
-        /* Remove from dirty list */
-        mdbx_page_wash(parent, di, lp, 1);
-      } while (parent->tw.loose_pages);
-      parent->tw.loose_count = 0;
-#if MDBX_ENABLE_REFUND
-      parent->tw.loose_refund_wl = 0;
-#endif /* MDBX_ENABLE_REFUND */
-      mdbx_tassert(parent, mdbx_dirtylist_check(parent));
-    }
-    txn->tw.dirtyroom = parent->tw.dirtyroom;
-    txn->tw.dirtylru = parent->tw.dirtylru;
-
-    mdbx_dpl_sort(parent);
-    if (parent->tw.spill_pages)
-      mdbx_spill_purge(parent);
-
-    mdbx_tassert(txn, MDBX_PNL_ALLOCLEN(txn->tw.reclaimed_pglist) >=
-                          MDBX_PNL_SIZE(parent->tw.reclaimed_pglist));
-    memcpy(txn->tw.reclaimed_pglist, parent->tw.reclaimed_pglist,
-           MDBX_PNL_SIZEOF(parent->tw.reclaimed_pglist));
-    mdbx_assert(env, mdbx_pnl_check4assert(
-                         txn->tw.reclaimed_pglist,
-                         (txn->mt_next_pgno /* LY: intentional assignment here,
-                                                   only for assertion */
-                          = parent->mt_next_pgno) -
-                             MDBX_ENABLE_REFUND));
-
-    txn->tw.last_reclaimed = parent->tw.last_reclaimed;
-    if (parent->tw.lifo_reclaimed) {
-      txn->tw.lifo_reclaimed = parent->tw.lifo_reclaimed;
-      parent->tw.lifo_reclaimed =
-          (void *)(intptr_t)MDBX_PNL_SIZE(parent->tw.lifo_reclaimed);
-    }
-
-    txn->tw.retired_pages = parent->tw.retired_pages;
-    parent->tw.retired_pages =
-        (void *)(intptr_t)MDBX_PNL_SIZE(parent->tw.retired_pages);
-
-    txn->mt_txnid = parent->mt_txnid;
-    txn->mt_front = parent->mt_front + 1;
-#if MDBX_ENABLE_REFUND
-    txn->tw.loose_refund_wl = 0;
-#endif /* MDBX_ENABLE_REFUND */
-    txn->mt_canary = parent->mt_canary;
-    parent->mt_flags |= MDBX_TXN_HAS_CHILD;
-    parent->mt_child = txn;
-    txn->mt_parent = parent;
-    txn->mt_numdbs = parent->mt_numdbs;
-    txn->mt_owner = parent->mt_owner;
-    memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDBX_db));
-    /* Copy parent's mt_dbistate, but clear DB_NEW */
-    for (unsigned i = 0; i < txn->mt_numdbs; i++)
-      txn->mt_dbistate[i] =
-          parent->mt_dbistate[i] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY);
-    mdbx_tassert(parent,
-                 parent->tw.dirtyroom + parent->tw.dirtylist->length ==
-                     (parent->mt_parent ? parent->mt_parent->tw.dirtyroom
-                                        : parent->mt_env->me_options.dp_limit));
-    mdbx_tassert(txn, txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                          (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                          : txn->mt_env->me_options.dp_limit));
-    env->me_txn = txn;
-    rc = mdbx_cursor_shadow(parent, txn);
-    if (mdbx_audit_enabled() && mdbx_assert_enabled()) {
-      txn->mt_signature = MDBX_MT_SIGNATURE;
-      mdbx_tassert(txn, mdbx_audit_ex(txn, 0, false) == 0);
-    }
-    if (unlikely(rc != MDBX_SUCCESS))
-      mdbx_txn_end(txn, MDBX_END_FAIL_BEGINCHILD);
-  } else { /* MDBX_TXN_RDONLY */
-    txn->mt_dbiseqs = env->me_dbiseqs;
-  renew:
-    rc = mdbx_txn_renew0(txn, flags);
-  }
-
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    if (txn != env->me_txn0)
-      mdbx_free(txn);
-  } else {
-    if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY))
-      mdbx_assert(env, txn->mt_flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED));
-    else if (flags & MDBX_TXN_RDONLY)
-      mdbx_assert(env, (txn->mt_flags &
-                        ~(MDBX_NOTLS | MDBX_TXN_RDONLY | MDBX_WRITEMAP |
-                          /* Win32: SRWL flag */ MDBX_SHRINK_ALLOWED)) == 0);
-    else {
-      mdbx_assert(env, (txn->mt_flags & ~(MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED |
-                                          MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC |
-                                          MDBX_TXN_SPILLS)) == 0);
-      assert(!txn->tw.spill_pages && !txn->tw.spill_least_removed);
-    }
-    txn->mt_signature = MDBX_MT_SIGNATURE;
-    txn->mt_userctx = context;
-    *ret = txn;
-    mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
-               "/%" PRIaPGNO,
-               txn->mt_txnid, (flags & MDBX_TXN_RDONLY) ? 'r' : 'w',
-               (void *)txn, (void *)env, txn->mt_dbs[MAIN_DBI].md_root,
-               txn->mt_dbs[FREE_DBI].md_root);
-  }
-
-  return rc;
-}
-
-int mdbx_txn_info(const MDBX_txn *txn, MDBX_txn_info *info, bool scan_rlt) {
-  int rc = check_txn(txn, MDBX_TXN_FINISHED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!info))
-    return MDBX_EINVAL;
-
-  MDBX_env *const env = txn->mt_env;
-#if MDBX_ENV_CHECKPID
-  if (unlikely(env->me_pid != mdbx_getpid())) {
-    env->me_flags |= MDBX_FATAL_ERROR;
-    return MDBX_PANIC;
-  }
-#endif /* MDBX_ENV_CHECKPID */
-
-  info->txn_id = txn->mt_txnid;
-  info->txn_space_used = pgno2bytes(env, txn->mt_geo.next);
-
-  if (txn->mt_flags & MDBX_TXN_RDONLY) {
-    volatile const MDBX_meta *head_meta;
-    txnid_t head_txnid;
-    uint64_t head_retired;
-    do {
-      /* fetch info from volatile head */
-      head_meta = meta_prefer_last(env);
-      head_txnid = meta_txnid(env, head_meta);
-      head_retired =
-          unaligned_peek_u64_volatile(4, head_meta->mm_pages_retired);
-      info->txn_space_limit_soft = pgno2bytes(env, head_meta->mm_geo.now);
-      info->txn_space_limit_hard = pgno2bytes(env, head_meta->mm_geo.upper);
-      info->txn_space_leftover =
-          pgno2bytes(env, head_meta->mm_geo.now - head_meta->mm_geo.next);
-      mdbx_compiler_barrier();
-    } while (unlikely(head_meta != meta_prefer_last(env) ||
-                      head_txnid != meta_txnid(env, head_meta)));
-
-    info->txn_reader_lag = head_txnid - info->txn_id;
-    info->txn_space_dirty = info->txn_space_retired = 0;
-    uint64_t reader_snapshot_pages_retired;
-    if (txn->to.reader &&
-        head_retired >
-            (reader_snapshot_pages_retired = atomic_load64(
-                 &txn->to.reader->mr_snapshot_pages_retired, mo_Relaxed))) {
-      info->txn_space_dirty = info->txn_space_retired = pgno2bytes(
-          env, (pgno_t)(head_retired - reader_snapshot_pages_retired));
-
-      size_t retired_next_reader = 0;
-      MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-      if (scan_rlt && info->txn_reader_lag > 1 && lck) {
-        /* find next more recent reader */
-        txnid_t next_reader = head_txnid;
-        const unsigned snap_nreaders =
-            atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-        for (unsigned i = 0; i < snap_nreaders; ++i) {
-        retry:
-          if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease)) {
-            mdbx_jitter4testing(true);
-            const txnid_t snap_txnid =
-                safe64_read(&lck->mti_readers[i].mr_txnid);
-            const uint64_t snap_retired =
-                atomic_load64(&lck->mti_readers[i].mr_snapshot_pages_retired,
-                              mo_AcquireRelease);
-            if (unlikely(snap_retired !=
-                         atomic_load64(
-                             &lck->mti_readers[i].mr_snapshot_pages_retired,
-                             mo_Relaxed)) ||
-                snap_txnid != safe64_read(&lck->mti_readers[i].mr_txnid))
-              goto retry;
-            if (snap_txnid <= txn->mt_txnid) {
-              retired_next_reader = 0;
-              break;
-            }
-            if (snap_txnid < next_reader) {
-              next_reader = snap_txnid;
-              retired_next_reader = pgno2bytes(
-                  env, (pgno_t)(snap_retired -
-                                atomic_load64(
-                                    &txn->to.reader->mr_snapshot_pages_retired,
-                                    mo_Relaxed)));
-            }
-          }
-        }
-      }
-      info->txn_space_dirty = retired_next_reader;
-    }
-  } else {
-    info->txn_space_limit_soft = pgno2bytes(env, txn->mt_geo.now);
-    info->txn_space_limit_hard = pgno2bytes(env, txn->mt_geo.upper);
-    info->txn_space_retired = pgno2bytes(
-        env, txn->mt_child ? (unsigned)(uintptr_t)txn->tw.retired_pages
-                           : MDBX_PNL_SIZE(txn->tw.retired_pages));
-    info->txn_space_leftover = pgno2bytes(env, txn->tw.dirtyroom);
-    info->txn_space_dirty =
-        pgno2bytes(env, txn->mt_env->me_options.dp_limit - txn->tw.dirtyroom);
-    info->txn_reader_lag = INT64_MAX;
-    MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-    if (scan_rlt && lck) {
-      txnid_t oldest_snapshot = txn->mt_txnid;
-      const unsigned snap_nreaders =
-          atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-      if (snap_nreaders) {
-        oldest_snapshot = mdbx_find_oldest(txn);
-        if (oldest_snapshot == txn->mt_txnid - 1) {
-          /* check if there is at least one reader */
-          bool exists = false;
-          for (unsigned i = 0; i < snap_nreaders; ++i) {
-            if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_Relaxed) &&
-                txn->mt_txnid > safe64_read(&lck->mti_readers[i].mr_txnid)) {
-              exists = true;
-              break;
-            }
-          }
-          oldest_snapshot += !exists;
-        }
-      }
-      info->txn_reader_lag = txn->mt_txnid - oldest_snapshot;
-    }
-  }
-
-  return MDBX_SUCCESS;
-}
-
-MDBX_env *mdbx_txn_env(const MDBX_txn *txn) {
-  if (unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE ||
-               txn->mt_env->me_signature.weak != MDBX_ME_SIGNATURE))
-    return NULL;
-  return txn->mt_env;
-}
-
-uint64_t mdbx_txn_id(const MDBX_txn *txn) {
-  if (unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE))
-    return 0;
-  return txn->mt_txnid;
-}
-
-int mdbx_txn_flags(const MDBX_txn *txn) {
-  if (unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE))
-    return -1;
-  return txn->mt_flags;
-}
-
-/* Check for misused dbi handles */
-#define TXN_DBI_CHANGED(txn, dbi)                                              \
-  ((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi])
-
-static void dbi_import_locked(MDBX_txn *txn) {
-  MDBX_env *const env = txn->mt_env;
-  const unsigned n = env->me_numdbs;
-  for (unsigned i = CORE_DBS; i < n; ++i) {
-    if (i >= txn->mt_numdbs) {
-      txn->mt_dbistate[i] = 0;
-      txn->mt_cursors[i] = NULL;
-    }
-    if ((env->me_dbflags[i] & DB_VALID) &&
-        !(txn->mt_dbistate[i] & DBI_USRVALID)) {
-      txn->mt_dbiseqs[i] = env->me_dbiseqs[i];
-      txn->mt_dbs[i].md_flags = env->me_dbflags[i] & DB_PERSISTENT_FLAGS;
-      txn->mt_dbistate[i] = DBI_VALID | DBI_USRVALID | DBI_STALE;
-      mdbx_tassert(txn, txn->mt_dbxs[i].md_cmp != NULL);
-      mdbx_tassert(txn, txn->mt_dbxs[i].md_name.iov_base != NULL);
-    }
-  }
-  txn->mt_numdbs = n;
-}
-
-/* Import DBI which opened after txn started into context */
-__cold static bool dbi_import(MDBX_txn *txn, MDBX_dbi dbi) {
-  if (dbi < CORE_DBS || dbi >= txn->mt_env->me_numdbs)
-    return false;
-
-  mdbx_ensure(txn->mt_env, mdbx_fastmutex_acquire(&txn->mt_env->me_dbi_lock) ==
-                               MDBX_SUCCESS);
-  dbi_import_locked(txn);
-  mdbx_ensure(txn->mt_env, mdbx_fastmutex_release(&txn->mt_env->me_dbi_lock) ==
-                               MDBX_SUCCESS);
-  return txn->mt_dbistate[dbi] & DBI_USRVALID;
-}
-
-/* Export or close DBI handles opened in this txn. */
-static void dbi_update(MDBX_txn *txn, int keep) {
-  mdbx_tassert(txn, !txn->mt_parent && txn == txn->mt_env->me_txn0);
-  MDBX_dbi n = txn->mt_numdbs;
-  if (n) {
-    bool locked = false;
-    MDBX_env *const env = txn->mt_env;
-
-    for (unsigned i = n; --i >= CORE_DBS;) {
-      if (likely((txn->mt_dbistate[i] & DBI_CREAT) == 0))
-        continue;
-      if (!locked) {
-        mdbx_ensure(env,
-                    mdbx_fastmutex_acquire(&env->me_dbi_lock) == MDBX_SUCCESS);
-        locked = true;
-      }
-      if (env->me_numdbs <= i || txn->mt_dbiseqs[i] != env->me_dbiseqs[i])
-        continue /* dbi explicitly closed and/or then re-opened by other txn */;
-      if (keep) {
-        env->me_dbflags[i] = txn->mt_dbs[i].md_flags | DB_VALID;
-      } else {
-        char *ptr = env->me_dbxs[i].md_name.iov_base;
-        if (ptr) {
-          env->me_dbxs[i].md_name.iov_len = 0;
-          mdbx_memory_fence(mo_AcquireRelease, true);
-          mdbx_assert(env, env->me_dbflags[i] == 0);
-          env->me_dbiseqs[i]++;
-          env->me_dbxs[i].md_name.iov_base = NULL;
-          mdbx_free(ptr);
-        }
-      }
-    }
-
-    n = env->me_numdbs;
-    if (n > CORE_DBS && unlikely(!(env->me_dbflags[n - 1] & DB_VALID))) {
-      if (!locked) {
-        mdbx_ensure(env,
-                    mdbx_fastmutex_acquire(&env->me_dbi_lock) == MDBX_SUCCESS);
-        locked = true;
-      }
-
-      n = env->me_numdbs;
-      while (n > CORE_DBS && !(env->me_dbflags[n - 1] & DB_VALID))
-        --n;
-      env->me_numdbs = n;
-    }
-
-    if (unlikely(locked))
-      mdbx_ensure(env,
-                  mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
-  }
-}
-
-/* Filter-out pgno list from transaction's dirty-page list */
-static void mdbx_dpl_sift(MDBX_txn *const txn, MDBX_PNL pl,
-                          const bool spilled) {
-  if (MDBX_PNL_SIZE(pl) && txn->tw.dirtylist->length) {
-    mdbx_tassert(
-        txn, mdbx_pnl_check4assert(pl, (size_t)txn->mt_next_pgno << spilled));
-    MDBX_dpl *dl = mdbx_dpl_sort(txn);
-
-    /* Scanning in ascend order */
-    const int step = MDBX_PNL_ASCENDING ? 1 : -1;
-    const int begin = MDBX_PNL_ASCENDING ? 1 : MDBX_PNL_SIZE(pl);
-    const int end = MDBX_PNL_ASCENDING ? MDBX_PNL_SIZE(pl) + 1 : 0;
-    mdbx_tassert(txn, pl[begin] <= pl[end - step]);
-
-    unsigned r = mdbx_dpl_search(txn, pl[begin] >> spilled);
-    mdbx_tassert(txn, dl->sorted == dl->length);
-    for (int i = begin; r <= dl->length;) { /* scan loop */
-      assert(i != end);
-      mdbx_tassert(txn, !spilled || (pl[i] & 1) == 0);
-      pgno_t pl_pgno = pl[i] >> spilled;
-      pgno_t dp_pgno = dl->items[r].pgno;
-      if (likely(dp_pgno != pl_pgno)) {
-        const bool cmp = dp_pgno < pl_pgno;
-        r += cmp;
-        i += cmp ? 0 : step;
-        if (likely(i != end))
-          continue;
-        return;
-      }
-
-      /* update loop */
-      unsigned w = r;
-    remove_dl:
-      if ((txn->mt_env->me_flags & MDBX_WRITEMAP) == 0) {
-        MDBX_page *dp = dl->items[r].ptr;
-        mdbx_dpage_free(txn->mt_env, dp, dpl_npages(dl, r));
-      }
-      ++r;
-    next_i:
-      i += step;
-      if (unlikely(i == end)) {
-        while (r <= dl->length)
-          dl->items[w++] = dl->items[r++];
-      } else {
-        while (r <= dl->length) {
-          assert(i != end);
-          mdbx_tassert(txn, !spilled || (pl[i] & 1) == 0);
-          pl_pgno = pl[i] >> spilled;
-          dp_pgno = dl->items[r].pgno;
-          if (dp_pgno < pl_pgno)
-            dl->items[w++] = dl->items[r++];
-          else if (dp_pgno > pl_pgno)
-            goto next_i;
-          else
-            goto remove_dl;
-        }
-      }
-      dl->sorted = dpl_setlen(dl, w - 1);
-      txn->tw.dirtyroom += r - w;
-      mdbx_tassert(txn,
-                   txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                       (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                       : txn->mt_env->me_options.dp_limit));
-      return;
-    }
-  }
-}
-
-/* End a transaction, except successful commit of a nested transaction.
- * May be called twice for readonly txns: First reset it, then abort.
- * [in] txn   the transaction handle to end
- * [in] mode  why and how to end the transaction */
-static int mdbx_txn_end(MDBX_txn *txn, const unsigned mode) {
-  MDBX_env *env = txn->mt_env;
-  static const char *const names[] = MDBX_END_NAMES;
-
-#if MDBX_ENV_CHECKPID
-  if (unlikely(txn->mt_env->me_pid != mdbx_getpid())) {
-    env->me_flags |= MDBX_FATAL_ERROR;
-    return MDBX_PANIC;
-  }
-#endif /* MDBX_ENV_CHECKPID */
-
-  mdbx_debug("%s txn %" PRIaTXN "%c %p on mdbenv %p, root page %" PRIaPGNO
-             "/%" PRIaPGNO,
-             names[mode & MDBX_END_OPMASK], txn->mt_txnid,
-             (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn,
-             (void *)env, txn->mt_dbs[MAIN_DBI].md_root,
-             txn->mt_dbs[FREE_DBI].md_root);
-
-  mdbx_ensure(env, txn->mt_txnid >=
-                       /* paranoia is appropriate here */ env->me_lck
-                           ->mti_oldest_reader.weak);
-
-  if (!(mode & MDBX_END_EOTDONE)) /* !(already closed cursors) */
-    mdbx_cursors_eot(txn, false);
-
-  int rc = MDBX_SUCCESS;
-  if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)) {
-    if (txn->to.reader) {
-      MDBX_reader *slot = txn->to.reader;
-      mdbx_assert(env, slot->mr_pid.weak == env->me_pid);
-      if (likely(!F_ISSET(txn->mt_flags, MDBX_TXN_FINISHED))) {
-        mdbx_assert(env, txn->mt_txnid == slot->mr_txnid.weak &&
-                             slot->mr_txnid.weak >=
-                                 env->me_lck->mti_oldest_reader.weak);
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-        mdbx_txn_valgrind(env, nullptr);
-#endif
-        atomic_store32(&slot->mr_snapshot_pages_used, 0, mo_Relaxed);
-        safe64_reset(&slot->mr_txnid, false);
-        atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
-                       mo_Relaxed);
-      } else {
-        mdbx_assert(env, slot->mr_pid.weak == env->me_pid);
-        mdbx_assert(env, slot->mr_txnid.weak >= SAFE64_INVALID_THRESHOLD);
-      }
-      if (mode & MDBX_END_SLOT) {
-        if ((env->me_flags & MDBX_ENV_TXKEY) == 0)
-          atomic_store32(&slot->mr_pid, 0, mo_Relaxed);
-        txn->to.reader = NULL;
-      }
-    }
-#if defined(_WIN32) || defined(_WIN64)
-    if (txn->mt_flags & MDBX_SHRINK_ALLOWED)
-      mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
-#endif
-    txn->mt_numdbs = 0; /* prevent further DBI activity */
-    txn->mt_flags = MDBX_TXN_RDONLY | MDBX_TXN_FINISHED;
-    txn->mt_owner = 0;
-  } else if (!F_ISSET(txn->mt_flags, MDBX_TXN_FINISHED)) {
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-    if (txn == env->me_txn0)
-      mdbx_txn_valgrind(env, nullptr);
-#endif
-
-    txn->mt_flags = MDBX_TXN_FINISHED;
-    txn->mt_owner = 0;
-    env->me_txn = txn->mt_parent;
-    mdbx_pnl_free(txn->tw.spill_pages);
-    txn->tw.spill_pages = nullptr;
-    if (txn == env->me_txn0) {
-      mdbx_assert(env, txn->mt_parent == NULL);
-      /* Export or close DBI handles created in this txn */
-      dbi_update(txn, mode & MDBX_END_UPDATE);
-      mdbx_pnl_shrink(&txn->tw.retired_pages);
-      mdbx_pnl_shrink(&txn->tw.reclaimed_pglist);
-      if (!(env->me_flags & MDBX_WRITEMAP))
-        mdbx_dlist_free(txn);
-      /* The writer mutex was locked in mdbx_txn_begin. */
-      mdbx_txn_unlock(env);
-    } else {
-      mdbx_assert(env, txn->mt_parent != NULL);
-      MDBX_txn *const parent = txn->mt_parent;
-      mdbx_assert(env, parent->mt_signature == MDBX_MT_SIGNATURE);
-      mdbx_assert(env, parent->mt_child == txn &&
-                           (parent->mt_flags & MDBX_TXN_HAS_CHILD) != 0);
-      mdbx_assert(
-          env, mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                     txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-
-      if (txn->tw.lifo_reclaimed) {
-        mdbx_assert(env, MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) >=
-                             (unsigned)(uintptr_t)parent->tw.lifo_reclaimed);
-        MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) =
-            (unsigned)(uintptr_t)parent->tw.lifo_reclaimed;
-        parent->tw.lifo_reclaimed = txn->tw.lifo_reclaimed;
-      }
-
-      if (txn->tw.retired_pages) {
-        mdbx_assert(env, MDBX_PNL_SIZE(txn->tw.retired_pages) >=
-                             (unsigned)(uintptr_t)parent->tw.retired_pages);
-        MDBX_PNL_SIZE(txn->tw.retired_pages) =
-            (unsigned)(uintptr_t)parent->tw.retired_pages;
-        parent->tw.retired_pages = txn->tw.retired_pages;
-      }
-
-      parent->mt_child = nullptr;
-      parent->mt_flags &= ~MDBX_TXN_HAS_CHILD;
-      parent->tw.dirtylru = txn->tw.dirtylru;
-      mdbx_tassert(parent, mdbx_dirtylist_check(parent));
-      mdbx_tassert(parent, mdbx_audit_ex(parent, 0, false) == 0);
-      if (!(env->me_flags & MDBX_WRITEMAP))
-        mdbx_dlist_free(txn);
-      mdbx_dpl_free(txn);
-      mdbx_pnl_free(txn->tw.reclaimed_pglist);
-
-      if (parent->mt_geo.upper != txn->mt_geo.upper ||
-          parent->mt_geo.now != txn->mt_geo.now) {
-        /* undo resize performed by child txn */
-        rc = mdbx_mapresize_implicit(env, parent->mt_next_pgno,
-                                     parent->mt_geo.now, parent->mt_geo.upper);
-        if (rc == MDBX_EPERM) {
-          /* unable undo resize (it is regular for Windows),
-           * therefore promote size changes from child to the parent txn */
-          mdbx_warning("unable undo resize performed by child txn, promote to "
-                       "the parent (%u->%u, %u->%u)",
-                       txn->mt_geo.now, parent->mt_geo.now, txn->mt_geo.upper,
-                       parent->mt_geo.upper);
-          parent->mt_geo.now = txn->mt_geo.now;
-          parent->mt_geo.upper = txn->mt_geo.upper;
-          parent->mt_flags |= MDBX_TXN_DIRTY;
-          rc = MDBX_SUCCESS;
-        } else if (unlikely(rc != MDBX_SUCCESS)) {
-          mdbx_error("error %d while undo resize performed by child txn, fail "
-                     "the parent",
-                     rc);
-          parent->mt_flags |= MDBX_TXN_ERROR;
-          if (!env->me_dxb_mmap.address)
-            env->me_flags |= MDBX_FATAL_ERROR;
-        }
-      }
-    }
-  }
-
-  mdbx_assert(env, txn == env->me_txn0 || txn->mt_owner == 0);
-  if ((mode & MDBX_END_FREE) != 0 && txn != env->me_txn0) {
-    txn->mt_signature = 0;
-    mdbx_free(txn);
-  }
-
-  return rc;
-}
-
-int mdbx_txn_reset(MDBX_txn *txn) {
-  int rc = check_txn(txn, 0);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  /* This call is only valid for read-only txns */
-  if (unlikely((txn->mt_flags & MDBX_TXN_RDONLY) == 0))
-    return MDBX_EINVAL;
-
-  /* LY: don't close DBI-handles */
-  rc = mdbx_txn_end(txn, MDBX_END_RESET | MDBX_END_UPDATE);
-  if (rc == MDBX_SUCCESS) {
-    mdbx_tassert(txn, txn->mt_signature == MDBX_MT_SIGNATURE);
-    mdbx_tassert(txn, txn->mt_owner == 0);
-  }
-  return rc;
-}
-
-int mdbx_txn_break(MDBX_txn *txn) {
-  do {
-    int rc = check_txn(txn, 0);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    txn->mt_flags |= MDBX_TXN_ERROR;
-    if (txn->mt_flags & MDBX_TXN_RDONLY)
-      break;
-    txn = txn->mt_child;
-  } while (txn);
-  return MDBX_SUCCESS;
-}
-
-int mdbx_txn_abort(MDBX_txn *txn) {
-  int rc = check_txn(txn, 0);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY))
-    /* LY: don't close DBI-handles */
-    return mdbx_txn_end(txn, MDBX_END_ABORT | MDBX_END_UPDATE | MDBX_END_SLOT |
-                                 MDBX_END_FREE);
-
-  if (txn->mt_child)
-    mdbx_txn_abort(txn->mt_child);
-
-  mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-  return mdbx_txn_end(txn, MDBX_END_ABORT | MDBX_END_SLOT | MDBX_END_FREE);
-}
-
-/* Count all the pages in each DB and in the GC and make sure
- * it matches the actual number of pages being used. */
-__cold static int mdbx_audit_ex(MDBX_txn *txn, unsigned retired_stored,
-                                bool dont_filter_gc) {
-  pgno_t pending = 0;
-  if ((txn->mt_flags & MDBX_TXN_RDONLY) == 0) {
-    pending = txn->tw.loose_count + MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) +
-              (MDBX_PNL_SIZE(txn->tw.retired_pages) - retired_stored);
-  }
-
-  MDBX_cursor_couple cx;
-  int rc = mdbx_cursor_init(&cx.outer, txn, FREE_DBI);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  pgno_t gc = 0;
-  MDBX_val key, data;
-  while ((rc = mdbx_cursor_get(&cx.outer, &key, &data, MDBX_NEXT)) == 0) {
-    if (!dont_filter_gc) {
-      if (unlikely(key.iov_len != sizeof(txnid_t)))
-        return MDBX_CORRUPTED;
-      txnid_t id = unaligned_peek_u64(4, key.iov_base);
-      if (txn->tw.lifo_reclaimed) {
-        for (unsigned i = 1; i <= MDBX_PNL_SIZE(txn->tw.lifo_reclaimed); ++i)
-          if (id == txn->tw.lifo_reclaimed[i])
-            goto skip;
-      } else if (id <= txn->tw.last_reclaimed)
-        goto skip;
-    }
-
-    gc += *(pgno_t *)data.iov_base;
-  skip:;
-  }
-  mdbx_tassert(txn, rc == MDBX_NOTFOUND);
-
-  for (MDBX_dbi i = FREE_DBI; i < txn->mt_numdbs; i++)
-    txn->mt_dbistate[i] &= ~DBI_AUDITED;
-
-  pgno_t used = NUM_METAS;
-  for (MDBX_dbi i = FREE_DBI; i <= MAIN_DBI; i++) {
-    if (!(txn->mt_dbistate[i] & DBI_VALID))
-      continue;
-    rc = mdbx_cursor_init(&cx.outer, txn, i);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    txn->mt_dbistate[i] |= DBI_AUDITED;
-    if (txn->mt_dbs[i].md_root == P_INVALID)
-      continue;
-    used += txn->mt_dbs[i].md_branch_pages + txn->mt_dbs[i].md_leaf_pages +
-            txn->mt_dbs[i].md_overflow_pages;
-
-    if (i != MAIN_DBI)
-      continue;
-    rc = mdbx_page_search(&cx.outer, NULL, MDBX_PS_FIRST);
-    while (rc == MDBX_SUCCESS) {
-      MDBX_page *mp = cx.outer.mc_pg[cx.outer.mc_top];
-      for (unsigned j = 0; j < page_numkeys(mp); j++) {
-        MDBX_node *node = page_node(mp, j);
-        if (node_flags(node) == F_SUBDATA) {
-          if (unlikely(node_ds(node) != sizeof(MDBX_db)))
-            return MDBX_CORRUPTED;
-          MDBX_db db_copy, *db;
-          memcpy(db = &db_copy, node_data(node), sizeof(db_copy));
-          if ((txn->mt_flags & MDBX_TXN_RDONLY) == 0) {
-            for (MDBX_dbi k = txn->mt_numdbs; --k > MAIN_DBI;) {
-              if ((txn->mt_dbistate[k] & DBI_VALID) &&
-                  /* txn->mt_dbxs[k].md_name.iov_len > 0 && */
-                  node_ks(node) == txn->mt_dbxs[k].md_name.iov_len &&
-                  memcmp(node_key(node), txn->mt_dbxs[k].md_name.iov_base,
-                         node_ks(node)) == 0) {
-                txn->mt_dbistate[k] |= DBI_AUDITED;
-                if (!(txn->mt_dbistate[k] & MDBX_DBI_STALE))
-                  db = txn->mt_dbs + k;
-                break;
-              }
-            }
-          }
-          used +=
-              db->md_branch_pages + db->md_leaf_pages + db->md_overflow_pages;
-        }
-      }
-      rc = mdbx_cursor_sibling(&cx.outer, SIBLING_RIGHT);
-    }
-    mdbx_tassert(txn, rc == MDBX_NOTFOUND);
-  }
-
-  for (MDBX_dbi i = FREE_DBI; i < txn->mt_numdbs; i++) {
-    if ((txn->mt_dbistate[i] & (DBI_VALID | DBI_AUDITED | DBI_STALE)) !=
-        DBI_VALID)
-      continue;
-    for (MDBX_txn *t = txn; t; t = t->mt_parent)
-      if (F_ISSET(t->mt_dbistate[i], DBI_DIRTY | DBI_CREAT)) {
-        used += t->mt_dbs[i].md_branch_pages + t->mt_dbs[i].md_leaf_pages +
-                t->mt_dbs[i].md_overflow_pages;
-        txn->mt_dbistate[i] |= DBI_AUDITED;
-        break;
-      }
-    if (!(txn->mt_dbistate[i] & DBI_AUDITED)) {
-      mdbx_warning("audit %s@%" PRIaTXN
-                   ": unable account dbi %d / \"%*s\", state 0x%02x",
-                   txn->mt_parent ? "nested-" : "", txn->mt_txnid, i,
-                   (int)txn->mt_dbxs[i].md_name.iov_len,
-                   (const char *)txn->mt_dbxs[i].md_name.iov_base,
-                   txn->mt_dbistate[i]);
-    }
-  }
-
-  if (pending + gc + used == txn->mt_next_pgno)
-    return MDBX_SUCCESS;
-
-  if ((txn->mt_flags & MDBX_TXN_RDONLY) == 0)
-    mdbx_error("audit @%" PRIaTXN ": %u(pending) = %u(loose) + "
-               "%u(reclaimed) + %u(retired-pending) - %u(retired-stored)",
-               txn->mt_txnid, pending, txn->tw.loose_count,
-               MDBX_PNL_SIZE(txn->tw.reclaimed_pglist),
-               txn->tw.retired_pages ? MDBX_PNL_SIZE(txn->tw.retired_pages) : 0,
-               retired_stored);
-  mdbx_error("audit @%" PRIaTXN ": %" PRIaPGNO "(pending) + %" PRIaPGNO
-             "(gc) + %" PRIaPGNO "(count) = %" PRIaPGNO "(total) <> %" PRIaPGNO
-             "(allocated)",
-             txn->mt_txnid, pending, gc, used, pending + gc + used,
-             txn->mt_next_pgno);
-  return MDBX_PROBLEM;
-}
-
-static __always_inline unsigned backlog_size(MDBX_txn *txn) {
-  return MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) + txn->tw.loose_count;
-}
-
-/* LY: Prepare a backlog of pages to modify GC itself,
- * while reclaiming is prohibited. It should be enough to prevent search
- * in mdbx_page_alloc() during a deleting, when GC tree is unbalanced. */
-static int mdbx_prep_backlog(MDBX_txn *txn, MDBX_cursor *gc_cursor,
-                             const size_t pnl_bytes, unsigned *retired_stored) {
-  const unsigned linear4list = number_of_ovpages(txn->mt_env, pnl_bytes);
-  const unsigned backlog4cow = txn->mt_dbs[FREE_DBI].md_depth;
-  const unsigned backlog4rebalance = backlog4cow + 1;
-
-  if (likely(linear4list == 1 &&
-             backlog_size(txn) > (pnl_bytes
-                                      ? backlog4rebalance
-                                      : (backlog4cow + backlog4rebalance))))
-    return MDBX_SUCCESS;
-
-  mdbx_trace(">> pnl_bytes %zu, backlog %u, 4list %u, 4cow %u, 4rebalance %u",
-             pnl_bytes, backlog_size(txn), linear4list, backlog4cow,
-             backlog4rebalance);
-
-  MDBX_val gc_key, fake_val;
-  int err;
-  if (unlikely(linear4list > 2)) {
-    gc_key.iov_base = fake_val.iov_base = nullptr;
-    gc_key.iov_len = sizeof(txnid_t);
-    fake_val.iov_len = pnl_bytes;
-    err = mdbx_cursor_spill(gc_cursor, &gc_key, &fake_val);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-  }
-
-  gc_cursor->mc_flags &= ~C_RECLAIMING;
-  err = mdbx_cursor_touch(gc_cursor);
-  mdbx_trace("== after-touch, backlog %u, err %d", backlog_size(txn), err);
-
-  if (unlikely(linear4list > 1) && err == MDBX_SUCCESS) {
-    if (retired_stored) {
-      gc_key.iov_base = &txn->mt_txnid;
-      gc_key.iov_len = sizeof(txn->mt_txnid);
-      const struct cursor_set_result csr =
-          mdbx_cursor_set(gc_cursor, &gc_key, &fake_val, MDBX_SET);
-      if (csr.err == MDBX_SUCCESS && csr.exact) {
-        *retired_stored = 0;
-        err = mdbx_cursor_del(gc_cursor, 0);
-        mdbx_trace("== clear-4linear, backlog %u, err %d", backlog_size(txn),
-                   err);
-      }
-    }
-    err =
-        mdbx_page_alloc(gc_cursor, linear4list, MDBX_ALLOC_GC | MDBX_ALLOC_FAKE)
-            .err;
-    mdbx_trace("== after-4linear, backlog %u, err %d", backlog_size(txn), err);
-    mdbx_cassert(gc_cursor,
-                 backlog_size(txn) >= linear4list || err != MDBX_SUCCESS);
-  }
-
-  while (backlog_size(txn) < backlog4cow + linear4list && err == MDBX_SUCCESS)
-    err = mdbx_page_alloc(gc_cursor, 0,
-                          MDBX_ALLOC_GC | MDBX_ALLOC_SLOT | MDBX_ALLOC_FAKE)
-              .err;
-
-  gc_cursor->mc_flags |= C_RECLAIMING;
-  mdbx_trace("<< backlog %u, err %d", backlog_size(txn), err);
-  return (err != MDBX_NOTFOUND) ? err : MDBX_SUCCESS;
-}
-
-static __inline void clean_reserved_gc_pnl(MDBX_env *env, MDBX_val pnl) {
-  /* PNL is initially empty, zero out at least the length */
-  memset(pnl.iov_base, 0, sizeof(pgno_t));
-  if ((env->me_flags & (MDBX_WRITEMAP | MDBX_NOMEMINIT)) == 0)
-    /* zero out to avoid leaking values from uninitialized malloc'ed memory
-     * to the file in non-writemap mode if length of the saving page-list
-     * was changed during space reservation. */
-    memset(pnl.iov_base, 0, pnl.iov_len);
-}
-
-/* Cleanups reclaimed GC (aka freeDB) records, saves the retired-list (aka
- * freelist) of current transaction to GC, puts back into GC leftover of the
- * reclaimed pages with chunking. This recursive changes the reclaimed-list,
- * loose-list and retired-list. Keep trying until it stabilizes.
- *
- * NOTE: This code is a consequence of many iterations of adding crutches (aka
- * "checks and balances") to partially bypass the fundamental design problems
- * inherited from LMDB. So do not try to understand it completely in order to
- * avoid your madness. */
-static int mdbx_update_gc(MDBX_txn *txn) {
-  /* txn->tw.reclaimed_pglist[] can grow and shrink during this call.
-   * txn->tw.last_reclaimed and txn->tw.retired_pages[] can only grow.
-   * Page numbers cannot disappear from txn->tw.retired_pages[]. */
-  MDBX_env *const env = txn->mt_env;
-  const bool lifo = (env->me_flags & MDBX_LIFORECLAIM) != 0;
-  const char *dbg_prefix_mode = lifo ? "    lifo" : "    fifo";
-  (void)dbg_prefix_mode;
-  mdbx_trace("\n>>> @%" PRIaTXN, txn->mt_txnid);
-
-  unsigned retired_stored = 0, loop = 0;
-  MDBX_cursor_couple couple;
-  int rc = mdbx_cursor_init(&couple.outer, txn, FREE_DBI);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto bailout_notracking;
-
-  couple.outer.mc_flags |= C_RECLAIMING;
-  couple.outer.mc_next = txn->mt_cursors[FREE_DBI];
-  txn->mt_cursors[FREE_DBI] = &couple.outer;
-  bool dense_gc = false;
-
-retry:
-  ++loop;
-  mdbx_trace("%s", " >> restart");
-  mdbx_tassert(txn,
-               mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                     txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-  mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-  if (unlikely(/* paranoia */ loop > ((MDBX_DEBUG > 0) ? 12 : 42))) {
-    mdbx_error("too more loops %u, bailout", loop);
-    rc = MDBX_PROBLEM;
-    goto bailout;
-  }
-
-  if (unlikely(dense_gc) && retired_stored) {
-    rc = mdbx_prep_backlog(txn, &couple.outer,
-                           MDBX_PNL_SIZEOF(txn->tw.retired_pages),
-                           &retired_stored);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-  }
-
-  unsigned settled = 0, cleaned_gc_slot = 0, reused_gc_slot = 0,
-           filled_gc_slot = ~0u;
-  txnid_t cleaned_gc_id = 0, gc_rid = txn->tw.last_reclaimed;
-  while (true) {
-    /* Come back here after each Put() in case retired-list changed */
-    MDBX_val key, data;
-    mdbx_trace("%s", " >> continue");
-
-    if (retired_stored != MDBX_PNL_SIZE(txn->tw.retired_pages) &&
-        MDBX_PNL_SIZE(txn->tw.retired_pages) > env->me_maxgc_ov1page) {
-      rc = mdbx_prep_backlog(txn, &couple.outer,
-                             MDBX_PNL_SIZEOF(txn->tw.retired_pages),
-                             &retired_stored);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-    }
-
-    mdbx_tassert(txn,
-                 mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                       txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-    if (lifo) {
-      if (cleaned_gc_slot < (txn->tw.lifo_reclaimed
-                                 ? MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)
-                                 : 0)) {
-        settled = 0;
-        cleaned_gc_slot = 0;
-        reused_gc_slot = 0;
-        filled_gc_slot = ~0u;
-        /* LY: cleanup reclaimed records. */
-        do {
-          cleaned_gc_id = txn->tw.lifo_reclaimed[++cleaned_gc_slot];
-          mdbx_tassert(txn,
-                       cleaned_gc_slot > 0 &&
-                           cleaned_gc_id < env->me_lck->mti_oldest_reader.weak);
-          key.iov_base = &cleaned_gc_id;
-          key.iov_len = sizeof(cleaned_gc_id);
-          rc = mdbx_cursor_get(&couple.outer, &key, NULL, MDBX_SET);
-          if (rc == MDBX_NOTFOUND)
-            continue;
-          if (unlikely(rc != MDBX_SUCCESS))
-            goto bailout;
-          if (likely(!dense_gc)) {
-            rc = mdbx_prep_backlog(txn, &couple.outer, 0, nullptr);
-            if (unlikely(rc != MDBX_SUCCESS))
-              goto bailout;
-          }
-          mdbx_tassert(txn,
-                       cleaned_gc_id < env->me_lck->mti_oldest_reader.weak);
-          mdbx_trace("%s: cleanup-reclaimed-id [%u]%" PRIaTXN, dbg_prefix_mode,
-                     cleaned_gc_slot, cleaned_gc_id);
-          mdbx_tassert(txn, *txn->mt_cursors == &couple.outer);
-          rc = mdbx_cursor_del(&couple.outer, 0);
-          if (unlikely(rc != MDBX_SUCCESS))
-            goto bailout;
-        } while (cleaned_gc_slot < MDBX_PNL_SIZE(txn->tw.lifo_reclaimed));
-        mdbx_txl_sort(txn->tw.lifo_reclaimed);
-      }
-    } else {
-      /* If using records from GC which we have not yet deleted,
-       * now delete them and any we reserved for tw.reclaimed_pglist. */
-      while (cleaned_gc_id <= txn->tw.last_reclaimed) {
-        rc = mdbx_cursor_first(&couple.outer, &key, NULL);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          if (rc == MDBX_NOTFOUND)
-            break;
-          goto bailout;
-        }
-        if (!MDBX_DISABLE_PAGECHECKS &&
-            unlikely(key.iov_len != sizeof(txnid_t))) {
-          rc = MDBX_CORRUPTED;
-          goto bailout;
-        }
-        gc_rid = cleaned_gc_id;
-        settled = 0;
-        reused_gc_slot = 0;
-        cleaned_gc_id = unaligned_peek_u64(4, key.iov_base);
-        if (!MDBX_DISABLE_PAGECHECKS &&
-            unlikely(cleaned_gc_id < MIN_TXNID || cleaned_gc_id > MAX_TXNID)) {
-          rc = MDBX_CORRUPTED;
-          goto bailout;
-        }
-        if (cleaned_gc_id > txn->tw.last_reclaimed)
-          break;
-        if (likely(!dense_gc)) {
-          rc = mdbx_prep_backlog(txn, &couple.outer, 0, nullptr);
-          if (unlikely(rc != MDBX_SUCCESS))
-            goto bailout;
-        }
-        mdbx_tassert(txn, cleaned_gc_id <= txn->tw.last_reclaimed);
-        mdbx_tassert(txn, cleaned_gc_id < env->me_lck->mti_oldest_reader.weak);
-        mdbx_trace("%s: cleanup-reclaimed-id %" PRIaTXN, dbg_prefix_mode,
-                   cleaned_gc_id);
-        mdbx_tassert(txn, *txn->mt_cursors == &couple.outer);
-        rc = mdbx_cursor_del(&couple.outer, 0);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      }
-    }
-
-    mdbx_tassert(txn,
-                 mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                       txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-    mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-    if (mdbx_audit_enabled()) {
-      rc = mdbx_audit_ex(txn, retired_stored, false);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-    }
-
-    /* return suitable into unallocated space */
-    if (mdbx_refund(txn)) {
-      mdbx_tassert(
-          txn, mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                     txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-      if (mdbx_audit_enabled()) {
-        rc = mdbx_audit_ex(txn, retired_stored, false);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      }
-    }
-
-    /* handle loose pages - put ones into the reclaimed- or retired-list */
-    if (txn->tw.loose_pages) {
-      /* Return loose page numbers to tw.reclaimed_pglist,
-       * though usually none are left at this point.
-       * The pages themselves remain in dirtylist. */
-      if (unlikely(!txn->tw.lifo_reclaimed && txn->tw.last_reclaimed < 1)) {
-        if (txn->tw.loose_count > 0) {
-          /* Put loose page numbers in tw.retired_pages,
-           * since unable to return them to tw.reclaimed_pglist. */
-          if (unlikely((rc = mdbx_pnl_need(&txn->tw.retired_pages,
-                                           txn->tw.loose_count)) != 0))
-            goto bailout;
-          for (MDBX_page *mp = txn->tw.loose_pages; mp; mp = mp->mp_next)
-            mdbx_pnl_xappend(txn->tw.retired_pages, mp->mp_pgno);
-          mdbx_trace("%s: append %u loose-pages to retired-pages",
-                     dbg_prefix_mode, txn->tw.loose_count);
-        }
-      } else {
-        /* Room for loose pages + temp PNL with same */
-        rc = mdbx_pnl_need(&txn->tw.reclaimed_pglist,
-                           2 * txn->tw.loose_count + 2);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-        MDBX_PNL loose = txn->tw.reclaimed_pglist +
-                         MDBX_PNL_ALLOCLEN(txn->tw.reclaimed_pglist) -
-                         txn->tw.loose_count - 1;
-        unsigned count = 0;
-        for (MDBX_page *mp = txn->tw.loose_pages; mp; mp = mp->mp_next) {
-          mdbx_tassert(txn, mp->mp_flags == P_LOOSE);
-          loose[++count] = mp->mp_pgno;
-        }
-        mdbx_tassert(txn, count == txn->tw.loose_count);
-        MDBX_PNL_SIZE(loose) = count;
-        mdbx_pnl_sort(loose, txn->mt_next_pgno);
-        mdbx_pnl_xmerge(txn->tw.reclaimed_pglist, loose);
-        mdbx_trace("%s: append %u loose-pages to reclaimed-pages",
-                   dbg_prefix_mode, txn->tw.loose_count);
-      }
-
-      /* filter-out list of dirty-pages from loose-pages */
-      MDBX_dpl *const dl = txn->tw.dirtylist;
-      unsigned w = 0;
-      for (unsigned r = w; ++r <= dl->length;) {
-        MDBX_page *dp = dl->items[r].ptr;
-        mdbx_tassert(txn, dp->mp_flags == P_LOOSE || IS_MODIFIABLE(txn, dp));
-        mdbx_tassert(txn, dpl_endpgno(dl, r) <= txn->mt_next_pgno);
-        if ((dp->mp_flags & P_LOOSE) == 0) {
-          if (++w != r)
-            dl->items[w] = dl->items[r];
-        } else {
-          mdbx_tassert(txn, dp->mp_flags == P_LOOSE);
-          if ((env->me_flags & MDBX_WRITEMAP) == 0)
-            mdbx_dpage_free(env, dp, 1);
-        }
-      }
-      mdbx_trace("%s: filtered-out loose-pages from %u -> %u dirty-pages",
-                 dbg_prefix_mode, dl->length, w);
-      mdbx_tassert(txn, txn->tw.loose_count == dl->length - w);
-      dpl_setlen(dl, w);
-      dl->sorted = 0;
-      txn->tw.dirtyroom += txn->tw.loose_count;
-      mdbx_tassert(txn,
-                   txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                       (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                       : txn->mt_env->me_options.dp_limit));
-      txn->tw.loose_pages = NULL;
-      txn->tw.loose_count = 0;
-#if MDBX_ENABLE_REFUND
-      txn->tw.loose_refund_wl = 0;
-#endif /* MDBX_ENABLE_REFUND */
-    }
-
-    const unsigned amount = (unsigned)MDBX_PNL_SIZE(txn->tw.reclaimed_pglist);
-    /* handle retired-list - store ones into single gc-record */
-    if (retired_stored < MDBX_PNL_SIZE(txn->tw.retired_pages)) {
-      if (unlikely(!retired_stored)) {
-        /* Make sure last page of GC is touched and on retired-list */
-        couple.outer.mc_flags &= ~C_RECLAIMING;
-        rc = mdbx_page_search(&couple.outer, NULL,
-                              MDBX_PS_LAST | MDBX_PS_MODIFY);
-        couple.outer.mc_flags |= C_RECLAIMING;
-        if (unlikely(rc != MDBX_SUCCESS) && rc != MDBX_NOTFOUND)
-          goto bailout;
-      }
-      /* Write to last page of GC */
-      key.iov_len = sizeof(txn->mt_txnid);
-      key.iov_base = &txn->mt_txnid;
-      do {
-        data.iov_len = MDBX_PNL_SIZEOF(txn->tw.retired_pages);
-        mdbx_prep_backlog(txn, &couple.outer, data.iov_len, &retired_stored);
-        rc = mdbx_cursor_put(&couple.outer, &key, &data, MDBX_RESERVE);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-        /* Retry if tw.retired_pages[] grew during the Put() */
-      } while (data.iov_len < MDBX_PNL_SIZEOF(txn->tw.retired_pages));
-
-      retired_stored = (unsigned)MDBX_PNL_SIZE(txn->tw.retired_pages);
-      mdbx_pnl_sort(txn->tw.retired_pages, txn->mt_next_pgno);
-      mdbx_assert(env, data.iov_len == MDBX_PNL_SIZEOF(txn->tw.retired_pages));
-      memcpy(data.iov_base, txn->tw.retired_pages, data.iov_len);
-
-      mdbx_trace("%s: put-retired #%u @ %" PRIaTXN, dbg_prefix_mode,
-                 retired_stored, txn->mt_txnid);
-
-      if (mdbx_log_enabled(MDBX_LOG_EXTRA)) {
-        unsigned i = retired_stored;
-        mdbx_debug_extra("PNL write txn %" PRIaTXN " root %" PRIaPGNO
-                         " num %u, PNL",
-                         txn->mt_txnid, txn->mt_dbs[FREE_DBI].md_root, i);
-        for (; i; i--)
-          mdbx_debug_extra_print(" %" PRIaPGNO, txn->tw.retired_pages[i]);
-        mdbx_debug_extra_print("%s\n", ".");
-      }
-      if (unlikely(amount != MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) &&
-                   settled)) {
-        mdbx_trace("%s: reclaimed-list changed %u -> %u, retry",
-                   dbg_prefix_mode, amount,
-                   (unsigned)MDBX_PNL_SIZE(txn->tw.reclaimed_pglist));
-        goto retry /* rare case, but avoids GC fragmentation
-                                and one cycle. */
-            ;
-      }
-      continue;
-    }
-
-    /* handle reclaimed and lost pages - merge and store both into gc */
-    mdbx_tassert(txn,
-                 mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                       txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-    mdbx_tassert(txn, txn->tw.loose_count == 0);
-
-    mdbx_trace("%s", " >> reserving");
-    if (mdbx_audit_enabled()) {
-      rc = mdbx_audit_ex(txn, retired_stored, false);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-    }
-    const unsigned left = amount - settled;
-    mdbx_trace("%s: amount %u, settled %d, left %d, lifo-reclaimed-slots %u, "
-               "reused-gc-slots %u",
-               dbg_prefix_mode, amount, settled, (int)left,
-               txn->tw.lifo_reclaimed
-                   ? (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)
-                   : 0,
-               reused_gc_slot);
-    if (0 >= (int)left)
-      break;
-
-    const unsigned prefer_max_scatter = 257;
-    txnid_t reservation_gc_id;
-    if (lifo) {
-      if (txn->tw.lifo_reclaimed == nullptr) {
-        txn->tw.lifo_reclaimed = mdbx_txl_alloc();
-        if (unlikely(!txn->tw.lifo_reclaimed)) {
-          rc = MDBX_ENOMEM;
-          goto bailout;
-        }
-      }
-      if ((unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) <
-              prefer_max_scatter &&
-          left > ((unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) -
-                  reused_gc_slot) *
-                     env->me_maxgc_ov1page &&
-          !dense_gc) {
-        /* LY: need just a txn-id for save page list. */
-        bool need_cleanup = false;
-        txnid_t snap_oldest;
-      retry_rid:
-        couple.outer.mc_flags &= ~C_RECLAIMING;
-        do {
-          snap_oldest = mdbx_find_oldest(txn);
-          rc =
-              mdbx_page_alloc(&couple.outer, 0,
-                              MDBX_ALLOC_GC | MDBX_ALLOC_SLOT | MDBX_ALLOC_FAKE)
-                  .err;
-          if (likely(rc == MDBX_SUCCESS)) {
-            mdbx_trace("%s: took @%" PRIaTXN " from GC", dbg_prefix_mode,
-                       MDBX_PNL_LAST(txn->tw.lifo_reclaimed));
-            need_cleanup = true;
-          }
-        } while (rc == MDBX_SUCCESS &&
-                 (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) <
-                     prefer_max_scatter &&
-                 left > ((unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) -
-                         reused_gc_slot) *
-                            env->me_maxgc_ov1page);
-        couple.outer.mc_flags |= C_RECLAIMING;
-
-        if (likely(rc == MDBX_SUCCESS)) {
-          mdbx_trace("%s: got enough from GC.", dbg_prefix_mode);
-          continue;
-        } else if (unlikely(rc != MDBX_NOTFOUND))
-          /* LY: some troubles... */
-          goto bailout;
-
-        if (MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)) {
-          if (need_cleanup) {
-            mdbx_txl_sort(txn->tw.lifo_reclaimed);
-            cleaned_gc_slot = 0;
-          }
-          gc_rid = MDBX_PNL_LAST(txn->tw.lifo_reclaimed);
-        } else {
-          mdbx_tassert(txn, txn->tw.last_reclaimed == 0);
-          if (unlikely(mdbx_find_oldest(txn) != snap_oldest))
-            /* should retry mdbx_page_alloc(MDBX_ALLOC_GC)
-             * if the oldest reader changes since the last attempt */
-            goto retry_rid;
-          /* no reclaimable GC entries,
-           * therefore no entries with ID < mdbx_find_oldest(txn) */
-          txn->tw.last_reclaimed = gc_rid = snap_oldest - 1;
-          mdbx_trace("%s: none recycled yet, set rid to @%" PRIaTXN,
-                     dbg_prefix_mode, gc_rid);
-        }
-
-        /* LY: GC is empty, will look any free txn-id in high2low order. */
-        while (MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) < prefer_max_scatter &&
-               left > ((unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) -
-                       reused_gc_slot) *
-                          env->me_maxgc_ov1page) {
-          if (unlikely(gc_rid <= MIN_TXNID)) {
-            if (unlikely(MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) <=
-                         reused_gc_slot)) {
-              mdbx_notice("** restart: reserve depleted (reused_gc_slot %u >= "
-                          "lifo_reclaimed %u" PRIaTXN,
-                          reused_gc_slot,
-                          (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed));
-              goto retry;
-            }
-            break;
-          }
-
-          mdbx_tassert(txn, gc_rid >= MIN_TXNID && gc_rid <= MAX_TXNID);
-          --gc_rid;
-          key.iov_base = &gc_rid;
-          key.iov_len = sizeof(gc_rid);
-          rc = mdbx_cursor_get(&couple.outer, &key, &data, MDBX_SET_KEY);
-          if (unlikely(rc == MDBX_SUCCESS)) {
-            mdbx_debug("%s: GC's id %" PRIaTXN
-                       " is used, continue bottom-up search",
-                       dbg_prefix_mode, gc_rid);
-            ++gc_rid;
-            rc = mdbx_cursor_get(&couple.outer, &key, &data, MDBX_FIRST);
-            if (rc == MDBX_NOTFOUND) {
-              mdbx_debug("%s: GC is empty (going dense-mode)", dbg_prefix_mode);
-              dense_gc = true;
-              break;
-            }
-            if (unlikely(rc != MDBX_SUCCESS ||
-                         key.iov_len != sizeof(mdbx_tid_t))) {
-              rc = MDBX_CORRUPTED;
-              goto bailout;
-            }
-            txnid_t gc_first = unaligned_peek_u64(4, key.iov_base);
-            if (!MDBX_DISABLE_PAGECHECKS &&
-                unlikely(gc_first < MIN_TXNID || gc_first > MAX_TXNID)) {
-              rc = MDBX_CORRUPTED;
-              goto bailout;
-            }
-            if (gc_first <= MIN_TXNID) {
-              mdbx_debug("%s: no free GC's id(s) less than %" PRIaTXN
-                         " (going dense-mode)",
-                         dbg_prefix_mode, gc_rid);
-              dense_gc = true;
-              break;
-            }
-            gc_rid = gc_first - 1;
-          }
-
-          mdbx_assert(env, !dense_gc);
-          rc = mdbx_txl_append(&txn->tw.lifo_reclaimed, gc_rid);
-          if (unlikely(rc != MDBX_SUCCESS))
-            goto bailout;
-
-          if (reused_gc_slot)
-            /* rare case, but it is better to clear and re-create GC entries
-             * with less fragmentation. */
-            need_cleanup = true;
-          else
-            cleaned_gc_slot +=
-                1 /* mark cleanup is not needed for added slot. */;
-
-          mdbx_trace("%s: append @%" PRIaTXN
-                     " to lifo-reclaimed, cleaned-gc-slot = %u",
-                     dbg_prefix_mode, gc_rid, cleaned_gc_slot);
-        }
-
-        if (need_cleanup || dense_gc) {
-          if (cleaned_gc_slot)
-            mdbx_trace(
-                "%s: restart inner-loop to clear and re-create GC entries",
-                dbg_prefix_mode);
-          cleaned_gc_slot = 0;
-          continue;
-        }
-      }
-
-      const unsigned i =
-          (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) - reused_gc_slot;
-      mdbx_tassert(txn, i > 0 && i <= MDBX_PNL_SIZE(txn->tw.lifo_reclaimed));
-      reservation_gc_id = txn->tw.lifo_reclaimed[i];
-      mdbx_trace("%s: take @%" PRIaTXN " from lifo-reclaimed[%u]",
-                 dbg_prefix_mode, reservation_gc_id, i);
-    } else {
-      mdbx_tassert(txn, txn->tw.lifo_reclaimed == NULL);
-      if (unlikely(gc_rid == 0)) {
-        gc_rid = mdbx_find_oldest(txn) - 1;
-        rc = mdbx_cursor_get(&couple.outer, &key, NULL, MDBX_FIRST);
-        if (rc == MDBX_SUCCESS) {
-          if (!MDBX_DISABLE_PAGECHECKS &&
-              unlikely(key.iov_len != sizeof(txnid_t))) {
-            rc = MDBX_CORRUPTED;
-            goto bailout;
-          }
-          txnid_t gc_first = unaligned_peek_u64(4, key.iov_base);
-          if (!MDBX_DISABLE_PAGECHECKS &&
-              unlikely(gc_first < MIN_TXNID || gc_first > MAX_TXNID)) {
-            rc = MDBX_CORRUPTED;
-            goto bailout;
-          }
-          if (gc_rid >= gc_first)
-            gc_rid = gc_first - 1;
-          if (unlikely(gc_rid == 0)) {
-            mdbx_error("%s", "** no GC tail-space to store (going dense-mode)");
-            dense_gc = true;
-            goto retry;
-          }
-        } else if (rc != MDBX_NOTFOUND)
-          goto bailout;
-        txn->tw.last_reclaimed = gc_rid;
-        cleaned_gc_id = gc_rid + 1;
-      }
-      reservation_gc_id = gc_rid--;
-      mdbx_trace("%s: take @%" PRIaTXN " from head-gc-id", dbg_prefix_mode,
-                 reservation_gc_id);
-    }
-    ++reused_gc_slot;
-
-    unsigned chunk = left;
-    if (unlikely(chunk > env->me_maxgc_ov1page)) {
-      const unsigned avail_gc_slots =
-          txn->tw.lifo_reclaimed
-              ? (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) -
-                    reused_gc_slot + 1
-          : (gc_rid < INT16_MAX) ? (unsigned)gc_rid
-                                 : INT16_MAX;
-      if (avail_gc_slots > 1) {
-        if (chunk < env->me_maxgc_ov1page * 2)
-          chunk /= 2;
-        else {
-          const unsigned threshold =
-              env->me_maxgc_ov1page * ((avail_gc_slots < prefer_max_scatter)
-                                           ? avail_gc_slots
-                                           : prefer_max_scatter);
-          if (left < threshold)
-            chunk = env->me_maxgc_ov1page;
-          else {
-            const unsigned tail = left - threshold + env->me_maxgc_ov1page + 1;
-            unsigned span = 1;
-            unsigned avail = (unsigned)((pgno2bytes(env, span) - PAGEHDRSZ) /
-                                        sizeof(pgno_t)) /* - 1 + span */;
-            if (tail > avail) {
-              for (unsigned i = amount - span; i > 0; --i) {
-                if (MDBX_PNL_ASCENDING
-                        ? (txn->tw.reclaimed_pglist[i] + span)
-                        : (txn->tw.reclaimed_pglist[i] - span) ==
-                              txn->tw.reclaimed_pglist[i + span]) {
-                  span += 1;
-                  avail = (unsigned)((pgno2bytes(env, span) - PAGEHDRSZ) /
-                                     sizeof(pgno_t)) -
-                          1 + span;
-                  if (avail >= tail)
-                    break;
-                }
-              }
-            }
-
-            chunk = (avail >= tail) ? tail - span
-                    : (avail_gc_slots > 3 &&
-                       reused_gc_slot < prefer_max_scatter - 3)
-                        ? avail - span
-                        : tail;
-          }
-        }
-      }
-    }
-    mdbx_tassert(txn, chunk > 0);
-
-    mdbx_trace("%s: gc_rid %" PRIaTXN ", reused_gc_slot %u, reservation-id "
-               "%" PRIaTXN,
-               dbg_prefix_mode, gc_rid, reused_gc_slot, reservation_gc_id);
-
-    mdbx_trace("%s: chunk %u, gc-per-ovpage %u", dbg_prefix_mode, chunk,
-               env->me_maxgc_ov1page);
-
-    mdbx_tassert(txn, reservation_gc_id < env->me_lck->mti_oldest_reader.weak);
-    if (unlikely(
-            reservation_gc_id < MIN_TXNID ||
-            reservation_gc_id >=
-                atomic_load64(&env->me_lck->mti_oldest_reader, mo_Relaxed))) {
-      mdbx_error("** internal error (reservation_gc_id %" PRIaTXN ")",
-                 reservation_gc_id);
-      rc = MDBX_PROBLEM;
-      goto bailout;
-    }
-
-    key.iov_len = sizeof(reservation_gc_id);
-    key.iov_base = &reservation_gc_id;
-    data.iov_len = (chunk + 1) * sizeof(pgno_t);
-    mdbx_trace("%s: reserve %u [%u...%u) @%" PRIaTXN, dbg_prefix_mode, chunk,
-               settled + 1, settled + chunk + 1, reservation_gc_id);
-    mdbx_prep_backlog(txn, &couple.outer, data.iov_len, nullptr);
-    rc = mdbx_cursor_put(&couple.outer, &key, &data,
-                         MDBX_RESERVE | MDBX_NOOVERWRITE);
-    mdbx_tassert(txn,
-                 mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                       txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-
-    clean_reserved_gc_pnl(env, data);
-    settled += chunk;
-    mdbx_trace("%s: settled %u (+%u), continue", dbg_prefix_mode, settled,
-               chunk);
-
-    if (txn->tw.lifo_reclaimed &&
-        unlikely(amount < MDBX_PNL_SIZE(txn->tw.reclaimed_pglist)) &&
-        (loop < 5 || MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) - amount >
-                         env->me_maxgc_ov1page)) {
-      mdbx_notice("** restart: reclaimed-list growth %u -> %u", amount,
-                  (unsigned)MDBX_PNL_SIZE(txn->tw.reclaimed_pglist));
-      goto retry;
-    }
-
-    continue;
-  }
-
-  mdbx_tassert(
-      txn,
-      cleaned_gc_slot ==
-          (txn->tw.lifo_reclaimed ? MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) : 0));
-
-  mdbx_trace("%s", " >> filling");
-  /* Fill in the reserved records */
-  filled_gc_slot =
-      txn->tw.lifo_reclaimed
-          ? (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) - reused_gc_slot
-          : reused_gc_slot;
-  rc = MDBX_SUCCESS;
-  mdbx_tassert(txn,
-               mdbx_pnl_check4assert(txn->tw.reclaimed_pglist,
-                                     txn->mt_next_pgno - MDBX_ENABLE_REFUND));
-  mdbx_tassert(txn, mdbx_dirtylist_check(txn));
-  if (MDBX_PNL_SIZE(txn->tw.reclaimed_pglist)) {
-    MDBX_val key, data;
-    key.iov_len = data.iov_len = 0; /* avoid MSVC warning */
-    key.iov_base = data.iov_base = NULL;
-
-    const unsigned amount = MDBX_PNL_SIZE(txn->tw.reclaimed_pglist);
-    unsigned left = amount;
-    if (txn->tw.lifo_reclaimed == nullptr) {
-      mdbx_tassert(txn, lifo == 0);
-      rc = mdbx_cursor_first(&couple.outer, &key, &data);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-    } else {
-      mdbx_tassert(txn, lifo != 0);
-    }
-
-    while (true) {
-      txnid_t fill_gc_id;
-      mdbx_trace("%s: left %u of %u", dbg_prefix_mode, left,
-                 (unsigned)MDBX_PNL_SIZE(txn->tw.reclaimed_pglist));
-      if (txn->tw.lifo_reclaimed == nullptr) {
-        mdbx_tassert(txn, lifo == 0);
-        fill_gc_id = unaligned_peek_u64(4, key.iov_base);
-        if (filled_gc_slot-- == 0 || fill_gc_id > txn->tw.last_reclaimed) {
-          mdbx_notice(
-              "** restart: reserve depleted (filled_slot %u, fill_id %" PRIaTXN
-              " > last_reclaimed %" PRIaTXN,
-              filled_gc_slot, fill_gc_id, txn->tw.last_reclaimed);
-          goto retry;
-        }
-      } else {
-        mdbx_tassert(txn, lifo != 0);
-        if (++filled_gc_slot >
-            (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)) {
-          mdbx_notice("** restart: reserve depleted (filled_gc_slot %u > "
-                      "lifo_reclaimed %u" PRIaTXN,
-                      filled_gc_slot,
-                      (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed));
-          goto retry;
-        }
-        fill_gc_id = txn->tw.lifo_reclaimed[filled_gc_slot];
-        mdbx_trace("%s: seek-reservation @%" PRIaTXN " at lifo_reclaimed[%u]",
-                   dbg_prefix_mode, fill_gc_id, filled_gc_slot);
-        key.iov_base = &fill_gc_id;
-        key.iov_len = sizeof(fill_gc_id);
-        rc = mdbx_cursor_get(&couple.outer, &key, &data, MDBX_SET_KEY);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      }
-      mdbx_tassert(txn, cleaned_gc_slot ==
-                            (txn->tw.lifo_reclaimed
-                                 ? MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)
-                                 : 0));
-      mdbx_tassert(txn, fill_gc_id > 0 &&
-                            fill_gc_id < env->me_lck->mti_oldest_reader.weak);
-      key.iov_base = &fill_gc_id;
-      key.iov_len = sizeof(fill_gc_id);
-
-      mdbx_tassert(txn, data.iov_len >= sizeof(pgno_t) * 2);
-      couple.outer.mc_flags |= C_GCFREEZE;
-      unsigned chunk = (unsigned)(data.iov_len / sizeof(pgno_t)) - 1;
-      if (unlikely(chunk > left)) {
-        mdbx_trace("%s: chunk %u > left %u, @%" PRIaTXN, dbg_prefix_mode, chunk,
-                   left, fill_gc_id);
-        if ((loop < 5 && chunk - left > loop / 2) ||
-            chunk - left > env->me_maxgc_ov1page) {
-          data.iov_len = (left + 1) * sizeof(pgno_t);
-          if (loop < 7)
-            couple.outer.mc_flags &= ~C_GCFREEZE;
-        }
-        chunk = left;
-      }
-      rc = mdbx_cursor_put(&couple.outer, &key, &data,
-                           MDBX_CURRENT | MDBX_RESERVE);
-      couple.outer.mc_flags &= ~C_GCFREEZE;
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-      clean_reserved_gc_pnl(env, data);
-
-      if (unlikely(txn->tw.loose_count ||
-                   amount != MDBX_PNL_SIZE(txn->tw.reclaimed_pglist))) {
-        mdbx_notice("** restart: reclaimed-list growth (%u -> %u, loose +%u)",
-                    amount, MDBX_PNL_SIZE(txn->tw.reclaimed_pglist),
-                    txn->tw.loose_count);
-        goto retry;
-      }
-      if (unlikely(txn->tw.lifo_reclaimed
-                       ? cleaned_gc_slot < MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)
-                       : cleaned_gc_id < txn->tw.last_reclaimed)) {
-        mdbx_notice("%s", "** restart: reclaimed-slots changed");
-        goto retry;
-      }
-      if (unlikely(retired_stored != MDBX_PNL_SIZE(txn->tw.retired_pages))) {
-        mdbx_tassert(txn,
-                     retired_stored < MDBX_PNL_SIZE(txn->tw.retired_pages));
-        mdbx_notice("** restart: retired-list growth (%u -> %u)",
-                    retired_stored, MDBX_PNL_SIZE(txn->tw.retired_pages));
-        goto retry;
-      }
-
-      pgno_t *dst = data.iov_base;
-      *dst++ = chunk;
-      pgno_t *src = MDBX_PNL_BEGIN(txn->tw.reclaimed_pglist) + left - chunk;
-      memcpy(dst, src, chunk * sizeof(pgno_t));
-      pgno_t *from = src, *to = src + chunk;
-      mdbx_trace("%s: fill %u [ %u:%" PRIaPGNO "...%u:%" PRIaPGNO
-                 "] @%" PRIaTXN,
-                 dbg_prefix_mode, chunk,
-                 (unsigned)(from - txn->tw.reclaimed_pglist), from[0],
-                 (unsigned)(to - txn->tw.reclaimed_pglist), to[-1], fill_gc_id);
-
-      left -= chunk;
-      if (mdbx_audit_enabled()) {
-        rc = mdbx_audit_ex(txn, retired_stored + amount - left, true);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      }
-      if (left == 0) {
-        rc = MDBX_SUCCESS;
-        break;
-      }
-
-      if (txn->tw.lifo_reclaimed == nullptr) {
-        mdbx_tassert(txn, lifo == 0);
-        rc = mdbx_cursor_next(&couple.outer, &key, &data, MDBX_NEXT);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      } else {
-        mdbx_tassert(txn, lifo != 0);
-      }
-    }
-  }
-
-  mdbx_tassert(txn, rc == MDBX_SUCCESS);
-  if (unlikely(txn->tw.loose_count != 0)) {
-    mdbx_notice("** restart: got %u loose pages", txn->tw.loose_count);
-    goto retry;
-  }
-  if (unlikely(filled_gc_slot !=
-               (txn->tw.lifo_reclaimed
-                    ? (unsigned)MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)
-                    : 0))) {
-
-    const bool will_retry = loop < 9;
-    mdbx_notice("** %s: reserve excess (filled-slot %u, loop %u)",
-                will_retry ? "restart" : "ignore", filled_gc_slot, loop);
-    if (will_retry)
-      goto retry;
-  }
-
-  mdbx_tassert(txn,
-               txn->tw.lifo_reclaimed == NULL ||
-                   cleaned_gc_slot == MDBX_PNL_SIZE(txn->tw.lifo_reclaimed));
-
-bailout:
-  txn->mt_cursors[FREE_DBI] = couple.outer.mc_next;
-
-bailout_notracking:
-  MDBX_PNL_SIZE(txn->tw.reclaimed_pglist) = 0;
-  mdbx_trace("<<< %u loops, rc = %d", loop, rc);
-  return rc;
-}
-
-static int mdbx_txn_write(MDBX_txn *txn, struct mdbx_iov_ctx *ctx) {
-  MDBX_dpl *const dl =
-      (txn->mt_flags & MDBX_WRITEMAP) ? txn->tw.dirtylist : mdbx_dpl_sort(txn);
-  int rc = MDBX_SUCCESS;
-  unsigned r, w;
-  for (w = 0, r = 1; r <= dl->length; ++r) {
-    MDBX_page *dp = dl->items[r].ptr;
-    if (dp->mp_flags & P_LOOSE) {
-      dl->items[++w] = dl->items[r];
-      continue;
-    }
-    unsigned npages = dpl_npages(dl, r);
-    rc = iov_page(txn, ctx, dp, npages);
-    if (unlikely(rc != MDBX_SUCCESS))
-      break;
-  }
-
-  if (ctx->iov_items)
-    rc = mdbx_iov_write(txn, ctx);
-
-  while (r <= dl->length)
-    dl->items[++w] = dl->items[r++];
-
-  dl->sorted = dpl_setlen(dl, w);
-  txn->tw.dirtyroom += r - 1 - w;
-  mdbx_tassert(txn, txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                        (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                        : txn->mt_env->me_options.dp_limit));
-  return rc;
-}
-
-/* Check txn and dbi arguments to a function */
-static __always_inline bool check_dbi(MDBX_txn *txn, MDBX_dbi dbi,
-                                      unsigned validity) {
-  if (likely(dbi < txn->mt_numdbs))
-    return likely((txn->mt_dbistate[dbi] & validity) &&
-                  !TXN_DBI_CHANGED(txn, dbi) &&
-                  (txn->mt_dbxs[dbi].md_name.iov_base || dbi < CORE_DBS));
-
-  return dbi_import(txn, dbi);
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-int mdbx_txn_commit(MDBX_txn *txn) { return __inline_mdbx_txn_commit(txn); }
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-/* Merge child txn into parent */
-static __inline void mdbx_txn_merge(MDBX_txn *const parent, MDBX_txn *const txn,
-                                    const unsigned parent_retired_len) {
-  MDBX_dpl *const src = mdbx_dpl_sort(txn);
-
-  /* Remove refunded pages from parent's dirty list */
-  MDBX_dpl *const dst = mdbx_dpl_sort(parent);
-  if (MDBX_ENABLE_REFUND) {
-    unsigned n = dst->length;
-    while (n && dst->items[n].pgno >= parent->mt_next_pgno) {
-      if (!(txn->mt_env->me_flags & MDBX_WRITEMAP)) {
-        MDBX_page *dp = dst->items[n].ptr;
-        mdbx_dpage_free(txn->mt_env, dp, dpl_npages(dst, n));
-      }
-      --n;
-    }
-    parent->tw.dirtyroom += dst->sorted - n;
-    dst->sorted = dpl_setlen(dst, n);
-    mdbx_tassert(parent,
-                 parent->tw.dirtyroom + parent->tw.dirtylist->length ==
-                     (parent->mt_parent ? parent->mt_parent->tw.dirtyroom
-                                        : parent->mt_env->me_options.dp_limit));
-  }
-
-  /* Remove reclaimed pages from parent's dirty list */
-  const MDBX_PNL reclaimed_list = parent->tw.reclaimed_pglist;
-  mdbx_dpl_sift(parent, reclaimed_list, false);
-
-  /* Move retired pages from parent's dirty & spilled list to reclaimed */
-  unsigned r, w, d, s, l;
-  for (r = w = parent_retired_len;
-       ++r <= MDBX_PNL_SIZE(parent->tw.retired_pages);) {
-    const pgno_t pgno = parent->tw.retired_pages[r];
-    const unsigned di = mdbx_dpl_exist(parent, pgno);
-    const unsigned si = !di ? mdbx_search_spilled(parent, pgno) : 0;
-    unsigned npages;
-    const char *kind;
-    if (di) {
-      MDBX_page *dp = dst->items[di].ptr;
-      mdbx_tassert(parent, (dp->mp_flags & ~(P_LEAF | P_LEAF2 | P_BRANCH |
-                                             P_OVERFLOW | P_SPILLED)) == 0);
-      npages = dpl_npages(dst, di);
-      mdbx_page_wash(parent, di, dp, npages);
-      kind = "dirty";
-      l = 1;
-      if (unlikely(npages > l)) {
-        /* OVERFLOW-страница могла быть переиспользована по частям. Тогда
-         * в retired-списке может быть только начало последовательности,
-         * а остаток растащен по dirty, spilled и reclaimed спискам. Поэтому
-         * переносим в reclaimed с проверкой на обрыв последовательности.
-         * В любом случае, все осколки будут учтены и отфильтрованы, т.е. если
-         * страница была разбита на части, то важно удалить dirty-элемент,
-         * а все осколки будут учтены отдельно. */
-
-        /* Список retired страниц не сортирован, но для ускорения сортировки
-         * дополняется в соответствии с MDBX_PNL_ASCENDING */
-#if MDBX_PNL_ASCENDING
-        const unsigned len = MDBX_PNL_SIZE(parent->tw.retired_pages);
-        while (r < len && parent->tw.retired_pages[r + 1] == pgno + l) {
-          ++r;
-          if (++l == npages)
-            break;
-        }
-#else
-        while (w > parent_retired_len &&
-               parent->tw.retired_pages[w - 1] == pgno + l) {
-          --w;
-          if (++l == npages)
-            break;
-        }
-#endif
-      }
-    } else if (unlikely(si)) {
-      l = npages = 1;
-      mdbx_spill_remove(parent, si, 1);
-      kind = "spilled";
-    } else {
-      parent->tw.retired_pages[++w] = pgno;
-      continue;
-    }
-
-    mdbx_debug("reclaim retired parent's %u->%u %s page %" PRIaPGNO, npages, l,
-               kind, pgno);
-    int err = mdbx_pnl_insert_range(&parent->tw.reclaimed_pglist, pgno, l);
-    mdbx_ensure(txn->mt_env, err == MDBX_SUCCESS);
-  }
-  MDBX_PNL_SIZE(parent->tw.retired_pages) = w;
-
-  /* Filter-out parent spill list */
-  if (parent->tw.spill_pages && MDBX_PNL_SIZE(parent->tw.spill_pages) > 0) {
-    const MDBX_PNL sl = mdbx_spill_purge(parent);
-    unsigned len = MDBX_PNL_SIZE(sl);
-    if (len) {
-      /* Remove refunded pages from parent's spill list */
-      if (MDBX_ENABLE_REFUND &&
-          MDBX_PNL_MOST(sl) >= (parent->mt_next_pgno << 1)) {
-#if MDBX_PNL_ASCENDING
-        unsigned i = MDBX_PNL_SIZE(sl);
-        assert(MDBX_PNL_MOST(sl) == MDBX_PNL_LAST(sl));
-        do {
-          if ((sl[i] & 1) == 0)
-            mdbx_debug("refund parent's spilled page %" PRIaPGNO, sl[i] >> 1);
-          i -= 1;
-        } while (i && sl[i] >= (parent->mt_next_pgno << 1));
-        MDBX_PNL_SIZE(sl) = i;
-#else
-        assert(MDBX_PNL_MOST(sl) == MDBX_PNL_FIRST(sl));
-        unsigned i = 0;
-        do {
-          ++i;
-          if ((sl[i] & 1) == 0)
-            mdbx_debug("refund parent's spilled page %" PRIaPGNO, sl[i] >> 1);
-        } while (i < len && sl[i + 1] >= (parent->mt_next_pgno << 1));
-        MDBX_PNL_SIZE(sl) = len -= i;
-        memmove(sl + 1, sl + 1 + i, len * sizeof(sl[0]));
-#endif
-      }
-      mdbx_tassert(
-          txn, mdbx_pnl_check4assert(sl, (size_t)parent->mt_next_pgno << 1));
-
-      /* Remove reclaimed pages from parent's spill list */
-      s = MDBX_PNL_SIZE(sl), r = MDBX_PNL_SIZE(reclaimed_list);
-      /* Scanning from end to begin */
-      while (s && r) {
-        if (sl[s] & 1) {
-          --s;
-          continue;
-        }
-        const pgno_t spilled_pgno = sl[s] >> 1;
-        const pgno_t reclaimed_pgno = reclaimed_list[r];
-        if (reclaimed_pgno != spilled_pgno) {
-          const bool cmp = MDBX_PNL_ORDERED(spilled_pgno, reclaimed_pgno);
-          s -= !cmp;
-          r -= cmp;
-        } else {
-          mdbx_debug("remove reclaimed parent's spilled page %" PRIaPGNO,
-                     reclaimed_pgno);
-          mdbx_spill_remove(parent, s, 1);
-          --s;
-          --r;
-        }
-      }
-
-      /* Remove anything in our dirty list from parent's spill list */
-      /* Scanning spill list in descend order */
-      const int step = MDBX_PNL_ASCENDING ? -1 : 1;
-      s = MDBX_PNL_ASCENDING ? MDBX_PNL_SIZE(sl) : 1;
-      d = src->length;
-      while (d && (MDBX_PNL_ASCENDING ? s > 0 : s <= MDBX_PNL_SIZE(sl))) {
-        if (sl[s] & 1) {
-          s += step;
-          continue;
-        }
-        const pgno_t spilled_pgno = sl[s] >> 1;
-        const pgno_t dirty_pgno_form = src->items[d].pgno;
-        const unsigned npages = dpl_npages(src, d);
-        const pgno_t dirty_pgno_to = dirty_pgno_form + npages;
-        if (dirty_pgno_form > spilled_pgno) {
-          --d;
-          continue;
-        }
-        if (dirty_pgno_to <= spilled_pgno) {
-          s += step;
-          continue;
-        }
-
-        mdbx_debug("remove dirtied parent's spilled %u page %" PRIaPGNO, npages,
-                   dirty_pgno_form);
-        mdbx_spill_remove(parent, s, 1);
-        s += step;
-      }
-
-      /* Squash deleted pagenums if we deleted any */
-      mdbx_spill_purge(parent);
-    }
-  }
-
-  /* Remove anything in our spill list from parent's dirty list */
-  if (txn->tw.spill_pages) {
-    mdbx_tassert(txn, mdbx_pnl_check4assert(txn->tw.spill_pages,
-                                            (size_t)parent->mt_next_pgno << 1));
-    mdbx_dpl_sift(parent, txn->tw.spill_pages, true);
-    mdbx_tassert(parent,
-                 parent->tw.dirtyroom + parent->tw.dirtylist->length ==
-                     (parent->mt_parent ? parent->mt_parent->tw.dirtyroom
-                                        : parent->mt_env->me_options.dp_limit));
-  }
-
-  /* Find length of merging our dirty list with parent's and release
-   * filter-out pages */
-  for (l = 0, d = dst->length, s = src->length; d > 0 && s > 0;) {
-    MDBX_page *sp = src->items[s].ptr;
-    mdbx_tassert(parent,
-                 (sp->mp_flags & ~(P_LEAF | P_LEAF2 | P_BRANCH | P_OVERFLOW |
-                                   P_LOOSE | P_SPILLED)) == 0);
-    const unsigned s_npages = dpl_npages(src, s);
-    const pgno_t s_pgno = src->items[s].pgno;
-
-    MDBX_page *dp = dst->items[d].ptr;
-    mdbx_tassert(parent, (dp->mp_flags & ~(P_LEAF | P_LEAF2 | P_BRANCH |
-                                           P_OVERFLOW | P_SPILLED)) == 0);
-    const unsigned d_npages = dpl_npages(dst, d);
-    const pgno_t d_pgno = dst->items[d].pgno;
-
-    if (d_pgno >= s_pgno + s_npages) {
-      --d;
-      ++l;
-    } else if (d_pgno + d_npages <= s_pgno) {
-      if (sp->mp_flags != P_LOOSE) {
-        sp->mp_txnid = parent->mt_front;
-        sp->mp_flags &= ~P_SPILLED;
-      }
-      --s;
-      ++l;
-    } else {
-      dst->items[d--].ptr = nullptr;
-      if ((txn->mt_flags & MDBX_WRITEMAP) == 0)
-        mdbx_dpage_free(txn->mt_env, dp, d_npages);
-    }
-  }
-  assert(dst->sorted == dst->length);
-  mdbx_tassert(parent, dst->detent >= l + d + s);
-  dst->sorted = l + d + s; /* the merged length */
-
-  while (s > 0) {
-    MDBX_page *sp = src->items[s].ptr;
-    mdbx_tassert(parent,
-                 (sp->mp_flags & ~(P_LEAF | P_LEAF2 | P_BRANCH | P_OVERFLOW |
-                                   P_LOOSE | P_SPILLED)) == 0);
-    if (sp->mp_flags != P_LOOSE) {
-      sp->mp_txnid = parent->mt_front;
-      sp->mp_flags &= ~P_SPILLED;
-    }
-    --s;
-  }
-
-  /* Merge our dirty list into parent's, i.e. merge(dst, src) -> dst */
-  if (dst->sorted >= dst->length) {
-    /* from end to begin with dst extending */
-    for (l = dst->sorted, s = src->length, d = dst->length; s > 0 && d > 0;) {
-      if (unlikely(l <= d)) {
-        /* squash to get a gap of free space for merge */
-        for (r = w = 1; r <= d; ++r)
-          if (dst->items[r].ptr) {
-            if (w != r) {
-              dst->items[w] = dst->items[r];
-              dst->items[r].ptr = nullptr;
-            }
-            ++w;
-          }
-        mdbx_notice("squash to begin for extending-merge %u -> %u", d, w - 1);
-        d = w - 1;
-        continue;
-      }
-      assert(l > d);
-      if (dst->items[d].ptr) {
-        dst->items[l--] = (dst->items[d].pgno > src->items[s].pgno)
-                              ? dst->items[d--]
-                              : src->items[s--];
-      } else
-        --d;
-    }
-    if (s > 0) {
-      assert(l == s);
-      while (d > 0) {
-        assert(dst->items[d].ptr == nullptr);
-        --d;
-      }
-      do {
-        assert(l > 0);
-        dst->items[l--] = src->items[s--];
-      } while (s > 0);
-    } else {
-      assert(l == d);
-      while (l > 0) {
-        assert(dst->items[l].ptr != nullptr);
-        --l;
-      }
-    }
-  } else {
-    /* from begin to end with dst shrinking (a lot of new overflow pages) */
-    for (l = s = d = 1; s <= src->length && d <= dst->length;) {
-      if (unlikely(l >= d)) {
-        /* squash to get a gap of free space for merge */
-        for (r = w = dst->length; r >= d; --r)
-          if (dst->items[r].ptr) {
-            if (w != r) {
-              dst->items[w] = dst->items[r];
-              dst->items[r].ptr = nullptr;
-            }
-            --w;
-          }
-        mdbx_notice("squash to end for shrinking-merge %u -> %u", d, w + 1);
-        d = w + 1;
-        continue;
-      }
-      assert(l < d);
-      if (dst->items[d].ptr) {
-        dst->items[l++] = (dst->items[d].pgno < src->items[s].pgno)
-                              ? dst->items[d++]
-                              : src->items[s++];
-      } else
-        ++d;
-    }
-    if (s <= src->length) {
-      assert(dst->sorted - l == src->length - s);
-      while (d <= dst->length) {
-        assert(dst->items[d].ptr == nullptr);
-        --d;
-      }
-      do {
-        assert(l <= dst->sorted);
-        dst->items[l++] = src->items[s++];
-      } while (s <= src->length);
-    } else {
-      assert(dst->sorted - l == dst->length - d);
-      while (l <= dst->sorted) {
-        assert(l <= d && d <= dst->length && dst->items[d].ptr);
-        dst->items[l++] = dst->items[d++];
-      }
-    }
-  }
-  parent->tw.dirtyroom -= dst->sorted - dst->length;
-  assert(parent->tw.dirtyroom <= parent->mt_env->me_options.dp_limit);
-  dpl_setlen(dst, dst->sorted);
-  parent->tw.dirtylru = txn->tw.dirtylru;
-  mdbx_tassert(parent, mdbx_dirtylist_check(parent));
-  mdbx_dpl_free(txn);
-
-  if (txn->tw.spill_pages) {
-    if (parent->tw.spill_pages) {
-      /* Must not fail since space was preserved above. */
-      mdbx_pnl_xmerge(parent->tw.spill_pages, txn->tw.spill_pages);
-      mdbx_pnl_free(txn->tw.spill_pages);
-    } else {
-      parent->tw.spill_pages = txn->tw.spill_pages;
-      parent->tw.spill_least_removed = txn->tw.spill_least_removed;
-    }
-    mdbx_tassert(parent, mdbx_dirtylist_check(parent));
-  }
-
-  parent->mt_flags &= ~MDBX_TXN_HAS_CHILD;
-  if (parent->tw.spill_pages) {
-    assert(mdbx_pnl_check4assert(parent->tw.spill_pages,
-                                 (size_t)parent->mt_next_pgno << 1));
-    if (MDBX_PNL_SIZE(parent->tw.spill_pages))
-      parent->mt_flags |= MDBX_TXN_SPILLS;
-  }
-}
-
-int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
-  STATIC_ASSERT(MDBX_TXN_FINISHED ==
-                MDBX_TXN_BLOCKED - MDBX_TXN_HAS_CHILD - MDBX_TXN_ERROR);
-  const uint64_t ts_0 = latency ? mdbx_osal_monotime() : 0;
-  uint64_t ts_1 = 0, ts_2 = 0, ts_3 = 0, ts_4 = 0;
-  uint32_t audit_duration = 0;
-
-  int rc = check_txn(txn, MDBX_TXN_FINISHED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto provide_latency;
-
-  if (unlikely(txn->mt_flags & MDBX_TXN_ERROR)) {
-    rc = MDBX_RESULT_TRUE;
-    goto fail;
-  }
-
-  MDBX_env *env = txn->mt_env;
-#if MDBX_ENV_CHECKPID
-  if (unlikely(env->me_pid != mdbx_getpid())) {
-    env->me_flags |= MDBX_FATAL_ERROR;
-    rc = MDBX_PANIC;
-    goto provide_latency;
-  }
-#endif /* MDBX_ENV_CHECKPID */
-
-  /* mdbx_txn_end() mode for a commit which writes nothing */
-  unsigned end_mode =
-      MDBX_END_PURE_COMMIT | MDBX_END_UPDATE | MDBX_END_SLOT | MDBX_END_FREE;
-  if (unlikely(F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
-    goto done;
-
-  if (txn->mt_child) {
-    rc = mdbx_txn_commit_ex(txn->mt_child, NULL);
-    mdbx_tassert(txn, txn->mt_child == NULL);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-  }
-
-  if (unlikely(txn != env->me_txn)) {
-    mdbx_debug("%s", "attempt to commit unknown transaction");
-    rc = MDBX_EINVAL;
-    goto fail;
-  }
-
-  if (txn->mt_parent) {
-    mdbx_tassert(txn, mdbx_audit_ex(txn, 0, false) == 0);
-    mdbx_assert(env, txn != env->me_txn0);
-    MDBX_txn *const parent = txn->mt_parent;
-    mdbx_assert(env, parent->mt_signature == MDBX_MT_SIGNATURE);
-    mdbx_assert(env, parent->mt_child == txn &&
-                         (parent->mt_flags & MDBX_TXN_HAS_CHILD) != 0);
-    mdbx_assert(env, mdbx_dirtylist_check(txn));
-
-    if (txn->tw.dirtylist->length == 0 && !(txn->mt_flags & MDBX_TXN_DIRTY) &&
-        parent->mt_numdbs == txn->mt_numdbs) {
-      for (int i = txn->mt_numdbs; --i >= 0;) {
-        mdbx_tassert(txn, (txn->mt_dbistate[i] & DBI_DIRTY) == 0);
-        if ((txn->mt_dbistate[i] & DBI_STALE) &&
-            !(parent->mt_dbistate[i] & DBI_STALE))
-          mdbx_tassert(txn, memcmp(&parent->mt_dbs[i], &txn->mt_dbs[i],
-                                   sizeof(MDBX_db)) == 0);
-      }
-
-      mdbx_tassert(txn, memcmp(&parent->mt_geo, &txn->mt_geo,
-                               sizeof(parent->mt_geo)) == 0);
-      mdbx_tassert(txn, memcmp(&parent->mt_canary, &txn->mt_canary,
-                               sizeof(parent->mt_canary)) == 0);
-      mdbx_tassert(txn, !txn->tw.spill_pages ||
-                            MDBX_PNL_SIZE(txn->tw.spill_pages) == 0);
-      mdbx_tassert(txn, txn->tw.loose_count == 0);
-
-      /* fast completion of pure nested transaction */
-      end_mode = MDBX_END_PURE_COMMIT | MDBX_END_SLOT | MDBX_END_FREE;
-      goto done;
-    }
-
-    /* Preserve space for spill list to avoid parent's state corruption
-     * if allocation fails. */
-    const unsigned parent_retired_len =
-        (unsigned)(uintptr_t)parent->tw.retired_pages;
-    mdbx_tassert(txn,
-                 parent_retired_len <= MDBX_PNL_SIZE(txn->tw.retired_pages));
-    const unsigned retired_delta =
-        MDBX_PNL_SIZE(txn->tw.retired_pages) - parent_retired_len;
-    if (retired_delta) {
-      rc = mdbx_pnl_need(&txn->tw.reclaimed_pglist, retired_delta);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto fail;
-    }
-
-    if (txn->tw.spill_pages) {
-      if (parent->tw.spill_pages) {
-        rc = mdbx_pnl_need(&parent->tw.spill_pages,
-                           MDBX_PNL_SIZE(txn->tw.spill_pages));
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto fail;
-      }
-      mdbx_spill_purge(txn);
-    }
-
-    if (unlikely(txn->tw.dirtylist->length + parent->tw.dirtylist->length >
-                     parent->tw.dirtylist->detent &&
-                 !mdbx_dpl_reserve(parent, txn->tw.dirtylist->length +
-                                               parent->tw.dirtylist->length))) {
-      rc = MDBX_ENOMEM;
-      goto fail;
-    }
-
-    //-------------------------------------------------------------------------
-
-    parent->tw.lifo_reclaimed = txn->tw.lifo_reclaimed;
-    txn->tw.lifo_reclaimed = NULL;
-
-    parent->tw.retired_pages = txn->tw.retired_pages;
-    txn->tw.retired_pages = NULL;
-
-    mdbx_pnl_free(parent->tw.reclaimed_pglist);
-    parent->tw.reclaimed_pglist = txn->tw.reclaimed_pglist;
-    txn->tw.reclaimed_pglist = NULL;
-    parent->tw.last_reclaimed = txn->tw.last_reclaimed;
-
-    parent->mt_geo = txn->mt_geo;
-    parent->mt_canary = txn->mt_canary;
-    parent->mt_flags |= txn->mt_flags & MDBX_TXN_DIRTY;
-
-    /* Move loose pages to parent */
-#if MDBX_ENABLE_REFUND
-    parent->tw.loose_refund_wl = txn->tw.loose_refund_wl;
-#endif /* MDBX_ENABLE_REFUND */
-    parent->tw.loose_count = txn->tw.loose_count;
-    parent->tw.loose_pages = txn->tw.loose_pages;
-
-    /* Merge our cursors into parent's and close them */
-    mdbx_cursors_eot(txn, true);
-    end_mode |= MDBX_END_EOTDONE;
-
-    /* Update parent's DBs array */
-    memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDBX_db));
-    parent->mt_numdbs = txn->mt_numdbs;
-    for (unsigned i = 0; i < txn->mt_numdbs; i++) {
-      /* preserve parent's status */
-      const uint8_t state =
-          txn->mt_dbistate[i] |
-          (parent->mt_dbistate[i] & (DBI_CREAT | DBI_FRESH | DBI_DIRTY));
-      mdbx_debug("db %u dbi-state %s 0x%02x -> 0x%02x", i,
-                 (parent->mt_dbistate[i] != state) ? "update" : "still",
-                 parent->mt_dbistate[i], state);
-      parent->mt_dbistate[i] = state;
-    }
-
-    ts_1 = latency ? mdbx_osal_monotime() : 0;
-    mdbx_txn_merge(parent, txn, parent_retired_len);
-    ts_2 = latency ? mdbx_osal_monotime() : 0;
-    env->me_txn = parent;
-    parent->mt_child = NULL;
-    mdbx_tassert(parent, mdbx_dirtylist_check(parent));
-
-#if MDBX_ENABLE_REFUND
-    mdbx_refund(parent);
-    if (mdbx_assert_enabled()) {
-      /* Check parent's loose pages not suitable for refund */
-      for (MDBX_page *lp = parent->tw.loose_pages; lp; lp = lp->mp_next)
-        mdbx_tassert(parent, lp->mp_pgno < parent->tw.loose_refund_wl &&
-                                 lp->mp_pgno + 1 < parent->mt_next_pgno);
-      /* Check parent's reclaimed pages not suitable for refund */
-      if (MDBX_PNL_SIZE(parent->tw.reclaimed_pglist))
-        mdbx_tassert(parent, MDBX_PNL_MOST(parent->tw.reclaimed_pglist) + 1 <
-                                 parent->mt_next_pgno);
-    }
-#endif /* MDBX_ENABLE_REFUND */
-
-    ts_4 = ts_3 = latency ? mdbx_osal_monotime() : 0;
-    txn->mt_signature = 0;
-    mdbx_free(txn);
-    mdbx_tassert(parent, mdbx_audit_ex(parent, 0, false) == 0);
-    rc = MDBX_SUCCESS;
-    goto provide_latency;
-  }
-
-  mdbx_tassert(txn, txn->tw.dirtyroom + txn->tw.dirtylist->length ==
-                        (txn->mt_parent ? txn->mt_parent->tw.dirtyroom
-                                        : txn->mt_env->me_options.dp_limit));
-  mdbx_cursors_eot(txn, false);
-  end_mode |= MDBX_END_EOTDONE;
-
-  if (txn->tw.dirtylist->length == 0 &&
-      (txn->mt_flags & (MDBX_TXN_DIRTY | MDBX_TXN_SPILLS)) == 0) {
-    for (int i = txn->mt_numdbs; --i >= 0;)
-      mdbx_tassert(txn, (txn->mt_dbistate[i] & DBI_DIRTY) == 0);
-    rc = MDBX_SUCCESS;
-    goto done;
-  }
-
-  mdbx_debug("committing txn %" PRIaTXN " %p on mdbenv %p, root page %" PRIaPGNO
-             "/%" PRIaPGNO,
-             txn->mt_txnid, (void *)txn, (void *)env,
-             txn->mt_dbs[MAIN_DBI].md_root, txn->mt_dbs[FREE_DBI].md_root);
-
-  /* Update DB root pointers */
-  if (txn->mt_numdbs > CORE_DBS) {
-    MDBX_cursor_couple couple;
-    MDBX_val data;
-    data.iov_len = sizeof(MDBX_db);
-
-    rc = mdbx_cursor_init(&couple.outer, txn, MAIN_DBI);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-    for (MDBX_dbi i = CORE_DBS; i < txn->mt_numdbs; i++) {
-      if (txn->mt_dbistate[i] & DBI_DIRTY) {
-        if (unlikely(TXN_DBI_CHANGED(txn, i))) {
-          rc = MDBX_BAD_DBI;
-          goto fail;
-        }
-        MDBX_db *db = &txn->mt_dbs[i];
-        mdbx_debug("update main's entry for sub-db %u, mod_txnid %" PRIaTXN
-                   " -> %" PRIaTXN,
-                   i, db->md_mod_txnid, txn->mt_txnid);
-        db->md_mod_txnid = txn->mt_txnid;
-        data.iov_base = db;
-        WITH_CURSOR_TRACKING(couple.outer,
-                             rc = mdbx_cursor_put(&couple.outer,
-                                                  &txn->mt_dbxs[i].md_name,
-                                                  &data, F_SUBDATA));
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto fail;
-      }
-    }
-  }
-
-  ts_1 = latency ? mdbx_osal_monotime() : 0;
-  rc = mdbx_update_gc(txn);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto fail;
-
-  txn->mt_dbs[FREE_DBI].md_mod_txnid = (txn->mt_dbistate[FREE_DBI] & DBI_DIRTY)
-                                           ? txn->mt_txnid
-                                           : txn->mt_dbs[FREE_DBI].md_mod_txnid;
-
-  txn->mt_dbs[MAIN_DBI].md_mod_txnid = (txn->mt_dbistate[MAIN_DBI] & DBI_DIRTY)
-                                           ? txn->mt_txnid
-                                           : txn->mt_dbs[MAIN_DBI].md_mod_txnid;
-
-  ts_2 = latency ? mdbx_osal_monotime() : 0;
-  if (mdbx_audit_enabled()) {
-    rc = mdbx_audit_ex(txn, MDBX_PNL_SIZE(txn->tw.retired_pages), true);
-    const uint64_t audit_end = mdbx_osal_monotime();
-    audit_duration = mdbx_osal_monotime_to_16dot16(audit_end - ts_2);
-    ts_2 = audit_end;
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-  }
-
-  struct mdbx_iov_ctx ctx;
-  mdbx_iov_init(txn, &ctx);
-  rc = mdbx_txn_write(txn, &ctx);
-  if (likely(rc == MDBX_SUCCESS))
-    mdbx_iov_done(txn, &ctx);
-  /* TODO: use ctx.flush_begin & ctx.flush_end for range-sync */
-  ts_3 = latency ? mdbx_osal_monotime() : 0;
-
-  if (likely(rc == MDBX_SUCCESS)) {
-    const MDBX_meta *head = constmeta_prefer_last(env);
-    MDBX_meta meta;
-    memcpy(meta.mm_magic_and_version, head->mm_magic_and_version, 8);
-    meta.mm_extra_flags = head->mm_extra_flags;
-    meta.mm_validator_id = head->mm_validator_id;
-    meta.mm_extra_pagehdr = head->mm_extra_pagehdr;
-    unaligned_poke_u64(4, meta.mm_pages_retired,
-                       unaligned_peek_u64(4, head->mm_pages_retired) +
-                           MDBX_PNL_SIZE(txn->tw.retired_pages));
-    meta.mm_geo = txn->mt_geo;
-    meta.mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI];
-    meta.mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI];
-    meta.mm_canary = txn->mt_canary;
-    meta_set_txnid(env, &meta, txn->mt_txnid);
-
-    rc = mdbx_sync_locked(
-        env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, &meta);
-  }
-  ts_4 = latency ? mdbx_osal_monotime() : 0;
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    env->me_flags |= MDBX_FATAL_ERROR;
-    goto fail;
-  }
-
-  end_mode = MDBX_END_COMMITTED | MDBX_END_UPDATE | MDBX_END_EOTDONE;
-
-done:
-  rc = mdbx_txn_end(txn, end_mode);
-
-provide_latency:
-  if (latency) {
-    latency->audit = audit_duration;
-    latency->preparation =
-        ts_1 ? mdbx_osal_monotime_to_16dot16(ts_1 - ts_0) : 0;
-    latency->gc =
-        (ts_1 && ts_2) ? mdbx_osal_monotime_to_16dot16(ts_2 - ts_1) : 0;
-    latency->write =
-        (ts_2 && ts_3) ? mdbx_osal_monotime_to_16dot16(ts_3 - ts_2) : 0;
-    latency->sync =
-        (ts_3 && ts_4) ? mdbx_osal_monotime_to_16dot16(ts_4 - ts_3) : 0;
-    const uint64_t ts_5 = mdbx_osal_monotime();
-    latency->ending = ts_4 ? mdbx_osal_monotime_to_16dot16(ts_5 - ts_4) : 0;
-    latency->whole = mdbx_osal_monotime_to_16dot16(ts_5 - ts_0);
-  }
-  return rc;
-
-fail:
-  mdbx_txn_abort(txn);
-  goto provide_latency;
-}
-
-static int mdbx_validate_meta(MDBX_env *env, MDBX_meta *const meta,
-                              const MDBX_page *const page,
-                              const unsigned meta_number,
-                              unsigned *guess_pagesize) {
-  const uint64_t magic_and_version =
-      unaligned_peek_u64(4, &meta->mm_magic_and_version);
-  if (unlikely(magic_and_version != MDBX_DATA_MAGIC &&
-               magic_and_version != MDBX_DATA_MAGIC_LEGACY_COMPAT &&
-               magic_and_version != MDBX_DATA_MAGIC_LEGACY_DEVEL)) {
-    mdbx_error("meta[%u] has invalid magic/version %" PRIx64, meta_number,
-               magic_and_version);
-    return ((magic_and_version >> 8) != MDBX_MAGIC) ? MDBX_INVALID
-                                                    : MDBX_VERSION_MISMATCH;
-  }
-
-  if (unlikely(page->mp_pgno != meta_number)) {
-    mdbx_error("meta[%u] has invalid pageno %" PRIaPGNO, meta_number,
-               page->mp_pgno);
-    return MDBX_INVALID;
-  }
-
-  if (unlikely(page->mp_flags != P_META)) {
-    mdbx_error("page #%u not a meta-page", meta_number);
-    return MDBX_INVALID;
-  }
-
-  /* LY: check pagesize */
-  if (unlikely(!is_powerof2(meta->mm_psize) || meta->mm_psize < MIN_PAGESIZE ||
-               meta->mm_psize > MAX_PAGESIZE)) {
-    mdbx_warning("meta[%u] has invalid pagesize (%u), skip it", meta_number,
-                 meta->mm_psize);
-    return is_powerof2(meta->mm_psize) ? MDBX_VERSION_MISMATCH : MDBX_INVALID;
-  }
-
-  if (guess_pagesize && *guess_pagesize != meta->mm_psize) {
-    *guess_pagesize = meta->mm_psize;
-    mdbx_verbose("meta[%u] took pagesize %u", meta_number, meta->mm_psize);
-  }
-
-  const txnid_t txnid = unaligned_peek_u64(4, &meta->mm_txnid_a);
-  if (unlikely(txnid != unaligned_peek_u64(4, &meta->mm_txnid_b))) {
-    mdbx_warning("meta[%u] not completely updated, skip it", meta_number);
-    return MDBX_RESULT_TRUE;
-  }
-
-  /* LY: check signature as a checksum */
-  if (META_IS_STEADY(meta) &&
-      unlikely(unaligned_peek_u64(4, &meta->mm_datasync_sign) !=
-               meta_sign(meta))) {
-    mdbx_warning("meta[%u] has invalid steady-checksum (0x%" PRIx64
-                 " != 0x%" PRIx64 "), skip it",
-                 meta_number, unaligned_peek_u64(4, &meta->mm_datasync_sign),
-                 meta_sign(meta));
-    return MDBX_RESULT_TRUE;
-  }
-
-  mdbx_debug("checking meta%" PRIaPGNO " = root %" PRIaPGNO "/%" PRIaPGNO
-             ", geo %" PRIaPGNO "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO
-             " +%u -%u, txn_id %" PRIaTXN ", %s",
-             page->mp_pgno, meta->mm_dbs[MAIN_DBI].md_root,
-             meta->mm_dbs[FREE_DBI].md_root, meta->mm_geo.lower,
-             meta->mm_geo.next, meta->mm_geo.now, meta->mm_geo.upper,
-             pv2pages(meta->mm_geo.grow_pv), pv2pages(meta->mm_geo.shrink_pv),
-             txnid, mdbx_durable_str(meta));
-
-  if (unlikely(txnid < MIN_TXNID || txnid > MAX_TXNID)) {
-    mdbx_warning("meta[%u] has invalid txnid %" PRIaTXN ", skip it",
-                 meta_number, txnid);
-    return MDBX_RESULT_TRUE;
-  }
-
-  /* LY: check min-pages value */
-  if (unlikely(meta->mm_geo.lower < MIN_PAGENO ||
-               meta->mm_geo.lower > MAX_PAGENO + 1)) {
-    mdbx_warning("meta[%u] has invalid min-pages (%" PRIaPGNO "), skip it",
-                 meta_number, meta->mm_geo.lower);
-    return MDBX_INVALID;
-  }
-
-  /* LY: check max-pages value */
-  if (unlikely(meta->mm_geo.upper < MIN_PAGENO ||
-               meta->mm_geo.upper > MAX_PAGENO + 1 ||
-               meta->mm_geo.upper < meta->mm_geo.lower)) {
-    mdbx_warning("meta[%u] has invalid max-pages (%" PRIaPGNO "), skip it",
-                 meta_number, meta->mm_geo.upper);
-    return MDBX_INVALID;
-  }
-
-  /* LY: check last_pgno */
-  if (unlikely(meta->mm_geo.next < MIN_PAGENO ||
-               meta->mm_geo.next - 1 > MAX_PAGENO)) {
-    mdbx_warning("meta[%u] has invalid next-pageno (%" PRIaPGNO "), skip it",
-                 meta_number, meta->mm_geo.next);
-    return MDBX_CORRUPTED;
-  }
-
-  /* LY: check filesize & used_bytes */
-  const uint64_t used_bytes = meta->mm_geo.next * (uint64_t)meta->mm_psize;
-  if (unlikely(used_bytes > env->me_dxb_mmap.filesize)) {
-    /* Here could be a race with DB-shrinking performed by other process */
-    int err = mdbx_filesize(env->me_lazy_fd, &env->me_dxb_mmap.filesize);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-    if (unlikely(used_bytes > env->me_dxb_mmap.filesize)) {
-      mdbx_warning("meta[%u] used-bytes (%" PRIu64 ") beyond filesize (%" PRIu64
-                   "), skip it",
-                   meta_number, used_bytes, env->me_dxb_mmap.filesize);
-      return MDBX_CORRUPTED;
-    }
-  }
-  if (unlikely(meta->mm_geo.next - 1 > MAX_PAGENO ||
-               used_bytes > MAX_MAPSIZE)) {
-    mdbx_warning("meta[%u] has too large used-space (%" PRIu64 "), skip it",
-                 meta_number, used_bytes);
-    return MDBX_TOO_LARGE;
-  }
-
-  /* LY: check mapsize limits */
-  pgno_t geo_lower = meta->mm_geo.lower;
-  uint64_t mapsize_min = geo_lower * (uint64_t)meta->mm_psize;
-  STATIC_ASSERT(MAX_MAPSIZE < PTRDIFF_MAX - MAX_PAGESIZE);
-  STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
-  STATIC_ASSERT((uint64_t)(MAX_PAGENO + 1) * MIN_PAGESIZE % (4ul << 20) == 0);
-  if (unlikely(mapsize_min < MIN_MAPSIZE || mapsize_min > MAX_MAPSIZE)) {
-    if (MAX_MAPSIZE != MAX_MAPSIZE64 && mapsize_min > MAX_MAPSIZE &&
-        mapsize_min <= MAX_MAPSIZE64) {
-      mdbx_assert(env, meta->mm_geo.next - 1 <= MAX_PAGENO &&
-                           used_bytes <= MAX_MAPSIZE);
-      mdbx_warning("meta[%u] has too large min-mapsize (%" PRIu64 "), "
-                   "but size of used space still acceptable (%" PRIu64 ")",
-                   meta_number, mapsize_min, used_bytes);
-      geo_lower = (pgno_t)((mapsize_min = MAX_MAPSIZE) / meta->mm_psize);
-      if (geo_lower > MAX_PAGENO + 1) {
-        geo_lower = MAX_PAGENO + 1;
-        mapsize_min = geo_lower * (uint64_t)meta->mm_psize;
-      }
-      mdbx_warning("meta[%u] consider get-%s pageno is %" PRIaPGNO
-                   " instead of wrong %" PRIaPGNO
-                   ", will be corrected on next commit(s)",
-                   meta_number, "lower", geo_lower, meta->mm_geo.lower);
-      meta->mm_geo.lower = geo_lower;
-    } else {
-      mdbx_warning("meta[%u] has invalid min-mapsize (%" PRIu64 "), skip it",
-                   meta_number, mapsize_min);
-      return MDBX_VERSION_MISMATCH;
-    }
-  }
-
-  pgno_t geo_upper = meta->mm_geo.upper;
-  uint64_t mapsize_max = geo_upper * (uint64_t)meta->mm_psize;
-  STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
-  if (unlikely(mapsize_max > MAX_MAPSIZE ||
-               (MAX_PAGENO + 1) <
-                   ceil_powerof2((size_t)mapsize_max, env->me_os_psize) /
-                       (size_t)meta->mm_psize)) {
-    if (mapsize_max > MAX_MAPSIZE64) {
-      mdbx_warning("meta[%u] has invalid max-mapsize (%" PRIu64 "), skip it",
-                   meta_number, mapsize_max);
-      return MDBX_VERSION_MISMATCH;
-    }
-    /* allow to open large DB from a 32-bit environment */
-    mdbx_assert(env, meta->mm_geo.next - 1 <= MAX_PAGENO &&
-                         used_bytes <= MAX_MAPSIZE);
-    mdbx_warning("meta[%u] has too large max-mapsize (%" PRIu64 "), "
-                 "but size of used space still acceptable (%" PRIu64 ")",
-                 meta_number, mapsize_max, used_bytes);
-    geo_upper = (pgno_t)((mapsize_max = MAX_MAPSIZE) / meta->mm_psize);
-    if (geo_upper > MAX_PAGENO + 1) {
-      geo_upper = MAX_PAGENO + 1;
-      mapsize_max = geo_upper * (uint64_t)meta->mm_psize;
-    }
-    mdbx_warning("meta[%u] consider get-%s pageno is %" PRIaPGNO
-                 " instead of wrong %" PRIaPGNO
-                 ", will be corrected on next commit(s)",
-                 meta_number, "upper", geo_upper, meta->mm_geo.upper);
-    meta->mm_geo.upper = geo_upper;
-  }
-
-  /* LY: check and silently put mm_geo.now into [geo.lower...geo.upper].
-   *
-   * Copy-with-compaction by previous version of libmdbx could produce DB-file
-   * less than meta.geo.lower bound, in case actual filling is low or no data
-   * at all. This is not a problem as there is no damage or loss of data.
-   * Therefore it is better not to consider such situation as an error, but
-   * silently correct it. */
-  pgno_t geo_now = meta->mm_geo.now;
-  if (geo_now < geo_lower)
-    geo_now = geo_lower;
-  if (geo_now > geo_upper && meta->mm_geo.next <= geo_upper)
-    geo_now = geo_upper;
-
-  if (unlikely(meta->mm_geo.next > geo_now)) {
-    mdbx_warning("meta[%u] next-pageno (%" PRIaPGNO
-                 ") is beyond end-pgno (%" PRIaPGNO "), skip it",
-                 meta_number, meta->mm_geo.next, geo_now);
-    return MDBX_CORRUPTED;
-  }
-  if (meta->mm_geo.now != geo_now) {
-    mdbx_warning("meta[%u] consider geo-%s pageno is %" PRIaPGNO
-                 " instead of wrong %" PRIaPGNO
-                 ", will be corrected on next commit(s)",
-                 meta_number, "now", geo_now, meta->mm_geo.now);
-    meta->mm_geo.now = geo_now;
-  }
-
-  /* GC */
-  if (meta->mm_dbs[FREE_DBI].md_root == P_INVALID) {
-    if (unlikely(meta->mm_dbs[FREE_DBI].md_branch_pages ||
-                 meta->mm_dbs[FREE_DBI].md_depth ||
-                 meta->mm_dbs[FREE_DBI].md_entries ||
-                 meta->mm_dbs[FREE_DBI].md_leaf_pages ||
-                 meta->mm_dbs[FREE_DBI].md_overflow_pages)) {
-      mdbx_warning("meta[%u] has false-empty %s, skip it", meta_number, "GC");
-      return MDBX_CORRUPTED;
-    }
-  } else if (unlikely(meta->mm_dbs[FREE_DBI].md_root >= meta->mm_geo.next)) {
-    mdbx_warning("meta[%u] has invalid %s-root %" PRIaPGNO ", skip it",
-                 meta_number, "GC", meta->mm_dbs[FREE_DBI].md_root);
-    return MDBX_CORRUPTED;
-  }
-
-  /* MainDB */
-  if (meta->mm_dbs[MAIN_DBI].md_root == P_INVALID) {
-    if (unlikely(meta->mm_dbs[MAIN_DBI].md_branch_pages ||
-                 meta->mm_dbs[MAIN_DBI].md_depth ||
-                 meta->mm_dbs[MAIN_DBI].md_entries ||
-                 meta->mm_dbs[MAIN_DBI].md_leaf_pages ||
-                 meta->mm_dbs[MAIN_DBI].md_overflow_pages)) {
-      mdbx_warning("meta[%u] has false-empty %s", meta_number, "MainDB");
-      return MDBX_CORRUPTED;
-    }
-  } else if (unlikely(meta->mm_dbs[MAIN_DBI].md_root >= meta->mm_geo.next)) {
-    mdbx_warning("meta[%u] has invalid %s-root %" PRIaPGNO ", skip it",
-                 meta_number, "MainDB", meta->mm_dbs[MAIN_DBI].md_root);
-    return MDBX_CORRUPTED;
-  }
-
-  if (unlikely(meta->mm_dbs[FREE_DBI].md_mod_txnid > txnid)) {
-    mdbx_warning("meta[%u] has wrong md_mod_txnid %" PRIaTXN " for %s, skip it",
-                 meta_number, meta->mm_dbs[FREE_DBI].md_mod_txnid, "GC");
-    return MDBX_CORRUPTED;
-  }
-
-  if (unlikely(meta->mm_dbs[MAIN_DBI].md_mod_txnid > txnid)) {
-    mdbx_warning("meta[%u] has wrong md_mod_txnid %" PRIaTXN " for %s, skip it",
-                 meta_number, meta->mm_dbs[MAIN_DBI].md_mod_txnid, "MainDB");
-    return MDBX_CORRUPTED;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-static int mdbx_validate_meta_copy(MDBX_env *env, const MDBX_meta *meta,
-                                   MDBX_meta *dest) {
-  *dest = *meta;
-  return mdbx_validate_meta(env, dest, data_page(meta),
-                            bytes2pgno(env, (uint8_t *)meta - env->me_map),
-                            nullptr);
-}
-
-/* Read the environment parameters of a DB environment
- * before mapping it into memory. */
-__cold static int mdbx_read_header(MDBX_env *env, MDBX_meta *dest,
-                                   const int lck_exclusive,
-                                   const mdbx_mode_t mode_bits) {
-  int rc = mdbx_filesize(env->me_lazy_fd, &env->me_dxb_mmap.filesize);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  memset(dest, 0, sizeof(MDBX_meta));
-  unaligned_poke_u64(4, dest->mm_datasync_sign, MDBX_DATASIGN_WEAK);
-  rc = MDBX_CORRUPTED;
-
-  /* Read twice all meta pages so we can find the latest one. */
-  unsigned loop_limit = NUM_METAS * 2;
-  /* We don't know the page size on first time. So, just guess it. */
-  unsigned guess_pagesize = 0;
-  for (unsigned loop_count = 0; loop_count < loop_limit; ++loop_count) {
-    const unsigned meta_number = loop_count % NUM_METAS;
-    const unsigned offset = (guess_pagesize             ? guess_pagesize
-                             : (loop_count > NUM_METAS) ? env->me_psize
-                                                        : env->me_os_psize) *
-                            meta_number;
-
-    char buffer[MIN_PAGESIZE];
-    unsigned retryleft = 42;
-    while (1) {
-      mdbx_trace("reading meta[%d]: offset %u, bytes %u, retry-left %u",
-                 meta_number, offset, MIN_PAGESIZE, retryleft);
-      int err = mdbx_pread(env->me_lazy_fd, buffer, MIN_PAGESIZE, offset);
-      if (err != MDBX_SUCCESS) {
-        if (err == MDBX_ENODATA && offset == 0 && loop_count == 0 &&
-            env->me_dxb_mmap.filesize == 0 &&
-            mode_bits /* non-zero for DB creation */ != 0)
-          mdbx_notice("read meta: empty file (%d, %s)", err,
-                      mdbx_strerror(err));
-        else
-          mdbx_error("read meta[%u,%u]: %i, %s", offset, MIN_PAGESIZE, err,
-                     mdbx_strerror(err));
-        return err;
-      }
-
-      char again[MIN_PAGESIZE];
-      err = mdbx_pread(env->me_lazy_fd, again, MIN_PAGESIZE, offset);
-      if (err != MDBX_SUCCESS) {
-        mdbx_error("read meta[%u,%u]: %i, %s", offset, MIN_PAGESIZE, err,
-                   mdbx_strerror(err));
-        return err;
-      }
-
-      if (memcmp(buffer, again, MIN_PAGESIZE) == 0 || --retryleft == 0)
-        break;
-
-      mdbx_verbose("meta[%u] was updated, re-read it", meta_number);
-    }
-
-    if (!retryleft) {
-      mdbx_error("meta[%u] is too volatile, skip it", meta_number);
-      continue;
-    }
-
-    MDBX_page *const page = (MDBX_page *)buffer;
-    MDBX_meta *const meta = page_meta(page);
-    rc = mdbx_validate_meta(env, meta, page, meta_number, &guess_pagesize);
-    if (rc != MDBX_SUCCESS)
-      continue;
-
-    if ((env->me_stuck_meta < 0)
-            ? meta_ot(meta_bootid_match(meta) ? prefer_last : prefer_steady,
-                      env, dest, meta)
-            : (meta_number == (unsigned)env->me_stuck_meta)) {
-      *dest = *meta;
-      if (!lck_exclusive && !META_IS_STEADY(dest))
-        loop_limit += 1; /* LY: should re-read to hush race with update */
-      mdbx_verbose("latch meta[%u]", meta_number);
-    }
-  }
-
-  if (dest->mm_psize == 0 ||
-      (env->me_stuck_meta < 0 &&
-       !(META_IS_STEADY(dest) ||
-         meta_weak_acceptable(env, dest, lck_exclusive)))) {
-    mdbx_error("%s", "no usable meta-pages, database is corrupted");
-    if (rc == MDBX_SUCCESS) {
-      /* TODO: try to restore the database by fully checking b-tree structure
-       * for the each meta page, if the corresponding option was given */
-      return MDBX_CORRUPTED;
-    }
-    return rc;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-__cold static MDBX_page *mdbx_meta_model(const MDBX_env *env, MDBX_page *model,
-                                         unsigned num) {
-  mdbx_ensure(env, is_powerof2(env->me_psize));
-  mdbx_ensure(env, env->me_psize >= MIN_PAGESIZE);
-  mdbx_ensure(env, env->me_psize <= MAX_PAGESIZE);
-  mdbx_ensure(env, env->me_dbgeo.lower >= MIN_MAPSIZE);
-  mdbx_ensure(env, env->me_dbgeo.upper <= MAX_MAPSIZE);
-  mdbx_ensure(env, env->me_dbgeo.now >= env->me_dbgeo.lower);
-  mdbx_ensure(env, env->me_dbgeo.now <= env->me_dbgeo.upper);
-
-  memset(model, 0, env->me_psize);
-  model->mp_pgno = num;
-  model->mp_flags = P_META;
-  MDBX_meta *const model_meta = page_meta(model);
-  unaligned_poke_u64(4, model_meta->mm_magic_and_version, MDBX_DATA_MAGIC);
-
-  model_meta->mm_geo.lower = bytes2pgno(env, env->me_dbgeo.lower);
-  model_meta->mm_geo.upper = bytes2pgno(env, env->me_dbgeo.upper);
-  model_meta->mm_geo.grow_pv = pages2pv(bytes2pgno(env, env->me_dbgeo.grow));
-  model_meta->mm_geo.shrink_pv =
-      pages2pv(bytes2pgno(env, env->me_dbgeo.shrink));
-  model_meta->mm_geo.now = bytes2pgno(env, env->me_dbgeo.now);
-  model_meta->mm_geo.next = NUM_METAS;
-
-  mdbx_ensure(env, model_meta->mm_geo.lower >= MIN_PAGENO);
-  mdbx_ensure(env, model_meta->mm_geo.upper <= MAX_PAGENO + 1);
-  mdbx_ensure(env, model_meta->mm_geo.now >= model_meta->mm_geo.lower);
-  mdbx_ensure(env, model_meta->mm_geo.now <= model_meta->mm_geo.upper);
-  mdbx_ensure(env, model_meta->mm_geo.next >= MIN_PAGENO);
-  mdbx_ensure(env, model_meta->mm_geo.next <= model_meta->mm_geo.now);
-  mdbx_ensure(env, model_meta->mm_geo.grow_pv ==
-                       pages2pv(pv2pages(model_meta->mm_geo.grow_pv)));
-  mdbx_ensure(env, model_meta->mm_geo.shrink_pv ==
-                       pages2pv(pv2pages(model_meta->mm_geo.shrink_pv)));
-
-  model_meta->mm_psize = env->me_psize;
-  model_meta->mm_dbs[FREE_DBI].md_flags = MDBX_INTEGERKEY;
-  model_meta->mm_dbs[FREE_DBI].md_root = P_INVALID;
-  model_meta->mm_dbs[MAIN_DBI].md_root = P_INVALID;
-  meta_set_txnid(env, model_meta, MIN_TXNID + num);
-  unaligned_poke_u64(4, model_meta->mm_datasync_sign, meta_sign(model_meta));
-  mdbx_assert(env, meta_checktxnid(env, model_meta, true));
-  return (MDBX_page *)((uint8_t *)model + env->me_psize);
-}
-
-/* Fill in most of the zeroed meta-pages for an empty database environment.
- * Return pointer to recently (head) meta-page. */
-__cold static MDBX_meta *mdbx_init_metas(const MDBX_env *env, void *buffer) {
-  MDBX_page *page0 = (MDBX_page *)buffer;
-  MDBX_page *page1 = mdbx_meta_model(env, page0, 0);
-  MDBX_page *page2 = mdbx_meta_model(env, page1, 1);
-  mdbx_meta_model(env, page2, 2);
-  mdbx_assert(env, !meta_eq(env, page_meta(page0), page_meta(page1)));
-  mdbx_assert(env, !meta_eq(env, page_meta(page1), page_meta(page2)));
-  mdbx_assert(env, !meta_eq(env, page_meta(page2), page_meta(page0)));
-  return page_meta(page2);
-}
-
-#if MDBX_ENABLE_MADVISE && !(defined(_WIN32) || defined(_WIN64))
-static size_t mdbx_madvise_threshold(const MDBX_env *env,
-                                     const size_t largest_bytes) {
-  /* TODO: use options */
-  const unsigned factor = 9;
-  const size_t threshold = (largest_bytes < (65536ul << factor))
-                               ? 65536 /* minimal threshold */
-                           : (largest_bytes > (MEGABYTE * 4 << factor))
-                               ? MEGABYTE * 4 /* maximal threshold */
-                               : largest_bytes >> factor;
-  return bytes_align2os_bytes(env, threshold);
-}
-#endif /* MDBX_ENABLE_MADVISE */
-
-static int mdbx_sync_locked(MDBX_env *env, unsigned flags,
-                            MDBX_meta *const pending) {
-  mdbx_assert(env, ((env->me_flags ^ flags) & MDBX_WRITEMAP) == 0);
-  const MDBX_meta *const meta0 = METAPAGE(env, 0);
-  const MDBX_meta *const meta1 = METAPAGE(env, 1);
-  const MDBX_meta *const meta2 = METAPAGE(env, 2);
-  const MDBX_meta *const head = constmeta_prefer_last(env);
-  int rc;
-
-  mdbx_assert(env, meta_eq_mask(env) == 0);
-  mdbx_assert(env,
-              pending < METAPAGE(env, 0) || pending > METAPAGE(env, NUM_METAS));
-  mdbx_assert(env, (env->me_flags & (MDBX_RDONLY | MDBX_FATAL_ERROR)) == 0);
-  mdbx_assert(env, pending->mm_geo.next <= pending->mm_geo.now);
-
-  if (flags & MDBX_SAFE_NOSYNC) {
-    /* Check auto-sync conditions */
-    const pgno_t autosync_threshold =
-        atomic_load32(&env->me_lck->mti_autosync_threshold, mo_Relaxed);
-    const uint64_t autosync_period =
-        atomic_load64(&env->me_lck->mti_autosync_period, mo_Relaxed);
-    if ((autosync_threshold &&
-         atomic_load32(&env->me_lck->mti_unsynced_pages, mo_Relaxed) >=
-             autosync_threshold) ||
-        (autosync_period &&
-         mdbx_osal_monotime() -
-                 atomic_load64(&env->me_lck->mti_sync_timestamp, mo_Relaxed) >=
-             autosync_period))
-      flags &= MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED; /* force steady */
-  }
-
-  pgno_t shrink = 0;
-  if (flags & MDBX_SHRINK_ALLOWED) {
-    /* LY: check conditions to discard unused pages */
-    const pgno_t largest_pgno = mdbx_find_largest(
-        env, (head->mm_geo.next > pending->mm_geo.next) ? head->mm_geo.next
-                                                        : pending->mm_geo.next);
-    mdbx_assert(env, largest_pgno >= NUM_METAS);
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-    const pgno_t edge = env->me_poison_edge;
-    if (edge > largest_pgno) {
-      env->me_poison_edge = largest_pgno;
-      VALGRIND_MAKE_MEM_NOACCESS(env->me_map + pgno2bytes(env, largest_pgno),
-                                 pgno2bytes(env, edge - largest_pgno));
-      MDBX_ASAN_POISON_MEMORY_REGION(env->me_map +
-                                         pgno2bytes(env, largest_pgno),
-                                     pgno2bytes(env, edge - largest_pgno));
-    }
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-#if MDBX_ENABLE_MADVISE &&                                                     \
-    (defined(MADV_DONTNEED) || defined(POSIX_MADV_DONTNEED))
-    const size_t largest_bytes = pgno2bytes(env, largest_pgno);
-    /* threshold to avoid unreasonable frequent madvise() calls */
-    const size_t madvise_threshold = mdbx_madvise_threshold(env, largest_bytes);
-    const size_t discard_edge_bytes = bytes_align2os_bytes(
-        env, ((MDBX_RDONLY &
-               (env->me_lck_mmap.lck ? env->me_lck_mmap.lck->mti_envmode.weak
-                                     : env->me_flags))
-                  ? largest_bytes
-                  : largest_bytes + madvise_threshold));
-    const pgno_t discard_edge_pgno = bytes2pgno(env, discard_edge_bytes);
-    const pgno_t prev_discarded_pgno =
-        atomic_load32(&env->me_lck->mti_discarded_tail, mo_Relaxed);
-    if (prev_discarded_pgno >=
-        discard_edge_pgno + bytes2pgno(env, madvise_threshold)) {
-      mdbx_notice("open-MADV_%s %u..%u", "DONTNEED", largest_pgno,
-                  prev_discarded_pgno);
-      atomic_store32(&env->me_lck->mti_discarded_tail, discard_edge_pgno,
-                     mo_Relaxed);
-      const size_t prev_discarded_bytes =
-          ceil_powerof2(pgno2bytes(env, prev_discarded_pgno), env->me_os_psize);
-      mdbx_ensure(env, prev_discarded_bytes > discard_edge_bytes);
-#if defined(MADV_DONTNEED)
-      int advise = MADV_DONTNEED;
-#if defined(MADV_FREE) &&                                                      \
-    0 /* MADV_FREE works for only anonymous vma at the moment */
-      if ((env->me_flags & MDBX_WRITEMAP) &&
-          mdbx_linux_kernel_version > 0x04050000)
-        advise = MADV_FREE;
-#endif /* MADV_FREE */
-      int err = madvise(env->me_map + discard_edge_bytes,
-                        prev_discarded_bytes - discard_edge_bytes, advise)
-                    ? ignore_enosys(errno)
-                    : MDBX_SUCCESS;
-#else
-      int err = ignore_enosys(posix_madvise(
-          env->me_map + discard_edge_bytes,
-          prev_discarded_bytes - discard_edge_bytes, POSIX_MADV_DONTNEED));
-#endif
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-    }
-#endif /* MDBX_ENABLE_MADVISE && (MADV_DONTNEED || POSIX_MADV_DONTNEED) */
-
-    /* LY: check conditions to shrink datafile */
-    const pgno_t backlog_gap = 3 + pending->mm_dbs[FREE_DBI].md_depth * 3;
-    pgno_t shrink_step = 0;
-    if (pending->mm_geo.shrink_pv &&
-        pending->mm_geo.now - pending->mm_geo.next >
-            (shrink_step = pv2pages(pending->mm_geo.shrink_pv)) + backlog_gap) {
-      if (pending->mm_geo.now > largest_pgno &&
-          pending->mm_geo.now - largest_pgno > shrink_step + backlog_gap) {
-        pgno_t grow_step = 0;
-        const pgno_t aligner =
-            pending->mm_geo.grow_pv
-                ? (grow_step = pv2pages(pending->mm_geo.grow_pv))
-                : shrink_step;
-        const pgno_t with_backlog_gap = largest_pgno + backlog_gap;
-        const pgno_t aligned = pgno_align2os_pgno(
-            env, with_backlog_gap + aligner - with_backlog_gap % aligner);
-        const pgno_t bottom =
-            (aligned > pending->mm_geo.lower) ? aligned : pending->mm_geo.lower;
-        if (pending->mm_geo.now > bottom) {
-          if (META_IS_STEADY(meta_prefer_steady(env)))
-            /* force steady, but only if steady-checkpoint is present */
-            flags &= MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED;
-          shrink = pending->mm_geo.now - bottom;
-          pending->mm_geo.now = bottom;
-          if (unlikely(constmeta_txnid(env, head) ==
-                       unaligned_peek_u64(4, pending->mm_txnid_a))) {
-            const txnid_t txnid =
-                safe64_txnid_next(unaligned_peek_u64(4, pending->mm_txnid_a));
-            mdbx_notice("force-forward pending-txn %" PRIaTXN " -> %" PRIaTXN,
-                        unaligned_peek_u64(4, pending->mm_txnid_a), txnid);
-            mdbx_ensure(env, env->me_txn0->mt_owner != mdbx_thread_self() &&
-                                 !env->me_txn);
-            if (unlikely(txnid > MAX_TXNID)) {
-              rc = MDBX_TXN_FULL;
-              mdbx_error("txnid overflow, raise %d", rc);
-              goto fail;
-            }
-            meta_set_txnid(env, pending, txnid);
-            mdbx_assert(env, meta_checktxnid(env, pending, true));
-          }
-        }
-      }
-    }
-  }
-
-  /* LY: step#1 - sync previously written/updated data-pages */
-  rc = MDBX_RESULT_FALSE /* carry steady */;
-  if (atomic_load32(&env->me_lck->mti_unsynced_pages, mo_Relaxed)) {
-    mdbx_assert(env, ((flags ^ env->me_flags) & MDBX_WRITEMAP) == 0);
-    enum mdbx_syncmode_bits mode_bits = MDBX_SYNC_NONE;
-    if ((flags & MDBX_SAFE_NOSYNC) == 0) {
-      mode_bits = MDBX_SYNC_DATA;
-      if (pending->mm_geo.next > meta_prefer_steady(env)->mm_geo.now)
-        mode_bits |= MDBX_SYNC_SIZE;
-      if (flags & MDBX_NOMETASYNC)
-        mode_bits |= MDBX_SYNC_IODQ;
-    }
-#if MDBX_ENABLE_PGOP_STAT
-    env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    if (flags & MDBX_WRITEMAP)
-      rc =
-          mdbx_msync(&env->me_dxb_mmap, 0,
-                     pgno_align2os_bytes(env, pending->mm_geo.next), mode_bits);
-    else
-      rc = mdbx_fsync(env->me_lazy_fd, mode_bits);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-    rc = (flags & MDBX_SAFE_NOSYNC) ? MDBX_RESULT_TRUE /* carry non-steady */
-                                    : MDBX_RESULT_FALSE /* carry steady */;
-  }
-  mdbx_assert(env, meta_checktxnid(env, pending, true));
-
-  /* Steady or Weak */
-  if (rc == MDBX_RESULT_FALSE /* carry steady */) {
-    atomic_store64(&env->me_lck->mti_sync_timestamp, mdbx_osal_monotime(),
-                   mo_Relaxed);
-    unaligned_poke_u64(4, pending->mm_datasync_sign, meta_sign(pending));
-    atomic_store32(&env->me_lck->mti_unsynced_pages, 0, mo_Relaxed);
-  } else {
-    assert(rc == MDBX_RESULT_TRUE /* carry non-steady */);
-    unaligned_poke_u64(4, pending->mm_datasync_sign, MDBX_DATASIGN_WEAK);
-  }
-
-  MDBX_meta *target = nullptr;
-  if (constmeta_txnid(env, head) ==
-      unaligned_peek_u64(4, pending->mm_txnid_a)) {
-    mdbx_assert(env, memcmp(&head->mm_dbs, &pending->mm_dbs,
-                            sizeof(head->mm_dbs)) == 0);
-    mdbx_assert(env, memcmp(&head->mm_canary, &pending->mm_canary,
-                            sizeof(head->mm_canary)) == 0);
-    mdbx_assert(env, memcmp(&head->mm_geo, &pending->mm_geo,
-                            sizeof(pending->mm_geo)) == 0);
-    if (!META_IS_STEADY(head) && META_IS_STEADY(pending))
-      target = (MDBX_meta *)head;
-    else {
-      mdbx_ensure(env, meta_eq(env, head, pending));
-      mdbx_debug("%s", "skip update meta");
-      return MDBX_SUCCESS;
-    }
-  } else if (head == meta0)
-    target = (MDBX_meta *)meta_ancient_prefer_weak(env, meta1, meta2);
-  else if (head == meta1)
-    target = (MDBX_meta *)meta_ancient_prefer_weak(env, meta0, meta2);
-  else {
-    mdbx_assert(env, head == meta2);
-    target = (MDBX_meta *)meta_ancient_prefer_weak(env, meta0, meta1);
-  }
-
-  /* LY: step#2 - update meta-page. */
-  mdbx_debug(
-      "writing meta%" PRIaPGNO " = root %" PRIaPGNO "/%" PRIaPGNO
-      ", geo %" PRIaPGNO "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO
-      " +%u -%u, txn_id %" PRIaTXN ", %s",
-      data_page(target)->mp_pgno, pending->mm_dbs[MAIN_DBI].md_root,
-      pending->mm_dbs[FREE_DBI].md_root, pending->mm_geo.lower,
-      pending->mm_geo.next, pending->mm_geo.now, pending->mm_geo.upper,
-      pv2pages(pending->mm_geo.grow_pv), pv2pages(pending->mm_geo.shrink_pv),
-      unaligned_peek_u64(4, pending->mm_txnid_a), mdbx_durable_str(pending));
-
-  mdbx_debug("meta0: %s, %s, txn_id %" PRIaTXN ", root %" PRIaPGNO
-             "/%" PRIaPGNO,
-             (meta0 == head)     ? "head"
-             : (meta0 == target) ? "tail"
-                                 : "stay",
-             mdbx_durable_str(meta0), meta_txnid(env, meta0),
-             meta0->mm_dbs[MAIN_DBI].md_root, meta0->mm_dbs[FREE_DBI].md_root);
-  mdbx_debug("meta1: %s, %s, txn_id %" PRIaTXN ", root %" PRIaPGNO
-             "/%" PRIaPGNO,
-             (meta1 == head)     ? "head"
-             : (meta1 == target) ? "tail"
-                                 : "stay",
-             mdbx_durable_str(meta1), meta_txnid(env, meta1),
-             meta1->mm_dbs[MAIN_DBI].md_root, meta1->mm_dbs[FREE_DBI].md_root);
-  mdbx_debug("meta2: %s, %s, txn_id %" PRIaTXN ", root %" PRIaPGNO
-             "/%" PRIaPGNO,
-             (meta2 == head)     ? "head"
-             : (meta2 == target) ? "tail"
-                                 : "stay",
-             mdbx_durable_str(meta2), meta_txnid(env, meta2),
-             meta2->mm_dbs[MAIN_DBI].md_root, meta2->mm_dbs[FREE_DBI].md_root);
-
-  mdbx_assert(env, !meta_eq(env, pending, meta0));
-  mdbx_assert(env, !meta_eq(env, pending, meta1));
-  mdbx_assert(env, !meta_eq(env, pending, meta2));
-
-  mdbx_assert(env, ((env->me_flags ^ flags) & MDBX_WRITEMAP) == 0);
-  mdbx_ensure(env,
-              target == head || constmeta_txnid(env, target) <
-                                    unaligned_peek_u64(4, pending->mm_txnid_a));
-#if MDBX_ENABLE_PGOP_STAT
-  env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  if (flags & MDBX_WRITEMAP) {
-    mdbx_jitter4testing(true);
-    if (likely(target != head)) {
-      /* LY: 'invalidate' the meta. */
-      meta_update_begin(env, target,
-                        unaligned_peek_u64(4, pending->mm_txnid_a));
-      unaligned_poke_u64(4, target->mm_datasync_sign, MDBX_DATASIGN_WEAK);
-#ifndef NDEBUG
-      /* debug: provoke failure to catch a violators, but don't touch mm_psize
-       * to allow readers catch actual pagesize. */
-      uint8_t *provoke_begin = (uint8_t *)&target->mm_dbs[FREE_DBI].md_root;
-      uint8_t *provoke_end = (uint8_t *)&target->mm_datasync_sign;
-      memset(provoke_begin, 0xCC, provoke_end - provoke_begin);
-      mdbx_jitter4testing(false);
-#endif
-
-      /* LY: update info */
-      target->mm_geo = pending->mm_geo;
-      target->mm_dbs[FREE_DBI] = pending->mm_dbs[FREE_DBI];
-      target->mm_dbs[MAIN_DBI] = pending->mm_dbs[MAIN_DBI];
-      target->mm_canary = pending->mm_canary;
-      memcpy(target->mm_pages_retired, pending->mm_pages_retired, 8);
-      mdbx_jitter4testing(true);
-
-      /* LY: 'commit' the meta */
-      meta_update_end(env, target, unaligned_peek_u64(4, pending->mm_txnid_b));
-      mdbx_jitter4testing(true);
-      mdbx_assert(env, meta_checktxnid(env, target, true));
-    } else {
-      /* dangerous case (target == head), only mm_datasync_sign could
-       * me updated, check assertions once again */
-      mdbx_ensure(env, constmeta_txnid(env, head) ==
-                               unaligned_peek_u64(4, pending->mm_txnid_a) &&
-                           !META_IS_STEADY(head) && META_IS_STEADY(pending));
-      mdbx_ensure(env, memcmp(&head->mm_geo, &pending->mm_geo,
-                              sizeof(head->mm_geo)) == 0);
-      mdbx_ensure(env, memcmp(&head->mm_dbs, &pending->mm_dbs,
-                              sizeof(head->mm_dbs)) == 0);
-      mdbx_ensure(env, memcmp(&head->mm_canary, &pending->mm_canary,
-                              sizeof(head->mm_canary)) == 0);
-    }
-    memcpy(target->mm_datasync_sign, pending->mm_datasync_sign, 8);
-    mdbx_flush_incoherent_cpu_writeback();
-    mdbx_jitter4testing(true);
-    /* sync meta-pages */
-    rc =
-        mdbx_msync(&env->me_dxb_mmap, 0, pgno_align2os_bytes(env, NUM_METAS),
-                   (flags & MDBX_NOMETASYNC) ? MDBX_SYNC_NONE
-                                             : MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto fail;
-  } else {
-    const MDBX_meta undo_meta = *target;
-    const mdbx_filehandle_t fd = (env->me_dsync_fd != INVALID_HANDLE_VALUE)
-                                     ? env->me_dsync_fd
-                                     : env->me_lazy_fd;
-#if MDBX_ENABLE_PGOP_STAT
-    env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    rc = mdbx_pwrite(fd, pending, sizeof(MDBX_meta),
-                     (uint8_t *)target - env->me_map);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-    undo:
-      mdbx_debug("%s", "write failed, disk error?");
-      /* On a failure, the pagecache still contains the new data.
-       * Try write some old data back, to prevent it from being used. */
-      mdbx_pwrite(fd, &undo_meta, sizeof(MDBX_meta),
-                  (uint8_t *)target - env->me_map);
-      goto fail;
-    }
-    mdbx_flush_incoherent_mmap(target, sizeof(MDBX_meta), env->me_os_psize);
-    /* sync meta-pages */
-    if ((flags & MDBX_NOMETASYNC) == 0 && fd == env->me_lazy_fd) {
-      rc = mdbx_fsync(env->me_lazy_fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-      if (rc != MDBX_SUCCESS)
-        goto undo;
-    }
-    mdbx_assert(env, meta_checktxnid(env, target, true));
-  }
-  env->me_lck->mti_meta_sync_txnid.weak =
-      (uint32_t)unaligned_peek_u64(4, pending->mm_txnid_a) -
-      ((flags & MDBX_NOMETASYNC) ? UINT32_MAX / 3 : 0);
-
-  /* LY: shrink datafile if needed */
-  if (unlikely(shrink)) {
-    mdbx_verbose("shrink to %" PRIaPGNO " pages (-%" PRIaPGNO ")",
-                 pending->mm_geo.now, shrink);
-    rc = mdbx_mapresize_implicit(env, pending->mm_geo.next, pending->mm_geo.now,
-                                 pending->mm_geo.upper);
-    if (rc != MDBX_SUCCESS && rc != MDBX_EPERM)
-      goto fail;
-    mdbx_assert(env, meta_checktxnid(env, target, true));
-  }
-
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (likely(lck))
-    /* toggle oldest refresh */
-    atomic_store32(&lck->mti_readers_refresh_flag, false, mo_Relaxed);
-
-  return MDBX_SUCCESS;
-
-fail:
-  env->me_flags |= MDBX_FATAL_ERROR;
-  return rc;
-}
-
-static void recalculate_merge_threshold(MDBX_env *env) {
-  const unsigned bytes = page_space(env);
-  env->me_merge_threshold =
-      (uint16_t)(bytes -
-                 (bytes * env->me_options.merge_threshold_16dot16_percent >>
-                  16));
-  env->me_merge_threshold_gc =
-      (uint16_t)(bytes -
-                 ((env->me_options.merge_threshold_16dot16_percent > 19005)
-                      ? bytes / 3 /* 33 % */
-                      : bytes / 4 /* 25 % */));
-}
-
-__cold static void mdbx_setup_pagesize(MDBX_env *env, const size_t pagesize) {
-  STATIC_ASSERT(PTRDIFF_MAX > MAX_MAPSIZE);
-  STATIC_ASSERT(MIN_PAGESIZE > sizeof(MDBX_page) + sizeof(MDBX_meta));
-  mdbx_ensure(env, is_powerof2(pagesize));
-  mdbx_ensure(env, pagesize >= MIN_PAGESIZE);
-  mdbx_ensure(env, pagesize <= MAX_PAGESIZE);
-  env->me_psize = (unsigned)pagesize;
-  if (env->me_pbuf) {
-    mdbx_memalign_free(env->me_pbuf);
-    env->me_pbuf = nullptr;
-  }
-
-  STATIC_ASSERT(MAX_GC1OVPAGE(MIN_PAGESIZE) > 4);
-  STATIC_ASSERT(MAX_GC1OVPAGE(MAX_PAGESIZE) < MDBX_PGL_LIMIT);
-  const intptr_t maxgc_ov1page = (pagesize - PAGEHDRSZ) / sizeof(pgno_t) - 1;
-  mdbx_ensure(env, maxgc_ov1page > 42 &&
-                       maxgc_ov1page < (intptr_t)MDBX_PGL_LIMIT / 4);
-  env->me_maxgc_ov1page = (unsigned)maxgc_ov1page;
-
-  STATIC_ASSERT(LEAF_NODE_MAX(MIN_PAGESIZE) > sizeof(MDBX_db) + NODESIZE + 42);
-  STATIC_ASSERT(LEAF_NODE_MAX(MAX_PAGESIZE) < UINT16_MAX);
-  STATIC_ASSERT(LEAF_NODE_MAX(MIN_PAGESIZE) >= BRANCH_NODE_MAX(MIN_PAGESIZE));
-  STATIC_ASSERT(BRANCH_NODE_MAX(MAX_PAGESIZE) > NODESIZE + 42);
-  STATIC_ASSERT(BRANCH_NODE_MAX(MAX_PAGESIZE) < UINT16_MAX);
-  const intptr_t branch_nodemax = BRANCH_NODE_MAX(pagesize);
-  const intptr_t leaf_nodemax = LEAF_NODE_MAX(pagesize);
-  mdbx_ensure(env,
-              branch_nodemax > (intptr_t)(NODESIZE + 42) &&
-                  branch_nodemax % 2 == 0 &&
-                  leaf_nodemax > (intptr_t)(sizeof(MDBX_db) + NODESIZE + 42) &&
-                  leaf_nodemax >= branch_nodemax &&
-                  leaf_nodemax < (int)UINT16_MAX && leaf_nodemax % 2 == 0);
-  env->me_leaf_nodemax = (unsigned)leaf_nodemax;
-  env->me_psize2log = (uint8_t)log2n_powerof2(pagesize);
-  mdbx_assert(env, pgno2bytes(env, 1) == pagesize);
-  mdbx_assert(env, bytes2pgno(env, pagesize + pagesize) == 2);
-  recalculate_merge_threshold(env);
-
-  const pgno_t max_pgno = bytes2pgno(env, MAX_MAPSIZE);
-  if (!env->me_options.flags.non_auto.dp_limit) {
-    /* auto-setup dp_limit by "The42" ;-) */
-    intptr_t total_ram_pages, avail_ram_pages;
-    int err = mdbx_get_sysraminfo(nullptr, &total_ram_pages, &avail_ram_pages);
-    if (unlikely(err != MDBX_SUCCESS))
-      mdbx_error("mdbx_get_sysraminfo(), rc %d", err);
-    else {
-      size_t reasonable_dpl_limit =
-          (size_t)(total_ram_pages + avail_ram_pages) / 42;
-      if (pagesize > env->me_os_psize)
-        reasonable_dpl_limit /= pagesize / env->me_os_psize;
-      else if (pagesize < env->me_os_psize)
-        reasonable_dpl_limit *= env->me_os_psize / pagesize;
-      reasonable_dpl_limit = (reasonable_dpl_limit < MDBX_PGL_LIMIT)
-                                 ? reasonable_dpl_limit
-                                 : MDBX_PGL_LIMIT;
-      reasonable_dpl_limit = (reasonable_dpl_limit > CURSOR_STACK * 4)
-                                 ? reasonable_dpl_limit
-                                 : CURSOR_STACK * 4;
-      env->me_options.dp_limit = (unsigned)reasonable_dpl_limit;
-    }
-  }
-  if (env->me_options.dp_limit > max_pgno - NUM_METAS)
-    env->me_options.dp_limit = max_pgno - NUM_METAS;
-  if (env->me_options.dp_initial > env->me_options.dp_limit)
-    env->me_options.dp_initial = env->me_options.dp_limit;
-}
-
-static __inline MDBX_CONST_FUNCTION MDBX_lockinfo *
-lckless_stub(const MDBX_env *env) {
-  uintptr_t stub = (uintptr_t)&env->x_lckless_stub;
-  /* align to avoid false-positive alarm from UndefinedBehaviorSanitizer */
-  stub = (stub + MDBX_CACHELINE_SIZE - 1) & ~(MDBX_CACHELINE_SIZE - 1);
-  return (MDBX_lockinfo *)stub;
-}
-
-__cold int mdbx_env_create(MDBX_env **penv) {
-  MDBX_env *env = mdbx_calloc(1, sizeof(MDBX_env));
-  if (unlikely(!env))
-    return MDBX_ENOMEM;
-
-  env->me_maxreaders = DEFAULT_READERS;
-  env->me_maxdbs = env->me_numdbs = CORE_DBS;
-  env->me_lazy_fd = INVALID_HANDLE_VALUE;
-  env->me_dsync_fd = INVALID_HANDLE_VALUE;
-  env->me_lfd = INVALID_HANDLE_VALUE;
-  env->me_pid = mdbx_getpid();
-  env->me_stuck_meta = -1;
-
-  env->me_options.dp_reserve_limit = 1024;
-  env->me_options.rp_augment_limit = 256 * 1024;
-  env->me_options.dp_limit = 64 * 1024;
-  if (env->me_options.dp_limit > MAX_PAGENO + 1 - NUM_METAS)
-    env->me_options.dp_limit = MAX_PAGENO + 1 - NUM_METAS;
-  env->me_options.dp_initial = MDBX_PNL_INITIAL;
-  if (env->me_options.dp_initial > env->me_options.dp_limit)
-    env->me_options.dp_initial = env->me_options.dp_limit;
-  env->me_options.spill_max_denominator = 8;
-  env->me_options.spill_min_denominator = 8;
-  env->me_options.spill_parent4child_denominator = 0;
-  env->me_options.dp_loose_limit = 64;
-  env->me_options.merge_threshold_16dot16_percent = 65536 / 4 /* 25% */;
-
-  int rc;
-  const size_t os_psize = mdbx_syspagesize();
-  if (unlikely(!is_powerof2(os_psize) || os_psize < MIN_PAGESIZE)) {
-    mdbx_error("unsuitable system pagesize %" PRIuPTR, os_psize);
-    rc = MDBX_INCOMPATIBLE;
-    goto bailout;
-  }
-  env->me_os_psize = (unsigned)os_psize;
-  mdbx_setup_pagesize(env, (env->me_os_psize < MAX_PAGESIZE) ? env->me_os_psize
-                                                             : MAX_PAGESIZE);
-
-  rc = mdbx_fastmutex_init(&env->me_dbi_lock);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto bailout;
-
-#if defined(_WIN32) || defined(_WIN64)
-  mdbx_srwlock_Init(&env->me_remap_guard);
-  InitializeCriticalSection(&env->me_windowsbug_lock);
-#else
-  rc = mdbx_fastmutex_init(&env->me_remap_guard);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    mdbx_fastmutex_destroy(&env->me_dbi_lock);
-    goto bailout;
-  }
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV
-  MDBX_lockinfo *const stub = lckless_stub(env);
-  rc = mdbx_ipclock_stub(&stub->mti_wlock);
-#endif /* MDBX_LOCKING */
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    mdbx_fastmutex_destroy(&env->me_remap_guard);
-    mdbx_fastmutex_destroy(&env->me_dbi_lock);
-    goto bailout;
-  }
-#endif /* Windows */
-
-  VALGRIND_CREATE_MEMPOOL(env, 0, 0);
-  env->me_signature.weak = MDBX_ME_SIGNATURE;
-  *penv = env;
-  return MDBX_SUCCESS;
-
-bailout:
-  mdbx_free(env);
-  *penv = nullptr;
-  return rc;
-}
-
-__cold static intptr_t get_reasonable_db_maxsize(intptr_t *cached_result) {
-  if (*cached_result == 0) {
-    intptr_t pagesize, total_ram_pages;
-    if (unlikely(mdbx_get_sysraminfo(&pagesize, &total_ram_pages, nullptr) !=
-                 MDBX_SUCCESS))
-      return *cached_result = MAX_MAPSIZE32 /* the 32-bit limit is good enough
-                                               for fallback */
-          ;
-
-    if (unlikely((size_t)total_ram_pages * 2 > MAX_MAPSIZE / (size_t)pagesize))
-      return *cached_result = MAX_MAPSIZE;
-    assert(MAX_MAPSIZE >= (size_t)(total_ram_pages * pagesize * 2));
-
-    /* Suggesting should not be more than golden ratio of the size of RAM. */
-    *cached_result = (intptr_t)((size_t)total_ram_pages * 207 >> 7) * pagesize;
-
-    /* Round to the nearest human-readable granulation. */
-    for (size_t unit = MEGABYTE; unit; unit <<= 5) {
-      const size_t floor = floor_powerof2(*cached_result, unit);
-      const size_t ceil = ceil_powerof2(*cached_result, unit);
-      const size_t threshold = (size_t)*cached_result >> 4;
-      const bool down =
-          *cached_result - floor < ceil - *cached_result || ceil > MAX_MAPSIZE;
-      if (threshold < (down ? *cached_result - floor : ceil - *cached_result))
-        break;
-      *cached_result = down ? floor : ceil;
-    }
-  }
-  return *cached_result;
-}
-
-__cold LIBMDBX_API int
-mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
-                      intptr_t size_upper, intptr_t growth_step,
-                      intptr_t shrink_threshold, intptr_t pagesize) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  const bool inside_txn =
-      (env->me_txn0 && env->me_txn0->mt_owner == mdbx_thread_self());
-
-#if MDBX_DEBUG
-  if (growth_step < 0) {
-    growth_step = 1;
-    if (shrink_threshold < 0)
-      shrink_threshold = 1;
-  }
-#endif /* MDBX_DEBUG */
-
-  intptr_t reasonable_maxsize = 0;
-  bool need_unlock = false;
-  if (env->me_map) {
-    /* env already mapped */
-    if (unlikely(env->me_flags & MDBX_RDONLY))
-      return MDBX_EACCESS;
-
-    if (!inside_txn) {
-      int err = mdbx_txn_lock(env, false);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-      need_unlock = true;
-    }
-    const MDBX_meta *head = constmeta_prefer_last(env);
-    if (!inside_txn) {
-      env->me_txn0->mt_txnid = constmeta_txnid(env, head);
-      mdbx_find_oldest(env->me_txn0);
-    }
-
-    /* get untouched params from DB */
-    if (pagesize <= 0 || pagesize >= INT_MAX)
-      pagesize = env->me_psize;
-    if (size_lower < 0)
-      size_lower = pgno2bytes(env, head->mm_geo.lower);
-    if (size_now < 0)
-      size_now = pgno2bytes(env, head->mm_geo.now);
-    if (size_upper < 0)
-      size_upper = pgno2bytes(env, head->mm_geo.upper);
-    if (growth_step < 0)
-      growth_step = pgno2bytes(env, pv2pages(head->mm_geo.grow_pv));
-    if (shrink_threshold < 0)
-      shrink_threshold = pgno2bytes(env, pv2pages(head->mm_geo.shrink_pv));
-
-    if (pagesize != (intptr_t)env->me_psize) {
-      rc = MDBX_EINVAL;
-      goto bailout;
-    }
-    const size_t usedbytes =
-        pgno2bytes(env, mdbx_find_largest(env, head->mm_geo.next));
-    if ((size_t)size_upper < usedbytes) {
-      rc = MDBX_MAP_FULL;
-      goto bailout;
-    }
-    if ((size_t)size_now < usedbytes)
-      size_now = usedbytes;
-  } else {
-    /* env NOT yet mapped */
-    if (unlikely(inside_txn))
-      return MDBX_PANIC;
-
-    /* is requested some auto-value for pagesize ? */
-    if (pagesize >= INT_MAX /* maximal */)
-      pagesize = MAX_PAGESIZE;
-    else if (pagesize <= 0) {
-      if (pagesize < 0 /* default */) {
-        pagesize = env->me_os_psize;
-        if ((uintptr_t)pagesize > MAX_PAGESIZE)
-          pagesize = MAX_PAGESIZE;
-        mdbx_assert(env, (uintptr_t)pagesize >= MIN_PAGESIZE);
-      } else if (pagesize == 0 /* minimal */)
-        pagesize = MIN_PAGESIZE;
-
-      /* choose pagesize */
-      intptr_t max_size = (size_now > size_lower) ? size_now : size_lower;
-      max_size = (size_upper > max_size) ? size_upper : max_size;
-      if (max_size < 0 /* default */)
-        max_size = DEFAULT_MAPSIZE;
-      else if (max_size == 0 /* minimal */)
-        max_size = MIN_MAPSIZE;
-      else if (max_size >= (intptr_t)MAX_MAPSIZE /* maximal */)
-        max_size = get_reasonable_db_maxsize(&reasonable_maxsize);
-
-      while (max_size > pagesize * (int64_t)(MAX_PAGENO + 1) &&
-             pagesize < MAX_PAGESIZE)
-        pagesize <<= 1;
-    }
-  }
-
-  if (pagesize < (intptr_t)MIN_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
-      !is_powerof2(pagesize)) {
-    rc = MDBX_EINVAL;
-    goto bailout;
-  }
-
-  if (size_lower <= 0) {
-    size_lower = MIN_MAPSIZE;
-    if (MIN_MAPSIZE / pagesize < MIN_PAGENO)
-      size_lower = MIN_PAGENO * pagesize;
-  }
-  if (size_lower >= INTPTR_MAX) {
-    size_lower = get_reasonable_db_maxsize(&reasonable_maxsize);
-    if ((size_t)size_lower / pagesize > MAX_PAGENO + 1)
-      size_lower = pagesize * (MAX_PAGENO + 1);
-  }
-
-  if (size_now <= 0) {
-    size_now = size_lower;
-    if (size_upper >= size_lower && size_now > size_upper)
-      size_now = size_upper;
-  }
-  if (size_now >= INTPTR_MAX) {
-    size_now = get_reasonable_db_maxsize(&reasonable_maxsize);
-    if ((size_t)size_now / pagesize > MAX_PAGENO + 1)
-      size_now = pagesize * (MAX_PAGENO + 1);
-  }
-
-  if (size_upper <= 0) {
-    if (size_now >= get_reasonable_db_maxsize(&reasonable_maxsize) / 2)
-      size_upper = get_reasonable_db_maxsize(&reasonable_maxsize);
-    else if (MAX_MAPSIZE != MAX_MAPSIZE32 &&
-             (size_t)size_now >= MAX_MAPSIZE32 / 2 &&
-             (size_t)size_now <= MAX_MAPSIZE32 / 4 * 3)
-      size_upper = MAX_MAPSIZE32;
-    else {
-      size_upper = size_now + size_now;
-      if ((size_t)size_upper < DEFAULT_MAPSIZE * 2)
-        size_upper = DEFAULT_MAPSIZE * 2;
-    }
-    if ((size_t)size_upper / pagesize > (MAX_PAGENO + 1))
-      size_upper = pagesize * (MAX_PAGENO + 1);
-  } else if (size_upper >= INTPTR_MAX) {
-    size_upper = get_reasonable_db_maxsize(&reasonable_maxsize);
-    if ((size_t)size_upper / pagesize > MAX_PAGENO + 1)
-      size_upper = pagesize * (MAX_PAGENO + 1);
-  }
-
-  if (unlikely(size_lower < (intptr_t)MIN_MAPSIZE || size_lower > size_upper)) {
-    rc = MDBX_EINVAL;
-    goto bailout;
-  }
-
-  if ((uint64_t)size_lower / pagesize < MIN_PAGENO) {
-    rc = MDBX_EINVAL;
-    goto bailout;
-  }
-
-  if (unlikely((size_t)size_upper > MAX_MAPSIZE ||
-               (uint64_t)size_upper / pagesize > MAX_PAGENO + 1)) {
-    rc = MDBX_TOO_LARGE;
-    goto bailout;
-  }
-
-  const size_t unit = (env->me_os_psize > (size_t)pagesize) ? env->me_os_psize
-                                                            : (size_t)pagesize;
-  size_lower = ceil_powerof2(size_lower, unit);
-  size_upper = ceil_powerof2(size_upper, unit);
-  size_now = ceil_powerof2(size_now, unit);
-
-  /* LY: подбираем значение size_upper:
-   *  - кратное размеру страницы
-   *  - без нарушения MAX_MAPSIZE и MAX_PAGENO */
-  while (unlikely((size_t)size_upper > MAX_MAPSIZE ||
-                  (uint64_t)size_upper / pagesize > MAX_PAGENO + 1)) {
-    if ((size_t)size_upper < unit + MIN_MAPSIZE ||
-        (size_t)size_upper < (size_t)pagesize * (MIN_PAGENO + 1)) {
-      /* паранойа на случай переполнения при невероятных значениях */
-      rc = MDBX_EINVAL;
-      goto bailout;
-    }
-    size_upper -= unit;
-    if ((size_t)size_upper < (size_t)size_lower)
-      size_lower = size_upper;
-  }
-  mdbx_assert(env, (size_upper - size_lower) % env->me_os_psize == 0);
-
-  if (size_now < size_lower)
-    size_now = size_lower;
-  if (size_now > size_upper)
-    size_now = size_upper;
-
-  if (growth_step < 0) {
-    growth_step = ((size_t)(size_upper - size_lower)) / 42;
-    if (growth_step > size_lower && size_lower < (intptr_t)MEGABYTE)
-      growth_step = size_lower;
-    if (growth_step < 65536)
-      growth_step = 65536;
-    if ((size_t)growth_step > MAX_MAPSIZE / 64)
-      growth_step = MAX_MAPSIZE / 64;
-  }
-  if (growth_step == 0 && shrink_threshold > 0)
-    growth_step = 1;
-  growth_step = ceil_powerof2(growth_step, unit);
-
-  if (shrink_threshold < 0)
-    shrink_threshold = growth_step + growth_step;
-  shrink_threshold = ceil_powerof2(shrink_threshold, unit);
-
-  //----------------------------------------------------------------------------
-
-  if (!env->me_map) {
-    /* save user's geo-params for future open/create */
-    if (pagesize != (intptr_t)env->me_psize)
-      mdbx_setup_pagesize(env, pagesize);
-    env->me_dbgeo.lower = size_lower;
-    env->me_dbgeo.now = size_now;
-    env->me_dbgeo.upper = size_upper;
-    env->me_dbgeo.grow =
-        pgno2bytes(env, pv2pages(pages2pv(bytes2pgno(env, growth_step))));
-    env->me_dbgeo.shrink =
-        pgno2bytes(env, pv2pages(pages2pv(bytes2pgno(env, shrink_threshold))));
-
-    mdbx_ensure(env, env->me_dbgeo.lower >= MIN_MAPSIZE);
-    mdbx_ensure(env, env->me_dbgeo.lower / (unsigned)pagesize >= MIN_PAGENO);
-    mdbx_ensure(env, env->me_dbgeo.lower % (unsigned)pagesize == 0);
-    mdbx_ensure(env, env->me_dbgeo.lower % env->me_os_psize == 0);
-
-    mdbx_ensure(env, env->me_dbgeo.upper <= MAX_MAPSIZE);
-    mdbx_ensure(env,
-                env->me_dbgeo.upper / (unsigned)pagesize <= MAX_PAGENO + 1);
-    mdbx_ensure(env, env->me_dbgeo.upper % (unsigned)pagesize == 0);
-    mdbx_ensure(env, env->me_dbgeo.upper % env->me_os_psize == 0);
-
-    mdbx_ensure(env, env->me_dbgeo.now >= env->me_dbgeo.lower);
-    mdbx_ensure(env, env->me_dbgeo.now <= env->me_dbgeo.upper);
-    mdbx_ensure(env, env->me_dbgeo.now % (unsigned)pagesize == 0);
-    mdbx_ensure(env, env->me_dbgeo.now % env->me_os_psize == 0);
-
-    mdbx_ensure(env, env->me_dbgeo.grow % (unsigned)pagesize == 0);
-    mdbx_ensure(env, env->me_dbgeo.grow % env->me_os_psize == 0);
-    mdbx_ensure(env, env->me_dbgeo.shrink % (unsigned)pagesize == 0);
-    mdbx_ensure(env, env->me_dbgeo.shrink % env->me_os_psize == 0);
-
-    rc = MDBX_SUCCESS;
-  } else {
-    /* apply new params to opened environment */
-    mdbx_ensure(env, pagesize == (intptr_t)env->me_psize);
-    MDBX_meta meta;
-    memset(&meta, 0, sizeof(meta));
-    const MDBX_geo *current_geo;
-    if (!inside_txn) {
-      mdbx_assert(env, need_unlock);
-      const MDBX_meta *head = constmeta_prefer_last(env);
-
-      uint64_t timestamp = 0;
-      while ("workaround for "
-             "todo4recovery://erased_by_github/libmdbx/issues/269") {
-        meta = *head;
-        rc = meta_waittxnid(env, &meta, &timestamp);
-        if (likely(rc == MDBX_SUCCESS))
-          break;
-        if (unlikely(rc != MDBX_RESULT_TRUE))
-          goto bailout;
-      }
-      const txnid_t txnid = safe64_txnid_next(constmeta_txnid(env, &meta));
-      if (unlikely(txnid > MAX_TXNID)) {
-        rc = MDBX_TXN_FULL;
-        mdbx_error("txnid overflow, raise %d", rc);
-        goto bailout;
-      }
-      meta_set_txnid(env, &meta, txnid);
-      current_geo = &meta.mm_geo;
-    } else {
-      current_geo = &env->me_txn->mt_geo;
-    }
-
-    MDBX_geo new_geo;
-    new_geo.lower = bytes2pgno(env, size_lower);
-    new_geo.now = bytes2pgno(env, size_now);
-    new_geo.upper = bytes2pgno(env, size_upper);
-    new_geo.grow_pv = pages2pv(bytes2pgno(env, growth_step));
-    new_geo.shrink_pv = pages2pv(bytes2pgno(env, shrink_threshold));
-    new_geo.next = current_geo->next;
-
-    mdbx_ensure(env,
-                pgno_align2os_bytes(env, new_geo.lower) == (size_t)size_lower);
-    mdbx_ensure(env,
-                pgno_align2os_bytes(env, new_geo.upper) == (size_t)size_upper);
-    mdbx_ensure(env, pgno_align2os_bytes(env, new_geo.now) == (size_t)size_now);
-    mdbx_ensure(env, new_geo.grow_pv == pages2pv(pv2pages(new_geo.grow_pv)));
-    mdbx_ensure(env,
-                new_geo.shrink_pv == pages2pv(pv2pages(new_geo.shrink_pv)));
-
-    mdbx_ensure(env, (size_t)size_lower >= MIN_MAPSIZE);
-    mdbx_ensure(env, new_geo.lower >= MIN_PAGENO);
-    mdbx_ensure(env, (size_t)size_upper <= MAX_MAPSIZE);
-    mdbx_ensure(env, new_geo.upper <= MAX_PAGENO + 1);
-    mdbx_ensure(env, new_geo.now >= new_geo.next);
-    mdbx_ensure(env, new_geo.upper >= new_geo.now);
-    mdbx_ensure(env, new_geo.now >= new_geo.lower);
-
-    if (memcmp(current_geo, &new_geo, sizeof(MDBX_geo)) != 0) {
-#if defined(_WIN32) || defined(_WIN64)
-      /* Was DB shrinking disabled before and now it will be enabled? */
-      if (new_geo.lower < new_geo.upper && new_geo.shrink_pv &&
-          !(current_geo->lower < current_geo->upper &&
-            current_geo->shrink_pv)) {
-        if (!env->me_lck_mmap.lck) {
-          rc = MDBX_EPERM;
-          goto bailout;
-        }
-        int err = mdbx_rdt_lock(env);
-        if (unlikely(MDBX_IS_ERROR(err))) {
-          rc = err;
-          goto bailout;
-        }
-
-        /* Check if there are any reading threads that do not use the SRWL */
-        const size_t CurrentTid = GetCurrentThreadId();
-        const MDBX_reader *const begin = env->me_lck_mmap.lck->mti_readers;
-        const MDBX_reader *const end =
-            begin + atomic_load32(&env->me_lck_mmap.lck->mti_numreaders,
-                                  mo_AcquireRelease);
-        for (const MDBX_reader *reader = begin; reader < end; ++reader) {
-          if (reader->mr_pid.weak == env->me_pid && reader->mr_tid.weak &&
-              reader->mr_tid.weak != 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 (new_geo.now != current_geo->now ||
-          new_geo.upper != current_geo->upper) {
-        rc = mdbx_mapresize(env, current_geo->next, new_geo.now, new_geo.upper,
-                            false);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      }
-      if (inside_txn) {
-        env->me_txn->mt_geo = new_geo;
-        env->me_txn->mt_flags |= MDBX_TXN_DIRTY;
-      } else {
-        meta.mm_geo = new_geo;
-        rc = mdbx_sync_locked(env, env->me_flags, &meta);
-      }
-
-      if (likely(rc == MDBX_SUCCESS)) {
-        /* store new geo to env to avoid influences */
-        env->me_dbgeo.now = pgno2bytes(env, new_geo.now);
-        env->me_dbgeo.lower = pgno2bytes(env, new_geo.lower);
-        env->me_dbgeo.upper = pgno2bytes(env, new_geo.upper);
-        env->me_dbgeo.grow = pgno2bytes(env, pv2pages(new_geo.grow_pv));
-        env->me_dbgeo.shrink = pgno2bytes(env, pv2pages(new_geo.shrink_pv));
-      }
-    }
-  }
-
-bailout:
-  if (need_unlock)
-    mdbx_txn_unlock(env);
-  return rc;
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold int mdbx_env_set_mapsize(MDBX_env *env, size_t size) {
-  return __inline_mdbx_env_set_mapsize(env, size);
-}
-
-__cold int mdbx_env_set_maxdbs(MDBX_env *env, MDBX_dbi dbs) {
-  return __inline_mdbx_env_set_maxdbs(env, dbs);
-}
-
-__cold int mdbx_env_get_maxdbs(const MDBX_env *env, MDBX_dbi *dbs) {
-  return __inline_mdbx_env_get_maxdbs(env, dbs);
-}
-
-__cold int mdbx_env_set_maxreaders(MDBX_env *env, unsigned readers) {
-  return __inline_mdbx_env_set_maxreaders(env, readers);
-}
-
-__cold int mdbx_env_get_maxreaders(const MDBX_env *env, unsigned *readers) {
-  return __inline_mdbx_env_get_maxreaders(env, readers);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-__cold static int alloc_page_buf(MDBX_env *env) {
-  return env->me_pbuf
-             ? MDBX_SUCCESS
-             : mdbx_memalign_alloc(env->me_os_psize, env->me_psize * NUM_METAS,
-                                   &env->me_pbuf);
-}
-
-/* Further setup required for opening an MDBX environment */
-__cold static int mdbx_setup_dxb(MDBX_env *env, const int lck_rc,
-                                 const mdbx_mode_t mode_bits) {
-  MDBX_meta meta;
-  int rc = MDBX_RESULT_FALSE;
-  int err = mdbx_read_header(env, &meta, lck_rc, mode_bits);
-  if (unlikely(err != MDBX_SUCCESS)) {
-    if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE || err != MDBX_ENODATA ||
-        (env->me_flags & MDBX_RDONLY) != 0 ||
-        /* recovery mode */ env->me_stuck_meta >= 0)
-      return err;
-
-    mdbx_debug("%s", "create new database");
-    rc = /* new database */ MDBX_RESULT_TRUE;
-
-    if (!env->me_dbgeo.now) {
-      /* set defaults if not configured */
-      err = mdbx_env_set_geometry(env, 0, -1, DEFAULT_MAPSIZE, -1, -1, -1);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-    }
-
-    err = alloc_page_buf(env);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-    meta = *mdbx_init_metas(env, env->me_pbuf);
-    err = mdbx_pwrite(env->me_lazy_fd, env->me_pbuf, env->me_psize * NUM_METAS,
-                      0);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-    err = mdbx_ftruncate(env->me_lazy_fd,
-                         env->me_dxb_mmap.filesize = env->me_dbgeo.now);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-#ifndef NDEBUG /* just for checking */
-    err = mdbx_read_header(env, &meta, lck_rc, mode_bits);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-#endif
-  }
-
-  mdbx_verbose(
-      "header: root %" PRIaPGNO "/%" PRIaPGNO ", geo %" PRIaPGNO "/%" PRIaPGNO
-      "-%" PRIaPGNO "/%" PRIaPGNO " +%u -%u, txn_id %" PRIaTXN ", %s",
-      meta.mm_dbs[MAIN_DBI].md_root, meta.mm_dbs[FREE_DBI].md_root,
-      meta.mm_geo.lower, meta.mm_geo.next, meta.mm_geo.now, meta.mm_geo.upper,
-      pv2pages(meta.mm_geo.grow_pv), pv2pages(meta.mm_geo.shrink_pv),
-      unaligned_peek_u64(4, meta.mm_txnid_a), mdbx_durable_str(&meta));
-
-  if (env->me_psize != meta.mm_psize)
-    mdbx_setup_pagesize(env, meta.mm_psize);
-  const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next);
-  const size_t used_aligned2os_bytes =
-      ceil_powerof2(used_bytes, env->me_os_psize);
-  if ((env->me_flags & MDBX_RDONLY) /* readonly */
-      || lck_rc != MDBX_RESULT_TRUE /* not exclusive */
-      || /* recovery mode */ env->me_stuck_meta >= 0) {
-    /* use present params from db */
-    const size_t pagesize = meta.mm_psize;
-    err = mdbx_env_set_geometry(
-        env, meta.mm_geo.lower * pagesize, meta.mm_geo.now * pagesize,
-        meta.mm_geo.upper * pagesize, pv2pages(meta.mm_geo.grow_pv) * pagesize,
-        pv2pages(meta.mm_geo.shrink_pv) * pagesize, meta.mm_psize);
-    if (unlikely(err != MDBX_SUCCESS)) {
-      mdbx_error("%s: err %d", "could not apply preconfigured geometry from db",
-                 err);
-      return (err == MDBX_EINVAL) ? MDBX_INCOMPATIBLE : err;
-    }
-  } else if (env->me_dbgeo.now) {
-    /* silently growth to last used page */
-    if (env->me_dbgeo.now < used_aligned2os_bytes)
-      env->me_dbgeo.now = used_aligned2os_bytes;
-    if (env->me_dbgeo.upper < used_aligned2os_bytes)
-      env->me_dbgeo.upper = used_aligned2os_bytes;
-
-    /* apply preconfigured params, but only if substantial changes:
-     *  - upper or lower limit changes
-     *  - shrink threshold or growth step
-     * But ignore change just a 'now/current' size. */
-    if (bytes_align2os_bytes(env, env->me_dbgeo.upper) !=
-            pgno2bytes(env, meta.mm_geo.upper) ||
-        bytes_align2os_bytes(env, env->me_dbgeo.lower) !=
-            pgno2bytes(env, meta.mm_geo.lower) ||
-        bytes_align2os_bytes(env, env->me_dbgeo.shrink) !=
-            pgno2bytes(env, pv2pages(meta.mm_geo.shrink_pv)) ||
-        bytes_align2os_bytes(env, env->me_dbgeo.grow) !=
-            pgno2bytes(env, pv2pages(meta.mm_geo.grow_pv))) {
-
-      if (env->me_dbgeo.shrink && env->me_dbgeo.now > used_bytes)
-        /* pre-shrink if enabled */
-        env->me_dbgeo.now = used_bytes + env->me_dbgeo.shrink -
-                            used_bytes % env->me_dbgeo.shrink;
-
-      err = mdbx_env_set_geometry(env, env->me_dbgeo.lower, env->me_dbgeo.now,
-                                  env->me_dbgeo.upper, env->me_dbgeo.grow,
-                                  env->me_dbgeo.shrink, meta.mm_psize);
-      if (unlikely(err != MDBX_SUCCESS)) {
-        mdbx_error("%s: err %d", "could not apply preconfigured db-geometry",
-                   err);
-        return (err == MDBX_EINVAL) ? MDBX_INCOMPATIBLE : err;
-      }
-
-      /* update meta fields */
-      meta.mm_geo.now = bytes2pgno(env, env->me_dbgeo.now);
-      meta.mm_geo.lower = bytes2pgno(env, env->me_dbgeo.lower);
-      meta.mm_geo.upper = bytes2pgno(env, env->me_dbgeo.upper);
-      meta.mm_geo.grow_pv = pages2pv(bytes2pgno(env, env->me_dbgeo.grow));
-      meta.mm_geo.shrink_pv = pages2pv(bytes2pgno(env, env->me_dbgeo.shrink));
-
-      mdbx_verbose("amended: root %" PRIaPGNO "/%" PRIaPGNO ", geo %" PRIaPGNO
-                   "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO
-                   " +%u -%u, txn_id %" PRIaTXN ", %s",
-                   meta.mm_dbs[MAIN_DBI].md_root, meta.mm_dbs[FREE_DBI].md_root,
-                   meta.mm_geo.lower, meta.mm_geo.next, meta.mm_geo.now,
-                   meta.mm_geo.upper, pv2pages(meta.mm_geo.grow_pv),
-                   pv2pages(meta.mm_geo.shrink_pv),
-                   unaligned_peek_u64(4, meta.mm_txnid_a),
-                   mdbx_durable_str(&meta));
-    } else {
-      /* fetch back 'now/current' size, since it was ignored during comparison
-       * and may differ. */
-      env->me_dbgeo.now = pgno_align2os_bytes(env, meta.mm_geo.now);
-    }
-    mdbx_ensure(env, meta.mm_geo.now >= meta.mm_geo.next);
-  } else {
-    /* geo-params are not pre-configured by user,
-     * get current values from the meta. */
-    env->me_dbgeo.now = pgno2bytes(env, meta.mm_geo.now);
-    env->me_dbgeo.lower = pgno2bytes(env, meta.mm_geo.lower);
-    env->me_dbgeo.upper = pgno2bytes(env, meta.mm_geo.upper);
-    env->me_dbgeo.grow = pgno2bytes(env, pv2pages(meta.mm_geo.grow_pv));
-    env->me_dbgeo.shrink = pgno2bytes(env, pv2pages(meta.mm_geo.shrink_pv));
-  }
-
-  mdbx_ensure(env,
-              pgno_align2os_bytes(env, meta.mm_geo.now) == env->me_dbgeo.now);
-  mdbx_ensure(env, env->me_dbgeo.now >= used_bytes);
-  const uint64_t filesize_before = env->me_dxb_mmap.filesize;
-  if (unlikely(filesize_before != env->me_dbgeo.now)) {
-    if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) {
-      mdbx_verbose("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO
-                   "p, have %" PRIu64 "b/%" PRIaPGNO "p), "
-                   "assume other process working",
-                   env->me_dbgeo.now, bytes2pgno(env, env->me_dbgeo.now),
-                   filesize_before, bytes2pgno(env, (size_t)filesize_before));
-    } else {
-      mdbx_warning("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO
-                   "p, have %" PRIu64 "b/%" PRIaPGNO "p)",
-                   env->me_dbgeo.now, bytes2pgno(env, env->me_dbgeo.now),
-                   filesize_before, bytes2pgno(env, (size_t)filesize_before));
-      if (filesize_before < used_bytes) {
-        mdbx_error("last-page beyond end-of-file (last %" PRIaPGNO
-                   ", have %" PRIaPGNO ")",
-                   meta.mm_geo.next, bytes2pgno(env, (size_t)filesize_before));
-        return MDBX_CORRUPTED;
-      }
-
-      if (env->me_flags & MDBX_RDONLY) {
-        if (filesize_before & (env->me_os_psize - 1)) {
-          mdbx_error("%s", "filesize should be rounded-up to system page");
-          return MDBX_WANNA_RECOVERY;
-        }
-        mdbx_warning("%s", "ignore filesize mismatch in readonly-mode");
-      } else {
-        mdbx_verbose("will resize datafile to %" PRIuSIZE " bytes, %" PRIaPGNO
-                     " pages",
-                     env->me_dbgeo.now, bytes2pgno(env, env->me_dbgeo.now));
-      }
-    }
-  }
-
-  mdbx_verbose("current boot-id %" PRIx64 "-%" PRIx64 " (%savailable)",
-               bootid.x, bootid.y, (bootid.x | bootid.y) ? "" : "not-");
-
-#if MDBX_ENABLE_MADVISE
-  /* calculate readahead hint before mmap with zero redundant pages */
-  const bool readahead =
-      !(env->me_flags & MDBX_NORDAHEAD) &&
-      mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE;
-#endif /* MDBX_ENABLE_MADVISE */
-
-  err = mdbx_mmap(env->me_flags, &env->me_dxb_mmap, env->me_dbgeo.now,
-                  env->me_dbgeo.upper, lck_rc ? MMAP_OPTION_TRUNCATE : 0);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-#if MDBX_ENABLE_MADVISE
-#if defined(MADV_DONTDUMP)
-  err = madvise(env->me_map, env->me_dxb_mmap.limit, MADV_DONTDUMP)
-            ? ignore_enosys(errno)
-            : MDBX_SUCCESS;
-  if (unlikely(MDBX_IS_ERROR(err)))
-    return err;
-#endif /* MADV_DONTDUMP */
-#if defined(MADV_DODUMP)
-  if (mdbx_runtime_flags & MDBX_DBG_DUMP) {
-    const size_t meta_length_aligned2os = pgno_align2os_bytes(env, NUM_METAS);
-    err = madvise(env->me_map, meta_length_aligned2os, MADV_DODUMP)
-              ? ignore_enosys(errno)
-              : MDBX_SUCCESS;
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-  }
-#endif /* MADV_DODUMP */
-#endif /* MDBX_ENABLE_MADVISE */
-
-#ifdef MDBX_USE_VALGRIND
-  env->me_valgrind_handle =
-      VALGRIND_CREATE_BLOCK(env->me_map, env->me_dxb_mmap.limit, "mdbx");
-#endif /* MDBX_USE_VALGRIND */
-
-  mdbx_assert(env, used_bytes >= pgno2bytes(env, NUM_METAS) &&
-                       used_bytes <= env->me_dxb_mmap.limit);
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  if (env->me_dxb_mmap.filesize > used_bytes &&
-      env->me_dxb_mmap.filesize < env->me_dxb_mmap.limit) {
-    VALGRIND_MAKE_MEM_NOACCESS(env->me_map + used_bytes,
-                               env->me_dxb_mmap.filesize - used_bytes);
-    MDBX_ASAN_POISON_MEMORY_REGION(env->me_map + used_bytes,
-                                   env->me_dxb_mmap.filesize - used_bytes);
-  }
-  env->me_poison_edge =
-      bytes2pgno(env, (env->me_dxb_mmap.filesize < env->me_dxb_mmap.limit)
-                          ? env->me_dxb_mmap.filesize
-                          : env->me_dxb_mmap.limit);
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-  //-------------------------------- validate/rollback head & steady meta-pages
-  if (unlikely(env->me_stuck_meta >= 0)) {
-    /* recovery mode */
-    MDBX_meta clone;
-    MDBX_meta const *const target = METAPAGE(env, env->me_stuck_meta);
-    err = mdbx_validate_meta_copy(env, target, &clone);
-    if (unlikely(err != MDBX_SUCCESS)) {
-      mdbx_error("target meta[%u] is corrupted",
-                 bytes2pgno(env, (uint8_t *)data_page(target) - env->me_map));
-      return MDBX_CORRUPTED;
-    }
-  } else /* not recovery mode */
-    while (1) {
-      const unsigned meta_clash_mask = meta_eq_mask(env);
-      if (unlikely(meta_clash_mask)) {
-        mdbx_error("meta-pages are clashed: mask 0x%d", meta_clash_mask);
-        return MDBX_CORRUPTED;
-      }
-
-      if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) {
-        /* non-exclusive mode,
-         * meta-pages should be validated by a first process opened the DB */
-        volatile const MDBX_meta *const head = meta_prefer_last(env);
-        volatile const MDBX_meta *const steady = meta_prefer_steady(env);
-        const txnid_t head_txnid = meta_txnid(env, head);
-        const txnid_t steady_txnid = meta_txnid(env, steady);
-        if (head_txnid == steady_txnid)
-          break;
-
-        if (!env->me_lck_mmap.lck) {
-          /* LY: without-lck (read-only) mode, so it is impossible that other
-           * process made weak checkpoint. */
-          mdbx_error("%s", "without-lck, unable recovery/rollback");
-          return MDBX_WANNA_RECOVERY;
-        }
-
-        /* LY: assume just have a collision with other running process,
-         *     or someone make a weak checkpoint */
-        mdbx_verbose("%s", "assume collision or online weak checkpoint");
-        break;
-      }
-      mdbx_assert(env, lck_rc == MDBX_RESULT_TRUE);
-      /* exclusive mode */
-
-      MDBX_meta clone;
-      const MDBX_meta *const steady = constmeta_prefer_steady(env);
-      const MDBX_meta *const head = constmeta_prefer_last(env);
-      const txnid_t steady_txnid = meta_txnid(env, steady);
-      if (META_IS_STEADY(steady)) {
-        err = mdbx_validate_meta_copy(env, steady, &clone);
-        if (unlikely(err != MDBX_SUCCESS)) {
-          mdbx_error("meta[%u] with %s txnid %" PRIaTXN
-                     " is corrupted, %s needed",
-                     bytes2pgno(env, (uint8_t *)steady - env->me_map), "steady",
-                     steady_txnid, "manual recovery");
-          return MDBX_CORRUPTED;
-        }
-        if (steady == head)
-          break;
-      }
-
-      const pgno_t pgno = bytes2pgno(env, (uint8_t *)head - env->me_map);
-      const txnid_t head_txnid = meta_txnid(env, head);
-      const bool head_valid =
-          mdbx_validate_meta_copy(env, head, &clone) == MDBX_SUCCESS;
-      mdbx_assert(env, !META_IS_STEADY(steady) || head_txnid != steady_txnid);
-      if (unlikely(!head_valid)) {
-        if (unlikely(!META_IS_STEADY(steady))) {
-          mdbx_error("%s for open or automatic rollback, %s",
-                     "there are no suitable meta-pages",
-                     "manual recovery is required");
-          return MDBX_CORRUPTED;
-        }
-        mdbx_warning("meta[%u] with last txnid %" PRIaTXN
-                     " is corrupted, rollback needed",
-                     pgno, head_txnid);
-        goto purge_meta_head;
-      }
-
-      if (meta_bootid_match(head)) {
-        if (env->me_flags & MDBX_RDONLY) {
-          mdbx_error("%s, but boot-id(%016" PRIx64 "-%016" PRIx64 ") is MATCH: "
-                     "rollback NOT needed, steady-sync NEEDED%s",
-                     "opening after an unclean shutdown", bootid.x, bootid.y,
-                     ", but unable in read-only mode");
-          return MDBX_WANNA_RECOVERY;
-        }
-        mdbx_warning("%s, but boot-id(%016" PRIx64 "-%016" PRIx64 ") is MATCH: "
-                     "rollback NOT needed, steady-sync NEEDED%s",
-                     "opening after an unclean shutdown", bootid.x, bootid.y,
-                     "");
-        meta = clone;
-        atomic_store32(&env->me_lck->mti_unsynced_pages, meta.mm_geo.next,
-                       mo_Relaxed);
-        break;
-      }
-      if (unlikely(!META_IS_STEADY(steady))) {
-        mdbx_error("%s, but %s for automatic rollback: %s",
-                   "opening after an unclean shutdown",
-                   "there are no suitable meta-pages",
-                   "manual recovery is required");
-        return MDBX_CORRUPTED;
-      }
-      if (env->me_flags & MDBX_RDONLY) {
-        mdbx_error("%s and rollback needed: (from head %" PRIaTXN
-                   " to steady %" PRIaTXN ")%s",
-                   "opening after an unclean shutdown", head_txnid,
-                   steady_txnid, ", but unable in read-only mode");
-        return MDBX_WANNA_RECOVERY;
-      }
-
-    purge_meta_head:
-      mdbx_notice("%s and doing automatic rollback: "
-                  "purge%s meta[%u] with%s txnid %" PRIaTXN,
-                  "opening after an unclean shutdown",
-                  head_valid ? "" : " invalid", pgno, head_valid ? " weak" : "",
-                  head_txnid);
-      mdbx_ensure(env, META_IS_STEADY(steady));
-      err = mdbx_override_meta(env, pgno, 0, head_valid ? head : steady);
-      if (err) {
-        mdbx_error("rollback: overwrite meta[%u] with txnid %" PRIaTXN
-                   ", error %d",
-                   pgno, head_txnid, err);
-        return err;
-      }
-      mdbx_ensure(env, 0 == meta_txnid(env, head));
-      mdbx_ensure(env, 0 == meta_eq_mask(env));
-    }
-
-  if (lck_rc == /* lck exclusive */ MDBX_RESULT_TRUE) {
-    //-------------------------------------------------- shrink DB & update geo
-    const MDBX_meta *head = constmeta_prefer_last(env);
-    /* re-check size after mmap */
-    if ((env->me_dxb_mmap.current & (env->me_os_psize - 1)) != 0 ||
-        env->me_dxb_mmap.current < used_bytes) {
-      mdbx_error("unacceptable/unexpected datafile size %" PRIuPTR,
-                 env->me_dxb_mmap.current);
-      return MDBX_PROBLEM;
-    }
-    if (env->me_dxb_mmap.current != env->me_dbgeo.now) {
-      meta.mm_geo.now = bytes2pgno(env, env->me_dxb_mmap.current);
-      mdbx_notice("need update meta-geo to filesize %" PRIuPTR
-                  " bytes, %" PRIaPGNO " pages",
-                  env->me_dxb_mmap.current, meta.mm_geo.now);
-    }
-
-    if (memcmp(&meta.mm_geo, &head->mm_geo, sizeof(meta.mm_geo))) {
-      if ((env->me_flags & MDBX_RDONLY) != 0 ||
-          /* recovery mode */ env->me_stuck_meta >= 0) {
-        mdbx_warning(
-            "skipped update meta.geo in %s mode: from l%" PRIaPGNO
-            "-n%" PRIaPGNO "-u%" PRIaPGNO "/s%u-g%u, to l%" PRIaPGNO
-            "-n%" PRIaPGNO "-u%" PRIaPGNO "/s%u-g%u",
-            (env->me_stuck_meta < 0) ? "read-only" : "recovery",
-            head->mm_geo.lower, head->mm_geo.now, head->mm_geo.upper,
-            pv2pages(head->mm_geo.shrink_pv), pv2pages(head->mm_geo.grow_pv),
-            meta.mm_geo.lower, meta.mm_geo.now, meta.mm_geo.upper,
-            pv2pages(meta.mm_geo.shrink_pv), pv2pages(meta.mm_geo.grow_pv));
-      } else {
-        const txnid_t txnid = constmeta_txnid(env, head);
-        const txnid_t next_txnid = safe64_txnid_next(txnid);
-        if (unlikely(txnid > MAX_TXNID)) {
-          mdbx_error("txnid overflow, raise %d", MDBX_TXN_FULL);
-          return MDBX_TXN_FULL;
-        }
-        mdbx_notice("updating meta.geo: "
-                    "from l%" PRIaPGNO "-n%" PRIaPGNO "-u%" PRIaPGNO
-                    "/s%u-g%u (txn#%" PRIaTXN "), "
-                    "to l%" PRIaPGNO "-n%" PRIaPGNO "-u%" PRIaPGNO
-                    "/s%u-g%u (txn#%" PRIaTXN ")",
-                    head->mm_geo.lower, head->mm_geo.now, head->mm_geo.upper,
-                    pv2pages(head->mm_geo.shrink_pv),
-                    pv2pages(head->mm_geo.grow_pv), txnid, meta.mm_geo.lower,
-                    meta.mm_geo.now, meta.mm_geo.upper,
-                    pv2pages(meta.mm_geo.shrink_pv),
-                    pv2pages(meta.mm_geo.grow_pv), next_txnid);
-
-        mdbx_ensure(env, meta_eq(env, &meta, head));
-        meta_set_txnid(env, &meta, next_txnid);
-        err = mdbx_sync_locked(env, env->me_flags | MDBX_SHRINK_ALLOWED, &meta);
-        if (err) {
-          mdbx_error("error %d, while updating meta.geo: "
-                     "from l%" PRIaPGNO "-n%" PRIaPGNO "-u%" PRIaPGNO
-                     "/s%u-g%u (txn#%" PRIaTXN "), "
-                     "to l%" PRIaPGNO "-n%" PRIaPGNO "-u%" PRIaPGNO
-                     "/s%u-g%u (txn#%" PRIaTXN ")",
-                     err, head->mm_geo.lower, head->mm_geo.now,
-                     head->mm_geo.upper, pv2pages(head->mm_geo.shrink_pv),
-                     pv2pages(head->mm_geo.grow_pv), txnid, meta.mm_geo.lower,
-                     meta.mm_geo.now, meta.mm_geo.upper,
-                     pv2pages(meta.mm_geo.shrink_pv),
-                     pv2pages(meta.mm_geo.grow_pv), next_txnid);
-          return err;
-        }
-      }
-    }
-
-    atomic_store32(&env->me_lck->mti_discarded_tail,
-                   bytes2pgno(env, used_aligned2os_bytes), mo_Relaxed);
-
-    if ((env->me_flags & MDBX_RDONLY) == 0 && env->me_stuck_meta < 0 &&
-        (mdbx_runtime_flags & MDBX_DBG_DONT_UPGRADE) == 0) {
-      for (int n = 0; n < NUM_METAS; ++n) {
-        MDBX_meta *const pmeta = METAPAGE(env, n);
-        if (unlikely(unaligned_peek_u64(4, &pmeta->mm_magic_and_version) !=
-                     MDBX_DATA_MAGIC)) {
-          const txnid_t txnid = meta_txnid(env, pmeta);
-          mdbx_notice("%s %s"
-                      "meta[%u], txnid %" PRIaTXN,
-                      "updating db-format signature for",
-                      META_IS_STEADY(pmeta) ? "stead-" : "weak-", n, txnid);
-          err = mdbx_override_meta(env, n, txnid, pmeta);
-          if (unlikely(err != MDBX_SUCCESS) &&
-              /* Just ignore the MDBX_PROBLEM error, since here it is
-               * returned only in case of the attempt to upgrade an obsolete
-               * meta-page that is invalid for current state of a DB,
-               * e.g. after shrinking DB file */
-              err != MDBX_PROBLEM) {
-            mdbx_error("%s meta[%u], txnid %" PRIaTXN ", error %d",
-                       "updating db-format signature for", n, txnid, err);
-            return err;
-          }
-        }
-      }
-    }
-  } /* lck exclusive, lck_rc == MDBX_RESULT_TRUE */
-
-  //---------------------------------------------------- setup madvise/readahead
-#if MDBX_ENABLE_MADVISE
-  if (used_aligned2os_bytes < env->me_dxb_mmap.current) {
-#if defined(MADV_REMOVE)
-    if (lck_rc && (env->me_flags & MDBX_WRITEMAP) != 0 &&
-        /* not recovery mode */ env->me_stuck_meta < 0) {
-      mdbx_notice("open-MADV_%s %u..%u", "REMOVE (deallocate file space)",
-                  env->me_lck->mti_discarded_tail.weak,
-                  bytes2pgno(env, env->me_dxb_mmap.current));
-      err =
-          madvise(env->me_map + used_aligned2os_bytes,
-                  env->me_dxb_mmap.current - used_aligned2os_bytes, MADV_REMOVE)
-              ? ignore_enosys(errno)
-              : MDBX_SUCCESS;
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-    }
-#endif /* MADV_REMOVE */
-#if defined(MADV_DONTNEED)
-    mdbx_notice("open-MADV_%s %u..%u", "DONTNEED",
-                env->me_lck->mti_discarded_tail.weak,
-                bytes2pgno(env, env->me_dxb_mmap.current));
-    err =
-        madvise(env->me_map + used_aligned2os_bytes,
-                env->me_dxb_mmap.current - used_aligned2os_bytes, MADV_DONTNEED)
-            ? ignore_enosys(errno)
-            : MDBX_SUCCESS;
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(POSIX_MADV_DONTNEED)
-    err = ignore_enosys(posix_madvise(
-        env->me_map + used_aligned2os_bytes,
-        env->me_dxb_mmap.current - used_aligned2os_bytes, POSIX_MADV_DONTNEED));
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#elif defined(POSIX_FADV_DONTNEED)
-    err = ignore_enosys(posix_fadvise(
-        env->me_lazy_fd, used_aligned2os_bytes,
-        env->me_dxb_mmap.current - used_aligned2os_bytes, POSIX_FADV_DONTNEED));
-    if (unlikely(MDBX_IS_ERROR(err)))
-      return err;
-#endif /* MADV_DONTNEED */
-  }
-
-  err = mdbx_set_readahead(env, bytes2pgno(env, used_bytes), readahead, true);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-#endif /* MDBX_ENABLE_MADVISE */
-
-  return rc;
-}
-
-/******************************************************************************/
-
-/* Open and/or initialize the lock region for the environment. */
-__cold static int mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
-                                 mdbx_mode_t mode) {
-  mdbx_assert(env, env->me_lazy_fd != INVALID_HANDLE_VALUE);
-  mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE);
-
-  int err = mdbx_openfile(MDBX_OPEN_LCK, env, lck_pathname, &env->me_lfd, mode);
-  if (err != MDBX_SUCCESS) {
-    if (!(err == MDBX_ENOFILE && (env->me_flags & MDBX_EXCLUSIVE)) &&
-        !((err == MDBX_EROFS || err == MDBX_EACCESS || err == MDBX_EPERM) &&
-          (env->me_flags & MDBX_RDONLY)))
-      return err;
-
-    /* ensure the file system is read-only */
-    err = mdbx_check_fs_rdonly(env->me_lazy_fd, lck_pathname, err);
-    if (err != MDBX_SUCCESS &&
-        /* ignore ERROR_NOT_SUPPORTED for exclusive mode */
-        !(err == MDBX_ENOSYS && (env->me_flags & MDBX_EXCLUSIVE)))
-      return err;
-
-    /* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
-    /* beginning of a locked section ---------------------------------------- */
-    lcklist_lock();
-    mdbx_assert(env, env->me_lcklist_next == nullptr);
-    env->me_lfd = INVALID_HANDLE_VALUE;
-    const int rc = mdbx_lck_seize(env);
-    if (MDBX_IS_ERROR(rc)) {
-      /* Calling lcklist_detach_locked() is required to restore POSIX-filelock
-       * and this job will be done by mdbx_env_close0(). */
-      lcklist_unlock();
-      return rc;
-    }
-    /* insert into inprocess lck-list */
-    env->me_lcklist_next = inprocess_lcklist_head;
-    inprocess_lcklist_head = env;
-    lcklist_unlock();
-    /* end of a locked section ---------------------------------------------- */
-
-    env->me_lck = lckless_stub(env);
-    env->me_maxreaders = UINT_MAX;
-    mdbx_debug("lck-setup:%s%s%s", " lck-less",
-               (env->me_flags & MDBX_RDONLY) ? " readonly" : "",
-               (rc == MDBX_RESULT_TRUE) ? " exclusive" : " cooperative");
-    return rc;
-  }
-
-  /* beginning of a locked section ------------------------------------------ */
-  lcklist_lock();
-  mdbx_assert(env, env->me_lcklist_next == nullptr);
-
-  /* Try to get exclusive lock. If we succeed, then
-   * nobody is using the lock region and we should initialize it. */
-  err = mdbx_lck_seize(env);
-  if (MDBX_IS_ERROR(err)) {
-  bailout:
-    /* Calling lcklist_detach_locked() is required to restore POSIX-filelock
-     * and this job will be done by mdbx_env_close0(). */
-    lcklist_unlock();
-    return err;
-  }
-
-  MDBX_env *inprocess_neighbor = nullptr;
-  if (err == MDBX_RESULT_TRUE) {
-    err = uniq_check(&env->me_lck_mmap, &inprocess_neighbor);
-    if (MDBX_IS_ERROR(err))
-      goto bailout;
-    if (inprocess_neighbor &&
-        ((mdbx_runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0 ||
-         (inprocess_neighbor->me_flags & MDBX_EXCLUSIVE) != 0)) {
-      err = MDBX_BUSY;
-      goto bailout;
-    }
-  }
-  const int lck_seize_rc = err;
-
-  mdbx_debug("lck-setup:%s%s%s", " with-lck",
-             (env->me_flags & MDBX_RDONLY) ? " readonly" : "",
-             (lck_seize_rc == MDBX_RESULT_TRUE) ? " exclusive"
-                                                : " cooperative");
-
-  uint64_t size = 0;
-  err = mdbx_filesize(env->me_lfd, &size);
-  if (unlikely(err != MDBX_SUCCESS))
-    goto bailout;
-
-  if (lck_seize_rc == MDBX_RESULT_TRUE) {
-    size = ceil_powerof2(env->me_maxreaders * sizeof(MDBX_reader) +
-                             sizeof(MDBX_lockinfo),
-                         env->me_os_psize);
-    mdbx_jitter4testing(false);
-  } else {
-    if (env->me_flags & MDBX_EXCLUSIVE) {
-      err = MDBX_BUSY;
-      goto bailout;
-    }
-    if (size > INT_MAX || (size & (env->me_os_psize - 1)) != 0 ||
-        size < env->me_os_psize) {
-      mdbx_error("lck-file has invalid size %" PRIu64 " bytes", size);
-      err = MDBX_PROBLEM;
-      goto bailout;
-    }
-  }
-
-  const size_t maxreaders =
-      ((size_t)size - sizeof(MDBX_lockinfo)) / sizeof(MDBX_reader);
-  if (maxreaders < 4) {
-    mdbx_error("lck-size too small (up to %" PRIuPTR " readers)", maxreaders);
-    err = MDBX_PROBLEM;
-    goto bailout;
-  }
-  env->me_maxreaders = (maxreaders <= MDBX_READERS_LIMIT)
-                           ? (unsigned)maxreaders
-                           : (unsigned)MDBX_READERS_LIMIT;
-
-  err = mdbx_mmap((env->me_flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP,
-                  &env->me_lck_mmap, (size_t)size, (size_t)size,
-                  lck_seize_rc ? MMAP_OPTION_TRUNCATE | MMAP_OPTION_SEMAPHORE
-                               : MMAP_OPTION_SEMAPHORE);
-  if (unlikely(err != MDBX_SUCCESS))
-    goto bailout;
-
-#if MDBX_ENABLE_MADVISE
-#ifdef MADV_DODUMP
-  err = madvise(env->me_lck_mmap.lck, size, MADV_DODUMP) ? ignore_enosys(errno)
-                                                         : MDBX_SUCCESS;
-  if (unlikely(MDBX_IS_ERROR(err)))
-    goto bailout;
-#endif /* MADV_DODUMP */
-
-#ifdef MADV_WILLNEED
-  err = madvise(env->me_lck_mmap.lck, size, MADV_WILLNEED)
-            ? ignore_enosys(errno)
-            : MDBX_SUCCESS;
-  if (unlikely(MDBX_IS_ERROR(err)))
-    goto bailout;
-#elif defined(POSIX_MADV_WILLNEED)
-  err = ignore_enosys(
-      posix_madvise(env->me_lck_mmap.lck, size, POSIX_MADV_WILLNEED));
-  if (unlikely(MDBX_IS_ERROR(err)))
-    goto bailout;
-#endif /* MADV_WILLNEED */
-#endif /* MDBX_ENABLE_MADVISE */
-
-  struct MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (lck_seize_rc == MDBX_RESULT_TRUE) {
-    /* LY: exclusive mode, check and reset lck content */
-    memset(lck, 0, (size_t)size);
-    mdbx_jitter4testing(false);
-    lck->mti_magic_and_version = MDBX_LOCK_MAGIC;
-    lck->mti_os_and_format = MDBX_LOCK_FORMAT;
-#if MDBX_ENABLE_PGOP_STAT
-    lck->mti_pgop_stat.wops.weak = 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-    err = mdbx_msync(&env->me_lck_mmap, 0, (size_t)size, MDBX_SYNC_NONE);
-    if (unlikely(err != MDBX_SUCCESS)) {
-      mdbx_error("initial-%s for lck-file failed", "msync");
-      goto bailout;
-    }
-    err = mdbx_fsync(env->me_lck_mmap.fd, MDBX_SYNC_SIZE);
-    if (unlikely(err != MDBX_SUCCESS)) {
-      mdbx_error("initial-%s for lck-file failed", "fsync");
-      goto bailout;
-    }
-  } else {
-    if (lck->mti_magic_and_version != MDBX_LOCK_MAGIC) {
-      const bool invalid = (lck->mti_magic_and_version >> 8) != MDBX_MAGIC;
-      mdbx_error(
-          "lock region has %s",
-          invalid
-              ? "invalid magic"
-              : "incompatible version (only applications with nearly or the "
-                "same versions of libmdbx can share the same database)");
-      err = invalid ? MDBX_INVALID : MDBX_VERSION_MISMATCH;
-      goto bailout;
-    }
-    if (lck->mti_os_and_format != MDBX_LOCK_FORMAT) {
-      mdbx_error("lock region has os/format signature 0x%" PRIx32
-                 ", expected 0x%" PRIx32,
-                 lck->mti_os_and_format, MDBX_LOCK_FORMAT);
-      err = MDBX_VERSION_MISMATCH;
-      goto bailout;
-    }
-  }
-
-  err = mdbx_lck_init(env, inprocess_neighbor, lck_seize_rc);
-  if (MDBX_IS_ERROR(err))
-    goto bailout;
-
-  mdbx_ensure(env, env->me_lcklist_next == nullptr);
-  /* insert into inprocess lck-list */
-  env->me_lcklist_next = inprocess_lcklist_head;
-  inprocess_lcklist_head = env;
-  lcklist_unlock();
-  /* end of a locked section ------------------------------------------------ */
-
-  mdbx_assert(env, !MDBX_IS_ERROR(lck_seize_rc));
-  env->me_lck = lck;
-  return lck_seize_rc;
-}
-
-__cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
-  if (volume <= 1024 * 1024 * 4ul)
-    return MDBX_RESULT_TRUE;
-
-  intptr_t pagesize, total_ram_pages;
-  int err = mdbx_get_sysraminfo(&pagesize, &total_ram_pages, nullptr);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  const int log2page = log2n_powerof2(pagesize);
-  const intptr_t volume_pages = (volume + pagesize - 1) >> log2page;
-  const intptr_t redundancy_pages =
-      (redundancy < 0) ? -(intptr_t)((-redundancy + pagesize - 1) >> log2page)
-                       : (intptr_t)(redundancy + pagesize - 1) >> log2page;
-  if (volume_pages >= total_ram_pages ||
-      volume_pages + redundancy_pages >= total_ram_pages)
-    return MDBX_RESULT_FALSE;
-
-  intptr_t avail_ram_pages;
-  err = mdbx_get_sysraminfo(nullptr, nullptr, &avail_ram_pages);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  return (volume_pages + redundancy_pages >= avail_ram_pages)
-             ? MDBX_RESULT_FALSE
-             : MDBX_RESULT_TRUE;
-}
-
-/* Merge sync flags */
-static uint32_t merge_sync_flags(const uint32_t a, const uint32_t b) {
-  uint32_t r = a | b;
-
-  /* avoid false MDBX_UTTERLY_NOSYNC */
-  if (F_ISSET(r, MDBX_UTTERLY_NOSYNC) && !F_ISSET(a, MDBX_UTTERLY_NOSYNC) &&
-      !F_ISSET(b, MDBX_UTTERLY_NOSYNC))
-    r = (r - MDBX_UTTERLY_NOSYNC) | MDBX_SAFE_NOSYNC;
-
-  /* convert MDBX_DEPRECATED_MAPASYNC to MDBX_SAFE_NOSYNC */
-  if ((r & (MDBX_WRITEMAP | MDBX_DEPRECATED_MAPASYNC)) ==
-          (MDBX_WRITEMAP | MDBX_DEPRECATED_MAPASYNC) &&
-      !F_ISSET(r, MDBX_UTTERLY_NOSYNC))
-    r = (r - MDBX_DEPRECATED_MAPASYNC) | MDBX_SAFE_NOSYNC;
-
-  /* force MDBX_NOMETASYNC if MDBX_SAFE_NOSYNC enabled */
-  if (r & MDBX_SAFE_NOSYNC)
-    r |= MDBX_NOMETASYNC;
-
-  assert(!(F_ISSET(r, MDBX_UTTERLY_NOSYNC) &&
-           !F_ISSET(a, MDBX_UTTERLY_NOSYNC) &&
-           !F_ISSET(b, MDBX_UTTERLY_NOSYNC)));
-  return r;
-}
-
-__cold static int __must_check_result mdbx_override_meta(
-    MDBX_env *env, unsigned target, txnid_t txnid, const MDBX_meta *shape) {
-  int rc = alloc_page_buf(env);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  MDBX_page *const page = env->me_pbuf;
-  mdbx_meta_model(env, page, target);
-  MDBX_meta *const model = page_meta(page);
-  meta_set_txnid(env, model, txnid);
-  mdbx_assert(env, meta_checktxnid(env, model, true));
-  if (shape) {
-    if (txnid && unlikely(!meta_checktxnid(env, shape, false))) {
-      mdbx_error("bailout overriding meta-%u since model failed "
-                 "freedb/maindb %s-check for txnid #%" PRIaTXN,
-                 target, "pre", constmeta_txnid(env, shape));
-      return MDBX_PROBLEM;
-    }
-    if (mdbx_runtime_flags & MDBX_DBG_DONT_UPGRADE)
-      memcpy(&model->mm_magic_and_version, &shape->mm_magic_and_version,
-             sizeof(model->mm_magic_and_version));
-    model->mm_extra_flags = shape->mm_extra_flags;
-    model->mm_validator_id = shape->mm_validator_id;
-    model->mm_extra_pagehdr = shape->mm_extra_pagehdr;
-    memcpy(&model->mm_geo, &shape->mm_geo, sizeof(model->mm_geo));
-    memcpy(&model->mm_dbs, &shape->mm_dbs, sizeof(model->mm_dbs));
-    memcpy(&model->mm_canary, &shape->mm_canary, sizeof(model->mm_canary));
-    memcpy(&model->mm_pages_retired, &shape->mm_pages_retired,
-           sizeof(model->mm_pages_retired));
-    if (txnid) {
-      if ((!model->mm_dbs[FREE_DBI].md_mod_txnid &&
-           model->mm_dbs[FREE_DBI].md_root != P_INVALID) ||
-          (!model->mm_dbs[MAIN_DBI].md_mod_txnid &&
-           model->mm_dbs[MAIN_DBI].md_root != P_INVALID))
-        memcpy(&model->mm_magic_and_version, &shape->mm_magic_and_version,
-               sizeof(model->mm_magic_and_version));
-      if (unlikely(!meta_checktxnid(env, model, false))) {
-        mdbx_error("bailout overriding meta-%u since model failed "
-                   "freedb/maindb %s-check for txnid #%" PRIaTXN,
-                   target, "post", txnid);
-        return MDBX_PROBLEM;
-      }
-    }
-  }
-  unaligned_poke_u64(4, model->mm_datasync_sign, meta_sign(model));
-  rc = mdbx_validate_meta(env, model, page, target, nullptr);
-  if (unlikely(MDBX_IS_ERROR(rc)))
-    return MDBX_PROBLEM;
-
-  if (shape && memcmp(model, shape, sizeof(MDBX_meta)) == 0)
-    return MDBX_SUCCESS;
-
-#if MDBX_ENABLE_PGOP_STAT
-  env->me_lck->mti_pgop_stat.wops.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  if (env->me_flags & MDBX_WRITEMAP) {
-    rc = mdbx_msync(&env->me_dxb_mmap, 0,
-                    pgno_align2os_bytes(env, model->mm_geo.next),
-                    MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    /* mdbx_override_meta() called only while current process have exclusive
-     * lock of a DB file. So meta-page could be updated directly without
-     * clearing consistency flag by mdbx_meta_update_begin() */
-    memcpy(pgno2page(env, target), page, env->me_psize);
-    mdbx_flush_incoherent_cpu_writeback();
-    rc = mdbx_msync(&env->me_dxb_mmap, 0, pgno_align2os_bytes(env, target + 1),
-                    MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-  } else {
-    const mdbx_filehandle_t fd = (env->me_dsync_fd != INVALID_HANDLE_VALUE)
-                                     ? env->me_dsync_fd
-                                     : env->me_lazy_fd;
-    rc = mdbx_pwrite(fd, page, env->me_psize, pgno2bytes(env, target));
-    if (rc == MDBX_SUCCESS && fd == env->me_lazy_fd)
-      rc = mdbx_fsync(env->me_lazy_fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-  }
-  mdbx_flush_incoherent_mmap(env->me_map, pgno2bytes(env, NUM_METAS),
-                             env->me_os_psize);
-  return rc;
-}
-
-__cold int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target) {
-  if (unlikely(target >= NUM_METAS))
-    return MDBX_EINVAL;
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely((env->me_flags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) !=
-               MDBX_EXCLUSIVE))
-    return MDBX_EPERM;
-
-  const MDBX_meta *target_meta = METAPAGE(env, target);
-  txnid_t new_txnid = safe64_txnid_next(constmeta_txnid(env, target_meta));
-  for (unsigned n = 0; n < NUM_METAS; ++n) {
-    MDBX_page *page = pgno2page(env, n);
-    MDBX_meta meta = *page_meta(page);
-    if (n == target)
-      continue;
-    if (mdbx_validate_meta(env, &meta, page, n, nullptr) != MDBX_SUCCESS) {
-      int err = mdbx_override_meta(env, n, 0, nullptr);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-    } else {
-      txnid_t txnid = constmeta_txnid(env, &meta);
-      if (new_txnid <= txnid)
-        new_txnid = safe64_txnid_next(txnid);
-    }
-  }
-
-  if (unlikely(new_txnid > MAX_TXNID)) {
-    mdbx_error("txnid overflow, raise %d", MDBX_TXN_FULL);
-    return MDBX_TXN_FULL;
-  }
-  return mdbx_override_meta(env, target, new_txnid, target_meta);
-}
-
-__cold int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname,
-                                      unsigned target_meta, bool writeable) {
-  if (unlikely(target_meta >= NUM_METAS))
-    return MDBX_EINVAL;
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  if (unlikely(env->me_map))
-    return MDBX_EPERM;
-
-  env->me_stuck_meta = (int8_t)target_meta;
-  return mdbx_env_open(
-      env, pathname, writeable ? MDBX_EXCLUSIVE : MDBX_EXCLUSIVE | MDBX_RDONLY,
-      0);
-}
-
-typedef struct {
-  void *buffer_for_free;
-  char *lck, *dxb;
-  size_t ent_len;
-} MDBX_handle_env_pathname;
-
-__cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx,
-                                           const char *pathname,
-                                           MDBX_env_flags_t *flags,
-                                           const mdbx_mode_t mode) {
-  int rc;
-  memset(ctx, 0, sizeof(*ctx));
-  if (unlikely(!pathname))
-    return MDBX_EINVAL;
-
-#if defined(_WIN32) || defined(_WIN64)
-  const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
-  if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
-    return ERROR_INVALID_NAME;
-  wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
-  if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
-    return ERROR_INVALID_NAME;
-
-  const DWORD dwAttrib = GetFileAttributesW(pathnameW);
-  if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
-    rc = GetLastError();
-    if (rc != MDBX_ENOFILE)
-      return rc;
-    if (mode == 0 || (*flags & MDBX_RDONLY) != 0)
-      /* can't open existing */
-      return rc;
-
-    /* auto-create directory if requested */
-    if ((*flags & MDBX_NOSUBDIR) == 0 &&
-        !CreateDirectoryW(pathnameW, nullptr)) {
-      rc = GetLastError();
-      if (rc != ERROR_ALREADY_EXISTS)
-        return rc;
-    }
-  } else {
-    /* ignore passed MDBX_NOSUBDIR flag and set it automatically */
-    *flags |= MDBX_NOSUBDIR;
-    if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)
-      *flags -= MDBX_NOSUBDIR;
-  }
-#else
-  struct stat st;
-  if (stat(pathname, &st)) {
-    rc = errno;
-    if (rc != MDBX_ENOFILE)
-      return rc;
-    if (mode == 0 || (*flags & MDBX_RDONLY) != 0)
-      /* can't open existing */
-      return rc;
-
-    /* auto-create directory if requested */
-    const mdbx_mode_t dir_mode =
-        (/* inherit read/write permissions for group and others */ mode &
-         (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
-        /* always add read/write/search for owner */ S_IRWXU |
-        ((mode & S_IRGRP) ? /* +search if readable by group */ S_IXGRP : 0) |
-        ((mode & S_IROTH) ? /* +search if readable by others */ S_IXOTH : 0);
-    if ((*flags & MDBX_NOSUBDIR) == 0 && mkdir(pathname, dir_mode)) {
-      rc = errno;
-      if (rc != EEXIST)
-        return rc;
-    }
-  } else {
-    /* ignore passed MDBX_NOSUBDIR flag and set it automatically */
-    *flags |= MDBX_NOSUBDIR;
-    if (S_ISDIR(st.st_mode))
-      *flags -= MDBX_NOSUBDIR;
-  }
-#endif
-
-  static const char dxb_name[] = MDBX_DATANAME;
-  static const size_t dxb_name_len = sizeof(dxb_name) - 1;
-  static const char lck_name[] = MDBX_LOCKNAME;
-  static const char lock_suffix[] = MDBX_LOCK_SUFFIX;
-
-  ctx->ent_len = strlen(pathname);
-  if ((*flags & MDBX_NOSUBDIR) && ctx->ent_len >= dxb_name_len &&
-      !memcmp(dxb_name, pathname + ctx->ent_len - dxb_name_len, dxb_name_len)) {
-    *flags -= MDBX_NOSUBDIR;
-    ctx->ent_len -= dxb_name_len;
-  }
-
-  const size_t bytes_needed =
-      ctx->ent_len * 2 + ((*flags & MDBX_NOSUBDIR)
-                              ? sizeof(lock_suffix) + 1
-                              : sizeof(lck_name) + sizeof(dxb_name));
-  ctx->buffer_for_free = mdbx_malloc(bytes_needed);
-  if (!ctx->buffer_for_free)
-    return MDBX_ENOMEM;
-
-  ctx->lck = ctx->buffer_for_free;
-  if (*flags & MDBX_NOSUBDIR) {
-    ctx->dxb = ctx->lck + ctx->ent_len + sizeof(lock_suffix);
-    sprintf(ctx->lck, "%s%s", pathname, lock_suffix);
-    strcpy(ctx->dxb, pathname);
-  } else {
-    ctx->dxb = ctx->lck + ctx->ent_len + sizeof(lck_name);
-    sprintf(ctx->lck, "%.*s%s", (int)ctx->ent_len, pathname, lck_name);
-    sprintf(ctx->dxb, "%.*s%s", (int)ctx->ent_len, pathname, dxb_name);
-  }
-
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) {
-  switch (mode) {
-  default:
-    return MDBX_EINVAL;
-  case MDBX_ENV_JUST_DELETE:
-  case MDBX_ENV_ENSURE_UNUSED:
-  case MDBX_ENV_WAIT_FOR_UNUSED:
-    break;
-  }
-
-#ifdef __e2k__ /* https://bugs.mcst.ru/bugzilla/show_bug.cgi?id=6011 */
-  MDBX_env *const dummy_env = alloca(sizeof(MDBX_env));
-#else
-  MDBX_env dummy_env_silo, *const dummy_env = &dummy_env_silo;
-#endif
-  memset(dummy_env, 0, sizeof(*dummy_env));
-  dummy_env->me_flags =
-      (mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS;
-  dummy_env->me_os_psize = (unsigned)mdbx_syspagesize();
-  dummy_env->me_psize = (unsigned)mdbx_default_pagesize();
-  dummy_env->me_pathname = (char *)pathname;
-
-  MDBX_handle_env_pathname env_pathname;
-  STATIC_ASSERT(sizeof(dummy_env->me_flags) == sizeof(MDBX_env_flags_t));
-  int rc = MDBX_RESULT_TRUE,
-      err = mdbx_handle_env_pathname(
-          &env_pathname, pathname, (MDBX_env_flags_t *)&dummy_env->me_flags, 0);
-  if (likely(err == MDBX_SUCCESS)) {
-    mdbx_filehandle_t clk_handle = INVALID_HANDLE_VALUE,
-                      dxb_handle = INVALID_HANDLE_VALUE;
-    if (mode > MDBX_ENV_JUST_DELETE) {
-      err = mdbx_openfile(MDBX_OPEN_DELETE, dummy_env, env_pathname.dxb,
-                          &dxb_handle, 0);
-      err = (err == MDBX_ENOFILE) ? MDBX_SUCCESS : err;
-      if (err == MDBX_SUCCESS) {
-        err = mdbx_openfile(MDBX_OPEN_DELETE, dummy_env, env_pathname.lck,
-                            &clk_handle, 0);
-        err = (err == MDBX_ENOFILE) ? MDBX_SUCCESS : err;
-      }
-      if (err == MDBX_SUCCESS && clk_handle != INVALID_HANDLE_VALUE)
-        err = mdbx_lockfile(clk_handle, mode == MDBX_ENV_WAIT_FOR_UNUSED);
-      if (err == MDBX_SUCCESS && dxb_handle != INVALID_HANDLE_VALUE)
-        err = mdbx_lockfile(dxb_handle, mode == MDBX_ENV_WAIT_FOR_UNUSED);
-    }
-
-    if (err == MDBX_SUCCESS) {
-      err = mdbx_removefile(env_pathname.dxb);
-      if (err == MDBX_SUCCESS)
-        rc = MDBX_SUCCESS;
-      else if (err == MDBX_ENOFILE)
-        err = MDBX_SUCCESS;
-    }
-
-    if (err == MDBX_SUCCESS) {
-      err = mdbx_removefile(env_pathname.lck);
-      if (err == MDBX_SUCCESS)
-        rc = MDBX_SUCCESS;
-      else if (err == MDBX_ENOFILE)
-        err = MDBX_SUCCESS;
-    }
-
-    if (err == MDBX_SUCCESS && !(dummy_env->me_flags & MDBX_NOSUBDIR)) {
-      err = mdbx_removedirectory(pathname);
-      if (err == MDBX_SUCCESS)
-        rc = MDBX_SUCCESS;
-      else if (err == MDBX_ENOFILE)
-        err = MDBX_SUCCESS;
-    }
-
-    if (dxb_handle != INVALID_HANDLE_VALUE)
-      mdbx_closefile(dxb_handle);
-    if (clk_handle != INVALID_HANDLE_VALUE)
-      mdbx_closefile(clk_handle);
-  } else if (err == MDBX_ENOFILE)
-    err = MDBX_SUCCESS;
-
-  mdbx_free(env_pathname.buffer_for_free);
-  return (err == MDBX_SUCCESS) ? rc : err;
-}
-
-__cold int mdbx_env_open(MDBX_env *env, const char *pathname,
-                         MDBX_env_flags_t flags, mdbx_mode_t mode) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(flags & ~ENV_USABLE_FLAGS))
-    return MDBX_EINVAL;
-
-  if (flags & MDBX_RDONLY)
-    mode = 0;
-
-  if (env->me_lazy_fd != INVALID_HANDLE_VALUE ||
-      (env->me_flags & MDBX_ENV_ACTIVE) != 0 || env->me_map)
-    return MDBX_EPERM;
-
-  /* pickup previously mdbx_env_set_flags(),
-   * but avoid MDBX_UTTERLY_NOSYNC by disjunction */
-  const uint32_t saved_me_flags = env->me_flags;
-  flags = merge_sync_flags(flags, env->me_flags);
-
-  MDBX_handle_env_pathname env_pathname;
-  rc = mdbx_handle_env_pathname(&env_pathname, pathname, &flags, mode);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto bailout;
-
-  if (flags & MDBX_RDONLY) {
-    /* LY: silently ignore irrelevant flags when
-     * we're only getting read access */
-    flags &= ~(MDBX_WRITEMAP | MDBX_DEPRECATED_MAPASYNC | MDBX_SAFE_NOSYNC |
-               MDBX_NOMETASYNC | MDBX_COALESCE | MDBX_LIFORECLAIM |
-               MDBX_NOMEMINIT | MDBX_ACCEDE);
-  } else {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-    /* Temporary `workaround` for OpenBSD kernel's flaw.
-     * See todo4recovery://erased_by_github/libmdbx/issues/67 */
-    if ((flags & MDBX_WRITEMAP) == 0) {
-      if (flags & MDBX_ACCEDE)
-        flags |= MDBX_WRITEMAP;
-      else {
-        mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__,
-                       "System (i.e. OpenBSD) requires MDBX_WRITEMAP because "
-                       "of an internal flaw(s) in a file/buffer/page cache.\n");
-        rc = 42 /* ENOPROTOOPT */;
-        goto bailout;
-      }
-    }
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-  }
-
-  env->me_flags = (flags & ~MDBX_FATAL_ERROR) | MDBX_ENV_ACTIVE;
-  env->me_pathname = mdbx_calloc(env_pathname.ent_len + 1, 1);
-  env->me_dbxs = mdbx_calloc(env->me_maxdbs, sizeof(MDBX_dbx));
-  env->me_dbflags = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbflags[0]));
-  env->me_dbiseqs = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0]));
-  if (!(env->me_dbxs && env->me_pathname && env->me_dbflags &&
-        env->me_dbiseqs)) {
-    rc = MDBX_ENOMEM;
-    goto bailout;
-  }
-  memcpy(env->me_pathname, env_pathname.dxb, env_pathname.ent_len);
-  env->me_dbxs[FREE_DBI].md_cmp = cmp_int_align4; /* aligned MDBX_INTEGERKEY */
-  env->me_dbxs[FREE_DBI].md_dcmp = cmp_lenfast;
-
-  rc = mdbx_openfile(F_ISSET(flags, MDBX_RDONLY) ? MDBX_OPEN_DXB_READ
-                                                 : MDBX_OPEN_DXB_LAZY,
-                     env, env_pathname.dxb, &env->me_lazy_fd, mode);
-  if (rc != MDBX_SUCCESS)
-    goto bailout;
-
-  mdbx_assert(env, env->me_dsync_fd == INVALID_HANDLE_VALUE);
-  if ((flags & (MDBX_RDONLY | MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC)) == 0) {
-    rc = mdbx_openfile(MDBX_OPEN_DXB_DSYNC, env, env_pathname.dxb,
-                       &env->me_dsync_fd, 0);
-    mdbx_ensure(env, (rc != MDBX_SUCCESS) ==
-                         (env->me_dsync_fd == INVALID_HANDLE_VALUE));
-  }
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  env->me_sysv_ipc.key = ftok(env_pathname.dxb, 42);
-  if (env->me_sysv_ipc.key == -1) {
-    rc = errno;
-    goto bailout;
-  }
-#endif /* MDBX_LOCKING */
-
-#if !(defined(_WIN32) || defined(_WIN64))
-  if (mode == 0) {
-    /* pickup mode for lck-file */
-    struct stat st;
-    if (fstat(env->me_lazy_fd, &st)) {
-      rc = errno;
-      goto bailout;
-    }
-    mode = st.st_mode;
-  }
-  mode = (/* inherit read permissions for group and others */ mode &
-          (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
-         /* always add read/write/search for owner */ S_IRUSR | S_IWUSR |
-         ((mode & S_IRGRP) ? /* +write if readable by group */ S_IWGRP : 0) |
-         ((mode & S_IROTH) ? /* +write if readable by others */ S_IWOTH : 0);
-#endif /* !Windows */
-  const int lck_rc = mdbx_setup_lck(env, env_pathname.lck, mode);
-  if (MDBX_IS_ERROR(lck_rc)) {
-    rc = lck_rc;
-    goto bailout;
-  }
-
-  /* Set the position in files outside of the data to avoid corruption
-   * due to erroneous use of file descriptors in the application code. */
-  mdbx_fseek(env->me_lfd, UINT64_C(1) << 63);
-  mdbx_fseek(env->me_lazy_fd, UINT64_C(1) << 63);
-  if (env->me_dsync_fd != INVALID_HANDLE_VALUE)
-    mdbx_fseek(env->me_dsync_fd, UINT64_C(1) << 63);
-
-  const MDBX_env_flags_t rigorous_flags =
-      MDBX_SAFE_NOSYNC | MDBX_DEPRECATED_MAPASYNC;
-  const MDBX_env_flags_t mode_flags = rigorous_flags | MDBX_NOMETASYNC |
-                                      MDBX_LIFORECLAIM | MDBX_COALESCE |
-                                      MDBX_NORDAHEAD;
-
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (lck && lck_rc != MDBX_RESULT_TRUE && (env->me_flags & MDBX_RDONLY) == 0) {
-    while (atomic_load32(&lck->mti_envmode, mo_AcquireRelease) == MDBX_RDONLY) {
-      if (atomic_cas32(&lck->mti_envmode, MDBX_RDONLY,
-                       env->me_flags & mode_flags)) {
-        /* The case:
-         *  - let's assume that for some reason the DB file is smaller
-         *    than it should be according to the geometry,
-         *    but not smaller than the last page used;
-         *  - the first process that opens the database (lc_rc = true)
-         *    does this in readonly mode and therefore cannot bring
-         *    the file size back to normal;
-         *  - some next process (lc_rc = false) opens the DB in read-write
-         *    mode and now is here.
-         *
-         * FIXME: Should we re-check and set the size of DB-file right here? */
-        break;
-      }
-      atomic_yield();
-    }
-
-    if (env->me_flags & MDBX_ACCEDE) {
-      /* pickup current mode-flags, including MDBX_LIFORECLAIM |
-       * MDBX_COALESCE | MDBX_NORDAHEAD */
-      const unsigned diff =
-          (lck->mti_envmode.weak ^ env->me_flags) & mode_flags;
-      mdbx_notice("accede mode-flags: 0x%X, 0x%X -> 0x%X", diff, env->me_flags,
-                  env->me_flags ^ diff);
-      env->me_flags ^= diff;
-    }
-
-    if ((lck->mti_envmode.weak ^ env->me_flags) & rigorous_flags) {
-      mdbx_error("%s", "current mode/flags incompatible with requested");
-      rc = MDBX_INCOMPATIBLE;
-      goto bailout;
-    }
-  }
-
-  const int dxb_rc = mdbx_setup_dxb(env, lck_rc, mode);
-  if (MDBX_IS_ERROR(dxb_rc)) {
-    rc = dxb_rc;
-    goto bailout;
-  }
-
-  if (unlikely(/* recovery mode */ env->me_stuck_meta >= 0) &&
-      (lck_rc != /* exclusive */ MDBX_RESULT_TRUE ||
-       (flags & MDBX_EXCLUSIVE) == 0)) {
-    mdbx_error("%s", "recovery requires exclusive mode");
-    rc = MDBX_BUSY;
-    goto bailout;
-  }
-
-  mdbx_debug("opened dbenv %p", (void *)env);
-  if (lck) {
-    if (lck_rc == MDBX_RESULT_TRUE) {
-      lck->mti_envmode.weak = env->me_flags & (mode_flags | MDBX_RDONLY);
-      rc = mdbx_lck_downgrade(env);
-      mdbx_debug("lck-downgrade-%s: rc %i",
-                 (env->me_flags & MDBX_EXCLUSIVE) ? "partial" : "full", rc);
-      if (rc != MDBX_SUCCESS)
-        goto bailout;
-    } else {
-      rc = mdbx_cleanup_dead_readers(env, false, NULL);
-      if (MDBX_IS_ERROR(rc))
-        goto bailout;
-    }
-
-    if ((env->me_flags & MDBX_NOTLS) == 0) {
-      rc = mdbx_rthc_alloc(&env->me_txkey, &lck->mti_readers[0],
-                           &lck->mti_readers[env->me_maxreaders]);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto bailout;
-      env->me_flags |= MDBX_ENV_TXKEY;
-    }
-  }
-
-  if ((flags & MDBX_RDONLY) == 0) {
-    const size_t tsize = sizeof(MDBX_txn),
-                 size = tsize + env->me_maxdbs *
-                                    (sizeof(MDBX_db) + sizeof(MDBX_cursor *) +
-                                     sizeof(unsigned) + 1);
-    rc = alloc_page_buf(env);
-    if (rc == MDBX_SUCCESS) {
-      memset(env->me_pbuf, -1, env->me_psize * 2);
-      MDBX_txn *txn = mdbx_calloc(1, size);
-      if (txn) {
-        txn->mt_dbs = (MDBX_db *)((char *)txn + tsize);
-        txn->mt_cursors = (MDBX_cursor **)(txn->mt_dbs + env->me_maxdbs);
-        txn->mt_dbiseqs = (unsigned *)(txn->mt_cursors + env->me_maxdbs);
-        txn->mt_dbistate = (uint8_t *)(txn->mt_dbiseqs + env->me_maxdbs);
-        txn->mt_env = env;
-        txn->mt_dbxs = env->me_dbxs;
-        txn->mt_flags = MDBX_TXN_FINISHED;
-        env->me_txn0 = txn;
-        txn->tw.retired_pages = mdbx_pnl_alloc(MDBX_PNL_INITIAL);
-        txn->tw.reclaimed_pglist = mdbx_pnl_alloc(MDBX_PNL_INITIAL);
-        if (unlikely(!txn->tw.retired_pages || !txn->tw.reclaimed_pglist))
-          rc = MDBX_ENOMEM;
-      } else
-        rc = MDBX_ENOMEM;
-    }
-  }
-
-#if MDBX_DEBUG
-  if (rc == MDBX_SUCCESS) {
-    const MDBX_meta *meta = constmeta_prefer_last(env);
-    const MDBX_db *db = &meta->mm_dbs[MAIN_DBI];
-
-    mdbx_debug("opened database version %u, pagesize %u",
-               (uint8_t)unaligned_peek_u64(4, meta->mm_magic_and_version),
-               env->me_psize);
-    mdbx_debug("using meta page %" PRIaPGNO ", txn %" PRIaTXN,
-               data_page(meta)->mp_pgno, meta_txnid(env, meta));
-    mdbx_debug("depth: %u", db->md_depth);
-    mdbx_debug("entries: %" PRIu64, db->md_entries);
-    mdbx_debug("branch pages: %" PRIaPGNO, db->md_branch_pages);
-    mdbx_debug("leaf pages: %" PRIaPGNO, db->md_leaf_pages);
-    mdbx_debug("overflow pages: %" PRIaPGNO, db->md_overflow_pages);
-    mdbx_debug("root: %" PRIaPGNO, db->md_root);
-    mdbx_debug("schema_altered: %" PRIaTXN, db->md_mod_txnid);
-  }
-#endif
-
-bailout:
-  if (rc != MDBX_SUCCESS) {
-    rc = mdbx_env_close0(env) ? MDBX_PANIC : rc;
-    env->me_flags =
-        saved_me_flags | ((rc != MDBX_PANIC) ? 0 : MDBX_FATAL_ERROR);
-  } else {
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-    mdbx_txn_valgrind(env, nullptr);
-#endif
-  }
-  mdbx_free(env_pathname.buffer_for_free);
-  return rc;
-}
-
-/* Destroy resources from mdbx_env_open(), clear our readers & DBIs */
-__cold static int mdbx_env_close0(MDBX_env *env) {
-  const unsigned flags = env->me_flags;
-  if (!(flags & MDBX_ENV_ACTIVE)) {
-    mdbx_ensure(env, env->me_lcklist_next == nullptr);
-    return MDBX_SUCCESS;
-  }
-
-  env->me_flags &= ~ENV_INTERNAL_FLAGS;
-  env->me_lck = nullptr;
-  if (flags & MDBX_ENV_TXKEY) {
-    mdbx_rthc_remove(env->me_txkey);
-    env->me_txkey = (mdbx_thread_key_t)0;
-  }
-
-  lcklist_lock();
-  const int rc = lcklist_detach_locked(env);
-  lcklist_unlock();
-
-  if (env->me_map) {
-    mdbx_munmap(&env->me_dxb_mmap);
-#ifdef MDBX_USE_VALGRIND
-    VALGRIND_DISCARD(env->me_valgrind_handle);
-    env->me_valgrind_handle = -1;
-#endif
-  }
-
-  if (env->me_dsync_fd != INVALID_HANDLE_VALUE) {
-    (void)mdbx_closefile(env->me_dsync_fd);
-    env->me_dsync_fd = INVALID_HANDLE_VALUE;
-  }
-
-  if (env->me_lazy_fd != INVALID_HANDLE_VALUE) {
-    (void)mdbx_closefile(env->me_lazy_fd);
-    env->me_lazy_fd = INVALID_HANDLE_VALUE;
-  }
-
-  if (env->me_lck_mmap.lck)
-    mdbx_munmap(&env->me_lck_mmap);
-
-  if (env->me_lfd != INVALID_HANDLE_VALUE) {
-    (void)mdbx_closefile(env->me_lfd);
-    env->me_lfd = INVALID_HANDLE_VALUE;
-  }
-
-  if (env->me_dbxs) {
-    for (unsigned i = env->me_numdbs; --i >= CORE_DBS;)
-      mdbx_free(env->me_dbxs[i].md_name.iov_base);
-    mdbx_free(env->me_dbxs);
-    env->me_dbxs = nullptr;
-  }
-  if (env->me_pbuf) {
-    mdbx_memalign_free(env->me_pbuf);
-    env->me_pbuf = nullptr;
-  }
-  if (env->me_dbiseqs) {
-    mdbx_free(env->me_dbiseqs);
-    env->me_dbiseqs = nullptr;
-  }
-  if (env->me_dbflags) {
-    mdbx_free(env->me_dbflags);
-    env->me_dbflags = nullptr;
-  }
-  if (env->me_pathname) {
-    mdbx_free(env->me_pathname);
-    env->me_pathname = nullptr;
-  }
-  if (env->me_txn0) {
-    mdbx_dpl_free(env->me_txn0);
-    mdbx_txl_free(env->me_txn0->tw.lifo_reclaimed);
-    mdbx_pnl_free(env->me_txn0->tw.retired_pages);
-    mdbx_pnl_free(env->me_txn0->tw.spill_pages);
-    mdbx_pnl_free(env->me_txn0->tw.reclaimed_pglist);
-    mdbx_free(env->me_txn0);
-    env->me_txn0 = nullptr;
-  }
-  env->me_stuck_meta = -1;
-  return rc;
-}
-
-__cold int mdbx_env_close_ex(MDBX_env *env, bool dont_sync) {
-  MDBX_page *dp;
-  int rc = MDBX_SUCCESS;
-
-  if (unlikely(!env))
-    return MDBX_EINVAL;
-
-  if (unlikely(env->me_signature.weak != MDBX_ME_SIGNATURE))
-    return MDBX_EBADSIGN;
-
-#if MDBX_ENV_CHECKPID || !(defined(_WIN32) || defined(_WIN64))
-  /* Check the PID even if MDBX_ENV_CHECKPID=0 on non-Windows
-   * platforms (i.e. where fork() is available).
-   * This is required to legitimize a call after fork()
-   * from a child process, that should be allowed to free resources. */
-  if (unlikely(env->me_pid != mdbx_getpid()))
-    env->me_flags |= MDBX_FATAL_ERROR;
-#endif /* MDBX_ENV_CHECKPID */
-
-  if (env->me_map && (env->me_flags & (MDBX_RDONLY | MDBX_FATAL_ERROR)) == 0 &&
-      env->me_txn0) {
-    if (env->me_txn0->mt_owner && env->me_txn0->mt_owner != mdbx_thread_self())
-      return MDBX_BUSY;
-  } else
-    dont_sync = true;
-
-  if (!atomic_cas32(&env->me_signature, MDBX_ME_SIGNATURE, 0))
-    return MDBX_EBADSIGN;
-
-  if (!dont_sync) {
-#if defined(_WIN32) || defined(_WIN64)
-    /* On windows, without blocking is impossible to determine whether another
-     * process is running a writing transaction or not.
-     * Because in the "owner died" condition kernel don't release
-     * file lock immediately. */
-    rc = mdbx_env_sync_internal(env, true, false);
-    rc = (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
-#else
-    struct stat st;
-    if (unlikely(fstat(env->me_lazy_fd, &st)))
-      rc = errno;
-    else if (st.st_nlink > 0 /* don't sync deleted files */) {
-      rc = mdbx_env_sync_internal(env, true, true);
-      rc = (rc == MDBX_BUSY || rc == EAGAIN || rc == EACCES || rc == EBUSY ||
-            rc == EWOULDBLOCK || rc == MDBX_RESULT_TRUE)
-               ? MDBX_SUCCESS
-               : rc;
-    }
-#endif
-  }
-
-  mdbx_assert(env, env->me_signature.weak == 0);
-  rc = mdbx_env_close0(env) ? MDBX_PANIC : rc;
-  mdbx_ensure(env, mdbx_fastmutex_destroy(&env->me_dbi_lock) == MDBX_SUCCESS);
-#if defined(_WIN32) || defined(_WIN64)
-  /* me_remap_guard don't have destructor (Slim Reader/Writer Lock) */
-  DeleteCriticalSection(&env->me_windowsbug_lock);
-#else
-  mdbx_ensure(env,
-              mdbx_fastmutex_destroy(&env->me_remap_guard) == MDBX_SUCCESS);
-#endif /* Windows */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV
-  MDBX_lockinfo *const stub = lckless_stub(env);
-  mdbx_ensure(env, mdbx_ipclock_destroy(&stub->mti_wlock) == 0);
-#endif /* MDBX_LOCKING */
-
-  while ((dp = env->me_dp_reserve) != NULL) {
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(dp, env->me_psize);
-    VALGRIND_MAKE_MEM_DEFINED(&dp->mp_next, sizeof(dp->mp_next));
-    env->me_dp_reserve = dp->mp_next;
-    mdbx_free(dp);
-  }
-  VALGRIND_DESTROY_MEMPOOL(env);
-  mdbx_ensure(env, env->me_lcklist_next == nullptr);
-  env->me_pid = 0;
-  mdbx_free(env);
-
-  return rc;
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold int mdbx_env_close(MDBX_env *env) {
-  return __inline_mdbx_env_close(env);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-/* Compare two items pointing at aligned unsigned int's. */
-static int __hot cmp_int_align4(const MDBX_val *a, const MDBX_val *b) {
-  mdbx_assert(NULL, a->iov_len == b->iov_len);
-  switch (a->iov_len) {
-  case 4:
-    return CMP2INT(unaligned_peek_u32(4, a->iov_base),
-                   unaligned_peek_u32(4, b->iov_base));
-  case 8:
-    return CMP2INT(unaligned_peek_u64(4, a->iov_base),
-                   unaligned_peek_u64(4, b->iov_base));
-  default:
-    mdbx_assert_fail(NULL, "invalid size for INTEGERKEY/INTEGERDUP", __func__,
-                     __LINE__);
-    return 0;
-  }
-}
-
-/* Compare two items pointing at 2-byte aligned unsigned int's. */
-static int __hot cmp_int_align2(const MDBX_val *a, const MDBX_val *b) {
-  mdbx_assert(NULL, a->iov_len == b->iov_len);
-  switch (a->iov_len) {
-  case 4:
-    return CMP2INT(unaligned_peek_u32(2, a->iov_base),
-                   unaligned_peek_u32(2, b->iov_base));
-  case 8:
-    return CMP2INT(unaligned_peek_u64(2, a->iov_base),
-                   unaligned_peek_u64(2, b->iov_base));
-  default:
-    mdbx_assert_fail(NULL, "invalid size for INTEGERKEY/INTEGERDUP", __func__,
-                     __LINE__);
-    return 0;
-  }
-}
-
-/* Compare two items pointing at unsigned values with unknown alignment.
- *
- * This is also set as MDBX_INTEGERDUP|MDBX_DUPFIXED's MDBX_dbx.md_dcmp. */
-static int __hot cmp_int_unaligned(const MDBX_val *a, const MDBX_val *b) {
-  mdbx_assert(NULL, a->iov_len == b->iov_len);
-  switch (a->iov_len) {
-  case 4:
-    return CMP2INT(unaligned_peek_u32(1, a->iov_base),
-                   unaligned_peek_u32(1, b->iov_base));
-  case 8:
-    return CMP2INT(unaligned_peek_u64(1, a->iov_base),
-                   unaligned_peek_u64(1, b->iov_base));
-  default:
-    mdbx_assert_fail(NULL, "invalid size for INTEGERKEY/INTEGERDUP", __func__,
-                     __LINE__);
-    return 0;
-  }
-}
-
-/* Compare two items lexically */
-static int __hot cmp_lexical(const MDBX_val *a, const MDBX_val *b) {
-  if (a->iov_len == b->iov_len)
-    return a->iov_len ? memcmp(a->iov_base, b->iov_base, a->iov_len) : 0;
-
-  const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
-  const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
-  int diff_data = shortest ? memcmp(a->iov_base, b->iov_base, shortest) : 0;
-  return likely(diff_data) ? diff_data : diff_len;
-}
-
-/* Compare two items in reverse byte order */
-static int __hot cmp_reverse(const MDBX_val *a, const MDBX_val *b) {
-  const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
-  if (likely(shortest)) {
-    const uint8_t *pa = (const uint8_t *)a->iov_base + a->iov_len;
-    const uint8_t *pb = (const uint8_t *)b->iov_base + b->iov_len;
-    const uint8_t *const end = pa - shortest;
-    do {
-      int diff = *--pa - *--pb;
-      if (likely(diff))
-        return diff;
-    } while (pa != end);
-  }
-  return CMP2INT(a->iov_len, b->iov_len);
-}
-
-/* Fast non-lexically comparator */
-static int __hot cmp_lenfast(const MDBX_val *a, const MDBX_val *b) {
-  int diff = CMP2INT(a->iov_len, b->iov_len);
-  return likely(diff || a->iov_len == 0)
-             ? diff
-             : memcmp(a->iov_base, b->iov_base, a->iov_len);
-}
-
-static bool unsure_equal(MDBX_cmp_func cmp, const MDBX_val *a,
-                         const MDBX_val *b) {
-  /* checking for the use of a known good comparator
-   * or/otherwise for a full byte-to-byte match */
-  return cmp == cmp_lenfast || cmp == cmp_lexical || cmp == cmp_reverse ||
-         cmp == cmp_int_unaligned || cmp_lenfast(a, b) == 0;
-}
-
-/* Search for key within a page, using binary search.
- * Returns the smallest entry larger or equal to the key.
- * Updates the cursor index with the index of the found entry.
- * If no entry larger or equal to the key is found, returns NULL. */
-static struct node_result __hot mdbx_node_search(MDBX_cursor *mc,
-                                                 const MDBX_val *key) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  const int nkeys = page_numkeys(mp);
-  DKBUF_DEBUG;
-
-  mdbx_debug("searching %u keys in %s %spage %" PRIaPGNO, nkeys,
-             IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "",
-             mp->mp_pgno);
-
-  struct node_result ret;
-  ret.exact = false;
-  STATIC_ASSERT(P_BRANCH == 1);
-  int low = mp->mp_flags & P_BRANCH;
-  int high = nkeys - 1;
-  if (unlikely(high < low)) {
-    mc->mc_ki[mc->mc_top] = 0;
-    ret.node = NULL;
-    return ret;
-  }
-
-  int cr = 0, i = 0;
-  MDBX_cmp_func *cmp = mc->mc_dbx->md_cmp;
-  MDBX_val nodekey;
-  if (unlikely(IS_LEAF2(mp))) {
-    mdbx_cassert(mc, mp->mp_leaf2_ksize == mc->mc_db->md_xsize);
-    nodekey.iov_len = mp->mp_leaf2_ksize;
-    do {
-      i = (low + high) >> 1;
-      nodekey.iov_base = page_leaf2key(mp, i, nodekey.iov_len);
-      mdbx_cassert(mc, (char *)mp + mc->mc_txn->mt_env->me_psize >=
-                           (char *)nodekey.iov_base + nodekey.iov_len);
-      cr = cmp(key, &nodekey);
-      mdbx_debug("found leaf index %u [%s], rc = %i", i, DKEY_DEBUG(&nodekey),
-                 cr);
-      if (unlikely(cr == 0)) {
-        ret.exact = true;
-        break;
-      }
-      low = (cr < 0) ? low : i + 1;
-      high = (cr < 0) ? i - 1 : high;
-    } while (likely(low <= high));
-
-    /* Found entry is less than the key. */
-    /* Skip to get the smallest entry larger than key. */
-    i += cr > 0;
-
-    /* store the key index */
-    mc->mc_ki[mc->mc_top] = (indx_t)i;
-    ret.node = (i < nkeys)
-                   ? /* fake for LEAF2 */ (MDBX_node *)(intptr_t)-1
-                   : /* There is no entry larger or equal to the key. */ NULL;
-    return ret;
-  }
-
-  if (IS_BRANCH(mp) && cmp == cmp_int_align2)
-    /* Branch pages have no data, so if using integer keys,
-     * alignment is guaranteed. Use faster cmp_int_align4(). */
-    cmp = cmp_int_align4;
-
-  MDBX_node *node;
-  do {
-    i = (low + high) >> 1;
-
-    node = page_node(mp, i);
-    nodekey.iov_len = node_ks(node);
-    nodekey.iov_base = node_key(node);
-    mdbx_cassert(mc, (char *)mp + mc->mc_txn->mt_env->me_psize >=
-                         (char *)nodekey.iov_base + nodekey.iov_len);
-
-    cr = cmp(key, &nodekey);
-    if (IS_LEAF(mp))
-      mdbx_debug("found leaf index %u [%s], rc = %i", i, DKEY_DEBUG(&nodekey),
-                 cr);
-    else
-      mdbx_debug("found branch index %u [%s -> %" PRIaPGNO "], rc = %i", i,
-                 DKEY_DEBUG(&nodekey), node_pgno(node), cr);
-    if (unlikely(cr == 0)) {
-      ret.exact = true;
-      break;
-    }
-    low = (cr < 0) ? low : i + 1;
-    high = (cr < 0) ? i - 1 : high;
-  } while (likely(low <= high));
-
-  /* Found entry is less than the key. */
-  /* Skip to get the smallest entry larger than key. */
-  i += cr > 0;
-
-  /* store the key index */
-  mc->mc_ki[mc->mc_top] = (indx_t)i;
-  ret.node = (i < nkeys)
-                 ? page_node(mp, i)
-                 : /* There is no entry larger or equal to the key. */ NULL;
-  return ret;
-}
-
-/* Pop a page off the top of the cursor's stack. */
-static __inline void mdbx_cursor_pop(MDBX_cursor *mc) {
-  if (mc->mc_snum) {
-    mdbx_debug("popped page %" PRIaPGNO " off db %d cursor %p",
-               mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *)mc);
-    if (--mc->mc_snum) {
-      mc->mc_top--;
-    } else {
-      mc->mc_flags &= ~C_INITIALIZED;
-    }
-  }
-}
-
-/* Push a page onto the top of the cursor's stack.
- * Set MDBX_TXN_ERROR on failure. */
-static __inline int mdbx_cursor_push(MDBX_cursor *mc, MDBX_page *mp) {
-  mdbx_debug("pushing page %" PRIaPGNO " on db %d cursor %p", mp->mp_pgno,
-             DDBI(mc), (void *)mc);
-
-  if (unlikely(mc->mc_snum >= CURSOR_STACK)) {
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return MDBX_CURSOR_FULL;
-  }
-
-  mdbx_cassert(mc, mc->mc_snum < UINT16_MAX);
-  mc->mc_top = mc->mc_snum++;
-  mc->mc_pg[mc->mc_top] = mp;
-  mc->mc_ki[mc->mc_top] = 0;
-
-  return MDBX_SUCCESS;
-}
-
-__hot static struct page_result
-mdbx_page_get_ex(MDBX_cursor *const mc, const pgno_t pgno,
-                 /* TODO: use parent-page ptr */ txnid_t front) {
-  struct page_result ret;
-  MDBX_txn *const txn = mc->mc_txn;
-  mdbx_tassert(txn, front <= txn->mt_front);
-  if (unlikely(pgno >= txn->mt_next_pgno)) {
-    mdbx_error("page #%" PRIaPGNO " beyond next-pgno", pgno);
-  notfound:
-    ret.page = nullptr;
-    ret.err = MDBX_PAGE_NOTFOUND;
-  bailout:
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return ret;
-  }
-
-  MDBX_env *const env = txn->mt_env;
-  mdbx_assert(env, ((txn->mt_flags ^ env->me_flags) & MDBX_WRITEMAP) == 0);
-  if (unlikely((txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP)) == 0)) {
-    const MDBX_txn *spiller = txn;
-    do {
-      /* Spilled pages were dirtied in this txn and flushed
-       * because the dirty list got full. Bring this page
-       * back in from the map (but don't unspill it here,
-       * leave that unless page_touch happens again). */
-      if (unlikely(spiller->mt_flags & MDBX_TXN_SPILLS) &&
-          mdbx_search_spilled(spiller, pgno)) {
-        goto spilled;
-      }
-
-      const unsigned i = mdbx_dpl_search(spiller, pgno);
-      assert((int)i > 0);
-      if (spiller->tw.dirtylist->items[i].pgno == pgno) {
-        ret.page = spiller->tw.dirtylist->items[i].ptr;
-        spiller->tw.dirtylist->items[i].lru = txn->tw.dirtylru++;
-        goto dirty;
-      }
-
-      spiller = spiller->mt_parent;
-    } while (spiller != NULL);
-  }
-
-spilled:
-  ret.page = pgno2page(env, pgno);
-
-dirty:
-  if (unlikely(ret.page->mp_pgno != pgno)) {
-    bad_page(ret.page,
-             "mismatch actual pgno (%" PRIaPGNO ") != expected (%" PRIaPGNO
-             ")\n",
-             ret.page->mp_pgno, pgno);
-    goto notfound;
-  }
-
-#if !MDBX_DISABLE_PAGECHECKS
-  if (unlikely(ret.page->mp_flags & P_ILL_BITS)) {
-    ret.err =
-        bad_page(ret.page, "invalid page's flags (%u)\n", ret.page->mp_flags);
-    goto bailout;
-  }
-
-  if (unlikely(ret.page->mp_txnid > front) &&
-      unlikely(ret.page->mp_txnid > txn->mt_front || front < txn->mt_txnid)) {
-    ret.err = bad_page(
-        ret.page,
-        "invalid page txnid (%" PRIaTXN ") for %s' txnid (%" PRIaTXN ")\n",
-        ret.page->mp_txnid,
-        (front == txn->mt_front && front != txn->mt_txnid) ? "front-txn"
-                                                           : "parent-page",
-        front);
-    goto bailout;
-  }
-
-  if (unlikely((ret.page->mp_upper < ret.page->mp_lower ||
-                ((ret.page->mp_lower | ret.page->mp_upper) & 1) ||
-                PAGEHDRSZ + ret.page->mp_upper > env->me_psize) &&
-               !IS_OVERFLOW(ret.page))) {
-    ret.err =
-        bad_page(ret.page, "invalid page lower(%u)/upper(%u) with limit (%u)\n",
-                 ret.page->mp_lower, ret.page->mp_upper, page_space(env));
-    goto bailout;
-  }
-#endif /* !MDBX_DISABLE_PAGECHECKS */
-
-  ret.err = MDBX_SUCCESS;
-  if (mdbx_audit_enabled())
-    ret.err = mdbx_page_check(mc, ret.page, C_UPDATING);
-  return ret;
-}
-
-/* Finish mdbx_page_search() / mdbx_page_search_lowest().
- * The cursor is at the root page, set up the rest of it. */
-__hot static int mdbx_page_search_root(MDBX_cursor *mc, const MDBX_val *key,
-                                       int flags) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  int rc;
-  DKBUF_DEBUG;
-
-  while (IS_BRANCH(mp)) {
-    MDBX_node *node;
-    int i;
-
-    mdbx_debug("branch page %" PRIaPGNO " has %u keys", mp->mp_pgno,
-               page_numkeys(mp));
-    /* Don't assert on branch pages in the GC. We can get here
-     * while in the process of rebalancing a GC branch page; we must
-     * let that proceed. ITS#8336 */
-    mdbx_cassert(mc, !mc->mc_dbi || page_numkeys(mp) > 1);
-    mdbx_debug("found index 0 to page %" PRIaPGNO, node_pgno(page_node(mp, 0)));
-
-    if (flags & (MDBX_PS_FIRST | MDBX_PS_LAST)) {
-      i = 0;
-      if (flags & MDBX_PS_LAST) {
-        i = page_numkeys(mp) - 1;
-        /* if already init'd, see if we're already in right place */
-        if (mc->mc_flags & C_INITIALIZED) {
-          if (mc->mc_ki[mc->mc_top] == i) {
-            mc->mc_top = mc->mc_snum++;
-            mp = mc->mc_pg[mc->mc_top];
-            goto ready;
-          }
-        }
-      }
-    } else {
-      const struct node_result nsr = mdbx_node_search(mc, key);
-      if (nsr.node)
-        i = mc->mc_ki[mc->mc_top] + nsr.exact - 1;
-      else
-        i = page_numkeys(mp) - 1;
-      mdbx_debug("following index %u for key [%s]", i, DKEY_DEBUG(key));
-    }
-
-    mdbx_cassert(mc, i >= 0 && i < (int)page_numkeys(mp));
-    node = page_node(mp, i);
-
-    if (unlikely((rc = mdbx_page_get(mc, node_pgno(node), &mp,
-                                     pp_txnid4chk(mp, mc->mc_txn))) != 0))
-      return rc;
-
-    mc->mc_ki[mc->mc_top] = (indx_t)i;
-    if (unlikely(rc = mdbx_cursor_push(mc, mp)))
-      return rc;
-
-  ready:
-    if (flags & MDBX_PS_MODIFY) {
-      if (unlikely((rc = mdbx_page_touch(mc)) != 0))
-        return rc;
-      mp = mc->mc_pg[mc->mc_top];
-    }
-  }
-
-#if !MDBX_DISABLE_PAGECHECKS
-  if (unlikely(!IS_LEAF(mp))) {
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return bad_page(mp, "index points to a page with 0x%02x flags\n",
-                    mp->mp_flags);
-  }
-#endif /* !MDBX_DISABLE_PAGECHECKS */
-
-  mdbx_debug("found leaf page %" PRIaPGNO " for key [%s]", mp->mp_pgno,
-             DKEY_DEBUG(key));
-  mc->mc_flags |= C_INITIALIZED;
-  mc->mc_flags &= ~C_EOF;
-
-  return MDBX_SUCCESS;
-}
-
-static int mdbx_setup_dbx(MDBX_dbx *const dbx, const MDBX_db *const db,
-                          const unsigned pagesize) {
-  if (unlikely(!dbx->md_cmp)) {
-    dbx->md_cmp = get_default_keycmp(db->md_flags);
-    dbx->md_dcmp = get_default_datacmp(db->md_flags);
-  }
-
-  dbx->md_klen_min =
-      (db->md_flags & MDBX_INTEGERKEY) ? 4 /* sizeof(uint32_t) */ : 0;
-  dbx->md_klen_max = keysize_max(pagesize, db->md_flags);
-  assert(dbx->md_klen_max != (unsigned)-1);
-
-  dbx->md_vlen_min = (db->md_flags & MDBX_INTEGERDUP)
-                         ? 4 /* sizeof(uint32_t) */
-                         : ((db->md_flags & MDBX_DUPFIXED) ? 1 : 0);
-  dbx->md_vlen_max = valsize_max(pagesize, db->md_flags);
-  assert(dbx->md_vlen_max != (unsigned)-1);
-
-  if ((db->md_flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->md_xsize) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely(db->md_xsize < dbx->md_vlen_min ||
-                                             db->md_xsize > dbx->md_vlen_max)) {
-      mdbx_error("db.md_xsize (%u) <> min/max value-length (%zu/%zu)",
-                 db->md_xsize, dbx->md_vlen_min, dbx->md_vlen_max);
-      return MDBX_CORRUPTED;
-    }
-    dbx->md_vlen_min = dbx->md_vlen_max = db->md_xsize;
-  }
-  return MDBX_SUCCESS;
-}
-
-static int mdbx_fetch_sdb(MDBX_txn *txn, MDBX_dbi dbi) {
-  MDBX_cursor_couple couple;
-  if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
-    return MDBX_BAD_DBI;
-  int rc = mdbx_cursor_init(&couple.outer, txn, MAIN_DBI);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  MDBX_dbx *const dbx = &txn->mt_dbxs[dbi];
-  rc = mdbx_page_search(&couple.outer, &dbx->md_name, 0);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return (rc == MDBX_NOTFOUND) ? MDBX_BAD_DBI : rc;
-
-  MDBX_val data;
-  struct node_result nsr = mdbx_node_search(&couple.outer, &dbx->md_name);
-  if (unlikely(!nsr.exact))
-    return MDBX_BAD_DBI;
-  if (unlikely((node_flags(nsr.node) & (F_DUPDATA | F_SUBDATA)) != F_SUBDATA))
-    return MDBX_INCOMPATIBLE; /* not a named DB */
-
-  const txnid_t pp_txnid =
-      pp_txnid4chk(couple.outer.mc_pg[couple.outer.mc_top], txn);
-  rc = mdbx_node_read(&couple.outer, nsr.node, &data, pp_txnid);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(data.iov_len != sizeof(MDBX_db)))
-    return MDBX_INCOMPATIBLE; /* not a named DB */
-
-  uint16_t md_flags = UNALIGNED_PEEK_16(data.iov_base, MDBX_db, md_flags);
-  /* The txn may not know this DBI, or another process may
-   * have dropped and recreated the DB with other flags. */
-  MDBX_db *const db = &txn->mt_dbs[dbi];
-  if (unlikely((db->md_flags & DB_PERSISTENT_FLAGS) != md_flags))
-    return MDBX_INCOMPATIBLE;
-
-  memcpy(db, data.iov_base, sizeof(MDBX_db));
-#if !MDBX_DISABLE_PAGECHECKS
-  mdbx_tassert(txn, txn->mt_front >= pp_txnid);
-  if (unlikely(db->md_mod_txnid > pp_txnid)) {
-    mdbx_error("db.md_mod_txnid (%" PRIaTXN ") > page-txnid (%" PRIaTXN ")",
-               db->md_mod_txnid, pp_txnid);
-    return MDBX_CORRUPTED;
-  }
-#endif /* !MDBX_DISABLE_PAGECHECKS */
-  rc = mdbx_setup_dbx(dbx, db, txn->mt_env->me_psize);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  txn->mt_dbistate[dbi] &= ~DBI_STALE;
-  return MDBX_SUCCESS;
-}
-
-/* Search for the lowest key under the current branch page.
- * This just bypasses a numkeys check in the current page
- * before calling mdbx_page_search_root(), because the callers
- * are all in situations where the current page is known to
- * be underfilled. */
-__hot static int mdbx_page_search_lowest(MDBX_cursor *mc) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  mdbx_cassert(mc, IS_BRANCH(mp));
-  MDBX_node *node = page_node(mp, 0);
-  int rc;
-
-  if (unlikely((rc = mdbx_page_get(mc, node_pgno(node), &mp,
-                                   pp_txnid4chk(mp, mc->mc_txn))) != 0))
-    return rc;
-
-  mc->mc_ki[mc->mc_top] = 0;
-  if (unlikely(rc = mdbx_cursor_push(mc, mp)))
-    return rc;
-  return mdbx_page_search_root(mc, NULL, MDBX_PS_FIRST);
-}
-
-/* Search for the page a given key should be in.
- * Push it and its parent pages on the cursor stack.
- *
- * [in,out] mc  the cursor for this operation.
- * [in] key     the key to search for, or NULL for first/last page.
- * [in] flags   If MDBX_PS_MODIFY is set, visited pages in the DB
- *              are touched (updated with new page numbers).
- *              If MDBX_PS_FIRST or MDBX_PS_LAST is set, find first or last
- * leaf.
- *              This is used by mdbx_cursor_first() and mdbx_cursor_last().
- *              If MDBX_PS_ROOTONLY set, just fetch root node, no further
- *              lookups.
- *
- * Returns 0 on success, non-zero on failure. */
-__hot static int mdbx_page_search(MDBX_cursor *mc, const MDBX_val *key,
-                                  int flags) {
-  int rc;
-  pgno_t root;
-
-  /* Make sure the txn is still viable, then find the root from
-   * the txn's db table and set it as the root of the cursor's stack. */
-  if (unlikely(mc->mc_txn->mt_flags & MDBX_TXN_BLOCKED)) {
-    mdbx_debug("%s", "transaction has failed, must abort");
-    return MDBX_BAD_TXN;
-  }
-
-  /* Make sure we're using an up-to-date root */
-  if (unlikely(*mc->mc_dbistate & DBI_STALE)) {
-    rc = mdbx_fetch_sdb(mc->mc_txn, mc->mc_dbi);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-  root = mc->mc_db->md_root;
-
-  if (unlikely(root == P_INVALID)) { /* Tree is empty. */
-    mdbx_debug("%s", "tree is empty");
-    return MDBX_NOTFOUND;
-  }
-
-  mdbx_cassert(mc, root >= NUM_METAS);
-  if (!mc->mc_pg[0] || mc->mc_pg[0]->mp_pgno != root) {
-    txnid_t pp_txnid = mc->mc_db->md_mod_txnid;
-    pp_txnid = /* mc->mc_db->md_mod_txnid maybe zero in a legacy DB */ pp_txnid
-                   ? pp_txnid
-                   : mc->mc_txn->mt_txnid;
-    if ((mc->mc_txn->mt_flags & MDBX_TXN_RDONLY) == 0) {
-      MDBX_txn *scan = mc->mc_txn;
-      do
-        if ((scan->mt_flags & MDBX_TXN_DIRTY) &&
-            (mc->mc_dbi == MAIN_DBI ||
-             (scan->mt_dbistate[mc->mc_dbi] & DBI_DIRTY))) {
-          pp_txnid = scan->mt_front;
-          break;
-        }
-      while (unlikely((scan = scan->mt_parent) != nullptr));
-    }
-    if (unlikely((rc = mdbx_page_get(mc, root, &mc->mc_pg[0], pp_txnid)) != 0))
-      return rc;
-  }
-
-  mc->mc_snum = 1;
-  mc->mc_top = 0;
-
-  mdbx_debug("db %d root page %" PRIaPGNO " has flags 0x%X", DDBI(mc), root,
-             mc->mc_pg[0]->mp_flags);
-
-  if (flags & MDBX_PS_MODIFY) {
-    if (!(*mc->mc_dbistate & DBI_DIRTY) && unlikely(rc = mdbx_touch_dbi(mc)))
-      return rc;
-    if (unlikely(rc = mdbx_page_touch(mc)))
-      return rc;
-  }
-
-  if (flags & MDBX_PS_ROOTONLY)
-    return MDBX_SUCCESS;
-
-  return mdbx_page_search_root(mc, key, flags);
-}
-
-/* Return the data associated with a given node.
- *
- * [in] mc      The cursor for this operation.
- * [in] leaf    The node being read.
- * [out] data   Updated to point to the node's data.
- *
- * Returns 0 on success, non-zero on failure. */
-static __always_inline int mdbx_node_read(MDBX_cursor *mc,
-                                          const MDBX_node *node, MDBX_val *data,
-                                          const txnid_t front) {
-  data->iov_len = node_ds(node);
-  data->iov_base = node_data(node);
-  if (unlikely(F_ISSET(node_flags(node), F_BIGDATA))) {
-    /* Read overflow data. */
-    MDBX_page *omp; /* overflow page */
-    int rc = mdbx_page_get(mc, node_largedata_pgno(node), &omp, front);
-    if (unlikely((rc != MDBX_SUCCESS))) {
-      mdbx_debug("read overflow page %" PRIaPGNO " failed",
-                 node_largedata_pgno(node));
-      return rc;
-    }
-    data->iov_base = page_data(omp);
-  }
-  return MDBX_SUCCESS;
-}
-
-int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data) {
-  DKBUF_DEBUG;
-  mdbx_debug("===> get db %u key [%s]", dbi, DKEY_DEBUG(key));
-
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!key || !data))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  MDBX_cursor_couple cx;
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_cursor_set(&cx.outer, (MDBX_val *)key, data, MDBX_SET).err;
-}
-
-int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
-                            MDBX_val *data) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!key || !data))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
-    return MDBX_BAD_TXN;
-
-  MDBX_cursor_couple cx;
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_cursor_get(&cx.outer, key, data, MDBX_SET_LOWERBOUND);
-}
-
-int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
-                size_t *values_count) {
-  DKBUF_DEBUG;
-  mdbx_debug("===> get db %u key [%s]", dbi, DKEY_DEBUG(key));
-
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!key || !data))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  MDBX_cursor_couple cx;
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  rc = mdbx_cursor_set(&cx.outer, key, data, MDBX_SET_KEY).err;
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    if (rc == MDBX_NOTFOUND && values_count)
-      *values_count = 0;
-    return rc;
-  }
-
-  if (values_count) {
-    *values_count = 1;
-    if (cx.outer.mc_xcursor != NULL) {
-      MDBX_node *node = page_node(cx.outer.mc_pg[cx.outer.mc_top],
-                                  cx.outer.mc_ki[cx.outer.mc_top]);
-      if (F_ISSET(node_flags(node), F_DUPDATA)) {
-        // coverity[uninit_use : FALSE]
-        mdbx_tassert(txn, cx.outer.mc_xcursor == &cx.inner &&
-                              (cx.inner.mx_cursor.mc_flags & C_INITIALIZED));
-        // coverity[uninit_use : FALSE]
-        *values_count =
-            (sizeof(*values_count) >= sizeof(cx.inner.mx_db.md_entries) ||
-             cx.inner.mx_db.md_entries <= PTRDIFF_MAX)
-                ? (size_t)cx.inner.mx_db.md_entries
-                : PTRDIFF_MAX;
-      }
-    }
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Find a sibling for a page.
- * Replaces the page at the top of the cursor's stack with the specified
- * sibling, if one exists.
- *
- * [in] mc    The cursor for this operation.
- * [in] dir   SIBLING_LEFT or SIBLING_RIGHT.
- *
- * Returns 0 on success, non-zero on failure. */
-static int mdbx_cursor_sibling(MDBX_cursor *mc, int dir) {
-  int rc;
-  MDBX_node *node;
-  MDBX_page *mp;
-  assert(dir == SIBLING_LEFT || dir == SIBLING_RIGHT);
-
-  if (unlikely(mc->mc_snum < 2))
-    return MDBX_NOTFOUND; /* root has no siblings */
-
-  mdbx_cursor_pop(mc);
-  mdbx_debug("parent page is page %" PRIaPGNO ", index %u",
-             mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top]);
-
-  if ((dir == SIBLING_RIGHT)
-          ? (mc->mc_ki[mc->mc_top] + 1u >= page_numkeys(mc->mc_pg[mc->mc_top]))
-          : (mc->mc_ki[mc->mc_top] == 0)) {
-    mdbx_debug("no more keys aside, moving to next %s sibling",
-               dir ? "right" : "left");
-    if (unlikely((rc = mdbx_cursor_sibling(mc, dir)) != MDBX_SUCCESS)) {
-      /* undo cursor_pop before returning */
-      mc->mc_top++;
-      mc->mc_snum++;
-      return rc;
-    }
-  } else {
-    assert((dir - 1) == -1 || (dir - 1) == 1);
-    mc->mc_ki[mc->mc_top] += (indx_t)(dir - 1);
-    mdbx_debug("just moving to %s index key %u",
-               (dir == SIBLING_RIGHT) ? "right" : "left",
-               mc->mc_ki[mc->mc_top]);
-  }
-  mdbx_cassert(mc, IS_BRANCH(mc->mc_pg[mc->mc_top]));
-
-  node = page_node(mp = mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-  if (unlikely((rc = mdbx_page_get(mc, node_pgno(node), &mp,
-                                   pp_txnid4chk(mp, mc->mc_txn))) != 0)) {
-    /* mc will be inconsistent if caller does mc_snum++ as above */
-    mc->mc_flags &= ~(C_INITIALIZED | C_EOF);
-    return rc;
-  }
-
-  rc = mdbx_cursor_push(mc, mp);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  mc->mc_ki[mc->mc_top] =
-      (indx_t)((dir == SIBLING_LEFT) ? page_numkeys(mp) - 1 : 0);
-  return MDBX_SUCCESS;
-}
-
-/* Move the cursor to the next data item. */
-static int mdbx_cursor_next(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
-                            MDBX_cursor_op op) {
-  MDBX_page *mp;
-  MDBX_node *node;
-  int rc;
-
-  if (unlikely(mc->mc_flags & C_DEL) && op == MDBX_NEXT_DUP)
-    return MDBX_NOTFOUND;
-
-  if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
-    return mdbx_cursor_first(mc, key, data);
-
-  mp = mc->mc_pg[mc->mc_top];
-  if (unlikely(mc->mc_flags & C_EOF)) {
-    if (mc->mc_ki[mc->mc_top] + 1u >= page_numkeys(mp))
-      return MDBX_NOTFOUND;
-    mc->mc_flags ^= C_EOF;
-  }
-
-  if (mc->mc_db->md_flags & MDBX_DUPSORT) {
-    node = page_node(mp, mc->mc_ki[mc->mc_top]);
-    if (F_ISSET(node_flags(node), F_DUPDATA)) {
-      if (op == MDBX_NEXT || op == MDBX_NEXT_DUP) {
-        rc =
-            mdbx_cursor_next(&mc->mc_xcursor->mx_cursor, data, NULL, MDBX_NEXT);
-        if (op != MDBX_NEXT || rc != MDBX_NOTFOUND) {
-          if (likely(rc == MDBX_SUCCESS))
-            get_key_optional(node, key);
-          return rc;
-        }
-      }
-    } else {
-      mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
-      if (op == MDBX_NEXT_DUP)
-        return MDBX_NOTFOUND;
-    }
-  }
-
-  mdbx_debug("cursor_next: top page is %" PRIaPGNO " in cursor %p", mp->mp_pgno,
-             (void *)mc);
-  if (mc->mc_flags & C_DEL) {
-    mc->mc_flags ^= C_DEL;
-    goto skip;
-  }
-
-  int ki = mc->mc_ki[mc->mc_top];
-  mc->mc_ki[mc->mc_top] = (indx_t)++ki;
-  const int numkeys = page_numkeys(mp);
-  if (unlikely(ki >= numkeys)) {
-    mdbx_debug("%s", "=====> move to next sibling page");
-    mc->mc_ki[mc->mc_top] = (indx_t)(numkeys - 1);
-    if (unlikely((rc = mdbx_cursor_sibling(mc, SIBLING_RIGHT)) !=
-                 MDBX_SUCCESS)) {
-      mc->mc_flags |= C_EOF;
-      return rc;
-    }
-    mp = mc->mc_pg[mc->mc_top];
-    mdbx_debug("next page is %" PRIaPGNO ", key index %u", mp->mp_pgno,
-               mc->mc_ki[mc->mc_top]);
-  }
-
-skip:
-  mdbx_debug("==> cursor points to page %" PRIaPGNO
-             " with %u keys, key index %u",
-             mp->mp_pgno, page_numkeys(mp), mc->mc_ki[mc->mc_top]);
-
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(!IS_LEAF(mp)))
-    return MDBX_CORRUPTED;
-
-  if (IS_LEAF2(mp)) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-      mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                 mp->mp_pgno);
-      return MDBX_CORRUPTED;
-    } else if (likely(key)) {
-      key->iov_len = mc->mc_db->md_xsize;
-      key->iov_base = page_leaf2key(mp, mc->mc_ki[mc->mc_top], key->iov_len);
-    }
-    return MDBX_SUCCESS;
-  }
-
-  node = page_node(mp, mc->mc_ki[mc->mc_top]);
-  if (F_ISSET(node_flags(node), F_DUPDATA)) {
-    rc = mdbx_xcursor_init1(mc, node, mp);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    rc = mdbx_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  } else if (likely(data)) {
-    if (unlikely((rc = mdbx_node_read(mc, node, data,
-                                      pp_txnid4chk(mp, mc->mc_txn))) !=
-                 MDBX_SUCCESS))
-      return rc;
-  }
-
-  get_key_optional(node, key);
-  return MDBX_SUCCESS;
-}
-
-/* Move the cursor to the previous data item. */
-static int mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
-                            MDBX_cursor_op op) {
-  MDBX_page *mp;
-  MDBX_node *node;
-  int rc;
-
-  if (unlikely(mc->mc_flags & C_DEL) && op == MDBX_PREV_DUP)
-    return MDBX_NOTFOUND;
-
-  if (unlikely(!(mc->mc_flags & C_INITIALIZED))) {
-    rc = mdbx_cursor_last(mc, key, data);
-    if (unlikely(rc))
-      return rc;
-    mc->mc_ki[mc->mc_top]++;
-  }
-
-  mp = mc->mc_pg[mc->mc_top];
-  if ((mc->mc_db->md_flags & MDBX_DUPSORT) &&
-      mc->mc_ki[mc->mc_top] < page_numkeys(mp)) {
-    node = page_node(mp, mc->mc_ki[mc->mc_top]);
-    if (F_ISSET(node_flags(node), F_DUPDATA)) {
-      if (op == MDBX_PREV || op == MDBX_PREV_DUP) {
-        rc =
-            mdbx_cursor_prev(&mc->mc_xcursor->mx_cursor, data, NULL, MDBX_PREV);
-        if (op != MDBX_PREV || rc != MDBX_NOTFOUND) {
-          if (likely(rc == MDBX_SUCCESS)) {
-            get_key_optional(node, key);
-            mc->mc_flags &= ~C_EOF;
-          }
-          return rc;
-        }
-      }
-    } else {
-      mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
-      if (op == MDBX_PREV_DUP)
-        return MDBX_NOTFOUND;
-    }
-  }
-
-  mdbx_debug("cursor_prev: top page is %" PRIaPGNO " in cursor %p", mp->mp_pgno,
-             (void *)mc);
-
-  mc->mc_flags &= ~(C_EOF | C_DEL);
-
-  int ki = mc->mc_ki[mc->mc_top];
-  mc->mc_ki[mc->mc_top] = (indx_t)--ki;
-  if (unlikely(ki < 0)) {
-    mc->mc_ki[mc->mc_top] = 0;
-    mdbx_debug("%s", "=====> move to prev sibling page");
-    if ((rc = mdbx_cursor_sibling(mc, SIBLING_LEFT)) != MDBX_SUCCESS)
-      return rc;
-    mp = mc->mc_pg[mc->mc_top];
-    mdbx_debug("prev page is %" PRIaPGNO ", key index %u", mp->mp_pgno,
-               mc->mc_ki[mc->mc_top]);
-  }
-  mdbx_debug("==> cursor points to page %" PRIaPGNO
-             " with %u keys, key index %u",
-             mp->mp_pgno, page_numkeys(mp), mc->mc_ki[mc->mc_top]);
-
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(!IS_LEAF(mp)))
-    return MDBX_CORRUPTED;
-
-  if (IS_LEAF2(mp)) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-      mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                 mp->mp_pgno);
-      return MDBX_CORRUPTED;
-    } else if (likely(key)) {
-      key->iov_len = mc->mc_db->md_xsize;
-      key->iov_base = page_leaf2key(mp, mc->mc_ki[mc->mc_top], key->iov_len);
-    }
-    return MDBX_SUCCESS;
-  }
-
-  node = page_node(mp, mc->mc_ki[mc->mc_top]);
-
-  if (F_ISSET(node_flags(node), F_DUPDATA)) {
-    rc = mdbx_xcursor_init1(mc, node, mp);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    rc = mdbx_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  } else if (likely(data)) {
-    if (unlikely((rc = mdbx_node_read(mc, node, data,
-                                      pp_txnid4chk(mp, mc->mc_txn))) !=
-                 MDBX_SUCCESS))
-      return rc;
-  }
-
-  get_key_optional(node, key);
-  return MDBX_SUCCESS;
-}
-
-/* Set the cursor on a specific data item. */
-static struct cursor_set_result mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key,
-                                                MDBX_val *data,
-                                                MDBX_cursor_op op) {
-  MDBX_page *mp;
-  MDBX_node *node = NULL;
-  DKBUF_DEBUG;
-
-  struct cursor_set_result ret;
-  ret.exact = false;
-  if (unlikely(key->iov_len < mc->mc_dbx->md_klen_min ||
-               key->iov_len > mc->mc_dbx->md_klen_max)) {
-    mdbx_cassert(mc, !"Invalid key-size");
-    ret.err = MDBX_BAD_VALSIZE;
-    return ret;
-  }
-
-  MDBX_val aligned_key = *key;
-  uint64_t aligned_keybytes;
-  if (mc->mc_db->md_flags & MDBX_INTEGERKEY) {
-    switch (aligned_key.iov_len) {
-    default:
-      mdbx_cassert(mc, !"key-size is invalid for MDBX_INTEGERKEY");
-      ret.err = MDBX_BAD_VALSIZE;
-      return ret;
-    case 4:
-      if (unlikely(3 & (uintptr_t)aligned_key.iov_base))
-        /* copy instead of return error to avoid break compatibility */
-        aligned_key.iov_base =
-            memcpy(&aligned_keybytes, aligned_key.iov_base, 4);
-      break;
-    case 8:
-      if (unlikely(7 & (uintptr_t)aligned_key.iov_base))
-        /* copy instead of return error to avoid break compatibility */
-        aligned_key.iov_base =
-            memcpy(&aligned_keybytes, aligned_key.iov_base, 8);
-      break;
-    }
-  }
-
-  if (mc->mc_xcursor)
-    mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
-
-  /* See if we're already on the right page */
-  if (mc->mc_flags & C_INITIALIZED) {
-    MDBX_val nodekey;
-
-    mdbx_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]));
-    mp = mc->mc_pg[mc->mc_top];
-    if (unlikely(!page_numkeys(mp))) {
-      mc->mc_ki[mc->mc_top] = 0;
-      mc->mc_flags |= C_EOF;
-      ret.err = MDBX_NOTFOUND;
-      return ret;
-    }
-    if (IS_LEAF2(mp)) {
-      nodekey.iov_len = mc->mc_db->md_xsize;
-      nodekey.iov_base = page_leaf2key(mp, 0, nodekey.iov_len);
-    } else {
-      node = page_node(mp, 0);
-      get_key(node, &nodekey);
-    }
-    int cmp = mc->mc_dbx->md_cmp(&aligned_key, &nodekey);
-    if (unlikely(cmp == 0)) {
-      /* Probably happens rarely, but first node on the page
-       * was the one we wanted. */
-      mc->mc_ki[mc->mc_top] = 0;
-      ret.exact = true;
-      mdbx_cassert(mc, mc->mc_ki[mc->mc_top] <
-                               page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                           (mc->mc_flags & C_EOF));
-      goto got_node;
-    }
-    if (cmp > 0) {
-      const unsigned nkeys = page_numkeys(mp);
-      if (nkeys > 1) {
-        if (IS_LEAF2(mp)) {
-          nodekey.iov_base = page_leaf2key(mp, nkeys - 1, nodekey.iov_len);
-        } else {
-          node = page_node(mp, nkeys - 1);
-          get_key(node, &nodekey);
-        }
-        cmp = mc->mc_dbx->md_cmp(&aligned_key, &nodekey);
-        if (cmp == 0) {
-          /* last node was the one we wanted */
-          mdbx_cassert(mc, nkeys >= 1 && nkeys <= UINT16_MAX + 1);
-          mc->mc_ki[mc->mc_top] = (indx_t)(nkeys - 1);
-          ret.exact = true;
-          mdbx_cassert(mc, mc->mc_ki[mc->mc_top] <
-                                   page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                               (mc->mc_flags & C_EOF));
-          goto got_node;
-        }
-        if (cmp < 0) {
-          if (mc->mc_ki[mc->mc_top] < page_numkeys(mp)) {
-            /* This is definitely the right page, skip search_page */
-            if (IS_LEAF2(mp)) {
-              nodekey.iov_base =
-                  page_leaf2key(mp, mc->mc_ki[mc->mc_top], nodekey.iov_len);
-            } else {
-              node = page_node(mp, mc->mc_ki[mc->mc_top]);
-              get_key(node, &nodekey);
-            }
-            cmp = mc->mc_dbx->md_cmp(&aligned_key, &nodekey);
-            if (cmp == 0) {
-              /* current node was the one we wanted */
-              ret.exact = true;
-              mdbx_cassert(mc, mc->mc_ki[mc->mc_top] <
-                                       page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                                   (mc->mc_flags & C_EOF));
-              goto got_node;
-            }
-          }
-          mc->mc_flags &= ~C_EOF;
-          goto search_node;
-        }
-      }
-      /* If any parents have right-sibs, search.
-       * Otherwise, there's nothing further. */
-      unsigned i;
-      for (i = 0; i < mc->mc_top; i++)
-        if (mc->mc_ki[i] < page_numkeys(mc->mc_pg[i]) - 1)
-          break;
-      if (i == mc->mc_top) {
-        /* There are no other pages */
-        mdbx_cassert(mc, nkeys <= UINT16_MAX);
-        mc->mc_ki[mc->mc_top] = (uint16_t)nkeys;
-        mc->mc_flags |= C_EOF;
-        ret.err = MDBX_NOTFOUND;
-        return ret;
-      }
-    }
-    if (!mc->mc_top) {
-      /* There are no other pages */
-      mc->mc_ki[mc->mc_top] = 0;
-      if (op == MDBX_SET_RANGE)
-        goto got_node;
-
-      mdbx_cassert(mc, mc->mc_ki[mc->mc_top] <
-                               page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                           (mc->mc_flags & C_EOF));
-      ret.err = MDBX_NOTFOUND;
-      return ret;
-    }
-  } else {
-    mc->mc_pg[0] = 0;
-  }
-
-  ret.err = mdbx_page_search(mc, &aligned_key, 0);
-  if (unlikely(ret.err != MDBX_SUCCESS))
-    return ret;
-
-  mp = mc->mc_pg[mc->mc_top];
-  mdbx_cassert(mc, IS_LEAF(mp));
-
-search_node:;
-  struct node_result nsr = mdbx_node_search(mc, &aligned_key);
-  node = nsr.node;
-  ret.exact = nsr.exact;
-  if (!ret.exact) {
-    if (op != MDBX_SET_RANGE) {
-      /* MDBX_SET specified and not an exact match. */
-      if (unlikely(mc->mc_ki[mc->mc_top] >=
-                   page_numkeys(mc->mc_pg[mc->mc_top])))
-        mc->mc_flags |= C_EOF;
-      ret.err = MDBX_NOTFOUND;
-      return ret;
-    }
-
-    if (node == NULL) {
-      mdbx_debug("%s", "===> inexact leaf not found, goto sibling");
-      ret.err = mdbx_cursor_sibling(mc, SIBLING_RIGHT);
-      if (unlikely(ret.err != MDBX_SUCCESS)) {
-        mc->mc_flags |= C_EOF;
-        return ret; /* no entries matched */
-      }
-      mp = mc->mc_pg[mc->mc_top];
-      mdbx_cassert(mc, IS_LEAF(mp));
-      if (!IS_LEAF2(mp))
-        node = page_node(mp, 0);
-    }
-  }
-  mdbx_cassert(mc,
-               mc->mc_ki[mc->mc_top] < page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                   (mc->mc_flags & C_EOF));
-
-got_node:
-  mc->mc_flags |= C_INITIALIZED;
-  mc->mc_flags &= ~C_EOF;
-
-  if (IS_LEAF2(mp)) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-      mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                 mp->mp_pgno);
-      ret.err = MDBX_CORRUPTED;
-    } else {
-      if (op == MDBX_SET_RANGE || op == MDBX_SET_KEY) {
-        key->iov_len = mc->mc_db->md_xsize;
-        key->iov_base = page_leaf2key(mp, mc->mc_ki[mc->mc_top], key->iov_len);
-      }
-      ret.err = MDBX_SUCCESS;
-    }
-    return ret;
-  }
-
-  if (F_ISSET(node_flags(node), F_DUPDATA)) {
-    ret.err = mdbx_xcursor_init1(mc, node, mp);
-    if (unlikely(ret.err != MDBX_SUCCESS))
-      return ret;
-    if (op == MDBX_SET || op == MDBX_SET_KEY || op == MDBX_SET_RANGE) {
-      ret.err = mdbx_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
-      if (unlikely(ret.err != MDBX_SUCCESS))
-        return ret;
-    } else {
-      ret = mdbx_cursor_set(&mc->mc_xcursor->mx_cursor, data, NULL,
-                            MDBX_SET_RANGE);
-      if (unlikely(ret.err != MDBX_SUCCESS))
-        return ret;
-      if (op == MDBX_GET_BOTH && !ret.exact) {
-        ret.err = MDBX_NOTFOUND;
-        return ret;
-      }
-    }
-  } else if (likely(data)) {
-    if (op == MDBX_GET_BOTH || op == MDBX_GET_BOTH_RANGE) {
-      if (unlikely(data->iov_len < mc->mc_dbx->md_vlen_min ||
-                   data->iov_len > mc->mc_dbx->md_vlen_max)) {
-        mdbx_cassert(mc, !"Invalid data-size");
-        ret.err = MDBX_BAD_VALSIZE;
-        return ret;
-      }
-      MDBX_val aligned_data = *data;
-      uint64_t aligned_databytes;
-      if (mc->mc_db->md_flags & MDBX_INTEGERDUP) {
-        switch (aligned_data.iov_len) {
-        default:
-          mdbx_cassert(mc, !"data-size is invalid for MDBX_INTEGERDUP");
-          ret.err = MDBX_BAD_VALSIZE;
-          return ret;
-        case 4:
-          if (unlikely(3 & (uintptr_t)aligned_data.iov_base))
-            /* copy instead of return error to avoid break compatibility */
-            aligned_data.iov_base =
-                memcpy(&aligned_databytes, aligned_data.iov_base, 4);
-          break;
-        case 8:
-          if (unlikely(7 & (uintptr_t)aligned_data.iov_base))
-            /* copy instead of return error to avoid break compatibility */
-            aligned_data.iov_base =
-                memcpy(&aligned_databytes, aligned_data.iov_base, 8);
-          break;
-        }
-      }
-      MDBX_val actual_data;
-      ret.err = mdbx_node_read(mc, node, &actual_data,
-                               pp_txnid4chk(mc->mc_pg[mc->mc_top], mc->mc_txn));
-      if (unlikely(ret.err != MDBX_SUCCESS))
-        return ret;
-      const int cmp = mc->mc_dbx->md_dcmp(&aligned_data, &actual_data);
-      if (cmp) {
-        mdbx_cassert(mc, mc->mc_ki[mc->mc_top] <
-                                 page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                             (mc->mc_flags & C_EOF));
-        if (op != MDBX_GET_BOTH_RANGE || cmp > 0) {
-          ret.err = MDBX_NOTFOUND;
-          return ret;
-        }
-      }
-      *data = actual_data;
-    } else {
-      ret.err = mdbx_node_read(mc, node, data,
-                               pp_txnid4chk(mc->mc_pg[mc->mc_top], mc->mc_txn));
-      if (unlikely(ret.err != MDBX_SUCCESS))
-        return ret;
-    }
-  }
-
-  /* The key already matches in all other cases */
-  if (op == MDBX_SET_RANGE || op == MDBX_SET_KEY)
-    get_key_optional(node, key);
-
-  mdbx_debug("==> cursor placed on key [%s], data [%s]", DKEY_DEBUG(key),
-             DVAL_DEBUG(data));
-  ret.err = MDBX_SUCCESS;
-  return ret;
-}
-
-/* Move the cursor to the first item in the database. */
-static int mdbx_cursor_first(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data) {
-  int rc;
-
-  if (mc->mc_xcursor)
-    mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
-
-  if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) {
-    rc = mdbx_page_search(mc, NULL, MDBX_PS_FIRST);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(!IS_LEAF(mc->mc_pg[mc->mc_top])))
-    return MDBX_CORRUPTED;
-
-  mc->mc_flags |= C_INITIALIZED;
-  mc->mc_flags &= ~C_EOF;
-  mc->mc_ki[mc->mc_top] = 0;
-
-  if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-      mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                 mc->mc_pg[mc->mc_top]->mp_pgno);
-      return MDBX_CORRUPTED;
-    } else if (likely(key)) {
-      key->iov_len = mc->mc_db->md_xsize;
-      key->iov_base = page_leaf2key(mc->mc_pg[mc->mc_top], 0, key->iov_len);
-    }
-    return MDBX_SUCCESS;
-  }
-
-  MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], 0);
-  if (F_ISSET(node_flags(node), F_DUPDATA)) {
-    rc = mdbx_xcursor_init1(mc, node, mc->mc_pg[mc->mc_top]);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    rc = mdbx_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
-    if (unlikely(rc))
-      return rc;
-  } else if (likely(data)) {
-    if (unlikely((rc = mdbx_node_read(
-                      mc, node, data,
-                      pp_txnid4chk(mc->mc_pg[mc->mc_top], mc->mc_txn))) !=
-                 MDBX_SUCCESS))
-      return rc;
-  }
-
-  get_key_optional(node, key);
-  return MDBX_SUCCESS;
-}
-
-/* Move the cursor to the last item in the database. */
-static int mdbx_cursor_last(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data) {
-  int rc;
-
-  if (mc->mc_xcursor)
-    mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
-
-  if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) {
-    rc = mdbx_page_search(mc, NULL, MDBX_PS_LAST);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(!IS_LEAF(mc->mc_pg[mc->mc_top])))
-    return MDBX_CORRUPTED;
-
-  mc->mc_ki[mc->mc_top] = (indx_t)page_numkeys(mc->mc_pg[mc->mc_top]) - 1;
-  mc->mc_flags |= C_INITIALIZED | C_EOF;
-
-  if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-      mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                 mc->mc_pg[mc->mc_top]->mp_pgno);
-      return MDBX_CORRUPTED;
-    } else if (likely(key)) {
-      key->iov_len = mc->mc_db->md_xsize;
-      key->iov_base = page_leaf2key(mc->mc_pg[mc->mc_top],
-                                    mc->mc_ki[mc->mc_top], key->iov_len);
-    }
-    return MDBX_SUCCESS;
-  }
-
-  MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-  if (F_ISSET(node_flags(node), F_DUPDATA)) {
-    rc = mdbx_xcursor_init1(mc, node, mc->mc_pg[mc->mc_top]);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    rc = mdbx_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL);
-    if (unlikely(rc))
-      return rc;
-  } else if (likely(data)) {
-    if (unlikely((rc = mdbx_node_read(
-                      mc, node, data,
-                      pp_txnid4chk(mc->mc_pg[mc->mc_top], mc->mc_txn))) !=
-                 MDBX_SUCCESS))
-      return rc;
-  }
-
-  get_key_optional(node, key);
-  return MDBX_SUCCESS;
-}
-
-int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
-                    MDBX_cursor_op op) {
-  if (unlikely(mc == NULL))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  int rc = check_txn(mc->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  int (*mfunc)(MDBX_cursor * mc, MDBX_val * key, MDBX_val * data);
-  switch (op) {
-  case MDBX_GET_CURRENT: {
-    if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
-      return MDBX_ENODATA;
-    MDBX_page *mp = mc->mc_pg[mc->mc_top];
-    const unsigned nkeys = page_numkeys(mp);
-    if (unlikely(mc->mc_ki[mc->mc_top] >= nkeys)) {
-      mdbx_cassert(mc, nkeys <= UINT16_MAX);
-      if (mc->mc_flags & C_EOF)
-        return MDBX_ENODATA;
-      mc->mc_ki[mc->mc_top] = (uint16_t)nkeys;
-      mc->mc_flags |= C_EOF;
-      return MDBX_NOTFOUND;
-    }
-    mdbx_cassert(mc, nkeys > 0);
-
-    rc = MDBX_SUCCESS;
-    if (IS_LEAF2(mp)) {
-      if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-        mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                   mp->mp_pgno);
-        return MDBX_CORRUPTED;
-      }
-      key->iov_len = mc->mc_db->md_xsize;
-      key->iov_base = page_leaf2key(mp, mc->mc_ki[mc->mc_top], key->iov_len);
-    } else {
-      MDBX_node *node = page_node(mp, mc->mc_ki[mc->mc_top]);
-      get_key_optional(node, key);
-      if (data) {
-        if (F_ISSET(node_flags(node), F_DUPDATA)) {
-          if (unlikely(!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))) {
-            rc = mdbx_xcursor_init1(mc, node, mp);
-            if (unlikely(rc != MDBX_SUCCESS))
-              return rc;
-            rc = mdbx_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
-            if (unlikely(rc))
-              return rc;
-          } else {
-            rc = mdbx_cursor_get(&mc->mc_xcursor->mx_cursor, data, NULL,
-                                 MDBX_GET_CURRENT);
-            if (unlikely(rc))
-              return rc;
-          }
-        } else {
-          rc = mdbx_node_read(mc, node, data, pp_txnid4chk(mp, mc->mc_txn));
-          if (unlikely(rc))
-            return rc;
-        }
-      }
-    }
-    break;
-  }
-  case MDBX_GET_BOTH:
-  case MDBX_GET_BOTH_RANGE:
-    if (unlikely(data == NULL))
-      return MDBX_EINVAL;
-    if (unlikely(mc->mc_xcursor == NULL))
-      return MDBX_INCOMPATIBLE;
-    /* fall through */
-    __fallthrough;
-  case MDBX_SET:
-  case MDBX_SET_KEY:
-  case MDBX_SET_RANGE:
-    if (unlikely(key == NULL))
-      return MDBX_EINVAL;
-    rc = mdbx_cursor_set(mc, key, data, op).err;
-    if (mc->mc_flags & C_INITIALIZED) {
-      mdbx_cassert(mc, mc->mc_snum > 0 && mc->mc_top < mc->mc_snum);
-      mdbx_cassert(mc, mc->mc_ki[mc->mc_top] <
-                               page_numkeys(mc->mc_pg[mc->mc_top]) ||
-                           (mc->mc_flags & C_EOF));
-    }
-    break;
-  case MDBX_GET_MULTIPLE:
-    if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED)))
-      return MDBX_EINVAL;
-    if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED)))
-      return MDBX_INCOMPATIBLE;
-    rc = MDBX_SUCCESS;
-    if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) !=
-        C_INITIALIZED)
-      break;
-    goto fetchm;
-  case MDBX_NEXT_MULTIPLE:
-    if (unlikely(data == NULL))
-      return MDBX_EINVAL;
-    if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED)))
-      return MDBX_INCOMPATIBLE;
-    rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT_DUP);
-    if (rc == MDBX_SUCCESS) {
-      if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
-        MDBX_cursor *mx;
-      fetchm:
-        mx = &mc->mc_xcursor->mx_cursor;
-        data->iov_len =
-            page_numkeys(mx->mc_pg[mx->mc_top]) * mx->mc_db->md_xsize;
-        data->iov_base = page_data(mx->mc_pg[mx->mc_top]);
-        mx->mc_ki[mx->mc_top] = (indx_t)page_numkeys(mx->mc_pg[mx->mc_top]) - 1;
-      } else {
-        rc = MDBX_NOTFOUND;
-      }
-    }
-    break;
-  case MDBX_PREV_MULTIPLE:
-    if (data == NULL)
-      return MDBX_EINVAL;
-    if (!(mc->mc_db->md_flags & MDBX_DUPFIXED))
-      return MDBX_INCOMPATIBLE;
-    rc = MDBX_SUCCESS;
-    if (!(mc->mc_flags & C_INITIALIZED))
-      rc = mdbx_cursor_last(mc, key, data);
-    if (rc == MDBX_SUCCESS) {
-      MDBX_cursor *mx = &mc->mc_xcursor->mx_cursor;
-      if (mx->mc_flags & C_INITIALIZED) {
-        rc = mdbx_cursor_sibling(mx, SIBLING_LEFT);
-        if (rc == MDBX_SUCCESS)
-          goto fetchm;
-      } else {
-        rc = MDBX_NOTFOUND;
-      }
-    }
-    break;
-  case MDBX_NEXT:
-  case MDBX_NEXT_DUP:
-  case MDBX_NEXT_NODUP:
-    rc = mdbx_cursor_next(mc, key, data, op);
-    break;
-  case MDBX_PREV:
-  case MDBX_PREV_DUP:
-  case MDBX_PREV_NODUP:
-    rc = mdbx_cursor_prev(mc, key, data, op);
-    break;
-  case MDBX_FIRST:
-    rc = mdbx_cursor_first(mc, key, data);
-    break;
-  case MDBX_FIRST_DUP:
-    mfunc = mdbx_cursor_first;
-  move:
-    if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED)))
-      return MDBX_EINVAL;
-    if (unlikely(mc->mc_xcursor == NULL))
-      return MDBX_INCOMPATIBLE;
-    if (mc->mc_ki[mc->mc_top] >= page_numkeys(mc->mc_pg[mc->mc_top])) {
-      mc->mc_ki[mc->mc_top] = (indx_t)page_numkeys(mc->mc_pg[mc->mc_top]);
-      mc->mc_flags |= C_EOF;
-      return MDBX_NOTFOUND;
-    }
-    {
-      MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-      if (!F_ISSET(node_flags(node), F_DUPDATA)) {
-        get_key_optional(node, key);
-        rc = mdbx_node_read(mc, node, data,
-                            pp_txnid4chk(mc->mc_pg[mc->mc_top], mc->mc_txn));
-        break;
-      }
-    }
-    if (unlikely(!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)))
-      return MDBX_EINVAL;
-    rc = mfunc(&mc->mc_xcursor->mx_cursor, data, NULL);
-    break;
-  case MDBX_LAST:
-    rc = mdbx_cursor_last(mc, key, data);
-    break;
-  case MDBX_LAST_DUP:
-    mfunc = mdbx_cursor_last;
-    goto move;
-  case MDBX_SET_UPPERBOUND: /* mostly same as MDBX_SET_LOWERBOUND */
-  case MDBX_SET_LOWERBOUND: {
-    if (unlikely(key == NULL || data == NULL))
-      return MDBX_EINVAL;
-    MDBX_val save_data = *data;
-    struct cursor_set_result csr =
-        mdbx_cursor_set(mc, key, data, MDBX_SET_RANGE);
-    rc = csr.err;
-    if (rc == MDBX_SUCCESS && csr.exact && mc->mc_xcursor) {
-      mc->mc_flags &= ~C_DEL;
-      csr.exact = false;
-      if (!save_data.iov_base && (mc->mc_db->md_flags & MDBX_DUPFIXED)) {
-        /* Avoiding search nested dupfixed hive if no data provided.
-         * This is changes the semantic of MDBX_SET_LOWERBOUND but avoid
-         * returning MDBX_BAD_VALSIZE. */
-      } else if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
-        *data = save_data;
-        csr = mdbx_cursor_set(&mc->mc_xcursor->mx_cursor, data, NULL,
-                              MDBX_SET_RANGE);
-        rc = csr.err;
-        if (rc == MDBX_NOTFOUND) {
-          mdbx_cassert(mc, !csr.exact);
-          rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT_NODUP);
-        }
-      } else {
-        int cmp = mc->mc_dbx->md_dcmp(&save_data, data);
-        csr.exact = (cmp == 0);
-        if (cmp > 0)
-          rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT_NODUP);
-      }
-    }
-    if (rc == MDBX_SUCCESS && !csr.exact)
-      rc = MDBX_RESULT_TRUE;
-    if (unlikely(op == MDBX_SET_UPPERBOUND)) {
-      /* minor fixups for MDBX_SET_UPPERBOUND */
-      if (rc == MDBX_RESULT_TRUE)
-        /* already at great-than by MDBX_SET_LOWERBOUND */
-        rc = MDBX_SUCCESS;
-      else if (rc == MDBX_SUCCESS)
-        /* exactly match, going next */
-        rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT);
-    }
-    break;
-  }
-  default:
-    mdbx_debug("unhandled/unimplemented cursor operation %u", op);
-    return MDBX_EINVAL;
-  }
-
-  mc->mc_flags &= ~C_DEL;
-  return rc;
-}
-
-static int cursor_first_batch(MDBX_cursor *mc) {
-  if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) {
-    int err = mdbx_page_search(mc, NULL, MDBX_PS_FIRST);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-  }
-  mdbx_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]));
-
-  mc->mc_flags |= C_INITIALIZED;
-  mc->mc_flags &= ~C_EOF;
-  mc->mc_ki[mc->mc_top] = 0;
-  return MDBX_SUCCESS;
-}
-
-static int cursor_next_batch(MDBX_cursor *mc) {
-  if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
-    return cursor_first_batch(mc);
-
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  if (unlikely(mc->mc_flags & C_EOF)) {
-    if ((unsigned)mc->mc_ki[mc->mc_top] + 1 >= page_numkeys(mp))
-      return MDBX_NOTFOUND;
-    mc->mc_flags ^= C_EOF;
-  }
-
-  int ki = mc->mc_ki[mc->mc_top];
-  mc->mc_ki[mc->mc_top] = (indx_t)++ki;
-  const int numkeys = page_numkeys(mp);
-  if (likely(ki >= numkeys)) {
-    mdbx_debug("%s", "=====> move to next sibling page");
-    mc->mc_ki[mc->mc_top] = (indx_t)(numkeys - 1);
-    int err = mdbx_cursor_sibling(mc, SIBLING_RIGHT);
-    if (unlikely(err != MDBX_SUCCESS)) {
-      mc->mc_flags |= C_EOF;
-      return err;
-    }
-    mp = mc->mc_pg[mc->mc_top];
-    mdbx_debug("next page is %" PRIaPGNO ", key index %u", mp->mp_pgno,
-               mc->mc_ki[mc->mc_top]);
-  }
-  return MDBX_SUCCESS;
-}
-
-int mdbx_cursor_get_batch(MDBX_cursor *mc, size_t *count, MDBX_val *pairs,
-                          size_t limit, MDBX_cursor_op op) {
-  if (unlikely(mc == NULL || count == NULL || limit < 4))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  int rc = check_txn(mc->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(mc->mc_db->md_flags & MDBX_DUPSORT))
-    return MDBX_INCOMPATIBLE /* must be a non-dupsort subDB */;
-
-  switch (op) {
-  case MDBX_FIRST:
-    rc = cursor_first_batch(mc);
-    break;
-  case MDBX_NEXT:
-    rc = cursor_next_batch(mc);
-    break;
-  case MDBX_GET_CURRENT:
-    rc = likely(mc->mc_flags & C_INITIALIZED) ? MDBX_SUCCESS : MDBX_ENODATA;
-    break;
-  default:
-    mdbx_debug("unhandled/unimplemented cursor operation %u", op);
-    rc = EINVAL;
-    break;
-  }
-
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    *count = 0;
-    return rc;
-  }
-
-  const MDBX_page *const page = mc->mc_pg[mc->mc_top];
-  const unsigned nkeys = page_numkeys(page);
-  unsigned i = mc->mc_ki[mc->mc_top], n = 0;
-  if (unlikely(i >= nkeys)) {
-    mdbx_cassert(mc, op == MDBX_GET_CURRENT);
-    mdbx_cassert(mc, mdbx_cursor_on_last(mc) == MDBX_RESULT_TRUE);
-    *count = 0;
-    if (mc->mc_flags & C_EOF) {
-      mdbx_cassert(mc, mdbx_cursor_on_last(mc) == MDBX_RESULT_TRUE);
-      return MDBX_ENODATA;
-    }
-    if (mdbx_cursor_on_last(mc) != MDBX_RESULT_TRUE)
-      return MDBX_EINVAL /* again MDBX_GET_CURRENT after MDBX_GET_CURRENT */;
-    mc->mc_flags |= C_EOF;
-    return MDBX_NOTFOUND;
-  }
-
-  const txnid_t pp_txnid = pp_txnid4chk(page, mc->mc_txn);
-  do {
-    if (unlikely(n + 2 > limit)) {
-      rc = MDBX_RESULT_TRUE;
-      break;
-    }
-    const MDBX_node *leaf = page_node(page, i);
-    get_key(leaf, &pairs[n]);
-    rc = mdbx_node_read(mc, leaf, &pairs[n + 1], pp_txnid);
-    if (unlikely(rc != MDBX_SUCCESS))
-      break;
-    n += 2;
-  } while (++i < nkeys);
-
-  mc->mc_ki[mc->mc_top] = (indx_t)i;
-  *count = n;
-  return rc;
-}
-
-static int mdbx_touch_dbi(MDBX_cursor *mc) {
-  mdbx_cassert(mc, (*mc->mc_dbistate & DBI_DIRTY) == 0);
-  *mc->mc_dbistate |= DBI_DIRTY;
-  mc->mc_txn->mt_flags |= MDBX_TXN_DIRTY;
-  if (mc->mc_dbi >= CORE_DBS) {
-    mdbx_cassert(mc, (mc->mc_flags & C_RECLAIMING) == 0);
-    /* Touch DB record of named DB */
-    MDBX_cursor_couple cx;
-    int rc = mdbx_cursor_init(&cx.outer, mc->mc_txn, MAIN_DBI);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    mc->mc_txn->mt_dbistate[MAIN_DBI] |= DBI_DIRTY;
-    rc = mdbx_page_search(&cx.outer, &mc->mc_dbx->md_name, MDBX_PS_MODIFY);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Touch all the pages in the cursor stack. Set mc_top.
- * Makes sure all the pages are writable, before attempting a write operation.
- * [in] mc The cursor to operate on. */
-static int mdbx_cursor_touch(MDBX_cursor *mc) {
-  int rc = MDBX_SUCCESS;
-  if (unlikely((*mc->mc_dbistate & DBI_DIRTY) == 0)) {
-    rc = mdbx_touch_dbi(mc);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-  if (likely(mc->mc_snum)) {
-    mc->mc_top = 0;
-    do {
-      rc = mdbx_page_touch(mc);
-    } while (!rc && ++(mc->mc_top) < mc->mc_snum);
-    mc->mc_top = mc->mc_snum - 1;
-  }
-  return rc;
-}
-
-int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
-                    unsigned flags) {
-  MDBX_env *env;
-  MDBX_page *sub_root = NULL;
-  MDBX_val xdata, *rdata, dkey, olddata;
-  MDBX_db nested_dupdb;
-  int err;
-  DKBUF_DEBUG;
-
-  if (unlikely(mc == NULL || key == NULL || data == NULL))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  int rc = check_txn_rw(mc->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)))
-    return MDBX_BAD_DBI;
-
-  mdbx_cassert(mc, cursor_is_tracked(mc));
-  env = mc->mc_txn->mt_env;
-
-  /* Check this first so counter will always be zero on any early failures. */
-  size_t mcount = 0, dcount = 0;
-  if (unlikely(flags & MDBX_MULTIPLE)) {
-    if (unlikely(flags & MDBX_RESERVE))
-      return MDBX_EINVAL;
-    if (unlikely(!F_ISSET(mc->mc_db->md_flags, MDBX_DUPFIXED)))
-      return MDBX_INCOMPATIBLE;
-    dcount = data[1].iov_len;
-    if (unlikely(dcount < 2 || data->iov_len == 0))
-      return MDBX_BAD_VALSIZE;
-    if (unlikely(mc->mc_db->md_xsize != data->iov_len) && mc->mc_db->md_xsize)
-      return MDBX_BAD_VALSIZE;
-    if (unlikely(dcount > MAX_MAPSIZE / 2 /
-                              (BRANCH_NODE_MAX(MAX_PAGESIZE) - NODESIZE))) {
-      /* checking for multiplication overflow */
-      if (unlikely(dcount > MAX_MAPSIZE / 2 / data->iov_len))
-        return MDBX_TOO_LARGE;
-    }
-    data[1].iov_len = 0 /* reset done item counter */;
-  }
-
-  if (flags & MDBX_RESERVE) {
-    if (unlikely(mc->mc_db->md_flags & (MDBX_DUPSORT | MDBX_REVERSEDUP |
-                                        MDBX_INTEGERDUP | MDBX_DUPFIXED)))
-      return MDBX_INCOMPATIBLE;
-    data->iov_base = nullptr;
-  }
-
-  const unsigned nospill = flags & MDBX_NOSPILL;
-  flags -= nospill;
-
-  if (unlikely(mc->mc_txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
-    return (mc->mc_txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS
-                                                    : MDBX_BAD_TXN;
-
-  uint64_t aligned_keybytes, aligned_databytes;
-  MDBX_val aligned_key, aligned_data;
-  if (likely((mc->mc_flags & C_SUB) == 0)) {
-    if (unlikely(key->iov_len < mc->mc_dbx->md_klen_min ||
-                 key->iov_len > mc->mc_dbx->md_klen_max)) {
-      mdbx_cassert(mc, !"Invalid key-size");
-      return MDBX_BAD_VALSIZE;
-    }
-    if (unlikely(data->iov_len < mc->mc_dbx->md_vlen_min ||
-                 data->iov_len > mc->mc_dbx->md_vlen_max)) {
-      mdbx_cassert(mc, !"Invalid data-size");
-      return MDBX_BAD_VALSIZE;
-    }
-
-    if (mc->mc_db->md_flags & MDBX_INTEGERKEY) {
-      switch (key->iov_len) {
-      default:
-        mdbx_cassert(mc, !"key-size is invalid for MDBX_INTEGERKEY");
-        return MDBX_BAD_VALSIZE;
-      case 4:
-        if (unlikely(3 & (uintptr_t)key->iov_base)) {
-          /* copy instead of return error to avoid break compatibility */
-          aligned_key.iov_base =
-              memcpy(&aligned_keybytes, key->iov_base, aligned_key.iov_len = 4);
-          key = &aligned_key;
-        }
-        break;
-      case 8:
-        if (unlikely(7 & (uintptr_t)key->iov_base)) {
-          /* copy instead of return error to avoid break compatibility */
-          aligned_key.iov_base =
-              memcpy(&aligned_keybytes, key->iov_base, aligned_key.iov_len = 8);
-          key = &aligned_key;
-        }
-        break;
-      }
-    }
-    if (mc->mc_db->md_flags & MDBX_INTEGERDUP) {
-      switch (data->iov_len) {
-      default:
-        mdbx_cassert(mc, !"data-size is invalid for MDBX_INTEGERKEY");
-        return MDBX_BAD_VALSIZE;
-      case 4:
-        if (unlikely(3 & (uintptr_t)data->iov_base)) {
-          if (unlikely(flags & MDBX_MULTIPLE))
-            return MDBX_BAD_VALSIZE;
-          /* copy instead of return error to avoid break compatibility */
-          aligned_data.iov_base = memcpy(&aligned_databytes, data->iov_base,
-                                         aligned_data.iov_len = 4);
-          data = &aligned_data;
-        }
-        break;
-      case 8:
-        if (unlikely(7 & (uintptr_t)data->iov_base)) {
-          if (unlikely(flags & MDBX_MULTIPLE))
-            return MDBX_BAD_VALSIZE;
-          /* copy instead of return error to avoid break compatibility */
-          aligned_data.iov_base = memcpy(&aligned_databytes, data->iov_base,
-                                         aligned_data.iov_len = 8);
-          data = &aligned_data;
-        }
-        break;
-      }
-    }
-  }
-
-  mdbx_debug(
-      "==> put db %d key [%s], size %" PRIuPTR ", data [%s] size %" PRIuPTR,
-      DDBI(mc), DKEY_DEBUG(key), key->iov_len,
-      DVAL_DEBUG((flags & MDBX_RESERVE) ? nullptr : data), data->iov_len);
-
-  int dupdata_flag = 0;
-  if ((flags & MDBX_CURRENT) != 0 && (mc->mc_flags & C_SUB) == 0) {
-    if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE)))
-      return MDBX_EINVAL;
-    /* Опция MDBX_CURRENT означает, что запрошено обновление текущей записи,
-     * на которой сейчас стоит курсор. Проверяем что переданный ключ совпадает
-     * со значением в текущей позиции курсора.
-     * Здесь проще вызвать mdbx_cursor_get(), так как для обслуживания таблиц
-     * с MDBX_DUPSORT также требуется текущий размер данных. */
-    MDBX_val current_key, current_data;
-    rc = mdbx_cursor_get(mc, &current_key, &current_data, MDBX_GET_CURRENT);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    if (mc->mc_dbx->md_cmp(key, &current_key) != 0)
-      return MDBX_EKEYMISMATCH;
-
-    if (unlikely((flags & MDBX_MULTIPLE)))
-      goto drop_current;
-
-    if (F_ISSET(mc->mc_db->md_flags, MDBX_DUPSORT)) {
-      MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-      if (F_ISSET(node_flags(node), F_DUPDATA)) {
-        mdbx_cassert(mc,
-                     mc->mc_xcursor != NULL &&
-                         (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED));
-        /* Если за ключом более одного значения, либо если размер данных
-         * отличается, то вместо обновления требуется удаление и
-         * последующая вставка. */
-        if (mc->mc_xcursor->mx_db.md_entries > 1 ||
-            current_data.iov_len != data->iov_len) {
-        drop_current:
-          rc = mdbx_cursor_del(mc, flags & MDBX_ALLDUPS);
-          if (unlikely(rc != MDBX_SUCCESS))
-            return rc;
-          flags -= MDBX_CURRENT;
-          goto skip_check_samedata;
-        }
-      } else if (unlikely(node_size(key, data) > env->me_leaf_nodemax)) {
-        rc = mdbx_cursor_del(mc, 0);
-        if (unlikely(rc != MDBX_SUCCESS))
-          return rc;
-        flags -= MDBX_CURRENT;
-        goto skip_check_samedata;
-      }
-    }
-    if (!(flags & MDBX_RESERVE) &&
-        unlikely(cmp_lenfast(&current_data, data) == 0))
-      return MDBX_SUCCESS /* the same data, nothing to update */;
-  skip_check_samedata:;
-  }
-
-  if (mc->mc_db->md_root == P_INVALID) {
-    /* new database, cursor has nothing to point to */
-    mc->mc_snum = 0;
-    mc->mc_top = 0;
-    mc->mc_flags &= ~C_INITIALIZED;
-    rc = MDBX_NO_ROOT;
-  } else if ((flags & MDBX_CURRENT) == 0) {
-    bool exact = false;
-    if ((flags & MDBX_APPEND) && mc->mc_db->md_entries > 0) {
-      rc = mdbx_cursor_last(mc, &dkey, &olddata);
-      if (likely(rc == MDBX_SUCCESS)) {
-        rc = mc->mc_dbx->md_cmp(key, &dkey);
-        if (likely(rc > 0)) {
-          mc->mc_ki[mc->mc_top]++; /* step forward for appending */
-          rc = MDBX_NOTFOUND;
-        } else {
-          if (unlikely(rc != MDBX_SUCCESS || !(flags & MDBX_APPENDDUP)))
-            /* new-key < last-key
-             * or new-key == last-key without MDBX_APPENDDUP */
-            return MDBX_EKEYMISMATCH;
-          exact = true;
-        }
-      }
-    } else {
-      struct cursor_set_result csr =
-          /* olddata may not be updated in case LEAF2-page of dupfixed-subDB */
-          mdbx_cursor_set(mc, (MDBX_val *)key, &olddata, MDBX_SET);
-      rc = csr.err;
-      exact = csr.exact;
-    }
-    if (likely(rc == MDBX_SUCCESS)) {
-      if (exact) {
-        if (unlikely(flags & MDBX_NOOVERWRITE)) {
-          mdbx_debug("duplicate key [%s]", DKEY_DEBUG(key));
-          *data = olddata;
-          return MDBX_KEYEXIST;
-        }
-        if (unlikely(mc->mc_flags & C_SUB)) {
-          /* nested subtree of DUPSORT-database with the same key,
-           * nothing to update */
-          mdbx_assert(env, data->iov_len == 0 &&
-                               (olddata.iov_len == 0 ||
-                                /* olddata may not be updated in case LEAF2-page
-                                   of dupfixed-subDB */
-                                (mc->mc_db->md_flags & MDBX_DUPFIXED)));
-          return MDBX_SUCCESS;
-        }
-        if (unlikely(flags & MDBX_ALLDUPS) && mc->mc_xcursor &&
-            (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
-          rc = mdbx_cursor_del(mc, MDBX_ALLDUPS);
-          if (unlikely(rc != MDBX_SUCCESS))
-            return rc;
-          flags -= MDBX_ALLDUPS;
-          rc = MDBX_NOTFOUND;
-          exact = false;
-        } else /* checking for early exit without dirtying pages */
-          if (!(flags & (MDBX_RESERVE | MDBX_MULTIPLE)) &&
-              unlikely(mc->mc_dbx->md_dcmp(data, &olddata) == 0)) {
-            if (!mc->mc_xcursor)
-              /* the same data, nothing to update */
-              return MDBX_SUCCESS;
-            if (flags & MDBX_NODUPDATA)
-              return MDBX_KEYEXIST;
-            if (flags & MDBX_APPENDDUP)
-              return MDBX_EKEYMISMATCH;
-            if (likely(unsure_equal(mc->mc_dbx->md_dcmp, data, &olddata)))
-              /* data is match exactly byte-to-byte, nothing to update */
-              return MDBX_SUCCESS;
-            else {
-              /* The data has differences, but the user-provided comparator
-               * considers them equal. So continue update since called without.
-               * Continue to update since was called without MDBX_NODUPDATA. */
-            }
-          }
-      }
-    } else if (unlikely(rc != MDBX_NOTFOUND))
-      return rc;
-  }
-
-  mc->mc_flags &= ~C_DEL;
-
-  /* Cursor is positioned, check for room in the dirty list */
-  if (!nospill) {
-    rdata = data;
-    if (unlikely(flags & MDBX_MULTIPLE)) {
-      rdata = &xdata;
-      xdata.iov_len = data->iov_len * dcount;
-    }
-    if (unlikely(err = mdbx_cursor_spill(mc, key, rdata)))
-      return err;
-  }
-
-  if (unlikely(rc == MDBX_NO_ROOT)) {
-    /* new database, write a root leaf page */
-    mdbx_debug("%s", "allocating new root leaf page");
-    if (unlikely((*mc->mc_dbistate & DBI_DIRTY) == 0)) {
-      err = mdbx_touch_dbi(mc);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-    }
-    struct page_result npr = mdbx_page_new(mc, P_LEAF, 1);
-    if (unlikely(npr.err != MDBX_SUCCESS))
-      return npr.err;
-    npr.err = mdbx_cursor_push(mc, npr.page);
-    if (unlikely(npr.err != MDBX_SUCCESS))
-      return npr.err;
-    mc->mc_db->md_root = npr.page->mp_pgno;
-    mc->mc_db->md_depth++;
-    if (mc->mc_db->md_flags & MDBX_INTEGERKEY) {
-      assert(key->iov_len >= mc->mc_dbx->md_klen_min &&
-             key->iov_len <= mc->mc_dbx->md_klen_max);
-      mc->mc_dbx->md_klen_min = mc->mc_dbx->md_klen_max = key->iov_len;
-    }
-    if (mc->mc_db->md_flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) {
-      assert(data->iov_len >= mc->mc_dbx->md_vlen_min &&
-             data->iov_len <= mc->mc_dbx->md_vlen_max);
-      assert(mc->mc_xcursor != NULL);
-      mc->mc_db->md_xsize = mc->mc_xcursor->mx_db.md_xsize =
-          (unsigned)(mc->mc_dbx->md_vlen_min = mc->mc_dbx->md_vlen_max =
-                         mc->mc_xcursor->mx_dbx.md_klen_min =
-                             mc->mc_xcursor->mx_dbx.md_klen_max =
-                                 data->iov_len);
-    }
-    if ((mc->mc_db->md_flags & (MDBX_DUPSORT | MDBX_DUPFIXED)) == MDBX_DUPFIXED)
-      npr.page->mp_flags |= P_LEAF2;
-    mc->mc_flags |= C_INITIALIZED;
-  } else {
-    /* make sure all cursor pages are writable */
-    err = mdbx_cursor_touch(mc);
-    if (unlikely(err))
-      return err;
-  }
-
-  bool insert_key, insert_data, do_sub = false;
-  insert_key = insert_data = (rc != MDBX_SUCCESS);
-  uint16_t fp_flags = P_LEAF;
-  MDBX_page *fp = env->me_pbuf;
-  fp->mp_txnid = mc->mc_txn->mt_front;
-  if (insert_key) {
-    /* The key does not exist */
-    mdbx_debug("inserting key at index %i", mc->mc_ki[mc->mc_top]);
-    if ((mc->mc_db->md_flags & MDBX_DUPSORT) &&
-        node_size(key, data) > env->me_leaf_nodemax) {
-      /* Too big for a node, insert in sub-DB.  Set up an empty
-       * "old sub-page" for prep_subDB to expand to a full page. */
-      fp->mp_leaf2_ksize =
-          (mc->mc_db->md_flags & MDBX_DUPFIXED) ? (uint16_t)data->iov_len : 0;
-      fp->mp_lower = fp->mp_upper = 0;
-      olddata.iov_len = PAGEHDRSZ;
-      goto prep_subDB;
-    }
-  } else {
-    /* there's only a key anyway, so this is a no-op */
-    if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
-      char *ptr;
-      unsigned ksize = mc->mc_db->md_xsize;
-      if (unlikely(key->iov_len != ksize))
-        return MDBX_BAD_VALSIZE;
-      ptr = page_leaf2key(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], ksize);
-      memcpy(ptr, key->iov_base, ksize);
-    fix_parent:
-      /* if overwriting slot 0 of leaf, need to
-       * update branch key if there is a parent page */
-      if (mc->mc_top && !mc->mc_ki[mc->mc_top]) {
-        unsigned dtop = 1;
-        mc->mc_top--;
-        /* slot 0 is always an empty key, find real slot */
-        while (mc->mc_top && !mc->mc_ki[mc->mc_top]) {
-          mc->mc_top--;
-          dtop++;
-        }
-        err = MDBX_SUCCESS;
-        if (mc->mc_ki[mc->mc_top])
-          err = mdbx_update_key(mc, key);
-        mdbx_cassert(mc, mc->mc_top + dtop < UINT16_MAX);
-        mc->mc_top += (uint16_t)dtop;
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-      }
-
-      if (mdbx_audit_enabled()) {
-        err = mdbx_cursor_check(mc, 0);
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-      }
-      return MDBX_SUCCESS;
-    }
-
-  more:;
-    if (mdbx_audit_enabled()) {
-      err = mdbx_cursor_check(mc, 0);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-    }
-    MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-
-    /* Large/Overflow page overwrites need special handling */
-    if (unlikely(F_ISSET(node_flags(node), F_BIGDATA))) {
-      int dpages = (node_size(key, data) > env->me_leaf_nodemax)
-                       ? number_of_ovpages(env, data->iov_len)
-                       : 0;
-
-      const pgno_t pgno = node_largedata_pgno(node);
-      struct page_result pgr = mdbx_page_get_ex(
-          mc, pgno, pp_txnid4chk(mc->mc_pg[mc->mc_top], mc->mc_txn));
-      if (unlikely(pgr.err != MDBX_SUCCESS))
-        return pgr.err;
-      if (unlikely(!IS_OVERFLOW(pgr.page)))
-        return MDBX_CORRUPTED;
-
-      /* Is the ov page from this txn (or a parent) and big enough? */
-      int ovpages = pgr.page->mp_pages;
-      if (!IS_FROZEN(mc->mc_txn, pgr.page) &&
-          (unlikely(mc->mc_flags & C_GCFREEZE)
-               ? (ovpages >= dpages)
-               : (ovpages ==
-                  /* LY: add configurable threshold to keep reserve space */
-                  dpages))) {
-        /* yes, overwrite it. */
-        if (!IS_MODIFIABLE(mc->mc_txn, pgr.page)) {
-          if (IS_SPILLED(mc->mc_txn, pgr.page)) {
-            pgr = /* TODO: avoid search and get txn & spill-index from
-                     page_result */
-                mdbx_page_unspill(mc->mc_txn, pgr.page);
-            if (unlikely(pgr.err))
-              return pgr.err;
-          } else {
-            if (unlikely(!mc->mc_txn->mt_parent)) {
-              mdbx_error(
-                  "Unexpected not frozen/modifiable/spilled but shadowed %s "
-                  "page %" PRIaPGNO " mod-txnid %" PRIaTXN ","
-                  " without parent transaction, current txn %" PRIaTXN
-                  " front %" PRIaTXN,
-                  "overflow/large", pgno, pgr.page->mp_txnid,
-                  mc->mc_txn->mt_txnid, mc->mc_txn->mt_front);
-              return MDBX_PROBLEM;
-            }
-
-            /* It is writable only in a parent txn */
-            MDBX_page *np = mdbx_page_malloc(mc->mc_txn, ovpages);
-            if (unlikely(!np))
-              return MDBX_ENOMEM;
-
-            memcpy(np, pgr.page, PAGEHDRSZ); /* Copy header of page */
-            err = mdbx_page_dirty(mc->mc_txn, pgr.page = np, ovpages);
-            if (unlikely(err != MDBX_SUCCESS))
-              return err;
-
-#if MDBX_ENABLE_PGOP_STAT
-            mc->mc_txn->mt_env->me_lck->mti_pgop_stat.clone.weak += ovpages;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-            mdbx_cassert(mc, mdbx_dirtylist_check(mc->mc_txn));
-          }
-        }
-        node_set_ds(node, data->iov_len);
-        if (F_ISSET(flags, MDBX_RESERVE))
-          data->iov_base = page_data(pgr.page);
-        else
-          memcpy(page_data(pgr.page), data->iov_base, data->iov_len);
-
-        if (mdbx_audit_enabled()) {
-          err = mdbx_cursor_check(mc, 0);
-          if (unlikely(err != MDBX_SUCCESS))
-            return err;
-        }
-        return MDBX_SUCCESS;
-      }
-
-      if ((err = mdbx_page_retire(mc, pgr.page)) != MDBX_SUCCESS)
-        return err;
-    } else {
-      olddata.iov_len = node_ds(node);
-      olddata.iov_base = node_data(node);
-      mdbx_cassert(mc, (char *)olddata.iov_base + olddata.iov_len <=
-                           (char *)(mc->mc_pg[mc->mc_top]) + env->me_psize);
-
-      /* DB has dups? */
-      if (F_ISSET(mc->mc_db->md_flags, MDBX_DUPSORT)) {
-        /* Prepare (sub-)page/sub-DB to accept the new item, if needed.
-         * fp: old sub-page or a header faking it.
-         * mp: new (sub-)page.  offset: growth in page size.
-         * xdata: node data with new page or DB. */
-        unsigned i;
-        size_t offset = 0;
-        MDBX_page *mp = fp = xdata.iov_base = env->me_pbuf;
-        mp->mp_pgno = mc->mc_pg[mc->mc_top]->mp_pgno;
-
-        /* Was a single item before, must convert now */
-        if (!F_ISSET(node_flags(node), F_DUPDATA)) {
-
-          /* does data match? */
-          const int cmp = mc->mc_dbx->md_dcmp(data, &olddata);
-          if ((flags & MDBX_APPENDDUP) && unlikely(cmp <= 0))
-            return MDBX_EKEYMISMATCH;
-          if (cmp == 0) {
-            if (flags & MDBX_NODUPDATA)
-              return MDBX_KEYEXIST;
-            if (likely(unsure_equal(mc->mc_dbx->md_dcmp, data, &olddata))) {
-              /* data is match exactly byte-to-byte, nothing to update */
-              if (unlikely(flags & MDBX_MULTIPLE)) {
-                rc = MDBX_SUCCESS;
-                goto continue_multiple;
-              }
-              return MDBX_SUCCESS;
-            } else {
-              /* The data has differences, but the user-provided comparator
-               * considers them equal. So continue update since called without.
-               * Continue to update since was called without MDBX_NODUPDATA. */
-            }
-            mdbx_cassert(mc, node_size(key, data) <= env->me_leaf_nodemax);
-            goto current;
-          }
-
-          /* Just overwrite the current item */
-          if (flags & MDBX_CURRENT) {
-            mdbx_cassert(mc, node_size(key, data) <= env->me_leaf_nodemax);
-            goto current;
-          }
-
-          /* Back up original data item */
-          memcpy(dkey.iov_base = fp + 1, olddata.iov_base,
-                 dkey.iov_len = olddata.iov_len);
-          dupdata_flag = 1;
-
-          /* Make sub-page header for the dup items, with dummy body */
-          fp->mp_flags = P_LEAF | P_SUBP;
-          fp->mp_lower = 0;
-          xdata.iov_len = PAGEHDRSZ + dkey.iov_len + data->iov_len;
-          if (mc->mc_db->md_flags & MDBX_DUPFIXED) {
-            fp->mp_flags |= P_LEAF2;
-            fp->mp_leaf2_ksize = (uint16_t)data->iov_len;
-            xdata.iov_len += 2 * data->iov_len; /* leave space for 2 more */
-            mdbx_cassert(mc, xdata.iov_len <= env->me_psize);
-          } else {
-            xdata.iov_len += 2 * (sizeof(indx_t) + NODESIZE) +
-                             (dkey.iov_len & 1) + (data->iov_len & 1);
-            mdbx_cassert(mc, xdata.iov_len <= env->me_psize);
-          }
-          fp->mp_upper = (uint16_t)(xdata.iov_len - PAGEHDRSZ);
-          olddata.iov_len = xdata.iov_len; /* pretend olddata is fp */
-        } else if (node_flags(node) & F_SUBDATA) {
-          /* Data is on sub-DB, just store it */
-          flags |= F_DUPDATA | F_SUBDATA;
-          goto put_sub;
-        } else {
-          /* Data is on sub-page */
-          fp = olddata.iov_base;
-          switch (flags) {
-          default:
-            if (!(mc->mc_db->md_flags & MDBX_DUPFIXED)) {
-              offset = node_size(data, nullptr) + sizeof(indx_t);
-              break;
-            }
-            offset = fp->mp_leaf2_ksize;
-            if (page_room(fp) < offset) {
-              offset *= 4; /* space for 4 more */
-              break;
-            }
-            /* FALLTHRU: Big enough MDBX_DUPFIXED sub-page */
-            __fallthrough;
-          case MDBX_CURRENT | MDBX_NODUPDATA:
-          case MDBX_CURRENT:
-            fp->mp_txnid = mc->mc_txn->mt_front;
-            fp->mp_pgno = mp->mp_pgno;
-            mc->mc_xcursor->mx_cursor.mc_pg[0] = fp;
-            flags |= F_DUPDATA;
-            goto put_sub;
-          }
-          xdata.iov_len = olddata.iov_len + offset;
-        }
-
-        fp_flags = fp->mp_flags;
-        if (node_size_len(node_ks(node), xdata.iov_len) >
-            env->me_leaf_nodemax) {
-          /* Too big for a sub-page, convert to sub-DB */
-          fp_flags &= ~P_SUBP;
-        prep_subDB:
-          nested_dupdb.md_xsize = 0;
-          nested_dupdb.md_flags = flags_db2sub(mc->mc_db->md_flags);
-          if (mc->mc_db->md_flags & MDBX_DUPFIXED) {
-            fp_flags |= P_LEAF2;
-            nested_dupdb.md_xsize = fp->mp_leaf2_ksize;
-          }
-          nested_dupdb.md_depth = 1;
-          nested_dupdb.md_branch_pages = 0;
-          nested_dupdb.md_leaf_pages = 1;
-          nested_dupdb.md_overflow_pages = 0;
-          nested_dupdb.md_entries = page_numkeys(fp);
-          xdata.iov_len = sizeof(nested_dupdb);
-          xdata.iov_base = &nested_dupdb;
-          const struct page_result par = mdbx_page_alloc(mc, 1, MDBX_ALLOC_ALL);
-          mp = par.page;
-          if (unlikely(par.err != MDBX_SUCCESS))
-            return par.err;
-          mc->mc_db->md_leaf_pages += 1;
-          mdbx_cassert(mc, env->me_psize > olddata.iov_len);
-          offset = env->me_psize - (unsigned)olddata.iov_len;
-          flags |= F_DUPDATA | F_SUBDATA;
-          nested_dupdb.md_root = mp->mp_pgno;
-          nested_dupdb.md_seq = 0;
-          nested_dupdb.md_mod_txnid = mc->mc_txn->mt_txnid;
-          sub_root = mp;
-        }
-        if (mp != fp) {
-          mp->mp_flags = fp_flags;
-          mp->mp_txnid = mc->mc_txn->mt_front;
-          mp->mp_leaf2_ksize = fp->mp_leaf2_ksize;
-          mp->mp_lower = fp->mp_lower;
-          mdbx_cassert(mc, fp->mp_upper + offset <= UINT16_MAX);
-          mp->mp_upper = (indx_t)(fp->mp_upper + offset);
-          if (unlikely(fp_flags & P_LEAF2)) {
-            memcpy(page_data(mp), page_data(fp),
-                   page_numkeys(fp) * fp->mp_leaf2_ksize);
-          } else {
-            memcpy((char *)mp + mp->mp_upper + PAGEHDRSZ,
-                   (char *)fp + fp->mp_upper + PAGEHDRSZ,
-                   olddata.iov_len - fp->mp_upper - PAGEHDRSZ);
-            memcpy((char *)(&mp->mp_ptrs), (char *)(&fp->mp_ptrs),
-                   page_numkeys(fp) * sizeof(mp->mp_ptrs[0]));
-            for (i = 0; i < page_numkeys(fp); i++) {
-              mdbx_cassert(mc, mp->mp_ptrs[i] + offset <= UINT16_MAX);
-              mp->mp_ptrs[i] += (indx_t)offset;
-            }
-          }
-        }
-
-        rdata = &xdata;
-        flags |= F_DUPDATA;
-        do_sub = true;
-        if (!insert_key)
-          mdbx_node_del(mc, 0);
-        goto new_sub;
-      }
-
-      /* MDBX passes F_SUBDATA in 'flags' to write a DB record */
-      if (unlikely((node_flags(node) ^ flags) & F_SUBDATA))
-        return MDBX_INCOMPATIBLE;
-
-    current:
-      if (data->iov_len == olddata.iov_len) {
-        mdbx_cassert(mc, EVEN(key->iov_len) == EVEN(node_ks(node)));
-        /* same size, just replace it. Note that we could
-         * also reuse this node if the new data is smaller,
-         * but instead we opt to shrink the node in that case. */
-        if (F_ISSET(flags, MDBX_RESERVE))
-          data->iov_base = olddata.iov_base;
-        else if (!(mc->mc_flags & C_SUB))
-          memcpy(olddata.iov_base, data->iov_base, data->iov_len);
-        else {
-          mdbx_cassert(mc, page_numkeys(mc->mc_pg[mc->mc_top]) == 1);
-          mdbx_cassert(mc, PAGETYPE(mc->mc_pg[mc->mc_top]) == P_LEAF);
-          mdbx_cassert(mc, node_ds(node) == 0);
-          mdbx_cassert(mc, node_flags(node) == 0);
-          mdbx_cassert(mc, key->iov_len < UINT16_MAX);
-          node_set_ks(node, key->iov_len);
-          memcpy(node_key(node), key->iov_base, key->iov_len);
-          mdbx_cassert(mc, (char *)node_key(node) + node_ds(node) <
-                               (char *)(mc->mc_pg[mc->mc_top]) + env->me_psize);
-          goto fix_parent;
-        }
-
-        if (mdbx_audit_enabled()) {
-          err = mdbx_cursor_check(mc, 0);
-          if (unlikely(err != MDBX_SUCCESS))
-            return err;
-        }
-        return MDBX_SUCCESS;
-      }
-    }
-    mdbx_node_del(mc, 0);
-  }
-
-  rdata = data;
-
-new_sub:;
-  unsigned nflags = flags & NODE_ADD_FLAGS;
-  size_t nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->iov_len
-                                                 : leaf_size(env, key, rdata);
-  if (page_room(mc->mc_pg[mc->mc_top]) < nsize) {
-    if (!insert_key)
-      nflags |= MDBX_SPLIT_REPLACE;
-    rc = mdbx_page_split(mc, key, rdata, P_INVALID, nflags);
-    if (rc == MDBX_SUCCESS && mdbx_audit_enabled())
-      rc = mdbx_cursor_check(mc, 0);
-  } else {
-    /* There is room already in this leaf page. */
-    if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
-      mdbx_cassert(mc, (nflags & (F_BIGDATA | F_SUBDATA | F_DUPDATA)) == 0 &&
-                           rdata->iov_len == 0);
-      rc = mdbx_node_add_leaf2(mc, mc->mc_ki[mc->mc_top], key);
-    } else
-      rc = mdbx_node_add_leaf(mc, mc->mc_ki[mc->mc_top], key, rdata, nflags);
-    if (likely(rc == 0)) {
-      /* Adjust other cursors pointing to mp */
-      const MDBX_dbi dbi = mc->mc_dbi;
-      const unsigned i = mc->mc_top;
-      MDBX_page *const mp = mc->mc_pg[i];
-      for (MDBX_cursor *m2 = mc->mc_txn->mt_cursors[dbi]; m2;
-           m2 = m2->mc_next) {
-        MDBX_cursor *m3 =
-            (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-        if (m3 == mc || m3->mc_snum < mc->mc_snum || m3->mc_pg[i] != mp)
-          continue;
-        if (m3->mc_ki[i] >= mc->mc_ki[i])
-          m3->mc_ki[i] += insert_key;
-        if (XCURSOR_INITED(m3))
-          XCURSOR_REFRESH(m3, mp, m3->mc_ki[i]);
-      }
-    }
-  }
-
-  if (likely(rc == MDBX_SUCCESS)) {
-    /* Now store the actual data in the child DB. Note that we're
-     * storing the user data in the keys field, so there are strict
-     * size limits on dupdata. The actual data fields of the child
-     * DB are all zero size. */
-    if (do_sub) {
-      int xflags;
-      size_t ecount;
-    put_sub:
-      xdata.iov_len = 0;
-      xdata.iov_base = nullptr;
-      MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-#define SHIFT_MDBX_NODUPDATA_TO_MDBX_NOOVERWRITE 1
-      STATIC_ASSERT(
-          (MDBX_NODUPDATA >> SHIFT_MDBX_NODUPDATA_TO_MDBX_NOOVERWRITE) ==
-          MDBX_NOOVERWRITE);
-      xflags = MDBX_CURRENT | MDBX_NOSPILL |
-               ((flags & MDBX_NODUPDATA) >>
-                SHIFT_MDBX_NODUPDATA_TO_MDBX_NOOVERWRITE);
-      if ((flags & MDBX_CURRENT) == 0) {
-        xflags -= MDBX_CURRENT;
-        err = mdbx_xcursor_init1(mc, node, mc->mc_pg[mc->mc_top]);
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-      }
-      if (sub_root)
-        mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root;
-      /* converted, write the original data first */
-      if (dupdata_flag) {
-        rc = mdbx_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
-        if (unlikely(rc))
-          goto bad_sub;
-        /* we've done our job */
-        dkey.iov_len = 0;
-      }
-      if (!(node_flags(node) & F_SUBDATA) || sub_root) {
-        /* Adjust other cursors pointing to mp */
-        MDBX_cursor *m2;
-        MDBX_xcursor *mx = mc->mc_xcursor;
-        unsigned i = mc->mc_top;
-        MDBX_page *mp = mc->mc_pg[i];
-        const int nkeys = page_numkeys(mp);
-
-        for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2 = m2->mc_next) {
-          if (m2 == mc || m2->mc_snum < mc->mc_snum)
-            continue;
-          if (!(m2->mc_flags & C_INITIALIZED))
-            continue;
-          if (m2->mc_pg[i] == mp) {
-            if (m2->mc_ki[i] == mc->mc_ki[i]) {
-              err = mdbx_xcursor_init2(m2, mx, dupdata_flag);
-              if (unlikely(err != MDBX_SUCCESS))
-                return err;
-            } else if (!insert_key && m2->mc_ki[i] < nkeys) {
-              XCURSOR_REFRESH(m2, mp, m2->mc_ki[i]);
-            }
-          }
-        }
-      }
-      mdbx_cassert(mc, mc->mc_xcursor->mx_db.md_entries < PTRDIFF_MAX);
-      ecount = (size_t)mc->mc_xcursor->mx_db.md_entries;
-#define SHIFT_MDBX_APPENDDUP_TO_MDBX_APPEND 1
-      STATIC_ASSERT((MDBX_APPENDDUP >> SHIFT_MDBX_APPENDDUP_TO_MDBX_APPEND) ==
-                    MDBX_APPEND);
-      xflags |= (flags & MDBX_APPENDDUP) >> SHIFT_MDBX_APPENDDUP_TO_MDBX_APPEND;
-      rc = mdbx_cursor_put(&mc->mc_xcursor->mx_cursor, data, &xdata, xflags);
-      if (flags & F_SUBDATA) {
-        void *db = node_data(node);
-        mc->mc_xcursor->mx_db.md_mod_txnid = mc->mc_txn->mt_txnid;
-        memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDBX_db));
-      }
-      insert_data = (ecount != (size_t)mc->mc_xcursor->mx_db.md_entries);
-    }
-    /* Increment count unless we just replaced an existing item. */
-    if (insert_data)
-      mc->mc_db->md_entries++;
-    if (insert_key) {
-      /* Invalidate txn if we created an empty sub-DB */
-      if (unlikely(rc))
-        goto bad_sub;
-      /* If we succeeded and the key didn't exist before,
-       * make sure the cursor is marked valid. */
-      mc->mc_flags |= C_INITIALIZED;
-    }
-    if (unlikely(flags & MDBX_MULTIPLE)) {
-      if (likely(rc == MDBX_SUCCESS)) {
-      continue_multiple:
-        mcount++;
-        /* let caller know how many succeeded, if any */
-        data[1].iov_len = mcount;
-        if (mcount < dcount) {
-          data[0].iov_base = (char *)data[0].iov_base + data[0].iov_len;
-          insert_key = insert_data = false;
-          goto more;
-        }
-      }
-    }
-    if (rc == MDBX_SUCCESS && mdbx_audit_enabled())
-      rc = mdbx_cursor_check(mc, 0);
-    return rc;
-  bad_sub:
-    if (unlikely(rc == MDBX_KEYEXIST)) {
-      /* should not happen, we deleted that item */
-      mdbx_error("Unexpected %i error while put to nested dupsort's hive", rc);
-      rc = MDBX_PROBLEM;
-    }
-  }
-  mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-  return rc;
-}
-
-int mdbx_cursor_del(MDBX_cursor *mc, MDBX_put_flags_t flags) {
-  if (unlikely(!mc))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  int rc = check_txn_rw(mc->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
-    return MDBX_ENODATA;
-
-  if (unlikely(mc->mc_ki[mc->mc_top] >= page_numkeys(mc->mc_pg[mc->mc_top])))
-    return MDBX_NOTFOUND;
-
-  if (likely((flags & MDBX_NOSPILL) == 0) &&
-      unlikely(rc = mdbx_cursor_spill(mc, NULL, NULL)))
-    return rc;
-
-  rc = mdbx_cursor_touch(mc);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(!IS_LEAF(mp)))
-    return MDBX_CORRUPTED;
-  if (IS_LEAF2(mp)) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely((mc->mc_flags & C_SUB) == 0)) {
-      mdbx_error("unexpected LEAF2-page %" PRIaPGNO "for non-dupsort cursor",
-                 mp->mp_pgno);
-      return MDBX_CORRUPTED;
-    }
-    goto del_key;
-  }
-
-  MDBX_node *node = page_node(mp, mc->mc_ki[mc->mc_top]);
-  if (F_ISSET(node_flags(node), F_DUPDATA)) {
-    if (flags & (MDBX_ALLDUPS | /* for compatibility */ MDBX_NODUPDATA)) {
-      /* mdbx_cursor_del0() will subtract the final entry */
-      mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries - 1;
-      mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
-    } else {
-      if (!F_ISSET(node_flags(node), F_SUBDATA))
-        mc->mc_xcursor->mx_cursor.mc_pg[0] = node_data(node);
-      rc = mdbx_cursor_del(&mc->mc_xcursor->mx_cursor, MDBX_NOSPILL);
-      if (unlikely(rc))
-        return rc;
-      /* If sub-DB still has entries, we're done */
-      if (mc->mc_xcursor->mx_db.md_entries) {
-        if (node_flags(node) & F_SUBDATA) {
-          /* update subDB info */
-          void *db = node_data(node);
-          mc->mc_xcursor->mx_db.md_mod_txnid = mc->mc_txn->mt_txnid;
-          memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDBX_db));
-        } else {
-          MDBX_cursor *m2;
-          /* shrink fake page */
-          mdbx_node_shrink(mp, mc->mc_ki[mc->mc_top]);
-          node = page_node(mp, mc->mc_ki[mc->mc_top]);
-          mc->mc_xcursor->mx_cursor.mc_pg[0] = node_data(node);
-          /* fix other sub-DB cursors pointed at fake pages on this page */
-          for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2 = m2->mc_next) {
-            if (m2 == mc || m2->mc_snum < mc->mc_snum)
-              continue;
-            if (!(m2->mc_flags & C_INITIALIZED))
-              continue;
-            if (m2->mc_pg[mc->mc_top] == mp) {
-              MDBX_node *inner = node;
-              if (m2->mc_ki[mc->mc_top] >= page_numkeys(mp))
-                continue;
-              if (m2->mc_ki[mc->mc_top] != mc->mc_ki[mc->mc_top]) {
-                inner = page_node(mp, m2->mc_ki[mc->mc_top]);
-                if (node_flags(inner) & F_SUBDATA)
-                  continue;
-              }
-              m2->mc_xcursor->mx_cursor.mc_pg[0] = node_data(inner);
-            }
-          }
-        }
-        mc->mc_db->md_entries--;
-        mdbx_cassert(mc, mc->mc_db->md_entries > 0 && mc->mc_db->md_depth > 0 &&
-                             mc->mc_db->md_root != P_INVALID);
-        return rc;
-      } else {
-        mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
-      }
-      /* otherwise fall thru and delete the sub-DB */
-    }
-
-    if (node_flags(node) & F_SUBDATA) {
-      /* add all the child DB's pages to the free list */
-      rc = mdbx_drop_tree(&mc->mc_xcursor->mx_cursor, false);
-      if (unlikely(rc))
-        goto fail;
-    }
-  }
-  /* MDBX passes F_SUBDATA in 'flags' to delete a DB record */
-  else if (unlikely((node_flags(node) ^ flags) & F_SUBDATA))
-    return MDBX_INCOMPATIBLE;
-
-  /* add overflow pages to free list */
-  if (F_ISSET(node_flags(node), F_BIGDATA)) {
-    MDBX_page *omp;
-    if (unlikely((rc = mdbx_page_get(mc, node_largedata_pgno(node), &omp,
-                                     pp_txnid4chk(mp, mc->mc_txn))) ||
-                 (rc = mdbx_page_retire(mc, omp))))
-      goto fail;
-  }
-
-del_key:
-  return mdbx_cursor_del0(mc);
-
-fail:
-  mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-  return rc;
-}
-
-/* Allocate and initialize new pages for a database.
- * Set MDBX_TXN_ERROR on failure.
- *
- * [in] mc a  cursor on the database being added to.
- * [in] flags flags defining what type of page is being allocated.
- * [in] num   the number of pages to allocate. This is usually 1,
- *            unless allocating overflow pages for a large record.
- * [out] mp   Address of a page, or NULL on failure.
- *
- * Returns 0 on success, non-zero on failure. */
-static struct page_result mdbx_page_new(MDBX_cursor *mc, const unsigned flags,
-                                        const unsigned npages) {
-  struct page_result ret = mdbx_page_alloc(mc, npages, MDBX_ALLOC_ALL);
-  if (unlikely(ret.err != MDBX_SUCCESS))
-    return ret;
-
-  mdbx_debug("db %u allocated new page %" PRIaPGNO ", num %u", mc->mc_dbi,
-             ret.page->mp_pgno, npages);
-  ret.page->mp_flags = (uint16_t)flags;
-  ret.page->mp_txnid = mc->mc_txn->mt_front;
-  mdbx_cassert(mc, *mc->mc_dbistate & DBI_DIRTY);
-  mdbx_cassert(mc, mc->mc_txn->mt_flags & MDBX_TXN_DIRTY);
-#if MDBX_ENABLE_PGOP_STAT
-  mc->mc_txn->mt_env->me_lck->mti_pgop_stat.newly.weak += npages;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-  if (likely((flags & P_OVERFLOW) == 0)) {
-    STATIC_ASSERT(P_BRANCH == 1);
-    const bool is_branch = flags & P_BRANCH;
-    ret.page->mp_lower = 0;
-    ret.page->mp_upper = (indx_t)(mc->mc_txn->mt_env->me_psize - PAGEHDRSZ);
-    mc->mc_db->md_branch_pages += is_branch;
-    mc->mc_db->md_leaf_pages += 1 - is_branch;
-    if (unlikely(mc->mc_flags & C_SUB)) {
-      MDBX_db *outer = mdbx_outer_db(mc);
-      outer->md_branch_pages += is_branch;
-      outer->md_leaf_pages += 1 - is_branch;
-    }
-  } else {
-    mc->mc_db->md_overflow_pages += npages;
-    ret.page->mp_pages = npages;
-    mdbx_cassert(mc, !(mc->mc_flags & C_SUB));
-  }
-
-  return ret;
-}
-
-static int __must_check_result mdbx_node_add_leaf2(MDBX_cursor *mc,
-                                                   unsigned indx,
-                                                   const MDBX_val *key) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  DKBUF_DEBUG;
-  mdbx_debug("add to leaf2-%spage %" PRIaPGNO " index %i, "
-             " key size %" PRIuPTR " [%s]",
-             IS_SUBP(mp) ? "sub-" : "", mp->mp_pgno, indx,
-             key ? key->iov_len : 0, DKEY_DEBUG(key));
-
-  mdbx_cassert(mc, key);
-  mdbx_cassert(mc, PAGETYPE(mp) == (P_LEAF | P_LEAF2));
-  const unsigned ksize = mc->mc_db->md_xsize;
-  mdbx_cassert(mc, ksize == key->iov_len);
-  const unsigned nkeys = page_numkeys(mp);
-
-  /* Just using these for counting */
-  const intptr_t lower = mp->mp_lower + sizeof(indx_t);
-  const intptr_t upper = mp->mp_upper - (ksize - sizeof(indx_t));
-  if (unlikely(lower > upper)) {
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return MDBX_PAGE_FULL;
-  }
-  mp->mp_lower = (indx_t)lower;
-  mp->mp_upper = (indx_t)upper;
-
-  char *const ptr = page_leaf2key(mp, indx, ksize);
-  mdbx_cassert(mc, nkeys >= indx);
-  const unsigned diff = nkeys - indx;
-  if (likely(diff > 0))
-    /* Move higher keys up one slot. */
-    memmove(ptr + ksize, ptr, diff * ksize);
-  /* insert new key */
-  memcpy(ptr, key->iov_base, ksize);
-  return MDBX_SUCCESS;
-}
-
-static int __must_check_result mdbx_node_add_branch(MDBX_cursor *mc,
-                                                    unsigned indx,
-                                                    const MDBX_val *key,
-                                                    pgno_t pgno) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  DKBUF_DEBUG;
-  mdbx_debug("add to branch-%spage %" PRIaPGNO " index %i, node-pgno %" PRIaPGNO
-             " key size %" PRIuPTR " [%s]",
-             IS_SUBP(mp) ? "sub-" : "", mp->mp_pgno, indx, pgno,
-             key ? key->iov_len : 0, DKEY_DEBUG(key));
-
-  mdbx_cassert(mc, PAGETYPE(mp) == P_BRANCH);
-  STATIC_ASSERT(NODESIZE % 2 == 0);
-
-  /* Move higher pointers up one slot. */
-  const unsigned nkeys = page_numkeys(mp);
-  mdbx_cassert(mc, nkeys >= indx);
-  for (unsigned i = nkeys; i > indx; --i)
-    mp->mp_ptrs[i] = mp->mp_ptrs[i - 1];
-
-  /* Adjust free space offsets. */
-  const size_t branch_bytes = branch_size(mc->mc_txn->mt_env, key);
-  const intptr_t lower = mp->mp_lower + sizeof(indx_t);
-  const intptr_t upper = mp->mp_upper - (branch_bytes - sizeof(indx_t));
-  if (unlikely(lower > upper)) {
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return MDBX_PAGE_FULL;
-  }
-  mp->mp_lower = (indx_t)lower;
-  mp->mp_ptrs[indx] = mp->mp_upper = (indx_t)upper;
-
-  /* Write the node data. */
-  MDBX_node *node = page_node(mp, indx);
-  node_set_pgno(node, pgno);
-  node_set_flags(node, 0);
-  UNALIGNED_POKE_8(node, MDBX_node, mn_extra, 0);
-  node_set_ks(node, 0);
-  if (likely(key != NULL)) {
-    node_set_ks(node, key->iov_len);
-    memcpy(node_key(node), key->iov_base, key->iov_len);
-  }
-  return MDBX_SUCCESS;
-}
-
-static int __must_check_result mdbx_node_add_leaf(MDBX_cursor *mc,
-                                                  unsigned indx,
-                                                  const MDBX_val *key,
-                                                  MDBX_val *data,
-                                                  unsigned flags) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  DKBUF_DEBUG;
-  mdbx_debug("add to leaf-%spage %" PRIaPGNO " index %i, data size %" PRIuPTR
-             " key size %" PRIuPTR " [%s]",
-             IS_SUBP(mp) ? "sub-" : "", mp->mp_pgno, indx,
-             data ? data->iov_len : 0, key ? key->iov_len : 0, DKEY_DEBUG(key));
-  mdbx_cassert(mc, key != NULL && data != NULL);
-  mdbx_cassert(mc, PAGETYPE(mp) == P_LEAF);
-  mdbx_cassert(mc, page_room(mp) >= leaf_size(mc->mc_txn->mt_env, key, data));
-  MDBX_page *largepage = NULL;
-
-  size_t node_bytes;
-  if (unlikely(flags & F_BIGDATA)) {
-    /* Data already on overflow page. */
-    STATIC_ASSERT(sizeof(pgno_t) % 2 == 0);
-    node_bytes =
-        node_size_len(key->iov_len, 0) + sizeof(pgno_t) + sizeof(indx_t);
-  } else if (unlikely(node_size(key, data) >
-                      mc->mc_txn->mt_env->me_leaf_nodemax)) {
-    /* Put data on overflow page. */
-    if (unlikely(mc->mc_db->md_flags & MDBX_DUPSORT)) {
-      mdbx_error("Unexpected target %s flags 0x%x for large data-item",
-                 "dupsort-db", mc->mc_db->md_flags);
-      return MDBX_PROBLEM;
-    }
-    if (unlikely(flags & (F_DUPDATA | F_SUBDATA))) {
-      mdbx_error("Unexpected target %s flags 0x%x for large data-item", "node",
-                 flags);
-      return MDBX_PROBLEM;
-    }
-    const pgno_t ovpages = number_of_ovpages(mc->mc_txn->mt_env, data->iov_len);
-    const struct page_result npr = mdbx_page_new(mc, P_OVERFLOW, ovpages);
-    if (unlikely(npr.err != MDBX_SUCCESS))
-      return npr.err;
-    largepage = npr.page;
-    mdbx_debug("allocated %u overflow page(s) %" PRIaPGNO "for %" PRIuPTR
-               " data bytes",
-               largepage->mp_pages, largepage->mp_pgno, data->iov_len);
-    flags |= F_BIGDATA;
-    node_bytes =
-        node_size_len(key->iov_len, 0) + sizeof(pgno_t) + sizeof(indx_t);
-  } else {
-    node_bytes = node_size(key, data) + sizeof(indx_t);
-  }
-  mdbx_cassert(mc, node_bytes == leaf_size(mc->mc_txn->mt_env, key, data));
-
-  /* Move higher pointers up one slot. */
-  const unsigned nkeys = page_numkeys(mp);
-  mdbx_cassert(mc, nkeys >= indx);
-  for (unsigned i = nkeys; i > indx; --i)
-    mp->mp_ptrs[i] = mp->mp_ptrs[i - 1];
-
-  /* Adjust free space offsets. */
-  const intptr_t lower = mp->mp_lower + sizeof(indx_t);
-  const intptr_t upper = mp->mp_upper - (node_bytes - sizeof(indx_t));
-  if (unlikely(lower > upper)) {
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return MDBX_PAGE_FULL;
-  }
-  mp->mp_lower = (indx_t)lower;
-  mp->mp_ptrs[indx] = mp->mp_upper = (indx_t)upper;
-
-  /* Write the node data. */
-  MDBX_node *node = page_node(mp, indx);
-  node_set_ks(node, key->iov_len);
-  node_set_flags(node, (uint8_t)flags);
-  UNALIGNED_POKE_8(node, MDBX_node, mn_extra, 0);
-  node_set_ds(node, data->iov_len);
-  memcpy(node_key(node), key->iov_base, key->iov_len);
-
-  void *nodedata = node_data(node);
-  if (likely(largepage == NULL)) {
-    if (unlikely(flags & F_BIGDATA))
-      memcpy(nodedata, data->iov_base, sizeof(pgno_t));
-    else if (unlikely(flags & MDBX_RESERVE))
-      data->iov_base = nodedata;
-    else if (likely(nodedata != data->iov_base &&
-                    data->iov_len /* to avoid UBSAN traps*/ != 0))
-      memcpy(nodedata, data->iov_base, data->iov_len);
-  } else {
-    poke_pgno(nodedata, largepage->mp_pgno);
-    nodedata = page_data(largepage);
-    if (unlikely(flags & MDBX_RESERVE))
-      data->iov_base = nodedata;
-    else if (likely(nodedata != data->iov_base &&
-                    data->iov_len /* to avoid UBSAN traps*/ != 0))
-      memcpy(nodedata, data->iov_base, data->iov_len);
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Delete the specified node from a page.
- * [in] mc Cursor pointing to the node to delete.
- * [in] ksize The size of a node. Only used if the page is
- * part of a MDBX_DUPFIXED database. */
-static void mdbx_node_del(MDBX_cursor *mc, size_t ksize) {
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  int indx = mc->mc_ki[mc->mc_top];
-  int i, j, nkeys, ptr;
-  MDBX_node *node;
-  char *base;
-
-  mdbx_debug("delete node %u on %s page %" PRIaPGNO, indx,
-             IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno);
-  nkeys = page_numkeys(mp);
-  mdbx_cassert(mc, indx < nkeys);
-
-  if (IS_LEAF2(mp)) {
-    mdbx_cassert(mc, ksize >= sizeof(indx_t));
-    unsigned diff = nkeys - 1 - indx;
-    base = page_leaf2key(mp, indx, ksize);
-    if (diff)
-      memmove(base, base + ksize, diff * ksize);
-    mdbx_cassert(mc, mp->mp_lower >= sizeof(indx_t));
-    mp->mp_lower -= sizeof(indx_t);
-    mdbx_cassert(mc,
-                 (size_t)UINT16_MAX - mp->mp_upper >= ksize - sizeof(indx_t));
-    mp->mp_upper += (indx_t)(ksize - sizeof(indx_t));
-    return;
-  }
-
-  node = page_node(mp, indx);
-  mdbx_cassert(mc, !IS_BRANCH(mp) || indx || node_ks(node) == 0);
-  size_t sz = NODESIZE + node_ks(node);
-  if (IS_LEAF(mp)) {
-    if (F_ISSET(node_flags(node), F_BIGDATA))
-      sz += sizeof(pgno_t);
-    else
-      sz += node_ds(node);
-  }
-  sz = EVEN(sz);
-
-  ptr = mp->mp_ptrs[indx];
-  for (i = j = 0; i < nkeys; i++) {
-    if (i != indx) {
-      mp->mp_ptrs[j] = mp->mp_ptrs[i];
-      if (mp->mp_ptrs[i] < ptr) {
-        mdbx_cassert(mc, (size_t)UINT16_MAX - mp->mp_ptrs[j] >= sz);
-        mp->mp_ptrs[j] += (indx_t)sz;
-      }
-      j++;
-    }
-  }
-
-  base = (char *)mp + mp->mp_upper + PAGEHDRSZ;
-  memmove(base + sz, base, ptr - mp->mp_upper);
-
-  mdbx_cassert(mc, mp->mp_lower >= sizeof(indx_t));
-  mp->mp_lower -= sizeof(indx_t);
-  mdbx_cassert(mc, (size_t)UINT16_MAX - mp->mp_upper >= sz);
-  mp->mp_upper += (indx_t)sz;
-
-#if MDBX_DEBUG > 0
-  if (mdbx_audit_enabled()) {
-    int page_check_err = mdbx_page_check(mc, mp, C_UPDATING);
-    mdbx_cassert(mc, page_check_err == MDBX_SUCCESS);
-  }
-#endif
-}
-
-/* Compact the main page after deleting a node on a subpage.
- * [in] mp The main page to operate on.
- * [in] indx The index of the subpage on the main page. */
-static void mdbx_node_shrink(MDBX_page *mp, unsigned indx) {
-  MDBX_node *node;
-  MDBX_page *sp, *xp;
-  char *base;
-  size_t nsize, delta, len, ptr;
-  int i;
-
-  node = page_node(mp, indx);
-  sp = (MDBX_page *)node_data(node);
-  delta = page_room(sp);
-  assert(delta > 0);
-
-  /* Prepare to shift upward, set len = length(subpage part to shift) */
-  if (IS_LEAF2(sp)) {
-    delta &= /* do not make the node uneven-sized */ ~(size_t)1;
-    if (unlikely(delta) == 0)
-      return;
-    nsize = node_ds(node) - delta;
-    assert(nsize % 1 == 0);
-    len = nsize;
-  } else {
-    xp = (MDBX_page *)((char *)sp + delta); /* destination subpage */
-    for (i = page_numkeys(sp); --i >= 0;) {
-      assert(sp->mp_ptrs[i] >= delta);
-      xp->mp_ptrs[i] = (indx_t)(sp->mp_ptrs[i] - delta);
-    }
-    nsize = node_ds(node) - delta;
-    len = PAGEHDRSZ;
-  }
-  sp->mp_upper = sp->mp_lower;
-  sp->mp_pgno = mp->mp_pgno;
-  node_set_ds(node, nsize);
-
-  /* Shift <lower nodes...initial part of subpage> upward */
-  base = (char *)mp + mp->mp_upper + PAGEHDRSZ;
-  memmove(base + delta, base, (char *)sp + len - base);
-
-  ptr = mp->mp_ptrs[indx];
-  for (i = page_numkeys(mp); --i >= 0;) {
-    if (mp->mp_ptrs[i] <= ptr) {
-      assert((size_t)UINT16_MAX - mp->mp_ptrs[i] >= delta);
-      mp->mp_ptrs[i] += (indx_t)delta;
-    }
-  }
-  assert((size_t)UINT16_MAX - mp->mp_upper >= delta);
-  mp->mp_upper += (indx_t)delta;
-}
-
-/* Initial setup of a sorted-dups cursor.
- *
- * Sorted duplicates are implemented as a sub-database for the given key.
- * The duplicate data items are actually keys of the sub-database.
- * Operations on the duplicate data items are performed using a sub-cursor
- * initialized when the sub-database is first accessed. This function does
- * the preliminary setup of the sub-cursor, filling in the fields that
- * depend only on the parent DB.
- *
- * [in] mc The main cursor whose sorted-dups cursor is to be initialized. */
-static int mdbx_xcursor_init0(MDBX_cursor *mc) {
-  MDBX_xcursor *mx = mc->mc_xcursor;
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(mx == nullptr)) {
-    mdbx_error("unexpected dupsort-page for non-dupsort db/cursor (dbi %u)",
-               mc->mc_dbi);
-    return MDBX_CORRUPTED;
-  }
-
-  mx->mx_cursor.mc_xcursor = NULL;
-  mx->mx_cursor.mc_next = NULL;
-  mx->mx_cursor.mc_txn = mc->mc_txn;
-  mx->mx_cursor.mc_db = &mx->mx_db;
-  mx->mx_cursor.mc_dbx = &mx->mx_dbx;
-  mx->mx_cursor.mc_dbi = mc->mc_dbi;
-  mx->mx_cursor.mc_dbistate = mc->mc_dbistate;
-  mx->mx_cursor.mc_snum = 0;
-  mx->mx_cursor.mc_top = 0;
-  mx->mx_cursor.mc_flags = C_SUB | (mc->mc_flags & (C_COPYING | C_SKIPORD));
-  mx->mx_dbx.md_name.iov_len = 0;
-  mx->mx_dbx.md_name.iov_base = NULL;
-  mx->mx_dbx.md_cmp = mc->mc_dbx->md_dcmp;
-  mx->mx_dbx.md_dcmp = NULL;
-  mx->mx_dbx.md_klen_min = INT_MAX;
-  mx->mx_dbx.md_vlen_min = mx->mx_dbx.md_klen_max = mx->mx_dbx.md_vlen_max = 0;
-  return MDBX_SUCCESS;
-}
-
-/* Final setup of a sorted-dups cursor.
- * Sets up the fields that depend on the data from the main cursor.
- * [in] mc The main cursor whose sorted-dups cursor is to be initialized.
- * [in] node The data containing the MDBX_db record for the sorted-dup database.
- */
-static int mdbx_xcursor_init1(MDBX_cursor *mc, MDBX_node *node,
-                              const MDBX_page *mp) {
-  MDBX_xcursor *mx = mc->mc_xcursor;
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(mx == nullptr)) {
-    mdbx_error("unexpected dupsort-page for non-dupsort db/cursor (dbi %u)",
-               mc->mc_dbi);
-    return MDBX_CORRUPTED;
-  }
-
-  const uint8_t flags = node_flags(node);
-  switch (flags) {
-  default:
-    mdbx_error("invalid node flags %u", flags);
-    return MDBX_CORRUPTED;
-  case F_DUPDATA | F_SUBDATA:
-    if (!MDBX_DISABLE_PAGECHECKS &&
-        unlikely(node_ds(node) != sizeof(MDBX_db))) {
-      mdbx_error("invalid nested-db record size %zu", node_ds(node));
-      return MDBX_CORRUPTED;
-    }
-    memcpy(&mx->mx_db, node_data(node), sizeof(MDBX_db));
-    const txnid_t pp_txnid = mp->mp_txnid;
-    if (!MDBX_DISABLE_PAGECHECKS &&
-        unlikely(mx->mx_db.md_mod_txnid > pp_txnid)) {
-      mdbx_error("nested-db.md_mod_txnid (%" PRIaTXN ") > page-txnid (%" PRIaTXN
-                 ")",
-                 mx->mx_db.md_mod_txnid, pp_txnid);
-      return MDBX_CORRUPTED;
-    }
-    mx->mx_cursor.mc_pg[0] = 0;
-    mx->mx_cursor.mc_snum = 0;
-    mx->mx_cursor.mc_top = 0;
-    mx->mx_cursor.mc_flags = C_SUB | (mc->mc_flags & (C_COPYING | C_SKIPORD));
-    break;
-  case F_DUPDATA:
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely(node_ds(node) <= PAGEHDRSZ)) {
-      mdbx_error("invalid nested-page size %zu", node_ds(node));
-      return MDBX_CORRUPTED;
-    }
-    MDBX_page *fp = node_data(node);
-    mx->mx_db.md_depth = 1;
-    mx->mx_db.md_branch_pages = 0;
-    mx->mx_db.md_leaf_pages = 1;
-    mx->mx_db.md_overflow_pages = 0;
-    mx->mx_db.md_entries = page_numkeys(fp);
-    mx->mx_db.md_root = fp->mp_pgno;
-    mx->mx_db.md_mod_txnid = mp->mp_txnid;
-    mx->mx_cursor.mc_snum = 1;
-    mx->mx_cursor.mc_top = 0;
-    mx->mx_cursor.mc_flags =
-        C_INITIALIZED | C_SUB | (mc->mc_flags & (C_COPYING | C_SKIPORD));
-    mx->mx_cursor.mc_pg[0] = fp;
-    mx->mx_cursor.mc_ki[0] = 0;
-    mx->mx_db.md_flags = flags_db2sub(mc->mc_db->md_flags);
-    mx->mx_db.md_xsize =
-        (mc->mc_db->md_flags & MDBX_DUPFIXED) ? fp->mp_leaf2_ksize : 0;
-    break;
-  }
-
-  if (unlikely(mx->mx_db.md_xsize != mc->mc_db->md_xsize)) {
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely(mc->mc_db->md_xsize != 0)) {
-      mdbx_error("cursor mismatched nested-db md_xsize %u",
-                 mc->mc_db->md_xsize);
-      return MDBX_CORRUPTED;
-    }
-    if (!MDBX_DISABLE_PAGECHECKS &&
-        unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0)) {
-      mdbx_error("mismatched nested-db md_flags %u", mc->mc_db->md_flags);
-      return MDBX_CORRUPTED;
-    }
-    if (!MDBX_DISABLE_PAGECHECKS &&
-        unlikely(mx->mx_db.md_xsize < mc->mc_dbx->md_vlen_min ||
-                 mx->mx_db.md_xsize > mc->mc_dbx->md_vlen_max)) {
-      mdbx_error("mismatched nested-db.md_xsize (%u) <> min/max value-length "
-                 "(%zu/%zu)",
-                 mx->mx_db.md_xsize, mc->mc_dbx->md_vlen_min,
-                 mc->mc_dbx->md_vlen_max);
-      return MDBX_CORRUPTED;
-    }
-    mc->mc_db->md_xsize = mx->mx_db.md_xsize;
-    mc->mc_dbx->md_vlen_min = mc->mc_dbx->md_vlen_max = mx->mx_db.md_xsize;
-  }
-  mx->mx_dbx.md_klen_min = mc->mc_dbx->md_vlen_min;
-  mx->mx_dbx.md_klen_max = mc->mc_dbx->md_vlen_max;
-
-  mdbx_debug("Sub-db -%u root page %" PRIaPGNO, mx->mx_cursor.mc_dbi,
-             mx->mx_db.md_root);
-  return MDBX_SUCCESS;
-}
-
-/* Fixup a sorted-dups cursor due to underlying update.
- * Sets up some fields that depend on the data from the main cursor.
- * Almost the same as init1, but skips initialization steps if the
- * xcursor had already been used.
- * [in] mc The main cursor whose sorted-dups cursor is to be fixed up.
- * [in] src_mx The xcursor of an up-to-date cursor.
- * [in] new_dupdata True if converting from a non-F_DUPDATA item. */
-static int mdbx_xcursor_init2(MDBX_cursor *mc, MDBX_xcursor *src_mx,
-                              bool new_dupdata) {
-  MDBX_xcursor *mx = mc->mc_xcursor;
-  if (!MDBX_DISABLE_PAGECHECKS && unlikely(mx == nullptr)) {
-    mdbx_error("unexpected dupsort-page for non-dupsort db/cursor (dbi %u)",
-               mc->mc_dbi);
-    return MDBX_CORRUPTED;
-  }
-
-  if (new_dupdata) {
-    mx->mx_cursor.mc_snum = 1;
-    mx->mx_cursor.mc_top = 0;
-    mx->mx_cursor.mc_flags |= C_INITIALIZED;
-    mx->mx_cursor.mc_ki[0] = 0;
-  }
-
-  mx->mx_dbx.md_klen_min = src_mx->mx_dbx.md_klen_min;
-  mx->mx_dbx.md_klen_max = src_mx->mx_dbx.md_klen_max;
-  mx->mx_dbx.md_cmp = src_mx->mx_dbx.md_cmp;
-  mx->mx_db = src_mx->mx_db;
-  mx->mx_cursor.mc_pg[0] = src_mx->mx_cursor.mc_pg[0];
-  if (mx->mx_cursor.mc_flags & C_INITIALIZED) {
-    mdbx_debug("Sub-db -%u root page %" PRIaPGNO, mx->mx_cursor.mc_dbi,
-               mx->mx_db.md_root);
-  }
-  return MDBX_SUCCESS;
-}
-
-static __inline int mdbx_couple_init(MDBX_cursor_couple *couple,
-                                     const MDBX_dbi dbi, MDBX_txn *const txn,
-                                     MDBX_db *const db, MDBX_dbx *const dbx,
-                                     uint8_t *const dbstate) {
-  couple->outer.mc_signature = MDBX_MC_LIVE;
-  couple->outer.mc_next = NULL;
-  couple->outer.mc_backup = NULL;
-  couple->outer.mc_dbi = dbi;
-  couple->outer.mc_txn = txn;
-  couple->outer.mc_db = db;
-  couple->outer.mc_dbx = dbx;
-  couple->outer.mc_dbistate = dbstate;
-  couple->outer.mc_snum = 0;
-  couple->outer.mc_top = 0;
-  couple->outer.mc_pg[0] = 0;
-  couple->outer.mc_flags = 0;
-  couple->outer.mc_ki[0] = 0;
-  couple->outer.mc_xcursor = NULL;
-
-  int rc = MDBX_SUCCESS;
-  if (unlikely(*couple->outer.mc_dbistate & DBI_STALE)) {
-    rc = mdbx_page_search(&couple->outer, NULL, MDBX_PS_ROOTONLY);
-    rc = (rc != MDBX_NOTFOUND) ? rc : MDBX_SUCCESS;
-  } else if (unlikely(couple->outer.mc_dbx->md_klen_max == 0)) {
-    rc = mdbx_setup_dbx(couple->outer.mc_dbx, couple->outer.mc_db,
-                        txn->mt_env->me_psize);
-  }
-
-  if (couple->outer.mc_db->md_flags & MDBX_DUPSORT) {
-    couple->inner.mx_cursor.mc_signature = MDBX_MC_LIVE;
-    couple->outer.mc_xcursor = &couple->inner;
-    rc = mdbx_xcursor_init0(&couple->outer);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    couple->inner.mx_dbx.md_klen_min = couple->outer.mc_dbx->md_vlen_min;
-    couple->inner.mx_dbx.md_klen_max = couple->outer.mc_dbx->md_vlen_max;
-  }
-  return rc;
-}
-
-/* Initialize a cursor for a given transaction and database. */
-static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi) {
-  STATIC_ASSERT(offsetof(MDBX_cursor_couple, outer) == 0);
-  if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
-    return MDBX_BAD_DBI;
-
-  return mdbx_couple_init(container_of(mc, MDBX_cursor_couple, outer), dbi, txn,
-                          &txn->mt_dbs[dbi], &txn->mt_dbxs[dbi],
-                          &txn->mt_dbistate[dbi]);
-}
-
-MDBX_cursor *mdbx_cursor_create(void *context) {
-  MDBX_cursor_couple *couple = mdbx_calloc(1, sizeof(MDBX_cursor_couple));
-  if (unlikely(!couple))
-    return nullptr;
-
-  couple->outer.mc_signature = MDBX_MC_READY4CLOSE;
-  couple->outer.mc_dbi = UINT_MAX;
-  couple->mc_userctx = context;
-  return &couple->outer;
-}
-
-int mdbx_cursor_set_userctx(MDBX_cursor *mc, void *ctx) {
-  if (unlikely(!mc))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_READY4CLOSE &&
-               mc->mc_signature != MDBX_MC_LIVE))
-    return MDBX_EBADSIGN;
-
-  MDBX_cursor_couple *couple = container_of(mc, MDBX_cursor_couple, outer);
-  couple->mc_userctx = ctx;
-  return MDBX_SUCCESS;
-}
-
-void *mdbx_cursor_get_userctx(const MDBX_cursor *mc) {
-  if (unlikely(!mc))
-    return nullptr;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_READY4CLOSE &&
-               mc->mc_signature != MDBX_MC_LIVE))
-    return nullptr;
-
-  MDBX_cursor_couple *couple = container_of(mc, MDBX_cursor_couple, outer);
-  return couple->mc_userctx;
-}
-
-int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
-  if (unlikely(!mc))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_READY4CLOSE &&
-               mc->mc_signature != MDBX_MC_LIVE))
-    return MDBX_EBADSIGN;
-
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_VALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
-    return MDBX_EACCESS;
-
-  if (unlikely(mc->mc_backup)) /* Cursor from parent transaction */ {
-    mdbx_cassert(mc, mc->mc_signature == MDBX_MC_LIVE);
-    if (unlikely(mc->mc_dbi != dbi ||
-                 /* paranoia */ mc->mc_signature != MDBX_MC_LIVE ||
-                 mc->mc_txn != txn))
-      return MDBX_EINVAL;
-
-    assert(mc->mc_db == &txn->mt_dbs[dbi]);
-    assert(mc->mc_dbx == &txn->mt_dbxs[dbi]);
-    assert(mc->mc_dbi == dbi);
-    assert(mc->mc_dbistate == &txn->mt_dbistate[dbi]);
-    return likely(mc->mc_dbi == dbi &&
-                  /* paranoia */ mc->mc_signature == MDBX_MC_LIVE &&
-                  mc->mc_txn == txn)
-               ? MDBX_SUCCESS
-               : MDBX_EINVAL /* Disallow change DBI in nested transactions */;
-  }
-
-  if (mc->mc_signature == MDBX_MC_LIVE) {
-    if (unlikely(!mc->mc_txn ||
-                 mc->mc_txn->mt_signature != MDBX_MT_SIGNATURE)) {
-      mdbx_error("Wrong cursor's transaction %p 0x%x",
-                 __Wpedantic_format_voidptr(mc->mc_txn),
-                 mc->mc_txn ? mc->mc_txn->mt_signature : 0);
-      return MDBX_PROBLEM;
-    }
-    if (mc->mc_flags & C_UNTRACK) {
-      MDBX_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
-      while (*prev && *prev != mc)
-        prev = &(*prev)->mc_next;
-      mdbx_cassert(mc, *prev == mc);
-      *prev = mc->mc_next;
-    }
-    mc->mc_signature = MDBX_MC_READY4CLOSE;
-    mc->mc_flags = 0;
-    mc->mc_dbi = UINT_MAX;
-    mc->mc_next = NULL;
-    mc->mc_db = NULL;
-    mc->mc_dbx = NULL;
-    mc->mc_dbistate = NULL;
-  }
-  mdbx_cassert(mc, !(mc->mc_flags & C_UNTRACK));
-
-  rc = mdbx_cursor_init(mc, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  mc->mc_next = txn->mt_cursors[dbi];
-  txn->mt_cursors[dbi] = mc;
-  mc->mc_flags |= C_UNTRACK;
-
-  return MDBX_SUCCESS;
-}
-
-int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
-  if (unlikely(!ret))
-    return MDBX_EINVAL;
-  *ret = NULL;
-
-  MDBX_cursor *const mc = mdbx_cursor_create(nullptr);
-  if (unlikely(!mc))
-    return MDBX_ENOMEM;
-
-  int rc = mdbx_cursor_bind(txn, mc, dbi);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    mdbx_cursor_close(mc);
-    return rc;
-  }
-
-  *ret = mc;
-  return MDBX_SUCCESS;
-}
-
-int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
-  return likely(mc) ? mdbx_cursor_bind(txn, mc, mc->mc_dbi) : MDBX_EINVAL;
-}
-
-int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest) {
-  if (unlikely(!src))
-    return MDBX_EINVAL;
-  if (unlikely(src->mc_signature != MDBX_MC_LIVE))
-    return (src->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                      : MDBX_EBADSIGN;
-
-  int rc = mdbx_cursor_bind(src->mc_txn, dest, src->mc_dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  assert(dest->mc_db == src->mc_db);
-  assert(dest->mc_dbi == src->mc_dbi);
-  assert(dest->mc_dbx == src->mc_dbx);
-  assert(dest->mc_dbistate == src->mc_dbistate);
-again:
-  assert(dest->mc_txn == src->mc_txn);
-  dest->mc_flags ^= (dest->mc_flags ^ src->mc_flags) & ~C_UNTRACK;
-  dest->mc_top = src->mc_top;
-  dest->mc_snum = src->mc_snum;
-  for (unsigned i = 0; i < src->mc_snum; ++i) {
-    dest->mc_ki[i] = src->mc_ki[i];
-    dest->mc_pg[i] = src->mc_pg[i];
-  }
-
-  if (src->mc_xcursor) {
-    dest->mc_xcursor->mx_db = src->mc_xcursor->mx_db;
-    dest->mc_xcursor->mx_dbx = src->mc_xcursor->mx_dbx;
-    src = &src->mc_xcursor->mx_cursor;
-    dest = &dest->mc_xcursor->mx_cursor;
-    goto again;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-void mdbx_cursor_close(MDBX_cursor *mc) {
-  if (likely(mc)) {
-    mdbx_ensure(NULL, mc->mc_signature == MDBX_MC_LIVE ||
-                          mc->mc_signature == MDBX_MC_READY4CLOSE);
-    MDBX_txn *const txn = mc->mc_txn;
-    if (!mc->mc_backup) {
-      mc->mc_txn = NULL;
-      /* Unlink from txn, if tracked. */
-      if (mc->mc_flags & C_UNTRACK) {
-        mdbx_ensure(txn->mt_env, check_txn(txn, 0) == MDBX_SUCCESS);
-        MDBX_cursor **prev = &txn->mt_cursors[mc->mc_dbi];
-        while (*prev && *prev != mc)
-          prev = &(*prev)->mc_next;
-        mdbx_tassert(txn, *prev == mc);
-        *prev = mc->mc_next;
-      }
-      mc->mc_signature = 0;
-      mc->mc_next = mc;
-      mdbx_free(mc);
-    } else {
-      /* Cursor closed before nested txn ends */
-      mdbx_tassert(txn, mc->mc_signature == MDBX_MC_LIVE);
-      mdbx_ensure(txn->mt_env, check_txn_rw(txn, 0) == MDBX_SUCCESS);
-      mc->mc_signature = MDBX_MC_WAIT4EOT;
-    }
-  }
-}
-
-MDBX_txn *mdbx_cursor_txn(const MDBX_cursor *mc) {
-  if (unlikely(!mc || mc->mc_signature != MDBX_MC_LIVE))
-    return NULL;
-  MDBX_txn *txn = mc->mc_txn;
-  if (unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE))
-    return NULL;
-  if (unlikely(txn->mt_flags & MDBX_TXN_FINISHED))
-    return NULL;
-  return txn;
-}
-
-MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *mc) {
-  if (unlikely(!mc || mc->mc_signature != MDBX_MC_LIVE))
-    return UINT_MAX;
-  return mc->mc_dbi;
-}
-
-/* Return the count of duplicate data items for the current key */
-int mdbx_cursor_count(const MDBX_cursor *mc, size_t *countp) {
-  if (unlikely(mc == NULL))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  int rc = check_txn(mc->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(countp == NULL || !(mc->mc_flags & C_INITIALIZED)))
-    return MDBX_EINVAL;
-
-  if (!mc->mc_snum) {
-    *countp = 0;
-    return MDBX_NOTFOUND;
-  }
-
-  MDBX_page *mp = mc->mc_pg[mc->mc_top];
-  if ((mc->mc_flags & C_EOF) && mc->mc_ki[mc->mc_top] >= page_numkeys(mp)) {
-    *countp = 0;
-    return MDBX_NOTFOUND;
-  }
-
-  *countp = 1;
-  if (mc->mc_xcursor != NULL) {
-    MDBX_node *node = page_node(mp, mc->mc_ki[mc->mc_top]);
-    if (F_ISSET(node_flags(node), F_DUPDATA)) {
-      mdbx_cassert(mc, mc->mc_xcursor && (mc->mc_xcursor->mx_cursor.mc_flags &
-                                          C_INITIALIZED));
-      *countp = unlikely(mc->mc_xcursor->mx_db.md_entries > PTRDIFF_MAX)
-                    ? PTRDIFF_MAX
-                    : (size_t)mc->mc_xcursor->mx_db.md_entries;
-    }
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Replace the key for a branch node with a new key.
- * Set MDBX_TXN_ERROR on failure.
- * [in] mc Cursor pointing to the node to operate on.
- * [in] key The new key to use.
- * Returns 0 on success, non-zero on failure. */
-static int mdbx_update_key(MDBX_cursor *mc, const MDBX_val *key) {
-  MDBX_page *mp;
-  MDBX_node *node;
-  char *base;
-  size_t len;
-  int delta, ksize, oksize;
-  int ptr, i, nkeys, indx;
-  DKBUF_DEBUG;
-
-  mdbx_cassert(mc, cursor_is_tracked(mc));
-  indx = mc->mc_ki[mc->mc_top];
-  mp = mc->mc_pg[mc->mc_top];
-  node = page_node(mp, indx);
-  ptr = mp->mp_ptrs[indx];
-#if MDBX_DEBUG
-  MDBX_val k2;
-  k2.iov_base = node_key(node);
-  k2.iov_len = node_ks(node);
-  mdbx_debug("update key %u (offset %u) [%s] to [%s] on page %" PRIaPGNO, indx,
-             ptr, DVAL_DEBUG(&k2), DKEY_DEBUG(key), mp->mp_pgno);
-#endif /* MDBX_DEBUG */
-
-  /* Sizes must be 2-byte aligned. */
-  ksize = EVEN(key->iov_len);
-  oksize = EVEN(node_ks(node));
-  delta = ksize - oksize;
-
-  /* Shift node contents if EVEN(key length) changed. */
-  if (delta) {
-    if (delta > (int)page_room(mp)) {
-      /* not enough space left, do a delete and split */
-      mdbx_debug("Not enough room, delta = %d, splitting...", delta);
-      pgno_t pgno = node_pgno(node);
-      mdbx_node_del(mc, 0);
-      int rc = mdbx_page_split(mc, key, NULL, pgno, MDBX_SPLIT_REPLACE);
-      if (rc == MDBX_SUCCESS && mdbx_audit_enabled())
-        rc = mdbx_cursor_check(mc, C_UPDATING);
-      return rc;
-    }
-
-    nkeys = page_numkeys(mp);
-    for (i = 0; i < nkeys; i++) {
-      if (mp->mp_ptrs[i] <= ptr) {
-        mdbx_cassert(mc, mp->mp_ptrs[i] >= delta);
-        mp->mp_ptrs[i] -= (indx_t)delta;
-      }
-    }
-
-    base = (char *)mp + mp->mp_upper + PAGEHDRSZ;
-    len = ptr - mp->mp_upper + NODESIZE;
-    memmove(base - delta, base, len);
-    mdbx_cassert(mc, mp->mp_upper >= delta);
-    mp->mp_upper -= (indx_t)delta;
-
-    node = page_node(mp, indx);
-  }
-
-  /* But even if no shift was needed, update ksize */
-  node_set_ks(node, key->iov_len);
-
-  if (likely(key->iov_len /* to avoid UBSAN traps*/ != 0))
-    memcpy(node_key(node), key->iov_base, key->iov_len);
-  return MDBX_SUCCESS;
-}
-
-/* Move a node from csrc to cdst. */
-static int mdbx_node_move(MDBX_cursor *csrc, MDBX_cursor *cdst, bool fromleft) {
-  int rc;
-  DKBUF_DEBUG;
-
-  MDBX_page *psrc = csrc->mc_pg[csrc->mc_top];
-  MDBX_page *pdst = cdst->mc_pg[cdst->mc_top];
-  mdbx_cassert(csrc, PAGETYPE(psrc) == PAGETYPE(pdst));
-  mdbx_cassert(csrc, csrc->mc_dbi == cdst->mc_dbi);
-  mdbx_cassert(csrc, csrc->mc_top == cdst->mc_top);
-  if (unlikely(PAGETYPE(psrc) != PAGETYPE(pdst))) {
-  bailout:
-    mdbx_error("Wrong or mismatch pages's types (src %d, dst %d) to move node",
-               PAGETYPE(psrc), PAGETYPE(pdst));
-    csrc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-    return MDBX_PROBLEM;
-  }
-
-  MDBX_val key4move;
-  switch (PAGETYPE(psrc)) {
-  case P_BRANCH: {
-    const MDBX_node *srcnode = page_node(psrc, csrc->mc_ki[csrc->mc_top]);
-    mdbx_cassert(csrc, node_flags(srcnode) == 0);
-    const pgno_t srcpg = node_pgno(srcnode);
-    key4move.iov_len = node_ks(srcnode);
-    key4move.iov_base = node_key(srcnode);
-
-    if (csrc->mc_ki[csrc->mc_top] == 0) {
-      const unsigned snum = csrc->mc_snum;
-      mdbx_cassert(csrc, snum > 0);
-      /* must find the lowest key below src */
-      rc = mdbx_page_search_lowest(csrc);
-      MDBX_page *lowest_page = csrc->mc_pg[csrc->mc_top];
-      if (unlikely(rc))
-        return rc;
-      mdbx_cassert(csrc, IS_LEAF(lowest_page));
-      if (unlikely(!IS_LEAF(lowest_page)))
-        goto bailout;
-      if (IS_LEAF2(lowest_page)) {
-        key4move.iov_len = csrc->mc_db->md_xsize;
-        key4move.iov_base = page_leaf2key(lowest_page, 0, key4move.iov_len);
-      } else {
-        const MDBX_node *lowest_node = page_node(lowest_page, 0);
-        key4move.iov_len = node_ks(lowest_node);
-        key4move.iov_base = node_key(lowest_node);
-      }
-
-      /* restore cursor after mdbx_page_search_lowest() */
-      csrc->mc_snum = snum;
-      csrc->mc_top = snum - 1;
-      csrc->mc_ki[csrc->mc_top] = 0;
-
-      /* paranoia */
-      mdbx_cassert(csrc, psrc == csrc->mc_pg[csrc->mc_top]);
-      mdbx_cassert(csrc, IS_BRANCH(psrc));
-      if (unlikely(!IS_BRANCH(psrc)))
-        goto bailout;
-    }
-
-    if (cdst->mc_ki[cdst->mc_top] == 0) {
-      const unsigned snum = cdst->mc_snum;
-      mdbx_cassert(csrc, snum > 0);
-      MDBX_cursor mn;
-      cursor_copy(cdst, &mn);
-      /* must find the lowest key below dst */
-      rc = mdbx_page_search_lowest(&mn);
-      if (unlikely(rc))
-        return rc;
-      MDBX_page *const lowest_page = mn.mc_pg[mn.mc_top];
-      mdbx_cassert(cdst, IS_LEAF(lowest_page));
-      if (unlikely(!IS_LEAF(lowest_page)))
-        goto bailout;
-      MDBX_val key;
-      if (IS_LEAF2(lowest_page)) {
-        key.iov_len = mn.mc_db->md_xsize;
-        key.iov_base = page_leaf2key(lowest_page, 0, key.iov_len);
-      } else {
-        MDBX_node *lowest_node = page_node(lowest_page, 0);
-        key.iov_len = node_ks(lowest_node);
-        key.iov_base = node_key(lowest_node);
-      }
-
-      /* restore cursor after mdbx_page_search_lowest() */
-      mn.mc_snum = snum;
-      mn.mc_top = snum - 1;
-      mn.mc_ki[mn.mc_top] = 0;
-
-      const intptr_t delta =
-          EVEN(key.iov_len) - EVEN(node_ks(page_node(mn.mc_pg[mn.mc_top], 0)));
-      const intptr_t needed =
-          branch_size(cdst->mc_txn->mt_env, &key4move) + delta;
-      const intptr_t have = page_room(pdst);
-      if (unlikely(needed > have))
-        return MDBX_RESULT_TRUE;
-
-      if (unlikely((rc = mdbx_page_touch(csrc)) ||
-                   (rc = mdbx_page_touch(cdst))))
-        return rc;
-      psrc = csrc->mc_pg[csrc->mc_top];
-      pdst = cdst->mc_pg[cdst->mc_top];
-
-      WITH_CURSOR_TRACKING(mn, rc = mdbx_update_key(&mn, &key));
-      if (unlikely(rc))
-        return rc;
-    } else {
-      const size_t needed = branch_size(cdst->mc_txn->mt_env, &key4move);
-      const size_t have = page_room(pdst);
-      if (unlikely(needed > have))
-        return MDBX_RESULT_TRUE;
-
-      if (unlikely((rc = mdbx_page_touch(csrc)) ||
-                   (rc = mdbx_page_touch(cdst))))
-        return rc;
-      psrc = csrc->mc_pg[csrc->mc_top];
-      pdst = cdst->mc_pg[cdst->mc_top];
-    }
-
-    mdbx_debug("moving %s-node %u [%s] on page %" PRIaPGNO
-               " to node %u on page %" PRIaPGNO,
-               "branch", csrc->mc_ki[csrc->mc_top], DKEY_DEBUG(&key4move),
-               psrc->mp_pgno, cdst->mc_ki[cdst->mc_top], pdst->mp_pgno);
-    /* Add the node to the destination page. */
-    rc =
-        mdbx_node_add_branch(cdst, cdst->mc_ki[cdst->mc_top], &key4move, srcpg);
-  } break;
-
-  case P_LEAF: {
-    /* Mark src and dst as dirty. */
-    if (unlikely((rc = mdbx_page_touch(csrc)) || (rc = mdbx_page_touch(cdst))))
-      return rc;
-    psrc = csrc->mc_pg[csrc->mc_top];
-    pdst = cdst->mc_pg[cdst->mc_top];
-    const MDBX_node *srcnode = page_node(psrc, csrc->mc_ki[csrc->mc_top]);
-    MDBX_val data;
-    data.iov_len = node_ds(srcnode);
-    data.iov_base = node_data(srcnode);
-    key4move.iov_len = node_ks(srcnode);
-    key4move.iov_base = node_key(srcnode);
-    mdbx_debug("moving %s-node %u [%s] on page %" PRIaPGNO
-               " to node %u on page %" PRIaPGNO,
-               "leaf", csrc->mc_ki[csrc->mc_top], DKEY_DEBUG(&key4move),
-               psrc->mp_pgno, cdst->mc_ki[cdst->mc_top], pdst->mp_pgno);
-    /* Add the node to the destination page. */
-    rc = mdbx_node_add_leaf(cdst, cdst->mc_ki[cdst->mc_top], &key4move, &data,
-                            node_flags(srcnode));
-  } break;
-
-  case P_LEAF | P_LEAF2: {
-    /* Mark src and dst as dirty. */
-    if (unlikely((rc = mdbx_page_touch(csrc)) || (rc = mdbx_page_touch(cdst))))
-      return rc;
-    psrc = csrc->mc_pg[csrc->mc_top];
-    pdst = cdst->mc_pg[cdst->mc_top];
-    key4move.iov_len = csrc->mc_db->md_xsize;
-    key4move.iov_base =
-        page_leaf2key(psrc, csrc->mc_ki[csrc->mc_top], key4move.iov_len);
-    mdbx_debug("moving %s-node %u [%s] on page %" PRIaPGNO
-               " to node %u on page %" PRIaPGNO,
-               "leaf2", csrc->mc_ki[csrc->mc_top], DKEY_DEBUG(&key4move),
-               psrc->mp_pgno, cdst->mc_ki[cdst->mc_top], pdst->mp_pgno);
-    /* Add the node to the destination page. */
-    rc = mdbx_node_add_leaf2(cdst, cdst->mc_ki[cdst->mc_top], &key4move);
-  } break;
-
-  default:
-    goto bailout;
-  }
-
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  /* Delete the node from the source page. */
-  mdbx_node_del(csrc, key4move.iov_len);
-
-  mdbx_cassert(csrc, psrc == csrc->mc_pg[csrc->mc_top]);
-  mdbx_cassert(cdst, pdst == cdst->mc_pg[cdst->mc_top]);
-  mdbx_cassert(csrc, PAGETYPE(psrc) == PAGETYPE(pdst));
-
-  {
-    /* Adjust other cursors pointing to mp */
-    MDBX_cursor *m2, *m3;
-    const MDBX_dbi dbi = csrc->mc_dbi;
-    mdbx_cassert(csrc, csrc->mc_top == cdst->mc_top);
-    if (fromleft) {
-      /* If we're adding on the left, bump others up */
-      for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) {
-        m3 = (csrc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-        if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top)
-          continue;
-        if (m3 != cdst && m3->mc_pg[csrc->mc_top] == pdst &&
-            m3->mc_ki[csrc->mc_top] >= cdst->mc_ki[csrc->mc_top]) {
-          m3->mc_ki[csrc->mc_top]++;
-        }
-        if (m3 != csrc && m3->mc_pg[csrc->mc_top] == psrc &&
-            m3->mc_ki[csrc->mc_top] == csrc->mc_ki[csrc->mc_top]) {
-          m3->mc_pg[csrc->mc_top] = pdst;
-          m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top];
-          mdbx_cassert(csrc, csrc->mc_top > 0);
-          m3->mc_ki[csrc->mc_top - 1]++;
-        }
-        if (XCURSOR_INITED(m3) && IS_LEAF(psrc))
-          XCURSOR_REFRESH(m3, m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]);
-      }
-    } else {
-      /* Adding on the right, bump others down */
-      for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) {
-        m3 = (csrc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-        if (m3 == csrc)
-          continue;
-        if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top)
-          continue;
-        if (m3->mc_pg[csrc->mc_top] == psrc) {
-          if (!m3->mc_ki[csrc->mc_top]) {
-            m3->mc_pg[csrc->mc_top] = pdst;
-            m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top];
-            mdbx_cassert(csrc, csrc->mc_top > 0);
-            m3->mc_ki[csrc->mc_top - 1]--;
-          } else {
-            m3->mc_ki[csrc->mc_top]--;
-          }
-          if (XCURSOR_INITED(m3) && IS_LEAF(psrc))
-            XCURSOR_REFRESH(m3, m3->mc_pg[csrc->mc_top],
-                            m3->mc_ki[csrc->mc_top]);
-        }
-      }
-    }
-  }
-
-  /* Update the parent separators. */
-  if (csrc->mc_ki[csrc->mc_top] == 0) {
-    mdbx_cassert(csrc, csrc->mc_top > 0);
-    if (csrc->mc_ki[csrc->mc_top - 1] != 0) {
-      MDBX_val key;
-      if (IS_LEAF2(psrc)) {
-        key.iov_len = psrc->mp_leaf2_ksize;
-        key.iov_base = page_leaf2key(psrc, 0, key.iov_len);
-      } else {
-        MDBX_node *srcnode = page_node(psrc, 0);
-        key.iov_len = node_ks(srcnode);
-        key.iov_base = node_key(srcnode);
-      }
-      mdbx_debug("update separator for source page %" PRIaPGNO " to [%s]",
-                 psrc->mp_pgno, DKEY_DEBUG(&key));
-      MDBX_cursor mn;
-      cursor_copy(csrc, &mn);
-      mdbx_cassert(csrc, mn.mc_snum > 0);
-      mn.mc_snum--;
-      mn.mc_top--;
-      /* We want mdbx_rebalance to find mn when doing fixups */
-      WITH_CURSOR_TRACKING(mn, rc = mdbx_update_key(&mn, &key));
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-    }
-    if (IS_BRANCH(psrc)) {
-      const MDBX_val nullkey = {0, 0};
-      const indx_t ix = csrc->mc_ki[csrc->mc_top];
-      csrc->mc_ki[csrc->mc_top] = 0;
-      rc = mdbx_update_key(csrc, &nullkey);
-      csrc->mc_ki[csrc->mc_top] = ix;
-      mdbx_cassert(csrc, rc == MDBX_SUCCESS);
-    }
-  }
-
-  if (cdst->mc_ki[cdst->mc_top] == 0) {
-    mdbx_cassert(cdst, cdst->mc_top > 0);
-    if (cdst->mc_ki[cdst->mc_top - 1] != 0) {
-      MDBX_val key;
-      if (IS_LEAF2(pdst)) {
-        key.iov_len = pdst->mp_leaf2_ksize;
-        key.iov_base = page_leaf2key(pdst, 0, key.iov_len);
-      } else {
-        MDBX_node *srcnode = page_node(pdst, 0);
-        key.iov_len = node_ks(srcnode);
-        key.iov_base = node_key(srcnode);
-      }
-      mdbx_debug("update separator for destination page %" PRIaPGNO " to [%s]",
-                 pdst->mp_pgno, DKEY_DEBUG(&key));
-      MDBX_cursor mn;
-      cursor_copy(cdst, &mn);
-      mdbx_cassert(cdst, mn.mc_snum > 0);
-      mn.mc_snum--;
-      mn.mc_top--;
-      /* We want mdbx_rebalance to find mn when doing fixups */
-      WITH_CURSOR_TRACKING(mn, rc = mdbx_update_key(&mn, &key));
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-    }
-    if (IS_BRANCH(pdst)) {
-      const MDBX_val nullkey = {0, 0};
-      const indx_t ix = cdst->mc_ki[cdst->mc_top];
-      cdst->mc_ki[cdst->mc_top] = 0;
-      rc = mdbx_update_key(cdst, &nullkey);
-      cdst->mc_ki[cdst->mc_top] = ix;
-      mdbx_cassert(cdst, rc == MDBX_SUCCESS);
-    }
-  }
-
-  return MDBX_SUCCESS;
-}
-
-/* Merge one page into another.
- *
- * The nodes from the page pointed to by csrc will be copied to the page
- * pointed to by cdst and then the csrc page will be freed.
- *
- * [in] csrc Cursor pointing to the source page.
- * [in] cdst Cursor pointing to the destination page.
- *
- * Returns 0 on success, non-zero on failure. */
-static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) {
-  MDBX_val key;
-  int rc;
-
-  mdbx_cassert(csrc, csrc != cdst);
-  mdbx_cassert(csrc, cursor_is_tracked(csrc));
-  mdbx_cassert(cdst, cursor_is_tracked(cdst));
-  const MDBX_page *const psrc = csrc->mc_pg[csrc->mc_top];
-  MDBX_page *pdst = cdst->mc_pg[cdst->mc_top];
-  mdbx_debug("merging page %" PRIaPGNO " into %" PRIaPGNO, psrc->mp_pgno,
-             pdst->mp_pgno);
-
-  mdbx_cassert(csrc, PAGETYPE(psrc) == PAGETYPE(pdst));
-  mdbx_cassert(csrc,
-               csrc->mc_dbi == cdst->mc_dbi && csrc->mc_db == cdst->mc_db);
-  mdbx_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */
-  mdbx_cassert(cdst, cdst->mc_snum > 1);
-  mdbx_cassert(cdst, cdst->mc_snum < cdst->mc_db->md_depth ||
-                         IS_LEAF(cdst->mc_pg[cdst->mc_db->md_depth - 1]));
-  mdbx_cassert(csrc, csrc->mc_snum < csrc->mc_db->md_depth ||
-                         IS_LEAF(csrc->mc_pg[csrc->mc_db->md_depth - 1]));
-  mdbx_cassert(cdst, page_room(pdst) >= page_used(cdst->mc_txn->mt_env, psrc));
-  const int pagetype = PAGETYPE(psrc);
-
-  /* Move all nodes from src to dst */
-  const unsigned dst_nkeys = page_numkeys(pdst);
-  const unsigned src_nkeys = page_numkeys(psrc);
-  mdbx_cassert(cdst, dst_nkeys + src_nkeys >= (IS_LEAF(psrc) ? 1u : 2u));
-  if (likely(src_nkeys)) {
-    unsigned j = dst_nkeys;
-    if (unlikely(pagetype & P_LEAF2)) {
-      /* Mark dst as dirty. */
-      if (unlikely(rc = mdbx_page_touch(cdst)))
-        return rc;
-
-      key.iov_len = csrc->mc_db->md_xsize;
-      key.iov_base = page_data(psrc);
-      unsigned i = 0;
-      do {
-        rc = mdbx_node_add_leaf2(cdst, j++, &key);
-        if (unlikely(rc != MDBX_SUCCESS))
-          return rc;
-        key.iov_base = (char *)key.iov_base + key.iov_len;
-      } while (++i != src_nkeys);
-    } else {
-      MDBX_node *srcnode = page_node(psrc, 0);
-      key.iov_len = node_ks(srcnode);
-      key.iov_base = node_key(srcnode);
-      if (pagetype & P_BRANCH) {
-        MDBX_cursor mn;
-        cursor_copy(csrc, &mn);
-        /* must find the lowest key below src */
-        rc = mdbx_page_search_lowest(&mn);
-        if (unlikely(rc))
-          return rc;
-
-        const MDBX_page *mp = mn.mc_pg[mn.mc_top];
-        if (likely(!IS_LEAF2(mp))) {
-          mdbx_cassert(&mn, IS_LEAF(mp));
-          const MDBX_node *lowest = page_node(mp, 0);
-          key.iov_len = node_ks(lowest);
-          key.iov_base = node_key(lowest);
-        } else {
-          mdbx_cassert(&mn, mn.mc_top > csrc->mc_top);
-          key.iov_len = mp->mp_leaf2_ksize;
-          key.iov_base = page_leaf2key(mp, mn.mc_ki[mn.mc_top], key.iov_len);
-        }
-        mdbx_cassert(&mn, key.iov_len >= csrc->mc_dbx->md_klen_min);
-        mdbx_cassert(&mn, key.iov_len <= csrc->mc_dbx->md_klen_max);
-
-        const size_t dst_room = page_room(pdst);
-        const size_t src_used = page_used(cdst->mc_txn->mt_env, psrc);
-        const size_t space_needed = src_used - node_ks(srcnode) + key.iov_len;
-        if (unlikely(space_needed > dst_room))
-          return MDBX_RESULT_TRUE;
-      }
-
-      /* Mark dst as dirty. */
-      if (unlikely(rc = mdbx_page_touch(cdst)))
-        return rc;
-
-      unsigned i = 0;
-      while (true) {
-        if (pagetype & P_LEAF) {
-          MDBX_val data;
-          data.iov_len = node_ds(srcnode);
-          data.iov_base = node_data(srcnode);
-          rc = mdbx_node_add_leaf(cdst, j++, &key, &data, node_flags(srcnode));
-        } else {
-          mdbx_cassert(csrc, node_flags(srcnode) == 0);
-          rc = mdbx_node_add_branch(cdst, j++, &key, node_pgno(srcnode));
-        }
-        if (unlikely(rc != MDBX_SUCCESS))
-          return rc;
-
-        if (++i == src_nkeys)
-          break;
-        srcnode = page_node(psrc, i);
-        key.iov_len = node_ks(srcnode);
-        key.iov_base = node_key(srcnode);
-      }
-    }
-
-    pdst = cdst->mc_pg[cdst->mc_top];
-    mdbx_debug("dst page %" PRIaPGNO " now has %u keys (%.1f%% filled)",
-               pdst->mp_pgno, page_numkeys(pdst),
-               page_fill(cdst->mc_txn->mt_env, pdst));
-
-    mdbx_cassert(csrc, psrc == csrc->mc_pg[csrc->mc_top]);
-    mdbx_cassert(cdst, pdst == cdst->mc_pg[cdst->mc_top]);
-  }
-
-  /* Unlink the src page from parent and add to free list. */
-  csrc->mc_top--;
-  mdbx_node_del(csrc, 0);
-  if (csrc->mc_ki[csrc->mc_top] == 0) {
-    const MDBX_val nullkey = {0, 0};
-    rc = mdbx_update_key(csrc, &nullkey);
-    if (unlikely(rc)) {
-      csrc->mc_top++;
-      return rc;
-    }
-  }
-  csrc->mc_top++;
-
-  mdbx_cassert(csrc, psrc == csrc->mc_pg[csrc->mc_top]);
-  mdbx_cassert(cdst, pdst == cdst->mc_pg[cdst->mc_top]);
-
-  {
-    /* Adjust other cursors pointing to mp */
-    MDBX_cursor *m2, *m3;
-    const MDBX_dbi dbi = csrc->mc_dbi;
-    const unsigned top = csrc->mc_top;
-
-    for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) {
-      m3 = (csrc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-      if (m3 == csrc || top >= m3->mc_snum)
-        continue;
-      if (m3->mc_pg[top] == psrc) {
-        m3->mc_pg[top] = pdst;
-        mdbx_cassert(m3, dst_nkeys + m3->mc_ki[top] <= UINT16_MAX);
-        m3->mc_ki[top] += (indx_t)dst_nkeys;
-        m3->mc_ki[top - 1] = cdst->mc_ki[top - 1];
-      } else if (m3->mc_pg[top - 1] == csrc->mc_pg[top - 1] &&
-                 m3->mc_ki[top - 1] > csrc->mc_ki[top - 1]) {
-        m3->mc_ki[top - 1]--;
-      }
-      if (XCURSOR_INITED(m3) && IS_LEAF(psrc))
-        XCURSOR_REFRESH(m3, m3->mc_pg[top], m3->mc_ki[top]);
-    }
-  }
-
-  /* If not operating on GC, allow this page to be reused
-   * in this txn. Otherwise just add to free list. */
-  rc = mdbx_page_retire(csrc, (MDBX_page *)psrc);
-  if (unlikely(rc))
-    return rc;
-
-  mdbx_cassert(cdst, cdst->mc_db->md_entries > 0);
-  mdbx_cassert(cdst, cdst->mc_snum <= cdst->mc_db->md_depth);
-  mdbx_cassert(cdst, cdst->mc_top > 0);
-  mdbx_cassert(cdst, cdst->mc_snum == cdst->mc_top + 1);
-  MDBX_page *const top_page = cdst->mc_pg[cdst->mc_top];
-  const indx_t top_indx = cdst->mc_ki[cdst->mc_top];
-  const unsigned save_snum = cdst->mc_snum;
-  const uint16_t save_depth = cdst->mc_db->md_depth;
-  mdbx_cursor_pop(cdst);
-  rc = mdbx_rebalance(cdst);
-  if (unlikely(rc))
-    return rc;
-
-  mdbx_cassert(cdst, cdst->mc_db->md_entries > 0);
-  mdbx_cassert(cdst, cdst->mc_snum <= cdst->mc_db->md_depth);
-  mdbx_cassert(cdst, cdst->mc_snum == cdst->mc_top + 1);
-
-#if MDBX_ENABLE_PGOP_STAT
-  cdst->mc_txn->mt_env->me_lck->mti_pgop_stat.merge.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-  if (IS_LEAF(cdst->mc_pg[cdst->mc_top])) {
-    /* LY: don't touch cursor if top-page is a LEAF */
-    mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) ||
-                           PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype);
-    return MDBX_SUCCESS;
-  }
-
-  mdbx_cassert(cdst, page_numkeys(top_page) == dst_nkeys + src_nkeys);
-
-  if (unlikely(pagetype != PAGETYPE(top_page))) {
-    /* LY: LEAF-page becomes BRANCH, unable restore cursor's stack */
-    goto bailout;
-  }
-
-  if (top_page == cdst->mc_pg[cdst->mc_top]) {
-    /* LY: don't touch cursor if prev top-page already on the top */
-    mdbx_cassert(cdst, cdst->mc_ki[cdst->mc_top] == top_indx);
-    mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) ||
-                           PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype);
-    return MDBX_SUCCESS;
-  }
-
-  const int new_snum = save_snum - save_depth + cdst->mc_db->md_depth;
-  if (unlikely(new_snum < 1 || new_snum > cdst->mc_db->md_depth)) {
-    /* LY: out of range, unable restore cursor's stack */
-    goto bailout;
-  }
-
-  if (top_page == cdst->mc_pg[new_snum - 1]) {
-    mdbx_cassert(cdst, cdst->mc_ki[new_snum - 1] == top_indx);
-    /* LY: restore cursor stack */
-    cdst->mc_snum = (uint16_t)new_snum;
-    cdst->mc_top = (uint16_t)new_snum - 1;
-    mdbx_cassert(cdst, cdst->mc_snum < cdst->mc_db->md_depth ||
-                           IS_LEAF(cdst->mc_pg[cdst->mc_db->md_depth - 1]));
-    mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) ||
-                           PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype);
-    return MDBX_SUCCESS;
-  }
-
-  MDBX_page *const stub_page = (MDBX_page *)(~(uintptr_t)top_page);
-  const indx_t stub_indx = top_indx;
-  if (save_depth > cdst->mc_db->md_depth &&
-      ((cdst->mc_pg[save_snum - 1] == top_page &&
-        cdst->mc_ki[save_snum - 1] == top_indx) ||
-       (cdst->mc_pg[save_snum - 1] == stub_page &&
-        cdst->mc_ki[save_snum - 1] == stub_indx))) {
-    /* LY: restore cursor stack */
-    cdst->mc_pg[new_snum - 1] = top_page;
-    cdst->mc_ki[new_snum - 1] = top_indx;
-    cdst->mc_pg[new_snum] = (MDBX_page *)(~(uintptr_t)cdst->mc_pg[new_snum]);
-    cdst->mc_ki[new_snum] = ~cdst->mc_ki[new_snum];
-    cdst->mc_snum = (uint16_t)new_snum;
-    cdst->mc_top = (uint16_t)new_snum - 1;
-    mdbx_cassert(cdst, cdst->mc_snum < cdst->mc_db->md_depth ||
-                           IS_LEAF(cdst->mc_pg[cdst->mc_db->md_depth - 1]));
-    mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) ||
-                           PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype);
-    return MDBX_SUCCESS;
-  }
-
-bailout:
-  /* LY: unable restore cursor's stack */
-  cdst->mc_flags &= ~C_INITIALIZED;
-  return MDBX_CURSOR_FULL;
-}
-
-static void cursor_restore(const MDBX_cursor *csrc, MDBX_cursor *cdst) {
-  mdbx_cassert(cdst, cdst->mc_dbi == csrc->mc_dbi);
-  mdbx_cassert(cdst, cdst->mc_txn == csrc->mc_txn);
-  mdbx_cassert(cdst, cdst->mc_db == csrc->mc_db);
-  mdbx_cassert(cdst, cdst->mc_dbx == csrc->mc_dbx);
-  mdbx_cassert(cdst, cdst->mc_dbistate == csrc->mc_dbistate);
-  cdst->mc_snum = csrc->mc_snum;
-  cdst->mc_top = csrc->mc_top;
-  cdst->mc_flags = csrc->mc_flags;
-
-  for (unsigned i = 0; i < csrc->mc_snum; i++) {
-    cdst->mc_pg[i] = csrc->mc_pg[i];
-    cdst->mc_ki[i] = csrc->mc_ki[i];
-  }
-}
-
-/* Copy the contents of a cursor.
- * [in] csrc The cursor to copy from.
- * [out] cdst The cursor to copy to. */
-static void cursor_copy(const MDBX_cursor *csrc, MDBX_cursor *cdst) {
-  mdbx_cassert(csrc, csrc->mc_txn->mt_txnid >=
-                         csrc->mc_txn->mt_env->me_lck->mti_oldest_reader.weak);
-  cdst->mc_dbi = csrc->mc_dbi;
-  cdst->mc_next = NULL;
-  cdst->mc_backup = NULL;
-  cdst->mc_xcursor = NULL;
-  cdst->mc_txn = csrc->mc_txn;
-  cdst->mc_db = csrc->mc_db;
-  cdst->mc_dbx = csrc->mc_dbx;
-  cdst->mc_dbistate = csrc->mc_dbistate;
-  cursor_restore(csrc, cdst);
-}
-
-/* Rebalance the tree after a delete operation.
- * [in] mc Cursor pointing to the page where rebalancing should begin.
- * Returns 0 on success, non-zero on failure. */
-static int mdbx_rebalance(MDBX_cursor *mc) {
-  mdbx_cassert(mc, cursor_is_tracked(mc));
-  mdbx_cassert(mc, mc->mc_snum > 0);
-  mdbx_cassert(mc, mc->mc_snum < mc->mc_db->md_depth ||
-                       IS_LEAF(mc->mc_pg[mc->mc_db->md_depth - 1]));
-  const int pagetype = PAGETYPE(mc->mc_pg[mc->mc_top]);
-
-  STATIC_ASSERT(P_BRANCH == 1);
-  const unsigned minkeys = (pagetype & P_BRANCH) + 1;
-
-  /* Pages emptier than this are candidates for merging. */
-  unsigned room_threshold = likely(mc->mc_dbi != FREE_DBI)
-                                ? mc->mc_txn->mt_env->me_merge_threshold
-                                : mc->mc_txn->mt_env->me_merge_threshold_gc;
-
-  const MDBX_page *const tp = mc->mc_pg[mc->mc_top];
-  const unsigned numkeys = page_numkeys(tp);
-  const unsigned room = page_room(tp);
-  mdbx_debug("rebalancing %s page %" PRIaPGNO
-             " (has %u keys, full %.1f%%, used %u, room %u bytes )",
-             (pagetype & P_LEAF) ? "leaf" : "branch", tp->mp_pgno, numkeys,
-             page_fill(mc->mc_txn->mt_env, tp),
-             page_used(mc->mc_txn->mt_env, tp), room);
-
-  if (unlikely(numkeys < minkeys)) {
-    mdbx_debug("page %" PRIaPGNO " must be merged due keys < %u threshold",
-               tp->mp_pgno, minkeys);
-  } else if (unlikely(room > room_threshold)) {
-    mdbx_debug("page %" PRIaPGNO " should be merged due room %u > %u threshold",
-               tp->mp_pgno, room, room_threshold);
-  } else {
-    mdbx_debug("no need to rebalance page %" PRIaPGNO
-               ", room %u < %u threshold",
-               tp->mp_pgno, room, room_threshold);
-    mdbx_cassert(mc, mc->mc_db->md_entries > 0);
-    return MDBX_SUCCESS;
-  }
-
-  int rc;
-  if (mc->mc_snum < 2) {
-    MDBX_page *const mp = mc->mc_pg[0];
-    const unsigned nkeys = page_numkeys(mp);
-    mdbx_cassert(mc, (mc->mc_db->md_entries == 0) == (nkeys == 0));
-    if (IS_SUBP(mp)) {
-      mdbx_debug("%s", "Can't rebalance a subpage, ignoring");
-      mdbx_cassert(mc, pagetype & P_LEAF);
-      return MDBX_SUCCESS;
-    }
-    if (nkeys == 0) {
-      mdbx_cassert(mc, IS_LEAF(mp));
-      mdbx_debug("%s", "tree is completely empty");
-      mdbx_cassert(mc, (*mc->mc_dbistate & DBI_DIRTY) != 0);
-      mc->mc_db->md_root = P_INVALID;
-      mc->mc_db->md_depth = 0;
-      mdbx_cassert(mc, mc->mc_db->md_branch_pages == 0 &&
-                           mc->mc_db->md_overflow_pages == 0 &&
-                           mc->mc_db->md_leaf_pages == 1);
-      /* Adjust cursors pointing to mp */
-      for (MDBX_cursor *m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2;
-           m2 = m2->mc_next) {
-        MDBX_cursor *m3 =
-            (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-        if (m3 == mc || !(m3->mc_flags & C_INITIALIZED))
-          continue;
-        if (m3->mc_pg[0] == mp) {
-          m3->mc_snum = 0;
-          m3->mc_top = 0;
-          m3->mc_flags &= ~C_INITIALIZED;
-        }
-      }
-      mc->mc_snum = 0;
-      mc->mc_top = 0;
-      mc->mc_flags &= ~C_INITIALIZED;
-
-      rc = mdbx_page_retire(mc, mp);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-    } else if (IS_BRANCH(mp) && nkeys == 1) {
-      mdbx_debug("%s", "collapsing root page!");
-      mc->mc_db->md_root = node_pgno(page_node(mp, 0));
-      rc = mdbx_page_get(mc, mc->mc_db->md_root, &mc->mc_pg[0],
-                         pp_txnid4chk(mp, mc->mc_txn));
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-      mc->mc_db->md_depth--;
-      mc->mc_ki[0] = mc->mc_ki[1];
-      for (int i = 1; i < mc->mc_db->md_depth; i++) {
-        mc->mc_pg[i] = mc->mc_pg[i + 1];
-        mc->mc_ki[i] = mc->mc_ki[i + 1];
-      }
-
-      /* Adjust other cursors pointing to mp */
-      for (MDBX_cursor *m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2;
-           m2 = m2->mc_next) {
-        MDBX_cursor *m3 =
-            (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-        if (m3 == mc || !(m3->mc_flags & C_INITIALIZED))
-          continue;
-        if (m3->mc_pg[0] == mp) {
-          for (int i = 0; i < mc->mc_db->md_depth; i++) {
-            m3->mc_pg[i] = m3->mc_pg[i + 1];
-            m3->mc_ki[i] = m3->mc_ki[i + 1];
-          }
-          m3->mc_snum--;
-          m3->mc_top--;
-        }
-      }
-      mdbx_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]) ||
-                           PAGETYPE(mc->mc_pg[mc->mc_top]) == pagetype);
-      mdbx_cassert(mc, mc->mc_snum < mc->mc_db->md_depth ||
-                           IS_LEAF(mc->mc_pg[mc->mc_db->md_depth - 1]));
-
-      rc = mdbx_page_retire(mc, mp);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-    } else {
-      mdbx_debug("root page %" PRIaPGNO
-                 " doesn't need rebalancing (flags 0x%x)",
-                 mp->mp_pgno, mp->mp_flags);
-    }
-    return MDBX_SUCCESS;
-  }
-
-  /* The parent (branch page) must have at least 2 pointers,
-   * otherwise the tree is invalid. */
-  const unsigned pre_top = mc->mc_top - 1;
-  mdbx_cassert(mc, IS_BRANCH(mc->mc_pg[pre_top]));
-  mdbx_cassert(mc, !IS_SUBP(mc->mc_pg[0]));
-  mdbx_cassert(mc, page_numkeys(mc->mc_pg[pre_top]) > 1);
-
-  /* Leaf page fill factor is below the threshold.
-   * Try to move keys from left or right neighbor, or
-   * merge with a neighbor page. */
-
-  /* Find neighbors. */
-  MDBX_cursor mn;
-  cursor_copy(mc, &mn);
-
-  MDBX_page *left = nullptr, *right = nullptr;
-  if (mn.mc_ki[pre_top] > 0) {
-    rc = mdbx_page_get(
-        &mn, node_pgno(page_node(mn.mc_pg[pre_top], mn.mc_ki[pre_top] - 1)),
-        &left, pp_txnid4chk(mn.mc_pg[pre_top], mc->mc_txn));
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    mdbx_cassert(mc, PAGETYPE(left) == PAGETYPE(mc->mc_pg[mc->mc_top]));
-  }
-  if (mn.mc_ki[pre_top] + 1u < page_numkeys(mn.mc_pg[pre_top])) {
-    rc = mdbx_page_get(
-        &mn, node_pgno(page_node(mn.mc_pg[pre_top], mn.mc_ki[pre_top] + 1)),
-        &right, pp_txnid4chk(mn.mc_pg[pre_top], mc->mc_txn));
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    mdbx_cassert(mc, PAGETYPE(right) == PAGETYPE(mc->mc_pg[mc->mc_top]));
-  }
-  mdbx_cassert(mc, left || right);
-
-  const unsigned ki_top = mc->mc_ki[mc->mc_top];
-  const unsigned ki_pre_top = mn.mc_ki[pre_top];
-  const unsigned nkeys = page_numkeys(mn.mc_pg[mn.mc_top]);
-
-  const unsigned left_room = left ? page_room(left) : 0;
-  const unsigned right_room = right ? page_room(right) : 0;
-  const unsigned left_nkeys = left ? page_numkeys(left) : 0;
-  const unsigned right_nkeys = right ? page_numkeys(right) : 0;
-retry:
-  if (left_room > room_threshold && left_room >= right_room) {
-    /* try merge with left */
-    mdbx_cassert(mc, left_nkeys >= minkeys);
-    mn.mc_pg[mn.mc_top] = left;
-    mn.mc_ki[mn.mc_top - 1] = (indx_t)(ki_pre_top - 1);
-    mn.mc_ki[mn.mc_top] = (indx_t)(left_nkeys - 1);
-    mc->mc_ki[mc->mc_top] = 0;
-    const unsigned new_ki = ki_top + left_nkeys;
-    mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1;
-    /* We want mdbx_rebalance to find mn when doing fixups */
-    WITH_CURSOR_TRACKING(mn, rc = mdbx_page_merge(mc, &mn));
-    if (likely(rc != MDBX_RESULT_TRUE)) {
-      cursor_restore(&mn, mc);
-      mc->mc_ki[mc->mc_top] = (indx_t)new_ki;
-      mdbx_cassert(mc, rc || page_numkeys(mc->mc_pg[mc->mc_top]) >= minkeys);
-      return rc;
-    }
-  }
-  if (right_room > room_threshold) {
-    /* try merge with right */
-    mdbx_cassert(mc, right_nkeys >= minkeys);
-    mn.mc_pg[mn.mc_top] = right;
-    mn.mc_ki[mn.mc_top - 1] = (indx_t)(ki_pre_top + 1);
-    mn.mc_ki[mn.mc_top] = 0;
-    mc->mc_ki[mc->mc_top] = (indx_t)nkeys;
-    WITH_CURSOR_TRACKING(mn, rc = mdbx_page_merge(&mn, mc));
-    if (likely(rc != MDBX_RESULT_TRUE)) {
-      mc->mc_ki[mc->mc_top] = (indx_t)ki_top;
-      mdbx_cassert(mc, rc || page_numkeys(mc->mc_pg[mc->mc_top]) >= minkeys);
-      return rc;
-    }
-  }
-
-  if (left_nkeys > minkeys &&
-      (right_nkeys <= left_nkeys || right_room >= left_room)) {
-    /* try move from left */
-    mn.mc_pg[mn.mc_top] = left;
-    mn.mc_ki[mn.mc_top - 1] = (indx_t)(ki_pre_top - 1);
-    mn.mc_ki[mn.mc_top] = (indx_t)(left_nkeys - 1);
-    mc->mc_ki[mc->mc_top] = 0;
-    WITH_CURSOR_TRACKING(mn, rc = mdbx_node_move(&mn, mc, true));
-    if (likely(rc != MDBX_RESULT_TRUE)) {
-      mc->mc_ki[mc->mc_top] = (indx_t)(ki_top + 1);
-      mdbx_cassert(mc, rc || page_numkeys(mc->mc_pg[mc->mc_top]) >= minkeys);
-      return rc;
-    }
-  }
-  if (right_nkeys > minkeys) {
-    /* try move from right */
-    mn.mc_pg[mn.mc_top] = right;
-    mn.mc_ki[mn.mc_top - 1] = (indx_t)(ki_pre_top + 1);
-    mn.mc_ki[mn.mc_top] = 0;
-    mc->mc_ki[mc->mc_top] = (indx_t)nkeys;
-    WITH_CURSOR_TRACKING(mn, rc = mdbx_node_move(&mn, mc, false));
-    if (likely(rc != MDBX_RESULT_TRUE)) {
-      mc->mc_ki[mc->mc_top] = (indx_t)ki_top;
-      mdbx_cassert(mc, rc || page_numkeys(mc->mc_pg[mc->mc_top]) >= minkeys);
-      return rc;
-    }
-  }
-
-  if (nkeys >= minkeys) {
-    mc->mc_ki[mc->mc_top] = (indx_t)ki_top;
-    if (!mdbx_audit_enabled())
-      return MDBX_SUCCESS;
-    return mdbx_cursor_check(mc, C_UPDATING);
-  }
-
-  if (likely(room_threshold > 0)) {
-    room_threshold = 0;
-    goto retry;
-  }
-  mdbx_error("Unable to merge/rebalance %s page %" PRIaPGNO
-             " (has %u keys, full %.1f%%, used %u, room %u bytes )",
-             (pagetype & P_LEAF) ? "leaf" : "branch", tp->mp_pgno, numkeys,
-             page_fill(mc->mc_txn->mt_env, tp),
-             page_used(mc->mc_txn->mt_env, tp), room);
-  return MDBX_PROBLEM;
-}
-
-__cold static int mdbx_page_check(MDBX_cursor *const mc,
-                                  const MDBX_page *const mp, unsigned options) {
-  DKBUF;
-  options |= mc->mc_flags;
-  MDBX_env *const env = mc->mc_txn->mt_env;
-  const unsigned nkeys = page_numkeys(mp);
-  char *const end_of_page = (char *)mp + env->me_psize;
-  if (unlikely(mp->mp_pgno < MIN_PAGENO || mp->mp_pgno > MAX_PAGENO))
-    return bad_page(mp, "invalid pgno (%u)\n", mp->mp_pgno);
-  if (IS_OVERFLOW(mp)) {
-    if (unlikely(mp->mp_pages < 1 && mp->mp_pages >= MAX_PAGENO / 2))
-      return bad_page(mp, "invalid overflow n-pages (%u)\n", mp->mp_pages);
-    if (unlikely(mp->mp_pgno + mp->mp_pages > mc->mc_txn->mt_next_pgno))
-      return bad_page(mp, "overflow page beyond (%u) next-pgno\n",
-                      mp->mp_pgno + mp->mp_pages);
-    if (unlikely((options & (C_SUB | C_COPYING)) == C_SUB))
-      return bad_page(mp,
-                      "unexpected overflow-page for dupsort db (flags 0x%x)\n",
-                      mc->mc_db->md_flags);
-    return MDBX_SUCCESS;
-  }
-
-  int rc = MDBX_SUCCESS;
-  if ((options & C_UPDATING) == 0 || !IS_MODIFIABLE(mc->mc_txn, mp)) {
-    if (unlikely(nkeys < 2 && IS_BRANCH(mp)))
-      rc = bad_page(mp, "branch-page nkey (%u) < 2\n", nkeys);
-  }
-  if (IS_LEAF2(mp) && unlikely((options & (C_SUB | C_COPYING)) == 0))
-    rc = bad_page(mp, "unexpected leaf2-page (db flags 0x%x)\n",
-                  mc->mc_db->md_flags);
-
-  MDBX_val here, prev = {0, 0};
-  for (unsigned i = 0; i < nkeys; ++i) {
-    if (IS_LEAF2(mp)) {
-      const size_t ksize = mp->mp_leaf2_ksize;
-      char *const key = page_leaf2key(mp, i, ksize);
-      if (unlikely(end_of_page < key + ksize)) {
-        rc = bad_page(mp, "leaf2-key beyond (%zu) page-end\n",
-                      key + ksize - end_of_page);
-        continue;
-      }
-
-      if ((options & C_COPYING) == 0) {
-        if (unlikely(ksize != mc->mc_dbx->md_klen_min)) {
-          if (unlikely(ksize < mc->mc_dbx->md_klen_min ||
-                       ksize > mc->mc_dbx->md_klen_max))
-            rc = bad_page(
-                mp, "leaf2-key size (%zu) <> min/max key-length (%zu/%zu)\n",
-                ksize, mc->mc_dbx->md_klen_min, mc->mc_dbx->md_klen_max);
-          else
-            mc->mc_dbx->md_klen_min = mc->mc_dbx->md_klen_max = ksize;
-        }
-        if ((options & C_SKIPORD) == 0) {
-          here.iov_len = ksize;
-          here.iov_base = key;
-          if (prev.iov_base && unlikely(mc->mc_dbx->md_cmp(&prev, &here) >= 0))
-            rc = bad_page(mp, "leaf2-key #%u wrong order (%s >= %s)\n", i,
-                          DKEY(&prev), DVAL(&here));
-          prev = here;
-        }
-      }
-    } else {
-      const MDBX_node *const node = page_node(mp, i);
-      const char *node_end = (char *)node + NODESIZE;
-      if (unlikely(node_end > end_of_page)) {
-        rc = bad_page(mp, "node[%u] (%zu) beyond page-end\n", i,
-                      node_end - end_of_page);
-        continue;
-      }
-      size_t ksize = node_ks(node);
-      char *key = node_key(node);
-      if (unlikely(end_of_page < key + ksize)) {
-        rc = bad_page(mp, "node[%u] key (%zu) beyond page-end\n", i,
-                      key + ksize - end_of_page);
-        continue;
-      }
-      if ((IS_LEAF(mp) || i > 0) && (options & C_COPYING) == 0) {
-        if (unlikely(ksize < mc->mc_dbx->md_klen_min ||
-                     ksize > mc->mc_dbx->md_klen_max))
-          rc = bad_page(
-              mp, "node[%u] key size (%zu) <> min/max key-length (%zu/%zu)\n",
-              i, ksize, mc->mc_dbx->md_klen_min, mc->mc_dbx->md_klen_max);
-        if ((options & C_SKIPORD) == 0) {
-          here.iov_base = key;
-          here.iov_len = ksize;
-          if (prev.iov_base && unlikely(mc->mc_dbx->md_cmp(&prev, &here) >= 0))
-            rc = bad_page(mp, "node[%u] key wrong order (%s >= %s)\n", i,
-                          DKEY(&prev), DVAL(&here));
-          prev = here;
-        }
-      }
-      if (IS_BRANCH(mp)) {
-        if ((options & C_UPDATING) == 0 && i == 0 && unlikely(ksize != 0))
-          rc = bad_page(mp, "branch-node[%u] wrong 0-node key-length (%zu)\n",
-                        i, ksize);
-        if ((options & C_RETIRING) == 0) {
-          const pgno_t ref = node_pgno(node);
-          if (unlikely(ref < MIN_PAGENO || ref >= mc->mc_txn->mt_next_pgno))
-            rc = bad_page(mp, "branch-node[%u] wrong pgno (%u)\n", i, ref);
-        }
-        if (unlikely(node_flags(node)))
-          rc = bad_page(mp, "branch-node[%u] wrong flags (%u)\n", i,
-                        node_flags(node));
-        continue;
-      }
-
-      switch (node_flags(node)) {
-      default:
-        rc = bad_page(mp, "invalid node[%u] flags (%u)\n", i, node_flags(node));
-        break;
-      case F_BIGDATA /* data on large-page */:
-      case 0 /* usual */:
-      case F_SUBDATA /* sub-db */:
-      case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */:
-      case F_DUPDATA /* short sub-page */:
-        break;
-      }
-
-      const size_t dsize = node_ds(node);
-      const char *const data = node_data(node);
-      if (node_flags(node) & F_BIGDATA) {
-        if (unlikely(end_of_page < data + sizeof(pgno_t))) {
-          rc = bad_page(
-              mp, "node-%s(%u of %u, %zu bytes) beyond (%zu) page-end\n",
-              "bigdata-pgno", i, nkeys, dsize, data + dsize - end_of_page);
-          continue;
-        }
-        if ((options & C_COPYING) == 0) {
-          if (unlikely(dsize <= mc->mc_dbx->md_vlen_min ||
-                       dsize > mc->mc_dbx->md_vlen_max))
-            rc = bad_page(
-                mp,
-                "big-node data size (%zu) <> min/max value-length (%zu/%zu)\n",
-                dsize, mc->mc_dbx->md_vlen_min, mc->mc_dbx->md_vlen_max);
-        }
-        if ((options & C_RETIRING) == 0) {
-          MDBX_page *lp;
-          int err = mdbx_page_get(mc, node_largedata_pgno(node), &lp,
-                                  pp_txnid4chk(mp, mc->mc_txn));
-          if (unlikely(err != MDBX_SUCCESS))
-            return err;
-          if (unlikely(!IS_OVERFLOW(lp))) {
-            rc = bad_page(mp, "big-node refs to non-overflow page (%u)\n",
-                          lp->mp_pgno);
-            continue;
-          }
-          if (unlikely(number_of_ovpages(env, dsize) > lp->mp_pages))
-            rc =
-                bad_page(mp, "big-node size (%zu) mismatch n-pages size (%u)\n",
-                         dsize, lp->mp_pages);
-        }
-        continue;
-      }
-
-      if (unlikely(end_of_page < data + dsize)) {
-        rc =
-            bad_page(mp, "node-%s(%u of %u, %zu bytes) beyond (%zu) page-end\n",
-                     "data", i, nkeys, dsize, data + dsize - end_of_page);
-        continue;
-      }
-
-      switch (node_flags(node)) {
-      default:
-        /* wrong, but already handled */
-        continue;
-      case 0 /* usual */:
-        if ((options & C_COPYING) == 0) {
-          if (unlikely(dsize < mc->mc_dbx->md_vlen_min ||
-                       dsize > mc->mc_dbx->md_vlen_max)) {
-            rc = bad_page(
-                mp, "node-data size (%zu) <> min/max value-length (%zu/%zu)\n",
-                dsize, mc->mc_dbx->md_vlen_min, mc->mc_dbx->md_vlen_max);
-            continue;
-          }
-        }
-        break;
-      case F_SUBDATA /* sub-db */:
-        if (unlikely(dsize != sizeof(MDBX_db))) {
-          rc = bad_page(mp, "invalid sub-db record size (%zu)\n", dsize);
-          continue;
-        }
-        break;
-      case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */:
-        if (unlikely(dsize != sizeof(MDBX_db))) {
-          rc = bad_page(mp, "invalid nested-db record size (%zu)\n", dsize);
-          continue;
-        }
-        break;
-      case F_DUPDATA /* short sub-page */:
-        if (unlikely(dsize <= PAGEHDRSZ)) {
-          rc = bad_page(mp, "invalid nested/sub-page record size (%zu)\n",
-                        dsize);
-          continue;
-        } else {
-          const MDBX_page *const sp = (MDBX_page *)data;
-          const char *const end_of_subpage = data + dsize;
-          const int nsubkeys = page_numkeys(sp);
-          switch (sp->mp_flags & /* ignore legacy P_DIRTY flag */ ~0x10) {
-          case P_LEAF | P_SUBP:
-          case P_LEAF | P_LEAF2 | P_SUBP:
-            break;
-          default:
-            rc = bad_page(mp, "invalid nested/sub-page flags (0x%02x)\n",
-                          sp->mp_flags);
-            continue;
-          }
-
-          MDBX_val sub_here, sub_prev = {0, 0};
-          for (int j = 0; j < nsubkeys; j++) {
-            if (IS_LEAF2(sp)) {
-              /* LEAF2 pages have no mp_ptrs[] or node headers */
-              size_t sub_ksize = sp->mp_leaf2_ksize;
-              char *sub_key = page_leaf2key(sp, j, sub_ksize);
-              if (unlikely(end_of_subpage < sub_key + sub_ksize)) {
-                rc = bad_page(mp, "nested-leaf2-key beyond (%zu) nested-page\n",
-                              sub_key + sub_ksize - end_of_subpage);
-                continue;
-              }
-
-              if ((options & C_COPYING) == 0) {
-                if (unlikely(sub_ksize != mc->mc_dbx->md_vlen_min)) {
-                  if (unlikely(sub_ksize < mc->mc_dbx->md_vlen_min ||
-                               sub_ksize > mc->mc_dbx->md_vlen_max)) {
-                    rc = bad_page(mp,
-                                  "nested-leaf2-key size (%zu) <> min/max "
-                                  "value-length (%zu/%zu)\n",
-                                  sub_ksize, mc->mc_dbx->md_vlen_min,
-                                  mc->mc_dbx->md_vlen_max);
-                    continue;
-                  }
-                  mc->mc_dbx->md_vlen_min = mc->mc_dbx->md_vlen_max = sub_ksize;
-                }
-                if ((options & C_SKIPORD) == 0) {
-                  sub_here.iov_len = sub_ksize;
-                  sub_here.iov_base = sub_key;
-                  if (sub_prev.iov_base &&
-                      unlikely(mc->mc_dbx->md_dcmp(&sub_prev, &sub_here) >= 0))
-                    rc = bad_page(
-                        mp, "nested-leaf2-key #%u wrong order (%s >= %s)\n", j,
-                        DKEY(&sub_prev), DVAL(&sub_here));
-                  sub_prev = sub_here;
-                }
-              }
-            } else {
-              const MDBX_node *const sub_node = page_node(sp, j);
-              const char *sub_node_end = (char *)sub_node + NODESIZE;
-              if (unlikely(sub_node_end > end_of_subpage)) {
-                rc = bad_page(mp, "nested-node beyond (%zu) nested-page\n",
-                              end_of_subpage - sub_node_end);
-                continue;
-              }
-              if (unlikely(node_flags(sub_node) != 0))
-                rc = bad_page(mp, "nested-node invalid flags (%u)\n",
-                              node_flags(sub_node));
-
-              size_t sub_ksize = node_ks(sub_node);
-              char *sub_key = node_key(sub_node);
-              size_t sub_dsize = node_ds(sub_node);
-              /* char *sub_data = node_data(sub_node); */
-
-              if ((options & C_COPYING) == 0) {
-                if (unlikely(sub_ksize < mc->mc_dbx->md_vlen_min ||
-                             sub_ksize > mc->mc_dbx->md_vlen_max))
-                  rc = bad_page(mp,
-                                "nested-node-key size (%zu) <> min/max "
-                                "value-length (%zu/%zu)\n",
-                                sub_ksize, mc->mc_dbx->md_vlen_min,
-                                mc->mc_dbx->md_vlen_max);
-
-                if ((options & C_SKIPORD) == 0) {
-                  sub_here.iov_len = sub_ksize;
-                  sub_here.iov_base = sub_key;
-                  if (sub_prev.iov_base &&
-                      unlikely(mc->mc_dbx->md_dcmp(&sub_prev, &sub_here) >= 0))
-                    rc = bad_page(
-                        mp, "nested-node-key #%u wrong order (%s >= %s)\n", j,
-                        DKEY(&sub_prev), DVAL(&sub_here));
-                  sub_prev = sub_here;
-                }
-              }
-              if (unlikely(sub_dsize != 0))
-                rc = bad_page(mp, "nested-node non-empty data size (%zu)\n",
-                              sub_dsize);
-              if (unlikely(end_of_subpage < sub_key + sub_ksize))
-                rc = bad_page(mp, "nested-node-key beyond (%zu) nested-page\n",
-                              sub_key + sub_ksize - end_of_subpage);
-            }
-          }
-        }
-        break;
-      }
-    }
-  }
-  return rc;
-}
-
-__cold static int mdbx_cursor_check(MDBX_cursor *mc, unsigned options) {
-  mdbx_cassert(mc,
-               mc->mc_txn->tw.dirtyroom + mc->mc_txn->tw.dirtylist->length ==
-                   (mc->mc_txn->mt_parent
-                        ? mc->mc_txn->mt_parent->tw.dirtyroom
-                        : mc->mc_txn->mt_env->me_options.dp_limit));
-  mdbx_cassert(mc, mc->mc_top == mc->mc_snum - 1 || (options & C_UPDATING));
-  if (unlikely(mc->mc_top != mc->mc_snum - 1) && (options & C_UPDATING) == 0)
-    return MDBX_CURSOR_FULL;
-  mdbx_cassert(mc, (options & C_UPDATING) ? mc->mc_snum <= mc->mc_db->md_depth
-                                          : mc->mc_snum == mc->mc_db->md_depth);
-  if (unlikely((options & C_UPDATING) ? mc->mc_snum > mc->mc_db->md_depth
-                                      : mc->mc_snum != mc->mc_db->md_depth))
-    return MDBX_CURSOR_FULL;
-
-  for (int n = 0; n < (int)mc->mc_snum; ++n) {
-    MDBX_page *mp = mc->mc_pg[n];
-    const unsigned nkeys = page_numkeys(mp);
-    const bool expect_branch = (n < mc->mc_db->md_depth - 1) ? true : false;
-    const bool expect_nested_leaf =
-        (n + 1 == mc->mc_db->md_depth - 1) ? true : false;
-    const bool branch = IS_BRANCH(mp) ? true : false;
-    mdbx_cassert(mc, branch == expect_branch);
-    if (unlikely(branch != expect_branch))
-      return MDBX_CURSOR_FULL;
-    if ((options & C_UPDATING) == 0) {
-      mdbx_cassert(mc,
-                   nkeys > mc->mc_ki[n] || (!branch && nkeys == mc->mc_ki[n] &&
-                                            (mc->mc_flags & C_EOF) != 0));
-      if (unlikely(nkeys <= mc->mc_ki[n] &&
-                   !(!branch && nkeys == mc->mc_ki[n] &&
-                     (mc->mc_flags & C_EOF) != 0)))
-        return MDBX_CURSOR_FULL;
-    } else {
-      mdbx_cassert(mc, nkeys + 1 >= mc->mc_ki[n]);
-      if (unlikely(nkeys + 1 < mc->mc_ki[n]))
-        return MDBX_CURSOR_FULL;
-    }
-
-    int err = mdbx_page_check(mc, mp, options);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-    for (unsigned i = 0; i < nkeys; ++i) {
-      if (branch) {
-        MDBX_node *node = page_node(mp, i);
-        mdbx_cassert(mc, node_flags(node) == 0);
-        if (unlikely(node_flags(node) != 0))
-          return MDBX_CURSOR_FULL;
-        pgno_t pgno = node_pgno(node);
-        MDBX_page *np;
-        int rc = mdbx_page_get(mc, pgno, &np, pp_txnid4chk(mp, mc->mc_txn));
-        mdbx_cassert(mc, rc == MDBX_SUCCESS);
-        if (unlikely(rc != MDBX_SUCCESS))
-          return rc;
-        const bool nested_leaf = IS_LEAF(np) ? true : false;
-        mdbx_cassert(mc, nested_leaf == expect_nested_leaf);
-        if (unlikely(nested_leaf != expect_nested_leaf))
-          return MDBX_CURSOR_FULL;
-        err = mdbx_page_check(mc, np, options);
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-      }
-    }
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Complete a delete operation started by mdbx_cursor_del(). */
-static int mdbx_cursor_del0(MDBX_cursor *mc) {
-  int rc;
-  MDBX_page *mp;
-  indx_t ki;
-  unsigned nkeys;
-  MDBX_dbi dbi = mc->mc_dbi;
-
-  mdbx_cassert(mc, cursor_is_tracked(mc));
-  mdbx_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]));
-  ki = mc->mc_ki[mc->mc_top];
-  mp = mc->mc_pg[mc->mc_top];
-  mdbx_node_del(mc, mc->mc_db->md_xsize);
-  mc->mc_db->md_entries--;
-
-  /* Adjust other cursors pointing to mp */
-  for (MDBX_cursor *m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) {
-    MDBX_cursor *m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-    if (m3 == mc || !(m2->mc_flags & m3->mc_flags & C_INITIALIZED))
-      continue;
-    if (m3->mc_snum < mc->mc_snum)
-      continue;
-    if (m3->mc_pg[mc->mc_top] == mp) {
-      if (m3->mc_ki[mc->mc_top] == ki) {
-        m3->mc_flags |= C_DEL;
-        if (mc->mc_db->md_flags & MDBX_DUPSORT) {
-          /* Sub-cursor referred into dataset which is gone */
-          m3->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
-        }
-        continue;
-      } else if (m3->mc_ki[mc->mc_top] > ki) {
-        m3->mc_ki[mc->mc_top]--;
-      }
-      if (XCURSOR_INITED(m3))
-        XCURSOR_REFRESH(m3, m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]);
-    }
-  }
-
-  rc = mdbx_rebalance(mc);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto bailout;
-
-  if (unlikely(!mc->mc_snum)) {
-    /* DB is totally empty now, just bail out.
-     * Other cursors adjustments were already done
-     * by mdbx_rebalance and aren't needed here. */
-    mdbx_cassert(mc, mc->mc_db->md_entries == 0 && mc->mc_db->md_depth == 0 &&
-                         mc->mc_db->md_root == P_INVALID);
-    mc->mc_flags |= C_EOF;
-    return MDBX_SUCCESS;
-  }
-
-  ki = mc->mc_ki[mc->mc_top];
-  mp = mc->mc_pg[mc->mc_top];
-  mdbx_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]));
-  nkeys = page_numkeys(mp);
-  mdbx_cassert(mc, (mc->mc_db->md_entries > 0 && nkeys > 0) ||
-                       ((mc->mc_flags & C_SUB) && mc->mc_db->md_entries == 0 &&
-                        nkeys == 0));
-
-  /* Adjust this and other cursors pointing to mp */
-  for (MDBX_cursor *m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) {
-    MDBX_cursor *m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-    if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED))
-      continue;
-    if (m3->mc_snum < mc->mc_snum)
-      continue;
-    if (m3->mc_pg[mc->mc_top] == mp) {
-      /* if m3 points past last node in page, find next sibling */
-      if (m3->mc_ki[mc->mc_top] >= nkeys) {
-        rc = mdbx_cursor_sibling(m3, SIBLING_RIGHT);
-        if (rc == MDBX_NOTFOUND) {
-          m3->mc_flags |= C_EOF;
-          rc = MDBX_SUCCESS;
-          continue;
-        }
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      }
-      if (m3->mc_ki[mc->mc_top] >= ki ||
-          /* moved to right sibling */ m3->mc_pg[mc->mc_top] != mp) {
-        if (m3->mc_xcursor && !(m3->mc_flags & C_EOF)) {
-          MDBX_node *node =
-              page_node(m3->mc_pg[m3->mc_top], m3->mc_ki[m3->mc_top]);
-          /* If this node has dupdata, it may need to be reinited
-           * because its data has moved.
-           * If the xcursor was not inited it must be reinited.
-           * Else if node points to a subDB, nothing is needed. */
-          if (node_flags(node) & F_DUPDATA) {
-            if (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
-              if (!(node_flags(node) & F_SUBDATA))
-                m3->mc_xcursor->mx_cursor.mc_pg[0] = node_data(node);
-            } else {
-              rc = mdbx_xcursor_init1(m3, node, m3->mc_pg[m3->mc_top]);
-              if (unlikely(rc != MDBX_SUCCESS))
-                goto bailout;
-              rc = mdbx_cursor_first(&m3->mc_xcursor->mx_cursor, NULL, NULL);
-              if (unlikely(rc != MDBX_SUCCESS))
-                goto bailout;
-            }
-          }
-          m3->mc_xcursor->mx_cursor.mc_flags |= C_DEL;
-        }
-        m3->mc_flags |= C_DEL;
-      }
-    }
-  }
-
-  mdbx_cassert(mc, rc == MDBX_SUCCESS);
-  if (mdbx_audit_enabled())
-    rc = mdbx_cursor_check(mc, 0);
-  return rc;
-
-bailout:
-  mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-  return rc;
-}
-
-int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-             const MDBX_val *data) {
-  int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!key))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
-    return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
-
-  return mdbx_del0(txn, dbi, key, data, 0);
-}
-
-static int mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                     const MDBX_val *data, unsigned flags) {
-  MDBX_cursor_couple cx;
-  MDBX_cursor_op op;
-  MDBX_val rdata;
-  int rc;
-  DKBUF_DEBUG;
-
-  mdbx_debug("====> delete db %u key [%s], data [%s]", dbi, DKEY_DEBUG(key),
-             DVAL_DEBUG(data));
-
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (data) {
-    op = MDBX_GET_BOTH;
-    rdata = *data;
-    data = &rdata;
-  } else {
-    op = MDBX_SET;
-    flags |= MDBX_ALLDUPS;
-  }
-  rc = mdbx_cursor_set(&cx.outer, (MDBX_val *)key, (MDBX_val *)data, op).err;
-  if (likely(rc == MDBX_SUCCESS)) {
-    /* let mdbx_page_split know about this cursor if needed:
-     * delete will trigger a rebalance; if it needs to move
-     * a node from one page to another, it will have to
-     * update the parent's separator key(s). If the new sepkey
-     * is larger than the current one, the parent page may
-     * run out of space, triggering a split. We need this
-     * cursor to be consistent until the end of the rebalance. */
-    cx.outer.mc_next = txn->mt_cursors[dbi];
-    txn->mt_cursors[dbi] = &cx.outer;
-    rc = mdbx_cursor_del(&cx.outer, flags);
-    txn->mt_cursors[dbi] = cx.outer.mc_next;
-  }
-  return rc;
-}
-
-/* Split a page and insert a new node.
- * Set MDBX_TXN_ERROR on failure.
- * [in,out] mc Cursor pointing to the page and desired insertion index.
- * The cursor will be updated to point to the actual page and index where
- * the node got inserted after the split.
- * [in] newkey The key for the newly inserted node.
- * [in] newdata The data for the newly inserted node.
- * [in] newpgno The page number, if the new node is a branch node.
- * [in] nflags The NODE_ADD_FLAGS for the new node.
- * Returns 0 on success, non-zero on failure. */
-static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *const newkey,
-                           MDBX_val *const newdata, pgno_t newpgno,
-                           unsigned nflags) {
-  unsigned flags;
-  int rc = MDBX_SUCCESS, foliage = 0;
-  unsigned i, ptop;
-  MDBX_env *const env = mc->mc_txn->mt_env;
-  MDBX_val sepkey, rkey, xdata;
-  MDBX_page *tmp_ki_copy = NULL;
-  DKBUF;
-
-  MDBX_page *const mp = mc->mc_pg[mc->mc_top];
-  const unsigned newindx = mc->mc_ki[mc->mc_top];
-  unsigned nkeys = page_numkeys(mp);
-  if (mdbx_audit_enabled()) {
-    rc = mdbx_cursor_check(mc, C_UPDATING);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-  STATIC_ASSERT(P_BRANCH == 1);
-  const unsigned minkeys = (mp->mp_flags & P_BRANCH) + 1;
-
-  mdbx_debug(">> splitting %s-page %" PRIaPGNO
-             " and adding %zu+%zu [%s] at %i, nkeys %i",
-             IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno, newkey->iov_len,
-             newdata ? newdata->iov_len : 0, DKEY_DEBUG(newkey),
-             mc->mc_ki[mc->mc_top], nkeys);
-  mdbx_cassert(mc, nkeys + 1 >= minkeys * 2);
-
-  /* Create a new sibling page. */
-  struct page_result npr = mdbx_page_new(mc, mp->mp_flags, 1);
-  if (unlikely(npr.err != MDBX_SUCCESS))
-    return npr.err;
-  MDBX_page *const sister = npr.page;
-  sister->mp_leaf2_ksize = mp->mp_leaf2_ksize;
-  mdbx_debug("new sibling: page %" PRIaPGNO, sister->mp_pgno);
-
-  /* Usually when splitting the root page, the cursor
-   * height is 1. But when called from mdbx_update_key,
-   * the cursor height may be greater because it walks
-   * up the stack while finding the branch slot to update. */
-  if (mc->mc_top < 1) {
-    npr = mdbx_page_new(mc, P_BRANCH, 1);
-    rc = npr.err;
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto done;
-    MDBX_page *const pp = npr.page;
-    /* shift current top to make room for new parent */
-    mdbx_cassert(mc, mc->mc_snum < 2 && mc->mc_db->md_depth > 0);
-#if MDBX_DEBUG
-    memset(mc->mc_pg + 3, 0, sizeof(mc->mc_pg) - sizeof(mc->mc_pg[0]) * 3);
-    memset(mc->mc_ki + 3, -1, sizeof(mc->mc_ki) - sizeof(mc->mc_ki[0]) * 3);
-#endif
-    mc->mc_pg[2] = mc->mc_pg[1];
-    mc->mc_ki[2] = mc->mc_ki[1];
-    mc->mc_pg[1] = mc->mc_pg[0];
-    mc->mc_ki[1] = mc->mc_ki[0];
-    mc->mc_pg[0] = pp;
-    mc->mc_ki[0] = 0;
-    mc->mc_db->md_root = pp->mp_pgno;
-    mdbx_debug("root split! new root = %" PRIaPGNO, pp->mp_pgno);
-    foliage = mc->mc_db->md_depth++;
-
-    /* Add left (implicit) pointer. */
-    rc = mdbx_node_add_branch(mc, 0, NULL, mp->mp_pgno);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      /* undo the pre-push */
-      mc->mc_pg[0] = mc->mc_pg[1];
-      mc->mc_ki[0] = mc->mc_ki[1];
-      mc->mc_db->md_root = mp->mp_pgno;
-      mc->mc_db->md_depth--;
-      goto done;
-    }
-    mc->mc_snum++;
-    mc->mc_top++;
-    ptop = 0;
-    if (mdbx_audit_enabled()) {
-      rc = mdbx_cursor_check(mc, C_UPDATING);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto done;
-    }
-  } else {
-    ptop = mc->mc_top - 1;
-    mdbx_debug("parent branch page is %" PRIaPGNO, mc->mc_pg[ptop]->mp_pgno);
-  }
-
-  MDBX_cursor mn;
-  cursor_copy(mc, &mn);
-  mn.mc_pg[mn.mc_top] = sister;
-  mn.mc_ki[mn.mc_top] = 0;
-  mn.mc_ki[ptop] = mc->mc_ki[ptop] + 1;
-
-  unsigned split_indx =
-      (newindx < nkeys)
-          ? /* split at the middle */ (nkeys + 1) / 2
-          : /* split at the end (i.e. like append-mode ) */ nkeys - minkeys + 1;
-
-  mdbx_cassert(mc, !IS_BRANCH(mp) || newindx > 0);
-  /* It is reasonable and possible to split the page at the begin */
-  if (unlikely(newindx < minkeys)) {
-    split_indx = minkeys;
-    if (newindx == 0 && foliage == 0 && !(nflags & MDBX_SPLIT_REPLACE)) {
-      split_indx = 0;
-      /* Checking for ability of splitting by the left-side insertion
-       * of a pure page with the new key */
-      for (i = 0; i < mc->mc_top; ++i)
-        if (mc->mc_ki[i]) {
-          get_key(page_node(mc->mc_pg[i], mc->mc_ki[i]), &sepkey);
-          if (mc->mc_dbx->md_cmp(newkey, &sepkey) >= 0)
-            split_indx = minkeys;
-          break;
-        }
-      if (split_indx == 0) {
-        /* Save the current first key which was omitted on the parent branch
-         * page and should be updated if the new first entry will be added */
-        if (IS_LEAF2(mp)) {
-          sepkey.iov_len = mp->mp_leaf2_ksize;
-          sepkey.iov_base = page_leaf2key(mp, 0, sepkey.iov_len);
-        } else
-          get_key(page_node(mp, 0), &sepkey);
-        mdbx_cassert(mc, mc->mc_dbx->md_cmp(newkey, &sepkey) < 0);
-        /* Avoiding rare complex cases of split the parent page */
-        if (page_room(mn.mc_pg[ptop]) < branch_size(env, &sepkey))
-          split_indx = minkeys;
-      }
-    }
-  }
-
-  const bool pure_right = split_indx == nkeys;
-  const bool pure_left = split_indx == 0;
-  if (unlikely(pure_right)) {
-    /* newindx == split_indx == nkeys */
-    mdbx_trace("no-split, but add new pure page at the %s", "right/after");
-    mdbx_cassert(mc, newindx == nkeys && split_indx == nkeys && minkeys == 1);
-    sepkey = *newkey;
-  } else if (unlikely(pure_left)) {
-    /* newindx == split_indx == 0 */
-    mdbx_trace("no-split, but add new pure page at the %s", "left/before");
-    mdbx_cassert(mc, newindx == 0 && split_indx == 0 && minkeys == 1);
-    mdbx_trace("old-first-key is %s", DKEY_DEBUG(&sepkey));
-  } else {
-    if (IS_LEAF2(sister)) {
-      char *split, *ins;
-      unsigned lsize, rsize, ksize;
-      /* Move half of the keys to the right sibling */
-      const int x = mc->mc_ki[mc->mc_top] - split_indx;
-      ksize = mc->mc_db->md_xsize;
-      split = page_leaf2key(mp, split_indx, ksize);
-      rsize = (nkeys - split_indx) * ksize;
-      lsize = (nkeys - split_indx) * sizeof(indx_t);
-      mdbx_cassert(mc, mp->mp_lower >= lsize);
-      mp->mp_lower -= (indx_t)lsize;
-      mdbx_cassert(mc, sister->mp_lower + lsize <= UINT16_MAX);
-      sister->mp_lower += (indx_t)lsize;
-      mdbx_cassert(mc, mp->mp_upper + rsize - lsize <= UINT16_MAX);
-      mp->mp_upper += (indx_t)(rsize - lsize);
-      mdbx_cassert(mc, sister->mp_upper >= rsize - lsize);
-      sister->mp_upper -= (indx_t)(rsize - lsize);
-      sepkey.iov_len = ksize;
-      sepkey.iov_base = (newindx != split_indx) ? split : newkey->iov_base;
-      if (x < 0) {
-        mdbx_cassert(mc, ksize >= sizeof(indx_t));
-        ins = page_leaf2key(mp, mc->mc_ki[mc->mc_top], ksize);
-        memcpy(sister->mp_ptrs, split, rsize);
-        sepkey.iov_base = sister->mp_ptrs;
-        memmove(ins + ksize, ins, (split_indx - mc->mc_ki[mc->mc_top]) * ksize);
-        memcpy(ins, newkey->iov_base, ksize);
-        mdbx_cassert(mc, UINT16_MAX - mp->mp_lower >= (int)sizeof(indx_t));
-        mp->mp_lower += sizeof(indx_t);
-        mdbx_cassert(mc, mp->mp_upper >= ksize - sizeof(indx_t));
-        mp->mp_upper -= (indx_t)(ksize - sizeof(indx_t));
-      } else {
-        memcpy(sister->mp_ptrs, split, x * ksize);
-        ins = page_leaf2key(sister, x, ksize);
-        memcpy(ins, newkey->iov_base, ksize);
-        memcpy(ins + ksize, split + x * ksize, rsize - x * ksize);
-        mdbx_cassert(mc, UINT16_MAX - sister->mp_lower >= (int)sizeof(indx_t));
-        sister->mp_lower += sizeof(indx_t);
-        mdbx_cassert(mc, sister->mp_upper >= ksize - sizeof(indx_t));
-        sister->mp_upper -= (indx_t)(ksize - sizeof(indx_t));
-        mdbx_cassert(mc, x <= (int)UINT16_MAX);
-        mc->mc_ki[mc->mc_top] = (indx_t)x;
-      }
-
-      if (mdbx_audit_enabled()) {
-        rc = mdbx_cursor_check(mc, C_UPDATING);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto done;
-        rc = mdbx_cursor_check(&mn, C_UPDATING);
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto done;
-      }
-    } else {
-      /* Maximum free space in an empty page */
-      const unsigned max_space = page_space(env);
-      const size_t new_size = IS_LEAF(mp) ? leaf_size(env, newkey, newdata)
-                                          : branch_size(env, newkey);
-
-      /* grab a page to hold a temporary copy */
-      tmp_ki_copy = mdbx_page_malloc(mc->mc_txn, 1);
-      if (unlikely(tmp_ki_copy == NULL)) {
-        rc = MDBX_ENOMEM;
-        goto done;
-      }
-
-      /* prepare to insert */
-      for (unsigned j = i = 0; i < nkeys; ++i, ++j) {
-        tmp_ki_copy->mp_ptrs[j] = 0;
-        j += (i == newindx);
-        tmp_ki_copy->mp_ptrs[j] = mp->mp_ptrs[i];
-      }
-      tmp_ki_copy->mp_pgno = mp->mp_pgno;
-      tmp_ki_copy->mp_flags = mp->mp_flags;
-      tmp_ki_copy->mp_txnid = INVALID_TXNID;
-      tmp_ki_copy->mp_lower = 0;
-      tmp_ki_copy->mp_upper = (indx_t)max_space;
-
-      /* When items are relatively large the split point needs
-       * to be checked, because being off-by-one will make the
-       * difference between success or failure in mdbx_node_add.
-       *
-       * It's also relevant if a page happens to be laid out
-       * such that one half of its nodes are all "small" and
-       * the other half of its nodes are "large". If the new
-       * item is also "large" and falls on the half with
-       * "large" nodes, it also may not fit.
-       *
-       * As a final tweak, if the new item goes on the last
-       * spot on the page (and thus, onto the new page), bias
-       * the split so the new page is emptier than the old page.
-       * This yields better packing during sequential inserts. */
-
-      if (nkeys < 32 || new_size > max_space / 16) {
-        /* Find split point */
-        int dir;
-        if (newindx <= split_indx) {
-          i = 0;
-          dir = 1;
-        } else {
-          i = nkeys;
-          dir = -1;
-        }
-        size_t before = 0, after = new_size + page_used(env, mp);
-        int best = split_indx;
-        int best_offset = nkeys + 1;
-
-        mdbx_trace("seek separator from %u, step %i, default %u, new-idx %u, "
-                   "new-size %zu",
-                   i, dir, split_indx, newindx, new_size);
-        do {
-          mdbx_cassert(mc, i <= nkeys);
-          size_t size = new_size;
-          if (i != newindx) {
-            MDBX_node *node =
-                (MDBX_node *)((char *)mp + tmp_ki_copy->mp_ptrs[i] + PAGEHDRSZ);
-            size = NODESIZE + node_ks(node) + sizeof(indx_t);
-            if (IS_LEAF(mp))
-              size += F_ISSET(node_flags(node), F_BIGDATA) ? sizeof(pgno_t)
-                                                           : node_ds(node);
-            size = EVEN(size);
-          }
-
-          before += size;
-          after -= size;
-          mdbx_trace("step %u, size %zu, before %zu, after %zu, max %u", i,
-                     size, before, after, max_space);
-
-          if (before <= max_space && after <= max_space) {
-            int offset = branchless_abs(split_indx - i);
-            if (offset >= best_offset)
-              break;
-            best_offset = offset;
-            best = i;
-          }
-          i += dir;
-        } while (i < nkeys);
-
-        split_indx = best + (dir > 0);
-        split_indx = (split_indx <= nkeys - minkeys + 1) ? split_indx
-                                                         : nkeys - minkeys + 1;
-        split_indx = (split_indx >= minkeys) ? split_indx : minkeys;
-        mdbx_trace("chosen %u", split_indx);
-      }
-
-      sepkey.iov_len = newkey->iov_len;
-      sepkey.iov_base = newkey->iov_base;
-      if (split_indx != newindx) {
-        MDBX_node *node =
-            (MDBX_node *)((char *)mp + tmp_ki_copy->mp_ptrs[split_indx] +
-                          PAGEHDRSZ);
-        sepkey.iov_len = node_ks(node);
-        sepkey.iov_base = node_key(node);
-      }
-    }
-  }
-  mdbx_debug("separator is %d [%s]", split_indx, DKEY_DEBUG(&sepkey));
-
-  bool did_split_parent = false;
-  /* Copy separator key to the parent. */
-  if (page_room(mn.mc_pg[ptop]) < branch_size(env, &sepkey)) {
-    mdbx_trace("need split parent branch-page for key %s", DKEY_DEBUG(&sepkey));
-    mdbx_cassert(mc, page_numkeys(mn.mc_pg[ptop]) > 2);
-    mdbx_cassert(mc, !pure_left);
-    const int snum = mc->mc_snum;
-    const int depth = mc->mc_db->md_depth;
-    mn.mc_snum--;
-    mn.mc_top--;
-    did_split_parent = true;
-    /* We want other splits to find mn when doing fixups */
-    WITH_CURSOR_TRACKING(
-        mn, rc = mdbx_page_split(&mn, &sepkey, NULL, sister->mp_pgno, 0));
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto done;
-    mdbx_cassert(mc, (int)mc->mc_snum - snum == mc->mc_db->md_depth - depth);
-    if (mdbx_audit_enabled()) {
-      rc = mdbx_cursor_check(mc, C_UPDATING);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto done;
-    }
-
-    /* root split? */
-    ptop += mc->mc_snum - snum;
-
-    /* Right page might now have changed parent.
-     * Check if left page also changed parent. */
-    if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
-        mc->mc_ki[ptop] >= page_numkeys(mc->mc_pg[ptop])) {
-      for (i = 0; i < ptop; i++) {
-        mc->mc_pg[i] = mn.mc_pg[i];
-        mc->mc_ki[i] = mn.mc_ki[i];
-      }
-      mc->mc_pg[ptop] = mn.mc_pg[ptop];
-      if (mn.mc_ki[ptop]) {
-        mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
-      } else {
-        /* find right page's left sibling */
-        mc->mc_ki[ptop] = mn.mc_ki[ptop];
-        rc = mdbx_cursor_sibling(mc, SIBLING_LEFT);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          if (rc == MDBX_NOTFOUND) /* improper mdbx_cursor_sibling() result */ {
-            mdbx_error("unexpected %i error going left sibling", rc);
-            rc = MDBX_PROBLEM;
-          }
-          goto done;
-        }
-      }
-    }
-  } else if (unlikely(pure_left)) {
-    MDBX_page *ptop_page = mc->mc_pg[ptop];
-    mdbx_debug("adding to parent page %u node[%u] left-leaf page #%u key %s",
-               ptop_page->mp_pgno, mc->mc_ki[ptop], sister->mp_pgno,
-               DKEY(mc->mc_ki[ptop] ? newkey : NULL));
-    mc->mc_top--;
-    rc = mdbx_node_add_branch(mc, mc->mc_ki[ptop],
-                              mc->mc_ki[ptop] ? newkey : NULL, sister->mp_pgno);
-    mdbx_cassert(mc, mp == mc->mc_pg[ptop + 1] &&
-                         newindx == mc->mc_ki[ptop + 1] && ptop == mc->mc_top);
-
-    if (likely(rc == MDBX_SUCCESS) && mc->mc_ki[ptop] == 0) {
-      mdbx_debug("update prev-first key on parent %s", DKEY(&sepkey));
-      MDBX_node *node = page_node(mc->mc_pg[ptop], 1);
-      mdbx_cassert(mc, node_ks(node) == 0 && node_pgno(node) == mp->mp_pgno);
-      mdbx_cassert(mc, mc->mc_top == ptop && mc->mc_ki[ptop] == 0);
-      mc->mc_ki[ptop] = 1;
-      rc = mdbx_update_key(mc, &sepkey);
-      mdbx_cassert(mc, mc->mc_top == ptop && mc->mc_ki[ptop] == 1);
-      mdbx_cassert(mc,
-                   mp == mc->mc_pg[ptop + 1] && newindx == mc->mc_ki[ptop + 1]);
-      mc->mc_ki[ptop] = 0;
-    }
-
-    mc->mc_top++;
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto done;
-
-    MDBX_node *node = page_node(mc->mc_pg[ptop], mc->mc_ki[ptop] + 1);
-    mdbx_cassert(mc, node_pgno(node) == mp->mp_pgno &&
-                         mc->mc_pg[ptop] == ptop_page);
-  } else {
-    mn.mc_top--;
-    mdbx_trace("add-to-parent the right-entry[%u] for new sibling-page",
-               mn.mc_ki[ptop]);
-    rc = mdbx_node_add_branch(&mn, mn.mc_ki[ptop], &sepkey, sister->mp_pgno);
-    mn.mc_top++;
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto done;
-  }
-
-  if (unlikely(pure_left | pure_right)) {
-    mc->mc_pg[mc->mc_top] = sister;
-    mc->mc_ki[mc->mc_top] = 0;
-    switch (PAGETYPE(sister)) {
-    case P_LEAF: {
-      mdbx_cassert(mc, newpgno == 0 || newpgno == P_INVALID);
-      rc = mdbx_node_add_leaf(mc, 0, newkey, newdata, nflags);
-    } break;
-    case P_LEAF | P_LEAF2: {
-      mdbx_cassert(mc, (nflags & (F_BIGDATA | F_SUBDATA | F_DUPDATA)) == 0);
-      mdbx_cassert(mc, newpgno == 0 || newpgno == P_INVALID);
-      rc = mdbx_node_add_leaf2(mc, 0, newkey);
-    } break;
-    default:
-      rc = bad_page(sister, "wrong page-type %u\n", PAGETYPE(sister));
-    }
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto done;
-
-    if (pure_right) {
-      for (i = 0; i < mc->mc_top; i++)
-        mc->mc_ki[i] = mn.mc_ki[i];
-    } else if (mc->mc_ki[mc->mc_top - 1] == 0) {
-      for (i = 2; i <= mc->mc_top; ++i)
-        if (mc->mc_ki[mc->mc_top - i]) {
-          get_key(
-              page_node(mc->mc_pg[mc->mc_top - i], mc->mc_ki[mc->mc_top - i]),
-              &sepkey);
-          if (mc->mc_dbx->md_cmp(newkey, &sepkey) < 0) {
-            mc->mc_top -= i;
-            mdbx_debug("update new-first on parent [%i] page %u key %s",
-                       mc->mc_ki[mc->mc_top], mc->mc_pg[mc->mc_top]->mp_pgno,
-                       DKEY(newkey));
-            rc = mdbx_update_key(mc, newkey);
-            mc->mc_top += i;
-            if (unlikely(rc != MDBX_SUCCESS))
-              goto done;
-          }
-          break;
-        }
-    }
-  } else if (!IS_LEAF2(mp)) {
-    /* Move nodes */
-    mc->mc_pg[mc->mc_top] = sister;
-    i = split_indx;
-    unsigned n = 0;
-    pgno_t pgno = 0;
-    do {
-      mdbx_trace("i %u, nkeys %u => n %u, rp #%u", i, nkeys, n,
-                 sister->mp_pgno);
-      MDBX_val *rdata = NULL;
-      if (i == newindx) {
-        rkey.iov_base = newkey->iov_base;
-        rkey.iov_len = newkey->iov_len;
-        if (IS_LEAF(mp))
-          rdata = newdata;
-        else
-          pgno = newpgno;
-        flags = nflags;
-        /* Update index for the new key. */
-        mc->mc_ki[mc->mc_top] = (indx_t)n;
-      } else {
-        MDBX_node *node =
-            (MDBX_node *)((char *)mp + tmp_ki_copy->mp_ptrs[i] + PAGEHDRSZ);
-        rkey.iov_base = node_key(node);
-        rkey.iov_len = node_ks(node);
-        if (IS_LEAF(mp)) {
-          xdata.iov_base = node_data(node);
-          xdata.iov_len = node_ds(node);
-          rdata = &xdata;
-        } else
-          pgno = node_pgno(node);
-        flags = node_flags(node);
-      }
-
-      switch (PAGETYPE(sister)) {
-      case P_BRANCH: {
-        mdbx_cassert(mc, 0 == (uint16_t)flags);
-        /* First branch index doesn't need key data. */
-        rc = mdbx_node_add_branch(mc, n, n ? &rkey : NULL, pgno);
-      } break;
-      case P_LEAF: {
-        mdbx_cassert(mc, pgno == 0);
-        mdbx_cassert(mc, rdata != NULL);
-        rc = mdbx_node_add_leaf(mc, n, &rkey, rdata, flags);
-      } break;
-      /* case P_LEAF | P_LEAF2: {
-        mdbx_cassert(mc, (nflags & (F_BIGDATA | F_SUBDATA | F_DUPDATA)) == 0);
-        mdbx_cassert(mc, gno == 0);
-        rc = mdbx_node_add_leaf2(mc, n, &rkey);
-      } break; */
-      default:
-        rc = bad_page(sister, "wrong page-type %u\n", PAGETYPE(sister));
-      }
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto done;
-
-      ++n;
-      if (++i > nkeys) {
-        i = 0;
-        n = 0;
-        mc->mc_pg[mc->mc_top] = tmp_ki_copy;
-        mdbx_trace("switch to mp #%u", tmp_ki_copy->mp_pgno);
-      }
-    } while (i != split_indx);
-
-    mdbx_trace("i %u, nkeys %u, n %u, pgno #%u", i, nkeys, n,
-               mc->mc_pg[mc->mc_top]->mp_pgno);
-
-    nkeys = page_numkeys(tmp_ki_copy);
-    for (i = 0; i < nkeys; i++)
-      mp->mp_ptrs[i] = tmp_ki_copy->mp_ptrs[i];
-    mp->mp_lower = tmp_ki_copy->mp_lower;
-    mp->mp_upper = tmp_ki_copy->mp_upper;
-    memcpy(page_node(mp, nkeys - 1), page_node(tmp_ki_copy, nkeys - 1),
-           env->me_psize - tmp_ki_copy->mp_upper - PAGEHDRSZ);
-
-    /* reset back to original page */
-    if (newindx < split_indx) {
-      mc->mc_pg[mc->mc_top] = mp;
-    } else {
-      mc->mc_pg[mc->mc_top] = sister;
-      mc->mc_ki[ptop]++;
-      /* Make sure mc_ki is still valid. */
-      if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
-          mc->mc_ki[ptop] >= page_numkeys(mc->mc_pg[ptop])) {
-        for (i = 0; i <= ptop; i++) {
-          mc->mc_pg[i] = mn.mc_pg[i];
-          mc->mc_ki[i] = mn.mc_ki[i];
-        }
-      }
-    }
-  } else if (newindx >= split_indx) {
-    mc->mc_pg[mc->mc_top] = sister;
-    mc->mc_ki[ptop]++;
-    /* Make sure mc_ki is still valid. */
-    if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
-        mc->mc_ki[ptop] >= page_numkeys(mc->mc_pg[ptop])) {
-      for (i = 0; i <= ptop; i++) {
-        mc->mc_pg[i] = mn.mc_pg[i];
-        mc->mc_ki[i] = mn.mc_ki[i];
-      }
-    }
-  }
-
-  /* Adjust other cursors pointing to mp and/or to parent page */
-  nkeys = page_numkeys(mp);
-  for (MDBX_cursor *m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2;
-       m2 = m2->mc_next) {
-    MDBX_cursor *m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
-    if (m3 == mc)
-      continue;
-    if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED))
-      continue;
-    if (foliage) {
-      /* sub cursors may be on different DB */
-      if (m3->mc_pg[0] != mp)
-        continue;
-      /* root split */
-      for (int k = foliage; k >= 0; k--) {
-        m3->mc_ki[k + 1] = m3->mc_ki[k];
-        m3->mc_pg[k + 1] = m3->mc_pg[k];
-      }
-      m3->mc_ki[0] = (m3->mc_ki[0] >= nkeys) ? 1 : 0;
-      m3->mc_pg[0] = mc->mc_pg[0];
-      m3->mc_snum++;
-      m3->mc_top++;
-    }
-
-    if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp && !pure_left) {
-      if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDBX_SPLIT_REPLACE))
-        m3->mc_ki[mc->mc_top]++;
-      if (m3->mc_ki[mc->mc_top] >= nkeys) {
-        m3->mc_pg[mc->mc_top] = sister;
-        mdbx_cassert(mc, m3->mc_ki[mc->mc_top] >= nkeys);
-        m3->mc_ki[mc->mc_top] -= (indx_t)nkeys;
-        for (i = 0; i < mc->mc_top; i++) {
-          m3->mc_ki[i] = mn.mc_ki[i];
-          m3->mc_pg[i] = mn.mc_pg[i];
-        }
-      }
-    } else if (!did_split_parent && m3->mc_top >= ptop &&
-               m3->mc_pg[ptop] == mc->mc_pg[ptop] &&
-               m3->mc_ki[ptop] >= mc->mc_ki[ptop]) {
-      m3->mc_ki[ptop]++; /* also for the `pure-left` case */
-    }
-    if (XCURSOR_INITED(m3) && IS_LEAF(mp))
-      XCURSOR_REFRESH(m3, m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]);
-  }
-  mdbx_trace("mp #%u left: %d, sister #%u left: %d", mp->mp_pgno, page_room(mp),
-             sister->mp_pgno, page_room(sister));
-
-done:
-  if (tmp_ki_copy)
-    mdbx_dpage_free(env, tmp_ki_copy, 1);
-
-  if (unlikely(rc != MDBX_SUCCESS))
-    mc->mc_txn->mt_flags |= MDBX_TXN_ERROR;
-  else {
-    if (mdbx_audit_enabled())
-      rc = mdbx_cursor_check(mc, C_UPDATING);
-    if (unlikely(nflags & MDBX_RESERVE)) {
-      MDBX_node *node = page_node(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
-      if (!(node_flags(node) & F_BIGDATA))
-        newdata->iov_base = node_data(node);
-    }
-#if MDBX_ENABLE_PGOP_STAT
-    env->me_lck->mti_pgop_stat.split.weak += 1;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-  }
-
-  mdbx_debug("<< mp #%u, rc %d", mp->mp_pgno, rc);
-  return rc;
-}
-
-int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data,
-             unsigned flags) {
-  int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!key || !data))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(flags & ~(MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_ALLDUPS |
-                         MDBX_ALLDUPS | MDBX_RESERVE | MDBX_APPEND |
-                         MDBX_APPENDDUP | MDBX_CURRENT | MDBX_MULTIPLE)))
-    return MDBX_EINVAL;
-
-  if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
-    return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
-
-  MDBX_cursor_couple cx;
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  cx.outer.mc_next = txn->mt_cursors[dbi];
-  txn->mt_cursors[dbi] = &cx.outer;
-
-  /* LY: support for update (explicit overwrite) */
-  if (flags & MDBX_CURRENT) {
-    rc = mdbx_cursor_get(&cx.outer, (MDBX_val *)key, NULL, MDBX_SET);
-    if (likely(rc == MDBX_SUCCESS) &&
-        (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) &&
-        (flags & MDBX_ALLDUPS) == 0) {
-      /* LY: allows update (explicit overwrite) only for unique keys */
-      MDBX_node *node = page_node(cx.outer.mc_pg[cx.outer.mc_top],
-                                  cx.outer.mc_ki[cx.outer.mc_top]);
-      if (F_ISSET(node_flags(node), F_DUPDATA)) {
-        mdbx_tassert(txn, XCURSOR_INITED(&cx.outer) &&
-                              cx.outer.mc_xcursor->mx_db.md_entries > 1);
-        rc = MDBX_EMULTIVAL;
-      }
-    }
-  }
-
-  if (likely(rc == MDBX_SUCCESS))
-    rc = mdbx_cursor_put(&cx.outer, key, data, flags);
-  txn->mt_cursors[dbi] = cx.outer.mc_next;
-
-  return rc;
-}
-
-/**** COPYING *****************************************************************/
-
-/* State needed for a double-buffering compacting copy. */
-typedef struct mdbx_copy {
-  MDBX_env *mc_env;
-  MDBX_txn *mc_txn;
-  mdbx_condpair_t mc_condpair;
-  uint8_t *mc_wbuf[2];
-  uint8_t *mc_over[2];
-  size_t mc_wlen[2];
-  size_t mc_olen[2];
-  mdbx_filehandle_t mc_fd;
-  /* Error code.  Never cleared if set.  Both threads can set nonzero
-   * to fail the copy.  Not mutex-protected, MDBX expects atomic int. */
-  volatile int mc_error;
-  pgno_t mc_next_pgno;
-  volatile unsigned mc_head;
-  volatile unsigned mc_tail;
-} mdbx_copy;
-
-/* Dedicated writer thread for compacting copy. */
-__cold static THREAD_RESULT THREAD_CALL mdbx_env_copythr(void *arg) {
-  mdbx_copy *my = arg;
-
-#if defined(EPIPE) && !(defined(_WIN32) || defined(_WIN64))
-  sigset_t sigset;
-  sigemptyset(&sigset);
-  sigaddset(&sigset, SIGPIPE);
-  my->mc_error = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
-#endif /* EPIPE */
-
-  mdbx_condpair_lock(&my->mc_condpair);
-  while (!my->mc_error) {
-    while (my->mc_tail == my->mc_head && !my->mc_error) {
-      int err = mdbx_condpair_wait(&my->mc_condpair, true);
-      if (err != MDBX_SUCCESS) {
-        my->mc_error = err;
-        goto bailout;
-      }
-    }
-    const unsigned toggle = my->mc_tail & 1;
-    size_t wsize = my->mc_wlen[toggle];
-    if (wsize == 0) {
-      my->mc_tail += 1;
-      break /* EOF */;
-    }
-    my->mc_wlen[toggle] = 0;
-    uint8_t *ptr = my->mc_wbuf[toggle];
-  again:
-    if (!my->mc_error) {
-      int err = mdbx_write(my->mc_fd, ptr, wsize);
-      if (err != MDBX_SUCCESS) {
-#if defined(EPIPE) && !(defined(_WIN32) || defined(_WIN64))
-        if (err == EPIPE) {
-          /* Collect the pending SIGPIPE,
-           * otherwise at least OS X gives it to the process on thread-exit. */
-          int unused;
-          sigwait(&sigset, &unused);
-        }
-#endif /* EPIPE */
-        my->mc_error = err;
-        goto bailout;
-      }
-    }
-
-    /* If there's an overflow page tail, write it too */
-    wsize = my->mc_olen[toggle];
-    if (wsize) {
-      my->mc_olen[toggle] = 0;
-      ptr = my->mc_over[toggle];
-      goto again;
-    }
-    my->mc_tail += 1;
-    mdbx_condpair_signal(&my->mc_condpair, false);
-  }
-bailout:
-  mdbx_condpair_unlock(&my->mc_condpair);
-  return (THREAD_RESULT)0;
-}
-
-/* Give buffer and/or MDBX_EOF to writer thread, await unused buffer. */
-__cold static int mdbx_env_cthr_toggle(mdbx_copy *my) {
-  mdbx_condpair_lock(&my->mc_condpair);
-  mdbx_assert(my->mc_env, my->mc_head - my->mc_tail < 2 || my->mc_error);
-  my->mc_head += 1;
-  mdbx_condpair_signal(&my->mc_condpair, true);
-  while (!my->mc_error &&
-         my->mc_head - my->mc_tail == 2 /* both buffers in use */) {
-    int err = mdbx_condpair_wait(&my->mc_condpair, false);
-    if (err != MDBX_SUCCESS)
-      my->mc_error = err;
-  }
-  mdbx_condpair_unlock(&my->mc_condpair);
-  return my->mc_error;
-}
-
-/* Depth-first tree traversal for compacting copy.
- * [in] my control structure.
- * [in,out] pg database root.
- * [in] flags includes F_DUPDATA if it is a sorted-duplicate sub-DB. */
-__cold static int mdbx_env_cwalk(mdbx_copy *my, pgno_t *pg, int flags) {
-  MDBX_cursor_couple couple;
-  MDBX_page *mo, *mp, *leaf;
-  char *buf, *ptr;
-  int rc;
-  unsigned i;
-
-  /* Empty DB, nothing to do */
-  if (*pg == P_INVALID)
-    return MDBX_SUCCESS;
-
-  memset(&couple, 0, sizeof(couple));
-  couple.outer.mc_snum = 1;
-  couple.outer.mc_txn = my->mc_txn;
-  couple.outer.mc_flags = couple.inner.mx_cursor.mc_flags =
-      C_COPYING | C_SKIPORD;
-
-  rc = mdbx_page_get(&couple.outer, *pg, &couple.outer.mc_pg[0],
-                     my->mc_txn->mt_txnid);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  rc = mdbx_page_search_root(&couple.outer, NULL, MDBX_PS_FIRST);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  /* Make cursor pages writable */
-  buf = ptr = mdbx_malloc(pgno2bytes(my->mc_env, couple.outer.mc_snum));
-  if (buf == NULL)
-    return MDBX_ENOMEM;
-
-  for (i = 0; i < couple.outer.mc_top; i++) {
-    mdbx_page_copy((MDBX_page *)ptr, couple.outer.mc_pg[i],
-                   my->mc_env->me_psize);
-    couple.outer.mc_pg[i] = (MDBX_page *)ptr;
-    ptr += my->mc_env->me_psize;
-  }
-
-  /* This is writable space for a leaf page. Usually not needed. */
-  leaf = (MDBX_page *)ptr;
-
-  while (couple.outer.mc_snum > 0) {
-    mp = couple.outer.mc_pg[couple.outer.mc_top];
-    unsigned n = page_numkeys(mp);
-
-    if (IS_LEAF(mp)) {
-      if (!IS_LEAF2(mp) && !(flags & F_DUPDATA)) {
-        for (i = 0; i < n; i++) {
-          MDBX_node *node = page_node(mp, i);
-          if (node_flags(node) & F_BIGDATA) {
-            MDBX_page *omp;
-
-            /* Need writable leaf */
-            if (mp != leaf) {
-              couple.outer.mc_pg[couple.outer.mc_top] = leaf;
-              mdbx_page_copy(leaf, mp, my->mc_env->me_psize);
-              mp = leaf;
-              node = page_node(mp, i);
-            }
-
-            const pgno_t pgno = node_largedata_pgno(node);
-            poke_pgno(node_data(node), my->mc_next_pgno);
-            rc = mdbx_page_get(&couple.outer, pgno, &omp,
-                               pp_txnid4chk(mp, my->mc_txn));
-            if (unlikely(rc != MDBX_SUCCESS))
-              goto done;
-            unsigned toggle = my->mc_head & 1;
-            if (my->mc_wlen[toggle] + my->mc_env->me_psize >
-                ((size_t)(MDBX_ENVCOPY_WRITEBUF))) {
-              rc = mdbx_env_cthr_toggle(my);
-              if (unlikely(rc != MDBX_SUCCESS))
-                goto done;
-              toggle = my->mc_head & 1;
-            }
-            mo = (MDBX_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]);
-            memcpy(mo, omp, my->mc_env->me_psize);
-            mo->mp_pgno = my->mc_next_pgno;
-            my->mc_next_pgno += omp->mp_pages;
-            my->mc_wlen[toggle] += my->mc_env->me_psize;
-            if (omp->mp_pages > 1) {
-              my->mc_olen[toggle] = pgno2bytes(my->mc_env, omp->mp_pages - 1);
-              my->mc_over[toggle] = (uint8_t *)omp + my->mc_env->me_psize;
-              rc = mdbx_env_cthr_toggle(my);
-              if (unlikely(rc != MDBX_SUCCESS))
-                goto done;
-              toggle = my->mc_head & 1;
-            }
-          } else if (node_flags(node) & F_SUBDATA) {
-            if (!MDBX_DISABLE_PAGECHECKS &&
-                unlikely(node_ds(node) != sizeof(MDBX_db))) {
-              rc = MDBX_CORRUPTED;
-              goto done;
-            }
-
-            /* Need writable leaf */
-            if (mp != leaf) {
-              couple.outer.mc_pg[couple.outer.mc_top] = leaf;
-              mdbx_page_copy(leaf, mp, my->mc_env->me_psize);
-              mp = leaf;
-              node = page_node(mp, i);
-            }
-
-            MDBX_db db;
-            memcpy(&db, node_data(node), sizeof(MDBX_db));
-            rc = mdbx_env_cwalk(my, &db.md_root, node_flags(node) & F_DUPDATA);
-            if (rc)
-              goto done;
-            memcpy(node_data(node), &db, sizeof(MDBX_db));
-          }
-        }
-      }
-    } else {
-      couple.outer.mc_ki[couple.outer.mc_top]++;
-      if (couple.outer.mc_ki[couple.outer.mc_top] < n) {
-      again:
-        rc = mdbx_page_get(
-            &couple.outer,
-            node_pgno(page_node(mp, couple.outer.mc_ki[couple.outer.mc_top])),
-            &mp, pp_txnid4chk(mp, my->mc_txn));
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto done;
-        couple.outer.mc_top++;
-        couple.outer.mc_snum++;
-        couple.outer.mc_ki[couple.outer.mc_top] = 0;
-        if (IS_BRANCH(mp)) {
-          /* Whenever we advance to a sibling branch page,
-           * we must proceed all the way down to its first leaf. */
-          mdbx_page_copy(couple.outer.mc_pg[couple.outer.mc_top], mp,
-                         my->mc_env->me_psize);
-          goto again;
-        } else
-          couple.outer.mc_pg[couple.outer.mc_top] = mp;
-        continue;
-      }
-    }
-    unsigned toggle = my->mc_head & 1;
-    if (my->mc_wlen[toggle] + my->mc_wlen[toggle] >
-        ((size_t)(MDBX_ENVCOPY_WRITEBUF))) {
-      rc = mdbx_env_cthr_toggle(my);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto done;
-      toggle = my->mc_head & 1;
-    }
-    mo = (MDBX_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]);
-    mdbx_page_copy(mo, mp, my->mc_env->me_psize);
-    mo->mp_pgno = my->mc_next_pgno++;
-    my->mc_wlen[toggle] += my->mc_env->me_psize;
-    if (couple.outer.mc_top) {
-      /* Update parent if there is one */
-      node_set_pgno(page_node(couple.outer.mc_pg[couple.outer.mc_top - 1],
-                              couple.outer.mc_ki[couple.outer.mc_top - 1]),
-                    mo->mp_pgno);
-      mdbx_cursor_pop(&couple.outer);
-    } else {
-      /* Otherwise we're done */
-      *pg = mo->mp_pgno;
-      break;
-    }
-  }
-done:
-  mdbx_free(buf);
-  return rc;
-}
-
-__cold static void compact_fixup_meta(MDBX_env *env, MDBX_meta *meta) {
-  /* Calculate filesize taking in account shrink/growing thresholds */
-  if (meta->mm_geo.next != meta->mm_geo.now) {
-    meta->mm_geo.now = meta->mm_geo.next;
-    const pgno_t aligner = pv2pages(
-        meta->mm_geo.grow_pv ? meta->mm_geo.grow_pv : meta->mm_geo.shrink_pv);
-    if (aligner) {
-      const pgno_t aligned = pgno_align2os_pgno(
-          env, meta->mm_geo.next + aligner - meta->mm_geo.next % aligner);
-      meta->mm_geo.now = aligned;
-    }
-  }
-
-  if (meta->mm_geo.now < meta->mm_geo.lower)
-    meta->mm_geo.now = meta->mm_geo.lower;
-  if (meta->mm_geo.now > meta->mm_geo.upper)
-    meta->mm_geo.now = meta->mm_geo.upper;
-
-  /* Update signature */
-  assert(meta->mm_geo.now >= meta->mm_geo.next);
-  unaligned_poke_u64(4, meta->mm_datasync_sign, meta_sign(meta));
-}
-
-/* Make resizeable */
-__cold static void make_sizeable(MDBX_meta *meta) {
-  meta->mm_geo.lower = MIN_PAGENO;
-  if (meta->mm_geo.grow_pv == 0) {
-    const pgno_t step = 1 + (meta->mm_geo.upper - meta->mm_geo.lower) / 42;
-    meta->mm_geo.grow_pv = pages2pv(step);
-  }
-  if (meta->mm_geo.shrink_pv == 0) {
-    const pgno_t step = pv2pages(meta->mm_geo.grow_pv) << 1;
-    meta->mm_geo.shrink_pv = pages2pv(step);
-  }
-}
-
-/* Copy environment with compaction. */
-__cold static int mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
-                                   mdbx_filehandle_t fd, uint8_t *buffer,
-                                   const bool dest_is_pipe, const int flags) {
-  const size_t meta_bytes = pgno2bytes(env, NUM_METAS);
-  uint8_t *const data_buffer =
-      buffer + ceil_powerof2(meta_bytes, env->me_os_psize);
-  MDBX_meta *const meta = mdbx_init_metas(env, buffer);
-  meta_set_txnid(env, meta, read_txn->mt_txnid);
-
-  if (flags & MDBX_CP_FORCE_DYNAMIC_SIZE)
-    make_sizeable(meta);
-
-  /* copy canary sequences if present */
-  if (read_txn->mt_canary.v) {
-    meta->mm_canary = read_txn->mt_canary;
-    meta->mm_canary.v = constmeta_txnid(env, meta);
-  }
-
-  /* Set metapage 1 with current main DB */
-  pgno_t new_root, root = read_txn->mt_dbs[MAIN_DBI].md_root;
-  if ((new_root = root) == P_INVALID) {
-    /* When the DB is empty, handle it specially to
-     * fix any breakage like page leaks from ITS#8174. */
-    meta->mm_dbs[MAIN_DBI].md_flags = read_txn->mt_dbs[MAIN_DBI].md_flags;
-    compact_fixup_meta(env, meta);
-    if (dest_is_pipe) {
-      int rc = mdbx_write(fd, buffer, meta_bytes);
-      if (rc != MDBX_SUCCESS)
-        return rc;
-    }
-  } else {
-    /* Count free pages + GC pages.  Subtract from last_pg
-     * to find the new last_pg, which also becomes the new root. */
-    pgno_t freecount = 0;
-    MDBX_cursor_couple couple;
-    MDBX_val key, data;
-
-    int rc = mdbx_cursor_init(&couple.outer, read_txn, FREE_DBI);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    while ((rc = mdbx_cursor_get(&couple.outer, &key, &data, MDBX_NEXT)) == 0)
-      freecount += *(pgno_t *)data.iov_base;
-    if (unlikely(rc != MDBX_NOTFOUND))
-      return rc;
-
-    freecount += read_txn->mt_dbs[FREE_DBI].md_branch_pages +
-                 read_txn->mt_dbs[FREE_DBI].md_leaf_pages +
-                 read_txn->mt_dbs[FREE_DBI].md_overflow_pages;
-
-    new_root = read_txn->mt_next_pgno - 1 - freecount;
-    meta->mm_geo.next = new_root + 1;
-    meta->mm_dbs[MAIN_DBI] = read_txn->mt_dbs[MAIN_DBI];
-    meta->mm_dbs[MAIN_DBI].md_root = new_root;
-
-    mdbx_copy ctx;
-    memset(&ctx, 0, sizeof(ctx));
-    rc = mdbx_condpair_init(&ctx.mc_condpair);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-
-    memset(data_buffer, 0, ((size_t)(MDBX_ENVCOPY_WRITEBUF)) * 2);
-    ctx.mc_wbuf[0] = data_buffer;
-    ctx.mc_wbuf[1] = data_buffer + ((size_t)(MDBX_ENVCOPY_WRITEBUF));
-    ctx.mc_next_pgno = NUM_METAS;
-    ctx.mc_env = env;
-    ctx.mc_fd = fd;
-    ctx.mc_txn = read_txn;
-
-    mdbx_thread_t thread;
-    int thread_err = mdbx_thread_create(&thread, mdbx_env_copythr, &ctx);
-    if (likely(thread_err == MDBX_SUCCESS)) {
-      if (dest_is_pipe) {
-        compact_fixup_meta(env, meta);
-        rc = mdbx_write(fd, buffer, meta_bytes);
-      }
-      if (rc == MDBX_SUCCESS)
-        rc = mdbx_env_cwalk(&ctx, &root, 0);
-      mdbx_env_cthr_toggle(&ctx);
-      mdbx_env_cthr_toggle(&ctx);
-      thread_err = mdbx_thread_join(thread);
-      mdbx_assert(env, (ctx.mc_tail == ctx.mc_head &&
-                        ctx.mc_wlen[ctx.mc_head & 1] == 0) ||
-                           ctx.mc_error);
-      mdbx_condpair_destroy(&ctx.mc_condpair);
-    }
-    if (unlikely(thread_err != MDBX_SUCCESS))
-      return thread_err;
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    if (unlikely(ctx.mc_error != MDBX_SUCCESS))
-      return ctx.mc_error;
-
-    if (dest_is_pipe) {
-      if (unlikely(root != new_root)) {
-        mdbx_error("post-compactification root %" PRIaPGNO
-                   " NE expected %" PRIaPGNO
-                   " (source DB corrupted or has a page leak(s))",
-                   root, new_root);
-        return MDBX_CORRUPTED; /* page leak or corrupt DB */
-      }
-    } else {
-      if (unlikely(root > new_root)) {
-        mdbx_error("post-compactification root %" PRIaPGNO
-                   " GT expected %" PRIaPGNO " (source DB corrupted)",
-                   root, new_root);
-        return MDBX_CORRUPTED; /* page leak or corrupt DB */
-      }
-      if (unlikely(root < new_root)) {
-        mdbx_warning("post-compactification root %" PRIaPGNO
-                     " LT expected %" PRIaPGNO " (page leak(s) in source DB)",
-                     root, new_root);
-        /* fixup meta */
-        meta->mm_dbs[MAIN_DBI].md_root = root;
-        meta->mm_geo.next = root + 1;
-      }
-      compact_fixup_meta(env, meta);
-    }
-  }
-
-  /* Extend file if required */
-  if (meta->mm_geo.now != meta->mm_geo.next) {
-    const size_t whole_size = pgno2bytes(env, meta->mm_geo.now);
-    if (!dest_is_pipe)
-      return mdbx_ftruncate(fd, whole_size);
-
-    const size_t used_size = pgno2bytes(env, meta->mm_geo.next);
-    memset(data_buffer, 0, ((size_t)(MDBX_ENVCOPY_WRITEBUF)));
-    for (size_t offset = used_size; offset < whole_size;) {
-      const size_t chunk =
-          (((size_t)(MDBX_ENVCOPY_WRITEBUF)) < whole_size - offset)
-              ? ((size_t)(MDBX_ENVCOPY_WRITEBUF))
-              : whole_size - offset;
-      /* copy to avoid EFAULT in case swapped-out */
-      int rc = mdbx_write(fd, data_buffer, chunk);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return rc;
-      offset += chunk;
-    }
-  }
-  return MDBX_SUCCESS;
-}
-
-/* Copy environment as-is. */
-__cold static int mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn,
-                                     mdbx_filehandle_t fd, uint8_t *buffer,
-                                     const bool dest_is_pipe, const int flags) {
-  /* We must start the actual read txn after blocking writers */
-  int rc = mdbx_txn_end(read_txn, MDBX_END_RESET_TMP);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  /* Temporarily block writers until we snapshot the meta pages */
-  rc = mdbx_txn_lock(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  rc = mdbx_txn_renew0(read_txn, MDBX_TXN_RDONLY);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    mdbx_txn_unlock(env);
-    return rc;
-  }
-
-  mdbx_jitter4testing(false);
-  const size_t meta_bytes = pgno2bytes(env, NUM_METAS);
-  /* Make a snapshot of meta-pages,
-   * but writing ones after the data was flushed */
-  memcpy(buffer, env->me_map, meta_bytes);
-  MDBX_meta *const headcopy = /* LY: get pointer to the snapshot copy */
-      (MDBX_meta *)(buffer + ((uint8_t *)meta_prefer_last(env) - env->me_map));
-  mdbx_txn_unlock(env);
-
-  if (flags & MDBX_CP_FORCE_DYNAMIC_SIZE)
-    make_sizeable(headcopy);
-  /* Update signature to steady */
-  unaligned_poke_u64(4, headcopy->mm_datasync_sign, meta_sign(headcopy));
-
-  /* Copy the data */
-  const size_t whole_size = pgno_align2os_bytes(env, read_txn->mt_end_pgno);
-  const size_t used_size = pgno2bytes(env, read_txn->mt_next_pgno);
-  mdbx_jitter4testing(false);
-
-  if (dest_is_pipe)
-    rc = mdbx_write(fd, buffer, meta_bytes);
-
-  uint8_t *const data_buffer =
-      buffer + ceil_powerof2(meta_bytes, env->me_os_psize);
-#if MDBX_USE_COPYFILERANGE
-  static bool copyfilerange_unavailable;
-  bool not_the_same_filesystem = false;
-#endif /* MDBX_USE_COPYFILERANGE */
-  for (size_t offset = meta_bytes; rc == MDBX_SUCCESS && offset < used_size;) {
-#if MDBX_USE_SENDFILE
-    static bool sendfile_unavailable;
-    if (dest_is_pipe && likely(!sendfile_unavailable)) {
-      off_t in_offset = offset;
-      const ssize_t written =
-          sendfile(fd, env->me_lazy_fd, &in_offset, used_size - offset);
-      if (likely(written > 0)) {
-        offset = in_offset;
-        continue;
-      }
-      rc = MDBX_ENODATA;
-      if (written == 0 || ignore_enosys(rc = errno) != MDBX_RESULT_TRUE)
-        break;
-      sendfile_unavailable = true;
-    }
-#endif /* MDBX_USE_SENDFILE */
-
-#if MDBX_USE_COPYFILERANGE
-    if (!dest_is_pipe && !not_the_same_filesystem &&
-        likely(!copyfilerange_unavailable)) {
-      off_t in_offset = offset, out_offset = offset;
-      ssize_t bytes_copied = copy_file_range(
-          env->me_lazy_fd, &in_offset, fd, &out_offset, used_size - offset, 0);
-      if (likely(bytes_copied > 0)) {
-        offset = in_offset;
-        continue;
-      }
-      rc = MDBX_ENODATA;
-      if (bytes_copied == 0)
-        break;
-      rc = errno;
-      if (rc == EXDEV)
-        not_the_same_filesystem = true;
-      else if (ignore_enosys(rc) == MDBX_RESULT_TRUE)
-        copyfilerange_unavailable = true;
-      else
-        break;
-    }
-#endif /* MDBX_USE_COPYFILERANGE */
-
-    /* fallback to portable */
-    const size_t chunk =
-        (((size_t)(MDBX_ENVCOPY_WRITEBUF)) < used_size - offset)
-            ? ((size_t)(MDBX_ENVCOPY_WRITEBUF))
-            : used_size - offset;
-    /* copy to avoid EFAULT in case swapped-out */
-    memcpy(data_buffer, env->me_map + offset, chunk);
-    rc = mdbx_write(fd, data_buffer, chunk);
-    offset += chunk;
-  }
-
-  /* Extend file if required */
-  if (likely(rc == MDBX_SUCCESS) && whole_size != used_size) {
-    if (!dest_is_pipe)
-      rc = mdbx_ftruncate(fd, whole_size);
-    else {
-      memset(data_buffer, 0, ((size_t)(MDBX_ENVCOPY_WRITEBUF)));
-      for (size_t offset = used_size;
-           rc == MDBX_SUCCESS && offset < whole_size;) {
-        const size_t chunk =
-            (((size_t)(MDBX_ENVCOPY_WRITEBUF)) < whole_size - offset)
-                ? ((size_t)(MDBX_ENVCOPY_WRITEBUF))
-                : whole_size - offset;
-        /* copy to avoid EFAULT in case swapped-out */
-        rc = mdbx_write(fd, data_buffer, chunk);
-        offset += chunk;
-      }
-    }
-  }
-
-  return rc;
-}
-
-__cold int mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd,
-                            unsigned flags) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  const int dest_is_pipe = mdbx_is_pipe(fd);
-  if (MDBX_IS_ERROR(dest_is_pipe))
-    return dest_is_pipe;
-
-  if (!dest_is_pipe) {
-    rc = mdbx_fseek(fd, 0);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  const size_t buffer_size =
-      pgno_align2os_bytes(env, NUM_METAS) +
-      ceil_powerof2(((flags & MDBX_CP_COMPACT)
-                         ? ((size_t)(MDBX_ENVCOPY_WRITEBUF)) * 2
-                         : ((size_t)(MDBX_ENVCOPY_WRITEBUF))),
-                    env->me_os_psize);
-
-  uint8_t *buffer = NULL;
-  rc = mdbx_memalign_alloc(env->me_os_psize, buffer_size, (void **)&buffer);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  MDBX_txn *read_txn = NULL;
-  /* Do the lock/unlock of the reader mutex before starting the
-   * write txn. Otherwise other read txns could block writers. */
-  rc = mdbx_txn_begin(env, NULL, MDBX_TXN_RDONLY, &read_txn);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    mdbx_memalign_free(buffer);
-    return rc;
-  }
-
-  if (!dest_is_pipe) {
-    /* Firstly write a stub to meta-pages.
-     * Now we sure to incomplete copy will not be used. */
-    memset(buffer, -1, pgno2bytes(env, NUM_METAS));
-    rc = mdbx_write(fd, buffer, pgno2bytes(env, NUM_METAS));
-  }
-
-  if (likely(rc == MDBX_SUCCESS)) {
-    memset(buffer, 0, pgno2bytes(env, NUM_METAS));
-    rc = ((flags & MDBX_CP_COMPACT) ? mdbx_env_compact : mdbx_env_copy_asis)(
-        env, read_txn, fd, buffer, dest_is_pipe, flags);
-  }
-  mdbx_txn_abort(read_txn);
-
-  if (!dest_is_pipe) {
-    if (likely(rc == MDBX_SUCCESS))
-      rc = mdbx_fsync(fd, MDBX_SYNC_DATA | MDBX_SYNC_SIZE);
-
-    /* Write actual meta */
-    if (likely(rc == MDBX_SUCCESS))
-      rc = mdbx_pwrite(fd, buffer, pgno2bytes(env, NUM_METAS), 0);
-
-    if (likely(rc == MDBX_SUCCESS))
-      rc = mdbx_fsync(fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
-  }
-
-  mdbx_memalign_free(buffer);
-  return rc;
-}
-
-__cold int mdbx_env_copy(MDBX_env *env, const char *dest_path,
-                         MDBX_copy_flags_t flags) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!dest_path))
-    return MDBX_EINVAL;
-
-  /* The destination path must exist, but the destination file must not.
-   * We don't want the OS to cache the writes, since the source data is
-   * already in the OS cache. */
-  mdbx_filehandle_t newfd;
-  rc = mdbx_openfile(MDBX_OPEN_COPY, env, dest_path, &newfd,
-#if defined(_WIN32) || defined(_WIN64)
-                     (mdbx_mode_t)-1
-#else
-                     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
-#endif
-  );
-
-  if (rc == MDBX_SUCCESS) {
-#if defined(_WIN32) || defined(_WIN64)
-    OVERLAPPED ov;
-    memset(&ov, 0, sizeof(ov));
-    if (!LockFileEx(newfd, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
-                    0, 0, INT32_MAX, &ov))
-      rc = GetLastError();
-#else
-    struct flock lock_op;
-    memset(&lock_op, 0, sizeof(lock_op));
-    lock_op.l_type = F_WRLCK;
-    lock_op.l_whence = SEEK_SET;
-    lock_op.l_start = 0;
-    lock_op.l_len =
-        (sizeof(lock_op.l_len) > 4 ? INT64_MAX : INT32_MAX) & ~(size_t)0xffff;
-    if (fcntl(newfd, F_SETLK, &lock_op)
-#if (defined(__linux__) || defined(__gnu_linux__)) && defined(LOCK_EX) &&      \
-    (!defined(__ANDROID_API__) || __ANDROID_API__ >= 24)
-        || flock(newfd, LOCK_EX | LOCK_NB)
-#endif /* Linux */
-    )
-      rc = errno;
-#endif /* Windows / POSIX */
-  }
-
-  if (rc == MDBX_SUCCESS)
-    rc = mdbx_env_copy2fd(env, newfd, flags);
-
-  if (newfd != INVALID_HANDLE_VALUE) {
-    int err = mdbx_closefile(newfd);
-    if (rc == MDBX_SUCCESS && err != rc)
-      rc = err;
-    if (rc != MDBX_SUCCESS)
-      (void)mdbx_removefile(dest_path);
-  }
-
-  return rc;
-}
-
-/******************************************************************************/
-
-__cold int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags,
-                              bool onoff) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(flags &
-               ((env->me_flags & MDBX_ENV_ACTIVE) ? ~ENV_CHANGEABLE_FLAGS
-                                                  : ~ENV_USABLE_FLAGS)))
-    return MDBX_EPERM;
-
-  if (unlikely(env->me_flags & MDBX_RDONLY))
-    return MDBX_EACCESS;
-
-  if ((env->me_flags & MDBX_ENV_ACTIVE) &&
-      unlikely(env->me_txn0->mt_owner == mdbx_thread_self()))
-    return MDBX_BUSY;
-
-  const bool lock_needed = (env->me_flags & MDBX_ENV_ACTIVE) &&
-                           env->me_txn0->mt_owner != mdbx_thread_self();
-  bool should_unlock = false;
-  if (lock_needed) {
-    rc = mdbx_txn_lock(env, false);
-    if (unlikely(rc))
-      return rc;
-    should_unlock = true;
-  }
-
-  if (onoff)
-    env->me_flags = merge_sync_flags(env->me_flags, flags);
-  else
-    env->me_flags &= ~flags;
-
-  if (should_unlock)
-    mdbx_txn_unlock(env);
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_env_get_flags(const MDBX_env *env, unsigned *arg) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!arg))
-    return MDBX_EINVAL;
-
-  *arg = env->me_flags & ENV_USABLE_FLAGS;
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_env_set_userctx(MDBX_env *env, void *ctx) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  env->me_userctx = ctx;
-  return MDBX_SUCCESS;
-}
-
-__cold void *mdbx_env_get_userctx(const MDBX_env *env) {
-  return env ? env->me_userctx : NULL;
-}
-
-__cold int mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-#if MDBX_DEBUG
-  env->me_assert_func = func;
-  return MDBX_SUCCESS;
-#else
-  (void)func;
-  return MDBX_ENOSYS;
-#endif
-}
-
-__cold int mdbx_env_get_path(const MDBX_env *env, const char **arg) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!arg))
-    return MDBX_EINVAL;
-
-  *arg = env->me_pathname;
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *arg) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!arg))
-    return MDBX_EINVAL;
-
-  *arg = env->me_lazy_fd;
-  return MDBX_SUCCESS;
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold int mdbx_env_stat(const MDBX_env *env, MDBX_stat *stat, size_t bytes) {
-  return __inline_mdbx_env_stat(env, stat, bytes);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-static void stat_get(const MDBX_db *db, MDBX_stat *st, size_t bytes) {
-  st->ms_depth = db->md_depth;
-  st->ms_branch_pages = db->md_branch_pages;
-  st->ms_leaf_pages = db->md_leaf_pages;
-  st->ms_overflow_pages = db->md_overflow_pages;
-  st->ms_entries = db->md_entries;
-  if (likely(bytes >=
-             offsetof(MDBX_stat, ms_mod_txnid) + sizeof(st->ms_mod_txnid)))
-    st->ms_mod_txnid = db->md_mod_txnid;
-}
-
-static void stat_add(const MDBX_db *db, MDBX_stat *const st,
-                     const size_t bytes) {
-  st->ms_depth += db->md_depth;
-  st->ms_branch_pages += db->md_branch_pages;
-  st->ms_leaf_pages += db->md_leaf_pages;
-  st->ms_overflow_pages += db->md_overflow_pages;
-  st->ms_entries += db->md_entries;
-  if (likely(bytes >=
-             offsetof(MDBX_stat, ms_mod_txnid) + sizeof(st->ms_mod_txnid)))
-    st->ms_mod_txnid = (st->ms_mod_txnid > db->md_mod_txnid) ? st->ms_mod_txnid
-                                                             : db->md_mod_txnid;
-}
-
-__cold static int stat_acc(const MDBX_txn *txn, MDBX_stat *st, size_t bytes) {
-  int err = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  st->ms_psize = txn->mt_env->me_psize;
-#if 1
-  /* assuming GC is internal and not subject for accounting */
-  stat_get(&txn->mt_dbs[MAIN_DBI], st, bytes);
-#else
-  stat_get(&txn->mt_dbs[FREE_DBI], st, bytes);
-  stat_add(&txn->mt_dbs[MAIN_DBI], st, bytes);
-#endif
-
-  /* account opened named subDBs */
-  for (MDBX_dbi dbi = CORE_DBS; dbi < txn->mt_numdbs; dbi++)
-    if ((txn->mt_dbistate[dbi] & (DBI_VALID | DBI_STALE)) == DBI_VALID)
-      stat_add(txn->mt_dbs + dbi, st, bytes);
-
-  if (!(txn->mt_dbs[MAIN_DBI].md_flags & (MDBX_DUPSORT | MDBX_INTEGERKEY)) &&
-      txn->mt_dbs[MAIN_DBI].md_entries /* TODO: use `md_subs` field */) {
-    MDBX_cursor_couple cx;
-    err = mdbx_cursor_init(&cx.outer, (MDBX_txn *)txn, MAIN_DBI);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-    /* scan and account not opened named subDBs */
-    err = mdbx_page_search(&cx.outer, NULL, MDBX_PS_FIRST);
-    while (err == MDBX_SUCCESS) {
-      const MDBX_page *mp = cx.outer.mc_pg[cx.outer.mc_top];
-      for (unsigned i = 0; i < page_numkeys(mp); i++) {
-        const MDBX_node *node = page_node(mp, i);
-        if (node_flags(node) != F_SUBDATA)
-          continue;
-        if (unlikely(node_ds(node) != sizeof(MDBX_db)))
-          return MDBX_CORRUPTED;
-
-        /* skip opened and already accounted */
-        for (MDBX_dbi dbi = CORE_DBS; dbi < txn->mt_numdbs; dbi++)
-          if ((txn->mt_dbistate[dbi] & (DBI_VALID | DBI_STALE)) == DBI_VALID &&
-              node_ks(node) == txn->mt_dbxs[dbi].md_name.iov_len &&
-              memcmp(node_key(node), txn->mt_dbxs[dbi].md_name.iov_base,
-                     node_ks(node)) == 0) {
-            node = NULL;
-            break;
-          }
-
-        if (node) {
-          MDBX_db db;
-          memcpy(&db, node_data(node), sizeof(db));
-          stat_add(&db, st, bytes);
-        }
-      }
-      err = mdbx_cursor_sibling(&cx.outer, SIBLING_RIGHT);
-    }
-    if (unlikely(err != MDBX_NOTFOUND))
-      return err;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn,
-                            MDBX_stat *dest, size_t bytes) {
-  if (unlikely(!dest))
-    return MDBX_EINVAL;
-  const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
-  if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
-    return MDBX_EINVAL;
-
-  if (likely(txn)) {
-    if (env && unlikely(txn->mt_env != env))
-      return MDBX_EINVAL;
-    return stat_acc(txn, dest, bytes);
-  }
-
-  int err = check_env(env, true);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  if (env->me_txn0 && env->me_txn0->mt_owner == mdbx_thread_self())
-    /* inside write-txn */
-    return stat_acc(env->me_txn, dest, bytes);
-
-  MDBX_txn *tmp_txn;
-  err = mdbx_txn_begin((MDBX_env *)env, NULL, MDBX_TXN_RDONLY, &tmp_txn);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  const int rc = stat_acc(tmp_txn, dest, bytes);
-  err = mdbx_txn_abort(tmp_txn);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-  return rc;
-}
-
-__cold int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
-                                      uint32_t *mask) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!mask))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_VALID)))
-    return MDBX_BAD_DBI;
-
-  MDBX_cursor_couple cx;
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  if ((cx.outer.mc_db->md_flags & MDBX_DUPSORT) == 0)
-    return MDBX_RESULT_TRUE;
-
-  MDBX_val key, data;
-  rc = mdbx_cursor_first(&cx.outer, &key, &data);
-  *mask = 0;
-  while (rc == MDBX_SUCCESS) {
-    const MDBX_node *node = page_node(cx.outer.mc_pg[cx.outer.mc_top],
-                                      cx.outer.mc_ki[cx.outer.mc_top]);
-    const MDBX_db *db = node_data(node);
-    const unsigned flags = node_flags(node);
-    switch (flags) {
-    case F_BIGDATA:
-    case 0:
-      /* single-value entry, deep = 0 */
-      *mask |= 1 << 0;
-      break;
-    case F_DUPDATA:
-      /* single sub-page, deep = 1 */
-      *mask |= 1 << 1;
-      break;
-    case F_DUPDATA | F_SUBDATA:
-      /* sub-tree */
-      *mask |= 1 << UNALIGNED_PEEK_16(db, MDBX_db, md_depth);
-      break;
-    default:
-      mdbx_error("wrong node-flags %u", flags);
-      return MDBX_CORRUPTED;
-    }
-    rc = mdbx_cursor_next(&cx.outer, &key, &data, MDBX_NEXT_NODUP);
-  }
-
-  return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold int mdbx_env_info(const MDBX_env *env, MDBX_envinfo *info,
-                         size_t bytes) {
-  return __inline_mdbx_env_info(env, info, bytes);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-__cold static int fetch_envinfo_ex(const MDBX_env *env, const MDBX_txn *txn,
-                                   MDBX_envinfo *arg, const size_t bytes) {
-
-  const size_t size_before_bootid = offsetof(MDBX_envinfo, mi_bootid);
-  const size_t size_before_pgop_stat = offsetof(MDBX_envinfo, mi_pgop_stat);
-
-  /* is the environment open?
-   * (todo4recovery://erased_by_github/libmdbx/issues/171) */
-  if (unlikely(!env->me_map)) {
-    /* environment not yet opened */
-#if 1
-    /* default behavior: returns the available info but zeroed the rest */
-    memset(arg, 0, bytes);
-    arg->mi_geo.lower = env->me_dbgeo.lower;
-    arg->mi_geo.upper = env->me_dbgeo.upper;
-    arg->mi_geo.shrink = env->me_dbgeo.shrink;
-    arg->mi_geo.grow = env->me_dbgeo.grow;
-    arg->mi_geo.current = env->me_dbgeo.now;
-    arg->mi_maxreaders = env->me_maxreaders;
-    arg->mi_dxb_pagesize = env->me_psize;
-    arg->mi_sys_pagesize = env->me_os_psize;
-    if (likely(bytes > size_before_bootid)) {
-      arg->mi_bootid.current.x = bootid.x;
-      arg->mi_bootid.current.y = bootid.y;
-    }
-    return MDBX_SUCCESS;
-#else
-    /* some users may prefer this behavior: return appropriate error */
-    return MDBX_EPERM;
-#endif
-  }
-
-  const MDBX_meta *const meta0 = METAPAGE(env, 0);
-  const MDBX_meta *const meta1 = METAPAGE(env, 1);
-  const MDBX_meta *const meta2 = METAPAGE(env, 2);
-  if (unlikely(env->me_flags & MDBX_FATAL_ERROR))
-    return MDBX_PANIC;
-
-  volatile const MDBX_meta *const recent_meta = meta_prefer_last(env);
-  arg->mi_recent_txnid = meta_txnid(env, recent_meta);
-  arg->mi_meta0_txnid = meta_txnid(env, meta0);
-  arg->mi_meta0_sign = unaligned_peek_u64(4, meta0->mm_datasync_sign);
-  arg->mi_meta1_txnid = meta_txnid(env, meta1);
-  arg->mi_meta1_sign = unaligned_peek_u64(4, meta1->mm_datasync_sign);
-  arg->mi_meta2_txnid = meta_txnid(env, meta2);
-  arg->mi_meta2_sign = unaligned_peek_u64(4, meta2->mm_datasync_sign);
-  if (likely(bytes > size_before_bootid)) {
-    memcpy(&arg->mi_bootid.meta0, &meta0->mm_bootid, 16);
-    memcpy(&arg->mi_bootid.meta1, &meta1->mm_bootid, 16);
-    memcpy(&arg->mi_bootid.meta2, &meta2->mm_bootid, 16);
-  }
-
-  volatile const MDBX_meta *txn_meta = recent_meta;
-  arg->mi_last_pgno = txn_meta->mm_geo.next - 1;
-  arg->mi_geo.current = pgno2bytes(env, txn_meta->mm_geo.now);
-  if (txn) {
-    arg->mi_last_pgno = txn->mt_next_pgno - 1;
-    arg->mi_geo.current = pgno2bytes(env, txn->mt_end_pgno);
-
-    const txnid_t wanna_meta_txnid = (txn->mt_flags & MDBX_TXN_RDONLY)
-                                         ? txn->mt_txnid
-                                         : txn->mt_txnid - xMDBX_TXNID_STEP;
-    txn_meta = (arg->mi_meta0_txnid == wanna_meta_txnid) ? meta0 : txn_meta;
-    txn_meta = (arg->mi_meta1_txnid == wanna_meta_txnid) ? meta1 : txn_meta;
-    txn_meta = (arg->mi_meta2_txnid == wanna_meta_txnid) ? meta2 : txn_meta;
-  }
-  arg->mi_geo.lower = pgno2bytes(env, txn_meta->mm_geo.lower);
-  arg->mi_geo.upper = pgno2bytes(env, txn_meta->mm_geo.upper);
-  arg->mi_geo.shrink = pgno2bytes(env, pv2pages(txn_meta->mm_geo.shrink_pv));
-  arg->mi_geo.grow = pgno2bytes(env, pv2pages(txn_meta->mm_geo.grow_pv));
-  const pgno_t unsynced_pages =
-      atomic_load32(&env->me_lck->mti_unsynced_pages, mo_Relaxed) +
-      (atomic_load32(&env->me_lck->mti_meta_sync_txnid, mo_Relaxed) !=
-       (uint32_t)arg->mi_recent_txnid);
-
-  arg->mi_mapsize = env->me_dxb_mmap.limit;
-
-  const MDBX_lockinfo *const lck = env->me_lck;
-  arg->mi_maxreaders = env->me_maxreaders;
-  arg->mi_numreaders = env->me_lck_mmap.lck
-                           ? atomic_load32(&lck->mti_numreaders, mo_Relaxed)
-                           : INT32_MAX;
-  arg->mi_dxb_pagesize = env->me_psize;
-  arg->mi_sys_pagesize = env->me_os_psize;
-
-  if (likely(bytes > size_before_bootid)) {
-    arg->mi_unsync_volume = pgno2bytes(env, unsynced_pages);
-    const uint64_t monotime_now = mdbx_osal_monotime();
-    uint64_t ts = atomic_load64(&lck->mti_sync_timestamp, mo_Relaxed);
-    arg->mi_since_sync_seconds16dot16 =
-        ts ? mdbx_osal_monotime_to_16dot16(monotime_now - ts) : 0;
-    ts = atomic_load64(&lck->mti_reader_check_timestamp, mo_Relaxed);
-    arg->mi_since_reader_check_seconds16dot16 =
-        ts ? mdbx_osal_monotime_to_16dot16(monotime_now - ts) : 0;
-    arg->mi_autosync_threshold = pgno2bytes(
-        env, atomic_load32(&lck->mti_autosync_threshold, mo_Relaxed));
-    arg->mi_autosync_period_seconds16dot16 = mdbx_osal_monotime_to_16dot16(
-        atomic_load64(&lck->mti_autosync_period, mo_Relaxed));
-    arg->mi_bootid.current.x = bootid.x;
-    arg->mi_bootid.current.y = bootid.y;
-    arg->mi_mode = env->me_lck_mmap.lck ? lck->mti_envmode.weak : env->me_flags;
-  }
-
-  if (likely(bytes > size_before_pgop_stat)) {
-#if MDBX_ENABLE_PGOP_STAT
-    arg->mi_pgop_stat.newly =
-        atomic_load64(&lck->mti_pgop_stat.newly, mo_Relaxed);
-    arg->mi_pgop_stat.cow = atomic_load64(&lck->mti_pgop_stat.cow, mo_Relaxed);
-    arg->mi_pgop_stat.clone =
-        atomic_load64(&lck->mti_pgop_stat.clone, mo_Relaxed);
-    arg->mi_pgop_stat.split =
-        atomic_load64(&lck->mti_pgop_stat.split, mo_Relaxed);
-    arg->mi_pgop_stat.merge =
-        atomic_load64(&lck->mti_pgop_stat.merge, mo_Relaxed);
-    arg->mi_pgop_stat.spill =
-        atomic_load64(&lck->mti_pgop_stat.spill, mo_Relaxed);
-    arg->mi_pgop_stat.unspill =
-        atomic_load64(&lck->mti_pgop_stat.unspill, mo_Relaxed);
-    arg->mi_pgop_stat.wops =
-        atomic_load64(&lck->mti_pgop_stat.wops, mo_Relaxed);
-#else
-    memset(&arg->mi_pgop_stat, 0, sizeof(arg->mi_pgop_stat));
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-  }
-
-  arg->mi_self_latter_reader_txnid = arg->mi_latter_reader_txnid =
-      arg->mi_recent_txnid;
-  for (unsigned i = 0; i < arg->mi_numreaders; ++i) {
-    const uint32_t pid =
-        atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease);
-    if (pid) {
-      const txnid_t txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
-      if (arg->mi_latter_reader_txnid > txnid)
-        arg->mi_latter_reader_txnid = txnid;
-      if (pid == env->me_pid && arg->mi_self_latter_reader_txnid > txnid)
-        arg->mi_self_latter_reader_txnid = txnid;
-    }
-  }
-
-  mdbx_compiler_barrier();
-  return MDBX_SUCCESS;
-}
-
-__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))
-    return MDBX_EINVAL;
-
-  if (txn) {
-    int err = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-  }
-  if (env) {
-    int err = check_env(env, false);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-    if (txn && unlikely(txn->mt_env != env))
-      return MDBX_EINVAL;
-  } else {
-    env = txn->mt_env;
-  }
-
-  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;
-
-  MDBX_envinfo snap;
-  int rc = fetch_envinfo_ex(env, txn, &snap, sizeof(snap));
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  while (1) {
-    rc = fetch_envinfo_ex(env, txn, arg, bytes);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    snap.mi_since_sync_seconds16dot16 = arg->mi_since_sync_seconds16dot16;
-    snap.mi_since_reader_check_seconds16dot16 =
-        arg->mi_since_reader_check_seconds16dot16;
-    if (likely(memcmp(&snap, arg, bytes) == 0))
-      return MDBX_SUCCESS;
-    memcpy(&snap, arg, bytes);
-  }
-}
-
-static __inline MDBX_cmp_func *get_default_keycmp(unsigned flags) {
-  return (flags & MDBX_REVERSEKEY)   ? cmp_reverse
-         : (flags & MDBX_INTEGERKEY) ? cmp_int_align2
-                                     : cmp_lexical;
-}
-
-static __inline MDBX_cmp_func *get_default_datacmp(unsigned flags) {
-  return !(flags & MDBX_DUPSORT)
-             ? cmp_lenfast
-             : ((flags & MDBX_INTEGERDUP)
-                    ? cmp_int_unaligned
-                    : ((flags & MDBX_REVERSEDUP) ? cmp_reverse : cmp_lexical));
-}
-
-static int mdbx_dbi_bind(MDBX_txn *txn, const MDBX_dbi dbi, unsigned user_flags,
-                         MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp) {
-  /* LY: so, accepting only three cases for the table's flags:
-   * 1) user_flags and both comparators are zero
-   *    = assume that a by-default mode/flags is requested for reading;
-   * 2) user_flags exactly the same
-   *    = assume that the target mode/flags are requested properly;
-   * 3) user_flags differs, but table is empty and MDBX_CREATE is provided
-   *    = assume that a properly create request with custom flags;
-   */
-  if ((user_flags ^ txn->mt_dbs[dbi].md_flags) & DB_PERSISTENT_FLAGS) {
-    /* flags are differs, check other conditions */
-    if ((!user_flags && (!keycmp || keycmp == txn->mt_dbxs[dbi].md_cmp) &&
-         (!datacmp || datacmp == txn->mt_dbxs[dbi].md_dcmp)) ||
-        user_flags == MDBX_ACCEDE) {
-      /* no comparators were provided and flags are zero,
-       * seems that is case #1 above */
-      user_flags = txn->mt_dbs[dbi].md_flags;
-    } else if ((user_flags & MDBX_CREATE) && txn->mt_dbs[dbi].md_entries == 0) {
-      if (txn->mt_flags & MDBX_TXN_RDONLY)
-        return /* FIXME: return extended info */ MDBX_EACCESS;
-      /* make sure flags changes get committed */
-      txn->mt_dbs[dbi].md_flags = user_flags & DB_PERSISTENT_FLAGS;
-      txn->mt_flags |= MDBX_TXN_DIRTY;
-    } else {
-      return /* FIXME: return extended info */ MDBX_INCOMPATIBLE;
-    }
-  }
-
-  if (!keycmp)
-    keycmp = txn->mt_dbxs[dbi].md_cmp ? txn->mt_dbxs[dbi].md_cmp
-                                      : get_default_keycmp(user_flags);
-  if (txn->mt_dbxs[dbi].md_cmp != keycmp) {
-    if (txn->mt_dbxs[dbi].md_cmp)
-      return MDBX_EINVAL;
-    txn->mt_dbxs[dbi].md_cmp = keycmp;
-  }
-
-  if (!datacmp)
-    datacmp = txn->mt_dbxs[dbi].md_dcmp ? txn->mt_dbxs[dbi].md_dcmp
-                                        : get_default_datacmp(user_flags);
-  if (txn->mt_dbxs[dbi].md_dcmp != datacmp) {
-    if (txn->mt_dbxs[dbi].md_dcmp)
-      return MDBX_EINVAL;
-    txn->mt_dbxs[dbi].md_dcmp = datacmp;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-static int dbi_open(MDBX_txn *txn, const char *table_name, unsigned user_flags,
-                    MDBX_dbi *dbi, MDBX_cmp_func *keycmp,
-                    MDBX_cmp_func *datacmp) {
-  int rc = MDBX_EINVAL;
-  if (unlikely(!dbi))
-    return rc;
-
-  if (unlikely((user_flags & ~DB_USABLE_FLAGS) != 0)) {
-  early_bailout:
-    *dbi = 0;
-    return rc;
-  }
-
-  rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto early_bailout;
-
-  switch (user_flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED | MDBX_DUPSORT |
-                        MDBX_REVERSEDUP | MDBX_ACCEDE)) {
-  case MDBX_ACCEDE:
-    if ((user_flags & MDBX_CREATE) == 0)
-      break;
-    __fallthrough /* fall through */;
-  default:
-    rc = MDBX_EINVAL;
-    goto early_bailout;
-
-  case MDBX_DUPSORT:
-  case MDBX_DUPSORT | MDBX_REVERSEDUP:
-  case MDBX_DUPSORT | MDBX_DUPFIXED:
-  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_REVERSEDUP:
-  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP:
-  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP | MDBX_REVERSEDUP:
-  case 0:
-    break;
-  }
-
-  /* main table? */
-  if (!table_name) {
-    rc = mdbx_dbi_bind(txn, MAIN_DBI, user_flags, keycmp, datacmp);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto early_bailout;
-    *dbi = MAIN_DBI;
-    return rc;
-  }
-
-  MDBX_env *env = txn->mt_env;
-  size_t len = strlen(table_name);
-  if (len > env->me_leaf_nodemax - NODESIZE - sizeof(MDBX_db))
-    return MDBX_EINVAL;
-
-  if (txn->mt_dbxs[MAIN_DBI].md_cmp == NULL) {
-    txn->mt_dbxs[MAIN_DBI].md_cmp =
-        get_default_keycmp(txn->mt_dbs[MAIN_DBI].md_flags);
-    txn->mt_dbxs[MAIN_DBI].md_dcmp =
-        get_default_datacmp(txn->mt_dbs[MAIN_DBI].md_flags);
-  }
-
-  /* Is the DB already open? */
-  MDBX_dbi scan, slot;
-  for (slot = scan = txn->mt_numdbs; --scan >= CORE_DBS;) {
-    if (!txn->mt_dbxs[scan].md_name.iov_len) {
-      /* Remember this free slot */
-      slot = scan;
-      continue;
-    }
-    if (len == txn->mt_dbxs[scan].md_name.iov_len &&
-        !strncmp(table_name, txn->mt_dbxs[scan].md_name.iov_base, len)) {
-      rc = mdbx_dbi_bind(txn, scan, user_flags, keycmp, datacmp);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto early_bailout;
-      *dbi = scan;
-      return rc;
-    }
-  }
-
-  /* Fail, if no free slot and max hit */
-  if (unlikely(slot >= env->me_maxdbs)) {
-    rc = MDBX_DBS_FULL;
-    goto early_bailout;
-  }
-
-  /* Cannot mix named table with some main-table flags */
-  if (unlikely(txn->mt_dbs[MAIN_DBI].md_flags &
-               (MDBX_DUPSORT | MDBX_INTEGERKEY))) {
-    rc = (user_flags & MDBX_CREATE) ? MDBX_INCOMPATIBLE : MDBX_NOTFOUND;
-    goto early_bailout;
-  }
-
-  /* Find the DB info */
-  MDBX_val key, data;
-  key.iov_len = len;
-  key.iov_base = (void *)table_name;
-  MDBX_cursor_couple couple;
-  rc = mdbx_cursor_init(&couple.outer, txn, MAIN_DBI);
-  if (unlikely(rc != MDBX_SUCCESS))
-    goto early_bailout;
-  rc = mdbx_cursor_set(&couple.outer, &key, &data, MDBX_SET).err;
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    if (rc != MDBX_NOTFOUND || !(user_flags & MDBX_CREATE))
-      goto early_bailout;
-  } else {
-    /* make sure this is actually a table */
-    MDBX_node *node = page_node(couple.outer.mc_pg[couple.outer.mc_top],
-                                couple.outer.mc_ki[couple.outer.mc_top]);
-    if (unlikely((node_flags(node) & (F_DUPDATA | F_SUBDATA)) != F_SUBDATA)) {
-      rc = MDBX_INCOMPATIBLE;
-      goto early_bailout;
-    }
-    if (!MDBX_DISABLE_PAGECHECKS && unlikely(data.iov_len != sizeof(MDBX_db))) {
-      rc = MDBX_CORRUPTED;
-      goto early_bailout;
-    }
-  }
-
-  if (rc != MDBX_SUCCESS && unlikely(txn->mt_flags & MDBX_TXN_RDONLY)) {
-    rc = MDBX_EACCESS;
-    goto early_bailout;
-  }
-
-  /* Done here so we cannot fail after creating a new DB */
-  char *namedup = mdbx_strdup(table_name);
-  if (unlikely(!namedup)) {
-    rc = MDBX_ENOMEM;
-    goto early_bailout;
-  }
-
-  int err = mdbx_fastmutex_acquire(&env->me_dbi_lock);
-  if (unlikely(err != MDBX_SUCCESS)) {
-    rc = err;
-    mdbx_free(namedup);
-    goto early_bailout;
-  }
-
-  /* Import handles from env */
-  dbi_import_locked(txn);
-
-  /* Rescan after mutex acquisition & import handles */
-  for (slot = scan = txn->mt_numdbs; --scan >= CORE_DBS;) {
-    if (!txn->mt_dbxs[scan].md_name.iov_len) {
-      /* Remember this free slot */
-      slot = scan;
-      continue;
-    }
-    if (len == txn->mt_dbxs[scan].md_name.iov_len &&
-        !strncmp(table_name, txn->mt_dbxs[scan].md_name.iov_base, len)) {
-      rc = mdbx_dbi_bind(txn, scan, user_flags, keycmp, datacmp);
-      if (unlikely(rc != MDBX_SUCCESS))
-        goto later_bailout;
-      *dbi = scan;
-      goto later_exit;
-    }
-  }
-
-  if (unlikely(slot >= env->me_maxdbs)) {
-    rc = MDBX_DBS_FULL;
-    goto later_bailout;
-  }
-
-  unsigned dbiflags = DBI_FRESH | DBI_VALID | DBI_USRVALID;
-  MDBX_db db_dummy;
-  if (unlikely(rc)) {
-    /* MDBX_NOTFOUND and MDBX_CREATE: Create new DB */
-    mdbx_tassert(txn, rc == MDBX_NOTFOUND);
-    memset(&db_dummy, 0, sizeof(db_dummy));
-    db_dummy.md_root = P_INVALID;
-    db_dummy.md_mod_txnid = txn->mt_txnid;
-    db_dummy.md_flags = user_flags & DB_PERSISTENT_FLAGS;
-    data.iov_len = sizeof(db_dummy);
-    data.iov_base = &db_dummy;
-    WITH_CURSOR_TRACKING(couple.outer,
-                         rc = mdbx_cursor_put(&couple.outer, &key, &data,
-                                              F_SUBDATA | MDBX_NOOVERWRITE));
-
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto later_bailout;
-
-    dbiflags |= DBI_DIRTY | DBI_CREAT;
-    txn->mt_flags |= MDBX_TXN_DIRTY;
-    mdbx_tassert(txn, (txn->mt_dbistate[MAIN_DBI] & DBI_DIRTY) != 0);
-  }
-
-  /* Got info, register DBI in this txn */
-  memset(txn->mt_dbxs + slot, 0, sizeof(MDBX_dbx));
-  memcpy(&txn->mt_dbs[slot], data.iov_base, sizeof(MDBX_db));
-  env->me_dbflags[slot] = 0;
-  rc = mdbx_dbi_bind(txn, slot, user_flags, keycmp, datacmp);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    mdbx_tassert(txn, (dbiflags & DBI_CREAT) == 0);
-  later_bailout:
-    *dbi = 0;
-  later_exit:
-    mdbx_free(namedup);
-  } else {
-    txn->mt_dbistate[slot] = (uint8_t)dbiflags;
-    txn->mt_dbxs[slot].md_name.iov_base = namedup;
-    txn->mt_dbxs[slot].md_name.iov_len = len;
-    txn->mt_dbiseqs[slot] = ++env->me_dbiseqs[slot];
-    if (!(dbiflags & DBI_CREAT))
-      env->me_dbflags[slot] = txn->mt_dbs[slot].md_flags | DB_VALID;
-    if (txn->mt_numdbs == slot) {
-      mdbx_compiler_barrier();
-      txn->mt_numdbs = env->me_numdbs = slot + 1;
-      txn->mt_cursors[slot] = NULL;
-    }
-    mdbx_assert(env, env->me_numdbs > slot);
-    *dbi = slot;
-  }
-
-  mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
-  return rc;
-}
-
-int mdbx_dbi_open(MDBX_txn *txn, const char *table_name,
-                  MDBX_db_flags_t table_flags, MDBX_dbi *dbi) {
-  return dbi_open(txn, table_name, table_flags, dbi, nullptr, nullptr);
-}
-
-int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name,
-                     MDBX_db_flags_t table_flags, MDBX_dbi *dbi,
-                     MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp) {
-  return dbi_open(txn, table_name, table_flags, dbi, keycmp, datacmp);
-}
-
-__cold int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
-                         size_t bytes) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!dest))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_VALID)))
-    return MDBX_BAD_DBI;
-
-  const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
-  if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
-    return MDBX_EINVAL;
-
-  if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
-    return MDBX_BAD_TXN;
-
-  if (unlikely(txn->mt_dbistate[dbi] & DBI_STALE)) {
-    rc = mdbx_fetch_sdb(txn, dbi);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  dest->ms_psize = txn->mt_env->me_psize;
-  stat_get(&txn->mt_dbs[dbi], dest, bytes);
-  return MDBX_SUCCESS;
-}
-
-static int mdbx_dbi_close_locked(MDBX_env *env, MDBX_dbi dbi) {
-  mdbx_assert(env, dbi >= CORE_DBS);
-  if (unlikely(dbi >= env->me_numdbs))
-    return MDBX_BAD_DBI;
-
-  char *ptr = env->me_dbxs[dbi].md_name.iov_base;
-  /* If there was no name, this was already closed */
-  if (unlikely(!ptr))
-    return MDBX_BAD_DBI;
-
-  env->me_dbflags[dbi] = 0;
-  env->me_dbiseqs[dbi]++;
-  env->me_dbxs[dbi].md_name.iov_len = 0;
-  mdbx_memory_fence(mo_AcquireRelease, true);
-  env->me_dbxs[dbi].md_name.iov_base = NULL;
-  mdbx_free(ptr);
-
-  if (env->me_numdbs == dbi + 1) {
-    unsigned i = env->me_numdbs;
-    do
-      --i;
-    while (i > CORE_DBS && !env->me_dbxs[i - 1].md_name.iov_base);
-    env->me_numdbs = i;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(dbi < CORE_DBS || dbi >= env->me_maxdbs))
-    return MDBX_BAD_DBI;
-
-  rc = mdbx_fastmutex_acquire(&env->me_dbi_lock);
-  if (likely(rc == MDBX_SUCCESS)) {
-    rc = (dbi < env->me_maxdbs && (env->me_dbflags[dbi] & DB_VALID))
-             ? mdbx_dbi_close_locked(env, dbi)
-             : MDBX_BAD_DBI;
-    mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
-  }
-  return rc;
-}
-
-int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
-                      unsigned *state) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!flags || !state))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_VALID)))
-    return MDBX_BAD_DBI;
-
-  *flags = txn->mt_dbs[dbi].md_flags & DB_PERSISTENT_FLAGS;
-  *state =
-      txn->mt_dbistate[dbi] & (DBI_FRESH | DBI_CREAT | DBI_DIRTY | DBI_STALE);
-
-  return MDBX_SUCCESS;
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags) {
-  return __inline_mdbx_dbi_flags(txn, dbi, flags);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-static int mdbx_drop_tree(MDBX_cursor *mc, const bool may_have_subDBs) {
-  int rc = mdbx_page_search(mc, NULL, MDBX_PS_FIRST);
-  if (likely(rc == MDBX_SUCCESS)) {
-    MDBX_txn *txn = mc->mc_txn;
-
-    /* DUPSORT sub-DBs have no ovpages/DBs. Omit scanning leaves.
-     * This also avoids any P_LEAF2 pages, which have no nodes.
-     * Also if the DB doesn't have sub-DBs and has no overflow
-     * pages, omit scanning leaves. */
-    if (!(may_have_subDBs | mc->mc_db->md_overflow_pages))
-      mdbx_cursor_pop(mc);
-
-    rc = mdbx_pnl_need(&txn->tw.retired_pages,
-                       mc->mc_db->md_branch_pages + mc->mc_db->md_leaf_pages +
-                           mc->mc_db->md_overflow_pages);
-    if (unlikely(rc != MDBX_SUCCESS))
-      goto bailout;
-
-    MDBX_cursor mx;
-    cursor_copy(mc, &mx);
-    while (mc->mc_snum > 0) {
-      MDBX_page *const mp = mc->mc_pg[mc->mc_top];
-      const unsigned nkeys = page_numkeys(mp);
-      if (IS_LEAF(mp)) {
-        mdbx_cassert(mc, mc->mc_snum == mc->mc_db->md_depth);
-        for (unsigned i = 0; i < nkeys; i++) {
-          MDBX_node *node = page_node(mp, i);
-          if (node_flags(node) & F_BIGDATA) {
-            rc = mdbx_page_retire_ex(mc, node_largedata_pgno(node), NULL, 0);
-            if (unlikely(rc != MDBX_SUCCESS))
-              goto bailout;
-            if (!(may_have_subDBs | mc->mc_db->md_overflow_pages))
-              goto pop;
-          } else if (node_flags(node) & F_SUBDATA) {
-            if (unlikely((node_flags(node) & F_DUPDATA) == 0)) {
-              rc = /* disallowing implicit subDB deletion */ MDBX_INCOMPATIBLE;
-              goto bailout;
-            }
-            rc = mdbx_xcursor_init1(mc, node, mp);
-            if (unlikely(rc != MDBX_SUCCESS))
-              goto bailout;
-            rc = mdbx_drop_tree(&mc->mc_xcursor->mx_cursor, false);
-            if (unlikely(rc != MDBX_SUCCESS))
-              goto bailout;
-          }
-        }
-      } else {
-        mdbx_cassert(mc, mc->mc_snum < mc->mc_db->md_depth);
-        if (mdbx_audit_enabled())
-          mc->mc_flags |= C_RETIRING;
-        const int pagetype =
-            (IS_FROZEN(txn, mp) ? P_FROZEN : 0) +
-            ((mc->mc_snum + 1 == mc->mc_db->md_depth) ? P_LEAF : P_BRANCH);
-        for (unsigned i = 0; i < nkeys; i++) {
-          MDBX_node *node = page_node(mp, i);
-          mdbx_tassert(txn, (node_flags(node) &
-                             (F_BIGDATA | F_SUBDATA | F_DUPDATA)) == 0);
-          const pgno_t pgno = node_pgno(node);
-          rc = mdbx_page_retire_ex(mc, pgno, NULL, pagetype);
-          if (unlikely(rc != MDBX_SUCCESS))
-            goto bailout;
-        }
-        if (mdbx_audit_enabled())
-          mc->mc_flags -= C_RETIRING;
-      }
-      if (!mc->mc_top)
-        break;
-      mdbx_cassert(mc, nkeys > 0);
-      mc->mc_ki[mc->mc_top] = (indx_t)nkeys;
-      rc = mdbx_cursor_sibling(mc, SIBLING_RIGHT);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        if (unlikely(rc != MDBX_NOTFOUND))
-          goto bailout;
-      /* no more siblings, go back to beginning
-       * of previous level. */
-      pop:
-        mdbx_cursor_pop(mc);
-        mc->mc_ki[0] = 0;
-        for (unsigned i = 1; i < mc->mc_snum; i++) {
-          mc->mc_ki[i] = 0;
-          mc->mc_pg[i] = mx.mc_pg[i];
-        }
-      }
-    }
-    rc = mdbx_page_retire(mc, mc->mc_pg[0]);
-  bailout:
-    if (unlikely(rc != MDBX_SUCCESS))
-      txn->mt_flags |= MDBX_TXN_ERROR;
-  } else if (rc == MDBX_NOTFOUND) {
-    rc = MDBX_SUCCESS;
-  }
-  mc->mc_flags &= ~C_INITIALIZED;
-  return rc;
-}
-
-int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del) {
-  int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  MDBX_cursor *mc;
-  rc = mdbx_cursor_open(txn, dbi, &mc);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  rc = mdbx_drop_tree(mc, dbi == MAIN_DBI ||
-                              (mc->mc_db->md_flags & MDBX_DUPSORT) != 0);
-  /* Invalidate the dropped DB's cursors */
-  for (MDBX_cursor *m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next)
-    m2->mc_flags &= ~(C_INITIALIZED | C_EOF);
-  if (unlikely(rc))
-    goto bailout;
-
-  /* Can't delete the main DB */
-  if (del && dbi >= CORE_DBS) {
-    rc = mdbx_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
-    if (likely(rc == MDBX_SUCCESS)) {
-      mdbx_tassert(txn, txn->mt_dbistate[MAIN_DBI] & DBI_DIRTY);
-      mdbx_tassert(txn, txn->mt_flags & MDBX_TXN_DIRTY);
-      txn->mt_dbistate[dbi] = DBI_STALE;
-      MDBX_env *env = txn->mt_env;
-      rc = mdbx_fastmutex_acquire(&env->me_dbi_lock);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        txn->mt_flags |= MDBX_TXN_ERROR;
-        goto bailout;
-      }
-      mdbx_dbi_close_locked(env, dbi);
-      mdbx_ensure(env,
-                  mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
-    } else {
-      txn->mt_flags |= MDBX_TXN_ERROR;
-    }
-  } else {
-    /* reset the DB record, mark it dirty */
-    txn->mt_dbistate[dbi] |= DBI_DIRTY;
-    txn->mt_dbs[dbi].md_depth = 0;
-    txn->mt_dbs[dbi].md_branch_pages = 0;
-    txn->mt_dbs[dbi].md_leaf_pages = 0;
-    txn->mt_dbs[dbi].md_overflow_pages = 0;
-    txn->mt_dbs[dbi].md_entries = 0;
-    txn->mt_dbs[dbi].md_root = P_INVALID;
-    txn->mt_dbs[dbi].md_seq = 0;
-    /* txn->mt_dbs[dbi].md_mod_txnid = txn->mt_txnid; */
-    txn->mt_flags |= MDBX_TXN_DIRTY;
-  }
-
-bailout:
-  mdbx_cursor_close(mc);
-  return rc;
-}
-
-int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  txn->mt_dbxs[dbi].md_cmp = cmp;
-  return MDBX_SUCCESS;
-}
-
-int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  txn->mt_dbxs[dbi].md_dcmp = cmp;
-  return MDBX_SUCCESS;
-}
-
-__cold int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func,
-                            void *ctx) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!func))
-    return MDBX_EINVAL;
-
-  rc = MDBX_RESULT_TRUE;
-  int serial = 0;
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (likely(lck)) {
-    const unsigned snap_nreaders =
-        atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-    for (unsigned i = 0; i < snap_nreaders; i++) {
-      const MDBX_reader *r = lck->mti_readers + i;
-    retry_reader:;
-      const uint32_t pid = atomic_load32(&r->mr_pid, mo_AcquireRelease);
-      if (!pid)
-        continue;
-      txnid_t txnid = safe64_read(&r->mr_txnid);
-      const uint64_t tid = atomic_load64(&r->mr_tid, mo_Relaxed);
-      const pgno_t pages_used =
-          atomic_load32(&r->mr_snapshot_pages_used, mo_Relaxed);
-      const uint64_t reader_pages_retired =
-          atomic_load64(&r->mr_snapshot_pages_retired, mo_Relaxed);
-      if (unlikely(
-              txnid != safe64_read(&r->mr_txnid) ||
-              pid != atomic_load32(&r->mr_pid, mo_AcquireRelease) ||
-              tid != atomic_load64(&r->mr_tid, mo_Relaxed) ||
-              pages_used !=
-                  atomic_load32(&r->mr_snapshot_pages_used, mo_Relaxed) ||
-              reader_pages_retired !=
-                  atomic_load64(&r->mr_snapshot_pages_retired, mo_Relaxed)))
-        goto retry_reader;
-
-      mdbx_assert(env, txnid > 0);
-      if (txnid >= SAFE64_INVALID_THRESHOLD)
-        txnid = 0;
-
-      size_t bytes_used = 0;
-      size_t bytes_retained = 0;
-      uint64_t lag = 0;
-      if (txnid) {
-      retry_header:;
-        volatile const MDBX_meta *const recent_meta = meta_prefer_last(env);
-        const uint64_t head_pages_retired =
-            unaligned_peek_u64_volatile(4, recent_meta->mm_pages_retired);
-        const txnid_t head_txnid = meta_txnid(env, recent_meta);
-        mdbx_compiler_barrier();
-        if (unlikely(recent_meta != meta_prefer_last(env) ||
-                     head_pages_retired !=
-                         unaligned_peek_u64_volatile(
-                             4, recent_meta->mm_pages_retired)) ||
-            head_txnid != meta_txnid(env, recent_meta))
-          goto retry_header;
-
-        lag = (head_txnid - txnid) / xMDBX_TXNID_STEP;
-        bytes_used = pgno2bytes(env, pages_used);
-        bytes_retained = (head_pages_retired > reader_pages_retired)
-                             ? pgno2bytes(env, (pgno_t)(head_pages_retired -
-                                                        reader_pages_retired))
-                             : 0;
-      }
-      rc = func(ctx, ++serial, i, pid, (mdbx_tid_t)tid, txnid, lag, bytes_used,
-                bytes_retained);
-      if (unlikely(rc != MDBX_SUCCESS))
-        break;
-    }
-  }
-
-  return rc;
-}
-
-/* Insert pid into list if not already present.
- * return -1 if already present. */
-__cold static bool mdbx_pid_insert(uint32_t *ids, uint32_t pid) {
-  /* binary search of pid in list */
-  unsigned base = 0;
-  unsigned cursor = 1;
-  int val = 0;
-  unsigned n = ids[0];
-
-  while (n > 0) {
-    unsigned pivot = n >> 1;
-    cursor = base + pivot + 1;
-    val = pid - ids[cursor];
-
-    if (val < 0) {
-      n = pivot;
-    } else if (val > 0) {
-      base = cursor;
-      n -= pivot + 1;
-    } else {
-      /* found, so it's a duplicate */
-      return false;
-    }
-  }
-
-  if (val > 0)
-    ++cursor;
-
-  ids[0]++;
-  for (n = ids[0]; n > cursor; n--)
-    ids[n] = ids[n - 1];
-  ids[n] = pid;
-  return true;
-}
-
-__cold int mdbx_reader_check(MDBX_env *env, int *dead) {
-  if (dead)
-    *dead = 0;
-  return mdbx_cleanup_dead_readers(env, false, dead);
-}
-
-/* Return:
- *  MDBX_RESULT_TRUE - done and mutex recovered
- *  MDBX_SUCCESS     - done
- *  Otherwise errcode. */
-__cold MDBX_INTERNAL_FUNC int
-mdbx_cleanup_dead_readers(MDBX_env *env, int rdt_locked, int *dead) {
-  int rc = check_env(env, true);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  mdbx_assert(env, rdt_locked >= 0);
-  MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-  if (unlikely(lck == NULL)) {
-    /* exclusive mode */
-    if (dead)
-      *dead = 0;
-    return MDBX_SUCCESS;
-  }
-
-  const unsigned snap_nreaders =
-      atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-  uint32_t pidsbuf_onstask[142];
-  uint32_t *const pids =
-      (snap_nreaders < ARRAY_LENGTH(pidsbuf_onstask))
-          ? pidsbuf_onstask
-          : mdbx_malloc((snap_nreaders + 1) * sizeof(uint32_t));
-  if (unlikely(!pids))
-    return MDBX_ENOMEM;
-
-  pids[0] = 0;
-  int count = 0;
-  for (unsigned i = 0; i < snap_nreaders; i++) {
-    const uint32_t pid =
-        atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease);
-    if (pid == 0)
-      continue /* skip empty */;
-    if (pid == env->me_pid)
-      continue /* skip self */;
-    if (!mdbx_pid_insert(pids, pid))
-      continue /* such pid already processed */;
-
-    int err = mdbx_rpid_check(env, pid);
-    if (err == MDBX_RESULT_TRUE)
-      continue /* reader is live */;
-
-    if (err != MDBX_SUCCESS) {
-      rc = err;
-      break /* mdbx_rpid_check() failed */;
-    }
-
-    /* stale reader found */
-    if (!rdt_locked) {
-      err = mdbx_rdt_lock(env);
-      if (MDBX_IS_ERROR(err)) {
-        rc = err;
-        break;
-      }
-
-      rdt_locked = -1;
-      if (err == MDBX_RESULT_TRUE) {
-        /* mutex recovered, the mdbx_ipclock_failed() checked all readers */
-        rc = MDBX_RESULT_TRUE;
-        break;
-      }
-
-      /* a other process may have clean and reused slot, recheck */
-      if (lck->mti_readers[i].mr_pid.weak != pid)
-        continue;
-
-      err = mdbx_rpid_check(env, pid);
-      if (MDBX_IS_ERROR(err)) {
-        rc = err;
-        break;
-      }
-
-      if (err != MDBX_SUCCESS)
-        continue /* the race with other process, slot reused */;
-    }
-
-    /* clean it */
-    for (unsigned j = i; j < snap_nreaders; j++) {
-      if (lck->mti_readers[j].mr_pid.weak == pid) {
-        mdbx_debug("clear stale reader pid %" PRIuPTR " txn %" PRIaTXN,
-                   (size_t)pid, lck->mti_readers[j].mr_txnid.weak);
-        atomic_store32(&lck->mti_readers[j].mr_pid, 0, mo_Relaxed);
-        atomic_store32(&lck->mti_readers_refresh_flag, true, mo_AcquireRelease);
-        count++;
-      }
-    }
-  }
-
-  if (likely(!MDBX_IS_ERROR(rc)))
-    atomic_store64(&lck->mti_reader_check_timestamp, mdbx_osal_monotime(),
-                   mo_Relaxed);
-
-  if (rdt_locked < 0)
-    mdbx_rdt_unlock(env);
-
-  if (pids != pidsbuf_onstask)
-    mdbx_free(pids);
-
-  if (dead)
-    *dead = count;
-  return rc;
-}
-
-__cold int mdbx_setup_debug(int loglevel, int flags, MDBX_debug_func *logger) {
-  const int rc = mdbx_runtime_flags | (mdbx_loglevel << 16);
-
-  if (loglevel != MDBX_LOG_DONTCHANGE)
-    mdbx_loglevel = (uint8_t)loglevel;
-
-  if (flags != MDBX_DBG_DONTCHANGE) {
-    flags &=
-#if MDBX_DEBUG
-        MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER |
-#endif
-        MDBX_DBG_DUMP | MDBX_DBG_LEGACY_MULTIOPEN | MDBX_DBG_LEGACY_OVERLAP |
-        MDBX_DBG_DONT_UPGRADE;
-    mdbx_runtime_flags = (uint8_t)flags;
-  }
-
-  if (logger != MDBX_LOGGER_DONTCHANGE)
-    mdbx_debug_logger = logger;
-  return rc;
-}
-
-__cold static txnid_t mdbx_kick_longlived_readers(MDBX_env *env,
-                                                  const txnid_t laggard) {
-  mdbx_debug("DB size maxed out by reading #%" PRIaTXN, laggard);
-
-  int retry;
-  for (retry = 0; retry < INT_MAX; ++retry) {
-    txnid_t oldest = mdbx_recent_steady_txnid(env);
-    mdbx_assert(env, oldest < env->me_txn0->mt_txnid);
-    mdbx_assert(env, oldest >= laggard);
-    mdbx_assert(env, oldest >= env->me_lck->mti_oldest_reader.weak);
-    MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
-    if (oldest == laggard || unlikely(!lck /* without-LCK mode */))
-      return oldest;
-
-    if (MDBX_IS_ERROR(mdbx_cleanup_dead_readers(env, false, NULL)))
-      break;
-
-    MDBX_reader *asleep = nullptr;
-    uint64_t oldest_retired = UINT64_MAX;
-    const unsigned snap_nreaders =
-        atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
-    for (unsigned i = 0; i < snap_nreaders; ++i) {
-    retry:
-      if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease)) {
-        /* mdbx_jitter4testing(true); */
-        const uint64_t snap_retired = atomic_load64(
-            &lck->mti_readers[i].mr_snapshot_pages_retired, mo_Relaxed);
-        const txnid_t snap_txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
-        if (unlikely(snap_retired !=
-                         atomic_load64(
-                             &lck->mti_readers[i].mr_snapshot_pages_retired,
-                             mo_AcquireRelease) ||
-                     snap_txnid != safe64_read(&lck->mti_readers[i].mr_txnid)))
-          goto retry;
-        if (oldest > snap_txnid &&
-            laggard <= /* ignore pending updates */ snap_txnid) {
-          oldest = snap_txnid;
-          oldest_retired = snap_retired;
-          asleep = &lck->mti_readers[i];
-        }
-      }
-    }
-
-    if (laggard < oldest || !asleep) {
-      if (retry && env->me_hsr_callback) {
-        /* LY: notify end of hsr-loop */
-        const txnid_t gap = oldest - laggard;
-        env->me_hsr_callback(env, env->me_txn, 0, 0, laggard,
-                             (gap < UINT_MAX) ? (unsigned)gap : UINT_MAX, 0,
-                             -retry);
-      }
-      mdbx_notice("hsr-kick: update oldest %" PRIaTXN " -> %" PRIaTXN,
-                  lck->mti_oldest_reader.weak, oldest);
-      mdbx_assert(env, lck->mti_oldest_reader.weak <= oldest);
-      return atomic_store64(&lck->mti_oldest_reader, oldest, mo_Relaxed);
-    }
-
-    if (!env->me_hsr_callback)
-      break;
-
-    uint32_t pid = atomic_load32(&asleep->mr_pid, mo_AcquireRelease);
-    uint64_t tid = asleep->mr_tid.weak;
-    if (safe64_read(&asleep->mr_txnid) != laggard || pid <= 0)
-      continue;
-
-    const MDBX_meta *head_meta = constmeta_prefer_last(env);
-    const txnid_t gap =
-        (constmeta_txnid(env, head_meta) - laggard) / xMDBX_TXNID_STEP;
-    const uint64_t head_retired =
-        unaligned_peek_u64(4, head_meta->mm_pages_retired);
-    const size_t space =
-        (head_retired > oldest_retired)
-            ? pgno2bytes(env, (pgno_t)(head_retired - oldest_retired))
-            : 0;
-    int rc = env->me_hsr_callback(
-        env, env->me_txn, pid, (mdbx_tid_t)tid, laggard,
-        (gap < UINT_MAX) ? (unsigned)gap : UINT_MAX, space, retry);
-    if (rc < 0)
-      break;
-
-    if (rc > 0) {
-      if (rc == 1) {
-        safe64_reset_compare(&asleep->mr_txnid, laggard);
-      } else {
-        safe64_reset(&asleep->mr_txnid, true);
-        atomic_store64(&asleep->mr_tid, 0, mo_Relaxed);
-        atomic_store32(&asleep->mr_pid, 0, mo_Relaxed);
-      }
-      atomic_store32(&lck->mti_readers_refresh_flag, true, mo_Relaxed);
-    }
-  }
-
-  if (retry && env->me_hsr_callback) {
-    /* LY: notify end of hsr-loop */
-    env->me_hsr_callback(env, env->me_txn, 0, 0, laggard, 0, 0, -retry);
-  }
-  return mdbx_find_oldest(env->me_txn);
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold int mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold) {
-  return __inline_mdbx_env_set_syncbytes(env, threshold);
-}
-
-__cold int mdbx_env_set_syncperiod(MDBX_env *env, unsigned seconds_16dot16) {
-  return __inline_mdbx_env_set_syncperiod(env, seconds_16dot16);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-__cold int mdbx_env_set_hsr(MDBX_env *env, MDBX_hsr_func *hsr) {
-  int rc = check_env(env, false);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  env->me_hsr_callback = hsr;
-  return MDBX_SUCCESS;
-}
-
-__cold MDBX_hsr_func *mdbx_env_get_hsr(const MDBX_env *env) {
-  return likely(env && env->me_signature.weak == MDBX_ME_SIGNATURE)
-             ? env->me_hsr_callback
-             : NULL;
-}
-
-#ifdef __SANITIZE_THREAD__
-/* LY: avoid tsan-trap by me_txn, mm_last_pg and mt_next_pgno */
-__attribute__((__no_sanitize_thread__, __noinline__))
-#endif
-int mdbx_txn_straggler(const MDBX_txn *txn, int *percent)
-{
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return (rc > 0) ? -rc : rc;
-
-  MDBX_env *env = txn->mt_env;
-  if (unlikely((txn->mt_flags & MDBX_TXN_RDONLY) == 0)) {
-    if (percent)
-      *percent =
-          (int)((txn->mt_next_pgno * UINT64_C(100) + txn->mt_end_pgno / 2) /
-                txn->mt_end_pgno);
-    return 0;
-  }
-
-  txnid_t recent = 0;
-  volatile const MDBX_meta *meta = nullptr;
-  do {
-    meta = meta_prefer_last(env);
-    recent = meta_txnid(env, meta);
-    if (percent) {
-      const pgno_t maxpg = meta->mm_geo.now;
-      *percent = (int)((meta->mm_geo.next * UINT64_C(100) + maxpg / 2) / maxpg);
-    }
-  } while (unlikely(recent != meta_txnid(env, meta)));
-
-  txnid_t lag = (recent - txn->mt_txnid) / xMDBX_TXNID_STEP;
-  return (lag > INT_MAX) ? INT_MAX : (int)lag;
-}
-
-typedef struct mdbx_walk_ctx {
-  void *mw_user;
-  MDBX_pgvisitor_func *mw_visitor;
-  MDBX_txn *mw_txn;
-  MDBX_cursor *mw_cursor;
-  bool mw_dont_check_keys_ordering;
-} mdbx_walk_ctx_t;
-
-__cold static int mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db,
-                                const char *name, int deep);
-
-static MDBX_page_type_t walk_page_type(const MDBX_page *mp) {
-  if (mp)
-    switch (mp->mp_flags) {
-    case P_BRANCH:
-      return MDBX_page_branch;
-    case P_LEAF:
-      return MDBX_page_leaf;
-    case P_LEAF | P_LEAF2:
-      return MDBX_page_dupfixed_leaf;
-    case P_OVERFLOW:
-      return MDBX_page_large;
-    case P_META:
-      return MDBX_page_meta;
-    }
-  return MDBX_page_broken;
-}
-
-/* Depth-first tree traversal. */
-__cold static int mdbx_walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno,
-                                 const char *name, int deep,
-                                 txnid_t parent_txnid) {
-  assert(pgno != P_INVALID);
-  MDBX_page *mp = nullptr;
-  int rc, err = mdbx_page_get(ctx->mw_cursor, pgno, &mp, parent_txnid);
-  if (err == MDBX_SUCCESS)
-    err = mdbx_page_check(ctx->mw_cursor, mp, 0);
-
-  MDBX_page_type_t type = walk_page_type(mp);
-  const int nentries = (mp && !IS_OVERFLOW(mp)) ? page_numkeys(mp) : 1;
-  unsigned npages = (mp && IS_OVERFLOW(mp)) ? mp->mp_pages : 1;
-  size_t pagesize = pgno2bytes(ctx->mw_txn->mt_env, npages);
-  size_t header_size = (mp && !IS_LEAF2(mp) && !IS_OVERFLOW(mp))
-                           ? PAGEHDRSZ + mp->mp_lower
-                           : PAGEHDRSZ;
-  size_t payload_size = 0;
-  size_t unused_size =
-      (mp && !IS_OVERFLOW(mp) ? page_room(mp) : pagesize - header_size) -
-      payload_size;
-  size_t align_bytes = 0;
-
-  if (err == MDBX_SUCCESS) {
-    /* LY: Don't use mask here, e.g bitwise
-     * (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP).
-     * Pages should not me marked dirty/loose or otherwise. */
-    switch (mp->mp_flags) {
-    default:
-      err = MDBX_CORRUPTED;
-      break;
-    case P_BRANCH:
-      if (unlikely(nentries < 2))
-        err = MDBX_CORRUPTED;
-    case P_LEAF:
-    case P_LEAF | P_LEAF2:
-      break;
-    }
-  }
-
-  for (int i = 0; err == MDBX_SUCCESS && i < nentries;
-       align_bytes += ((payload_size + align_bytes) & 1), i++) {
-    if (type == MDBX_page_dupfixed_leaf) {
-      /* LEAF2 pages have no mp_ptrs[] or node headers */
-      payload_size += mp->mp_leaf2_ksize;
-      continue;
-    }
-
-    MDBX_node *node = page_node(mp, i);
-    payload_size += NODESIZE + node_ks(node);
-
-    if (type == MDBX_page_branch) {
-      assert(i > 0 || node_ks(node) == 0);
-      continue;
-    }
-
-    assert(type == MDBX_page_leaf);
-    switch (node_flags(node)) {
-    case 0 /* usual node */:
-      payload_size += node_ds(node);
-      break;
-
-    case F_BIGDATA /* long data on the large/overflow page */: {
-      payload_size += sizeof(pgno_t);
-      const pgno_t large_pgno = node_largedata_pgno(node);
-      const size_t over_payload = node_ds(node);
-      const size_t over_header = PAGEHDRSZ;
-      npages = 1;
-
-      MDBX_page *op;
-      err = mdbx_page_get(ctx->mw_cursor, large_pgno, &op,
-                          pp_txnid4chk(mp, ctx->mw_txn));
-      if (err == MDBX_SUCCESS)
-        err = mdbx_page_check(ctx->mw_cursor, op, 0);
-      if (err == MDBX_SUCCESS) {
-        /* LY: Don't use mask here, e.g bitwise
-         * (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP).
-         * Pages should not me marked dirty/loose or otherwise. */
-        if (unlikely(P_OVERFLOW != op->mp_flags))
-          err = bad_page(mp, "wrong page type %d for large data", op->mp_flags);
-        else
-          npages = op->mp_pages;
-      }
-
-      pagesize = pgno2bytes(ctx->mw_txn->mt_env, npages);
-      const size_t over_unused = pagesize - over_payload - over_header;
-      rc = ctx->mw_visitor(large_pgno, npages, ctx->mw_user, deep, name,
-                           pagesize, MDBX_page_large, err, 1, over_payload,
-                           over_header, over_unused);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
-    } break;
-
-    case F_SUBDATA /* sub-db */: {
-      const size_t namelen = node_ks(node);
-      payload_size += node_ds(node);
-      if (unlikely(namelen == 0 || node_ds(node) != sizeof(MDBX_db)))
-        err = MDBX_CORRUPTED;
-    } break;
-
-    case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */:
-      payload_size += sizeof(MDBX_db);
-      if (unlikely(node_ds(node) != sizeof(MDBX_db)))
-        err = MDBX_CORRUPTED;
-      break;
-
-    case F_DUPDATA /* short sub-page */: {
-      if (unlikely(node_ds(node) <= PAGEHDRSZ)) {
-        err = MDBX_CORRUPTED;
-        break;
-      }
-
-      MDBX_page *sp = node_data(node);
-      const int nsubkeys = page_numkeys(sp);
-      size_t subheader_size =
-          IS_LEAF2(sp) ? PAGEHDRSZ : PAGEHDRSZ + sp->mp_lower;
-      size_t subunused_size = page_room(sp);
-      size_t subpayload_size = 0;
-      size_t subalign_bytes = 0;
-      MDBX_page_type_t subtype;
-
-      switch (sp->mp_flags & /* ignore legacy P_DIRTY flag */ ~0x10) {
-      case P_LEAF | P_SUBP:
-        subtype = MDBX_subpage_leaf;
-        break;
-      case P_LEAF | P_LEAF2 | P_SUBP:
-        subtype = MDBX_subpage_dupfixed_leaf;
-        break;
-      default:
-        subtype = MDBX_subpage_broken;
-        err = MDBX_CORRUPTED;
-      }
-
-      for (int j = 0; err == MDBX_SUCCESS && j < nsubkeys;
-           subalign_bytes += ((subpayload_size + subalign_bytes) & 1), j++) {
-
-        if (subtype == MDBX_subpage_dupfixed_leaf) {
-          /* LEAF2 pages have no mp_ptrs[] or node headers */
-          subpayload_size += sp->mp_leaf2_ksize;
-        } else {
-          assert(subtype == MDBX_subpage_leaf);
-          MDBX_node *subnode = page_node(sp, j);
-          subpayload_size += NODESIZE + node_ks(subnode) + node_ds(subnode);
-          if (unlikely(node_flags(subnode) != 0))
-            err = MDBX_CORRUPTED;
-        }
-      }
-
-      rc = ctx->mw_visitor(pgno, 0, ctx->mw_user, deep + 1, name, node_ds(node),
-                           subtype, err, nsubkeys, subpayload_size,
-                           subheader_size, subunused_size + subalign_bytes);
-      if (unlikely(rc != MDBX_SUCCESS))
-        return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
-      header_size += subheader_size;
-      unused_size += subunused_size;
-      payload_size += subpayload_size;
-      align_bytes += subalign_bytes;
-    } break;
-
-    default:
-      err = MDBX_CORRUPTED;
-    }
-  }
-
-  rc = ctx->mw_visitor(pgno, 1, ctx->mw_user, deep, name,
-                       ctx->mw_txn->mt_env->me_psize, type, err, nentries,
-                       payload_size, header_size, unused_size + align_bytes);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
-
-  for (int i = 0; err == MDBX_SUCCESS && i < nentries; i++) {
-    if (type == MDBX_page_dupfixed_leaf)
-      continue;
-
-    MDBX_node *node = page_node(mp, i);
-    if (type == MDBX_page_branch) {
-      err = mdbx_walk_tree(ctx, node_pgno(node), name, deep + 1,
-                           pp_txnid4chk(mp, ctx->mw_txn));
-      if (unlikely(err != MDBX_SUCCESS)) {
-        if (err == MDBX_RESULT_TRUE)
-          break;
-        return err;
-      }
-      continue;
-    }
-
-    assert(type == MDBX_page_leaf);
-    MDBX_db db;
-    switch (node_flags(node)) {
-    default:
-      continue;
-
-    case F_SUBDATA /* sub-db */: {
-      const size_t namelen = node_ks(node);
-      if (unlikely(namelen == 0 || node_ds(node) != sizeof(MDBX_db))) {
-        err = MDBX_CORRUPTED;
-        break;
-      }
-
-      char namebuf_onstask[64];
-      char *const sub_name = (namelen < sizeof(namebuf_onstask))
-                                 ? namebuf_onstask
-                                 : mdbx_malloc(namelen + 1);
-      if (sub_name) {
-        memcpy(sub_name, node_key(node), namelen);
-        sub_name[namelen] = 0;
-        memcpy(&db, node_data(node), sizeof(db));
-        err = mdbx_walk_sdb(ctx, &db, sub_name, deep + 1);
-        if (sub_name != namebuf_onstask)
-          mdbx_free(sub_name);
-      } else {
-        err = MDBX_ENOMEM;
-      }
-    } break;
-
-    case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */:
-      if (unlikely(node_ds(node) != sizeof(MDBX_db) ||
-                   ctx->mw_cursor->mc_xcursor == NULL))
-        err = MDBX_CORRUPTED;
-      else {
-        memcpy(&db, node_data(node), sizeof(db));
-        assert(ctx->mw_cursor->mc_xcursor ==
-               &container_of(ctx->mw_cursor, MDBX_cursor_couple, outer)->inner);
-        ctx->mw_cursor = &ctx->mw_cursor->mc_xcursor->mx_cursor;
-        err = mdbx_walk_tree(ctx, db.md_root, name, deep + 1,
-                             pp_txnid4chk(mp, ctx->mw_txn));
-        MDBX_xcursor *inner_xcursor =
-            container_of(ctx->mw_cursor, MDBX_xcursor, mx_cursor);
-        MDBX_cursor_couple *couple =
-            container_of(inner_xcursor, MDBX_cursor_couple, inner);
-        ctx->mw_cursor = &couple->outer;
-      }
-      break;
-    }
-  }
-
-  return MDBX_SUCCESS;
-}
-
-__cold static int mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db,
-                                const char *name, int deep) {
-  if (unlikely(db->md_root == P_INVALID))
-    return MDBX_SUCCESS; /* empty db */
-
-  MDBX_cursor_couple couple;
-  MDBX_dbx dbx = {.md_klen_min = INT_MAX};
-  uint8_t dbistate = DBI_VALID | DBI_AUDITED;
-  int rc = mdbx_couple_init(&couple, ~0u, ctx->mw_txn, db, &dbx, &dbistate);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (ctx->mw_dont_check_keys_ordering) {
-    couple.outer.mc_flags |= C_SKIPORD;
-    couple.inner.mx_cursor.mc_flags |= C_SKIPORD;
-  }
-  couple.outer.mc_next = ctx->mw_cursor;
-  ctx->mw_cursor = &couple.outer;
-  rc = mdbx_walk_tree(ctx, db->md_root, name, deep, ctx->mw_txn->mt_txnid);
-  ctx->mw_cursor = couple.outer.mc_next;
-  return rc;
-}
-
-__cold int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
-                           void *user, bool dont_check_keys_ordering) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  mdbx_walk_ctx_t ctx;
-  memset(&ctx, 0, sizeof(ctx));
-  ctx.mw_txn = txn;
-  ctx.mw_user = user;
-  ctx.mw_visitor = visitor;
-  ctx.mw_dont_check_keys_ordering = dont_check_keys_ordering;
-
-  rc = visitor(0, NUM_METAS, user, 0, MDBX_PGWALK_META,
-               pgno2bytes(txn->mt_env, NUM_METAS), MDBX_page_meta, MDBX_SUCCESS,
-               NUM_METAS, sizeof(MDBX_meta) * NUM_METAS, PAGEHDRSZ * NUM_METAS,
-               (txn->mt_env->me_psize - sizeof(MDBX_meta) - PAGEHDRSZ) *
-                   NUM_METAS);
-  if (!MDBX_IS_ERROR(rc))
-    rc = mdbx_walk_sdb(&ctx, &txn->mt_dbs[FREE_DBI], MDBX_PGWALK_GC, 0);
-  if (!MDBX_IS_ERROR(rc))
-    rc = mdbx_walk_sdb(&ctx, &txn->mt_dbs[MAIN_DBI], MDBX_PGWALK_MAIN, 0);
-  return rc;
-}
-
-int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary) {
-  int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (likely(canary)) {
-    if (txn->mt_canary.x == canary->x && txn->mt_canary.y == canary->y &&
-        txn->mt_canary.z == canary->z)
-      return MDBX_SUCCESS;
-    txn->mt_canary.x = canary->x;
-    txn->mt_canary.y = canary->y;
-    txn->mt_canary.z = canary->z;
-  }
-  txn->mt_canary.v = txn->mt_txnid;
-  txn->mt_flags |= MDBX_TXN_DIRTY;
-
-  return MDBX_SUCCESS;
-}
-
-int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(canary == NULL))
-    return MDBX_EINVAL;
-
-  *canary = txn->mt_canary;
-  return MDBX_SUCCESS;
-}
-
-int mdbx_cursor_on_first(const MDBX_cursor *mc) {
-  if (unlikely(mc == NULL))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  if (!(mc->mc_flags & C_INITIALIZED))
-    return mc->mc_db->md_entries ? MDBX_RESULT_FALSE : MDBX_RESULT_TRUE;
-
-  for (unsigned i = 0; i < mc->mc_snum; ++i) {
-    if (mc->mc_ki[i])
-      return MDBX_RESULT_FALSE;
-  }
-
-  return MDBX_RESULT_TRUE;
-}
-
-int mdbx_cursor_on_last(const MDBX_cursor *mc) {
-  if (unlikely(mc == NULL))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  if (!(mc->mc_flags & C_INITIALIZED))
-    return mc->mc_db->md_entries ? MDBX_RESULT_FALSE : MDBX_RESULT_TRUE;
-
-  for (unsigned i = 0; i < mc->mc_snum; ++i) {
-    unsigned nkeys = page_numkeys(mc->mc_pg[i]);
-    if (mc->mc_ki[i] < nkeys - 1)
-      return MDBX_RESULT_FALSE;
-  }
-
-  return MDBX_RESULT_TRUE;
-}
-
-int mdbx_cursor_eof(const MDBX_cursor *mc) {
-  if (unlikely(mc == NULL))
-    return MDBX_EINVAL;
-
-  if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
-    return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                     : MDBX_EBADSIGN;
-
-  return ((mc->mc_flags & (C_INITIALIZED | C_EOF)) == C_INITIALIZED &&
-          mc->mc_snum &&
-          mc->mc_ki[mc->mc_top] < page_numkeys(mc->mc_pg[mc->mc_top]))
-             ? MDBX_RESULT_FALSE
-             : MDBX_RESULT_TRUE;
-}
-
-//------------------------------------------------------------------------------
-
-struct diff_result {
-  ptrdiff_t diff;
-  unsigned level;
-  int root_nkeys;
-};
-
-/* calculates: r = x - y */
-__hot static int cursor_diff(const MDBX_cursor *const __restrict x,
-                             const MDBX_cursor *const __restrict y,
-                             struct diff_result *const __restrict r) {
-  r->diff = 0;
-  r->level = 0;
-  r->root_nkeys = 0;
-
-  if (unlikely(x->mc_signature != MDBX_MC_LIVE))
-    return (x->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                    : MDBX_EBADSIGN;
-
-  if (unlikely(y->mc_signature != MDBX_MC_LIVE))
-    return (y->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                    : MDBX_EBADSIGN;
-
-  int rc = check_txn(x->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(x->mc_txn != y->mc_txn))
-    return MDBX_BAD_TXN;
-
-  if (unlikely(y->mc_dbi != x->mc_dbi))
-    return MDBX_EINVAL;
-
-  if (unlikely(!(y->mc_flags & x->mc_flags & C_INITIALIZED)))
-    return MDBX_ENODATA;
-
-  while (likely(r->level < y->mc_snum && r->level < x->mc_snum)) {
-    if (unlikely(y->mc_pg[r->level] != x->mc_pg[r->level])) {
-      mdbx_error("Mismatch cursors's pages at %u level", r->level);
-      return MDBX_PROBLEM;
-    }
-
-    int nkeys = page_numkeys(y->mc_pg[r->level]);
-    assert(nkeys > 0);
-    if (r->level == 0)
-      r->root_nkeys = nkeys;
-
-    const int limit_ki = nkeys - 1;
-    const int x_ki = x->mc_ki[r->level];
-    const int y_ki = y->mc_ki[r->level];
-    r->diff = ((x_ki < limit_ki) ? x_ki : limit_ki) -
-              ((y_ki < limit_ki) ? y_ki : limit_ki);
-    if (r->diff == 0) {
-      r->level += 1;
-      continue;
-    }
-
-    while (unlikely(r->diff == 1) &&
-           likely(r->level + 1 < y->mc_snum && r->level + 1 < x->mc_snum)) {
-      r->level += 1;
-      /*   DB'PAGEs: 0------------------>MAX
-       *
-       *    CURSORs:       y < x
-       *  STACK[i ]:         |
-       *  STACK[+1]:  ...y++N|0++x...
-       */
-      nkeys = page_numkeys(y->mc_pg[r->level]);
-      r->diff = (nkeys - y->mc_ki[r->level]) + x->mc_ki[r->level];
-      assert(r->diff > 0);
-    }
-
-    while (unlikely(r->diff == -1) &&
-           likely(r->level + 1 < y->mc_snum && r->level + 1 < x->mc_snum)) {
-      r->level += 1;
-      /*   DB'PAGEs: 0------------------>MAX
-       *
-       *    CURSORs:       x < y
-       *  STACK[i ]:         |
-       *  STACK[+1]:  ...x--N|0--y...
-       */
-      nkeys = page_numkeys(x->mc_pg[r->level]);
-      r->diff = -(nkeys - x->mc_ki[r->level]) - y->mc_ki[r->level];
-      assert(r->diff < 0);
-    }
-
-    return MDBX_SUCCESS;
-  }
-
-  r->diff = CMP2INT(x->mc_flags & C_EOF, y->mc_flags & C_EOF);
-  return MDBX_SUCCESS;
-}
-
-__hot static ptrdiff_t estimate(const MDBX_db *db,
-                                struct diff_result *const __restrict dr) {
-  /*        root: branch-page    => scale = leaf-factor * branch-factor^(N-1)
-   *     level-1: branch-page(s) => scale = leaf-factor * branch-factor^2
-   *     level-2: branch-page(s) => scale = leaf-factor * branch-factor
-   *     level-N: branch-page(s) => scale = leaf-factor
-   *  leaf-level: leaf-page(s)   => scale = 1
-   */
-  ptrdiff_t btree_power = (ptrdiff_t)db->md_depth - 2 - (ptrdiff_t)dr->level;
-  if (btree_power < 0)
-    return dr->diff;
-
-  ptrdiff_t estimated =
-      (ptrdiff_t)db->md_entries * dr->diff / (ptrdiff_t)db->md_leaf_pages;
-  if (btree_power == 0)
-    return estimated;
-
-  if (db->md_depth < 4) {
-    assert(dr->level == 0 && btree_power == 1);
-    return (ptrdiff_t)db->md_entries * dr->diff / (ptrdiff_t)dr->root_nkeys;
-  }
-
-  /* average_branchpage_fillfactor = total(branch_entries) / branch_pages
-     total(branch_entries) = leaf_pages + branch_pages - 1 (root page) */
-  const size_t log2_fixedpoint = sizeof(size_t) - 1;
-  const size_t half = UINT64_C(1) << (log2_fixedpoint - 1);
-  const size_t factor =
-      ((db->md_leaf_pages + db->md_branch_pages - 1) << log2_fixedpoint) /
-      db->md_branch_pages;
-  while (1) {
-    switch ((size_t)btree_power) {
-    default: {
-      const size_t square = (factor * factor + half) >> log2_fixedpoint;
-      const size_t quad = (square * square + half) >> log2_fixedpoint;
-      do {
-        estimated = estimated * quad + half;
-        estimated >>= log2_fixedpoint;
-        btree_power -= 4;
-      } while (btree_power >= 4);
-      continue;
-    }
-    case 3:
-      estimated = estimated * factor + half;
-      estimated >>= log2_fixedpoint;
-      __fallthrough /* fall through */;
-    case 2:
-      estimated = estimated * factor + half;
-      estimated >>= log2_fixedpoint;
-      __fallthrough /* fall through */;
-    case 1:
-      estimated = estimated * factor + half;
-      estimated >>= log2_fixedpoint;
-      __fallthrough /* fall through */;
-    case 0:
-      if (unlikely(estimated > (ptrdiff_t)db->md_entries))
-        return (ptrdiff_t)db->md_entries;
-      if (unlikely(estimated < -(ptrdiff_t)db->md_entries))
-        return -(ptrdiff_t)db->md_entries;
-      return estimated;
-    }
-  }
-}
-
-int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *last,
-                           ptrdiff_t *distance_items) {
-  if (unlikely(first == NULL || last == NULL || distance_items == NULL))
-    return MDBX_EINVAL;
-
-  *distance_items = 0;
-  struct diff_result dr;
-  int rc = cursor_diff(last, first, &dr);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(dr.diff == 0) &&
-      F_ISSET(first->mc_db->md_flags & last->mc_db->md_flags,
-              MDBX_DUPSORT | C_INITIALIZED)) {
-    first = &first->mc_xcursor->mx_cursor;
-    last = &last->mc_xcursor->mx_cursor;
-    rc = cursor_diff(first, last, &dr);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  if (likely(dr.diff != 0))
-    *distance_items = estimate(first->mc_db, &dr);
-
-  return MDBX_SUCCESS;
-}
-
-int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
-                       MDBX_cursor_op move_op, ptrdiff_t *distance_items) {
-  if (unlikely(cursor == NULL || distance_items == NULL ||
-               move_op == MDBX_GET_CURRENT || move_op == MDBX_GET_MULTIPLE))
-    return MDBX_EINVAL;
-
-  if (unlikely(cursor->mc_signature != MDBX_MC_LIVE))
-    return (cursor->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL
-                                                         : MDBX_EBADSIGN;
-
-  int rc = check_txn(cursor->mc_txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (!(cursor->mc_flags & C_INITIALIZED))
-    return MDBX_ENODATA;
-
-  MDBX_cursor_couple next;
-  cursor_copy(cursor, &next.outer);
-  if (cursor->mc_db->md_flags & MDBX_DUPSORT) {
-    next.outer.mc_xcursor = &next.inner;
-    rc = mdbx_xcursor_init0(&next.outer);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    MDBX_xcursor *mx = &container_of(cursor, MDBX_cursor_couple, outer)->inner;
-    cursor_copy(&mx->mx_cursor, &next.inner.mx_cursor);
-  }
-
-  MDBX_val stub = {0, 0};
-  if (data == NULL) {
-    const unsigned mask =
-        1 << MDBX_GET_BOTH | 1 << MDBX_GET_BOTH_RANGE | 1 << MDBX_SET_KEY;
-    if (unlikely(mask & (1 << move_op)))
-      return MDBX_EINVAL;
-    data = &stub;
-  }
-
-  if (key == NULL) {
-    const unsigned mask = 1 << MDBX_GET_BOTH | 1 << MDBX_GET_BOTH_RANGE |
-                          1 << MDBX_SET_KEY | 1 << MDBX_SET |
-                          1 << MDBX_SET_RANGE;
-    if (unlikely(mask & (1 << move_op)))
-      return MDBX_EINVAL;
-    key = &stub;
-  }
-
-  next.outer.mc_signature = MDBX_MC_LIVE;
-  rc = mdbx_cursor_get(&next.outer, key, data, move_op);
-  if (unlikely(rc != MDBX_SUCCESS &&
-               (rc != MDBX_NOTFOUND || !(next.outer.mc_flags & C_INITIALIZED))))
-    return rc;
-
-  return mdbx_estimate_distance(cursor, &next.outer, distance_items);
-}
-
-int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
-                        MDBX_val *begin_data, MDBX_val *end_key,
-                        MDBX_val *end_data, ptrdiff_t *size_items) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!size_items))
-    return MDBX_EINVAL;
-
-  if (unlikely(begin_data && (begin_key == NULL || begin_key == MDBX_EPSILON)))
-    return MDBX_EINVAL;
-
-  if (unlikely(end_data && (end_key == NULL || end_key == MDBX_EPSILON)))
-    return MDBX_EINVAL;
-
-  if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  MDBX_cursor_couple begin;
-  /* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */
-  rc = mdbx_cursor_init(&begin.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(begin.outer.mc_db->md_entries == 0)) {
-    *size_items = 0;
-    return MDBX_SUCCESS;
-  }
-
-  if (!begin_key) {
-    if (unlikely(!end_key)) {
-      /* LY: FIRST..LAST case */
-      *size_items = (ptrdiff_t)begin.outer.mc_db->md_entries;
-      return MDBX_SUCCESS;
-    }
-    MDBX_val stub = {0, 0};
-    rc = mdbx_cursor_first(&begin.outer, &stub, &stub);
-    if (unlikely(end_key == MDBX_EPSILON)) {
-      /* LY: FIRST..+epsilon case */
-      return (rc == MDBX_SUCCESS)
-                 ? mdbx_cursor_count(&begin.outer, (size_t *)size_items)
-                 : rc;
-    }
-  } else {
-    if (unlikely(begin_key == MDBX_EPSILON)) {
-      if (end_key == NULL) {
-        /* LY: -epsilon..LAST case */
-        MDBX_val stub = {0, 0};
-        rc = mdbx_cursor_last(&begin.outer, &stub, &stub);
-        return (rc == MDBX_SUCCESS)
-                   ? mdbx_cursor_count(&begin.outer, (size_t *)size_items)
-                   : rc;
-      }
-      /* LY: -epsilon..value case */
-      assert(end_key != MDBX_EPSILON);
-      begin_key = end_key;
-    } else if (unlikely(end_key == MDBX_EPSILON)) {
-      /* LY: value..+epsilon case */
-      assert(begin_key != MDBX_EPSILON);
-      end_key = begin_key;
-    }
-    if (end_key && !begin_data && !end_data &&
-        (begin_key == end_key ||
-         begin.outer.mc_dbx->md_cmp(begin_key, end_key) == 0)) {
-      /* LY: single key case */
-      rc = mdbx_cursor_set(&begin.outer, begin_key, NULL, MDBX_SET).err;
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        *size_items = 0;
-        return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
-      }
-      *size_items = 1;
-      if (begin.outer.mc_xcursor != NULL) {
-        MDBX_node *node = page_node(begin.outer.mc_pg[begin.outer.mc_top],
-                                    begin.outer.mc_ki[begin.outer.mc_top]);
-        if (F_ISSET(node_flags(node), F_DUPDATA)) {
-          /* LY: return the number of duplicates for given key */
-          mdbx_tassert(txn,
-                       begin.outer.mc_xcursor == &begin.inner &&
-                           (begin.inner.mx_cursor.mc_flags & C_INITIALIZED));
-          *size_items =
-              (sizeof(*size_items) >= sizeof(begin.inner.mx_db.md_entries) ||
-               begin.inner.mx_db.md_entries <= PTRDIFF_MAX)
-                  ? (size_t)begin.inner.mx_db.md_entries
-                  : PTRDIFF_MAX;
-        }
-      }
-      return MDBX_SUCCESS;
-    } else {
-      rc = mdbx_cursor_set(&begin.outer, begin_key, begin_data,
-                           begin_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE)
-               .err;
-    }
-  }
-
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    if (rc != MDBX_NOTFOUND || !(begin.outer.mc_flags & C_INITIALIZED))
-      return rc;
-  }
-
-  MDBX_cursor_couple end;
-  rc = mdbx_cursor_init(&end.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  if (!end_key) {
-    MDBX_val stub = {0, 0};
-    rc = mdbx_cursor_last(&end.outer, &stub, &stub);
-  } else {
-    rc = mdbx_cursor_set(&end.outer, end_key, end_data,
-                         end_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE)
-             .err;
-  }
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    if (rc != MDBX_NOTFOUND || !(end.outer.mc_flags & C_INITIALIZED))
-      return rc;
-  }
-
-  rc = mdbx_estimate_distance(&begin.outer, &end.outer, size_items);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  assert(*size_items >= -(ptrdiff_t)begin.outer.mc_db->md_entries &&
-         *size_items <= (ptrdiff_t)begin.outer.mc_db->md_entries);
-
-#if 0 /* LY: Was decided to returns as-is (i.e. negative) the estimation       \
-       * results for an inverted ranges. */
-
-  /* Commit 8ddfd1f34ad7cf7a3c4aa75d2e248ca7e639ed63
-     Change-Id: If59eccf7311123ab6384c4b93f9b1fed5a0a10d1 */
-
-  if (*size_items < 0) {
-    /* LY: inverted range case */
-    *size_items += (ptrdiff_t)begin.outer.mc_db->md_entries;
-  } else if (*size_items == 0 && begin_key && end_key) {
-    int cmp = begin.outer.mc_dbx->md_cmp(&origin_begin_key, &origin_end_key);
-    if (cmp == 0 && (begin.inner.mx_cursor.mc_flags & C_INITIALIZED) &&
-        begin_data && end_data)
-      cmp = begin.outer.mc_dbx->md_dcmp(&origin_begin_data, &origin_end_data);
-    if (cmp > 0) {
-      /* LY: inverted range case with empty scope */
-      *size_items = (ptrdiff_t)begin.outer.mc_db->md_entries;
-    }
-  }
-  assert(*size_items >= 0 &&
-         *size_items <= (ptrdiff_t)begin.outer.mc_db->md_entries);
-#endif
-
-  return MDBX_SUCCESS;
-}
-
-//------------------------------------------------------------------------------
-
-/* Позволяет обновить или удалить существующую запись с получением
- * в old_data предыдущего значения данных. При этом если new_data равен
- * нулю, то выполняется удаление, иначе обновление/вставка.
- *
- * Текущее значение может находиться в уже измененной (грязной) странице.
- * В этом случае страница будет перезаписана при обновлении, а само старое
- * значение утрачено. Поэтому исходно в old_data должен быть передан
- * дополнительный буфер для копирования старого значения.
- * Если переданный буфер слишком мал, то функция вернет -1, установив
- * old_data->iov_len в соответствующее значение.
- *
- * Для не-уникальных ключей также возможен второй сценарий использования,
- * когда посредством old_data из записей с одинаковым ключом для
- * удаления/обновления выбирается конкретная. Для выбора этого сценария
- * во flags следует одновременно указать MDBX_CURRENT и MDBX_NOOVERWRITE.
- * Именно эта комбинация выбрана, так как она лишена смысла, и этим позволяет
- * идентифицировать запрос такого сценария.
- *
- * Функция может быть замещена соответствующими операциями с курсорами
- * после двух доработок (TODO):
- *  - внешняя аллокация курсоров, в том числе на стеке (без malloc).
- *  - получения dirty-статуса страницы по адресу (знать о MUTABLE/WRITEABLE).
- */
-
-int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                    MDBX_val *new_data, MDBX_val *old_data,
-                    MDBX_put_flags_t flags, MDBX_preserve_func preserver,
-                    void *preserver_context) {
-  int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!key || !old_data || old_data == new_data))
-    return MDBX_EINVAL;
-
-  if (unlikely(old_data->iov_base == NULL && old_data->iov_len))
-    return MDBX_EINVAL;
-
-  if (unlikely(new_data == NULL &&
-               (flags & (MDBX_CURRENT | MDBX_RESERVE)) != MDBX_CURRENT))
-    return MDBX_EINVAL;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(flags &
-               ~(MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_ALLDUPS |
-                 MDBX_RESERVE | MDBX_APPEND | MDBX_APPENDDUP | MDBX_CURRENT)))
-    return MDBX_EINVAL;
-
-  MDBX_cursor_couple cx;
-  rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  cx.outer.mc_next = txn->mt_cursors[dbi];
-  txn->mt_cursors[dbi] = &cx.outer;
-
-  MDBX_val present_key = *key;
-  if (F_ISSET(flags, MDBX_CURRENT | MDBX_NOOVERWRITE)) {
-    /* в old_data значение для выбора конкретного дубликата */
-    if (unlikely(!(txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT))) {
-      rc = MDBX_EINVAL;
-      goto bailout;
-    }
-
-    /* убираем лишний бит, он был признаком запрошенного режима */
-    flags -= MDBX_NOOVERWRITE;
-
-    rc = mdbx_cursor_get(&cx.outer, &present_key, old_data, MDBX_GET_BOTH);
-    if (rc != MDBX_SUCCESS)
-      goto bailout;
-  } else {
-    /* в old_data буфер для сохранения предыдущего значения */
-    if (unlikely(new_data && old_data->iov_base == new_data->iov_base))
-      return MDBX_EINVAL;
-    MDBX_val present_data;
-    rc = mdbx_cursor_get(&cx.outer, &present_key, &present_data, MDBX_SET_KEY);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      old_data->iov_base = NULL;
-      old_data->iov_len = 0;
-      if (rc != MDBX_NOTFOUND || (flags & MDBX_CURRENT))
-        goto bailout;
-    } else if (flags & MDBX_NOOVERWRITE) {
-      rc = MDBX_KEYEXIST;
-      *old_data = present_data;
-      goto bailout;
-    } else {
-      MDBX_page *page = cx.outer.mc_pg[cx.outer.mc_top];
-      if (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) {
-        if (flags & MDBX_CURRENT) {
-          /* disallow update/delete for multi-values */
-          MDBX_node *node = page_node(page, cx.outer.mc_ki[cx.outer.mc_top]);
-          if (F_ISSET(node_flags(node), F_DUPDATA)) {
-            mdbx_tassert(txn, XCURSOR_INITED(&cx.outer) &&
-                                  cx.outer.mc_xcursor->mx_db.md_entries > 1);
-            if (cx.outer.mc_xcursor->mx_db.md_entries > 1) {
-              rc = MDBX_EMULTIVAL;
-              goto bailout;
-            }
-          }
-          /* В оригинальной LMDB флажок MDBX_CURRENT здесь приведет
-           * к замене данных без учета MDBX_DUPSORT сортировки,
-           * но здесь это в любом случае допустимо, так как мы
-           * проверили что для ключа есть только одно значение. */
-        }
-      }
-
-      if (IS_MODIFIABLE(txn, page)) {
-        if (new_data && cmp_lenfast(&present_data, new_data) == 0) {
-          /* если данные совпадают, то ничего делать не надо */
-          *old_data = *new_data;
-          goto bailout;
-        }
-        rc = preserver ? preserver(preserver_context, old_data,
-                                   present_data.iov_base, present_data.iov_len)
-                       : MDBX_SUCCESS;
-        if (unlikely(rc != MDBX_SUCCESS))
-          goto bailout;
-      } else {
-        *old_data = present_data;
-      }
-      flags |= MDBX_CURRENT;
-    }
-  }
-
-  if (likely(new_data))
-    rc = mdbx_cursor_put(&cx.outer, key, new_data, flags);
-  else
-    rc = mdbx_cursor_del(&cx.outer, flags & MDBX_ALLDUPS);
-
-bailout:
-  txn->mt_cursors[dbi] = cx.outer.mc_next;
-  return rc;
-}
-
-static int default_value_preserver(void *context, MDBX_val *target,
-                                   const void *src, size_t bytes) {
-  (void)context;
-  if (unlikely(target->iov_len < bytes)) {
-    target->iov_base = nullptr;
-    target->iov_len = bytes;
-    return MDBX_RESULT_TRUE;
-  }
-  memcpy(target->iov_base, src, target->iov_len = bytes);
-  return MDBX_SUCCESS;
-}
-
-int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                 MDBX_val *new_data, MDBX_val *old_data,
-                 MDBX_put_flags_t flags) {
-  return mdbx_replace_ex(txn, dbi, key, new_data, old_data, flags,
-                         default_value_preserver, nullptr);
-}
-
-/* Функция сообщает находится ли указанный адрес в "грязной" странице у
- * заданной пишущей транзакции. В конечном счете это позволяет избавиться от
- * лишнего копирования данных из НЕ-грязных страниц.
- *
- * "Грязные" страницы - это те, которые уже были изменены в ходе пишущей
- * транзакции. Соответственно, какие-либо дальнейшие изменения могут привести
- * к перезаписи таких страниц. Поэтому все функции, выполняющие изменения, в
- * качестве аргументов НЕ должны получать указатели на данные в таких
- * страницах. В свою очередь "НЕ грязные" страницы перед модификацией будут
- * скопированы.
- *
- * Другими словами, данные из "грязных" страниц должны быть либо скопированы
- * перед передачей в качестве аргументов для дальнейших модификаций, либо
- * отвергнуты на стадии проверки корректности аргументов.
- *
- * Таким образом, функция позволяет как избавится от лишнего копирования,
- * так и выполнить более полную проверку аргументов.
- *
- * ВАЖНО: Передаваемый указатель должен указывать на начало данных. Только
- * так гарантируется что актуальный заголовок страницы будет физически
- * расположен в той-же странице памяти, в том числе для многостраничных
- * P_OVERFLOW страниц с длинными данными. */
-int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  const MDBX_env *env = txn->mt_env;
-  const ptrdiff_t offset = (uint8_t *)ptr - env->me_map;
-  if (offset >= 0) {
-    const pgno_t pgno = bytes2pgno(env, offset);
-    if (likely(pgno < txn->mt_next_pgno)) {
-      const MDBX_page *page = pgno2page(env, pgno);
-      if (unlikely(page->mp_pgno != pgno ||
-                   (page->mp_flags & P_ILL_BITS) != 0)) {
-        /* The ptr pointed into middle of a large page,
-         * not to the beginning of a data. */
-        return MDBX_EINVAL;
-      }
-      return ((txn->mt_flags & MDBX_TXN_RDONLY) || !IS_MODIFIABLE(txn, page))
-                 ? MDBX_RESULT_FALSE
-                 : MDBX_RESULT_TRUE;
-    }
-    if ((size_t)offset < env->me_dxb_mmap.limit) {
-      /* Указатель адресует что-то в пределах mmap, но за границей
-       * распределенных страниц. Такое может случится если mdbx_is_dirty()
-       * вызывается после операции, в ходе которой грязная страница была
-       * возвращена в нераспределенное пространство. */
-      return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EINVAL : MDBX_RESULT_TRUE;
-    }
-  }
-
-  /* Страница вне используемого mmap-диапазона, т.е. либо в функцию был
-   * передан некорректный адрес, либо адрес в теневой странице, которая была
-   * выделена посредством malloc().
-   *
-   * Для режима MDBX_WRITE_MAP режима страница однозначно "не грязная",
-   * а для режимов без MDBX_WRITE_MAP однозначно "не чистая". */
-  return (txn->mt_flags & (MDBX_WRITEMAP | MDBX_TXN_RDONLY)) ? MDBX_EINVAL
-                                                             : MDBX_RESULT_TRUE;
-}
-
-int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
-                      uint64_t increment) {
-  int rc = check_txn(txn, MDBX_TXN_BLOCKED);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(txn->mt_dbistate[dbi] & DBI_STALE)) {
-    rc = mdbx_fetch_sdb(txn, dbi);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-  }
-
-  MDBX_db *dbs = &txn->mt_dbs[dbi];
-  if (likely(result))
-    *result = dbs->md_seq;
-
-  if (likely(increment > 0)) {
-    if (unlikely(txn->mt_flags & MDBX_TXN_RDONLY))
-      return MDBX_EACCESS;
-
-    uint64_t new = dbs->md_seq + increment;
-    if (unlikely(new < increment))
-      return MDBX_RESULT_TRUE;
-
-    mdbx_tassert(txn, new > dbs->md_seq);
-    dbs->md_seq = new;
-    txn->mt_flags |= MDBX_TXN_DIRTY;
-    txn->mt_dbistate[dbi] |= DBI_DIRTY;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-__cold MDBX_NOTHROW_CONST_FUNCTION intptr_t mdbx_limits_pgsize_min(void) {
-  return __inline_mdbx_limits_pgsize_min();
-}
-
-__cold MDBX_NOTHROW_CONST_FUNCTION intptr_t mdbx_limits_pgsize_max(void) {
-  return __inline_mdbx_limits_pgsize_max();
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-__cold intptr_t mdbx_limits_dbsize_min(intptr_t pagesize) {
-  if (pagesize < 1)
-    pagesize = (intptr_t)mdbx_default_pagesize();
-  else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
-                    pagesize > (intptr_t)MAX_PAGESIZE ||
-                    !is_powerof2((size_t)pagesize)))
-    return -1;
-
-  return MIN_PAGENO * pagesize;
-}
-
-__cold intptr_t mdbx_limits_dbsize_max(intptr_t pagesize) {
-  if (pagesize < 1)
-    pagesize = (intptr_t)mdbx_default_pagesize();
-  else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
-                    pagesize > (intptr_t)MAX_PAGESIZE ||
-                    !is_powerof2((size_t)pagesize)))
-    return -1;
-
-  STATIC_ASSERT(MAX_MAPSIZE < INTPTR_MAX);
-  const uint64_t limit = (1 + (uint64_t)MAX_PAGENO) * pagesize;
-  return (limit < MAX_MAPSIZE) ? (intptr_t)limit : (intptr_t)MAX_MAPSIZE;
-}
-
-__cold intptr_t mdbx_limits_txnsize_max(intptr_t pagesize) {
-  if (pagesize < 1)
-    pagesize = (intptr_t)mdbx_default_pagesize();
-  else if (unlikely(pagesize < (intptr_t)MIN_PAGESIZE ||
-                    pagesize > (intptr_t)MAX_PAGESIZE ||
-                    !is_powerof2((size_t)pagesize)))
-    return -1;
-
-  STATIC_ASSERT(MAX_MAPSIZE < INTPTR_MAX);
-  const uint64_t pgl_limit =
-      pagesize * (uint64_t)(MDBX_PGL_LIMIT / 1.6180339887498948482);
-  const uint64_t map_limit = (uint64_t)(MAX_MAPSIZE / 1.6180339887498948482);
-  return (pgl_limit < map_limit) ? (intptr_t)pgl_limit : (intptr_t)map_limit;
-}
-
-/*** Key-making functions to avoid custom comparators *************************/
-
-static __always_inline double key2double(const int64_t key) {
-  union {
-    uint64_t u;
-    double f;
-  } casting;
-
-  casting.u = (key < 0) ? key + UINT64_C(0x8000000000000000)
-                        : UINT64_C(0xffffFFFFffffFFFF) - key;
-  return casting.f;
-}
-
-static __always_inline uint64_t double2key(const double *const ptr) {
-  STATIC_ASSERT(sizeof(double) == sizeof(int64_t));
-  const int64_t i = *(const int64_t *)ptr;
-  const uint64_t u = (i < 0) ? UINT64_C(0xffffFFFFffffFFFF) - i
-                             : i + UINT64_C(0x8000000000000000);
-  if (mdbx_assert_enabled()) {
-    const double f = key2double(u);
-    assert(memcmp(&f, ptr, 8) == 0);
-  }
-  return u;
-}
-
-static __always_inline float key2float(const int32_t key) {
-  union {
-    uint32_t u;
-    float f;
-  } casting;
-
-  casting.u =
-      (key < 0) ? key + UINT32_C(0x80000000) : UINT32_C(0xffffFFFF) - key;
-  return casting.f;
-}
-
-static __always_inline uint32_t float2key(const float *const ptr) {
-  STATIC_ASSERT(sizeof(float) == sizeof(int32_t));
-  const int32_t i = *(const int32_t *)ptr;
-  const uint32_t u =
-      (i < 0) ? UINT32_C(0xffffFFFF) - i : i + UINT32_C(0x80000000);
-  if (mdbx_assert_enabled()) {
-    const float f = key2float(u);
-    assert(memcmp(&f, ptr, 4) == 0);
-  }
-  return u;
-}
-
-uint64_t mdbx_key_from_double(const double ieee754_64bit) {
-  return double2key(&ieee754_64bit);
-}
-
-uint64_t mdbx_key_from_ptrdouble(const double *const ieee754_64bit) {
-  return double2key(ieee754_64bit);
-}
-
-uint32_t mdbx_key_from_float(const float ieee754_32bit) {
-  return float2key(&ieee754_32bit);
-}
-
-uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit) {
-  return float2key(ieee754_32bit);
-}
-
-#ifndef LIBMDBX_NO_EXPORTS_LEGACY_API
-MDBX_NOTHROW_CONST_FUNCTION uint64_t mdbx_key_from_int64(const int64_t i64) {
-  return __inline_mdbx_key_from_int64(i64);
-}
-
-MDBX_NOTHROW_CONST_FUNCTION uint32_t mdbx_key_from_int32(const int32_t i32) {
-  return __inline_mdbx_key_from_int32(i32);
-}
-#endif /* LIBMDBX_NO_EXPORTS_LEGACY_API */
-
-#define IEEE754_DOUBLE_MANTISSA_SIZE 52
-#define IEEE754_DOUBLE_EXPONENTA_BIAS 0x3FF
-#define IEEE754_DOUBLE_EXPONENTA_MAX 0x7FF
-#define IEEE754_DOUBLE_IMPLICIT_LEAD UINT64_C(0x0010000000000000)
-#define IEEE754_DOUBLE_MANTISSA_MASK UINT64_C(0x000FFFFFFFFFFFFF)
-#define IEEE754_DOUBLE_MANTISSA_AMAX UINT64_C(0x001FFFFFFFFFFFFF)
-
-static __inline int clz64(uint64_t value) {
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_clzl)
-  if (sizeof(value) == sizeof(int))
-    return __builtin_clz(value);
-  if (sizeof(value) == sizeof(long))
-    return __builtin_clzl(value);
-#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 8) ||            \
-    __has_builtin(__builtin_clzll)
-  return __builtin_clzll(value);
-#endif /* have(long long) && long long == uint64_t */
-#endif /* GNU C */
-
-#if defined(_MSC_VER)
-  unsigned long index;
-#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_X64)
-  _BitScanReverse64(&index, value);
-  return 63 - index;
-#else
-  if (value > UINT32_MAX) {
-    _BitScanReverse(&index, (uint32_t)(value >> 32));
-    return 31 - index;
-  }
-  _BitScanReverse(&index, (uint32_t)value);
-  return 63 - index;
-#endif
-#endif /* MSVC */
-
-  value |= value >> 1;
-  value |= value >> 2;
-  value |= value >> 4;
-  value |= value >> 8;
-  value |= value >> 16;
-  value |= value >> 32;
-  static const uint8_t debruijn_clz64[64] = {
-      63, 16, 62, 7,  15, 36, 61, 3,  6,  14, 22, 26, 35, 47, 60, 2,
-      9,  5,  28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
-      17, 8,  37, 4,  23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
-      38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0};
-  return debruijn_clz64[value * UINT64_C(0x03F79D71B4CB0A89) >> 58];
-}
-
-static __inline uint64_t round_mantissa(const uint64_t u64, int shift) {
-  assert(shift < 0 && u64 > 0);
-  shift = -shift;
-  const unsigned half = 1 << (shift - 1);
-  const unsigned lsb = 1 & (unsigned)(u64 >> shift);
-  const unsigned tie2even = 1 ^ lsb;
-  return (u64 + half - tie2even) >> shift;
-}
-
-uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) {
-  const uint64_t bias = UINT64_C(0x8000000000000000);
-  if (json_integer > 0) {
-    const uint64_t u64 = json_integer;
-    int shift = clz64(u64) - (64 - IEEE754_DOUBLE_MANTISSA_SIZE - 1);
-    uint64_t mantissa = u64 << shift;
-    if (unlikely(shift < 0)) {
-      mantissa = round_mantissa(u64, shift);
-      if (mantissa > IEEE754_DOUBLE_MANTISSA_AMAX)
-        mantissa = round_mantissa(u64, --shift);
-    }
-
-    assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD &&
-           mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX);
-    const uint64_t exponent =
-        IEEE754_DOUBLE_EXPONENTA_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift;
-    assert(exponent > 0 && exponent <= IEEE754_DOUBLE_EXPONENTA_MAX);
-    const uint64_t key = bias + (exponent << IEEE754_DOUBLE_MANTISSA_SIZE) +
-                         (mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD);
-#if !defined(_MSC_VER) ||                                                      \
-    defined(                                                                   \
-        _DEBUG) /* Workaround for MSVC error LNK2019: unresolved external      \
-                   symbol __except1 referenced in function __ftol3_except */
-    assert(key == mdbx_key_from_double((double)json_integer));
-#endif /* Workaround for MSVC */
-    return key;
-  }
-
-  if (json_integer < 0) {
-    const uint64_t u64 = -json_integer;
-    int shift = clz64(u64) - (64 - IEEE754_DOUBLE_MANTISSA_SIZE - 1);
-    uint64_t mantissa = u64 << shift;
-    if (unlikely(shift < 0)) {
-      mantissa = round_mantissa(u64, shift);
-      if (mantissa > IEEE754_DOUBLE_MANTISSA_AMAX)
-        mantissa = round_mantissa(u64, --shift);
-    }
-
-    assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD &&
-           mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX);
-    const uint64_t exponent =
-        IEEE754_DOUBLE_EXPONENTA_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift;
-    assert(exponent > 0 && exponent <= IEEE754_DOUBLE_EXPONENTA_MAX);
-    const uint64_t key = bias - 1 - (exponent << IEEE754_DOUBLE_MANTISSA_SIZE) -
-                         (mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD);
-#if !defined(_MSC_VER) ||                                                      \
-    defined(                                                                   \
-        _DEBUG) /* Workaround for MSVC error LNK2019: unresolved external      \
-                   symbol __except1 referenced in function __ftol3_except */
-    assert(key == mdbx_key_from_double((double)json_integer));
-#endif /* Workaround for MSVC */
-    return key;
-  }
-
-  return bias;
-}
-
-int64_t mdbx_jsonInteger_from_key(const MDBX_val v) {
-  assert(v.iov_len == 8);
-  const uint64_t key = unaligned_peek_u64(2, v.iov_base);
-  const uint64_t bias = UINT64_C(0x8000000000000000);
-  const uint64_t covalent = (key > bias) ? key - bias : bias - key - 1;
-  const int shift = IEEE754_DOUBLE_EXPONENTA_BIAS + 63 -
-                    (IEEE754_DOUBLE_EXPONENTA_MAX &
-                     (int)(covalent >> IEEE754_DOUBLE_MANTISSA_SIZE));
-  if (unlikely(shift < 1))
-    return (key < bias) ? INT64_MIN : INT64_MAX;
-  if (unlikely(shift > 63))
-    return 0;
-
-  const uint64_t unscaled = ((covalent & IEEE754_DOUBLE_MANTISSA_MASK)
-                             << (63 - IEEE754_DOUBLE_MANTISSA_SIZE)) +
-                            bias;
-  const int64_t absolute = unscaled >> shift;
-  const int64_t value = (key < bias) ? -absolute : absolute;
-  assert(key == mdbx_key_from_jsonInteger(value) ||
-         (mdbx_key_from_jsonInteger(value - 1) < key &&
-          key < mdbx_key_from_jsonInteger(value + 1)));
-  return value;
-}
-
-double mdbx_double_from_key(const MDBX_val v) {
-  assert(v.iov_len == 8);
-  return key2double(unaligned_peek_u64(2, v.iov_base));
-}
-
-float mdbx_float_from_key(const MDBX_val v) {
-  assert(v.iov_len == 4);
-  return key2float(unaligned_peek_u32(2, v.iov_base));
-}
-
-int32_t mdbx_int32_from_key(const MDBX_val v) {
-  assert(v.iov_len == 4);
-  return (int32_t)(unaligned_peek_u32(2, v.iov_base) - UINT32_C(0x80000000));
-}
-
-int64_t mdbx_int64_from_key(const MDBX_val v) {
-  assert(v.iov_len == 8);
-  return (int64_t)(unaligned_peek_u64(2, v.iov_base) -
-                   UINT64_C(0x8000000000000000));
-}
-
-__cold MDBX_cmp_func *mdbx_get_keycmp(unsigned flags) {
-  return get_default_keycmp(flags);
-}
-
-__cold MDBX_cmp_func *mdbx_get_datacmp(unsigned flags) {
-  return get_default_datacmp(flags);
-}
-
-__cold int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option,
-                               uint64_t value) {
-  int err = check_env(env, false);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  const bool lock_needed = ((env->me_flags & MDBX_ENV_ACTIVE) && env->me_txn0 &&
-                            env->me_txn0->mt_owner != mdbx_thread_self());
-  bool should_unlock = false;
-  switch (option) {
-  case MDBX_opt_sync_bytes:
-    if (value == UINT64_MAX)
-      value = SIZE_MAX - 65536;
-    if (unlikely(env->me_flags & MDBX_RDONLY))
-      return MDBX_EACCESS;
-    if (unlikely(!(env->me_flags & MDBX_ENV_ACTIVE)))
-      return MDBX_EPERM;
-    if (unlikely(value > SIZE_MAX - 65536))
-      return MDBX_TOO_LARGE;
-    if (atomic_store32(&env->me_lck->mti_autosync_threshold,
-                       bytes2pgno(env, (size_t)value + env->me_psize - 1),
-                       mo_Relaxed) != 0 &&
-        (env->me_flags & MDBX_ENV_ACTIVE)) {
-      err = mdbx_env_sync_poll(env);
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-      err = MDBX_SUCCESS;
-    }
-    break;
-
-  case MDBX_opt_sync_period:
-    if (value == UINT64_MAX)
-      value = UINT32_MAX;
-    if (unlikely(env->me_flags & MDBX_RDONLY))
-      return MDBX_EACCESS;
-    if (unlikely(!(env->me_flags & MDBX_ENV_ACTIVE)))
-      return MDBX_EPERM;
-    if (unlikely(value > UINT32_MAX))
-      return MDBX_TOO_LARGE;
-    if (atomic_store64(&env->me_lck->mti_autosync_period,
-                       mdbx_osal_16dot16_to_monotime((uint32_t)value),
-                       mo_Relaxed) != 0 &&
-        (env->me_flags & MDBX_ENV_ACTIVE)) {
-      err = mdbx_env_sync_poll(env);
-      if (unlikely(MDBX_IS_ERROR(err)))
-        return err;
-      err = MDBX_SUCCESS;
-    }
-    break;
-
-  case MDBX_opt_max_db:
-    if (value == UINT64_MAX)
-      value = MDBX_MAX_DBI;
-    if (unlikely(value > MDBX_MAX_DBI))
-      return MDBX_EINVAL;
-    if (unlikely(env->me_map))
-      return MDBX_EPERM;
-    env->me_maxdbs = (unsigned)value + CORE_DBS;
-    break;
-
-  case MDBX_opt_max_readers:
-    if (value == UINT64_MAX)
-      value = MDBX_READERS_LIMIT;
-    if (unlikely(value < 1 || value > MDBX_READERS_LIMIT))
-      return MDBX_EINVAL;
-    if (unlikely(env->me_map))
-      return MDBX_EPERM;
-    env->me_maxreaders = (unsigned)value;
-    break;
-
-  case MDBX_opt_dp_reserve_limit:
-    if (value == UINT64_MAX)
-      value = INT_MAX;
-    if (unlikely(value > INT_MAX))
-      return MDBX_EINVAL;
-    if (env->me_options.dp_reserve_limit != (unsigned)value) {
-      if (lock_needed) {
-        err = mdbx_txn_lock(env, false);
-        if (unlikely(err != MDBX_SUCCESS))
-          return err;
-        should_unlock = true;
-      }
-      env->me_options.dp_reserve_limit = (unsigned)value;
-      while (env->me_dp_reserve_len > env->me_options.dp_reserve_limit) {
-        mdbx_assert(env, env->me_dp_reserve != NULL);
-        MDBX_page *dp = env->me_dp_reserve;
-        MDBX_ASAN_UNPOISON_MEMORY_REGION(dp, env->me_psize);
-        VALGRIND_MAKE_MEM_DEFINED(&dp->mp_next, sizeof(dp->mp_next));
-        env->me_dp_reserve = dp->mp_next;
-        VALGRIND_MEMPOOL_FREE(env, dp);
-        mdbx_free(dp);
-        env->me_dp_reserve_len -= 1;
-      }
-    }
-    break;
-
-  case MDBX_opt_rp_augment_limit:
-    if (value == UINT64_MAX)
-      value = MDBX_PGL_LIMIT;
-    if (unlikely(value > MDBX_PGL_LIMIT))
-      return MDBX_EINVAL;
-    env->me_options.rp_augment_limit = (unsigned)value;
-    break;
-
-  case MDBX_opt_txn_dp_limit:
-  case MDBX_opt_txn_dp_initial:
-    if (value == UINT64_MAX)
-      value = MDBX_PGL_LIMIT;
-    if (unlikely(value > MDBX_PGL_LIMIT || value < CURSOR_STACK * 4))
-      return MDBX_EINVAL;
-    if (unlikely(env->me_flags & MDBX_RDONLY))
-      return MDBX_EACCESS;
-    if (lock_needed) {
-      err = mdbx_txn_lock(env, false);
-      if (unlikely(err != MDBX_SUCCESS))
-        return err;
-      should_unlock = true;
-    }
-    if (env->me_txn)
-      err = MDBX_EPERM /* unable change during transaction */;
-    else {
-      const pgno_t value32 = (pgno_t)value;
-      if (option == MDBX_opt_txn_dp_initial &&
-          env->me_options.dp_initial != value32) {
-        env->me_options.dp_initial = value32;
-        if (env->me_options.dp_limit < value32) {
-          env->me_options.dp_limit = value32;
-          env->me_options.flags.non_auto.dp_limit = 1;
-        }
-      }
-      if (option == MDBX_opt_txn_dp_limit &&
-          env->me_options.dp_limit != value32) {
-        env->me_options.dp_limit = value32;
-        env->me_options.flags.non_auto.dp_limit = 1;
-        if (env->me_options.dp_initial > value32)
-          env->me_options.dp_initial = value32;
-      }
-    }
-    break;
-
-  case MDBX_opt_spill_max_denominator:
-    if (value == UINT64_MAX)
-      value = 255;
-    if (unlikely(value > 255))
-      return MDBX_EINVAL;
-    env->me_options.spill_max_denominator = (uint8_t)value;
-    break;
-  case MDBX_opt_spill_min_denominator:
-    if (unlikely(value > 255))
-      return MDBX_EINVAL;
-    env->me_options.spill_min_denominator = (uint8_t)value;
-    break;
-  case MDBX_opt_spill_parent4child_denominator:
-    if (unlikely(value > 255))
-      return MDBX_EINVAL;
-    env->me_options.spill_parent4child_denominator = (uint8_t)value;
-    break;
-
-  case MDBX_opt_loose_limit:
-    if (value == UINT64_MAX)
-      value = 255;
-    if (unlikely(value > 255))
-      return MDBX_EINVAL;
-    env->me_options.dp_loose_limit = (uint8_t)value;
-    break;
-
-  case MDBX_opt_merge_threshold_16dot16_percent:
-    if (value == UINT64_MAX)
-      value = 32768;
-    if (unlikely(value < 8192 || value > 32768))
-      return MDBX_EINVAL;
-    env->me_options.merge_threshold_16dot16_percent = (unsigned)value;
-    recalculate_merge_threshold(env);
-    break;
-
-  default:
-    return MDBX_EINVAL;
-  }
-
-  if (should_unlock)
-    mdbx_txn_unlock(env);
-  return err;
-}
-
-__cold int mdbx_env_get_option(const MDBX_env *env, const MDBX_option_t option,
-                               uint64_t *pvalue) {
-  int err = check_env(env, false);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-  if (unlikely(!pvalue))
-    return MDBX_EINVAL;
-
-  switch (option) {
-  case MDBX_opt_sync_bytes:
-    if (unlikely(!(env->me_flags & MDBX_ENV_ACTIVE)))
-      return MDBX_EPERM;
-    *pvalue = pgno2bytes(
-        env, atomic_load32(&env->me_lck->mti_autosync_threshold, mo_Relaxed));
-    break;
-
-  case MDBX_opt_sync_period:
-    if (unlikely(!(env->me_flags & MDBX_ENV_ACTIVE)))
-      return MDBX_EPERM;
-    *pvalue = mdbx_osal_monotime_to_16dot16(
-        atomic_load64(&env->me_lck->mti_autosync_period, mo_Relaxed));
-    break;
-
-  case MDBX_opt_max_db:
-    *pvalue = env->me_maxdbs - CORE_DBS;
-    break;
-
-  case MDBX_opt_max_readers:
-    *pvalue = env->me_maxreaders;
-    break;
-
-  case MDBX_opt_dp_reserve_limit:
-    *pvalue = env->me_options.dp_reserve_limit;
-    break;
-
-  case MDBX_opt_rp_augment_limit:
-    *pvalue = env->me_options.rp_augment_limit;
-    break;
-
-  case MDBX_opt_txn_dp_limit:
-    *pvalue = env->me_options.dp_limit;
-    break;
-  case MDBX_opt_txn_dp_initial:
-    *pvalue = env->me_options.dp_initial;
-    break;
-
-  case MDBX_opt_spill_max_denominator:
-    *pvalue = env->me_options.spill_max_denominator;
-    break;
-  case MDBX_opt_spill_min_denominator:
-    *pvalue = env->me_options.spill_min_denominator;
-    break;
-  case MDBX_opt_spill_parent4child_denominator:
-    *pvalue = env->me_options.spill_parent4child_denominator;
-    break;
-
-  case MDBX_opt_loose_limit:
-    *pvalue = env->me_options.dp_loose_limit;
-    break;
-
-  case MDBX_opt_merge_threshold_16dot16_percent:
-    *pvalue = env->me_options.merge_threshold_16dot16_percent;
-    break;
-
-  default:
-    return MDBX_EINVAL;
-  }
-
-  return MDBX_SUCCESS;
-}
-
-/*** Attribute support functions for Nexenta **********************************/
-#ifdef MDBX_NEXENTA_ATTRS
-
-static __inline int mdbx_attr_peek(MDBX_val *data, mdbx_attr_t *attrptr) {
-  if (unlikely(data->iov_len < sizeof(mdbx_attr_t)))
-    return MDBX_INCOMPATIBLE;
-
-  if (likely(attrptr != NULL))
-    *attrptr = *(mdbx_attr_t *)data->iov_base;
-  data->iov_len -= sizeof(mdbx_attr_t);
-  data->iov_base =
-      likely(data->iov_len > 0) ? ((mdbx_attr_t *)data->iov_base) + 1 : NULL;
-
-  return MDBX_SUCCESS;
-}
-
-static __inline int mdbx_attr_poke(MDBX_val *reserved, MDBX_val *data,
-                                   mdbx_attr_t attr, MDBX_put_flags_t flags) {
-  mdbx_attr_t *space = reserved->iov_base;
-  if (flags & MDBX_RESERVE) {
-    if (likely(data != NULL)) {
-      data->iov_base = data->iov_len ? space + 1 : NULL;
-    }
-  } else {
-    *space = attr;
-    if (likely(data != NULL)) {
-      memcpy(space + 1, data->iov_base, data->iov_len);
-    }
-  }
-
-  return MDBX_SUCCESS;
-}
-
-int mdbx_cursor_get_attr(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
-                         mdbx_attr_t *attrptr, MDBX_cursor_op op) {
-  int rc = mdbx_cursor_get(mc, key, data, op);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_attr_peek(data, attrptr);
-}
-
-int mdbx_get_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
-                  uint64_t *attrptr) {
-  int rc = mdbx_get(txn, dbi, key, data);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_attr_peek(data, attrptr);
-}
-
-int mdbx_put_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
-                  mdbx_attr_t attr, MDBX_put_flags_t flags) {
-  MDBX_val reserve;
-  reserve.iov_base = NULL;
-  reserve.iov_len = (data ? data->iov_len : 0) + sizeof(mdbx_attr_t);
-
-  int rc = mdbx_put(txn, dbi, key, &reserve, flags | MDBX_RESERVE);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_attr_poke(&reserve, data, attr, flags);
-}
-
-int mdbx_cursor_put_attr(MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
-                         mdbx_attr_t attr, MDBX_put_flags_t flags) {
-  MDBX_val reserve;
-  reserve.iov_base = NULL;
-  reserve.iov_len = (data ? data->iov_len : 0) + sizeof(mdbx_attr_t);
-
-  int rc = mdbx_cursor_put(cursor, key, &reserve, flags | MDBX_RESERVE);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  return mdbx_attr_poke(&reserve, data, attr, flags);
-}
-
-int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
-                  mdbx_attr_t attr) {
-  if (unlikely(!key || !txn))
-    return MDBX_EINVAL;
-
-  if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
-    return MDBX_EBADSIGN;
-
-  if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
-    return MDBX_BAD_DBI;
-
-  if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
-    return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
-
-  MDBX_cursor_couple cx;
-  MDBX_val old_data;
-  int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-  rc = mdbx_cursor_set(&cx.outer, key, &old_data, MDBX_SET, NULL);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    if (rc == MDBX_NOTFOUND && data) {
-      cx.outer.mc_next = txn->mt_cursors[dbi];
-      txn->mt_cursors[dbi] = &cx.outer;
-      rc = mdbx_cursor_put_attr(&cx.outer, key, data, attr, 0);
-      txn->mt_cursors[dbi] = cx.outer.mc_next;
-    }
-    return rc;
-  }
-
-  mdbx_attr_t old_attr = 0;
-  rc = mdbx_attr_peek(&old_data, &old_attr);
-  if (unlikely(rc != MDBX_SUCCESS))
-    return rc;
-
-  if (old_attr == attr && (!data || (data->iov_len == old_data.iov_len &&
-                                     memcmp(data->iov_base, old_data.iov_base,
-                                            old_data.iov_len) == 0)))
-    return MDBX_SUCCESS;
-
-  cx.outer.mc_next = txn->mt_cursors[dbi];
-  txn->mt_cursors[dbi] = &cx.outer;
-  rc = mdbx_cursor_put_attr(&cx.outer, key, data ? data : &old_data, attr,
-                            MDBX_CURRENT);
-  txn->mt_cursors[dbi] = cx.outer.mc_next;
-  return rc;
-}
-#endif /* MDBX_NEXENTA_ATTRS */
-
-/******************************************************************************/
-/* *INDENT-OFF* */
-/* clang-format off */
-
-__dll_export
-#ifdef __attribute_used__
-    __attribute_used__
-#elif defined(__GNUC__) || __has_attribute(__used__)
-    __attribute__((__used__))
-#endif
-#ifdef __attribute_externally_visible__
-        __attribute_externally_visible__
-#elif (defined(__GNUC__) && !defined(__clang__)) ||                            \
-    __has_attribute(__externally_visible__)
-    __attribute__((__externally_visible__))
-#endif
-    const struct MDBX_build_info mdbx_build = {
-#ifdef MDBX_BUILD_TIMESTAMP
-    MDBX_BUILD_TIMESTAMP
-#else
-    "\"" __DATE__ " " __TIME__ "\""
-#endif /* MDBX_BUILD_TIMESTAMP */
-
-    ,
-#ifdef MDBX_BUILD_TARGET
-    MDBX_BUILD_TARGET
-#else
-  #if defined(__ANDROID_API__)
-    "Android" MDBX_STRINGIFY(__ANDROID_API__)
-  #elif defined(__linux__) || defined(__gnu_linux__)
-    "Linux"
-  #elif defined(EMSCRIPTEN) || defined(__EMSCRIPTEN__)
-    "webassembly"
-  #elif defined(__CYGWIN__)
-    "CYGWIN"
-  #elif defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) \
-      || defined(__WINDOWS__)
-    "Windows"
-  #elif defined(__APPLE__)
-    #if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) \
-      || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)
-      "iOS"
-    #else
-      "MacOS"
-    #endif
-  #elif defined(__FreeBSD__)
-    "FreeBSD"
-  #elif defined(__DragonFly__)
-    "DragonFlyBSD"
-  #elif defined(__NetBSD__)
-    "NetBSD"
-  #elif defined(__OpenBSD__)
-    "OpenBSD"
-  #elif defined(__bsdi__)
-    "UnixBSDI"
-  #elif defined(__MACH__)
-    "MACH"
-  #elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC))
-    "HPUX"
-  #elif defined(_AIX)
-    "AIX"
-  #elif defined(__sun) && defined(__SVR4)
-    "Solaris"
-  #elif defined(__BSD__) || defined(BSD)
-    "UnixBSD"
-  #elif defined(__unix__) || defined(UNIX) || defined(__unix) \
-      || defined(__UNIX) || defined(__UNIX__)
-    "UNIX"
-  #elif defined(_POSIX_VERSION)
-    "POSIX" MDBX_STRINGIFY(_POSIX_VERSION)
-  #else
-    "UnknownOS"
-  #endif /* Target OS */
-
-    "-"
-
-  #if defined(__amd64__)
-    "AMD64"
-  #elif defined(__ia32__)
-    "IA32"
-  #elif defined(__e2k__) || defined(__elbrus__)
-    "Elbrus"
-  #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
-    "Alpha"
-  #elif defined(__aarch64__) || defined(_M_ARM64)
-    "ARM64"
-  #elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) \
-      || defined(__TARGET_ARCH_THUMB) || defined(_ARM) || defined(_M_ARM) \
-      || defined(_M_ARMT) || defined(__arm)
-    "ARM"
-  #elif defined(__mips64) || defined(__mips64__) || (defined(__mips) && (__mips >= 64))
-    "MIPS64"
-  #elif defined(__mips__) || defined(__mips) || defined(_R4000) || defined(__MIPS__)
-    "MIPS"
-  #elif defined(__hppa64__) || defined(__HPPA64__) || defined(__hppa64)
-    "PARISC64"
-  #elif defined(__hppa__) || defined(__HPPA__) || defined(__hppa)
-    "PARISC"
-  #elif defined(__ia64__) || defined(__ia64) || defined(_IA64) \
-      || defined(__IA64__) || defined(_M_IA64) || defined(__itanium__)
-    "Itanium"
-  #elif defined(__powerpc64__) || defined(__ppc64__) || defined(__ppc64) \
-      || defined(__powerpc64) || defined(_ARCH_PPC64)
-    "PowerPC64"
-  #elif defined(__powerpc__) || defined(__ppc__) || defined(__powerpc) \
-      || defined(__ppc) || defined(_ARCH_PPC) || defined(__PPC__) || defined(__POWERPC__)
-    "PowerPC"
-  #elif defined(__sparc64__) || defined(__sparc64)
-    "SPARC64"
-  #elif defined(__sparc__) || defined(__sparc)
-    "SPARC"
-  #elif defined(__s390__) || defined(__s390) || defined(__zarch__) || defined(__zarch)
-    "S390"
-  #else
-    "UnknownARCH"
-  #endif
-#endif /* MDBX_BUILD_TARGET */
-
-#ifdef MDBX_BUILD_TYPE
-# if defined(_MSC_VER)
-#   pragma message("Configuration-depended MDBX_BUILD_TYPE: " MDBX_BUILD_TYPE)
-# endif
-    "-" MDBX_BUILD_TYPE
-#endif /* MDBX_BUILD_TYPE */
-    ,
-    "MDBX_DEBUG=" MDBX_STRINGIFY(MDBX_DEBUG)
-    " MDBX_WORDBITS=" MDBX_STRINGIFY(MDBX_WORDBITS)
-    " BYTE_ORDER="
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    "LITTLE_ENDIAN"
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    "BIG_ENDIAN"
-#else
-    #error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-    " MDBX_ENV_CHECKPID=" MDBX_ENV_CHECKPID_CONFIG
-    " MDBX_TXN_CHECKOWNER=" MDBX_TXN_CHECKOWNER_CONFIG
-    " MDBX_64BIT_ATOMIC=" MDBX_64BIT_ATOMIC_CONFIG
-    " MDBX_64BIT_CAS=" MDBX_64BIT_CAS_CONFIG
-    " MDBX_TRUST_RTC=" MDBX_TRUST_RTC_CONFIG
-    " MDBX_ENABLE_REFUND=" MDBX_STRINGIFY(MDBX_ENABLE_REFUND)
-    " MDBX_ENABLE_MADVISE=" MDBX_STRINGIFY(MDBX_ENABLE_MADVISE)
-#if MDBX_DISABLE_PAGECHECKS
-    " MDBX_DISABLE_PAGECHECKS=YES"
-#endif /* MDBX_DISABLE_PAGECHECKS */
-#ifdef __SANITIZE_ADDRESS__
-    " SANITIZE_ADDRESS=YES"
-#endif /* __SANITIZE_ADDRESS__ */
-#ifdef MDBX_USE_VALGRIND
-    " MDBX_USE_VALGRIND=YES"
-#endif /* MDBX_USE_VALGRIND */
-#if MDBX_FORCE_ASSERTIONS
-    " MDBX_FORCE_ASSERTIONS=YES"
-#endif /* MDBX_FORCE_ASSERTIONS */
-#ifdef _GNU_SOURCE
-    " _GNU_SOURCE=YES"
-#else
-    " _GNU_SOURCE=NO"
-#endif /* _GNU_SOURCE */
-#ifdef __APPLE__
-    " MDBX_OSX_SPEED_INSTEADOF_DURABILITY=" MDBX_STRINGIFY(MDBX_OSX_SPEED_INSTEADOF_DURABILITY)
-#endif /* MacOS */
-#if defined(_WIN32) || defined(_WIN64)
-    " MDBX_WITHOUT_MSVC_CRT=" MDBX_STRINGIFY(MDBX_WITHOUT_MSVC_CRT)
-    " MDBX_BUILD_SHARED_LIBRARY=" MDBX_STRINGIFY(MDBX_BUILD_SHARED_LIBRARY)
-#if !MDBX_BUILD_SHARED_LIBRARY
-    " MDBX_MANUAL_MODULE_HANDLER=" MDBX_STRINGIFY(MDBX_MANUAL_MODULE_HANDLER)
-#endif
-    " WINVER=" MDBX_STRINGIFY(WINVER)
-#else /* Windows */
-    " MDBX_LOCKING=" MDBX_LOCKING_CONFIG
-    " MDBX_USE_OFDLOCKS=" MDBX_USE_OFDLOCKS_CONFIG
-#endif /* !Windows */
-    " MDBX_CACHELINE_SIZE=" MDBX_STRINGIFY(MDBX_CACHELINE_SIZE)
-    " MDBX_CPU_WRITEBACK_INCOHERENT=" MDBX_STRINGIFY(MDBX_CPU_WRITEBACK_INCOHERENT)
-    " MDBX_MMAP_INCOHERENT_CPU_CACHE=" MDBX_STRINGIFY(MDBX_MMAP_INCOHERENT_CPU_CACHE)
-    " MDBX_MMAP_INCOHERENT_FILE_WRITE=" MDBX_STRINGIFY(MDBX_MMAP_INCOHERENT_FILE_WRITE)
-    " MDBX_UNALIGNED_OK=" MDBX_STRINGIFY(MDBX_UNALIGNED_OK)
-    " MDBX_PNL_ASCENDING=" MDBX_STRINGIFY(MDBX_PNL_ASCENDING)
-    ,
-#ifdef MDBX_BUILD_COMPILER
-    MDBX_BUILD_COMPILER
-#else
-  #ifdef __INTEL_COMPILER
-    "Intel C/C++ " MDBX_STRINGIFY(__INTEL_COMPILER)
-  #elif defined(__apple_build_version__)
-    "Apple clang " MDBX_STRINGIFY(__apple_build_version__)
-  #elif defined(__ibmxl__)
-    "IBM clang C " MDBX_STRINGIFY(__ibmxl_version__) "." MDBX_STRINGIFY(__ibmxl_release__)
-    "." MDBX_STRINGIFY(__ibmxl_modification__) "." MDBX_STRINGIFY(__ibmxl_ptf_fix_level__)
-  #elif defined(__clang__)
-    "clang " MDBX_STRINGIFY(__clang_version__)
-  #elif defined(__MINGW64__)
-    "MINGW-64 " MDBX_STRINGIFY(__MINGW64_MAJOR_VERSION) "." MDBX_STRINGIFY(__MINGW64_MINOR_VERSION)
-  #elif defined(__MINGW32__)
-    "MINGW-32 " MDBX_STRINGIFY(__MINGW32_MAJOR_VERSION) "." MDBX_STRINGIFY(__MINGW32_MINOR_VERSION)
-  #elif defined(__IBMC__)
-    "IBM C " MDBX_STRINGIFY(__IBMC__)
-  #elif defined(__GNUC__)
-    "GNU C/C++ "
-    #ifdef __VERSION__
-      __VERSION__
-    #else
-      MDBX_STRINGIFY(__GNUC__) "." MDBX_STRINGIFY(__GNUC_MINOR__) "." MDBX_STRINGIFY(__GNUC_PATCHLEVEL__)
-    #endif
-  #elif defined(_MSC_VER)
-    "MSVC " MDBX_STRINGIFY(_MSC_FULL_VER) "-" MDBX_STRINGIFY(_MSC_BUILD)
-  #else
-    "Unknown compiler"
-  #endif
-#endif /* MDBX_BUILD_COMPILER */
-    ,
-#ifdef MDBX_BUILD_FLAGS_CONFIG
-    MDBX_BUILD_FLAGS_CONFIG
-#endif /* MDBX_BUILD_FLAGS_CONFIG */
-#ifdef MDBX_BUILD_FLAGS
-    MDBX_BUILD_FLAGS
-#endif /* MDBX_BUILD_FLAGS */
-#if !(defined(MDBX_BUILD_FLAGS_CONFIG) || defined(MDBX_BUILD_FLAGS))
-    "undefined (please use correct build script)"
-#ifdef _MSC_VER
-#pragma message("warning: Build flags undefined. Please use correct build script")
-#else
-#warning "Build flags undefined. Please use correct build script"
-#endif // _MSC_VER
-#endif
-};
-
-#ifdef __SANITIZE_ADDRESS__
-LIBMDBX_API __attribute__((__weak__)) const char *__asan_default_options() {
-  return "symbolize=1:allow_addr2line=1:"
-#if MDBX_DEBUG
-         "debug=1:"
-         "verbosity=2:"
-#endif /* MDBX_DEBUG */
-         "log_threads=1:"
-         "report_globals=1:"
-         "replace_str=1:replace_intrin=1:"
-         "malloc_context_size=9:"
-         "detect_leaks=1:"
-         "check_printf=1:"
-         "detect_deadlocks=1:"
-#ifndef LTO_ENABLED
-         "check_initialization_order=1:"
-#endif
-         "detect_stack_use_after_return=1:"
-         "intercept_tls_get_addr=1:"
-         "decorate_proc_maps=1:"
-         "abort_on_error=1";
-}
-#endif /* __SANITIZE_ADDRESS__ */
-
-/* *INDENT-ON* */
-/* clang-format on */
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-#if defined(_WIN32) || defined(_WIN64)
-
-#include <winioctl.h>
-
-static int waitstatus2errcode(DWORD result) {
-  switch (result) {
-  case WAIT_OBJECT_0:
-    return MDBX_SUCCESS;
-  case WAIT_FAILED:
-    return (int)GetLastError();
-  case WAIT_ABANDONED:
-    return ERROR_ABANDONED_WAIT_0;
-  case WAIT_IO_COMPLETION:
-    return ERROR_USER_APC;
-  case WAIT_TIMEOUT:
-    return ERROR_TIMEOUT;
-  default:
-    return ERROR_UNHANDLED_ERROR;
-  }
-}
-
-/* Map a result from an NTAPI call to WIN32 error code. */
-static int ntstatus2errcode(NTSTATUS status) {
-  DWORD dummy;
-  OVERLAPPED ov;
-  memset(&ov, 0, sizeof(ov));
-  ov.Internal = status;
-  return GetOverlappedResult(NULL, &ov, &dummy, FALSE) ? MDBX_SUCCESS
-                                                       : (int)GetLastError();
-}
-
-/* We use native NT APIs to setup the memory map, so that we can
- * let the DB file grow incrementally instead of always preallocating
- * the full size. These APIs are defined in <wdm.h> and <ntifs.h>
- * but those headers are meant for driver-level development and
- * conflict with the regular user-level headers, so we explicitly
- * declare them here. Using these APIs also means we must link to
- * ntdll.dll, which is not linked by default in user code. */
-
-extern NTSTATUS NTAPI NtCreateSection(
-    OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess,
-    IN OPTIONAL POBJECT_ATTRIBUTES ObjectAttributes,
-    IN OPTIONAL PLARGE_INTEGER MaximumSize, IN ULONG SectionPageProtection,
-    IN ULONG AllocationAttributes, IN OPTIONAL HANDLE FileHandle);
-
-typedef struct _SECTION_BASIC_INFORMATION {
-  ULONG Unknown;
-  ULONG SectionAttributes;
-  LARGE_INTEGER SectionSize;
-} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
-
-extern NTSTATUS NTAPI NtMapViewOfSection(
-    IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
-    IN ULONG_PTR ZeroBits, IN SIZE_T CommitSize,
-    IN OUT OPTIONAL PLARGE_INTEGER SectionOffset, IN OUT PSIZE_T ViewSize,
-    IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType,
-    IN ULONG Win32Protect);
-
-extern NTSTATUS NTAPI NtUnmapViewOfSection(IN HANDLE ProcessHandle,
-                                           IN OPTIONAL PVOID BaseAddress);
-
-extern NTSTATUS NTAPI NtClose(HANDLE Handle);
-
-extern NTSTATUS NTAPI NtAllocateVirtualMemory(
-    IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG_PTR ZeroBits,
-    IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect);
-
-extern NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle,
-                                          IN PVOID *BaseAddress,
-                                          IN OUT PSIZE_T RegionSize,
-                                          IN ULONG FreeType);
-
-#ifndef WOF_CURRENT_VERSION
-typedef struct _WOF_EXTERNAL_INFO {
-  DWORD Version;
-  DWORD Provider;
-} WOF_EXTERNAL_INFO, *PWOF_EXTERNAL_INFO;
-#endif /* WOF_CURRENT_VERSION */
-
-#ifndef WIM_PROVIDER_CURRENT_VERSION
-#define WIM_PROVIDER_HASH_SIZE 20
-
-typedef struct _WIM_PROVIDER_EXTERNAL_INFO {
-  DWORD Version;
-  DWORD Flags;
-  LARGE_INTEGER DataSourceId;
-  BYTE ResourceHash[WIM_PROVIDER_HASH_SIZE];
-} WIM_PROVIDER_EXTERNAL_INFO, *PWIM_PROVIDER_EXTERNAL_INFO;
-#endif /* WIM_PROVIDER_CURRENT_VERSION */
-
-#ifndef FILE_PROVIDER_CURRENT_VERSION
-typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 {
-  ULONG Version;
-  ULONG Algorithm;
-  ULONG Flags;
-} FILE_PROVIDER_EXTERNAL_INFO_V1, *PFILE_PROVIDER_EXTERNAL_INFO_V1;
-#endif /* FILE_PROVIDER_CURRENT_VERSION */
-
-#ifndef STATUS_OBJECT_NOT_EXTERNALLY_BACKED
-#define STATUS_OBJECT_NOT_EXTERNALLY_BACKED ((NTSTATUS)0xC000046DL)
-#endif
-#ifndef STATUS_INVALID_DEVICE_REQUEST
-#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L)
-#endif
-#ifndef STATUS_NOT_SUPPORTED
-#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
-#endif
-
-#ifndef FILE_DEVICE_FILE_SYSTEM
-#define FILE_DEVICE_FILE_SYSTEM 0x00000009
-#endif
-
-#ifndef FSCTL_GET_EXTERNAL_BACKING
-#define FSCTL_GET_EXTERNAL_BACKING                                             \
-  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 196, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#endif
-
-#ifndef ERROR_NOT_CAPABLE
-#define ERROR_NOT_CAPABLE 775L
-#endif
-
-#endif /* _WIN32 || _WIN64 */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(__UCLIBC__)
-__extern_C void __assert(const char *, const char *, unsigned int, const char *)
-#ifdef __THROW
-    __THROW
-#else
-    __nothrow
-#endif /* __THROW */
-    MDBX_NORETURN;
-#define __assert_fail(assertion, file, line, function)                         \
-  __assert(assertion, file, line, function)
-
-#elif _POSIX_C_SOURCE > 200212 &&                                              \
-    /* workaround for avoid musl libc wrong prototype */ (                     \
-        defined(__GLIBC__) || defined(__GNU_LIBRARY__))
-/* Prototype should match libc runtime. ISO POSIX (2003) & LSB 1.x-3.x */
-__extern_C void __assert_fail(const char *assertion, const char *file,
-                              unsigned line, const char *function)
-#ifdef __THROW
-    __THROW
-#else
-    __nothrow
-#endif /* __THROW */
-    MDBX_NORETURN;
-
-#elif defined(__APPLE__) || defined(__MACH__)
-__extern_C void __assert_rtn(const char *function, const char *file, int line,
-                             const char *assertion) /* __nothrow */
-#ifdef __dead2
-    __dead2
-#else
-    MDBX_NORETURN
-#endif /* __dead2 */
-#ifdef __disable_tail_calls
-    __disable_tail_calls
-#endif /* __disable_tail_calls */
-    ;
-
-#define __assert_fail(assertion, file, line, function)                         \
-  __assert_rtn(function, file, line, assertion)
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-__extern_C void __assert_c99(const char *assection, const char *file, int line,
-                             const char *function) MDBX_NORETURN;
-#define __assert_fail(assertion, file, line, function)                         \
-  __assert_c99(assertion, file, line, function)
-#elif defined(__OpenBSD__)
-__extern_C __dead void __assert2(const char *file, int line,
-                                 const char *function,
-                                 const char *assertion) /* __nothrow */;
-#define __assert_fail(assertion, file, line, function)                         \
-  __assert2(file, line, function, assertion)
-#elif defined(__NetBSD__)
-__extern_C __dead void __assert13(const char *file, int line,
-                                  const char *function,
-                                  const char *assertion) /* __nothrow */;
-#define __assert_fail(assertion, file, line, function)                         \
-  __assert13(file, line, function, assertion)
-#elif defined(__FreeBSD__) || defined(__BSD__) || defined(__bsdi__) ||         \
-    defined(__DragonFly__)
-__extern_C void __assert(const char *function, const char *file, int line,
-                         const char *assertion) /* __nothrow */
-#ifdef __dead2
-    __dead2
-#else
-    MDBX_NORETURN
-#endif /* __dead2 */
-#ifdef __disable_tail_calls
-    __disable_tail_calls
-#endif /* __disable_tail_calls */
-    ;
-#define __assert_fail(assertion, file, line, function)                         \
-  __assert(function, file, line, assertion)
-
-#endif /* __assert_fail */
-
-#if !defined(__ANDROID_API__) || MDBX_DEBUG
-
-__cold void mdbx_assert_fail(const MDBX_env *env, const char *msg,
-                             const char *func, int line) {
-#if MDBX_DEBUG
-  if (env && env->me_assert_func) {
-    env->me_assert_func(env, msg, func, line);
-    return;
-  }
-#else
-  (void)env;
-#endif /* MDBX_DEBUG */
-
-  if (mdbx_debug_logger)
-    mdbx_debug_log(MDBX_LOG_FATAL, func, line, "assert: %s\n", msg);
-  else {
-#if defined(_WIN32) || defined(_WIN64)
-    char *message = nullptr;
-    const int num = mdbx_asprintf(&message, "\r\nMDBX-ASSERTION: %s, %s:%u",
-                                  msg, func ? func : "unknown", line);
-    if (num < 1 || !message)
-      message = "<troubles with assertion-message preparation>";
-    OutputDebugStringA(message);
-    if (IsDebuggerPresent())
-      DebugBreak();
-#elif defined(__ANDROID_API__)
-    __android_log_assert(msg, "mdbx", "%s:%u", func, line);
-#else
-    __assert_fail(msg, "mdbx", line, func);
-#endif
-  }
-
-#if defined(_WIN32) || defined(_WIN64)
-  FatalExit(ERROR_UNHANDLED_ERROR);
-#else
-  abort();
-#endif
-}
-
-#endif /* __ANDROID_API__ || MDBX_DEBUG */
-
-__cold void mdbx_panic(const char *fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-
-  char *message = nullptr;
-  const int num = mdbx_vasprintf(&message, fmt, ap);
-  va_end(ap);
-  const char *const const_message =
-      (num < 1 || !message) ? "<troubles with panic-message preparation>"
-                            : message;
-
-#if defined(_WIN32) || defined(_WIN64)
-  OutputDebugStringA("\r\nMDBX-PANIC: ");
-  OutputDebugStringA(const_message);
-  if (IsDebuggerPresent())
-    DebugBreak();
-  FatalExit(ERROR_UNHANDLED_ERROR);
-#else
-#if defined(__ANDROID_API__)
-  __android_log_assert("panic", "mdbx", "%s", const_message);
-#else
-  __assert_fail(const_message, "mdbx", 0, "panic");
-#endif /* __ANDROID_API__ */
-  abort();
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef mdbx_vasprintf
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt,
-                                      va_list ap) {
-  va_list ones;
-  va_copy(ones, ap);
-  int needed = vsnprintf(nullptr, 0, fmt, ap);
-
-  if (unlikely(needed < 0 || needed >= INT_MAX)) {
-    *strp = nullptr;
-    va_end(ones);
-    return needed;
-  }
-
-  *strp = mdbx_malloc(needed + 1);
-  if (unlikely(*strp == nullptr)) {
-    va_end(ones);
-#if defined(_WIN32) || defined(_WIN64)
-    SetLastError(MDBX_ENOMEM);
-#else
-    errno = MDBX_ENOMEM;
-#endif
-    return -1;
-  }
-
-  int actual = vsnprintf(*strp, needed + 1, fmt, ones);
-  va_end(ones);
-
-  assert(actual == needed);
-  if (unlikely(actual < 0)) {
-    mdbx_free(*strp);
-    *strp = nullptr;
-  }
-  return actual;
-}
-#endif /* mdbx_vasprintf */
-
-#ifndef mdbx_asprintf
-MDBX_INTERNAL_FUNC int mdbx_asprintf(char **strp, const char *fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  int rc = mdbx_vasprintf(strp, fmt, ap);
-  va_end(ap);
-  return rc;
-}
-#endif /* mdbx_asprintf */
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result) {
-  assert(is_powerof2(alignment) && alignment >= sizeof(void *));
-#if defined(_WIN32) || defined(_WIN64)
-  (void)alignment;
-  *result = VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-  return *result ? MDBX_SUCCESS : MDBX_ENOMEM /* ERROR_OUTOFMEMORY */;
-#elif defined(_ISOC11_SOURCE)
-  *result = aligned_alloc(alignment, ceil_powerof2(bytes, alignment));
-  return *result ? MDBX_SUCCESS : errno;
-#elif _POSIX_VERSION >= 200112L &&                                             \
-    (!defined(__ANDROID_API__) || __ANDROID_API__ >= 17)
-  *result = nullptr;
-  return posix_memalign(result, alignment, bytes);
-#elif __GLIBC_PREREQ(2, 16) || __STDC_VERSION__ >= 201112L
-  *result = memalign(alignment, bytes);
-  return *result ? MDBX_SUCCESS : errno;
-#else
-#error FIXME
-#endif
-}
-#endif /* mdbx_memalign_alloc */
-
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr) {
-#if defined(_WIN32) || defined(_WIN64)
-  VirtualFree(ptr, 0, MEM_RELEASE);
-#else
-  mdbx_free(ptr);
-#endif
-}
-#endif /* mdbx_memalign_free */
-
-#ifndef mdbx_strdup
-char *mdbx_strdup(const char *str) {
-  if (!str)
-    return NULL;
-  size_t bytes = strlen(str) + 1;
-  char *dup = mdbx_malloc(bytes);
-  if (dup)
-    memcpy(dup, str, bytes);
-  return dup;
-}
-#endif /* mdbx_strdup */
-
-/*----------------------------------------------------------------------------*/
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair) {
-  int rc;
-  memset(condpair, 0, sizeof(mdbx_condpair_t));
-#if defined(_WIN32) || defined(_WIN64)
-  if ((condpair->mutex = CreateMutexW(NULL, FALSE, NULL)) == NULL) {
-    rc = (int)GetLastError();
-    goto bailout_mutex;
-  }
-  if ((condpair->event[0] = CreateEventW(NULL, FALSE, FALSE, NULL)) == NULL) {
-    rc = (int)GetLastError();
-    goto bailout_event;
-  }
-  if ((condpair->event[1] = CreateEventW(NULL, FALSE, FALSE, NULL)) != NULL)
-    return MDBX_SUCCESS;
-
-  rc = (int)GetLastError();
-  (void)CloseHandle(condpair->event[0]);
-bailout_event:
-  (void)CloseHandle(condpair->mutex);
-#else
-  rc = pthread_mutex_init(&condpair->mutex, NULL);
-  if (unlikely(rc != 0))
-    goto bailout_mutex;
-  rc = pthread_cond_init(&condpair->cond[0], NULL);
-  if (unlikely(rc != 0))
-    goto bailout_cond;
-  rc = pthread_cond_init(&condpair->cond[1], NULL);
-  if (likely(rc == 0))
-    return MDBX_SUCCESS;
-
-  (void)pthread_cond_destroy(&condpair->cond[0]);
-bailout_cond:
-  (void)pthread_mutex_destroy(&condpair->mutex);
-#endif
-bailout_mutex:
-  memset(condpair, 0, sizeof(mdbx_condpair_t));
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair) {
-#if defined(_WIN32) || defined(_WIN64)
-  int rc = CloseHandle(condpair->mutex) ? MDBX_SUCCESS : (int)GetLastError();
-  rc = CloseHandle(condpair->event[0]) ? rc : (int)GetLastError();
-  rc = CloseHandle(condpair->event[1]) ? rc : (int)GetLastError();
-#else
-  int err, rc = pthread_mutex_destroy(&condpair->mutex);
-  rc = (err = pthread_cond_destroy(&condpair->cond[0])) ? err : rc;
-  rc = (err = pthread_cond_destroy(&condpair->cond[1])) ? err : rc;
-#endif
-  memset(condpair, 0, sizeof(mdbx_condpair_t));
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD code = WaitForSingleObject(condpair->mutex, INFINITE);
-  return waitstatus2errcode(code);
-#else
-  return mdbx_pthread_mutex_lock(&condpair->mutex);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair) {
-#if defined(_WIN32) || defined(_WIN64)
-  return ReleaseMutex(condpair->mutex) ? MDBX_SUCCESS : (int)GetLastError();
-#else
-  return pthread_mutex_unlock(&condpair->mutex);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part) {
-#if defined(_WIN32) || defined(_WIN64)
-  return SetEvent(condpair->event[part]) ? MDBX_SUCCESS : (int)GetLastError();
-#else
-  return pthread_cond_signal(&condpair->cond[part]);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair,
-                                          bool part) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD code = SignalObjectAndWait(condpair->mutex, condpair->event[part],
-                                   INFINITE, FALSE);
-  if (code == WAIT_OBJECT_0) {
-    code = WaitForSingleObject(condpair->mutex, INFINITE);
-    if (code == WAIT_OBJECT_0)
-      return MDBX_SUCCESS;
-  }
-  return waitstatus2errcode(code);
-#else
-  return pthread_cond_wait(&condpair->cond[part], &condpair->mutex);
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex) {
-#if defined(_WIN32) || defined(_WIN64)
-  InitializeCriticalSection(fastmutex);
-  return MDBX_SUCCESS;
-#else
-  return pthread_mutex_init(fastmutex, NULL);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex) {
-#if defined(_WIN32) || defined(_WIN64)
-  DeleteCriticalSection(fastmutex);
-  return MDBX_SUCCESS;
-#else
-  return pthread_mutex_destroy(fastmutex);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex) {
-#if defined(_WIN32) || defined(_WIN64)
-  __try {
-    EnterCriticalSection(fastmutex);
-  } __except (
-      (GetExceptionCode() ==
-       0xC0000194 /* STATUS_POSSIBLE_DEADLOCK / EXCEPTION_POSSIBLE_DEADLOCK */)
-          ? EXCEPTION_EXECUTE_HANDLER
-          : EXCEPTION_CONTINUE_SEARCH) {
-    return ERROR_POSSIBLE_DEADLOCK;
-  }
-  return MDBX_SUCCESS;
-#else
-  return mdbx_pthread_mutex_lock(fastmutex);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) {
-#if defined(_WIN32) || defined(_WIN64)
-  LeaveCriticalSection(fastmutex);
-  return MDBX_SUCCESS;
-#else
-  return pthread_mutex_unlock(fastmutex);
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
-#if defined(_WIN32) || defined(_WIN64)
-  const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
-  if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
-    return ERROR_INVALID_NAME;
-  wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
-  if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
-    return ERROR_INVALID_NAME;
-  return DeleteFileW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError();
-#else
-  return unlink(pathname) ? errno : MDBX_SUCCESS;
-#endif
-}
-
-#if !(defined(_WIN32) || defined(_WIN64))
-static bool is_valid_fd(int fd) { return !(isatty(fd) < 0 && errno == EBADF); }
-#endif /*! Windows */
-
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname) {
-#if defined(_WIN32) || defined(_WIN64)
-  const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
-  if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
-    return ERROR_INVALID_NAME;
-  wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
-  if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
-    return ERROR_INVALID_NAME;
-  return RemoveDirectoryW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError();
-#else
-  return rmdir(pathname) ? errno : MDBX_SUCCESS;
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits) {
-  *fd = INVALID_HANDLE_VALUE;
-
-#if defined(_WIN32) || defined(_WIN64)
-  const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
-  if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
-    return ERROR_INVALID_NAME;
-  wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
-  if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
-    return ERROR_INVALID_NAME;
-
-  DWORD CreationDisposition = unix_mode_bits ? OPEN_ALWAYS : OPEN_EXISTING;
-  DWORD FlagsAndAttributes =
-      FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
-  DWORD DesiredAccess = FILE_READ_ATTRIBUTES;
-  DWORD ShareMode = (env->me_flags & MDBX_EXCLUSIVE)
-                        ? 0
-                        : (FILE_SHARE_READ | FILE_SHARE_WRITE);
-
-  switch (purpose) {
-  default:
-    return ERROR_INVALID_PARAMETER;
-  case MDBX_OPEN_LCK:
-    CreationDisposition = OPEN_ALWAYS;
-    DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
-    FlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY;
-    break;
-  case MDBX_OPEN_DXB_READ:
-    CreationDisposition = OPEN_EXISTING;
-    DesiredAccess |= GENERIC_READ;
-    ShareMode |= FILE_SHARE_READ;
-    break;
-  case MDBX_OPEN_DXB_LAZY:
-    DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
-    break;
-  case MDBX_OPEN_DXB_DSYNC:
-    CreationDisposition = OPEN_EXISTING;
-    DesiredAccess |= GENERIC_WRITE;
-    FlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
-    break;
-  case MDBX_OPEN_COPY:
-    CreationDisposition = CREATE_NEW;
-    ShareMode = 0;
-    DesiredAccess |= GENERIC_WRITE;
-    FlagsAndAttributes |=
-        (env->me_psize < env->me_os_psize) ? 0 : FILE_FLAG_NO_BUFFERING;
-    break;
-  case MDBX_OPEN_DELETE:
-    CreationDisposition = OPEN_EXISTING;
-    ShareMode |= FILE_SHARE_DELETE;
-    DesiredAccess =
-        FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE;
-    break;
-  }
-
-  *fd = CreateFileW(pathnameW, DesiredAccess, ShareMode, NULL,
-                    CreationDisposition, FlagsAndAttributes, NULL);
-  if (*fd == INVALID_HANDLE_VALUE)
-    return (int)GetLastError();
-
-  BY_HANDLE_FILE_INFORMATION info;
-  if (!GetFileInformationByHandle(*fd, &info)) {
-    int err = (int)GetLastError();
-    CloseHandle(*fd);
-    *fd = INVALID_HANDLE_VALUE;
-    return err;
-  }
-  const DWORD AttributesDiff =
-      (info.dwFileAttributes ^ FlagsAndAttributes) &
-      (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
-       FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_COMPRESSED);
-  if (AttributesDiff)
-    (void)SetFileAttributesW(pathnameW, info.dwFileAttributes ^ AttributesDiff);
-
-#else
-  int flags = unix_mode_bits ? O_CREAT : 0;
-  switch (purpose) {
-  default:
-    return EINVAL;
-  case MDBX_OPEN_LCK:
-    flags |= O_RDWR;
-    break;
-  case MDBX_OPEN_DXB_READ:
-    flags = O_RDONLY;
-    break;
-  case MDBX_OPEN_DXB_LAZY:
-    flags |= O_RDWR;
-    break;
-  case MDBX_OPEN_COPY:
-    flags = O_CREAT | O_WRONLY | O_EXCL;
-    break;
-  case MDBX_OPEN_DXB_DSYNC:
-    flags |= O_WRONLY;
-#if defined(O_DSYNC)
-    flags |= O_DSYNC;
-#elif defined(O_SYNC)
-    flags |= O_SYNC;
-#elif defined(O_FSYNC)
-    flags |= O_FSYNC;
-#endif
-    break;
-  case MDBX_OPEN_DELETE:
-    flags = O_RDWR;
-    break;
-  }
-
-  const bool direct_nocache_for_copy =
-      env->me_psize >= env->me_os_psize && purpose == MDBX_OPEN_COPY;
-  if (direct_nocache_for_copy) {
-#if defined(O_DIRECT)
-    flags |= O_DIRECT;
-#endif /* O_DIRECT */
-#if defined(O_NOCACHE)
-    flags |= O_NOCACHE;
-#endif /* O_NOCACHE */
-  }
-
-#ifdef O_CLOEXEC
-  flags |= O_CLOEXEC;
-#endif /* O_CLOEXEC */
-
-  /* Safeguard for todo4recovery://erased_by_github/libmdbx/issues/144 */
-#if STDIN_FILENO == 0 && STDOUT_FILENO == 1 && STDERR_FILENO == 2
-  int stub_fd0 = -1, stub_fd1 = -1, stub_fd2 = -1;
-  static const char dev_null[] = "/dev/null";
-  if (!is_valid_fd(STDIN_FILENO)) {
-    mdbx_warning("STD%s_FILENO/%d is invalid, open %s for temporary stub", "IN",
-                 STDIN_FILENO, dev_null);
-    stub_fd0 = open(dev_null, O_RDONLY | O_NOCTTY);
-  }
-  if (!is_valid_fd(STDOUT_FILENO)) {
-    mdbx_warning("STD%s_FILENO/%d is invalid, open %s for temporary stub",
-                 "OUT", STDOUT_FILENO, dev_null);
-    stub_fd1 = open(dev_null, O_WRONLY | O_NOCTTY);
-  }
-  if (!is_valid_fd(STDERR_FILENO)) {
-    mdbx_warning("STD%s_FILENO/%d is invalid, open %s for temporary stub",
-                 "ERR", STDERR_FILENO, dev_null);
-    stub_fd2 = open(dev_null, O_WRONLY | O_NOCTTY);
-  }
-#else
-#error "Unexpected or unsupported UNIX or POSIX system"
-#endif /* STDIN_FILENO == 0 && STDERR_FILENO == 2 */
-
-  *fd = open(pathname, flags, unix_mode_bits);
-#if defined(O_DIRECT)
-  if (*fd < 0 && (flags & O_DIRECT) &&
-      (errno == EINVAL || errno == EAFNOSUPPORT)) {
-    flags &= ~(O_DIRECT | O_EXCL);
-    *fd = open(pathname, flags, unix_mode_bits);
-  }
-#endif /* O_DIRECT */
-
-  /* Safeguard for todo4recovery://erased_by_github/libmdbx/issues/144 */
-#if STDIN_FILENO == 0 && STDOUT_FILENO == 1 && STDERR_FILENO == 2
-  if (*fd == STDIN_FILENO) {
-    mdbx_warning("Got STD%s_FILENO/%d, avoid using it by dup(fd)", "IN",
-                 STDIN_FILENO);
-    assert(stub_fd0 == -1);
-    *fd = dup(stub_fd0 = *fd);
-  }
-  if (*fd == STDOUT_FILENO) {
-    mdbx_warning("Got STD%s_FILENO/%d, avoid using it by dup(fd)", "OUT",
-                 STDOUT_FILENO);
-    assert(stub_fd1 == -1);
-    *fd = dup(stub_fd1 = *fd);
-  }
-  if (*fd == STDERR_FILENO) {
-    mdbx_warning("Got STD%s_FILENO/%d, avoid using it by dup(fd)", "ERR",
-                 STDERR_FILENO);
-    assert(stub_fd2 == -1);
-    *fd = dup(stub_fd2 = *fd);
-  }
-  if (stub_fd0 != -1)
-    close(stub_fd0);
-  if (stub_fd1 != -1)
-    close(stub_fd1);
-  if (stub_fd2 != -1)
-    close(stub_fd2);
-  if (*fd >= STDIN_FILENO && *fd <= STDERR_FILENO) {
-    mdbx_error(
-        "Rejecting the use of a FD in the range "
-        "STDIN_FILENO/%d..STDERR_FILENO/%d to prevent database corruption",
-        STDIN_FILENO, STDERR_FILENO);
-    close(*fd);
-    return EBADF;
-  }
-#else
-#error "Unexpected or unsupported UNIX or POSIX system"
-#endif /* STDIN_FILENO == 0 && STDERR_FILENO == 2 */
-
-  if (*fd < 0)
-    return errno;
-
-#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
-  const int fd_flags = fcntl(*fd, F_GETFD);
-  if (fd_flags != -1)
-    (void)fcntl(*fd, F_SETFD, fd_flags | FD_CLOEXEC);
-#endif /* FD_CLOEXEC && !O_CLOEXEC */
-
-  if (direct_nocache_for_copy) {
-#if defined(F_NOCACHE) && !defined(O_NOCACHE)
-    (void)fcntl(*fd, F_NOCACHE, 1);
-#endif /* F_NOCACHE */
-  }
-
-#endif
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd) {
-#if defined(_WIN32) || defined(_WIN64)
-  return CloseHandle(fd) ? MDBX_SUCCESS : (int)GetLastError();
-#else
-  assert(fd > STDERR_FILENO);
-  return (close(fd) == 0) ? MDBX_SUCCESS : errno;
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t bytes,
-                                  uint64_t offset) {
-  if (bytes > MAX_WRITE)
-    return MDBX_EINVAL;
-#if defined(_WIN32) || defined(_WIN64)
-  OVERLAPPED ov;
-  ov.hEvent = 0;
-  ov.Offset = (DWORD)offset;
-  ov.OffsetHigh = HIGH_DWORD(offset);
-
-  DWORD read = 0;
-  if (unlikely(!ReadFile(fd, buf, (DWORD)bytes, &read, &ov))) {
-    int rc = (int)GetLastError();
-    return (rc == MDBX_SUCCESS) ? /* paranoia */ ERROR_READ_FAULT : rc;
-  }
-#else
-  STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
-                    "libmdbx requires 64-bit file I/O on 64-bit systems");
-  intptr_t read = pread(fd, buf, bytes, offset);
-  if (read < 0) {
-    int rc = errno;
-    return (rc == MDBX_SUCCESS) ? /* paranoia */ MDBX_EIO : rc;
-  }
-#endif
-  return (bytes == (size_t)read) ? MDBX_SUCCESS : MDBX_ENODATA;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t bytes, uint64_t offset) {
-  while (true) {
-#if defined(_WIN32) || defined(_WIN64)
-    OVERLAPPED ov;
-    ov.hEvent = 0;
-    ov.Offset = (DWORD)offset;
-    ov.OffsetHigh = HIGH_DWORD(offset);
-
-    DWORD written;
-    if (unlikely(!WriteFile(
-            fd, buf, likely(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
-            &written, &ov)))
-      return (int)GetLastError();
-    if (likely(bytes == written))
-      return MDBX_SUCCESS;
-#else
-    STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
-                      "libmdbx requires 64-bit file I/O on 64-bit systems");
-    const intptr_t written =
-        pwrite(fd, buf, likely(bytes <= MAX_WRITE) ? bytes : MAX_WRITE, offset);
-    if (likely(bytes == (size_t)written))
-      return MDBX_SUCCESS;
-    if (written < 0) {
-      const int rc = errno;
-      if (rc != EINTR)
-        return rc;
-      continue;
-    }
-#endif
-    bytes -= written;
-    offset += written;
-    buf = (char *)buf + written;
-  }
-}
-
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t bytes) {
-  while (true) {
-#if defined(_WIN32) || defined(_WIN64)
-    DWORD written;
-    if (unlikely(!WriteFile(
-            fd, buf, likely(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
-            &written, nullptr)))
-      return (int)GetLastError();
-    if (likely(bytes == written))
-      return MDBX_SUCCESS;
-#else
-    STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
-                      "libmdbx requires 64-bit file I/O on 64-bit systems");
-    const intptr_t written =
-        write(fd, buf, likely(bytes <= MAX_WRITE) ? bytes : MAX_WRITE);
-    if (likely(bytes == (size_t)written))
-      return MDBX_SUCCESS;
-    if (written < 0) {
-      const int rc = errno;
-      if (rc != EINTR)
-        return rc;
-      continue;
-    }
-#endif
-    bytes -= written;
-    buf = (char *)buf + written;
-  }
-}
-
-int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt,
-                 uint64_t offset, size_t expected_written) {
-#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__) ||                \
-    (defined(__ANDROID_API__) && __ANDROID_API__ < 24)
-  size_t written = 0;
-  for (int i = 0; i < iovcnt; ++i) {
-    int rc = mdbx_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
-    if (unlikely(rc != MDBX_SUCCESS))
-      return rc;
-    written += iov[i].iov_len;
-    offset += iov[i].iov_len;
-  }
-  return (expected_written == written) ? MDBX_SUCCESS
-                                       : MDBX_EIO /* ERROR_WRITE_FAULT */;
-#else
-  int rc;
-  intptr_t written;
-  do {
-    STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
-                      "libmdbx requires 64-bit file I/O on 64-bit systems");
-    written = pwritev(fd, iov, iovcnt, offset);
-    if (likely(expected_written == (size_t)written))
-      return MDBX_SUCCESS;
-    rc = errno;
-  } while (rc == EINTR);
-  return (written < 0) ? rc : MDBX_EIO /* Use which error code? */;
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  enum mdbx_syncmode_bits mode_bits) {
-#if defined(_WIN32) || defined(_WIN64)
-  if ((mode_bits & (MDBX_SYNC_DATA | MDBX_SYNC_IODQ)) && !FlushFileBuffers(fd))
-    return (int)GetLastError();
-  return MDBX_SUCCESS;
-#else
-
-#if defined(__APPLE__) &&                                                      \
-    MDBX_OSX_SPEED_INSTEADOF_DURABILITY == MDBX_OSX_WANNA_DURABILITY
-  if (mode_bits & MDBX_SYNC_IODQ)
-    return likely(fcntl(fd, F_FULLFSYNC) != -1) ? MDBX_SUCCESS : errno;
-#endif /* MacOS */
-
-  /* LY: This approach is always safe and without appreciable performance
-   * degradation, even on a kernel with fdatasync's bug.
-   *
-   * For more info about of a corresponding fdatasync() bug
-   * see http://www.spinics.net/lists/linux-ext4/msg33714.html */
-  while (1) {
-    switch (mode_bits & (MDBX_SYNC_DATA | MDBX_SYNC_SIZE)) {
-    case MDBX_SYNC_NONE:
-      return MDBX_SUCCESS /* nothing to do */;
-#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
-    case MDBX_SYNC_DATA:
-      if (fdatasync(fd) == 0)
-        return MDBX_SUCCESS;
-      break /* error */;
-#if defined(__linux__) || defined(__gnu_linux__)
-    case MDBX_SYNC_SIZE:
-      if (mdbx_linux_kernel_version >= 0x03060000)
-        return MDBX_SUCCESS;
-      __fallthrough /* fall through */;
-#endif /* Linux */
-#endif /* _POSIX_SYNCHRONIZED_IO > 0 */
-    default:
-      if (fsync(fd) == 0)
-        return MDBX_SUCCESS;
-    }
-
-    int rc = errno;
-    if (rc != EINTR)
-      return rc;
-  }
-#endif
-}
-
-int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length) {
-#if defined(_WIN32) || defined(_WIN64)
-  BY_HANDLE_FILE_INFORMATION info;
-  if (!GetFileInformationByHandle(fd, &info))
-    return (int)GetLastError();
-  *length = info.nFileSizeLow | (uint64_t)info.nFileSizeHigh << 32;
-#else
-  struct stat st;
-
-  STATIC_ASSERT_MSG(sizeof(off_t) <= sizeof(uint64_t),
-                    "libmdbx requires 64-bit file I/O on 64-bit systems");
-  if (fstat(fd, &st))
-    return errno;
-
-  *length = st.st_size;
-#endif
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd) {
-#if defined(_WIN32) || defined(_WIN64)
-  switch (GetFileType(fd)) {
-  case FILE_TYPE_DISK:
-    return MDBX_RESULT_FALSE;
-  case FILE_TYPE_CHAR:
-  case FILE_TYPE_PIPE:
-    return MDBX_RESULT_TRUE;
-  default:
-    return (int)GetLastError();
-  }
-#else
-  struct stat info;
-  if (fstat(fd, &info))
-    return errno;
-  switch (info.st_mode & S_IFMT) {
-  case S_IFBLK:
-  case S_IFREG:
-    return MDBX_RESULT_FALSE;
-  case S_IFCHR:
-  case S_IFIFO:
-  case S_IFSOCK:
-    return MDBX_RESULT_TRUE;
-  case S_IFDIR:
-  case S_IFLNK:
-  default:
-    return MDBX_INCOMPATIBLE;
-  }
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
-#if defined(_WIN32) || defined(_WIN64)
-  if (mdbx_SetFileInformationByHandle) {
-    FILE_END_OF_FILE_INFO EndOfFileInfo;
-    EndOfFileInfo.EndOfFile.QuadPart = length;
-    return mdbx_SetFileInformationByHandle(fd, FileEndOfFileInfo,
-                                           &EndOfFileInfo,
-                                           sizeof(FILE_END_OF_FILE_INFO))
-               ? MDBX_SUCCESS
-               : (int)GetLastError();
-  } else {
-    LARGE_INTEGER li;
-    li.QuadPart = length;
-    return (SetFilePointerEx(fd, li, NULL, FILE_BEGIN) && SetEndOfFile(fd))
-               ? MDBX_SUCCESS
-               : (int)GetLastError();
-  }
-#else
-  STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
-                    "libmdbx requires 64-bit file I/O on 64-bit systems");
-  return ftruncate(fd, length) == 0 ? MDBX_SUCCESS : errno;
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos) {
-#if defined(_WIN32) || defined(_WIN64)
-  LARGE_INTEGER li;
-  li.QuadPart = pos;
-  return SetFilePointerEx(fd, li, NULL, FILE_BEGIN) ? MDBX_SUCCESS
-                                                    : (int)GetLastError();
-#else
-  STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
-                    "libmdbx requires 64-bit file I/O on 64-bit systems");
-  return (lseek(fd, pos, SEEK_SET) < 0) ? errno : MDBX_SUCCESS;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg) {
-#if defined(_WIN32) || defined(_WIN64)
-  *thread = CreateThread(NULL, 0, start_routine, arg, 0, NULL);
-  return *thread ? MDBX_SUCCESS : (int)GetLastError();
-#else
-  return pthread_create(thread, NULL, start_routine, arg);
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD code = WaitForSingleObject(thread, INFINITE);
-  return waitstatus2errcode(code);
-#else
-  void *unused_retval = &unused_retval;
-  return pthread_join(thread, &unused_retval);
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits) {
-  uint8_t *ptr = (uint8_t *)map->address + offset;
-#if defined(_WIN32) || defined(_WIN64)
-  if (!FlushViewOfFile(ptr, length))
-    return (int)GetLastError();
-#else
-#if defined(__linux__) || defined(__gnu_linux__)
-  if (mode_bits == MDBX_SYNC_NONE && mdbx_linux_kernel_version > 0x02061300)
-    /* Since Linux 2.6.19, MS_ASYNC is in fact a no-op. The kernel properly
-     * tracks dirty pages and flushes them to storage as necessary. */
-    return MDBX_SUCCESS;
-#endif /* Linux */
-  if (msync(ptr, length, (mode_bits & MDBX_SYNC_DATA) ? MS_SYNC : MS_ASYNC))
-    return errno;
-  mode_bits &= ~MDBX_SYNC_DATA;
-#endif
-  return mdbx_fsync(map->fd, mode_bits);
-}
-
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err) {
-#if defined(_WIN32) || defined(_WIN64)
-  (void)pathname;
-  (void)err;
-  if (!mdbx_GetVolumeInformationByHandleW)
-    return MDBX_ENOSYS;
-  DWORD unused, flags;
-  if (!mdbx_GetVolumeInformationByHandleW(handle, nullptr, 0, nullptr, &unused,
-                                          &flags, nullptr, 0))
-    return (int)GetLastError();
-  if ((flags & FILE_READ_ONLY_VOLUME) == 0)
-    return MDBX_EACCESS;
-#else
-  struct statvfs info;
-  if (err != MDBX_ENOFILE) {
-    if (statvfs(pathname, &info))
-      return errno;
-    if ((info.f_flag & ST_RDONLY) == 0)
-      return err;
-  }
-  if (fstatvfs(handle, &info))
-    return errno;
-  if ((info.f_flag & ST_RDONLY) == 0)
-    return (err == MDBX_ENOFILE) ? MDBX_EACCESS : err;
-#endif /* !Windows */
-  return MDBX_SUCCESS;
-}
-
-static int mdbx_check_fs_local(mdbx_filehandle_t handle, int flags) {
-#if defined(_WIN32) || defined(_WIN64)
-  if (mdbx_RunningUnderWine() && !(flags & MDBX_EXCLUSIVE))
-    return ERROR_NOT_CAPABLE /* workaround for Wine */;
-
-  if (GetFileType(handle) != FILE_TYPE_DISK)
-    return ERROR_FILE_OFFLINE;
-
-  if (mdbx_GetFileInformationByHandleEx) {
-    FILE_REMOTE_PROTOCOL_INFO RemoteProtocolInfo;
-    if (mdbx_GetFileInformationByHandleEx(handle, FileRemoteProtocolInfo,
-                                          &RemoteProtocolInfo,
-                                          sizeof(RemoteProtocolInfo))) {
-      if ((RemoteProtocolInfo.Flags & REMOTE_PROTOCOL_INFO_FLAG_OFFLINE) &&
-          !(flags & MDBX_RDONLY))
-        return ERROR_FILE_OFFLINE;
-      if (!(RemoteProtocolInfo.Flags & REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK) &&
-          !(flags & MDBX_EXCLUSIVE))
-        return ERROR_REMOTE_STORAGE_MEDIA_ERROR;
-    }
-  }
-
-  if (mdbx_NtFsControlFile) {
-    NTSTATUS rc;
-    struct {
-      WOF_EXTERNAL_INFO wof_info;
-      union {
-        WIM_PROVIDER_EXTERNAL_INFO wim_info;
-        FILE_PROVIDER_EXTERNAL_INFO_V1 file_info;
-      };
-      size_t reserved_for_microsoft_madness[42];
-    } GetExternalBacking_OutputBuffer;
-    IO_STATUS_BLOCK StatusBlock;
-    rc = mdbx_NtFsControlFile(handle, NULL, NULL, NULL, &StatusBlock,
-                              FSCTL_GET_EXTERNAL_BACKING, NULL, 0,
-                              &GetExternalBacking_OutputBuffer,
-                              sizeof(GetExternalBacking_OutputBuffer));
-    if (NT_SUCCESS(rc)) {
-      if (!(flags & MDBX_EXCLUSIVE))
-        return ERROR_REMOTE_STORAGE_MEDIA_ERROR;
-    } else if (rc != STATUS_OBJECT_NOT_EXTERNALLY_BACKED &&
-               rc != STATUS_INVALID_DEVICE_REQUEST &&
-               rc != STATUS_NOT_SUPPORTED)
-      return ntstatus2errcode(rc);
-  }
-
-  if (mdbx_GetVolumeInformationByHandleW && mdbx_GetFinalPathNameByHandleW) {
-    WCHAR *PathBuffer = mdbx_malloc(sizeof(WCHAR) * INT16_MAX);
-    if (!PathBuffer)
-      return MDBX_ENOMEM;
-
-    int rc = MDBX_SUCCESS;
-    DWORD VolumeSerialNumber, FileSystemFlags;
-    if (!mdbx_GetVolumeInformationByHandleW(handle, PathBuffer, INT16_MAX,
-                                            &VolumeSerialNumber, NULL,
-                                            &FileSystemFlags, NULL, 0)) {
-      rc = (int)GetLastError();
-      goto bailout;
-    }
-
-    if ((flags & MDBX_RDONLY) == 0) {
-      if (FileSystemFlags &
-          (FILE_SEQUENTIAL_WRITE_ONCE | FILE_READ_ONLY_VOLUME |
-           FILE_VOLUME_IS_COMPRESSED)) {
-        rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR;
-        goto bailout;
-      }
-    }
-
-    if (!mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX,
-                                        FILE_NAME_NORMALIZED |
-                                            VOLUME_NAME_NT)) {
-      rc = (int)GetLastError();
-      goto bailout;
-    }
-
-    if (_wcsnicmp(PathBuffer, L"\\Device\\Mup\\", 12) == 0) {
-      if (!(flags & MDBX_EXCLUSIVE)) {
-        rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR;
-        goto bailout;
-      }
-    } else if (mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX,
-                                              FILE_NAME_NORMALIZED |
-                                                  VOLUME_NAME_DOS)) {
-      UINT DriveType = GetDriveTypeW(PathBuffer);
-      if (DriveType == DRIVE_NO_ROOT_DIR &&
-          _wcsnicmp(PathBuffer, L"\\\\?\\", 4) == 0 &&
-          _wcsnicmp(PathBuffer + 5, L":\\", 2) == 0) {
-        PathBuffer[7] = 0;
-        DriveType = GetDriveTypeW(PathBuffer + 4);
-      }
-      switch (DriveType) {
-      case DRIVE_CDROM:
-        if (flags & MDBX_RDONLY)
-          break;
-      // fall through
-      case DRIVE_UNKNOWN:
-      case DRIVE_NO_ROOT_DIR:
-      case DRIVE_REMOTE:
-      default:
-        if (!(flags & MDBX_EXCLUSIVE))
-          rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR;
-      // fall through
-      case DRIVE_REMOVABLE:
-      case DRIVE_FIXED:
-      case DRIVE_RAMDISK:
-        break;
-      }
-    }
-  bailout:
-    mdbx_free(PathBuffer);
-    return rc;
-  }
-
-#else
-
-  struct statvfs statvfs_info;
-  if (fstatvfs(handle, &statvfs_info))
-    return errno;
-#if defined(ST_LOCAL) || defined(ST_EXPORTED)
-  const unsigned long st_flags = statvfs_info.f_flag;
-#endif /* ST_LOCAL || ST_EXPORTED */
-
-#if defined(__NetBSD__)
-  const unsigned type = 0;
-  const char *const name = statvfs_info.f_fstypename;
-  const size_t name_len = VFS_NAMELEN;
-#elif defined(_AIX) || defined(__OS400__)
-  const char *const name = statvfs_info.f_basetype;
-  const size_t name_len = sizeof(statvfs_info.f_basetype);
-  struct stat st;
-  if (fstat(handle, &st))
-    return errno;
-  const unsigned type = st.st_vfstype;
-  if ((st.st_flag & FS_REMOTE) != 0 && !(flags & MDBX_EXCLUSIVE))
-    return MDBX_EREMOTE;
-#elif defined(FSTYPSZ) || defined(_FSTYPSZ)
-  const unsigned type = 0;
-  const char *const name = statvfs_info.f_basetype;
-  const size_t name_len = sizeof(statvfs_info.f_basetype);
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-    defined(ST_FSTYPSZ) || defined(_ST_FSTYPSZ)
-  const unsigned type = 0;
-  struct stat st;
-  if (fstat(handle, &st))
-    return errno;
-  const char *const name = st.st_fstype;
-  const size_t name_len = strlen(name);
-#else
-  struct statfs statfs_info;
-  if (fstatfs(handle, &statfs_info))
-    return errno;
-#if defined(__OpenBSD__)
-  const unsigned type = 0;
-#else
-  const unsigned type = statfs_info.f_type;
-#endif
-#if defined(MNT_LOCAL) || defined(MNT_EXPORTED)
-  const unsigned long mnt_flags = statfs_info.f_flags;
-#endif /* MNT_LOCAL || MNT_EXPORTED */
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__) || defined(MFSNAMELEN) ||          \
-    defined(MFSTYPENAMELEN) || defined(VFS_NAMELEN)
-  const char *const name = statfs_info.f_fstypename;
-  const size_t name_len = sizeof(statfs_info.f_fstypename);
-#elif defined(__ANDROID_API__) && __ANDROID_API__ < 21
-  const char *const name = "";
-  const unsigned name_len = 0;
-#else
-
-  const char *name = "";
-  unsigned name_len = 0;
-
-  struct stat st;
-  if (fstat(handle, &st))
-    return errno;
-
-  char pathbuf[PATH_MAX];
-  FILE *mounted = nullptr;
-#if defined(__linux__) || defined(__gnu_linux__)
-  mounted = setmntent("/proc/mounts", "r");
-#endif /* Linux */
-  if (!mounted)
-    mounted = setmntent("/etc/mtab", "r");
-  if (mounted) {
-    const struct mntent *ent;
-#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(__BIONIC__) ||    \
-    (defined(_DEFAULT_SOURCE) && __GLIBC_PREREQ(2, 19))
-    struct mntent entbuf;
-    const bool should_copy = false;
-    while (nullptr !=
-           (ent = getmntent_r(mounted, &entbuf, pathbuf, sizeof(pathbuf))))
-#else
-    const bool should_copy = true;
-    while (nullptr != (ent = getmntent(mounted)))
-#endif
-    {
-      struct stat mnt;
-      if (!stat(ent->mnt_dir, &mnt) && mnt.st_dev == st.st_dev) {
-        if (should_copy) {
-          name =
-              strncpy(pathbuf, ent->mnt_fsname, name_len = sizeof(pathbuf) - 1);
-          pathbuf[name_len] = 0;
-        } else {
-          name = ent->mnt_fsname;
-          name_len = strlen(name);
-        }
-        break;
-      }
-    }
-    endmntent(mounted);
-  }
-#endif /* !xBSD && !Android/Bionic */
-#endif
-
-  if (name_len) {
-    if (((name_len > 2 && strncasecmp("nfs", name, 3) == 0) ||
-         strncasecmp("cifs", name, name_len) == 0 ||
-         strncasecmp("ncpfs", name, name_len) == 0 ||
-         strncasecmp("smbfs", name, name_len) == 0 ||
-         strcasecmp("9P" /* WSL2 */, name) == 0 ||
-         ((name_len > 3 && strncasecmp("fuse", name, 4) == 0) &&
-          strncasecmp("fuseblk", name, name_len) != 0)) &&
-        !(flags & MDBX_EXCLUSIVE))
-      return MDBX_EREMOTE;
-    if (strcasecmp("ftp", name) == 0 || strcasecmp("http", name) == 0 ||
-        strcasecmp("sshfs", name) == 0)
-      return MDBX_EREMOTE;
-  }
-
-#ifdef ST_LOCAL
-  if ((st_flags & ST_LOCAL) == 0 && !(flags & MDBX_EXCLUSIVE))
-    return MDBX_EREMOTE;
-#elif defined(MNT_LOCAL)
-  if ((mnt_flags & MNT_LOCAL) == 0 && !(flags & MDBX_EXCLUSIVE))
-    return MDBX_EREMOTE;
-#endif /* ST/MNT_LOCAL */
-
-#ifdef ST_EXPORTED
-  if ((st_flags & ST_EXPORTED) != 0 && !(flags & MDBX_RDONLY))
-    return MDBX_EREMOTE;
-#elif defined(MNT_EXPORTED)
-  if ((mnt_flags & MNT_EXPORTED) != 0 && !(flags & MDBX_RDONLY))
-    return MDBX_EREMOTE;
-#endif /* ST/MNT_EXPORTED */
-
-  switch (type) {
-  case 0xFF534D42 /* CIFS_MAGIC_NUMBER */:
-  case 0x6969 /* NFS_SUPER_MAGIC */:
-  case 0x564c /* NCP_SUPER_MAGIC */:
-  case 0x517B /* SMB_SUPER_MAGIC */:
-#if defined(__digital__) || defined(__osf__) || defined(__osf)
-  case 0x0E /* Tru64 NFS */:
-#endif
-#ifdef ST_FST_NFS
-  case ST_FST_NFS:
-#endif
-    if ((flags & MDBX_EXCLUSIVE) == 0)
-      return MDBX_EREMOTE;
-  case 0:
-  default:
-    break;
-  }
-#endif /* Unix */
-
-  return MDBX_SUCCESS;
-}
-
-static int check_mmap_limit(const size_t limit) {
-  const bool should_check =
-#if defined(__SANITIZE_ADDRESS__)
-      true;
-#else
-      RUNNING_ON_VALGRIND;
-#endif /* __SANITIZE_ADDRESS__ */
-
-  if (should_check) {
-    intptr_t pagesize, total_ram_pages, avail_ram_pages;
-    int err =
-        mdbx_get_sysraminfo(&pagesize, &total_ram_pages, &avail_ram_pages);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-    const int log2page = log2n_powerof2(pagesize);
-    if ((limit >> (log2page + 7)) > (size_t)total_ram_pages ||
-        (limit >> (log2page + 6)) > (size_t)avail_ram_pages) {
-      mdbx_error(
-          "%s (%zu pages) is too large for available (%zu pages) or total "
-          "(%zu pages) system RAM",
-          "database upper size limit", limit >> log2page, avail_ram_pages,
-          total_ram_pages);
-      return MDBX_TOO_LARGE;
-    }
-  }
-
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t size, const size_t limit,
-                                 const unsigned options) {
-  assert(size <= limit);
-  map->limit = 0;
-  map->current = 0;
-  map->address = nullptr;
-  map->filesize = 0;
-#if defined(_WIN32) || defined(_WIN64)
-  map->section = NULL;
-#endif /* Windows */
-
-  int err = mdbx_check_fs_local(map->fd, flags);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  err = check_mmap_limit(limit);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  if ((flags & MDBX_RDONLY) == 0 && (options & MMAP_OPTION_TRUNCATE) != 0) {
-    err = mdbx_ftruncate(map->fd, size);
-    if (err != MDBX_SUCCESS)
-      return err;
-    map->filesize = size;
-#if !(defined(_WIN32) || defined(_WIN64))
-    map->current = size;
-#endif /* !Windows */
-  } else {
-    err = mdbx_filesize(map->fd, &map->filesize);
-    if (err != MDBX_SUCCESS)
-      return err;
-#if !(defined(_WIN32) || defined(_WIN64))
-    map->current = (map->filesize > limit) ? limit : (size_t)map->filesize;
-#endif /* !Windows */
-  }
-
-#if defined(_WIN32) || defined(_WIN64)
-  LARGE_INTEGER SectionSize;
-  SectionSize.QuadPart = size;
-  err = NtCreateSection(
-      &map->section,
-      /* DesiredAccess */
-      (flags & MDBX_WRITEMAP)
-          ? SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE |
-                SECTION_MAP_WRITE
-          : SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE,
-      /* ObjectAttributes */ NULL, /* MaximumSize (InitialSize) */ &SectionSize,
-      /* SectionPageProtection */
-      (flags & MDBX_RDONLY) ? PAGE_READONLY : PAGE_READWRITE,
-      /* AllocationAttributes */ SEC_RESERVE, map->fd);
-  if (!NT_SUCCESS(err))
-    return ntstatus2errcode(err);
-
-  SIZE_T ViewSize = (flags & MDBX_RDONLY)     ? 0
-                    : mdbx_RunningUnderWine() ? size
-                                              : limit;
-  err = NtMapViewOfSection(
-      map->section, GetCurrentProcess(), &map->address,
-      /* ZeroBits */ 0,
-      /* CommitSize */ 0,
-      /* SectionOffset */ NULL, &ViewSize,
-      /* InheritDisposition */ ViewUnmap,
-      /* AllocationType */ (flags & MDBX_RDONLY) ? 0 : MEM_RESERVE,
-      /* Win32Protect */
-      (flags & MDBX_WRITEMAP) ? PAGE_READWRITE : PAGE_READONLY);
-  if (!NT_SUCCESS(err)) {
-    NtClose(map->section);
-    map->section = 0;
-    map->address = nullptr;
-    return ntstatus2errcode(err);
-  }
-  assert(map->address != MAP_FAILED);
-
-  map->current = (size_t)SectionSize.QuadPart;
-  map->limit = ViewSize;
-
-#else /* Windows */
-
-#ifndef MAP_TRYFIXED
-#define MAP_TRYFIXED 0
-#endif
-
-#ifndef MAP_HASSEMAPHORE
-#define MAP_HASSEMAPHORE 0
-#endif
-
-#ifndef MAP_CONCEAL
-#define MAP_CONCEAL 0
-#endif
-
-#ifndef MAP_NOSYNC
-#define MAP_NOSYNC 0
-#endif
-
-#ifndef MAP_FIXED_NOREPLACE
-#define MAP_FIXED_NOREPLACE 0
-#endif
-
-#ifndef MAP_NORESERVE
-#define MAP_NORESERVE 0
-#endif
-
-  map->address = mmap(
-      NULL, limit, (flags & MDBX_WRITEMAP) ? PROT_READ | PROT_WRITE : PROT_READ,
-      MAP_SHARED | MAP_FILE | MAP_NORESERVE |
-          (F_ISSET(flags, MDBX_UTTERLY_NOSYNC) ? MAP_NOSYNC : 0) |
-          ((options & MMAP_OPTION_SEMAPHORE) ? MAP_HASSEMAPHORE | MAP_NOSYNC
-                                             : MAP_CONCEAL),
-      map->fd, 0);
-
-  if (unlikely(map->address == MAP_FAILED)) {
-    map->limit = 0;
-    map->current = 0;
-    map->address = nullptr;
-    return errno;
-  }
-  map->limit = limit;
-
-#if MDBX_ENABLE_MADVISE
-#ifdef MADV_DONTFORK
-  if (unlikely(madvise(map->address, map->limit, MADV_DONTFORK) != 0))
-    return errno;
-#endif /* MADV_DONTFORK */
-#ifdef MADV_NOHUGEPAGE
-  (void)madvise(map->address, map->limit, MADV_NOHUGEPAGE);
-#endif /* MADV_NOHUGEPAGE */
-#endif /* MDBX_ENABLE_MADVISE */
-
-#endif /* ! Windows */
-
-  VALGRIND_MAKE_MEM_DEFINED(map->address, map->current);
-  MDBX_ASAN_UNPOISON_MEMORY_REGION(map->address, map->current);
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map) {
-  VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
-  /* Unpoisoning is required for ASAN to avoid false-positive diagnostic
-   * when this memory will re-used by malloc or another mmapping.
-   * See todo4recovery://erased_by_github/libmdbx/pull/93#issuecomment-613687203
-   */
-  MDBX_ASAN_UNPOISON_MEMORY_REGION(map->address,
-                                   (map->filesize && map->filesize < map->limit)
-                                       ? map->filesize
-                                       : map->limit);
-#if defined(_WIN32) || defined(_WIN64)
-  if (map->section)
-    NtClose(map->section);
-  NTSTATUS rc = NtUnmapViewOfSection(GetCurrentProcess(), map->address);
-  if (!NT_SUCCESS(rc))
-    ntstatus2errcode(rc);
-#else
-  if (unlikely(munmap(map->address, map->limit)))
-    return errno;
-#endif /* ! Windows */
-
-  map->limit = 0;
-  map->current = 0;
-  map->address = nullptr;
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit) {
-  assert(size <= limit);
-#if defined(_WIN32) || defined(_WIN64)
-  assert(size != map->current || limit != map->limit || size < map->filesize);
-
-  NTSTATUS status;
-  LARGE_INTEGER SectionSize;
-  int err, rc = MDBX_SUCCESS;
-
-  if (!(flags & MDBX_RDONLY) && limit == map->limit && size > map->current &&
-      /* workaround for Wine */ mdbx_NtExtendSection) {
-    /* growth rw-section */
-    SectionSize.QuadPart = size;
-    status = mdbx_NtExtendSection(map->section, &SectionSize);
-    if (!NT_SUCCESS(status))
-      return ntstatus2errcode(status);
-    map->current = size;
-    if (map->filesize < size)
-      map->filesize = size;
-    return MDBX_SUCCESS;
-  }
-
-  if (limit > map->limit) {
-    err = check_mmap_limit(limit);
-    if (unlikely(err != MDBX_SUCCESS))
-      return err;
-
-    /* check ability of address space for growth before unmap */
-    PVOID BaseAddress = (PBYTE)map->address + map->limit;
-    SIZE_T RegionSize = limit - map->limit;
-    status = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0,
-                                     &RegionSize, MEM_RESERVE, PAGE_NOACCESS);
-    if (status == (NTSTATUS) /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018)
-      return MDBX_UNABLE_EXTEND_MAPSIZE;
-    if (!NT_SUCCESS(status))
-      return ntstatus2errcode(status);
-
-    status = NtFreeVirtualMemory(GetCurrentProcess(), &BaseAddress, &RegionSize,
-                                 MEM_RELEASE);
-    if (!NT_SUCCESS(status))
-      return ntstatus2errcode(status);
-  }
-
-  /* Windows unable:
-   *  - shrink a mapped file;
-   *  - change size of mapped view;
-   *  - extend read-only mapping;
-   * Therefore we should unmap/map entire section. */
-  if ((flags & MDBX_MRESIZE_MAY_UNMAP) == 0)
-    return MDBX_EPERM;
-
-  /* Unpoisoning is required for ASAN to avoid false-positive diagnostic
-   * when this memory will re-used by malloc or another mmapping.
-   * See todo4recovery://erased_by_github/libmdbx/pull/93#issuecomment-613687203
-   */
-  MDBX_ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
-  status = NtUnmapViewOfSection(GetCurrentProcess(), map->address);
-  if (!NT_SUCCESS(status))
-    return ntstatus2errcode(status);
-  status = NtClose(map->section);
-  map->section = NULL;
-  PVOID ReservedAddress = NULL;
-  SIZE_T ReservedSize = limit;
-
-  if (!NT_SUCCESS(status)) {
-  bailout_ntstatus:
-    err = ntstatus2errcode(status);
-  bailout:
-    map->address = NULL;
-    map->current = map->limit = 0;
-    if (ReservedAddress) {
-      ReservedSize = 0;
-      status = NtFreeVirtualMemory(GetCurrentProcess(), &ReservedAddress,
-                                   &ReservedSize, MEM_RELEASE);
-      assert(NT_SUCCESS(status));
-      (void)status;
-    }
-    return err;
-  }
-
-retry_file_and_section:
-  /* resizing of the file may take a while,
-   * therefore we reserve address space to avoid occupy it by other threads */
-  ReservedAddress = map->address;
-  status = NtAllocateVirtualMemory(GetCurrentProcess(), &ReservedAddress, 0,
-                                   &ReservedSize, MEM_RESERVE, PAGE_NOACCESS);
-  if (!NT_SUCCESS(status)) {
-    ReservedAddress = NULL;
-    if (status != (NTSTATUS) /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018)
-      goto bailout_ntstatus /* no way to recovery */;
-
-    if (flags & MDBX_MRESIZE_MAY_MOVE)
-      /* the base address could be changed */
-      map->address = NULL;
-  }
-
-  err = mdbx_filesize(map->fd, &map->filesize);
-  if (err != MDBX_SUCCESS)
-    goto bailout;
-
-  if ((flags & MDBX_RDONLY) == 0 && map->filesize != size) {
-    err = mdbx_ftruncate(map->fd, size);
-    if (err == MDBX_SUCCESS)
-      map->filesize = size;
-    /* ignore error, because Windows unable shrink file
-     * that already mapped (by another process) */
-  }
-
-  SectionSize.QuadPart = size;
-  status = NtCreateSection(
-      &map->section,
-      /* DesiredAccess */
-      (flags & MDBX_WRITEMAP)
-          ? SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE |
-                SECTION_MAP_WRITE
-          : SECTION_QUERY | SECTION_MAP_READ | SECTION_EXTEND_SIZE,
-      /* ObjectAttributes */ NULL,
-      /* MaximumSize (InitialSize) */ &SectionSize,
-      /* SectionPageProtection */
-      (flags & MDBX_RDONLY) ? PAGE_READONLY : PAGE_READWRITE,
-      /* AllocationAttributes */ SEC_RESERVE, map->fd);
-
-  if (!NT_SUCCESS(status))
-    goto bailout_ntstatus;
-
-  if (ReservedAddress) {
-    /* release reserved address space */
-    ReservedSize = 0;
-    status = NtFreeVirtualMemory(GetCurrentProcess(), &ReservedAddress,
-                                 &ReservedSize, MEM_RELEASE);
-    ReservedAddress = NULL;
-    if (!NT_SUCCESS(status))
-      goto bailout_ntstatus;
-  }
-
-retry_mapview:;
-  SIZE_T ViewSize = (flags & MDBX_RDONLY) ? size : limit;
-  status = NtMapViewOfSection(
-      map->section, GetCurrentProcess(), &map->address,
-      /* ZeroBits */ 0,
-      /* CommitSize */ 0,
-      /* SectionOffset */ NULL, &ViewSize,
-      /* InheritDisposition */ ViewUnmap,
-      /* AllocationType */ (flags & MDBX_RDONLY) ? 0 : MEM_RESERVE,
-      /* Win32Protect */
-      (flags & MDBX_WRITEMAP) ? PAGE_READWRITE : PAGE_READONLY);
-
-  if (!NT_SUCCESS(status)) {
-    if (status == (NTSTATUS) /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 &&
-        map->address && (flags & MDBX_MRESIZE_MAY_MOVE) != 0) {
-      /* try remap at another base address */
-      map->address = NULL;
-      goto retry_mapview;
-    }
-    NtClose(map->section);
-    map->section = NULL;
-
-    if (map->address && (size != map->current || limit != map->limit)) {
-      /* try remap with previously size and limit,
-       * but will return MDBX_UNABLE_EXTEND_MAPSIZE on success */
-      rc = (limit > map->limit) ? MDBX_UNABLE_EXTEND_MAPSIZE : MDBX_EPERM;
-      size = map->current;
-      ReservedSize = limit = map->limit;
-      goto retry_file_and_section;
-    }
-
-    /* no way to recovery */
-    goto bailout_ntstatus;
-  }
-  assert(map->address != MAP_FAILED);
-
-  map->current = (size_t)SectionSize.QuadPart;
-  map->limit = ViewSize;
-
-#else /* Windows */
-
-  map->filesize = 0;
-  int rc = mdbx_filesize(map->fd, &map->filesize);
-  if (rc != MDBX_SUCCESS)
-    return rc;
-
-  if (flags & MDBX_RDONLY) {
-    map->current = (map->filesize > limit) ? limit : (size_t)map->filesize;
-    if (map->current != size)
-      rc = (size > map->current) ? MDBX_UNABLE_EXTEND_MAPSIZE : MDBX_EPERM;
-  } else {
-    if (map->filesize != size) {
-      rc = mdbx_ftruncate(map->fd, size);
-      if (rc != MDBX_SUCCESS)
-        return rc;
-      map->filesize = size;
-    }
-
-    if (map->current > size) {
-      /* Clearing asan's bitmask for the region which released in shrinking,
-       * since:
-       *  - after the shrinking we will get an exception when accessing
-       *    this region and (therefore) do not need the help of ASAN.
-       *  - this allows us to clear the mask only within the file size
-       *    when closing the mapping. */
-      MDBX_ASAN_UNPOISON_MEMORY_REGION(
-          (char *)map->address + size,
-          ((map->current < map->limit) ? map->current : map->limit) - size);
-    }
-    map->current = size;
-  }
-
-  if (limit == map->limit)
-    return rc;
-
-  if (limit < map->limit) {
-    /* unmap an excess at end of mapping. */
-    // coverity[offset_free : FALSE]
-    if (unlikely(munmap(map->dxb + limit, map->limit - limit)))
-      return errno;
-    map->limit = limit;
-    return rc;
-  }
-
-  int err = check_mmap_limit(limit);
-  if (unlikely(err != MDBX_SUCCESS))
-    return err;
-
-  assert(limit > map->limit);
-  uint8_t *ptr = MAP_FAILED;
-
-#if defined(MREMAP_MAYMOVE)
-  ptr = mremap(map->address, map->limit, limit,
-               (flags & MDBX_MRESIZE_MAY_MOVE) ? MREMAP_MAYMOVE : 0);
-  if (ptr == MAP_FAILED) {
-    err = errno;
-    switch (err) {
-    default:
-      return err;
-    case EAGAIN:
-    case ENOMEM:
-      return MDBX_UNABLE_EXTEND_MAPSIZE;
-    case EFAULT /* MADV_DODUMP / MADV_DONTDUMP are mixed for mmap-range */:
-      break;
-    }
-  }
-#endif /* MREMAP_MAYMOVE */
-
-  const unsigned mmap_flags =
-      MAP_CONCEAL | MAP_SHARED | MAP_FILE | MAP_NORESERVE |
-      (F_ISSET(flags, MDBX_UTTERLY_NOSYNC) ? MAP_NOSYNC : 0);
-  const unsigned mmap_prot =
-      (flags & MDBX_WRITEMAP) ? PROT_READ | PROT_WRITE : PROT_READ;
-
-  if (ptr == MAP_FAILED) {
-    /* Try to mmap additional space beyond the end of mapping. */
-    ptr = mmap(map->dxb + map->limit, limit - map->limit, mmap_prot,
-               mmap_flags | MAP_FIXED_NOREPLACE, map->fd, map->limit);
-    if (ptr == map->dxb + map->limit)
-      ptr = map->dxb;
-    else if (ptr != MAP_FAILED) {
-      /* the desired address is busy, unmap unsuitable one */
-      if (unlikely(munmap(ptr, limit - map->limit)))
-        return errno;
-      ptr = MAP_FAILED;
-    } else {
-      err = errno;
-      switch (err) {
-      default:
-        return err;
-      case EAGAIN:
-      case ENOMEM:
-        return MDBX_UNABLE_EXTEND_MAPSIZE;
-      case EEXIST: /* address busy */
-      case EINVAL: /* kernel don't support MAP_FIXED_NOREPLACE */
-        break;
-      }
-    }
-  }
-
-  if (ptr == MAP_FAILED) {
-    /* unmap and map again whole region */
-    if ((flags & MDBX_MRESIZE_MAY_UNMAP) == 0) {
-      /* TODO: Perhaps here it is worth to implement suspend/resume threads
-       * and perform unmap/map as like for Windows. */
-      return MDBX_UNABLE_EXTEND_MAPSIZE;
-    }
-
-    if (unlikely(munmap(map->address, map->limit)))
-      return errno;
-
-    // coverity[pass_freed_arg : FALSE]
-    ptr = mmap(map->address, limit, mmap_prot,
-               (flags & MDBX_MRESIZE_MAY_MOVE)
-                   ? mmap_flags
-                   : mmap_flags | (MAP_FIXED_NOREPLACE ? MAP_FIXED_NOREPLACE
-                                                       : MAP_FIXED),
-               map->fd, 0);
-    if (MAP_FIXED_NOREPLACE != 0 && MAP_FIXED_NOREPLACE != MAP_FIXED &&
-        unlikely(ptr == MAP_FAILED) && !(flags & MDBX_MRESIZE_MAY_MOVE) &&
-        errno == /* kernel don't support MAP_FIXED_NOREPLACE */ EINVAL)
-      // coverity[pass_freed_arg : FALSE]
-      ptr = mmap(map->address, limit, mmap_prot, mmap_flags | MAP_FIXED,
-                 map->fd, 0);
-
-    if (unlikely(ptr == MAP_FAILED)) {
-      /* try to restore prev mapping */
-      // coverity[pass_freed_arg : FALSE]
-      ptr = mmap(map->address, map->limit, mmap_prot,
-                 (flags & MDBX_MRESIZE_MAY_MOVE)
-                     ? mmap_flags
-                     : mmap_flags | (MAP_FIXED_NOREPLACE ? MAP_FIXED_NOREPLACE
-                                                         : MAP_FIXED),
-                 map->fd, 0);
-      if (MAP_FIXED_NOREPLACE != 0 && MAP_FIXED_NOREPLACE != MAP_FIXED &&
-          unlikely(ptr == MAP_FAILED) && !(flags & MDBX_MRESIZE_MAY_MOVE) &&
-          errno == /* kernel don't support MAP_FIXED_NOREPLACE */ EINVAL)
-        // coverity[pass_freed_arg : FALSE]
-        ptr = mmap(map->address, map->limit, mmap_prot, mmap_flags | MAP_FIXED,
-                   map->fd, 0);
-      if (unlikely(ptr == MAP_FAILED)) {
-        VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
-        /* Unpoisoning is required for ASAN to avoid false-positive diagnostic
-         * when this memory will re-used by malloc or another mmapping.
-         * See
-         * todo4recovery://erased_by_github/libmdbx/pull/93#issuecomment-613687203
-         */
-        MDBX_ASAN_UNPOISON_MEMORY_REGION(
-            map->address,
-            (map->current < map->limit) ? map->current : map->limit);
-        map->limit = 0;
-        map->current = 0;
-        map->address = nullptr;
-        return errno;
-      }
-      rc = MDBX_UNABLE_EXTEND_MAPSIZE;
-      limit = map->limit;
-    }
-  }
-
-  assert(ptr && ptr != MAP_FAILED);
-  if (map->address != ptr) {
-    VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
-    /* Unpoisoning is required for ASAN to avoid false-positive diagnostic
-     * when this memory will re-used by malloc or another mmapping.
-     * See
-     * todo4recovery://erased_by_github/libmdbx/pull/93#issuecomment-613687203
-     */
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(
-        map->address, (map->current < map->limit) ? map->current : map->limit);
-
-    VALGRIND_MAKE_MEM_DEFINED(ptr, map->current);
-    MDBX_ASAN_UNPOISON_MEMORY_REGION(ptr, map->current);
-    map->address = ptr;
-  }
-  map->limit = limit;
-
-#if MDBX_ENABLE_MADVISE
-#ifdef MADV_DONTFORK
-  if (unlikely(madvise(map->address, map->limit, MADV_DONTFORK) != 0))
-    return errno;
-#endif /* MADV_DONTFORK */
-#ifdef MADV_NOHUGEPAGE
-  (void)madvise(map->address, map->limit, MADV_NOHUGEPAGE);
-#endif /* MADV_NOHUGEPAGE */
-#endif /* MDBX_ENABLE_MADVISE */
-
-#endif /* POSIX / Windows */
-
-  return rc;
-}
-
-/*----------------------------------------------------------------------------*/
-
-__cold MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny) {
-  for (;;) {
-#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) ||                \
-    defined(__x86_64__)
-    const unsigned salt = 277u * (unsigned)__rdtsc();
-#elif (defined(_WIN32) || defined(_WIN64)) && MDBX_WITHOUT_MSVC_CRT
-    static ULONG state;
-    const unsigned salt = (unsigned)RtlRandomEx(&state);
-#else
-    const unsigned salt = rand();
-#endif
-
-    const unsigned coin = salt % (tiny ? 29u : 43u);
-    if (coin < 43 / 3)
-      break;
-#if defined(_WIN32) || defined(_WIN64)
-    SwitchToThread();
-    if (coin > 43 * 2 / 3)
-      Sleep(1);
-#else
-    sched_yield();
-    if (coin > 43 * 2 / 3)
-      usleep(coin);
-#endif
-  }
-}
-
-#if defined(_WIN32) || defined(_WIN64)
-#elif defined(__APPLE__) || defined(__MACH__)
-#include <mach/mach_time.h>
-#elif defined(__linux__) || defined(__gnu_linux__)
-__cold static clockid_t choice_monoclock(void) {
-  struct timespec probe;
-#if defined(CLOCK_BOOTTIME)
-  if (clock_gettime(CLOCK_BOOTTIME, &probe) == 0)
-    return CLOCK_BOOTTIME;
-#elif defined(CLOCK_MONOTONIC_RAW)
-  if (clock_gettime(CLOCK_MONOTONIC_RAW, &probe) == 0)
-    return CLOCK_MONOTONIC_RAW;
-#elif defined(CLOCK_MONOTONIC_COARSE)
-  if (clock_gettime(CLOCK_MONOTONIC_COARSE, &probe) == 0)
-    return CLOCK_MONOTONIC_COARSE;
-#endif
-  return CLOCK_MONOTONIC;
-}
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_WIN32) || defined(_WIN64)
-static LARGE_INTEGER performance_frequency;
-#elif defined(__APPLE__) || defined(__MACH__)
-static uint64_t ratio_16dot16_to_monotine;
-#endif
-
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16) {
-#if defined(_WIN32) || defined(_WIN64)
-  if (unlikely(performance_frequency.QuadPart == 0))
-    QueryPerformanceFrequency(&performance_frequency);
-  const uint64_t ratio = performance_frequency.QuadPart;
-#elif defined(__APPLE__) || defined(__MACH__)
-  if (unlikely(ratio_16dot16_to_monotine == 0)) {
-    mach_timebase_info_data_t ti;
-    mach_timebase_info(&ti);
-    ratio_16dot16_to_monotine = UINT64_C(1000000000) * ti.denom / ti.numer;
-  }
-  const uint64_t ratio = ratio_16dot16_to_monotine;
-#else
-  const uint64_t ratio = UINT64_C(1000000000);
-#endif
-  const uint64_t ret = (ratio * seconds_16dot16 + 32768) >> 16;
-  return likely(ret || seconds_16dot16 == 0) ? ret : /* fix underflow */ 1;
-}
-
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime) {
-  static uint64_t limit;
-  if (unlikely(monotime > limit)) {
-    if (limit != 0)
-      return UINT32_MAX;
-    limit = mdbx_osal_16dot16_to_monotime(UINT32_MAX - 1);
-    if (monotime > limit)
-      return UINT32_MAX;
-  }
-  const uint32_t ret =
-#if defined(_WIN32) || defined(_WIN64)
-      (uint32_t)((monotime << 16) / performance_frequency.QuadPart);
-#elif defined(__APPLE__) || defined(__MACH__)
-      (uint32_t)((monotime << 16) / ratio_16dot16_to_monotine);
-#else
-      (uint32_t)(monotime * 128 / 1953125);
-#endif
-  return likely(ret || monotime == 0) ? ret : /* fix underflow */ 1;
-}
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  LARGE_INTEGER counter;
-  counter.QuadPart = 0;
-  QueryPerformanceCounter(&counter);
-  return counter.QuadPart;
-#elif defined(__APPLE__) || defined(__MACH__)
-  return mach_absolute_time();
-#else
-
-#if defined(__linux__) || defined(__gnu_linux__)
-  static clockid_t posix_clockid = -1;
-  if (unlikely(posix_clockid < 0))
-    posix_clockid = choice_monoclock();
-#elif defined(CLOCK_MONOTONIC)
-#define posix_clockid CLOCK_MONOTONIC
-#else
-#define posix_clockid CLOCK_REALTIME
-#endif
-
-  struct timespec ts;
-  if (unlikely(clock_gettime(posix_clockid, &ts) != 0)) {
-    ts.tv_nsec = 0;
-    ts.tv_sec = 0;
-  }
-  return ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-
-static void bootid_shake(bin128_t *p) {
-  /* Bob Jenkins's PRNG: https://burtleburtle.net/bob/rand/smallprng.html */
-  const uint32_t e = p->a - (p->b << 23 | p->b >> 9);
-  p->a = p->b ^ (p->c << 16 | p->c >> 16);
-  p->b = p->c + (p->d << 11 | p->d >> 21);
-  p->c = p->d + e;
-  p->d = e + p->a;
-}
-
-static void bootid_collect(bin128_t *p, const void *s, size_t n) {
-  p->y += UINT64_C(64526882297375213);
-  bootid_shake(p);
-  for (size_t i = 0; i < n; ++i) {
-    bootid_shake(p);
-    p->y ^= UINT64_C(48797879452804441) * ((const uint8_t *)s)[i];
-    bootid_shake(p);
-    p->y += 14621231;
-  }
-  bootid_shake(p);
-
-  /* minor non-linear tomfoolery */
-  const unsigned z = p->x % 61;
-  p->y = p->y << z | p->y >> (64 - z);
-  bootid_shake(p);
-  bootid_shake(p);
-  const unsigned q = p->x % 59;
-  p->y = p->y << q | p->y >> (64 - q);
-  bootid_shake(p);
-  bootid_shake(p);
-  bootid_shake(p);
-}
-
-#if defined(_WIN32) || defined(_WIN64)
-
-static uint64_t windows_systemtime_ms() {
-  FILETIME ft;
-  GetSystemTimeAsFileTime(&ft);
-  return ((uint64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10000ul;
-}
-
-static uint64_t windows_bootime(void) {
-  unsigned confirmed = 0;
-  uint64_t boottime = 0;
-  uint64_t up0 = mdbx_GetTickCount64();
-  uint64_t st0 = windows_systemtime_ms();
-  for (uint64_t fuse = st0; up0 && st0 < fuse + 1000 * 1000u / 42;) {
-    YieldProcessor();
-    const uint64_t up1 = mdbx_GetTickCount64();
-    const uint64_t st1 = windows_systemtime_ms();
-    if (st1 > fuse && st1 == st0 && up1 == up0) {
-      uint64_t diff = st1 - up1;
-      if (boottime == diff) {
-        if (++confirmed > 4)
-          return boottime;
-      } else {
-        confirmed = 0;
-        boottime = diff;
-      }
-      fuse = st1;
-      Sleep(1);
-    }
-    st0 = st1;
-    up0 = up1;
-  }
-  return 0;
-}
-
-static LSTATUS mdbx_RegGetValue(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValue,
-                                PVOID pvData, LPDWORD pcbData) {
-  LSTATUS rc;
-  if (!mdbx_RegGetValueA) {
-    /* an old Windows 2000/XP */
-    HKEY hSubKey;
-    rc = RegOpenKeyA(hKey, lpSubKey, &hSubKey);
-    if (rc == ERROR_SUCCESS) {
-      rc = RegQueryValueExA(hSubKey, lpValue, NULL, NULL, pvData, pcbData);
-      RegCloseKey(hSubKey);
-    }
-    return rc;
-  }
-
-  rc = mdbx_RegGetValueA(hKey, lpSubKey, lpValue, RRF_RT_ANY, NULL, pvData,
-                         pcbData);
-  if (rc != ERROR_FILE_NOT_FOUND)
-    return rc;
-
-  rc = mdbx_RegGetValueA(hKey, lpSubKey, lpValue,
-                         RRF_RT_ANY | 0x00010000 /* RRF_SUBKEY_WOW6464KEY */,
-                         NULL, pvData, pcbData);
-  if (rc != ERROR_FILE_NOT_FOUND)
-    return rc;
-  return mdbx_RegGetValueA(hKey, lpSubKey, lpValue,
-                           RRF_RT_ANY | 0x00020000 /* RRF_SUBKEY_WOW6432KEY */,
-                           NULL, pvData, pcbData);
-}
-#endif
-
-__cold MDBX_MAYBE_UNUSED static bool
-bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
-  if (n > 31) {
-    unsigned bits = 0;
-    for (unsigned i = 0; i < n; ++i) /* try parse an UUID in text form */ {
-      uint8_t c = ((const uint8_t *)p)[i];
-      if (c >= '0' && c <= '9')
-        c -= '0';
-      else if (c >= 'a' && c <= 'f')
-        c -= 'a' - 10;
-      else if (c >= 'A' && c <= 'F')
-        c -= 'A' - 10;
-      else
-        continue;
-      assert(c <= 15);
-      c ^= s->y >> 60;
-      s->y = s->y << 4 | s->x >> 60;
-      s->x = s->x << 4 | c;
-      bits += 4;
-    }
-    if (bits > 42 * 3)
-      /* UUID parsed successfully */
-      return true;
-  }
-
-  if (n > 15) /* is enough handle it as a binary? */ {
-    if (n == sizeof(bin128_t)) {
-      bin128_t aligned;
-      memcpy(&aligned, p, sizeof(bin128_t));
-      s->x += aligned.x;
-      s->y += aligned.y;
-    } else
-      bootid_collect(s, p, n);
-    return true;
-  }
-
-  if (n)
-    bootid_collect(s, p, n);
-  return false;
-}
-
-__cold MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void) {
-  bin128_t bin = {{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;
-    }
-  }
-#endif /* Linux */
-
-#if defined(__APPLE__) || defined(__MACH__)
-  {
-    char buf[42];
-    size_t len = sizeof(buf);
-    if (!sysctlbyname("kern.bootsessionuuid", buf, &len, nullptr, 0) &&
-        bootid_parse_uuid(&bin, buf, len))
-      return bin;
-
-#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) &&                                \
-    __MAC_OS_X_VERSION_MIN_REQUIRED > 1050
-    uuid_t uuid;
-    struct timespec wait = {0, 1000000000u / 42};
-    if (!gethostuuid(uuid, &wait) &&
-        bootid_parse_uuid(&bin, uuid, sizeof(uuid)))
-      got_machineid = true;
-#endif /* > 10.5 */
-
-    struct timeval boottime;
-    len = sizeof(boottime);
-    if (!sysctlbyname("kern.boottime", &boottime, &len, nullptr, 0) &&
-        len == sizeof(boottime) && boottime.tv_sec)
-      got_boottime = true;
-  }
-#endif /* Apple/Darwin */
-
-#if defined(_WIN32) || defined(_WIN64)
-  {
-    union buf {
-      DWORD BootId;
-      DWORD BaseTime;
-      SYSTEM_TIMEOFDAY_INFORMATION SysTimeOfDayInfo;
-      struct {
-        LARGE_INTEGER BootTime;
-        LARGE_INTEGER CurrentTime;
-        LARGE_INTEGER TimeZoneBias;
-        ULONG TimeZoneId;
-        ULONG Reserved;
-        ULONGLONG BootTimeBias;
-        ULONGLONG SleepTimeBias;
-      } SysTimeOfDayInfoHacked;
-      wchar_t MachineGuid[42];
-      char DigitalProductId[248];
-    } buf;
-
-    static const char HKLM_MicrosoftCryptography[] =
-        "SOFTWARE\\Microsoft\\Cryptography";
-    DWORD len = sizeof(buf);
-    /* Windows is madness and must die */
-    if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_MicrosoftCryptography,
-                         "MachineGuid", &buf.MachineGuid,
-                         &len) == ERROR_SUCCESS &&
-        len < sizeof(buf))
-      got_machineid = bootid_parse_uuid(&bin, &buf.MachineGuid, len);
-
-    if (!got_machineid) {
-      /* again, Windows is madness */
-      static const char HKLM_WindowsNT[] =
-          "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
-      static const char HKLM_WindowsNT_DPK[] =
-          "SOFTWARE\\Microsoft\\Windows "
-          "NT\\CurrentVersion\\DefaultProductKey";
-      static const char HKLM_WindowsNT_DPK2[] =
-          "SOFTWARE\\Microsoft\\Windows "
-          "NT\\CurrentVersion\\DefaultProductKey2";
-
-      len = sizeof(buf);
-      if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_WindowsNT,
-                           "DigitalProductId", &buf.DigitalProductId,
-                           &len) == ERROR_SUCCESS &&
-          len > 42 && len < sizeof(buf)) {
-        bootid_collect(&bin, &buf.DigitalProductId, len);
-        got_machineid = true;
-      }
-      len = sizeof(buf);
-      if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_WindowsNT_DPK,
-                           "DigitalProductId", &buf.DigitalProductId,
-                           &len) == ERROR_SUCCESS &&
-          len > 42 && len < sizeof(buf)) {
-        bootid_collect(&bin, &buf.DigitalProductId, len);
-        got_machineid = true;
-      }
-      len = sizeof(buf);
-      if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_WindowsNT_DPK2,
-                           "DigitalProductId", &buf.DigitalProductId,
-                           &len) == ERROR_SUCCESS &&
-          len > 42 && len < sizeof(buf)) {
-        bootid_collect(&bin, &buf.DigitalProductId, len);
-        got_machineid = true;
-      }
-    }
-
-    static const char HKLM_PrefetcherParams[] =
-        "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory "
-        "Management\\PrefetchParameters";
-    len = sizeof(buf);
-    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);
-      got_bootseq = true;
-    }
-
-    len = sizeof(buf);
-    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);
-      got_boottime = true;
-    }
-
-    /* BootTime from SYSTEM_TIMEOFDAY_INFORMATION */
-    NTSTATUS status = NtQuerySystemInformation(
-        0x03 /* SystemTmeOfDayInformation */, &buf.SysTimeOfDayInfo,
-        sizeof(buf.SysTimeOfDayInfo), &len);
-    if (NT_SUCCESS(status) &&
-        len >= offsetof(union buf, SysTimeOfDayInfoHacked.BootTimeBias) +
-                   sizeof(buf.SysTimeOfDayInfoHacked.BootTimeBias) &&
-        buf.SysTimeOfDayInfoHacked.BootTime.QuadPart) {
-      const uint64_t UnbiasedBootTime =
-          buf.SysTimeOfDayInfoHacked.BootTime.QuadPart -
-          buf.SysTimeOfDayInfoHacked.BootTimeBias;
-      if (UnbiasedBootTime) {
-        bootid_collect(&bin, &UnbiasedBootTime, sizeof(UnbiasedBootTime));
-        got_boottime = true;
-      }
-    }
-
-    if (!got_boottime) {
-      uint64_t boottime = windows_bootime();
-      if (boottime) {
-        bootid_collect(&bin, &boottime, sizeof(boottime));
-        got_boottime = true;
-      }
-    }
-  }
-#endif /* Windows */
-
-#if defined(CTL_HW) && defined(HW_UUID)
-  if (!got_machineid) {
-    static const int mib[] = {CTL_HW, HW_UUID};
-    char buf[42];
-    size_t len = sizeof(buf);
-    if (sysctl(
-#ifdef SYSCTL_LEGACY_NONCONST_MIB
-            (int *)
-#endif
-                mib,
-            ARRAY_LENGTH(mib), &buf, &len, NULL, 0) == 0)
-      got_machineid = bootid_parse_uuid(&bin, buf, len);
-  }
-#endif /* CTL_HW && HW_UUID */
-
-#if defined(CTL_KERN) && defined(KERN_HOSTUUID)
-  if (!got_machineid) {
-    static const int mib[] = {CTL_KERN, KERN_HOSTUUID};
-    char buf[42];
-    size_t len = sizeof(buf);
-    if (sysctl(
-#ifdef SYSCTL_LEGACY_NONCONST_MIB
-            (int *)
-#endif
-                mib,
-            ARRAY_LENGTH(mib), &buf, &len, NULL, 0) == 0)
-      got_machineid = bootid_parse_uuid(&bin, buf, len);
-  }
-#endif /* CTL_KERN && KERN_HOSTUUID */
-
-#if defined(__NetBSD__)
-  if (!got_machineid) {
-    char buf[42];
-    size_t len = sizeof(buf);
-    if (sysctlbyname("machdep.dmi.system-uuid", buf, &len, NULL, 0) == 0)
-      got_machineid = bootid_parse_uuid(&bin, buf, len);
-  }
-#endif /* __NetBSD__ */
-
-#if _XOPEN_SOURCE_EXTENDED
-  if (!got_machineid) {
-    const int hostid = gethostid();
-    if (hostid > 0) {
-      bootid_collect(&bin, &hostid, sizeof(hostid));
-      got_machineid = true;
-    }
-  }
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-  if (!got_machineid) {
-  lack:
-    bin.x = bin.y = 0;
-    return bin;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-#if defined(CTL_KERN) && defined(KERN_BOOTTIME)
-  if (!got_boottime) {
-    static const int mib[] = {CTL_KERN, KERN_BOOTTIME};
-    struct timeval boottime;
-    size_t len = sizeof(boottime);
-    if (sysctl(
-#ifdef SYSCTL_LEGACY_NONCONST_MIB
-            (int *)
-#endif
-                mib,
-            ARRAY_LENGTH(mib), &boottime, &len, NULL, 0) == 0 &&
-        len == sizeof(boottime) && boottime.tv_sec) {
-      bootid_collect(&bin, &boottime, len);
-      got_boottime = true;
-    }
-  }
-#endif /* CTL_KERN && KERN_BOOTTIME */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-  if (!got_boottime) {
-    kstat_ctl_t *kc = kstat_open();
-    if (kc) {
-      kstat_t *kp = kstat_lookup(kc, "unix", 0, "system_misc");
-      if (kp && kstat_read(kc, kp, 0) != -1) {
-        kstat_named_t *kn = (kstat_named_t *)kstat_data_lookup(kp, "boot_time");
-        if (kn) {
-          switch (kn->data_type) {
-          case KSTAT_DATA_INT32:
-          case KSTAT_DATA_UINT32:
-            bootid_collect(&bin, &kn->value, sizeof(int32_t));
-            got_boottime = true;
-          case KSTAT_DATA_INT64:
-          case KSTAT_DATA_UINT64:
-            bootid_collect(&bin, &kn->value, sizeof(int64_t));
-            got_boottime = true;
-          }
-        }
-      }
-      kstat_close(kc);
-    }
-  }
-#endif /* SunOS / Solaris */
-
-#if _XOPEN_SOURCE_EXTENDED && defined(BOOT_TIME)
-  if (!got_boottime) {
-    setutxent();
-    const struct utmpx id = {.ut_type = BOOT_TIME};
-    const struct utmpx *entry = getutxid(&id);
-    if (entry) {
-      bootid_collect(&bin, 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));
-        got_bootseq = true;
-      }
-    }
-    endutxent();
-  }
-#endif /* _XOPEN_SOURCE_EXTENDED && BOOT_TIME */
-
-  if (!got_bootseq) {
-    if (!got_boottime || !MDBX_TRUST_RTC)
-      goto lack;
-
-#if defined(_WIN32) || defined(_WIN64)
-    FILETIME now;
-    GetSystemTimeAsFileTime(&now);
-    if (0x1CCCCCC > now.dwHighDateTime)
-#else
-    struct timespec mono, real;
-    if (clock_gettime(CLOCK_MONOTONIC, &mono) ||
-        clock_gettime(CLOCK_REALTIME, &real) ||
-        /* wrong time, RTC is mad or absent */
-        1555555555l > real.tv_sec ||
-        /* seems no adjustment by RTC/NTP, i.e. a fake time */
-        real.tv_sec < mono.tv_sec || 1234567890l > real.tv_sec - mono.tv_sec ||
-        (real.tv_sec - mono.tv_sec) % 900u == 0)
-#endif
-      goto lack;
-  }
-
-  return bin;
-}
-
-__cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages,
-                               intptr_t *avail_pages) {
-  if (!page_size && !total_pages && !avail_pages)
-    return MDBX_EINVAL;
-  if (total_pages)
-    *total_pages = -1;
-  if (avail_pages)
-    *avail_pages = -1;
-
-  const intptr_t pagesize = mdbx_syspagesize();
-  if (page_size)
-    *page_size = pagesize;
-  if (unlikely(pagesize < MIN_PAGESIZE || !is_powerof2(pagesize)))
-    return MDBX_INCOMPATIBLE;
-
-  MDBX_MAYBE_UNUSED const int log2page = log2n_powerof2(pagesize);
-  assert(pagesize == (INT64_C(1) << log2page));
-  (void)log2page;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MEMORYSTATUSEX info;
-  memset(&info, 0, sizeof(info));
-  info.dwLength = sizeof(info);
-  if (!GlobalMemoryStatusEx(&info))
-    return (int)GetLastError();
-#endif
-
-  if (total_pages) {
-#if defined(_WIN32) || defined(_WIN64)
-    const intptr_t total_ram_pages = (intptr_t)(info.ullTotalPhys >> log2page);
-#elif defined(_SC_PHYS_PAGES)
-    const intptr_t total_ram_pages = sysconf(_SC_PHYS_PAGES);
-    if (total_ram_pages == -1)
-      return errno;
-#elif defined(_SC_AIX_REALMEM)
-    const intptr_t total_ram_Kb = sysconf(_SC_AIX_REALMEM);
-    if (total_ram_Kb == -1)
-      return errno;
-    const intptr_t total_ram_pages = (total_ram_Kb << 10) >> log2page;
-#elif defined(HW_USERMEM) || defined(HW_PHYSMEM64) || defined(HW_MEMSIZE) ||   \
-    defined(HW_PHYSMEM)
-    size_t ram, len = sizeof(ram);
-    static const int mib[] = {
-      CTL_HW,
-#if defined(HW_USERMEM)
-      HW_USERMEM
-#elif defined(HW_PHYSMEM64)
-      HW_PHYSMEM64
-#elif defined(HW_MEMSIZE)
-      HW_MEMSIZE
-#else
-      HW_PHYSMEM
-#endif
-    };
-    if (sysctl(
-#ifdef SYSCTL_LEGACY_NONCONST_MIB
-            (int *)
-#endif
-                mib,
-            ARRAY_LENGTH(mib), &ram, &len, NULL, 0) != 0)
-      return errno;
-    if (len != sizeof(ram))
-      return MDBX_ENOSYS;
-    const intptr_t total_ram_pages = (intptr_t)(ram >> log2page);
-#else
-#error "FIXME: Get User-accessible or physical RAM"
-#endif
-    *total_pages = total_ram_pages;
-    if (total_ram_pages < 1)
-      return MDBX_ENOSYS;
-  }
-
-  if (avail_pages) {
-#if defined(_WIN32) || defined(_WIN64)
-    const intptr_t avail_ram_pages = (intptr_t)(info.ullAvailPhys >> log2page);
-#elif defined(_SC_AVPHYS_PAGES)
-    const intptr_t avail_ram_pages = sysconf(_SC_AVPHYS_PAGES);
-    if (avail_ram_pages == -1)
-      return errno;
-#elif defined(__MACH__)
-    mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
-    vm_statistics_data_t vmstat;
-    mach_port_t mport = mach_host_self();
-    kern_return_t kerr = host_statistics(mach_host_self(), HOST_VM_INFO,
-                                         (host_info_t)&vmstat, &count);
-    mach_port_deallocate(mach_task_self(), mport);
-    if (unlikely(kerr != KERN_SUCCESS))
-      return MDBX_ENOSYS;
-    const intptr_t avail_ram_pages = vmstat.free_count;
-#elif defined(VM_TOTAL) || defined(VM_METER)
-    struct vmtotal info;
-    size_t len = sizeof(info);
-    static const int mib[] = {
-      CTL_VM,
-#if defined(VM_TOTAL)
-      VM_TOTAL
-#elif defined(VM_METER)
-      VM_METER
-#endif
-    };
-    if (sysctl(
-#ifdef SYSCTL_LEGACY_NONCONST_MIB
-            (int *)
-#endif
-                mib,
-            ARRAY_LENGTH(mib), &info, &len, NULL, 0) != 0)
-      return errno;
-    if (len != sizeof(info))
-      return MDBX_ENOSYS;
-    const intptr_t avail_ram_pages = info.t_free;
-#else
-#error "FIXME: Get Available RAM"
-#endif
-    *avail_pages = avail_ram_pages;
-    if (avail_ram_pages < 1)
-      return MDBX_ENOSYS;
-  }
-
-  return MDBX_SUCCESS;
-}
-/* This is CMake-template for libmdbx's version.c
- ******************************************************************************/
-
-
-#if MDBX_VERSION_MAJOR != 0 ||                             \
-    MDBX_VERSION_MINOR != 11
-#error "API version mismatch! Had `git fetch --tags` done?"
-#endif
-
-static const char sourcery[] = MDBX_STRINGIFY(MDBX_BUILD_SOURCERY);
-
-__dll_export
-#ifdef __attribute_used__
-    __attribute_used__
-#elif defined(__GNUC__) || __has_attribute(__used__)
-    __attribute__((__used__))
-#endif
-#ifdef __attribute_externally_visible__
-        __attribute_externally_visible__
-#elif (defined(__GNUC__) && !defined(__clang__)) ||                            \
-    __has_attribute(__externally_visible__)
-    __attribute__((__externally_visible__))
-#endif
-    const struct MDBX_version_info mdbx_version = {
-        0,
-        11,
-        7,
-        0,
-        {"2022-04-22T23:28:56+03:00", "6fdefd6844bd6d212ea6dec99892ae1fac981521", "40ec559c8c1e0b9794cdc0cd12c155d05e7e8547",
-         "v0.11.7-0-g40ec559c"},
-        sourcery};
-
-__dll_export
-#ifdef __attribute_used__
-    __attribute_used__
-#elif defined(__GNUC__) || __has_attribute(__used__)
-    __attribute__((__used__))
-#endif
-#ifdef __attribute_externally_visible__
-        __attribute_externally_visible__
-#elif (defined(__GNUC__) && !defined(__clang__)) ||                            \
-    __has_attribute(__externally_visible__)
-    __attribute__((__externally_visible__))
-#endif
-    const char *const mdbx_sourcery_anchor = sourcery;
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-#if defined(_WIN32) || defined(_WIN64) /* Windows LCK-implementation */
-
-/* PREAMBLE FOR WINDOWS:
- *
- * We are not concerned for performance here.
- * If you are running Windows a performance could NOT be the goal.
- * Otherwise please use Linux. */
-
-
-static void mdbx_winnt_import(void);
-
-#if MDBX_BUILD_SHARED_LIBRARY
-#if MDBX_WITHOUT_MSVC_CRT && defined(NDEBUG)
-/* DEBUG/CHECKED builds still require MSVC's CRT for runtime checks.
- *
- * Define dll's entry point only for Release build when NDEBUG is defined and
- * MDBX_WITHOUT_MSVC_CRT=ON. if the entry point isn't defined then MSVC's will
- * automatically use DllMainCRTStartup() from CRT library, which also
- * automatically call DllMain() from our mdbx.dll */
-#pragma comment(linker, "/ENTRY:DllMain")
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved)
-#else
-#if !MDBX_MANUAL_MODULE_HANDLER
-static
-#endif /* !MDBX_MANUAL_MODULE_HANDLER */
-    void NTAPI
-    mdbx_module_handler(PVOID module, DWORD reason, PVOID reserved)
-#endif /* MDBX_BUILD_SHARED_LIBRARY */
-{
-  (void)reserved;
-  switch (reason) {
-  case DLL_PROCESS_ATTACH:
-    mdbx_winnt_import();
-    mdbx_rthc_global_init();
-    break;
-  case DLL_PROCESS_DETACH:
-    mdbx_rthc_global_dtor();
-    break;
-
-  case DLL_THREAD_ATTACH:
-    break;
-  case DLL_THREAD_DETACH:
-    mdbx_rthc_thread_dtor(module);
-    break;
-  }
-#if MDBX_BUILD_SHARED_LIBRARY
-  return TRUE;
-#endif
-}
-
-#if !MDBX_BUILD_SHARED_LIBRARY && !MDBX_MANUAL_MODULE_HANDLER
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(_MSC_VER)
-#  pragma const_seg(push)
-#  pragma data_seg(push)
-
-#  ifndef _M_IX86
-     /* kick a linker to create the TLS directory if not already done */
-#    pragma comment(linker, "/INCLUDE:_tls_used")
-     /* Force some symbol references. */
-#    pragma comment(linker, "/INCLUDE:mdbx_tls_anchor")
-     /* specific const-segment for WIN64 */
-#    pragma const_seg(".CRT$XLB")
-     const
-#  else
-     /* kick a linker to create the TLS directory if not already done */
-#    pragma comment(linker, "/INCLUDE:__tls_used")
-     /* Force some symbol references. */
-#    pragma comment(linker, "/INCLUDE:_mdbx_tls_anchor")
-     /* specific data-segment for WIN32 */
-#    pragma data_seg(".CRT$XLB")
-#  endif
-
-   __declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK mdbx_tls_anchor = mdbx_module_handler;
-#  pragma data_seg(pop)
-#  pragma const_seg(pop)
-
-#elif defined(__GNUC__)
-#  ifndef _M_IX86
-     const
-#  endif
-   PIMAGE_TLS_CALLBACK mdbx_tls_anchor __attribute__((__section__(".CRT$XLB"), used)) = mdbx_module_handler;
-#else
-#  error FIXME
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* !MDBX_BUILD_SHARED_LIBRARY && !MDBX_MANUAL_MODULE_HANDLER */
-
-/*----------------------------------------------------------------------------*/
-
-#define LCK_SHARED 0
-#define LCK_EXCLUSIVE LOCKFILE_EXCLUSIVE_LOCK
-#define LCK_WAITFOR 0
-#define LCK_DONTWAIT LOCKFILE_FAIL_IMMEDIATELY
-
-static __inline BOOL flock(mdbx_filehandle_t fd, DWORD flags, uint64_t offset,
-                           size_t bytes) {
-  OVERLAPPED ov;
-  ov.hEvent = 0;
-  ov.Offset = (DWORD)offset;
-  ov.OffsetHigh = HIGH_DWORD(offset);
-  return LockFileEx(fd, flags, 0, (DWORD)bytes, HIGH_DWORD(bytes), &ov);
-}
-
-static __inline BOOL funlock(mdbx_filehandle_t fd, uint64_t offset,
-                             size_t bytes) {
-  return UnlockFile(fd, (DWORD)offset, HIGH_DWORD(offset), (DWORD)bytes,
-                    HIGH_DWORD(bytes));
-}
-
-/*----------------------------------------------------------------------------*/
-/* global `write` lock for write-txt processing,
- * exclusive locking both meta-pages) */
-
-#define LCK_MAXLEN (1u + ((~(size_t)0) >> 1))
-#define LCK_META_OFFSET 0
-#define LCK_META_LEN (MAX_PAGESIZE * NUM_METAS)
-#define LCK_BODY_OFFSET LCK_META_LEN
-#define LCK_BODY_LEN (LCK_MAXLEN - LCK_BODY_OFFSET)
-#define LCK_BODY LCK_BODY_OFFSET, LCK_BODY_LEN
-#define LCK_WHOLE 0, LCK_MAXLEN
-
-int mdbx_txn_lock(MDBX_env *env, bool dontwait) {
-  if (dontwait) {
-    if (!TryEnterCriticalSection(&env->me_windowsbug_lock))
-      return MDBX_BUSY;
-  } else {
-    __try {
-      EnterCriticalSection(&env->me_windowsbug_lock);
-    }
-    __except ((GetExceptionCode() ==
-                 0xC0000194 /* STATUS_POSSIBLE_DEADLOCK / EXCEPTION_POSSIBLE_DEADLOCK */)
-                    ? EXCEPTION_EXECUTE_HANDLER
-                    : EXCEPTION_CONTINUE_SEARCH) {
-      return ERROR_POSSIBLE_DEADLOCK;
-    }
-  }
-
-  if ((env->me_flags & MDBX_EXCLUSIVE) ||
-      flock(env->me_lazy_fd,
-            dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT)
-                     : (LCK_EXCLUSIVE | LCK_WAITFOR),
-            LCK_BODY))
-    return MDBX_SUCCESS;
-  int rc = (int)GetLastError();
-  LeaveCriticalSection(&env->me_windowsbug_lock);
-  return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY;
-}
-
-void mdbx_txn_unlock(MDBX_env *env) {
-  int rc = (env->me_flags & MDBX_EXCLUSIVE)
-               ? TRUE
-               : funlock(env->me_lazy_fd, LCK_BODY);
-  LeaveCriticalSection(&env->me_windowsbug_lock);
-  if (!rc)
-    mdbx_panic("%s failed: err %u", __func__, (int)GetLastError());
-}
-
-/*----------------------------------------------------------------------------*/
-/* global `read` lock for readers registration,
- * exclusive locking `mti_numreaders` (second) cacheline */
-
-#define LCK_LO_OFFSET 0
-#define LCK_LO_LEN offsetof(MDBX_lockinfo, mti_numreaders)
-#define LCK_UP_OFFSET LCK_LO_LEN
-#define LCK_UP_LEN (sizeof(MDBX_lockinfo) - LCK_UP_OFFSET)
-#define LCK_LOWER LCK_LO_OFFSET, LCK_LO_LEN
-#define LCK_UPPER LCK_UP_OFFSET, LCK_UP_LEN
-
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env) {
-  mdbx_srwlock_AcquireShared(&env->me_remap_guard);
-  if (env->me_lfd == INVALID_HANDLE_VALUE)
-    return MDBX_SUCCESS; /* readonly database in readonly filesystem */
-
-  /* transition from S-? (used) to S-E (locked),
-   * e.g. exclusive lock upper-part */
-  if ((env->me_flags & MDBX_EXCLUSIVE) ||
-      flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER))
-    return MDBX_SUCCESS;
-
-  int rc = (int)GetLastError();
-  mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) {
-  if (env->me_lfd != INVALID_HANDLE_VALUE) {
-    /* transition from S-E (locked) to S-? (used), e.g. unlock upper-part */
-    if ((env->me_flags & MDBX_EXCLUSIVE) == 0 &&
-        !funlock(env->me_lfd, LCK_UPPER))
-      mdbx_panic("%s failed: err %u", __func__, (int)GetLastError());
-  }
-  mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
-  return flock(fd,
-               wait ? LCK_EXCLUSIVE | LCK_WAITFOR
-                    : LCK_EXCLUSIVE | LCK_DONTWAIT,
-               0, LCK_MAXLEN)
-             ? MDBX_SUCCESS
-             : (int)GetLastError();
-}
-
-static int suspend_and_append(mdbx_handle_array_t **array,
-                              const DWORD ThreadId) {
-  const unsigned limit = (*array)->limit;
-  if ((*array)->count == limit) {
-    void *ptr = mdbx_realloc(
-        (limit > ARRAY_LENGTH((*array)->handles))
-            ? *array
-            : /* don't free initial array on the stack */ NULL,
-        sizeof(mdbx_handle_array_t) +
-            sizeof(HANDLE) * (limit * 2 - ARRAY_LENGTH((*array)->handles)));
-    if (!ptr)
-      return MDBX_ENOMEM;
-    if (limit == ARRAY_LENGTH((*array)->handles))
-      memcpy(ptr, *array, sizeof(mdbx_handle_array_t));
-    *array = (mdbx_handle_array_t *)ptr;
-    (*array)->limit = limit * 2;
-  }
-
-  HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
-                              FALSE, ThreadId);
-  if (hThread == NULL)
-    return (int)GetLastError();
-
-  if (SuspendThread(hThread) == (DWORD)-1) {
-    int err = (int)GetLastError();
-    DWORD ExitCode;
-    if (err == /* workaround for Win10 UCRT bug */ ERROR_ACCESS_DENIED ||
-        !GetExitCodeThread(hThread, &ExitCode) || ExitCode != STILL_ACTIVE)
-      err = MDBX_SUCCESS;
-    CloseHandle(hThread);
-    return err;
-  }
-
-  (*array)->handles[(*array)->count++] = hThread;
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
-  mdbx_assert(env, (env->me_flags & MDBX_NOTLS) == 0);
-  const uintptr_t CurrentTid = GetCurrentThreadId();
-  int rc;
-  if (env->me_lck_mmap.lck) {
-    /* Scan LCK for threads of the current process */
-    const MDBX_reader *const begin = env->me_lck_mmap.lck->mti_readers;
-    const MDBX_reader *const end =
-        begin +
-        atomic_load32(&env->me_lck_mmap.lck->mti_numreaders, mo_AcquireRelease);
-    const uintptr_t WriteTxnOwner = env->me_txn0 ? env->me_txn0->mt_owner : 0;
-    for (const MDBX_reader *reader = begin; reader < end; ++reader) {
-      if (reader->mr_pid.weak != env->me_pid || !reader->mr_tid.weak) {
-      skip_lck:
-        continue;
-      }
-      if (reader->mr_tid.weak == CurrentTid ||
-          reader->mr_tid.weak == WriteTxnOwner)
-        goto skip_lck;
-
-      rc = suspend_and_append(array, (mdbx_tid_t)reader->mr_tid.weak);
-      if (rc != MDBX_SUCCESS) {
-      bailout_lck:
-        (void)mdbx_resume_threads_after_remap(*array);
-        return rc;
-      }
-    }
-    if (WriteTxnOwner && WriteTxnOwner != CurrentTid) {
-      rc = suspend_and_append(array, (mdbx_tid_t)WriteTxnOwner);
-      if (rc != MDBX_SUCCESS)
-        goto bailout_lck;
-    }
-  } else {
-    /* Without LCK (i.e. read-only mode).
-     * Walk through a snapshot of all running threads */
-    mdbx_assert(env, env->me_flags & (MDBX_EXCLUSIVE | MDBX_RDONLY));
-    const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
-    if (hSnapshot == INVALID_HANDLE_VALUE)
-      return (int)GetLastError();
-
-    THREADENTRY32 entry;
-    entry.dwSize = sizeof(THREADENTRY32);
-
-    if (!Thread32First(hSnapshot, &entry)) {
-      rc = (int)GetLastError();
-    bailout_toolhelp:
-      CloseHandle(hSnapshot);
-      (void)mdbx_resume_threads_after_remap(*array);
-      return rc;
-    }
-
-    do {
-      if (entry.th32OwnerProcessID != env->me_pid ||
-          entry.th32ThreadID == CurrentTid)
-        continue;
-
-      rc = suspend_and_append(array, entry.th32ThreadID);
-      if (rc != MDBX_SUCCESS)
-        goto bailout_toolhelp;
-
-    } while (Thread32Next(hSnapshot, &entry));
-
-    rc = (int)GetLastError();
-    if (rc != ERROR_NO_MORE_FILES)
-      goto bailout_toolhelp;
-    CloseHandle(hSnapshot);
-  }
-
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) {
-  int rc = MDBX_SUCCESS;
-  for (unsigned i = 0; i < array->count; ++i) {
-    const HANDLE hThread = array->handles[i];
-    if (ResumeThread(hThread) == (DWORD)-1) {
-      const int err = (int)GetLastError();
-      DWORD ExitCode;
-      if (err != /* workaround for Win10 UCRT bug */ ERROR_ACCESS_DENIED &&
-          GetExitCodeThread(hThread, &ExitCode) && ExitCode == STILL_ACTIVE)
-        rc = err;
-    }
-    CloseHandle(hThread);
-  }
-  return rc;
-}
-
-/*----------------------------------------------------------------------------*/
-/* global `initial` lock for lockfile initialization,
- * exclusive/shared locking first cacheline */
-
-/* Briefly description of locking schema/algorithm:
- *  - Windows does not support upgrading or downgrading for file locking.
- *  - Therefore upgrading/downgrading is emulated by shared and exclusive
- *    locking of upper and lower halves.
- *  - In other words, we have FSM with possible 9 states,
- *    i.e. free/shared/exclusive x free/shared/exclusive == 9.
- *    Only 6 states of FSM are used, which 2 of ones are transitive.
- *
- * States:
- *   ?-?  = free, i.e. unlocked
- *   S-?  = used, i.e. shared lock
- *   E-?  = exclusive-read, i.e. operational exclusive
- *   ?-S
- *   ?-E  = middle (transitive state)
- *   S-S
- *   S-E  = locked (transitive state)
- *   E-S
- *   E-E  = exclusive-write, i.e. exclusive due (re)initialization
- *
- *  The mdbx_lck_seize() moves the locking-FSM from the initial free/unlocked
- *  state to the "exclusive write" (and returns MDBX_RESULT_TRUE) if possible,
- *  or to the "used" (and returns MDBX_RESULT_FALSE).
- *
- *  The mdbx_lck_downgrade() moves the locking-FSM from "exclusive write"
- *  state to the "used" (i.e. shared) state.
- *
- *  The mdbx_lck_upgrade() moves the locking-FSM from "used" (i.e. shared)
- *  state to the "exclusive write" state.
- */
-
-static void lck_unlock(MDBX_env *env) {
-  int err;
-
-  if (env->me_lfd != INVALID_HANDLE_VALUE) {
-    /* double `unlock` for robustly remove overlapped shared/exclusive locks */
-    while (funlock(env->me_lfd, LCK_LOWER))
-      ;
-    err = (int)GetLastError();
-    assert(err == ERROR_NOT_LOCKED ||
-           (mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
-    (void)err;
-    SetLastError(ERROR_SUCCESS);
-
-    while (funlock(env->me_lfd, LCK_UPPER))
-      ;
-    err = (int)GetLastError();
-    assert(err == ERROR_NOT_LOCKED ||
-           (mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
-    (void)err;
-    SetLastError(ERROR_SUCCESS);
-  }
-
-  if (env->me_lazy_fd != INVALID_HANDLE_VALUE) {
-    /* explicitly unlock to avoid latency for other processes (windows kernel
-     * releases such locks via deferred queues) */
-    while (funlock(env->me_lazy_fd, LCK_BODY))
-      ;
-    err = (int)GetLastError();
-    assert(err == ERROR_NOT_LOCKED ||
-           (mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
-    (void)err;
-    SetLastError(ERROR_SUCCESS);
-
-    while (funlock(env->me_lazy_fd, LCK_WHOLE))
-      ;
-    err = (int)GetLastError();
-    assert(err == ERROR_NOT_LOCKED ||
-           (mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
-    (void)err;
-    SetLastError(ERROR_SUCCESS);
-  }
-}
-
-/* Seize state as 'exclusive-write' (E-E and returns MDBX_RESULT_TRUE)
- * or as 'used' (S-? and returns MDBX_RESULT_FALSE).
- * Otherwise returns an error. */
-static int internal_seize_lck(HANDLE lfd) {
-  int rc;
-  assert(lfd != INVALID_HANDLE_VALUE);
-
-  /* 1) now on ?-? (free), get ?-E (middle) */
-  mdbx_jitter4testing(false);
-  if (!flock(lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER)) {
-    rc = (int)GetLastError() /* 2) something went wrong, give up */;
-    mdbx_error("%s, err %u", "?-?(free) >> ?-E(middle)", rc);
-    return rc;
-  }
-
-  /* 3) now on ?-E (middle), try E-E (exclusive-write) */
-  mdbx_jitter4testing(false);
-  if (flock(lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER))
-    return MDBX_RESULT_TRUE /* 4) got E-E (exclusive-write), done */;
-
-  /* 5) still on ?-E (middle) */
-  rc = (int)GetLastError();
-  mdbx_jitter4testing(false);
-  if (rc != ERROR_SHARING_VIOLATION && rc != ERROR_LOCK_VIOLATION) {
-    /* 6) something went wrong, give up */
-    if (!funlock(lfd, LCK_UPPER))
-      mdbx_panic("%s(%s) failed: err %u", __func__, "?-E(middle) >> ?-?(free)",
-                 (int)GetLastError());
-    return rc;
-  }
-
-  /* 7) still on ?-E (middle), try S-E (locked) */
-  mdbx_jitter4testing(false);
-  rc = flock(lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER) ? MDBX_RESULT_FALSE
-                                                        : (int)GetLastError();
-
-  mdbx_jitter4testing(false);
-  if (rc != MDBX_RESULT_FALSE)
-    mdbx_error("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
-
-  /* 8) now on S-E (locked) or still on ?-E (middle),
-   *    transition to S-? (used) or ?-? (free) */
-  if (!funlock(lfd, LCK_UPPER))
-    mdbx_panic("%s(%s) failed: err %u", __func__,
-               "X-E(locked/middle) >> X-?(used/free)", (int)GetLastError());
-
-  /* 9) now on S-? (used, DONE) or ?-? (free, FAILURE) */
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
-  int rc;
-
-  assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
-  if (env->me_flags & MDBX_EXCLUSIVE)
-    return MDBX_RESULT_TRUE /* nope since files were must be opened
-                               non-shareable */
-        ;
-
-  if (env->me_lfd == INVALID_HANDLE_VALUE) {
-    /* LY: without-lck mode (e.g. on read-only filesystem) */
-    mdbx_jitter4testing(false);
-    if (!flock(env->me_lazy_fd, LCK_SHARED | LCK_DONTWAIT, LCK_WHOLE)) {
-      rc = (int)GetLastError();
-      mdbx_error("%s, err %u", "without-lck", rc);
-      return rc;
-    }
-    return MDBX_RESULT_FALSE;
-  }
-
-  rc = internal_seize_lck(env->me_lfd);
-  mdbx_jitter4testing(false);
-  if (rc == MDBX_RESULT_TRUE && (env->me_flags & MDBX_RDONLY) == 0) {
-    /* Check that another process don't operates in without-lck mode.
-     * Doing such check by exclusive locking the body-part of db. Should be
-     * noted:
-     *  - we need an exclusive lock for do so;
-     *  - we can't lock meta-pages, otherwise other process could get an error
-     *    while opening db in valid (non-conflict) mode. */
-    if (!flock(env->me_lazy_fd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_BODY)) {
-      rc = (int)GetLastError();
-      mdbx_error("%s, err %u", "lock-against-without-lck", rc);
-      mdbx_jitter4testing(false);
-      lck_unlock(env);
-    } else {
-      mdbx_jitter4testing(false);
-      if (!funlock(env->me_lazy_fd, LCK_BODY))
-        mdbx_panic("%s(%s) failed: err %u", __func__,
-                   "unlock-against-without-lck", (int)GetLastError());
-    }
-  }
-
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
-  /* Transite from exclusive-write state (E-E) to used (S-?) */
-  assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
-  assert(env->me_lfd != INVALID_HANDLE_VALUE);
-
-  if (env->me_flags & MDBX_EXCLUSIVE)
-    return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
-        ;
-  /* 1) now at E-E (exclusive-write), transition to ?_E (middle) */
-  if (!funlock(env->me_lfd, LCK_LOWER))
-    mdbx_panic("%s(%s) failed: err %u", __func__,
-               "E-E(exclusive-write) >> ?-E(middle)", (int)GetLastError());
-
-  /* 2) now at ?-E (middle), transition to S-E (locked) */
-  if (!flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER)) {
-    int rc = (int)GetLastError() /* 3) something went wrong, give up */;
-    mdbx_error("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
-    return rc;
-  }
-
-  /* 4) got S-E (locked), continue transition to S-? (used) */
-  if (!funlock(env->me_lfd, LCK_UPPER))
-    mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> S-?(used)",
-               (int)GetLastError());
-
-  return MDBX_SUCCESS /* 5) now at S-? (used), done */;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lck_upgrade(MDBX_env *env) {
-  /* Transite from used state (S-?) to exclusive-write (E-E) */
-  assert(env->me_lfd != INVALID_HANDLE_VALUE);
-
-  if (env->me_flags & MDBX_EXCLUSIVE)
-    return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
-        ;
-
-  int rc;
-  /* 1) now on S-? (used), try S-E (locked) */
-  mdbx_jitter4testing(false);
-  if (!flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_UPPER)) {
-    rc = (int)GetLastError() /* 2) something went wrong, give up */;
-    mdbx_verbose("%s, err %u", "S-?(used) >> S-E(locked)", rc);
-    return rc;
-  }
-
-  /* 3) now on S-E (locked), transition to ?-E (middle) */
-  if (!funlock(env->me_lfd, LCK_LOWER))
-    mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> ?-E(middle)",
-               (int)GetLastError());
-
-  /* 4) now on ?-E (middle), try E-E (exclusive-write) */
-  mdbx_jitter4testing(false);
-  if (!flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) {
-    rc = (int)GetLastError() /* 5) something went wrong, give up */;
-    mdbx_verbose("%s, err %u", "?-E(middle) >> E-E(exclusive-write)", rc);
-    return rc;
-  }
-
-  return MDBX_SUCCESS /* 6) now at E-E (exclusive-write), done */;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag) {
-  (void)env;
-  (void)inprocess_neighbor;
-  (void)global_uniqueness_flag;
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor) {
-  /* LY: should unmap before releasing the locks to avoid race condition and
-   * STATUS_USER_MAPPED_FILE/ERROR_USER_MAPPED_FILE */
-  if (env->me_map)
-    mdbx_munmap(&env->me_dxb_mmap);
-  if (env->me_lck_mmap.lck) {
-    const bool synced = env->me_lck_mmap.lck->mti_unsynced_pages.weak == 0;
-    mdbx_munmap(&env->me_lck_mmap);
-    if (synced && !inprocess_neighbor && env->me_lfd != INVALID_HANDLE_VALUE &&
-        mdbx_lck_upgrade(env) == MDBX_SUCCESS)
-      /* this will fail if LCK is used/mmapped by other process(es) */
-      mdbx_ftruncate(env->me_lfd, 0);
-  }
-  lck_unlock(env);
-  return MDBX_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------*/
-/* reader checking (by pid) */
-
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env) {
-  (void)env;
-  return MDBX_SUCCESS;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env) {
-  (void)env;
-  return MDBX_SUCCESS;
-}
-
-/* Checks reader by pid.
- *
- * Returns:
- *   MDBX_RESULT_TRUE, if pid is live (unable to acquire lock)
- *   MDBX_RESULT_FALSE, if pid is dead (lock acquired)
- *   or otherwise the errcode. */
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid) {
-  (void)env;
-  HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
-  int rc;
-  if (likely(hProcess)) {
-    rc = WaitForSingleObject(hProcess, 0);
-    if (unlikely(rc == (int)WAIT_FAILED))
-      rc = (int)GetLastError();
-    CloseHandle(hProcess);
-  } else {
-    rc = (int)GetLastError();
-  }
-
-  switch (rc) {
-  case ERROR_INVALID_PARAMETER:
-    /* pid seems invalid */
-    return MDBX_RESULT_FALSE;
-  case WAIT_OBJECT_0:
-    /* process just exited */
-    return MDBX_RESULT_FALSE;
-  case ERROR_ACCESS_DENIED:
-    /* The ERROR_ACCESS_DENIED would be returned for CSRSS-processes, etc.
-     * assume pid exists */
-    return MDBX_RESULT_TRUE;
-  case WAIT_TIMEOUT:
-    /* pid running */
-    return MDBX_RESULT_TRUE;
-  default:
-    /* failure */
-    return rc;
-  }
-}
-
-//----------------------------------------------------------------------------
-// Stub for slim read-write lock
-// Copyright (C) 1995-2002 Brad Wilson
-
-static void WINAPI stub_srwlock_Init(MDBX_srwlock *srwl) {
-  srwl->readerCount = srwl->writerCount = 0;
-}
-
-static void WINAPI stub_srwlock_AcquireShared(MDBX_srwlock *srwl) {
-  while (true) {
-    assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
-
-    //  If there's a writer already, spin without unnecessarily
-    //  interlocking the CPUs
-    if (srwl->writerCount != 0) {
-      YieldProcessor();
-      continue;
-    }
-
-    //  Add to the readers list
-    _InterlockedIncrement(&srwl->readerCount);
-
-    // Check for writers again (we may have been preempted). If
-    // there are no writers writing or waiting, then we're done.
-    if (srwl->writerCount == 0)
-      break;
-
-    // Remove from the readers list, spin, try again
-    _InterlockedDecrement(&srwl->readerCount);
-    YieldProcessor();
-  }
-}
-
-static void WINAPI stub_srwlock_ReleaseShared(MDBX_srwlock *srwl) {
-  assert(srwl->readerCount > 0);
-  _InterlockedDecrement(&srwl->readerCount);
-}
-
-static void WINAPI stub_srwlock_AcquireExclusive(MDBX_srwlock *srwl) {
-  while (true) {
-    assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
-
-    //  If there's a writer already, spin without unnecessarily
-    //  interlocking the CPUs
-    if (srwl->writerCount != 0) {
-      YieldProcessor();
-      continue;
-    }
-
-    // See if we can become the writer (expensive, because it inter-
-    // locks the CPUs, so writing should be an infrequent process)
-    if (_InterlockedExchange(&srwl->writerCount, 1) == 0)
-      break;
-  }
-
-  // Now we're the writer, but there may be outstanding readers.
-  // Spin until there aren't any more; new readers will wait now
-  // that we're the writer.
-  while (srwl->readerCount != 0) {
-    assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
-    YieldProcessor();
-  }
-}
-
-static void WINAPI stub_srwlock_ReleaseExclusive(MDBX_srwlock *srwl) {
-  assert(srwl->writerCount == 1 && srwl->readerCount >= 0);
-  srwl->writerCount = 0;
-}
-
-static uint64_t WINAPI stub_GetTickCount64(void) {
-  LARGE_INTEGER Counter, Frequency;
-  return (QueryPerformanceFrequency(&Frequency) &&
-          QueryPerformanceCounter(&Counter))
-             ? Counter.QuadPart * 1000ul / Frequency.QuadPart
-             : 0;
-}
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef xMDBX_ALLOY
-MDBX_srwlock_function mdbx_srwlock_Init, mdbx_srwlock_AcquireShared,
-    mdbx_srwlock_ReleaseShared, mdbx_srwlock_AcquireExclusive,
-    mdbx_srwlock_ReleaseExclusive;
-
-MDBX_NtExtendSection mdbx_NtExtendSection;
-MDBX_GetFileInformationByHandleEx mdbx_GetFileInformationByHandleEx;
-MDBX_GetVolumeInformationByHandleW mdbx_GetVolumeInformationByHandleW;
-MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-MDBX_SetFileInformationByHandle mdbx_SetFileInformationByHandle;
-MDBX_NtFsControlFile mdbx_NtFsControlFile;
-MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-MDBX_GetTickCount64 mdbx_GetTickCount64;
-MDBX_RegGetValueA mdbx_RegGetValueA;
-#endif /* xMDBX_ALLOY */
-
-#if __GNUC_PREREQ(8, 0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif /* GCC/MINGW */
-
-static void mdbx_winnt_import(void) {
-  const HINSTANCE hNtdll = GetModuleHandleA("ntdll.dll");
-
-#define GET_PROC_ADDR(dll, ENTRY)                                              \
-  mdbx_##ENTRY = (MDBX_##ENTRY)GetProcAddress(dll, #ENTRY)
-
-  if (GetProcAddress(hNtdll, "wine_get_version")) {
-    assert(mdbx_RunningUnderWine());
-  } else {
-    GET_PROC_ADDR(hNtdll, NtFsControlFile);
-    GET_PROC_ADDR(hNtdll, NtExtendSection);
-    assert(!mdbx_RunningUnderWine());
-  }
-
-  const HINSTANCE hKernel32dll = GetModuleHandleA("kernel32.dll");
-  GET_PROC_ADDR(hKernel32dll, GetFileInformationByHandleEx);
-  GET_PROC_ADDR(hKernel32dll, GetTickCount64);
-  if (!mdbx_GetTickCount64)
-    mdbx_GetTickCount64 = stub_GetTickCount64;
-  if (!mdbx_RunningUnderWine()) {
-    GET_PROC_ADDR(hKernel32dll, SetFileInformationByHandle);
-    GET_PROC_ADDR(hKernel32dll, GetVolumeInformationByHandleW);
-    GET_PROC_ADDR(hKernel32dll, GetFinalPathNameByHandleW);
-    GET_PROC_ADDR(hKernel32dll, PrefetchVirtualMemory);
-  }
-
-  const HINSTANCE hAdvapi32dll = GetModuleHandleA("advapi32.dll");
-  GET_PROC_ADDR(hAdvapi32dll, RegGetValueA);
-#undef GET_PROC_ADDR
-
-  const MDBX_srwlock_function init =
-      (MDBX_srwlock_function)GetProcAddress(hKernel32dll, "InitializeSRWLock");
-  if (init != NULL) {
-    mdbx_srwlock_Init = init;
-    mdbx_srwlock_AcquireShared = (MDBX_srwlock_function)GetProcAddress(
-        hKernel32dll, "AcquireSRWLockShared");
-    mdbx_srwlock_ReleaseShared = (MDBX_srwlock_function)GetProcAddress(
-        hKernel32dll, "ReleaseSRWLockShared");
-    mdbx_srwlock_AcquireExclusive = (MDBX_srwlock_function)GetProcAddress(
-        hKernel32dll, "AcquireSRWLockExclusive");
-    mdbx_srwlock_ReleaseExclusive = (MDBX_srwlock_function)GetProcAddress(
-        hKernel32dll, "ReleaseSRWLockExclusive");
-  } else {
-    mdbx_srwlock_Init = stub_srwlock_Init;
-    mdbx_srwlock_AcquireShared = stub_srwlock_AcquireShared;
-    mdbx_srwlock_ReleaseShared = stub_srwlock_ReleaseShared;
-    mdbx_srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive;
-    mdbx_srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive;
-  }
-}
-
-#if __GNUC_PREREQ(8, 0)
-#pragma GCC diagnostic pop
-#endif /* GCC/MINGW */
-
-#endif /* Windows LCK-implementation */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-#if !(defined(_WIN32) || defined(_WIN64)) /* !Windows LCK-implementation */
-
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-#include <sys/sem.h>
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-/*----------------------------------------------------------------------------*/
-/* global constructor/destructor */
-
-#if defined(__linux__) || defined(__gnu_linux__)
-
-#include <sys/utsname.h>
-
-#ifndef xMDBX_ALLOY
-uint32_t mdbx_linux_kernel_version;
-bool mdbx_RunningOnWSL1;
-#endif /* xMDBX_ALLOY */
-
-__cold static uint8_t probe_for_WSL(const char *tag) {
-  const char *const WSL = strstr(tag, "WSL");
-  if (WSL && WSL[3] >= '2' && WSL[3] <= '9')
-    return WSL[3] - '0';
-  const char *const wsl = strstr(tag, "wsl");
-  if (wsl && wsl[3] >= '2' && wsl[3] <= '9')
-    return wsl[3] - '0';
-  if (WSL || wsl || strcasestr(tag, "Microsoft"))
-    /* Expecting no new kernel within WSL1, either it will explicitly
-     * marked by an appropriate WSL-version hint. */
-    return (mdbx_linux_kernel_version < /* 4.19.x */ 0x04130000) ? 1 : 2;
-  return 0;
-}
-
-#endif /* Linux */
-
-__cold static __attribute__((__constructor__)) void
-mdbx_global_constructor(void) {
-#if defined(__linux__) || defined(__gnu_linux__)
-  struct utsname buffer;
-  if (uname(&buffer) == 0) {
-    int i = 0;
-    char *p = buffer.release;
-    while (*p && i < 4) {
-      if (*p >= '0' && *p <= '9') {
-        long number = strtol(p, &p, 10);
-        if (number > 0) {
-          if (number > 255)
-            number = 255;
-          mdbx_linux_kernel_version += number << (24 - i * 8);
-        }
-        ++i;
-      } else {
-        ++p;
-      }
-    }
-    /* "Official" way of detecting WSL1 but not WSL2
-     * https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
-     *
-     * WARNING: False negative detection of WSL1 will result in DATA LOSS!
-     * So, the REQUIREMENTS for this code:
-     *  1. MUST detect WSL1 without false-negatives.
-     *  2. DESIRABLE detect WSL2 but without the risk of violating the first. */
-    mdbx_RunningOnWSL1 = probe_for_WSL(buffer.version) == 1 ||
-                         probe_for_WSL(buffer.sysname) == 1 ||
-                         probe_for_WSL(buffer.release) == 1;
-  }
-#endif /* Linux */
-
-  mdbx_rthc_global_init();
-}
-
-__cold static __attribute__((__destructor__)) void
-mdbx_global_destructor(void) {
-  mdbx_rthc_global_dtor();
-}
-
-/*----------------------------------------------------------------------------*/
-/* lck */
-
-/* Описание реализации блокировок для POSIX & Linux:
- *
- * lck-файл отображается в память, в нём организуется таблица читателей и
- * размещаются совместно используемые posix-мьютексы (futex). Посредством
- * этих мьютексов (см struct MDBX_lockinfo) реализуются:
- *  - Блокировка таблицы читателей для регистрации,
- *    т.е. функции mdbx_rdt_lock() и mdbx_rdt_unlock().
- *  - Блокировка БД для пишущих транзакций,
- *    т.е. функции mdbx_txn_lock() и mdbx_txn_unlock().
- *
- * Остальной функционал реализуется отдельно посредством файловых блокировок:
- *  - Первоначальный захват БД в режиме exclusive/shared и последующий перевод
- *    в операционный режим, функции mdbx_lck_seize() и mdbx_lck_downgrade().
- *  - Проверка присутствие процессов-читателей,
- *    т.е. функции mdbx_rpid_set(), mdbx_rpid_clear() и mdbx_rpid_check().
- *
- * Для блокировки файлов используется fcntl(F_SETLK), так как:
- *  - lockf() оперирует только эксклюзивной блокировкой и требует
- *    открытия файла в RW-режиме.
- *  - flock() не гарантирует атомарности при смене блокировок
- *    и оперирует только всем файлом целиком.
- *  - Для контроля процессов-читателей используются однобайтовые
- *    range-блокировки lck-файла посредством fcntl(F_SETLK). При этом
- *    в качестве позиции используется pid процесса-читателя.
- *  - Для первоначального захвата и shared/exclusive выполняется блокировка
- *    основного файла БД и при успехе lck-файла.
- *
- * ----------------------------------------------------------------------------
- * УДЕРЖИВАЕМЫЕ БЛОКИРОВКИ В ЗАВИСИМОСТИ ОТ РЕЖИМА И СОСТОЯНИЯ
- *
- * Эксклюзивный режим без lck-файла:
- *   = заблокирован весь dxb-файл посредством F_RDLCK или F_WRLCK,
- *     в зависимости от MDBX_RDONLY.
- *
- * Не-операционный режим на время пере-инициализации и разрушении lck-файла:
- *   = F_WRLCK блокировка первого байта lck-файла, другие процессы ждут её
- *     снятия при получении F_RDLCK через F_SETLKW.
- *   - блокировки dxb-файла могут меняться до снятие эксклюзивной блокировки
- *    lck-файла:
- *       + для НЕ-эксклюзивного режима блокировка pid-байта в dxb-файле
- *         посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
- *       + для ЭКСКЛЮЗИВНОГО режима блокировка pid-байта всего dxb-файла
- *         посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
- *
- * ОПЕРАЦИОННЫЙ режим с lck-файлом:
- *   = F_RDLCK блокировка первого байта lck-файла, другие процессы не могут
- *     получить F_WRLCK и таким образом видят что БД используется.
- *   + F_WRLCK блокировка pid-байта в clk-файле после первой транзакции чтения.
- *   + для НЕ-эксклюзивного режима блокировка pid-байта в dxb-файле
- *     посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
- *   + для ЭКСКЛЮЗИВНОГО режима блокировка pid-байта всего dxb-файла
- *     посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
- */
-
-#if MDBX_USE_OFDLOCKS
-static int op_setlk, op_setlkw, op_getlk;
-__cold static void choice_fcntl() {
-  assert(!op_setlk && !op_setlkw && !op_getlk);
-  if ((mdbx_runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0
-#if defined(__linux__) || defined(__gnu_linux__)
-      && mdbx_linux_kernel_version >
-             0x030f0000 /* OFD locks are available since 3.15, but engages here
-                           only for 3.16 and later kernels (i.e. LTS) because
-                           of reliability reasons */
-#endif                  /* linux */
-  ) {
-    op_setlk = F_OFD_SETLK;
-    op_setlkw = F_OFD_SETLKW;
-    op_getlk = F_OFD_GETLK;
-    return;
-  }
-  op_setlk = F_SETLK;
-  op_setlkw = F_SETLKW;
-  op_getlk = F_GETLK;
-}
-#else
-#define op_setlk F_SETLK
-#define op_setlkw F_SETLKW
-#define op_getlk F_GETLK
-#endif /* MDBX_USE_OFDLOCKS */
-
-#ifndef OFF_T_MAX
-#define OFF_T_MAX                                                              \
-  (((sizeof(off_t) > 4) ? INT64_MAX : INT32_MAX) & ~(size_t)0xffff)
-#endif
-
-static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck,
-                  const off_t offset, off_t len) {
-  STATIC_ASSERT(sizeof(off_t) >= sizeof(void *) &&
-                sizeof(off_t) >= sizeof(size_t));
-#ifdef __ANDROID_API__
-  STATIC_ASSERT_MSG((sizeof(off_t) * 8 == MDBX_WORDBITS),
-                    "The bitness of system `off_t` type is mismatch. Please "
-                    "fix build and/or NDK configuration.");
-#endif /* Android */
-  mdbx_jitter4testing(true);
-  assert(offset >= 0 && len > 0);
-  assert((uint64_t)offset < (uint64_t)INT64_MAX &&
-         (uint64_t)len < (uint64_t)INT64_MAX &&
-         (uint64_t)(offset + len) > (uint64_t)offset);
-
-  assert((uint64_t)offset < (uint64_t)OFF_T_MAX &&
-         (uint64_t)len <= (uint64_t)OFF_T_MAX &&
-         (uint64_t)(offset + len) <= (uint64_t)OFF_T_MAX);
-
-  assert((uint64_t)((off_t)((uint64_t)offset + (uint64_t)len)) ==
-         ((uint64_t)offset + (uint64_t)len));
-  for (;;) {
-    struct flock lock_op;
-    STATIC_ASSERT(sizeof(off_t) <= sizeof(lock_op.l_start) &&
-                  sizeof(off_t) <= sizeof(lock_op.l_len) &&
-                  OFF_T_MAX == (off_t)OFF_T_MAX);
-    memset(&lock_op, 0, sizeof(lock_op));
-    lock_op.l_type = lck;
-    lock_op.l_whence = SEEK_SET;
-    lock_op.l_start = offset;
-    lock_op.l_len = len;
-    int rc = fcntl(fd, cmd, &lock_op);
-    mdbx_jitter4testing(true);
-    if (rc != -1) {
-      if (cmd == op_getlk) {
-        /* Checks reader by pid. Returns:
-         *   MDBX_RESULT_TRUE   - if pid is live (reader holds a lock).
-         *   MDBX_RESULT_FALSE  - if pid is dead (a lock could be placed). */
-        return (lock_op.l_type == F_UNLCK) ? MDBX_RESULT_FALSE
-                                           : MDBX_RESULT_TRUE;
-      }
-      return MDBX_SUCCESS;
-    }
-    rc = errno;
-#if MDBX_USE_OFDLOCKS
-    if (rc == EINVAL &&
-        (cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW || cmd == F_OFD_GETLK)) {
-      /* fallback to non-OFD locks */
-      if (cmd == F_OFD_SETLK)
-        cmd = F_SETLK;
-      else if (cmd == F_OFD_SETLKW)
-        cmd = F_SETLKW;
-      else
-        cmd = F_GETLK;
-      op_setlk = F_SETLK;
-      op_setlkw = F_SETLKW;
-      op_getlk = F_GETLK;
-      continue;
-    }
-#endif /* MDBX_USE_OFDLOCKS */
-    if (rc != EINTR || cmd == op_setlkw) {
-      assert(MDBX_IS_ERROR(rc));
-      return rc;
-    }
-  }
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
-#if MDBX_USE_OFDLOCKS
-  if (unlikely(op_setlk == 0))
-    choice_fcntl();
-#endif /* MDBX_USE_OFDLOCKS */
-  return lck_op(fd, wait ? op_setlkw : op_setlk, F_WRLCK, 0, OFF_T_MAX);
-}
-
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env) {
-  assert(env->me_lfd != INVALID_HANDLE_VALUE);
-  assert(env->me_pid > 0);
-  if (unlikely(mdbx_getpid() != env->me_pid))
-    return MDBX_PANIC;
-  return lck_op(env->me_lfd, op_setlk, F_WRLCK, env->me_pid, 1);
-}
-
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env) {
-  assert(env->me_lfd != INVALID_HANDLE_VALUE);
-  assert(env->me_pid > 0);
-  return lck_op(env->me_lfd, op_setlk, F_UNLCK, env->me_pid, 1);
-}
-
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid) {
-  assert(env->me_lfd != INVALID_HANDLE_VALUE);
-  assert(pid > 0);
-  return lck_op(env->me_lfd, op_getlk, F_WRLCK, pid, 1);
-}
-
-/*---------------------------------------------------------------------------*/
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc) {
-#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-  return sem_init(ipc, false, 1) ? errno : 0;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-  return pthread_mutex_init(ipc, nullptr);
-#else
-#error "FIXME"
-#endif
-}
-
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc) {
-#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-  return sem_destroy(ipc) ? errno : 0;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-  return pthread_mutex_destroy(ipc);
-#else
-#error "FIXME"
-#endif
-}
-#endif /* MDBX_LOCKING > MDBX_LOCKING_SYSV */
-
-static int check_fstat(MDBX_env *env) {
-  struct stat st;
-
-  int rc = MDBX_SUCCESS;
-  if (fstat(env->me_lazy_fd, &st)) {
-    rc = errno;
-    mdbx_error("fstat(%s), err %d", "DXB", rc);
-    return rc;
-  }
-
-  if (!S_ISREG(st.st_mode) || st.st_nlink < 1) {
-#ifdef EBADFD
-    rc = EBADFD;
-#else
-    rc = EPERM;
-#endif
-    mdbx_error("%s %s, err %d", "DXB",
-               (st.st_nlink < 1) ? "file was removed" : "not a regular file",
-               rc);
-    return rc;
-  }
-
-  if (st.st_size < (off_t)(MDBX_MIN_PAGESIZE * NUM_METAS)) {
-    mdbx_verbose("dxb-file is too short (%u), exclusive-lock needed",
-                 (unsigned)st.st_size);
-    rc = MDBX_RESULT_TRUE;
-  }
-
-  //----------------------------------------------------------------------------
-
-  if (fstat(env->me_lfd, &st)) {
-    rc = errno;
-    mdbx_error("fstat(%s), err %d", "LCK", rc);
-    return rc;
-  }
-
-  if (!S_ISREG(st.st_mode) || st.st_nlink < 1) {
-#ifdef EBADFD
-    rc = EBADFD;
-#else
-    rc = EPERM;
-#endif
-    mdbx_error("%s %s, err %d", "LCK",
-               (st.st_nlink < 1) ? "file was removed" : "not a regular file",
-               rc);
-    return rc;
-  }
-
-  /* Checking file size for detect the situation when we got the shared lock
-   * immediately after mdbx_lck_destroy(). */
-  if (st.st_size < (off_t)(sizeof(MDBX_lockinfo) + sizeof(MDBX_reader))) {
-    mdbx_verbose("lck-file is too short (%u), exclusive-lock needed",
-                 (unsigned)st.st_size);
-    rc = MDBX_RESULT_TRUE;
-  }
-
-  return rc;
-}
-
-__cold MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
-  assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
-  if (unlikely(mdbx_getpid() != env->me_pid))
-    return MDBX_PANIC;
-#if MDBX_USE_OFDLOCKS
-  if (unlikely(op_setlk == 0))
-    choice_fcntl();
-#endif /* MDBX_USE_OFDLOCKS */
-
-  int rc = MDBX_SUCCESS;
-#if defined(__linux__) || defined(__gnu_linux__)
-  if (unlikely(mdbx_RunningOnWSL1)) {
-    rc = ENOLCK /* No record locks available */;
-    mdbx_error("%s, err %u",
-               "WSL1 (Windows Subsystem for Linux) is mad and trouble-full, "
-               "injecting failure to avoid data loss",
-               rc);
-    return rc;
-  }
-#endif /* Linux */
-
-  if (env->me_lfd == INVALID_HANDLE_VALUE) {
-    /* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
-    rc =
-        lck_op(env->me_lazy_fd, op_setlk,
-               (env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
-    if (rc != MDBX_SUCCESS) {
-      mdbx_error("%s, err %u", "without-lck", rc);
-      mdbx_assert(env, MDBX_IS_ERROR(rc));
-      return rc;
-    }
-    return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
-  }
-#if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
-  sched_yield();
-#endif
-
-retry:
-  if (rc == MDBX_RESULT_TRUE) {
-    rc = lck_op(env->me_lfd, op_setlk, F_UNLCK, 0, 1);
-    if (rc != MDBX_SUCCESS) {
-      mdbx_error("%s, err %u", "unlock-before-retry", rc);
-      mdbx_assert(env, MDBX_IS_ERROR(rc));
-      return rc;
-    }
-  }
-
-  /* Firstly try to get exclusive locking.  */
-  rc = lck_op(env->me_lfd, op_setlk, F_WRLCK, 0, 1);
-  if (rc == MDBX_SUCCESS) {
-    rc = check_fstat(env);
-    if (MDBX_IS_ERROR(rc))
-      return rc;
-
-  continue_dxb_exclusive:
-    rc =
-        lck_op(env->me_lazy_fd, op_setlk,
-               (env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
-    if (rc == MDBX_SUCCESS)
-      return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
-
-    int err = check_fstat(env);
-    if (MDBX_IS_ERROR(err))
-      return err;
-
-    /* the cause may be a collision with POSIX's file-lock recovery. */
-    if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK ||
-          rc == EDEADLK)) {
-      mdbx_error("%s, err %u", "dxb-exclusive", rc);
-      mdbx_assert(env, MDBX_IS_ERROR(rc));
-      return rc;
-    }
-
-    /* Fallback to lck-shared */
-  } else if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY ||
-               rc == EWOULDBLOCK || rc == EDEADLK)) {
-    mdbx_error("%s, err %u", "try-exclusive", rc);
-    mdbx_assert(env, MDBX_IS_ERROR(rc));
-    return rc;
-  }
-
-  /* Here could be one of two:
-   *  - mdbx_lck_destroy() from the another process was hold the lock
-   *    during a destruction.
-   *  - either mdbx_lck_seize() from the another process was got the exclusive
-   *    lock and doing initialization.
-   * For distinguish these cases will use size of the lck-file later. */
-
-  /* Wait for lck-shared now. */
-  /* Here may be await during transient processes, for instance until another
-   * competing process doesn't call lck_downgrade(). */
-  rc = lck_op(env->me_lfd, op_setlkw, F_RDLCK, 0, 1);
-  if (rc != MDBX_SUCCESS) {
-    mdbx_error("%s, err %u", "try-shared", rc);
-    mdbx_assert(env, MDBX_IS_ERROR(rc));
-    return rc;
-  }
-
-  rc = check_fstat(env);
-  if (rc == MDBX_RESULT_TRUE)
-    goto retry;
-  if (rc != MDBX_SUCCESS) {
-    mdbx_error("%s, err %u", "lck_fstat", rc);
-    return rc;
-  }
-
-  /* got shared, retry exclusive */
-  rc = lck_op(env->me_lfd, op_setlk, F_WRLCK, 0, 1);
-  if (rc == MDBX_SUCCESS)
-    goto continue_dxb_exclusive;
-
-  if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK ||
-        rc == EDEADLK)) {
-    mdbx_error("%s, err %u", "try-exclusive", rc);
-    mdbx_assert(env, MDBX_IS_ERROR(rc));
-    return rc;
-  }
-
-  /* Lock against another process operating in without-lck or exclusive mode. */
-  rc =
-      lck_op(env->me_lazy_fd, op_setlk,
-             (env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, env->me_pid, 1);
-  if (rc != MDBX_SUCCESS) {
-    mdbx_error("%s, err %u", "lock-against-without-lck", rc);
-    mdbx_assert(env, MDBX_IS_ERROR(rc));
-    return rc;
-  }
-
-  /* Done: return with shared locking. */
-  return MDBX_RESULT_FALSE;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
-  assert(env->me_lfd != INVALID_HANDLE_VALUE);
-  if (unlikely(mdbx_getpid() != env->me_pid))
-    return MDBX_PANIC;
-
-  int rc = MDBX_SUCCESS;
-  if ((env->me_flags & MDBX_EXCLUSIVE) == 0) {
-    rc = lck_op(env->me_lazy_fd, op_setlk, F_UNLCK, 0, env->me_pid);
-    if (rc == MDBX_SUCCESS)
-      rc = lck_op(env->me_lazy_fd, op_setlk, F_UNLCK, env->me_pid + 1,
-                  OFF_T_MAX - env->me_pid - 1);
-  }
-  if (rc == MDBX_SUCCESS)
-    rc = lck_op(env->me_lfd, op_setlk, F_RDLCK, 0, 1);
-  if (unlikely(rc != 0)) {
-    mdbx_error("%s, err %u", "lck", rc);
-    assert(MDBX_IS_ERROR(rc));
-  }
-  return rc;
-}
-
-__cold MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                               MDBX_env *inprocess_neighbor) {
-  if (unlikely(mdbx_getpid() != env->me_pid))
-    return MDBX_PANIC;
-
-  int rc = MDBX_SUCCESS;
-  struct stat lck_info;
-  MDBX_lockinfo *lck = env->me_lck_mmap.lck;
-  if (env->me_lfd != INVALID_HANDLE_VALUE && !inprocess_neighbor && lck &&
-      /* try get exclusive access */
-      lck_op(env->me_lfd, op_setlk, F_WRLCK, 0, OFF_T_MAX) == 0 &&
-      /* if LCK was not removed */
-      fstat(env->me_lfd, &lck_info) == 0 && lck_info.st_nlink > 0 &&
-      lck_op(env->me_lazy_fd, op_setlk,
-             (env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0,
-             OFF_T_MAX) == 0) {
-
-    mdbx_verbose("%p got exclusive, drown locks", (void *)env);
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-    if (env->me_sysv_ipc.semid != -1)
-      rc = semctl(env->me_sysv_ipc.semid, 2, IPC_RMID) ? errno : 0;
-#else
-    rc = mdbx_ipclock_destroy(&lck->mti_rlock);
-    if (rc == 0)
-      rc = mdbx_ipclock_destroy(&lck->mti_wlock);
-#endif /* MDBX_LOCKING */
-
-    mdbx_assert(env, rc == 0);
-    if (rc == 0) {
-      const bool synced = lck->mti_unsynced_pages.weak == 0;
-      mdbx_munmap(&env->me_lck_mmap);
-      if (synced)
-        rc = ftruncate(env->me_lfd, 0) ? errno : 0;
-    }
-
-    mdbx_jitter4testing(false);
-  }
-
-  /* 1) POSIX's fcntl() locks (i.e. when op_setlk == F_SETLK) should be restored
-   * after file was closed.
-   *
-   * 2) File locks would be released (by kernel) while the file-descriptors will
-   * be closed. But to avoid false-positive EACCESS and EDEADLK from the kernel,
-   * locks should be released here explicitly with properly order. */
-
-  /* close dxb and restore lock */
-  if (env->me_dsync_fd != INVALID_HANDLE_VALUE) {
-    if (unlikely(close(env->me_dsync_fd) != 0) && rc == MDBX_SUCCESS)
-      rc = errno;
-    env->me_dsync_fd = INVALID_HANDLE_VALUE;
-  }
-  if (env->me_lazy_fd != INVALID_HANDLE_VALUE) {
-    if (unlikely(close(env->me_lazy_fd) != 0) && rc == MDBX_SUCCESS)
-      rc = errno;
-    env->me_lazy_fd = INVALID_HANDLE_VALUE;
-    if (op_setlk == F_SETLK && inprocess_neighbor && rc == MDBX_SUCCESS) {
-      /* restore file-lock */
-      rc = lck_op(
-          inprocess_neighbor->me_lazy_fd, F_SETLKW,
-          (inprocess_neighbor->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK,
-          (inprocess_neighbor->me_flags & MDBX_EXCLUSIVE)
-              ? 0
-              : inprocess_neighbor->me_pid,
-          (inprocess_neighbor->me_flags & MDBX_EXCLUSIVE) ? OFF_T_MAX : 1);
-    }
-  }
-
-  /* close clk and restore locks */
-  if (env->me_lfd != INVALID_HANDLE_VALUE) {
-    if (unlikely(close(env->me_lfd) != 0) && rc == MDBX_SUCCESS)
-      rc = errno;
-    env->me_lfd = INVALID_HANDLE_VALUE;
-    if (op_setlk == F_SETLK && inprocess_neighbor && rc == MDBX_SUCCESS) {
-      /* restore file-locks */
-      rc = lck_op(inprocess_neighbor->me_lfd, F_SETLKW, F_RDLCK, 0, 1);
-      if (rc == MDBX_SUCCESS && inprocess_neighbor->me_live_reader)
-        rc = mdbx_rpid_set(inprocess_neighbor);
-    }
-  }
-
-  if (inprocess_neighbor && rc != MDBX_SUCCESS)
-    inprocess_neighbor->me_flags |= MDBX_FATAL_ERROR;
-  return rc;
-}
-
-/*---------------------------------------------------------------------------*/
-
-__cold MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                            MDBX_env *inprocess_neighbor,
-                                            int global_uniqueness_flag) {
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  int semid = -1;
-  /* don't initialize semaphores twice */
-  (void)inprocess_neighbor;
-  if (global_uniqueness_flag == MDBX_RESULT_TRUE) {
-    struct stat st;
-    if (fstat(env->me_lazy_fd, &st))
-      return errno;
-  sysv_retry_create:
-    semid = semget(env->me_sysv_ipc.key, 2,
-                   IPC_CREAT | IPC_EXCL |
-                       (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)));
-    if (unlikely(semid == -1)) {
-      int err = errno;
-      if (err != EEXIST)
-        return err;
-
-      /* remove and re-create semaphore set */
-      semid = semget(env->me_sysv_ipc.key, 2, 0);
-      if (semid == -1) {
-        err = errno;
-        if (err != ENOENT)
-          return err;
-        goto sysv_retry_create;
-      }
-      if (semctl(semid, 2, IPC_RMID)) {
-        err = errno;
-        if (err != EIDRM)
-          return err;
-      }
-      goto sysv_retry_create;
-    }
-
-    unsigned short val_array[2] = {1, 1};
-    if (semctl(semid, 2, SETALL, val_array))
-      return errno;
-  } else {
-    semid = semget(env->me_sysv_ipc.key, 2, 0);
-    if (semid == -1)
-      return errno;
-
-    /* check read & write access */
-    struct semid_ds data[2];
-    if (semctl(semid, 2, IPC_STAT, data) || semctl(semid, 2, IPC_SET, data))
-      return errno;
-  }
-
-  env->me_sysv_ipc.semid = semid;
-  return MDBX_SUCCESS;
-
-#elif MDBX_LOCKING == MDBX_LOCKING_FUTEX
-  (void)inprocess_neighbor;
-  if (global_uniqueness_flag != MDBX_RESULT_TRUE)
-    return MDBX_SUCCESS;
-#error "FIXME: Not implemented"
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-
-  /* don't initialize semaphores twice */
-  (void)inprocess_neighbor;
-  if (global_uniqueness_flag == MDBX_RESULT_TRUE) {
-    if (sem_init(&env->me_lck_mmap.lck->mti_rlock, true, 1))
-      return errno;
-    if (sem_init(&env->me_lck_mmap.lck->mti_wlock, true, 1))
-      return errno;
-  }
-  return MDBX_SUCCESS;
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-  if (inprocess_neighbor)
-    return MDBX_SUCCESS /* don't need any initialization for mutexes
-      if LCK already opened/used inside current process */
-        ;
-
-    /* FIXME: Unfortunately, there is no other reliable way but to long testing
-     * on each platform. On the other hand, behavior like FreeBSD is incorrect
-     * and we can expect it to be rare. Moreover, even on FreeBSD without
-     * additional in-process initialization, the probability of an problem
-     * occurring is vanishingly small, and the symptom is a return of EINVAL
-     * while locking a mutex. In other words, in the worst case, the problem
-     * results in an EINVAL error at the start of the transaction, but NOT data
-     * loss, nor database corruption, nor other fatal troubles. Thus, the code
-     * below I am inclined to think the workaround for erroneous platforms (like
-     * FreeBSD), rather than a defect of libmdbx. */
-#if defined(__FreeBSD__)
-  /* seems that shared mutexes on FreeBSD required in-process initialization */
-  (void)global_uniqueness_flag;
-#else
-  /* shared mutexes on many other platforms (including Darwin and Linux's
-   * futexes) doesn't need any addition in-process initialization */
-  if (global_uniqueness_flag != MDBX_RESULT_TRUE)
-    return MDBX_SUCCESS;
-#endif
-
-  pthread_mutexattr_t ma;
-  int rc = pthread_mutexattr_init(&ma);
-  if (rc)
-    return rc;
-
-  rc = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
-  if (rc)
-    goto bailout;
-
-#if MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#if defined(PTHREAD_MUTEX_ROBUST) || defined(pthread_mutexattr_setrobust)
-  rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
-#elif defined(PTHREAD_MUTEX_ROBUST_NP) ||                                      \
-    defined(pthread_mutexattr_setrobust_np)
-  rc = pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);
-#elif _POSIX_THREAD_PROCESS_SHARED < 200809L
-  rc = pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);
-#else
-  rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
-#endif
-  if (rc)
-    goto bailout;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_POSIX2008 */
-
-#if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT >= 0 &&  \
-    !defined(MDBX_SAFE4QEMU)
-  rc = pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);
-  if (rc == ENOTSUP)
-    rc = pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_NONE);
-  if (rc && rc != ENOTSUP)
-    goto bailout;
-#endif /* PTHREAD_PRIO_INHERIT */
-
-  rc = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
-  if (rc && rc != ENOTSUP)
-    goto bailout;
-
-  rc = pthread_mutex_init(&env->me_lck_mmap.lck->mti_rlock, &ma);
-  if (rc)
-    goto bailout;
-  rc = pthread_mutex_init(&env->me_lck_mmap.lck->mti_wlock, &ma);
-
-bailout:
-  pthread_mutexattr_destroy(&ma);
-  return rc;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING > 0 */
-}
-
-__cold static int mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
-                                      const int err) {
-  int rc = err;
-#if MDBX_LOCKING == MDBX_LOCKING_POSIX2008 || MDBX_LOCKING == MDBX_LOCKING_SYSV
-  if (err == EOWNERDEAD) {
-    /* We own the mutex. Clean up after dead previous owner. */
-
-    const bool rlocked = ipc == &env->me_lck->mti_rlock;
-    rc = MDBX_SUCCESS;
-    if (!rlocked) {
-      if (unlikely(env->me_txn)) {
-        /* env is hosed if the dead thread was ours */
-        env->me_flags |= MDBX_FATAL_ERROR;
-        env->me_txn = NULL;
-        rc = MDBX_PANIC;
-      }
-    }
-    mdbx_warning("%clock owner died, %s", (rlocked ? 'r' : 'w'),
-                 (rc ? "this process' env is hosed" : "recovering"));
-
-    int check_rc = mdbx_cleanup_dead_readers(env, rlocked, NULL);
-    check_rc = (check_rc == MDBX_SUCCESS) ? MDBX_RESULT_TRUE : check_rc;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-    rc = (rc == MDBX_SUCCESS) ? check_rc : rc;
-#else
-#if defined(PTHREAD_MUTEX_ROBUST) || defined(pthread_mutex_consistent)
-    int mreco_rc = pthread_mutex_consistent(ipc);
-#elif defined(PTHREAD_MUTEX_ROBUST_NP) || defined(pthread_mutex_consistent_np)
-    int mreco_rc = pthread_mutex_consistent_np(ipc);
-#elif _POSIX_THREAD_PROCESS_SHARED < 200809L
-    int mreco_rc = pthread_mutex_consistent_np(ipc);
-#else
-    int mreco_rc = pthread_mutex_consistent(ipc);
-#endif
-    check_rc = (mreco_rc == 0) ? check_rc : mreco_rc;
-
-    if (unlikely(mreco_rc))
-      mdbx_error("lock recovery failed, %s", mdbx_strerror(mreco_rc));
-
-    rc = (rc == MDBX_SUCCESS) ? check_rc : rc;
-    if (MDBX_IS_ERROR(rc))
-      pthread_mutex_unlock(ipc);
-#endif /* MDBX_LOCKING == MDBX_LOCKING_POSIX2008 */
-    return rc;
-  }
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001
-  (void)ipc;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-  (void)ipc;
-#elif MDBX_LOCKING == MDBX_LOCKING_FUTEX
-#ifdef _MSC_VER
-#pragma message("warning: TODO")
-#else
-#warning "TODO"
-#endif
-  (void)ipc;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-  mdbx_error("mutex (un)lock failed, %s", mdbx_strerror(err));
-  if (rc != EDEADLK)
-    env->me_flags |= MDBX_FATAL_ERROR;
-  return rc;
-}
-
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void) {
-  /* avoid 32-bit Bionic bug/hang with 32-pit TID */
-  if (sizeof(pthread_mutex_t) < sizeof(pid_t) + sizeof(unsigned)) {
-    pid_t tid = gettid();
-    if (unlikely(tid > 0xffff)) {
-      mdbx_fatal("Raise the ENOSYS(%d) error to avoid hang due "
-                 "the 32-bit Bionic/Android bug with tid/thread_id 0x%08x(%i) "
-                 "that don’t fit in 16 bits, see "
-                 "https://android.googlesource.com/platform/bionic/+/master/"
-                 "docs/32-bit-abi.md#is-too-small-for-large-pids",
-                 ENOSYS, tid, tid);
-      return ENOSYS;
-    }
-  }
-  return 0;
-}
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-static int mdbx_ipclock_lock(MDBX_env *env, mdbx_ipclock_t *ipc,
-                             const bool dont_wait) {
-#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                  \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-  int rc = mdbx_check_tid4bionic();
-  if (likely(rc == 0))
-    rc = dont_wait ? pthread_mutex_trylock(ipc) : pthread_mutex_lock(ipc);
-  rc = (rc == EBUSY && dont_wait) ? MDBX_BUSY : rc;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-  int rc = MDBX_SUCCESS;
-  if (dont_wait) {
-    if (sem_trywait(ipc)) {
-      rc = errno;
-      if (rc == EAGAIN)
-        rc = MDBX_BUSY;
-    }
-  } else if (sem_wait(ipc))
-    rc = errno;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-  struct sembuf op = {.sem_num = (ipc != &env->me_lck->mti_wlock),
-                      .sem_op = -1,
-                      .sem_flg = dont_wait ? IPC_NOWAIT | SEM_UNDO : SEM_UNDO};
-  int rc;
-  if (semop(env->me_sysv_ipc.semid, &op, 1)) {
-    rc = errno;
-    if (dont_wait && rc == EAGAIN)
-      rc = MDBX_BUSY;
-  } else {
-    rc = *ipc ? EOWNERDEAD : MDBX_SUCCESS;
-    *ipc = env->me_pid;
-  }
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-  if (unlikely(rc != MDBX_SUCCESS && rc != MDBX_BUSY))
-    rc = mdbx_ipclock_failed(env, ipc, rc);
-  return rc;
-}
-
-static int mdbx_ipclock_unlock(MDBX_env *env, mdbx_ipclock_t *ipc) {
-#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                  \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-  int rc = pthread_mutex_unlock(ipc);
-  (void)env;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-  int rc = sem_post(ipc) ? errno : MDBX_SUCCESS;
-  (void)env;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-  if (unlikely(*ipc != (pid_t)env->me_pid))
-    return EPERM;
-  *ipc = 0;
-  struct sembuf op = {.sem_num = (ipc != &env->me_lck->mti_wlock),
-                      .sem_op = 1,
-                      .sem_flg = SEM_UNDO};
-  int rc = semop(env->me_sysv_ipc.semid, &op, 1) ? errno : MDBX_SUCCESS;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env) {
-  mdbx_trace("%s", ">>");
-  mdbx_jitter4testing(true);
-  int rc = mdbx_ipclock_lock(env, &env->me_lck->mti_rlock, false);
-  mdbx_trace("<< rc %d", rc);
-  return rc;
-}
-
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) {
-  mdbx_trace("%s", ">>");
-  int rc = mdbx_ipclock_unlock(env, &env->me_lck->mti_rlock);
-  mdbx_trace("<< rc %d", rc);
-  if (unlikely(rc != MDBX_SUCCESS))
-    mdbx_panic("%s() failed: err %d\n", __func__, rc);
-  mdbx_jitter4testing(true);
-}
-
-int mdbx_txn_lock(MDBX_env *env, bool dont_wait) {
-  mdbx_trace("%swait %s", dont_wait ? "dont-" : "", ">>");
-  mdbx_jitter4testing(true);
-  int rc = mdbx_ipclock_lock(env, &env->me_lck->mti_wlock, dont_wait);
-  mdbx_trace("<< rc %d", rc);
-  return MDBX_IS_ERROR(rc) ? rc : MDBX_SUCCESS;
-}
-
-void mdbx_txn_unlock(MDBX_env *env) {
-  mdbx_trace("%s", ">>");
-  int rc = mdbx_ipclock_unlock(env, &env->me_lck->mti_wlock);
-  mdbx_trace("<< rc %d", rc);
-  if (unlikely(rc != MDBX_SUCCESS))
-    mdbx_panic("%s() failed: err %d\n", __func__, rc);
-  mdbx_jitter4testing(true);
-}
-
-#else
-#ifdef _MSC_VER
-#pragma warning(disable : 4206) /* nonstandard extension used: translation     \
-                                   unit is empty */
-#endif                          /* _MSC_VER (warnings) */
-#endif                          /* !Windows LCK-implementation */
diff --git a/3rdparty/libmdbx/mdbx.c++ b/3rdparty/libmdbx/mdbx.c++
deleted file mode 100644
index b890b48b0c5654447382248b69c3c5d62f9239f0..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx.c++
+++ /dev/null
@@ -1,5202 +0,0 @@
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define xMDBX_ALLOY 1
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h++"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-//
-// Copyright (c) 2020-2022, Leonid Yuriev <leo@yuriev.ru>.
-// SPDX-License-Identifier: Apache-2.0
-//
-// Non-inline part of the libmdbx C++ API
-//
-
-#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-
-
-#include <array>
-#include <atomic>
-#include <cctype> // for isxdigit(), etc
-#include <system_error>
-
-namespace {
-
-#if 0 /* Unused for now */
-
-class trouble_location {
-
-#ifndef TROUBLE_PROVIDE_LINENO
-#define TROUBLE_PROVIDE_LINENO 1
-#endif
-
-#ifndef TROUBLE_PROVIDE_CONDITION
-#define TROUBLE_PROVIDE_CONDITION 1
-#endif
-
-#ifndef TROUBLE_PROVIDE_FUNCTION
-#define TROUBLE_PROVIDE_FUNCTION 1
-#endif
-
-#ifndef TROUBLE_PROVIDE_FILENAME
-#define TROUBLE_PROVIDE_FILENAME 1
-#endif
-
-#if TROUBLE_PROVIDE_LINENO
-  const unsigned line_;
-#endif
-#if TROUBLE_PROVIDE_CONDITION
-  const char *const condition_;
-#endif
-#if TROUBLE_PROVIDE_FUNCTION
-  const char *const function_;
-#endif
-#if TROUBLE_PROVIDE_FILENAME
-  const char *const filename_;
-#endif
-
-public:
-  MDBX_CXX11_CONSTEXPR trouble_location(unsigned line, const char *condition,
-                                   const char *function, const char *filename)
-      :
-#if TROUBLE_PROVIDE_LINENO
-        line_(line)
-#endif
-#if TROUBLE_PROVIDE_CONDITION
-        ,
-        condition_(condition)
-#endif
-#if TROUBLE_PROVIDE_FUNCTION
-        ,
-        function_(function)
-#endif
-#if TROUBLE_PROVIDE_FILENAME
-        ,
-        filename_(filename)
-#endif
-  {
-#if !TROUBLE_PROVIDE_LINENO
-    (void)line;
-#endif
-#if !TROUBLE_PROVIDE_CONDITION
-    (void)condition;
-#endif
-#if !TROUBLE_PROVIDE_FUNCTION
-    (void)function;
-#endif
-#if !TROUBLE_PROVIDE_FILENAME
-    (void)filename;
-#endif
-  }
-
-  trouble_location(const trouble_location &&) = delete;
-
-  unsigned line() const {
-#if TROUBLE_PROVIDE_LINENO
-    return line_;
-#else
-    return 0;
-#endif
-  }
-
-  const char *condition() const {
-#if TROUBLE_PROVIDE_CONDITION
-    return condition_;
-#else
-    return "";
-#endif
-  }
-
-  const char *function() const {
-#if TROUBLE_PROVIDE_FUNCTION
-    return function_;
-#else
-    return "";
-#endif
-  }
-
-  const char *filename() const {
-#if TROUBLE_PROVIDE_FILENAME
-    return filename_;
-#else
-    return "";
-#endif
-  }
-};
-
-//------------------------------------------------------------------------------
-
-__cold  std::string format_va(const char *fmt, va_list ap) {
-  va_list ones;
-  va_copy(ones, ap);
-#ifdef _MSC_VER
-  int needed = _vscprintf(fmt, ap);
-#else
-  int needed = vsnprintf(nullptr, 0, fmt, ap);
-#endif
-  assert(needed >= 0);
-  std::string result;
-  result.reserve(size_t(needed + 1));
-  result.resize(size_t(needed), '\0');
-  assert(int(result.capacity()) > needed);
-  int actual = vsnprintf(const_cast<char *>(result.data()), result.capacity(),
-                         fmt, ones);
-  assert(actual == needed);
-  (void)actual;
-  va_end(ones);
-  return result;
-}
-
-__cold  std::string format(const char *fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  std::string result = format_va(fmt, ap);
-  va_end(ap);
-  return result;
-}
-
-class bug : public std::runtime_error {
-  const trouble_location &location_;
-
-public:
-  bug(const trouble_location &) noexcept;
-  /* temporary workaround for "private field 'FOO' is not used" from CLANG
-   * and for "function 'BAR' was declared but never referenced" from LCC. */
-#ifndef __LCC__
-  const trouble_location &location() const noexcept { return location_; }
-#endif
-  virtual ~bug() noexcept;
-};
-
-__cold  bug::bug(const trouble_location &location) noexcept
-    : std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(),
-                                location.condition(), location.filename(),
-                                location.line())),
-      location_(location) {}
-
-__cold  bug::~bug() noexcept {}
-
-[[noreturn]] __cold  void raise_bug(const trouble_location &what_and_where) {
-  throw bug(what_and_where);
-}
-
-#define RAISE_BUG(line, condition, function, file)                             \
-  do {                                                                         \
-    static MDBX_CXX11_CONSTEXPR_VAR trouble_location bug(line, condition,      \
-                                                         function, file);      \
-    raise_bug(bug);                                                            \
-  } while (0)
-
-#define ENSURE(condition)                                                      \
-  do                                                                           \
-    if (MDBX_UNLIKELY(!(condition)))                                           \
-      MDBX_CXX20_UNLIKELY RAISE_BUG(__LINE__, #condition, __func__, __FILE__); \
-  while (0)
-
-#define NOT_IMPLEMENTED()                                                      \
-  RAISE_BUG(__LINE__, "not_implemented", __func__, __FILE__);
-
-#endif /* Unused*/
-
-//------------------------------------------------------------------------------
-
-template <typename PATH> struct path_to_pchar {
-  const std::string str;
-  path_to_pchar(const PATH &path) : str(path.generic_string()) {}
-  operator const char *() const { return str.c_str(); }
-};
-
-template <typename PATH>
-MDBX_MAYBE_UNUSED PATH pchar_to_path(const char *c_str) {
-  return PATH(c_str);
-}
-
-template <> struct path_to_pchar<std::string> {
-  const char *const ptr;
-  path_to_pchar(const std::string &path) : ptr(path.c_str()) {}
-  operator const char *() const { return ptr; }
-};
-
-#if defined(_WIN32) || defined(_WIN64)
-
-#ifndef WC_ERR_INVALID_CHARS
-static const DWORD WC_ERR_INVALID_CHARS =
-    (6 /* Windows Vista */ <= /* MajorVersion */ LOBYTE(LOWORD(GetVersion())))
-        ? 0x00000080
-        : 0;
-#endif /* WC_ERR_INVALID_CHARS */
-
-template <> struct path_to_pchar<std::wstring> {
-  std::string str;
-  path_to_pchar(const std::wstring &path) {
-    if (!path.empty()) {
-      const int chars =
-          WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(),
-                              int(path.size()), nullptr, 0, nullptr, nullptr);
-      if (chars == 0)
-        mdbx::error::throw_exception(GetLastError());
-      str.append(chars, '\0');
-      WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(),
-                          int(path.size()), const_cast<char *>(str.data()),
-                          chars, nullptr, nullptr);
-    }
-  }
-  operator const char *() const { return str.c_str(); }
-};
-
-template <>
-MDBX_MAYBE_UNUSED std::wstring pchar_to_path<std::wstring>(const char *c_str) {
-  std::wstring wstr;
-  if (c_str && *c_str) {
-    const int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
-                                          int(strlen(c_str)), nullptr, 0);
-    if (chars == 0)
-      mdbx::error::throw_exception(GetLastError());
-    wstr.append(chars, '\0');
-    MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
-                        int(strlen(c_str)), const_cast<wchar_t *>(wstr.data()),
-                        chars);
-  }
-  return wstr;
-}
-
-#endif /* Windows */
-
-} // namespace
-
-//------------------------------------------------------------------------------
-
-namespace mdbx {
-
-[[noreturn]] __cold void throw_max_length_exceeded() {
-  throw std::length_error(
-      "mdbx:: Exceeded the maximal length of data/slice/buffer.");
-}
-
-[[noreturn]] __cold void throw_too_small_target_buffer() {
-  throw std::length_error("mdbx:: The target buffer is too small.");
-}
-
-[[noreturn]] __cold void throw_out_range() {
-  throw std::out_of_range("mdbx:: Slice or buffer method was called with "
-                          "an argument that exceeds the length.");
-}
-
-[[noreturn]] __cold void throw_allocators_mismatch() {
-  throw std::logic_error(
-      "mdbx:: An allocators mismatch, so an object could not be transferred "
-      "into an incompatible memory allocation scheme.");
-}
-
-__cold exception::exception(const ::mdbx::error &error) noexcept
-    : base(error.what()), error_(error) {}
-
-__cold exception::~exception() noexcept {}
-
-static std::atomic_int fatal_countdown;
-
-__cold fatal::fatal(const ::mdbx::error &error) noexcept : base(error) {
-  ++fatal_countdown;
-}
-
-__cold fatal::~fatal() noexcept {
-  if (--fatal_countdown == 0)
-    std::terminate();
-}
-
-#define DEFINE_EXCEPTION(NAME)                                                 \
-  __cold NAME::NAME(const ::mdbx::error &rc) : exception(rc) {}                \
-  __cold NAME::~NAME() noexcept {}
-
-DEFINE_EXCEPTION(bad_map_id)
-DEFINE_EXCEPTION(bad_transaction)
-DEFINE_EXCEPTION(bad_value_size)
-DEFINE_EXCEPTION(db_corrupted)
-DEFINE_EXCEPTION(db_full)
-DEFINE_EXCEPTION(db_invalid)
-DEFINE_EXCEPTION(db_too_large)
-DEFINE_EXCEPTION(db_unable_extend)
-DEFINE_EXCEPTION(db_version_mismatch)
-DEFINE_EXCEPTION(db_wanna_write_for_recovery)
-DEFINE_EXCEPTION(incompatible_operation)
-DEFINE_EXCEPTION(internal_page_full)
-DEFINE_EXCEPTION(internal_problem)
-DEFINE_EXCEPTION(key_exists)
-DEFINE_EXCEPTION(key_mismatch)
-DEFINE_EXCEPTION(max_maps_reached)
-DEFINE_EXCEPTION(max_readers_reached)
-DEFINE_EXCEPTION(multivalue)
-DEFINE_EXCEPTION(no_data)
-DEFINE_EXCEPTION(not_found)
-DEFINE_EXCEPTION(operation_not_permitted)
-DEFINE_EXCEPTION(permission_denied_or_not_writeable)
-DEFINE_EXCEPTION(reader_slot_busy)
-DEFINE_EXCEPTION(remote_media)
-DEFINE_EXCEPTION(something_busy)
-DEFINE_EXCEPTION(thread_mismatch)
-DEFINE_EXCEPTION(transaction_full)
-DEFINE_EXCEPTION(transaction_overlapping)
-
-#undef DEFINE_EXCEPTION
-
-__cold const char *error::what() const noexcept {
-  if (is_mdbx_error())
-    return mdbx_liberr2str(code());
-
-  switch (code()) {
-#define ERROR_CASE(CODE)                                                       \
-  case CODE:                                                                   \
-    return MDBX_STRINGIFY(CODE)
-    ERROR_CASE(MDBX_ENODATA);
-    ERROR_CASE(MDBX_EINVAL);
-    ERROR_CASE(MDBX_EACCESS);
-    ERROR_CASE(MDBX_ENOMEM);
-    ERROR_CASE(MDBX_EROFS);
-    ERROR_CASE(MDBX_ENOSYS);
-    ERROR_CASE(MDBX_EIO);
-    ERROR_CASE(MDBX_EPERM);
-    ERROR_CASE(MDBX_EINTR);
-    ERROR_CASE(MDBX_ENOFILE);
-    ERROR_CASE(MDBX_EREMOTE);
-#undef ERROR_CASE
-  default:
-    return "SYSTEM";
-  }
-}
-
-__cold std::string error::message() const {
-  char buf[1024];
-  const char *msg = ::mdbx_strerror_r(code(), buf, sizeof(buf));
-  return std::string(msg ? msg : "unknown");
-}
-
-[[noreturn]] __cold void error::panic(const char *context,
-                                      const char *func) const noexcept {
-  assert(code() != MDBX_SUCCESS);
-  ::mdbx_panic("mdbx::%s.%s(): \"%s\" (%d)", context, func, what(), code());
-  std::terminate();
-}
-
-__cold void error::throw_exception() const {
-  switch (code()) {
-  case MDBX_EINVAL:
-    throw std::invalid_argument("mdbx");
-  case MDBX_ENOMEM:
-    throw std::bad_alloc();
-  case MDBX_SUCCESS:
-    static_assert(MDBX_SUCCESS == MDBX_RESULT_FALSE, "WTF?");
-    throw std::logic_error("MDBX_SUCCESS (MDBX_RESULT_FALSE)");
-  case MDBX_RESULT_TRUE:
-    throw std::logic_error("MDBX_RESULT_TRUE");
-#define CASE_EXCEPTION(NAME, CODE)                                             \
-  case CODE:                                                                   \
-    throw NAME(code())
-    CASE_EXCEPTION(bad_map_id, MDBX_BAD_DBI);
-    CASE_EXCEPTION(bad_transaction, MDBX_BAD_TXN);
-    CASE_EXCEPTION(bad_value_size, MDBX_BAD_VALSIZE);
-    CASE_EXCEPTION(db_corrupted, MDBX_CORRUPTED);
-    CASE_EXCEPTION(db_corrupted, MDBX_CURSOR_FULL); /* branch-pages loop */
-    CASE_EXCEPTION(db_corrupted, MDBX_PAGE_NOTFOUND);
-    CASE_EXCEPTION(db_full, MDBX_MAP_FULL);
-    CASE_EXCEPTION(db_invalid, MDBX_INVALID);
-    CASE_EXCEPTION(db_too_large, MDBX_TOO_LARGE);
-    CASE_EXCEPTION(db_unable_extend, MDBX_UNABLE_EXTEND_MAPSIZE);
-    CASE_EXCEPTION(db_version_mismatch, MDBX_VERSION_MISMATCH);
-    CASE_EXCEPTION(db_wanna_write_for_recovery, MDBX_WANNA_RECOVERY);
-    CASE_EXCEPTION(fatal, MDBX_EBADSIGN);
-    CASE_EXCEPTION(fatal, MDBX_PANIC);
-    CASE_EXCEPTION(incompatible_operation, MDBX_INCOMPATIBLE);
-    CASE_EXCEPTION(internal_page_full, MDBX_PAGE_FULL);
-    CASE_EXCEPTION(internal_problem, MDBX_PROBLEM);
-    CASE_EXCEPTION(key_mismatch, MDBX_EKEYMISMATCH);
-    CASE_EXCEPTION(max_maps_reached, MDBX_DBS_FULL);
-    CASE_EXCEPTION(max_readers_reached, MDBX_READERS_FULL);
-    CASE_EXCEPTION(multivalue, MDBX_EMULTIVAL);
-    CASE_EXCEPTION(no_data, MDBX_ENODATA);
-    CASE_EXCEPTION(not_found, MDBX_NOTFOUND);
-    CASE_EXCEPTION(operation_not_permitted, MDBX_EPERM);
-    CASE_EXCEPTION(permission_denied_or_not_writeable, MDBX_EACCESS);
-    CASE_EXCEPTION(reader_slot_busy, MDBX_BAD_RSLOT);
-    CASE_EXCEPTION(remote_media, MDBX_EREMOTE);
-    CASE_EXCEPTION(something_busy, MDBX_BUSY);
-    CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH);
-    CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL);
-    CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING);
-#undef CASE_EXCEPTION
-  default:
-    if (is_mdbx_error())
-      throw exception(*this);
-    throw std::system_error(std::error_code(code(), std::system_category()));
-  }
-}
-
-//------------------------------------------------------------------------------
-
-bool slice::is_printable(bool disable_utf8) const noexcept {
-  enum : byte {
-    LS = 4,                     // shift for UTF8 sequence length
-    P_ = 1 << LS,               // printable ASCII flag
-    N_ = 0,                     // non-printable ASCII
-    second_range_mask = P_ - 1, // mask for range flag
-    r80_BF = 0,                 // flag for UTF8 2nd byte range
-    rA0_BF = 1,                 // flag for UTF8 2nd byte range
-    r80_9F = 2,                 // flag for UTF8 2nd byte range
-    r90_BF = 3,                 // flag for UTF8 2nd byte range
-    r80_8F = 4,                 // flag for UTF8 2nd byte range
-
-    // valid utf-8 byte sequences
-    // http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94
-    //                        Code               | Bytes  |        |        |
-    //                        Points             | 1st    | 2nd    | 3rd    |4th
-    //                       --------------------|--------|--------|--------|---
-    C2 = 2 << LS | r80_BF, // U+000080..U+0007FF | C2..DF | 80..BF |        |
-    E0 = 3 << LS | rA0_BF, // U+000800..U+000FFF | E0     | A0..BF | 80..BF |
-    E1 = 3 << LS | r80_BF, // U+001000..U+00CFFF | E1..EC | 80..BF | 80..BF |
-    ED = 3 << LS | r80_9F, // U+00D000..U+00D7FF | ED     | 80..9F | 80..BF |
-    EE = 3 << LS | r80_BF, // U+00E000..U+00FFFF | EE..EF | 80..BF | 80..BF |
-    F0 = 4 << LS | r90_BF, // U+010000..U+03FFFF | F0     | 90..BF | 80..BF |...
-    F1 = 4 << LS | r80_BF, // U+040000..U+0FFFFF | F1..F3 | 80..BF | 80..BF |...
-    F4 = 4 << LS | r80_BF, // U+100000..U+10FFFF | F4     | 80..8F | 80..BF |...
-  };
-
-  static const byte range_from[] = {0x80, 0xA0, 0x80, 0x90, 0x80};
-  static const byte range_to[] = {0xBF, 0xBF, 0x9F, 0xBF, 0x8F};
-
-  static const byte map[256] = {
-      //  1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
-      N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, // 00
-      N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, // 10
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 20
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 30
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 40
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 50
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 60
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, // 70
-      N_, N_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, P_, N_, // 80
-      N_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, P_, P_, // 90
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // a0
-      P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // b0
-      P_, P_, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // c0
-      C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // df
-      E0, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, ED, EE, EE, // e0
-      F0, F1, F1, F1, F4, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_  // f0
-  };
-
-  if (MDBX_UNLIKELY(length() < 1))
-    MDBX_CXX20_UNLIKELY return false;
-
-  auto src = byte_ptr();
-  const auto end = src + length();
-  if (MDBX_UNLIKELY(disable_utf8)) {
-    do
-      if (MDBX_UNLIKELY((P_ & map[*src]) == 0))
-        MDBX_CXX20_UNLIKELY return false;
-    while (++src < end);
-    return true;
-  }
-
-  do {
-    const auto bits = map[*src];
-    const auto second_from = range_from[bits & second_range_mask];
-    const auto second_to = range_to[bits & second_range_mask];
-    switch (bits >> LS) {
-    default:
-      MDBX_CXX20_UNLIKELY return false;
-    case 1:
-      src += 1;
-      continue;
-    case 2:
-      if (MDBX_UNLIKELY(src + 1 >= end))
-        MDBX_CXX20_UNLIKELY return false;
-      if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
-        MDBX_CXX20_UNLIKELY return false;
-      src += 2;
-      continue;
-    case 3:
-      if (MDBX_UNLIKELY(src + 3 >= end))
-        MDBX_CXX20_UNLIKELY return false;
-      if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
-        MDBX_CXX20_UNLIKELY return false;
-      if (MDBX_UNLIKELY(src[2] < 0x80 || src[2] > 0xBF))
-        MDBX_CXX20_UNLIKELY return false;
-      src += 3;
-      continue;
-    case 4:
-      if (MDBX_UNLIKELY(src + 4 >= end))
-        MDBX_CXX20_UNLIKELY return false;
-      if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
-        MDBX_CXX20_UNLIKELY return false;
-      if (MDBX_UNLIKELY(src[2] < 0x80 || src[2] > 0xBF))
-        MDBX_CXX20_UNLIKELY return false;
-      if (MDBX_UNLIKELY(src[3] < 0x80 || src[3] > 0xBF))
-        MDBX_CXX20_UNLIKELY return false;
-      src += 4;
-      continue;
-    }
-  } while (src < end);
-
-  return true;
-}
-
-//------------------------------------------------------------------------------
-
-char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
-  if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
-    MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
-
-  auto ptr = dest;
-  auto src = source.byte_ptr();
-  const char alphabase = (uppercase ? 'A' : 'a') - 10;
-  auto line = ptr;
-  for (const auto end = source.end_byte_ptr(); src != end; ++src) {
-    if (wrap_width && size_t(ptr - line) >= wrap_width) {
-      *ptr = '\n';
-      line = ++ptr;
-    }
-    const int8_t hi = *src >> 4;
-    const int8_t lo = *src & 15;
-    ptr[0] = char(alphabase + hi + (((hi - 10) >> 7) & -7));
-    ptr[1] = char(alphabase + lo + (((lo - 10) >> 7) & -7));
-    ptr += 2;
-    assert(ptr <= dest + dest_size);
-  }
-  return ptr;
-}
-
-::std::ostream &to_hex::output(::std::ostream &out) const {
-  if (MDBX_LIKELY(!is_empty()))
-    MDBX_CXX20_LIKELY {
-      ::std::ostream::sentry sentry(out);
-      auto src = source.byte_ptr();
-      const char alphabase = (uppercase ? 'A' : 'a') - 10;
-      unsigned width = 0;
-      for (const auto end = source.end_byte_ptr(); src != end; ++src) {
-        if (wrap_width && width >= wrap_width) {
-          out << ::std::endl;
-          width = 0;
-        }
-        const int8_t hi = *src >> 4;
-        const int8_t lo = *src & 15;
-        out.put(char(alphabase + hi + (((hi - 10) >> 7) & -7)));
-        out.put(char(alphabase + lo + (((lo - 10) >> 7) & -7)));
-        width += 2;
-      }
-    }
-  return out;
-}
-
-char *from_hex::write_bytes(char *__restrict const dest,
-                            size_t dest_size) const {
-  if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
-    MDBX_CXX20_UNLIKELY throw std::domain_error(
-        "mdbx::from_hex:: odd length of hexadecimal string");
-  if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
-    MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
-
-  auto ptr = dest;
-  auto src = source.byte_ptr();
-  for (auto left = source.length(); left > 0;) {
-    if (MDBX_UNLIKELY(*src <= ' ') &&
-        MDBX_LIKELY(ignore_spaces && isspace(*src))) {
-      ++src;
-      --left;
-      continue;
-    }
-
-    if (MDBX_UNLIKELY(left < 1 || !isxdigit(src[0]) || !isxdigit(src[1])))
-      MDBX_CXX20_UNLIKELY throw std::domain_error(
-          "mdbx::from_hex:: invalid hexadecimal string");
-
-    int8_t hi = src[0];
-    hi = (hi | 0x20) - 'a';
-    hi += 10 + ((hi >> 7) & 7);
-
-    int8_t lo = src[1];
-    lo = (lo | 0x20) - 'a';
-    lo += 10 + ((lo >> 7) & 7);
-
-    *ptr++ = hi << 4 | lo;
-    src += 2;
-    left -= 2;
-    assert(ptr <= dest + dest_size);
-  }
-  return ptr;
-}
-
-bool from_hex::is_erroneous() const noexcept {
-  if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
-    MDBX_CXX20_UNLIKELY return true;
-
-  bool got = false;
-  auto src = source.byte_ptr();
-  for (auto left = source.length(); left > 0;) {
-    if (MDBX_UNLIKELY(*src <= ' ') &&
-        MDBX_LIKELY(ignore_spaces && isspace(*src))) {
-      ++src;
-      --left;
-      continue;
-    }
-
-    if (MDBX_UNLIKELY(left < 1 || !isxdigit(src[0]) || !isxdigit(src[1])))
-      MDBX_CXX20_UNLIKELY return true;
-
-    got = true;
-    src += 2;
-    left -= 2;
-  }
-  return !got;
-}
-
-//------------------------------------------------------------------------------
-
-enum : signed char {
-  OO /* ASCII NUL */ = -8,
-  EQ /* BASE64 '=' pad */ = -4,
-  SP /* SPACE */ = -2,
-  IL /* invalid */ = -1
-};
-
-static const byte b58_alphabet[58] = {
-    '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
-    'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-    'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
-    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
-
-#ifndef bswap64
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-static inline uint64_t bswap64(uint64_t v) noexcept {
-#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) ||                             \
-    __has_builtin(__builtin_bswap64)
-  return __builtin_bswap64(v);
-#elif defined(_MSC_VER) && !defined(__clang__)
-  return _byteswap_uint64(v);
-#elif defined(__bswap_64)
-  return __bswap_64(v);
-#elif defined(bswap_64)
-  return bswap_64(v);
-#else
-  return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) |
-         ((v << 24) & UINT64_C(0x0000ff0000000000)) |
-         ((v << 8) & UINT64_C(0x000000ff00000000)) |
-         ((v >> 8) & UINT64_C(0x00000000ff000000)) |
-         ((v >> 24) & UINT64_C(0x0000000000ff0000)) |
-         ((v >> 40) & UINT64_C(0x000000000000ff00));
-#endif
-}
-#endif /* __BYTE_ORDER__ */
-#endif /* ifndef bswap64 */
-
-static inline char b58_8to11(uint64_t &v) noexcept {
-  const unsigned i = unsigned(v % 58);
-  v /= 58;
-  return b58_alphabet[i];
-}
-
-char *to_base58::write_bytes(char *__restrict const dest,
-                             size_t dest_size) const {
-  if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
-    MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
-
-  auto ptr = dest;
-  auto src = source.byte_ptr();
-  size_t left = source.length();
-  auto line = ptr;
-  while (MDBX_LIKELY(left > 7)) {
-    uint64_t v;
-    std::memcpy(&v, src, 8);
-    src += 8;
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    v = bswap64(v);
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-    ptr[10] = b58_8to11(v);
-    ptr[9] = b58_8to11(v);
-    ptr[8] = b58_8to11(v);
-    ptr[7] = b58_8to11(v);
-    ptr[6] = b58_8to11(v);
-    ptr[5] = b58_8to11(v);
-    ptr[4] = b58_8to11(v);
-    ptr[3] = b58_8to11(v);
-    ptr[2] = b58_8to11(v);
-    ptr[1] = b58_8to11(v);
-    ptr[0] = b58_8to11(v);
-    assert(v == 0);
-    ptr += 11;
-    left -= 8;
-    if (wrap_width && size_t(ptr - line) >= wrap_width && left) {
-      *ptr = '\n';
-      line = ++ptr;
-    }
-    assert(ptr <= dest + dest_size);
-  }
-
-  if (left) {
-    uint64_t v = 0;
-    unsigned parrots = 31;
-    do {
-      v = (v << 8) + *src++;
-      parrots += 43;
-    } while (--left);
-
-    auto tail = ptr += parrots >> 5;
-    assert(ptr <= dest + dest_size);
-    do {
-      *--tail = b58_8to11(v);
-      parrots -= 32;
-    } while (parrots > 31);
-    assert(v == 0);
-  }
-
-  return ptr;
-}
-
-::std::ostream &to_base58::output(::std::ostream &out) const {
-  if (MDBX_LIKELY(!is_empty()))
-    MDBX_CXX20_LIKELY {
-      ::std::ostream::sentry sentry(out);
-      auto src = source.byte_ptr();
-      size_t left = source.length();
-      unsigned width = 0;
-      std::array<char, 11> buf;
-
-      while (MDBX_LIKELY(left > 7)) {
-        uint64_t v;
-        std::memcpy(&v, src, 8);
-        src += 8;
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-        v = bswap64(v);
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-        buf[10] = b58_8to11(v);
-        buf[9] = b58_8to11(v);
-        buf[8] = b58_8to11(v);
-        buf[7] = b58_8to11(v);
-        buf[6] = b58_8to11(v);
-        buf[5] = b58_8to11(v);
-        buf[4] = b58_8to11(v);
-        buf[3] = b58_8to11(v);
-        buf[2] = b58_8to11(v);
-        buf[1] = b58_8to11(v);
-        buf[0] = b58_8to11(v);
-        assert(v == 0);
-        out.write(&buf.front(), 11);
-        left -= 8;
-        if (wrap_width && (width += 11) >= wrap_width && left) {
-          out << ::std::endl;
-          width = 0;
-        }
-      }
-
-      if (left) {
-        uint64_t v = 0;
-        unsigned parrots = 31;
-        do {
-          v = (v << 8) + *src++;
-          parrots += 43;
-        } while (--left);
-
-        auto ptr = buf.end();
-        do {
-          *--ptr = b58_8to11(v);
-          parrots -= 32;
-        } while (parrots > 31);
-        assert(v == 0);
-        out.write(&*ptr, buf.end() - ptr);
-      }
-    }
-  return out;
-}
-
-const signed char b58_map[256] = {
-    //   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
-    OO, IL, IL, IL, IL, IL, IL, IL, IL, SP, SP, SP, SP, SP, IL, IL, // 00
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 10
-    SP, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 20
-    IL, 0,  1,  2,  3,  4,  5,  6,  7,  8,  IL, IL, IL, IL, IL, IL, // 30
-    IL, 9,  10, 11, 12, 13, 14, 15, 16, IL, 17, 18, 19, 20, 21, IL, // 40
-    22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, IL, IL, IL, IL, IL, // 50
-    IL, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, IL, 44, 45, 46, // 60
-    47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, IL, IL, IL, IL, IL, // 70
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 80
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 90
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // a0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // b0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // c0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // d0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // e0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL  // f0
-};
-
-static inline signed char b58_11to8(uint64_t &v, const byte c) noexcept {
-  const signed char m = b58_map[c];
-  v = v * 58 + m;
-  return m;
-}
-
-char *from_base58::write_bytes(char *__restrict const dest,
-                               size_t dest_size) const {
-  if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
-    MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
-
-  auto ptr = dest;
-  auto src = source.byte_ptr();
-  for (auto left = source.length(); left > 0;) {
-    if (MDBX_UNLIKELY(isspace(*src)) && ignore_spaces) {
-      ++src;
-      --left;
-      continue;
-    }
-
-    if (MDBX_LIKELY(left > 10)) {
-      uint64_t v = 0;
-      if (MDBX_UNLIKELY((b58_11to8(v, src[0]) | b58_11to8(v, src[1]) |
-                         b58_11to8(v, src[2]) | b58_11to8(v, src[3]) |
-                         b58_11to8(v, src[4]) | b58_11to8(v, src[5]) |
-                         b58_11to8(v, src[6]) | b58_11to8(v, src[7]) |
-                         b58_11to8(v, src[8]) | b58_11to8(v, src[9]) |
-                         b58_11to8(v, src[10])) < 0))
-        MDBX_CXX20_UNLIKELY goto bailout;
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-      v = bswap64(v);
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-      std::memcpy(ptr, &v, 8);
-      ptr += 8;
-      src += 11;
-      left -= 11;
-      assert(ptr <= dest + dest_size);
-      continue;
-    }
-
-    constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
-    if (MDBX_UNLIKELY(invalid_length_mask & (1 << left)))
-      MDBX_CXX20_UNLIKELY goto bailout;
-
-    uint64_t v = 1;
-    unsigned parrots = 0;
-    do {
-      if (MDBX_UNLIKELY(b58_11to8(v, *src++) < 0))
-        MDBX_CXX20_UNLIKELY goto bailout;
-      parrots += 32;
-    } while (--left);
-
-    auto tail = ptr += parrots / 43;
-    assert(ptr <= dest + dest_size);
-    do {
-      *--tail = byte(v);
-      v >>= 8;
-    } while (v > 255);
-    break;
-  }
-  return ptr;
-
-bailout:
-  throw std::domain_error("mdbx::from_base58:: invalid base58 string");
-}
-
-bool from_base58::is_erroneous() const noexcept {
-  bool got = false;
-  auto src = source.byte_ptr();
-  for (auto left = source.length(); left > 0;) {
-    if (MDBX_UNLIKELY(*src <= ' ') &&
-        MDBX_LIKELY(ignore_spaces && isspace(*src))) {
-      ++src;
-      --left;
-      continue;
-    }
-
-    if (MDBX_LIKELY(left > 10)) {
-      if (MDBX_UNLIKELY((b58_map[src[0]] | b58_map[src[1]] | b58_map[src[2]] |
-                         b58_map[src[3]] | b58_map[src[4]] | b58_map[src[5]] |
-                         b58_map[src[6]] | b58_map[src[7]] | b58_map[src[8]] |
-                         b58_map[src[9]] | b58_map[src[10]]) < 0))
-        MDBX_CXX20_UNLIKELY return true;
-      src += 11;
-      left -= 11;
-      got = true;
-      continue;
-    }
-
-    constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
-    if (invalid_length_mask & (1 << left))
-      return false;
-
-    do
-      if (MDBX_UNLIKELY(b58_map[*src++] < 0))
-        MDBX_CXX20_UNLIKELY return true;
-    while (--left);
-    got = true;
-    break;
-  }
-  return !got;
-}
-
-//------------------------------------------------------------------------------
-
-static inline void b64_3to4(const byte x, const byte y, const byte z,
-                            char *__restrict dest) noexcept {
-  static const byte alphabet[64] = {
-      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
-      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
-  dest[0] = alphabet[(x & 0xfc) >> 2];
-  dest[1] = alphabet[((x & 0x03) << 4) + ((y & 0xf0) >> 4)];
-  dest[2] = alphabet[((y & 0x0f) << 2) + ((z & 0xc0) >> 6)];
-  dest[3] = alphabet[z & 0x3f];
-}
-
-char *to_base64::write_bytes(char *__restrict const dest,
-                             size_t dest_size) const {
-  if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
-    MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
-
-  auto ptr = dest;
-  auto src = source.byte_ptr();
-  size_t left = source.length();
-  auto line = ptr;
-  while (true) {
-    switch (left) {
-    default:
-      MDBX_CXX20_LIKELY left -= 3;
-      b64_3to4(src[0], src[1], src[2], ptr);
-      ptr += 4;
-      src += 3;
-      if (wrap_width && size_t(ptr - line) >= wrap_width && left) {
-        *ptr = '\n';
-        line = ++ptr;
-      }
-      assert(ptr <= dest + dest_size);
-      continue;
-    case 2:
-      b64_3to4(src[0], src[1], 0, ptr);
-      ptr[3] = '=';
-      assert(ptr + 4 <= dest + dest_size);
-      return ptr + 4;
-    case 1:
-      b64_3to4(src[0], 0, 0, ptr);
-      ptr[2] = ptr[3] = '=';
-      assert(ptr + 4 <= dest + dest_size);
-      return ptr + 4;
-    case 0:
-      return ptr;
-    }
-  }
-}
-
-::std::ostream &to_base64::output(::std::ostream &out) const {
-  if (MDBX_LIKELY(!is_empty()))
-    MDBX_CXX20_LIKELY {
-      ::std::ostream::sentry sentry(out);
-      auto src = source.byte_ptr();
-      size_t left = source.length();
-      unsigned width = 0;
-      std::array<char, 4> buf;
-
-      while (true) {
-        switch (left) {
-        default:
-          MDBX_CXX20_LIKELY left -= 3;
-          b64_3to4(src[0], src[1], src[2], &buf.front());
-          src += 3;
-          out.write(&buf.front(), 4);
-          if (wrap_width && (width += 4) >= wrap_width && left) {
-            out << ::std::endl;
-            width = 0;
-          }
-          continue;
-        case 2:
-          b64_3to4(src[0], src[1], 0, &buf.front());
-          buf[3] = '=';
-          return out.write(&buf.front(), 4);
-        case 1:
-          b64_3to4(src[0], 0, 0, &buf.front());
-          buf[2] = buf[3] = '=';
-          return out.write(&buf.front(), 4);
-        case 0:
-          return out;
-        }
-      }
-    }
-  return out;
-}
-
-static const signed char b64_map[256] = {
-    //   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
-    OO, IL, IL, IL, IL, IL, IL, IL, IL, SP, SP, SP, SP, SP, IL, IL, // 00
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 10
-    SP, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, 62, IL, IL, IL, 63, // 20
-    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, IL, IL, IL, EQ, IL, IL, // 30
-    IL, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, // 40
-    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, IL, IL, IL, IL, IL, // 50
-    IL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60
-    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, IL, IL, IL, IL, IL, // 70
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 80
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 90
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // a0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // b0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // c0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // d0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // e0
-    IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL  // f0
-};
-
-static inline signed char b64_4to3(signed char a, signed char b, signed char c,
-                                   signed char d,
-                                   char *__restrict dest) noexcept {
-  dest[0] = byte((a << 2) + ((b & 0x30) >> 4));
-  dest[1] = byte(((b & 0xf) << 4) + ((c & 0x3c) >> 2));
-  dest[2] = byte(((c & 0x3) << 6) + d);
-  return a | b | c | d;
-}
-
-char *from_base64::write_bytes(char *__restrict const dest,
-                               size_t dest_size) const {
-  if (MDBX_UNLIKELY(source.length() % 4 && !ignore_spaces))
-    MDBX_CXX20_UNLIKELY throw std::domain_error(
-        "mdbx::from_base64:: odd length of base64 string");
-  if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
-    MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
-
-  auto ptr = dest;
-  auto src = source.byte_ptr();
-  for (auto left = source.length(); left > 0;) {
-    if (MDBX_UNLIKELY(*src <= ' ') &&
-        MDBX_LIKELY(ignore_spaces && isspace(*src))) {
-      ++src;
-      --left;
-      continue;
-    }
-
-    if (MDBX_UNLIKELY(left < 3))
-      MDBX_CXX20_UNLIKELY {
-      bailout:
-        throw std::domain_error("mdbx::from_base64:: invalid base64 string");
-      }
-    const signed char a = b64_map[src[0]], b = b64_map[src[1]],
-                      c = b64_map[src[2]], d = b64_map[src[3]];
-    if (MDBX_UNLIKELY(b64_4to3(a, b, c, d, ptr) < 0)) {
-      if (left == 4 && (a | b) >= 0 && d == EQ) {
-        if (c >= 0) {
-          assert(ptr + 2 <= dest + dest_size);
-          return ptr + 2;
-        }
-        if (c == d) {
-          assert(ptr + 1 <= dest + dest_size);
-          return ptr + 1;
-        }
-      }
-      MDBX_CXX20_UNLIKELY goto bailout;
-    }
-    src += 4;
-    left -= 4;
-    ptr += 3;
-    assert(ptr <= dest + dest_size);
-  }
-  return ptr;
-}
-
-bool from_base64::is_erroneous() const noexcept {
-  if (MDBX_UNLIKELY(source.length() % 4 && !ignore_spaces))
-    MDBX_CXX20_UNLIKELY return true;
-
-  bool got = false;
-  auto src = source.byte_ptr();
-  for (auto left = source.length(); left > 0;) {
-    if (MDBX_UNLIKELY(*src <= ' ') &&
-        MDBX_LIKELY(ignore_spaces && isspace(*src))) {
-      ++src;
-      --left;
-      continue;
-    }
-
-    if (MDBX_UNLIKELY(left < 3))
-      MDBX_CXX20_UNLIKELY return false;
-    const signed char a = b64_map[src[0]], b = b64_map[src[1]],
-                      c = b64_map[src[2]], d = b64_map[src[3]];
-    if (MDBX_UNLIKELY((a | b | c | d) < 0))
-      MDBX_CXX20_UNLIKELY {
-        if (left == 4 && (a | b) >= 0 && d == EQ && (c >= 0 || c == d))
-          return false;
-        return true;
-      }
-    got = true;
-    src += 4;
-    left -= 4;
-  }
-  return !got;
-}
-
-//------------------------------------------------------------------------------
-
-template class LIBMDBX_API_TYPE buffer<legacy_allocator>;
-
-#if defined(__cpp_lib_memory_resource) &&                                      \
-    __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI
-template class LIBMDBX_API_TYPE buffer<polymorphic_allocator>;
-#endif /* __cpp_lib_memory_resource >= 201603L */
-
-//------------------------------------------------------------------------------
-
-static inline MDBX_env_flags_t mode2flags(env::mode mode) {
-  switch (mode) {
-  default:
-    MDBX_CXX20_UNLIKELY throw std::invalid_argument("db::mode is invalid");
-  case env::mode::readonly:
-    return MDBX_RDONLY;
-  case env::mode::write_file_io:
-    return MDBX_ENV_DEFAULTS;
-  case env::mode::write_mapped_io:
-    return MDBX_WRITEMAP;
-  }
-}
-
-__cold MDBX_env_flags_t
-env::operate_parameters::make_flags(bool accede, bool use_subdirectory) const {
-  MDBX_env_flags_t flags = mode2flags(mode);
-  if (accede)
-    flags |= MDBX_ACCEDE;
-  if (!use_subdirectory)
-    flags |= MDBX_NOSUBDIR;
-  if (options.exclusive)
-    flags |= MDBX_EXCLUSIVE;
-  if (options.orphan_read_transactions)
-    flags |= MDBX_NOTLS;
-  if (options.disable_readahead)
-    flags |= MDBX_NORDAHEAD;
-  if (options.disable_clear_memory)
-    flags |= MDBX_NOMEMINIT;
-
-  if (mode != readonly) {
-    if (options.nested_write_transactions)
-      flags &= ~MDBX_WRITEMAP;
-    if (reclaiming.coalesce)
-      flags |= MDBX_COALESCE;
-    if (reclaiming.lifo)
-      flags |= MDBX_LIFORECLAIM;
-    switch (durability) {
-    default:
-      MDBX_CXX20_UNLIKELY throw std::invalid_argument(
-          "db::durability is invalid");
-    case env::durability::robust_synchronous:
-      break;
-    case env::durability::half_synchronous_weak_last:
-      flags |= MDBX_NOMETASYNC;
-      break;
-    case env::durability::lazy_weak_tail:
-      static_assert(MDBX_MAPASYNC == MDBX_SAFE_NOSYNC, "WTF? Obsolete C API?");
-      flags |= MDBX_SAFE_NOSYNC;
-      break;
-    case env::durability::whole_fragile:
-      flags |= MDBX_UTTERLY_NOSYNC;
-      break;
-    }
-  }
-  return flags;
-}
-
-env::mode
-env::operate_parameters::mode_from_flags(MDBX_env_flags_t flags) noexcept {
-  if (flags & MDBX_RDONLY)
-    return env::mode::readonly;
-  return (flags & MDBX_WRITEMAP) ? env::mode::write_mapped_io
-                                 : env::mode::write_file_io;
-}
-
-env::durability env::operate_parameters::durability_from_flags(
-    MDBX_env_flags_t flags) noexcept {
-  if ((flags & MDBX_UTTERLY_NOSYNC) == MDBX_UTTERLY_NOSYNC)
-    return env::durability::whole_fragile;
-  if (flags & MDBX_SAFE_NOSYNC)
-    return env::durability::lazy_weak_tail;
-  if (flags & MDBX_NOMETASYNC)
-    return env::durability::half_synchronous_weak_last;
-  return env::durability::robust_synchronous;
-}
-
-env::reclaiming_options::reclaiming_options(MDBX_env_flags_t flags) noexcept
-    : lifo((flags & MDBX_LIFORECLAIM) ? true : false),
-      coalesce((flags & MDBX_COALESCE) ? true : false) {}
-
-env::operate_options::operate_options(MDBX_env_flags_t flags) noexcept
-    : orphan_read_transactions(
-          ((flags & (MDBX_NOTLS | MDBX_EXCLUSIVE)) == MDBX_NOTLS) ? true
-                                                                  : false),
-      nested_write_transactions((flags & (MDBX_WRITEMAP | MDBX_RDONLY)) ? false
-                                                                        : true),
-      exclusive((flags & MDBX_EXCLUSIVE) ? true : false),
-      disable_readahead((flags & MDBX_NORDAHEAD) ? true : false),
-      disable_clear_memory((flags & MDBX_NOMEMINIT) ? true : false) {}
-
-bool env::is_pristine() const {
-  return get_stat().ms_mod_txnid == 0 &&
-         get_info().mi_recent_txnid == INITIAL_TXNID;
-}
-
-bool env::is_empty() const { return get_stat().ms_leaf_pages == 0; }
-
-#ifdef MDBX_STD_FILESYSTEM_PATH
-env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
-               bool force_dynamic_size) {
-  const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(destination);
-  error::success_or_throw(
-      ::mdbx_env_copy(handle_, utf8,
-                      (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
-                          (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
-                                              : MDBX_CP_DEFAULTS)));
-  return *this;
-}
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-
-#if defined(_WIN32) || defined(_WIN64)
-env &env::copy(const ::std::wstring &destination, bool compactify,
-               bool force_dynamic_size) {
-  const path_to_pchar<::std::wstring> utf8(destination);
-  error::success_or_throw(
-      ::mdbx_env_copy(handle_, utf8,
-                      (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
-                          (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
-                                              : MDBX_CP_DEFAULTS)));
-  return *this;
-}
-#endif /* Windows */
-
-env &env::copy(const ::std::string &destination, bool compactify,
-               bool force_dynamic_size) {
-  const path_to_pchar<::std::string> utf8(destination);
-  error::success_or_throw(
-      ::mdbx_env_copy(handle_, utf8,
-                      (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
-                          (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
-                                              : MDBX_CP_DEFAULTS)));
-  return *this;
-}
-
-env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
-  error::success_or_throw(
-      ::mdbx_env_copy2fd(handle_, fd,
-                         (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
-                             (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
-                                                 : MDBX_CP_DEFAULTS)));
-  return *this;
-}
-
-path env::get_path() const {
-  const char *c_str;
-  error::success_or_throw(::mdbx_env_get_path(handle_, &c_str));
-  return pchar_to_path<path>(c_str);
-}
-
-#ifdef MDBX_STD_FILESYSTEM_PATH
-bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
-                 const remove_mode mode) {
-  const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(pathname);
-  return error::boolean_or_throw(
-      ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode)));
-}
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-
-#if defined(_WIN32) || defined(_WIN64)
-bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
-  const path_to_pchar<::std::wstring> utf8(pathname);
-  return error::boolean_or_throw(
-      ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode)));
-}
-#endif /* Windows */
-
-bool env::remove(const ::std::string &pathname, const remove_mode mode) {
-  const path_to_pchar<::std::string> utf8(pathname);
-  return error::boolean_or_throw(
-      ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode)));
-}
-
-//------------------------------------------------------------------------------
-
-static inline MDBX_env *create_env() {
-  MDBX_env *ptr;
-  error::success_or_throw(::mdbx_env_create(&ptr));
-  assert(ptr != nullptr);
-  return ptr;
-}
-
-env_managed::~env_managed() noexcept {
-  if (MDBX_UNLIKELY(handle_))
-    MDBX_CXX20_UNLIKELY error::success_or_panic(
-        ::mdbx_env_close(handle_), "mdbx::~env()", "mdbx_env_close");
-}
-
-void env_managed::close(bool dont_sync) {
-  const error rc =
-      static_cast<MDBX_error_t>(::mdbx_env_close_ex(handle_, dont_sync));
-  switch (rc.code()) {
-  case MDBX_EBADSIGN:
-    MDBX_CXX20_UNLIKELY handle_ = nullptr;
-    __fallthrough /* fall through */;
-  default:
-    MDBX_CXX20_UNLIKELY rc.throw_exception();
-  case MDBX_SUCCESS:
-    MDBX_CXX20_LIKELY handle_ = nullptr;
-  }
-}
-
-__cold void env_managed::setup(unsigned max_maps, unsigned max_readers) {
-  if (max_readers > 0)
-    error::success_or_throw(::mdbx_env_set_maxreaders(handle_, max_readers));
-  if (max_maps > 0)
-    error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps));
-}
-
-#ifdef MDBX_STD_FILESYSTEM_PATH
-__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
-                                const operate_parameters &op, bool accede)
-    : env_managed(create_env()) {
-  setup(op.max_maps, op.max_readers);
-  const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(pathname);
-  error::success_or_throw(
-      ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0));
-
-  if (op.options.nested_write_transactions &&
-      !get_options().nested_write_transactions)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
-}
-
-__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
-                                const env_managed::create_parameters &cp,
-                                const env::operate_parameters &op, bool accede)
-    : env_managed(create_env()) {
-  setup(op.max_maps, op.max_readers);
-  const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(pathname);
-  set_geometry(cp.geometry);
-  error::success_or_throw(
-      ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory),
-                      cp.file_mode_bits));
-
-  if (op.options.nested_write_transactions &&
-      !get_options().nested_write_transactions)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
-}
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-
-#if defined(_WIN32) || defined(_WIN64)
-__cold env_managed::env_managed(const ::std::wstring &pathname,
-                                const operate_parameters &op, bool accede)
-    : env_managed(create_env()) {
-  setup(op.max_maps, op.max_readers);
-  const path_to_pchar<::std::wstring> utf8(pathname);
-  error::success_or_throw(
-      ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0));
-
-  if (op.options.nested_write_transactions &&
-      !get_options().nested_write_transactions)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
-}
-
-__cold env_managed::env_managed(const ::std::wstring &pathname,
-                                const env_managed::create_parameters &cp,
-                                const env::operate_parameters &op, bool accede)
-    : env_managed(create_env()) {
-  setup(op.max_maps, op.max_readers);
-  const path_to_pchar<::std::wstring> utf8(pathname);
-  set_geometry(cp.geometry);
-  error::success_or_throw(
-      ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory),
-                      cp.file_mode_bits));
-
-  if (op.options.nested_write_transactions &&
-      !get_options().nested_write_transactions)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
-}
-#endif /* Windows */
-
-__cold env_managed::env_managed(const ::std::string &pathname,
-                                const operate_parameters &op, bool accede)
-    : env_managed(create_env()) {
-  setup(op.max_maps, op.max_readers);
-  const path_to_pchar<::std::string> utf8(pathname);
-  error::success_or_throw(
-      ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0));
-
-  if (op.options.nested_write_transactions &&
-      !get_options().nested_write_transactions)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
-}
-
-__cold env_managed::env_managed(const ::std::string &pathname,
-                                const env_managed::create_parameters &cp,
-                                const env::operate_parameters &op, bool accede)
-    : env_managed(create_env()) {
-  setup(op.max_maps, op.max_readers);
-  const path_to_pchar<::std::string> utf8(pathname);
-  set_geometry(cp.geometry);
-  error::success_or_throw(
-      ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory),
-                      cp.file_mode_bits));
-
-  if (op.options.nested_write_transactions &&
-      !get_options().nested_write_transactions)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
-}
-
-//------------------------------------------------------------------------------
-
-txn_managed txn::start_nested() {
-  MDBX_txn *nested;
-  error::throw_on_nullptr(handle_, MDBX_BAD_TXN);
-  error::success_or_throw(::mdbx_txn_begin(mdbx_txn_env(handle_), handle_,
-                                           MDBX_TXN_READWRITE, &nested));
-  assert(nested != nullptr);
-  return txn_managed(nested);
-}
-
-txn_managed::~txn_managed() noexcept {
-  if (MDBX_UNLIKELY(handle_))
-    MDBX_CXX20_UNLIKELY error::success_or_panic(::mdbx_txn_abort(handle_),
-                                                "mdbx::~txn", "mdbx_txn_abort");
-}
-
-void txn_managed::abort() {
-  const error err = static_cast<MDBX_error_t>(::mdbx_txn_abort(handle_));
-  if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
-    MDBX_CXX20_LIKELY handle_ = nullptr;
-  if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
-    MDBX_CXX20_UNLIKELY err.throw_exception();
-}
-
-void txn_managed::commit() {
-  const error err = static_cast<MDBX_error_t>(::mdbx_txn_commit(handle_));
-  if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
-    MDBX_CXX20_LIKELY handle_ = nullptr;
-  if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
-    MDBX_CXX20_UNLIKELY err.throw_exception();
-}
-
-//------------------------------------------------------------------------------
-
-bool txn::drop_map(const char *name, bool throw_if_absent) {
-  map_handle map;
-  const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
-  switch (err) {
-  case MDBX_SUCCESS:
-    drop_map(map);
-    return true;
-  case MDBX_NOTFOUND:
-  case MDBX_BAD_DBI:
-    if (!throw_if_absent)
-      return false;
-    MDBX_CXX17_FALLTHROUGH /* fallthrough */;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-bool txn::clear_map(const char *name, bool throw_if_absent) {
-  map_handle map;
-  const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
-  switch (err) {
-  case MDBX_SUCCESS:
-    clear_map(map);
-    return true;
-  case MDBX_NOTFOUND:
-  case MDBX_BAD_DBI:
-    if (!throw_if_absent)
-      return false;
-    MDBX_CXX17_FALLTHROUGH /* fallthrough */;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-//------------------------------------------------------------------------------
-
-void cursor_managed::close() {
-  if (MDBX_UNLIKELY(!handle_))
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  ::mdbx_cursor_close(handle_);
-  handle_ = nullptr;
-}
-
-//------------------------------------------------------------------------------
-
-__cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) {
-  out << "{";
-  if (!it.is_valid())
-    out << "INVALID." << it.length();
-  else if (it.is_null())
-    out << "NULL";
-  else if (it.empty())
-    out << "EMPTY->" << it.data();
-  else {
-    const slice root(it.head(std::min(it.length(), size_t(64))));
-    out << it.length() << ".";
-    if (root.is_printable())
-      (out << "\"").write(root.char_ptr(), root.length()) << "\"";
-    else
-      out << root.encode_base58();
-    if (root.length() < it.length())
-      out << "...";
-  }
-  return out << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out, const pair &it) {
-  return out << "{" << it.key << " => " << it.value << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out, const pair_result &it) {
-  return out << "{" << (it.done ? "done: " : "non-done: ") << it.key << " => "
-             << it.value << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const ::mdbx::env::geometry::size &it) {
-  switch (it.bytes) {
-  case ::mdbx::env::geometry::default_value:
-    return out << "default";
-  case ::mdbx::env::geometry::minimal_value:
-    return out << "minimal";
-  case ::mdbx::env::geometry::maximal_value:
-    return out << "maximal";
-  }
-
-  const auto bytes = (it.bytes < 0) ? out << "-",
-             size_t(-it.bytes)      : size_t(it.bytes);
-  struct {
-    size_t one;
-    const char *suffix;
-  } static const scales[] = {
-#if MDBX_WORDBITS > 32
-    {env_managed::geometry::EiB, "EiB"},
-    {env_managed::geometry::EB, "EB"},
-    {env_managed::geometry::PiB, "PiB"},
-    {env_managed::geometry::PB, "PB"},
-    {env_managed::geometry::TiB, "TiB"},
-    {env_managed::geometry::TB, "TB"},
-#endif
-    {env_managed::geometry::GiB, "GiB"},
-    {env_managed::geometry::GB, "GB"},
-    {env_managed::geometry::MiB, "MiB"},
-    {env_managed::geometry::MB, "MB"},
-    {env_managed::geometry::KiB, "KiB"},
-    {env_managed::geometry::kB, "kB"},
-    {1, " bytes"}
-  };
-
-  for (const auto i : scales)
-    if (bytes % i.one == 0)
-      return out << bytes / i.one << i.suffix;
-
-  assert(false);
-  __unreachable();
-  return out;
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const env::geometry &it) {
-  return                                                                //
-      out << "\tlower " << env::geometry::size(it.size_lower)           //
-          << ",\n\tnow " << env::geometry::size(it.size_now)            //
-          << ",\n\tupper " << env::geometry::size(it.size_upper)        //
-          << ",\n\tgrowth " << env::geometry::size(it.growth_step)      //
-          << ",\n\tshrink " << env::geometry::size(it.shrink_threshold) //
-          << ",\n\tpagesize " << env::geometry::size(it.pagesize) << "\n";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const env::operate_parameters &it) {
-  return out << "{\n"                                 //
-             << "\tmax_maps " << it.max_maps          //
-             << ",\n\tmax_readers " << it.max_readers //
-             << ",\n\tmode " << it.mode               //
-             << ",\n\tdurability " << it.durability   //
-             << ",\n\treclaiming " << it.reclaiming   //
-             << ",\n\toptions " << it.options         //
-             << "\n}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out, const env::mode &it) {
-  switch (it) {
-  case env::mode::readonly:
-    return out << "readonly";
-  case env::mode::write_file_io:
-    return out << "write_file_io";
-  case env::mode::write_mapped_io:
-    return out << "write_mapped_io";
-  default:
-    return out << "mdbx::env::mode::invalid";
-  }
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const env::durability &it) {
-  switch (it) {
-  case env::durability::robust_synchronous:
-    return out << "robust_synchronous";
-  case env::durability::half_synchronous_weak_last:
-    return out << "half_synchronous_weak_last";
-  case env::durability::lazy_weak_tail:
-    return out << "lazy_weak_tail";
-  case env::durability::whole_fragile:
-    return out << "whole_fragile";
-  default:
-    return out << "mdbx::env::durability::invalid";
-  }
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const env::reclaiming_options &it) {
-  return out << "{"                                            //
-             << "lifo: " << (it.lifo ? "yes" : "no")           //
-             << ", coalesce: " << (it.coalesce ? "yes" : "no") //
-             << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const env::operate_options &it) {
-  static const char comma[] = ", ";
-  const char *delimiter = "";
-  out << "{";
-  if (it.orphan_read_transactions) {
-    out << delimiter << "orphan_read_transactions";
-    delimiter = comma;
-  }
-  if (it.nested_write_transactions) {
-    out << delimiter << "nested_write_transactions";
-    delimiter = comma;
-  }
-  if (it.exclusive) {
-    out << delimiter << "exclusive";
-    delimiter = comma;
-  }
-  if (it.disable_readahead) {
-    out << delimiter << "disable_readahead";
-    delimiter = comma;
-  }
-  if (it.disable_clear_memory) {
-    out << delimiter << "disable_clear_memory";
-    delimiter = comma;
-  }
-  if (delimiter != comma)
-    out << "default";
-  return out << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const env_managed::create_parameters &it) {
-  return out << "{\n"                                                        //
-             << "\tfile_mode " << std::oct << it.file_mode_bits << std::dec  //
-             << ",\n\tsubdirectory " << (it.use_subdirectory ? "yes" : "no") //
-             << ",\n"
-             << it.geometry << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const MDBX_log_level_t &it) {
-  switch (it) {
-  case MDBX_LOG_FATAL:
-    return out << "LOG_FATAL";
-  case MDBX_LOG_ERROR:
-    return out << "LOG_ERROR";
-  case MDBX_LOG_WARN:
-    return out << "LOG_WARN";
-  case MDBX_LOG_NOTICE:
-    return out << "LOG_NOTICE";
-  case MDBX_LOG_VERBOSE:
-    return out << "LOG_VERBOSE";
-  case MDBX_LOG_DEBUG:
-    return out << "LOG_DEBUG";
-  case MDBX_LOG_TRACE:
-    return out << "LOG_TRACE";
-  case MDBX_LOG_EXTRA:
-    return out << "LOG_EXTRA";
-  case MDBX_LOG_DONTCHANGE:
-    return out << "LOG_DONTCHANGE";
-  default:
-    return out << "mdbx::log_level::invalid";
-  }
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const MDBX_debug_flags_t &it) {
-  if (it == MDBX_DBG_DONTCHANGE)
-    return out << "DBG_DONTCHANGE";
-
-  static const char comma[] = "|";
-  const char *delimiter = "";
-  out << "{";
-  if (it & MDBX_DBG_ASSERT) {
-    out << delimiter << "DBG_ASSERT";
-    delimiter = comma;
-  }
-  if (it & MDBX_DBG_AUDIT) {
-    out << delimiter << "DBG_AUDIT";
-    delimiter = comma;
-  }
-  if (it & MDBX_DBG_JITTER) {
-    out << delimiter << "DBG_JITTER";
-    delimiter = comma;
-  }
-  if (it & MDBX_DBG_DUMP) {
-    out << delimiter << "DBG_DUMP";
-    delimiter = comma;
-  }
-  if (it & MDBX_DBG_LEGACY_MULTIOPEN) {
-    out << delimiter << "DBG_LEGACY_MULTIOPEN";
-    delimiter = comma;
-  }
-  if (it & MDBX_DBG_LEGACY_OVERLAP) {
-    out << delimiter << "DBG_LEGACY_OVERLAP";
-    delimiter = comma;
-  }
-  if (delimiter != comma)
-    out << "DBG_NONE";
-  return out << "}";
-}
-
-__cold ::std::ostream &operator<<(::std::ostream &out,
-                                  const ::mdbx::error &err) {
-  return out << err.what() << " (" << long(err.code()) << ")";
-}
-
-} // namespace mdbx
diff --git a/3rdparty/libmdbx/mdbx.h b/3rdparty/libmdbx/mdbx.h
deleted file mode 100644
index 2fc7e2de0ad17f646eece08e7189951da0a20a9f..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx.h
+++ /dev/null
@@ -1,5333 +0,0 @@
-/**
-
-_libmdbx_ is an extremely fast, compact, powerful, embedded,
-transactional [key-value
-store](https://en.wikipedia.org/wiki/Key-value_database) database, with
-[permissive license](./LICENSE). _MDBX_ has a specific set of properties and
-capabilities, focused on creating unique lightweight solutions with
-extraordinary performance.
-
-_libmdbx_ is superior to [LMDB](https://bit.ly/26ts7tL) in terms of features
-and reliability, not inferior in performance. In comparison to LMDB, _libmdbx_
-makes many things just work perfectly, not silently and catastrophically
-break down. _libmdbx_ supports Linux, Windows, MacOS, OSX, iOS, Android,
-FreeBSD, DragonFly, Solaris, OpenSolaris, OpenIndiana, NetBSD, OpenBSD and other
-systems compliant with POSIX.1-2008.
-
-The origin has been migrated to
-[GitFlic](https://gitflic.ru/project/erthink/libmdbx) since on 2022-04-15
-the Github administration, without any warning nor explanation, deleted libmdbx
-along with a lot of other projects, simultaneously blocking access for many
-developers. For the same reason ~~Github~~ is blacklisted forever.
-
-_The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет хорошо._
-
-
-\section copyright LICENSE & COPYRIGHT
-
-\authors Copyright (c) 2015-2022, Leonid Yuriev <leo@yuriev.ru>
-and other _libmdbx_ authors: please see [AUTHORS](./AUTHORS) file.
-
-\copyright Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP Public License.
-
-A copy of this license is available in the file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-<http://www.OpenLDAP.org/license.html>.
-
- ---
-
-This code is derived from "LMDB engine" written by
-Howard Chu (Symas Corporation), which itself derived from btree.c
-written by Martin Hedenfalk.
-
- ---
-
-Portions Copyright 2011-2015 Howard Chu, Symas Corp. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
-A copy of this license is available in the file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-<http://www.OpenLDAP.org/license.html>.
-
- ---
-
-Portions Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
-
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-*******************************************************************************/
-
-#pragma once
-#ifndef LIBMDBX_H
-#define LIBMDBX_H
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-/**
- \file mdbx.h
- \brief The libmdbx C API header file
-
- \defgroup c_api C API
- @{
- \defgroup c_err Error handling
- \defgroup c_opening Opening & Closing
- \defgroup c_transactions Transactions
- \defgroup c_dbi Databases
- \defgroup c_crud Create/Read/Update/Delete (see Quick Reference in details)
-
- \details
- \anchor c_crud_hints
-# Quick Reference for Insert/Update/Delete operations
-
-Historically, libmdbx inherits the API basis from LMDB, where it is often
-difficult to select flags/options and functions for the desired operation.
-So it is recommend using this hints.
-
-## Databases with UNIQUE keys
-
-In databases created without the \ref MDBX_DUPSORT option, keys are always
-unique. Thus always a single value corresponds to the each key, and so there
-are only a few cases of changing data.
-
-| Case                                        | Flags to use        | Result                 |
-|---------------------------------------------|---------------------|------------------------|
-| _INSERTING_|||
-|Key is absent → Insertion                    |\ref MDBX_NOOVERWRITE|Insertion               |
-|Key exist → Error since key present          |\ref MDBX_NOOVERWRITE|Error \ref MDBX_KEYEXIST and return Present value|
-| _UPSERTING_|||
-|Key is absent → Insertion                    |\ref MDBX_UPSERT     |Insertion               |
-|Key exist → Update                           |\ref MDBX_UPSERT     |Update                  |
-|  _UPDATING_|||
-|Key is absent → Error since no such key      |\ref MDBX_CURRENT    |Error \ref MDBX_NOTFOUND|
-|Key exist → Update                           |\ref MDBX_CURRENT    |Update value            |
-| _DELETING_|||
-|Key is absent → Error since no such key      |\ref mdbx_del() or \ref mdbx_replace()|Error \ref MDBX_NOTFOUND|
-|Key exist → Delete by key                    |\ref mdbx_del() with the parameter `data = NULL`|Deletion|
-|Key exist → Delete by key with with data matching check|\ref mdbx_del() with the parameter `data` filled with the value which should be match for deletion|Deletion or \ref MDBX_NOTFOUND if the value does not match|
-|Delete at the current cursor position        |\ref mdbx_cursor_del() with \ref MDBX_CURRENT flag|Deletion|
-|Extract (read & delete) value by the key     |\ref mdbx_replace() with zero flag and parameter `new_data = NULL`|Returning a deleted value|
-
-
-## Databases with NON-UNIQUE keys
-
-In databases created with the \ref MDBX_DUPSORT (Sorted Duplicates) option, keys
-may be non unique. Such non-unique keys in a key-value database may be treated
-as a duplicates or as like a multiple values corresponds to keys.
-
-
-| Case                                        | Flags to use        | Result                 |
-|---------------------------------------------|---------------------|------------------------|
-| _INSERTING_|||
-|Key is absent → Insertion                    |\ref MDBX_NOOVERWRITE|Insertion|
-|Key exist → Needn't to add new values        |\ref MDBX_NOOVERWRITE|Error \ref MDBX_KEYEXIST with returning the first value from those already present|
-| _UPSERTING_|||
-|Key is absent → Insertion                    |\ref MDBX_UPSERT     |Insertion|
-|Key exist → Wanna to add new values          |\ref MDBX_UPSERT     |Add one more value to the key|
-|Key exist → Replace all values with a new one|\ref MDBX_UPSERT + \ref MDBX_ALLDUPS|Overwrite by single new value|
-|  _UPDATING_|||
-|Key is absent → Error since no such key      |\ref MDBX_CURRENT    |Error \ref MDBX_NOTFOUND|
-|Key exist, Single value → Update             |\ref MDBX_CURRENT    |Update single value    |
-|Key exist, Multiple values → Replace all values with a new one|\ref MDBX_CURRENT + \ref MDBX_ALLDUPS|Overwrite by single new value|
-|Key exist, Multiple values → Error since it is unclear which of the values should be updated|\ref mdbx_put() with \ref MDBX_CURRENT|Error \ref MDBX_EMULTIVAL|
-|Key exist, Multiple values → Update particular entry of multi-value|\ref mdbx_replace() with \ref MDBX_CURRENT + \ref MDBX_NOOVERWRITE and the parameter `old_value` filled with the value that wanna to update|Update one multi-value entry|
-|Key exist, Multiple values → Update the current entry of multi-value|\ref mdbx_cursor_put() with \ref MDBX_CURRENT|Update one multi-value entry|
-| _DELETING_|||
-|Key is absent → Error since no such key      |\ref mdbx_del() or \ref mdbx_replace()|Error \ref MDBX_NOTFOUND|
-|Key exist → Delete all values corresponds given key|\ref mdbx_del() with the parameter `data = NULL`|Deletion|
-|Key exist → Delete particular value corresponds given key|\ref mdbx_del() with the parameter `data` filled with the value that wanna to delete, or \ref mdbx_replace() with \ref MDBX_CURRENT + \ref MDBX_NOOVERWRITE and the `old_value` parameter filled with the value that wanna to delete and `new_data = NULL`| Deletion or \ref MDBX_NOTFOUND if no such key-value pair|
-|Delete one value at the current cursor position|\ref mdbx_cursor_del() with \ref MDBX_CURRENT flag|Deletion only the current entry|
-|Delete all values of key at the current cursor position|\ref mdbx_cursor_del() with with \ref MDBX_ALLDUPS flag|Deletion all duplicates of key (all multi-values) at the current cursor position|
-
- \defgroup c_cursors Cursors
- \defgroup c_statinfo Statistics & Information
- \defgroup c_settings Settings
- \defgroup c_debug Logging and runtime debug
- \defgroup c_rqest Range query estimation
- \defgroup c_extra Extra operations
-*/
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#if !defined(NDEBUG) && !defined(assert)
-#include <assert.h>
-#endif /* NDEBUG */
-
-#if defined(_WIN32) || defined(_WIN64)
-#include <windows.h>
-#include <winnt.h>
-#ifndef __mode_t_defined
-typedef unsigned short mdbx_mode_t;
-#else
-typedef mode_t mdbx_mode_t;
-#endif /* __mode_t_defined */
-typedef HANDLE mdbx_filehandle_t;
-typedef DWORD mdbx_pid_t;
-typedef DWORD mdbx_tid_t;
-#else                  /* Windows */
-#include <errno.h>     /* for error codes */
-#include <pthread.h>   /* for pthread_t */
-#include <sys/types.h> /* for pid_t */
-#include <sys/uio.h>   /* for struct iovec */
-#define HAVE_STRUCT_IOVEC 1
-typedef int mdbx_filehandle_t;
-typedef pid_t mdbx_pid_t;
-typedef pthread_t mdbx_tid_t;
-typedef mode_t mdbx_mode_t;
-#endif /* !Windows */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-/** @} close c_api
- * \defgroup api_macros Common Macros
- * @{ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __has_attribute
-#define __has_attribute(x) (0)
-#endif /* __has_attribute */
-
-#ifndef __has_cpp_attribute
-#define __has_cpp_attribute(x) 0
-#endif /* __has_cpp_attribute */
-
-#ifndef __has_feature
-#define __has_feature(x) (0)
-#endif /* __has_feature */
-
-#ifndef __has_extension
-#define __has_extension(x) (0)
-#endif /* __has_extension */
-
-#ifndef __has_builtin
-#define __has_builtin(x) (0)
-#endif /* __has_builtin */
-
-/** Many functions have no effects except the return value and their
- * return value depends only on the parameters and/or global variables.
- * Such a function can be subject to common subexpression elimination
- * and loop optimization just as an arithmetic operator would be.
- * These functions should be declared with the attribute pure. */
-#if (defined(__GNUC__) || __has_attribute(__pure__)) &&                        \
-    (!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */     \
-     || !defined(__cplusplus) || !__has_feature(cxx_exceptions))
-#define MDBX_PURE_FUNCTION __attribute__((__pure__))
-#elif defined(_MSC_VER) && !defined(__clang__) && _MSC_VER >= 1920
-#define MDBX_PURE_FUNCTION
-#elif defined(__cplusplus) && __has_cpp_attribute(gnu::pure) &&                \
-    (!defined(__clang__) || !__has_feature(cxx_exceptions))
-#define MDBX_PURE_FUNCTION [[gnu::pure]]
-#else
-#define MDBX_PURE_FUNCTION
-#endif /* MDBX_PURE_FUNCTION */
-
-/** Like \ref MDBX_PURE_FUNCTION with addition `noexcept` restriction
- * that is compatible to CLANG and proposed [[pure]]. */
-#if defined(__GNUC__) ||                                                       \
-    (__has_attribute(__pure__) && __has_attribute(__nothrow__))
-#define MDBX_NOTHROW_PURE_FUNCTION __attribute__((__pure__, __nothrow__))
-#elif defined(_MSC_VER) && !defined(__clang__) && _MSC_VER >= 1920
-#if __has_cpp_attribute(pure)
-#define MDBX_NOTHROW_PURE_FUNCTION [[pure]]
-#else
-#define MDBX_NOTHROW_PURE_FUNCTION
-#endif
-#elif defined(__cplusplus) && __has_cpp_attribute(gnu::pure)
-#if __has_cpp_attribute(gnu::nothrow)
-#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::pure, gnu::nothrow]]
-#else
-#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::pure]]
-#endif
-#elif defined(__cplusplus) && __has_cpp_attribute(pure)
-#define MDBX_NOTHROW_PURE_FUNCTION [[pure]]
-#else
-#define MDBX_NOTHROW_PURE_FUNCTION
-#endif /* MDBX_NOTHROW_PURE_FUNCTION */
-
-/** Many functions do not examine any values except their arguments,
- * and have no effects except the return value. Basically this is just
- * slightly more strict class than the PURE attribute, since function
- * is not allowed to read global memory.
- *
- * Note that a function that has pointer arguments and examines the
- * data pointed to must not be declared const. Likewise, a function
- * that calls a non-const function usually must not be const.
- * It does not make sense for a const function to return void. */
-#if (defined(__GNUC__) || __has_attribute(__pure__)) &&                        \
-    (!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */     \
-     || !defined(__cplusplus) || !__has_feature(cxx_exceptions))
-#define MDBX_CONST_FUNCTION __attribute__((__const__))
-#elif defined(_MSC_VER) && !defined(__clang__) && _MSC_VER >= 1920
-#define MDBX_CONST_FUNCTION MDBX_PURE_FUNCTION
-#elif defined(__cplusplus) && __has_cpp_attribute(gnu::const) &&               \
-    (!defined(__clang__) || !__has_feature(cxx_exceptions))
-#define MDBX_CONST_FUNCTION [[gnu::const]]
-#else
-#define MDBX_CONST_FUNCTION MDBX_PURE_FUNCTION
-#endif /* MDBX_CONST_FUNCTION */
-
-/** Like \ref MDBX_CONST_FUNCTION with addition `noexcept` restriction
- * that is compatible to CLANG and future [[const]]. */
-#if defined(__GNUC__) ||                                                       \
-    (__has_attribute(__const__) && __has_attribute(__nothrow__))
-#define MDBX_NOTHROW_CONST_FUNCTION __attribute__((__const__, __nothrow__))
-#elif defined(_MSC_VER) && !defined(__clang__) && _MSC_VER >= 1920
-#define MDBX_NOTHROW_CONST_FUNCTION MDBX_NOTHROW_PURE_FUNCTION
-#elif defined(__cplusplus) && __has_cpp_attribute(gnu::const)
-#if __has_cpp_attribute(gnu::nothrow)
-#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::const, gnu::nothrow]]
-#else
-#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::const]]
-#endif
-#elif defined(__cplusplus) && __has_cpp_attribute(const)
-#define MDBX_NOTHROW_CONST_FUNCTION [[const]]
-#else
-#define MDBX_NOTHROW_CONST_FUNCTION MDBX_NOTHROW_PURE_FUNCTION
-#endif /* MDBX_NOTHROW_CONST_FUNCTION */
-
-#ifndef MDBX_DEPRECATED /* may be predefined to avoid warnings "deprecated" */
-#ifdef __deprecated
-#define MDBX_DEPRECATED __deprecated
-#elif defined(__GNUC__) || __has_attribute(__deprecated__)
-#define MDBX_DEPRECATED __attribute__((__deprecated__))
-#elif defined(_MSC_VER)
-#define MDBX_DEPRECATED __declspec(deprecated)
-#else
-#define MDBX_DEPRECATED
-#endif
-#endif /* MDBX_DEPRECATED */
-
-#ifndef __dll_export
-#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) ||               \
-    defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
-#if defined(__GNUC__) || __has_attribute(__dllexport__)
-#define __dll_export __attribute__((__dllexport__))
-#elif defined(_MSC_VER)
-#define __dll_export __declspec(dllexport)
-#else
-#define __dll_export
-#endif
-#elif defined(__GNUC__) || __has_attribute(__visibility__)
-#define __dll_export __attribute__((__visibility__("default")))
-#else
-#define __dll_export
-#endif
-#endif /* __dll_export */
-
-#ifndef __dll_import
-#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) ||               \
-    defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
-#if defined(__GNUC__) || __has_attribute(__dllimport__)
-#define __dll_import __attribute__((__dllimport__))
-#elif defined(_MSC_VER)
-#define __dll_import __declspec(dllimport)
-#else
-#define __dll_import
-#endif
-#else
-#define __dll_import
-#endif
-#endif /* __dll_import */
-
-/** \brief Auxiliary macro for robustly define the both inline version of API
- * function and non-inline fallback dll-exported version for applications linked
- * with old version of libmdbx, with a strictly ODR-common implementation. */
-#if defined(LIBMDBX_INTERNALS) && !defined(LIBMDBX_NO_EXPORTS_LEGACY_API)
-#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS)                                   \
-  /* proto of exported which uses common impl */ LIBMDBX_API TYPE NAME ARGS;   \
-  /* definition of common impl */ static __inline TYPE __inline_##NAME ARGS
-#else
-#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS) static __inline TYPE NAME ARGS
-#endif /* LIBMDBX_INLINE_API */
-
-/** \brief Converts a macro argument into a string constant. */
-#ifndef MDBX_STRINGIFY
-#define MDBX_STRINGIFY_HELPER(x) #x
-#define MDBX_STRINGIFY(x) MDBX_STRINGIFY_HELPER(x)
-#endif /* MDBX_STRINGIFY */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __cplusplus
-#ifndef bool
-#define bool _Bool
-#endif
-#ifndef true
-#define true (1)
-#endif
-#ifndef false
-#define false (0)
-#endif
-#endif /* bool without __cplusplus */
-
-#if !defined(DOXYGEN) && (!defined(__cpp_noexcept_function_type) ||            \
-                          __cpp_noexcept_function_type < 201510L)
-#define MDBX_CXX17_NOEXCEPT
-#else
-#define MDBX_CXX17_NOEXCEPT noexcept
-#endif /* MDBX_CXX17_NOEXCEPT */
-
-/* Workaround for old compilers without properly support for constexpr. */
-#if !defined(__cplusplus)
-#define MDBX_CXX01_CONSTEXPR __inline
-#define MDBX_CXX01_CONSTEXPR_VAR const
-#elif !defined(DOXYGEN) &&                                                     \
-    ((__cplusplus < 201103L && defined(__cpp_constexpr) &&                     \
-      __cpp_constexpr < 200704L) ||                                            \
-     (defined(__LCC__) && __LCC__ < 124) ||                                    \
-     (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 407) &&          \
-      !defined(__clang__) && !defined(__LCC__)) ||                             \
-     (defined(_MSC_VER) && _MSC_VER < 1910) ||                                 \
-     (defined(__clang__) && __clang_major__ < 4))
-#define MDBX_CXX01_CONSTEXPR inline
-#define MDBX_CXX01_CONSTEXPR_VAR const
-#else
-#define MDBX_CXX01_CONSTEXPR constexpr
-#define MDBX_CXX01_CONSTEXPR_VAR constexpr
-#endif /* MDBX_CXX01_CONSTEXPR */
-
-#if !defined(__cplusplus)
-#define MDBX_CXX11_CONSTEXPR __inline
-#define MDBX_CXX11_CONSTEXPR_VAR const
-#elif !defined(DOXYGEN) &&                                                     \
-    (!defined(__cpp_constexpr) || __cpp_constexpr < 201304L ||                 \
-     (defined(__LCC__) && __LCC__ < 124) ||                                    \
-     (defined(__GNUC__) && __GNUC__ < 6 && !defined(__clang__) &&              \
-      !defined(__LCC__)) ||                                                    \
-     (defined(_MSC_VER) && _MSC_VER < 1910) ||                                 \
-     (defined(__clang__) && __clang_major__ < 5))
-#define MDBX_CXX11_CONSTEXPR inline
-#define MDBX_CXX11_CONSTEXPR_VAR const
-#else
-#define MDBX_CXX11_CONSTEXPR constexpr
-#define MDBX_CXX11_CONSTEXPR_VAR constexpr
-#endif /* MDBX_CXX11_CONSTEXPR */
-
-#if !defined(__cplusplus)
-#define MDBX_CXX14_CONSTEXPR __inline
-#define MDBX_CXX14_CONSTEXPR_VAR const
-#elif defined(DOXYGEN) ||                                                      \
-    defined(__cpp_constexpr) && __cpp_constexpr >= 201304L &&                  \
-        ((defined(_MSC_VER) && _MSC_VER >= 1910) ||                            \
-         (defined(__clang__) && __clang_major__ > 4) ||                        \
-         (defined(__GNUC__) && __GNUC__ > 6) ||                                \
-         (!defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER)))
-#define MDBX_CXX14_CONSTEXPR constexpr
-#define MDBX_CXX14_CONSTEXPR_VAR constexpr
-#else
-#define MDBX_CXX14_CONSTEXPR inline
-#define MDBX_CXX14_CONSTEXPR_VAR const
-#endif /* MDBX_CXX14_CONSTEXPR */
-
-#if defined(__noreturn)
-#define MDBX_NORETURN __noreturn
-#elif defined(_Noreturn)
-#define MDBX_NORETURN _Noreturn
-#elif defined(__GNUC__) || __has_attribute(__noreturn__)
-#define MDBX_NORETURN __attribute__((__noreturn__))
-#elif defined(_MSC_VER) && !defined(__clang__)
-#define MDBX_NORETURN __declspec(noreturn)
-#else
-#define MDBX_NORETURN
-#endif /* MDBX_NORETURN */
-
-#ifndef MDBX_PRINTF_ARGS
-#if defined(__GNUC__) || __has_attribute(__format__)
-#if defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
-#define MDBX_PRINTF_ARGS(format_index, first_arg)                              \
-  __attribute__((__format__(__gnu_printf__, format_index, first_arg)))
-#else
-#define MDBX_PRINTF_ARGS(format_index, first_arg)                              \
-  __attribute__((__format__(__printf__, format_index, first_arg)))
-#endif /* MinGW */
-#else
-#define MDBX_PRINTF_ARGS(format_index, first_arg)
-#endif
-#endif /* MDBX_PRINTF_ARGS */
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cplusplus) && __cplusplus >= 201603 &&                          \
-     __has_cpp_attribute(maybe_unused) &&                                      \
-     __has_cpp_attribute(maybe_unused) >= 201603) ||                           \
-    (!defined(__cplusplus) && defined(__STDC_VERSION__) &&                     \
-     __STDC_VERSION__ > 202005L)
-#define MDBX_MAYBE_UNUSED [[maybe_unused]]
-#elif defined(__GNUC__) || __has_attribute(__unused__)
-#define MDBX_MAYBE_UNUSED __attribute__((__unused__))
-#else
-#define MDBX_MAYBE_UNUSED
-#endif /* MDBX_MAYBE_UNUSED */
-
-#if __has_attribute(no_sanitize)
-#define MDBX_NOSANITIZE_ENUM __attribute((__no_sanitize__("enum")))
-#else
-#define MDBX_NOSANITIZE_ENUM
-#endif /* MDBX_NOSANITIZE_ENUM */
-
-/* Oh, below are some songs and dances since:
- *  - C++ requires explicit definition of the necessary operators.
- *  - the proper implementation of DEFINE_ENUM_FLAG_OPERATORS for C++ required
- *    the constexpr feature which is broken in most old compilers;
- *  - DEFINE_ENUM_FLAG_OPERATORS may be defined broken as in the Windows SDK. */
-#ifndef DEFINE_ENUM_FLAG_OPERATORS
-
-#ifdef __cplusplus
-#if !defined(__cpp_constexpr) || __cpp_constexpr < 200704L ||                  \
-    (defined(__LCC__) && __LCC__ < 124) ||                                     \
-    (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 407) &&           \
-     !defined(__clang__) && !defined(__LCC__)) ||                              \
-    (defined(_MSC_VER) && _MSC_VER < 1910) ||                                  \
-    (defined(__clang__) && __clang_major__ < 4)
-/* The constexpr feature is not available or (may be) broken */
-#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 0
-#else
-/* C always allows these operators for enums */
-#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 1
-#endif /* __cpp_constexpr */
-
-/// Define operator overloads to enable bit operations on enum values that are
-/// used to define flags (based on Microsoft's DEFINE_ENUM_FLAG_OPERATORS).
-#define DEFINE_ENUM_FLAG_OPERATORS(ENUM)                                       \
-  extern "C++" {                                                               \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator|(ENUM a, ENUM b) {   \
-    return ENUM(unsigned(a) | unsigned(b));                                    \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator|=(ENUM &a,          \
-                                                             ENUM b) {         \
-    return a = a | b;                                                          \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, ENUM b) {   \
-    return ENUM(unsigned(a) & unsigned(b));                                    \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a,             \
-                                                           unsigned b) {       \
-    return ENUM(unsigned(a) & b);                                              \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(unsigned a,         \
-                                                           ENUM b) {           \
-    return ENUM(a & unsigned(b));                                              \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a,          \
-                                                             ENUM b) {         \
-    return a = a & b;                                                          \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a,          \
-                                                             unsigned b) {     \
-    return a = a & b;                                                          \
-  }                                                                            \
-  MDBX_CXX01_CONSTEXPR unsigned operator~(ENUM a) { return ~unsigned(a); }     \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator^(ENUM a, ENUM b) {   \
-    return ENUM(unsigned(a) ^ unsigned(b));                                    \
-  }                                                                            \
-  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator^=(ENUM &a,          \
-                                                             ENUM b) {         \
-    return a = a ^ b;                                                          \
-  }                                                                            \
-  }
-#else /* __cplusplus */
-/* nope for C since it always allows these operators for enums */
-#define DEFINE_ENUM_FLAG_OPERATORS(ENUM)
-#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 1
-#endif /* !__cplusplus */
-
-#elif !defined(CONSTEXPR_ENUM_FLAGS_OPERATIONS)
-
-#ifdef __cplusplus
-/* DEFINE_ENUM_FLAG_OPERATORS may be defined broken as in the Windows SDK */
-#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 0
-#else
-/* C always allows these operators for enums */
-#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 1
-#endif
-
-#endif /* DEFINE_ENUM_FLAG_OPERATORS */
-
-/** @} end of Common Macros */
-
-/*----------------------------------------------------------------------------*/
-
-/** \addtogroup c_api
- * @{ */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* MDBX version 0.11.x */
-#define MDBX_VERSION_MAJOR 0
-#define MDBX_VERSION_MINOR 11
-
-#ifndef LIBMDBX_API
-#if defined(LIBMDBX_EXPORTS)
-#define LIBMDBX_API __dll_export
-#elif defined(LIBMDBX_IMPORTS)
-#define LIBMDBX_API __dll_import
-#else
-#define LIBMDBX_API
-#endif
-#endif /* LIBMDBX_API */
-
-#ifdef __cplusplus
-#if defined(__clang__) || __has_attribute(type_visibility)
-#define LIBMDBX_API_TYPE LIBMDBX_API __attribute__((type_visibility("default")))
-#else
-#define LIBMDBX_API_TYPE LIBMDBX_API
-#endif
-#else
-#define LIBMDBX_API_TYPE
-#endif /* LIBMDBX_API_TYPE */
-
-#if defined(LIBMDBX_IMPORTS)
-#define LIBMDBX_VERINFO_API __dll_import
-#else
-#define LIBMDBX_VERINFO_API __dll_export
-#endif /* LIBMDBX_VERINFO_API */
-
-/** \brief libmdbx version information */
-extern LIBMDBX_VERINFO_API const struct MDBX_version_info {
-  uint8_t major;     /**< Major version number */
-  uint8_t minor;     /**< Minor version number */
-  uint16_t release;  /**< Release number of Major.Minor */
-  uint32_t revision; /**< Revision number of Release */
-  struct {
-    const char *datetime; /**< committer date, strict ISO-8601 format */
-    const char *tree;     /**< commit hash (hexadecimal digits) */
-    const char *commit;   /**< tree hash, i.e. digest of the source code */
-    const char *describe; /**< git-describe string */
-  } git;                  /**< source information from git */
-  const char *sourcery;   /**< sourcery anchor for pinning */
-} /** \brief libmdbx version information */ mdbx_version;
-
-/** \brief libmdbx build information
- * \attention Some strings could be NULL in case no corresponding information
- *            was provided at build time (i.e. flags). */
-extern LIBMDBX_VERINFO_API const struct MDBX_build_info {
-  const char *datetime; /**< build timestamp (ISO-8601 or __DATE__ __TIME__) */
-  const char *target;   /**< cpu/arch-system-config triplet */
-  const char *options;  /**< mdbx-related options */
-  const char *compiler; /**< compiler */
-  const char *flags;    /**< CFLAGS and CXXFLAGS */
-} /** \brief libmdbx build information */ mdbx_build;
-
-#if (defined(_WIN32) || defined(_WIN64)) && !MDBX_BUILD_SHARED_LIBRARY
-/* MDBX internally uses global and thread local storage destructors to
- * automatically (de)initialization, releasing reader lock table slots
- * and so on.
- *
- * If MDBX builded as a DLL this is done out-of-the-box by DllEntry() function,
- * which called automatically by Windows core with passing corresponding reason
- * argument.
- *
- * Otherwise, if MDBX was builded not as a DLL, some black magic
- * may be required depending of Windows version:
- *
- *  - Modern Windows versions, including Windows Vista and later, provides
- *    support for "TLS Directory" (e.g .CRT$XL[A-Z] sections in executable
- *    or dll file). In this case, MDBX capable of doing all automatically,
- *    therefore you DON'T NEED to call mdbx_module_handler()
- *    so the MDBX_MANUAL_MODULE_HANDLER defined as 0.
- *
- *  - Obsolete versions of Windows, prior to Windows Vista, REQUIRES calling
- *    mdbx_module_handler() manually from corresponding DllMain() or WinMain()
- *    of your DLL or application,
- *    so the MDBX_MANUAL_MODULE_HANDLER defined as 1.
- *
- * Therefore, building MDBX as a DLL is recommended for all version of Windows.
- * So, if you doubt, just build MDBX as the separate DLL and don't care about
- * the MDBX_MANUAL_MODULE_HANDLER. */
-
-#ifndef _WIN32_WINNT
-#error Non-dll build libmdbx requires target Windows version \
-  to be explicitly defined via _WIN32_WINNT for properly \
-  handling thread local storage destructors.
-#endif /* _WIN32_WINNT */
-
-#if _WIN32_WINNT >= 0x0600 /* Windows Vista */
-/* As described above mdbx_module_handler() is NOT needed for Windows Vista
- * and later. */
-#define MDBX_MANUAL_MODULE_HANDLER 0
-#else
-/* As described above mdbx_module_handler() IS REQUIRED for Windows versions
- * prior to Windows Vista. */
-#define MDBX_MANUAL_MODULE_HANDLER 1
-void LIBMDBX_API NTAPI mdbx_module_handler(PVOID module, DWORD reason,
-                                           PVOID reserved);
-#endif
-
-#endif /* Windows && !DLL && MDBX_MANUAL_MODULE_HANDLER */
-
-/* OPACITY STRUCTURES *********************************************************/
-
-/** \brief Opaque structure for a database environment.
- * \details An environment supports multiple key-value sub-databases (aka
- * key-value spaces or tables), all residing in the same shared-memory map.
- * \see mdbx_env_create() \see mdbx_env_close() */
-#ifndef __cplusplus
-typedef struct MDBX_env MDBX_env;
-#else
-struct MDBX_env;
-#endif
-
-/** \brief Opaque structure for a transaction handle.
- * \ingroup c_transactions
- * \details All database operations require a transaction handle. Transactions
- * may be read-only or read-write.
- * \see mdbx_txn_begin() \see mdbx_txn_commit() \see mdbx_txn_abort() */
-#ifndef __cplusplus
-typedef struct MDBX_txn MDBX_txn;
-#else
-struct MDBX_txn;
-#endif
-
-/** \brief A handle for an individual database (key-value spaces) in the
- * environment.
- * \ingroup c_dbi
- * \details Zero handle is used internally (hidden Garbage Collection subDB).
- * So, any valid DBI-handle great than 0 and less than or equal
- * \ref MDBX_MAX_DBI.
- * \see mdbx_dbi_open() \see mdbx_dbi_close() */
-typedef uint32_t MDBX_dbi;
-
-/** \brief Opaque structure for navigating through a database
- * \ingroup c_cursors
- * \see mdbx_cursor_create() \see mdbx_cursor_bind() \see mdbx_cursor_close()
- */
-#ifndef __cplusplus
-typedef struct MDBX_cursor MDBX_cursor;
-#else
-struct MDBX_cursor;
-#endif
-
-/** \brief Generic structure used for passing keys and data in and out of the
- * database.
- * \anchor MDBX_val \see mdbx::slice \see mdbx::buffer
- *
- * \details Values returned from the database are valid only until a subsequent
- * update operation, or the end of the transaction. Do not modify or
- * free them, they commonly point into the database itself.
- *
- * Key sizes must be between 0 and \ref mdbx_env_get_maxkeysize() inclusive.
- * The same applies to data sizes in databases with the \ref MDBX_DUPSORT flag.
- * Other data items can in theory be from 0 to \ref MDBX_MAXDATASIZE bytes long.
- *
- * \note The notable difference between MDBX and LMDB is that MDBX support zero
- * length keys. */
-#ifndef HAVE_STRUCT_IOVEC
-struct iovec {
-  void *iov_base; /**< pointer to some data */
-  size_t iov_len; /**< the length of data in bytes */
-};
-#define HAVE_STRUCT_IOVEC
-#endif /* HAVE_STRUCT_IOVEC */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-/* The `iov_len` is signed on Sun/Solaris.
- * So define custom MDBX_val to avoid a lot of warnings. */
-struct MDBX_val {
-  void *iov_base; /**< pointer to some data */
-  size_t iov_len; /**< the length of data in bytes */
-};
-#ifndef __cplusplus
-typedef struct MDBX_val MDBX_val;
-#endif
-#else  /* SunOS */
-typedef struct iovec MDBX_val;
-#endif /* ! SunOS */
-
-enum MDBX_constants {
-  /** The hard limit for DBI handles */
-  MDBX_MAX_DBI = UINT32_C(32765),
-
-  /** The maximum size of a data item. */
-  MDBX_MAXDATASIZE = UINT32_C(0x7fff0000),
-
-  /** The minimal database page size in bytes. */
-  MDBX_MIN_PAGESIZE = 256,
-
-  /** The maximal database page size in bytes. */
-  MDBX_MAX_PAGESIZE = 65536,
-};
-
-/* THE FILES *******************************************************************
- * At the file system level, the environment corresponds to a pair of files. */
-
-/** \brief The name of the lock file in the environment */
-#define MDBX_LOCKNAME "/mdbx.lck"
-/** \brief The name of the data file in the environment */
-#define MDBX_DATANAME "/mdbx.dat"
-
-/** \brief The suffix of the lock file when \ref MDBX_NOSUBDIR is used */
-#define MDBX_LOCK_SUFFIX "-lck"
-
-/* DEBUG & LOGGING ************************************************************/
-
-/** \addtogroup c_debug
- * \note Most of debug feature enabled only when libmdbx builded with
- * \ref MDBX_DEBUG build option. @{ */
-
-/** Log level
- * \note Levels detailed than (great than) \ref MDBX_LOG_NOTICE
- * requires build libmdbx with \ref MDBX_DEBUG option. */
-enum MDBX_log_level_t {
-  /** Critical conditions, i.e. assertion failures.
-   * \note libmdbx always produces such messages regardless
-   * of \ref MDBX_DEBUG build option. */
-  MDBX_LOG_FATAL = 0,
-
-  /** Enables logging for error conditions
-   * and \ref MDBX_LOG_FATAL.
-   * \note libmdbx always produces such messages regardless
-   * of \ref MDBX_DEBUG build option. */
-  MDBX_LOG_ERROR = 1,
-
-  /** Enables logging for warning conditions
-   * and \ref MDBX_LOG_ERROR ... \ref MDBX_LOG_FATAL.
-   * \note libmdbx always produces such messages regardless
-   * of \ref MDBX_DEBUG build option. */
-  MDBX_LOG_WARN = 2,
-
-  /** Enables logging for normal but significant condition
-   * and \ref MDBX_LOG_WARN ... \ref MDBX_LOG_FATAL.
-   * \note libmdbx always produces such messages regardless
-   * of \ref MDBX_DEBUG build option. */
-  MDBX_LOG_NOTICE = 3,
-
-  /** Enables logging for verbose informational
-   * and \ref MDBX_LOG_NOTICE ... \ref MDBX_LOG_FATAL.
-   * \note Requires build libmdbx with \ref MDBX_DEBUG option. */
-  MDBX_LOG_VERBOSE = 4,
-
-  /** Enables logging for debug-level messages
-   * and \ref MDBX_LOG_VERBOSE ... \ref MDBX_LOG_FATAL.
-   * \note Requires build libmdbx with \ref MDBX_DEBUG option. */
-  MDBX_LOG_DEBUG = 5,
-
-  /** Enables logging for trace debug-level messages
-   * and \ref MDBX_LOG_DEBUG ... \ref MDBX_LOG_FATAL.
-   * \note Requires build libmdbx with \ref MDBX_DEBUG option. */
-  MDBX_LOG_TRACE = 6,
-
-  /** Enables extra debug-level messages (dump pgno lists)
-   * and all other log-messages.
-   * \note Requires build libmdbx with \ref MDBX_DEBUG option. */
-  MDBX_LOG_EXTRA = 7,
-
-#ifdef ENABLE_UBSAN
-  MDBX_LOG_MAX = 7 /* avoid UBSAN false-positive trap by a tests */,
-#endif /* ENABLE_UBSAN */
-
-  /** for \ref mdbx_setup_debug() only: Don't change current settings */
-  MDBX_LOG_DONTCHANGE = -1
-};
-#ifndef __cplusplus
-typedef enum MDBX_log_level_t MDBX_log_level_t;
-#endif
-
-/** \brief Runtime debug flags
- *
- * \details `MDBX_DBG_DUMP` and `MDBX_DBG_LEGACY_MULTIOPEN` always have an
- * effect, but `MDBX_DBG_ASSERT`, `MDBX_DBG_AUDIT` and `MDBX_DBG_JITTER` only if
- * libmdbx builded with \ref MDBX_DEBUG. */
-enum MDBX_debug_flags_t {
-  MDBX_DBG_NONE = 0,
-
-  /** Enable assertion checks.
-   * \note Always enabled for builds with `MDBX_FORCE_ASSERTIONS` option,
-   * otherwise requires build with \ref MDBX_DEBUG > 0 */
-  MDBX_DBG_ASSERT = 1,
-
-  /** Enable pages usage audit at commit transactions.
-   * \note Requires build with \ref MDBX_DEBUG > 0 */
-  MDBX_DBG_AUDIT = 2,
-
-  /** Enable small random delays in critical points.
-   * \note Requires build with \ref MDBX_DEBUG > 0 */
-  MDBX_DBG_JITTER = 4,
-
-  /** Include or not meta-pages in coredump files.
-   * \note May affect performance in \ref MDBX_WRITEMAP mode */
-  MDBX_DBG_DUMP = 8,
-
-  /** Allow multi-opening environment(s) */
-  MDBX_DBG_LEGACY_MULTIOPEN = 16,
-
-  /** Allow read and write transactions overlapping for the same thread. */
-  MDBX_DBG_LEGACY_OVERLAP = 32,
-
-  /** Don't auto-upgrade format signature.
-   * \note However a new write transactions will use and store
-   * the last signature regardless this flag */
-  MDBX_DBG_DONT_UPGRADE = 64,
-
-#ifdef ENABLE_UBSAN
-  MDBX_DBG_MAX = ((unsigned)MDBX_LOG_MAX) << 16 |
-                 127 /* avoid UBSAN false-positive trap by a tests */,
-#endif /* ENABLE_UBSAN */
-
-  /** for mdbx_setup_debug() only: Don't change current settings */
-  MDBX_DBG_DONTCHANGE = -1
-};
-#ifndef __cplusplus
-typedef enum MDBX_debug_flags_t MDBX_debug_flags_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_debug_flags_t)
-#endif
-
-/** \brief A debug-logger callback function,
- * called before printing the message and aborting.
- * \see mdbx_setup_debug()
- *
- * \param [in] env  An environment handle returned by \ref mdbx_env_create().
- * \param [in] msg  The assertion message, not including newline. */
-typedef void MDBX_debug_func(MDBX_log_level_t loglevel, const char *function,
-                             int line, const char *fmt,
-                             va_list args) MDBX_CXX17_NOEXCEPT;
-
-/** \brief The "don't change `logger`" value for mdbx_setup_debug() */
-#define MDBX_LOGGER_DONTCHANGE ((MDBX_debug_func *)(intptr_t)-1)
-
-/** \brief Setup global log-level, debug options and debug logger.
- * \returns The previously `debug_flags` in the 0-15 bits
- *          and `log_level` in the 16-31 bits. */
-LIBMDBX_API int mdbx_setup_debug(MDBX_log_level_t log_level,
-                                 MDBX_debug_flags_t debug_flags,
-                                 MDBX_debug_func *logger);
-
-/** \brief A callback function for most MDBX assert() failures,
- * called before printing the message and aborting.
- * \see mdbx_env_set_assert()
- *
- * \param [in] env  An environment handle returned by mdbx_env_create().
- * \param [in] msg  The assertion message, not including newline. */
-typedef void MDBX_assert_func(const MDBX_env *env, const char *msg,
-                              const char *function,
-                              unsigned line) MDBX_CXX17_NOEXCEPT;
-
-/** \brief Set or reset the assert() callback of the environment.
- *
- * Does nothing if libmdbx was built with MDBX_DEBUG=0 or with NDEBUG,
- * and will return `MDBX_ENOSYS` in such case.
- *
- * \param [in] env   An environment handle returned by mdbx_env_create().
- * \param [in] func  An MDBX_assert_func function, or 0.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func);
-
-/** \brief Dump given MDBX_val to the buffer
- *
- * Dumps it as string if value is printable (all bytes in the range 0x20..0x7E),
- * otherwise made hexadecimal dump. Requires at least 4 byte length buffer.
- *
- * \returns One of:
- *  - NULL if given buffer size less than 4 bytes;
- *  - pointer to constant string if given value NULL or empty;
- *  - otherwise pointer to given buffer. */
-LIBMDBX_API const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
-                                      const size_t bufsize);
-
-/** \brief Panics with message and causes abnormal process termination. */
-LIBMDBX_API void mdbx_panic(const char *fmt, ...) MDBX_PRINTF_ARGS(1, 2);
-
-/** @} end of logging & debug */
-
-/** \brief Environment flags
- * \ingroup c_opening
- * \anchor env_flags
- * \see mdbx_env_open() \see mdbx_env_set_flags() */
-enum MDBX_env_flags_t {
-  MDBX_ENV_DEFAULTS = 0,
-
-  /** No environment directory.
-   *
-   * By default, MDBX creates its environment in a directory whose pathname is
-   * given in path, and creates its data and lock files under that directory.
-   * With this option, path is used as-is for the database main data file.
-   * The database lock file is the path with "-lck" appended.
-   *
-   * - with `MDBX_NOSUBDIR` = in a filesystem we have the pair of MDBX-files
-   *   which names derived from given pathname by appending predefined suffixes.
-   *
-   * - without `MDBX_NOSUBDIR` = in a filesystem we have the MDBX-directory with
-   *   given pathname, within that a pair of MDBX-files with predefined names.
-   *
-   * This flag affects only at new environment creating by \ref mdbx_env_open(),
-   * otherwise at opening an existing environment libmdbx will choice this
-   * automatically. */
-  MDBX_NOSUBDIR = UINT32_C(0x4000),
-
-  /** Read only mode.
-   *
-   * Open the environment in read-only mode. No write operations will be
-   * allowed. MDBX will still modify the lock file - except on read-only
-   * filesystems, where MDBX does not use locks.
-   *
-   * - with `MDBX_RDONLY` = open environment in read-only mode.
-   *   MDBX supports pure read-only mode (i.e. without opening LCK-file) only
-   *   when environment directory and/or both files are not writable (and the
-   *   LCK-file may be missing). In such case allowing file(s) to be placed
-   *   on a network read-only share.
-   *
-   * - without `MDBX_RDONLY` = open environment in read-write mode.
-   *
-   * This flag affects only at environment opening but can't be changed after.
-   */
-  MDBX_RDONLY = UINT32_C(0x20000),
-
-  /** Open environment in exclusive/monopolistic mode.
-   *
-   * `MDBX_EXCLUSIVE` flag can be used as a replacement for `MDB_NOLOCK`,
-   * which don't supported by MDBX.
-   * In this way, you can get the minimal overhead, but with the correct
-   * multi-process and multi-thread locking.
-   *
-   * - with `MDBX_EXCLUSIVE` = open environment in exclusive/monopolistic mode
-   *   or return \ref MDBX_BUSY if environment already used by other process.
-   *   The main feature of the exclusive mode is the ability to open the
-   *   environment placed on a network share.
-   *
-   * - without `MDBX_EXCLUSIVE` = open environment in cooperative mode,
-   *   i.e. for multi-process access/interaction/cooperation.
-   *   The main requirements of the cooperative mode are:
-   *
-   *   1. data files MUST be placed in the LOCAL file system,
-   *      but NOT on a network share.
-   *   2. environment MUST be opened only by LOCAL processes,
-   *      but NOT over a network.
-   *   3. OS kernel (i.e. file system and memory mapping implementation) and
-   *      all processes that open the given environment MUST be running
-   *      in the physically single RAM with cache-coherency. The only
-   *      exception for cache-consistency requirement is Linux on MIPS
-   *      architecture, but this case has not been tested for a long time).
-   *
-   * This flag affects only at environment opening but can't be changed after.
-   */
-  MDBX_EXCLUSIVE = UINT32_C(0x400000),
-
-  /** Using database/environment which already opened by another process(es).
-   *
-   * The `MDBX_ACCEDE` flag is useful to avoid \ref MDBX_INCOMPATIBLE error
-   * while opening the database/environment which is already used by another
-   * process(es) with unknown mode/flags. In such cases, if there is a
-   * difference in the specified flags (\ref MDBX_NOMETASYNC,
-   * \ref MDBX_SAFE_NOSYNC, \ref MDBX_UTTERLY_NOSYNC, \ref MDBX_LIFORECLAIM,
-   * \ref MDBX_COALESCE and \ref MDBX_NORDAHEAD), instead of returning an error,
-   * the database will be opened in a compatibility with the already used mode.
-   *
-   * `MDBX_ACCEDE` has no effect if the current process is the only one either
-   * opening the DB in read-only mode or other process(es) uses the DB in
-   * read-only mode. */
-  MDBX_ACCEDE = UINT32_C(0x40000000),
-
-  /** Map data into memory with write permission.
-   *
-   * Use a writeable memory map unless \ref MDBX_RDONLY is set. This uses fewer
-   * mallocs and requires much less work for tracking database pages, but
-   * loses protection from application bugs like wild pointer writes and other
-   * bad updates into the database. This may be slightly faster for DBs that
-   * fit entirely in RAM, but is slower for DBs larger than RAM. Also adds the
-   * possibility for stray application writes thru pointers to silently
-   * corrupt the database.
-   *
-   * - with `MDBX_WRITEMAP` = all data will be mapped into memory in the
-   *   read-write mode. This offers a significant performance benefit, since the
-   *   data will be modified directly in mapped memory and then flushed to disk
-   *   by single system call, without any memory management nor copying.
-   *
-   * - without `MDBX_WRITEMAP` = data will be mapped into memory in the
-   *   read-only mode. This requires stocking all modified database pages in
-   *   memory and then writing them to disk through file operations.
-   *
-   * \warning On the other hand, `MDBX_WRITEMAP` adds the possibility for stray
-   * application writes thru pointers to silently corrupt the database.
-   *
-   * \note The `MDBX_WRITEMAP` mode is incompatible with nested transactions,
-   * since this is unreasonable. I.e. nested transactions requires mallocation
-   * of database pages and more work for tracking ones, which neuters a
-   * performance boost caused by the `MDBX_WRITEMAP` mode.
-   *
-   * This flag affects only at environment opening but can't be changed after.
-   */
-  MDBX_WRITEMAP = UINT32_C(0x80000),
-
-  /** Tie reader locktable slots to read-only transactions
-   * instead of to threads.
-   *
-   * Don't use Thread-Local Storage, instead tie reader locktable slots to
-   * \ref MDBX_txn objects instead of to threads. So, \ref mdbx_txn_reset()
-   * keeps the slot reserved for the \ref MDBX_txn object. A thread may use
-   * parallel read-only transactions. And a read-only transaction may span
-   * threads if you synchronizes its use.
-   *
-   * Applications that multiplex many user threads over individual OS threads
-   * need this option. Such an application must also serialize the write
-   * transactions in an OS thread, since MDBX's write locking is unaware of
-   * the user threads.
-   *
-   * \note Regardless to `MDBX_NOTLS` flag a write transaction entirely should
-   * always be used in one thread from start to finish. MDBX checks this in a
-   * reasonable manner and return the \ref MDBX_THREAD_MISMATCH error in rules
-   * violation.
-   *
-   * This flag affects only at environment opening but can't be changed after.
-   */
-  MDBX_NOTLS = UINT32_C(0x200000),
-
-  /** Don't do readahead.
-   *
-   * Turn off readahead. Most operating systems perform readahead on read
-   * requests by default. This option turns it off if the OS supports it.
-   * Turning it off may help random read performance when the DB is larger
-   * than RAM and system RAM is full.
-   *
-   * By default libmdbx dynamically enables/disables readahead depending on
-   * the actual database size and currently available memory. On the other
-   * hand, such automation has some limitation, i.e. could be performed only
-   * when DB size changing but can't tracks and reacts changing a free RAM
-   * availability, since it changes independently and asynchronously.
-   *
-   * \note The mdbx_is_readahead_reasonable() function allows to quickly find
-   * out whether to use readahead or not based on the size of the data and the
-   * amount of available memory.
-   *
-   * This flag affects only at environment opening and can't be changed after.
-   */
-  MDBX_NORDAHEAD = UINT32_C(0x800000),
-
-  /** Don't initialize malloc'ed memory before writing to datafile.
-   *
-   * Don't initialize malloc'ed memory before writing to unused spaces in the
-   * data file. By default, memory for pages written to the data file is
-   * obtained using malloc. While these pages may be reused in subsequent
-   * transactions, freshly malloc'ed pages will be initialized to zeroes before
-   * use. This avoids persisting leftover data from other code (that used the
-   * heap and subsequently freed the memory) into the data file.
-   *
-   * Note that many other system libraries may allocate and free memory from
-   * the heap for arbitrary uses. E.g., stdio may use the heap for file I/O
-   * buffers. This initialization step has a modest performance cost so some
-   * applications may want to disable it using this flag. This option can be a
-   * problem for applications which handle sensitive data like passwords, and
-   * it makes memory checkers like Valgrind noisy. This flag is not needed
-   * with \ref MDBX_WRITEMAP, which writes directly to the mmap instead of using
-   * malloc for pages. The initialization is also skipped if \ref MDBX_RESERVE
-   * is used; the caller is expected to overwrite all of the memory that was
-   * reserved in that case.
-   *
-   * This flag may be changed at any time using `mdbx_env_set_flags()`. */
-  MDBX_NOMEMINIT = UINT32_C(0x1000000),
-
-  /** Aims to coalesce a Garbage Collection items.
-   *
-   * With `MDBX_COALESCE` flag MDBX will aims to coalesce items while recycling
-   * a Garbage Collection. Technically, when possible short lists of pages
-   * will be combined into longer ones, but to fit on one database page. As a
-   * result, there will be fewer items in Garbage Collection and a page lists
-   * are longer, which slightly increases the likelihood of returning pages to
-   * Unallocated space and reducing the database file.
-   *
-   * This flag may be changed at any time using mdbx_env_set_flags(). */
-  MDBX_COALESCE = UINT32_C(0x2000000),
-
-  /** LIFO policy for recycling a Garbage Collection items.
-   *
-   * `MDBX_LIFORECLAIM` flag turns on LIFO policy for recycling a Garbage
-   * Collection items, instead of FIFO by default. On systems with a disk
-   * write-back cache, this can significantly increase write performance, up
-   * to several times in a best case scenario.
-   *
-   * LIFO recycling policy means that for reuse pages will be taken which became
-   * unused the lastest (i.e. just now or most recently). Therefore the loop of
-   * database pages circulation becomes as short as possible. In other words,
-   * the number of pages, that are overwritten in memory and on disk during a
-   * series of write transactions, will be as small as possible. Thus creates
-   * ideal conditions for the efficient operation of the disk write-back cache.
-   *
-   * \ref MDBX_LIFORECLAIM is compatible with all no-sync flags, but gives NO
-   * noticeable impact in combination with \ref MDBX_SAFE_NOSYNC or
-   * \ref MDBX_UTTERLY_NOSYNC. Because MDBX will reused pages only before the
-   * last "steady" MVCC-snapshot, i.e. the loop length of database pages
-   * circulation will be mostly defined by frequency of calling
-   * \ref mdbx_env_sync() rather than LIFO and FIFO difference.
-   *
-   * This flag may be changed at any time using mdbx_env_set_flags(). */
-  MDBX_LIFORECLAIM = UINT32_C(0x4000000),
-
-  /** Debugging option, fill/perturb released pages. */
-  MDBX_PAGEPERTURB = UINT32_C(0x8000000),
-
-  /* SYNC MODES****************************************************************/
-  /** \defgroup sync_modes SYNC MODES
-   *
-   * \attention Using any combination of \ref MDBX_SAFE_NOSYNC, \ref
-   * MDBX_NOMETASYNC and especially \ref MDBX_UTTERLY_NOSYNC is always a deal to
-   * reduce durability for gain write performance. You must know exactly what
-   * you are doing and what risks you are taking!
-   *
-   * \note for LMDB users: \ref MDBX_SAFE_NOSYNC is NOT similar to LMDB_NOSYNC,
-   * but \ref MDBX_UTTERLY_NOSYNC is exactly match LMDB_NOSYNC. See details
-   * below.
-   *
-   * THE SCENE:
-   * - The DAT-file contains several MVCC-snapshots of B-tree at same time,
-   *   each of those B-tree has its own root page.
-   * - Each of meta pages at the beginning of the DAT file contains a
-   *   pointer to the root page of B-tree which is the result of the particular
-   *   transaction, and a number of this transaction.
-   * - For data durability, MDBX must first write all MVCC-snapshot data
-   *   pages and ensure that are written to the disk, then update a meta page
-   *   with the new transaction number and a pointer to the corresponding new
-   *   root page, and flush any buffers yet again.
-   * - Thus during commit a I/O buffers should be flushed to the disk twice;
-   *   i.e. fdatasync(), FlushFileBuffers() or similar syscall should be
-   *   called twice for each commit. This is very expensive for performance,
-   *   but guaranteed durability even on unexpected system failure or power
-   *   outage. Of course, provided that the operating system and the
-   *   underlying hardware (e.g. disk) work correctly.
-   *
-   * TRADE-OFF:
-   * By skipping some stages described above, you can significantly benefit in
-   * speed, while partially or completely losing in the guarantee of data
-   * durability and/or consistency in the event of system or power failure.
-   * Moreover, if for any reason disk write order is not preserved, then at
-   * moment of a system crash, a meta-page with a pointer to the new B-tree may
-   * be written to disk, while the itself B-tree not yet. In that case, the
-   * database will be corrupted!
-   *
-   * \see MDBX_SYNC_DURABLE \see MDBX_NOMETASYNC \see MDBX_SAFE_NOSYNC
-   * \see MDBX_UTTERLY_NOSYNC
-   *
-   * @{ */
-
-  /** Default robust and durable sync mode.
-   *
-   * Metadata is written and flushed to disk after a data is written and
-   * flushed, which guarantees the integrity of the database in the event
-   * of a crash at any time.
-   *
-   * \attention Please do not use other modes until you have studied all the
-   * details and are sure. Otherwise, you may lose your users' data, as happens
-   * in [Miranda NG](https://www.miranda-ng.org/) messenger. */
-  MDBX_SYNC_DURABLE = 0,
-
-  /** Don't sync the meta-page after commit.
-   *
-   * Flush system buffers to disk only once per transaction commit, omit the
-   * metadata flush. Defer that until the system flushes files to disk,
-   * or next non-\ref MDBX_RDONLY commit or \ref mdbx_env_sync(). Depending on
-   * the platform and hardware, with \ref MDBX_NOMETASYNC you may get a doubling
-   * of write performance.
-   *
-   * This trade-off maintains database integrity, but a system crash may
-   * undo the last committed transaction. I.e. it preserves the ACI
-   * (atomicity, consistency, isolation) but not D (durability) database
-   * property.
-   *
-   * `MDBX_NOMETASYNC` flag may be changed at any time using
-   * \ref mdbx_env_set_flags() or by passing to \ref mdbx_txn_begin() for
-   * particular write transaction. \see sync_modes */
-  MDBX_NOMETASYNC = UINT32_C(0x40000),
-
-  /** Don't sync anything but keep previous steady commits.
-   *
-   * Like \ref MDBX_UTTERLY_NOSYNC the `MDBX_SAFE_NOSYNC` flag disable similarly
-   * flush system buffers to disk when committing a transaction. But there is a
-   * huge difference in how are recycled the MVCC snapshots corresponding to
-   * previous "steady" transactions (see below).
-   *
-   * With \ref MDBX_WRITEMAP the `MDBX_SAFE_NOSYNC` instructs MDBX to use
-   * asynchronous mmap-flushes to disk. Asynchronous mmap-flushes means that
-   * actually all writes will scheduled and performed by operation system on it
-   * own manner, i.e. unordered. MDBX itself just notify operating system that
-   * it would be nice to write data to disk, but no more.
-   *
-   * Depending on the platform and hardware, with `MDBX_SAFE_NOSYNC` you may get
-   * a multiple increase of write performance, even 10 times or more.
-   *
-   * In contrast to \ref MDBX_UTTERLY_NOSYNC mode, with `MDBX_SAFE_NOSYNC` flag
-   * MDBX will keeps untouched pages within B-tree of the last transaction
-   * "steady" which was synced to disk completely. This has big implications for
-   * both data durability and (unfortunately) performance:
-   *  - a system crash can't corrupt the database, but you will lose the last
-   *    transactions; because MDBX will rollback to last steady commit since it
-   *    kept explicitly.
-   *  - the last steady transaction makes an effect similar to "long-lived" read
-   *    transaction (see above in the \ref restrictions section) since prevents
-   *    reuse of pages freed by newer write transactions, thus the any data
-   *    changes will be placed in newly allocated pages.
-   *  - to avoid rapid database growth, the system will sync data and issue
-   *    a steady commit-point to resume reuse pages, each time there is
-   *    insufficient space and before increasing the size of the file on disk.
-   *
-   * In other words, with `MDBX_SAFE_NOSYNC` flag MDBX insures you from the
-   * whole database corruption, at the cost increasing database size and/or
-   * number of disk IOPs. So, `MDBX_SAFE_NOSYNC` flag could be used with
-   * \ref mdbx_env_sync() as alternatively for batch committing or nested
-   * transaction (in some cases). As well, auto-sync feature exposed by
-   * \ref mdbx_env_set_syncbytes() and \ref mdbx_env_set_syncperiod() functions
-   * could be very useful with `MDBX_SAFE_NOSYNC` flag.
-   *
-   * The number and volume of of disk IOPs with MDBX_SAFE_NOSYNC flag will
-   * exactly the as without any no-sync flags. However, you should expect a
-   * larger process's [work set](https://bit.ly/2kA2tFX) and significantly worse
-   * a [locality of reference](https://bit.ly/2mbYq2J), due to the more
-   * intensive allocation of previously unused pages and increase the size of
-   * the database.
-   *
-   * `MDBX_SAFE_NOSYNC` flag may be changed at any time using
-   * \ref mdbx_env_set_flags() or by passing to \ref mdbx_txn_begin() for
-   * particular write transaction. */
-  MDBX_SAFE_NOSYNC = UINT32_C(0x10000),
-
-  /** \deprecated Please use \ref MDBX_SAFE_NOSYNC instead of `MDBX_MAPASYNC`.
-   *
-   * Since version 0.9.x the `MDBX_MAPASYNC` is deprecated and has the same
-   * effect as \ref MDBX_SAFE_NOSYNC with \ref MDBX_WRITEMAP. This just API
-   * simplification is for convenience and clarity. */
-  MDBX_MAPASYNC = MDBX_SAFE_NOSYNC,
-
-  /** Don't sync anything and wipe previous steady commits.
-   *
-   * Don't flush system buffers to disk when committing a transaction. This
-   * optimization means a system crash can corrupt the database, if buffers are
-   * not yet flushed to disk. Depending on the platform and hardware, with
-   * `MDBX_UTTERLY_NOSYNC` you may get a multiple increase of write performance,
-   * even 100 times or more.
-   *
-   * If the filesystem preserves write order (which is rare and never provided
-   * unless explicitly noted) and the \ref MDBX_WRITEMAP and \ref
-   * MDBX_LIFORECLAIM flags are not used, then a system crash can't corrupt the
-   * database, but you can lose the last transactions, if at least one buffer is
-   * not yet flushed to disk. The risk is governed by how often the system
-   * flushes dirty buffers to disk and how often \ref mdbx_env_sync() is called.
-   * So, transactions exhibit ACI (atomicity, consistency, isolation) properties
-   * and only lose `D` (durability). I.e. database integrity is maintained, but
-   * a system crash may undo the final transactions.
-   *
-   * Otherwise, if the filesystem not preserves write order (which is
-   * typically) or \ref MDBX_WRITEMAP or \ref MDBX_LIFORECLAIM flags are used,
-   * you should expect the corrupted database after a system crash.
-   *
-   * So, most important thing about `MDBX_UTTERLY_NOSYNC`:
-   *  - a system crash immediately after commit the write transaction
-   *    high likely lead to database corruption.
-   *  - successful completion of mdbx_env_sync(force = true) after one or
-   *    more committed transactions guarantees consistency and durability.
-   *  - BUT by committing two or more transactions you back database into
-   *    a weak state, in which a system crash may lead to database corruption!
-   *    In case single transaction after mdbx_env_sync, you may lose transaction
-   *    itself, but not a whole database.
-   *
-   * Nevertheless, `MDBX_UTTERLY_NOSYNC` provides "weak" durability in case
-   * of an application crash (but no durability on system failure), and
-   * therefore may be very useful in scenarios where data durability is
-   * not required over a system failure (e.g for short-lived data), or if you
-   * can take such risk.
-   *
-   * `MDBX_UTTERLY_NOSYNC` flag may be changed at any time using
-   * \ref mdbx_env_set_flags(), but don't has effect if passed to
-   * \ref mdbx_txn_begin() for particular write transaction. \see sync_modes */
-  MDBX_UTTERLY_NOSYNC = MDBX_SAFE_NOSYNC | UINT32_C(0x100000),
-
-  /** @} end of SYNC MODES */
-};
-#ifndef __cplusplus
-/** \ingroup c_opening */
-typedef enum MDBX_env_flags_t MDBX_env_flags_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_env_flags_t)
-#endif
-
-/** Transaction flags
- * \ingroup c_transactions
- * \anchor txn_flags
- * \see mdbx_txn_begin() \see mdbx_txn_flags() */
-enum MDBX_txn_flags_t {
-  /** Start read-write transaction.
-   *
-   * Only one write transaction may be active at a time. Writes are fully
-   * serialized, which guarantees that writers can never deadlock. */
-  MDBX_TXN_READWRITE = 0,
-
-  /** Start read-only transaction.
-   *
-   * There can be multiple read-only transactions simultaneously that do not
-   * block each other and a write transactions. */
-  MDBX_TXN_RDONLY = MDBX_RDONLY,
-
-/** Prepare but not start read-only transaction.
- *
- * Transaction will not be started immediately, but created transaction handle
- * will be ready for use with \ref mdbx_txn_renew(). This flag allows to
- * preallocate memory and assign a reader slot, thus avoiding these operations
- * at the next start of the transaction. */
-#if CONSTEXPR_ENUM_FLAGS_OPERATIONS || defined(DOXYGEN)
-  MDBX_TXN_RDONLY_PREPARE = MDBX_RDONLY | MDBX_NOMEMINIT,
-#else
-  MDBX_TXN_RDONLY_PREPARE = uint32_t(MDBX_RDONLY) | uint32_t(MDBX_NOMEMINIT),
-#endif
-
-  /** Do not block when starting a write transaction. */
-  MDBX_TXN_TRY = UINT32_C(0x10000000),
-
-  /** Exactly the same as \ref MDBX_NOMETASYNC,
-   * but for this transaction only */
-  MDBX_TXN_NOMETASYNC = MDBX_NOMETASYNC,
-
-  /** Exactly the same as \ref MDBX_SAFE_NOSYNC,
-   * but for this transaction only */
-  MDBX_TXN_NOSYNC = MDBX_SAFE_NOSYNC
-};
-#ifndef __cplusplus
-typedef enum MDBX_txn_flags_t MDBX_txn_flags_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_txn_flags_t)
-#endif
-
-/** \brief Database flags
- * \ingroup c_dbi
- * \anchor db_flags
- * \see mdbx_dbi_open() */
-enum MDBX_db_flags_t {
-  /** Variable length unique keys with usual byte-by-byte string comparison. */
-  MDBX_DB_DEFAULTS = 0,
-
-  /** Use reverse string comparison for keys. */
-  MDBX_REVERSEKEY = UINT32_C(0x02),
-
-  /** Use sorted duplicates, i.e. allow multi-values for a keys. */
-  MDBX_DUPSORT = UINT32_C(0x04),
-
-  /** Numeric keys in native byte order either uint32_t or uint64_t
-   * (must be one of uint32_t or uint64_t, other integer types, for example,
-   * signed integer or uint16_t will not work).
-   * The keys must all be of the same size and must be aligned while passing as
-   * arguments. */
-  MDBX_INTEGERKEY = UINT32_C(0x08),
-
-  /** With \ref MDBX_DUPSORT; sorted dup items have fixed size. The data values
-   * must all be of the same size. */
-  MDBX_DUPFIXED = UINT32_C(0x10),
-
-  /** With \ref MDBX_DUPSORT and with \ref MDBX_DUPFIXED; dups are fixed size
-   * like \ref MDBX_INTEGERKEY -style integers. The data values must all be of
-   * the same size and must be aligned while passing as arguments. */
-  MDBX_INTEGERDUP = UINT32_C(0x20),
-
-  /** With \ref MDBX_DUPSORT; use reverse string comparison for data values. */
-  MDBX_REVERSEDUP = UINT32_C(0x40),
-
-  /** Create DB if not already existing. */
-  MDBX_CREATE = UINT32_C(0x40000),
-
-  /** Opens an existing sub-database created with unknown flags.
-   *
-   * The `MDBX_DB_ACCEDE` flag is intend to open a existing sub-database which
-   * was created with unknown flags (\ref MDBX_REVERSEKEY, \ref MDBX_DUPSORT,
-   * \ref MDBX_INTEGERKEY, \ref MDBX_DUPFIXED, \ref MDBX_INTEGERDUP and
-   * \ref MDBX_REVERSEDUP).
-   *
-   * In such cases, instead of returning the \ref MDBX_INCOMPATIBLE error, the
-   * sub-database will be opened with flags which it was created, and then an
-   * application could determine the actual flags by \ref mdbx_dbi_flags(). */
-  MDBX_DB_ACCEDE = MDBX_ACCEDE
-};
-#ifndef __cplusplus
-/** \ingroup c_dbi */
-typedef enum MDBX_db_flags_t MDBX_db_flags_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_db_flags_t)
-#endif
-
-/** \brief Data changing flags
- * \ingroup c_crud
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- * \see mdbx_put() \see mdbx_cursor_put() \see mdbx_replace() */
-enum MDBX_put_flags_t {
-  /** Upsertion by default (without any other flags) */
-  MDBX_UPSERT = 0,
-
-  /** For insertion: Don't write if the key already exists. */
-  MDBX_NOOVERWRITE = UINT32_C(0x10),
-
-  /** Has effect only for \ref MDBX_DUPSORT databases.
-   * For upsertion: don't write if the key-value pair already exist.
-   * For deletion: remove all values for key. */
-  MDBX_NODUPDATA = UINT32_C(0x20),
-
-  /** For upsertion: overwrite the current key/data pair.
-   * MDBX allows this flag for \ref mdbx_put() for explicit overwrite/update
-   * without insertion.
-   * For deletion: remove only single entry at the current cursor position. */
-  MDBX_CURRENT = UINT32_C(0x40),
-
-  /** Has effect only for \ref MDBX_DUPSORT databases.
-   * For deletion: remove all multi-values (aka duplicates) for given key.
-   * For upsertion: replace all multi-values for given key with a new one. */
-  MDBX_ALLDUPS = UINT32_C(0x80),
-
-  /** For upsertion: Just reserve space for data, don't copy it.
-   * Return a pointer to the reserved space. */
-  MDBX_RESERVE = UINT32_C(0x10000),
-
-  /** Data is being appended.
-   * Don't split full pages, continue on a new instead. */
-  MDBX_APPEND = UINT32_C(0x20000),
-
-  /** Has effect only for \ref MDBX_DUPSORT databases.
-   * Duplicate data is being appended.
-   * Don't split full pages, continue on a new instead. */
-  MDBX_APPENDDUP = UINT32_C(0x40000),
-
-  /** Only for \ref MDBX_DUPFIXED.
-   * Store multiple data items in one call. */
-  MDBX_MULTIPLE = UINT32_C(0x80000)
-};
-#ifndef __cplusplus
-/** \ingroup c_crud */
-typedef enum MDBX_put_flags_t MDBX_put_flags_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_put_flags_t)
-#endif
-
-/** \brief Environment copy flags
- * \ingroup c_extra
- * \see mdbx_env_copy() \see mdbx_env_copy2fd() */
-enum MDBX_copy_flags_t {
-  MDBX_CP_DEFAULTS = 0,
-
-  /** Copy with compactification: Omit free space from copy and renumber all
-   * pages sequentially */
-  MDBX_CP_COMPACT = 1u,
-
-  /** Force to make resizeable copy, i.e. dynamic size instead of fixed */
-  MDBX_CP_FORCE_DYNAMIC_SIZE = 2u
-};
-#ifndef __cplusplus
-/** \ingroup c_extra */
-typedef enum MDBX_copy_flags_t MDBX_copy_flags_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_copy_flags_t)
-#endif
-
-/** \brief Cursor operations
- * \ingroup c_cursors
- * This is the set of all operations for retrieving data using a cursor.
- * \see mdbx_cursor_get() */
-enum MDBX_cursor_op {
-  /** Position at first key/data item */
-  MDBX_FIRST,
-
-  /** \ref MDBX_DUPSORT -only: Position at first data item of current key. */
-  MDBX_FIRST_DUP,
-
-  /** \ref MDBX_DUPSORT -only: Position at key/data pair. */
-  MDBX_GET_BOTH,
-
-  /** \ref MDBX_DUPSORT -only: Position at given key and at first data greater
-   * than or equal to specified data. */
-  MDBX_GET_BOTH_RANGE,
-
-  /** Return key/data at current cursor position */
-  MDBX_GET_CURRENT,
-
-  /** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items
-   * from current cursor position. Move cursor to prepare
-   * for \ref MDBX_NEXT_MULTIPLE. */
-  MDBX_GET_MULTIPLE,
-
-  /** Position at last key/data item */
-  MDBX_LAST,
-
-  /** \ref MDBX_DUPSORT -only: Position at last data item of current key. */
-  MDBX_LAST_DUP,
-
-  /** Position at next data item */
-  MDBX_NEXT,
-
-  /** \ref MDBX_DUPSORT -only: Position at next data item of current key. */
-  MDBX_NEXT_DUP,
-
-  /** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items
-   * from next cursor position. Move cursor to prepare
-   * for `MDBX_NEXT_MULTIPLE`. */
-  MDBX_NEXT_MULTIPLE,
-
-  /** Position at first data item of next key */
-  MDBX_NEXT_NODUP,
-
-  /** Position at previous data item */
-  MDBX_PREV,
-
-  /** \ref MDBX_DUPSORT -only: Position at previous data item of current key. */
-  MDBX_PREV_DUP,
-
-  /** Position at last data item of previous key */
-  MDBX_PREV_NODUP,
-
-  /** Position at specified key */
-  MDBX_SET,
-
-  /** Position at specified key, return both key and data */
-  MDBX_SET_KEY,
-
-  /** Position at first key greater than or equal to specified key. */
-  MDBX_SET_RANGE,
-
-  /** \ref MDBX_DUPFIXED -only: Position at previous page and return up to
-   * a page of duplicate data items. */
-  MDBX_PREV_MULTIPLE,
-
-  /** Positions cursor at first key-value pair greater than or equal to
-   * specified, return both key and data, and the return code depends on whether
-   * a exact match.
-   *
-   * For non DUPSORT-ed collections this work the same to \ref MDBX_SET_RANGE,
-   * but returns \ref MDBX_SUCCESS if key found exactly or
-   * \ref MDBX_RESULT_TRUE if greater key was found.
-   *
-   * For DUPSORT-ed a data value is taken into account for duplicates,
-   * i.e. for a pairs/tuples of a key and an each data value of duplicates.
-   * Returns \ref MDBX_SUCCESS if key-value pair found exactly or
-   * \ref MDBX_RESULT_TRUE if the next pair was returned. */
-  MDBX_SET_LOWERBOUND,
-
-  /** Positions cursor at first key-value pair greater than specified,
-   * return both key and data, and the return code depends on whether a
-   * upper-bound was found.
-   *
-   * For non DUPSORT-ed collections this work the same to \ref MDBX_SET_RANGE,
-   * but returns \ref MDBX_SUCCESS if the greater key was found or
-   * \ref MDBX_NOTFOUND otherwise.
-   *
-   * For DUPSORT-ed a data value is taken into account for duplicates,
-   * i.e. for a pairs/tuples of a key and an each data value of duplicates.
-   * Returns \ref MDBX_SUCCESS if the greater pair was returned or
-   * \ref MDBX_NOTFOUND otherwise. */
-  MDBX_SET_UPPERBOUND
-};
-#ifndef __cplusplus
-/** \ingroup c_cursors */
-typedef enum MDBX_cursor_op MDBX_cursor_op;
-#endif
-
-/** \brief Errors and return codes
- * \ingroup c_err
- *
- * BerkeleyDB uses -30800 to -30999, we'll go under them
- * \see mdbx_strerror() \see mdbx_strerror_r() \see mdbx_liberr2str() */
-enum MDBX_error_t {
-  /** Successful result */
-  MDBX_SUCCESS = 0,
-
-  /** Alias for \ref MDBX_SUCCESS */
-  MDBX_RESULT_FALSE = MDBX_SUCCESS,
-
-  /** Successful result with special meaning or a flag */
-  MDBX_RESULT_TRUE = -1,
-
-  /** key/data pair already exists */
-  MDBX_KEYEXIST = -30799,
-
-  /** The first LMDB-compatible defined error code */
-  MDBX_FIRST_LMDB_ERRCODE = MDBX_KEYEXIST,
-
-  /** key/data pair not found (EOF) */
-  MDBX_NOTFOUND = -30798,
-
-  /** Requested page not found - this usually indicates corruption */
-  MDBX_PAGE_NOTFOUND = -30797,
-
-  /** Database is corrupted (page was wrong type and so on) */
-  MDBX_CORRUPTED = -30796,
-
-  /** Environment had fatal error,
-   * i.e. update of meta page failed and so on. */
-  MDBX_PANIC = -30795,
-
-  /** DB file version mismatch with libmdbx */
-  MDBX_VERSION_MISMATCH = -30794,
-
-  /** File is not a valid MDBX file */
-  MDBX_INVALID = -30793,
-
-  /** Environment mapsize reached */
-  MDBX_MAP_FULL = -30792,
-
-  /** Environment maxdbs reached */
-  MDBX_DBS_FULL = -30791,
-
-  /** Environment maxreaders reached */
-  MDBX_READERS_FULL = -30790,
-
-  /** Transaction has too many dirty pages, i.e transaction too big */
-  MDBX_TXN_FULL = -30788,
-
-  /** Cursor stack too deep - this usually indicates corruption,
-   * i.e branch-pages loop */
-  MDBX_CURSOR_FULL = -30787,
-
-  /** Page has not enough space - internal error */
-  MDBX_PAGE_FULL = -30786,
-
-  /** Database engine was unable to extend mapping, e.g. since address space
-   * is unavailable or busy. This can mean:
-   *  - Database size extended by other process beyond to environment mapsize
-   *    and engine was unable to extend mapping while starting read
-   *    transaction. Environment should be reopened to continue.
-   *  - Engine was unable to extend mapping during write transaction
-   *    or explicit call of \ref mdbx_env_set_geometry(). */
-  MDBX_UNABLE_EXTEND_MAPSIZE = -30785,
-
-  /** Environment or database is not compatible with the requested operation
-   * or the specified flags. This can mean:
-   *  - The operation expects an \ref MDBX_DUPSORT / \ref MDBX_DUPFIXED
-   *    database.
-   *  - Opening a named DB when the unnamed DB has \ref MDBX_DUPSORT /
-   *    \ref MDBX_INTEGERKEY.
-   *  - Accessing a data record as a database, or vice versa.
-   *  - The database was dropped and recreated with different flags. */
-  MDBX_INCOMPATIBLE = -30784,
-
-  /** Invalid reuse of reader locktable slot,
-   * e.g. read-transaction already run for current thread */
-  MDBX_BAD_RSLOT = -30783,
-
-  /** Transaction is not valid for requested operation,
-   * e.g. had errored and be must aborted, has a child, or is invalid */
-  MDBX_BAD_TXN = -30782,
-
-  /** Invalid size or alignment of key or data for target database,
-   * either invalid subDB name */
-  MDBX_BAD_VALSIZE = -30781,
-
-  /** The specified DBI-handle is invalid
-   * or changed by another thread/transaction */
-  MDBX_BAD_DBI = -30780,
-
-  /** Unexpected internal error, transaction should be aborted */
-  MDBX_PROBLEM = -30779,
-
-  /** The last LMDB-compatible defined error code */
-  MDBX_LAST_LMDB_ERRCODE = MDBX_PROBLEM,
-
-  /** Another write transaction is running or environment is already used while
-   * opening with \ref MDBX_EXCLUSIVE flag */
-  MDBX_BUSY = -30778,
-
-  /** The first of MDBX-added error codes */
-  MDBX_FIRST_ADDED_ERRCODE = MDBX_BUSY,
-
-  /** The specified key has more than one associated value */
-  MDBX_EMULTIVAL = -30421,
-
-  /** Bad signature of a runtime object(s), this can mean:
-   *  - memory corruption or double-free;
-   *  - ABI version mismatch (rare case); */
-  MDBX_EBADSIGN = -30420,
-
-  /** Database should be recovered, but this could NOT be done for now
-   * since it opened in read-only mode */
-  MDBX_WANNA_RECOVERY = -30419,
-
-  /** The given key value is mismatched to the current cursor position */
-  MDBX_EKEYMISMATCH = -30418,
-
-  /** Database is too large for current system,
-   * e.g. could NOT be mapped into RAM. */
-  MDBX_TOO_LARGE = -30417,
-
-  /** A thread has attempted to use a not owned object,
-   * e.g. a transaction that started by another thread. */
-  MDBX_THREAD_MISMATCH = -30416,
-
-  /** Overlapping read and write transactions for the current thread */
-  MDBX_TXN_OVERLAPPING = -30415,
-
-  /* The last of MDBX-added error codes */
-  MDBX_LAST_ADDED_ERRCODE = MDBX_TXN_OVERLAPPING,
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_ENODATA = ERROR_HANDLE_EOF,
-  MDBX_EINVAL = ERROR_INVALID_PARAMETER,
-  MDBX_EACCESS = ERROR_ACCESS_DENIED,
-  MDBX_ENOMEM = ERROR_OUTOFMEMORY,
-  MDBX_EROFS = ERROR_FILE_READ_ONLY,
-  MDBX_ENOSYS = ERROR_NOT_SUPPORTED,
-  MDBX_EIO = ERROR_WRITE_FAULT,
-  MDBX_EPERM = ERROR_INVALID_FUNCTION,
-  MDBX_EINTR = ERROR_CANCELLED,
-  MDBX_ENOFILE = ERROR_FILE_NOT_FOUND,
-  MDBX_EREMOTE = ERROR_REMOTE_STORAGE_MEDIA_ERROR
-#else /* Windows */
-#ifdef ENODATA
-  MDBX_ENODATA = ENODATA,
-#else
-  MDBX_ENODATA = 9919 /* for compatibility with LLVM's C++ libraries/headers */,
-#endif /* ENODATA */
-  MDBX_EINVAL = EINVAL,
-  MDBX_EACCESS = EACCES,
-  MDBX_ENOMEM = ENOMEM,
-  MDBX_EROFS = EROFS,
-  MDBX_ENOSYS = ENOSYS,
-  MDBX_EIO = EIO,
-  MDBX_EPERM = EPERM,
-  MDBX_EINTR = EINTR,
-  MDBX_ENOFILE = ENOENT,
-  MDBX_EREMOTE = ENOTBLK
-#endif /* !Windows */
-};
-#ifndef __cplusplus
-/** \ingroup c_err */
-typedef enum MDBX_error_t MDBX_error_t;
-#endif
-
-/** MDBX_MAP_RESIZED
- * \ingroup c_err
- * \deprecated Please review your code to use MDBX_UNABLE_EXTEND_MAPSIZE
- * instead. */
-MDBX_DEPRECATED static __inline int MDBX_MAP_RESIZED_is_deprecated() {
-  return MDBX_UNABLE_EXTEND_MAPSIZE;
-}
-#define MDBX_MAP_RESIZED MDBX_MAP_RESIZED_is_deprecated()
-
-/** \brief Return a string describing a given error code.
- * \ingroup c_err
- *
- * This function is a superset of the ANSI C X3.159-1989 (ANSI C) `strerror()`
- * function. If the error code is greater than or equal to 0, then the string
- * returned by the system function `strerror()` is returned. If the error code
- * is less than 0, an error string corresponding to the MDBX library error is
- * returned. See errors for a list of MDBX-specific error codes.
- *
- * `mdbx_strerror()` is NOT thread-safe because may share common internal buffer
- * for system messages. The returned string must NOT be modified by the
- * application, but MAY be modified by a subsequent call to
- * \ref mdbx_strerror(), `strerror()` and other related functions.
- * \see mdbx_strerror_r()
- *
- * \param [in] errnum  The error code.
- *
- * \returns "error message" The description of the error. */
-LIBMDBX_API const char *mdbx_strerror(int errnum);
-
-/** \brief Return a string describing a given error code.
- * \ingroup c_err
- *
- * This function is a superset of the ANSI C X3.159-1989 (ANSI C) `strerror()`
- * function. If the error code is greater than or equal to 0, then the string
- * returned by the system function `strerror()` is returned. If the error code
- * is less than 0, an error string corresponding to the MDBX library error is
- * returned. See errors for a list of MDBX-specific error codes.
- *
- * `mdbx_strerror_r()` is thread-safe since uses user-supplied buffer where
- * appropriate. The returned string must NOT be modified by the application,
- * since it may be pointer to internal constant string. However, there is no
- * restriction if the returned string points to the supplied buffer.
- * \see mdbx_strerror()
- *
- * mdbx_liberr2str() returns string describing only MDBX error numbers but NULL
- * for non-MDBX error codes. This function is thread-safe since return pointer
- * to constant non-localized strings.
- *
- * \param [in] errnum  The error code.
- * \param [in,out] buf Buffer to store the error message.
- * \param [in] buflen The size of buffer to store the message.
- *
- * \returns "error message" The description of the error. */
-LIBMDBX_API const char *mdbx_strerror_r(int errnum, char *buf, size_t buflen);
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API const char *mdbx_liberr2str(int errnum);
-
-#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
-/** Bit of Windows' madness. The similar to \ref mdbx_strerror() but returns
- * Windows error-messages in the OEM-encoding for console utilities.
- * \ingroup c_err
- * \see mdbx_strerror_r_ANSI2OEM() */
-LIBMDBX_API const char *mdbx_strerror_ANSI2OEM(int errnum);
-
-/** Bit of Windows' madness. The similar to \ref mdbx_strerror_r() but returns
- * Windows error-messages in the OEM-encoding for console utilities.
- * \ingroup c_err
- * \see mdbx_strerror_ANSI2OEM() */
-LIBMDBX_API const char *mdbx_strerror_r_ANSI2OEM(int errnum, char *buf,
-                                                 size_t buflen);
-#endif /* Bit of Windows' madness */
-
-/** \brief Create an MDBX environment instance.
- * \ingroup c_opening
- *
- * This function allocates memory for a \ref MDBX_env structure. To release
- * the allocated memory and discard the handle, call \ref mdbx_env_close().
- * Before the handle may be used, it must be opened using \ref mdbx_env_open().
- *
- * Various other options may also need to be set before opening the handle,
- * e.g. \ref mdbx_env_set_geometry(), \ref mdbx_env_set_maxreaders(),
- * \ref mdbx_env_set_maxdbs(), depending on usage requirements.
- *
- * \param [out] penv  The address where the new handle will be stored.
- *
- * \returns a non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_create(MDBX_env **penv);
-
-/** \brief MDBX environment options. */
-enum MDBX_option_t {
-  /** \brief Controls the maximum number of named databases for the environment.
-   *
-   * \details By default only unnamed key-value database could used and
-   * appropriate value should set by `MDBX_opt_max_db` to using any more named
-   * subDB(s). To reduce overhead, use the minimum sufficient value. This option
-   * may only set after \ref mdbx_env_create() and before \ref mdbx_env_open().
-   *
-   * \see mdbx_env_set_maxdbs() \see mdbx_env_get_maxdbs() */
-  MDBX_opt_max_db,
-
-  /** \brief Defines the maximum number of threads/reader slots
-   * for all processes interacting with the database.
-   *
-   * \details This defines the number of slots in the lock table that is used to
-   * track readers in the the environment. The default is about 100 for 4K
-   * system page size. Starting a read-only transaction normally ties a lock
-   * table slot to the current thread until the environment closes or the thread
-   * exits. If \ref MDBX_NOTLS is in use, \ref mdbx_txn_begin() instead ties the
-   * slot to the \ref MDBX_txn object until it or the \ref MDBX_env object is
-   * destroyed. This option may only set after \ref mdbx_env_create() and before
-   * \ref mdbx_env_open(), and has an effect only when the database is opened by
-   * the first process interacts with the database.
-   *
-   * \see mdbx_env_set_maxreaders() \see mdbx_env_get_maxreaders() */
-  MDBX_opt_max_readers,
-
-  /** \brief Controls interprocess/shared threshold to force flush the data
-   * buffers to disk, if \ref MDBX_SAFE_NOSYNC is used.
-   *
-   * \see mdbx_env_set_syncbytes() \see mdbx_env_get_syncbytes() */
-  MDBX_opt_sync_bytes,
-
-  /** \brief Controls interprocess/shared relative period since the last
-   * unsteady commit to force flush the data buffers to disk,
-   * if \ref MDBX_SAFE_NOSYNC is used.
-   * \see mdbx_env_set_syncperiod() \see mdbx_env_get_syncperiod() */
-  MDBX_opt_sync_period,
-
-  /** \brief Controls the in-process limit to grow a list of reclaimed/recycled
-   * page's numbers for finding a sequence of contiguous pages for large data
-   * items.
-   *
-   * \details A long values requires allocation of contiguous database pages.
-   * To find such sequences, it may be necessary to accumulate very large lists,
-   * especially when placing very long values (more than a megabyte) in a large
-   * databases (several tens of gigabytes), which is much expensive in extreme
-   * cases. This threshold allows you to avoid such costs by allocating new
-   * pages at the end of the database (with its possible growth on disk),
-   * instead of further accumulating/reclaiming Garbage Collection records.
-   *
-   * On the other hand, too small threshold will lead to unreasonable database
-   * growth, or/and to the inability of put long values.
-   *
-   * The `MDBX_opt_rp_augment_limit` controls described limit for the current
-   * process. Default is 262144, it is usually enough for most cases. */
-  MDBX_opt_rp_augment_limit,
-
-  /** \brief Controls the in-process limit to grow a cache of dirty
-   * pages for reuse in the current transaction.
-   *
-   * \details A 'dirty page' refers to a page that has been updated in memory
-   * only, the changes to a dirty page are not yet stored on disk.
-   * To reduce overhead, it is reasonable to release not all such pages
-   * immediately, but to leave some ones in cache for reuse in the current
-   * transaction.
-   *
-   * The `MDBX_opt_loose_limit` allows you to set a limit for such cache inside
-   * the current process. Should be in the range 0..255, default is 64. */
-  MDBX_opt_loose_limit,
-
-  /** \brief Controls the in-process limit of a pre-allocated memory items
-   * for dirty pages.
-   *
-   * \details A 'dirty page' refers to a page that has been updated in memory
-   * only, the changes to a dirty page are not yet stored on disk.
-   * Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and
-   * released when a transaction is committed. To reduce overhead, it is
-   * reasonable to release not all ones, but to leave some allocations in
-   * reserve for reuse in the next transaction(s).
-   *
-   * The `MDBX_opt_dp_reserve_limit` allows you to set a limit for such reserve
-   * inside the current process. Default is 1024. */
-  MDBX_opt_dp_reserve_limit,
-
-  /** \brief Controls the in-process limit of dirty pages
-   * for a write transaction.
-   *
-   * \details A 'dirty page' refers to a page that has been updated in memory
-   * only, the changes to a dirty page are not yet stored on disk.
-   * Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and will
-   * be busy until are written to disk. Therefore for a large transactions is
-   * reasonable to limit dirty pages collecting above an some threshold but
-   * spill to disk instead.
-   *
-   * The `MDBX_opt_txn_dp_limit` controls described threshold for the current
-   * process. Default is 65536, it is usually enough for most cases. */
-  MDBX_opt_txn_dp_limit,
-
-  /** \brief Controls the in-process initial allocation size for dirty pages
-   * list of a write transaction. Default is 1024. */
-  MDBX_opt_txn_dp_initial,
-
-  /** \brief Controls the in-process how maximal part of the dirty pages may be
-   * spilled when necessary.
-   *
-   * \details The `MDBX_opt_spill_max_denominator` defines the denominator for
-   * limiting from the top for part of the current dirty pages may be spilled
-   * when the free room for a new dirty pages (i.e. distance to the
-   * `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
-   * operation.
-   * Exactly `max_pages_to_spill = dirty_pages - dirty_pages / N`,
-   * where `N` is the value set by `MDBX_opt_spill_max_denominator`.
-   *
-   * Should be in the range 0..255, where zero means no limit, i.e. all dirty
-   * pages could be spilled. Default is 8, i.e. no more than 7/8 of the current
-   * dirty pages may be spilled when reached the condition described above. */
-  MDBX_opt_spill_max_denominator,
-
-  /** \brief Controls the in-process how minimal part of the dirty pages should
-   * be spilled when necessary.
-   *
-   * \details The `MDBX_opt_spill_min_denominator` defines the denominator for
-   * limiting from the bottom for part of the current dirty pages should be
-   * spilled when the free room for a new dirty pages (i.e. distance to the
-   * `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
-   * operation.
-   * Exactly `min_pages_to_spill = dirty_pages / N`,
-   * where `N` is the value set by `MDBX_opt_spill_min_denominator`.
-   *
-   * Should be in the range 0..255, where zero means no restriction at the
-   * bottom. Default is 8, i.e. at least the 1/8 of the current dirty pages
-   * should be spilled when reached the condition described above. */
-  MDBX_opt_spill_min_denominator,
-
-  /** \brief Controls the in-process how much of the parent transaction dirty
-   * pages will be spilled while start each child transaction.
-   *
-   * \details The `MDBX_opt_spill_parent4child_denominator` defines the
-   * denominator to determine how much of parent transaction dirty pages will be
-   * spilled explicitly while start each child transaction.
-   * Exactly `pages_to_spill = dirty_pages / N`,
-   * where `N` is the value set by `MDBX_opt_spill_parent4child_denominator`.
-   *
-   * For a stack of nested transactions each dirty page could be spilled only
-   * once, and parent's dirty pages couldn't be spilled while child
-   * transaction(s) are running. Therefore a child transaction could reach
-   * \ref MDBX_TXN_FULL when parent(s) transaction has  spilled too less (and
-   * child reach the limit of dirty pages), either when parent(s) has spilled
-   * too more (since child can't spill already spilled pages). So there is no
-   * universal golden ratio.
-   *
-   * Should be in the range 0..255, where zero means no explicit spilling will
-   * be performed during starting nested transactions.
-   * Default is 0, i.e. by default no spilling performed during starting nested
-   * transactions, that correspond historically behaviour. */
-  MDBX_opt_spill_parent4child_denominator,
-
-  /** \brief Controls the in-process threshold of semi-empty pages merge.
-   * \warning This is experimental option and subject for change or removal.
-   * \details This option controls the in-process threshold of minimum page
-   * fill, as used space of percentage of a page. Neighbour pages emptier than
-   * this value are candidates for merging. The threshold value is specified
-   * in 1/65536 of percent, which is equivalent to the 16-dot-16 fixed point
-   * format. The specified value must be in the range from 12.5% (almost empty)
-   * to 50% (half empty) which corresponds to the range from 8192 and to 32768
-   * in units respectively. */
-  MDBX_opt_merge_threshold_16dot16_percent,
-};
-#ifndef __cplusplus
-/** \ingroup c_settings */
-typedef enum MDBX_option_t MDBX_option_t;
-#endif
-
-/** \brief Sets the value of a runtime options for an environment.
- * \ingroup c_settings
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- * \param [in] option  The option from \ref MDBX_option_t to set value of it.
- * \param [in] value   The value of option to be set.
- *
- * \see MDBX_option_t
- * \see mdbx_env_get_option()
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option,
-                                    uint64_t value);
-
-/** \brief Gets the value of runtime options from an environment.
- * \ingroup c_settings
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- * \param [in] option  The option from \ref MDBX_option_t to get value of it.
- * \param [out] pvalue The address where the option's value will be stored.
- *
- * \see MDBX_option_t
- * \see mdbx_env_get_option()
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env,
-                                    const MDBX_option_t option,
-                                    uint64_t *pvalue);
-
-/** \brief Open an environment instance.
- * \ingroup c_opening
- *
- * Indifferently this function will fails or not, the \ref mdbx_env_close() must
- * be called later to discard the \ref MDBX_env handle and release associated
- * resources.
- *
- * \param [in] env       An environment handle returned
- *                       by \ref mdbx_env_create()
- *
- * \param [in] pathname  The pathname for the database or the directory in which
- *                       the database files reside. In the case of directory it
- *                       must already exist and be writable.
- *
- * \param [in] flags     Specifies options for this environment.
- *                       This parameter must be bitwise OR'ing together
- *                       any constants described above in the \ref env_flags
- *                       and \ref sync_modes sections.
- *
- * Flags set by mdbx_env_set_flags() are also used:
- *  - \ref MDBX_ENV_DEFAULTS, \ref MDBX_NOSUBDIR, \ref MDBX_RDONLY,
- *    \ref MDBX_EXCLUSIVE, \ref MDBX_WRITEMAP, \ref MDBX_NOTLS,
- *    \ref MDBX_NORDAHEAD, \ref MDBX_NOMEMINIT, \ref MDBX_COALESCE,
- *    \ref MDBX_LIFORECLAIM. See \ref env_flags section.
- *
- *  - \ref MDBX_SYNC_DURABLE, \ref MDBX_NOMETASYNC, \ref MDBX_SAFE_NOSYNC,
- *    \ref MDBX_UTTERLY_NOSYNC. See \ref sync_modes section.
- *
- * \note `MDB_NOLOCK` flag don't supported by MDBX,
- *       try use \ref MDBX_EXCLUSIVE as a replacement.
- *
- * \note MDBX don't allow to mix processes with different \ref MDBX_SAFE_NOSYNC
- *       flags on the same environment.
- *       In such case \ref MDBX_INCOMPATIBLE will be returned.
- *
- * If the database is already exist and parameters specified early by
- * \ref mdbx_env_set_geometry() are incompatible (i.e. for instance, different
- * page size) then \ref mdbx_env_open() will return \ref MDBX_INCOMPATIBLE
- * error.
- *
- * \param [in] mode   The UNIX permissions to set on created files.
- *                    Zero value means to open existing, but do not create.
- *
- * \return A non-zero error value on failure and 0 on success,
- *         some possible errors are:
- * \retval MDBX_VERSION_MISMATCH The version of the MDBX library doesn't match
- *                            the version that created the database environment.
- * \retval MDBX_INVALID       The environment file headers are corrupted.
- * \retval MDBX_ENOENT        The directory specified by the path parameter
- *                            doesn't exist.
- * \retval MDBX_EACCES        The user didn't have permission to access
- *                            the environment files.
- * \retval MDBX_EAGAIN        The environment was locked by another process.
- * \retval MDBX_BUSY          The \ref MDBX_EXCLUSIVE flag was specified and the
- *                            environment is in use by another process,
- *                            or the current process tries to open environment
- *                            more than once.
- * \retval MDBX_INCOMPATIBLE  Environment is already opened by another process,
- *                            but with different set of \ref MDBX_SAFE_NOSYNC,
- *                            \ref MDBX_UTTERLY_NOSYNC flags.
- *                            Or if the database is already exist and parameters
- *                            specified early by \ref mdbx_env_set_geometry()
- *                            are incompatible (i.e. different pagesize, etc).
- *
- * \retval MDBX_WANNA_RECOVERY The \ref MDBX_RDONLY flag was specified but
- *                             read-write access is required to rollback
- *                             inconsistent state after a system crash.
- *
- * \retval MDBX_TOO_LARGE      Database is too large for this process,
- *                             i.e. 32-bit process tries to open >4Gb database.
- */
-LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname,
-                              MDBX_env_flags_t flags, mdbx_mode_t mode);
-
-/** \brief Deletion modes for \ref mdbx_env_delete().
- * \ingroup c_extra
- * \see mdbx_env_delete() */
-enum MDBX_env_delete_mode_t {
-  /** \brief Just delete the environment's files and directory if any.
-   * \note On POSIX systems, processes already working with the database will
-   * continue to work without interference until it close the environment.
-   * \note On Windows, the behavior of `MDB_ENV_JUST_DELETE` is different
-   * because the system does not support deleting files that are currently
-   * memory mapped. */
-  MDBX_ENV_JUST_DELETE = 0,
-  /** \brief Make sure that the environment is not being used by other
-   * processes, or return an error otherwise. */
-  MDBX_ENV_ENSURE_UNUSED = 1,
-  /** \brief Wait until other processes closes the environment before deletion.
-   */
-  MDBX_ENV_WAIT_FOR_UNUSED = 2,
-};
-#ifndef __cplusplus
-/** \ingroup c_extra */
-typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t;
-#endif
-
-/** \brief Delete the environment's files in a proper and multiprocess-safe way.
- * \ingroup c_extra
- *
- * \param [in] pathname  The pathname for the database or the directory in which
- *                       the database files reside.
- *
- * \param [in] mode      Specifies deletion mode for the environment. This
- *                       parameter must be set to one of the constants described
- *                       above in the \ref MDBX_env_delete_mode_t section.
- *
- * \note The \ref MDBX_ENV_JUST_DELETE don't supported on Windows since system
- * unable to delete a memory-mapped files.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_RESULT_TRUE   No corresponding files or directories were found,
- *                            so no deletion was performed. */
-LIBMDBX_API int mdbx_env_delete(const char *pathname,
-                                MDBX_env_delete_mode_t mode);
-
-/** \brief Copy an MDBX environment to the specified path, with options.
- * \ingroup c_extra
- *
- * This function may be used to make a backup of an existing environment.
- * No lockfile is created, since it gets recreated at need.
- * \note This call can trigger significant file size growth if run in
- * parallel with write transactions, because it employs a read-only
- * transaction. See long-lived transactions under \ref restrictions section.
- *
- * \param [in] env    An environment handle returned by mdbx_env_create().
- *                    It must have already been opened successfully.
- * \param [in] dest   The pathname of a file in which the copy will reside.
- *                    This file must not be already exist, but parent directory
- *                    must be writable.
- * \param [in] flags  Specifies options for this operation. This parameter
- *                    must be bitwise OR'ing together any of the constants
- *                    described here:
- *
- *  - \ref MDBX_CP_DEFAULTS
- *      Perform copy as-is without compaction, etc.
- *
- *  - \ref MDBX_CP_COMPACT
- *      Perform compaction while copying: omit free pages and sequentially
- *      renumber all pages in output. This option consumes little bit more
- *      CPU for processing, but may running quickly than the default, on
- *      account skipping free pages.
- *
- *  - \ref MDBX_CP_FORCE_DYNAMIC_SIZE
- *      Force to make resizeable copy, i.e. dynamic size instead of fixed.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_copy(MDBX_env *env, const char *dest,
-                              MDBX_copy_flags_t flags);
-
-/** \brief Copy an environment to the specified file descriptor, with
- * options.
- * \ingroup c_extra
- *
- * This function may be used to make a backup of an existing environment.
- * No lockfile is created, since it gets recreated at need.
- * \see mdbx_env_copy()
- *
- * \note This call can trigger significant file size growth if run in
- *       parallel with write transactions, because it employs a read-only
- *       transaction. See long-lived transactions under \ref restrictions
- *       section.
- *
- * \note Fails if the environment has suffered a page leak and the destination
- *       file descriptor is associated with a pipe, socket, or FIFO.
- *
- * \param [in] env     An environment handle returned by mdbx_env_create().
- *                     It must have already been opened successfully.
- * \param [in] fd      The file descriptor to write the copy to. It must have
- *                     already been opened for Write access.
- * \param [in] flags   Special options for this operation. \see mdbx_env_copy()
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd,
-                                 MDBX_copy_flags_t flags);
-
-/** \brief Statistics for a database in the environment
- * \ingroup c_statinfo
- * \see mdbx_env_stat_ex() \see mdbx_dbi_stat() */
-struct MDBX_stat {
-  uint32_t ms_psize; /**< Size of a database page. This is the same for all
-                        databases. */
-  uint32_t ms_depth; /**< Depth (height) of the B-tree */
-  uint64_t ms_branch_pages;   /**< Number of internal (non-leaf) pages */
-  uint64_t ms_leaf_pages;     /**< Number of leaf pages */
-  uint64_t ms_overflow_pages; /**< Number of overflow pages */
-  uint64_t ms_entries;        /**< Number of data items */
-  uint64_t ms_mod_txnid; /**< Transaction ID of committed last modification */
-};
-#ifndef __cplusplus
-/** \ingroup c_statinfo */
-typedef struct MDBX_stat MDBX_stat;
-#endif
-
-/** \brief Return statistics about the MDBX environment.
- * \ingroup c_statinfo
- *
- * At least one of env or txn argument must be non-null. If txn is passed
- * non-null then stat will be filled accordingly to the given transaction.
- * Otherwise, if txn is null, then stat will be populated by a snapshot from
- * the last committed write transaction, and at next time, other information
- * can be returned.
- *
- * Legacy mdbx_env_stat() correspond to calling \ref mdbx_env_stat_ex() with the
- * null `txn` argument.
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create()
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin()
- * \param [out] stat   The address of an \ref MDBX_stat structure where
- *                     the statistics will be copied
- * \param [in] bytes   The size of \ref MDBX_stat.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn,
-                                 MDBX_stat *stat, size_t bytes);
-
-/** \brief Return statistics about the MDBX environment.
- * \ingroup c_statinfo
- * \deprecated Please use mdbx_env_stat_ex() instead. */
-MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_stat,
-                                   (const MDBX_env *env, MDBX_stat *stat,
-                                    size_t bytes)) {
-  return mdbx_env_stat_ex(env, NULL, stat, bytes);
-}
-
-/** \brief Information about the environment
- * \ingroup c_statinfo
- * \see mdbx_env_info_ex() */
-struct MDBX_envinfo {
-  struct {
-    uint64_t lower;   /**< Lower limit for datafile size */
-    uint64_t upper;   /**< Upper limit for datafile size */
-    uint64_t current; /**< Current datafile size */
-    uint64_t shrink;  /**< Shrink threshold for datafile */
-    uint64_t grow;    /**< Growth step for datafile */
-  } mi_geo;
-  uint64_t mi_mapsize;             /**< Size of the data memory map */
-  uint64_t mi_last_pgno;           /**< Number of the last used page */
-  uint64_t mi_recent_txnid;        /**< ID of the last committed transaction */
-  uint64_t mi_latter_reader_txnid; /**< ID of the last reader transaction */
-  uint64_t mi_self_latter_reader_txnid; /**< ID of the last reader transaction
-                                           of caller process */
-  uint64_t mi_meta0_txnid, mi_meta0_sign;
-  uint64_t mi_meta1_txnid, mi_meta1_sign;
-  uint64_t mi_meta2_txnid, mi_meta2_sign;
-  uint32_t mi_maxreaders;   /**< Total reader slots in the environment */
-  uint32_t mi_numreaders;   /**< Max reader slots used in the environment */
-  uint32_t mi_dxb_pagesize; /**< Database pagesize */
-  uint32_t mi_sys_pagesize; /**< System pagesize */
-
-  /** \brief A mostly unique ID that is regenerated on each boot.
-
-   As such it can be used to identify the local machine's current boot. MDBX
-   uses such when open the database to determine whether rollback required to
-   the last steady sync point or not. I.e. if current bootid is differ from the
-   value within a database then the system was rebooted and all changes since
-   last steady sync must be reverted for data integrity. Zeros mean that no
-   relevant information is available from the system. */
-  struct {
-    struct {
-      uint64_t x, y;
-    } current, meta0, meta1, meta2;
-  } mi_bootid;
-
-  /** Bytes not explicitly synchronized to disk */
-  uint64_t mi_unsync_volume;
-  /** Current auto-sync threshold, see \ref mdbx_env_set_syncbytes(). */
-  uint64_t mi_autosync_threshold;
-  /** Time since the last steady sync in 1/65536 of second */
-  uint32_t mi_since_sync_seconds16dot16;
-  /** Current auto-sync period in 1/65536 of second,
-   * see \ref mdbx_env_set_syncperiod(). */
-  uint32_t mi_autosync_period_seconds16dot16;
-  /** Time since the last readers check in 1/65536 of second,
-   * see \ref mdbx_reader_check(). */
-  uint32_t mi_since_reader_check_seconds16dot16;
-  /** Current environment mode.
-   * The same as \ref mdbx_env_get_flags() returns. */
-  uint32_t mi_mode;
-
-  /** Statistics of page operations.
-   * \details Overall statistics of page operations of all (running, completed
-   * and aborted) transactions in the current multi-process session (since the
-   * first process opened the database after everyone had previously closed it).
-   */
-  struct {
-    uint64_t newly;   /**< Quantity of a new pages added */
-    uint64_t cow;     /**< Quantity of pages copied for update */
-    uint64_t clone;   /**< Quantity of parent's dirty pages clones
-                           for nested transactions */
-    uint64_t split;   /**< Page splits */
-    uint64_t merge;   /**< Page merges */
-    uint64_t spill;   /**< Quantity of spilled dirty pages */
-    uint64_t unspill; /**< Quantity of unspilled/reloaded pages */
-    uint64_t wops;    /**< Number of explicit write operations (not a pages)
-                           to a disk */
-  } mi_pgop_stat;
-};
-#ifndef __cplusplus
-/** \ingroup c_statinfo */
-typedef struct MDBX_envinfo MDBX_envinfo;
-#endif
-
-/** \brief Return information about the MDBX environment.
- * \ingroup c_statinfo
- *
- * At least one of env or txn argument must be non-null. If txn is passed
- * non-null then stat will be filled accordingly to the given transaction.
- * Otherwise, if txn is null, then stat will be populated by a snapshot from
- * the last committed write transaction, and at next time, other information
- * can be returned.
- *
- * Legacy \ref mdbx_env_info() correspond to calling \ref mdbx_env_info_ex()
- * with the null `txn` argument.
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create()
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin()
- * \param [out] info   The address of an \ref MDBX_envinfo structure
- *                     where the information will be copied
- * \param [in] bytes   The size of \ref MDBX_envinfo.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn,
-                                 MDBX_envinfo *info, size_t bytes);
-/** \brief Return information about the MDBX environment.
- * \ingroup c_statinfo
- * \deprecated Please use mdbx_env_info_ex() instead. */
-MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_info,
-                                   (const MDBX_env *env, MDBX_envinfo *info,
-                                    size_t bytes)) {
-  return mdbx_env_info_ex(env, NULL, info, bytes);
-}
-
-/** \brief Flush the environment data buffers to disk.
- * \ingroup c_extra
- *
- * Unless the environment was opened with no-sync flags (\ref MDBX_NOMETASYNC,
- * \ref MDBX_SAFE_NOSYNC and \ref MDBX_UTTERLY_NOSYNC), then
- * data is always written an flushed to disk when \ref mdbx_txn_commit() is
- * called. Otherwise \ref mdbx_env_sync() may be called to manually write and
- * flush unsynced data to disk.
- *
- * Besides, \ref mdbx_env_sync_ex() with argument `force=false` may be used to
- * provide polling mode for lazy/asynchronous sync in conjunction with
- * \ref mdbx_env_set_syncbytes() and/or \ref mdbx_env_set_syncperiod().
- *
- * \note This call is not valid if the environment was opened with MDBX_RDONLY.
- *
- * \param [in] env      An environment handle returned by \ref mdbx_env_create()
- * \param [in] force    If non-zero, force a flush. Otherwise, If force is
- *                      zero, then will run in polling mode,
- *                      i.e. it will check the thresholds that were
- *                      set \ref mdbx_env_set_syncbytes()
- *                      and/or \ref mdbx_env_set_syncperiod() and perform flush
- *                      if at least one of the thresholds is reached.
- *
- * \param [in] nonblock Don't wait if write transaction
- *                      is running by other thread.
- *
- * \returns A non-zero error value on failure and \ref MDBX_RESULT_TRUE or 0 on
- *     success. The \ref MDBX_RESULT_TRUE means no data pending for flush
- *     to disk, and 0 otherwise. Some possible errors are:
- *
- * \retval MDBX_EACCES   the environment is read-only.
- * \retval MDBX_BUSY     the environment is used by other thread
- *                       and `nonblock=true`.
- * \retval MDBX_EINVAL   an invalid parameter was specified.
- * \retval MDBX_EIO      an error occurred during synchronization. */
-LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock);
-
-/** \brief The shortcut to calling \ref mdbx_env_sync_ex() with
- * the `force=true` and `nonblock=false` arguments.
- * \ingroup c_extra */
-LIBMDBX_INLINE_API(int, mdbx_env_sync, (MDBX_env * env)) {
-  return mdbx_env_sync_ex(env, true, false);
-}
-
-/** \brief The shortcut to calling \ref mdbx_env_sync_ex() with
- * the `force=false` and `nonblock=true` arguments.
- * \ingroup c_extra */
-LIBMDBX_INLINE_API(int, mdbx_env_sync_poll, (MDBX_env * env)) {
-  return mdbx_env_sync_ex(env, false, true);
-}
-
-/** \brief Sets threshold to force flush the data buffers to disk, even any of
- * \ref MDBX_SAFE_NOSYNC flag in the environment.
- * \ingroup c_settings
- * \see mdbx_env_get_syncbytes \see MDBX_opt_sync_bytes
- *
- * The threshold value affects all processes which operates with given
- * environment until the last process close environment or a new value will be
- * settled.
- *
- * Data is always written to disk when \ref mdbx_txn_commit() is called, but
- * the operating system may keep it buffered. MDBX always flushes the OS buffers
- * upon commit as well, unless the environment was opened with
- * \ref MDBX_SAFE_NOSYNC, \ref MDBX_UTTERLY_NOSYNC
- * or in part \ref MDBX_NOMETASYNC.
- *
- * The default is 0, than mean no any threshold checked, and no additional
- * flush will be made.
- *
- * \param [in] env         An environment handle returned by mdbx_env_create().
- * \param [in] threshold   The size in bytes of summary changes when
- *                         a synchronous flush would be made.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_INLINE_API(int, mdbx_env_set_syncbytes,
-                   (MDBX_env * env, size_t threshold)) {
-  return mdbx_env_set_option(env, MDBX_opt_sync_bytes, threshold);
-}
-
-/** \brief Get threshold to force flush the data buffers to disk, even any of
- * \ref MDBX_SAFE_NOSYNC flag in the environment.
- * \ingroup c_statinfo
- * \see mdbx_env_set_syncbytes() \see MDBX_opt_sync_bytes
- *
- * \param [in] env       An environment handle returned
- *                       by \ref mdbx_env_create().
- * \param [out] threshold  Address of an size_t to store
- *                         the number of bytes of summary changes when
- *                         a synchronous flush would be made.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL   An invalid parameter was specified. */
-LIBMDBX_INLINE_API(int, mdbx_env_get_syncbytes,
-                   (const MDBX_env *env, size_t *threshold)) {
-  int rc = MDBX_EINVAL;
-  if (threshold) {
-    uint64_t proxy = 0;
-    rc = mdbx_env_get_option(env, MDBX_opt_sync_bytes, &proxy);
-#ifdef assert
-    assert(proxy <= SIZE_MAX);
-#endif /* assert */
-    *threshold = (size_t)proxy;
-  }
-  return rc;
-}
-
-/** \brief Sets relative period since the last unsteady commit to force flush
- * the data buffers to disk, even of \ref MDBX_SAFE_NOSYNC flag in the
- * environment.
- * \ingroup c_settings
- * \see mdbx_env_get_syncperiod \see MDBX_opt_sync_period
- *
- * The relative period value affects all processes which operates with given
- * environment until the last process close environment or a new value will be
- * settled.
- *
- * Data is always written to disk when \ref mdbx_txn_commit() is called, but the
- * operating system may keep it buffered. MDBX always flushes the OS buffers
- * upon commit as well, unless the environment was opened with
- * \ref MDBX_SAFE_NOSYNC or in part \ref MDBX_NOMETASYNC.
- *
- * Settled period don't checked asynchronously, but only by the
- * \ref mdbx_txn_commit() and \ref mdbx_env_sync() functions. Therefore, in
- * cases where transactions are committed infrequently and/or irregularly,
- * polling by \ref mdbx_env_sync() may be a reasonable solution to timeout
- * enforcement.
- *
- * The default is 0, than mean no any timeout checked, and no additional
- * flush will be made.
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- * \param [in] seconds_16dot16  The period in 1/65536 of second when
- *                              a synchronous flush would be made since
- *                              the last unsteady commit.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_INLINE_API(int, mdbx_env_set_syncperiod,
-                   (MDBX_env * env, unsigned seconds_16dot16)) {
-  return mdbx_env_set_option(env, MDBX_opt_sync_period, seconds_16dot16);
-}
-
-/** \brief Get relative period since the last unsteady commit to force flush
- * the data buffers to disk, even of \ref MDBX_SAFE_NOSYNC flag in the
- * environment.
- * \ingroup c_statinfo
- * \see mdbx_env_set_syncperiod() \see MDBX_opt_sync_period
- *
- * \param [in] env       An environment handle returned
- *                       by \ref mdbx_env_create().
- * \param [out] period_seconds_16dot16  Address of an size_t to store
- *                                      the period in 1/65536 of second when
- *                                      a synchronous flush would be made since
- *                                      the last unsteady commit.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL   An invalid parameter was specified. */
-LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod,
-                   (const MDBX_env *env, unsigned *period_seconds_16dot16)) {
-  int rc = MDBX_EINVAL;
-  if (period_seconds_16dot16) {
-    uint64_t proxy = 0;
-    rc = mdbx_env_get_option(env, MDBX_opt_sync_period, &proxy);
-#ifdef assert
-    assert(proxy <= UINT32_MAX);
-#endif /* assert */
-    *period_seconds_16dot16 = (unsigned)proxy;
-  }
-  return rc;
-}
-
-/** \brief Close the environment and release the memory map.
- * \ingroup c_opening
- *
- * Only a single thread may call this function. All transactions, databases,
- * and cursors must already be closed before calling this function. Attempts
- * to use any such handles after calling this function will cause a `SIGSEGV`.
- * The environment handle will be freed and must not be used again after this
- * call.
- *
- * \param [in] env        An environment handle returned by
- *                        \ref mdbx_env_create().
- *
- * \param [in] dont_sync  A dont'sync flag, if non-zero the last checkpoint
- *                        will be kept "as is" and may be still "weak" in the
- *                        \ref MDBX_SAFE_NOSYNC or \ref MDBX_UTTERLY_NOSYNC
- *                        modes. Such "weak" checkpoint will be ignored on
- *                        opening next time, and transactions since the last
- *                        non-weak checkpoint (meta-page update) will rolledback
- *                        for consistency guarantee.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_BUSY   The write transaction is running by other thread,
- *                     in such case \ref MDBX_env instance has NOT be destroyed
- *                     not released!
- *                     \note If any OTHER error code was returned then
- *                     given MDBX_env instance has been destroyed and released.
- *
- * \retval MDBX_EBADSIGN  Environment handle already closed or not valid,
- *                        i.e. \ref mdbx_env_close() was already called for the
- *                        `env` or was not created by \ref mdbx_env_create().
- *
- * \retval MDBX_PANIC  If \ref mdbx_env_close_ex() was called in the child
- *                     process after `fork()`. In this case \ref MDBX_PANIC
- *                     is expected, i.e. \ref MDBX_env instance was freed in
- *                     proper manner.
- *
- * \retval MDBX_EIO    An error occurred during synchronization. */
-LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync);
-
-/** \brief The shortcut to calling \ref mdbx_env_close_ex() with
- * the `dont_sync=false` argument.
- * \ingroup c_opening */
-LIBMDBX_INLINE_API(int, mdbx_env_close, (MDBX_env * env)) {
-  return mdbx_env_close_ex(env, false);
-}
-
-/** \brief Set environment flags.
- * \ingroup c_settings
- *
- * This may be used to set some flags in addition to those from
- * mdbx_env_open(), or to unset these flags.
- * \see mdbx_env_get_flags()
- *
- * \note In contrast to LMDB, the MDBX serialize threads via mutex while
- * changing the flags. Therefore this function will be blocked while a write
- * transaction running by other thread, or \ref MDBX_BUSY will be returned if
- * function called within a write transaction.
- *
- * \param [in] env      An environment handle returned
- *                      by \ref mdbx_env_create().
- * \param [in] flags    The \ref env_flags to change, bitwise OR'ed together.
- * \param [in] onoff    A non-zero value sets the flags, zero clears them.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL  An invalid parameter was specified. */
-LIBMDBX_API int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags,
-                                   bool onoff);
-
-/** \brief Get environment flags.
- * \ingroup c_statinfo
- * \see mdbx_env_set_flags()
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- * \param [out] flags  The address of an integer to store the flags.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL An invalid parameter was specified. */
-LIBMDBX_API int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags);
-
-/** \brief Return the path that was used in mdbx_env_open().
- * \ingroup c_statinfo
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create()
- * \param [out] dest   Address of a string pointer to contain the path.
- *                     This is the actual string in the environment, not a
- *                     copy. It should not be altered in any way.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL  An invalid parameter was specified. */
-LIBMDBX_API int mdbx_env_get_path(const MDBX_env *env, const char **dest);
-
-/** \brief Return the file descriptor for the given environment.
- * \ingroup c_statinfo
- *
- * \note All MDBX file descriptors have `FD_CLOEXEC` and
- *       couldn't be used after exec() and or `fork()`.
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- * \param [out] fd   Address of a int to contain the descriptor.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL  An invalid parameter was specified. */
-LIBMDBX_API int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *fd);
-
-/** \brief Set all size-related parameters of environment, including page size
- * and the min/max size of the memory map.
- * \ingroup c_settings
- *
- * In contrast to LMDB, the MDBX provide automatic size management of an
- * database according the given parameters, including shrinking and resizing
- * on the fly. From user point of view all of these just working. Nevertheless,
- * it is reasonable to know some details in order to make optimal decisions
- * when choosing parameters.
- *
- * Both \ref mdbx_env_set_geometry() and legacy \ref mdbx_env_set_mapsize() are
- * inapplicable to read-only opened environment.
- *
- * Both \ref mdbx_env_set_geometry() and legacy \ref mdbx_env_set_mapsize()
- * could be called either before or after \ref mdbx_env_open(), either within
- * the write transaction running by current thread or not:
- *
- *  - In case \ref mdbx_env_set_geometry() or legacy \ref mdbx_env_set_mapsize()
- *    was called BEFORE \ref mdbx_env_open(), i.e. for closed environment, then
- *    the specified parameters will be used for new database creation,
- *    or will be applied during opening if database exists and no other process
- *    using it.
- *
- *    If the database is already exist, opened with \ref MDBX_EXCLUSIVE or not
- *    used by any other process, and parameters specified by
- *    \ref mdbx_env_set_geometry() are incompatible (i.e. for instance,
- *    different page size) then \ref mdbx_env_open() will return
- *    \ref MDBX_INCOMPATIBLE error.
- *
- *    In another way, if database will opened read-only or will used by other
- *    process during calling \ref mdbx_env_open() that specified parameters will
- *    silently discarded (open the database with \ref MDBX_EXCLUSIVE flag
- *    to avoid this).
- *
- *  - In case \ref mdbx_env_set_geometry() or legacy \ref mdbx_env_set_mapsize()
- *    was called after \ref mdbx_env_open() WITHIN the write transaction running
- *    by current thread, then specified parameters will be applied as a part of
- *    write transaction, i.e. will not be completely visible to any others
- *    processes until the current write transaction has been committed by the
- *    current process. However, if transaction will be aborted, then the
- *    database file will be reverted to the previous size not immediately, but
- *    when a next transaction will be committed or when the database will be
- *    opened next time.
- *
- *  - In case \ref mdbx_env_set_geometry() or legacy \ref mdbx_env_set_mapsize()
- *    was called after \ref mdbx_env_open() but OUTSIDE a write transaction,
- *    then MDBX will execute internal pseudo-transaction to apply new parameters
- *    (but only if anything has been changed), and changes be visible to any
- *    others processes immediately after succesful completion of function.
- *
- * Essentially a concept of "automatic size management" is simple and useful:
- *  - There are the lower and upper bounds of the database file size;
- *  - There is the growth step by which the database file will be increased,
- *    in case of lack of space;
- *  - There is the threshold for unused space, beyond which the database file
- *    will be shrunk;
- *  - The size of the memory map is also the maximum size of the database;
- *  - MDBX will automatically manage both the size of the database and the size
- *    of memory map, according to the given parameters.
- *
- * So, there some considerations about choosing these parameters:
- *  - The lower bound allows you to prevent database shrinking below certain
- *    reasonable size to avoid unnecessary resizing costs.
- *  - The upper bound allows you to prevent database growth above certain
- *    reasonable size. Besides, the upper bound defines the linear address space
- *    reservation in each process that opens the database. Therefore changing
- *    the upper bound is costly and may be required reopening environment in
- *    case of \ref MDBX_UNABLE_EXTEND_MAPSIZE errors, and so on. Therefore, this
- *    value should be chosen reasonable large, to accommodate future growth of
- *    the database.
- *  - The growth step must be greater than zero to allow the database to grow,
- *    but also reasonable not too small, since increasing the size by little
- *    steps will result a large overhead.
- *  - The shrink threshold must be greater than zero to allow the database
- *    to shrink but also reasonable not too small (to avoid extra overhead) and
- *    not less than growth step to avoid up-and-down flouncing.
- *  - The current size (i.e. `size_now` argument) is an auxiliary parameter for
- *    simulation legacy \ref mdbx_env_set_mapsize() and as workaround Windows
- *    issues (see below).
- *
- * Unfortunately, Windows has is a several issue
- * with resizing of memory-mapped file:
- *  - Windows unable shrinking a memory-mapped file (i.e memory-mapped section)
- *    in any way except unmapping file entirely and then map again. Moreover,
- *    it is impossible in any way when a memory-mapped file is used more than
- *    one process.
- *  - Windows does not provide the usual API to augment a memory-mapped file
- *    (i.e. a memory-mapped partition), but only by using "Native API"
- *    in an undocumented way.
- *
- * MDBX bypasses all Windows issues, but at a cost:
- *  - Ability to resize database on the fly requires an additional lock
- *    and release `SlimReadWriteLock` during each read-only transaction.
- *  - During resize all in-process threads should be paused and then resumed.
- *  - Shrinking of database file is performed only when it used by single
- *    process, i.e. when a database closes by the last process or opened
- *    by the first.
- *  = Therefore, the size_now argument may be useful to set database size
- *    by the first process which open a database, and thus avoid expensive
- *    remapping further.
- *
- * For create a new database with particular parameters, including the page
- * size, \ref mdbx_env_set_geometry() should be called after
- * \ref mdbx_env_create() and before \ref mdbx_env_open(). Once the database is
- * created, the page size cannot be changed. If you do not specify all or some
- * of the parameters, the corresponding default values will be used. For
- * instance, the default for database size is 10485760 bytes.
- *
- * If the mapsize is increased by another process, MDBX silently and
- * transparently adopt these changes at next transaction start. However,
- * \ref mdbx_txn_begin() will return \ref MDBX_UNABLE_EXTEND_MAPSIZE if new
- * mapping size could not be applied for current process (for instance if
- * address space is busy).  Therefore, in the case of
- * \ref MDBX_UNABLE_EXTEND_MAPSIZE error you need close and reopen the
- * environment to resolve error.
- *
- * \note Actual values may be different than your have specified because of
- * rounding to specified database page size, the system page size and/or the
- * size of the system virtual memory management unit. You can get actual values
- * by \ref mdbx_env_sync_ex() or see by using the tool `mdbx_chk` with the `-v`
- * option.
- *
- * Legacy \ref mdbx_env_set_mapsize() correspond to calling
- * \ref mdbx_env_set_geometry() with the arguments `size_lower`, `size_now`,
- * `size_upper` equal to the `size` and `-1` (i.e. default) for all other
- * parameters.
- *
- * \param [in] env         An environment handle returned
- *                         by \ref mdbx_env_create()
- *
- * \param [in] size_lower  The lower bound of database size in bytes.
- *                         Zero value means "minimal acceptable",
- *                         and negative means "keep current or use default".
- *
- * \param [in] size_now    The size in bytes to setup the database size for
- *                         now. Zero value means "minimal acceptable", and
- *                         negative means "keep current or use default". So,
- *                         it is recommended always pass -1 in this argument
- *                         except some special cases.
- *
- * \param [in] size_upper The upper bound of database size in bytes.
- *                        Zero value means "minimal acceptable",
- *                        and negative means "keep current or use default".
- *                        It is recommended to avoid change upper bound while
- *                        database is used by other processes or threaded
- *                        (i.e. just pass -1 in this argument except absolutely
- *                        necessary). Otherwise you must be ready for
- *                        \ref MDBX_UNABLE_EXTEND_MAPSIZE error(s), unexpected
- *                        pauses during remapping and/or system errors like
- *                        "address busy", and so on. In other words, there
- *                        is no way to handle a growth of the upper bound
- *                        robustly because there may be a lack of appropriate
- *                        system resources (which are extremely volatile in
- *                        a multi-process multi-threaded environment).
- *
- * \param [in] growth_step  The growth step in bytes, must be greater than
- *                          zero to allow the database to grow. Negative value
- *                          means "keep current or use default".
- *
- * \param [in] shrink_threshold  The shrink threshold in bytes, must be greater
- *                               than zero to allow the database to shrink and
- *                               greater than growth_step to avoid shrinking
- *                               right after grow.
- *                               Negative value means "keep current
- *                               or use default". Default is 2*growth_step.
- *
- * \param [in] pagesize          The database page size for new database
- *                               creation or -1 otherwise. Once the database
- *                               is created, the page size cannot be changed.
- *                               Must be power of 2 in the range between
- *                               \ref MDBX_MIN_PAGESIZE and
- *                               \ref MDBX_MAX_PAGESIZE. Zero value means
- *                               "minimal acceptable", and negative means
- *                               "keep current or use default".
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL    An invalid parameter was specified,
- *                        or the environment has an active write transaction.
- * \retval MDBX_EPERM     Two specific cases for Windows:
- *                        1) Shrinking was disabled before via geometry settings
- *                        and now it enabled, but there are reading threads that
- *                        don't use the additional `SRWL` (which is required to
- *                        avoid Windows issues).
- *                        2) Temporary close memory mapped is required to change
- *                        geometry, but there read transaction(s) is running
- *                        and no corresponding thread(s) could be suspended
- *                        since the \ref MDBX_NOTLS mode is used.
- * \retval MDBX_EACCESS   The environment opened in read-only.
- * \retval MDBX_MAP_FULL  Specified size smaller than the space already
- *                        consumed by the environment.
- * \retval MDBX_TOO_LARGE Specified size is too large, i.e. too many pages for
- *                        given size, or a 32-bit process requests too much
- *                        bytes for the 32-bit address space. */
-LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
-                                      intptr_t size_now, intptr_t size_upper,
-                                      intptr_t growth_step,
-                                      intptr_t shrink_threshold,
-                                      intptr_t pagesize);
-
-/** \deprecated Please use \ref mdbx_env_set_geometry() instead.
- * \ingroup c_settings */
-MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_set_mapsize,
-                                   (MDBX_env * env, size_t size)) {
-  return mdbx_env_set_geometry(env, size, size, size, -1, -1, -1);
-}
-
-/** \brief Find out whether to use readahead or not, based on the given database
- * size and the amount of available memory.
- * \ingroup c_extra
- *
- * \param [in] volume      The expected database size in bytes.
- * \param [in] redundancy  Additional reserve or overload in case of negative
- *                         value.
- *
- * \returns A \ref MDBX_RESULT_TRUE or \ref MDBX_RESULT_FALSE value,
- *          otherwise the error code:
- * \retval MDBX_RESULT_TRUE   Readahead is reasonable.
- * \retval MDBX_RESULT_FALSE  Readahead is NOT reasonable,
- *                            i.e. \ref MDBX_NORDAHEAD is useful to
- *                            open environment by \ref mdbx_env_open().
- * \retval Otherwise the error code. */
-LIBMDBX_API int mdbx_is_readahead_reasonable(size_t volume,
-                                             intptr_t redundancy);
-
-/** \brief Returns the minimal database page size in bytes.
- * \ingroup c_statinfo */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(intptr_t, mdbx_limits_pgsize_min,
-                                               (void)) {
-  return MDBX_MIN_PAGESIZE;
-}
-
-/** \brief Returns the maximal database page size in bytes.
- * \ingroup c_statinfo */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(intptr_t, mdbx_limits_pgsize_max,
-                                               (void)) {
-  return MDBX_MAX_PAGESIZE;
-}
-
-/** \brief Returns minimal database size in bytes for given page size,
- * or -1 if pagesize is invalid.
- * \ingroup c_statinfo */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
-mdbx_limits_dbsize_min(intptr_t pagesize);
-
-/** \brief Returns maximal database size in bytes for given page size,
- * or -1 if pagesize is invalid.
- * \ingroup c_statinfo */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
-mdbx_limits_dbsize_max(intptr_t pagesize);
-
-/** \brief Returns maximal key size in bytes for given page size
- * and database flags, or -1 if pagesize is invalid.
- * \ingroup c_statinfo
- * \see db_flags */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
-mdbx_limits_keysize_max(intptr_t pagesize, MDBX_db_flags_t flags);
-
-/** \brief Returns maximal data size in bytes for given page size
- * and database flags, or -1 if pagesize is invalid.
- * \ingroup c_statinfo
- * \see db_flags */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
-mdbx_limits_valsize_max(intptr_t pagesize, MDBX_db_flags_t flags);
-
-/** \brief Returns maximal write transaction size (i.e. limit for summary volume
- * of dirty pages) in bytes for given page size, or -1 if pagesize is invalid.
- * \ingroup c_statinfo */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
-mdbx_limits_txnsize_max(intptr_t pagesize);
-
-/** \brief Set the maximum number of threads/reader slots for for all processes
- * interacts with the database.
- * \ingroup c_settings
- *
- * \details This defines the number of slots in the lock table that is used to
- * track readers in the the environment. The default is about 100 for 4K system
- * page size. Starting a read-only transaction normally ties a lock table slot
- * to the current thread until the environment closes or the thread exits. If
- * \ref MDBX_NOTLS is in use, \ref mdbx_txn_begin() instead ties the slot to the
- * \ref MDBX_txn object until it or the \ref MDBX_env object is destroyed.
- * This function may only be called after \ref mdbx_env_create() and before
- * \ref mdbx_env_open(), and has an effect only when the database is opened by
- * the first process interacts with the database.
- * \see mdbx_env_get_maxreaders()
- *
- * \param [in] env       An environment handle returned
- *                       by \ref mdbx_env_create().
- * \param [in] readers   The maximum number of reader lock table slots.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL   An invalid parameter was specified.
- * \retval MDBX_EPERM    The environment is already open. */
-LIBMDBX_INLINE_API(int, mdbx_env_set_maxreaders,
-                   (MDBX_env * env, unsigned readers)) {
-  return mdbx_env_set_option(env, MDBX_opt_max_readers, readers);
-}
-
-/** \brief Get the maximum number of threads/reader slots for the environment.
- * \ingroup c_statinfo
- * \see mdbx_env_set_maxreaders()
- *
- * \param [in] env       An environment handle returned
- *                       by \ref mdbx_env_create().
- * \param [out] readers  Address of an integer to store the number of readers.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL   An invalid parameter was specified. */
-LIBMDBX_INLINE_API(int, mdbx_env_get_maxreaders,
-                   (const MDBX_env *env, unsigned *readers)) {
-  int rc = MDBX_EINVAL;
-  if (readers) {
-    uint64_t proxy = 0;
-    rc = mdbx_env_get_option(env, MDBX_opt_max_readers, &proxy);
-    *readers = (unsigned)proxy;
-  }
-  return rc;
-}
-
-/** \brief Set the maximum number of named databases for the environment.
- * \ingroup c_settings
- *
- * This function is only needed if multiple databases will be used in the
- * environment. Simpler applications that use the environment as a single
- * unnamed database can ignore this option.
- * This function may only be called after \ref mdbx_env_create() and before
- * \ref mdbx_env_open().
- *
- * Currently a moderate number of slots are cheap but a huge number gets
- * expensive: 7-120 words per transaction, and every \ref mdbx_dbi_open()
- * does a linear search of the opened slots.
- * \see mdbx_env_get_maxdbs()
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- * \param [in] dbs   The maximum number of databases.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL   An invalid parameter was specified.
- * \retval MDBX_EPERM    The environment is already open. */
-LIBMDBX_INLINE_API(int, mdbx_env_set_maxdbs, (MDBX_env * env, MDBX_dbi dbs)) {
-  return mdbx_env_set_option(env, MDBX_opt_max_db, dbs);
-}
-
-/** \brief Get the maximum number of named databases for the environment.
- * \ingroup c_statinfo
- * \see mdbx_env_set_maxdbs()
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- * \param [out] dbs  Address to store the maximum number of databases.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EINVAL   An invalid parameter was specified. */
-LIBMDBX_INLINE_API(int, mdbx_env_get_maxdbs,
-                   (const MDBX_env *env, MDBX_dbi *dbs)) {
-  int rc = MDBX_EINVAL;
-  if (dbs) {
-    uint64_t proxy = 0;
-    rc = mdbx_env_get_option(env, MDBX_opt_max_db, &proxy);
-    *dbs = (MDBX_dbi)proxy;
-  }
-  return rc;
-}
-
-/** \brief Returns the default size of database page for the current system.
- * \ingroup c_statinfo
- * \details Default size of database page depends on the size of the system
- * page and usually exactly match it. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API size_t mdbx_default_pagesize(void);
-
-/** \brief Returns basic information about system RAM.
- * This function provides a portable way to get information about available RAM
- * and can be useful in that it returns the same information that libmdbx uses
- * internally to adjust various options and control readahead.
- * \ingroup c_statinfo
- *
- * \param [out] page_size     Optional address where the system page size
- *                            will be stored.
- * \param [out] total_pages   Optional address where the number of total RAM
- *                            pages will be stored.
- * \param [out] avail_pages   Optional address where the number of
- *                            available/free RAM pages will be stored.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages,
-                                    intptr_t *avail_pages);
-
-/** \brief Returns the maximum size of keys can put.
- * \ingroup c_statinfo
- *
- * \param [in] env    An environment handle returned by \ref mdbx_env_create().
- * \param [in] flags  Database options (\ref MDBX_DUPSORT, \ref MDBX_INTEGERKEY
- *                    and so on). \see db_flags
- *
- * \returns The maximum size of a key can write,
- *          or -1 if something is wrong. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
-mdbx_env_get_maxkeysize_ex(const MDBX_env *env, MDBX_db_flags_t flags);
-
-/** \brief Returns the maximum size of data we can put.
- * \ingroup c_statinfo
- *
- * \param [in] env    An environment handle returned by \ref mdbx_env_create().
- * \param [in] flags  Database options (\ref MDBX_DUPSORT, \ref MDBX_INTEGERKEY
- *                    and so on). \see db_flags
- *
- * \returns The maximum size of a data can write,
- *          or -1 if something is wrong. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
-mdbx_env_get_maxvalsize_ex(const MDBX_env *env, MDBX_db_flags_t flags);
-
-/** \deprecated Please use \ref mdbx_env_get_maxkeysize_ex()
- *              and/or \ref mdbx_env_get_maxvalsize_ex()
- * \ingroup c_statinfo */
-MDBX_NOTHROW_PURE_FUNCTION MDBX_DEPRECATED LIBMDBX_API int
-mdbx_env_get_maxkeysize(const MDBX_env *env);
-
-/** \brief Sets application information (a context pointer) associated with
- * the environment.
- * \see mdbx_env_get_userctx()
- * \ingroup c_settings
- *
- * \param [in] env  An environment handle returned by \ref mdbx_env_create().
- * \param [in] ctx  An arbitrary pointer for whatever the application needs.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_set_userctx(MDBX_env *env, void *ctx);
-
-/** \brief Returns an application information (a context pointer) associated
- * with the environment.
- * \see mdbx_env_set_userctx()
- * \ingroup c_statinfo
- *
- * \param [in] env An environment handle returned by \ref mdbx_env_create()
- * \returns The pointer set by \ref mdbx_env_set_userctx()
- *          or `NULL` if something wrong. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *
-mdbx_env_get_userctx(const MDBX_env *env);
-
-/** \brief Create a transaction with a user provided context pointer
- * for use with the environment.
- * \ingroup c_transactions
- *
- * The transaction handle may be discarded using \ref mdbx_txn_abort()
- * or \ref mdbx_txn_commit().
- * \see mdbx_txn_begin()
- *
- * \note A transaction and its cursors must only be used by a single thread,
- * and a thread may only have a single transaction at a time. If \ref MDBX_NOTLS
- * is in use, this does not apply to read-only transactions.
- *
- * \note Cursors may not span transactions.
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- *
- * \param [in] parent  If this parameter is non-NULL, the new transaction will
- *                     be a nested transaction, with the transaction indicated
- *                     by parent as its parent. Transactions may be nested
- *                     to any level. A parent transaction and its cursors may
- *                     not issue any other operations than mdbx_txn_commit and
- *                     \ref mdbx_txn_abort() while it has active child
- *                     transactions.
- *
- * \param [in] flags   Special options for this transaction. This parameter
- *                     must be set to 0 or by bitwise OR'ing together one
- *                     or more of the values described here:
- *                      - \ref MDBX_RDONLY   This transaction will not perform
- *                                           any write operations.
- *
- *                      - \ref MDBX_TXN_TRY  Do not block when starting
- *                                           a write transaction.
- *
- *                      - \ref MDBX_SAFE_NOSYNC, \ref MDBX_NOMETASYNC.
- *                        Do not sync data to disk corresponding
- *                        to \ref MDBX_NOMETASYNC or \ref MDBX_SAFE_NOSYNC
- *                        description. \see sync_modes
- *
- * \param [out] txn    Address where the new \ref MDBX_txn handle
- *                     will be stored.
- *
- * \param [in] context A pointer to application context to be associated with
- *                     created transaction and could be retrieved by
- *                     \ref mdbx_txn_get_userctx() until transaction finished.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_PANIC         A fatal error occurred earlier and the
- *                            environment must be shut down.
- * \retval MDBX_UNABLE_EXTEND_MAPSIZE  Another process wrote data beyond
- *                                     this MDBX_env's mapsize and this
- *                                     environment map must be resized as well.
- *                                     See \ref mdbx_env_set_mapsize().
- * \retval MDBX_READERS_FULL  A read-only transaction was requested and
- *                            the reader lock table is full.
- *                            See \ref mdbx_env_set_maxreaders().
- * \retval MDBX_ENOMEM        Out of memory.
- * \retval MDBX_BUSY          The write transaction is already started by the
- *                            current thread. */
-LIBMDBX_API int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent,
-                                  MDBX_txn_flags_t flags, MDBX_txn **txn,
-                                  void *context);
-
-/** \brief Create a transaction for use with the environment.
- * \ingroup c_transactions
- *
- * The transaction handle may be discarded using \ref mdbx_txn_abort()
- * or \ref mdbx_txn_commit().
- * \see mdbx_txn_begin_ex()
- *
- * \note A transaction and its cursors must only be used by a single thread,
- * and a thread may only have a single transaction at a time. If \ref MDBX_NOTLS
- * is in use, this does not apply to read-only transactions.
- *
- * \note Cursors may not span transactions.
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- *
- * \param [in] parent  If this parameter is non-NULL, the new transaction will
- *                     be a nested transaction, with the transaction indicated
- *                     by parent as its parent. Transactions may be nested
- *                     to any level. A parent transaction and its cursors may
- *                     not issue any other operations than mdbx_txn_commit and
- *                     \ref mdbx_txn_abort() while it has active child
- *                     transactions.
- *
- * \param [in] flags   Special options for this transaction. This parameter
- *                     must be set to 0 or by bitwise OR'ing together one
- *                     or more of the values described here:
- *                      - \ref MDBX_RDONLY   This transaction will not perform
- *                                           any write operations.
- *
- *                      - \ref MDBX_TXN_TRY  Do not block when starting
- *                                           a write transaction.
- *
- *                      - \ref MDBX_SAFE_NOSYNC, \ref MDBX_NOMETASYNC.
- *                        Do not sync data to disk corresponding
- *                        to \ref MDBX_NOMETASYNC or \ref MDBX_SAFE_NOSYNC
- *                        description. \see sync_modes
- *
- * \param [out] txn    Address where the new \ref MDBX_txn handle
- *                     will be stored.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_PANIC         A fatal error occurred earlier and the
- *                            environment must be shut down.
- * \retval MDBX_UNABLE_EXTEND_MAPSIZE  Another process wrote data beyond
- *                                     this MDBX_env's mapsize and this
- *                                     environment map must be resized as well.
- *                                     See \ref mdbx_env_set_mapsize().
- * \retval MDBX_READERS_FULL  A read-only transaction was requested and
- *                            the reader lock table is full.
- *                            See \ref mdbx_env_set_maxreaders().
- * \retval MDBX_ENOMEM        Out of memory.
- * \retval MDBX_BUSY          The write transaction is already started by the
- *                            current thread. */
-LIBMDBX_INLINE_API(int, mdbx_txn_begin,
-                   (MDBX_env * env, MDBX_txn *parent, MDBX_txn_flags_t flags,
-                    MDBX_txn **txn)) {
-  return mdbx_txn_begin_ex(env, parent, flags, txn, NULL);
-}
-
-/** \brief Sets application information associated (a context pointer) with the
- * transaction.
- * \ingroup c_transactions
- * \see mdbx_txn_get_userctx()
- *
- * \param [in] txn  An transaction handle returned by \ref mdbx_txn_begin_ex()
- *                  or \ref mdbx_txn_begin().
- * \param [in] ctx  An arbitrary pointer for whatever the application needs.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx);
-
-/** \brief Returns an application information (a context pointer) associated
- * with the transaction.
- * \ingroup c_transactions
- * \see mdbx_txn_set_userctx()
- *
- * \param [in] txn  An transaction handle returned by \ref mdbx_txn_begin_ex()
- *                  or \ref mdbx_txn_begin().
- * \returns The pointer which was passed via the `context` parameter
- *          of `mdbx_txn_begin_ex()` or set by \ref mdbx_txn_set_userctx(),
- *          or `NULL` if something wrong. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *
-mdbx_txn_get_userctx(const MDBX_txn *txn);
-
-/** \brief Information about the transaction
- * \ingroup c_statinfo
- * \see mdbx_txn_info */
-struct MDBX_txn_info {
-  /** The ID of the transaction. For a READ-ONLY transaction, this corresponds
-      to the snapshot being read. */
-  uint64_t txn_id;
-
-  /** For READ-ONLY transaction: the lag from a recent MVCC-snapshot, i.e. the
-     number of committed transaction since read transaction started.
-     For WRITE transaction (provided if `scan_rlt=true`): the lag of the oldest
-     reader from current transaction (i.e. at least 1 if any reader running). */
-  uint64_t txn_reader_lag;
-
-  /** Used space by this transaction, i.e. corresponding to the last used
-   * database page. */
-  uint64_t txn_space_used;
-
-  /** Current size of database file. */
-  uint64_t txn_space_limit_soft;
-
-  /** Upper bound for size the database file, i.e. the value `size_upper`
-     argument of the appropriate call of \ref mdbx_env_set_geometry(). */
-  uint64_t txn_space_limit_hard;
-
-  /** For READ-ONLY transaction: The total size of the database pages that were
-     retired by committed write transactions after the reader's MVCC-snapshot,
-     i.e. the space which would be freed after the Reader releases the
-     MVCC-snapshot for reuse by completion read transaction.
-     For WRITE transaction: The summarized size of the database pages that were
-     retired for now due Copy-On-Write during this transaction. */
-  uint64_t txn_space_retired;
-
-  /** For READ-ONLY transaction: the space available for writer(s) and that
-     must be exhausted for reason to call the Handle-Slow-Readers callback for
-     this read transaction.
-     For WRITE transaction: the space inside transaction
-     that left to `MDBX_TXN_FULL` error. */
-  uint64_t txn_space_leftover;
-
-  /** For READ-ONLY transaction (provided if `scan_rlt=true`): The space that
-     actually become available for reuse when only this transaction will be
-     finished.
-     For WRITE transaction: The summarized size of the dirty database
-     pages that generated during this transaction. */
-  uint64_t txn_space_dirty;
-};
-#ifndef __cplusplus
-/** \ingroup c_statinfo */
-typedef struct MDBX_txn_info MDBX_txn_info;
-#endif
-
-/** \brief Return information about the MDBX transaction.
- * \ingroup c_statinfo
- *
- * \param [in] txn        A transaction handle returned by \ref mdbx_txn_begin()
- * \param [out] info      The address of an \ref MDBX_txn_info structure
- *                        where the information will be copied.
- * \param [in] scan_rlt   The boolean flag controls the scan of the read lock
- *                        table to provide complete information. Such scan
- *                        is relatively expensive and you can avoid it
- *                        if corresponding fields are not needed.
- *                        See description of \ref MDBX_txn_info.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_txn_info(const MDBX_txn *txn, MDBX_txn_info *info,
-                              bool scan_rlt);
-
-/** \brief Returns the transaction's MDBX_env.
- * \ingroup c_transactions
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin() */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_env *
-mdbx_txn_env(const MDBX_txn *txn);
-
-/** \brief Return the transaction's flags.
- * \ingroup c_transactions
- *
- * This returns the flags associated with this transaction.
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \returns A transaction flags, valid if input is an valid transaction,
- *          otherwise -1. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_txn_flags(const MDBX_txn *txn);
-
-/** \brief Return the transaction's ID.
- * \ingroup c_statinfo
- *
- * This returns the identifier associated with this transaction. For a
- * read-only transaction, this corresponds to the snapshot being read;
- * concurrent readers will frequently have the same transaction ID.
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \returns A transaction ID, valid if input is an active transaction,
- *          otherwise 0. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint64_t
-mdbx_txn_id(const MDBX_txn *txn);
-
-/** \brief Latency of commit stages in 1/65536 of seconds units.
- * \warning This structure may be changed in future releases.
- * \see mdbx_txn_commit_ex() */
-struct MDBX_commit_latency {
-  /** \brief Duration of preparation (commit child transactions, update
-   * sub-databases records and cursors destroying). */
-  uint32_t preparation;
-  /** \brief Duration of GC/freeDB handling & updation. */
-  uint32_t gc;
-  /** \brief Duration of internal audit if enabled. */
-  uint32_t audit;
-  /** \brief Duration of writing dirty/modified data pages to a filesystem,
-   * i.e. the summary duration of a `write()` syscalls during commit. */
-  uint32_t write;
-  /** \brief Duration of syncing written data to the disk/storage, i.e.
-   * the duration of a `fdatasync()` or a `msync()` syscall during commit. */
-  uint32_t sync;
-  /** \brief Duration of transaction ending (releasing resources). */
-  uint32_t ending;
-  /** \brief The total duration of a commit. */
-  uint32_t whole;
-};
-#ifndef __cplusplus
-/** \ingroup c_statinfo */
-typedef struct MDBX_commit_latency MDBX_commit_latency;
-#endif
-
-/** \brief Commit all the operations of a transaction into the database and
- * collect latency information.
- * \see mdbx_txn_commit()
- * \ingroup c_statinfo
- * \warning This function may be changed in future releases. */
-LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency);
-
-/** \brief Commit all the operations of a transaction into the database.
- * \ingroup c_transactions
- *
- * If the current thread is not eligible to manage the transaction then
- * the \ref MDBX_THREAD_MISMATCH error will returned. Otherwise the transaction
- * will be committed and its handle is freed. If the transaction cannot
- * be committed, it will be aborted with the corresponding error returned.
- *
- * Thus, a result other than \ref MDBX_THREAD_MISMATCH means that the
- * transaction is terminated:
- *  - Resources are released;
- *  - Transaction handle is invalid;
- *  - Cursor(s) associated with transaction must not be used, except with
- *    mdbx_cursor_renew() and \ref mdbx_cursor_close().
- *    Such cursor(s) must be closed explicitly by \ref mdbx_cursor_close()
- *    before or after transaction commit, either can be reused with
- *    \ref mdbx_cursor_renew() until it will be explicitly closed by
- *    \ref mdbx_cursor_close().
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_RESULT_TRUE      Transaction was aborted since it should
- *                               be aborted due to previous errors.
- * \retval MDBX_PANIC            A fatal error occurred earlier
- *                               and the environment must be shut down.
- * \retval MDBX_BAD_TXN          Transaction is already finished or never began.
- * \retval MDBX_EBADSIGN         Transaction object has invalid signature,
- *                               e.g. transaction was already terminated
- *                               or memory was corrupted.
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL           Transaction handle is NULL.
- * \retval MDBX_ENOSPC           No more disk space.
- * \retval MDBX_EIO              A system-level I/O error occurred.
- * \retval MDBX_ENOMEM           Out of memory. */
-LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) {
-  return mdbx_txn_commit_ex(txn, NULL);
-}
-
-/** \brief Abandon all the operations of the transaction instead of saving them.
- * \ingroup c_transactions
- *
- * The transaction handle is freed. It and its cursors must not be used again
- * after this call, except with \ref mdbx_cursor_renew() and
- * \ref mdbx_cursor_close().
- *
- * If the current thread is not eligible to manage the transaction then
- * the \ref MDBX_THREAD_MISMATCH error will returned. Otherwise the transaction
- * will be aborted and its handle is freed. Thus, a result other than
- * \ref MDBX_THREAD_MISMATCH means that the transaction is terminated:
- *  - Resources are released;
- *  - Transaction handle is invalid;
- *  - Cursor(s) associated with transaction must not be used, except with
- *    \ref mdbx_cursor_renew() and \ref mdbx_cursor_close().
- *    Such cursor(s) must be closed explicitly by \ref mdbx_cursor_close()
- *    before or after transaction abort, either can be reused with
- *    \ref mdbx_cursor_renew() until it will be explicitly closed by
- *    \ref mdbx_cursor_close().
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_PANIC            A fatal error occurred earlier and
- *                               the environment must be shut down.
- * \retval MDBX_BAD_TXN          Transaction is already finished or never began.
- * \retval MDBX_EBADSIGN         Transaction object has invalid signature,
- *                               e.g. transaction was already terminated
- *                               or memory was corrupted.
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL           Transaction handle is NULL. */
-LIBMDBX_API int mdbx_txn_abort(MDBX_txn *txn);
-
-/** \brief Marks transaction as broken.
- * \ingroup c_transactions
- *
- * Function keeps the transaction handle and corresponding locks, but makes
- * impossible to perform any operations within a broken transaction.
- * Broken transaction must then be aborted explicitly later.
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \see mdbx_txn_abort() \see mdbx_txn_reset() \see mdbx_txn_commit()
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_txn_break(MDBX_txn *txn);
-
-/** \brief Reset a read-only transaction.
- * \ingroup c_transactions
- *
- * Abort the read-only transaction like \ref mdbx_txn_abort(), but keep the
- * transaction handle. Therefore \ref mdbx_txn_renew() may reuse the handle.
- * This saves allocation overhead if the process will start a new read-only
- * transaction soon, and also locking overhead if \ref MDBX_NOTLS is in use. The
- * reader table lock is released, but the table slot stays tied to its thread
- * or \ref MDBX_txn. Use \ref mdbx_txn_abort() to discard a reset handle, and to
- * free its lock table slot if \ref MDBX_NOTLS is in use.
- *
- * Cursors opened within the transaction must not be used again after this
- * call, except with \ref mdbx_cursor_renew() and \ref mdbx_cursor_close().
- *
- * Reader locks generally don't interfere with writers, but they keep old
- * versions of database pages allocated. Thus they prevent the old pages from
- * being reused when writers commit new data, and so under heavy load the
- * database size may grow much more rapidly than otherwise.
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_PANIC            A fatal error occurred earlier and
- *                               the environment must be shut down.
- * \retval MDBX_BAD_TXN          Transaction is already finished or never began.
- * \retval MDBX_EBADSIGN         Transaction object has invalid signature,
- *                               e.g. transaction was already terminated
- *                               or memory was corrupted.
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL           Transaction handle is NULL. */
-LIBMDBX_API int mdbx_txn_reset(MDBX_txn *txn);
-
-/** \brief Renew a read-only transaction.
- * \ingroup c_transactions
- *
- * This acquires a new reader lock for a transaction handle that had been
- * released by \ref mdbx_txn_reset(). It must be called before a reset
- * transaction may be used again.
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_PANIC            A fatal error occurred earlier and
- *                               the environment must be shut down.
- * \retval MDBX_BAD_TXN          Transaction is already finished or never began.
- * \retval MDBX_EBADSIGN         Transaction object has invalid signature,
- *                               e.g. transaction was already terminated
- *                               or memory was corrupted.
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL           Transaction handle is NULL. */
-LIBMDBX_API int mdbx_txn_renew(MDBX_txn *txn);
-
-/** \brief The fours integers markers (aka "canary") associated with the
- * environment.
- * \ingroup c_crud
- * \see mdbx_canary_set()
- * \see mdbx_canary_get()
- *
- * The `x`, `y` and `z` values could be set by \ref mdbx_canary_put(), while the
- * 'v' will be always set to the transaction number. Updated values becomes
- * visible outside the current transaction only after it was committed. Current
- * values could be retrieved by \ref mdbx_canary_get(). */
-struct MDBX_canary {
-  uint64_t x, y, z, v;
-};
-#ifndef __cplusplus
-/** \ingroup c_crud */
-typedef struct MDBX_canary MDBX_canary;
-#endif
-
-/** \brief Set integers markers (aka "canary") associated with the environment.
- * \ingroup c_crud
- * \see mdbx_canary_get()
- *
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin()
- * \param [in] canary  A optional pointer to \ref MDBX_canary structure for `x`,
- *              `y` and `z` values from.
- *            - If canary is NOT NULL then the `x`, `y` and `z` values will be
- *              updated from given canary argument, but the 'v' be always set
- *              to the current transaction number if at least one `x`, `y` or
- *              `z` values have changed (i.e. if `x`, `y` and `z` have the same
- *              values as currently present then nothing will be changes or
- *              updated).
- *            - if canary is NULL then the `v` value will be explicitly update
- *              to the current transaction number without changes `x`, `y` nor
- *              `z`.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary);
-
-/** \brief Returns fours integers markers (aka "canary") associated with the
- * environment.
- * \ingroup c_crud
- * \see mdbx_canary_set()
- *
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] canary  The address of an MDBX_canary structure where the
- *                     information will be copied.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary);
-
-/** \brief A callback function used to compare two keys in a database
- * \ingroup c_crud
- * \see mdbx_cmp() \see mdbx_get_keycmp()
- * \see mdbx_get_datacmp \see mdbx_dcmp()
- *
- * \anchor avoid_custom_comparators
- * It is recommend not using custom comparison functions, but instead
- * converting the keys to one of the forms that are suitable for built-in
- * comparators (for instance take look to the \ref value2key).
- * The reasons to not using custom comparators are:
- *   - The order of records could not be validated without your code.
- *     So `mdbx_chk` utility will reports "wrong order" errors
- *     and the `-i` option is required to suppress ones.
- *   - A records could not be ordered or sorted without your code.
- *     So `mdbx_load` utility should be used with `-a` option to preserve
- *     input data order.
- *   - However, the custom comparators feature will never be removed.
- *     You have been warned but still can use custom comparators knowing
- *     about the issues noted above. In this case you should ignore `deprecated`
- *     warnings or define `MDBX_DEPRECATED` macro to empty to avoid ones. */
-typedef int(MDBX_cmp_func)(const MDBX_val *a,
-                           const MDBX_val *b) MDBX_CXX17_NOEXCEPT;
-
-/** \brief Open or Create a database in the environment.
- * \ingroup c_dbi
- *
- * A database handle denotes the name and parameters of a database,
- * independently of whether such a database exists. The database handle may be
- * discarded by calling \ref mdbx_dbi_close(). The old database handle is
- * returned if the database was already open. The handle may only be closed
- * once.
- *
- * \note A notable difference between MDBX and LMDB is that MDBX make handles
- * opened for existing databases immediately available for other transactions,
- * regardless this transaction will be aborted or reset. The REASON for this is
- * to avoiding the requirement for multiple opening a same handles in
- * concurrent read transactions, and tracking of such open but hidden handles
- * until the completion of read transactions which opened them.
- *
- * Nevertheless, the handle for the NEWLY CREATED database will be invisible
- * for other transactions until the this write transaction is successfully
- * committed. If the write transaction is aborted the handle will be closed
- * automatically. After a successful commit the such handle will reside in the
- * shared environment, and may be used by other transactions.
- *
- * In contrast to LMDB, the MDBX allow this function to be called from multiple
- * concurrent transactions or threads in the same process.
- *
- * To use named database (with name != NULL), \ref mdbx_env_set_maxdbs()
- * must be called before opening the environment. Table names are
- * keys in the internal unnamed database, and may be read but not written.
- *
- * \param [in] txn    transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] name   The name of the database to open. If only a single
- *                    database is needed in the environment,
- *                    this value may be NULL.
- * \param [in] flags  Special options for this database. This parameter must
- *                    be bitwise OR'ing together any of the constants
- *                    described here:
- *
- *  - \ref MDBX_DB_DEFAULTS
- *      Keys are arbitrary byte strings and compared from beginning to end.
- *  - \ref MDBX_REVERSEKEY
- *      Keys are arbitrary byte strings to be compared in reverse order,
- *      from the end of the strings to the beginning.
- *  - \ref MDBX_INTEGERKEY
- *      Keys are binary integers in native byte order, either uint32_t or
- *      uint64_t, and will be sorted as such. The keys must all be of the
- *      same size and must be aligned while passing as arguments.
- *  - \ref MDBX_DUPSORT
- *      Duplicate keys may be used in the database. Or, from another point of
- *      view, keys may have multiple data items, stored in sorted order. By
- *      default keys must be unique and may have only a single data item.
- *  - \ref MDBX_DUPFIXED
- *      This flag may only be used in combination with \ref MDBX_DUPSORT. This
- *      option tells the library that the data items for this database are
- *      all the same size, which allows further optimizations in storage and
- *      retrieval. When all data items are the same size, the
- *      \ref MDBX_GET_MULTIPLE, \ref MDBX_NEXT_MULTIPLE and
- *      \ref MDBX_PREV_MULTIPLE cursor operations may be used to retrieve
- *      multiple items at once.
- *  - \ref MDBX_INTEGERDUP
- *      This option specifies that duplicate data items are binary integers,
- *      similar to \ref MDBX_INTEGERKEY keys. The data values must all be of the
- *      same size and must be aligned while passing as arguments.
- *  - \ref MDBX_REVERSEDUP
- *      This option specifies that duplicate data items should be compared as
- *      strings in reverse order (the comparison is performed in the direction
- *      from the last byte to the first).
- *  - \ref MDBX_CREATE
- *      Create the named database if it doesn't exist. This option is not
- *      allowed in a read-only transaction or a read-only environment.
- *
- * \param [out] dbi     Address where the new \ref MDBX_dbi handle
- *                      will be stored.
- *
- * For \ref mdbx_dbi_open_ex() additional arguments allow you to set custom
- * comparison functions for keys and values (for multimaps).
- * \see avoid_custom_comparators
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_NOTFOUND   The specified database doesn't exist in the
- *                         environment and \ref MDBX_CREATE was not specified.
- * \retval MDBX_DBS_FULL   Too many databases have been opened.
- *                         \see mdbx_env_set_maxdbs()
- * \retval MDBX_INCOMPATIBLE  Database is incompatible with given flags,
- *                         i.e. the passed flags is different with which the
- *                         database was created, or the database was already
- *                         opened with a different comparison function(s).
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread. */
-LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name,
-                              MDBX_db_flags_t flags, MDBX_dbi *dbi);
-
-/** \deprecated Please
- * \ref avoid_custom_comparators "avoid using custom comparators" and use
- * \ref mdbx_dbi_open() instead.
- *
- * \ingroup c_dbi
- *
- * \param [in] txn    transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] name   The name of the database to open. If only a single
- *                    database is needed in the environment,
- *                    this value may be NULL.
- * \param [in] flags  Special options for this database.
- * \param [in] keycmp  Optional custom key comparison function for a database.
- * \param [in] datacmp Optional custom data comparison function for a database.
- * \param [out] dbi    Address where the new MDBX_dbi handle will be stored.
- * \returns A non-zero error value on failure and 0 on success. */
-MDBX_DEPRECATED LIBMDBX_API int
-mdbx_dbi_open_ex(MDBX_txn *txn, const char *name, MDBX_db_flags_t flags,
-                 MDBX_dbi *dbi, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
-
-/** \defgroup value2key Value-to-Key functions
- * \brief Value-to-Key functions to
- * \ref avoid_custom_comparators "avoid using custom comparators"
- * \see key2value
- * @{
- *
- * The \ref mdbx_key_from_jsonInteger() build a keys which are comparable with
- * keys created by \ref mdbx_key_from_double(). So this allows mixing `int64_t`
- * and IEEE754 double values in one index for JSON-numbers with restriction for
- * integer numbers range corresponding to RFC-7159, i.e. \f$[-2^{53}+1,
- * 2^{53}-1]\f$. See bottom of page 6 at https://tools.ietf.org/html/rfc7159 */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API uint64_t
-mdbx_key_from_jsonInteger(const int64_t json_integer);
-
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API uint64_t
-mdbx_key_from_double(const double ieee754_64bit);
-
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint64_t
-mdbx_key_from_ptrdouble(const double *const ieee754_64bit);
-
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API uint32_t
-mdbx_key_from_float(const float ieee754_32bit);
-
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint32_t
-mdbx_key_from_ptrfloat(const float *const ieee754_32bit);
-
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(uint64_t, mdbx_key_from_int64,
-                                               (const int64_t i64)) {
-  return UINT64_C(0x8000000000000000) + i64;
-}
-
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(uint32_t, mdbx_key_from_int32,
-                                               (const int32_t i32)) {
-  return UINT32_C(0x80000000) + i32;
-}
-/** @} */
-
-/** \defgroup key2value Key-to-Value functions
- * \brief Key-to-Value functions to
- * \ref avoid_custom_comparators "avoid using custom comparators"
- * \see value2key
- * @{ */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int64_t
-mdbx_jsonInteger_from_key(const MDBX_val);
-
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API double
-mdbx_double_from_key(const MDBX_val);
-
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API float
-mdbx_float_from_key(const MDBX_val);
-
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int32_t
-mdbx_int32_from_key(const MDBX_val);
-
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int64_t
-mdbx_int64_from_key(const MDBX_val);
-/** @} */
-
-/** \brief Retrieve statistics for a database.
- * \ingroup c_statinfo
- *
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi     A database handle returned by \ref mdbx_dbi_open().
- * \param [out] stat   The address of an \ref MDBX_stat structure where
- *                     the statistics will be copied.
- * \param [in] bytes   The size of \ref MDBX_stat.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL   An invalid parameter was specified. */
-LIBMDBX_API int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat,
-                              size_t bytes);
-
-/** \brief Retrieve depth (bitmask) information of nested dupsort (multi-value)
- * B+trees for given database.
- * \ingroup c_statinfo
- *
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi     A database handle returned by \ref mdbx_dbi_open().
- * \param [out] mask   The address of an uint32_t value where the bitmask
- *                     will be stored.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL       An invalid parameter was specified.
- * \retval MDBX_RESULT_TRUE  The dbi isn't a dupsort (multi-value) database. */
-LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
-                                           uint32_t *mask);
-
-/** \brief DBI state bits returted by \ref mdbx_dbi_flags_ex()
- * \ingroup c_statinfo
- * \see mdbx_dbi_flags_ex() */
-enum MDBX_dbi_state_t {
-  /** DB was written in this txn */
-  MDBX_DBI_DIRTY = 0x01,
-  /** Named-DB record is older than txnID */
-  MDBX_DBI_STALE = 0x02,
-  /** Named-DB handle opened in this txn */
-  MDBX_DBI_FRESH = 0x04,
-  /** Named-DB handle created in this txn */
-  MDBX_DBI_CREAT = 0x08,
-};
-#ifndef __cplusplus
-/** \ingroup c_statinfo */
-typedef enum MDBX_dbi_state_t MDBX_dbi_state_t;
-#else
-DEFINE_ENUM_FLAG_OPERATORS(MDBX_dbi_state_t)
-#endif
-
-/** \brief Retrieve the DB flags and status for a database handle.
- * \ingroup c_statinfo
- *
- * \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi     A database handle returned by \ref mdbx_dbi_open().
- * \param [out] flags  Address where the flags will be returned.
- * \param [out] state  Address where the state will be returned.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
-                                  unsigned *state);
-/** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL`
- * for discarding it result.
- * \ingroup c_statinfo */
-LIBMDBX_INLINE_API(int, mdbx_dbi_flags,
-                   (MDBX_txn * txn, MDBX_dbi dbi, unsigned *flags)) {
-  unsigned state;
-  return mdbx_dbi_flags_ex(txn, dbi, flags, &state);
-}
-
-/** \brief Close a database handle. Normally unnecessary.
- * \ingroup c_dbi
- *
- * Closing a database handle is not necessary, but lets \ref mdbx_dbi_open()
- * reuse the handle value. Usually it's better to set a bigger
- * \ref mdbx_env_set_maxdbs(), unless that value would be large.
- *
- * \note Use with care.
- * This call is synchronized via mutex with \ref mdbx_dbi_close(), but NOT with
- * other transactions running by other threads. The "next" version of libmdbx
- * (\ref MithrilDB) will solve this issue.
- *
- * Handles should only be closed if no other threads are going to reference
- * the database handle or one of its cursors any further. Do not close a handle
- * if an existing transaction has modified its database. Doing so can cause
- * misbehavior from database corruption to errors like \ref MDBX_BAD_DBI
- * (since the DB name is gone).
- *
- * \param [in] env  An environment handle returned by \ref mdbx_env_create().
- * \param [in] dbi  A database handle returned by \ref mdbx_dbi_open().
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi);
-
-/** \brief Empty or delete and close a database.
- * \ingroup c_crud
- *
- * \see mdbx_dbi_close() \see mdbx_dbi_open()
- *
- * \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi  A database handle returned by \ref mdbx_dbi_open().
- * \param [in] del  `false` to empty the DB, `true` to delete it
- *                  from the environment and close the DB handle.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del);
-
-/** \brief Get items from a database.
- * \ingroup c_crud
- *
- * This function retrieves key/data pairs from the database. The address
- * and length of the data associated with the specified key are returned
- * in the structure to which data refers.
- * If the database supports duplicate keys (\ref MDBX_DUPSORT) then the
- * first data item for the key will be returned. Retrieval of other
- * items requires the use of \ref mdbx_cursor_get().
- *
- * \note The memory pointed to by the returned values is owned by the
- * database. The caller need not dispose of the memory, and may not
- * modify it in any way. For values returned in a read-only transaction
- * any modification attempts will cause a `SIGSEGV`.
- *
- * \note Values returned from the database are valid only until a
- * subsequent update operation, or the end of the transaction.
- *
- * \param [in] txn       A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi       A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key       The key to search for in the database.
- * \param [in,out] data  The data corresponding to the key.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_NOTFOUND  The key was not in the database.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                         MDBX_val *data);
-
-/** \brief Get items from a database
- * and optionally number of data items for a given key.
- *
- * \ingroup c_crud
- *
- * Briefly this function does the same as \ref mdbx_get() with a few
- * differences:
- *  1. If values_count is NOT NULL, then returns the count
- *     of multi-values/duplicates for a given key.
- *  2. Updates BOTH the key and the data for pointing to the actual key-value
- *     pair inside the database.
- *
- * \param [in] txn           A transaction handle returned
- *                           by \ref mdbx_txn_begin().
- * \param [in] dbi           A database handle returned by \ref mdbx_dbi_open().
- * \param [in,out] key       The key to search for in the database.
- * \param [in,out] data      The data corresponding to the key.
- * \param [out] values_count The optional address to return number of values
- *                           associated with given key:
- *                            = 0 - in case \ref MDBX_NOTFOUND error;
- *                            = 1 - exactly for databases
- *                                  WITHOUT \ref MDBX_DUPSORT;
- *                            >= 1 for databases WITH \ref MDBX_DUPSORT.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_NOTFOUND  The key was not in the database.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
-                            MDBX_val *data, size_t *values_count);
-
-/** \brief Get equal or great item from a database.
- * \ingroup c_crud
- *
- * Briefly this function does the same as \ref mdbx_get() with a few
- * differences:
- * 1. Return equal or great (due comparison function) key-value
- *    pair, but not only exactly matching with the key.
- * 2. On success return \ref MDBX_SUCCESS if key found exactly,
- *    and \ref MDBX_RESULT_TRUE otherwise. Moreover, for databases with
- *    \ref MDBX_DUPSORT flag the data argument also will be used to match over
- *    multi-value/duplicates, and \ref MDBX_SUCCESS will be returned only when
- *    BOTH the key and the data match exactly.
- * 3. Updates BOTH the key and the data for pointing to the actual key-value
- *    pair inside the database.
- *
- * \param [in] txn           A transaction handle returned
- *                           by \ref mdbx_txn_begin().
- * \param [in] dbi           A database handle returned by \ref mdbx_dbi_open().
- * \param [in,out] key       The key to search for in the database.
- * \param [in,out] data      The data corresponding to the key.
- *
- * \returns A non-zero error value on failure and \ref MDBX_RESULT_FALSE
- *          or \ref MDBX_RESULT_TRUE on success (as described above).
- *          Some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_NOTFOUND      The key was not in the database.
- * \retval MDBX_EINVAL        An invalid parameter was specified. */
-LIBMDBX_API int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi,
-                                        MDBX_val *key, MDBX_val *data);
-
-/** \brief Store items into a database.
- * \ingroup c_crud
- *
- * This function stores key/data pairs in the database. The default behavior
- * is to enter the new key/data pair, replacing any previously existing key
- * if duplicates are disallowed, or adding a duplicate data item if
- * duplicates are allowed (see \ref MDBX_DUPSORT).
- *
- * \param [in] txn        A transaction handle returned
- *                        by \ref mdbx_txn_begin().
- * \param [in] dbi        A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key        The key to store in the database.
- * \param [in,out] data   The data to store.
- * \param [in] flags      Special options for this operation.
- *                        This parameter must be set to 0 or by bitwise OR'ing
- *                        together one or more of the values described here:
- *   - \ref MDBX_NODUPDATA
- *      Enter the new key-value pair only if it does not already appear
- *      in the database. This flag may only be specified if the database
- *      was opened with \ref MDBX_DUPSORT. The function will return
- *      \ref MDBX_KEYEXIST if the key/data pair already appears in the database.
- *
- *  - \ref MDBX_NOOVERWRITE
- *      Enter the new key/data pair only if the key does not already appear
- *      in the database. The function will return \ref MDBX_KEYEXIST if the key
- *      already appears in the database, even if the database supports
- *      duplicates (see \ref  MDBX_DUPSORT). The data parameter will be set
- *      to point to the existing item.
- *
- *  - \ref MDBX_CURRENT
- *      Update an single existing entry, but not add new ones. The function will
- *      return \ref MDBX_NOTFOUND if the given key not exist in the database.
- *      In case multi-values for the given key, with combination of
- *      the \ref MDBX_ALLDUPS will replace all multi-values,
- *      otherwise return the \ref MDBX_EMULTIVAL.
- *
- *  - \ref MDBX_RESERVE
- *      Reserve space for data of the given size, but don't copy the given
- *      data. Instead, return a pointer to the reserved space, which the
- *      caller can fill in later - before the next update operation or the
- *      transaction ends. This saves an extra memcpy if the data is being
- *      generated later. MDBX does nothing else with this memory, the caller
- *      is expected to modify all of the space requested. This flag must not
- *      be specified if the database was opened with \ref MDBX_DUPSORT.
- *
- *  - \ref MDBX_APPEND
- *      Append the given key/data pair to the end of the database. This option
- *      allows fast bulk loading when keys are already known to be in the
- *      correct order. Loading unsorted keys with this flag will cause
- *      a \ref MDBX_EKEYMISMATCH error.
- *
- *  - \ref MDBX_APPENDDUP
- *      As above, but for sorted dup data.
- *
- *  - \ref MDBX_MULTIPLE
- *      Store multiple contiguous data elements in a single request. This flag
- *      may only be specified if the database was opened with
- *      \ref MDBX_DUPFIXED. With combination the \ref MDBX_ALLDUPS
- *      will replace all multi-values.
- *      The data argument must be an array of two \ref MDBX_val. The `iov_len`
- *      of the first \ref MDBX_val must be the size of a single data element.
- *      The `iov_base` of the first \ref MDBX_val must point to the beginning
- *      of the array of contiguous data elements which must be properly aligned
- *      in case of database with \ref MDBX_INTEGERDUP flag.
- *      The `iov_len` of the second \ref MDBX_val must be the count of the
- *      number of data elements to store. On return this field will be set to
- *      the count of the number of elements actually written. The `iov_base` of
- *      the second \ref MDBX_val is unused.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_KEYEXIST  The key/value pair already exists in the database.
- * \retval MDBX_MAP_FULL  The database is full, see \ref mdbx_env_set_mapsize().
- * \retval MDBX_TXN_FULL  The transaction has too many dirty pages.
- * \retval MDBX_EACCES    An attempt was made to write
- *                        in a read-only transaction.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                         MDBX_val *data, MDBX_put_flags_t flags);
-
-/** \brief Replace items in a database.
- * \ingroup c_crud
- *
- * This function allows to update or delete an existing value at the same time
- * as the previous value is retrieved. If the argument new_data equal is NULL
- * zero, the removal is performed, otherwise the update/insert.
- *
- * The current value may be in an already changed (aka dirty) page. In this
- * case, the page will be overwritten during the update, and the old value will
- * be lost. Therefore, an additional buffer must be passed via old_data
- * argument initially to copy the old value. If the buffer passed in is too
- * small, the function will return \ref MDBX_RESULT_TRUE by setting iov_len
- * field pointed by old_data argument to the appropriate value, without
- * performing any changes.
- *
- * For databases with non-unique keys (i.e. with \ref MDBX_DUPSORT flag),
- * another use case is also possible, when by old_data argument selects a
- * specific item from multi-value/duplicates with the same key for deletion or
- * update. To select this scenario in flags should simultaneously specify
- * \ref MDBX_CURRENT and \ref MDBX_NOOVERWRITE. This combination is chosen
- * because it makes no sense, and thus allows you to identify the request of
- * such a scenario.
- *
- * \param [in] txn           A transaction handle returned
- *                           by \ref mdbx_txn_begin().
- * \param [in] dbi           A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key           The key to store in the database.
- * \param [in] new_data      The data to store, if NULL then deletion will
- *                           be performed.
- * \param [in,out] old_data  The buffer for retrieve previous value as describe
- *                           above.
- * \param [in] flags         Special options for this operation.
- *                           This parameter must be set to 0 or by bitwise
- *                           OR'ing together one or more of the values
- *                           described in \ref mdbx_put() description above,
- *                           and additionally
- *                           (\ref MDBX_CURRENT | \ref MDBX_NOOVERWRITE)
- *                           combination for selection particular item from
- *                           multi-value/duplicates.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                             MDBX_val *new_data, MDBX_val *old_data,
-                             MDBX_put_flags_t flags);
-
-typedef int (*MDBX_preserve_func)(void *context, MDBX_val *target,
-                                  const void *src, size_t bytes);
-LIBMDBX_API int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi,
-                                const MDBX_val *key, MDBX_val *new_data,
-                                MDBX_val *old_data, MDBX_put_flags_t flags,
-                                MDBX_preserve_func preserver,
-                                void *preserver_context);
-
-/** \brief Delete items from a database.
- * \ingroup c_crud
- *
- * This function removes key/data pairs from the database.
- *
- * \note The data parameter is NOT ignored regardless the database does
- * support sorted duplicate data items or not. If the data parameter
- * is non-NULL only the matching data item will be deleted. Otherwise, if data
- * parameter is NULL, any/all value(s) for specified key will be deleted.
- *
- * This function will return \ref MDBX_NOTFOUND if the specified key/data
- * pair is not in the database.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \param [in] txn   A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi   A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key   The key to delete from the database.
- * \param [in] data  The data to delete.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EACCES   An attempt was made to write
- *                       in a read-only transaction.
- * \retval MDBX_EINVAL   An invalid parameter was specified. */
-LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
-                         const MDBX_val *data);
-
-/** \brief Create a cursor handle but not bind it to transaction nor DBI handle.
- * \ingroup c_cursors
- *
- * A cursor cannot be used when its database handle is closed. Nor when its
- * transaction has ended, except with \ref mdbx_cursor_bind() and \ref
- * mdbx_cursor_renew(). Also it can be discarded with \ref mdbx_cursor_close().
- *
- * A cursor must be closed explicitly always, before or after its transaction
- * ends. It can be reused with \ref mdbx_cursor_bind()
- * or \ref mdbx_cursor_renew() before finally closing it.
- *
- * \note In contrast to LMDB, the MDBX required that any opened cursors can be
- * reused and must be freed explicitly, regardless ones was opened in a
- * read-only or write transaction. The REASON for this is eliminates ambiguity
- * which helps to avoid errors such as: use-after-free, double-free, i.e.
- * memory corruption and segfaults.
- *
- * \param [in] context A pointer to application context to be associated with
- *                     created cursor and could be retrieved by
- *                     \ref mdbx_cursor_get_userctx() until cursor closed.
- *
- * \returns Created cursor handle or NULL in case out of memory. */
-LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context);
-
-/** \brief Set application information associated with the \ref MDBX_cursor.
- * \ingroup c_cursors
- * \see mdbx_cursor_get_userctx()
- *
- * \param [in] cursor  An cursor handle returned by \ref mdbx_cursor_create()
- *                     or \ref mdbx_cursor_open().
- * \param [in] ctx     An arbitrary pointer for whatever the application needs.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_cursor_set_userctx(MDBX_cursor *cursor, void *ctx);
-
-/** \brief Get the application information associated with the MDBX_cursor.
- * \ingroup c_cursors
- * \see mdbx_cursor_set_userctx()
- *
- * \param [in] cursor  An cursor handle returned by \ref mdbx_cursor_create()
- *                     or \ref mdbx_cursor_open().
- * \returns The pointer which was passed via the `context` parameter
- *          of `mdbx_cursor_create()` or set by \ref mdbx_cursor_set_userctx(),
- *          or `NULL` if something wrong. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *
-mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
-
-/** \brief Bind cursor to specified transaction and DBI handle.
- * \ingroup c_cursors
- *
- * Using of the `mdbx_cursor_bind()` is equivalent to calling
- * \ref mdbx_cursor_renew() but with specifying an arbitrary dbi handle.
- *
- * A cursor may be associated with a new transaction, and referencing a new or
- * the same database handle as it was created with. This may be done whether the
- * previous transaction is live or dead.
- *
- * \note In contrast to LMDB, the MDBX required that any opened cursors can be
- * reused and must be freed explicitly, regardless ones was opened in a
- * read-only or write transaction. The REASON for this is eliminates ambiguity
- * which helps to avoid errors such as: use-after-free, double-free, i.e.
- * memory corruption and segfaults.
- *
- * \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi      A database handle returned by \ref mdbx_dbi_open().
- * \param [out] cursor  A cursor handle returned by \ref mdbx_cursor_create().
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL  An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor,
-                                 MDBX_dbi dbi);
-
-/** \brief Create a cursor handle for the specified transaction and DBI handle.
- * \ingroup c_cursors
- *
- * Using of the `mdbx_cursor_open()` is equivalent to calling
- * \ref mdbx_cursor_create() and then \ref mdbx_cursor_bind() functions.
- *
- * A cursor cannot be used when its database handle is closed. Nor when its
- * transaction has ended, except with \ref mdbx_cursor_bind() and \ref
- * mdbx_cursor_renew(). Also it can be discarded with \ref mdbx_cursor_close().
- *
- * A cursor must be closed explicitly always, before or after its transaction
- * ends. It can be reused with \ref mdbx_cursor_bind()
- * or \ref mdbx_cursor_renew() before finally closing it.
- *
- * \note In contrast to LMDB, the MDBX required that any opened cursors can be
- * reused and must be freed explicitly, regardless ones was opened in a
- * read-only or write transaction. The REASON for this is eliminates ambiguity
- * which helps to avoid errors such as: use-after-free, double-free, i.e.
- * memory corruption and segfaults.
- *
- * \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi      A database handle returned by \ref mdbx_dbi_open().
- * \param [out] cursor  Address where the new \ref MDBX_cursor handle will be
- *                      stored.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL  An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi,
-                                 MDBX_cursor **cursor);
-
-/** \brief Close a cursor handle.
- * \ingroup c_cursors
- *
- * The cursor handle will be freed and must not be used again after this call,
- * but its transaction may still be live.
- *
- * \note In contrast to LMDB, the MDBX required that any opened cursors can be
- * reused and must be freed explicitly, regardless ones was opened in a
- * read-only or write transaction. The REASON for this is eliminates ambiguity
- * which helps to avoid errors such as: use-after-free, double-free, i.e.
- * memory corruption and segfaults.
- *
- * \param [in] cursor  A cursor handle returned by \ref mdbx_cursor_open()
- *                     or \ref mdbx_cursor_create(). */
-LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
-
-/** \brief Renew a cursor handle.
- * \ingroup c_cursors
- *
- * The cursor may be associated with a new transaction, and referencing a new or
- * the same database handle as it was created with. This may be done whether the
- * previous transaction is live or dead.
- *
- * Using of the `mdbx_cursor_renew()` is equivalent to calling
- * \ref mdbx_cursor_bind() with the DBI handle that previously
- * the cursor was used with.
- *
- * \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using
- * \ref mdbx_cursor_renew(), to avoid unnecessary malloc/free overhead until it
- * freed by \ref mdbx_cursor_close().
- *
- * \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] cursor   A cursor handle returned by \ref mdbx_cursor_open().
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL  An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
-
-/** \brief Return the cursor's transaction handle.
- * \ingroup c_cursors
- *
- * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_txn *
-mdbx_cursor_txn(const MDBX_cursor *cursor);
-
-/** \brief Return the cursor's database handle.
- * \ingroup c_cursors
- *
- * \param [in] cursor  A cursor handle returned by \ref mdbx_cursor_open(). */
-LIBMDBX_API MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *cursor);
-
-/** \brief Copy cursor position and state.
- * \ingroup c_cursors
- *
- * \param [in] src       A source cursor handle returned
- * by \ref mdbx_cursor_create() or \ref mdbx_cursor_open().
- *
- * \param [in,out] dest  A destination cursor handle returned
- * by \ref mdbx_cursor_create() or \ref mdbx_cursor_open().
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest);
-
-/** \brief Retrieve by cursor.
- * \ingroup c_crud
- *
- * This function retrieves key/data pairs from the database. The address and
- * length of the key are returned in the object to which key refers (except
- * for the case of the \ref MDBX_SET option, in which the key object is
- * unchanged), and the address and length of the data are returned in the object
- * to which data refers.
- * \see mdbx_get()
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- * \param [in,out] key   The key for a retrieved item.
- * \param [in,out] data  The data of a retrieved item.
- * \param [in] op        A cursor operation \ref MDBX_cursor_op.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_NOTFOUND  No matching key found.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_get(MDBX_cursor *cursor, MDBX_val *key,
-                                MDBX_val *data, MDBX_cursor_op op);
-
-/** \brief Retrieve multiple non-dupsort key/value pairs by cursor.
- * \ingroup c_crud
- *
- * This function retrieves multiple key/data pairs from the database without
- * \ref MDBX_DUPSORT option. For `MDBX_DUPSORT` databases please
- * use \ref MDBX_GET_MULTIPLE and \ref MDBX_NEXT_MULTIPLE.
- *
- * The number of key and value items is returned in the `size_t count`
- * refers. The addresses and lengths of the keys and values are returned in the
- * array to which `pairs` refers.
- * \see mdbx_cursor_get()
- *
- * \param [in] cursor     A cursor handle returned by \ref mdbx_cursor_open().
- * \param [out] count     The number of key and value item returned, on success
- *                        it always be the even because the key-value
- *                        pairs are returned.
- * \param [in,out] pairs  A pointer to the array of key value pairs.
- * \param [in] limit      The size of pairs buffer as the number of items,
- *                        but not a pairs.
- * \param [in] op         A cursor operation \ref MDBX_cursor_op (only
- *                        \ref MDBX_FIRST, \ref MDBX_NEXT, \ref MDBX_GET_CURRENT
- *                        are supported).
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_NOTFOUND         No more key-value pairs are available.
- * \retval MDBX_ENODATA          The cursor is already at the end of data.
- * \retval MDBX_RESULT_TRUE      The specified limit is less than the available
- *                               key-value pairs on the current page/position
- *                               that the cursor points to.
- * \retval MDBX_EINVAL           An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_get_batch(MDBX_cursor *cursor, size_t *count,
-                                      MDBX_val *pairs, size_t limit,
-                                      MDBX_cursor_op op);
-
-/** \brief Store by cursor.
- * \ingroup c_crud
- *
- * This function stores key/data pairs into the database. The cursor is
- * positioned at the new item, or on failure usually near it.
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- * \param [in] key       The key operated on.
- * \param [in,out] data  The data operated on.
- * \param [in] flags     Options for this operation. This parameter
- *                       must be set to 0 or by bitwise OR'ing together
- *                       one or more of the values described here:
- *  - \ref MDBX_CURRENT
- *      Replace the item at the current cursor position. The key parameter
- *      must still be provided, and must match it, otherwise the function
- *      return \ref MDBX_EKEYMISMATCH. With combination the
- *      \ref MDBX_ALLDUPS will replace all multi-values.
- *
- *      \note MDBX allows (unlike LMDB) you to change the size of the data and
- *      automatically handles reordering for sorted duplicates
- *      (see \ref MDBX_DUPSORT).
- *
- *  - \ref MDBX_NODUPDATA
- *      Enter the new key-value pair only if it does not already appear in the
- *      database. This flag may only be specified if the database was opened
- *      with \ref MDBX_DUPSORT. The function will return \ref MDBX_KEYEXIST
- *      if the key/data pair already appears in the database.
- *
- *  - \ref MDBX_NOOVERWRITE
- *      Enter the new key/data pair only if the key does not already appear
- *      in the database. The function will return \ref MDBX_KEYEXIST if the key
- *      already appears in the database, even if the database supports
- *      duplicates (\ref MDBX_DUPSORT).
- *
- *  - \ref MDBX_RESERVE
- *      Reserve space for data of the given size, but don't copy the given
- *      data. Instead, return a pointer to the reserved space, which the
- *      caller can fill in later - before the next update operation or the
- *      transaction ends. This saves an extra memcpy if the data is being
- *      generated later. This flag must not be specified if the database
- *      was opened with \ref MDBX_DUPSORT.
- *
- *  - \ref MDBX_APPEND
- *      Append the given key/data pair to the end of the database. No key
- *      comparisons are performed. This option allows fast bulk loading when
- *      keys are already known to be in the correct order. Loading unsorted
- *      keys with this flag will cause a \ref MDBX_KEYEXIST error.
- *
- *  - \ref MDBX_APPENDDUP
- *      As above, but for sorted dup data.
- *
- *  - \ref MDBX_MULTIPLE
- *      Store multiple contiguous data elements in a single request. This flag
- *      may only be specified if the database was opened with
- *      \ref MDBX_DUPFIXED. With combination the \ref MDBX_ALLDUPS
- *      will replace all multi-values.
- *      The data argument must be an array of two \ref MDBX_val. The `iov_len`
- *      of the first \ref MDBX_val must be the size of a single data element.
- *      The `iov_base` of the first \ref MDBX_val must point to the beginning
- *      of the array of contiguous data elements which must be properly aligned
- *      in case of database with \ref MDBX_INTEGERDUP flag.
- *      The `iov_len` of the second \ref MDBX_val must be the count of the
- *      number of data elements to store. On return this field will be set to
- *      the count of the number of elements actually written. The `iov_base` of
- *      the second \ref MDBX_val is unused.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EKEYMISMATCH  The given key value is mismatched to the current
- *                            cursor position
- * \retval MDBX_MAP_FULL      The database is full,
- *                             see \ref mdbx_env_set_mapsize().
- * \retval MDBX_TXN_FULL      The transaction has too many dirty pages.
- * \retval MDBX_EACCES        An attempt was made to write in a read-only
- *                            transaction.
- * \retval MDBX_EINVAL        An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_put(MDBX_cursor *cursor, const MDBX_val *key,
-                                MDBX_val *data, MDBX_put_flags_t flags);
-
-/** \brief Delete current key/data pair.
- * \ingroup c_crud
- *
- * This function deletes the key/data pair to which the cursor refers. This
- * does not invalidate the cursor, so operations such as \ref MDBX_NEXT can
- * still be used on it. Both \ref MDBX_NEXT and \ref MDBX_GET_CURRENT will
- * return the same record after this operation.
- *
- * \param [in] cursor  A cursor handle returned by mdbx_cursor_open().
- * \param [in] flags   Options for this operation. This parameter must be set
- * to one of the values described here.
- *
- *  - \ref MDBX_CURRENT Delete only single entry at current cursor position.
- *  - \ref MDBX_ALLDUPS
- *    or \ref MDBX_NODUPDATA (supported for compatibility)
- *      Delete all of the data items for the current key. This flag has effect
- *      only for database(s) was created with \ref MDBX_DUPSORT.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_MAP_FULL      The database is full,
- *                            see \ref mdbx_env_set_mapsize().
- * \retval MDBX_TXN_FULL      The transaction has too many dirty pages.
- * \retval MDBX_EACCES        An attempt was made to write in a read-only
- *                            transaction.
- * \retval MDBX_EINVAL        An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_del(MDBX_cursor *cursor, MDBX_put_flags_t flags);
-
-/** \brief Return count of duplicates for current key.
- * \ingroup c_crud
- *
- * This call is valid for all databases, but reasonable only for that support
- * sorted duplicate data items \ref MDBX_DUPSORT.
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- * \param [out] pcount   Address where the count will be stored.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
- *                               by current thread.
- * \retval MDBX_EINVAL   Cursor is not initialized, or an invalid parameter
- *                       was specified. */
-LIBMDBX_API int mdbx_cursor_count(const MDBX_cursor *cursor, size_t *pcount);
-
-/** \brief Determines whether the cursor is pointed to a key-value pair or not,
- * i.e. was not positioned or points to the end of data.
- * \ingroup c_cursors
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- *
- * \returns A \ref MDBX_RESULT_TRUE or \ref MDBX_RESULT_FALSE value,
- *          otherwise the error code:
- * \retval MDBX_RESULT_TRUE    No more data available or cursor not
- *                             positioned
- * \retval MDBX_RESULT_FALSE   A data is available
- * \retval Otherwise the error code */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
-mdbx_cursor_eof(const MDBX_cursor *cursor);
-
-/** \brief Determines whether the cursor is pointed to the first key-value pair
- * or not.
- * \ingroup c_cursors
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- *
- * \returns A MDBX_RESULT_TRUE or MDBX_RESULT_FALSE value,
- *          otherwise the error code:
- * \retval MDBX_RESULT_TRUE   Cursor positioned to the first key-value pair
- * \retval MDBX_RESULT_FALSE  Cursor NOT positioned to the first key-value
- * pair \retval Otherwise the error code */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
-mdbx_cursor_on_first(const MDBX_cursor *cursor);
-
-/** \brief Determines whether the cursor is pointed to the last key-value pair
- * or not.
- * \ingroup c_cursors
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- *
- * \returns A \ref MDBX_RESULT_TRUE or \ref MDBX_RESULT_FALSE value,
- *          otherwise the error code:
- * \retval MDBX_RESULT_TRUE   Cursor positioned to the last key-value pair
- * \retval MDBX_RESULT_FALSE  Cursor NOT positioned to the last key-value pair
- * \retval Otherwise the error code */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
-mdbx_cursor_on_last(const MDBX_cursor *cursor);
-
-/** \addtogroup c_rqest
- * \details \note The estimation result varies greatly depending on the filling
- * of specific pages and the overall balance of the b-tree:
- *
- * 1. The number of items is estimated by analyzing the height and fullness of
- * the b-tree. The accuracy of the result directly depends on the balance of
- * the b-tree, which in turn is determined by the history of previous
- * insert/delete operations and the nature of the data (i.e. variability of
- * keys length and so on). Therefore, the accuracy of the estimation can vary
- * greatly in a particular situation.
- *
- * 2. To understand the potential spread of results, you should consider a
- * possible situations basing on the general criteria for splitting and merging
- * b-tree pages:
- *  - the page is split into two when there is no space for added data;
- *  - two pages merge if the result fits in half a page;
- *  - thus, the b-tree can consist of an arbitrary combination of pages filled
- *    both completely and only 1/4. Therefore, in the worst case, the result
- *    can diverge 4 times for each level of the b-tree excepting the first and
- *    the last.
- *
- * 3. In practice, the probability of extreme cases of the above situation is
- * close to zero and in most cases the error does not exceed a few percent. On
- * the other hand, it's just a chance you shouldn't overestimate. */
-
-/** \brief Estimates the distance between cursors as a number of elements.
- * \ingroup c_rqest
- *
- * This function performs a rough estimate based only on b-tree pages that are
- * common for the both cursor's stacks. The results of such estimation can be
- * used to build and/or optimize query execution plans.
- *
- * Please see notes on accuracy of the result in the details
- * of \ref c_rqest section.
- *
- * Both cursors must be initialized for the same database and the same
- * transaction.
- *
- * \param [in] first            The first cursor for estimation.
- * \param [in] last             The second cursor for estimation.
- * \param [out] distance_items  The pointer to store estimated distance value,
- *                              i.e. `*distance_items = distance(first, last)`.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_estimate_distance(const MDBX_cursor *first,
-                                       const MDBX_cursor *last,
-                                       ptrdiff_t *distance_items);
-
-/** \brief Estimates the move distance.
- * \ingroup c_rqest
- *
- * This function performs a rough estimate distance between the current
- * cursor position and next position after the specified move-operation with
- * given key and data. The results of such estimation can be used to build
- * and/or optimize query execution plans. Current cursor position and state are
- * preserved.
- *
- * Please see notes on accuracy of the result in the details
- * of \ref c_rqest section.
- *
- * \param [in] cursor            Cursor for estimation.
- * \param [in,out] key           The key for a retrieved item.
- * \param [in,out] data          The data of a retrieved item.
- * \param [in] move_op           A cursor operation \ref MDBX_cursor_op.
- * \param [out] distance_items   A pointer to store estimated move distance
- *                               as the number of elements.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key,
-                                   MDBX_val *data, MDBX_cursor_op move_op,
-                                   ptrdiff_t *distance_items);
-
-/** \brief Estimates the size of a range as a number of elements.
- * \ingroup c_rqest
- *
- * The results of such estimation can be used to build and/or optimize query
- * execution plans.
- *
- * Please see notes on accuracy of the result in the details
- * of \ref c_rqest section.
- *
- *
- * \param [in] txn        A transaction handle returned
- *                        by \ref mdbx_txn_begin().
- * \param [in] dbi        A database handle returned by  \ref mdbx_dbi_open().
- * \param [in] begin_key  The key of range beginning or NULL for explicit FIRST.
- * \param [in] begin_data Optional additional data to seeking among sorted
- *                        duplicates.
- *                        Only for \ref MDBX_DUPSORT, NULL otherwise.
- * \param [in] end_key    The key of range ending or NULL for explicit LAST.
- * \param [in] end_data   Optional additional data to seeking among sorted
- *                        duplicates.
- *                        Only for \ref MDBX_DUPSORT, NULL otherwise.
- * \param [out] distance_items  A pointer to store range estimation result.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi,
-                                    MDBX_val *begin_key, MDBX_val *begin_data,
-                                    MDBX_val *end_key, MDBX_val *end_data,
-                                    ptrdiff_t *distance_items);
-
-/** \brief The EPSILON value for mdbx_estimate_range()
- * \ingroup c_rqest */
-#define MDBX_EPSILON ((MDBX_val *)((ptrdiff_t)-1))
-
-/** \brief Determines whether the given address is on a dirty database page of
- * the transaction or not.
- * \ingroup c_statinfo
- *
- * Ultimately, this allows to avoid copy data from non-dirty pages.
- *
- * "Dirty" pages are those that have already been changed during a write
- * transaction. Accordingly, any further changes may result in such pages being
- * overwritten. Therefore, all functions libmdbx performing changes inside the
- * database as arguments should NOT get pointers to data in those pages. In
- * turn, "not dirty" pages before modification will be copied.
- *
- * In other words, data from dirty pages must either be copied before being
- * passed as arguments for further processing or rejected at the argument
- * validation stage. Thus, `mdbx_is_dirty()` allows you to get rid of
- * unnecessary copying, and perform a more complete check of the arguments.
- *
- * \note The address passed must point to the beginning of the data. This is
- * the only way to ensure that the actual page header is physically located in
- * the same memory page, including for multi-pages with long data.
- *
- * \note In rare cases the function may return a false positive answer
- * (\ref MDBX_RESULT_TRUE when data is NOT on a dirty page), but never a false
- * negative if the arguments are correct.
- *
- * \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] ptr      The address of data to check.
- *
- * \returns A MDBX_RESULT_TRUE or MDBX_RESULT_FALSE value,
- *          otherwise the error code:
- * \retval MDBX_RESULT_TRUE    Given address is on the dirty page.
- * \retval MDBX_RESULT_FALSE   Given address is NOT on the dirty page.
- * \retval Otherwise the error code. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_is_dirty(const MDBX_txn *txn,
-                                                         const void *ptr);
-
-/** \brief Sequence generation for a database.
- * \ingroup c_crud
- *
- * The function allows to create a linear sequence of unique positive integers
- * for each database. The function can be called for a read transaction to
- * retrieve the current sequence value, and the increment must be zero.
- * Sequence changes become visible outside the current write transaction after
- * it is committed, and discarded on abort.
- *
- * \param [in] txn        A transaction handle returned
- *                        by \ref mdbx_txn_begin().
- * \param [in] dbi        A database handle returned by \ref mdbx_dbi_open().
- * \param [out] result    The optional address where the value of sequence
- *                        before the change will be stored.
- * \param [in] increment  Value to increase the sequence,
- *                        must be 0 for read-only transactions.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_RESULT_TRUE   Increasing the sequence has resulted in an
- *                            overflow and therefore cannot be executed. */
-LIBMDBX_API int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
-                                  uint64_t increment);
-
-/** \brief Compare two keys according to a particular database.
- * \ingroup c_crud
- * \see MDBX_cmp_func
- *
- * This returns a comparison as if the two data items were keys in the
- * specified database.
- *
- * \warning There ss a Undefined behavior if one of arguments is invalid.
- *
- * \param [in] txn   A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi   A database handle returned by \ref mdbx_dbi_open().
- * \param [in] a     The first item to compare.
- * \param [in] b     The second item to compare.
- *
- * \returns < 0 if a < b, 0 if a == b, > 0 if a > b */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cmp(const MDBX_txn *txn,
-                                                    MDBX_dbi dbi,
-                                                    const MDBX_val *a,
-                                                    const MDBX_val *b);
-
-/** \brief Returns default internal key's comparator for given database flags.
- * \ingroup c_extra */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API MDBX_cmp_func *
-mdbx_get_keycmp(MDBX_db_flags_t flags);
-
-/** \brief Compare two data items according to a particular database.
- * \ingroup c_crud
- * \see MDBX_cmp_func
- *
- * This returns a comparison as if the two items were data items of the
- * specified database.
- *
- * \warning There ss a Undefined behavior if one of arguments is invalid.
- *
- * \param [in] txn   A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi   A database handle returned by \ref mdbx_dbi_open().
- * \param [in] a     The first item to compare.
- * \param [in] b     The second item to compare.
- *
- * \returns < 0 if a < b, 0 if a == b, > 0 if a > b */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_dcmp(const MDBX_txn *txn,
-                                                     MDBX_dbi dbi,
-                                                     const MDBX_val *a,
-                                                     const MDBX_val *b);
-
-/** \brief Returns default internal data's comparator for given database flags
- * \ingroup c_extra */
-MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API MDBX_cmp_func *
-mdbx_get_datacmp(MDBX_db_flags_t flags);
-
-/** \brief A callback function used to enumerate the reader lock table.
- * \ingroup c_statinfo
- *
- * \param [in] ctx            An arbitrary context pointer for the callback.
- * \param [in] num            The serial number during enumeration,
- *                            starting from 1.
- * \param [in] slot           The reader lock table slot number.
- * \param [in] txnid          The ID of the transaction being read,
- *                            i.e. the MVCC-snapshot number.
- * \param [in] lag            The lag from a recent MVCC-snapshot,
- *                            i.e. the number of committed write transactions
- *                            since the current read transaction started.
- * \param [in] pid            The reader process ID.
- * \param [in] thread         The reader thread ID.
- * \param [in] bytes_used     The number of last used page
- *                            in the MVCC-snapshot which being read,
- *                            i.e. database file can't shrinked beyond this.
- * \param [in] bytes_retained The total size of the database pages that were
- *                            retired by committed write transactions after
- *                            the reader's MVCC-snapshot,
- *                            i.e. the space which would be freed after
- *                            the Reader releases the MVCC-snapshot
- *                            for reuse by completion read transaction.
- *
- * \returns < 0 on failure, >= 0 on success. \see mdbx_reader_list() */
-typedef int(MDBX_reader_list_func)(void *ctx, int num, int slot, mdbx_pid_t pid,
-                                   mdbx_tid_t thread, uint64_t txnid,
-                                   uint64_t lag, size_t bytes_used,
-                                   size_t bytes_retained) MDBX_CXX17_NOEXCEPT;
-
-/** \brief Enumerate the entries in the reader lock table.
- *
- * \ingroup c_statinfo
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- * \param [in] func    A \ref MDBX_reader_list_func function.
- * \param [in] ctx     An arbitrary context pointer for the enumeration
- *                     function.
- *
- * \returns A non-zero error value on failure and 0 on success,
- * or \ref MDBX_RESULT_TRUE if the reader lock table is empty. */
-LIBMDBX_API int mdbx_reader_list(const MDBX_env *env,
-                                 MDBX_reader_list_func *func, void *ctx);
-
-/** \brief Check for stale entries in the reader lock table.
- * \ingroup c_extra
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- * \param [out] dead   Number of stale slots that were cleared.
- *
- * \returns A non-zero error value on failure and 0 on success,
- * or \ref MDBX_RESULT_TRUE if a dead reader(s) found or mutex was recovered. */
-LIBMDBX_API int mdbx_reader_check(MDBX_env *env, int *dead);
-
-/** \brief Returns a lag of the reading for the given transaction.
- * \ingroup c_statinfo
- *
- * Returns an information for estimate how much given read-only
- * transaction is lagging relative the to actual head.
- * \deprecated Please use \ref mdbx_txn_info() instead.
- *
- * \param [in] txn       A transaction handle returned by \ref mdbx_txn_begin().
- * \param [out] percent  Percentage of page allocation in the database.
- *
- * \returns Number of transactions committed after the given was started for
- *          read, or negative value on failure. */
-MDBX_DEPRECATED LIBMDBX_API int mdbx_txn_straggler(const MDBX_txn *txn,
-                                                   int *percent);
-
-/** \brief Registers the current thread as a reader for the environment.
- * \ingroup c_extra
- *
- * To perform read operations without blocking, a reader slot must be assigned
- * for each thread. However, this assignment requires a short-term lock
- * acquisition which is performed automatically. This function allows you to
- * assign the reader slot in advance and thus avoid capturing the blocker when
- * the read transaction starts firstly from current thread.
- * \see mdbx_thread_unregister()
- *
- * \note Threads are registered automatically the first time a read transaction
- *       starts. Therefore, there is no need to use this function, except in
- *       special cases.
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- *
- * \returns A non-zero error value on failure and 0 on success,
- * or \ref MDBX_RESULT_TRUE if thread is already registered. */
-LIBMDBX_API int mdbx_thread_register(const MDBX_env *env);
-
-/** \brief Unregisters the current thread as a reader for the environment.
- * \ingroup c_extra
- *
- * To perform read operations without blocking, a reader slot must be assigned
- * for each thread. However, the assigned reader slot will remain occupied until
- * the thread ends or the environment closes. This function allows you to
- * explicitly release the assigned reader slot.
- * \see mdbx_thread_register()
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- *
- * \returns A non-zero error value on failure and 0 on success, or
- * \ref MDBX_RESULT_TRUE if thread is not registered or already unregistered. */
-LIBMDBX_API int mdbx_thread_unregister(const MDBX_env *env);
-
-/** \brief A Handle-Slow-Readers callback function to resolve database
- * full/overflow issue due to a reader(s) which prevents the old data from being
- * recycled.
- * \ingroup c_err
- *
- * Read transactions prevent reuse of pages freed by newer write transactions,
- * thus the database can grow quickly. This callback will be called when there
- * is not enough space in the database (i.e. before increasing the database size
- * or before \ref MDBX_MAP_FULL error) and thus can be used to resolve issues
- * with a "long-lived" read transactions.
- * \see mdbx_env_set_hsr()
- * \see mdbx_env_get_hsr()
- * \see <a href="intro.html#long-lived-read">Long-lived read transactions</a>
- *
- * Using this callback you can choose how to resolve the situation:
- *   - abort the write transaction with an error;
- *   - wait for the read transaction(s) to complete;
- *   - notify a thread performing a long-lived read transaction
- *     and wait for an effect;
- *   - kill the thread or whole process that performs the long-lived read
- *     transaction;
- *
- * Depending on the arguments and needs, your implementation may wait,
- * terminate a process or thread that is performing a long read, or perform
- * some other action. In doing so it is important that the returned code always
- * corresponds to the performed action.
- *
- * \param [in] env     An environment handle returned by \ref mdbx_env_create().
- * \param [in] txn     The current write transaction which internally at
- *                     the \ref MDBX_MAP_FULL condition.
- * \param [in] pid     A pid of the reader process.
- * \param [in] tid     A thread_id of the reader thread.
- * \param [in] laggard An oldest read transaction number on which stalled.
- * \param [in] gap     A lag from the last committed txn.
- * \param [in] space   A space that actually become available for reuse after
- *                     this reader finished. The callback function can take
- *                     this value into account to evaluate the impact that
- *                     a long-running transaction has.
- * \param [in] retry   A retry number starting from 0.
- *                     If callback has returned 0 at least once, then at end
- *                     of current handling loop the callback function will be
- *                     called additionally with negative value to notify about
- *                     the end of loop. The callback function can use this value
- *                     to implement timeout logic while waiting for readers.
- *
- * \returns The RETURN CODE determines the further actions libmdbx and must
- *          match the action which was executed by the callback:
- *
- * \retval -2 or less  An error condition and the reader was not killed.
- *
- * \retval -1          The callback was unable to solve the problem and
- *                     agreed on \ref MDBX_MAP_FULL error;
- *                     libmdbx should increase the database size or
- *                     return \ref MDBX_MAP_FULL error.
- *
- * \retval 0 (zero)    The callback solved the problem or just waited for
- *                     a while, libmdbx should rescan the reader lock table and
- *                     retry. This also includes a situation when corresponding
- *                     transaction terminated in normal way by
- *                     \ref mdbx_txn_abort() or \ref mdbx_txn_reset(),
- *                     and my be restarted. I.e. reader slot don't needed
- *                     to be cleaned from transaction.
- *
- * \retval 1           Transaction aborted asynchronous and reader slot
- *                     should be cleared immediately, i.e. read transaction
- *                     will not continue but \ref mdbx_txn_abort()
- *                     or \ref mdbx_txn_reset() will be called later.
- *
- * \retval 2 or great  The reader process was terminated or killed,
- *                     and libmdbx should entirely reset reader registration.
- */
-typedef int(MDBX_hsr_func)(const MDBX_env *env, const MDBX_txn *txn,
-                           mdbx_pid_t pid, mdbx_tid_t tid, uint64_t laggard,
-                           unsigned gap, size_t space,
-                           int retry) MDBX_CXX17_NOEXCEPT;
-
-/** \brief Sets a Handle-Slow-Readers callback to resolve database full/overflow
- * issue due to a reader(s) which prevents the old data from being recycled.
- * \ingroup c_err
- *
- * The callback will only be triggered when the database is full due to a
- * reader(s) prevents the old data from being recycled.
- *
- * \see MDBX_hsr_func
- * \see mdbx_env_get_hsr()
- * \see <a href="intro.html#long-lived-read">Long-lived read transactions</a>
- *
- * \param [in] env             An environment handle returned
- *                             by \ref mdbx_env_create().
- * \param [in] hsr_callback    A \ref MDBX_hsr_func function
- *                             or NULL to disable.
- *
- * \returns A non-zero error value on failure and 0 on success. */
-LIBMDBX_API int mdbx_env_set_hsr(MDBX_env *env, MDBX_hsr_func *hsr_callback);
-
-/** \brief Gets current Handle-Slow-Readers callback used to resolve database
- * full/overflow issue due to a reader(s) which prevents the old data from being
- * recycled.
- * \see MDBX_hsr_func
- * \see mdbx_env_set_hsr()
- * \see <a href="intro.html#long-lived-read">Long-lived read transactions</a>
- *
- * \param [in] env   An environment handle returned by \ref mdbx_env_create().
- *
- * \returns A MDBX_hsr_func function or NULL if disabled
- *          or something wrong. */
-MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_hsr_func *
-mdbx_env_get_hsr(const MDBX_env *env);
-
-/** \defgroup btree_traversal B-tree Traversal
- * This is internal API for mdbx_chk tool. You should avoid to use it, except
- * some extremal special cases.
- * \ingroup c_extra
- * @{ */
-
-/** \brief Page types for traverse the b-tree.
- * \see mdbx_env_pgwalk() \see MDBX_pgvisitor_func */
-enum MDBX_page_type_t {
-  MDBX_page_broken,
-  MDBX_page_meta,
-  MDBX_page_large,
-  MDBX_page_branch,
-  MDBX_page_leaf,
-  MDBX_page_dupfixed_leaf,
-  MDBX_subpage_leaf,
-  MDBX_subpage_dupfixed_leaf,
-  MDBX_subpage_broken,
-};
-#ifndef __cplusplus
-typedef enum MDBX_page_type_t MDBX_page_type_t;
-#endif
-
-/** \brief Pseudo-name for MainDB */
-#define MDBX_PGWALK_MAIN ((const char *)((ptrdiff_t)0))
-/** \brief Pseudo-name for GarbageCollectorDB */
-#define MDBX_PGWALK_GC ((const char *)((ptrdiff_t)-1))
-/** \brief Pseudo-name for MetaPages */
-#define MDBX_PGWALK_META ((const char *)((ptrdiff_t)-2))
-
-/** \brief Callback function for traverse the b-tree. \see mdbx_env_pgwalk() */
-typedef int MDBX_pgvisitor_func(
-    const uint64_t pgno, const unsigned number, void *const ctx, const int deep,
-    const char *const dbi, const size_t page_size, const MDBX_page_type_t type,
-    const MDBX_error_t err, const size_t nentries, const size_t payload_bytes,
-    const size_t header_bytes, const size_t unused_bytes) MDBX_CXX17_NOEXCEPT;
-
-/** \brief B-tree traversal function. */
-LIBMDBX_API int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
-                                void *ctx, bool dont_check_keys_ordering);
-
-/** \brief Open an environment instance using specific meta-page
- * for checking and recovery.
- *
- * This function mostly of internal API for `mdbx_chk` utility and subject to
- * change at any time. Do not use this function to avoid shooting your own
- * leg(s). */
-LIBMDBX_API int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname,
-                                           unsigned target_meta,
-                                           bool writeable);
-
-/** \brief Turn database to the specified meta-page.
- *
- * This function mostly of internal API for `mdbx_chk` utility and subject to
- * change at any time. Do not use this function to avoid shooting your own
- * leg(s). */
-LIBMDBX_API int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target_meta);
-
-/** @} B-tree Traversal */
-
-/**** Attribute support functions for Nexenta (scheduled for removal)
- * *****************************************************************/
-#if defined(MDBX_NEXENTA_ATTRS) || defined(DOXYGEN)
-/** \defgroup nexenta Attribute support functions for Nexenta
- * \ingroup c_crud
- * @{ */
-typedef uint_fast64_t mdbx_attr_t;
-
-/** Store by cursor with attribute.
- *
- * This function stores key/data pairs into the database. The cursor is
- * positioned at the new item, or on failure usually near it.
- *
- * \note Internally based on \ref MDBX_RESERVE feature,
- *       therefore doesn't support \ref MDBX_DUPSORT.
- *
- * \param [in] cursor  A cursor handle returned by \ref mdbx_cursor_open()
- * \param [in] key     The key operated on.
- * \param [in] data    The data operated on.
- * \param [in] attr    The attribute.
- * \param [in] flags   Options for this operation. This parameter must be set
- *                     to 0 or one of the values described here:
- *  - \ref MDBX_CURRENT
- *      Replace the item at the current cursor position. The key parameter
- *      must still be provided, and must match it, otherwise the function
- *      return \ref MDBX_EKEYMISMATCH.
- *
- *  - \ref MDBX_APPEND
- *      Append the given key/data pair to the end of the database. No key
- *      comparisons are performed. This option allows fast bulk loading when
- *      keys are already known to be in the correct order. Loading unsorted
- *      keys with this flag will cause a \ref MDBX_KEYEXIST error.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_EKEYMISMATCH
- * \retval MDBX_MAP_FULL  The database is full, see \ref mdbx_env_set_mapsize().
- * \retval MDBX_TXN_FULL  The transaction has too many dirty pages.
- * \retval MDBX_EACCES    An attempt was made to write in a read-only
- *                        transaction.
- * \retval MDBX_EINVAL    an invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_put_attr(MDBX_cursor *cursor, MDBX_val *key,
-                                     MDBX_val *data, mdbx_attr_t attr,
-                                     MDBX_put_flags_t flags);
-
-/** Store items and attributes into a database.
- *
- * This function stores key/data pairs in the database. The default behavior
- * is to enter the new key/data pair, replacing any previously existing key
- * if duplicates are disallowed.
- *
- * \note Internally based on \ref MDBX_RESERVE feature,
- *       therefore doesn't support \ref MDBX_DUPSORT.
- *
- * \param [in] txn       A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi       A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key       The key to store in the database.
- * \param [in] attr      The attribute to store in the database.
- * \param [in,out] data  The data to store.
- * \param [in] flags     Special options for this operation. This parameter
- *                       must be set to 0 or by bitwise OR'ing together one or
- *                       more of the values described here:
- *  - \ref MDBX_NOOVERWRITE
- *      Enter the new key/data pair only if the key does not already appear
- *      in the database. The function will return \ref MDBX_KEYEXIST if the key
- *      already appears in the database. The data parameter will be set to
- *      point to the existing item.
- *
- *  - \ref MDBX_CURRENT
- *      Update an single existing entry, but not add new ones. The function
- *      will return \ref MDBX_NOTFOUND if the given key not exist in the
- *      database. Or the \ref MDBX_EMULTIVAL in case duplicates for the given
- *     key.
- *
- *  - \ref MDBX_APPEND
- *      Append the given key/data pair to the end of the database. This option
- *      allows fast bulk loading when keys are already known to be in the
- *      correct order. Loading unsorted keys with this flag will cause
- *      a \ref MDBX_EKEYMISMATCH error.
- *
- * \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_KEYEXIST
- * \retval MDBX_MAP_FULL  The database is full, see \ref mdbx_env_set_mapsize().
- * \retval MDBX_TXN_FULL  The transaction has too many dirty pages.
- * \retval MDBX_EACCES    An attempt was made to write
- *                        in a read-only transaction.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_put_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
-                              MDBX_val *data, mdbx_attr_t attr,
-                              MDBX_put_flags_t flags);
-
-/** Set items attribute from a database.
- *
- * This function stores key/data pairs attribute to the database.
- *
- * \note Internally based on \ref MDBX_RESERVE feature,
- *       therefore doesn't support \ref MDBX_DUPSORT.
- *
- * \param [in] txn   A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi   A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key   The key to search for in the database.
- * \param [in] data  The data to be stored or NULL to save previous value.
- * \param [in] attr  The attribute to be stored.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_NOTFOUND   The key-value pair was not in the database.
- * \retval MDBX_EINVAL     An invalid parameter was specified. */
-LIBMDBX_API int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
-                              MDBX_val *data, mdbx_attr_t attr);
-
-/** Get items attribute from a database cursor.
- *
- * This function retrieves key/data pairs from the database. The address and
- * length of the key are returned in the object to which key refers (except
- * for the case of the \ref MDBX_SET option, in which the key object is
- * unchanged), and the address and length of the data are returned in the object
- * to which data refers.
- * \see mdbx_get()
- *
- * \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
- * \param [in,out] key   The key for a retrieved item.
- * \param [in,out] data  The data of a retrieved item.
- * \param [out] pattr    The pointer to retrieve attribute.
- * \param [in] op        A cursor operation MDBX_cursor_op.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_NOTFOUND  No matching key found.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_cursor_get_attr(MDBX_cursor *cursor, MDBX_val *key,
-                                     MDBX_val *data, mdbx_attr_t *pattr,
-                                     MDBX_cursor_op op);
-
-/** Get items attribute from a database.
- *
- * This function retrieves key/data pairs from the database. The address
- * and length of the data associated with the specified key are returned
- * in the structure to which data refers.
- * If the database supports duplicate keys (see \ref MDBX_DUPSORT) then the
- * first data item for the key will be returned. Retrieval of other
- * items requires the use of \ref mdbx_cursor_get().
- *
- * \note The memory pointed to by the returned values is owned by the
- * database. The caller need not dispose of the memory, and may not
- * modify it in any way. For values returned in a read-only transaction
- * any modification attempts will cause a `SIGSEGV`.
- *
- * \note Values returned from the database are valid only until a
- * subsequent update operation, or the end of the transaction.
- *
- * \param [in] txn       A transaction handle returned by \ref mdbx_txn_begin().
- * \param [in] dbi       A database handle returned by \ref mdbx_dbi_open().
- * \param [in] key       The key to search for in the database.
- * \param [in,out] data  The data corresponding to the key.
- * \param [out] pattr    The pointer to retrieve attribute.
- *
- * \returns A non-zero error value on failure and 0 on success,
- *          some possible errors are:
- * \retval MDBX_NOTFOUND  The key was not in the database.
- * \retval MDBX_EINVAL    An invalid parameter was specified. */
-LIBMDBX_API int mdbx_get_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
-                              MDBX_val *data, mdbx_attr_t *pattr);
-/** @} end of Attribute support functions for Nexenta */
-#endif /* MDBX_NEXENTA_ATTRS */
-
-/** @} end of C API */
-
-/*******************************************************************************
- * Workaround for mmaped-lookahead-cross-page-boundary bug
- * in an obsolete versions of Elbrus's libc and kernels. */
-#if defined(__e2k__) && defined(MDBX_E2K_MLHCPB_WORKAROUND) &&                 \
-    MDBX_E2K_MLHCPB_WORKAROUND
-LIBMDBX_API int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
-                                               size_t n);
-LIBMDBX_API int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2);
-LIBMDBX_API int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
-                                                size_t n);
-LIBMDBX_API size_t mdbx_e2k_strlen_bug_workaround(const char *s);
-LIBMDBX_API size_t mdbx_e2k_strnlen_bug_workaround(const char *s,
-                                                   size_t maxlen);
-#ifdef __cplusplus
-namespace std {
-inline int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
-                                          size_t n) {
-  return ::mdbx_e2k_memcmp_bug_workaround(s1, s2, n);
-}
-inline int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2) {
-  return ::mdbx_e2k_strcmp_bug_workaround(s1, s2);
-}
-inline int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
-                                           size_t n) {
-  return ::mdbx_e2k_strncmp_bug_workaround(s1, s2, n);
-}
-inline size_t mdbx_e2k_strlen_bug_workaround(const char *s) {
-  return ::mdbx_e2k_strlen_bug_workaround(s);
-}
-inline size_t mdbx_e2k_strnlen_bug_workaround(const char *s, size_t maxlen) {
-  return ::mdbx_e2k_strnlen_bug_workaround(s, maxlen);
-}
-} // namespace std
-#endif /* __cplusplus */
-
-#include <string.h>
-#include <strings.h>
-#undef memcmp
-#define memcmp mdbx_e2k_memcmp_bug_workaround
-#undef bcmp
-#define bcmp mdbx_e2k_memcmp_bug_workaround
-#undef strcmp
-#define strcmp mdbx_e2k_strcmp_bug_workaround
-#undef strncmp
-#define strncmp mdbx_e2k_strncmp_bug_workaround
-#undef strlen
-#define strlen mdbx_e2k_strlen_bug_workaround
-#undef strnlen
-#define strnlen mdbx_e2k_strnlen_bug_workaround
-#endif /* MDBX_E2K_MLHCPB_WORKAROUND */
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* LIBMDBX_H */
diff --git a/3rdparty/libmdbx/mdbx.h++ b/3rdparty/libmdbx/mdbx.h++
deleted file mode 100644
index 11d209e6948984d2a9724e65ec9f5008456c06c1..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx.h++
+++ /dev/null
@@ -1,5983 +0,0 @@
-/// \file mdbx.h++
-/// \brief The libmdbx C++ API header file.
-///
-/// \author Copyright (c) 2020-2022, Leonid Yuriev <leo@yuriev.ru>.
-/// \copyright SPDX-License-Identifier: Apache-2.0
-///
-/// Tested with:
-///  - Elbrus LCC >= 1.23 (http://www.mcst.ru/lcc);
-///  - GNU C++ >= 4.8;
-///  - clang >= 3.9;
-///  - MSVC >= 14.0 (Visual Studio 2015),
-///    but 19.2x could hang due optimizer bug;
-///  - AppleClang, but without C++20 concepts.
-///
-
-///
-/// The origin has been migrated to https://gitflic.ru/project/erthink/libmdbx
-/// since on 2022-04-15 the Github administration, without any warning nor
-/// explanation, deleted libmdbx along with a lot of other projects,
-/// simultaneously blocking access for many developers.
-/// For the same reason Github is blacklisted forever.
-///
-
-#pragma once
-
-/* Workaround for modern libstdc++ with CLANG < 4.x */
-#if defined(__SIZEOF_INT128__) && !defined(__GLIBCXX_TYPE_INT_N_0) &&          \
-    defined(__clang__) && __clang_major__ < 4
-#define __GLIBCXX_BITSIZE_INT_N_0 128
-#define __GLIBCXX_TYPE_INT_N_0 __int128
-#endif /* Workaround for modern libstdc++ with CLANG < 4.x */
-
-#if !defined(__cplusplus) || __cplusplus < 201103L
-#if !defined(_MSC_VER) || _MSC_VER < 1900
-#error "C++11 compiler or better is required"
-#elif _MSC_VER >= 1910
-#error                                                                         \
-    "Please add `/Zc:__cplusplus` to MSVC compiler options to enforce it conform ISO C++"
-#endif /* MSVC is mad and don't define __cplusplus properly */
-#endif /* __cplusplus < 201103L */
-
-#if (defined(_WIN32) || defined(_WIN64)) && MDBX_WITHOUT_MSVC_CRT
-#error                                                                         \
-    "CRT is required for C++ API, the MDBX_WITHOUT_MSVC_CRT option must be disabled"
-#endif /* Windows */
-
-#ifndef __has_include
-#define __has_include(header) (0)
-#endif /* __has_include */
-
-#if __has_include(<version>)
-#include <version>
-#endif /* <version> */
-
-/* Disable min/max macros from C' headers */
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#include <algorithm>   // for std::min/max
-#include <cassert>     // for assert()
-#include <climits>     // for CHAR_BIT
-#include <cstring>     // for std::strlen, str:memcmp
-#include <exception>   // for std::exception_ptr
-#include <ostream>     // for std::ostream
-#include <sstream>     // for std::ostringstream
-#include <stdexcept>   // for std::invalid_argument
-#include <string>      // for std::string
-#include <type_traits> // for std::is_pod<>, etc.
-#include <utility>     // for std::make_pair
-#include <vector>      // for std::vector<> as template args
-
-#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L
-#include <memory_resource>
-#endif
-
-#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
-#include <string_view>
-#endif
-
-#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
-#include <filesystem>
-#elif __has_include(<experimental/filesystem>)
-#include <experimental/filesystem>
-#endif
-
-#include "mdbx.h"
-
-#if (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L) ||          \
-    (defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L) ||              \
-    (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) ||              \
-    (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L)
-#include <bit>
-#elif !(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) &&         \
-        defined(__ORDER_BIG_ENDIAN__))
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-#endif
-#endif
-#endif /* Byte Order */
-
-#if defined(DOXYGEN) ||                                                        \
-    defined(__cpp_constexpr) && __cpp_constexpr >= 201603L &&                  \
-        ((defined(_MSC_VER) && _MSC_VER >= 1915) ||                            \
-         (defined(__clang__) && __clang_major__ > 5) ||                        \
-         (defined(__GNUC__) && __GNUC__ > 7) ||                                \
-         (!defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER)))
-#define MDBX_CXX17_CONSTEXPR constexpr
-#else
-#define MDBX_CXX17_CONSTEXPR inline
-#endif /* MDBX_CXX17_CONSTEXPR */
-
-#if defined(DOXYGEN) || defined(__cpp_lib_is_constant_evaluated) &&            \
-                            __cpp_lib_is_constant_evaluated >= 201811L &&      \
-                            defined(__cpp_lib_constexpr_string) &&             \
-                            __cpp_lib_constexpr_string >= 201907L
-#define MDBX_CXX20_CONSTEXPR constexpr
-#else
-#define MDBX_CXX20_CONSTEXPR inline
-#endif /* MDBX_CXX20_CONSTEXPR */
-
-#if defined(CONSTEXPR_ASSERT)
-#define MDBX_CONSTEXPR_ASSERT(expr) CONSTEXPR_ASSERT(expr)
-#elif defined NDEBUG
-#define MDBX_CONSTEXPR_ASSERT(expr) void(0)
-#else
-#define MDBX_CONSTEXPR_ASSERT(expr)                                            \
-  ((expr) ? void(0) : [] { assert(!#expr); }())
-#endif /* MDBX_CONSTEXPR_ASSERT */
-
-#ifndef MDBX_LIKELY
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__GNUC__) || __has_builtin(__builtin_expect)) &&                  \
-        !defined(__COVERITY__)
-#define MDBX_LIKELY(cond) __builtin_expect(!!(cond), 1)
-#else
-#define MDBX_LIKELY(x) (x)
-#endif
-#endif /* MDBX_LIKELY */
-
-#ifndef MDBX_UNLIKELY
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__GNUC__) || __has_builtin(__builtin_expect)) &&                  \
-        !defined(__COVERITY__)
-#define MDBX_UNLIKELY(cond) __builtin_expect(!!(cond), 0)
-#else
-#define MDBX_UNLIKELY(x) (x)
-#endif
-#endif /* MDBX_UNLIKELY */
-
-#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
-#define MDBX_IF_CONSTEXPR constexpr
-#else
-#define MDBX_IF_CONSTEXPR
-#endif /* MDBX_IF_CONSTEXPR */
-
-#if defined(DOXYGEN) ||                                                        \
-    (__has_cpp_attribute(fallthrough) &&                                       \
-     (!defined(__clang__) || __clang__ > 4)) ||                                \
-    __cplusplus >= 201703L
-#define MDBX_CXX17_FALLTHROUGH [[fallthrough]]
-#else
-#define MDBX_CXX17_FALLTHROUGH
-#endif /* MDBX_CXX17_FALLTHROUGH */
-
-#if defined(DOXYGEN) || (__has_cpp_attribute(likely) >= 201803L &&             \
-                         (!defined(__GNUC__) || __GNUC__ > 9))
-#define MDBX_CXX20_LIKELY [[likely]]
-#else
-#define MDBX_CXX20_LIKELY
-#endif /* MDBX_CXX20_LIKELY */
-
-#ifndef MDBX_CXX20_UNLIKELY
-#if defined(DOXYGEN) || (__has_cpp_attribute(unlikely) >= 201803L &&           \
-                         (!defined(__GNUC__) || __GNUC__ > 9))
-#define MDBX_CXX20_UNLIKELY [[unlikely]]
-#else
-#define MDBX_CXX20_UNLIKELY
-#endif
-#endif /* MDBX_CXX20_UNLIKELY */
-
-#ifndef MDBX_HAVE_CXX20_CONCEPTS
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_concepts) && __cpp_concepts >= 201907L &&                   \
-     (!defined(__clang__) || __has_include(<concepts>) ||                      \
-  (defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L)))
-#if __has_include(<concepts>) ||                                               \
-  (defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L)
-#include <concepts>
-#endif /* <concepts> */
-#define MDBX_HAVE_CXX20_CONCEPTS 1
-#else
-#define MDBX_HAVE_CXX20_CONCEPTS 0
-#endif
-#endif /* MDBX_HAVE_CXX20_CONCEPTS */
-
-#ifndef MDBX_CXX20_CONCEPT
-#if MDBX_HAVE_CXX20_CONCEPTS
-#define MDBX_CXX20_CONCEPT(CONCEPT, NAME) CONCEPT NAME
-#else
-#define MDBX_CXX20_CONCEPT(CONCEPT, NAME) typename NAME
-#endif
-#endif /* MDBX_CXX20_CONCEPT */
-
-#ifndef MDBX_ASSERT_CXX20_CONCEPT_SATISFIED
-#if MDBX_HAVE_CXX20_CONCEPTS
-#define MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(CONCEPT, TYPE)                     \
-  static_assert(CONCEPT<TYPE>)
-#else
-#define MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(CONCEPT, NAME)                     \
-  static_assert(true, MDBX_STRINGIFY(CONCEPT) "<" MDBX_STRINGIFY(TYPE) ">")
-#endif
-#endif /* MDBX_ASSERT_CXX20_CONCEPT_SATISFIED */
-
-#ifdef _MSC_VER
-#pragma warning(push, 4)
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4251) /* 'std::FOO' needs to have dll-interface to   \
-                                   be used by clients of 'mdbx::BAR' */
-#pragma warning(disable : 4275) /* non dll-interface 'std::FOO' used as        \
-                                   base for dll-interface 'mdbx::BAR' */
-/* MSVC is mad and can generate this warning for its own intermediate
- * automatically generated code, which becomes unreachable after some kinds of
- * optimization (copy elision, etc). */
-#pragma warning(disable : 4702) /* unreachable code */
-#endif                          /* _MSC_VER (warnings) */
-
-//------------------------------------------------------------------------------
-/// \defgroup cxx_api C++ API
-/// @{
-
-namespace mdbx {
-
-// Functions whose signature depends on the `mdbx::byte` type
-// must be strictly defined as inline!
-#if defined(DOXYGEN) || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811)
-// To enable all kinds of an compiler optimizations we use a byte-like type
-// that don't presumes aliases for pointers as does the `char` type and its
-// derivatives/typedefs.
-// Please see todo4recovery://erased_by_github/libmdbx/issues/263
-// for reasoning of the use of `char8_t` type and switching to `__restrict__`.
-using byte = char8_t;
-#else
-// Avoid `std::byte` since it doesn't add features but inconvenient
-// restrictions.
-using byte = unsigned char;
-#endif /* __cpp_char8_t >= 201811*/
-
-#if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L
-using endian = ::std::endian;
-#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) &&           \
-    defined(__ORDER_BIG_ENDIAN__)
-enum class endian {
-  little = __ORDER_LITTLE_ENDIAN__,
-  big = __ORDER_BIG_ENDIAN__,
-  native = __BYTE_ORDER__
-};
-#else
-#error                                                                         \
-    "Please use a C++ compiler provides byte order information or C++20 support"
-#endif /* Byte Order enum */
-
-/// \copydoc MDBX_version_info
-using version_info = ::MDBX_version_info;
-/// \brief Returns libmdbx version information.
-MDBX_CXX11_CONSTEXPR const version_info &get_version() noexcept;
-/// \copydoc MDBX_build_info
-using build_info = ::MDBX_build_info;
-/// \brief Returns libmdbx build information.
-MDBX_CXX11_CONSTEXPR const build_info &get_build() noexcept;
-
-/// \brief constexpr-compatible strlen().
-static MDBX_CXX17_CONSTEXPR size_t strlen(const char *c_str) noexcept;
-
-/// \brief Legacy default allocator
-/// but it is recommended to use \ref polymorphic_allocator.
-using legacy_allocator = ::std::string::allocator_type;
-
-struct slice;
-struct default_capacity_policy;
-template <class ALLOCATOR = legacy_allocator,
-          class CAPACITY_POLICY = default_capacity_policy>
-class buffer;
-class env;
-class env_managed;
-class txn;
-class txn_managed;
-class cursor;
-class cursor_managed;
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_memory_resource) &&                                     \
-     __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI)
-/// \brief Default polymorphic allocator for modern code.
-using polymorphic_allocator = ::std::pmr::string::allocator_type;
-#endif /* __cpp_lib_memory_resource >= 201603L */
-
-/// \brief Default singe-byte string.
-template <class ALLOCATOR = legacy_allocator>
-using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
-
-using filehandle = ::mdbx_filehandle_t;
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L &&       \
-     (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ||                             \
-      __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) &&                            \
-     (!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ||                            \
-      __IPHONE_OS_VERSION_MIN_REQUIRED >= 130100))
-namespace filesystem = ::std::filesystem;
-#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path
-#elif defined(__cpp_lib_experimental_filesystem) &&                            \
-    __cpp_lib_experimental_filesystem >= 201406L
-namespace filesystem = ::std::experimental::filesystem;
-#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-
-#ifdef MDBX_STD_FILESYSTEM_PATH
-using path = MDBX_STD_FILESYSTEM_PATH;
-#elif defined(_WIN32) || defined(_WIN64)
-using path = ::std::wstring;
-#else
-using path = ::std::string;
-#endif /* mdbx::path */
-
-/// \brief Transfers C++ exceptions thru C callbacks.
-/// \details Implements saving exceptions before returning
-/// from an C++'s environment to the intermediate C code and re-throwing after
-/// returning from C to the C++'s environment.
-class LIBMDBX_API_TYPE exception_thunk {
-  ::std::exception_ptr captured_;
-
-public:
-  exception_thunk() noexcept = default;
-  exception_thunk(const exception_thunk &) = delete;
-  exception_thunk(exception_thunk &&) = delete;
-  exception_thunk &operator=(const exception_thunk &) = delete;
-  exception_thunk &operator=(exception_thunk &&) = delete;
-  inline bool is_clean() const noexcept;
-  inline void capture() noexcept;
-  inline void rethrow_captured() const;
-};
-
-/// \brief Implements error information and throwing corresponding exceptions.
-class LIBMDBX_API_TYPE error {
-  MDBX_error_t code_;
-  inline error &operator=(MDBX_error_t error_code) noexcept;
-
-public:
-  MDBX_CXX11_CONSTEXPR error(MDBX_error_t error_code) noexcept;
-  error(const error &) = default;
-  error(error &&) = default;
-  error &operator=(const error &) = default;
-  error &operator=(error &&) = default;
-
-  MDBX_CXX11_CONSTEXPR friend bool operator==(const error &a,
-                                              const error &b) noexcept;
-  MDBX_CXX11_CONSTEXPR friend bool operator!=(const error &a,
-                                              const error &b) noexcept;
-
-  MDBX_CXX11_CONSTEXPR bool is_success() const noexcept;
-  MDBX_CXX11_CONSTEXPR bool is_result_true() const noexcept;
-  MDBX_CXX11_CONSTEXPR bool is_result_false() const noexcept;
-  MDBX_CXX11_CONSTEXPR bool is_failure() const noexcept;
-
-  /// \brief Returns error code.
-  MDBX_CXX11_CONSTEXPR MDBX_error_t code() const noexcept;
-
-  /// \brief Returns message for MDBX's errors only and "SYSTEM" for others.
-  const char *what() const noexcept;
-
-  /// \brief Returns message for any errors.
-  ::std::string message() const;
-
-  /// \brief Returns true for MDBX's errors.
-  MDBX_CXX11_CONSTEXPR bool is_mdbx_error() const noexcept;
-  /// \brief Panics on unrecoverable errors inside destructors etc.
-  [[noreturn]] void panic(const char *context_where_when,
-                          const char *func_who_what) const noexcept;
-  [[noreturn]] void throw_exception() const;
-  [[noreturn]] static inline void throw_exception(int error_code);
-  inline void throw_on_failure() const;
-  inline void success_or_throw() const;
-  inline void success_or_throw(const exception_thunk &) const;
-  inline void panic_on_failure(const char *context_where,
-                               const char *func_who) const noexcept;
-  inline void success_or_panic(const char *context_where,
-                               const char *func_who) const noexcept;
-  static inline void throw_on_nullptr(const void *ptr, MDBX_error_t error_code);
-  static inline void success_or_throw(MDBX_error_t error_code);
-  static void success_or_throw(int error_code) {
-    success_or_throw(static_cast<MDBX_error_t>(error_code));
-  }
-  static inline void throw_on_failure(int error_code);
-  static inline bool boolean_or_throw(int error_code);
-  static inline void success_or_throw(int error_code, const exception_thunk &);
-  static inline void panic_on_failure(int error_code, const char *context_where,
-                                      const char *func_who) noexcept;
-  static inline void success_or_panic(int error_code, const char *context_where,
-                                      const char *func_who) noexcept;
-};
-
-/// \brief Base class for all libmdbx's exceptions that are corresponds
-/// to libmdbx errors.
-///
-/// \see MDBX_error_t
-class LIBMDBX_API_TYPE exception : public ::std::runtime_error {
-  using base = ::std::runtime_error;
-  ::mdbx::error error_;
-
-public:
-  exception(const ::mdbx::error &) noexcept;
-  exception(const exception &) = default;
-  exception(exception &&) = default;
-  exception &operator=(const exception &) = default;
-  exception &operator=(exception &&) = default;
-  virtual ~exception() noexcept;
-  const ::mdbx::error error() const noexcept { return error_; }
-};
-
-/// \brief Fatal exception that lead termination anyway
-/// in dangerous unrecoverable cases.
-class LIBMDBX_API_TYPE fatal : public exception {
-  using base = exception;
-
-public:
-  fatal(const ::mdbx::error &) noexcept;
-  fatal(const exception &src) noexcept : fatal(src.error()) {}
-  fatal(exception &&src) noexcept : fatal(src.error()) {}
-  fatal(const fatal &src) noexcept : fatal(src.error()) {}
-  fatal(fatal &&src) noexcept : fatal(src.error()) {}
-  fatal &operator=(fatal &&) = default;
-  fatal &operator=(const fatal &) = default;
-  virtual ~fatal() noexcept;
-};
-
-#define MDBX_DECLARE_EXCEPTION(NAME)                                           \
-  struct LIBMDBX_API_TYPE NAME : public exception {                            \
-    NAME(const ::mdbx::error &);                                               \
-    virtual ~NAME() noexcept;                                                  \
-  }
-MDBX_DECLARE_EXCEPTION(bad_map_id);
-MDBX_DECLARE_EXCEPTION(bad_transaction);
-MDBX_DECLARE_EXCEPTION(bad_value_size);
-MDBX_DECLARE_EXCEPTION(db_corrupted);
-MDBX_DECLARE_EXCEPTION(db_full);
-MDBX_DECLARE_EXCEPTION(db_invalid);
-MDBX_DECLARE_EXCEPTION(db_too_large);
-MDBX_DECLARE_EXCEPTION(db_unable_extend);
-MDBX_DECLARE_EXCEPTION(db_version_mismatch);
-MDBX_DECLARE_EXCEPTION(db_wanna_write_for_recovery);
-MDBX_DECLARE_EXCEPTION(incompatible_operation);
-MDBX_DECLARE_EXCEPTION(internal_page_full);
-MDBX_DECLARE_EXCEPTION(internal_problem);
-MDBX_DECLARE_EXCEPTION(key_exists);
-MDBX_DECLARE_EXCEPTION(key_mismatch);
-MDBX_DECLARE_EXCEPTION(max_maps_reached);
-MDBX_DECLARE_EXCEPTION(max_readers_reached);
-MDBX_DECLARE_EXCEPTION(multivalue);
-MDBX_DECLARE_EXCEPTION(no_data);
-MDBX_DECLARE_EXCEPTION(not_found);
-MDBX_DECLARE_EXCEPTION(operation_not_permitted);
-MDBX_DECLARE_EXCEPTION(permission_denied_or_not_writeable);
-MDBX_DECLARE_EXCEPTION(reader_slot_busy);
-MDBX_DECLARE_EXCEPTION(remote_media);
-MDBX_DECLARE_EXCEPTION(something_busy);
-MDBX_DECLARE_EXCEPTION(thread_mismatch);
-MDBX_DECLARE_EXCEPTION(transaction_full);
-MDBX_DECLARE_EXCEPTION(transaction_overlapping);
-#undef MDBX_DECLARE_EXCEPTION
-
-[[noreturn]] LIBMDBX_API void throw_too_small_target_buffer();
-[[noreturn]] LIBMDBX_API void throw_max_length_exceeded();
-[[noreturn]] LIBMDBX_API void throw_out_range();
-[[noreturn]] LIBMDBX_API void throw_allocators_mismatch();
-static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes);
-static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom,
-                                                size_t payload);
-static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, size_t payload,
-                                                size_t tailroom);
-static MDBX_CXX17_CONSTEXPR size_t strlen(const char *c_str) noexcept;
-static MDBX_CXX20_CONSTEXPR void *memcpy(void *dest, const void *src,
-                                         size_t bytes) noexcept;
-//------------------------------------------------------------------------------
-
-#if MDBX_HAVE_CXX20_CONCEPTS
-
-template <typename T>
-concept MutableByteProducer = requires(T a, char array[42]) {
-  { a.is_empty() } -> std::same_as<bool>;
-  { a.envisage_result_length() } -> std::same_as<size_t>;
-  { a.write_bytes(&array[0], size_t(42)) } -> std::same_as<char *>;
-};
-
-template <typename T>
-concept ImmutableByteProducer = requires(const T &a, char array[42]) {
-  { a.is_empty() } -> std::same_as<bool>;
-  { a.envisage_result_length() } -> std::same_as<size_t>;
-  { a.write_bytes(&array[0], size_t(42)) } -> std::same_as<char *>;
-};
-
-template <typename T>
-concept SliceTranscoder = ImmutableByteProducer<T> &&
-    requires(const slice &source, const T &a) {
-  T(source);
-  { a.is_erroneous() } -> std::same_as<bool>;
-};
-
-#endif /* MDBX_HAVE_CXX20_CONCEPTS */
-
-template <class ALLOCATOR = legacy_allocator,
-          typename CAPACITY_POLICY = default_capacity_policy,
-          MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-make_buffer(PRODUCER &producer, const ALLOCATOR &allocator = ALLOCATOR());
-
-template <class ALLOCATOR = legacy_allocator,
-          typename CAPACITY_POLICY = default_capacity_policy,
-          MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-make_buffer(const PRODUCER &producer, const ALLOCATOR &allocator = ALLOCATOR());
-
-template <class ALLOCATOR = legacy_allocator,
-          MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)>
-inline string<ALLOCATOR> make_string(PRODUCER &producer,
-                                     const ALLOCATOR &allocator = ALLOCATOR());
-
-template <class ALLOCATOR = legacy_allocator,
-          MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)>
-inline string<ALLOCATOR> make_string(const PRODUCER &producer,
-                                     const ALLOCATOR &allocator = ALLOCATOR());
-
-/// \brief References a data located outside the slice.
-///
-/// The `slice` is similar in many ways to `std::string_view`, but it
-/// implements specific capabilities and manipulates with bytes but
-/// not a characters.
-///
-/// \copydetails MDBX_val
-struct LIBMDBX_API_TYPE slice : public ::MDBX_val {
-  /// \todo slice& operator<<(slice&, ...) for reading
-  /// \todo key-to-value (parse/unpack) functions
-  /// \todo template<class X> key(X); for decoding keys while reading
-
-  enum { max_length = MDBX_MAXDATASIZE };
-
-  /// \brief Create an empty slice.
-  MDBX_CXX11_CONSTEXPR slice() noexcept;
-
-  /// \brief Create a slice that refers to [0,bytes-1] of memory bytes pointed
-  /// by ptr.
-  MDBX_CXX14_CONSTEXPR slice(const void *ptr, size_t bytes);
-
-  /// \brief Create a slice that refers to [begin,end] of memory bytes.
-  MDBX_CXX14_CONSTEXPR slice(const void *begin, const void *end);
-
-  /// \brief Create a slice that refers to text[0,strlen(text)-1].
-  template <size_t SIZE>
-  MDBX_CXX14_CONSTEXPR slice(const char (&text)[SIZE]) : slice(text, SIZE - 1) {
-    MDBX_CONSTEXPR_ASSERT(SIZE > 0 && text[SIZE - 1] == '\0');
-  }
-  /// \brief Create a slice that refers to c_str[0,strlen(c_str)-1].
-  explicit MDBX_CXX17_CONSTEXPR slice(const char *c_str);
-
-  /// \brief Create a slice that refers to the contents of "str".
-  /// \note 'explicit' to avoid reference to the temporary std::string instance.
-  template <class CHAR, class T, class A>
-  explicit MDBX_CXX20_CONSTEXPR
-  slice(const ::std::basic_string<CHAR, T, A> &str)
-      : slice(str.data(), str.length() * sizeof(CHAR)) {}
-
-  MDBX_CXX14_CONSTEXPR slice(const MDBX_val &src);
-  MDBX_CXX11_CONSTEXPR slice(const slice &) noexcept = default;
-  MDBX_CXX14_CONSTEXPR slice(MDBX_val &&src);
-  MDBX_CXX14_CONSTEXPR slice(slice &&src) noexcept;
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  /// \brief Create a slice that refers to the same contents as "string_view"
-  template <class CHAR, class T>
-  MDBX_CXX14_CONSTEXPR slice(const ::std::basic_string_view<CHAR, T> &sv)
-      : slice(sv.data(), sv.data() + sv.length()) {}
-
-  template <class CHAR, class T>
-  slice(::std::basic_string_view<CHAR, T> &&sv) : slice(sv) {
-    sv = {};
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  template <size_t SIZE>
-  static MDBX_CXX14_CONSTEXPR slice wrap(const char (&text)[SIZE]) {
-    return slice(text);
-  }
-
-  template <typename POD>
-  MDBX_CXX14_CONSTEXPR static slice wrap(const POD &pod) {
-    static_assert(::std::is_standard_layout<POD>::value &&
-                      !::std::is_pointer<POD>::value,
-                  "Must be a standard layout type!");
-    return slice(&pod, sizeof(pod));
-  }
-
-  inline slice &assign(const void *ptr, size_t bytes);
-  inline slice &assign(const slice &src) noexcept;
-  inline slice &assign(const ::MDBX_val &src);
-  inline slice &assign(slice &&src) noexcept;
-  inline slice &assign(::MDBX_val &&src);
-  inline slice &assign(const void *begin, const void *end);
-  template <class CHAR, class T, class ALLOCATOR>
-  slice &assign(const ::std::basic_string<CHAR, T, ALLOCATOR> &str) {
-    return assign(str.data(), str.length() * sizeof(CHAR));
-  }
-  inline slice &assign(const char *c_str);
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  slice &assign(const ::std::basic_string_view<CHAR, T> &view) {
-    return assign(view.begin(), view.end());
-  }
-  template <class CHAR, class T>
-  slice &assign(::std::basic_string_view<CHAR, T> &&view) {
-    assign(view);
-    view = {};
-    return *this;
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  slice &operator=(const slice &) noexcept = default;
-  inline slice &operator=(slice &&src) noexcept;
-  inline slice &operator=(::MDBX_val &&src);
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  slice &operator=(const ::std::basic_string_view<CHAR, T> &view) {
-    return assign(view);
-  }
-
-  template <class CHAR, class T>
-  slice &operator=(::std::basic_string_view<CHAR, T> &&view) {
-    return assign(view);
-  }
-
-  /// \brief Return a string_view that references the same data as this slice.
-  template <class CHAR = char, class T = ::std::char_traits<CHAR>>
-  MDBX_CXX11_CONSTEXPR ::std::basic_string_view<CHAR, T>
-  string_view() const noexcept {
-    static_assert(sizeof(CHAR) == 1, "Must be single byte characters");
-    return ::std::basic_string_view<CHAR, T>(char_ptr(), length());
-  }
-
-  /// \brief Return a string_view that references the same data as this slice.
-  template <class CHAR, class T>
-  MDBX_CXX11_CONSTEXPR explicit
-  operator ::std::basic_string_view<CHAR, T>() const noexcept {
-    return this->string_view<CHAR, T>();
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  template <class CHAR = char, class T = ::std::char_traits<CHAR>,
-            class ALLOCATOR = legacy_allocator>
-  MDBX_CXX20_CONSTEXPR ::std::basic_string<CHAR, T, ALLOCATOR>
-  as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    static_assert(sizeof(CHAR) == 1, "Must be single byte characters");
-    return ::std::basic_string<CHAR, T, ALLOCATOR>(char_ptr(), length(),
-                                                   allocator);
-  }
-
-  template <class CHAR, class T, class ALLOCATOR>
-  MDBX_CXX20_CONSTEXPR explicit
-  operator ::std::basic_string<CHAR, T, ALLOCATOR>() const {
-    return as_string<CHAR, T, ALLOCATOR>();
-  }
-
-  /// \brief Returns a string with a hexadecimal dump of the slice content.
-  template <class ALLOCATOR = legacy_allocator>
-  inline string<ALLOCATOR>
-  as_hex_string(bool uppercase = false, unsigned wrap_width = 0,
-                const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Returns a string with a
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the slice content.
-  template <class ALLOCATOR = legacy_allocator>
-  inline string<ALLOCATOR>
-  as_base58_string(unsigned wrap_width = 0,
-                   const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Returns a string with a
-  /// [Base58](https://en.wikipedia.org/wiki/Base64) dump of the slice content.
-  template <class ALLOCATOR = legacy_allocator>
-  inline string<ALLOCATOR>
-  as_base64_string(unsigned wrap_width = 0,
-                   const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Returns a buffer with a hexadecimal dump of the slice content.
-  template <class ALLOCATOR = legacy_allocator,
-            class CAPACITY_POLICY = default_capacity_policy>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  encode_hex(bool uppercase = false, unsigned wrap_width = 0,
-             const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Returns a buffer with a
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the slice content.
-  template <class ALLOCATOR = legacy_allocator,
-            class CAPACITY_POLICY = default_capacity_policy>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  encode_base58(unsigned wrap_width = 0,
-                const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Returns a buffer with a
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the slice content.
-  template <class ALLOCATOR = legacy_allocator,
-            class CAPACITY_POLICY = default_capacity_policy>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  encode_base64(unsigned wrap_width = 0,
-                const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Decodes hexadecimal dump from the slice content to returned buffer.
-  template <class ALLOCATOR = legacy_allocator,
-            class CAPACITY_POLICY = default_capacity_policy>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  hex_decode(bool ignore_spaces = false,
-             const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump
-  /// from the slice content to returned buffer.
-  template <class ALLOCATOR = legacy_allocator,
-            class CAPACITY_POLICY = default_capacity_policy>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  base58_decode(bool ignore_spaces = false,
-                const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump
-  /// from the slice content to returned buffer.
-  template <class ALLOCATOR = legacy_allocator,
-            class CAPACITY_POLICY = default_capacity_policy>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  base64_decode(bool ignore_spaces = false,
-                const ALLOCATOR &allocator = ALLOCATOR()) const;
-
-  /// \brief Checks whether the content of the slice is printable.
-  /// \param [in] disable_utf8 By default if `disable_utf8` is `false` function
-  /// checks that content bytes are printable ASCII-7 characters or a valid UTF8
-  /// sequences. Otherwise, if if `disable_utf8` is `true` function checks that
-  /// content bytes are printable extended 8-bit ASCII codes.
-  MDBX_NOTHROW_PURE_FUNCTION bool
-  is_printable(bool disable_utf8 = false) const noexcept;
-
-  /// \brief Checks whether the content of the slice is a hexadecimal dump.
-  /// \param [in] ignore_spaces If `true` function will skips spaces surrounding
-  /// (before, between and after) a encoded bytes. However, spaces should not
-  /// break a pair of characters encoding a single byte.
-  inline MDBX_NOTHROW_PURE_FUNCTION bool
-  is_hex(bool ignore_spaces = false) const noexcept;
-
-  /// \brief Checks whether the content of the slice is a
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump.
-  /// \param [in] ignore_spaces If `true` function will skips spaces surrounding
-  /// (before, between and after) a encoded bytes. However, spaces should not
-  /// break a code group of characters.
-  inline MDBX_NOTHROW_PURE_FUNCTION bool
-  is_base58(bool ignore_spaces = false) const noexcept;
-
-  /// \brief Checks whether the content of the slice is a
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump.
-  /// \param [in] ignore_spaces If `true` function will skips spaces surrounding
-  /// (before, between and after) a encoded bytes. However, spaces should not
-  /// break a code group of characters.
-  inline MDBX_NOTHROW_PURE_FUNCTION bool
-  is_base64(bool ignore_spaces = false) const noexcept;
-
-  inline void swap(slice &other) noexcept;
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  void swap(::std::basic_string_view<CHAR, T> &view) noexcept {
-    static_assert(sizeof(CHAR) == 1, "Must be single byte characters");
-    const auto temp = ::std::basic_string_view<CHAR, T>(*this);
-    *this = view;
-    view = temp;
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  /// \brief Returns casted to pointer to byte an address of data.
-  MDBX_CXX11_CONSTEXPR const byte *byte_ptr() const noexcept;
-  MDBX_CXX11_CONSTEXPR byte *byte_ptr() noexcept;
-
-  /// \brief Returns casted to pointer to byte an end of data.
-  MDBX_CXX11_CONSTEXPR const byte *end_byte_ptr() const noexcept;
-  MDBX_CXX11_CONSTEXPR byte *end_byte_ptr() noexcept;
-
-  /// \brief Returns casted to pointer to char an address of data.
-  MDBX_CXX11_CONSTEXPR const char *char_ptr() const noexcept;
-  MDBX_CXX11_CONSTEXPR char *char_ptr() noexcept;
-
-  /// \brief Returns casted to pointer to char an end of data.
-  MDBX_CXX11_CONSTEXPR const char *end_char_ptr() const noexcept;
-  MDBX_CXX11_CONSTEXPR char *end_char_ptr() noexcept;
-
-  /// \brief Return a pointer to the beginning of the referenced data.
-  MDBX_CXX11_CONSTEXPR const void *data() const noexcept;
-  MDBX_CXX11_CONSTEXPR void *data() noexcept;
-
-  /// \brief Return a pointer to the ending of the referenced data.
-  MDBX_CXX11_CONSTEXPR const void *end() const noexcept;
-  MDBX_CXX11_CONSTEXPR void *end() noexcept;
-
-  /// \brief Returns the number of bytes.
-  MDBX_CXX11_CONSTEXPR size_t length() const noexcept;
-
-  /// \brief Set slice length.
-  MDBX_CXX14_CONSTEXPR slice &set_length(size_t bytes);
-
-  /// \brief Sets the length by specifying the end of the slice data.
-  MDBX_CXX14_CONSTEXPR slice &set_end(const void *ptr);
-
-  /// \brief Checks whether the slice is empty.
-  MDBX_CXX11_CONSTEXPR bool empty() const noexcept;
-
-  /// \brief Checks whether the slice data pointer is nullptr.
-  MDBX_CXX11_CONSTEXPR bool is_null() const noexcept;
-
-  /// \brief Returns the number of bytes.
-  MDBX_CXX11_CONSTEXPR size_t size() const noexcept;
-
-  /// \brief Returns true if slice is not empty.
-  MDBX_CXX11_CONSTEXPR operator bool() const noexcept;
-
-  /// \brief Depletes content of slice and make it invalid.
-  MDBX_CXX14_CONSTEXPR void invalidate() noexcept;
-
-  /// \brief Makes the slice empty and referencing to nothing.
-  MDBX_CXX14_CONSTEXPR void clear() noexcept;
-
-  /// \brief Drops the first "n" bytes from this slice.
-  /// \pre REQUIRES: `n <= size()`
-  inline void remove_prefix(size_t n) noexcept;
-
-  /// \brief Drops the last "n" bytes from this slice.
-  /// \pre REQUIRES: `n <= size()`
-  inline void remove_suffix(size_t n) noexcept;
-
-  /// \brief Drops the first "n" bytes from this slice.
-  /// \throws std::out_of_range if `n > size()`
-  inline void safe_remove_prefix(size_t n);
-
-  /// \brief Drops the last "n" bytes from this slice.
-  /// \throws std::out_of_range if `n > size()`
-  inline void safe_remove_suffix(size_t n);
-
-  /// \brief Checks if the data starts with the given prefix.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-  starts_with(const slice &prefix) const noexcept;
-
-  /// \brief Checks if the data ends with the given suffix.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-  ends_with(const slice &suffix) const noexcept;
-
-  /// \brief Returns the nth byte in the referenced data.
-  /// \pre REQUIRES: `n < size()`
-  MDBX_CXX11_CONSTEXPR byte operator[](size_t n) const noexcept;
-
-  /// \brief Returns the nth byte in the referenced data with bounds checking.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX11_CONSTEXPR byte at(size_t n) const;
-
-  /// \brief Returns the first "n" bytes of the slice.
-  /// \pre REQUIRES: `n <= size()`
-  MDBX_CXX14_CONSTEXPR slice head(size_t n) const noexcept;
-
-  /// \brief Returns the last "n" bytes of the slice.
-  /// \pre REQUIRES: `n <= size()`
-  MDBX_CXX14_CONSTEXPR slice tail(size_t n) const noexcept;
-
-  /// \brief Returns the middle "n" bytes of the slice.
-  /// \pre REQUIRES: `from + n <= size()`
-  MDBX_CXX14_CONSTEXPR slice middle(size_t from, size_t n) const noexcept;
-
-  /// \brief Returns the first "n" bytes of the slice.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX14_CONSTEXPR slice safe_head(size_t n) const;
-
-  /// \brief Returns the last "n" bytes of the slice.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX14_CONSTEXPR slice safe_tail(size_t n) const;
-
-  /// \brief Returns the middle "n" bytes of the slice.
-  /// \throws std::out_of_range if `from + n >= size()`
-  MDBX_CXX14_CONSTEXPR slice safe_middle(size_t from, size_t n) const;
-
-  /// \brief Returns the hash value of referenced data.
-  /// \attention Function implementation and returned hash values may changed
-  /// version to version, and in future the t1ha3 will be used here. Therefore
-  /// values obtained from this function shouldn't be persisted anywhere.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR size_t
-  hash_value() const noexcept;
-
-  /// \brief Three-way fast non-lexicographically length-based comparison.
-  /// \return value:
-  ///   == 0 if "a" == "b",
-  ///   <  0 if "a" shorter than "b",
-  ///   >  0 if "a" longer than "b",
-  ///   <  0 if "a" length-equal and lexicographically less than "b",
-  ///   >  0 if "a" length-equal and lexicographically great than "b".
-  MDBX_NOTHROW_PURE_FUNCTION static MDBX_CXX14_CONSTEXPR intptr_t
-  compare_fast(const slice &a, const slice &b) noexcept;
-
-  /// \brief Three-way lexicographically comparison.
-  /// \return value:
-  ///   <  0 if "a" <  "b",
-  ///   == 0 if "a" == "b",
-  ///   >  0 if "a" >  "b".
-  MDBX_NOTHROW_PURE_FUNCTION static MDBX_CXX14_CONSTEXPR intptr_t
-  compare_lexicographically(const slice &a, const slice &b) noexcept;
-  friend MDBX_CXX14_CONSTEXPR bool operator==(const slice &a,
-                                              const slice &b) noexcept;
-  friend MDBX_CXX14_CONSTEXPR bool operator<(const slice &a,
-                                             const slice &b) noexcept;
-  friend MDBX_CXX14_CONSTEXPR bool operator>(const slice &a,
-                                             const slice &b) noexcept;
-  friend MDBX_CXX14_CONSTEXPR bool operator<=(const slice &a,
-                                              const slice &b) noexcept;
-  friend MDBX_CXX14_CONSTEXPR bool operator>=(const slice &a,
-                                              const slice &b) noexcept;
-  friend MDBX_CXX14_CONSTEXPR bool operator!=(const slice &a,
-                                              const slice &b) noexcept;
-
-  /// \brief Checks the slice is not refers to null address or has zero length.
-  MDBX_CXX11_CONSTEXPR bool is_valid() const noexcept {
-    return !(iov_base == nullptr && iov_len != 0);
-  }
-
-  /// \brief Build an invalid slice which non-zero length and refers to null
-  /// address.
-  MDBX_CXX14_CONSTEXPR static slice invalid() noexcept {
-    return slice(size_t(-1));
-  }
-
-protected:
-  MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept
-      : ::MDBX_val({nullptr, invalid_length}) {}
-};
-
-//------------------------------------------------------------------------------
-
-namespace allocation_aware_details {
-
-template <typename A> constexpr bool allocator_is_always_equal() noexcept {
-#if defined(__cpp_lib_allocator_traits_is_always_equal) &&                     \
-    __cpp_lib_allocator_traits_is_always_equal >= 201411L
-  return ::std::allocator_traits<A>::is_always_equal::value;
-#else
-  return ::std::is_empty<A>::value;
-#endif /* __cpp_lib_allocator_traits_is_always_equal */
-}
-
-template <typename T, typename A = typename T::allocator_type,
-          bool PoCMA = ::std::allocator_traits<
-              A>::propagate_on_container_move_assignment::value>
-struct move_assign_alloc;
-
-template <typename T, typename A> struct move_assign_alloc<T, A, false> {
-  static constexpr bool is_nothrow() noexcept {
-    return allocator_is_always_equal<A>();
-  }
-  static MDBX_CXX20_CONSTEXPR bool is_moveable(T *target, T &source) noexcept {
-    return allocator_is_always_equal<A>() ||
-           target->get_allocator() == source.get_allocator();
-  }
-  static MDBX_CXX20_CONSTEXPR void propagate(T *target, T &source) noexcept {
-    assert(target->get_allocator() != source.get_allocator());
-    (void)target;
-    (void)source;
-  }
-};
-
-template <typename T, typename A> struct move_assign_alloc<T, A, true> {
-  static constexpr bool is_nothrow() noexcept {
-    return allocator_is_always_equal<A>() ||
-           ::std::is_nothrow_move_assignable<A>::value;
-  }
-  static constexpr bool is_moveable(T *, T &) noexcept { return true; }
-  static MDBX_CXX20_CONSTEXPR void propagate(T *target, T &source) {
-    assert(target->get_allocator() != source.get_allocator());
-    target->get_allocator() = ::std::move(source.get_allocator());
-  }
-};
-
-template <typename T, typename A = typename T::allocator_type,
-          bool PoCCA = ::std::allocator_traits<
-              A>::propagate_on_container_copy_assignment::value>
-struct copy_assign_alloc;
-
-template <typename T, typename A> struct copy_assign_alloc<T, A, false> {
-  static constexpr bool is_nothrow() noexcept { return false; }
-  static MDBX_CXX20_CONSTEXPR void propagate(T *target,
-                                             const T &source) noexcept {
-    assert(target->get_allocator() != source.get_allocator());
-    (void)target;
-    (void)source;
-  }
-};
-
-template <typename T, typename A> struct copy_assign_alloc<T, A, true> {
-  static constexpr bool is_nothrow() noexcept {
-    return allocator_is_always_equal<A>() ||
-           ::std::is_nothrow_copy_assignable<A>::value;
-  }
-  static MDBX_CXX20_CONSTEXPR void
-  propagate(T *target, const T &source) noexcept(is_nothrow()) {
-    if MDBX_IF_CONSTEXPR (!allocator_is_always_equal<A>()) {
-      if (MDBX_UNLIKELY(target->get_allocator() != source.get_allocator()))
-        MDBX_CXX20_UNLIKELY target->get_allocator() =
-            ::std::allocator_traits<A>::select_on_container_copy_construction(
-                source.get_allocator());
-    } else {
-      /* gag for buggy compilers */
-      (void)target;
-      (void)source;
-    }
-  }
-};
-
-template <typename T, typename A = typename T::allocator_type,
-          bool PoCS =
-              ::std::allocator_traits<A>::propagate_on_container_swap::value>
-struct swap_alloc;
-
-template <typename T, typename A> struct swap_alloc<T, A, false> {
-  static constexpr bool is_nothrow() noexcept {
-    return allocator_is_always_equal<A>();
-  }
-  static MDBX_CXX20_CONSTEXPR void propagate(T *target,
-                                             T &source) noexcept(is_nothrow()) {
-    if MDBX_IF_CONSTEXPR (!allocator_is_always_equal<A>()) {
-      if (MDBX_UNLIKELY(target->get_allocator() != source.get_allocator()))
-        MDBX_CXX20_UNLIKELY throw_allocators_mismatch();
-    } else {
-      /* gag for buggy compilers */
-      (void)target;
-      (void)source;
-    }
-  }
-};
-
-template <typename T, typename A> struct swap_alloc<T, A, true> {
-  static constexpr bool is_nothrow() noexcept {
-    return allocator_is_always_equal<A>() ||
-#if defined(__cpp_lib_is_swappable) && __cpp_lib_is_swappable >= 201603L
-           ::std::is_nothrow_swappable<A>() ||
-#endif /* __cpp_lib_is_swappable >= 201603L */
-           (::std::is_nothrow_move_constructible<A>::value &&
-            ::std::is_nothrow_move_assignable<A>::value);
-  }
-  static MDBX_CXX20_CONSTEXPR void propagate(T *target,
-                                             T &source) noexcept(is_nothrow()) {
-    if MDBX_IF_CONSTEXPR (!allocator_is_always_equal<A>()) {
-      if (MDBX_UNLIKELY(target->get_allocator() != source.get_allocator()))
-        MDBX_CXX20_UNLIKELY ::std::swap(*target, source);
-    } else {
-      /* gag for buggy compilers */
-      (void)target;
-      (void)source;
-    }
-  }
-};
-
-} // namespace allocation_aware_details
-
-struct default_capacity_policy {
-  enum : size_t {
-    extra_inplace_storage = 0,
-    pettiness_threshold = 64,
-    max_reserve = 65536
-  };
-
-  static MDBX_CXX11_CONSTEXPR size_t round(const size_t value) {
-    static_assert((pettiness_threshold & (pettiness_threshold - 1)) == 0,
-                  "pettiness_threshold must be a power of 2");
-    static_assert(pettiness_threshold % 2 == 0,
-                  "pettiness_threshold must be even");
-    static_assert(pettiness_threshold >= sizeof(uint64_t),
-                  "pettiness_threshold must be > 7");
-    constexpr const auto pettiness_mask = ~size_t(pettiness_threshold - 1);
-    return (value + pettiness_threshold - 1) & pettiness_mask;
-  }
-
-  static MDBX_CXX11_CONSTEXPR size_t advise(const size_t current,
-                                            const size_t wanna) {
-    static_assert(max_reserve % pettiness_threshold == 0,
-                  "max_reserve must be a multiple of pettiness_threshold");
-    static_assert(max_reserve / 3 > pettiness_threshold,
-                  "max_reserve must be > pettiness_threshold * 3");
-    if (wanna > current)
-      /* doubling capacity, but don't made reserve more than max_reserve */
-      return round(wanna + ::std::min(size_t(max_reserve), current));
-
-    if (current - wanna >
-        /* shrink if reserve will more than half of current or max_reserve,
-         * but not less than pettiness_threshold */
-        ::std::min(wanna + pettiness_threshold, size_t(max_reserve)))
-      return round(wanna);
-
-    /* keep unchanged */
-    return current;
-  }
-};
-
-/// \brief Hexadecimal encoder which satisfy \ref SliceTranscoder concept.
-struct LIBMDBX_API to_hex {
-  const slice source;
-  const bool uppercase = false;
-  const unsigned wrap_width = 0;
-  MDBX_CXX11_CONSTEXPR to_hex(const slice &source, bool uppercase = false,
-                              unsigned wrap_width = 0) noexcept
-      : source(source), uppercase(uppercase), wrap_width(wrap_width) {
-    MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, to_hex);
-  }
-
-  /// \brief Returns a string with a hexadecimal dump of a passed slice.
-  template <class ALLOCATOR = legacy_allocator>
-  string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_string<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns a buffer with a hexadecimal dump of a passed slice.
-  template <class ALLOCATOR = legacy_allocator,
-            typename CAPACITY_POLICY = default_capacity_policy>
-  buffer<ALLOCATOR, CAPACITY_POLICY>
-  as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_buffer<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns the buffer size in bytes needed for hexadecimal
-  /// dump of a passed slice.
-  MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
-    const size_t bytes = source.length() << 1;
-    return wrap_width ? bytes + bytes / wrap_width : bytes;
-  }
-
-  /// \brief Fills the buffer by hexadecimal dump of a passed slice.
-  /// \throws std::length_error if given buffer is too small.
-  char *write_bytes(char *dest, size_t dest_size) const;
-
-  /// \brief Output hexadecimal dump of passed slice to the std::ostream.
-  /// \throws std::ios_base::failure corresponding to std::ostream::write()
-  /// behaviour.
-  ::std::ostream &output(::std::ostream &out) const;
-
-  /// \brief Checks whether a passed slice is empty,
-  /// and therefore there will be no output bytes.
-  bool is_empty() const noexcept { return source.empty(); }
-
-  /// \brief Checks whether the content of a passed slice is a valid data
-  /// and could be encoded or unexpectedly not.
-  bool is_erroneous() const noexcept { return false; }
-};
-
-/// \brief [Base58](https://en.wikipedia.org/wiki/Base58) encoder which satisfy
-/// \ref SliceTranscoder concept.
-struct LIBMDBX_API to_base58 {
-  const slice source;
-  const unsigned wrap_width = 0;
-  MDBX_CXX11_CONSTEXPR
-  to_base58(const slice &source, unsigned wrap_width = 0) noexcept
-      : source(source), wrap_width(wrap_width) {
-    MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, to_base58);
-  }
-
-  /// \brief Returns a string with a
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump of a passed slice.
-  template <class ALLOCATOR = legacy_allocator>
-  string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_string<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns a buffer with a
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump of a passed slice.
-  template <class ALLOCATOR = legacy_allocator,
-            typename CAPACITY_POLICY = default_capacity_policy>
-  buffer<ALLOCATOR, CAPACITY_POLICY>
-  as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_buffer<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns the buffer size in bytes needed for
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice.
-  MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
-    const size_t bytes =
-        source.length() / 8 * 11 + (source.length() % 8 * 43 + 31) / 32;
-    return wrap_width ? bytes + bytes / wrap_width : bytes;
-  }
-
-  /// \brief Fills the buffer by [Base58](https://en.wikipedia.org/wiki/Base58)
-  /// dump of passed slice.
-  /// \throws std::length_error if given buffer is too small.
-  char *write_bytes(char *dest, size_t dest_size) const;
-
-  /// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58)
-  /// dump of passed slice to the std::ostream.
-  /// \throws std::ios_base::failure corresponding to std::ostream::write()
-  /// behaviour.
-  ::std::ostream &output(::std::ostream &out) const;
-
-  /// \brief Checks whether a passed slice is empty,
-  /// and therefore there will be no output bytes.
-  bool is_empty() const noexcept { return source.empty(); }
-
-  /// \brief Checks whether the content of a passed slice is a valid data
-  /// and could be encoded or unexpectedly not.
-  bool is_erroneous() const noexcept { return false; }
-};
-
-/// \brief [Base64](https://en.wikipedia.org/wiki/Base64) encoder which satisfy
-/// \ref SliceTranscoder concept.
-struct LIBMDBX_API to_base64 {
-  const slice source;
-  const unsigned wrap_width = 0;
-  MDBX_CXX11_CONSTEXPR
-  to_base64(const slice &source, unsigned wrap_width = 0) noexcept
-      : source(source), wrap_width(wrap_width) {
-    MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, to_base64);
-  }
-
-  /// \brief Returns a string with a
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump of a passed slice.
-  template <class ALLOCATOR = legacy_allocator>
-  string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_string<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns a buffer with a
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump of a passed slice.
-  template <class ALLOCATOR = legacy_allocator,
-            typename CAPACITY_POLICY = default_capacity_policy>
-  buffer<ALLOCATOR, CAPACITY_POLICY>
-  as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_buffer<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns the buffer size in bytes needed for
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump of passed slice.
-  MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
-    const size_t bytes = (source.length() + 2) / 3 * 4;
-    return wrap_width ? bytes + bytes / wrap_width : bytes;
-  }
-
-  /// \brief Fills the buffer by [Base64](https://en.wikipedia.org/wiki/Base64)
-  /// dump of passed slice.
-  /// \throws std::length_error if given buffer is too small.
-  char *write_bytes(char *dest, size_t dest_size) const;
-
-  /// \brief Output [Base64](https://en.wikipedia.org/wiki/Base64)
-  /// dump of passed slice to the std::ostream.
-  /// \throws std::ios_base::failure corresponding to std::ostream::write()
-  /// behaviour.
-  ::std::ostream &output(::std::ostream &out) const;
-
-  /// \brief Checks whether a passed slice is empty,
-  /// and therefore there will be no output bytes.
-  bool is_empty() const noexcept { return source.empty(); }
-
-  /// \brief Checks whether the content of a passed slice is a valid data
-  /// and could be encoded or unexpectedly not.
-  bool is_erroneous() const noexcept { return false; }
-};
-
-inline ::std::ostream &operator<<(::std::ostream &out, const to_hex &wrapper) {
-  return wrapper.output(out);
-}
-inline ::std::ostream &operator<<(::std::ostream &out,
-                                  const to_base58 &wrapper) {
-  return wrapper.output(out);
-}
-inline ::std::ostream &operator<<(::std::ostream &out,
-                                  const to_base64 &wrapper) {
-  return wrapper.output(out);
-}
-
-/// \brief Hexadecimal decoder which satisfy \ref SliceTranscoder concept.
-struct LIBMDBX_API from_hex {
-  const slice source;
-  const bool ignore_spaces = false;
-  MDBX_CXX11_CONSTEXPR from_hex(const slice &source,
-                                bool ignore_spaces = false) noexcept
-      : source(source), ignore_spaces(ignore_spaces) {
-    MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, from_hex);
-  }
-
-  /// \brief Decodes hexadecimal dump from a passed slice to returned string.
-  template <class ALLOCATOR = legacy_allocator>
-  string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_string<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Decodes hexadecimal dump from a passed slice to returned buffer.
-  template <class ALLOCATOR = legacy_allocator,
-            typename CAPACITY_POLICY = default_capacity_policy>
-  buffer<ALLOCATOR, CAPACITY_POLICY>
-  as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_buffer<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns the number of bytes needed for conversion
-  /// hexadecimal dump from a passed slice to decoded data.
-  MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
-    return source.length() >> 1;
-  }
-
-  /// \brief Fills the destination with data decoded from hexadecimal dump
-  /// from a passed slice.
-  /// \throws std::length_error if given buffer is too small.
-  char *write_bytes(char *dest, size_t dest_size) const;
-
-  /// \brief Checks whether a passed slice is empty,
-  /// and therefore there will be no output bytes.
-  bool is_empty() const noexcept { return source.empty(); }
-
-  /// \brief Checks whether the content of a passed slice is a valid hexadecimal
-  /// dump, and therefore there could be decoded or not.
-  bool is_erroneous() const noexcept;
-};
-
-/// \brief [Base58](https://en.wikipedia.org/wiki/Base58) decoder which satisfy
-/// \ref SliceTranscoder concept.
-struct LIBMDBX_API from_base58 {
-  const slice source;
-  const bool ignore_spaces = false;
-  MDBX_CXX11_CONSTEXPR from_base58(const slice &source,
-                                   bool ignore_spaces = false) noexcept
-      : source(source), ignore_spaces(ignore_spaces) {
-    MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, from_base58);
-  }
-
-  /// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump from a
-  /// passed slice to returned string.
-  template <class ALLOCATOR = legacy_allocator>
-  string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_string<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump from a
-  /// passed slice to returned buffer.
-  template <class ALLOCATOR = legacy_allocator,
-            typename CAPACITY_POLICY = default_capacity_policy>
-  buffer<ALLOCATOR, CAPACITY_POLICY>
-  as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_buffer<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns the number of bytes needed for conversion
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to
-  /// decoded data.
-  MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
-    return source.length() / 11 * 8 + source.length() % 11 * 32 / 43;
-  }
-
-  /// \brief Fills the destination with data decoded from
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice.
-  /// \throws std::length_error if given buffer is too small.
-  char *write_bytes(char *dest, size_t dest_size) const;
-
-  /// \brief Checks whether a passed slice is empty,
-  /// and therefore there will be no output bytes.
-  bool is_empty() const noexcept { return source.empty(); }
-
-  /// \brief Checks whether the content of a passed slice is a valid
-  /// [Base58](https://en.wikipedia.org/wiki/Base58) dump, and therefore there
-  /// could be decoded or not.
-  bool is_erroneous() const noexcept;
-};
-
-/// \brief [Base64](https://en.wikipedia.org/wiki/Base64) decoder which satisfy
-/// \ref SliceTranscoder concept.
-struct LIBMDBX_API from_base64 {
-  const slice source;
-  const bool ignore_spaces = false;
-  MDBX_CXX11_CONSTEXPR from_base64(const slice &source,
-                                   bool ignore_spaces = false) noexcept
-      : source(source), ignore_spaces(ignore_spaces) {
-    MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, from_base64);
-  }
-
-  /// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump from a
-  /// passed slice to returned string.
-  template <class ALLOCATOR = legacy_allocator>
-  string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_string<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump from a
-  /// passed slice to returned buffer.
-  template <class ALLOCATOR = legacy_allocator,
-            typename CAPACITY_POLICY = default_capacity_policy>
-  buffer<ALLOCATOR, CAPACITY_POLICY>
-  as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const {
-    return make_buffer<ALLOCATOR>(*this, allocator);
-  }
-
-  /// \brief Returns the number of bytes needed for conversion
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump from a passed slice to
-  /// decoded data.
-  MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
-    return (source.length() + 3) / 4 * 3;
-  }
-
-  /// \brief Fills the destination with data decoded from
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump from a passed slice.
-  /// \throws std::length_error if given buffer is too small.
-  char *write_bytes(char *dest, size_t dest_size) const;
-
-  /// \brief Checks whether a passed slice is empty,
-  /// and therefore there will be no output bytes.
-  bool is_empty() const noexcept { return source.empty(); }
-
-  /// \brief Checks whether the content of a passed slice is a valid
-  /// [Base64](https://en.wikipedia.org/wiki/Base64) dump, and therefore there
-  /// could be decoded or not.
-  bool is_erroneous() const noexcept;
-};
-
-/// \brief The chunk of data stored inside the buffer or located outside it.
-template <class ALLOCATOR, typename CAPACITY_POLICY> class buffer {
-public:
-#if !defined(_MSC_VER) || _MSC_VER > 1900
-  using allocator_type = typename ::std::allocator_traits<
-      ALLOCATOR>::template rebind_alloc<uint64_t>;
-#else
-  using allocator_type = typename ALLOCATOR::template rebind<uint64_t>::other;
-#endif /* MSVC is mad */
-  using allocator_traits = ::std::allocator_traits<allocator_type>;
-  using reservation_policy = CAPACITY_POLICY;
-  enum : size_t {
-    max_length = MDBX_MAXDATASIZE,
-    max_capacity = (max_length / 3u * 4u + 1023u) & ~size_t(1023),
-    extra_inplace_storage = reservation_policy::extra_inplace_storage,
-    pettiness_threshold = reservation_policy::pettiness_threshold
-  };
-
-private:
-  friend class txn;
-  struct silo;
-  using move_assign_alloc =
-      allocation_aware_details::move_assign_alloc<silo, allocator_type>;
-  using copy_assign_alloc =
-      allocation_aware_details::copy_assign_alloc<silo, allocator_type>;
-  using swap_alloc = allocation_aware_details::swap_alloc<silo, allocator_type>;
-  struct silo /* Empty Base Class Optimization */ : public allocator_type {
-    MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept {
-      return *this;
-    }
-    MDBX_CXX20_CONSTEXPR allocator_type &get_allocator() noexcept {
-      return *this;
-    }
-
-    using allocator_pointer = typename allocator_traits::pointer;
-    using allocator_const_pointer = typename allocator_traits::const_pointer;
-
-    MDBX_CXX20_CONSTEXPR ::std::pair<allocator_pointer, size_t>
-    allocate_storage(size_t bytes) {
-      assert(bytes >= sizeof(bin));
-      constexpr size_t unit = sizeof(typename allocator_type::value_type);
-      static_assert((unit & (unit - 1)) == 0,
-                    "size of ALLOCATOR::value_type should be a power of 2");
-      static_assert(unit > 0, "size of ALLOCATOR::value_type must be > 0");
-      const size_t n = (bytes + unit - 1) / unit;
-      return ::std::make_pair(allocator_traits::allocate(get_allocator(), n),
-                              n * unit);
-    }
-    MDBX_CXX20_CONSTEXPR void deallocate_storage(allocator_pointer ptr,
-                                                 size_t bytes) {
-      constexpr size_t unit = sizeof(typename allocator_type::value_type);
-      assert(ptr && bytes >= sizeof(bin) && bytes >= unit && bytes % unit == 0);
-      allocator_traits::deallocate(get_allocator(), ptr, bytes / unit);
-    }
-
-    static MDBX_CXX17_CONSTEXPR void *
-    to_address(allocator_pointer ptr) noexcept {
-#if defined(__cpp_lib_to_address) && __cpp_lib_to_address >= 201711L
-      return static_cast<void *>(::std::to_address(ptr));
-#else
-      return static_cast<void *>(::std::addressof(*ptr));
-#endif /* __cpp_lib_to_address */
-    }
-    static MDBX_CXX17_CONSTEXPR const void *
-    to_address(allocator_const_pointer ptr) noexcept {
-#if defined(__cpp_lib_to_address) && __cpp_lib_to_address >= 201711L
-      return static_cast<const void *>(::std::to_address(ptr));
-#else
-      return static_cast<const void *>(::std::addressof(*ptr));
-#endif /* __cpp_lib_to_address */
-    }
-
-    union bin {
-      struct allocated {
-        allocator_pointer ptr_;
-        size_t capacity_bytes_;
-        constexpr allocated(allocator_pointer ptr, size_t bytes) noexcept
-            : ptr_(ptr), capacity_bytes_(bytes) {}
-        constexpr allocated(const allocated &) noexcept = default;
-        constexpr allocated(allocated &&) noexcept = default;
-        MDBX_CXX17_CONSTEXPR allocated &
-        operator=(const allocated &) noexcept = default;
-        MDBX_CXX17_CONSTEXPR allocated &
-        operator=(allocated &&) noexcept = default;
-      };
-
-      allocated allocated_;
-      uint64_t align_hint_;
-      byte inplace_[(sizeof(allocated) + extra_inplace_storage + 7u) &
-                    ~size_t(7)];
-
-      static constexpr bool
-      is_suitable_for_inplace(size_t capacity_bytes) noexcept {
-        static_assert(sizeof(bin) == sizeof(inplace_), "WTF?");
-        return capacity_bytes < sizeof(bin);
-      }
-
-      enum : byte {
-        /* Little Endian:
-         *   last byte is the most significant byte of u_.allocated.cap,
-         *   so use higher bit of capacity as the inplace-flag */
-        le_lastbyte_mask = 0x80,
-        /* Big Endian:
-         *   last byte is the least significant byte of u_.allocated.cap,
-         *   so use lower bit of capacity as the inplace-flag. */
-        be_lastbyte_mask = 0x01
-      };
-
-      static constexpr byte inplace_lastbyte_mask() noexcept {
-        static_assert(
-            endian::native == endian::little || endian::native == endian::big,
-            "Only the little-endian or big-endian bytes order are supported");
-        return (endian::native == endian::little) ? le_lastbyte_mask
-                                                  : be_lastbyte_mask;
-      }
-      constexpr byte lastbyte() const noexcept {
-        return inplace_[sizeof(bin) - 1];
-      }
-      MDBX_CXX17_CONSTEXPR byte &lastbyte() noexcept {
-        return inplace_[sizeof(bin) - 1];
-      }
-
-      constexpr bool is_inplace() const noexcept {
-        return (lastbyte() & inplace_lastbyte_mask()) != 0;
-      }
-      constexpr bool is_allocated() const noexcept { return !is_inplace(); }
-
-      template <bool destroy_ptr>
-      MDBX_CXX17_CONSTEXPR byte *make_inplace() noexcept {
-        if (destroy_ptr) {
-          MDBX_CONSTEXPR_ASSERT(is_allocated());
-          /* properly destroy allocator::pointer */
-          allocated_.~allocated();
-        }
-        if (::std::is_trivial<allocator_pointer>::value)
-          /* workaround for "uninitialized" warning from some compilers */
-          ::std::memset(&allocated_.ptr_, 0, sizeof(allocated_.ptr_));
-        lastbyte() = inplace_lastbyte_mask();
-        MDBX_CONSTEXPR_ASSERT(is_inplace() && address() == inplace_ &&
-                              is_suitable_for_inplace(capacity()));
-        return address();
-      }
-
-      template <bool construct_ptr>
-      MDBX_CXX17_CONSTEXPR byte *
-      make_allocated(allocator_pointer ptr, size_t capacity_bytes) noexcept {
-        MDBX_CONSTEXPR_ASSERT(
-            (capacity_bytes & be_lastbyte_mask) == 0 &&
-            ((capacity_bytes >>
-              (sizeof(allocated_.capacity_bytes_) - 1) * CHAR_BIT) &
-             le_lastbyte_mask) == 0);
-        if (construct_ptr)
-          /* properly construct allocator::pointer */
-          new (&allocated_) allocated(ptr, capacity_bytes);
-        else {
-          MDBX_CONSTEXPR_ASSERT(is_allocated());
-          allocated_.ptr_ = ptr;
-          allocated_.capacity_bytes_ = capacity_bytes;
-        }
-        MDBX_CONSTEXPR_ASSERT(is_allocated() && address() == to_address(ptr) &&
-                              capacity() == capacity_bytes);
-        return address();
-      }
-
-      MDBX_CXX20_CONSTEXPR bin(size_t capacity_bytes = 0) noexcept {
-        MDBX_CONSTEXPR_ASSERT(is_suitable_for_inplace(capacity_bytes));
-        make_inplace<false>();
-        (void)capacity_bytes;
-      }
-      MDBX_CXX20_CONSTEXPR bin(allocator_pointer ptr,
-                               size_t capacity_bytes) noexcept {
-        MDBX_CONSTEXPR_ASSERT(!is_suitable_for_inplace(capacity_bytes));
-        make_allocated<true>(ptr, capacity_bytes);
-      }
-      MDBX_CXX20_CONSTEXPR ~bin() {
-        if (is_allocated())
-          /* properly destroy allocator::pointer */
-          allocated_.~allocated();
-      }
-      MDBX_CXX20_CONSTEXPR bin(bin &&ditto) noexcept {
-        if (ditto.is_inplace()) {
-          // micro-optimization: don't use make_inplace<> here
-          //                     since memcpy() will copy the flag.
-          memcpy(inplace_, ditto.inplace_, sizeof(inplace_));
-          MDBX_CONSTEXPR_ASSERT(is_inplace());
-        } else {
-          new (&allocated_) allocated(::std::move(ditto.allocated_));
-          ditto.make_inplace<true>();
-          MDBX_CONSTEXPR_ASSERT(is_allocated());
-        }
-      }
-
-      MDBX_CXX17_CONSTEXPR bin &operator=(const bin &ditto) noexcept {
-        if (ditto.is_inplace()) {
-          // micro-optimization: don't use make_inplace<> here
-          //                     since memcpy() will copy the flag.
-          if (is_allocated())
-            /* properly destroy allocator::pointer */
-            allocated_.~allocated();
-          memcpy(inplace_, ditto.inplace_, sizeof(inplace_));
-          MDBX_CONSTEXPR_ASSERT(is_inplace());
-        } else if (is_inplace())
-          make_allocated<true>(ditto.allocated_.ptr_,
-                               ditto.allocated_.capacity_bytes_);
-        else
-          make_allocated<false>(ditto.allocated_.ptr_,
-                                ditto.allocated_.capacity_bytes_);
-        return *this;
-      }
-
-      MDBX_CXX17_CONSTEXPR bin &operator=(bin &&ditto) noexcept {
-        operator=(const_cast<const bin &>(ditto));
-        if (ditto.is_allocated())
-          ditto.make_inplace<true>();
-        return *this;
-      }
-
-      static MDBX_CXX20_CONSTEXPR size_t advise_capacity(const size_t current,
-                                                         const size_t wanna) {
-        if (MDBX_UNLIKELY(wanna > max_capacity))
-          MDBX_CXX20_UNLIKELY throw_max_length_exceeded();
-
-        const size_t advised = reservation_policy::advise(current, wanna);
-        assert(advised >= wanna);
-        return ::std::min(size_t(max_capacity),
-                          ::std::max(sizeof(bin) - 1, advised));
-      }
-
-      constexpr const byte *address() const noexcept {
-        return is_inplace()
-                   ? inplace_
-                   : static_cast<const byte *>(to_address(allocated_.ptr_));
-      }
-      MDBX_CXX17_CONSTEXPR byte *address() noexcept {
-        return is_inplace() ? inplace_
-                            : static_cast<byte *>(to_address(allocated_.ptr_));
-      }
-      constexpr size_t capacity() const noexcept {
-        return is_inplace() ? sizeof(bin) - 1 : allocated_.capacity_bytes_;
-      }
-    } bin_;
-
-    MDBX_CXX20_CONSTEXPR void *init(size_t capacity) {
-      capacity = bin::advise_capacity(0, capacity);
-      if (bin_.is_suitable_for_inplace(capacity))
-        new (&bin_) bin();
-      else {
-        const auto pair = allocate_storage(capacity);
-        assert(pair.second >= capacity);
-        new (&bin_) bin(pair.first, pair.second);
-      }
-      return bin_.address();
-    }
-
-    MDBX_CXX20_CONSTEXPR void release() noexcept {
-      if (bin_.is_allocated()) {
-        deallocate_storage(bin_.allocated_.ptr_,
-                           bin_.allocated_.capacity_bytes_);
-        bin_.template make_inplace<true>();
-      }
-    }
-
-    template <bool external_content>
-    MDBX_CXX20_CONSTEXPR void *
-    reshape(const size_t wanna_capacity, const size_t wanna_headroom,
-            const void *const content, const size_t length) {
-      assert(wanna_capacity >= wanna_headroom + length);
-      const size_t old_capacity = bin_.capacity();
-      const size_t new_capacity =
-          bin::advise_capacity(old_capacity, wanna_capacity);
-      assert(new_capacity >= wanna_capacity);
-      if (MDBX_LIKELY(new_capacity == old_capacity))
-        MDBX_CXX20_LIKELY {
-          assert(bin_.is_inplace() ==
-                 bin::is_suitable_for_inplace(new_capacity));
-          byte *const new_place = bin_.address() + wanna_headroom;
-          if (MDBX_LIKELY(length))
-            MDBX_CXX20_LIKELY {
-              if (external_content)
-                memcpy(new_place, content, length);
-              else {
-                const size_t old_headroom =
-                    bin_.address() - static_cast<const byte *>(content);
-                assert(old_capacity >= old_headroom + length);
-                if (MDBX_UNLIKELY(old_headroom != wanna_headroom))
-                  MDBX_CXX20_UNLIKELY ::std::memmove(new_place, content,
-                                                     length);
-              }
-            }
-          return new_place;
-        }
-
-      if (bin::is_suitable_for_inplace(new_capacity)) {
-        assert(bin_.is_allocated());
-        const auto old_allocated = ::std::move(bin_.allocated_.ptr_);
-        byte *const new_place =
-            bin_.template make_inplace<true>() + wanna_headroom;
-        if (MDBX_LIKELY(length))
-          MDBX_CXX20_LIKELY memcpy(new_place, content, length);
-        deallocate_storage(old_allocated, old_capacity);
-        return new_place;
-      }
-
-      if (!bin_.is_allocated()) {
-        const auto pair = allocate_storage(new_capacity);
-        assert(pair.second >= new_capacity);
-        byte *const new_place =
-            static_cast<byte *>(to_address(pair.first)) + wanna_headroom;
-        if (MDBX_LIKELY(length))
-          MDBX_CXX20_LIKELY memcpy(new_place, content, length);
-        bin_.template make_allocated<true>(pair.first, pair.second);
-        return new_place;
-      }
-
-      const auto old_allocated = ::std::move(bin_.allocated_.ptr_);
-      if (external_content)
-        deallocate_storage(old_allocated, old_capacity);
-      const auto pair = allocate_storage(new_capacity);
-      assert(pair.second >= new_capacity);
-      byte *const new_place =
-          bin_.template make_allocated<false>(pair.first, pair.second) +
-          wanna_headroom;
-      if (MDBX_LIKELY(length))
-        MDBX_CXX20_LIKELY memcpy(new_place, content, length);
-      if (!external_content)
-        deallocate_storage(old_allocated, old_capacity);
-      return new_place;
-    }
-
-    MDBX_CXX20_CONSTEXPR const byte *get(size_t offset = 0) const noexcept {
-      assert(capacity() >= offset);
-      return bin_.address() + offset;
-    }
-    MDBX_CXX20_CONSTEXPR byte *get(size_t offset = 0) noexcept {
-      assert(capacity() >= offset);
-      return bin_.address() + offset;
-    }
-    MDBX_CXX20_CONSTEXPR byte *put(size_t offset, const void *ptr,
-                                   size_t length) {
-      assert(capacity() >= offset + length);
-      return static_cast<byte *>(memcpy(get(offset), ptr, length));
-    }
-
-    //--------------------------------------------------------------------------
-
-    MDBX_CXX20_CONSTEXPR
-    silo() noexcept : allocator_type() { init(0); }
-    MDBX_CXX20_CONSTEXPR
-    silo(const allocator_type &alloc) noexcept : allocator_type(alloc) {
-      init(0);
-    }
-    MDBX_CXX20_CONSTEXPR silo(size_t capacity) { init(capacity); }
-    MDBX_CXX20_CONSTEXPR silo(size_t capacity, const allocator_type &alloc)
-        : silo(alloc) {
-      init(capacity);
-    }
-
-    MDBX_CXX20_CONSTEXPR silo(silo &&ditto) noexcept(
-        ::std::is_nothrow_move_constructible<allocator_type>::value)
-        : allocator_type(::std::move(ditto.get_allocator())),
-          bin_(::std::move(ditto.bin_)) {}
-
-    MDBX_CXX20_CONSTEXPR silo(size_t capacity, size_t headroom, const void *ptr,
-                              size_t length)
-        : silo(capacity) {
-      assert(capacity >= headroom + length);
-      if (length)
-        put(headroom, ptr, length);
-    }
-
-    // select_on_container_copy_construction()
-    MDBX_CXX20_CONSTEXPR silo(size_t capacity, size_t headroom, const void *ptr,
-                              size_t length, const allocator_type &alloc)
-        : silo(capacity, alloc) {
-      assert(capacity >= headroom + length);
-      if (length)
-        put(headroom, ptr, length);
-    }
-
-    MDBX_CXX20_CONSTEXPR silo(const void *ptr, size_t length)
-        : silo(length, 0, ptr, length) {}
-    MDBX_CXX20_CONSTEXPR silo(const void *ptr, size_t length,
-                              const allocator_type &alloc)
-        : silo(length, 0, ptr, length, alloc) {}
-
-    ~silo() { release(); }
-
-    //--------------------------------------------------------------------------
-
-    MDBX_CXX20_CONSTEXPR void *assign(size_t headroom, const void *ptr,
-                                      size_t length, size_t tailroom) {
-      return reshape<true>(headroom + length + tailroom, headroom, ptr, length);
-    }
-    MDBX_CXX20_CONSTEXPR void *assign(const void *ptr, size_t length) {
-      return assign(0, ptr, length, 0);
-    }
-
-    MDBX_CXX20_CONSTEXPR silo &assign(const silo &ditto, size_t headroom,
-                                      slice &content) {
-      assert(ditto.get() + headroom == content.byte_ptr());
-      if MDBX_IF_CONSTEXPR (!allocation_aware_details::
-                                allocator_is_always_equal<allocator_type>()) {
-        if (MDBX_UNLIKELY(get_allocator() != ditto.get_allocator()))
-          MDBX_CXX20_UNLIKELY {
-            release();
-            allocation_aware_details::copy_assign_alloc<
-                silo, allocator_type>::propagate(this, ditto);
-          }
-      }
-      content.iov_base = reshape<true>(ditto.capacity(), headroom,
-                                       content.data(), content.length());
-      return *this;
-    }
-
-    MDBX_CXX20_CONSTEXPR silo &
-    assign(silo &&ditto, size_t headroom, slice &content) noexcept(
-        allocation_aware_details::move_assign_alloc<
-            silo, allocator_type>::is_nothrow()) {
-      assert(ditto.get() + headroom == content.byte_ptr());
-      if (allocation_aware_details::move_assign_alloc<
-              silo, allocator_type>::is_moveable(this, ditto)) {
-        release();
-        allocation_aware_details::move_assign_alloc<
-            silo, allocator_type>::propagate(this, ditto);
-        /* no reallocation nor copying required */
-        bin_ = ::std::move(ditto.bin_);
-        assert(get() + headroom == content.byte_ptr());
-      } else {
-        /* copy content since allocators are different */
-        content.iov_base = reshape<true>(ditto.capacity(), headroom,
-                                         content.data(), content.length());
-        ditto.release();
-      }
-      return *this;
-    }
-
-    MDBX_CXX20_CONSTEXPR void clear() { reshape<true>(0, 0, nullptr, 0); }
-    MDBX_CXX20_CONSTEXPR void resize(size_t capacity, size_t headroom,
-                                     slice &content) {
-      content.iov_base =
-          reshape<false>(capacity, headroom, content.iov_base, content.iov_len);
-    }
-    MDBX_CXX20_CONSTEXPR void swap(silo &ditto) noexcept(
-        allocation_aware_details::swap_alloc<silo,
-                                             allocator_type>::is_nothrow()) {
-      allocation_aware_details::swap_alloc<silo, allocator_type>::propagate(
-          this, ditto);
-      ::std::swap(bin_, ditto.bin_);
-    }
-
-    /* MDBX_CXX20_CONSTEXPR void shrink_to_fit() { TODO } */
-
-    MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX11_CONSTEXPR size_t
-    capacity() const noexcept {
-      return bin_.capacity();
-    }
-    MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX11_CONSTEXPR const void *
-    data(size_t offset = 0) const noexcept {
-      return get(offset);
-    }
-    MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX11_CONSTEXPR void *
-    data(size_t offset = 0) noexcept {
-      return get(offset);
-    }
-  };
-
-  silo silo_;
-  ::mdbx::slice slice_;
-
-  void insulate() {
-    assert(is_reference());
-    silo_.assign(slice_.char_ptr(), slice_.length());
-    slice_.iov_base = silo_.data();
-  }
-
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR const byte *
-  silo_begin() const noexcept {
-    return static_cast<const byte *>(silo_.data());
-  }
-
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR const byte *
-  silo_end() const noexcept {
-    return silo_begin() + silo_.capacity();
-  }
-
-  struct data_preserver : public exception_thunk {
-    buffer data;
-    data_preserver(allocator_type &allocator) : data(allocator) {}
-    static int callback(void *context, MDBX_val *target, const void *src,
-                        size_t bytes) noexcept {
-      auto self = static_cast<data_preserver *>(context);
-      assert(self->is_clean());
-      assert(&self->data.slice_ == target);
-      (void)target;
-      try {
-        self->data.assign(src, bytes, false);
-        return MDBX_RESULT_FALSE;
-      } catch (... /* capture any exception to rethrow it over C code */) {
-        self->capture();
-        return MDBX_RESULT_TRUE;
-      }
-    }
-    MDBX_CXX11_CONSTEXPR operator MDBX_preserve_func() const noexcept {
-      return callback;
-    }
-    MDBX_CXX11_CONSTEXPR operator const buffer &() const noexcept {
-      return data;
-    }
-    MDBX_CXX11_CONSTEXPR operator buffer &() noexcept { return data; }
-  };
-
-public:
-  /// \todo buffer& operator<<(buffer&, ...) for writing
-  /// \todo buffer& operator>>(buffer&, ...) for reading (delegated to slice)
-  /// \todo template<class X> key(X) for encoding keys while writing
-
-  /// \brief Returns the associated allocator.
-  MDBX_CXX20_CONSTEXPR allocator_type get_allocator() const {
-    return silo_.get_allocator();
-  }
-
-  /// \brief Checks whether data chunk stored inside the buffer, otherwise
-  /// buffer just refers to data located outside the buffer.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR bool
-  is_freestanding() const noexcept {
-    static_assert(size_t(-long(max_length)) > max_length, "WTF?");
-    return size_t(byte_ptr() - silo_begin()) < silo_.capacity();
-  }
-
-  /// \brief Checks whether the buffer just refers to data located outside
-  /// the buffer, rather than stores it.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR bool
-  is_reference() const noexcept {
-    return !is_freestanding();
-  }
-
-  /// \brief Returns the number of bytes that can be held in currently allocated
-  /// storage.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR size_t
-  capacity() const noexcept {
-    return is_freestanding() ? silo_.capacity() : 0;
-  }
-
-  /// \brief Returns the number of bytes that available in currently allocated
-  /// storage ahead the currently beginning of data.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR size_t
-  headroom() const noexcept {
-    return is_freestanding() ? slice_.byte_ptr() - silo_begin() : 0;
-  }
-
-  /// \brief Returns the number of bytes that available in currently allocated
-  /// storage after the currently data end.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR size_t
-  tailroom() const noexcept {
-    return is_freestanding() ? capacity() - headroom() - slice_.length() : 0;
-  }
-
-  /// \brief Returns casted to const pointer to byte an address of data.
-  MDBX_CXX11_CONSTEXPR const byte *byte_ptr() const noexcept {
-    return slice_.byte_ptr();
-  }
-
-  /// \brief Returns casted to const pointer to byte an end of data.
-  MDBX_CXX11_CONSTEXPR const byte *end_byte_ptr() const noexcept {
-    return slice_.end_byte_ptr();
-  }
-
-  /// \brief Returns casted to pointer to byte an address of data.
-  /// \pre REQUIRES: The buffer should store data chunk, but not referenced to
-  /// an external one.
-  MDBX_CXX11_CONSTEXPR byte *byte_ptr() noexcept {
-    MDBX_CONSTEXPR_ASSERT(is_freestanding());
-    return const_cast<byte *>(slice_.byte_ptr());
-  }
-
-  /// \brief Returns casted to pointer to byte an end of data.
-  /// \pre REQUIRES: The buffer should store data chunk, but not referenced to
-  /// an external one.
-  MDBX_CXX11_CONSTEXPR byte *end_byte_ptr() noexcept {
-    MDBX_CONSTEXPR_ASSERT(is_freestanding());
-    return const_cast<byte *>(slice_.end_byte_ptr());
-  }
-
-  /// \brief Returns casted to const pointer to char an address of data.
-  MDBX_CXX11_CONSTEXPR const char *char_ptr() const noexcept {
-    return slice_.char_ptr();
-  }
-
-  /// \brief Returns casted to const pointer to char an end of data.
-  MDBX_CXX11_CONSTEXPR const char *end_char_ptr() const noexcept {
-    return slice_.end_char_ptr();
-  }
-
-  /// \brief Returns casted to pointer to char an address of data.
-  /// \pre REQUIRES: The buffer should store data chunk, but not referenced to
-  /// an external one.
-  MDBX_CXX11_CONSTEXPR char *char_ptr() noexcept {
-    MDBX_CONSTEXPR_ASSERT(is_freestanding());
-    return const_cast<char *>(slice_.char_ptr());
-  }
-
-  /// \brief Returns casted to pointer to char an end of data.
-  /// \pre REQUIRES: The buffer should store data chunk, but not referenced to
-  /// an external one.
-  MDBX_CXX11_CONSTEXPR char *end_char_ptr() noexcept {
-    MDBX_CONSTEXPR_ASSERT(is_freestanding());
-    return const_cast<char *>(slice_.end_char_ptr());
-  }
-
-  /// \brief Return a const pointer to the beginning of the referenced data.
-  MDBX_CXX11_CONSTEXPR const void *data() const noexcept {
-    return slice_.data();
-  }
-
-  /// \brief Return a const pointer to the end of the referenced data.
-  MDBX_CXX11_CONSTEXPR const void *end() const noexcept { return slice_.end(); }
-
-  /// \brief Return a pointer to the beginning of the referenced data.
-  /// \pre REQUIRES: The buffer should store data chunk, but not referenced to
-  /// an external one.
-  MDBX_CXX11_CONSTEXPR void *data() noexcept {
-    MDBX_CONSTEXPR_ASSERT(is_freestanding());
-    return const_cast<void *>(slice_.data());
-  }
-
-  /// \brief Return a pointer to the end of the referenced data.
-  /// \pre REQUIRES: The buffer should store data chunk, but not referenced to
-  /// an external one.
-  MDBX_CXX11_CONSTEXPR void *end() noexcept {
-    MDBX_CONSTEXPR_ASSERT(is_freestanding());
-    return const_cast<void *>(slice_.end());
-  }
-
-  /// \brief Returns the number of bytes.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR size_t
-  length() const noexcept {
-    return MDBX_CONSTEXPR_ASSERT(is_reference() ||
-                                 slice_.length() + headroom() <=
-                                     silo_.capacity()),
-           slice_.length();
-  }
-
-  /// \brief Set length of data.
-  MDBX_CXX14_CONSTEXPR buffer &set_length(size_t bytes) {
-    MDBX_CONSTEXPR_ASSERT(is_reference() ||
-                          bytes + headroom() <= silo_.capacity());
-    slice_.set_length(bytes);
-    return *this;
-  }
-
-  /// \brief Sets the length by specifying the end of the data.
-  MDBX_CXX14_CONSTEXPR buffer &set_end(const void *ptr) {
-    MDBX_CONSTEXPR_ASSERT(static_cast<const char *>(ptr) >= char_ptr());
-    return set_length(static_cast<const char *>(ptr) - char_ptr());
-  }
-
-  /// \brief Makes buffer owning the data.
-  /// \details If buffer refers to an external data, then makes it the owner
-  /// of clone by allocating storage and copying the data.
-  void make_freestanding() {
-    if (is_reference())
-      insulate();
-  }
-
-  MDBX_CXX20_CONSTEXPR buffer() noexcept = default;
-  MDBX_CXX20_CONSTEXPR buffer(const allocator_type &allocator) noexcept
-      : silo_(allocator) {}
-
-  buffer(const struct slice &src, bool make_reference,
-         const allocator_type &allocator = allocator_type())
-      : silo_(allocator), slice_(src) {
-    if (!make_reference)
-      insulate();
-  }
-
-  buffer(const buffer &src, bool make_reference,
-         const allocator_type &allocator = allocator_type())
-      : buffer(src.slice_, make_reference, allocator) {}
-
-  buffer(const void *ptr, size_t bytes, bool make_reference,
-         const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(ptr, bytes), make_reference, allocator) {}
-
-  template <class CHAR, class T, class A>
-  buffer(const ::std::basic_string<CHAR, T, A> &) = delete;
-  template <class CHAR, class T, class A>
-  buffer(const ::std::basic_string<CHAR, T, A> &&) = delete;
-
-  buffer(const char *c_str, bool make_reference,
-         const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(c_str), make_reference, allocator) {}
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  buffer(const ::std::basic_string_view<CHAR, T> &view, bool make_reference,
-         const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(view), make_reference, allocator) {}
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  MDBX_CXX20_CONSTEXPR
-  buffer(const struct slice &src,
-         const allocator_type &allocator = allocator_type())
-      : silo_(src.data(), src.length(), allocator),
-        slice_(silo_.data(), src.length()) {}
-
-  MDBX_CXX20_CONSTEXPR
-  buffer(const buffer &src, const allocator_type &allocator = allocator_type())
-      : buffer(src.slice_, allocator) {}
-
-  MDBX_CXX20_CONSTEXPR
-  buffer(const void *ptr, size_t bytes,
-         const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(ptr, bytes), allocator) {}
-
-  template <class CHAR, class T, class A>
-  MDBX_CXX20_CONSTEXPR
-  buffer(const ::std::basic_string<CHAR, T, A> &str,
-         const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(str), allocator) {}
-
-  MDBX_CXX20_CONSTEXPR
-  buffer(const char *c_str, const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(c_str), allocator) {}
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  MDBX_CXX20_CONSTEXPR
-  buffer(const ::std::basic_string_view<CHAR, T> &view,
-         const allocator_type &allocator = allocator_type())
-      : buffer(::mdbx::slice(view), allocator) {}
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  buffer(size_t head_room, size_t tail_room,
-         const allocator_type &allocator = allocator_type())
-      : silo_(allocator) {
-    slice_.iov_base = silo_.init(check_length(head_room, tail_room));
-    assert(slice_.iov_len == 0);
-  }
-
-  buffer(size_t capacity, const allocator_type &allocator = allocator_type())
-      : silo_(allocator) {
-    slice_.iov_base = silo_.init(check_length(capacity));
-    assert(slice_.iov_len == 0);
-  }
-
-  buffer(size_t head_room, const struct slice &src, size_t tail_room,
-         const allocator_type &allocator = allocator_type())
-      : silo_(allocator) {
-    slice_.iov_base =
-        silo_.init(check_length(head_room, src.length(), tail_room));
-    slice_.iov_len = src.length();
-    memcpy(slice_.iov_base, src.data(), src.length());
-  }
-
-  buffer(size_t head_room, const buffer &src, size_t tail_room,
-         const allocator_type &allocator = allocator_type())
-      : buffer(head_room, src.slice_, tail_room, allocator) {}
-
-  inline buffer(const ::mdbx::txn &txn, const struct slice &src,
-                const allocator_type &allocator = allocator_type());
-
-  buffer(buffer &&src) noexcept(move_assign_alloc::is_nothrow())
-      : silo_(::std::move(src.silo_)), slice_(::std::move(src.slice_)) {}
-
-  MDBX_CXX11_CONSTEXPR const struct slice &slice() const noexcept {
-    return slice_;
-  }
-
-  MDBX_CXX11_CONSTEXPR operator const struct slice &() const noexcept {
-    return slice_;
-  }
-
-  template <typename POD>
-  static buffer wrap(const POD &pod, bool make_reference = false,
-                     const allocator_type &allocator = allocator_type()) {
-    return buffer(::mdbx::slice::wrap(pod), make_reference, allocator);
-  }
-
-  /// \brief Reserves storage space.
-  void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
-    wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom),
-                                wanna_headroom + pettiness_threshold);
-    wanna_tailroom = ::std::min(::std::max(tailroom(), wanna_tailroom),
-                                wanna_tailroom + pettiness_threshold);
-    const size_t wanna_capacity =
-        check_length(wanna_headroom, slice_.length(), wanna_tailroom);
-    silo_.resize(wanna_capacity, wanna_headroom, slice_);
-    assert(headroom() >= wanna_headroom &&
-           headroom() <= wanna_headroom + pettiness_threshold);
-    assert(tailroom() >= wanna_tailroom &&
-           tailroom() <= wanna_tailroom + pettiness_threshold);
-  }
-
-  /// \brief Reserves space before the payload.
-  void reserve_headroom(size_t wanna_headroom) { reserve(wanna_headroom, 0); }
-
-  /// \brief Reserves space after the payload.
-  void reserve_tailroom(size_t wanna_tailroom) { reserve(0, wanna_tailroom); }
-
-  buffer &assign_reference(const void *ptr, size_t bytes) {
-    silo_.clear();
-    slice_.assign(ptr, bytes);
-    return *this;
-  }
-
-  buffer &assign_freestanding(const void *ptr, size_t bytes) {
-    silo_.assign(static_cast<const typename silo::value_type *>(ptr),
-                 check_length(bytes));
-    slice_.assign(silo_.data(), bytes);
-    return *this;
-  }
-
-  MDBX_CXX20_CONSTEXPR void
-  swap(buffer &other) noexcept(swap_alloc::is_nothrow()) {
-    silo_.swap(other.silo_);
-    slice_.swap(other.slice_);
-  }
-
-  static buffer clone(const buffer &src,
-                      const allocator_type &allocator = allocator_type()) {
-    return buffer(src.headroom(), src.slice_, src.tailroom(), allocator);
-  }
-
-  buffer &assign(const buffer &src, bool make_reference = false) {
-    return assign(src.slice_, make_reference);
-  }
-
-  buffer &assign(const void *ptr, size_t bytes, bool make_reference = false) {
-    return make_reference ? assign_reference(ptr, bytes)
-                          : assign_freestanding(ptr, bytes);
-  }
-
-  buffer &assign(const struct slice &src, bool make_reference = false) {
-    return assign(src.data(), src.length(), make_reference);
-  }
-
-  buffer &assign(const ::MDBX_val &src, bool make_reference = false) {
-    return assign(src.iov_base, src.iov_len, make_reference);
-  }
-
-  buffer &assign(struct slice &&src, bool make_reference = false) {
-    assign(src.data(), src.length(), make_reference);
-    src.invalidate();
-    return *this;
-  }
-
-  buffer &assign(::MDBX_val &&src, bool make_reference = false) {
-    assign(src.iov_base, src.iov_len, make_reference);
-    src.iov_base = nullptr;
-    return *this;
-  }
-
-  buffer &assign(const void *begin, const void *end,
-                 bool make_reference = false) {
-    return assign(begin,
-                  static_cast<const byte *>(end) -
-                      static_cast<const byte *>(begin),
-                  make_reference);
-  }
-
-  template <class CHAR, class T, class A>
-  buffer &assign(const ::std::basic_string<CHAR, T, A> &str,
-                 bool make_reference = false) {
-    return assign(str.data(), str.length(), make_reference);
-  }
-
-  buffer &assign(const char *c_str, bool make_reference = false) {
-    return assign(c_str, ::mdbx::strlen(c_str), make_reference);
-  }
-
-#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
-  template <class CHAR, class T>
-  buffer &assign(const ::std::basic_string_view<CHAR, T> &view,
-                 bool make_reference = false) {
-    return assign(view.data(), view.length(), make_reference);
-  }
-
-  template <class CHAR, class T>
-  buffer &assign(::std::basic_string_view<CHAR, T> &&view,
-                 bool make_reference = false) {
-    assign(view.data(), view.length(), make_reference);
-    view = {};
-    return *this;
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  buffer &operator=(const buffer &src) { return assign(src); }
-
-  buffer &operator=(buffer &&src) noexcept(move_assign_alloc::is_nothrow()) {
-    return assign(::std::move(src));
-  }
-
-  buffer &operator=(const struct slice &src) { return assign(src); }
-
-  buffer &operator=(struct slice &&src) { return assign(::std::move(src)); }
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  buffer &operator=(const ::std::basic_string_view<CHAR, T> &view) noexcept {
-    return assign(view);
-  }
-
-  /// \brief Return a string_view that references the data of this buffer.
-  template <class CHAR = char, class T = ::std::char_traits<CHAR>>
-  ::std::basic_string_view<CHAR, T> string_view() const noexcept {
-    return slice_.string_view<CHAR, T>();
-  }
-
-  /// \brief Return a string_view that references the data of this buffer.
-  template <class CHAR, class T>
-  operator ::std::basic_string_view<CHAR, T>() const noexcept {
-    return string_view<CHAR, T>();
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  /// \brief Checks whether the string is empty.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR bool empty() const noexcept {
-    return length() == 0;
-  }
-
-  /// \brief Checks whether the data pointer of the buffer is nullptr.
-  MDBX_CXX11_CONSTEXPR bool is_null() const noexcept {
-    return data() == nullptr;
-  }
-
-  /// \brief Returns the number of bytes.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR size_t size() const noexcept {
-    return length();
-  }
-
-  /// \brief Returns the hash value of the data.
-  /// \attention Function implementation and returned hash values may changed
-  /// version to version, and in future the t1ha3 will be used here. Therefore
-  /// values obtained from this function shouldn't be persisted anywhere.
-  MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR size_t
-  hash_value() const noexcept {
-    return slice_.hash_value();
-  }
-
-  template <class CHAR = char, class T = ::std::char_traits<CHAR>,
-            class A = legacy_allocator>
-  MDBX_CXX20_CONSTEXPR ::std::basic_string<CHAR, T, A>
-  as_string(const A &allocator = A()) const {
-    return slice_.as_string<CHAR, T, A>(allocator);
-  }
-
-  template <class CHAR, class T, class A>
-  MDBX_CXX20_CONSTEXPR explicit
-  operator ::std::basic_string<CHAR, T, A>() const {
-    return as_string<CHAR, T, A>();
-  }
-
-  /// \brief Checks if the data starts with the given prefix.
-  MDBX_NOTHROW_PURE_FUNCTION bool
-  starts_with(const struct slice &prefix) const noexcept {
-    return slice_.starts_with(prefix);
-  }
-
-  /// \brief Checks if the data ends with the given suffix.
-  MDBX_NOTHROW_PURE_FUNCTION bool
-  ends_with(const struct slice &suffix) const noexcept {
-    return slice_.ends_with(suffix);
-  }
-
-  /// \brief Clears the contents and storage.
-  void clear() noexcept {
-    slice_.clear();
-    silo_.clear();
-  }
-
-  /// \brief Reduces memory usage by freeing unused storage space.
-  void shrink_to_fit() { reserve(0, 0); }
-
-  /// \brief Drops the first "n" bytes from the data chunk.
-  /// \pre REQUIRES: `n <= size()`
-  void remove_prefix(size_t n) noexcept { slice_.remove_prefix(n); }
-
-  /// \brief Drops the last "n" bytes from the data chunk.
-  /// \pre REQUIRES: `n <= size()`
-  void remove_suffix(size_t n) noexcept { slice_.remove_suffix(n); }
-
-  /// \brief Drops the first "n" bytes from the data chunk.
-  /// \throws std::out_of_range if `n > size()`
-  void safe_remove_prefix(size_t n) { slice_.safe_remove_prefix(n); }
-
-  /// \brief Drops the last "n" bytes from the data chunk.
-  /// \throws std::out_of_range if `n > size()`
-  void safe_remove_suffix(size_t n) { slice_.safe_remove_suffix(n); }
-
-  /// \brief Accesses the specified byte of data chunk.
-  /// \pre REQUIRES: `n < size()`
-  MDBX_CXX11_CONSTEXPR byte operator[](size_t n) const noexcept {
-    MDBX_CONSTEXPR_ASSERT(n < size());
-    return slice_[n];
-  }
-
-  /// \brief Accesses the specified byte of data chunk.
-  /// \pre REQUIRES: `n < size()`
-  MDBX_CXX11_CONSTEXPR byte &operator[](size_t n) noexcept {
-    MDBX_CONSTEXPR_ASSERT(n < size());
-    return byte_ptr()[n];
-  }
-
-  /// \brief Accesses the specified byte of data chunk with bounds checking.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX14_CONSTEXPR byte at(size_t n) const { return slice_.at(n); }
-
-  /// \brief Accesses the specified byte of data chunk with bounds checking.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX14_CONSTEXPR byte &at(size_t n) {
-    if (MDBX_UNLIKELY(n >= size()))
-      MDBX_CXX20_UNLIKELY throw_out_range();
-    return byte_ptr()[n];
-  }
-
-  /// \brief Returns the first "n" bytes of the data chunk.
-  /// \pre REQUIRES: `n <= size()`
-  MDBX_CXX14_CONSTEXPR struct slice head(size_t n) const noexcept {
-    return slice_.head(n);
-  }
-
-  /// \brief Returns the last "n" bytes of the data chunk.
-  /// \pre REQUIRES: `n <= size()`
-  MDBX_CXX14_CONSTEXPR struct slice tail(size_t n) const noexcept {
-    return slice_.tail(n);
-  }
-
-  /// \brief Returns the middle "n" bytes of the data chunk.
-  /// \pre REQUIRES: `from + n <= size()`
-  MDBX_CXX14_CONSTEXPR struct slice middle(size_t from,
-                                           size_t n) const noexcept {
-    return slice_.middle(from, n);
-  }
-
-  /// \brief Returns the first "n" bytes of the data chunk.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX14_CONSTEXPR struct slice safe_head(size_t n) const {
-    return slice_.safe_head(n);
-  }
-
-  /// \brief Returns the last "n" bytes of the data chunk.
-  /// \throws std::out_of_range if `n >= size()`
-  MDBX_CXX14_CONSTEXPR struct slice safe_tail(size_t n) const {
-    return slice_.safe_tail(n);
-  }
-
-  /// \brief Returns the middle "n" bytes of the data chunk.
-  /// \throws std::out_of_range if `from + n >= size()`
-  MDBX_CXX14_CONSTEXPR struct slice safe_middle(size_t from, size_t n) const {
-    return slice_.safe_middle(from, n);
-  }
-
-  buffer &append(const void *src, size_t bytes) {
-    if (MDBX_UNLIKELY(tailroom() < check_length(bytes)))
-      MDBX_CXX20_UNLIKELY reserve_tailroom(bytes);
-    memcpy(slice_.byte_ptr() + size(), src, bytes);
-    slice_.iov_len += bytes;
-    return *this;
-  }
-
-  buffer &append(const struct slice &chunk) {
-    return append(chunk.data(), chunk.size());
-  }
-
-  buffer &add_header(const void *src, size_t bytes) {
-    if (MDBX_UNLIKELY(headroom() < check_length(bytes)))
-      MDBX_CXX20_UNLIKELY reserve_headroom(bytes);
-    slice_.iov_base =
-        memcpy(static_cast<char *>(slice_.iov_base) - bytes, src, bytes);
-    slice_.iov_len += bytes;
-    return *this;
-  }
-
-  buffer &add_header(const struct slice &chunk) {
-    return add_header(chunk.data(), chunk.size());
-  }
-
-  template <MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)>
-  buffer &append_producer(PRODUCER &producer) {
-    const size_t wanna_bytes = producer.envisage_result_length();
-    if (MDBX_UNLIKELY(tailroom() < check_length(wanna_bytes)))
-      MDBX_CXX20_UNLIKELY reserve_tailroom(wanna_bytes);
-    return set_end(producer.write_bytes(end_char_ptr(), tailroom()));
-  }
-
-  template <MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)>
-  buffer &append_producer(const PRODUCER &producer) {
-    const size_t wanna_bytes = producer.envisage_result_length();
-    if (MDBX_UNLIKELY(tailroom() < check_length(wanna_bytes)))
-      MDBX_CXX20_UNLIKELY reserve_tailroom(wanna_bytes);
-    return set_end(producer.write_bytes(end_char_ptr(), tailroom()));
-  }
-
-  buffer &append_hex(const struct slice &data, bool uppercase = false,
-                     unsigned wrap_width = 0) {
-    return append_producer(to_hex(data, uppercase, wrap_width));
-  }
-
-  buffer &append_base58(const struct slice &data, unsigned wrap_width = 0) {
-    return append_producer(to_base58(data, wrap_width));
-  }
-
-  buffer &append_base64(const struct slice &data, unsigned wrap_width = 0) {
-    return append_producer(to_base64(data, wrap_width));
-  }
-
-  buffer &append_decoded_hex(const struct slice &data,
-                             bool ignore_spaces = false) {
-    return append_producer(from_hex(data, ignore_spaces));
-  }
-
-  buffer &append_decoded_base58(const struct slice &data,
-                                bool ignore_spaces = false) {
-    return append_producer(from_base58(data, ignore_spaces));
-  }
-
-  buffer &append_decoded_base64(const struct slice &data,
-                                bool ignore_spaces = false) {
-    return append_producer(from_base64(data, ignore_spaces));
-  }
-
-  //----------------------------------------------------------------------------
-
-  template <size_t SIZE>
-  static buffer key_from(const char (&text)[SIZE], bool make_reference = true) {
-    return buffer(::mdbx::slice(text), make_reference);
-  }
-
-#if defined(DOXYGEN) ||                                                        \
-    (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
-  template <class CHAR, class T>
-  static buffer key_from(const ::std::basic_string_view<CHAR, T> &src,
-                         bool make_reference = false) {
-    return buffer(src, make_reference);
-  }
-#endif /* __cpp_lib_string_view >= 201606L */
-
-  static buffer key_from(const char *src, bool make_reference = false) {
-    return buffer(src, make_reference);
-  }
-
-  template <class CHAR, class T, class A>
-  static buffer key_from(const ::std::basic_string<CHAR, T, A> &src,
-                         bool make_reference = false) {
-    return buffer(src, make_reference);
-  }
-
-  static buffer key_from(const silo &&src) noexcept {
-    return buffer(::std::move(src));
-  }
-
-  static buffer key_from(const double ieee754_64bit) {
-    return wrap(::mdbx_key_from_double(ieee754_64bit));
-  }
-
-  static buffer key_from(const double *ieee754_64bit) {
-    return wrap(::mdbx_key_from_ptrdouble(ieee754_64bit));
-  }
-
-  static buffer key_from(const uint64_t unsigned_int64) {
-    return wrap(unsigned_int64);
-  }
-
-  static buffer key_from(const int64_t signed_int64) {
-    return wrap(::mdbx_key_from_int64(signed_int64));
-  }
-
-  static buffer key_from_jsonInteger(const int64_t json_integer) {
-    return wrap(::mdbx_key_from_jsonInteger(json_integer));
-  }
-
-  static buffer key_from(const float ieee754_32bit) {
-    return wrap(::mdbx_key_from_float(ieee754_32bit));
-  }
-
-  static buffer key_from(const float *ieee754_32bit) {
-    return wrap(::mdbx_key_from_ptrfloat(ieee754_32bit));
-  }
-
-  static buffer key_from(const uint32_t unsigned_int32) {
-    return wrap(unsigned_int32);
-  }
-
-  static buffer key_from(const int32_t signed_int32) {
-    return wrap(::mdbx_key_from_int32(signed_int32));
-  }
-};
-
-template <class ALLOCATOR, class CAPACITY_POLICY,
-          MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-make_buffer(PRODUCER &producer, const ALLOCATOR &allocator) {
-  if (MDBX_LIKELY(!producer.is_empty()))
-    MDBX_CXX20_LIKELY {
-      buffer<ALLOCATOR, CAPACITY_POLICY> result(
-          producer.envisage_result_length(), allocator);
-      result.set_end(
-          producer.write_bytes(result.end_char_ptr(), result.tailroom()));
-      return result;
-    }
-  return buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY,
-          MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-make_buffer(const PRODUCER &producer, const ALLOCATOR &allocator) {
-  if (MDBX_LIKELY(!producer.is_empty()))
-    MDBX_CXX20_LIKELY {
-      buffer<ALLOCATOR, CAPACITY_POLICY> result(
-          producer.envisage_result_length(), allocator);
-      result.set_end(
-          producer.write_bytes(result.end_char_ptr(), result.tailroom()));
-      return result;
-    }
-  return buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)>
-inline string<ALLOCATOR> make_string(PRODUCER &producer,
-                                     const ALLOCATOR &allocator) {
-  string<ALLOCATOR> result(allocator);
-  if (MDBX_LIKELY(!producer.is_empty()))
-    MDBX_CXX20_LIKELY {
-      result.resize(producer.envisage_result_length());
-      result.resize(producer.write_bytes(const_cast<char *>(result.data()),
-                                         result.capacity()) -
-                    result.data());
-    }
-  return result;
-}
-
-template <class ALLOCATOR, MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)>
-inline string<ALLOCATOR> make_string(const PRODUCER &producer,
-                                     const ALLOCATOR &allocator) {
-  string<ALLOCATOR> result(allocator);
-  if (MDBX_LIKELY(!producer.is_empty()))
-    MDBX_CXX20_LIKELY {
-      result.resize(producer.envisage_result_length());
-      result.resize(producer.write_bytes(const_cast<char *>(result.data()),
-                                         result.capacity()) -
-                    result.data());
-    }
-  return result;
-}
-
-/// \brief Combines data slice with boolean flag to represent result of certain
-/// operations.
-struct value_result {
-  slice value;
-  bool done;
-  value_result(const slice &value, bool done) noexcept
-      : value(value), done(done) {}
-  value_result(const value_result &) noexcept = default;
-  value_result &operator=(const value_result &) noexcept = default;
-  MDBX_CXX14_CONSTEXPR operator bool() const noexcept {
-    assert(!done || bool(value));
-    return done;
-  }
-};
-
-/// \brief Combines pair of slices for key and value to represent result of
-/// certain operations.
-struct pair {
-  slice key, value;
-  pair(const slice &key, const slice &value) noexcept
-      : key(key), value(value) {}
-  pair(const pair &) noexcept = default;
-  pair &operator=(const pair &) noexcept = default;
-  MDBX_CXX14_CONSTEXPR operator bool() const noexcept {
-    assert(bool(key) == bool(value));
-    return key;
-  }
-};
-
-/// \brief Combines pair of slices for key and value with boolean flag to
-/// represent result of certain operations.
-struct pair_result : public pair {
-  bool done;
-  pair_result(const slice &key, const slice &value, bool done) noexcept
-      : pair(key, value), done(done) {}
-  pair_result(const pair_result &) noexcept = default;
-  pair_result &operator=(const pair_result &) noexcept = default;
-  MDBX_CXX14_CONSTEXPR operator bool() const noexcept {
-    assert(!done || (bool(key) && bool(value)));
-    return done;
-  }
-};
-
-//------------------------------------------------------------------------------
-
-/// \brief Loop control constants for readers enumeration functor and other
-/// cases. \see env::enumerate_readers()
-enum loop_control { continue_loop = 0, exit_loop = INT32_MIN };
-
-/// \brief Kinds of the keys and corresponding modes of comparing it.
-enum class key_mode {
-  usual = MDBX_DB_DEFAULTS,  ///< Usual variable length keys with byte-by-byte
-                             ///< lexicographic comparison like `std::memcmp()`.
-  reverse = MDBX_REVERSEKEY, ///< Variable length keys with byte-by-byte
-                             ///< lexicographic comparison in reverse order,
-                             ///< from the end of the keys to the beginning.
-  ordinal = MDBX_INTEGERKEY, ///< Keys are binary integers in native byte order,
-                             ///< either `uint32_t` or `uint64_t`, and will be
-                             ///< sorted as such. The keys must all be of the
-                             ///< same size and must be aligned while passing
-                             ///< as arguments.
-  msgpack = -1 ///< Keys are in [MessagePack](https://msgpack.org/)
-               ///< format with appropriate comparison.
-               ///< \note Not yet implemented and PRs are welcome.
-};
-
-/// \brief Kind of the values and sorted multi-values with corresponding
-/// comparison.
-enum class value_mode {
-  single = MDBX_DB_DEFAULTS, ///< Usual single value for each key. In terms of
-                             ///< keys, they are unique.
-  multi =
-      MDBX_DUPSORT, ///< A more than one data value could be associated with
-                    ///< each key. Internally each key is stored once, and the
-                    ///< corresponding data values are sorted by byte-by-byte
-                    ///< lexicographic comparison like `std::memcmp()`.
-                    ///< In terms of keys, they are not unique, i.e. has
-                    ///< duplicates which are sorted by associated data values.
-#if CONSTEXPR_ENUM_FLAGS_OPERATIONS || defined(DOXYGEN)
-  multi_reverse =
-      MDBX_DUPSORT |
-      MDBX_REVERSEDUP, ///< A more than one data value could be associated with
-                       ///< each key. Internally each key is stored once, and
-                       ///< the corresponding data values are sorted by
-                       ///< byte-by-byte lexicographic comparison in reverse
-                       ///< order, from the end of the keys to the beginning.
-                       ///< In terms of keys, they are not unique, i.e. has
-                       ///< duplicates which are sorted by associated data
-                       ///< values.
-  multi_samelength =
-      MDBX_DUPSORT |
-      MDBX_DUPFIXED, ///< A more than one data value could be associated with
-                     ///< each key, and all data values must be same length.
-                     ///< Internally each key is stored once, and the
-                     ///< corresponding data values are sorted by byte-by-byte
-                     ///< lexicographic comparison like `std::memcmp()`. In
-                     ///< terms of keys, they are not unique, i.e. has
-                     ///< duplicates which are sorted by associated data values.
-  multi_ordinal =
-      MDBX_DUPSORT | MDBX_DUPFIXED |
-      MDBX_INTEGERDUP, ///< A more than one data value could be associated with
-                       ///< each key, and all data values are binary integers in
-                       ///< native byte order, either `uint32_t` or `uint64_t`,
-                       ///< and will be sorted as such. Internally each key is
-                       ///< stored once, and the corresponding data values are
-                       ///< sorted. In terms of keys, they are not unique, i.e.
-                       ///< has duplicates which are sorted by associated data
-                       ///< values.
-  multi_reverse_samelength =
-      MDBX_DUPSORT | MDBX_REVERSEDUP |
-      MDBX_DUPFIXED, ///< A more than one data value could be associated with
-                     ///< each key, and all data values must be same length.
-                     ///< Internally each key is stored once, and the
-                     ///< corresponding data values are sorted by byte-by-byte
-                     ///< lexicographic comparison in reverse order, from the
-                     ///< end of the keys to the beginning. In terms of keys,
-                     ///< they are not unique, i.e. has duplicates which are
-                     ///< sorted by associated data values.
-  msgpack = -1 ///< A more than one data value could be associated with each
-               ///< key. Values are in [MessagePack](https://msgpack.org/)
-               ///< format with appropriate comparison. Internally each key is
-               ///< stored once, and the corresponding data values are sorted.
-               ///< In terms of keys, they are not unique, i.e. has duplicates
-               ///< which are sorted by associated data values.
-               ///< \note Not yet implemented and PRs are welcome.
-#else
-  multi_reverse = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_REVERSEDUP),
-  multi_samelength = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_DUPFIXED),
-  multi_ordinal = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_DUPFIXED) |
-                  uint32_t(MDBX_INTEGERDUP),
-  multi_reverse_samelength = uint32_t(MDBX_DUPSORT) |
-                             uint32_t(MDBX_REVERSEDUP) | uint32_t(MDBX_DUPFIXED)
-#endif
-};
-
-/// \brief A handle for an individual database (key-value spaces) in the
-/// environment.
-/// \see txn::open_map() \see txn::create_map()
-/// \see txn::clear_map() \see txn::drop_map()
-/// \see txn::get_handle_info() \see txn::get_map_stat()
-/// \see env::close_map()
-/// \see cursor::map()
-struct LIBMDBX_API_TYPE map_handle {
-  MDBX_dbi dbi{0};
-  MDBX_CXX11_CONSTEXPR map_handle() noexcept {}
-  MDBX_CXX11_CONSTEXPR map_handle(MDBX_dbi dbi) noexcept : dbi(dbi) {}
-  map_handle(const map_handle &) noexcept = default;
-  map_handle &operator=(const map_handle &) noexcept = default;
-  operator bool() const noexcept { return dbi != 0; }
-
-  using flags = ::MDBX_db_flags_t;
-  using state = ::MDBX_dbi_state_t;
-  struct LIBMDBX_API_TYPE info {
-    map_handle::flags flags;
-    map_handle::state state;
-    MDBX_CXX11_CONSTEXPR info(map_handle::flags flags,
-                              map_handle::state state) noexcept;
-    info(const info &) noexcept = default;
-    info &operator=(const info &) noexcept = default;
-#if CONSTEXPR_ENUM_FLAGS_OPERATIONS
-    MDBX_CXX11_CONSTEXPR
-#else
-    inline
-#endif
-    ::mdbx::key_mode key_mode() const noexcept;
-#if CONSTEXPR_ENUM_FLAGS_OPERATIONS
-    MDBX_CXX11_CONSTEXPR
-#else
-    inline
-#endif
-    ::mdbx::value_mode value_mode() const noexcept;
-  };
-};
-
-/// \brief Key-value pairs put mode.
-enum put_mode {
-  insert_unique = MDBX_NOOVERWRITE, ///< Insert only unique keys.
-  upsert = MDBX_UPSERT,             ///< Insert or update.
-  update = MDBX_CURRENT,            ///< Update existing, don't insert new.
-};
-
-/// \brief Unmanaged database environment.
-///
-/// Like other unmanaged classes, `env` allows copying and assignment for
-/// instances, but does not destroys the represented underlying object from the
-/// own class destructor.
-///
-/// An environment supports multiple key-value sub-databases (aka key-value
-/// spaces or tables), all residing in the same shared-memory map.
-class LIBMDBX_API_TYPE env {
-  friend class txn;
-
-protected:
-  MDBX_env *handle_{nullptr};
-  MDBX_CXX11_CONSTEXPR env(MDBX_env *ptr) noexcept;
-
-public:
-  MDBX_CXX11_CONSTEXPR env() noexcept = default;
-  env(const env &) noexcept = default;
-  inline env &operator=(env &&other) noexcept;
-  inline env(env &&other) noexcept;
-  inline ~env() noexcept;
-
-  MDBX_CXX14_CONSTEXPR operator bool() const noexcept;
-  MDBX_CXX14_CONSTEXPR operator const MDBX_env *() const;
-  MDBX_CXX14_CONSTEXPR operator MDBX_env *();
-  friend MDBX_CXX11_CONSTEXPR bool operator==(const env &a,
-                                              const env &b) noexcept;
-  friend MDBX_CXX11_CONSTEXPR bool operator!=(const env &a,
-                                              const env &b) noexcept;
-
-  //----------------------------------------------------------------------------
-
-  /// Database geometry for size management.
-  struct LIBMDBX_API_TYPE geometry {
-    enum : int64_t {
-      default_value = -1,         ///< Means "keep current or use default"
-      minimal_value = 0,          ///< Means "minimal acceptable"
-      maximal_value = INTPTR_MAX, ///< Means "maximal acceptable"
-      kB = 1000,                  ///< \f$10^{3}\f$ bytes
-      MB = kB * 1000,             ///< \f$10^{6}\f$ bytes
-      GB = MB * 1000,             ///< \f$10^{9}\f$ bytes
-      TB = GB * 1000,             ///< \f$10^{12}\f$ bytes
-      PB = TB * 1000,             ///< \f$10^{15}\f$ bytes
-      EB = PB * 1000,             ///< \f$10^{18}\f$ bytes
-      KiB = 1024,                 ///< \f$2^{10}\f$ bytes
-      MiB = KiB << 10,            ///< \f$2^{20}\f$ bytes
-      GiB = MiB << 10,            ///< \f$2^{30}\f$ bytes
-      TiB = GiB << 10,            ///< \f$2^{40}\f$ bytes
-      PiB = TiB << 10,            ///< \f$2^{50}\f$ bytes
-      EiB = PiB << 10,            ///< \f$2^{60}\f$ bytes
-    };
-
-    /// \brief Tagged type for output to std::ostream
-    struct size {
-      intptr_t bytes;
-      MDBX_CXX11_CONSTEXPR size(intptr_t bytes) noexcept : bytes(bytes) {}
-      MDBX_CXX11_CONSTEXPR operator intptr_t() const noexcept { return bytes; }
-    };
-
-    /// \brief The lower bound of database size in bytes.
-    intptr_t size_lower{minimal_value};
-
-    /// \brief The size in bytes to setup the database size for now.
-    /// \details It is recommended always pass \ref default_value in this
-    /// argument except some special cases.
-    intptr_t size_now{default_value};
-
-    /// \brief The upper bound of database size in bytes.
-    /// \details It is recommended to avoid change upper bound while database is
-    /// used by other processes or threaded (i.e. just pass \ref default_value
-    /// in this argument except absolutely necessary). Otherwise you must be
-    /// ready for \ref MDBX_UNABLE_EXTEND_MAPSIZE error(s), unexpected pauses
-    /// during remapping and/or system errors like "address busy", and so on. In
-    /// other words, there is no way to handle a growth of the upper bound
-    /// robustly because there may be a lack of appropriate system resources
-    /// (which are extremely volatile in a multi-process multi-threaded
-    /// environment).
-    intptr_t size_upper{maximal_value};
-
-    /// \brief The growth step in bytes, must be greater than zero to allow the
-    /// database to grow.
-    intptr_t growth_step{default_value};
-
-    /// \brief The shrink threshold in bytes, must be greater than zero to allow
-    /// the database to shrink.
-    intptr_t shrink_threshold{default_value};
-
-    /// \brief The database page size for new database creation
-    /// or \ref default_value otherwise.
-    /// \details Must be power of 2 in the range between \ref MDBX_MIN_PAGESIZE
-    /// and \ref MDBX_MAX_PAGESIZE.
-    intptr_t pagesize{default_value};
-
-    inline geometry &make_fixed(intptr_t size) noexcept;
-    inline geometry &make_dynamic(intptr_t lower = minimal_value,
-                                  intptr_t upper = maximal_value) noexcept;
-    MDBX_CXX11_CONSTEXPR geometry() noexcept {}
-    MDBX_CXX11_CONSTEXPR
-    geometry(const geometry &) noexcept = default;
-    MDBX_CXX11_CONSTEXPR geometry(intptr_t size_lower,
-                                  intptr_t size_now = default_value,
-                                  intptr_t size_upper = maximal_value,
-                                  intptr_t growth_step = default_value,
-                                  intptr_t shrink_threshold = default_value,
-                                  intptr_t pagesize = default_value) noexcept
-        : size_lower(size_lower), size_now(size_now), size_upper(size_upper),
-          growth_step(growth_step), shrink_threshold(shrink_threshold),
-          pagesize(pagesize) {}
-  };
-
-  /// \brief Operation mode.
-  enum mode {
-    readonly,       ///< \copydoc MDBX_RDONLY
-    write_file_io,  // don't available on OpenBSD
-    write_mapped_io ///< \copydoc MDBX_WRITEMAP
-  };
-
-  /// \brief Durability level.
-  enum durability {
-    robust_synchronous,         ///< \copydoc MDBX_SYNC_DURABLE
-    half_synchronous_weak_last, ///< \copydoc MDBX_NOMETASYNC
-    lazy_weak_tail,             ///< \copydoc MDBX_SAFE_NOSYNC
-    whole_fragile               ///< \copydoc MDBX_UTTERLY_NOSYNC
-  };
-
-  /// \brief Garbage reclaiming options.
-  struct LIBMDBX_API_TYPE reclaiming_options {
-    /// \copydoc MDBX_LIFORECLAIM
-    bool lifo{false};
-    /// \copydoc MDBX_COALESCE
-    bool coalesce{false};
-    MDBX_CXX11_CONSTEXPR reclaiming_options() noexcept {}
-    MDBX_CXX11_CONSTEXPR
-    reclaiming_options(const reclaiming_options &) noexcept = default;
-    MDBX_CXX14_CONSTEXPR reclaiming_options &
-    operator=(const reclaiming_options &) noexcept = default;
-    reclaiming_options(MDBX_env_flags_t) noexcept;
-  };
-
-  /// \brief Operate options.
-  struct LIBMDBX_API_TYPE operate_options {
-    /// \copydoc MDBX_NOTLS
-    bool orphan_read_transactions{false};
-    bool nested_write_transactions{false};
-    /// \copydoc MDBX_EXCLUSIVE
-    bool exclusive{false};
-    /// \copydoc MDBX_NORDAHEAD
-    bool disable_readahead{false};
-    /// \copydoc MDBX_NOMEMINIT
-    bool disable_clear_memory{false};
-    MDBX_CXX11_CONSTEXPR operate_options() noexcept {}
-    MDBX_CXX11_CONSTEXPR
-    operate_options(const operate_options &) noexcept = default;
-    MDBX_CXX14_CONSTEXPR operate_options &
-    operator=(const operate_options &) noexcept = default;
-    operate_options(MDBX_env_flags_t) noexcept;
-  };
-
-  /// \brief Operate parameters.
-  struct LIBMDBX_API_TYPE operate_parameters {
-    /// \brief The maximum number of named databases for the environment.
-    /// Zero means default value.
-    unsigned max_maps{0};
-    /// \brief The maximum number of threads/reader slots for the environment.
-    /// Zero means default value.
-    unsigned max_readers{0};
-    env::mode mode{write_mapped_io};
-    env::durability durability{robust_synchronous};
-    env::reclaiming_options reclaiming;
-    env::operate_options options;
-
-    MDBX_CXX11_CONSTEXPR operate_parameters() noexcept {}
-    MDBX_CXX11_CONSTEXPR
-    operate_parameters(
-        const unsigned max_maps, const unsigned max_readers = 0,
-        const env::mode mode = env::mode::write_mapped_io,
-        env::durability durability = env::durability::robust_synchronous,
-        const env::reclaiming_options &reclaiming = env::reclaiming_options(),
-        const env::operate_options &options = env::operate_options()) noexcept
-        : max_maps(max_maps), max_readers(max_readers), mode(mode),
-          durability(durability), reclaiming(reclaiming), options(options) {}
-    MDBX_CXX11_CONSTEXPR
-    operate_parameters(const operate_parameters &) noexcept = default;
-    MDBX_CXX14_CONSTEXPR operate_parameters &
-    operator=(const operate_parameters &) noexcept = default;
-    MDBX_env_flags_t
-    make_flags(bool accede = true, ///< \copydoc MDBX_ACCEDE
-               bool use_subdirectory =
-                   false ///< use subdirectory to place the DB files
-    ) const;
-    static env::mode mode_from_flags(MDBX_env_flags_t) noexcept;
-    static env::durability durability_from_flags(MDBX_env_flags_t) noexcept;
-    inline static env::reclaiming_options
-    reclaiming_from_flags(MDBX_env_flags_t flags) noexcept;
-    inline static env::operate_options
-    options_from_flags(MDBX_env_flags_t flags) noexcept;
-  };
-
-  /// \brief Returns current operation parameters.
-  inline env::operate_parameters get_operation_parameters() const;
-  /// \brief Returns current operation mode.
-  inline env::mode get_mode() const;
-  /// \brief Returns current durability mode.
-  inline env::durability get_durability() const;
-  /// \brief Returns current reclaiming options.
-  inline env::reclaiming_options get_reclaiming() const;
-  /// \brief Returns current operate options.
-  inline env::operate_options get_options() const;
-
-  /// \brief Returns `true` for a freshly created database,
-  /// but `false` if at least one transaction was committed.
-  bool is_pristine() const;
-
-  /// \brief Checks whether the database is empty.
-  bool is_empty() const;
-
-  /// \brief Returns default page size for current system/platform.
-  static size_t default_pagesize() noexcept {
-    return ::mdbx_default_pagesize();
-  }
-
-  struct limits {
-    limits() = delete;
-    /// \brief Returns the minimal database page size in bytes.
-    static inline size_t pagesize_min() noexcept;
-    /// \brief Returns the maximal database page size in bytes.
-    static inline size_t pagesize_max() noexcept;
-    /// \brief Returns the minimal database size in bytes for specified page
-    /// size.
-    static inline size_t dbsize_min(intptr_t pagesize);
-    /// \brief Returns the maximal database size in bytes for specified page
-    /// size.
-    static inline size_t dbsize_max(intptr_t pagesize);
-    /// \brief Returns the minimal key size in bytes for specified database
-    /// flags.
-    static inline size_t key_min(MDBX_db_flags_t flags) noexcept;
-    /// \brief Returns the minimal key size in bytes for specified keys mode.
-    static inline size_t key_min(key_mode mode) noexcept;
-    /// \brief Returns the maximal key size in bytes for specified page size and
-    /// database flags.
-    static inline size_t key_max(intptr_t pagesize, MDBX_db_flags_t flags);
-    /// \brief Returns the maximal key size in bytes for specified page size and
-    /// keys mode.
-    static inline size_t key_max(intptr_t pagesize, key_mode mode);
-    /// \brief Returns the maximal key size in bytes for given environment and
-    /// database flags.
-    static inline size_t key_max(const env &, MDBX_db_flags_t flags);
-    /// \brief Returns the maximal key size in bytes for given environment and
-    /// keys mode.
-    static inline size_t key_max(const env &, key_mode mode);
-    /// \brief Returns the minimal values size in bytes for specified database
-    /// flags.
-    static inline size_t value_min(MDBX_db_flags_t flags) noexcept;
-    /// \brief Returns the minimal values size in bytes for specified values
-    /// mode.
-    static inline size_t value_min(value_mode) noexcept;
-    /// \brief Returns the maximal value size in bytes for specified page size
-    /// and database flags.
-    static inline size_t value_max(intptr_t pagesize, MDBX_db_flags_t flags);
-    /// \brief Returns the maximal value size in bytes for specified page size
-    /// and values mode.
-    static inline size_t value_max(intptr_t pagesize, value_mode);
-    /// \brief Returns the maximal value size in bytes for given environment and
-    /// database flags.
-    static inline size_t value_max(const env &, MDBX_db_flags_t flags);
-    /// \brief Returns the maximal value size in bytes for specified page size
-    /// and values mode.
-    static inline size_t value_max(const env &, value_mode);
-    /// \brief Returns the maximal write transaction size (i.e. limit for
-    /// summary volume of dirty pages) in bytes for specified page size.
-    static inline size_t transaction_size_max(intptr_t pagesize);
-  };
-
-  /// \brief Returns the minimal database size in bytes for the environment.
-  size_t dbsize_min() const { return limits::dbsize_min(this->get_pagesize()); }
-  /// \brief Returns the maximal database size in bytes for the environment.
-  size_t dbsize_max() const { return limits::dbsize_max(this->get_pagesize()); }
-  /// \brief Returns the minimal key size in bytes for specified keys mode.
-  size_t key_min(key_mode mode) const noexcept { return limits::key_min(mode); }
-  /// \brief Returns the maximal key size in bytes for specified keys mode.
-  size_t key_max(key_mode mode) const { return limits::key_max(*this, mode); }
-  /// \brief Returns the minimal value size in bytes for specified values mode.
-  size_t value_min(value_mode mode) const noexcept {
-    return limits::value_min(mode);
-  }
-  /// \brief Returns the maximal value size in bytes for specified values mode.
-  size_t value_max(value_mode mode) const {
-    return limits::value_max(*this, mode);
-  }
-  /// \brief Returns the maximal write transaction size (i.e. limit for summary
-  /// volume of dirty pages) in bytes.
-  size_t transaction_size_max() const {
-    return limits::transaction_size_max(this->get_pagesize());
-  }
-
-  /// \brief Make a copy (backup) of an existing environment to the specified
-  /// path.
-#ifdef MDBX_STD_FILESYSTEM_PATH
-  env &copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
-            bool force_dynamic_size = false);
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-#if defined(_WIN32) || defined(_WIN64)
-  env &copy(const ::std::wstring &destination, bool compactify,
-            bool force_dynamic_size = false);
-#endif /* Windows */
-  env &copy(const ::std::string &destination, bool compactify,
-            bool force_dynamic_size = false);
-
-  /// \brief Copy an environment to the specified file descriptor.
-  env &copy(filehandle fd, bool compactify, bool force_dynamic_size = false);
-
-  /// \brief Deletion modes for \ref remove().
-  enum remove_mode {
-    /// \brief Just delete the environment's files and directory if any.
-    /// \note On POSIX systems, processes already working with the database will
-    /// continue to work without interference until it close the environment.
-    /// \note On Windows, the behavior of `just_remove` is different
-    /// because the system does not support deleting files that are currently
-    /// memory mapped.
-    just_remove = MDBX_ENV_JUST_DELETE,
-    /// \brief Make sure that the environment is not being used by other
-    /// processes, or return an error otherwise.
-    ensure_unused = MDBX_ENV_ENSURE_UNUSED,
-    /// \brief Wait until other processes closes the environment before
-    /// deletion.
-    wait_for_unused = MDBX_ENV_WAIT_FOR_UNUSED
-  };
-
-  /// \brief Removes the environment's files in a proper and multiprocess-safe
-  /// way.
-#ifdef MDBX_STD_FILESYSTEM_PATH
-  static bool remove(const MDBX_STD_FILESYSTEM_PATH &,
-                     const remove_mode mode = just_remove);
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-#if defined(_WIN32) || defined(_WIN64)
-  static bool remove(const ::std::wstring &,
-                     const remove_mode mode = just_remove);
-#endif /* Windows */
-  static bool remove(const ::std::string &,
-                     const remove_mode mode = just_remove);
-
-  /// \brief Statistics for a database in the MDBX environment.
-  using stat = ::MDBX_stat;
-
-  /// \brief Information about the environment.
-  using info = ::MDBX_envinfo;
-
-  /// \brief Returns snapshot statistics about the MDBX environment.
-  inline stat get_stat() const;
-
-  /// \brief Returns pagesize of this MDBX environment.
-  size_t get_pagesize() const { return get_stat().ms_psize; }
-
-  /// \brief Return snapshot information about the MDBX environment.
-  inline info get_info() const;
-
-  /// \brief Return statistics about the MDBX environment accordingly to the
-  /// specified transaction.
-  inline stat get_stat(const txn &) const;
-
-  /// \brief Return information about the MDBX environment accordingly to the
-  /// specified transaction.
-  inline info get_info(const txn &) const;
-
-  /// \brief Returns the file descriptor for the DXB file of MDBX environment.
-  inline filehandle get_filehandle() const;
-
-  /// \brief Return the path that was used for opening the environment.
-  path get_path() const;
-
-  /// Returns environment flags.
-  inline MDBX_env_flags_t get_flags() const;
-
-  /// \brief Returns the maximum number of threads/reader slots for the
-  /// environment.
-  inline unsigned max_readers() const;
-
-  /// \brief Returns the maximum number of named databases for the environment.
-  inline unsigned max_maps() const;
-
-  /// \brief Returns the application context associated with the environment.
-  inline void *get_context() const noexcept;
-
-  /// \brief Sets the application context associated with the environment.
-  inline env &set_context(void *);
-
-  /// \brief Sets threshold to force flush the data buffers to disk, for
-  /// non-sync durability modes.
-  ///
-  /// The threshold value affects all processes which operates with given
-  /// environment until the last process close environment or a new value will
-  /// be settled.
-  /// Data is always written to disk when \ref txn_managed::commit() is called,
-  /// but the operating system may keep it buffered. MDBX always flushes the OS
-  /// buffers upon commit as well, unless the environment was opened with \ref
-  /// whole_fragile, \ref lazy_weak_tail or in part \ref
-  /// half_synchronous_weak_last. The default is 0, than mean no any threshold
-  /// checked, and no additional flush will be made.
-  ///
-  inline env &set_sync_threshold(size_t bytes);
-
-  /// \brief Sets relative period since the last unsteady commit to force flush
-  /// the data buffers to disk, for non-sync durability modes.
-  ///
-  /// The relative period value affects all processes which operates with given
-  /// environment until the last process close environment or a new value will
-  /// be settled.
-  /// Data is always written to disk when \ref txn_managed::commit() is called,
-  /// but the operating system may keep it buffered. MDBX always flushes the OS
-  /// buffers upon commit as well, unless the environment was opened with \ref
-  /// whole_fragile, \ref lazy_weak_tail or in part \ref
-  /// half_synchronous_weak_last. Settled period don't checked asynchronously,
-  /// but only by the \ref txn_managed::commit() and \ref env::sync_to_disk()
-  /// functions. Therefore, in cases where transactions are committed
-  /// infrequently and/or irregularly, polling by \ref env::poll_sync_to_disk()
-  /// may be a reasonable solution to timeout enforcement. The default is 0,
-  /// than mean no any timeout checked, and no additional flush will be made.
-  ///
-  /// \param [in] seconds_16dot16  The period in 1/65536 of second when a
-  /// synchronous flush would be made since the last unsteady commit.
-  inline env &set_sync_period(unsigned seconds_16dot16);
-
-  /// \brief Sets relative period since the last unsteady commit to force flush
-  /// the data buffers to disk, for non-sync durability modes.
-  ///
-  /// The relative period value affects all processes which operates with given
-  /// environment until the last process close environment or a new value will
-  /// be settled.
-  /// Data is always written to disk when \ref txn_managed::commit() is called,
-  /// but the operating system may keep it buffered. MDBX always flushes the OS
-  /// buffers upon commit as well, unless the environment was opened with \ref
-  /// whole_fragile, \ref lazy_weak_tail or in part \ref
-  /// half_synchronous_weak_last. Settled period don't checked asynchronously,
-  /// but only by the \ref txn_managed::commit() and \ref env::sync_to_disk()
-  /// functions. Therefore, in cases where transactions are committed
-  /// infrequently and/or irregularly, polling by \ref env::poll_sync_to_disk()
-  /// may be a reasonable solution to timeout enforcement. The default is 0,
-  /// than mean no any timeout checked, and no additional flush will be made.
-  ///
-  /// \param [in] seconds  The period in second when a synchronous flush would
-  /// be made since the last unsteady commit.
-  inline env &set_sync_period(double seconds);
-
-  /// \brief Alter environment flags.
-  inline env &alter_flags(MDBX_env_flags_t flags, bool on_off);
-
-  /// \brief Set all size-related parameters of environment.
-  inline env &set_geometry(const geometry &size);
-
-  /// \brief Flush the environment data buffers.
-  /// \return `True` if sync done or no data to sync, or `false` if the
-  /// environment is busy by other thread or none of the thresholds are reached.
-  inline bool sync_to_disk(bool force = true, bool nonblock = false);
-
-  /// \brief Performs non-blocking polling of sync-to-disk thresholds.
-  /// \return `True` if sync done or no data to sync, or `false` if the
-  /// environment is busy by other thread or none of the thresholds are reached.
-  bool poll_sync_to_disk() { return sync_to_disk(false, true); }
-
-  /// \brief Close a key-value map (aka sub-database) handle. Normally
-  /// unnecessary.
-  ///
-  /// Closing a database handle is not necessary, but lets \ref txn::open_map()
-  /// reuse the handle value. Usually it's better to set a bigger
-  /// \ref env::operate_parameters::max_maps, unless that value would be
-  /// large.
-  ///
-  /// \note Use with care.
-  /// This call is synchronized via mutex with other calls \ref close_map(), but
-  /// NOT with other transactions running by other threads. The "next" version
-  /// of libmdbx (\ref MithrilDB) will solve this issue.
-  ///
-  /// Handles should only be closed if no other threads are going to reference
-  /// the database handle or one of its cursors any further. Do not close a
-  /// handle if an existing transaction has modified its database. Doing so can
-  /// cause misbehavior from database corruption to errors like
-  /// \ref MDBX_BAD_DBI (since the DB name is gone).
-  inline void close_map(const map_handle &);
-
-  /// \brief Reader information
-  struct reader_info {
-    int slot;                 ///< The reader lock table slot number.
-    mdbx_pid_t pid;           ///< The reader process ID.
-    mdbx_tid_t thread;        ///< The reader thread ID.
-    uint64_t transaction_id;  ///< The ID of the transaction being read,
-                              ///< i.e. the MVCC-snapshot number.
-    uint64_t transaction_lag; ///< The lag from a recent MVCC-snapshot,
-                              ///< i.e. the number of committed write
-                              /// transactions since the current read
-                              /// transaction started.
-    size_t bytes_used; ///< The number of last used page in the MVCC-snapshot
-                       ///< which being read, i.e. database file can't shrinked
-                       ///< beyond this.
-    size_t bytes_retained; ///< The total size of the database pages that
-                           ///< were retired by committed write transactions
-                           ///< after the reader's MVCC-snapshot, i.e. the space
-                           ///< which would be freed after the Reader releases
-                           ///< the MVCC-snapshot for reuse by completion read
-                           ///< transaction.
-
-    MDBX_CXX11_CONSTEXPR reader_info(int slot, mdbx_pid_t pid,
-                                     mdbx_tid_t thread, uint64_t txnid,
-                                     uint64_t lag, size_t used,
-                                     size_t retained) noexcept;
-  };
-
-  /// \brief Enumerate readers.
-  ///
-  /// The VISITOR class must have `int operator(const reader_info&, int serial)`
-  /// which should return \ref continue_loop (zero) to continue enumeration,
-  /// or any non-zero value to exit.
-  ///
-  /// \returns The last value returned from visitor' functor.
-  template <typename VISITOR> inline int enumerate_readers(VISITOR &visitor);
-
-  /// \brief Checks for stale readers in the lock table and
-  /// return number of cleared slots.
-  inline unsigned check_readers();
-
-  /// \brief Sets a Handle-Slow-Readers callback to resolve database
-  /// full/overflow issue due to a reader(s) which prevents the old data from
-  /// being recycled.
-  ///
-  /// Such callback will be triggered in a case where there is not enough free
-  /// space in the database due to long read transaction(s) which impedes
-  /// reusing the pages of an old MVCC snapshot(s).
-  ///
-  /// Using this callback you can choose how to resolve the situation:
-  ///  - abort the write transaction with an error;
-  ///  - wait for the read transaction(s) to complete;
-  ///  - notify a thread performing a long-lived read transaction
-  ///    and wait for an effect;
-  ///  - kill the thread or whole process that performs the long-lived read
-  ///    transaction;
-  ///
-  /// \see long-lived-read
-  inline env &set_HandleSlowReaders(MDBX_hsr_func *);
-
-  /// \brief Returns the current Handle-Slow-Readers callback used to resolve
-  /// database full/overflow issue due to a reader(s) which prevents the old
-  /// data from being recycled.
-  /// \see set_HandleSlowReaders()
-  inline MDBX_hsr_func *get_HandleSlowReaders() const noexcept;
-
-  /// \brief Starts read (read-only) transaction.
-  inline txn_managed start_read() const;
-
-  /// \brief Creates but not start read transaction.
-  inline txn_managed prepare_read() const;
-
-  /// \brief Starts write (read-write) transaction.
-  inline txn_managed start_write(bool dont_wait = false);
-
-  /// \brief Tries to start write (read-write) transaction without blocking.
-  inline txn_managed try_start_write();
-};
-
-/// \brief Managed database environment.
-///
-/// As other managed classes, `env_managed` destroys the represented underlying
-/// object from the own class destructor, but disallows copying and assignment
-/// for instances.
-///
-/// An environment supports multiple key-value databases (aka key-value spaces
-/// or tables), all residing in the same shared-memory map.
-class LIBMDBX_API_TYPE env_managed : public env {
-  using inherited = env;
-  /// delegated constructor for RAII
-  MDBX_CXX11_CONSTEXPR env_managed(MDBX_env *ptr) noexcept : inherited(ptr) {}
-  void setup(unsigned max_maps, unsigned max_readers = 0);
-
-public:
-  MDBX_CXX11_CONSTEXPR env_managed() noexcept = default;
-
-  /// \brief Open existing database.
-#ifdef MDBX_STD_FILESYSTEM_PATH
-  env_managed(const MDBX_STD_FILESYSTEM_PATH &, const operate_parameters &,
-              bool accede = true);
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-#if defined(_WIN32) || defined(_WIN64)
-  env_managed(const ::std::wstring &, const operate_parameters &,
-              bool accede = true);
-#endif /* Windows */
-  env_managed(const ::std::string &, const operate_parameters &,
-              bool accede = true);
-
-  /// \brief Additional parameters for creating a new database.
-  struct create_parameters {
-    env::geometry geometry;
-    mdbx_mode_t file_mode_bits{0640};
-    bool use_subdirectory{false};
-    MDBX_CXX11_CONSTEXPR create_parameters() noexcept = default;
-    create_parameters(const create_parameters &) noexcept = default;
-  };
-
-  /// \brief Create new or open existing database.
-#ifdef MDBX_STD_FILESYSTEM_PATH
-  env_managed(const MDBX_STD_FILESYSTEM_PATH &, const create_parameters &,
-              const operate_parameters &, bool accede = true);
-#endif /* MDBX_STD_FILESYSTEM_PATH */
-#if defined(_WIN32) || defined(_WIN64)
-  env_managed(const ::std::wstring &, const create_parameters &,
-              const operate_parameters &, bool accede = true);
-#endif /* Windows */
-  env_managed(const ::std::string &, const create_parameters &,
-              const operate_parameters &, bool accede = true);
-
-  /// \brief Explicitly closes the environment and release the memory map.
-  ///
-  /// Only a single thread may call this function. All transactions, databases,
-  /// and cursors must already be closed before calling this function. Attempts
-  /// to use any such handles after calling this function will cause a
-  /// `SIGSEGV`. The environment handle will be freed and must not be used again
-  /// after this call.
-  ///
-  /// \param [in] dont_sync  A dont'sync flag, if non-zero the last checkpoint
-  /// will be kept "as is" and may be still "weak" in the \ref lazy_weak_tail
-  /// or \ref whole_fragile modes. Such "weak" checkpoint will be ignored
-  /// on opening next time, and transactions since the last non-weak checkpoint
-  /// (meta-page update) will rolledback for consistency guarantee.
-  void close(bool dont_sync = false);
-
-  env_managed(env_managed &&) = default;
-  env_managed &operator=(env_managed &&other) {
-    if (MDBX_UNLIKELY(handle_))
-      MDBX_CXX20_UNLIKELY {
-        assert(handle_ != other.handle_);
-        close();
-      }
-    inherited::operator=(std::move(other));
-    return *this;
-  }
-  env_managed(const env_managed &) = delete;
-  env_managed &operator=(const env_managed &) = delete;
-  virtual ~env_managed() noexcept;
-};
-
-/// \brief Unmanaged database transaction.
-///
-/// Like other unmanaged classes, `txn` allows copying and assignment for
-/// instances, but does not destroys the represented underlying object from the
-/// own class destructor.
-///
-/// All database operations require a transaction handle. Transactions may be
-/// read-only or read-write.
-class LIBMDBX_API_TYPE txn {
-protected:
-  friend class cursor;
-  MDBX_txn *handle_{nullptr};
-  MDBX_CXX11_CONSTEXPR txn(MDBX_txn *ptr) noexcept;
-
-public:
-  MDBX_CXX11_CONSTEXPR txn() noexcept = default;
-  txn(const txn &) noexcept = default;
-  inline txn &operator=(txn &&other) noexcept;
-  inline txn(txn &&other) noexcept;
-  inline ~txn() noexcept;
-
-  MDBX_CXX14_CONSTEXPR operator bool() const noexcept;
-  MDBX_CXX14_CONSTEXPR operator const MDBX_txn *() const;
-  MDBX_CXX14_CONSTEXPR operator MDBX_txn *();
-  friend MDBX_CXX11_CONSTEXPR bool operator==(const txn &a,
-                                              const txn &b) noexcept;
-  friend MDBX_CXX11_CONSTEXPR bool operator!=(const txn &a,
-                                              const txn &b) noexcept;
-
-  /// \brief Returns the transaction's environment.
-  inline ::mdbx::env env() const noexcept;
-  /// \brief Returns transaction's flags.
-  inline MDBX_txn_flags_t flags() const;
-  /// \brief Return the transaction's ID.
-  inline uint64_t id() const;
-
-  /// \brief Checks whether the given data is on a dirty page.
-  inline bool is_dirty(const void *ptr) const;
-
-  /// \brief Checks whether the transaction is read-only.
-  bool is_readonly() const { return (flags() & MDBX_TXN_RDONLY) != 0; }
-
-  /// \brief Checks whether the transaction is read-write.
-  bool is_readwrite() const { return (flags() & MDBX_TXN_RDONLY) == 0; }
-
-  using info = ::MDBX_txn_info;
-  /// \brief Returns information about the MDBX transaction.
-  inline info get_info(bool scan_reader_lock_table = false) const;
-
-  /// \brief Returns maximal write transaction size (i.e. limit for summary
-  /// volume of dirty pages) in bytes.
-  size_t size_max() const { return env().transaction_size_max(); }
-
-  /// \brief Returns current write transaction size (i.e.summary volume of dirty
-  /// pages) in bytes.
-  size_t size_current() const {
-    assert(is_readwrite());
-    return size_t(get_info().txn_space_dirty);
-  }
-
-  //----------------------------------------------------------------------------
-
-  /// \brief Reset a read-only transaction.
-  inline void reset_reading();
-
-  /// \brief Renew a read-only transaction.
-  inline void renew_reading();
-
-  /// \brief Start nested write transaction.
-  txn_managed start_nested();
-
-  /// \brief Opens cursor for specified key-value map handle.
-  inline cursor_managed open_cursor(map_handle map);
-
-  /// \brief Open existing key-value map.
-  inline map_handle open_map(
-      const char *name,
-      const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual,
-      const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) const;
-  /// \brief Open existing key-value map.
-  inline map_handle open_map(
-      const ::std::string &name,
-      const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual,
-      const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) const;
-
-  /// \brief Create new or open existing key-value map.
-  inline map_handle
-  create_map(const char *name,
-             const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual,
-             const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single);
-  /// \brief Create new or open existing key-value map.
-  inline map_handle
-  create_map(const ::std::string &name,
-             const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual,
-             const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single);
-
-  /// \brief Drops key-value map using handle.
-  inline void drop_map(map_handle map);
-  /// \brief Drops key-value map using name.
-  /// \return `True` if the key-value map existed and was deleted, either
-  /// `false` if the key-value map did not exist and there is nothing to delete.
-  bool drop_map(const char *name, bool throw_if_absent = false);
-  /// \brief Drop key-value map.
-  /// \return `True` if the key-value map existed and was deleted, either
-  /// `false` if the key-value map did not exist and there is nothing to delete.
-  inline bool drop_map(const ::std::string &name, bool throw_if_absent = false);
-
-  /// \brief Clear key-value map.
-  inline void clear_map(map_handle map);
-  /// \return `True` if the key-value map existed and was cleared, either
-  /// `false` if the key-value map did not exist and there is nothing to clear.
-  bool clear_map(const char *name, bool throw_if_absent = false);
-  /// \return `True` if the key-value map existed and was cleared, either
-  /// `false` if the key-value map did not exist and there is nothing to clear.
-  inline bool clear_map(const ::std::string &name,
-                        bool throw_if_absent = false);
-
-  using map_stat = ::MDBX_stat;
-  /// \brief Returns statistics for a sub-database.
-  inline map_stat get_map_stat(map_handle map) const;
-  /// \brief Returns depth (bitmask) information of nested dupsort (multi-value)
-  /// B+trees for given database.
-  inline uint32_t get_tree_deepmask(map_handle map) const;
-  /// \brief Returns information about key-value map (aka sub-database) handle.
-  inline map_handle::info get_handle_info(map_handle map) const;
-
-  using canary = ::MDBX_canary;
-  /// \brief Set integers markers (aka "canary") associated with the
-  /// environment.
-  inline txn &put_canary(const canary &);
-  /// \brief Returns fours integers markers (aka "canary") associated with the
-  /// environment.
-  inline canary get_canary() const;
-
-  /// Reads sequence generator associated with a key-value map (aka
-  /// sub-database).
-  inline uint64_t sequence(map_handle map) const;
-  /// \brief Reads and increment sequence generator associated with a key-value
-  /// map (aka sub-database).
-  inline uint64_t sequence(map_handle map, uint64_t increment);
-
-  /// \brief Compare two keys according to a particular key-value map (aka
-  /// sub-database).
-  inline int compare_keys(map_handle map, const slice &a,
-                          const slice &b) const noexcept;
-  /// \brief Compare two values according to a particular key-value map (aka
-  /// sub-database).
-  inline int compare_values(map_handle map, const slice &a,
-                            const slice &b) const noexcept;
-  /// \brief Compare keys of two pairs according to a particular key-value map
-  /// (aka sub-database).
-  inline int compare_keys(map_handle map, const pair &a,
-                          const pair &b) const noexcept;
-  /// \brief Compare values of two pairs according to a particular key-value map
-  /// (aka sub-database).
-  inline int compare_values(map_handle map, const pair &a,
-                            const pair &b) const noexcept;
-
-  /// \brief Get value by key from a key-value map (aka sub-database).
-  inline slice get(map_handle map, const slice &key) const;
-  /// \brief Get first of multi-value and values count by key from a key-value
-  /// multimap (aka sub-database).
-  inline slice get(map_handle map, slice key, size_t &values_count) const;
-  /// \brief Get value by key from a key-value map (aka sub-database).
-  inline slice get(map_handle map, const slice &key,
-                   const slice &value_at_absence) const;
-  /// \brief Get first of multi-value and values count by key from a key-value
-  /// multimap (aka sub-database).
-  inline slice get(map_handle map, slice key, size_t &values_count,
-                   const slice &value_at_absence) const;
-  /// \brief Get value for equal or great key from a database.
-  /// \return Bundle of key-value pair and boolean flag,
-  /// which will be `true` if the exact key was found and `false` otherwise.
-  inline pair_result get_equal_or_great(map_handle map, const slice &key) const;
-  /// \brief Get value for equal or great key from a database.
-  /// \return Bundle of key-value pair and boolean flag,
-  /// which will be `true` if the exact key was found and `false` otherwise.
-  inline pair_result get_equal_or_great(map_handle map, const slice &key,
-                                        const slice &value_at_absence) const;
-
-  inline MDBX_error_t put(map_handle map, const slice &key, slice *value,
-                          MDBX_put_flags_t flags) noexcept;
-  inline void put(map_handle map, const slice &key, slice value, put_mode mode);
-  inline void insert(map_handle map, const slice &key, slice value);
-  inline value_result try_insert(map_handle map, const slice &key, slice value);
-  inline slice insert_reserve(map_handle map, const slice &key,
-                              size_t value_length);
-  inline value_result try_insert_reserve(map_handle map, const slice &key,
-                                         size_t value_length);
-
-  inline void upsert(map_handle map, const slice &key, const slice &value);
-  inline slice upsert_reserve(map_handle map, const slice &key,
-                              size_t value_length);
-
-  inline void update(map_handle map, const slice &key, const slice &value);
-  inline bool try_update(map_handle map, const slice &key, const slice &value);
-  inline slice update_reserve(map_handle map, const slice &key,
-                              size_t value_length);
-  inline value_result try_update_reserve(map_handle map, const slice &key,
-                                         size_t value_length);
-
-  /// \brief Removes all values for given key.
-  inline bool erase(map_handle map, const slice &key);
-
-  /// \brief Removes the particular multi-value entry of the key.
-  inline bool erase(map_handle map, const slice &key, const slice &value);
-
-  /// \brief Replaces the particular multi-value of the key with a new value.
-  inline void replace(map_handle map, const slice &key, slice old_value,
-                      const slice &new_value);
-
-  /// \brief Removes and return a value of the key.
-  template <class ALLOCATOR, typename CAPACITY_POLICY>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  extract(map_handle map, const slice &key,
-          const typename buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type &
-              allocator = buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type());
-
-  /// \brief Replaces and returns a value of the key with new one.
-  template <class ALLOCATOR, typename CAPACITY_POLICY>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY>
-  replace(map_handle map, const slice &key, const slice &new_value,
-          const typename buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type &
-              allocator = buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type());
-
-  template <class ALLOCATOR, typename CAPACITY_POLICY>
-  inline buffer<ALLOCATOR, CAPACITY_POLICY> replace_reserve(
-      map_handle map, const slice &key, slice &new_value,
-      const typename buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type
-          &allocator = buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type());
-
-  /// \brief Adding a key-value pair, provided that ascending order of the keys
-  /// and (optionally) values are preserved.
-  ///
-  /// Instead of splitting the full b+tree pages, the data will be placed on new
-  /// ones. Thus appending is about two times faster than insertion, and the
-  /// pages will be filled in completely mostly but not half as after splitting
-  /// ones. On the other hand, any subsequent insertion or update with an
-  /// increase in the length of the value will be twice as slow, since it will
-  /// require splitting already filled pages.
-  ///
-  /// \param [in] map   A map handle to append
-  /// \param [in] key   A key to be append
-  /// \param [in] value A value to store with the key
-  /// \param [in] multivalue_order_preserved
-  /// If `multivalue_order_preserved == true` then the same rules applied for
-  /// to pages of nested b+tree of multimap's values.
-  inline void append(map_handle map, const slice &key, const slice &value,
-                     bool multivalue_order_preserved = true);
-
-  size_t put_multiple(map_handle map, const slice &key,
-                      const size_t value_length, const void *values_array,
-                      size_t values_count, put_mode mode,
-                      bool allow_partial = false);
-  template <typename VALUE>
-  void put_multiple(map_handle map, const slice &key,
-                    const ::std::vector<VALUE> &vector, put_mode mode) {
-    put_multiple(map, key, sizeof(VALUE), vector.data(), vector.size(), mode,
-                 false);
-  }
-
-  inline ptrdiff_t estimate(map_handle map, pair from, pair to) const;
-  inline ptrdiff_t estimate(map_handle map, slice from, slice to) const;
-  inline ptrdiff_t estimate_from_first(map_handle map, slice to) const;
-  inline ptrdiff_t estimate_to_last(map_handle map, slice from) const;
-};
-
-/// \brief Managed database transaction.
-///
-/// As other managed classes, `txn_managed` destroys the represented underlying
-/// object from the own class destructor, but disallows copying and assignment
-/// for instances.
-///
-/// All database operations require a transaction handle. Transactions may be
-/// read-only or read-write.
-class LIBMDBX_API_TYPE txn_managed : public txn {
-  using inherited = txn;
-  friend class env;
-  friend class txn;
-  /// delegated constructor for RAII
-  MDBX_CXX11_CONSTEXPR txn_managed(MDBX_txn *ptr) noexcept : inherited(ptr) {}
-
-public:
-  MDBX_CXX11_CONSTEXPR txn_managed() noexcept = default;
-  txn_managed(txn_managed &&) = default;
-  txn_managed &operator=(txn_managed &&other) {
-    if (MDBX_UNLIKELY(handle_))
-      MDBX_CXX20_UNLIKELY {
-        assert(handle_ != other.handle_);
-        abort();
-      }
-    inherited::operator=(std::move(other));
-    return *this;
-  }
-  txn_managed(const txn_managed &) = delete;
-  txn_managed &operator=(const txn_managed &) = delete;
-  ~txn_managed() noexcept;
-
-  //----------------------------------------------------------------------------
-
-  /// \brief Abandon all the operations of the transaction instead of saving
-  /// them.
-  void abort();
-
-  /// \brief Commit all the operations of a transaction into the database.
-  void commit();
-};
-
-/// \brief Unmanaged cursor.
-///
-/// Like other unmanaged classes, `cursor` allows copying and assignment for
-/// instances, but does not destroys the represented underlying object from the
-/// own class destructor.
-///
-/// \copydetails MDBX_cursor
-class LIBMDBX_API_TYPE cursor {
-protected:
-  MDBX_cursor *handle_{nullptr};
-  MDBX_CXX11_CONSTEXPR cursor(MDBX_cursor *ptr) noexcept;
-
-public:
-  MDBX_CXX11_CONSTEXPR cursor() noexcept = default;
-  cursor(const cursor &) noexcept = default;
-  inline cursor &operator=(cursor &&other) noexcept;
-  inline cursor(cursor &&other) noexcept;
-  inline ~cursor() noexcept;
-  MDBX_CXX14_CONSTEXPR operator bool() const noexcept;
-  MDBX_CXX14_CONSTEXPR operator const MDBX_cursor *() const;
-  MDBX_CXX14_CONSTEXPR operator MDBX_cursor *();
-  friend MDBX_CXX11_CONSTEXPR bool operator==(const cursor &a,
-                                              const cursor &b) noexcept;
-  friend MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
-                                              const cursor &b) noexcept;
-
-  enum move_operation {
-    first = MDBX_FIRST,
-    last = MDBX_LAST,
-    next = MDBX_NEXT,
-    previous = MDBX_PREV,
-    get_current = MDBX_GET_CURRENT,
-
-    multi_prevkey_lastvalue = MDBX_PREV_NODUP,
-    multi_currentkey_firstvalue = MDBX_FIRST_DUP,
-    multi_currentkey_prevvalue = MDBX_PREV_DUP,
-    multi_currentkey_nextvalue = MDBX_NEXT_DUP,
-    multi_currentkey_lastvalue = MDBX_LAST_DUP,
-    multi_nextkey_firstvalue = MDBX_NEXT_NODUP,
-
-    multi_find_pair = MDBX_GET_BOTH,
-    multi_exactkey_lowerboundvalue = MDBX_GET_BOTH_RANGE,
-
-    find_key = MDBX_SET,
-    key_exact = MDBX_SET_KEY,
-    key_lowerbound = MDBX_SET_RANGE
-  };
-
-  struct move_result : public pair_result {
-    inline move_result(const cursor &cursor, bool throw_notfound);
-    inline move_result(cursor &cursor, move_operation operation,
-                       bool throw_notfound);
-    inline move_result(cursor &cursor, move_operation operation,
-                       const slice &key, bool throw_notfound);
-    inline move_result(cursor &cursor, move_operation operation,
-                       const slice &key, const slice &value,
-                       bool throw_notfound);
-    move_result(const move_result &) noexcept = default;
-    move_result &operator=(const move_result &) noexcept = default;
-  };
-
-protected:
-  inline bool move(move_operation operation, MDBX_val *key, MDBX_val *value,
-                   bool throw_notfound) const
-      /* fake const, i.e. for some operations */;
-  inline ptrdiff_t estimate(move_operation operation, MDBX_val *key,
-                            MDBX_val *value) const;
-
-public:
-  inline move_result move(move_operation operation, bool throw_notfound);
-  inline move_result to_first(bool throw_notfound = true);
-  inline move_result to_previous(bool throw_notfound = true);
-  inline move_result to_previous_last_multi(bool throw_notfound = true);
-  inline move_result to_current_first_multi(bool throw_notfound = true);
-  inline move_result to_current_prev_multi(bool throw_notfound = true);
-  inline move_result current(bool throw_notfound = true) const;
-  inline move_result to_current_next_multi(bool throw_notfound = true);
-  inline move_result to_current_last_multi(bool throw_notfound = true);
-  inline move_result to_next_first_multi(bool throw_notfound = true);
-  inline move_result to_next(bool throw_notfound = true);
-  inline move_result to_last(bool throw_notfound = true);
-
-  inline move_result move(move_operation operation, const slice &key,
-                          bool throw_notfound);
-  inline move_result find(const slice &key, bool throw_notfound = true);
-  inline move_result lower_bound(const slice &key, bool throw_notfound = true);
-
-  inline move_result move(move_operation operation, const slice &key,
-                          const slice &value, bool throw_notfound);
-  inline move_result find_multivalue(const slice &key, const slice &value,
-                                     bool throw_notfound = true);
-  inline move_result lower_bound_multivalue(const slice &key,
-                                            const slice &value,
-                                            bool throw_notfound = false);
-
-  inline bool seek(const slice &key);
-  inline bool move(move_operation operation, slice &key, slice &value,
-                   bool throw_notfound);
-
-  /// \brief Return count of duplicates for current key.
-  inline size_t count_multivalue() const;
-
-  inline bool eof() const;
-  inline bool on_first() const;
-  inline bool on_last() const;
-  inline ptrdiff_t estimate(slice key, slice value) const;
-  inline ptrdiff_t estimate(slice key) const;
-  inline ptrdiff_t estimate(move_operation operation) const;
-
-  //----------------------------------------------------------------------------
-
-  /// \brief Renew/bind a cursor with a new transaction and previously used
-  /// key-value map handle.
-  inline void renew(::mdbx::txn &txn);
-
-  /// \brief Bind/renew a cursor with a new transaction and specified key-value
-  /// map handle.
-  inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle);
-
-  /// \brief Returns the cursor's transaction.
-  inline ::mdbx::txn txn() const;
-  inline map_handle map() const;
-
-  inline operator ::mdbx::txn() const { return txn(); }
-  inline operator ::mdbx::map_handle() const { return map(); }
-
-  inline MDBX_error_t put(const slice &key, slice *value,
-                          MDBX_put_flags_t flags) noexcept;
-  inline void insert(const slice &key, slice value);
-  inline value_result try_insert(const slice &key, slice value);
-  inline slice insert_reserve(const slice &key, size_t value_length);
-  inline value_result try_insert_reserve(const slice &key, size_t value_length);
-
-  inline void upsert(const slice &key, const slice &value);
-  inline slice upsert_reserve(const slice &key, size_t value_length);
-
-  inline void update(const slice &key, const slice &value);
-  inline bool try_update(const slice &key, const slice &value);
-  inline slice update_reserve(const slice &key, size_t value_length);
-  inline value_result try_update_reserve(const slice &key, size_t value_length);
-
-  /// \brief Removes single key-value pair or all multi-values at the current
-  /// cursor position.
-  inline bool erase(bool whole_multivalue = false);
-
-  /// \brief Seeks and removes first value or whole multi-value of the given
-  /// key.
-  /// \return `True` if the key is found and a value(s) is removed.
-  inline bool erase(const slice &key, bool whole_multivalue = true);
-
-  /// \brief Seeks and removes the particular multi-value entry of the key.
-  /// \return `True` if the given key-value pair is found and removed.
-  inline bool erase(const slice &key, const slice &value);
-};
-
-/// \brief Managed cursor.
-///
-/// As other managed classes, `cursor_managed` destroys the represented
-/// underlying object from the own class destructor, but disallows copying and
-/// assignment for instances.
-///
-/// \copydetails MDBX_cursor
-class LIBMDBX_API_TYPE cursor_managed : public cursor {
-  using inherited = cursor;
-  friend class txn;
-  /// delegated constructor for RAII
-  MDBX_CXX11_CONSTEXPR cursor_managed(MDBX_cursor *ptr) noexcept
-      : inherited(ptr) {}
-
-public:
-  /// \brief Creates a new managed cursor with underlying object.
-  cursor_managed() : cursor_managed(::mdbx_cursor_create(nullptr)) {
-    if (MDBX_UNLIKELY(!handle_))
-      MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_ENOMEM);
-  }
-
-  /// \brief Explicitly closes the cursor.
-  void close();
-
-  cursor_managed(cursor_managed &&) = default;
-  cursor_managed &operator=(cursor_managed &&other) {
-    if (MDBX_UNLIKELY(handle_))
-      MDBX_CXX20_UNLIKELY {
-        assert(handle_ != other.handle_);
-        close();
-      }
-    inherited::operator=(std::move(other));
-    return *this;
-  }
-
-  cursor_managed(const cursor_managed &) = delete;
-  cursor_managed &operator=(const cursor_managed &) = delete;
-  ~cursor_managed() noexcept { ::mdbx_cursor_close(handle_); }
-};
-
-//------------------------------------------------------------------------------
-
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &, const slice &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &, const pair &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &, const pair_result &);
-template <class ALLOCATOR, typename CAPACITY_POLICY>
-inline ::std::ostream &
-operator<<(::std::ostream &out, const buffer<ALLOCATOR, CAPACITY_POLICY> &it) {
-  return (it.is_freestanding()
-              ? out << "buf-" << it.headroom() << "." << it.tailroom()
-              : out << "ref-")
-         << it.slice();
-}
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const env::geometry::size &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &, const env::geometry &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const env::operate_parameters &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &, const env::mode &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const env::durability &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const env::reclaiming_options &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const env::operate_options &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const env_managed::create_parameters &);
-
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const MDBX_log_level_t &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &,
-                                       const MDBX_debug_flags_t &);
-LIBMDBX_API ::std::ostream &operator<<(::std::ostream &, const error &);
-inline ::std::ostream &operator<<(::std::ostream &out,
-                                  const MDBX_error_t &errcode) {
-  return out << error(errcode);
-}
-
-//==============================================================================
-//
-// Inline body of the libmdbx C++ API
-//
-
-MDBX_CXX11_CONSTEXPR const version_info &get_version() noexcept {
-  return ::mdbx_version;
-}
-MDBX_CXX11_CONSTEXPR const build_info &get_build() noexcept {
-  return ::mdbx_build;
-}
-
-static MDBX_CXX17_CONSTEXPR size_t strlen(const char *c_str) noexcept {
-#if defined(__cpp_lib_is_constant_evaluated) &&                                \
-    __cpp_lib_is_constant_evaluated >= 201811L
-  if (::std::is_constant_evaluated()) {
-    for (size_t i = 0; c_str; ++i)
-      if (!c_str[i])
-        return i;
-    return 0;
-  }
-#endif /* __cpp_lib_is_constant_evaluated >= 201811 */
-#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
-  return c_str ? ::std::string_view(c_str).length() : 0;
-#else
-  return c_str ? ::std::strlen(c_str) : 0;
-#endif
-}
-
-MDBX_MAYBE_UNUSED static MDBX_CXX20_CONSTEXPR void *
-memcpy(void *dest, const void *src, size_t bytes) noexcept {
-#if defined(__cpp_lib_is_constant_evaluated) &&                                \
-    __cpp_lib_is_constant_evaluated >= 201811L
-  if (::std::is_constant_evaluated()) {
-    for (size_t i = 0; i < bytes; ++i)
-      static_cast<byte *>(dest)[i] = static_cast<const byte *>(src)[i];
-    return dest;
-  } else
-#endif /* __cpp_lib_is_constant_evaluated >= 201811 */
-    return ::std::memcpy(dest, src, bytes);
-}
-
-static MDBX_CXX20_CONSTEXPR int memcmp(const void *a, const void *b,
-                                       size_t bytes) noexcept {
-#if defined(__cpp_lib_is_constant_evaluated) &&                                \
-    __cpp_lib_is_constant_evaluated >= 201811L
-  if (::std::is_constant_evaluated()) {
-    for (size_t i = 0; i < bytes; ++i) {
-      const int diff =
-          static_cast<const byte *>(a)[i] - static_cast<const byte *>(b)[i];
-      if (diff)
-        return diff;
-    }
-    return 0;
-  } else
-#endif /* __cpp_lib_is_constant_evaluated >= 201811 */
-    return ::std::memcmp(a, b, bytes);
-}
-
-static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes) {
-  if (MDBX_UNLIKELY(bytes > size_t(MDBX_MAXDATASIZE)))
-    MDBX_CXX20_UNLIKELY throw_max_length_exceeded();
-  return bytes;
-}
-
-static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom,
-                                                size_t payload) {
-  return check_length(check_length(headroom) + check_length(payload));
-}
-
-MDBX_MAYBE_UNUSED static MDBX_CXX14_CONSTEXPR size_t
-check_length(size_t headroom, size_t payload, size_t tailroom) {
-  return check_length(check_length(headroom, payload) + check_length(tailroom));
-}
-
-inline bool exception_thunk::is_clean() const noexcept { return !captured_; }
-
-inline void exception_thunk::capture() noexcept {
-  assert(is_clean());
-  captured_ = ::std::current_exception();
-}
-
-inline void exception_thunk::rethrow_captured() const {
-  if (captured_)
-    MDBX_CXX20_UNLIKELY ::std::rethrow_exception(captured_);
-}
-
-//------------------------------------------------------------------------------
-
-MDBX_CXX11_CONSTEXPR error::error(MDBX_error_t error_code) noexcept
-    : code_(error_code) {}
-
-inline error &error::operator=(MDBX_error_t error_code) noexcept {
-  code_ = error_code;
-  return *this;
-}
-
-MDBX_CXX11_CONSTEXPR bool operator==(const error &a, const error &b) noexcept {
-  return a.code_ == b.code_;
-}
-
-MDBX_CXX11_CONSTEXPR bool operator!=(const error &a, const error &b) noexcept {
-  return !(a == b);
-}
-
-MDBX_CXX11_CONSTEXPR bool error::is_success() const noexcept {
-  return code_ == MDBX_SUCCESS;
-}
-
-MDBX_CXX11_CONSTEXPR bool error::is_result_true() const noexcept {
-  return code_ == MDBX_RESULT_FALSE;
-}
-
-MDBX_CXX11_CONSTEXPR bool error::is_result_false() const noexcept {
-  return code_ == MDBX_RESULT_TRUE;
-}
-
-MDBX_CXX11_CONSTEXPR bool error::is_failure() const noexcept {
-  return code_ != MDBX_SUCCESS && code_ != MDBX_RESULT_TRUE;
-}
-
-MDBX_CXX11_CONSTEXPR MDBX_error_t error::code() const noexcept { return code_; }
-
-MDBX_CXX11_CONSTEXPR bool error::is_mdbx_error() const noexcept {
-  return (code() >= MDBX_FIRST_LMDB_ERRCODE &&
-          code() <= MDBX_LAST_LMDB_ERRCODE) ||
-         (code() >= MDBX_FIRST_ADDED_ERRCODE &&
-          code() <= MDBX_LAST_ADDED_ERRCODE);
-}
-
-inline void error::throw_exception(int error_code) {
-  const error trouble(static_cast<MDBX_error_t>(error_code));
-  trouble.throw_exception();
-}
-
-inline void error::throw_on_failure() const {
-  if (MDBX_UNLIKELY(is_failure()))
-    MDBX_CXX20_UNLIKELY throw_exception();
-}
-
-inline void error::success_or_throw() const {
-  if (MDBX_UNLIKELY(!is_success()))
-    MDBX_CXX20_UNLIKELY throw_exception();
-}
-
-inline void error::success_or_throw(const exception_thunk &thunk) const {
-  assert(thunk.is_clean() || code() != MDBX_SUCCESS);
-  if (MDBX_UNLIKELY(!is_success())) {
-    MDBX_CXX20_UNLIKELY if (!thunk.is_clean()) thunk.rethrow_captured();
-    else throw_exception();
-  }
-}
-
-inline void error::panic_on_failure(const char *context_where,
-                                    const char *func_who) const noexcept {
-  if (MDBX_UNLIKELY(is_failure()))
-    MDBX_CXX20_UNLIKELY panic(context_where, func_who);
-}
-
-inline void error::success_or_panic(const char *context_where,
-                                    const char *func_who) const noexcept {
-  if (MDBX_UNLIKELY(!is_success()))
-    MDBX_CXX20_UNLIKELY panic(context_where, func_who);
-}
-
-inline void error::throw_on_nullptr(const void *ptr, MDBX_error_t error_code) {
-  if (MDBX_UNLIKELY(ptr == nullptr))
-    MDBX_CXX20_UNLIKELY error(error_code).throw_exception();
-}
-
-inline void error::throw_on_failure(int error_code) {
-  error rc(static_cast<MDBX_error_t>(error_code));
-  rc.throw_on_failure();
-}
-
-inline void error::success_or_throw(MDBX_error_t error_code) {
-  error rc(error_code);
-  rc.success_or_throw();
-}
-
-inline bool error::boolean_or_throw(int error_code) {
-  switch (error_code) {
-  case MDBX_RESULT_FALSE:
-    return false;
-  case MDBX_RESULT_TRUE:
-    return true;
-  default:
-    MDBX_CXX20_UNLIKELY throw_exception(error_code);
-  }
-}
-
-inline void error::success_or_throw(int error_code,
-                                    const exception_thunk &thunk) {
-  error rc(static_cast<MDBX_error_t>(error_code));
-  rc.success_or_throw(thunk);
-}
-
-inline void error::panic_on_failure(int error_code, const char *context_where,
-                                    const char *func_who) noexcept {
-  error rc(static_cast<MDBX_error_t>(error_code));
-  rc.panic_on_failure(context_where, func_who);
-}
-
-inline void error::success_or_panic(int error_code, const char *context_where,
-                                    const char *func_who) noexcept {
-  error rc(static_cast<MDBX_error_t>(error_code));
-  rc.success_or_panic(context_where, func_who);
-}
-
-//------------------------------------------------------------------------------
-
-MDBX_CXX11_CONSTEXPR slice::slice() noexcept : ::MDBX_val({nullptr, 0}) {}
-
-MDBX_CXX14_CONSTEXPR slice::slice(const void *ptr, size_t bytes)
-    : ::MDBX_val({const_cast<void *>(ptr), check_length(bytes)}) {}
-
-MDBX_CXX14_CONSTEXPR slice::slice(const void *begin, const void *end)
-    : slice(begin, static_cast<const byte *>(end) -
-                       static_cast<const byte *>(begin)) {}
-
-MDBX_CXX17_CONSTEXPR slice::slice(const char *c_str)
-    : slice(c_str, ::mdbx::strlen(c_str)) {}
-
-MDBX_CXX14_CONSTEXPR slice::slice(const MDBX_val &src)
-    : slice(src.iov_base, src.iov_len) {}
-
-MDBX_CXX14_CONSTEXPR slice::slice(MDBX_val &&src) : slice(src) {
-  src.iov_base = nullptr;
-}
-
-MDBX_CXX14_CONSTEXPR slice::slice(slice &&src) noexcept : slice(src) {
-  src.invalidate();
-}
-
-inline slice &slice::assign(const void *ptr, size_t bytes) {
-  iov_base = const_cast<void *>(ptr);
-  iov_len = check_length(bytes);
-  return *this;
-}
-
-inline slice &slice::assign(const slice &src) noexcept {
-  iov_base = src.iov_base;
-  iov_len = src.iov_len;
-  return *this;
-}
-
-inline slice &slice::assign(const ::MDBX_val &src) {
-  return assign(src.iov_base, src.iov_len);
-}
-
-slice &slice::assign(slice &&src) noexcept {
-  assign(src);
-  src.invalidate();
-  return *this;
-}
-
-inline slice &slice::assign(::MDBX_val &&src) {
-  assign(src.iov_base, src.iov_len);
-  src.iov_base = nullptr;
-  return *this;
-}
-
-inline slice &slice::assign(const void *begin, const void *end) {
-  return assign(begin, static_cast<const byte *>(end) -
-                           static_cast<const byte *>(begin));
-}
-
-inline slice &slice::assign(const char *c_str) {
-  return assign(c_str, ::mdbx::strlen(c_str));
-}
-
-inline slice &slice::operator=(slice &&src) noexcept {
-  return assign(::std::move(src));
-}
-
-inline slice &slice::operator=(::MDBX_val &&src) {
-  return assign(::std::move(src));
-}
-
-inline void slice::swap(slice &other) noexcept {
-  const auto temp = *this;
-  *this = other;
-  other = temp;
-}
-
-MDBX_CXX11_CONSTEXPR const ::mdbx::byte *slice::byte_ptr() const noexcept {
-  return static_cast<const byte *>(iov_base);
-}
-
-MDBX_CXX11_CONSTEXPR const ::mdbx::byte *slice::end_byte_ptr() const noexcept {
-  return byte_ptr() + length();
-}
-
-MDBX_CXX11_CONSTEXPR ::mdbx::byte *slice::byte_ptr() noexcept {
-  return static_cast<byte *>(iov_base);
-}
-
-MDBX_CXX11_CONSTEXPR ::mdbx::byte *slice::end_byte_ptr() noexcept {
-  return byte_ptr() + length();
-}
-
-MDBX_CXX11_CONSTEXPR const char *slice::char_ptr() const noexcept {
-  return static_cast<const char *>(iov_base);
-}
-
-MDBX_CXX11_CONSTEXPR const char *slice::end_char_ptr() const noexcept {
-  return char_ptr() + length();
-}
-
-MDBX_CXX11_CONSTEXPR char *slice::char_ptr() noexcept {
-  return static_cast<char *>(iov_base);
-}
-
-MDBX_CXX11_CONSTEXPR char *slice::end_char_ptr() noexcept {
-  return char_ptr() + length();
-}
-
-MDBX_CXX11_CONSTEXPR const void *slice::data() const noexcept {
-  return iov_base;
-}
-
-MDBX_CXX11_CONSTEXPR const void *slice::end() const noexcept {
-  return static_cast<const void *>(end_byte_ptr());
-}
-
-MDBX_CXX11_CONSTEXPR void *slice::data() noexcept { return iov_base; }
-
-MDBX_CXX11_CONSTEXPR void *slice::end() noexcept {
-  return static_cast<void *>(end_byte_ptr());
-}
-
-MDBX_CXX11_CONSTEXPR size_t slice::length() const noexcept { return iov_len; }
-
-MDBX_CXX14_CONSTEXPR slice &slice::set_length(size_t bytes) {
-  iov_len = check_length(bytes);
-  return *this;
-}
-
-MDBX_CXX14_CONSTEXPR slice &slice::set_end(const void *ptr) {
-  MDBX_CONSTEXPR_ASSERT(static_cast<const char *>(ptr) >= char_ptr());
-  return set_length(static_cast<const char *>(ptr) - char_ptr());
-}
-
-MDBX_CXX11_CONSTEXPR bool slice::empty() const noexcept {
-  return length() == 0;
-}
-
-MDBX_CXX11_CONSTEXPR bool slice::is_null() const noexcept {
-  return data() == nullptr;
-}
-
-MDBX_CXX11_CONSTEXPR size_t slice::size() const noexcept { return length(); }
-
-MDBX_CXX11_CONSTEXPR slice::operator bool() const noexcept {
-  return !is_null();
-}
-
-MDBX_CXX14_CONSTEXPR void slice::invalidate() noexcept { iov_base = nullptr; }
-
-MDBX_CXX14_CONSTEXPR void slice::clear() noexcept {
-  iov_base = nullptr;
-  iov_len = 0;
-}
-
-inline void slice::remove_prefix(size_t n) noexcept {
-  assert(n <= size());
-  iov_base = static_cast<byte *>(iov_base) + n;
-  iov_len -= n;
-}
-
-inline void slice::safe_remove_prefix(size_t n) {
-  if (MDBX_UNLIKELY(n > size()))
-    MDBX_CXX20_UNLIKELY throw_out_range();
-  remove_prefix(n);
-}
-
-inline void slice::remove_suffix(size_t n) noexcept {
-  assert(n <= size());
-  iov_len -= n;
-}
-
-inline void slice::safe_remove_suffix(size_t n) {
-  if (MDBX_UNLIKELY(n > size()))
-    MDBX_CXX20_UNLIKELY throw_out_range();
-  remove_suffix(n);
-}
-
-MDBX_CXX14_CONSTEXPR bool
-slice::starts_with(const slice &prefix) const noexcept {
-  return length() >= prefix.length() &&
-         memcmp(data(), prefix.data(), prefix.length()) == 0;
-}
-
-MDBX_CXX14_CONSTEXPR bool slice::ends_with(const slice &suffix) const noexcept {
-  return length() >= suffix.length() &&
-         memcmp(byte_ptr() + length() - suffix.length(), suffix.data(),
-                suffix.length()) == 0;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR size_t
-slice::hash_value() const noexcept {
-  size_t h = length() * 3977471;
-  for (size_t i = 0; i < length(); ++i)
-    h = (h ^ static_cast<const uint8_t *>(data())[i]) * 1664525 + 1013904223;
-  return h ^ 3863194411 * (h >> 11);
-}
-
-MDBX_CXX11_CONSTEXPR byte slice::operator[](size_t n) const noexcept {
-  MDBX_CONSTEXPR_ASSERT(n < size());
-  return byte_ptr()[n];
-}
-
-MDBX_CXX11_CONSTEXPR byte slice::at(size_t n) const {
-  if (MDBX_UNLIKELY(n >= size()))
-    MDBX_CXX20_UNLIKELY throw_out_range();
-  return byte_ptr()[n];
-}
-
-MDBX_CXX14_CONSTEXPR slice slice::head(size_t n) const noexcept {
-  MDBX_CONSTEXPR_ASSERT(n <= size());
-  return slice(data(), n);
-}
-
-MDBX_CXX14_CONSTEXPR slice slice::tail(size_t n) const noexcept {
-  MDBX_CONSTEXPR_ASSERT(n <= size());
-  return slice(char_ptr() + size() - n, n);
-}
-
-MDBX_CXX14_CONSTEXPR slice slice::middle(size_t from, size_t n) const noexcept {
-  MDBX_CONSTEXPR_ASSERT(from + n <= size());
-  return slice(char_ptr() + from, n);
-}
-
-MDBX_CXX14_CONSTEXPR slice slice::safe_head(size_t n) const {
-  if (MDBX_UNLIKELY(n > size()))
-    MDBX_CXX20_UNLIKELY throw_out_range();
-  return head(n);
-}
-
-MDBX_CXX14_CONSTEXPR slice slice::safe_tail(size_t n) const {
-  if (MDBX_UNLIKELY(n > size()))
-    MDBX_CXX20_UNLIKELY throw_out_range();
-  return tail(n);
-}
-
-MDBX_CXX14_CONSTEXPR slice slice::safe_middle(size_t from, size_t n) const {
-  if (MDBX_UNLIKELY(n > max_length))
-    MDBX_CXX20_UNLIKELY throw_max_length_exceeded();
-  if (MDBX_UNLIKELY(from + n > size()))
-    MDBX_CXX20_UNLIKELY throw_out_range();
-  return middle(from, n);
-}
-
-MDBX_CXX14_CONSTEXPR intptr_t slice::compare_fast(const slice &a,
-                                                  const slice &b) noexcept {
-  const intptr_t diff = intptr_t(a.length()) - intptr_t(b.length());
-  return diff ? diff
-         : MDBX_UNLIKELY(a.length() == 0 || a.data() == b.data())
-             ? 0
-             : memcmp(a.data(), b.data(), a.length());
-}
-
-MDBX_CXX14_CONSTEXPR intptr_t
-slice::compare_lexicographically(const slice &a, const slice &b) noexcept {
-  const size_t shortest = ::std::min(a.length(), b.length());
-  if (MDBX_LIKELY(shortest > 0))
-    MDBX_CXX20_LIKELY {
-      const intptr_t diff = memcmp(a.data(), b.data(), shortest);
-      if (MDBX_LIKELY(diff != 0))
-        MDBX_CXX20_LIKELY return diff;
-    }
-  return intptr_t(a.length()) - intptr_t(b.length());
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-operator==(const slice &a, const slice &b) noexcept {
-  return slice::compare_fast(a, b) == 0;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-operator<(const slice &a, const slice &b) noexcept {
-  return slice::compare_lexicographically(a, b) < 0;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-operator>(const slice &a, const slice &b) noexcept {
-  return slice::compare_lexicographically(a, b) > 0;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-operator<=(const slice &a, const slice &b) noexcept {
-  return slice::compare_lexicographically(a, b) <= 0;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-operator>=(const slice &a, const slice &b) noexcept {
-  return slice::compare_lexicographically(a, b) >= 0;
-}
-
-MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool
-operator!=(const slice &a, const slice &b) noexcept {
-  return slice::compare_fast(a, b) != 0;
-}
-
-template <class ALLOCATOR>
-inline string<ALLOCATOR>
-slice::as_hex_string(bool uppercase, unsigned wrap_width,
-                     const ALLOCATOR &allocator) const {
-  return to_hex(*this, uppercase, wrap_width).as_string<ALLOCATOR>(allocator);
-}
-
-template <class ALLOCATOR>
-inline string<ALLOCATOR>
-slice::as_base58_string(unsigned wrap_width, const ALLOCATOR &allocator) const {
-  return to_base58(*this, wrap_width).as_string<ALLOCATOR>(allocator);
-}
-
-template <class ALLOCATOR>
-inline string<ALLOCATOR>
-slice::as_base64_string(unsigned wrap_width, const ALLOCATOR &allocator) const {
-  return to_base64(*this, wrap_width).as_string<ALLOCATOR>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-slice::encode_hex(bool uppercase, unsigned wrap_width,
-                  const ALLOCATOR &allocator) const {
-  return to_hex(*this, uppercase, wrap_width)
-      .as_buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-slice::encode_base58(unsigned wrap_width, const ALLOCATOR &allocator) const {
-  return to_base58(*this, wrap_width)
-      .as_buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-slice::encode_base64(unsigned wrap_width, const ALLOCATOR &allocator) const {
-  return to_base64(*this, wrap_width)
-      .as_buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-slice::hex_decode(bool ignore_spaces, const ALLOCATOR &allocator) const {
-  return from_hex(*this, ignore_spaces)
-      .as_buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-slice::base58_decode(bool ignore_spaces, const ALLOCATOR &allocator) const {
-  return from_base58(*this, ignore_spaces)
-      .as_buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-template <class ALLOCATOR, class CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-slice::base64_decode(bool ignore_spaces, const ALLOCATOR &allocator) const {
-  return from_base64(*this, ignore_spaces)
-      .as_buffer<ALLOCATOR, CAPACITY_POLICY>(allocator);
-}
-
-inline MDBX_NOTHROW_PURE_FUNCTION bool
-slice::is_hex(bool ignore_spaces) const noexcept {
-  return !from_hex(*this, ignore_spaces).is_erroneous();
-}
-
-inline MDBX_NOTHROW_PURE_FUNCTION bool
-slice::is_base58(bool ignore_spaces) const noexcept {
-  return !from_base58(*this, ignore_spaces).is_erroneous();
-}
-
-inline MDBX_NOTHROW_PURE_FUNCTION bool
-slice::is_base64(bool ignore_spaces) const noexcept {
-  return !from_base64(*this, ignore_spaces).is_erroneous();
-}
-
-//------------------------------------------------------------------------------
-
-template <class ALLOCATOR, typename CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>::buffer(
-    const txn &txn, const struct slice &src, const allocator_type &allocator)
-    : buffer(src, !txn.is_dirty(src.data()), allocator) {}
-
-//------------------------------------------------------------------------------
-
-MDBX_CXX11_CONSTEXPR map_handle::info::info(map_handle::flags flags,
-                                            map_handle::state state) noexcept
-    : flags(flags), state(state) {}
-
-#if CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_CXX11_CONSTEXPR
-#endif
-::mdbx::key_mode map_handle::info::key_mode() const noexcept {
-  return ::mdbx::key_mode(flags & (MDBX_REVERSEKEY | MDBX_INTEGERKEY));
-}
-
-#if CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_CXX11_CONSTEXPR
-#endif
-::mdbx::value_mode map_handle::info::value_mode() const noexcept {
-  return ::mdbx::value_mode(flags & (MDBX_DUPSORT | MDBX_REVERSEDUP |
-                                     MDBX_DUPFIXED | MDBX_INTEGERDUP));
-}
-
-//------------------------------------------------------------------------------
-
-MDBX_CXX11_CONSTEXPR env::env(MDBX_env *ptr) noexcept : handle_(ptr) {}
-
-inline env &env::operator=(env &&other) noexcept {
-  handle_ = other.handle_;
-  other.handle_ = nullptr;
-  return *this;
-}
-
-inline env::env(env &&other) noexcept : handle_(other.handle_) {
-  other.handle_ = nullptr;
-}
-
-inline env::~env() noexcept {
-#ifndef NDEBUG
-  handle_ = reinterpret_cast<MDBX_env *>(uintptr_t(0xDeadBeef));
-#endif
-}
-
-MDBX_CXX14_CONSTEXPR env::operator bool() const noexcept {
-  return handle_ != nullptr;
-}
-
-MDBX_CXX14_CONSTEXPR env::operator const MDBX_env *() const { return handle_; }
-
-MDBX_CXX14_CONSTEXPR env::operator MDBX_env *() { return handle_; }
-
-MDBX_CXX11_CONSTEXPR bool operator==(const env &a, const env &b) noexcept {
-  return a.handle_ == b.handle_;
-}
-
-MDBX_CXX11_CONSTEXPR bool operator!=(const env &a, const env &b) noexcept {
-  return a.handle_ != b.handle_;
-}
-
-inline env::geometry &env::geometry::make_fixed(intptr_t size) noexcept {
-  size_lower = size_now = size_upper = size;
-  growth_step = shrink_threshold = 0;
-  return *this;
-}
-
-inline env::geometry &env::geometry::make_dynamic(intptr_t lower,
-                                                  intptr_t upper) noexcept {
-  size_now = size_lower = lower;
-  size_upper = upper;
-  growth_step = shrink_threshold = default_value;
-  return *this;
-}
-
-inline env::reclaiming_options env::operate_parameters::reclaiming_from_flags(
-    MDBX_env_flags_t flags) noexcept {
-  return reclaiming_options(flags);
-}
-
-inline env::operate_options
-env::operate_parameters::options_from_flags(MDBX_env_flags_t flags) noexcept {
-  return operate_options(flags);
-}
-
-inline size_t env::limits::pagesize_min() noexcept { return MDBX_MIN_PAGESIZE; }
-
-inline size_t env::limits::pagesize_max() noexcept { return MDBX_MAX_PAGESIZE; }
-
-inline size_t env::limits::dbsize_min(intptr_t pagesize) {
-  const intptr_t result = mdbx_limits_dbsize_min(pagesize);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline size_t env::limits::dbsize_max(intptr_t pagesize) {
-  const intptr_t result = mdbx_limits_dbsize_max(pagesize);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline size_t env::limits::key_min(MDBX_db_flags_t flags) noexcept {
-  return (flags & MDBX_INTEGERKEY) ? 4 : 0;
-}
-
-inline size_t env::limits::key_min(key_mode mode) noexcept {
-  return key_min(MDBX_db_flags_t(mode));
-}
-
-inline size_t env::limits::key_max(intptr_t pagesize, MDBX_db_flags_t flags) {
-  const intptr_t result = mdbx_limits_keysize_max(pagesize, flags);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline size_t env::limits::key_max(intptr_t pagesize, key_mode mode) {
-  return key_max(pagesize, MDBX_db_flags_t(mode));
-}
-
-inline size_t env::limits::key_max(const env &env, MDBX_db_flags_t flags) {
-  const intptr_t result = mdbx_env_get_maxkeysize_ex(env, flags);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline size_t env::limits::key_max(const env &env, key_mode mode) {
-  return key_max(env, MDBX_db_flags_t(mode));
-}
-
-inline size_t env::limits::value_min(MDBX_db_flags_t flags) noexcept {
-  return (flags & MDBX_INTEGERDUP) ? 4 : 0;
-}
-
-inline size_t env::limits::value_min(value_mode mode) noexcept {
-  return value_min(MDBX_db_flags_t(mode));
-}
-
-inline size_t env::limits::value_max(intptr_t pagesize, MDBX_db_flags_t flags) {
-  const intptr_t result = mdbx_limits_valsize_max(pagesize, flags);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline size_t env::limits::value_max(intptr_t pagesize, value_mode mode) {
-  return value_max(pagesize, MDBX_db_flags_t(mode));
-}
-
-inline size_t env::limits::value_max(const env &env, MDBX_db_flags_t flags) {
-  const intptr_t result = mdbx_env_get_maxvalsize_ex(env, flags);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline size_t env::limits::value_max(const env &env, value_mode mode) {
-  return value_max(env, MDBX_db_flags_t(mode));
-}
-
-inline size_t env::limits::transaction_size_max(intptr_t pagesize) {
-  const intptr_t result = mdbx_limits_txnsize_max(pagesize);
-  if (result < 0)
-    MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
-  return static_cast<size_t>(result);
-}
-
-inline env::operate_parameters env::get_operation_parameters() const {
-  const auto flags = get_flags();
-  return operate_parameters(max_maps(), max_readers(),
-                            operate_parameters::mode_from_flags(flags),
-                            operate_parameters::durability_from_flags(flags),
-                            operate_parameters::reclaiming_from_flags(flags),
-                            operate_parameters::options_from_flags(flags));
-}
-
-inline env::mode env::get_mode() const {
-  return operate_parameters::mode_from_flags(get_flags());
-}
-
-inline env::durability env::get_durability() const {
-  return env::operate_parameters::durability_from_flags(get_flags());
-}
-
-inline env::reclaiming_options env::get_reclaiming() const {
-  return env::operate_parameters::reclaiming_from_flags(get_flags());
-}
-
-inline env::operate_options env::get_options() const {
-  return env::operate_parameters::options_from_flags(get_flags());
-}
-
-inline env::stat env::get_stat() const {
-  env::stat r;
-  error::success_or_throw(::mdbx_env_stat_ex(handle_, nullptr, &r, sizeof(r)));
-  return r;
-}
-
-inline env::stat env::get_stat(const txn &txn) const {
-  env::stat r;
-  error::success_or_throw(::mdbx_env_stat_ex(handle_, txn, &r, sizeof(r)));
-  return r;
-}
-
-inline env::info env::get_info() const {
-  env::info r;
-  error::success_or_throw(::mdbx_env_info_ex(handle_, nullptr, &r, sizeof(r)));
-  return r;
-}
-
-inline env::info env::get_info(const txn &txn) const {
-  env::info r;
-  error::success_or_throw(::mdbx_env_info_ex(handle_, txn, &r, sizeof(r)));
-  return r;
-}
-
-inline filehandle env::get_filehandle() const {
-  filehandle fd;
-  error::success_or_throw(::mdbx_env_get_fd(handle_, &fd));
-  return fd;
-}
-
-inline MDBX_env_flags_t env::get_flags() const {
-  unsigned bits;
-  error::success_or_throw(::mdbx_env_get_flags(handle_, &bits));
-  return MDBX_env_flags_t(bits);
-}
-
-inline unsigned env::max_readers() const {
-  unsigned r;
-  error::success_or_throw(::mdbx_env_get_maxreaders(handle_, &r));
-  return r;
-}
-
-inline unsigned env::max_maps() const {
-  unsigned r;
-  error::success_or_throw(::mdbx_env_get_maxdbs(handle_, &r));
-  return r;
-}
-
-inline void *env::get_context() const noexcept {
-  return mdbx_env_get_userctx(handle_);
-}
-
-inline env &env::set_context(void *ptr) {
-  error::success_or_throw(::mdbx_env_set_userctx(handle_, ptr));
-  return *this;
-}
-
-inline env &env::set_sync_threshold(size_t bytes) {
-  error::success_or_throw(::mdbx_env_set_syncbytes(handle_, bytes));
-  return *this;
-}
-
-inline env &env::set_sync_period(unsigned seconds_16dot16) {
-  error::success_or_throw(::mdbx_env_set_syncperiod(handle_, seconds_16dot16));
-  return *this;
-}
-
-inline env &env::set_sync_period(double seconds) {
-  return set_sync_period(unsigned(seconds * 65536));
-}
-
-inline env &env::alter_flags(MDBX_env_flags_t flags, bool on_off) {
-  error::success_or_throw(::mdbx_env_set_flags(handle_, flags, on_off));
-  return *this;
-}
-
-inline env &env::set_geometry(const geometry &geo) {
-  error::success_or_throw(::mdbx_env_set_geometry(
-      handle_, geo.size_lower, geo.size_now, geo.size_upper, geo.growth_step,
-      geo.shrink_threshold, geo.pagesize));
-  return *this;
-}
-
-inline bool env::sync_to_disk(bool force, bool nonblock) {
-  const int err = ::mdbx_env_sync_ex(handle_, force, nonblock);
-  switch (err) {
-  case MDBX_SUCCESS /* flush done */:
-  case MDBX_RESULT_TRUE /* no data pending for flush to disk */:
-    return true;
-  case MDBX_BUSY /* the environment is used by other thread */:
-    return false;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline void env::close_map(const map_handle &handle) {
-  error::success_or_throw(::mdbx_dbi_close(*this, handle.dbi));
-}
-
-MDBX_CXX11_CONSTEXPR
-env::reader_info::reader_info(int slot, mdbx_pid_t pid, mdbx_tid_t thread,
-                              uint64_t txnid, uint64_t lag, size_t used,
-                              size_t retained) noexcept
-    : slot(slot), pid(pid), thread(thread), transaction_id(txnid),
-      transaction_lag(lag), bytes_used(used), bytes_retained(retained) {}
-
-template <typename VISITOR>
-inline int env::enumerate_readers(VISITOR &visitor) {
-  struct reader_visitor_thunk : public exception_thunk {
-    VISITOR &visitor_;
-    static int cb(void *ctx, int number, int slot, mdbx_pid_t pid,
-                  mdbx_tid_t thread, uint64_t txnid, uint64_t lag, size_t used,
-                  size_t retained) noexcept {
-      reader_visitor_thunk *thunk = static_cast<reader_visitor_thunk *>(ctx);
-      assert(thunk->is_clean());
-      try {
-        const reader_info info(slot, pid, thread, txnid, lag, used, retained);
-        return loop_control(thunk->visitor_(info, number));
-      } catch (... /* capture any exception to rethrow it over C code */) {
-        thunk->capture();
-        return loop_control::exit_loop;
-      }
-    }
-    MDBX_CXX11_CONSTEXPR reader_visitor_thunk(VISITOR &visitor) noexcept
-        : visitor_(visitor) {}
-  };
-  reader_visitor_thunk thunk(visitor);
-  const auto rc = ::mdbx_reader_list(*this, thunk.cb, &thunk);
-  thunk.rethrow_captured();
-  return rc;
-}
-
-inline unsigned env::check_readers() {
-  int dead_count;
-  error::throw_on_failure(::mdbx_reader_check(*this, &dead_count));
-  assert(dead_count >= 0);
-  return static_cast<unsigned>(dead_count);
-}
-
-inline env &env::set_HandleSlowReaders(MDBX_hsr_func *cb) {
-  error::success_or_throw(::mdbx_env_set_hsr(handle_, cb));
-  return *this;
-}
-
-inline MDBX_hsr_func *env::get_HandleSlowReaders() const noexcept {
-  return ::mdbx_env_get_hsr(handle_);
-}
-
-inline txn_managed env::start_read() const {
-  ::MDBX_txn *ptr;
-  error::success_or_throw(
-      ::mdbx_txn_begin(handle_, nullptr, MDBX_TXN_RDONLY, &ptr));
-  assert(ptr != nullptr);
-  return txn_managed(ptr);
-}
-
-inline txn_managed env::prepare_read() const {
-  ::MDBX_txn *ptr;
-  error::success_or_throw(
-      ::mdbx_txn_begin(handle_, nullptr, MDBX_TXN_RDONLY_PREPARE, &ptr));
-  assert(ptr != nullptr);
-  return txn_managed(ptr);
-}
-
-inline txn_managed env::start_write(bool dont_wait) {
-  ::MDBX_txn *ptr;
-  error::success_or_throw(::mdbx_txn_begin(
-      handle_, nullptr, dont_wait ? MDBX_TXN_TRY : MDBX_TXN_READWRITE, &ptr));
-  assert(ptr != nullptr);
-  return txn_managed(ptr);
-}
-
-inline txn_managed env::try_start_write() { return start_write(true); }
-
-//------------------------------------------------------------------------------
-
-MDBX_CXX11_CONSTEXPR txn::txn(MDBX_txn *ptr) noexcept : handle_(ptr) {}
-
-inline txn &txn::operator=(txn &&other) noexcept {
-  handle_ = other.handle_;
-  other.handle_ = nullptr;
-  return *this;
-}
-
-inline txn::txn(txn &&other) noexcept : handle_(other.handle_) {
-  other.handle_ = nullptr;
-}
-
-inline txn::~txn() noexcept {
-#ifndef NDEBUG
-  handle_ = reinterpret_cast<MDBX_txn *>(uintptr_t(0xDeadBeef));
-#endif
-}
-
-MDBX_CXX14_CONSTEXPR txn::operator bool() const noexcept {
-  return handle_ != nullptr;
-}
-
-MDBX_CXX14_CONSTEXPR txn::operator const MDBX_txn *() const { return handle_; }
-
-MDBX_CXX14_CONSTEXPR txn::operator MDBX_txn *() { return handle_; }
-
-MDBX_CXX11_CONSTEXPR bool operator==(const txn &a, const txn &b) noexcept {
-  return a.handle_ == b.handle_;
-}
-
-MDBX_CXX11_CONSTEXPR bool operator!=(const txn &a, const txn &b) noexcept {
-  return a.handle_ != b.handle_;
-}
-
-inline bool txn::is_dirty(const void *ptr) const {
-  int err = ::mdbx_is_dirty(handle_, ptr);
-  switch (err) {
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  case MDBX_RESULT_TRUE:
-    return true;
-  case MDBX_RESULT_FALSE:
-    return false;
-  }
-}
-
-inline ::mdbx::env txn::env() const noexcept { return ::mdbx_txn_env(handle_); }
-
-inline MDBX_txn_flags_t txn::flags() const {
-  const int bits = mdbx_txn_flags(handle_);
-  error::throw_on_failure((bits != -1) ? MDBX_SUCCESS : MDBX_BAD_TXN);
-  return static_cast<MDBX_txn_flags_t>(bits);
-}
-
-inline uint64_t txn::id() const {
-  const uint64_t txnid = mdbx_txn_id(handle_);
-  error::throw_on_failure(txnid ? MDBX_SUCCESS : MDBX_BAD_TXN);
-  return txnid;
-}
-
-inline void txn::reset_reading() {
-  error::success_or_throw(::mdbx_txn_reset(handle_));
-}
-
-inline void txn::renew_reading() {
-  error::success_or_throw(::mdbx_txn_renew(handle_));
-}
-
-inline txn::info txn::get_info(bool scan_reader_lock_table) const {
-  txn::info r;
-  error::success_or_throw(::mdbx_txn_info(handle_, &r, scan_reader_lock_table));
-  return r;
-}
-
-inline cursor_managed txn::open_cursor(map_handle map) {
-  MDBX_cursor *ptr;
-  error::success_or_throw(::mdbx_cursor_open(handle_, map.dbi, &ptr));
-  return cursor_managed(ptr);
-}
-
-inline ::mdbx::map_handle
-txn::open_map(const char *name, const ::mdbx::key_mode key_mode,
-              const ::mdbx::value_mode value_mode) const {
-  ::mdbx::map_handle map;
-  error::success_or_throw(::mdbx_dbi_open(
-      handle_, name, MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode),
-      &map.dbi));
-  assert(map.dbi != 0);
-  return map;
-}
-
-inline ::mdbx::map_handle
-txn::open_map(const ::std::string &name, const ::mdbx::key_mode key_mode,
-              const ::mdbx::value_mode value_mode) const {
-  return open_map(name.c_str(), key_mode, value_mode);
-}
-
-inline ::mdbx::map_handle txn::create_map(const char *name,
-                                          const ::mdbx::key_mode key_mode,
-                                          const ::mdbx::value_mode value_mode) {
-  ::mdbx::map_handle map;
-  error::success_or_throw(::mdbx_dbi_open(
-      handle_, name,
-      MDBX_CREATE | MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode),
-      &map.dbi));
-  assert(map.dbi != 0);
-  return map;
-}
-
-inline ::mdbx::map_handle txn::create_map(const ::std::string &name,
-                                          const ::mdbx::key_mode key_mode,
-                                          const ::mdbx::value_mode value_mode) {
-  return create_map(name.c_str(), key_mode, value_mode);
-}
-
-inline void txn::drop_map(map_handle map) {
-  error::success_or_throw(::mdbx_drop(handle_, map.dbi, true));
-}
-
-inline bool txn::drop_map(const ::std::string &name, bool throw_if_absent) {
-  return drop_map(name.c_str(), throw_if_absent);
-}
-
-inline void txn::clear_map(map_handle map) {
-  error::success_or_throw(::mdbx_drop(handle_, map.dbi, false));
-}
-
-inline bool txn::clear_map(const ::std::string &name, bool throw_if_absent) {
-  return clear_map(name.c_str(), throw_if_absent);
-}
-
-inline txn::map_stat txn::get_map_stat(map_handle map) const {
-  txn::map_stat r;
-  error::success_or_throw(::mdbx_dbi_stat(handle_, map.dbi, &r, sizeof(r)));
-  return r;
-}
-
-inline uint32_t txn::get_tree_deepmask(map_handle map) const {
-  uint32_t r;
-  error::success_or_throw(::mdbx_dbi_dupsort_depthmask(handle_, map.dbi, &r));
-  return r;
-}
-
-inline map_handle::info txn::get_handle_info(map_handle map) const {
-  unsigned flags, state;
-  error::success_or_throw(
-      ::mdbx_dbi_flags_ex(handle_, map.dbi, &flags, &state));
-  return map_handle::info(MDBX_db_flags_t(flags), MDBX_dbi_state_t(state));
-}
-
-inline txn &txn::put_canary(const txn::canary &canary) {
-  error::success_or_throw(::mdbx_canary_put(handle_, &canary));
-  return *this;
-}
-
-inline txn::canary txn::get_canary() const {
-  txn::canary r;
-  error::success_or_throw(::mdbx_canary_get(handle_, &r));
-  return r;
-}
-
-inline uint64_t txn::sequence(map_handle map) const {
-  uint64_t result;
-  error::success_or_throw(::mdbx_dbi_sequence(handle_, map.dbi, &result, 0));
-  return result;
-}
-
-inline uint64_t txn::sequence(map_handle map, uint64_t increment) {
-  uint64_t result;
-  error::success_or_throw(
-      ::mdbx_dbi_sequence(handle_, map.dbi, &result, increment));
-  return result;
-}
-
-inline int txn::compare_keys(map_handle map, const slice &a,
-                             const slice &b) const noexcept {
-  return ::mdbx_cmp(handle_, map.dbi, &a, &b);
-}
-
-inline int txn::compare_values(map_handle map, const slice &a,
-                               const slice &b) const noexcept {
-  return ::mdbx_dcmp(handle_, map.dbi, &a, &b);
-}
-
-inline int txn::compare_keys(map_handle map, const pair &a,
-                             const pair &b) const noexcept {
-  return compare_keys(map, a.key, b.key);
-}
-
-inline int txn::compare_values(map_handle map, const pair &a,
-                               const pair &b) const noexcept {
-  return compare_values(map, a.value, b.value);
-}
-
-inline slice txn::get(map_handle map, const slice &key) const {
-  slice result;
-  error::success_or_throw(::mdbx_get(handle_, map.dbi, &key, &result));
-  return result;
-}
-
-inline slice txn::get(map_handle map, slice key, size_t &values_count) const {
-  slice result;
-  error::success_or_throw(
-      ::mdbx_get_ex(handle_, map.dbi, &key, &result, &values_count));
-  return result;
-}
-
-inline slice txn::get(map_handle map, const slice &key,
-                      const slice &value_at_absence) const {
-  slice result;
-  const int err = ::mdbx_get(handle_, map.dbi, &key, &result);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return result;
-  case MDBX_NOTFOUND:
-    return value_at_absence;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline slice txn::get(map_handle map, slice key, size_t &values_count,
-                      const slice &value_at_absence) const {
-  slice result;
-  const int err = ::mdbx_get_ex(handle_, map.dbi, &key, &result, &values_count);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return result;
-  case MDBX_NOTFOUND:
-    return value_at_absence;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline pair_result txn::get_equal_or_great(map_handle map,
-                                           const slice &key) const {
-  pair result(key, slice());
-  bool exact = !error::boolean_or_throw(
-      ::mdbx_get_equal_or_great(handle_, map.dbi, &result.key, &result.value));
-  return pair_result(result.key, result.value, exact);
-}
-
-inline pair_result
-txn::get_equal_or_great(map_handle map, const slice &key,
-                        const slice &value_at_absence) const {
-  pair result{key, slice()};
-  const int err =
-      ::mdbx_get_equal_or_great(handle_, map.dbi, &result.key, &result.value);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return pair_result{result.key, result.value, true};
-  case MDBX_RESULT_TRUE:
-    return pair_result{result.key, result.value, false};
-  case MDBX_NOTFOUND:
-    return pair_result{key, value_at_absence, false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline MDBX_error_t txn::put(map_handle map, const slice &key, slice *value,
-                             MDBX_put_flags_t flags) noexcept {
-  return MDBX_error_t(::mdbx_put(handle_, map.dbi, &key, value, flags));
-}
-
-inline void txn::put(map_handle map, const slice &key, slice value,
-                     put_mode mode) {
-  error::success_or_throw(put(map, key, &value, MDBX_put_flags_t(mode)));
-}
-
-inline void txn::insert(map_handle map, const slice &key, slice value) {
-  error::success_or_throw(
-      put(map, key, &value /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique)));
-}
-
-inline value_result txn::try_insert(map_handle map, const slice &key,
-                                    slice value) {
-  const int err =
-      put(map, key, &value /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique));
-  switch (err) {
-  case MDBX_SUCCESS:
-    return value_result{slice(), true};
-  case MDBX_KEYEXIST:
-    return value_result{value, false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline slice txn::insert_reserve(map_handle map, const slice &key,
-                                 size_t value_length) {
-  slice result(nullptr, value_length);
-  error::success_or_throw(
-      put(map, key, &result /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique) | MDBX_RESERVE));
-  return result;
-}
-
-inline value_result txn::try_insert_reserve(map_handle map, const slice &key,
-                                            size_t value_length) {
-  slice result(nullptr, value_length);
-  const int err =
-      put(map, key, &result /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique) | MDBX_RESERVE);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return value_result{result, true};
-  case MDBX_KEYEXIST:
-    return value_result{result, false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline void txn::upsert(map_handle map, const slice &key, const slice &value) {
-  error::success_or_throw(put(map, key, const_cast<slice *>(&value),
-                              MDBX_put_flags_t(put_mode::upsert)));
-}
-
-inline slice txn::upsert_reserve(map_handle map, const slice &key,
-                                 size_t value_length) {
-  slice result(nullptr, value_length);
-  error::success_or_throw(put(
-      map, key, &result, MDBX_put_flags_t(put_mode::upsert) | MDBX_RESERVE));
-  return result;
-}
-
-inline void txn::update(map_handle map, const slice &key, const slice &value) {
-  error::success_or_throw(put(map, key, const_cast<slice *>(&value),
-                              MDBX_put_flags_t(put_mode::update)));
-}
-
-inline bool txn::try_update(map_handle map, const slice &key,
-                            const slice &value) {
-  const int err = put(map, key, const_cast<slice *>(&value),
-                      MDBX_put_flags_t(put_mode::update));
-  switch (err) {
-  case MDBX_SUCCESS:
-    return true;
-  case MDBX_NOTFOUND:
-    return false;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline slice txn::update_reserve(map_handle map, const slice &key,
-                                 size_t value_length) {
-  slice result(nullptr, value_length);
-  error::success_or_throw(put(
-      map, key, &result, MDBX_put_flags_t(put_mode::update) | MDBX_RESERVE));
-  return result;
-}
-
-inline value_result txn::try_update_reserve(map_handle map, const slice &key,
-                                            size_t value_length) {
-  slice result(nullptr, value_length);
-  const int err =
-      put(map, key, &result, MDBX_put_flags_t(put_mode::update) | MDBX_RESERVE);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return value_result{result, true};
-  case MDBX_NOTFOUND:
-    return value_result{slice(), false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline bool txn::erase(map_handle map, const slice &key) {
-  const int err = ::mdbx_del(handle_, map.dbi, &key, nullptr);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return true;
-  case MDBX_NOTFOUND:
-    return false;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline bool txn::erase(map_handle map, const slice &key, const slice &value) {
-  const int err = ::mdbx_del(handle_, map.dbi, &key, &value);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return true;
-  case MDBX_NOTFOUND:
-    return false;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline void txn::replace(map_handle map, const slice &key, slice old_value,
-                         const slice &new_value) {
-  error::success_or_throw(::mdbx_replace_ex(
-      handle_, map.dbi, &key, const_cast<slice *>(&new_value), &old_value,
-      MDBX_CURRENT | MDBX_NOOVERWRITE, nullptr, nullptr));
-}
-
-template <class ALLOCATOR, typename CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-txn::extract(map_handle map, const slice &key,
-             const typename buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type
-                 &allocator) {
-  typename buffer<ALLOCATOR, CAPACITY_POLICY>::data_preserver result(allocator);
-  error::success_or_throw(::mdbx_replace_ex(handle_, map.dbi, &key, nullptr,
-                                            &result.slice_, MDBX_CURRENT,
-                                            result, &result),
-                          result);
-  return result;
-}
-
-template <class ALLOCATOR, typename CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY>
-txn::replace(map_handle map, const slice &key, const slice &new_value,
-             const typename buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type
-                 &allocator) {
-  typename buffer<ALLOCATOR, CAPACITY_POLICY>::data_preserver result(allocator);
-  error::success_or_throw(
-      ::mdbx_replace_ex(handle_, map.dbi, &key, const_cast<slice *>(&new_value),
-                        &result.slice_, MDBX_CURRENT, result, &result),
-      result);
-  return result;
-}
-
-template <class ALLOCATOR, typename CAPACITY_POLICY>
-inline buffer<ALLOCATOR, CAPACITY_POLICY> txn::replace_reserve(
-    map_handle map, const slice &key, slice &new_value,
-    const typename buffer<ALLOCATOR, CAPACITY_POLICY>::allocator_type
-        &allocator) {
-  typename buffer<ALLOCATOR, CAPACITY_POLICY>::data_preserver result(allocator);
-  error::success_or_throw(
-      ::mdbx_replace_ex(handle_, map.dbi, &key, &new_value, &result.slice_,
-                        MDBX_CURRENT | MDBX_RESERVE, result, &result),
-      result);
-  return result;
-}
-
-inline void txn::append(map_handle map, const slice &key, const slice &value,
-                        bool multivalue_order_preserved) {
-  error::success_or_throw(::mdbx_put(
-      handle_, map.dbi, const_cast<slice *>(&key), const_cast<slice *>(&value),
-      multivalue_order_preserved ? (MDBX_APPEND | MDBX_APPENDDUP)
-                                 : MDBX_APPEND));
-}
-
-inline size_t txn::put_multiple(map_handle map, const slice &key,
-                                const size_t value_length,
-                                const void *values_array, size_t values_count,
-                                put_mode mode, bool allow_partial) {
-  MDBX_val args[2] = {{const_cast<void *>(values_array), value_length},
-                      {nullptr, values_count}};
-  const int err = ::mdbx_put(handle_, map.dbi, const_cast<slice *>(&key), args,
-                             MDBX_put_flags_t(mode) | MDBX_MULTIPLE);
-  switch (err) {
-  case MDBX_SUCCESS:
-    MDBX_CXX20_LIKELY break;
-  case MDBX_KEYEXIST:
-    if (allow_partial)
-      break;
-    mdbx_txn_break(handle_);
-    MDBX_CXX17_FALLTHROUGH /* fallthrough */;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-  return args[1].iov_len /* done item count */;
-}
-
-inline ptrdiff_t txn::estimate(map_handle map, pair from, pair to) const {
-  ptrdiff_t result;
-  error::success_or_throw(mdbx_estimate_range(
-      handle_, map.dbi, &from.key, &from.value, &to.key, &to.value, &result));
-  return result;
-}
-
-inline ptrdiff_t txn::estimate(map_handle map, slice from, slice to) const {
-  ptrdiff_t result;
-  error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
-                                              &to, nullptr, &result));
-  return result;
-}
-
-inline ptrdiff_t txn::estimate_from_first(map_handle map, slice to) const {
-  ptrdiff_t result;
-  error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, nullptr,
-                                              nullptr, &to, nullptr, &result));
-  return result;
-}
-
-inline ptrdiff_t txn::estimate_to_last(map_handle map, slice from) const {
-  ptrdiff_t result;
-  error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
-                                              nullptr, nullptr, &result));
-  return result;
-}
-
-//------------------------------------------------------------------------------
-
-MDBX_CXX11_CONSTEXPR cursor::cursor(MDBX_cursor *ptr) noexcept : handle_(ptr) {}
-
-inline cursor &cursor::operator=(cursor &&other) noexcept {
-  handle_ = other.handle_;
-  other.handle_ = nullptr;
-  return *this;
-}
-
-inline cursor::cursor(cursor &&other) noexcept : handle_(other.handle_) {
-  other.handle_ = nullptr;
-}
-
-inline cursor::~cursor() noexcept {
-#ifndef NDEBUG
-  handle_ = reinterpret_cast<MDBX_cursor *>(uintptr_t(0xDeadBeef));
-#endif
-}
-
-MDBX_CXX14_CONSTEXPR cursor::operator bool() const noexcept {
-  return handle_ != nullptr;
-}
-
-MDBX_CXX14_CONSTEXPR cursor::operator const MDBX_cursor *() const {
-  return handle_;
-}
-
-MDBX_CXX14_CONSTEXPR cursor::operator MDBX_cursor *() { return handle_; }
-
-MDBX_CXX11_CONSTEXPR bool operator==(const cursor &a,
-                                     const cursor &b) noexcept {
-  return a.handle_ == b.handle_;
-}
-
-MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
-                                     const cursor &b) noexcept {
-  return a.handle_ != b.handle_;
-}
-
-inline cursor::move_result::move_result(const cursor &cursor,
-                                        bool throw_notfound)
-    : pair_result(key, value, false) {
-  done = cursor.move(get_current, &key, &value, throw_notfound);
-}
-
-inline cursor::move_result::move_result(cursor &cursor,
-                                        move_operation operation,
-                                        bool throw_notfound)
-    : pair_result(key, value, false) {
-  done = cursor.move(operation, &key, &value, throw_notfound);
-}
-
-inline cursor::move_result::move_result(cursor &cursor,
-                                        move_operation operation,
-                                        const slice &key, bool throw_notfound)
-    : pair_result(key, slice(), false) {
-  this->done = cursor.move(operation, &this->key, &this->value, throw_notfound);
-}
-
-inline cursor::move_result::move_result(cursor &cursor,
-                                        move_operation operation,
-                                        const slice &key, const slice &value,
-                                        bool throw_notfound)
-    : pair_result(key, value, false) {
-  this->done = cursor.move(operation, &this->key, &this->value, throw_notfound);
-}
-
-inline bool cursor::move(move_operation operation, MDBX_val *key,
-                         MDBX_val *value, bool throw_notfound) const {
-  const int err =
-      ::mdbx_cursor_get(handle_, key, value, MDBX_cursor_op(operation));
-  switch (err) {
-  case MDBX_SUCCESS:
-    MDBX_CXX20_LIKELY return true;
-  case MDBX_NOTFOUND:
-    if (!throw_notfound)
-      return false;
-    MDBX_CXX17_FALLTHROUGH /* fallthrough */;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline ptrdiff_t cursor::estimate(move_operation operation, MDBX_val *key,
-                                  MDBX_val *value) const {
-  ptrdiff_t result;
-  error::success_or_throw(::mdbx_estimate_move(
-      *this, key, value, MDBX_cursor_op(operation), &result));
-  return result;
-}
-
-inline ptrdiff_t estimate(const cursor &from, const cursor &to) {
-  ptrdiff_t result;
-  error::success_or_throw(mdbx_estimate_distance(from, to, &result));
-  return result;
-}
-
-inline cursor::move_result cursor::move(move_operation operation,
-                                        bool throw_notfound) {
-  return move_result(*this, operation, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_first(bool throw_notfound) {
-  return move(first, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_previous(bool throw_notfound) {
-  return move(previous, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_previous_last_multi(bool throw_notfound) {
-  return move(multi_prevkey_lastvalue, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_current_first_multi(bool throw_notfound) {
-  return move(multi_currentkey_firstvalue, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_current_prev_multi(bool throw_notfound) {
-  return move(multi_currentkey_prevvalue, throw_notfound);
-}
-
-inline cursor::move_result cursor::current(bool throw_notfound) const {
-  return move_result(*this, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_current_next_multi(bool throw_notfound) {
-  return move(multi_currentkey_nextvalue, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_current_last_multi(bool throw_notfound) {
-  return move(multi_currentkey_lastvalue, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_next_first_multi(bool throw_notfound) {
-  return move(multi_nextkey_firstvalue, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_next(bool throw_notfound) {
-  return move(next, throw_notfound);
-}
-
-inline cursor::move_result cursor::to_last(bool throw_notfound) {
-  return move(last, throw_notfound);
-}
-
-inline cursor::move_result cursor::move(move_operation operation,
-                                        const slice &key, bool throw_notfound) {
-  return move_result(*this, operation, key, throw_notfound);
-}
-
-inline cursor::move_result cursor::find(const slice &key, bool throw_notfound) {
-  return move(key_exact, key, throw_notfound);
-}
-
-inline cursor::move_result cursor::lower_bound(const slice &key,
-                                               bool throw_notfound) {
-  return move(key_lowerbound, key, throw_notfound);
-}
-
-inline cursor::move_result cursor::move(move_operation operation,
-                                        const slice &key, const slice &value,
-                                        bool throw_notfound) {
-  return move_result(*this, operation, key, value, throw_notfound);
-}
-
-inline cursor::move_result cursor::find_multivalue(const slice &key,
-                                                   const slice &value,
-                                                   bool throw_notfound) {
-  return move(multi_find_pair, key, value, throw_notfound);
-}
-
-inline cursor::move_result cursor::lower_bound_multivalue(const slice &key,
-                                                          const slice &value,
-                                                          bool throw_notfound) {
-  return move(multi_exactkey_lowerboundvalue, key, value, throw_notfound);
-}
-
-inline bool cursor::seek(const slice &key) {
-  return move(find_key, const_cast<slice *>(&key), nullptr, false);
-}
-
-inline bool cursor::move(move_operation operation, slice &key, slice &value,
-                         bool throw_notfound) {
-  return move(operation, &key, &value, throw_notfound);
-}
-
-inline size_t cursor::count_multivalue() const {
-  size_t result;
-  error::success_or_throw(::mdbx_cursor_count(*this, &result));
-  return result;
-}
-
-inline bool cursor::eof() const {
-  return error::boolean_or_throw(::mdbx_cursor_eof(*this));
-}
-
-inline bool cursor::on_first() const {
-  return error::boolean_or_throw(::mdbx_cursor_on_first(*this));
-}
-
-inline bool cursor::on_last() const {
-  return error::boolean_or_throw(::mdbx_cursor_on_last(*this));
-}
-
-inline ptrdiff_t cursor::estimate(slice key, slice value) const {
-  return estimate(multi_exactkey_lowerboundvalue, &key, &value);
-}
-
-inline ptrdiff_t cursor::estimate(slice key) const {
-  return estimate(key_lowerbound, &key, nullptr);
-}
-
-inline ptrdiff_t cursor::estimate(move_operation operation) const {
-  slice unused_key;
-  return estimate(operation, &unused_key, nullptr);
-}
-
-inline void cursor::renew(::mdbx::txn &txn) {
-  error::success_or_throw(::mdbx_cursor_renew(txn, handle_));
-}
-
-inline void cursor::bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle) {
-  error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi));
-}
-
-inline txn cursor::txn() const {
-  MDBX_txn *txn = ::mdbx_cursor_txn(handle_);
-  error::throw_on_nullptr(txn, MDBX_EINVAL);
-  return ::mdbx::txn(txn);
-}
-
-inline map_handle cursor::map() const {
-  const MDBX_dbi dbi = ::mdbx_cursor_dbi(handle_);
-  if (MDBX_UNLIKELY(dbi > MDBX_MAX_DBI))
-    error::throw_exception(MDBX_EINVAL);
-  return map_handle(dbi);
-}
-
-inline MDBX_error_t cursor::put(const slice &key, slice *value,
-                                MDBX_put_flags_t flags) noexcept {
-  return MDBX_error_t(::mdbx_cursor_put(handle_, &key, value, flags));
-}
-
-inline void cursor::insert(const slice &key, slice value) {
-  error::success_or_throw(
-      put(key, &value /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique)));
-}
-
-inline value_result cursor::try_insert(const slice &key, slice value) {
-  const int err =
-      put(key, &value /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique));
-  switch (err) {
-  case MDBX_SUCCESS:
-    return value_result{slice(), true};
-  case MDBX_KEYEXIST:
-    return value_result{value, false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline slice cursor::insert_reserve(const slice &key, size_t value_length) {
-  slice result(nullptr, value_length);
-  error::success_or_throw(
-      put(key, &result /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique) | MDBX_RESERVE));
-  return result;
-}
-
-inline value_result cursor::try_insert_reserve(const slice &key,
-                                               size_t value_length) {
-  slice result(nullptr, value_length);
-  const int err =
-      put(key, &result /* takes the present value in case MDBX_KEYEXIST */,
-          MDBX_put_flags_t(put_mode::insert_unique) | MDBX_RESERVE);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return value_result{result, true};
-  case MDBX_KEYEXIST:
-    return value_result{result, false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline void cursor::upsert(const slice &key, const slice &value) {
-  error::success_or_throw(put(key, const_cast<slice *>(&value),
-                              MDBX_put_flags_t(put_mode::upsert)));
-}
-
-inline slice cursor::upsert_reserve(const slice &key, size_t value_length) {
-  slice result(nullptr, value_length);
-  error::success_or_throw(
-      put(key, &result, MDBX_put_flags_t(put_mode::upsert) | MDBX_RESERVE));
-  return result;
-}
-
-inline void cursor::update(const slice &key, const slice &value) {
-  error::success_or_throw(put(key, const_cast<slice *>(&value),
-                              MDBX_put_flags_t(put_mode::update)));
-}
-
-inline bool cursor::try_update(const slice &key, const slice &value) {
-  const int err =
-      put(key, const_cast<slice *>(&value), MDBX_put_flags_t(put_mode::update));
-  switch (err) {
-  case MDBX_SUCCESS:
-    return true;
-  case MDBX_NOTFOUND:
-    return false;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline slice cursor::update_reserve(const slice &key, size_t value_length) {
-  slice result(nullptr, value_length);
-  error::success_or_throw(
-      put(key, &result, MDBX_put_flags_t(put_mode::update) | MDBX_RESERVE));
-  return result;
-}
-
-inline value_result cursor::try_update_reserve(const slice &key,
-                                               size_t value_length) {
-  slice result(nullptr, value_length);
-  const int err =
-      put(key, &result, MDBX_put_flags_t(put_mode::update) | MDBX_RESERVE);
-  switch (err) {
-  case MDBX_SUCCESS:
-    return value_result{result, true};
-  case MDBX_NOTFOUND:
-    return value_result{slice(), false};
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline bool cursor::erase(bool whole_multivalue) {
-  const int err = ::mdbx_cursor_del(handle_, whole_multivalue ? MDBX_ALLDUPS
-                                                              : MDBX_CURRENT);
-  switch (err) {
-  case MDBX_SUCCESS:
-    MDBX_CXX20_LIKELY return true;
-  case MDBX_NOTFOUND:
-    return false;
-  default:
-    MDBX_CXX20_UNLIKELY error::throw_exception(err);
-  }
-}
-
-inline bool cursor::erase(const slice &key, bool whole_multivalue) {
-  bool found = seek(key);
-  return found ? erase(whole_multivalue) : found;
-}
-
-inline bool cursor::erase(const slice &key, const slice &value) {
-  move_result data = find_multivalue(key, value, false);
-  return data.done && erase();
-}
-
-} // namespace mdbx
-
-//------------------------------------------------------------------------------
-
-namespace std {
-
-inline string to_string(const ::mdbx::slice &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-template <class ALLOCATOR, typename CAPACITY_POLICY>
-inline string
-to_string(const ::mdbx::buffer<ALLOCATOR, CAPACITY_POLICY> &buffer) {
-  ostringstream out;
-  out << buffer;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::pair &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env::geometry &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env::operate_parameters &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env::mode &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env::durability &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env::reclaiming_options &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env::operate_options &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::env_managed::create_parameters &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::MDBX_log_level_t &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::MDBX_debug_flags_t &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::mdbx::error &value) {
-  ostringstream out;
-  out << value;
-  return out.str();
-}
-
-inline string to_string(const ::MDBX_error_t &errcode) {
-  return to_string(::mdbx::error(errcode));
-}
-
-template <> struct hash<::mdbx::slice> {
-  MDBX_CXX14_CONSTEXPR size_t
-  operator()(::mdbx::slice const &slice) const noexcept {
-    return slice.hash_value();
-  }
-};
-
-} // namespace std
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-/// @} end of C++ API
diff --git a/3rdparty/libmdbx/mdbx_chk.c b/3rdparty/libmdbx/mdbx_chk.c
deleted file mode 100644
index 27506c7386a1a0d0f74098883fc5f3dd06aafc7a..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx_chk.c
+++ /dev/null
@@ -1,5264 +0,0 @@
-/* mdbx_chk.c - memory-mapped database check tool */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#ifdef _MSC_VER
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
-#endif                          /* _MSC_VER (warnings) */
-
-#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-
-typedef struct flagbit {
-  int bit;
-  const char *name;
-} flagbit;
-
-const flagbit dbflags[] = {{MDBX_DUPSORT, "dupsort"},
-                           {MDBX_INTEGERKEY, "integerkey"},
-                           {MDBX_REVERSEKEY, "reversekey"},
-                           {MDBX_DUPFIXED, "dupfixed"},
-                           {MDBX_REVERSEDUP, "reversedup"},
-                           {MDBX_INTEGERDUP, "integerdup"},
-                           {0, nullptr}};
-
-#if defined(_WIN32) || defined(_WIN64)
-/*
- * POSIX getopt for Windows
- *
- * AT&T Public License
- *
- * Code given out at the 1985 UNIFORUM conference in Dallas.
- */
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-#endif /* _MSC_VER (warnings) */
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-/*----------------------------------------------------------------------------*/
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *opts) {
-  static int sp = 1;
-  int c;
-  const char *cp;
-
-  if (sp == 1) {
-    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
-      return EOF;
-    else if (strcmp(argv[optind], "--") == 0) {
-      optind++;
-      return EOF;
-    }
-  }
-  optopt = c = argv[optind][sp];
-  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
-    fprintf(stderr, "%s: %s -- %c\n", argv[0], "illegal option", c);
-    if (argv[optind][++sp] == '\0') {
-      optind++;
-      sp = 1;
-    }
-    return '?';
-  }
-  if (*++cp == ':') {
-    if (argv[optind][sp + 1] != '\0')
-      optarg = &argv[optind++][sp + 1];
-    else if (++optind >= argc) {
-      fprintf(stderr, "%s: %s -- %c\n", argv[0], "option requires an argument",
-              c);
-      sp = 1;
-      return '?';
-    } else
-      optarg = argv[optind++];
-    sp = 1;
-  } else {
-    if (argv[optind][++sp] == '\0') {
-      sp = 1;
-      optind++;
-    }
-    optarg = NULL;
-  }
-  return c;
-}
-
-static volatile BOOL user_break;
-static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
-  (void)dwCtrlType;
-  user_break = 1;
-  return true;
-}
-
-static uint64_t GetMilliseconds(void) {
-  LARGE_INTEGER Counter, Frequency;
-  return (QueryPerformanceFrequency(&Frequency) &&
-          QueryPerformanceCounter(&Counter))
-             ? Counter.QuadPart * 1000ul / Frequency.QuadPart
-             : 0;
-}
-
-#else /* WINDOWS */
-
-static volatile sig_atomic_t user_break;
-static void signal_handler(int sig) {
-  (void)sig;
-  user_break = 1;
-}
-
-#endif /* !WINDOWS */
-
-#define EXIT_INTERRUPTED (EXIT_FAILURE + 4)
-#define EXIT_FAILURE_SYS (EXIT_FAILURE + 3)
-#define EXIT_FAILURE_MDBX (EXIT_FAILURE + 2)
-#define EXIT_FAILURE_CHECK_MAJOR (EXIT_FAILURE + 1)
-#define EXIT_FAILURE_CHECK_MINOR EXIT_FAILURE
-
-typedef struct {
-  const char *name;
-  struct {
-    uint64_t branch, large_count, large_volume, leaf;
-    uint64_t subleaf_dupsort, leaf_dupfixed, subleaf_dupfixed;
-    uint64_t total, empty, other;
-  } pages;
-  uint64_t payload_bytes;
-  uint64_t lost_bytes;
-} walk_dbi_t;
-
-struct {
-  short *pagemap;
-  uint64_t total_payload_bytes;
-  uint64_t pgcount;
-  walk_dbi_t
-      dbi[MDBX_MAX_DBI + CORE_DBS + /* account pseudo-entry for meta */ 1];
-} walk;
-
-#define dbi_free walk.dbi[FREE_DBI]
-#define dbi_main walk.dbi[MAIN_DBI]
-#define dbi_meta walk.dbi[CORE_DBS]
-
-int envflags = MDBX_RDONLY | MDBX_EXCLUSIVE;
-MDBX_env *env;
-MDBX_txn *txn;
-MDBX_envinfo envinfo;
-size_t userdb_count, skipped_subdb;
-uint64_t total_unused_bytes, reclaimable_pages, gc_pages, alloc_pages,
-    unused_pages, backed_pages;
-unsigned verbose;
-bool ignore_wrong_order, quiet, dont_traversal;
-const char *only_subdb;
-int stuck_meta = -1;
-
-struct problem {
-  struct problem *pr_next;
-  size_t count;
-  const char *caption;
-};
-
-struct problem *problems_list;
-unsigned total_problems, data_tree_problems, gc_tree_problems;
-
-static void MDBX_PRINTF_ARGS(1, 2) print(const char *msg, ...) {
-  if (!quiet) {
-    va_list args;
-
-    fflush(stderr);
-    va_start(args, msg);
-    vfprintf(stdout, msg, args);
-    va_end(args);
-  }
-}
-
-static void va_log(MDBX_log_level_t level, const char *msg, va_list args) {
-  static const char *const prefixes[] = {
-      "!!!fatal: ",       " ! " /* error */,      " ~ " /* warning */,
-      "   " /* notice */, "   // " /* verbose */, "   //// " /* debug */,
-      "   ////// " /* trace */
-  };
-
-  FILE *out = stdout;
-  if (level <= MDBX_LOG_ERROR) {
-    total_problems++;
-    out = stderr;
-  }
-
-  if (!quiet && verbose + 1 >= (unsigned)level &&
-      (unsigned)level < ARRAY_LENGTH(prefixes)) {
-    fflush(nullptr);
-    fputs(prefixes[level], out);
-    vfprintf(out, msg, args);
-    if (msg[strlen(msg) - 1] != '\n')
-      fputc('\n', out);
-    fflush(nullptr);
-  }
-
-  if (level == MDBX_LOG_FATAL) {
-    exit(EXIT_FAILURE_MDBX);
-    abort();
-  }
-}
-
-static void MDBX_PRINTF_ARGS(1, 2) error(const char *msg, ...) {
-  va_list args;
-  va_start(args, msg);
-  va_log(MDBX_LOG_ERROR, msg, args);
-  va_end(args);
-}
-
-static void logger(MDBX_log_level_t level, const char *function, int line,
-                   const char *msg, va_list args) {
-  (void)line;
-  (void)function;
-  if (level < MDBX_LOG_EXTRA)
-    va_log(level, msg, args);
-}
-
-static int check_user_break(void) {
-  switch (user_break) {
-  case 0:
-    return MDBX_SUCCESS;
-  case 1:
-    print(" - interrupted by signal\n");
-    fflush(nullptr);
-    user_break = 2;
-  }
-  return MDBX_EINTR;
-}
-
-static void pagemap_cleanup(void) {
-  for (size_t i = CORE_DBS + /* account pseudo-entry for meta */ 1;
-       i < ARRAY_LENGTH(walk.dbi); ++i) {
-    if (walk.dbi[i].name) {
-      mdbx_free((void *)walk.dbi[i].name);
-      walk.dbi[i].name = nullptr;
-    }
-  }
-
-  mdbx_free(walk.pagemap);
-  walk.pagemap = nullptr;
-}
-
-static walk_dbi_t *pagemap_lookup_dbi(const char *dbi_name, bool silent) {
-  static walk_dbi_t *last;
-
-  if (dbi_name == MDBX_PGWALK_MAIN)
-    return &dbi_main;
-  if (dbi_name == MDBX_PGWALK_GC)
-    return &dbi_free;
-  if (dbi_name == MDBX_PGWALK_META)
-    return &dbi_meta;
-
-  if (last && strcmp(last->name, dbi_name) == 0)
-    return last;
-
-  walk_dbi_t *dbi = walk.dbi + CORE_DBS + /* account pseudo-entry for meta */ 1;
-  for (; dbi < ARRAY_END(walk.dbi) && dbi->name; ++dbi) {
-    if (strcmp(dbi->name, dbi_name) == 0)
-      return last = dbi;
-  }
-
-  if (verbose > 0 && !silent) {
-    print(" - found '%s' area\n", dbi_name);
-    fflush(nullptr);
-  }
-
-  if (dbi == ARRAY_END(walk.dbi))
-    return nullptr;
-
-  dbi->name = mdbx_strdup(dbi_name);
-  return last = dbi;
-}
-
-static void MDBX_PRINTF_ARGS(4, 5)
-    problem_add(const char *object, uint64_t entry_number, const char *msg,
-                const char *extra, ...) {
-  total_problems++;
-
-  if (!quiet) {
-    int need_fflush = 0;
-    struct problem *p;
-
-    for (p = problems_list; p; p = p->pr_next)
-      if (p->caption == msg)
-        break;
-
-    if (!p) {
-      p = mdbx_calloc(1, sizeof(*p));
-      if (unlikely(!p))
-        return;
-      p->caption = msg;
-      p->pr_next = problems_list;
-      problems_list = p;
-      need_fflush = 1;
-    }
-
-    p->count++;
-    if (verbose > 1) {
-      print("     %s #%" PRIu64 ": %s", object, entry_number, msg);
-      if (extra) {
-        va_list args;
-        printf(" (");
-        va_start(args, extra);
-        vfprintf(stdout, extra, args);
-        va_end(args);
-        printf(")");
-      }
-      printf("\n");
-      if (need_fflush)
-        fflush(nullptr);
-    }
-  }
-}
-
-static struct problem *problems_push(void) {
-  struct problem *p = problems_list;
-  problems_list = nullptr;
-  return p;
-}
-
-static size_t problems_pop(struct problem *list) {
-  size_t count = 0;
-
-  if (problems_list) {
-    int i;
-
-    print(" - problems: ");
-    for (i = 0; problems_list; ++i) {
-      struct problem *p = problems_list->pr_next;
-      count += problems_list->count;
-      print("%s%s (%" PRIuPTR ")", i ? ", " : "", problems_list->caption,
-            problems_list->count);
-      mdbx_free(problems_list);
-      problems_list = p;
-    }
-    print("\n");
-    fflush(nullptr);
-  }
-
-  problems_list = list;
-  return count;
-}
-
-static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
-                     void *const ctx, const int deep,
-                     const char *const dbi_name_or_tag, const size_t page_size,
-                     const MDBX_page_type_t pagetype, const MDBX_error_t err,
-                     const size_t nentries, const size_t payload_bytes,
-                     const size_t header_bytes, const size_t unused_bytes) {
-  (void)ctx;
-  const bool is_gc_tree = dbi_name_or_tag == MDBX_PGWALK_GC;
-  if (deep > 42) {
-    problem_add("deep", deep, "too large", nullptr);
-    data_tree_problems += !is_gc_tree;
-    gc_tree_problems += is_gc_tree;
-    return MDBX_CORRUPTED /* avoid infinite loop/recursion */;
-  }
-
-  walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false);
-  if (!dbi) {
-    data_tree_problems += !is_gc_tree;
-    gc_tree_problems += is_gc_tree;
-    return MDBX_ENOMEM;
-  }
-
-  const size_t page_bytes = payload_bytes + header_bytes + unused_bytes;
-  walk.pgcount += pgnumber;
-
-  const char *pagetype_caption;
-  bool branch = false;
-  switch (pagetype) {
-  default:
-    problem_add("page", pgno, "unknown page-type", "type %u, deep %i",
-                (unsigned)pagetype, deep);
-    pagetype_caption = "unknown";
-    dbi->pages.other += pgnumber;
-    data_tree_problems += !is_gc_tree;
-    gc_tree_problems += is_gc_tree;
-    break;
-  case MDBX_page_broken:
-    pagetype_caption = "broken";
-    dbi->pages.other += pgnumber;
-    data_tree_problems += !is_gc_tree;
-    gc_tree_problems += is_gc_tree;
-    break;
-  case MDBX_subpage_broken:
-    pagetype_caption = "broken-subpage";
-    data_tree_problems += !is_gc_tree;
-    gc_tree_problems += is_gc_tree;
-    break;
-  case MDBX_page_meta:
-    pagetype_caption = "meta";
-    dbi->pages.other += pgnumber;
-    break;
-  case MDBX_page_large:
-    pagetype_caption = "large";
-    dbi->pages.large_volume += pgnumber;
-    dbi->pages.large_count += 1;
-    break;
-  case MDBX_page_branch:
-    pagetype_caption = "branch";
-    dbi->pages.branch += pgnumber;
-    branch = true;
-    break;
-  case MDBX_page_leaf:
-    pagetype_caption = "leaf";
-    dbi->pages.leaf += pgnumber;
-    break;
-  case MDBX_page_dupfixed_leaf:
-    pagetype_caption = "leaf-dupfixed";
-    dbi->pages.leaf_dupfixed += pgnumber;
-    break;
-  case MDBX_subpage_leaf:
-    pagetype_caption = "subleaf-dupsort";
-    dbi->pages.subleaf_dupsort += 1;
-    break;
-  case MDBX_subpage_dupfixed_leaf:
-    pagetype_caption = "subleaf-dupfixed";
-    dbi->pages.subleaf_dupfixed += 1;
-    break;
-  }
-
-  if (pgnumber) {
-    if (verbose > 3 && (!only_subdb || strcmp(only_subdb, dbi->name) == 0)) {
-      if (pgnumber == 1)
-        print("     %s-page %" PRIu64, pagetype_caption, pgno);
-      else
-        print("     %s-span %" PRIu64 "[%u]", pagetype_caption, pgno, pgnumber);
-      print(" of %s: header %" PRIiPTR ", %s %" PRIiPTR ", payload %" PRIiPTR
-            ", unused %" PRIiPTR ", deep %i\n",
-            dbi->name, header_bytes,
-            (pagetype == MDBX_page_branch) ? "keys" : "entries", nentries,
-            payload_bytes, unused_bytes, deep);
-    }
-
-    bool already_used = false;
-    for (unsigned n = 0; n < pgnumber; ++n) {
-      uint64_t spanpgno = pgno + n;
-      if (spanpgno >= alloc_pages) {
-        problem_add("page", spanpgno, "wrong page-no",
-                    "%s-page: %" PRIu64 " > %" PRIu64 ", deep %i",
-                    pagetype_caption, spanpgno, alloc_pages, deep);
-        data_tree_problems += !is_gc_tree;
-        gc_tree_problems += is_gc_tree;
-      } else if (walk.pagemap[spanpgno]) {
-        walk_dbi_t *coll_dbi = &walk.dbi[walk.pagemap[spanpgno] - 1];
-        problem_add("page", spanpgno,
-                    (branch && coll_dbi == dbi) ? "loop" : "already used",
-                    "%s-page: by %s, deep %i", pagetype_caption, coll_dbi->name,
-                    deep);
-        already_used = true;
-        data_tree_problems += !is_gc_tree;
-        gc_tree_problems += is_gc_tree;
-      } else {
-        walk.pagemap[spanpgno] = (short)(dbi - walk.dbi + 1);
-        dbi->pages.total += 1;
-      }
-    }
-
-    if (already_used)
-      return branch ? MDBX_RESULT_TRUE /* avoid infinite loop/recursion */
-                    : MDBX_SUCCESS;
-  }
-
-  if (MDBX_IS_ERROR(err)) {
-    problem_add("page", pgno, "invalid/corrupted", "%s-page", pagetype_caption);
-    data_tree_problems += !is_gc_tree;
-    gc_tree_problems += is_gc_tree;
-  } else {
-    if (unused_bytes > page_size) {
-      problem_add("page", pgno, "illegal unused-bytes",
-                  "%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0,
-                  unused_bytes, envinfo.mi_dxb_pagesize);
-      data_tree_problems += !is_gc_tree;
-      gc_tree_problems += is_gc_tree;
-    }
-
-    if (header_bytes < (int)sizeof(long) ||
-        (size_t)header_bytes >= envinfo.mi_dxb_pagesize - sizeof(long)) {
-      problem_add("page", pgno, "illegal header-length",
-                  "%s-page: %" PRIuPTR " < %" PRIuPTR " < %" PRIuPTR,
-                  pagetype_caption, sizeof(long), header_bytes,
-                  envinfo.mi_dxb_pagesize - sizeof(long));
-      data_tree_problems += !is_gc_tree;
-      gc_tree_problems += is_gc_tree;
-    }
-    if (payload_bytes < 1) {
-      if (nentries > 1) {
-        problem_add("page", pgno, "zero size-of-entry",
-                    "%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR " entries",
-                    pagetype_caption, payload_bytes, nentries);
-        /* if ((size_t)header_bytes + unused_bytes < page_size) {
-          // LY: hush a misuse error
-          page_bytes = page_size;
-        } */
-        data_tree_problems += !is_gc_tree;
-        gc_tree_problems += is_gc_tree;
-      } else {
-        problem_add("page", pgno, "empty",
-                    "%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
-                    " entries, deep %i",
-                    pagetype_caption, payload_bytes, nentries, deep);
-        dbi->pages.empty += 1;
-        data_tree_problems += !is_gc_tree;
-        gc_tree_problems += is_gc_tree;
-      }
-    }
-
-    if (pgnumber) {
-      if (page_bytes != page_size) {
-        problem_add("page", pgno, "misused",
-                    "%s-page: %" PRIuPTR " != %" PRIuPTR " (%" PRIuPTR
-                    "h + %" PRIuPTR "p + %" PRIuPTR "u), deep %i",
-                    pagetype_caption, page_size, page_bytes, header_bytes,
-                    payload_bytes, unused_bytes, deep);
-        if (page_size > page_bytes)
-          dbi->lost_bytes += page_size - page_bytes;
-        data_tree_problems += !is_gc_tree;
-        gc_tree_problems += is_gc_tree;
-      } else {
-        dbi->payload_bytes += payload_bytes + header_bytes;
-        walk.total_payload_bytes += payload_bytes + header_bytes;
-      }
-    }
-  }
-
-  return check_user_break();
-}
-
-typedef int(visitor)(const uint64_t record_number, const MDBX_val *key,
-                     const MDBX_val *data);
-static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
-                      bool silent);
-
-static int handle_userdb(const uint64_t record_number, const MDBX_val *key,
-                         const MDBX_val *data) {
-  (void)record_number;
-  (void)key;
-  (void)data;
-  return check_user_break();
-}
-
-static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
-                         const MDBX_val *data) {
-  char *bad = "";
-  pgno_t *iptr = data->iov_base;
-
-  if (key->iov_len != sizeof(txnid_t))
-    problem_add("entry", record_number, "wrong txn-id size",
-                "key-size %" PRIiPTR, key->iov_len);
-  else {
-    txnid_t txnid;
-    memcpy(&txnid, key->iov_base, sizeof(txnid));
-    if (txnid < 1 || txnid > envinfo.mi_recent_txnid)
-      problem_add("entry", record_number, "wrong txn-id", "%" PRIaTXN, txnid);
-    else {
-      if (data->iov_len < sizeof(pgno_t) || data->iov_len % sizeof(pgno_t))
-        problem_add("entry", txnid, "wrong idl size", "%" PRIuPTR,
-                    data->iov_len);
-      size_t number = (data->iov_len >= sizeof(pgno_t)) ? *iptr++ : 0;
-      if (number < 1 || number > MDBX_PGL_LIMIT)
-        problem_add("entry", txnid, "wrong idl length", "%" PRIuPTR, number);
-      else if ((number + 1) * sizeof(pgno_t) > data->iov_len) {
-        problem_add("entry", txnid, "trimmed idl",
-                    "%" PRIuSIZE " > %" PRIuSIZE " (corruption)",
-                    (number + 1) * sizeof(pgno_t), data->iov_len);
-        number = data->iov_len / sizeof(pgno_t) - 1;
-      } else if (data->iov_len - (number + 1) * sizeof(pgno_t) >=
-                 /* LY: allow gap up to one page. it is ok
-                  * and better than shink-and-retry inside mdbx_update_gc() */
-                 envinfo.mi_dxb_pagesize)
-        problem_add("entry", txnid, "extra idl space",
-                    "%" PRIuSIZE " < %" PRIuSIZE " (minor, not a trouble)",
-                    (number + 1) * sizeof(pgno_t), data->iov_len);
-
-      gc_pages += number;
-      if (envinfo.mi_latter_reader_txnid > txnid)
-        reclaimable_pages += number;
-
-      pgno_t prev = MDBX_PNL_ASCENDING ? NUM_METAS - 1 : txn->mt_next_pgno;
-      pgno_t span = 1;
-      for (unsigned i = 0; i < number; ++i) {
-        if (check_user_break())
-          return MDBX_EINTR;
-        const pgno_t pgno = iptr[i];
-        if (pgno < NUM_METAS)
-          problem_add("entry", txnid, "wrong idl entry",
-                      "pgno %" PRIaPGNO " < meta-pages %u", pgno, NUM_METAS);
-        else if (pgno >= backed_pages)
-          problem_add("entry", txnid, "wrong idl entry",
-                      "pgno %" PRIaPGNO " > backed-pages %" PRIu64, pgno,
-                      backed_pages);
-        else if (pgno >= alloc_pages)
-          problem_add("entry", txnid, "wrong idl entry",
-                      "pgno %" PRIaPGNO " > alloc-pages %" PRIu64, pgno,
-                      alloc_pages - 1);
-        else {
-          if (MDBX_PNL_DISORDERED(prev, pgno)) {
-            bad = " [bad sequence]";
-            problem_add("entry", txnid, "bad sequence",
-                        "%" PRIaPGNO " %c [%u].%" PRIaPGNO, prev,
-                        (prev == pgno) ? '=' : (MDBX_PNL_ASCENDING ? '>' : '<'),
-                        i, pgno);
-          }
-          if (walk.pagemap) {
-            int idx = walk.pagemap[pgno];
-            if (idx == 0)
-              walk.pagemap[pgno] = -1;
-            else if (idx > 0)
-              problem_add("page", pgno, "already used", "by %s",
-                          walk.dbi[idx - 1].name);
-            else
-              problem_add("page", pgno, "already listed in GC", nullptr);
-          }
-        }
-        prev = pgno;
-        while (i + span < number &&
-               iptr[i + span] == (MDBX_PNL_ASCENDING ? pgno_add(pgno, span)
-                                                     : pgno_sub(pgno, span)))
-          ++span;
-      }
-      if (verbose > 3 && !only_subdb) {
-        print("     transaction %" PRIaTXN ", %" PRIuPTR
-              " pages, maxspan %" PRIaPGNO "%s\n",
-              txnid, number, span, bad);
-        if (verbose > 4) {
-          for (unsigned i = 0; i < number; i += span) {
-            const pgno_t pgno = iptr[i];
-            for (span = 1;
-                 i + span < number &&
-                 iptr[i + span] == (MDBX_PNL_ASCENDING ? pgno_add(pgno, span)
-                                                       : pgno_sub(pgno, span));
-                 ++span)
-              ;
-            if (span > 1) {
-              print("    %9" PRIaPGNO "[%" PRIaPGNO "]\n", pgno, span);
-            } else
-              print("    %9" PRIaPGNO "\n", pgno);
-          }
-        }
-      }
-    }
-  }
-
-  return check_user_break();
-}
-
-static int equal_or_greater(const MDBX_val *a, const MDBX_val *b) {
-  return (a->iov_len == b->iov_len &&
-          memcmp(a->iov_base, b->iov_base, a->iov_len) == 0)
-             ? 0
-             : 1;
-}
-
-static int handle_maindb(const uint64_t record_number, const MDBX_val *key,
-                         const MDBX_val *data) {
-  char *name;
-  int rc;
-  size_t i;
-
-  name = key->iov_base;
-  for (i = 0; i < key->iov_len; ++i) {
-    if (name[i] < ' ')
-      return handle_userdb(record_number, key, data);
-  }
-
-  name = mdbx_malloc(key->iov_len + 1);
-  if (unlikely(!name))
-    return MDBX_ENOMEM;
-  memcpy(name, key->iov_base, key->iov_len);
-  name[key->iov_len] = '\0';
-  userdb_count++;
-
-  rc = process_db(~0u, name, handle_userdb, false);
-  mdbx_free(name);
-  if (rc != MDBX_INCOMPATIBLE)
-    return rc;
-
-  return handle_userdb(record_number, key, data);
-}
-
-static const char *db_flags2keymode(unsigned flags) {
-  flags &= (MDBX_REVERSEKEY | MDBX_INTEGERKEY);
-  switch (flags) {
-  case 0:
-    return "usual";
-  case MDBX_REVERSEKEY:
-    return "reserve";
-  case MDBX_INTEGERKEY:
-    return "ordinal";
-  case MDBX_REVERSEKEY | MDBX_INTEGERKEY:
-    return "msgpack";
-  default:
-    assert(false);
-    __unreachable();
-  }
-}
-
-static const char *db_flags2valuemode(unsigned flags) {
-  flags &= (MDBX_DUPSORT | MDBX_REVERSEDUP | MDBX_DUPFIXED | MDBX_INTEGERDUP);
-  switch (flags) {
-  case 0:
-    return "single";
-  case MDBX_DUPSORT:
-    return "multi";
-  case MDBX_REVERSEDUP:
-  case MDBX_DUPSORT | MDBX_REVERSEDUP:
-    return "multi-reverse";
-  case MDBX_DUPFIXED:
-  case MDBX_DUPSORT | MDBX_DUPFIXED:
-    return "multi-samelength";
-  case MDBX_DUPFIXED | MDBX_REVERSEDUP:
-  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_REVERSEDUP:
-    return "multi-reverse-samelength";
-  case MDBX_INTEGERDUP:
-  case MDBX_DUPSORT | MDBX_INTEGERDUP:
-  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP:
-  case MDBX_DUPFIXED | MDBX_INTEGERDUP:
-    return "multi-ordinal";
-  case MDBX_INTEGERDUP | MDBX_REVERSEDUP:
-  case MDBX_DUPSORT | MDBX_INTEGERDUP | MDBX_REVERSEDUP:
-    return "multi-msgpack";
-  case MDBX_DUPFIXED | MDBX_INTEGERDUP | MDBX_REVERSEDUP:
-  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP | MDBX_REVERSEDUP:
-    return "reserved";
-  default:
-    assert(false);
-    __unreachable();
-  }
-}
-
-static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
-                      bool silent) {
-  MDBX_cursor *mc;
-  MDBX_stat ms;
-  MDBX_val key, data;
-  MDBX_val prev_key, prev_data;
-  unsigned flags;
-  int rc, i;
-  struct problem *saved_list;
-  uint64_t problems_count;
-
-  uint64_t record_count = 0, dups = 0;
-  uint64_t key_bytes = 0, data_bytes = 0;
-
-  if ((MDBX_TXN_FINISHED | MDBX_TXN_ERROR) & mdbx_txn_flags(txn)) {
-    print(" ! abort processing '%s' due to a previous error\n",
-          dbi_name ? dbi_name : "@MAIN");
-    return MDBX_BAD_TXN;
-  }
-
-  if (dbi_handle == ~0u) {
-    rc = mdbx_dbi_open_ex(
-        txn, dbi_name, MDBX_DB_ACCEDE, &dbi_handle,
-        (dbi_name && ignore_wrong_order) ? equal_or_greater : nullptr,
-        (dbi_name && ignore_wrong_order) ? equal_or_greater : nullptr);
-    if (rc) {
-      if (!dbi_name ||
-          rc !=
-              MDBX_INCOMPATIBLE) /* LY: mainDB's record is not a user's DB. */ {
-        error("mdbx_dbi_open('%s') failed, error %d %s\n",
-              dbi_name ? dbi_name : "main", rc, mdbx_strerror(rc));
-      }
-      return rc;
-    }
-  }
-
-  if (dbi_handle >= CORE_DBS && dbi_name && only_subdb &&
-      strcmp(only_subdb, dbi_name) != 0) {
-    if (verbose) {
-      print("Skip processing '%s'...\n", dbi_name);
-      fflush(nullptr);
-    }
-    skipped_subdb++;
-    return MDBX_SUCCESS;
-  }
-
-  if (!silent && verbose) {
-    print("Processing '%s'...\n", dbi_name ? dbi_name : "@MAIN");
-    fflush(nullptr);
-  }
-
-  rc = mdbx_dbi_flags(txn, dbi_handle, &flags);
-  if (rc) {
-    error("mdbx_dbi_flags() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    return rc;
-  }
-
-  rc = mdbx_dbi_stat(txn, dbi_handle, &ms, sizeof(ms));
-  if (rc) {
-    error("mdbx_dbi_stat() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    return rc;
-  }
-
-  if (!silent && verbose) {
-    print(" - key-value kind: %s-key => %s-value", db_flags2keymode(flags),
-          db_flags2valuemode(flags));
-    if (verbose > 1) {
-      print(", flags:");
-      if (!flags)
-        print(" none");
-      else {
-        for (i = 0; dbflags[i].bit; i++)
-          if (flags & dbflags[i].bit)
-            print(" %s", dbflags[i].name);
-      }
-      if (verbose > 2)
-        print(" (0x%02X), dbi-id %d", flags, dbi_handle);
-    }
-    print("\n");
-    if (ms.ms_mod_txnid)
-      print(" - last modification txn#%" PRIu64 "\n", ms.ms_mod_txnid);
-    if (verbose > 1) {
-      print(" - page size %u, entries %" PRIu64 "\n", ms.ms_psize,
-            ms.ms_entries);
-      print(" - b-tree depth %u, pages: branch %" PRIu64 ", leaf %" PRIu64
-            ", overflow %" PRIu64 "\n",
-            ms.ms_depth, ms.ms_branch_pages, ms.ms_leaf_pages,
-            ms.ms_overflow_pages);
-    }
-  }
-
-  walk_dbi_t *dbi = (dbi_handle < CORE_DBS)
-                        ? &walk.dbi[dbi_handle]
-                        : pagemap_lookup_dbi(dbi_name, true);
-  if (!dbi) {
-    error("too many DBIs or out of memory\n");
-    return MDBX_ENOMEM;
-  }
-  if (!dont_traversal) {
-    const uint64_t subtotal_pages =
-        ms.ms_branch_pages + ms.ms_leaf_pages + ms.ms_overflow_pages;
-    if (subtotal_pages != dbi->pages.total)
-      error("%s pages mismatch (%" PRIu64 " != walked %" PRIu64 ")\n",
-            "subtotal", subtotal_pages, dbi->pages.total);
-    if (ms.ms_branch_pages != dbi->pages.branch)
-      error("%s pages mismatch (%" PRIu64 " != walked %" PRIu64 ")\n", "branch",
-            ms.ms_branch_pages, dbi->pages.branch);
-    const uint64_t allleaf_pages = dbi->pages.leaf + dbi->pages.leaf_dupfixed;
-    if (ms.ms_leaf_pages != allleaf_pages)
-      error("%s pages mismatch (%" PRIu64 " != walked %" PRIu64 ")\n",
-            "all-leaf", ms.ms_leaf_pages, allleaf_pages);
-    if (ms.ms_overflow_pages != dbi->pages.large_volume)
-      error("%s pages mismatch (%" PRIu64 " != walked %" PRIu64 ")\n",
-            "large/overlow", ms.ms_overflow_pages, dbi->pages.large_volume);
-  }
-  rc = mdbx_cursor_open(txn, dbi_handle, &mc);
-  if (rc) {
-    error("mdbx_cursor_open() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    return rc;
-  }
-
-  if (ignore_wrong_order) { /* for debugging with enabled assertions */
-    mc->mc_flags |= C_SKIPORD;
-    if (mc->mc_xcursor)
-      mc->mc_xcursor->mx_cursor.mc_flags |= C_SKIPORD;
-  }
-
-  const size_t maxkeysize = mdbx_env_get_maxkeysize_ex(env, flags);
-  saved_list = problems_push();
-  prev_key.iov_base = nullptr;
-  prev_key.iov_len = 0;
-  prev_data.iov_base = nullptr;
-  prev_data.iov_len = 0;
-  rc = mdbx_cursor_get(mc, &key, &data, MDBX_FIRST);
-  while (rc == MDBX_SUCCESS) {
-    rc = check_user_break();
-    if (rc)
-      goto bailout;
-
-    bool bad_key = false;
-    if (key.iov_len > maxkeysize) {
-      problem_add("entry", record_count, "key length exceeds max-key-size",
-                  "%" PRIuPTR " > %" PRIuPTR, key.iov_len, maxkeysize);
-      bad_key = true;
-    } else if ((flags & MDBX_INTEGERKEY) && key.iov_len != sizeof(uint64_t) &&
-               key.iov_len != sizeof(uint32_t)) {
-      problem_add("entry", record_count, "wrong key length",
-                  "%" PRIuPTR " != 4or8", key.iov_len);
-      bad_key = true;
-    }
-
-    bool bad_data = false;
-    if ((flags & MDBX_INTEGERDUP) && data.iov_len != sizeof(uint64_t) &&
-        data.iov_len != sizeof(uint32_t)) {
-      problem_add("entry", record_count, "wrong data length",
-                  "%" PRIuPTR " != 4or8", data.iov_len);
-      bad_data = true;
-    }
-
-    if (prev_key.iov_base) {
-      if (prev_data.iov_base && !bad_data && (flags & MDBX_DUPFIXED) &&
-          prev_data.iov_len != data.iov_len) {
-        problem_add("entry", record_count, "different data length",
-                    "%" PRIuPTR " != %" PRIuPTR, prev_data.iov_len,
-                    data.iov_len);
-        bad_data = true;
-      }
-
-      if (!bad_key) {
-        int cmp = mdbx_cmp(txn, dbi_handle, &key, &prev_key);
-        if (cmp == 0) {
-          ++dups;
-          if ((flags & MDBX_DUPSORT) == 0) {
-            problem_add("entry", record_count, "duplicated entries", nullptr);
-            if (prev_data.iov_base && data.iov_len == prev_data.iov_len &&
-                memcmp(data.iov_base, prev_data.iov_base, data.iov_len) == 0) {
-              problem_add("entry", record_count, "complete duplicate", nullptr);
-            }
-          } else if (!bad_data && prev_data.iov_base) {
-            cmp = mdbx_dcmp(txn, dbi_handle, &data, &prev_data);
-            if (cmp == 0) {
-              problem_add("entry", record_count, "complete duplicate", nullptr);
-            } else if (cmp < 0 && !ignore_wrong_order) {
-              problem_add("entry", record_count, "wrong order of multi-values",
-                          nullptr);
-            }
-          }
-        } else if (cmp < 0 && !ignore_wrong_order) {
-          problem_add("entry", record_count, "wrong order of entries", nullptr);
-        }
-      }
-    }
-
-    if (handler) {
-      rc = handler(record_count, &key, &data);
-      if (MDBX_IS_ERROR(rc))
-        goto bailout;
-    }
-
-    record_count++;
-    key_bytes += key.iov_len;
-    data_bytes += data.iov_len;
-
-    if (!bad_key) {
-      if (verbose && (flags & MDBX_INTEGERKEY) && !prev_key.iov_base)
-        print(" - fixed key-size %" PRIuPTR "\n", key.iov_len);
-      prev_key = key;
-    }
-    if (!bad_data) {
-      if (verbose && (flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) &&
-          !prev_data.iov_base)
-        print(" - fixed data-size %" PRIuPTR "\n", data.iov_len);
-      prev_data = data;
-    }
-    rc = mdbx_cursor_get(mc, &key, &data, MDBX_NEXT);
-  }
-  if (rc != MDBX_NOTFOUND)
-    error("mdbx_cursor_get() failed, error %d %s\n", rc, mdbx_strerror(rc));
-  else
-    rc = 0;
-
-  if (record_count != ms.ms_entries)
-    problem_add("entry", record_count, "different number of entries",
-                "%" PRIu64 " != %" PRIu64, record_count, ms.ms_entries);
-bailout:
-  problems_count = problems_pop(saved_list);
-  if (!silent && verbose) {
-    print(" - summary: %" PRIu64 " records, %" PRIu64 " dups, %" PRIu64
-          " key's bytes, %" PRIu64 " data's "
-          "bytes, %" PRIu64 " problems\n",
-          record_count, dups, key_bytes, data_bytes, problems_count);
-    fflush(nullptr);
-  }
-
-  mdbx_cursor_close(mc);
-  return (rc || problems_count) ? MDBX_RESULT_TRUE : MDBX_SUCCESS;
-}
-
-static void usage(char *prog) {
-  fprintf(stderr,
-          "usage: %s [-V] [-v] [-q] [-c] [-0|1|2] [-w] [-d] [-i] [-s subdb] "
-          "dbpath\n"
-          "  -V\t\tprint version and exit\n"
-          "  -v\t\tmore verbose, could be used multiple times\n"
-          "  -q\t\tbe quiet\n"
-          "  -c\t\tforce cooperative mode (don't try exclusive)\n"
-          "  -w\t\twrite-mode checking\n"
-          "  -d\t\tdisable page-by-page traversal of B-tree\n"
-          "  -i\t\tignore wrong order errors (for custom comparators case)\n"
-          "  -s subdb\tprocess a specific subdatabase only\n"
-          "  -0|1|2\tforce using specific meta-page 0, or 2 for checking\n"
-          "  -t\t\tturn to a specified meta-page on successful check\n"
-          "  -T\t\tturn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!\n",
-          prog);
-  exit(EXIT_INTERRUPTED);
-}
-
-static bool meta_ot(txnid_t txn_a, uint64_t sign_a, txnid_t txn_b,
-                    uint64_t sign_b, const bool wanna_steady) {
-  if (txn_a == txn_b)
-    return SIGN_IS_STEADY(sign_b);
-
-  if (wanna_steady && SIGN_IS_STEADY(sign_a) != SIGN_IS_STEADY(sign_b))
-    return SIGN_IS_STEADY(sign_b);
-
-  return txn_a < txn_b;
-}
-
-static bool meta_eq(txnid_t txn_a, uint64_t sign_a, txnid_t txn_b,
-                    uint64_t sign_b) {
-  if (!txn_a || txn_a != txn_b)
-    return false;
-
-  if (SIGN_IS_STEADY(sign_a) != SIGN_IS_STEADY(sign_b))
-    return false;
-
-  return true;
-}
-
-static int meta_recent(const bool wanna_steady) {
-  if (meta_ot(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
-              envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign, wanna_steady))
-    return meta_ot(envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign,
-                   envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign, wanna_steady)
-               ? 1
-               : 2;
-  else
-    return meta_ot(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
-                   envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign, wanna_steady)
-               ? 2
-               : 0;
-}
-
-static int meta_tail(int head) {
-  switch (head) {
-  case 0:
-    return meta_ot(envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign,
-                   envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign, true)
-               ? 1
-               : 2;
-  case 1:
-    return meta_ot(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
-                   envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign, true)
-               ? 0
-               : 2;
-  case 2:
-    return meta_ot(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
-                   envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign, true)
-               ? 0
-               : 1;
-  default:
-    assert(false);
-    return -1;
-  }
-}
-
-static int meta_head(void) { return meta_recent(false); }
-
-void verbose_meta(int num, txnid_t txnid, uint64_t sign, uint64_t bootid_x,
-                  uint64_t bootid_y) {
-  const bool have_bootid = (bootid_x | bootid_y) != 0;
-  const bool bootid_match = bootid_x == envinfo.mi_bootid.current.x &&
-                            bootid_y == envinfo.mi_bootid.current.y;
-
-  print(" - meta-%d: ", num);
-  switch (sign) {
-  case MDBX_DATASIGN_NONE:
-    print("no-sync/legacy");
-    break;
-  case MDBX_DATASIGN_WEAK:
-    print("weak-%s", bootid_match ? (have_bootid ? "intact (same boot-id)"
-                                                 : "unknown (no boot-id")
-                                  : "dead");
-    break;
-  default:
-    print("steady");
-    break;
-  }
-  print(" txn#%" PRIu64, txnid);
-
-  const int head = meta_head();
-  if (num == head)
-    print(", head");
-  else if (num == meta_tail(head))
-    print(", tail");
-  else
-    print(", stay");
-
-  if (stuck_meta >= 0) {
-    if (num == stuck_meta)
-      print(", forced for checking");
-  } else if (txnid > envinfo.mi_recent_txnid &&
-             (envflags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) == MDBX_EXCLUSIVE)
-    print(", rolled-back %" PRIu64 " (%" PRIu64 " >>> %" PRIu64 ")",
-          txnid - envinfo.mi_recent_txnid, txnid, envinfo.mi_recent_txnid);
-  print("\n");
-}
-
-static uint64_t get_meta_txnid(const unsigned meta_id) {
-  switch (meta_id) {
-  default:
-    assert(false);
-    error("unexpected meta_id %u\n", meta_id);
-    return 0;
-  case 0:
-    return envinfo.mi_meta0_txnid;
-  case 1:
-    return envinfo.mi_meta1_txnid;
-  case 2:
-    return envinfo.mi_meta2_txnid;
-  }
-}
-
-static void print_size(const char *prefix, const uint64_t value,
-                       const char *suffix) {
-  const char sf[] =
-      "KMGTPEZY"; /* LY: Kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta! */
-  double k = 1024.0;
-  size_t i;
-  for (i = 0; sf[i + 1] && value / k > 1000.0; ++i)
-    k *= 1024;
-  print("%s%" PRIu64 " (%.2f %cb)%s", prefix, value, value / k, sf[i], suffix);
-}
-
-int main(int argc, char *argv[]) {
-  int rc;
-  char *prog = argv[0];
-  char *envname;
-  unsigned problems_maindb = 0, problems_freedb = 0, problems_meta = 0;
-  bool write_locked = false;
-  bool turn_meta = false;
-  bool force_turn_meta = false;
-
-  double elapsed;
-#if defined(_WIN32) || defined(_WIN64)
-  uint64_t timestamp_start, timestamp_finish;
-  timestamp_start = GetMilliseconds();
-#else
-  struct timespec timestamp_start, timestamp_finish;
-  if (clock_gettime(CLOCK_MONOTONIC, &timestamp_start)) {
-    rc = errno;
-    error("clock_gettime() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    return EXIT_FAILURE_SYS;
-  }
-#endif
-
-  dbi_meta.name = "@META";
-  dbi_free.name = "@GC";
-  dbi_main.name = "@MAIN";
-  atexit(pagemap_cleanup);
-
-  if (argc < 2)
-    usage(prog);
-
-  for (int i; (i = getopt(argc, argv,
-                          "0"
-                          "1"
-                          "2"
-                          "T"
-                          "V"
-                          "v"
-                          "q"
-                          "n"
-                          "w"
-                          "c"
-                          "t"
-                          "d"
-                          "i"
-                          "s:")) != EOF;) {
-    switch (i) {
-    case 'V':
-      printf("mdbx_chk version %d.%d.%d.%d\n"
-             " - source: %s %s, commit %s, tree %s\n"
-             " - anchor: %s\n"
-             " - build: %s for %s by %s\n"
-             " - flags: %s\n"
-             " - options: %s\n",
-             mdbx_version.major, mdbx_version.minor, mdbx_version.release,
-             mdbx_version.revision, mdbx_version.git.describe,
-             mdbx_version.git.datetime, mdbx_version.git.commit,
-             mdbx_version.git.tree, mdbx_sourcery_anchor, mdbx_build.datetime,
-             mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
-             mdbx_build.options);
-      return EXIT_SUCCESS;
-    case 'v':
-      verbose++;
-      break;
-    case '0':
-      stuck_meta = 0;
-      break;
-    case '1':
-      stuck_meta = 1;
-      break;
-    case '2':
-      stuck_meta = 2;
-      break;
-    case 't':
-      turn_meta = true;
-      break;
-    case 'T':
-      turn_meta = force_turn_meta = true;
-      quiet = false;
-      if (verbose < 2)
-        verbose = 2;
-      break;
-    case 'q':
-      quiet = true;
-      break;
-    case 'n':
-      break;
-    case 'w':
-      envflags &= ~MDBX_RDONLY;
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-      /* Temporary `workaround` for OpenBSD kernel's flaw.
-       * See todo4recovery://erased_by_github/libmdbx/issues/67 */
-      envflags |= MDBX_WRITEMAP;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-      break;
-    case 'c':
-      envflags = (envflags & ~MDBX_EXCLUSIVE) | MDBX_ACCEDE;
-      break;
-    case 'd':
-      dont_traversal = true;
-      break;
-    case 's':
-      if (only_subdb && strcmp(only_subdb, optarg))
-        usage(prog);
-      only_subdb = optarg;
-      break;
-    case 'i':
-      ignore_wrong_order = true;
-      break;
-    default:
-      usage(prog);
-    }
-  }
-
-  if (optind != argc - 1)
-    usage(prog);
-
-  rc = MDBX_SUCCESS;
-  if (stuck_meta >= 0 && (envflags & MDBX_EXCLUSIVE) == 0) {
-    error("exclusive mode is required to using specific meta-page(%d) for "
-          "checking.\n",
-          stuck_meta);
-    rc = EXIT_INTERRUPTED;
-  }
-  if (turn_meta) {
-    if (stuck_meta < 0) {
-      error("meta-page must be specified (by -0, -1 or -2 options) to turn to "
-            "it.\n");
-      rc = EXIT_INTERRUPTED;
-    }
-    if (envflags & MDBX_RDONLY) {
-      error("write-mode must be enabled to turn to the specified meta-page.\n");
-      rc = EXIT_INTERRUPTED;
-    }
-    if (only_subdb || dont_traversal) {
-      error("whole database checking with tree-traversal are required to turn "
-            "to the specified meta-page.\n");
-      rc = EXIT_INTERRUPTED;
-    }
-  }
-  if (rc)
-    exit(rc);
-
-#if defined(_WIN32) || defined(_WIN64)
-  SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
-#else
-#ifdef SIGPIPE
-  signal(SIGPIPE, signal_handler);
-#endif
-#ifdef SIGHUP
-  signal(SIGHUP, signal_handler);
-#endif
-  signal(SIGINT, signal_handler);
-  signal(SIGTERM, signal_handler);
-#endif /* !WINDOWS */
-
-  envname = argv[optind];
-  print("mdbx_chk %s (%s, T-%s)\nRunning for %s in 'read-%s' mode...\n",
-        mdbx_version.git.describe, mdbx_version.git.datetime,
-        mdbx_version.git.tree, envname,
-        (envflags & MDBX_RDONLY) ? "only" : "write");
-  fflush(nullptr);
-  mdbx_setup_debug((verbose < MDBX_LOG_TRACE - 1)
-                       ? (MDBX_log_level_t)(verbose + 1)
-                       : MDBX_LOG_TRACE,
-                   MDBX_DBG_LEGACY_OVERLAP | MDBX_DBG_DONT_UPGRADE, logger);
-
-  rc = mdbx_env_create(&env);
-  if (rc) {
-    error("mdbx_env_create() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    return rc < 0 ? EXIT_FAILURE_MDBX : EXIT_FAILURE_SYS;
-  }
-
-  rc = mdbx_env_set_maxdbs(env, MDBX_MAX_DBI);
-  if (rc) {
-    error("mdbx_env_set_maxdbs() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    goto bailout;
-  }
-
-  if (stuck_meta >= 0) {
-    rc = mdbx_env_open_for_recovery(env, envname, stuck_meta,
-                                    (envflags & MDBX_RDONLY) ? false : true);
-  } else {
-    rc = mdbx_env_open(env, envname, envflags, 0);
-    if ((envflags & MDBX_EXCLUSIVE) &&
-        (rc == MDBX_BUSY ||
-#if defined(_WIN32) || defined(_WIN64)
-         rc == ERROR_LOCK_VIOLATION || rc == ERROR_SHARING_VIOLATION
-#else
-         rc == EBUSY || rc == EAGAIN
-#endif
-         )) {
-      envflags &= ~MDBX_EXCLUSIVE;
-      rc = mdbx_env_open(env, envname, envflags | MDBX_ACCEDE, 0);
-    }
-  }
-
-  if (rc) {
-    error("mdbx_env_open() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    if (rc == MDBX_WANNA_RECOVERY && (envflags & MDBX_RDONLY))
-      print("Please run %s in the read-write mode (with '-w' option).\n", prog);
-    goto bailout;
-  }
-  if (verbose)
-    print(" - %s mode\n",
-          (envflags & MDBX_EXCLUSIVE) ? "monopolistic" : "cooperative");
-
-  if ((envflags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == 0) {
-    rc = mdbx_txn_lock(env, false);
-    if (rc != MDBX_SUCCESS) {
-      error("mdbx_txn_lock() failed, error %d %s\n", rc, mdbx_strerror(rc));
-      goto bailout;
-    }
-    write_locked = true;
-  }
-
-  rc = mdbx_txn_begin(env, nullptr, MDBX_TXN_RDONLY, &txn);
-  if (rc) {
-    error("mdbx_txn_begin() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    goto bailout;
-  }
-
-  rc = mdbx_env_info_ex(env, txn, &envinfo, sizeof(envinfo));
-  if (rc) {
-    error("mdbx_env_info_ex() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    goto bailout;
-  }
-  if (verbose) {
-    print(" - current boot-id ");
-    if (envinfo.mi_bootid.current.x | envinfo.mi_bootid.current.y)
-      print("%016" PRIx64 "-%016" PRIx64 "\n", envinfo.mi_bootid.current.x,
-            envinfo.mi_bootid.current.y);
-    else
-      print("unavailable\n");
-  }
-
-  mdbx_filehandle_t dxb_fd;
-  rc = mdbx_env_get_fd(env, &dxb_fd);
-  if (rc) {
-    error("mdbx_env_get_fd() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    goto bailout;
-  }
-
-  uint64_t dxb_filesize = 0;
-#if defined(_WIN32) || defined(_WIN64)
-  {
-    BY_HANDLE_FILE_INFORMATION info;
-    if (!GetFileInformationByHandle(dxb_fd, &info))
-      rc = GetLastError();
-    else
-      dxb_filesize = info.nFileSizeLow | (uint64_t)info.nFileSizeHigh << 32;
-  }
-#else
-  {
-    struct stat st;
-    STATIC_ASSERT_MSG(sizeof(off_t) <= sizeof(uint64_t),
-                      "libmdbx requires 64-bit file I/O on 64-bit systems");
-    if (fstat(dxb_fd, &st))
-      rc = errno;
-    else
-      dxb_filesize = st.st_size;
-  }
-#endif
-  if (rc) {
-    error("mdbx_filesize() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    goto bailout;
-  }
-
-  errno = 0;
-  const uint64_t dxbfile_pages = dxb_filesize / envinfo.mi_dxb_pagesize;
-  alloc_pages = txn->mt_next_pgno;
-  backed_pages = envinfo.mi_geo.current / envinfo.mi_dxb_pagesize;
-  if (backed_pages > dxbfile_pages) {
-    print(" ! backed-pages %" PRIu64 " > file-pages %" PRIu64 "\n",
-          backed_pages, dxbfile_pages);
-    ++problems_meta;
-  }
-  if (dxbfile_pages < NUM_METAS)
-    print(" ! file-pages %" PRIu64 " < %u\n", dxbfile_pages, NUM_METAS);
-  if (backed_pages < NUM_METAS)
-    print(" ! backed-pages %" PRIu64 " < %u\n", backed_pages, NUM_METAS);
-  if (backed_pages < NUM_METAS || dxbfile_pages < NUM_METAS)
-    goto bailout;
-  if (backed_pages > MAX_PAGENO + 1) {
-    print(" ! backed-pages %" PRIu64 " > max-pages %" PRIaPGNO "\n",
-          backed_pages, MAX_PAGENO + 1);
-    ++problems_meta;
-    backed_pages = MAX_PAGENO + 1;
-  }
-
-  if ((envflags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) != MDBX_RDONLY) {
-    if (backed_pages > dxbfile_pages) {
-      print(" ! backed-pages %" PRIu64 " > file-pages %" PRIu64 "\n",
-            backed_pages, dxbfile_pages);
-      ++problems_meta;
-      backed_pages = dxbfile_pages;
-    }
-    if (alloc_pages > backed_pages) {
-      print(" ! alloc-pages %" PRIu64 " > backed-pages %" PRIu64 "\n",
-            alloc_pages, backed_pages);
-      ++problems_meta;
-      alloc_pages = backed_pages;
-    }
-  } else {
-    /* LY: DB may be shrinked by writer down to the allocated pages. */
-    if (alloc_pages > backed_pages) {
-      print(" ! alloc-pages %" PRIu64 " > backed-pages %" PRIu64 "\n",
-            alloc_pages, backed_pages);
-      ++problems_meta;
-      alloc_pages = backed_pages;
-    }
-    if (alloc_pages > dxbfile_pages) {
-      print(" ! alloc-pages %" PRIu64 " > file-pages %" PRIu64 "\n",
-            alloc_pages, dxbfile_pages);
-      ++problems_meta;
-      alloc_pages = dxbfile_pages;
-    }
-    if (backed_pages > dxbfile_pages)
-      backed_pages = dxbfile_pages;
-  }
-
-  if (verbose) {
-    print(" - pagesize %u (%u system), max keysize %d..%d"
-          ", max readers %u\n",
-          envinfo.mi_dxb_pagesize, envinfo.mi_sys_pagesize,
-          mdbx_env_get_maxkeysize_ex(env, MDBX_DUPSORT),
-          mdbx_env_get_maxkeysize_ex(env, 0), envinfo.mi_maxreaders);
-    print_size(" - mapsize ", envinfo.mi_mapsize, "\n");
-    if (envinfo.mi_geo.lower == envinfo.mi_geo.upper)
-      print_size(" - fixed datafile: ", envinfo.mi_geo.current, "");
-    else {
-      print_size(" - dynamic datafile: ", envinfo.mi_geo.lower, "");
-      print_size(" .. ", envinfo.mi_geo.upper, ", ");
-      print_size("+", envinfo.mi_geo.grow, ", ");
-      print_size("-", envinfo.mi_geo.shrink, "\n");
-      print_size(" - current datafile: ", envinfo.mi_geo.current, "");
-    }
-    printf(", %" PRIu64 " pages\n",
-           envinfo.mi_geo.current / envinfo.mi_dxb_pagesize);
-#if defined(_WIN32) || defined(_WIN64)
-    if (envinfo.mi_geo.shrink && envinfo.mi_geo.current != envinfo.mi_geo.upper)
-      print(
-          "                     WARNING: Due Windows system limitations a "
-          "file couldn't\n                     be truncated while the database "
-          "is opened. So, the size\n                     database file "
-          "of may by large than the database itself,\n                     "
-          "until it will be closed or reopened in read-write mode.\n");
-#endif
-    verbose_meta(0, envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
-                 envinfo.mi_bootid.meta0.x, envinfo.mi_bootid.meta0.y);
-    verbose_meta(1, envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign,
-                 envinfo.mi_bootid.meta1.x, envinfo.mi_bootid.meta1.y);
-    verbose_meta(2, envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign,
-                 envinfo.mi_bootid.meta2.x, envinfo.mi_bootid.meta2.y);
-  }
-
-  if (stuck_meta >= 0) {
-    if (verbose) {
-      print(" - skip checking meta-pages since the %u"
-            " is selected for verification\n",
-            stuck_meta);
-      print(" - transactions: recent %" PRIu64
-            ", selected for verification %" PRIu64 ", lag %" PRIi64 "\n",
-            envinfo.mi_recent_txnid, get_meta_txnid(stuck_meta),
-            envinfo.mi_recent_txnid - get_meta_txnid(stuck_meta));
-    }
-  } else {
-    if (verbose > 1)
-      print(" - performs check for meta-pages clashes\n");
-    if (meta_eq(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
-                envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign)) {
-      print(" ! meta-%d and meta-%d are clashed\n", 0, 1);
-      ++problems_meta;
-    }
-    if (meta_eq(envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign,
-                envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign)) {
-      print(" ! meta-%d and meta-%d are clashed\n", 1, 2);
-      ++problems_meta;
-    }
-    if (meta_eq(envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign,
-                envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign)) {
-      print(" ! meta-%d and meta-%d are clashed\n", 2, 0);
-      ++problems_meta;
-    }
-
-    const unsigned steady_meta_id = meta_recent(true);
-    const uint64_t steady_meta_txnid = get_meta_txnid(steady_meta_id);
-    const unsigned weak_meta_id = meta_recent(false);
-    const uint64_t weak_meta_txnid = get_meta_txnid(weak_meta_id);
-    if (envflags & MDBX_EXCLUSIVE) {
-      if (verbose > 1)
-        print(" - performs full check recent-txn-id with meta-pages\n");
-      if (steady_meta_txnid != envinfo.mi_recent_txnid) {
-        print(" ! steady meta-%d txn-id mismatch recent-txn-id (%" PRIi64
-              " != %" PRIi64 ")\n",
-              steady_meta_id, steady_meta_txnid, envinfo.mi_recent_txnid);
-        ++problems_meta;
-      }
-    } else if (write_locked) {
-      if (verbose > 1)
-        print(" - performs lite check recent-txn-id with meta-pages (not a "
-              "monopolistic mode)\n");
-      if (weak_meta_txnid != envinfo.mi_recent_txnid) {
-        print(" ! weak meta-%d txn-id mismatch recent-txn-id (%" PRIi64
-              " != %" PRIi64 ")\n",
-              weak_meta_id, weak_meta_txnid, envinfo.mi_recent_txnid);
-        ++problems_meta;
-      }
-    } else if (verbose) {
-      print(" - skip check recent-txn-id with meta-pages (monopolistic or "
-            "read-write mode only)\n");
-    }
-    total_problems += problems_meta;
-
-    if (verbose)
-      print(" - transactions: recent %" PRIu64 ", latter reader %" PRIu64
-            ", lag %" PRIi64 "\n",
-            envinfo.mi_recent_txnid, envinfo.mi_latter_reader_txnid,
-            envinfo.mi_recent_txnid - envinfo.mi_latter_reader_txnid);
-  }
-
-  if (!dont_traversal) {
-    struct problem *saved_list;
-    size_t traversal_problems;
-    uint64_t empty_pages, lost_bytes;
-
-    print("Traversal b-tree by txn#%" PRIaTXN "...\n", txn->mt_txnid);
-    fflush(nullptr);
-    walk.pagemap = mdbx_calloc((size_t)backed_pages, sizeof(*walk.pagemap));
-    if (!walk.pagemap) {
-      rc = errno ? errno : MDBX_ENOMEM;
-      error("calloc() failed, error %d %s\n", rc, mdbx_strerror(rc));
-      goto bailout;
-    }
-
-    saved_list = problems_push();
-    rc = mdbx_env_pgwalk(txn, pgvisitor, nullptr,
-                         true /* always skip key ordering checking to avoid
-                               MDBX_CORRUPTED when using custom comparators */);
-    traversal_problems = problems_pop(saved_list);
-
-    if (rc) {
-      if (rc != MDBX_EINTR || !check_user_break())
-        error("mdbx_env_pgwalk() failed, error %d %s\n", rc, mdbx_strerror(rc));
-      goto bailout;
-    }
-
-    for (uint64_t n = 0; n < alloc_pages; ++n)
-      if (!walk.pagemap[n])
-        unused_pages += 1;
-
-    empty_pages = lost_bytes = 0;
-    for (walk_dbi_t *dbi = &dbi_main; dbi < ARRAY_END(walk.dbi) && dbi->name;
-         ++dbi) {
-      empty_pages += dbi->pages.empty;
-      lost_bytes += dbi->lost_bytes;
-    }
-
-    if (verbose) {
-      uint64_t total_page_bytes = walk.pgcount * envinfo.mi_dxb_pagesize;
-      print(" - pages: walked %" PRIu64 ", left/unused %" PRIu64 "\n",
-            walk.pgcount, unused_pages);
-      if (verbose > 1) {
-        for (walk_dbi_t *dbi = walk.dbi; dbi < ARRAY_END(walk.dbi) && dbi->name;
-             ++dbi) {
-          print("     %s: subtotal %" PRIu64, dbi->name, dbi->pages.total);
-          if (dbi->pages.other && dbi->pages.other != dbi->pages.total)
-            print(", other %" PRIu64, dbi->pages.other);
-          if (dbi->pages.branch)
-            print(", branch %" PRIu64, dbi->pages.branch);
-          if (dbi->pages.large_count)
-            print(", large %" PRIu64, dbi->pages.large_count);
-          uint64_t all_leaf = dbi->pages.leaf + dbi->pages.leaf_dupfixed;
-          if (all_leaf) {
-            print(", leaf %" PRIu64, all_leaf);
-            if (verbose > 2 &&
-                (dbi->pages.subleaf_dupsort | dbi->pages.leaf_dupfixed |
-                 dbi->pages.subleaf_dupfixed))
-              print(" (usual %" PRIu64 ", sub-dupsort %" PRIu64
-                    ", dupfixed %" PRIu64 ", sub-dupfixed %" PRIu64 ")",
-                    dbi->pages.leaf, dbi->pages.subleaf_dupsort,
-                    dbi->pages.leaf_dupfixed, dbi->pages.subleaf_dupfixed);
-          }
-          print("\n");
-        }
-      }
-
-      if (verbose > 1)
-        print(" - usage: total %" PRIu64 " bytes, payload %" PRIu64
-              " (%.1f%%), unused "
-              "%" PRIu64 " (%.1f%%)\n",
-              total_page_bytes, walk.total_payload_bytes,
-              walk.total_payload_bytes * 100.0 / total_page_bytes,
-              total_page_bytes - walk.total_payload_bytes,
-              (total_page_bytes - walk.total_payload_bytes) * 100.0 /
-                  total_page_bytes);
-      if (verbose > 2) {
-        for (walk_dbi_t *dbi = walk.dbi; dbi < ARRAY_END(walk.dbi) && dbi->name;
-             ++dbi)
-          if (dbi->pages.total) {
-            uint64_t dbi_bytes = dbi->pages.total * envinfo.mi_dxb_pagesize;
-            print("     %s: subtotal %" PRIu64 " bytes (%.1f%%),"
-                  " payload %" PRIu64 " (%.1f%%), unused %" PRIu64 " (%.1f%%)",
-                  dbi->name, dbi_bytes, dbi_bytes * 100.0 / total_page_bytes,
-                  dbi->payload_bytes, dbi->payload_bytes * 100.0 / dbi_bytes,
-                  dbi_bytes - dbi->payload_bytes,
-                  (dbi_bytes - dbi->payload_bytes) * 100.0 / dbi_bytes);
-            if (dbi->pages.empty)
-              print(", %" PRIu64 " empty pages", dbi->pages.empty);
-            if (dbi->lost_bytes)
-              print(", %" PRIu64 " bytes lost", dbi->lost_bytes);
-            print("\n");
-          } else
-            print("     %s: empty\n", dbi->name);
-      }
-      print(" - summary: average fill %.1f%%",
-            walk.total_payload_bytes * 100.0 / total_page_bytes);
-      if (empty_pages)
-        print(", %" PRIu64 " empty pages", empty_pages);
-      if (lost_bytes)
-        print(", %" PRIu64 " bytes lost", lost_bytes);
-      print(", %" PRIuPTR " problems\n", traversal_problems);
-    }
-  } else if (verbose) {
-    print("Skipping b-tree walk...\n");
-    fflush(nullptr);
-  }
-
-  if (!verbose)
-    print("Iterating DBIs...\n");
-  if (data_tree_problems) {
-    print("Skip processing %s since tree is corrupted (%u problems)\n", "@MAIN",
-          data_tree_problems);
-    problems_maindb = data_tree_problems;
-  } else
-    problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr, false);
-
-  if (gc_tree_problems) {
-    print("Skip processing %s since tree is corrupted (%u problems)\n", "@GC",
-          gc_tree_problems);
-    problems_freedb = gc_tree_problems;
-  } else
-    problems_freedb = process_db(FREE_DBI, "@GC", handle_freedb, false);
-
-  if (verbose) {
-    uint64_t value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize;
-    double percent = value / 100.0;
-    print(" - space: %" PRIu64 " total pages", value);
-    print(", backed %" PRIu64 " (%.1f%%)", backed_pages,
-          backed_pages / percent);
-    print(", allocated %" PRIu64 " (%.1f%%)", alloc_pages,
-          alloc_pages / percent);
-
-    if (verbose > 1) {
-      value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize - alloc_pages;
-      print(", remained %" PRIu64 " (%.1f%%)", value, value / percent);
-
-      value = dont_traversal ? alloc_pages - gc_pages : walk.pgcount;
-      print(", used %" PRIu64 " (%.1f%%)", value, value / percent);
-
-      print(", gc %" PRIu64 " (%.1f%%)", gc_pages, gc_pages / percent);
-
-      value = gc_pages - reclaimable_pages;
-      print(", detained %" PRIu64 " (%.1f%%)", value, value / percent);
-
-      print(", reclaimable %" PRIu64 " (%.1f%%)", reclaimable_pages,
-            reclaimable_pages / percent);
-    }
-
-    value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize - alloc_pages +
-            reclaimable_pages;
-    print(", available %" PRIu64 " (%.1f%%)\n", value, value / percent);
-  }
-
-  if (problems_maindb == 0 && problems_freedb == 0) {
-    if (!dont_traversal &&
-        (envflags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) != MDBX_RDONLY) {
-      if (walk.pgcount != alloc_pages - gc_pages) {
-        error("used pages mismatch (%" PRIu64 "(walked) != %" PRIu64
-              "(allocated - GC))\n",
-              walk.pgcount, alloc_pages - gc_pages);
-      }
-      if (unused_pages != gc_pages) {
-        error("gc pages mismatch (%" PRIu64 "(expected) != %" PRIu64 "(GC))\n",
-              unused_pages, gc_pages);
-      }
-    } else if (verbose) {
-      print(" - skip check used and gc pages (btree-traversal with "
-            "monopolistic or read-write mode only)\n");
-    }
-
-    if (!process_db(MAIN_DBI, nullptr, handle_maindb, true)) {
-      if (!userdb_count && verbose)
-        print(" - does not contain multiple databases\n");
-    }
-  }
-
-  if (rc == 0 && total_problems == 1 && problems_meta == 1 && !dont_traversal &&
-      (envflags & MDBX_RDONLY) == 0 && !only_subdb && stuck_meta < 0 &&
-      get_meta_txnid(meta_recent(true)) < envinfo.mi_recent_txnid) {
-    print("Perform sync-to-disk for make steady checkpoint at txn-id #%" PRIi64
-          "\n",
-          envinfo.mi_recent_txnid);
-    fflush(nullptr);
-    if (write_locked) {
-      mdbx_txn_unlock(env);
-      write_locked = false;
-    }
-    rc = mdbx_env_sync_ex(env, true, false);
-    if (rc != MDBX_SUCCESS)
-      error("mdbx_env_pgwalk() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    else {
-      total_problems -= 1;
-      problems_meta -= 1;
-    }
-  }
-
-  if (turn_meta && stuck_meta >= 0 && !dont_traversal && !only_subdb &&
-      (envflags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == MDBX_EXCLUSIVE) {
-    const bool successful_check = (rc | total_problems | problems_meta) == 0;
-    if (successful_check || force_turn_meta) {
-      fflush(nullptr);
-      print(" = Performing turn to the specified meta-page (%d) due to %s!\n",
-            stuck_meta,
-            successful_check ? "successful check" : "the -T option was given");
-      fflush(nullptr);
-      rc = mdbx_env_turn_for_recovery(env, stuck_meta);
-      if (rc != MDBX_SUCCESS)
-        error("mdbx_env_turn_for_recovery() failed, error %d %s\n", rc,
-              mdbx_strerror(rc));
-    } else {
-      print(" = Skipping turn to the specified meta-page (%d) due to "
-            "unsuccessful check!\n",
-            stuck_meta);
-    }
-  }
-
-bailout:
-  if (txn)
-    mdbx_txn_abort(txn);
-  if (write_locked) {
-    mdbx_txn_unlock(env);
-    write_locked = false;
-  }
-  if (env) {
-    const bool dont_sync = rc != 0 || total_problems;
-    mdbx_env_close_ex(env, dont_sync);
-  }
-  fflush(nullptr);
-  if (rc) {
-    if (rc < 0)
-      return user_break ? EXIT_INTERRUPTED : EXIT_FAILURE_SYS;
-    return EXIT_FAILURE_MDBX;
-  }
-
-#if defined(_WIN32) || defined(_WIN64)
-  timestamp_finish = GetMilliseconds();
-  elapsed = (timestamp_finish - timestamp_start) * 1e-3;
-#else
-  if (clock_gettime(CLOCK_MONOTONIC, &timestamp_finish)) {
-    rc = errno;
-    error("clock_gettime() failed, error %d %s\n", rc, mdbx_strerror(rc));
-    return EXIT_FAILURE_SYS;
-  }
-  elapsed = timestamp_finish.tv_sec - timestamp_start.tv_sec +
-            (timestamp_finish.tv_nsec - timestamp_start.tv_nsec) * 1e-9;
-#endif /* !WINDOWS */
-
-  if (total_problems) {
-    print("Total %u error%s detected, elapsed %.3f seconds.\n", total_problems,
-          (total_problems > 1) ? "s are" : " is", elapsed);
-    if (problems_meta || problems_maindb || problems_freedb)
-      return EXIT_FAILURE_CHECK_MAJOR;
-    return EXIT_FAILURE_CHECK_MINOR;
-  }
-  print("No error is detected, elapsed %.3f seconds\n", elapsed);
-  return EXIT_SUCCESS;
-}
diff --git a/3rdparty/libmdbx/mdbx_copy.c b/3rdparty/libmdbx/mdbx_copy.c
deleted file mode 100644
index 8cfc4f5cfff71f0135b10d9c9df78d9feda35a37..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx_copy.c
+++ /dev/null
@@ -1,3660 +0,0 @@
-/* mdbx_copy.c - memory-mapped database backup tool */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#ifdef _MSC_VER
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
-#endif                          /* _MSC_VER (warnings) */
-
-#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-
-#if defined(_WIN32) || defined(_WIN64)
-/*
- * POSIX getopt for Windows
- *
- * AT&T Public License
- *
- * Code given out at the 1985 UNIFORUM conference in Dallas.
- */
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-#endif /* _MSC_VER (warnings) */
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-/*----------------------------------------------------------------------------*/
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *opts) {
-  static int sp = 1;
-  int c;
-  const char *cp;
-
-  if (sp == 1) {
-    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
-      return EOF;
-    else if (strcmp(argv[optind], "--") == 0) {
-      optind++;
-      return EOF;
-    }
-  }
-  optopt = c = argv[optind][sp];
-  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
-    fprintf(stderr, "%s: %s -- %c\n", argv[0], "illegal option", c);
-    if (argv[optind][++sp] == '\0') {
-      optind++;
-      sp = 1;
-    }
-    return '?';
-  }
-  if (*++cp == ':') {
-    if (argv[optind][sp + 1] != '\0')
-      optarg = &argv[optind++][sp + 1];
-    else if (++optind >= argc) {
-      fprintf(stderr, "%s: %s -- %c\n", argv[0], "option requires an argument",
-              c);
-      sp = 1;
-      return '?';
-    } else
-      optarg = argv[optind++];
-    sp = 1;
-  } else {
-    if (argv[optind][++sp] == '\0') {
-      sp = 1;
-      optind++;
-    }
-    optarg = NULL;
-  }
-  return c;
-}
-
-static volatile BOOL user_break;
-static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
-  (void)dwCtrlType;
-  user_break = true;
-  return true;
-}
-
-#else /* WINDOWS */
-
-static volatile sig_atomic_t user_break;
-static void signal_handler(int sig) {
-  (void)sig;
-  user_break = 1;
-}
-
-#endif /* !WINDOWS */
-
-static void usage(const char *prog) {
-  fprintf(stderr,
-          "usage: %s [-V] [-q] [-c] src_path [dest_path]\n"
-          "  -V\t\tprint version and exit\n"
-          "  -q\t\tbe quiet\n"
-          "  -c\t\tenable compactification (skip unused pages)\n"
-          "  src_path\tsource database\n"
-          "  dest_path\tdestination (stdout if not specified)\n",
-          prog);
-  exit(EXIT_FAILURE);
-}
-
-int main(int argc, char *argv[]) {
-  int rc;
-  MDBX_env *env = NULL;
-  const char *progname = argv[0], *act;
-  unsigned flags = MDBX_RDONLY;
-  unsigned cpflags = 0;
-  bool quiet = false;
-
-  for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
-    if (argv[1][1] == 'n' && argv[1][2] == '\0')
-      flags |= MDBX_NOSUBDIR;
-    else if (argv[1][1] == 'c' && argv[1][2] == '\0')
-      cpflags |= MDBX_CP_COMPACT;
-    else if (argv[1][1] == 'q' && argv[1][2] == '\0')
-      quiet = true;
-    else if ((argv[1][1] == 'h' && argv[1][2] == '\0') ||
-             strcmp(argv[1], "--help") == 0)
-      usage(progname);
-    else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
-      printf("mdbx_copy version %d.%d.%d.%d\n"
-             " - source: %s %s, commit %s, tree %s\n"
-             " - anchor: %s\n"
-             " - build: %s for %s by %s\n"
-             " - flags: %s\n"
-             " - options: %s\n",
-             mdbx_version.major, mdbx_version.minor, mdbx_version.release,
-             mdbx_version.revision, mdbx_version.git.describe,
-             mdbx_version.git.datetime, mdbx_version.git.commit,
-             mdbx_version.git.tree, mdbx_sourcery_anchor, mdbx_build.datetime,
-             mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
-             mdbx_build.options);
-      return EXIT_SUCCESS;
-    } else
-      argc = 0;
-  }
-
-  if (argc < 2 || argc > 3)
-    usage(progname);
-
-#if defined(_WIN32) || defined(_WIN64)
-  SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
-#else
-#ifdef SIGPIPE
-  signal(SIGPIPE, signal_handler);
-#endif
-#ifdef SIGHUP
-  signal(SIGHUP, signal_handler);
-#endif
-  signal(SIGINT, signal_handler);
-  signal(SIGTERM, signal_handler);
-#endif /* !WINDOWS */
-
-  if (!quiet) {
-    fprintf((argc == 2) ? stderr : stdout,
-            "mdbx_copy %s (%s, T-%s)\nRunning for copy %s to %s...\n",
-            mdbx_version.git.describe, mdbx_version.git.datetime,
-            mdbx_version.git.tree, argv[1], (argc == 2) ? "stdout" : argv[2]);
-    fflush(NULL);
-  }
-
-  act = "opening environment";
-  rc = mdbx_env_create(&env);
-  if (rc == MDBX_SUCCESS)
-    rc = mdbx_env_open(env, argv[1], flags, 0);
-
-  if (rc == MDBX_SUCCESS) {
-    act = "copying";
-    if (argc == 2) {
-      mdbx_filehandle_t fd;
-#if defined(_WIN32) || defined(_WIN64)
-      fd = GetStdHandle(STD_OUTPUT_HANDLE);
-#else
-      fd = fileno(stdout);
-#endif
-      rc = mdbx_env_copy2fd(env, fd, cpflags);
-    } else
-      rc = mdbx_env_copy(env, argv[2], cpflags);
-  }
-  if (rc)
-    fprintf(stderr, "%s: %s failed, error %d (%s)\n", progname, act, rc,
-            mdbx_strerror(rc));
-  mdbx_env_close(env);
-
-  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/3rdparty/libmdbx/mdbx_drop.c b/3rdparty/libmdbx/mdbx_drop.c
deleted file mode 100644
index 9b0487161c459e4f5382b73ce67c602d3958bc62..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx_drop.c
+++ /dev/null
@@ -1,3715 +0,0 @@
-/* mdbx_drop.c - memory-mapped database delete tool */
-
-/*
- * Copyright 2021 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- *
- * Copyright 2016-2022 Howard Chu, Symas Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#ifdef _MSC_VER
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
-#endif                          /* _MSC_VER (warnings) */
-
-#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-
-#include <ctype.h>
-
-#if defined(_WIN32) || defined(_WIN64)
-/*
- * POSIX getopt for Windows
- *
- * AT&T Public License
- *
- * Code given out at the 1985 UNIFORUM conference in Dallas.
- */
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-#endif /* _MSC_VER (warnings) */
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-/*----------------------------------------------------------------------------*/
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *opts) {
-  static int sp = 1;
-  int c;
-  const char *cp;
-
-  if (sp == 1) {
-    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
-      return EOF;
-    else if (strcmp(argv[optind], "--") == 0) {
-      optind++;
-      return EOF;
-    }
-  }
-  optopt = c = argv[optind][sp];
-  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
-    fprintf(stderr, "%s: %s -- %c\n", argv[0], "illegal option", c);
-    if (argv[optind][++sp] == '\0') {
-      optind++;
-      sp = 1;
-    }
-    return '?';
-  }
-  if (*++cp == ':') {
-    if (argv[optind][sp + 1] != '\0')
-      optarg = &argv[optind++][sp + 1];
-    else if (++optind >= argc) {
-      fprintf(stderr, "%s: %s -- %c\n", argv[0], "option requires an argument",
-              c);
-      sp = 1;
-      return '?';
-    } else
-      optarg = argv[optind++];
-    sp = 1;
-  } else {
-    if (argv[optind][++sp] == '\0') {
-      sp = 1;
-      optind++;
-    }
-    optarg = NULL;
-  }
-  return c;
-}
-
-static volatile BOOL user_break;
-static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
-  (void)dwCtrlType;
-  user_break = true;
-  return true;
-}
-
-#else /* WINDOWS */
-
-static volatile sig_atomic_t user_break;
-static void signal_handler(int sig) {
-  (void)sig;
-  user_break = 1;
-}
-
-#endif /* !WINDOWS */
-
-static char *prog;
-bool quiet = false;
-static void usage(void) {
-  fprintf(stderr,
-          "usage: %s [-V] [-q] [-d] [-s name] dbpath\n"
-          "  -V\t\tprint version and exit\n"
-          "  -q\t\tbe quiet\n"
-          "  -d\t\tdelete the specified database, don't just empty it\n"
-          "  -s name\tdrop the specified named subDB\n"
-          "  \t\tby default empty the main DB\n",
-          prog);
-  exit(EXIT_FAILURE);
-}
-
-static void error(const char *func, int rc) {
-  if (!quiet)
-    fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc,
-            mdbx_strerror(rc));
-}
-
-int main(int argc, char *argv[]) {
-  int i, rc;
-  MDBX_env *env;
-  MDBX_txn *txn;
-  MDBX_dbi dbi;
-  char *envname = nullptr;
-  char *subname = nullptr;
-  int envflags = MDBX_ACCEDE;
-  bool delete = false;
-
-  prog = argv[0];
-  if (argc < 2)
-    usage();
-
-  while ((i = getopt(argc, argv,
-                     "d"
-                     "s:"
-                     "n"
-                     "q"
-                     "V")) != EOF) {
-    switch (i) {
-    case 'V':
-      printf("mdbx_drop version %d.%d.%d.%d\n"
-             " - source: %s %s, commit %s, tree %s\n"
-             " - anchor: %s\n"
-             " - build: %s for %s by %s\n"
-             " - flags: %s\n"
-             " - options: %s\n",
-             mdbx_version.major, mdbx_version.minor, mdbx_version.release,
-             mdbx_version.revision, mdbx_version.git.describe,
-             mdbx_version.git.datetime, mdbx_version.git.commit,
-             mdbx_version.git.tree, mdbx_sourcery_anchor, mdbx_build.datetime,
-             mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
-             mdbx_build.options);
-      return EXIT_SUCCESS;
-    case 'q':
-      quiet = true;
-      break;
-    case 'd':
-      delete = true;
-      break;
-    case 'n':
-      break;
-    case 's':
-      subname = optarg;
-      break;
-    default:
-      usage();
-    }
-  }
-
-  if (optind != argc - 1)
-    usage();
-
-#if defined(_WIN32) || defined(_WIN64)
-  SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
-#else
-#ifdef SIGPIPE
-  signal(SIGPIPE, signal_handler);
-#endif
-#ifdef SIGHUP
-  signal(SIGHUP, signal_handler);
-#endif
-  signal(SIGINT, signal_handler);
-  signal(SIGTERM, signal_handler);
-#endif /* !WINDOWS */
-
-  envname = argv[optind];
-  if (!quiet) {
-    printf("mdbx_drop %s (%s, T-%s)\nRunning for %s/%s...\n",
-           mdbx_version.git.describe, mdbx_version.git.datetime,
-           mdbx_version.git.tree, envname, subname ? subname : "@MAIN");
-    fflush(nullptr);
-  }
-
-  rc = mdbx_env_create(&env);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_create", rc);
-    return EXIT_FAILURE;
-  }
-
-  if (subname) {
-    rc = mdbx_env_set_maxdbs(env, 2);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_env_set_maxdbs", rc);
-      goto env_close;
-    }
-  }
-
-  rc = mdbx_env_open(env, envname, envflags, 0);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_open", rc);
-    goto env_close;
-  }
-
-  rc = mdbx_txn_begin(env, NULL, 0, &txn);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_txn_begin", rc);
-    goto env_close;
-  }
-
-  rc = mdbx_dbi_open(txn, subname, MDBX_DB_ACCEDE, &dbi);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_open", rc);
-    goto txn_abort;
-  }
-
-  rc = mdbx_drop(txn, dbi, delete);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_drop", rc);
-    goto txn_abort;
-  }
-
-  rc = mdbx_txn_commit(txn);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_txn_commit", rc);
-    goto txn_abort;
-  }
-  txn = nullptr;
-
-txn_abort:
-  if (txn)
-    mdbx_txn_abort(txn);
-env_close:
-  mdbx_env_close(env);
-
-  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/3rdparty/libmdbx/mdbx_dump.c b/3rdparty/libmdbx/mdbx_dump.c
deleted file mode 100644
index e806fa8c99ab4922fc7949138e6c921ed7b79cdf..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx_dump.c
+++ /dev/null
@@ -1,4020 +0,0 @@
-/* mdbx_dump.c - memory-mapped database dump tool */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#ifdef _MSC_VER
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
-#endif                          /* _MSC_VER (warnings) */
-
-#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-
-#include <ctype.h>
-
-#define PRINT 1
-#define GLOBAL 2
-static int mode = GLOBAL;
-
-typedef struct flagbit {
-  int bit;
-  char *name;
-} flagbit;
-
-flagbit dbflags[] = {{MDBX_REVERSEKEY, "reversekey"},
-                     {MDBX_DUPSORT, "dupsort"},
-                     {MDBX_INTEGERKEY, "integerkey"},
-                     {MDBX_DUPFIXED, "dupfixed"},
-                     {MDBX_INTEGERDUP, "integerdup"},
-                     {MDBX_REVERSEDUP, "reversedup"},
-                     {0, nullptr}};
-
-#if defined(_WIN32) || defined(_WIN64)
-/*
- * POSIX getopt for Windows
- *
- * AT&T Public License
- *
- * Code given out at the 1985 UNIFORUM conference in Dallas.
- */
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-#endif /* _MSC_VER (warnings) */
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-/*----------------------------------------------------------------------------*/
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *opts) {
-  static int sp = 1;
-  int c;
-  const char *cp;
-
-  if (sp == 1) {
-    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
-      return EOF;
-    else if (strcmp(argv[optind], "--") == 0) {
-      optind++;
-      return EOF;
-    }
-  }
-  optopt = c = argv[optind][sp];
-  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
-    fprintf(stderr, "%s: %s -- %c\n", argv[0], "illegal option", c);
-    if (argv[optind][++sp] == '\0') {
-      optind++;
-      sp = 1;
-    }
-    return '?';
-  }
-  if (*++cp == ':') {
-    if (argv[optind][sp + 1] != '\0')
-      optarg = &argv[optind++][sp + 1];
-    else if (++optind >= argc) {
-      fprintf(stderr, "%s: %s -- %c\n", argv[0], "option requires an argument",
-              c);
-      sp = 1;
-      return '?';
-    } else
-      optarg = argv[optind++];
-    sp = 1;
-  } else {
-    if (argv[optind][++sp] == '\0') {
-      sp = 1;
-      optind++;
-    }
-    optarg = NULL;
-  }
-  return c;
-}
-
-static volatile BOOL user_break;
-static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
-  (void)dwCtrlType;
-  user_break = true;
-  return true;
-}
-
-#else /* WINDOWS */
-
-static volatile sig_atomic_t user_break;
-static void signal_handler(int sig) {
-  (void)sig;
-  user_break = 1;
-}
-
-#endif /* !WINDOWS */
-
-static const char hexc[] = "0123456789abcdef";
-
-static void dumpbyte(unsigned char c) {
-  putchar(hexc[c >> 4]);
-  putchar(hexc[c & 0xf]);
-}
-
-static void text(MDBX_val *v) {
-  unsigned char *c, *end;
-
-  putchar(' ');
-  c = v->iov_base;
-  end = c + v->iov_len;
-  while (c < end) {
-    if (isprint(*c) && *c != '\\') {
-      putchar(*c);
-    } else {
-      putchar('\\');
-      dumpbyte(*c);
-    }
-    c++;
-  }
-  putchar('\n');
-}
-
-static void dumpval(MDBX_val *v) {
-  unsigned char *c, *end;
-
-  putchar(' ');
-  c = v->iov_base;
-  end = c + v->iov_len;
-  while (c < end)
-    dumpbyte(*c++);
-  putchar('\n');
-}
-
-bool quiet = false, rescue = false;
-const char *prog;
-static void error(const char *func, int rc) {
-  if (!quiet)
-    fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc,
-            mdbx_strerror(rc));
-}
-
-/* Dump in BDB-compatible format */
-static int dump_sdb(MDBX_txn *txn, MDBX_dbi dbi, char *name) {
-  unsigned int flags;
-  int rc = mdbx_dbi_flags(txn, dbi, &flags);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_flags", rc);
-    return rc;
-  }
-
-  MDBX_stat ms;
-  rc = mdbx_dbi_stat(txn, dbi, &ms, sizeof(ms));
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_stat", rc);
-    return rc;
-  }
-
-  MDBX_envinfo info;
-  rc = mdbx_env_info_ex(mdbx_txn_env(txn), txn, &info, sizeof(info));
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_info_ex", rc);
-    return rc;
-  }
-
-  printf("VERSION=3\n");
-  if (mode & GLOBAL) {
-    mode -= GLOBAL;
-    if (info.mi_geo.upper != info.mi_geo.lower)
-      printf("geometry=l%" PRIu64 ",c%" PRIu64 ",u%" PRIu64 ",s%" PRIu64
-             ",g%" PRIu64 "\n",
-             info.mi_geo.lower, info.mi_geo.current, info.mi_geo.upper,
-             info.mi_geo.shrink, info.mi_geo.grow);
-    printf("mapsize=%" PRIu64 "\n", info.mi_geo.upper);
-    printf("maxreaders=%u\n", info.mi_maxreaders);
-
-    MDBX_canary canary;
-    rc = mdbx_canary_get(txn, &canary);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_canary_get", rc);
-      return rc;
-    }
-    if (canary.v)
-      printf("canary=v%" PRIu64 ",x%" PRIu64 ",y%" PRIu64 ",z%" PRIu64 "\n",
-             canary.v, canary.x, canary.y, canary.z);
-  }
-  printf("format=%s\n", mode & PRINT ? "print" : "bytevalue");
-  if (name)
-    printf("database=%s\n", name);
-  printf("type=btree\n");
-  printf("db_pagesize=%u\n", ms.ms_psize);
-  /* if (ms.ms_mod_txnid)
-    printf("txnid=%" PRIaTXN "\n", ms.ms_mod_txnid);
-  else if (!name)
-    printf("txnid=%" PRIaTXN "\n", mdbx_txn_id(txn)); */
-
-  printf("duplicates=%d\n", (flags & (MDBX_DUPSORT | MDBX_DUPFIXED |
-                                      MDBX_INTEGERDUP | MDBX_REVERSEDUP))
-                                ? 1
-                                : 0);
-  for (int i = 0; dbflags[i].bit; i++)
-    if (flags & dbflags[i].bit)
-      printf("%s=1\n", dbflags[i].name);
-
-  uint64_t sequence;
-  rc = mdbx_dbi_sequence(txn, dbi, &sequence, 0);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_sequence", rc);
-    return rc;
-  }
-  if (sequence)
-    printf("sequence=%" PRIu64 "\n", sequence);
-
-  printf("HEADER=END\n"); /*-------------------------------------------------*/
-
-  MDBX_cursor *cursor;
-  MDBX_val key, data;
-  rc = mdbx_cursor_open(txn, dbi, &cursor);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_cursor_open", rc);
-    return rc;
-  }
-  if (MDBX_DEBUG > 0 && rescue) {
-    cursor->mc_flags |= C_SKIPORD;
-    if (cursor->mc_xcursor)
-      cursor->mc_xcursor->mx_cursor.mc_flags |= C_SKIPORD;
-  }
-
-  while ((rc = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) ==
-         MDBX_SUCCESS) {
-    if (user_break) {
-      rc = MDBX_EINTR;
-      break;
-    }
-    if (mode & PRINT) {
-      text(&key);
-      text(&data);
-    } else {
-      dumpval(&key);
-      dumpval(&data);
-    }
-  }
-  printf("DATA=END\n");
-  if (rc == MDBX_NOTFOUND)
-    rc = MDBX_SUCCESS;
-  if (unlikely(rc != MDBX_SUCCESS))
-    error("mdbx_cursor_get", rc);
-
-  mdbx_cursor_close(cursor);
-  return rc;
-}
-
-static void usage(void) {
-  fprintf(stderr,
-          "usage: %s [-V] [-q] [-f file] [-l] [-p] [-r] [-a|-s subdb] "
-          "dbpath\n"
-          "  -V\t\tprint version and exit\n"
-          "  -q\t\tbe quiet\n"
-          "  -f\t\twrite to file instead of stdout\n"
-          "  -l\t\tlist subDBs and exit\n"
-          "  -p\t\tuse printable characters\n"
-          "  -r\t\trescue mode (ignore errors to dump corrupted DB)\n"
-          "  -a\t\tdump main DB and all subDBs\n"
-          "  -s name\tdump only the specified named subDB\n"
-          "  \t\tby default dump only the main DB\n",
-          prog);
-  exit(EXIT_FAILURE);
-}
-
-static int equal_or_greater(const MDBX_val *a, const MDBX_val *b) {
-  return (a->iov_len == b->iov_len &&
-          memcmp(a->iov_base, b->iov_base, a->iov_len) == 0)
-             ? 0
-             : 1;
-}
-
-int main(int argc, char *argv[]) {
-  int i, rc;
-  MDBX_env *env;
-  MDBX_txn *txn;
-  MDBX_dbi dbi;
-  prog = argv[0];
-  char *envname;
-  char *subname = nullptr, *buf4free = nullptr;
-  unsigned envflags = 0;
-  bool alldbs = false, list = false;
-
-  if (argc < 2)
-    usage();
-
-  while ((i = getopt(argc, argv,
-                     "a"
-                     "f:"
-                     "l"
-                     "n"
-                     "p"
-                     "s:"
-                     "V"
-                     "r"
-                     "q")) != EOF) {
-    switch (i) {
-    case 'V':
-      printf("mdbx_dump version %d.%d.%d.%d\n"
-             " - source: %s %s, commit %s, tree %s\n"
-             " - anchor: %s\n"
-             " - build: %s for %s by %s\n"
-             " - flags: %s\n"
-             " - options: %s\n",
-             mdbx_version.major, mdbx_version.minor, mdbx_version.release,
-             mdbx_version.revision, mdbx_version.git.describe,
-             mdbx_version.git.datetime, mdbx_version.git.commit,
-             mdbx_version.git.tree, mdbx_sourcery_anchor, mdbx_build.datetime,
-             mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
-             mdbx_build.options);
-      return EXIT_SUCCESS;
-    case 'l':
-      list = true;
-      /*FALLTHROUGH*/;
-      __fallthrough;
-    case 'a':
-      if (subname)
-        usage();
-      alldbs = true;
-      break;
-    case 'f':
-      if (freopen(optarg, "w", stdout) == nullptr) {
-        fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg,
-                mdbx_strerror(errno));
-        exit(EXIT_FAILURE);
-      }
-      break;
-    case 'n':
-      break;
-    case 'p':
-      mode |= PRINT;
-      break;
-    case 's':
-      if (alldbs)
-        usage();
-      subname = optarg;
-      break;
-    case 'q':
-      quiet = true;
-      break;
-    case 'r':
-      rescue = true;
-      break;
-    default:
-      usage();
-    }
-  }
-
-  if (optind != argc - 1)
-    usage();
-
-#if defined(_WIN32) || defined(_WIN64)
-  SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
-#else
-#ifdef SIGPIPE
-  signal(SIGPIPE, signal_handler);
-#endif
-#ifdef SIGHUP
-  signal(SIGHUP, signal_handler);
-#endif
-  signal(SIGINT, signal_handler);
-  signal(SIGTERM, signal_handler);
-#endif /* !WINDOWS */
-
-  envname = argv[optind];
-  if (!quiet) {
-    fprintf(stderr, "mdbx_dump %s (%s, T-%s)\nRunning for %s...\n",
-            mdbx_version.git.describe, mdbx_version.git.datetime,
-            mdbx_version.git.tree, envname);
-    fflush(nullptr);
-  }
-
-  rc = mdbx_env_create(&env);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_create", rc);
-    return EXIT_FAILURE;
-  }
-
-  if (alldbs || subname) {
-    rc = mdbx_env_set_maxdbs(env, 2);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_env_set_maxdbs", rc);
-      goto env_close;
-    }
-  }
-
-  rc = mdbx_env_open(
-      env, envname,
-      envflags | (rescue ? MDBX_RDONLY | MDBX_EXCLUSIVE : MDBX_RDONLY), 0);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_open", rc);
-    goto env_close;
-  }
-
-  rc = mdbx_txn_begin(env, nullptr, MDBX_TXN_RDONLY, &txn);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_txn_begin", rc);
-    goto env_close;
-  }
-
-  rc = mdbx_dbi_open(txn, subname, MDBX_DB_ACCEDE, &dbi);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_open", rc);
-    goto txn_abort;
-  }
-
-  if (alldbs) {
-    assert(dbi == MAIN_DBI);
-
-    MDBX_cursor *cursor;
-    rc = mdbx_cursor_open(txn, MAIN_DBI, &cursor);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_cursor_open", rc);
-      goto txn_abort;
-    }
-    if (MDBX_DEBUG > 0 && rescue) {
-      cursor->mc_flags |= C_SKIPORD;
-      if (cursor->mc_xcursor)
-        cursor->mc_xcursor->mx_cursor.mc_flags |= C_SKIPORD;
-    }
-
-    bool have_raw = false;
-    int count = 0;
-    MDBX_val key;
-    while (MDBX_SUCCESS ==
-           (rc = mdbx_cursor_get(cursor, &key, nullptr, MDBX_NEXT_NODUP))) {
-      if (user_break) {
-        rc = MDBX_EINTR;
-        break;
-      }
-
-      if (memchr(key.iov_base, '\0', key.iov_len))
-        continue;
-      subname = mdbx_realloc(buf4free, key.iov_len + 1);
-      if (!subname) {
-        rc = MDBX_ENOMEM;
-        break;
-      }
-
-      buf4free = subname;
-      memcpy(subname, key.iov_base, key.iov_len);
-      subname[key.iov_len] = '\0';
-
-      MDBX_dbi sub_dbi;
-      rc = mdbx_dbi_open_ex(txn, subname, MDBX_DB_ACCEDE, &sub_dbi,
-                            rescue ? equal_or_greater : nullptr,
-                            rescue ? equal_or_greater : nullptr);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        if (rc == MDBX_INCOMPATIBLE) {
-          have_raw = true;
-          continue;
-        }
-        error("mdbx_dbi_open", rc);
-        if (!rescue)
-          break;
-      } else {
-        count++;
-        if (list) {
-          printf("%s\n", subname);
-        } else {
-          rc = dump_sdb(txn, sub_dbi, subname);
-          if (unlikely(rc != MDBX_SUCCESS)) {
-            if (!rescue)
-              break;
-            if (!quiet)
-              fprintf(stderr, "%s: %s: ignore %s for `%s` and continue\n", prog,
-                      envname, mdbx_strerror(rc), subname);
-            /* Here is a hack for rescue mode, don't do that:
-             *  - we should restart transaction in case error due
-             *    database corruption;
-             *  - but we won't close cursor, reopen and re-positioning it
-             *    for new a transaction;
-             *  - this is possible since DB is opened in read-only exclusive
-             *    mode and transaction is the same, i.e. has the same address
-             *    and so on. */
-            rc = mdbx_txn_reset(txn);
-            if (unlikely(rc != MDBX_SUCCESS)) {
-              error("mdbx_txn_reset", rc);
-              goto env_close;
-            }
-            rc = mdbx_txn_renew(txn);
-            if (unlikely(rc != MDBX_SUCCESS)) {
-              error("mdbx_txn_renew", rc);
-              goto env_close;
-            }
-          }
-        }
-        rc = mdbx_dbi_close(env, sub_dbi);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          error("mdbx_dbi_close", rc);
-          break;
-        }
-      }
-    }
-    mdbx_cursor_close(cursor);
-    cursor = nullptr;
-
-    if (have_raw && (!count /* || rescue */))
-      rc = dump_sdb(txn, MAIN_DBI, nullptr);
-    else if (!count) {
-      if (!quiet)
-        fprintf(stderr, "%s: %s does not contain multiple databases\n", prog,
-                envname);
-      rc = MDBX_NOTFOUND;
-    }
-  } else {
-    rc = dump_sdb(txn, dbi, subname);
-  }
-
-  switch (rc) {
-  case MDBX_NOTFOUND:
-    rc = MDBX_SUCCESS;
-  case MDBX_SUCCESS:
-    break;
-  case MDBX_EINTR:
-    if (!quiet)
-      fprintf(stderr, "Interrupted by signal/user\n");
-    break;
-  default:
-    if (unlikely(rc != MDBX_SUCCESS))
-      error("mdbx_cursor_get", rc);
-  }
-
-  mdbx_dbi_close(env, dbi);
-txn_abort:
-  mdbx_txn_abort(txn);
-env_close:
-  mdbx_env_close(env);
-  free(buf4free);
-
-  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/3rdparty/libmdbx/mdbx_load.c b/3rdparty/libmdbx/mdbx_load.c
deleted file mode 100644
index 098ccd536b976d5f1464d49c0cb5d36f22c6f2af..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx_load.c
+++ /dev/null
@@ -1,4391 +0,0 @@
-/* mdbx_load.c - memory-mapped database load tool */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#ifdef _MSC_VER
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
-#endif                          /* _MSC_VER (warnings) */
-
-#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-
-#include <ctype.h>
-
-#if defined(_WIN32) || defined(_WIN64)
-/*
- * POSIX getopt for Windows
- *
- * AT&T Public License
- *
- * Code given out at the 1985 UNIFORUM conference in Dallas.
- */
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-#endif /* _MSC_VER (warnings) */
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-/*----------------------------------------------------------------------------*/
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *opts) {
-  static int sp = 1;
-  int c;
-  const char *cp;
-
-  if (sp == 1) {
-    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
-      return EOF;
-    else if (strcmp(argv[optind], "--") == 0) {
-      optind++;
-      return EOF;
-    }
-  }
-  optopt = c = argv[optind][sp];
-  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
-    fprintf(stderr, "%s: %s -- %c\n", argv[0], "illegal option", c);
-    if (argv[optind][++sp] == '\0') {
-      optind++;
-      sp = 1;
-    }
-    return '?';
-  }
-  if (*++cp == ':') {
-    if (argv[optind][sp + 1] != '\0')
-      optarg = &argv[optind++][sp + 1];
-    else if (++optind >= argc) {
-      fprintf(stderr, "%s: %s -- %c\n", argv[0], "option requires an argument",
-              c);
-      sp = 1;
-      return '?';
-    } else
-      optarg = argv[optind++];
-    sp = 1;
-  } else {
-    if (argv[optind][++sp] == '\0') {
-      sp = 1;
-      optind++;
-    }
-    optarg = NULL;
-  }
-  return c;
-}
-
-static volatile BOOL user_break;
-static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
-  (void)dwCtrlType;
-  user_break = true;
-  return true;
-}
-
-#else /* WINDOWS */
-
-static volatile sig_atomic_t user_break;
-static void signal_handler(int sig) {
-  (void)sig;
-  user_break = 1;
-}
-
-#endif /* !WINDOWS */
-
-static char *prog;
-static bool quiet = false;
-static size_t lineno;
-static void error(const char *func, int rc) {
-  if (!quiet) {
-    if (lineno)
-      fprintf(stderr, "%s: at input line %" PRIiSIZE ": %s() error %d, %s\n",
-              prog, lineno, func, rc, mdbx_strerror(rc));
-    else
-      fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc,
-              mdbx_strerror(rc));
-  }
-}
-
-static char *valstr(char *line, const char *item) {
-  const size_t len = strlen(item);
-  if (strncmp(line, item, len) != 0)
-    return nullptr;
-  if (line[len] != '=') {
-    if (line[len] > ' ')
-      return nullptr;
-    if (!quiet)
-      fprintf(stderr,
-              "%s: line %" PRIiSIZE ": unexpected line format for '%s'\n", prog,
-              lineno, item);
-    exit(EXIT_FAILURE);
-  }
-  char *ptr = strchr(line, '\n');
-  if (ptr)
-    *ptr = '\0';
-  return line + len + 1;
-}
-
-static bool valnum(char *line, const char *item, uint64_t *value) {
-  char *str = valstr(line, item);
-  if (!str)
-    return false;
-
-  char *end = nullptr;
-  *value = strtoull(str, &end, 0);
-  if (end && *end) {
-    if (!quiet)
-      fprintf(stderr,
-              "%s: line %" PRIiSIZE ": unexpected number format for '%s'\n",
-              prog, lineno, item);
-    exit(EXIT_FAILURE);
-  }
-  return true;
-}
-
-static bool valbool(char *line, const char *item, bool *value) {
-  uint64_t u64;
-  if (!valnum(line, item, &u64))
-    return false;
-
-  if (u64 > 1) {
-    if (!quiet)
-      fprintf(stderr, "%s: line %" PRIiSIZE ": unexpected value for '%s'\n",
-              prog, lineno, item);
-    exit(EXIT_FAILURE);
-  }
-  *value = u64 != 0;
-  return true;
-}
-
-/*----------------------------------------------------------------------------*/
-
-static char *subname = nullptr;
-static int dbi_flags;
-static txnid_t txnid;
-static uint64_t sequence;
-static MDBX_canary canary;
-static MDBX_envinfo envinfo;
-
-#define PRINT 1
-#define NOHDR 2
-#define GLOBAL 4
-static int mode = GLOBAL;
-
-static MDBX_val kbuf, dbuf;
-
-#define STRLENOF(s) (sizeof(s) - 1)
-
-typedef struct flagbit {
-  unsigned bit;
-  unsigned len;
-  char *name;
-} flagbit;
-
-#define S(s) STRLENOF(s), s
-
-flagbit dbflags[] = {
-    {MDBX_REVERSEKEY, S("reversekey")}, {MDBX_DUPSORT, S("duplicates")},
-    {MDBX_DUPSORT, S("dupsort")},       {MDBX_INTEGERKEY, S("integerkey")},
-    {MDBX_DUPFIXED, S("dupfixed")},     {MDBX_INTEGERDUP, S("integerdup")},
-    {MDBX_REVERSEDUP, S("reversedup")}, {0, 0, nullptr}};
-
-static int readhdr(void) {
-  /* reset parameters */
-  if (subname) {
-    free(subname);
-    subname = nullptr;
-  }
-  dbi_flags = 0;
-  txnid = 0;
-  sequence = 0;
-
-  while (true) {
-    errno = 0;
-    if (fgets(dbuf.iov_base, (int)dbuf.iov_len, stdin) == nullptr)
-      return errno ? errno : EOF;
-    if (user_break)
-      return MDBX_EINTR;
-
-    lineno++;
-    uint64_t u64;
-
-    if (valnum(dbuf.iov_base, "VERSION", &u64)) {
-      if (u64 != 3) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": unsupported value %" PRIu64
-                  " for %s\n",
-                  prog, lineno, u64, "VERSION");
-        exit(EXIT_FAILURE);
-      }
-      continue;
-    }
-
-    if (valnum(dbuf.iov_base, "db_pagesize", &u64)) {
-      if (!(mode & GLOBAL) && envinfo.mi_dxb_pagesize != u64) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore value %" PRIu64
-                  " for '%s' in non-global context\n",
-                  prog, lineno, u64, "db_pagesize");
-      } else if (u64 < MDBX_MIN_PAGESIZE || u64 > MDBX_MAX_PAGESIZE) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore unsupported value %" PRIu64
-                  " for %s\n",
-                  prog, lineno, u64, "db_pagesize");
-      } else
-        envinfo.mi_dxb_pagesize = (uint32_t)u64;
-      continue;
-    }
-
-    char *str = valstr(dbuf.iov_base, "format");
-    if (str) {
-      if (strcmp(str, "print") == 0) {
-        mode |= PRINT;
-        continue;
-      }
-      if (strcmp(str, "bytevalue") == 0) {
-        mode &= ~PRINT;
-        continue;
-      }
-      if (!quiet)
-        fprintf(stderr,
-                "%s: line %" PRIiSIZE ": unsupported value '%s' for %s\n", prog,
-                lineno, str, "format");
-      exit(EXIT_FAILURE);
-    }
-
-    str = valstr(dbuf.iov_base, "database");
-    if (str) {
-      if (*str) {
-        free(subname);
-        subname = mdbx_strdup(str);
-        if (!subname) {
-          if (!quiet)
-            perror("strdup()");
-          exit(EXIT_FAILURE);
-        }
-      }
-      continue;
-    }
-
-    str = valstr(dbuf.iov_base, "type");
-    if (str) {
-      if (strcmp(str, "btree") != 0) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": unsupported value '%s' for %s\n",
-                  prog, lineno, str, "type");
-        free(subname);
-        exit(EXIT_FAILURE);
-      }
-      continue;
-    }
-
-    if (valnum(dbuf.iov_base, "mapaddr", &u64)) {
-      if (u64) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore unsupported value 0x%" PRIx64
-                  " for %s\n",
-                  prog, lineno, u64, "mapaddr");
-      }
-      continue;
-    }
-
-    if (valnum(dbuf.iov_base, "mapsize", &u64)) {
-      if (!(mode & GLOBAL)) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore value %" PRIu64
-                  " for '%s' in non-global context\n",
-                  prog, lineno, u64, "mapsize");
-      } else if (u64 < MIN_MAPSIZE || u64 > MAX_MAPSIZE64) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore unsupported value 0x%" PRIx64
-                  " for %s\n",
-                  prog, lineno, u64, "mapsize");
-      } else
-        envinfo.mi_mapsize = (size_t)u64;
-      continue;
-    }
-
-    if (valnum(dbuf.iov_base, "maxreaders", &u64)) {
-      if (!(mode & GLOBAL)) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore value %" PRIu64
-                  " for '%s' in non-global context\n",
-                  prog, lineno, u64, "maxreaders");
-      } else if (u64 < 1 || u64 > MDBX_READERS_LIMIT) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore unsupported value 0x%" PRIx64
-                  " for %s\n",
-                  prog, lineno, u64, "maxreaders");
-      } else
-        envinfo.mi_maxreaders = (int)u64;
-      continue;
-    }
-
-    if (valnum(dbuf.iov_base, "txnid", &u64)) {
-      if (u64 < MIN_TXNID || u64 > MAX_TXNID) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore unsupported value 0x%" PRIx64
-                  " for %s\n",
-                  prog, lineno, u64, "txnid");
-      } else
-        txnid = u64;
-      continue;
-    }
-
-    if (valnum(dbuf.iov_base, "sequence", &u64)) {
-      sequence = u64;
-      continue;
-    }
-
-    str = valstr(dbuf.iov_base, "geometry");
-    if (str) {
-      if (!(mode & GLOBAL)) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore values %s"
-                  " for '%s' in non-global context\n",
-                  prog, lineno, str, "geometry");
-      } else if (sscanf(str,
-                        "l%" PRIu64 ",c%" PRIu64 ",u%" PRIu64 ",s%" PRIu64
-                        ",g%" PRIu64,
-                        &envinfo.mi_geo.lower, &envinfo.mi_geo.current,
-                        &envinfo.mi_geo.upper, &envinfo.mi_geo.shrink,
-                        &envinfo.mi_geo.grow) != 5) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": unexpected line format for '%s'\n",
-                  prog, lineno, "geometry");
-        exit(EXIT_FAILURE);
-      }
-      continue;
-    }
-
-    str = valstr(dbuf.iov_base, "canary");
-    if (str) {
-      if (!(mode & GLOBAL)) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": ignore values %s"
-                  " for '%s' in non-global context\n",
-                  prog, lineno, str, "canary");
-      } else if (sscanf(str, "v%" PRIu64 ",x%" PRIu64 ",y%" PRIu64 ",z%" PRIu64,
-                        &canary.v, &canary.x, &canary.y, &canary.z) != 4) {
-        if (!quiet)
-          fprintf(stderr,
-                  "%s: line %" PRIiSIZE ": unexpected line format for '%s'\n",
-                  prog, lineno, "canary");
-        exit(EXIT_FAILURE);
-      }
-      continue;
-    }
-
-    for (int i = 0; dbflags[i].bit; i++) {
-      bool value = false;
-      if (valbool(dbuf.iov_base, dbflags[i].name, &value)) {
-        if (value)
-          dbi_flags |= dbflags[i].bit;
-        else
-          dbi_flags &= ~dbflags[i].bit;
-        goto next;
-      }
-    }
-
-    str = valstr(dbuf.iov_base, "HEADER");
-    if (str) {
-      if (strcmp(str, "END") == 0)
-        return MDBX_SUCCESS;
-    }
-
-    if (!quiet)
-      fprintf(stderr,
-              "%s: line %" PRIiSIZE ": unrecognized keyword ignored: %s\n",
-              prog, lineno, (char *)dbuf.iov_base);
-  next:;
-  }
-  return EOF;
-}
-
-static int badend(void) {
-  if (!quiet)
-    fprintf(stderr, "%s: line %" PRIiSIZE ": unexpected end of input\n", prog,
-            lineno);
-  return errno ? errno : MDBX_ENODATA;
-}
-
-static __inline int unhex(unsigned char *c2) {
-  int x, c;
-  x = *c2++ & 0x4f;
-  if (x & 0x40)
-    x -= 55;
-  c = x << 4;
-  x = *c2 & 0x4f;
-  if (x & 0x40)
-    x -= 55;
-  c |= x;
-  return c;
-}
-
-__hot static int readline(MDBX_val *out, MDBX_val *buf) {
-  unsigned char *c1, *c2, *end;
-  size_t len, l2;
-  int c;
-
-  if (user_break)
-    return MDBX_EINTR;
-
-  errno = 0;
-  if (!(mode & NOHDR)) {
-    c = fgetc(stdin);
-    if (c == EOF)
-      return errno ? errno : EOF;
-    if (c != ' ') {
-      lineno++;
-      errno = 0;
-      if (fgets(buf->iov_base, (int)buf->iov_len, stdin)) {
-        if (c == 'D' && !strncmp(buf->iov_base, "ATA=END", STRLENOF("ATA=END")))
-          return EOF;
-      }
-      return badend();
-    }
-  }
-  if (fgets(buf->iov_base, (int)buf->iov_len, stdin) == nullptr)
-    return errno ? errno : EOF;
-  lineno++;
-
-  c1 = buf->iov_base;
-  len = strlen((char *)c1);
-  l2 = len;
-
-  /* Is buffer too short? */
-  while (c1[len - 1] != '\n') {
-    buf->iov_base = mdbx_realloc(buf->iov_base, buf->iov_len * 2);
-    if (!buf->iov_base) {
-      if (!quiet)
-        fprintf(stderr,
-                "%s: line %" PRIiSIZE ": out of memory, line too long\n", prog,
-                lineno);
-      return MDBX_ENOMEM;
-    }
-    c1 = buf->iov_base;
-    c1 += l2;
-    errno = 0;
-    if (fgets((char *)c1, (int)buf->iov_len + 1, stdin) == nullptr)
-      return errno ? errno : EOF;
-    buf->iov_len *= 2;
-    len = strlen((char *)c1);
-    l2 += len;
-  }
-  c1 = c2 = buf->iov_base;
-  len = l2;
-  c1[--len] = '\0';
-  end = c1 + len;
-
-  if (mode & PRINT) {
-    while (c2 < end) {
-      if (unlikely(*c2 == '\\')) {
-        if (c2[1] == '\\') {
-          *c1++ = '\\';
-        } else {
-          if (c2 + 3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2]))
-            return badend();
-          *c1++ = (char)unhex(++c2);
-        }
-        c2 += 2;
-      } else {
-        /* copies are redundant when no escapes were used */
-        *c1++ = *c2++;
-      }
-    }
-  } else {
-    /* odd length not allowed */
-    if (len & 1)
-      return badend();
-    while (c2 < end) {
-      if (!isxdigit(*c2) || !isxdigit(c2[1]))
-        return badend();
-      *c1++ = (char)unhex(c2);
-      c2 += 2;
-    }
-  }
-  c2 = out->iov_base = buf->iov_base;
-  out->iov_len = c1 - c2;
-
-  return MDBX_SUCCESS;
-}
-
-static void usage(void) {
-  fprintf(stderr,
-          "usage: %s "
-          "[-V] [-q] [-a] [-f file] [-s name] [-N] [-p] [-T] [-r] [-n] dbpath\n"
-          "  -V\t\tprint version and exit\n"
-          "  -q\t\tbe quiet\n"
-          "  -a\t\tappend records in input order (required for custom "
-          "comparators)\n"
-          "  -f file\tread from file instead of stdin\n"
-          "  -s name\tload into specified named subDB\n"
-          "  -N\t\tdon't overwrite existing records when loading, just skip "
-          "ones\n"
-          "  -p\t\tpurge subDB before loading\n"
-          "  -T\t\tread plaintext\n"
-          "  -r\t\trescue mode (ignore errors to load corrupted DB dump)\n"
-          "  -n\t\tdon't use subdirectory for newly created database "
-          "(MDBX_NOSUBDIR)\n",
-          prog);
-  exit(EXIT_FAILURE);
-}
-
-static int equal_or_greater(const MDBX_val *a, const MDBX_val *b) {
-  return (a->iov_len == b->iov_len &&
-          memcmp(a->iov_base, b->iov_base, a->iov_len) == 0)
-             ? 0
-             : 1;
-}
-
-int main(int argc, char *argv[]) {
-  int i, rc;
-  MDBX_env *env = nullptr;
-  MDBX_txn *txn = nullptr;
-  MDBX_cursor *mc = nullptr;
-  MDBX_dbi dbi;
-  char *envname = nullptr;
-  int envflags = MDBX_SAFE_NOSYNC | MDBX_ACCEDE, putflags = MDBX_UPSERT;
-  bool rescue = false;
-  bool purge = false;
-
-  prog = argv[0];
-  if (argc < 2)
-    usage();
-
-  while ((i = getopt(argc, argv,
-                     "a"
-                     "f:"
-                     "n"
-                     "s:"
-                     "N"
-                     "p"
-                     "T"
-                     "V"
-                     "r"
-                     "q")) != EOF) {
-    switch (i) {
-    case 'V':
-      printf("mdbx_load version %d.%d.%d.%d\n"
-             " - source: %s %s, commit %s, tree %s\n"
-             " - anchor: %s\n"
-             " - build: %s for %s by %s\n"
-             " - flags: %s\n"
-             " - options: %s\n",
-             mdbx_version.major, mdbx_version.minor, mdbx_version.release,
-             mdbx_version.revision, mdbx_version.git.describe,
-             mdbx_version.git.datetime, mdbx_version.git.commit,
-             mdbx_version.git.tree, mdbx_sourcery_anchor, mdbx_build.datetime,
-             mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
-             mdbx_build.options);
-      return EXIT_SUCCESS;
-    case 'a':
-      putflags |= MDBX_APPEND;
-      break;
-    case 'f':
-      if (freopen(optarg, "r", stdin) == nullptr) {
-        if (!quiet)
-          fprintf(stderr, "%s: %s: open: %s\n", prog, optarg,
-                  mdbx_strerror(errno));
-        exit(EXIT_FAILURE);
-      }
-      break;
-    case 'n':
-      envflags |= MDBX_NOSUBDIR;
-      break;
-    case 's':
-      subname = mdbx_strdup(optarg);
-      break;
-    case 'N':
-      putflags |= MDBX_NOOVERWRITE | MDBX_NODUPDATA;
-      break;
-    case 'p':
-      purge = true;
-      break;
-    case 'T':
-      mode |= NOHDR | PRINT;
-      break;
-    case 'q':
-      quiet = true;
-      break;
-    case 'r':
-      rescue = true;
-      break;
-    default:
-      usage();
-    }
-  }
-
-  if (optind != argc - 1)
-    usage();
-
-#if defined(_WIN32) || defined(_WIN64)
-  SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
-#else
-#ifdef SIGPIPE
-  signal(SIGPIPE, signal_handler);
-#endif
-#ifdef SIGHUP
-  signal(SIGHUP, signal_handler);
-#endif
-  signal(SIGINT, signal_handler);
-  signal(SIGTERM, signal_handler);
-#endif /* !WINDOWS */
-
-  envname = argv[optind];
-  if (!quiet)
-    printf("mdbx_load %s (%s, T-%s)\nRunning for %s...\n",
-           mdbx_version.git.describe, mdbx_version.git.datetime,
-           mdbx_version.git.tree, envname);
-  fflush(nullptr);
-
-  dbuf.iov_len = 4096;
-  dbuf.iov_base = mdbx_malloc(dbuf.iov_len);
-  if (!dbuf.iov_base) {
-    rc = MDBX_ENOMEM;
-    error("value-buffer", rc);
-    goto env_close;
-  }
-
-  /* read first header for mapsize= */
-  if (!(mode & NOHDR)) {
-    rc = readhdr();
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      if (rc == EOF)
-        rc = MDBX_ENODATA;
-      error("readheader", rc);
-      goto env_close;
-    }
-  }
-
-  rc = mdbx_env_create(&env);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_create", rc);
-    return EXIT_FAILURE;
-  }
-
-  mdbx_env_set_maxdbs(env, 2);
-  if (envinfo.mi_maxreaders) {
-    rc = mdbx_env_set_maxreaders(env, envinfo.mi_maxreaders);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_env_set_maxreaders", rc);
-      goto env_close;
-    }
-  }
-
-  if (envinfo.mi_geo.current | envinfo.mi_mapsize) {
-    if (envinfo.mi_geo.current) {
-      rc = mdbx_env_set_geometry(
-          env, (intptr_t)envinfo.mi_geo.lower, (intptr_t)envinfo.mi_geo.current,
-          (intptr_t)envinfo.mi_geo.upper, (intptr_t)envinfo.mi_geo.shrink,
-          (intptr_t)envinfo.mi_geo.grow,
-          envinfo.mi_dxb_pagesize ? (intptr_t)envinfo.mi_dxb_pagesize : -1);
-    } else {
-      if (envinfo.mi_mapsize > MAX_MAPSIZE) {
-        if (!quiet)
-          fprintf(
-              stderr,
-              "Database size is too large for current system (mapsize=%" PRIu64
-              " is great than system-limit %zu)\n",
-              envinfo.mi_mapsize, (size_t)MAX_MAPSIZE);
-        goto env_close;
-      }
-      rc = mdbx_env_set_geometry(
-          env, (intptr_t)envinfo.mi_mapsize, (intptr_t)envinfo.mi_mapsize,
-          (intptr_t)envinfo.mi_mapsize, 0, 0,
-          envinfo.mi_dxb_pagesize ? (intptr_t)envinfo.mi_dxb_pagesize : -1);
-    }
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_env_set_geometry", rc);
-      goto env_close;
-    }
-  }
-
-  rc = mdbx_env_open(env, envname, envflags, 0664);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_open", rc);
-    goto env_close;
-  }
-
-  kbuf.iov_len = mdbx_env_get_maxvalsize_ex(env, 0) + 1;
-  if (kbuf.iov_len >= INTPTR_MAX / 2) {
-    if (!quiet)
-      fprintf(stderr, "mdbx_env_get_maxkeysize() failed, returns %zu\n",
-              kbuf.iov_len);
-    goto env_close;
-  }
-
-  kbuf.iov_base = malloc(kbuf.iov_len);
-  if (!kbuf.iov_base) {
-    rc = MDBX_ENOMEM;
-    error("key-buffer", rc);
-    goto env_close;
-  }
-
-  while (rc == MDBX_SUCCESS) {
-    if (user_break) {
-      rc = MDBX_EINTR;
-      break;
-    }
-
-    rc = mdbx_txn_begin(env, nullptr, 0, &txn);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_txn_begin", rc);
-      goto env_close;
-    }
-
-    if (mode & GLOBAL) {
-      mode -= GLOBAL;
-      if (canary.v | canary.x | canary.y | canary.z) {
-        rc = mdbx_canary_put(txn, &canary);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          error("mdbx_canary_put", rc);
-          goto txn_abort;
-        }
-      }
-    }
-
-    const char *const dbi_name = subname ? subname : "@MAIN";
-    rc =
-        mdbx_dbi_open_ex(txn, subname, dbi_flags | MDBX_CREATE, &dbi,
-                         (putflags & MDBX_APPEND) ? equal_or_greater : nullptr,
-                         (putflags & MDBX_APPEND) ? equal_or_greater : nullptr);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_dbi_open_ex", rc);
-      goto txn_abort;
-    }
-
-    uint64_t present_sequence;
-    rc = mdbx_dbi_sequence(txn, dbi, &present_sequence, 0);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_dbi_sequence", rc);
-      goto txn_abort;
-    }
-    if (present_sequence > sequence) {
-      if (!quiet)
-        fprintf(stderr,
-                "present sequence for '%s' value (%" PRIu64
-                ") is greater than loaded (%" PRIu64 ")\n",
-                dbi_name, present_sequence, sequence);
-      rc = MDBX_RESULT_TRUE;
-      goto txn_abort;
-    }
-    if (present_sequence < sequence) {
-      rc = mdbx_dbi_sequence(txn, dbi, nullptr, sequence - present_sequence);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_dbi_sequence", rc);
-        goto txn_abort;
-      }
-    }
-
-    if (purge) {
-      rc = mdbx_drop(txn, dbi, false);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_drop", rc);
-        goto txn_abort;
-      }
-    }
-
-    if (putflags & MDBX_APPEND)
-      putflags = (dbi_flags & MDBX_DUPSORT) ? putflags | MDBX_APPENDDUP
-                                            : putflags & ~MDBX_APPENDDUP;
-
-    rc = mdbx_cursor_open(txn, dbi, &mc);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_cursor_open", rc);
-      goto txn_abort;
-    }
-
-    int batch = 0;
-    while (rc == MDBX_SUCCESS) {
-      MDBX_val key, data;
-      rc = readline(&key, &kbuf);
-      if (rc == EOF)
-        break;
-
-      if (rc == MDBX_SUCCESS)
-        rc = readline(&data, &dbuf);
-      if (rc) {
-        if (!quiet)
-          fprintf(stderr, "%s: line %" PRIiSIZE ": failed to read key value\n",
-                  prog, lineno);
-        goto txn_abort;
-      }
-
-      rc = mdbx_cursor_put(mc, &key, &data, putflags);
-      if (rc == MDBX_KEYEXIST && putflags)
-        continue;
-      if (rc == MDBX_BAD_VALSIZE && rescue) {
-        if (!quiet)
-          fprintf(stderr, "%s: skip line %" PRIiSIZE ": due %s\n", prog, lineno,
-                  mdbx_strerror(rc));
-        continue;
-      }
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_cursor_put", rc);
-        goto txn_abort;
-      }
-      batch++;
-
-      MDBX_txn_info txn_info;
-      rc = mdbx_txn_info(txn, &txn_info, false);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_txn_info", rc);
-        goto txn_abort;
-      }
-
-      if (batch == 10000 || txn_info.txn_space_dirty > MEGABYTE * 256) {
-        rc = mdbx_txn_commit(txn);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          error("mdbx_txn_commit", rc);
-          goto env_close;
-        }
-        batch = 0;
-
-        rc = mdbx_txn_begin(env, nullptr, 0, &txn);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          error("mdbx_txn_begin", rc);
-          goto env_close;
-        }
-        rc = mdbx_cursor_bind(txn, mc, dbi);
-        if (unlikely(rc != MDBX_SUCCESS)) {
-          error("mdbx_cursor_bind", rc);
-          goto txn_abort;
-        }
-      }
-    }
-
-    mdbx_cursor_close(mc);
-    mc = nullptr;
-    rc = mdbx_txn_commit(txn);
-    txn = nullptr;
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_txn_commit", rc);
-      goto env_close;
-    }
-    if (subname) {
-      assert(dbi != MAIN_DBI);
-      rc = mdbx_dbi_close(env, dbi);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_dbi_close", rc);
-        goto env_close;
-      }
-    } else {
-      assert(dbi == MAIN_DBI);
-    }
-
-    /* try read next header */
-    if (!(mode & NOHDR))
-      rc = readhdr();
-    else if (ferror(stdin) || feof(stdin))
-      break;
-  }
-
-  switch (rc) {
-  case EOF:
-    rc = MDBX_SUCCESS;
-  case MDBX_SUCCESS:
-    break;
-  case MDBX_EINTR:
-    if (!quiet)
-      fprintf(stderr, "Interrupted by signal/user\n");
-    break;
-  default:
-    if (unlikely(rc != MDBX_SUCCESS))
-      error("readline", rc);
-  }
-
-txn_abort:
-  mdbx_cursor_close(mc);
-  mdbx_txn_abort(txn);
-env_close:
-  mdbx_env_close(env);
-  free(kbuf.iov_base);
-  free(dbuf.iov_base);
-
-  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/3rdparty/libmdbx/mdbx_stat.c b/3rdparty/libmdbx/mdbx_stat.c
deleted file mode 100644
index 68a46191eb4bc3d52b2e9290eea05253a074bc04..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/mdbx_stat.c
+++ /dev/null
@@ -1,4041 +0,0 @@
-/* mdbx_stat.c - memory-mapped database status tool */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#ifdef _MSC_VER
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
-#endif                          /* _MSC_VER (warnings) */
-
-#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>. */
-
-#define MDBX_BUILD_SOURCERY c510b93d78b5848764f976ea67f06d278a7b99f141b4c98ceb095285f834f31c_v0_11_7_0_g40ec559c
-#ifdef MDBX_CONFIG_H
-#include MDBX_CONFIG_H
-#endif
-
-#define LIBMDBX_INTERNALS
-#ifdef xMDBX_TOOLS
-#define MDBX_DEPRECATED
-#endif /* xMDBX_TOOLS */
-
-#ifdef xMDBX_ALLOY
-/* Amalgamated build */
-#define MDBX_INTERNAL_FUNC static
-#define MDBX_INTERNAL_VAR static
-#else
-/* Non-amalgamated build */
-#define MDBX_INTERNAL_FUNC
-#define MDBX_INTERNAL_VAR extern
-#endif /* xMDBX_ALLOY */
-
-/** Disables using GNU/Linux libc extensions.
- * \ingroup build_option
- * \note This option couldn't be moved to the options.h since dependant
- * control macros/defined should be prepared before include the options.h */
-#ifndef MDBX_DISABLE_GNU_SOURCE
-#define MDBX_DISABLE_GNU_SOURCE 0
-#endif
-#if MDBX_DISABLE_GNU_SOURCE
-#undef _GNU_SOURCE
-#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif /* MDBX_DISABLE_GNU_SOURCE */
-
-/*----------------------------------------------------------------------------*/
-
-/* Should be defined before any includes */
-#if !defined(_FILE_OFFSET_BITS) && !defined(__ANDROID_API__) &&                \
-    !defined(ANDROID)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-#ifdef __APPLE__
-#define _DARWIN_C_SOURCE
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_FULL_VER < 190024234
-/* Actually libmdbx was not tested with compilers older than 19.00.24234 (Visual
- * Studio 2015 Update 3). But you could remove this #error and try to continue
- * at your own risk. In such case please don't rise up an issues related ONLY to
- * old compilers.
- *
- * NOTE:
- *   Unfortunately, there are several different builds of "Visual Studio" that
- *   are called "Visual Studio 2015 Update 3".
- *
- *   The 190024234 is used here because it is minimal version of Visual Studio
- *   that was used for build and testing libmdbx in recent years. Soon this
- *   value will be increased to 19.0.24241.7, since build and testing using
- *   "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
- *
- *   Please ask Microsoft (but not us) for information about version differences
- *   and how to and where you can obtain the latest "Visual Studio 2015" build
- *   with all fixes.
- */
-#error                                                                         \
-    "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
-#endif
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if _MSC_VER > 1800
-#pragma warning(disable : 4464) /* relative include path contains '..' */
-#endif
-#if _MSC_VER > 1913
-#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation...  \
-                                 */
-#endif
-#if _MSC_VER > 1914
-#pragma warning(                                                               \
-    disable : 5105) /* winbase.h(9531): warning C5105: macro expansion         \
-                       producing 'defined' has undefined behavior */
-#endif
-#pragma warning(disable : 4710) /* 'xyz': function not inlined */
-#pragma warning(disable : 4711) /* function 'xyz' selected for automatic       \
-                                   inline expansion */
-#pragma warning(                                                               \
-    disable : 4201) /* nonstandard extension used : nameless struct / union */
-#pragma warning(disable : 4702) /* unreachable code */
-#pragma warning(disable : 4706) /* assignment within conditional expression */
-#pragma warning(disable : 4127) /* conditional expression is constant */
-#pragma warning(disable : 4324) /* 'xyz': structure was padded due to          \
-                                   alignment specifier */
-#pragma warning(disable : 4310) /* cast truncates constant value */
-#pragma warning(                                                               \
-    disable : 4820) /* bytes padding added after data member for alignment */
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4366) /* the result of the unary '&' operator may be \
-                                   unaligned */
-#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized      \
-                                   array in struct/union */
-#pragma warning(disable : 4204) /* nonstandard extension used: non-constant    \
-                                   aggregate initializer */
-#pragma warning(                                                               \
-    disable : 4505) /* unreferenced local function has been removed */
-#endif              /* _MSC_VER (warnings) */
-
-#if defined(__GNUC__) && __GNUC__ < 9
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif /* GCC < 9 */
-
-#if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) &&    \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* __USE_MINGW_ANSI_STDIO */
-
-#include "mdbx.h"
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-
-#ifndef __GNUC_PREREQ
-#   if defined(__GNUC__) && defined(__GNUC_MINOR__)
-#       define __GNUC_PREREQ(maj, min) \
-          ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GNUC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GNUC_PREREQ */
-
-#ifndef __CLANG_PREREQ
-#   ifdef __clang__
-#       define __CLANG_PREREQ(maj,min) \
-          ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
-#   else
-#       define __CLANG_PREREQ(maj,min) (0)
-#   endif
-#endif /* __CLANG_PREREQ */
-
-#ifndef __GLIBC_PREREQ
-#   if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#       define __GLIBC_PREREQ(maj, min) \
-          ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-#   else
-#       define __GLIBC_PREREQ(maj, min) (0)
-#   endif
-#endif /* __GLIBC_PREREQ */
-
-#ifndef __has_warning
-#   define __has_warning(x) (0)
-#endif
-
-#ifndef __has_include
-#   define __has_include(x) (0)
-#endif
-
-#if __has_feature(thread_sanitizer)
-#   define __SANITIZE_THREAD__ 1
-#endif
-
-#if __has_feature(address_sanitizer)
-#   define __SANITIZE_ADDRESS__ 1
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __extern_C
-#   ifdef __cplusplus
-#       define __extern_C extern "C"
-#   else
-#       define __extern_C
-#   endif
-#endif /* __extern_C */
-
-#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
-#   define nullptr NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef __always_inline
-#   if defined(__GNUC__) || __has_attribute(__always_inline__)
-#       define __always_inline __inline __attribute__((__always_inline__))
-#   elif defined(_MSC_VER)
-#       define __always_inline __forceinline
-#   else
-#       define __always_inline
-#   endif
-#endif /* __always_inline */
-
-#ifndef __noinline
-#   if defined(__GNUC__) || __has_attribute(__noinline__)
-#       define __noinline __attribute__((__noinline__))
-#   elif defined(_MSC_VER)
-#       define __noinline __declspec(noinline)
-#   else
-#       define __noinline
-#   endif
-#endif /* __noinline */
-
-#ifndef __must_check_result
-#   if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
-#       define __must_check_result __attribute__((__warn_unused_result__))
-#   else
-#       define __must_check_result
-#   endif
-#endif /* __must_check_result */
-
-#if !defined(__noop) && !defined(_MSC_VER)
-#   define __noop(...) do {} while(0)
-#endif /* __noop */
-
-#if defined(__fallthrough) &&                                                  \
-    (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
-#undef __fallthrough
-#endif /* __fallthrough workaround for MinGW */
-
-#ifndef __fallthrough
-#  if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) &&             \
-     (!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
-#    define __fallthrough [[fallthrough]]
-#  elif __GNUC_PREREQ(7, 0) &&                                                 \
-    (!defined(__LCC__) || (__LCC__ == 124 && __LCC_MINOR__ >= 12) ||           \
-     (__LCC__ == 125 && __LCC_MINOR__ >= 5) || (__LCC__ >= 126))
-#    define __fallthrough __attribute__((__fallthrough__))
-#  elif defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L &&\
-    __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#    define __fallthrough [[clang::fallthrough]]
-#  else
-#    define __fallthrough
-#  endif
-#endif /* __fallthrough */
-
-#ifndef __unreachable
-#   if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-#       define __unreachable() __builtin_unreachable()
-#   elif defined(_MSC_VER)
-#       define __unreachable() __assume(0)
-#   else
-#       define __unreachable() __noop()
-#   endif
-#endif /* __unreachable */
-
-#ifndef __prefetch
-#   if defined(__GNUC__) || defined(__clang__) || __has_builtin(__builtin_prefetch)
-#       define __prefetch(ptr) __builtin_prefetch(ptr)
-#   else
-#       define __prefetch(ptr) __noop(ptr)
-#   endif
-#endif /* __prefetch */
-
-#ifndef __nothrow
-#   if defined(__cplusplus)
-#       if __cplusplus < 201703L
-#           define __nothrow throw()
-#       else
-#           define __nothrow noexcept(true)
-#       endif /* __cplusplus */
-#   elif defined(__GNUC__) || __has_attribute(__nothrow__)
-#       define __nothrow __attribute__((__nothrow__))
-#   elif defined(_MSC_VER) && defined(__cplusplus)
-#       define __nothrow __declspec(nothrow)
-#   else
-#       define __nothrow
-#   endif
-#endif /* __nothrow */
-
-#ifndef __hidden
-#   if defined(__GNUC__) || __has_attribute(__visibility__)
-#       define __hidden __attribute__((__visibility__("hidden")))
-#   else
-#       define __hidden
-#   endif
-#endif /* __hidden */
-
-#ifndef __optimize
-#   if defined(__OPTIMIZE__)
-#       if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__optimize__)
-#           define __optimize(ops) __attribute__((__optimize__(ops)))
-#       else
-#           define __optimize(ops)
-#       endif
-#   else
-#       define __optimize(ops)
-#   endif
-#endif /* __optimize */
-
-#ifndef __hot
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __hot __attribute__((__hot__)) __optimize(3)
-#       elif defined(__clang__) && !__has_attribute(__hot_) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put frequently used functions in separate section */
-#           define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
-#       elif defined(__GNUC__) || __has_attribute(__hot__)
-#           define __hot __attribute__((__hot__)) __optimize("O3")
-#       else
-#           define __hot __optimize("O3")
-#       endif
-#   else
-#       define __hot
-#   endif
-#endif /* __hot */
-
-#ifndef __cold
-#   if defined(__OPTIMIZE__)
-#       if defined(__e2k__)
-#           define __cold __attribute__((__cold__)) __optimize(1)
-#       elif defined(__clang__) && !__has_attribute(cold) \
-        && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
-            /* just put infrequently used functions in separate section */
-#           define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
-#       elif defined(__GNUC__) || __has_attribute(cold)
-#           define __cold __attribute__((__cold__)) __optimize("Os")
-#       else
-#           define __cold __optimize("Os")
-#       endif
-#   else
-#       define __cold
-#   endif
-#endif /* __cold */
-
-#ifndef __flatten
-#   if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
-#       define __flatten __attribute__((__flatten__))
-#   else
-#       define __flatten
-#   endif
-#endif /* __flatten */
-
-#ifndef likely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define likely(cond) __builtin_expect(!!(cond), 1)
-#   else
-#       define likely(x) (!!(x))
-#   endif
-#endif /* likely */
-
-#ifndef unlikely
-#   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
-#       define unlikely(cond) __builtin_expect(!!(cond), 0)
-#   else
-#       define unlikely(x) (!!(x))
-#   endif
-#endif /* unlikely */
-
-#ifndef __anonymous_struct_extension__
-#   if defined(__GNUC__)
-#       define __anonymous_struct_extension__ __extension__
-#   else
-#       define __anonymous_struct_extension__
-#   endif
-#endif /* __anonymous_struct_extension__ */
-
-#ifndef __Wpedantic_format_voidptr
-    MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline  const void*
-        __Wpedantic_format_voidptr(const void* ptr) {return ptr;}
-#   define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
-#endif /* __Wpedantic_format_voidptr */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(MDBX_USE_VALGRIND)
-#   include <valgrind/memcheck.h>
-#   ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
-        /* LY: available since Valgrind 3.10 */
-#       define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#       define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   endif
-#elif !defined(RUNNING_ON_VALGRIND)
-#   define VALGRIND_CREATE_MEMPOOL(h,r,z)
-#   define VALGRIND_DESTROY_MEMPOOL(h)
-#   define VALGRIND_MEMPOOL_TRIM(h,a,s)
-#   define VALGRIND_MEMPOOL_ALLOC(h,a,s)
-#   define VALGRIND_MEMPOOL_FREE(h,a)
-#   define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
-#   define VALGRIND_MAKE_MEM_NOACCESS(a,s)
-#   define VALGRIND_MAKE_MEM_DEFINED(a,s)
-#   define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
-#   define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
-#   define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
-#   define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
-#   define RUNNING_ON_VALGRIND (0)
-#endif /* MDBX_USE_VALGRIND */
-
-#ifdef __SANITIZE_ADDRESS__
-#   include <sanitizer/asan_interface.h>
-#elif !defined(ASAN_POISON_MEMORY_REGION)
-#   define ASAN_POISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#   define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
-        ((void)(addr), (void)(size))
-#endif /* __SANITIZE_ADDRESS__ */
-
-/*----------------------------------------------------------------------------*/
-
-#ifndef ARRAY_LENGTH
-#   ifdef __cplusplus
-        template <typename T, size_t N>
-        char (&__ArraySizeHelper(T (&array)[N]))[N];
-#       define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
-#   else
-#       define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
-#   endif
-#endif /* ARRAY_LENGTH */
-
-#ifndef ARRAY_END
-#   define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
-#endif /* ARRAY_END */
-
-#define CONCAT(a,b) a##b
-#define XCONCAT(a,b) CONCAT(a,b)
-
-#ifndef offsetof
-#   define offsetof(type, member)  __builtin_offsetof(type, member)
-#endif /* offsetof */
-
-#ifndef container_of
-#   define container_of(ptr, type, member) \
-        ((type *)((char *)(ptr) - offsetof(type, member)))
-#endif /* container_of */
-
-#define MDBX_TETRAD(a, b, c, d)                                                \
-  ((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
-
-#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
-
-#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
-
-#ifndef STATIC_ASSERT_MSG
-#   if defined(static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
-#   elif defined(_STATIC_ASSERT)
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif defined(_MSC_VER)
-#       include <crtdbg.h>
-#       define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
-#   elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
-          || __has_feature(c_static_assert)
-#       define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
-#   else
-#       define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
-#   endif
-#endif /* STATIC_ASSERT */
-
-#ifndef STATIC_ASSERT
-#   define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
-#endif
-
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__GNUC__) && !__GNUC_PREREQ(4, 2)
-/* Actually libmdbx was not tested with compilers older than GCC 4.2.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required GCC >= 4.2"
-#endif
-
-#if defined(__clang__) && !__CLANG_PREREQ(3, 8)
-/* Actually libmdbx was not tested with CLANG older than 3.8.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old compilers.
- */
-#warning "libmdbx required CLANG >= 3.8"
-#endif
-
-#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 12)
-/* Actually libmdbx was not tested with something older than glibc 2.12.
- * But you could ignore this warning at your own risk.
- * In such case please don't rise up an issues related ONLY to old systems.
- */
-#warning "libmdbx was only tested with GLIBC >= 2.12."
-#endif
-
-#ifdef __SANITIZE_THREAD__
-#warning                                                                       \
-    "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
-#endif /* __SANITIZE_THREAD__ */
-
-#if __has_warning("-Wnested-anon-types")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wnested-anon-types"
-#else
-#pragma warning disable "nested-anon-types"
-#endif
-#endif /* -Wnested-anon-types */
-
-#if __has_warning("-Wconstant-logical-operand")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wconstant-logical-operand"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
-#else
-#pragma warning disable "constant-logical-operand"
-#endif
-#endif /* -Wconstant-logical-operand */
-
-#if defined(__LCC__) && (__LCC__ <= 121)
-/* bug #2798 */
-#pragma diag_suppress alignment_reduction_ignored
-#elif defined(__ICC)
-#pragma warning(disable : 3453 1366)
-#elif __has_warning("-Walignment-reduction-ignored")
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
-#else
-#pragma warning disable "alignment-reduction-ignored"
-#endif
-#endif /* -Walignment-reduction-ignored */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
-
-/*
- * Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
- * and other libmdbx authors: please see AUTHORS file.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#endif                          /* _MSC_VER (warnings) */
-
-#if defined(_WIN32) || defined(_WIN64)
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY &&             \
-    !defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
-#define _NO_CRT_STDIO_INLINE
-#endif
-#elif !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200809L
-#endif /* Windows */
-
-/*----------------------------------------------------------------------------*/
-/* C99 includes */
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-/* C11' alignas() */
-#if __has_include(<stdalign.h>)
-#include <stdalign.h>
-#endif
-#if defined(alignas) || defined(__cplusplus)
-#define MDBX_ALIGNAS(N) alignas(N)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-#define MDBX_ALIGNAS(N) _Alignas(N)
-#elif defined(_MSC_VER)
-#define MDBX_ALIGNAS(N) __declspec(align(N))
-#elif __has_attribute(__aligned__) || defined(__GNUC__)
-#define MDBX_ALIGNAS(N) __attribute__((__aligned__(N)))
-#else
-#error "FIXME: Required alignas() or equivalent."
-#endif /* MDBX_ALIGNAS */
-
-/*----------------------------------------------------------------------------*/
-/* Systems includes */
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#endif /* Apple OSX & iOS */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
-    defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) ||         \
-    defined(__APPLE__) || defined(__MACH__)
-#include <sys/cdefs.h>
-#include <sys/mount.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <vm/vm_param.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
-#include <uvm/uvm_param.h>
-#else
-#define SYSCTL_LEGACY_NONCONST_MIB
-#endif
-#ifndef __MACH__
-#include <sys/vmmeter.h>
-#endif
-#else
-#include <malloc.h>
-#if !(defined(__sun) || defined(__SVR4) || defined(__svr4__) ||                \
-      defined(_WIN32) || defined(_WIN64))
-#include <mntent.h>
-#endif /* !Solaris */
-#endif /* !xBSD */
-
-#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
-#include <malloc_np.h>
-#endif
-
-#if defined(__APPLE__) || defined(__MACH__) || __has_include(<malloc/malloc.h>)
-#include <malloc/malloc.h>
-#endif /* MacOS */
-
-#if defined(__MACH__)
-#include <mach/host_info.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-#include <uuid/uuid.h>
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-#include <sched.h>
-#include <sys/sendfile.h>
-#include <sys/statfs.h>
-#endif /* Linux */
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 0
-#endif
-
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 0
-#else
-#include <utmpx.h>
-#endif /* _XOPEN_SOURCE_EXTENDED */
-
-#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#include <kstat.h>
-#include <sys/mnttab.h>
-/* On Solaris, it's easier to add a missing prototype rather than find a
- * combination of #defines that break nothing. */
-__extern_C key_t ftok(const char *, int);
-#endif /* SunOS/Solaris */
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 /* Windows 7 */
-#elif _WIN32_WINNT < 0x0500
-#error At least 'Windows 2000' API is required for libmdbx.
-#endif /* _WIN32_WINNT */
-#if (defined(__MINGW32__) || defined(__MINGW64__)) &&                          \
-    !defined(__USE_MINGW_ANSI_STDIO)
-#define __USE_MINGW_ANSI_STDIO 1
-#endif /* MinGW */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-#include <excpt.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winnt.h>
-#include <winternl.h>
-#define HAVE_SYS_STAT_H
-#define HAVE_SYS_TYPES_H
-typedef HANDLE mdbx_thread_t;
-typedef unsigned mdbx_thread_key_t;
-#define MAP_FAILED NULL
-#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
-#define THREAD_CALL WINAPI
-#define THREAD_RESULT DWORD
-typedef struct {
-  HANDLE mutex;
-  HANDLE event[2];
-} mdbx_condpair_t;
-typedef CRITICAL_SECTION mdbx_fastmutex_t;
-
-#if !defined(_MSC_VER) && !defined(__try)
-/* *INDENT-OFF* */
-/* clang-format off */
-#define __try
-#define __except(COND) if(false)
-/* *INDENT-ON* */
-/* clang-format on */
-#endif /* stub for MSVC's __try/__except */
-
-#if MDBX_WITHOUT_MSVC_CRT
-
-#ifndef mdbx_malloc
-static inline void *mdbx_malloc(size_t bytes) {
-  return HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_malloc */
-
-#ifndef mdbx_calloc
-static inline void *mdbx_calloc(size_t nelem, size_t size) {
-  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
-}
-#endif /* mdbx_calloc */
-
-#ifndef mdbx_realloc
-static inline void *mdbx_realloc(void *ptr, size_t bytes) {
-  return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
-             : HeapAlloc(GetProcessHeap(), 0, bytes);
-}
-#endif /* mdbx_realloc */
-
-#ifndef mdbx_free
-static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
-#endif /* mdbx_free */
-
-#else /* MDBX_WITHOUT_MSVC_CRT */
-
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup _strdup
-
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-#ifndef snprintf
-#define snprintf _snprintf /* ntdll */
-#endif
-
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf /* ntdll */
-#endif
-
-#else /*----------------------------------------------------------------------*/
-
-#include <unistd.h>
-#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES < 1
-#error "libmdbx requires the _POSIX_MAPPED_FILES feature"
-#endif /* _POSIX_MAPPED_FILES */
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/uio.h>
-typedef pthread_t mdbx_thread_t;
-typedef pthread_key_t mdbx_thread_key_t;
-#define INVALID_HANDLE_VALUE (-1)
-#define THREAD_CALL
-#define THREAD_RESULT void *
-typedef struct {
-  pthread_mutex_t mutex;
-  pthread_cond_t cond[2];
-} mdbx_condpair_t;
-typedef pthread_mutex_t mdbx_fastmutex_t;
-#define mdbx_malloc malloc
-#define mdbx_calloc calloc
-#define mdbx_realloc realloc
-#define mdbx_free free
-#define mdbx_strdup strdup
-#endif /* Platform */
-
-#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
-/* malloc_usable_size() already provided */
-#elif defined(__APPLE__)
-#define malloc_usable_size(ptr) malloc_size(ptr)
-#elif defined(_MSC_VER) && !MDBX_WITHOUT_MSVC_CRT
-#define malloc_usable_size(ptr) _msize(ptr)
-#endif /* malloc_usable_size */
-
-#ifdef __ANDROID_API__
-#include <android/log.h>
-#if __ANDROID_API__ >= 21
-#include <sys/sendfile.h>
-#endif
-#endif /* Android */
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
-#include <sys/types.h>
-#endif
-#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
-#include <sys/file.h>
-#endif
-/* *INDENT-ON* */
-/* clang-format on */
-
-#ifndef SSIZE_MAX
-#define SSIZE_MAX INTPTR_MAX
-#endif
-
-#if !defined(MADV_DODUMP) && defined(MADV_CORE)
-#define MADV_DODUMP MADV_CORE
-#endif /* MADV_CORE -> MADV_DODUMP */
-
-#if !defined(MADV_DONTDUMP) && defined(MADV_NOCORE)
-#define MADV_DONTDUMP MADV_NOCORE
-#endif /* MADV_NOCORE -> MADV_DONTDUMP */
-
-#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
-    defined(i486) || defined(__i486) || defined(__i486__) ||                   \
-    defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) ||   \
-    defined(__i686) || defined(__i686__) || defined(_M_IX86) ||                \
-    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) ||            \
-    defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) ||          \
-    defined(__amd64__) || defined(__amd64) || defined(_M_X64) ||               \
-    defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
-#ifndef __ia32__
-/* LY: define neutral __ia32__ for x86 and x86-64 */
-#define __ia32__ 1
-#endif /* __ia32__ */
-#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) ||        \
-                            defined(__amd64) || defined(_M_X64))
-/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
-#define __amd64__ 1
-#endif /* __amd64__ */
-#endif /* all x86 */
-
-#if (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
-#error                                                                         \
-    "Sanity checking failed: Two's complement, reasonably sized integer types"
-#endif
-
-#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
-#define MDBX_WORDBITS 64
-#else
-#define MDBX_WORDBITS 32
-#endif /* MDBX_WORDBITS */
-
-#if defined(__ANDROID_API__) || defined(ANDROID)
-#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
-#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
-#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
-#endif
-#endif /* Android */
-
-/*----------------------------------------------------------------------------*/
-/* Compiler's includes for builtins/intrinsics */
-
-#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
-#include <intrin.h>
-#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
-#if defined(__ia32__) || defined(__e2k__)
-#include <x86intrin.h>
-#endif /* __ia32__ */
-#if defined(__ia32__)
-#include <cpuid.h>
-#endif /* __ia32__ */
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-#include <mbarrier.h>
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-#include <machine/sys/inline.h>
-#elif defined(__IBMC__) && defined(__powerpc)
-#include <atomic.h>
-#elif defined(_AIX)
-#include <builtins.h>
-#include <sys/atomic_op.h>
-#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
-#include <c_asm.h>
-#include <machine/builtins.h>
-#elif defined(__MWERKS__)
-/* CodeWarrior - troubles ? */
-#pragma gcc_extensions
-#elif defined(__SNC__)
-/* Sony PS3 - troubles ? */
-#elif defined(__hppa__) || defined(__hppa)
-#include <machine/inline.h>
-#else
-#error Unsupported C compiler, please use GNU C 4.4 or newer
-#endif /* Compiler */
-
-/*----------------------------------------------------------------------------*/
-/* Byteorder */
-
-#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
-    !defined(__ORDER_BIG_ENDIAN__)
-
-/* *INDENT-OFF* */
-/* clang-format off */
-#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID_API__) ||  \
-    defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
-#include <endian.h>
-#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) ||       \
-    defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
-#include <machine/endian.h>
-#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
-#include <sys/isa_defs.h>
-#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) ||             \
-    (__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
-#include <sys/endian.h>
-#include <sys/types.h>
-#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) ||   \
-    defined(__NetBSD__) ||                              \
-    defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
-#include <sys/param.h>
-#endif /* OS */
-/* *INDENT-ON* */
-/* clang-format on */
-
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
-#define __BYTE_ORDER__ __BYTE_ORDER
-#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
-#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
-#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
-#define __BYTE_ORDER__ _BYTE_ORDER
-#else
-#define __ORDER_LITTLE_ENDIAN__ 1234
-#define __ORDER_BIG_ENDIAN__ 4321
-
-#if defined(__LITTLE_ENDIAN__) ||                                              \
-    (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) ||                      \
-    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) ||    \
-    defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) ||            \
-    defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) ||                \
-    defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) ||   \
-    defined(__BFIN__) || defined(__ia64__) || defined(_IA64) ||                \
-    defined(__IA64__) || defined(__ia64) || defined(_M_IA64) ||                \
-    defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) ||        \
-    defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) ||              \
-    defined(__WINDOWS__)
-#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
-#elif defined(__BIG_ENDIAN__) ||                                               \
-    (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) ||                      \
-    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) ||    \
-    defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) ||            \
-    defined(__m68k__) || defined(M68000) || defined(__hppa__) ||               \
-    defined(__hppa) || defined(__HPPA__) || defined(__sparc__) ||              \
-    defined(__sparc) || defined(__370__) || defined(__THW_370__) ||            \
-    defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
-#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
-
-#else
-#error __BYTE_ORDER__ should be defined.
-#endif /* Arch */
-
-#endif
-#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
-
-/* Get the size of a memory page for the system.
- * This is the basic size that the platform's memory manager uses, and is
- * fundamental to the use of memory-mapped files. */
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
-mdbx_syspagesize(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-typedef struct mdbx_mmap_param {
-  union {
-    void *address;
-    uint8_t *dxb;
-    struct MDBX_lockinfo *lck;
-  };
-  mdbx_filehandle_t fd;
-  size_t limit;   /* mapping length, but NOT a size of file nor DB */
-  size_t current; /* mapped region size, i.e. the size of file and DB */
-  uint64_t filesize /* in-process cache of a file size */;
-#if defined(_WIN32) || defined(_WIN64)
-  HANDLE section; /* memory-mapped section handle */
-#endif
-} mdbx_mmap_t;
-
-typedef union bin128 {
-  __anonymous_struct_extension__ struct { uint64_t x, y; };
-  __anonymous_struct_extension__ struct { uint32_t a, b, c, d; };
-} bin128_t;
-
-#if defined(_WIN32) || defined(_WIN64)
-typedef union MDBX_srwlock {
-  __anonymous_struct_extension__ struct {
-    long volatile readerCount;
-    long volatile writerCount;
-  };
-  RTL_SRWLOCK native;
-} MDBX_srwlock;
-#endif /* Windows */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && (__has_include(<cstdatomic>) || __has_extension(cxx_atomic))
-#include <cstdatomic>
-#define MDBX_HAVE_C11ATOMICS
-#elif !defined(__cplusplus) &&                                                 \
-    (__STDC_VERSION__ >= 201112L || __has_extension(c_atomic)) &&              \
-    !defined(__STDC_NO_ATOMICS__) &&                                           \
-    (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) ||                            \
-     !(defined(__GNUC__) || defined(__clang__)))
-#include <stdatomic.h>
-#define MDBX_HAVE_C11ATOMICS
-#elif defined(__GNUC__) || defined(__clang__)
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */
-#pragma warning(disable : 4133) /* 'function': incompatible types - from       \
-                                   'size_t' to 'LONGLONG' */
-#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to     \
-                                   'std::size_t', possible loss of data */
-#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to     \
-                                   'long', possible loss of data */
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange)
-#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64)
-#elif defined(__APPLE__)
-#include <libkern/OSAtomic.h>
-#else
-#error FIXME atomic-ops
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Memory/Compiler barriers, cache coherence */
-
-#if __has_include(<sys/cachectl.h>)
-#include <sys/cachectl.h>
-#elif defined(__mips) || defined(__mips__) || defined(__mips64) ||             \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS should have explicit cache control */
-#include <sys/cachectl.h>
-#endif
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
-#if defined(__clang__) || defined(__GNUC__)
-  __asm__ __volatile__("" ::: "memory");
-#elif defined(_MSC_VER)
-  _ReadWriteBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-  __memory_barrier();
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __compiler_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_sched_fence(/* LY: no-arg meaning 'all expect ALU', e.g. 0x3D3D */);
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __fence();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(memory_order_seq_cst);
-#elif defined(__ATOMIC_SEQ_CST)
-#ifdef __clang__
-  __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
-#else
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-#endif
-#elif defined(__clang__) || defined(__GNUC__)
-  __sync_synchronize();
-#elif defined(_WIN32) || defined(_WIN64)
-  MemoryBarrier();
-#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
-#if defined(__ia32__)
-  _mm_mfence();
-#else
-  __mf();
-#endif
-#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
-  __machine_rw_barrier();
-#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) &&       \
-    (defined(HP_IA64) || defined(__ia64))
-  _Asm_mf();
-#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) ||             \
-    defined(__ppc64__) || defined(__powerpc64__)
-  __lwsync();
-#else
-#error "Could not guess the kind of compiler, please report to us."
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* libc compatibility stuff */
-
-#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) &&                           \
-    (defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
-#define mdbx_asprintf asprintf
-#define mdbx_vasprintf vasprintf
-#else
-MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
-    MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
-MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* OS abstraction layer stuff */
-
-/* max bytes to write in one call */
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_WRITE UINT32_C(0x01000000)
-#else
-#define MAX_WRITE UINT32_C(0x3fff0000)
-#endif
-
-#if defined(__linux__) || defined(__gnu_linux__)
-MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
-MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
-#endif /* Linux */
-
-#ifndef mdbx_strdup
-LIBMDBX_API char *mdbx_strdup(const char *str);
-#endif
-
-MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
-#if defined(_WIN32) || defined(_WIN64)
-  DWORD rc = GetLastError();
-#else
-  int rc = errno;
-#endif
-  return rc;
-}
-
-#ifndef mdbx_memalign_alloc
-MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
-                                           void **result);
-#endif
-#ifndef mdbx_memalign_free
-MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
-#endif
-
-MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
-MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
-                                            bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
-MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
-
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
-MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
-
-MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
-                                    int iovcnt, uint64_t offset,
-                                    size_t expected_written);
-MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
-                                  uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
-                                   size_t count, uint64_t offset);
-MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
-                                  size_t count);
-
-MDBX_INTERNAL_FUNC int
-mdbx_thread_create(mdbx_thread_t *thread,
-                   THREAD_RESULT(THREAD_CALL *start_routine)(void *),
-                   void *arg);
-MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
-
-enum mdbx_syncmode_bits {
-  MDBX_SYNC_NONE = 0,
-  MDBX_SYNC_DATA = 1,
-  MDBX_SYNC_SIZE = 2,
-  MDBX_SYNC_IODQ = 4
-};
-
-MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
-                                  const enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
-MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
-MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
-
-enum mdbx_openfile_purpose {
-  MDBX_OPEN_DXB_READ = 0,
-  MDBX_OPEN_DXB_LAZY = 1,
-  MDBX_OPEN_DXB_DSYNC = 2,
-  MDBX_OPEN_LCK = 3,
-  MDBX_OPEN_COPY = 4,
-  MDBX_OPEN_DELETE = 5
-};
-
-MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
-                                     const MDBX_env *env, const char *pathname,
-                                     mdbx_filehandle_t *fd,
-                                     mdbx_mode_t unix_mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
-MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
-MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
-
-#define MMAP_OPTION_TRUNCATE 1
-#define MMAP_OPTION_SEMAPHORE 2
-MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
-                                 const size_t must, const size_t limit,
-                                 const unsigned options);
-MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
-#define MDBX_MRESIZE_MAY_MOVE 0x00000100
-#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
-MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
-                                    size_t size, size_t limit);
-#if defined(_WIN32) || defined(_WIN64)
-typedef struct {
-  unsigned limit, count;
-  HANDLE handles[31];
-} mdbx_handle_array_t;
-MDBX_INTERNAL_FUNC int
-mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
-MDBX_INTERNAL_FUNC int
-mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
-#endif /* Windows */
-MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
-                                  size_t length,
-                                  enum mdbx_syncmode_bits mode_bits);
-MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
-                                            const char *pathname, int err);
-
-MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
-  STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
-#if defined(_WIN32) || defined(_WIN64)
-  return GetCurrentProcessId();
-#else
-  STATIC_ASSERT(sizeof(pid_t) <= sizeof(uint32_t));
-  return getpid();
-#endif
-}
-
-MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
-  mdbx_tid_t thunk;
-  STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
-#if defined(_WIN32) || defined(_WIN64)
-  thunk = GetCurrentThreadId();
-#else
-  thunk = pthread_self();
-#endif
-  return (uintptr_t)thunk;
-}
-
-#if !defined(_WIN32) && !defined(_WIN64)
-#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
-MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
-#else
-static __inline int mdbx_check_tid4bionic(void) { return 0; }
-#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
-
-MDBX_MAYBE_UNUSED static __inline int
-mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
-  int err = mdbx_check_tid4bionic();
-  return unlikely(err) ? err : pthread_mutex_lock(mutex);
-}
-#endif /* !Windows */
-
-MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
-MDBX_INTERNAL_FUNC uint64_t
-mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
-MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
-
-MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
-/*----------------------------------------------------------------------------*/
-/* lck stuff */
-
-/// \brief Initialization of synchronization primitives linked with MDBX_env
-///   instance both in LCK-file and within the current process.
-/// \param
-///   global_uniqueness_flag = true - denotes that there are no other processes
-///     working with DB and LCK-file. Thus the function MUST initialize
-///     shared synchronization objects in memory-mapped LCK-file.
-///   global_uniqueness_flag = false - denotes that at least one process is
-///     already working with DB and LCK-file, including the case when DB
-///     has already been opened in the current process. Thus the function
-///     MUST NOT initialize shared synchronization objects in memory-mapped
-///     LCK-file that are already in use.
-/// \return Error code or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
-                                     MDBX_env *inprocess_neighbor,
-                                     int global_uniqueness_flag);
-
-/// \brief Disconnects from shared interprocess objects and destructs
-///   synchronization objects linked with MDBX_env instance
-///   within the current process.
-/// \param
-///   inprocess_neighbor = NULL - if the current process does not have other
-///     instances of MDBX_env linked with the DB being closed.
-///     Thus the function MUST check for other processes working with DB or
-///     LCK-file, and keep or destroy shared synchronization objects in
-///     memory-mapped LCK-file depending on the result.
-///   inprocess_neighbor = not-NULL - pointer to another instance of MDBX_env
-///     (anyone of there is several) working with DB or LCK-file within the
-///     current process. Thus the function MUST NOT try to acquire exclusive
-///     lock and/or try to destruct shared synchronization objects linked with
-///     DB or LCK-file. Moreover, the implementation MUST ensure correct work
-///     of other instances of MDBX_env within the current process, e.g.
-///     restore POSIX-fcntl locks after the closing of file descriptors.
-/// \return Error code (MDBX_PANIC) or zero on success.
-MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
-                                        MDBX_env *inprocess_neighbor);
-
-/// \brief Connects to shared interprocess locking objects and tries to acquire
-///   the maximum lock level (shared if exclusive is not available)
-///   Depending on implementation or/and platform (Windows) this function may
-///   acquire the non-OS super-level lock (e.g. for shared synchronization
-///   objects initialization), which will be downgraded to OS-exclusive or
-///   shared via explicit calling of mdbx_lck_downgrade().
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
-///     the current process is the first and only after the last use of DB.
-///   MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
-///     DB has already been opened and now is used by other processes.
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
-
-/// \brief Downgrades the level of initially acquired lock to
-///   operational level specified by argument. The reson for such downgrade:
-///    - unblocking of other processes that are waiting for access, i.e.
-///      if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
-///      should be made aware that access is unavailable rather than
-///      wait for it.
-///    - freeing locks that interfere file operation (especially for Windows)
-///   (env->me_flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
-///   (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
-///   operational lock.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
-
-/// \brief Locks LCK-file or/and table of readers for (de)registering.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
-
-/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
-MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
-
-/// \brief Acquires lock for DB change (on writing transaction start)
-///   Reading transactions will not be blocked.
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-/// \return Error code or zero on success
-LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);
-
-/// \brief Releases lock once DB changes is made (after writing transaction
-///   has finished).
-///   Declared as LIBMDBX_API because it is used in mdbx_chk.
-LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
-
-/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
-///   the current process. The function does no more than needed for
-///   the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
-
-/// \brief Resets alive-flag of reader presence (indicative lock)
-///   for PID of the current process. The function does no more than needed
-///   for the correct working of mdbx_rpid_check() in other processes.
-/// \return Error code or zero on success
-MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
-
-/// \brief Checks for reading process status with the given pid with help of
-///   alive-flag of presence (indicative lock) or using another way.
-/// \return
-///   MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
-///     and working with DB (indicative lock is present).
-///   MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
-///     or not working with DB (indicative lock is not present).
-///   Otherwise (not 0 and not -1) - error code.
-MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
-
-#if defined(_WIN32) || defined(_WIN64)
-
-typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
-MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
-    mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
-    mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
-
-#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
-typedef enum _FILE_INFO_BY_HANDLE_CLASS {
-  FileBasicInfo,
-  FileStandardInfo,
-  FileNameInfo,
-  FileRenameInfo,
-  FileDispositionInfo,
-  FileAllocationInfo,
-  FileEndOfFileInfo,
-  FileStreamInfo,
-  FileCompressionInfo,
-  FileAttributeTagInfo,
-  FileIdBothDirectoryInfo,
-  FileIdBothDirectoryRestartInfo,
-  FileIoPriorityHintInfo,
-  FileRemoteProtocolInfo,
-  MaximumFileInfoByHandleClass
-} FILE_INFO_BY_HANDLE_CLASS,
-    *PFILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct _FILE_END_OF_FILE_INFO {
-  LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFO, *PFILE_END_OF_FILE_INFO;
-
-#define REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK 0x00000001
-#define REMOTE_PROTOCOL_INFO_FLAG_OFFLINE 0x00000002
-
-typedef struct _FILE_REMOTE_PROTOCOL_INFO {
-  USHORT StructureVersion;
-  USHORT StructureSize;
-  DWORD Protocol;
-  USHORT ProtocolMajorVersion;
-  USHORT ProtocolMinorVersion;
-  USHORT ProtocolRevision;
-  USHORT Reserved;
-  DWORD Flags;
-  struct {
-    DWORD Reserved[8];
-  } GenericReserved;
-  struct {
-    DWORD Reserved[16];
-  } ProtocolSpecificReserved;
-} FILE_REMOTE_PROTOCOL_INFO, *PFILE_REMOTE_PROTOCOL_INFO;
-
-#endif /* _WIN32_WINNT < 0x0600 (prior to Windows Vista) */
-
-typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_GetFileInformationByHandleEx
-    mdbx_GetFileInformationByHandleEx;
-
-typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)(
-    _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer,
-    _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber,
-    _Out_opt_ LPDWORD lpMaximumComponentLength,
-    _Out_opt_ LPDWORD lpFileSystemFlags,
-    _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize);
-MDBX_INTERNAL_VAR MDBX_GetVolumeInformationByHandleW
-    mdbx_GetVolumeInformationByHandleW;
-
-typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile,
-                                                      _Out_ LPWSTR lpszFilePath,
-                                                      _In_ DWORD cchFilePath,
-                                                      _In_ DWORD dwFlags);
-MDBX_INTERNAL_VAR MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW;
-
-typedef BOOL(WINAPI *MDBX_SetFileInformationByHandle)(
-    _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
-    _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize);
-MDBX_INTERNAL_VAR MDBX_SetFileInformationByHandle
-    mdbx_SetFileInformationByHandle;
-
-typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)(
-    IN HANDLE FileHandle, IN OUT HANDLE Event,
-    IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext,
-    OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode,
-    IN OUT PVOID InputBuffer, IN ULONG InputBufferLength,
-    OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength);
-MDBX_INTERNAL_VAR MDBX_NtFsControlFile mdbx_NtFsControlFile;
-
-typedef uint64_t(WINAPI *MDBX_GetTickCount64)(void);
-MDBX_INTERNAL_VAR MDBX_GetTickCount64 mdbx_GetTickCount64;
-
-#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < _WIN32_WINNT_WIN8
-typedef struct _WIN32_MEMORY_RANGE_ENTRY {
-  PVOID VirtualAddress;
-  SIZE_T NumberOfBytes;
-} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
-#endif /* Windows 8.x */
-
-typedef BOOL(WINAPI *MDBX_PrefetchVirtualMemory)(
-    HANDLE hProcess, ULONG_PTR NumberOfEntries,
-    PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses, ULONG Flags);
-MDBX_INTERNAL_VAR MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
-
-typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
-
-typedef NTSTATUS(NTAPI *MDBX_NtExtendSection)(IN HANDLE SectionHandle,
-                                              IN PLARGE_INTEGER NewSectionSize);
-MDBX_INTERNAL_VAR MDBX_NtExtendSection mdbx_NtExtendSection;
-
-static __inline bool mdbx_RunningUnderWine(void) {
-  return !mdbx_NtExtendSection;
-}
-
-typedef LSTATUS(WINAPI *MDBX_RegGetValueA)(HKEY hkey, LPCSTR lpSubKey,
-                                           LPCSTR lpValue, DWORD dwFlags,
-                                           LPDWORD pdwType, PVOID pvData,
-                                           LPDWORD pcbData);
-MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
-
-NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
-
-#endif /* Windows */
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-
-#if defined(_MSC_VER) && _MSC_VER >= 1900
-/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
- * for internal format-args checker. */
-#undef PRIuPTR
-#undef PRIiPTR
-#undef PRIdPTR
-#undef PRIxPTR
-#define PRIuPTR "Iu"
-#define PRIiPTR "Ii"
-#define PRIdPTR "Id"
-#define PRIxPTR "Ix"
-#define PRIuSIZE "zu"
-#define PRIiSIZE "zi"
-#define PRIdSIZE "zd"
-#define PRIxSIZE "zx"
-#endif /* fix PRI*PTR for _MSC_VER */
-
-#ifndef PRIuSIZE
-#define PRIuSIZE PRIuPTR
-#define PRIiSIZE PRIiPTR
-#define PRIdSIZE PRIdPTR
-#define PRIxSIZE PRIxPTR
-#endif /* PRI*SIZE macros for MSVC */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
-#if defined(xMDBX_TOOLS)
-extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
-#endif
-
-/*******************************************************************************
- *******************************************************************************
- *******************************************************************************
- *
- *
- *         ####   #####    #####     #     ####   #    #   ####
- *        #    #  #    #     #       #    #    #  ##   #  #
- *        #    #  #    #     #       #    #    #  # #  #   ####
- *        #    #  #####      #       #    #    #  #  # #       #
- *        #    #  #          #       #    #    #  #   ##  #    #
- *         ####   #          #       #     ####   #    #   ####
- *
- *
- */
-
-/** \defgroup build_option Build options
- * The libmdbx build options.
- @{ */
-
-/** Using fcntl(F_FULLFSYNC) with 5-10 times slowdown */
-#define MDBX_OSX_WANNA_DURABILITY 0
-/** Using fsync() with chance of data lost on power failure */
-#define MDBX_OSX_WANNA_SPEED 1
-
-#ifndef MDBX_OSX_SPEED_INSTEADOF_DURABILITY
-/** Choices \ref MDBX_OSX_WANNA_DURABILITY or \ref MDBX_OSX_WANNA_SPEED
- * for OSX & iOS */
-#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
-#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
-
-/** Controls checking PID against reuse DB environment after the fork() */
-#ifndef MDBX_ENV_CHECKPID
-#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
-/* PID check could be omitted:
- *  - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
- *    mapped pages will not be available for child process.
- *  - in Windows where fork() not available. */
-#define MDBX_ENV_CHECKPID 0
-#else
-#define MDBX_ENV_CHECKPID 1
-#endif
-#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#else
-#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
-#endif /* MDBX_ENV_CHECKPID */
-
-/** Controls checking transaction owner thread against misuse transactions from
- * other threads. */
-#ifndef MDBX_TXN_CHECKOWNER
-#define MDBX_TXN_CHECKOWNER 1
-#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#else
-#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
-#endif /* MDBX_TXN_CHECKOWNER */
-
-/** Does a system have battery-backed Real-Time Clock or just a fake. */
-#ifndef MDBX_TRUST_RTC
-#if defined(__linux__) || defined(__gnu_linux__) || defined(__NetBSD__) ||     \
-    defined(__OpenBSD__)
-#define MDBX_TRUST_RTC 0 /* a lot of embedded systems have a fake RTC */
-#else
-#define MDBX_TRUST_RTC 1
-#endif
-#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#else
-#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
-#endif /* MDBX_TRUST_RTC */
-
-/** Controls online database auto-compactification during write-transactions. */
-#ifndef MDBX_ENABLE_REFUND
-#define MDBX_ENABLE_REFUND 1
-#elif !(MDBX_ENABLE_REFUND == 0 || MDBX_ENABLE_REFUND == 1)
-#error MDBX_ENABLE_REFUND must be defined as 0 or 1
-#endif /* MDBX_ENABLE_REFUND */
-
-/** Controls gathering statistics for page operations. */
-#ifndef MDBX_ENABLE_PGOP_STAT
-#define MDBX_ENABLE_PGOP_STAT 1
-#elif !(MDBX_ENABLE_PGOP_STAT == 0 || MDBX_ENABLE_PGOP_STAT == 1)
-#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-/** Controls use of POSIX madvise() hints and friends. */
-#ifndef MDBX_ENABLE_MADVISE
-#define MDBX_ENABLE_MADVISE 1
-#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
-#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
-#endif /* MDBX_ENABLE_MADVISE */
-
-/** Disable some checks to reduce an overhead and detection probability of
- * database corruption to a values closer to the LMDB. */
-#ifndef MDBX_DISABLE_PAGECHECKS
-#define MDBX_DISABLE_PAGECHECKS 0
-#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
-#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
-#endif /* MDBX_DISABLE_PAGECHECKS */
-
-#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
-#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_PNL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_PNL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_PNL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_PNL_PREALLOC_FOR_RADIXSORT */
-
-#ifndef MDBX_DPL_PREALLOC_FOR_RADIXSORT
-#define MDBX_DPL_PREALLOC_FOR_RADIXSORT 1
-#elif !(MDBX_DPL_PREALLOC_FOR_RADIXSORT == 0 ||                                \
-        MDBX_DPL_PREALLOC_FOR_RADIXSORT == 1)
-#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
-#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
-
-/* Basically, this build-option is for TODO. Guess it should be replaced
- * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
- *  0/OFF = Don't track dirty pages at all and don't spilling ones.
- *          This should be by-default on Linux and may-be other systems
- *          (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
- *          properly LRU tracking and async writing on-demand.
- *  1/ON  = Lite tracking of dirty pages but with LRU labels and explicit
- *          spilling with msync(MS_ASYNC). */
-#ifndef MDBX_FAKE_SPILL_WRITEMAP
-#if defined(__linux__) || defined(__gnu_linux__)
-#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
-#else
-#define MDBX_FAKE_SPILL_WRITEMAP 0
-#endif
-#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
-#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
-#endif /* MDBX_FAKE_SPILL_WRITEMAP */
-
-/** Controls sort order of internal page number lists.
- * This mostly experimental/advanced option with not for regular MDBX users.
- * \warning The database format depend on this option and libmdbx builded with
- * different option value are incompatible. */
-#ifndef MDBX_PNL_ASCENDING
-#define MDBX_PNL_ASCENDING 0
-#elif !(MDBX_PNL_ASCENDING == 0 || MDBX_PNL_ASCENDING == 1)
-#error MDBX_PNL_ASCENDING must be defined as 0 or 1
-#endif /* MDBX_PNL_ASCENDING */
-
-/** Avoid dependence from MSVC CRT and use ntdll.dll instead. */
-#ifndef MDBX_WITHOUT_MSVC_CRT
-#define MDBX_WITHOUT_MSVC_CRT 1
-#elif !(MDBX_WITHOUT_MSVC_CRT == 0 || MDBX_WITHOUT_MSVC_CRT == 1)
-#error MDBX_WITHOUT_MSVC_CRT must be defined as 0 or 1
-#endif /* MDBX_WITHOUT_MSVC_CRT */
-
-/** Size of buffer used during copying a environment/database file. */
-#ifndef MDBX_ENVCOPY_WRITEBUF
-#define MDBX_ENVCOPY_WRITEBUF 1048576u
-#elif MDBX_ENVCOPY_WRITEBUF < 65536u || MDBX_ENVCOPY_WRITEBUF > 1073741824u || \
-    MDBX_ENVCOPY_WRITEBUF % 65536u
-#error MDBX_ENVCOPY_WRITEBUF must be defined in range 65536..1073741824 and be multiple of 65536
-#endif /* MDBX_ENVCOPY_WRITEBUF */
-
-/** Forces assertion checking */
-#ifndef MDBX_FORCE_ASSERTIONS
-#define MDBX_FORCE_ASSERTIONS 0
-#elif !(MDBX_FORCE_ASSERTIONS == 0 || MDBX_FORCE_ASSERTIONS == 1)
-#error MDBX_FORCE_ASSERTIONS must be defined as 0 or 1
-#endif /* MDBX_FORCE_ASSERTIONS */
-
-/** Presumed malloc size overhead for each allocation
- * to adjust allocations to be more aligned. */
-#ifndef MDBX_ASSUME_MALLOC_OVERHEAD
-#ifdef __SIZEOF_POINTER__
-#define MDBX_ASSUME_MALLOC_OVERHEAD (__SIZEOF_POINTER__ * 2u)
-#else
-#define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u)
-#endif
-#elif MDBX_ASSUME_MALLOC_OVERHEAD < 0 || MDBX_ASSUME_MALLOC_OVERHEAD > 64 ||   \
-    MDBX_ASSUME_MALLOC_OVERHEAD % 4
-#error MDBX_ASSUME_MALLOC_OVERHEAD must be defined in range 0..64 and be multiple of 4
-#endif /* MDBX_ASSUME_MALLOC_OVERHEAD */
-
-/** In case the MDBX_DEBUG is undefined set it corresponding to NDEBUG */
-#ifndef MDBX_DEBUG
-#ifdef NDEBUG
-#define MDBX_DEBUG 0
-#else
-#define MDBX_DEBUG 1
-#endif
-#endif /* MDBX_DEBUG */
-
-/** If defined then enables integration with Valgrind,
- * a memory analyzing tool. */
-#ifndef MDBX_USE_VALGRIND
-#endif /* MDBX_USE_VALGRIND */
-
-/** If defined then enables use C11 atomics,
- *  otherwise detects ones availability automatically. */
-#ifndef MDBX_HAVE_C11ATOMICS
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-//------------------------------------------------------------------------------
-
-/** Win32 File Locking API for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_WIN32FILES -1
-
-/** SystemV IPC semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_SYSV 5
-
-/** POSIX-1 Shared anonymous semaphores for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX1988 1988
-
-/** POSIX-2001 Shared Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2001 2001
-
-/** POSIX-2008 Robust Mutexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_POSIX2008 2008
-
-/** BeOS Benaphores, aka Futexes for \ref MDBX_LOCKING */
-#define MDBX_LOCKING_BENAPHORE 1995
-
-/** Advanced: Choices the locking implementation (autodetection by default). */
-#if defined(_WIN32) || defined(_WIN64)
-#define MDBX_LOCKING MDBX_LOCKING_WIN32FILES
-#else
-#ifndef MDBX_LOCKING
-#if defined(_POSIX_THREAD_PROCESS_SHARED) &&                                   \
-    _POSIX_THREAD_PROCESS_SHARED >= 200112L && !defined(__FreeBSD__)
-
-/* Some platforms define the EOWNERDEAD error code even though they
- * don't support Robust Mutexes. If doubt compile with -MDBX_LOCKING=2001. */
-#if defined(EOWNERDEAD) && _POSIX_THREAD_PROCESS_SHARED >= 200809L &&          \
-    ((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) ||                                \
-     (defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) &&                            \
-      _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) ||                                \
-     defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) &&     \
-    (!defined(__GLIBC__) ||                                                    \
-     __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
-#else
-#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
-#endif
-#elif defined(__sun) || defined(__SVR4) || defined(__svr4__)
-#define MDBX_LOCKING MDBX_LOCKING_POSIX1988
-#else
-#define MDBX_LOCKING MDBX_LOCKING_SYSV
-#endif
-#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
-#else
-#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
-#endif /* MDBX_LOCKING */
-#endif /* !Windows */
-
-/** Advanced: Using POSIX OFD-locks (autodetection by default). */
-#ifndef MDBX_USE_OFDLOCKS
-#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) &&   \
-    !defined(MDBX_SAFE4QEMU) &&                                                \
-    !defined(__sun) /* OFD-lock are broken on Solaris */
-#define MDBX_USE_OFDLOCKS 1
-#else
-#define MDBX_USE_OFDLOCKS 0
-#endif
-#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#else
-#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
-#endif /* MDBX_USE_OFDLOCKS */
-
-/** Advanced: Using sendfile() syscall (autodetection by default). */
-#ifndef MDBX_USE_SENDFILE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     !defined(__ANDROID_API__)) ||                                             \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#define MDBX_USE_SENDFILE 1
-#else
-#define MDBX_USE_SENDFILE 0
-#endif
-#endif /* MDBX_USE_SENDFILE */
-
-/** Advanced: Using copy_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_COPYFILERANGE
-#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
-#define MDBX_USE_COPYFILERANGE 1
-#else
-#define MDBX_USE_COPYFILERANGE 0
-#endif
-#endif /* MDBX_USE_COPYFILERANGE */
-
-/** Advanced: Using sync_file_range() syscall (autodetection by default). */
-#ifndef MDBX_USE_SYNCFILERANGE
-#if ((defined(__linux__) || defined(__gnu_linux__)) &&                         \
-     defined(SYNC_FILE_RANGE_WRITE) && !defined(__ANDROID_API__)) ||           \
-    (defined(__ANDROID_API__) && __ANDROID_API__ >= 26)
-#define MDBX_USE_SYNCFILERANGE 1
-#else
-#define MDBX_USE_SYNCFILERANGE 0
-#endif
-#endif /* MDBX_USE_SYNCFILERANGE */
-
-//------------------------------------------------------------------------------
-
-#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
-#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) ||                \
-    defined(__hppa__) || defined(DOXYGEN)
-#define MDBX_CPU_WRITEBACK_INCOHERENT 0
-#else
-#define MDBX_CPU_WRITEBACK_INCOHERENT 1
-#endif
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
-#ifdef __OpenBSD__
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 1
-#else
-#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
-#if defined(__mips) || defined(__mips__) || defined(__mips64) ||               \
-    defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) ||            \
-    defined(__MWERKS__) || defined(__sgi)
-/* MIPS has cache coherency issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 1
-#else
-/* LY: assume no relevant mmap/dcache issues. */
-#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
-#endif
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#ifndef MDBX_64BIT_ATOMIC
-#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
-#define MDBX_64BIT_ATOMIC 1
-#else
-#define MDBX_64BIT_ATOMIC 0
-#endif
-#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#else
-#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
-#endif /* MDBX_64BIT_ATOMIC */
-
-#ifndef MDBX_64BIT_CAS
-#if defined(ATOMIC_LLONG_LOCK_FREE)
-#if ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE)
-#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE)
-#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS 0
-#endif
-#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
-#define MDBX_64BIT_CAS 1
-#else
-#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
-#endif
-#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#else
-#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
-#endif /* MDBX_64BIT_CAS */
-
-#ifndef MDBX_UNALIGNED_OK
-#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#elif defined(__ARM_FEATURE_UNALIGNED)
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
-/* expecting an optimization will well done, also this
- * hushes false-positives from UBSAN (undefined behaviour sanitizer) */
-#define MDBX_UNALIGNED_OK 0
-#elif defined(__e2k__) || defined(__elbrus__)
-#if __iset__ > 4
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
-#endif
-#elif defined(__ia32__)
-#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
-#else
-#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
-#endif
-#elif MDBX_UNALIGNED_OK == 1
-#undef MDBX_UNALIGNED_OK
-#define MDBX_UNALIGNED_OK 32 /* any unaligned access allowed */
-#endif                       /* MDBX_UNALIGNED_OK */
-
-#ifndef MDBX_CACHELINE_SIZE
-#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
-#define MDBX_CACHELINE_SIZE SYSTEM_CACHE_ALIGNMENT_SIZE
-#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
-#define MDBX_CACHELINE_SIZE 128
-#else
-#define MDBX_CACHELINE_SIZE 64
-#endif
-#endif /* MDBX_CACHELINE_SIZE */
-
-/** @} end of build options */
-/*******************************************************************************
- *******************************************************************************
- ******************************************************************************/
-
-#ifdef DOXYGEN
-/* !!! Actually this is a fake definitions     !!!
- * !!! for documentation generation by Doxygen !!! */
-
-/** Controls enabling of debugging features.
- *
- *  - `MDBX_DEBUG = 0` (by default) Disables any debugging features at all,
- *                     including logging and assertion controls.
- *                     Logging level and corresponding debug flags changing
- *                     by \ref mdbx_setup_debug() will not have effect.
- *  - `MDBX_DEBUG > 0` Enables code for the debugging features (logging,
- *                     assertions checking and internal audit).
- *                     Simultaneously sets the default logging level
- *                     to the `MDBX_DEBUG` value.
- *                     Also enables \ref MDBX_DBG_AUDIT if `MDBX_DEBUG >= 2`.
- *
- * \ingroup build_option */
-#define MDBX_DEBUG 0...7
-
-/** Disables using of GNU libc extensions. */
-#define MDBX_DISABLE_GNU_SOURCE 0 or 1
-
-#endif /* DOXYGEN */
-
-/* Undefine the NDEBUG if debugging is enforced by MDBX_DEBUG */
-#if MDBX_DEBUG
-#undef NDEBUG
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Atomics */
-
-enum MDBX_memory_order {
-  mo_Relaxed,
-  mo_AcquireRelease,
-  mo_SequentialConsistency
-};
-
-typedef union {
-  volatile uint32_t weak;
-#ifdef MDBX_HAVE_C11ATOMICS
-  volatile _Atomic uint32_t c11a;
-#endif /* MDBX_HAVE_C11ATOMICS */
-} MDBX_atomic_uint32_t;
-
-typedef union {
-  volatile uint64_t weak;
-#if defined(MDBX_HAVE_C11ATOMICS) && (MDBX_64BIT_CAS || MDBX_64BIT_ATOMIC)
-  volatile _Atomic uint64_t c11a;
-#endif
-#if !defined(MDBX_HAVE_C11ATOMICS) || !MDBX_64BIT_CAS || !MDBX_64BIT_ATOMIC
-  __anonymous_struct_extension__ struct {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    MDBX_atomic_uint32_t low, high;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-    MDBX_atomic_uint32_t high, low;
-#else
-#error "FIXME: Unsupported byte order"
-#endif /* __BYTE_ORDER__ */
-  };
-#endif
-} MDBX_atomic_uint64_t;
-
-#ifdef MDBX_HAVE_C11ATOMICS
-
-/* Crutches for C11 atomic compiler's bugs */
-#if defined(__e2k__) && defined(__LCC__) && __LCC__ < /* FIXME */ 127
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->weak)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->weak)
-#elif defined(__clang__) && __clang__ < 8
-#define MDBX_c11a_ro(type, ptr) ((volatile _Atomic(type) *)&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#else
-#define MDBX_c11a_ro(type, ptr) (&(ptr)->c11a)
-#define MDBX_c11a_rw(type, ptr) (&(ptr)->c11a)
-#endif /* Crutches for C11 atomic compiler's bugs */
-
-static __always_inline memory_order mo_c11_store(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_release;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-
-static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
-  switch (fence) {
-  default:
-    assert(false);
-    __unreachable();
-  case mo_Relaxed:
-    return memory_order_relaxed;
-  case mo_AcquireRelease:
-    return memory_order_acquire;
-  case mo_SequentialConsistency:
-    return memory_order_seq_cst;
-  }
-}
-#endif /* MDBX_HAVE_C11ATOMICS */
-
-#ifndef __cplusplus
-
-MDBX_MAYBE_UNUSED static __always_inline void
-mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
-#ifdef MDBX_HAVE_C11ATOMICS
-  atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_compiler_barrier();
-  if (write &&
-      order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed : mo_AcquireRelease))
-    mdbx_memory_barrier();
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
-               enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_rw(uint32_t, p)));
-  atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  p->weak = value;
-  mdbx_memory_fence(order, true);
-#endif /* MDBX_HAVE_C11ATOMICS */
-  return value;
-}
-
-MDBX_MAYBE_UNUSED static __always_inline uint32_t
-atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
-  STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
-#ifdef MDBX_HAVE_C11ATOMICS
-  assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p)));
-  return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order));
-#else  /* MDBX_HAVE_C11ATOMICS */
-  mdbx_memory_fence(order, false);
-  const uint32_t value = p->weak;
-  if (order != mo_Relaxed)
-    mdbx_compiler_barrier();
-  return value;
-#endif /* MDBX_HAVE_C11ATOMICS */
-}
-
-#endif /* !__cplusplus */
-
-/*----------------------------------------------------------------------------*/
-/* Basic constants and types */
-
-/* A stamp that identifies a file as an MDBX file.
- * There's nothing special about this value other than that it is easily
- * recognizable, and it will reflect any byte order mismatches. */
-#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
-
-/* FROZEN: The version number for a database's datafile format. */
-#define MDBX_DATA_VERSION 3
-/* The version number for a database's lockfile format. */
-#define MDBX_LOCK_VERSION 4
-
-/* handle for the DB used to track free pages. */
-#define FREE_DBI 0
-/* handle for the default DB. */
-#define MAIN_DBI 1
-/* Number of DBs in metapage (free and main) - also hardcoded elsewhere */
-#define CORE_DBS 2
-
-/* Number of meta pages - also hardcoded elsewhere */
-#define NUM_METAS 3
-
-/* A page number in the database.
- *
- * MDBX uses 32 bit for page numbers. This limits database
- * size up to 2^44 bytes, in case of 4K pages. */
-typedef uint32_t pgno_t;
-typedef MDBX_atomic_uint32_t atomic_pgno_t;
-#define PRIaPGNO PRIu32
-#define MAX_PAGENO UINT32_C(0x7FFFffff)
-#define MIN_PAGENO NUM_METAS
-
-#define SAFE64_INVALID_THRESHOLD UINT64_C(0xffffFFFF00000000)
-
-/* A transaction ID. */
-typedef uint64_t txnid_t;
-typedef MDBX_atomic_uint64_t atomic_txnid_t;
-#define PRIaTXN PRIi64
-#define MIN_TXNID UINT64_C(1)
-#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
-#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
-#define INVALID_TXNID UINT64_MAX
-/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
- * #define xMDBX_TXNID_STEP (UINT32_MAX / 3) */
-#ifndef xMDBX_TXNID_STEP
-#if MDBX_64BIT_CAS
-#define xMDBX_TXNID_STEP 1u
-#else
-#define xMDBX_TXNID_STEP 2u
-#endif
-#endif /* xMDBX_TXNID_STEP */
-
-/* Used for offsets within a single page.
- * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
- * this is plenty. */
-typedef uint16_t indx_t;
-
-#define MEGABYTE ((size_t)1 << 20)
-
-/*----------------------------------------------------------------------------*/
-/* Core structures for database and shared memory (i.e. format definition) */
-#pragma pack(push, 4)
-
-/* Information about a single database in the environment. */
-typedef struct MDBX_db {
-  uint16_t md_flags;        /* see mdbx_dbi_open */
-  uint16_t md_depth;        /* depth of this tree */
-  uint32_t md_xsize;        /* key-size for MDBX_DUPFIXED (LEAF2 pages) */
-  pgno_t md_root;           /* the root page of this tree */
-  pgno_t md_branch_pages;   /* number of internal pages */
-  pgno_t md_leaf_pages;     /* number of leaf pages */
-  pgno_t md_overflow_pages; /* number of overflow pages */
-  uint64_t md_seq;          /* table sequence counter */
-  uint64_t md_entries;      /* number of data items */
-  uint64_t md_mod_txnid;    /* txnid of last committed modification */
-} MDBX_db;
-
-/* database size-related parameters */
-typedef struct MDBX_geo {
-  uint16_t grow_pv;   /* datafile growth step as a 16-bit packed (exponential
-                           quantized) value */
-  uint16_t shrink_pv; /* datafile shrink threshold as a 16-bit packed
-                           (exponential quantized) value */
-  pgno_t lower;       /* minimal size of datafile in pages */
-  pgno_t upper;       /* maximal size of datafile in pages */
-  pgno_t now;         /* current size of datafile in pages */
-  pgno_t next;        /* first unused page in the datafile,
-                         but actually the file may be shorter. */
-} MDBX_geo;
-
-/* Meta page content.
- * A meta page is the start point for accessing a database snapshot.
- * Pages 0-1 are meta pages. Transaction N writes meta page (N % 2). */
-typedef struct MDBX_meta {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with MDBX_DATA_VERSION. */
-  uint32_t mm_magic_and_version[2];
-
-  /* txnid that committed this page, the first of a two-phase-update pair */
-  uint32_t mm_txnid_a[2];
-
-  uint16_t mm_extra_flags;  /* extra DB flags, zero (nothing) for now */
-  uint8_t mm_validator_id;  /* ID of checksum and page validation method,
-                             * zero (nothing) for now */
-  uint8_t mm_extra_pagehdr; /* extra bytes in the page header,
-                             * zero (nothing) for now */
-
-  MDBX_geo mm_geo; /* database size-related parameters */
-
-  MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
-                            /* The size of pages used in this DB */
-#define mm_psize mm_dbs[FREE_DBI].md_xsize
-  MDBX_canary mm_canary;
-
-#define MDBX_DATASIGN_NONE 0u
-#define MDBX_DATASIGN_WEAK 1u
-#define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK)
-#define META_IS_STEADY(meta)                                                   \
-  SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign))
-  uint32_t mm_datasync_sign[2];
-
-  /* txnid that committed this page, the second of a two-phase-update pair */
-  uint32_t mm_txnid_b[2];
-
-  /* Number of non-meta pages which were put in GC after COW. May be 0 in case
-   * DB was previously handled by libmdbx without corresponding feature.
-   * This value in couple with mr_snapshot_pages_retired allows fast estimation
-   * of "how much reader is restraining GC recycling". */
-  uint32_t mm_pages_retired[2];
-
-  /* The analogue /proc/sys/kernel/random/boot_id or similar to determine
-   * whether the system was rebooted after the last use of the database files.
-   * If there was no reboot, but there is no need to rollback to the last
-   * steady sync point. Zeros mean that no relevant information is available
-   * from the system. */
-  bin128_t mm_bootid;
-
-} MDBX_meta;
-
-#pragma pack(1)
-
-/* Common header for all page types. The page type depends on mp_flags.
- *
- * P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
- * sorted mp_ptrs[] entries referring to them. Exception: P_LEAF2 pages
- * omit mp_ptrs and pack sorted MDBX_DUPFIXED values after the page header.
- *
- * P_OVERFLOW records occupy one or more contiguous pages where only the
- * first has a page header. They hold the real data of F_BIGDATA nodes.
- *
- * P_SUBP sub-pages are small leaf "pages" with duplicate data.
- * A node with flag F_DUPDATA but not F_SUBDATA contains a sub-page.
- * (Duplicate data can also go in sub-databases, which use normal pages.)
- *
- * P_META pages contain MDBX_meta, the start point of an MDBX snapshot.
- *
- * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
- * in the snapshot: Either used by a database or listed in a GC record. */
-typedef struct MDBX_page {
-  union {
-#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
-#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
-#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
-#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
-#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
-    uint64_t mp_txnid;
-    struct MDBX_page *mp_next; /* for in-memory list of freed pages */
-  };
-  uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
-#define P_BRANCH 0x01      /* branch page */
-#define P_LEAF 0x02        /* leaf page */
-#define P_OVERFLOW 0x04    /* overflow page */
-#define P_META 0x08        /* meta page */
-#define P_BAD 0x10         /* explicit flag for invalid/bad page */
-#define P_LEAF2 0x20       /* for MDBX_DUPFIXED records */
-#define P_SUBP 0x40        /* for MDBX_DUPSORT sub-pages */
-#define P_SPILLED 0x2000   /* spilled in parent txn */
-#define P_LOOSE 0x4000     /* page was dirtied then freed, can be reused */
-#define P_FROZEN 0x8000    /* used for retire page with known status */
-#define P_ILL_BITS (~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED))
-  uint16_t mp_flags;
-  union {
-    uint32_t mp_pages; /* number of overflow pages */
-    __anonymous_struct_extension__ struct {
-      indx_t mp_lower; /* lower bound of free space */
-      indx_t mp_upper; /* upper bound of free space */
-    };
-  };
-  pgno_t mp_pgno; /* page number */
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  indx_t mp_ptrs[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_page;
-
-/* Size of the page header, excluding dynamic data at the end */
-#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs))
-
-#pragma pack(pop)
-
-#if MDBX_ENABLE_PGOP_STAT
-/* Statistics of page operations overall of all (running, completed and aborted)
- * transactions */
-typedef struct {
-  MDBX_atomic_uint64_t newly;   /* Quantity of a new pages added */
-  MDBX_atomic_uint64_t cow;     /* Quantity of pages copied for update */
-  MDBX_atomic_uint64_t clone;   /* Quantity of parent's dirty pages clones
-                                   for nested transactions */
-  MDBX_atomic_uint64_t split;   /* Page splits */
-  MDBX_atomic_uint64_t merge;   /* Page merges */
-  MDBX_atomic_uint64_t spill;   /* Quantity of spilled dirty pages */
-  MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
-  MDBX_atomic_uint64_t
-      wops; /* Number of explicit write operations (not a pages) to a disk */
-} MDBX_pgop_stat_t;
-#endif /* MDBX_ENABLE_PGOP_STAT */
-
-#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
-#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
-typedef void mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
-
-#define MDBX_CLOCK_SIGN UINT32_C(0xF18D)
-typedef mdbx_pid_t mdbx_ipclock_t;
-#ifndef EOWNERDEAD
-#define EOWNERDEAD MDBX_RESULT_TRUE
-#endif
-
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 ||                                \
-    MDBX_LOCKING == MDBX_LOCKING_POSIX2008
-#define MDBX_CLOCK_SIGN UINT32_C(0x8017)
-typedef pthread_mutex_t mdbx_ipclock_t;
-#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
-#define MDBX_CLOCK_SIGN UINT32_C(0xFC29)
-typedef sem_t mdbx_ipclock_t;
-#else
-#error "FIXME"
-#endif /* MDBX_LOCKING */
-
-#if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus)
-MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc);
-MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc);
-#endif /* MDBX_LOCKING */
-
-/* Reader Lock Table
- *
- * Readers don't acquire any locks for their data access. Instead, they
- * simply record their transaction ID in the reader table. The reader
- * mutex is needed just to find an empty slot in the reader table. The
- * slot's address is saved in thread-specific data so that subsequent
- * read transactions started by the same thread need no further locking to
- * proceed.
- *
- * If MDBX_NOTLS is set, the slot address is not saved in thread-specific data.
- * No reader table is used if the database is on a read-only filesystem.
- *
- * Since the database uses multi-version concurrency control, readers don't
- * actually need any locking. This table is used to keep track of which
- * readers are using data from which old transactions, so that we'll know
- * when a particular old transaction is no longer in use. Old transactions
- * that have discarded any data pages can then have those pages reclaimed
- * for use by a later write transaction.
- *
- * The lock table is constructed such that reader slots are aligned with the
- * processor's cache line size. Any slot is only ever used by one thread.
- * This alignment guarantees that there will be no contention or cache
- * thrashing as threads update their own slot info, and also eliminates
- * any need for locking when accessing a slot.
- *
- * A writer thread will scan every slot in the table to determine the oldest
- * outstanding reader transaction. Any freed pages older than this will be
- * reclaimed by the writer. The writer doesn't use any locks when scanning
- * this table. This means that there's no guarantee that the writer will
- * see the most up-to-date reader info, but that's not required for correct
- * operation - all we need is to know the upper bound on the oldest reader,
- * we don't care at all about the newest reader. So the only consequence of
- * reading stale information here is that old pages might hang around a
- * while longer before being reclaimed. That's actually good anyway, because
- * the longer we delay reclaiming old pages, the more likely it is that a
- * string of contiguous pages can be found after coalescing old pages from
- * many old transactions together. */
-
-/* The actual reader record, with cacheline padding. */
-typedef struct MDBX_reader {
-  /* Current Transaction ID when this transaction began, or (txnid_t)-1.
-   * Multiple readers that start at the same time will probably have the
-   * same ID here. Again, it's not important to exclude them from
-   * anything; all we need to know is which version of the DB they
-   * started from so we can avoid overwriting any data used in that
-   * particular version. */
-  MDBX_atomic_uint64_t /* txnid_t */ mr_txnid;
-
-  /* The information we store in a single slot of the reader table.
-   * In addition to a transaction ID, we also record the process and
-   * thread ID that owns a slot, so that we can detect stale information,
-   * e.g. threads or processes that went away without cleaning up.
-   *
-   * NOTE: We currently don't check for stale records.
-   * We simply re-init the table when we know that we're the only process
-   * opening the lock file. */
-
-  /* The thread ID of the thread owning this txn. */
-  MDBX_atomic_uint64_t mr_tid;
-
-  /* The process ID of the process owning this reader txn. */
-  MDBX_atomic_uint32_t mr_pid;
-
-  /* The number of pages used in the reader's MVCC snapshot,
-   * i.e. the value of meta->mm_geo.next and txn->mt_next_pgno */
-  atomic_pgno_t mr_snapshot_pages_used;
-  /* Number of retired pages at the time this reader starts transaction. So,
-   * at any time the difference mm_pages_retired - mr_snapshot_pages_retired
-   * will give the number of pages which this reader restraining from reuse. */
-  MDBX_atomic_uint64_t mr_snapshot_pages_retired;
-} MDBX_reader;
-
-/* The header for the reader table (a memory-mapped lock file). */
-typedef struct MDBX_lockinfo {
-  /* Stamp identifying this as an MDBX file.
-   * It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
-  uint64_t mti_magic_and_version;
-
-  /* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
-  uint32_t mti_os_and_format;
-
-  /* Flags which environment was opened. */
-  MDBX_atomic_uint32_t mti_envmode;
-
-  /* Threshold of un-synced-with-disk pages for auto-sync feature,
-   * zero means no-threshold, i.e. auto-sync is disabled. */
-  atomic_pgno_t mti_autosync_threshold;
-
-  /* Low 32-bit of txnid with which meta-pages was synced,
-   * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
-  MDBX_atomic_uint32_t mti_meta_sync_txnid;
-
-  /* Period for timed auto-sync feature, i.e. at the every steady checkpoint
-   * the mti_unsynced_timeout sets to the current_time + mti_autosync_period.
-   * The time value is represented in a suitable system-dependent form, for
-   * example clock_gettime(CLOCK_BOOTTIME) or clock_gettime(CLOCK_MONOTONIC).
-   * Zero means timed auto-sync is disabled. */
-  MDBX_atomic_uint64_t mti_autosync_period;
-
-  /* Marker to distinguish uniqueness of DB/CLK. */
-  MDBX_atomic_uint64_t mti_bait_uniqueness;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-#if MDBX_ENABLE_PGOP_STAT
-  /* Statistics of costly ops of all (running, completed and aborted)
-   * transactions */
-  MDBX_pgop_stat_t mti_pgop_stat;
-#endif /* MDBX_ENABLE_PGOP_STAT*/
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Write transaction lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_wlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  atomic_txnid_t mti_oldest_reader;
-
-  /* Timestamp of the last steady sync. Value is represented in a suitable
-   * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or
-   * clock_gettime(CLOCK_MONOTONIC). */
-  MDBX_atomic_uint64_t mti_sync_timestamp;
-
-  /* Number un-synced-with-disk pages for auto-sync feature. */
-  atomic_pgno_t mti_unsynced_pages;
-
-  /* Number of page which was discarded last time by madvise(MADV_FREE). */
-  atomic_pgno_t mti_discarded_tail;
-
-  /* Timestamp of the last readers check. */
-  MDBX_atomic_uint64_t mti_reader_check_timestamp;
-
-  /* Shared anchor for tracking readahead edge and enabled/disabled status. */
-  pgno_t mti_readahead_anchor;
-
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-
-  /* Readeaders registration lock. */
-#if MDBX_LOCKING > 0
-  mdbx_ipclock_t mti_rlock;
-#endif /* MDBX_LOCKING > 0 */
-
-  /* The number of slots that have been used in the reader table.
-   * This always records the maximum count, it is not decremented
-   * when readers release their slots. */
-  MDBX_atomic_uint32_t mti_numreaders;
-  MDBX_atomic_uint32_t mti_readers_refresh_flag;
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
-  MDBX_reader mti_readers[] /* dynamic size */;
-#endif /* C99 */
-} MDBX_lockinfo;
-
-/* Lockfile format signature: version, features and field layout */
-#define MDBX_LOCK_FORMAT                                                       \
-  (MDBX_CLOCK_SIGN * 27733 + (unsigned)sizeof(MDBX_reader) * 13 +              \
-   (unsigned)offsetof(MDBX_reader, mr_snapshot_pages_used) * 251 +             \
-   (unsigned)offsetof(MDBX_lockinfo, mti_oldest_reader) * 83 +                 \
-   (unsigned)offsetof(MDBX_lockinfo, mti_numreaders) * 37 +                    \
-   (unsigned)offsetof(MDBX_lockinfo, mti_readers) * 29)
-
-#define MDBX_DATA_MAGIC                                                        \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
-
-#define MDBX_DATA_MAGIC_LEGACY_COMPAT                                          \
-  ((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
-
-#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
-
-#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
-
-/* The maximum size of a database page.
- *
- * It is 64K, but value-PAGEHDRSZ must fit in MDBX_page.mp_upper.
- *
- * MDBX will use database pages < OS pages if needed.
- * That causes more I/O in write transactions: The OS must
- * know (read) the whole page before writing a partial page.
- *
- * Note that we don't currently support Huge pages. On Linux,
- * regular data files cannot use Huge pages, and in general
- * Huge pages aren't actually pageable. We rely on the OS
- * demand-pager to read our data and page it out when memory
- * pressure from other processes is high. So until OSs have
- * actual paging support for Huge pages, they're not viable. */
-#define MAX_PAGESIZE MDBX_MAX_PAGESIZE
-#define MIN_PAGESIZE MDBX_MIN_PAGESIZE
-
-#define MIN_MAPSIZE (MIN_PAGESIZE * MIN_PAGENO)
-#if defined(_WIN32) || defined(_WIN64)
-#define MAX_MAPSIZE32 UINT32_C(0x38000000)
-#else
-#define MAX_MAPSIZE32 UINT32_C(0x7f000000)
-#endif
-#define MAX_MAPSIZE64 ((MAX_PAGENO + 1) * (uint64_t)MAX_PAGESIZE)
-
-#if MDBX_WORDBITS >= 64
-#define MAX_MAPSIZE MAX_MAPSIZE64
-#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
-#else
-#define MAX_MAPSIZE MAX_MAPSIZE32
-#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
-#endif /* MDBX_WORDBITS */
-
-#define MDBX_READERS_LIMIT 32767
-#define MDBX_RADIXSORT_THRESHOLD 333
-
-/*----------------------------------------------------------------------------*/
-
-/* An PNL is an Page Number List, a sorted array of IDs.
- * The first element of the array is a counter for how many actual page-numbers
- * are in the list. By default PNLs are sorted in descending order, this allow
- * cut off a page with lowest pgno (at the tail) just truncating the list. The
- * sort order of PNLs is controlled by the MDBX_PNL_ASCENDING build option. */
-typedef pgno_t *MDBX_PNL;
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_ORDERED(first, last) ((first) < (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) >= (last))
-#else
-#define MDBX_PNL_ORDERED(first, last) ((first) > (last))
-#define MDBX_PNL_DISORDERED(first, last) ((first) <= (last))
-#endif
-
-/* List of txnid, only for MDBX_txn.tw.lifo_reclaimed */
-typedef txnid_t *MDBX_TXL;
-
-/* An Dirty-Page list item is an pgno/pointer pair. */
-typedef struct MDBX_dp {
-  MDBX_page *ptr;
-  pgno_t pgno;
-  union {
-    unsigned extra;
-    __anonymous_struct_extension__ struct {
-      unsigned multi : 1;
-      unsigned lru : 31;
-    };
-  };
-} MDBX_dp;
-
-/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
-typedef struct MDBX_dpl {
-  unsigned sorted;
-  unsigned length;
-  unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  MDBX_dp items[] /* dynamic size with holes at zero and after the last */;
-#endif
-} MDBX_dpl;
-
-/* PNL sizes */
-#define MDBX_PNL_GRANULATE 1024
-#define MDBX_PNL_INITIAL                                                       \
-  (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
-
-#define MDBX_TXL_GRANULATE 32
-#define MDBX_TXL_INITIAL                                                       \
-  (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-#define MDBX_TXL_MAX                                                           \
-  ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
-
-#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
-#define MDBX_PNL_SIZE(pl) ((pl)[0])
-#define MDBX_PNL_FIRST(pl) ((pl)[1])
-#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)])
-#define MDBX_PNL_BEGIN(pl) (&(pl)[1])
-#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1])
-
-#if MDBX_PNL_ASCENDING
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
-#else
-#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
-#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
-#endif
-
-#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t))
-#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0)
-
-/*----------------------------------------------------------------------------*/
-/* Internal structures */
-
-/* Auxiliary DB info.
- * The information here is mostly static/read-only. There is
- * only a single copy of this record in the environment. */
-typedef struct MDBX_dbx {
-  MDBX_val md_name;                /* name of the database */
-  MDBX_cmp_func *md_cmp;           /* function for comparing keys */
-  MDBX_cmp_func *md_dcmp;          /* function for comparing data items */
-  size_t md_klen_min, md_klen_max; /* min/max key length for the database */
-  size_t md_vlen_min,
-      md_vlen_max; /* min/max value/data length for the database */
-} MDBX_dbx;
-
-/* A database transaction.
- * Every operation requires a transaction handle. */
-struct MDBX_txn {
-#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
-  uint32_t mt_signature;
-
-  /* Transaction Flags */
-  /* mdbx_txn_begin() flags */
-#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
-#define MDBX_TXN_RW_BEGIN_FLAGS                                                \
-  (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
-  /* Additional flag for mdbx_sync_locked() */
-#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
-
-  /* internal txn flags */
-#define MDBX_TXN_FINISHED 0x01  /* txn is finished or never began */
-#define MDBX_TXN_ERROR 0x02     /* txn is unusable after an error */
-#define MDBX_TXN_DIRTY 0x04     /* must write, even if dirty list is empty */
-#define MDBX_TXN_SPILLS 0x08    /* txn or a parent has spilled pages */
-#define MDBX_TXN_HAS_CHILD 0x10 /* txn has an MDBX_txn.mt_child */
-  /* most operations on the txn are currently illegal */
-#define MDBX_TXN_BLOCKED                                                       \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
-
-#define TXN_FLAGS                                                              \
-  (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS |     \
-   MDBX_TXN_HAS_CHILD)
-
-#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) ||       \
-    ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) &         \
-     MDBX_SHRINK_ALLOWED)
-#error "Oops, some flags overlapped or wrong"
-#endif
-  uint32_t mt_flags;
-
-  MDBX_txn *mt_parent; /* parent of a nested txn */
-  /* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
-  MDBX_txn *mt_child;
-  MDBX_geo mt_geo;
-  /* next unallocated page */
-#define mt_next_pgno mt_geo.next
-  /* corresponding to the current size of datafile */
-#define mt_end_pgno mt_geo.now
-
-  /* The ID of this transaction. IDs are integers incrementing from 1.
-   * Only committed write transactions increment the ID. If a transaction
-   * aborts, the ID may be re-used by the next writer. */
-  txnid_t mt_txnid;
-  txnid_t mt_front;
-
-  MDBX_env *mt_env; /* the DB environment */
-  /* Array of records for each DB known in the environment. */
-  MDBX_dbx *mt_dbxs;
-  /* Array of MDBX_db records for each known DB */
-  MDBX_db *mt_dbs;
-  /* Array of sequence numbers for each DB handle */
-  unsigned *mt_dbiseqs;
-
-  /* Transaction DBI Flags */
-#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
-#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
-#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
-#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
-#define DBI_VALID 0x10           /* DB handle is valid, see also DB_VALID */
-#define DBI_USRVALID 0x20        /* As DB_VALID, but not set for FREE_DBI */
-#define DBI_AUDITED 0x40         /* Internal flag for accounting during audit */
-  /* Array of flags for each DB */
-  uint8_t *mt_dbistate;
-  /* Number of DB records in use, or 0 when the txn is finished.
-   * This number only ever increments until the txn finishes; we
-   * don't decrement it when individual DB handles are closed. */
-  MDBX_dbi mt_numdbs;
-  size_t mt_owner; /* thread ID that owns this transaction */
-  MDBX_canary mt_canary;
-  void *mt_userctx; /* User-settable context */
-  MDBX_cursor **mt_cursors;
-
-  union {
-    struct {
-      /* For read txns: This thread/txn's reader table slot, or NULL. */
-      MDBX_reader *reader;
-    } to;
-    struct {
-      /* In write txns, array of cursors for each DB */
-      pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
-      txnid_t last_reclaimed;   /* ID of last used record */
-#if MDBX_ENABLE_REFUND
-      pgno_t loose_refund_wl /* FIXME: describe */;
-#endif /* MDBX_ENABLE_REFUND */
-      /* dirtylist room: Dirty array size - dirty pages visible to this txn.
-       * Includes ancestor txns' dirty pages not hidden by other txns'
-       * dirty/spilled pages. Thus commit(nested txn) has room to merge
-       * dirtylist into mt_parent after freeing hidden mt_parent pages. */
-      unsigned dirtyroom;
-      /* a sequence to spilling dirty page with LRU policy */
-      unsigned dirtylru;
-      /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
-      MDBX_dpl *dirtylist;
-      /* The list of reclaimed txns from GC */
-      MDBX_TXL lifo_reclaimed;
-      /* The list of pages that became unused during this transaction. */
-      MDBX_PNL retired_pages;
-      /* The list of loose pages that became unused and may be reused
-       * in this transaction, linked through `mp_next`. */
-      MDBX_page *loose_pages;
-      /* Number of loose pages (tw.loose_pages) */
-      unsigned loose_count;
-      /* The sorted list of dirty pages we temporarily wrote to disk
-       * because the dirty list was full. page numbers in here are
-       * shifted left by 1, deleted slots have the LSB set. */
-      MDBX_PNL spill_pages;
-      unsigned spill_least_removed;
-    } tw;
-  };
-};
-
-#if MDBX_WORDBITS >= 64
-#define CURSOR_STACK 32
-#else
-#define CURSOR_STACK 24
-#endif
-
-struct MDBX_xcursor;
-
-/* Cursors are used for all DB operations.
- * A cursor holds a path of (page pointer, key index) from the DB
- * root to a position in the DB, plus other state. MDBX_DUPSORT
- * cursors include an xcursor to the current data item. Write txns
- * track their cursors and keep them up to date when data moves.
- * Exception: An xcursor's pointer to a P_SUBP page can be stale.
- * (A node with F_DUPDATA but no F_SUBDATA contains a subpage). */
-struct MDBX_cursor {
-#define MDBX_MC_LIVE UINT32_C(0xFE05D5B1)
-#define MDBX_MC_READY4CLOSE UINT32_C(0x2817A047)
-#define MDBX_MC_WAIT4EOT UINT32_C(0x90E297A7)
-  uint32_t mc_signature;
-  /* The database handle this cursor operates on */
-  MDBX_dbi mc_dbi;
-  /* Next cursor on this DB in this txn */
-  MDBX_cursor *mc_next;
-  /* Backup of the original cursor if this cursor is a shadow */
-  MDBX_cursor *mc_backup;
-  /* Context used for databases with MDBX_DUPSORT, otherwise NULL */
-  struct MDBX_xcursor *mc_xcursor;
-  /* The transaction that owns this cursor */
-  MDBX_txn *mc_txn;
-  /* The database record for this cursor */
-  MDBX_db *mc_db;
-  /* The database auxiliary record for this cursor */
-  MDBX_dbx *mc_dbx;
-  /* The mt_dbistate for this database */
-  uint8_t *mc_dbistate;
-  unsigned mc_snum; /* number of pushed pages */
-  unsigned mc_top;  /* index of top page, normally mc_snum-1 */
-
-  /* Cursor state flags. */
-#define C_INITIALIZED 0x01 /* cursor has been initialized and is valid */
-#define C_EOF 0x02         /* No more data */
-#define C_SUB 0x04         /* Cursor is a sub-cursor */
-#define C_DEL 0x08         /* last op was a cursor_del */
-#define C_UNTRACK 0x10     /* Un-track cursor when closing */
-#define C_RECLAIMING 0x20  /* GC lookup is prohibited */
-#define C_GCFREEZE 0x40    /* reclaimed_pglist must not be updated */
-
-  /* Cursor checking flags. */
-#define C_COPYING 0x100  /* skip key-value length check (copying simplify) */
-#define C_UPDATING 0x200 /* update/rebalance pending */
-#define C_RETIRING 0x400 /* refs to child pages may be invalid */
-#define C_SKIPORD 0x800  /* don't check keys ordering */
-
-  unsigned mc_flags;              /* see mdbx_cursor */
-  MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
-  indx_t mc_ki[CURSOR_STACK];     /* stack of page indices */
-};
-
-/* Context for sorted-dup records.
- * We could have gone to a fully recursive design, with arbitrarily
- * deep nesting of sub-databases. But for now we only handle these
- * levels - main DB, optional sub-DB, sorted-duplicate DB. */
-typedef struct MDBX_xcursor {
-  /* A sub-cursor for traversing the Dup DB */
-  MDBX_cursor mx_cursor;
-  /* The database record for this Dup DB */
-  MDBX_db mx_db;
-  /* The auxiliary DB record for this Dup DB */
-  MDBX_dbx mx_dbx;
-} MDBX_xcursor;
-
-typedef struct MDBX_cursor_couple {
-  MDBX_cursor outer;
-  void *mc_userctx; /* User-settable context */
-  MDBX_xcursor inner;
-} MDBX_cursor_couple;
-
-/* The database environment. */
-struct MDBX_env {
-  /* ----------------------------------------------------- mostly static part */
-#define MDBX_ME_SIGNATURE UINT32_C(0x9A899641)
-  MDBX_atomic_uint32_t me_signature;
-  /* Failed to update the meta page. Probably an I/O error. */
-#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
-  /* Some fields are initialized. */
-#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
-  /* me_txkey is set */
-#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
-  /* Legacy MDBX_MAPASYNC (prior v0.9) */
-#define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000)
-#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
-  uint32_t me_flags;
-  mdbx_mmap_t me_dxb_mmap; /* The main data file */
-#define me_map me_dxb_mmap.dxb
-#define me_lazy_fd me_dxb_mmap.fd
-  mdbx_filehandle_t me_dsync_fd;
-  mdbx_mmap_t me_lck_mmap; /* The lock file */
-#define me_lfd me_lck_mmap.fd
-  struct MDBX_lockinfo *me_lck;
-
-  unsigned me_psize;        /* DB page size, initialized from me_os_psize */
-  unsigned me_leaf_nodemax; /* max size of a leaf-node */
-  uint8_t me_psize2log;     /* log2 of DB page size */
-  int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
-  uint16_t me_merge_threshold,
-      me_merge_threshold_gc;  /* pages emptier than this are candidates for
-                                 merging */
-  unsigned me_os_psize;       /* OS page size, from mdbx_syspagesize() */
-  unsigned me_maxreaders;     /* size of the reader table */
-  MDBX_dbi me_maxdbs;         /* size of the DB table */
-  uint32_t me_pid;            /* process ID of this env */
-  mdbx_thread_key_t me_txkey; /* thread-key for readers */
-  char *me_pathname;          /* path to the DB files */
-  void *me_pbuf;              /* scratch area for DUPSORT put() */
-  MDBX_txn *me_txn0;          /* preallocated write transaction */
-
-  MDBX_dbx *me_dbxs;    /* array of static DB info */
-  uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
-  unsigned *me_dbiseqs; /* array of dbi sequence numbers */
-  unsigned
-      me_maxgc_ov1page;    /* Number of pgno_t fit in a single overflow page */
-  uint32_t me_live_reader; /* have liveness lock in reader table */
-  void *me_userctx;        /* User-settable context */
-  MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
-
-  struct {
-    unsigned dp_reserve_limit;
-    unsigned rp_augment_limit;
-    unsigned dp_limit;
-    unsigned dp_initial;
-    uint8_t dp_loose_limit;
-    uint8_t spill_max_denominator;
-    uint8_t spill_min_denominator;
-    uint8_t spill_parent4child_denominator;
-    unsigned merge_threshold_16dot16_percent;
-    union {
-      unsigned all;
-      /* tracks options with non-auto values but tuned by user */
-      struct {
-        unsigned dp_limit : 1;
-      } non_auto;
-    } flags;
-  } me_options;
-
-  /* struct me_dbgeo used for accepting db-geo params from user for the new
-   * database creation, i.e. when mdbx_env_set_geometry() was called before
-   * mdbx_env_open(). */
-  struct {
-    size_t lower;  /* minimal size of datafile */
-    size_t upper;  /* maximal size of datafile */
-    size_t now;    /* current size of datafile */
-    size_t grow;   /* step to grow datafile */
-    size_t shrink; /* threshold to shrink datafile */
-  } me_dbgeo;
-
-#if MDBX_LOCKING == MDBX_LOCKING_SYSV
-  union {
-    key_t key;
-    int semid;
-  } me_sysv_ipc;
-#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
-
-  MDBX_env *me_lcklist_next;
-
-  /* --------------------------------------------------- mostly volatile part */
-
-  MDBX_txn *me_txn; /* current write transaction */
-  mdbx_fastmutex_t me_dbi_lock;
-  MDBX_dbi me_numdbs; /* number of DBs opened */
-
-  MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
-  unsigned me_dp_reserve_len;
-  /* PNL of pages that became unused in a write txn */
-  MDBX_PNL me_retired_pages;
-
-#if defined(_WIN32) || defined(_WIN64)
-  MDBX_srwlock me_remap_guard;
-  /* Workaround for LockFileEx and WriteFile multithread bug */
-  CRITICAL_SECTION me_windowsbug_lock;
-#else
-  mdbx_fastmutex_t me_remap_guard;
-#endif
-
-  /* -------------------------------------------------------------- debugging */
-
-#if MDBX_DEBUG
-  MDBX_assert_func *me_assert_func; /*  Callback for assertion failures */
-#endif
-#ifdef MDBX_USE_VALGRIND
-  int me_valgrind_handle;
-#endif
-#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
-  pgno_t me_poison_edge;
-#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
-
-#ifndef xMDBX_DEBUG_SPILLING
-#define xMDBX_DEBUG_SPILLING 0
-#endif
-#if xMDBX_DEBUG_SPILLING == 2
-  unsigned debug_dirtied_est, debug_dirtied_act;
-#endif /* xMDBX_DEBUG_SPILLING */
-
-  /* ------------------------------------------------- stub for lck-less mode */
-  MDBX_atomic_uint64_t
-      x_lckless_stub[(sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) /
-                     sizeof(MDBX_atomic_uint64_t)];
-};
-
-#ifndef __cplusplus
-/*----------------------------------------------------------------------------*/
-/* Debug and Logging stuff */
-
-#define MDBX_RUNTIME_FLAGS_INIT                                                \
-  ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
-
-extern uint8_t mdbx_runtime_flags;
-extern uint8_t mdbx_loglevel;
-extern MDBX_debug_func *mdbx_debug_logger;
-
-MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
-#if MDBX_DEBUG
-  if (MDBX_DBG_JITTER & mdbx_runtime_flags)
-    mdbx_osal_jitter(tiny);
-#else
-  (void)tiny;
-#endif
-}
-
-MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
-    mdbx_debug_log(int level, const char *function, int line, const char *fmt,
-                   ...) MDBX_PRINTF_ARGS(4, 5);
-MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
-                                          int line, const char *fmt,
-                                          va_list args);
-
-#if MDBX_DEBUG
-#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT))
-#else /* MDBX_DEBUG */
-#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel)
-#define mdbx_audit_enabled() (0)
-#endif /* MDBX_DEBUG */
-
-#if MDBX_FORCE_ASSERTIONS
-#define mdbx_assert_enabled() (1)
-#elif MDBX_DEBUG
-#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT))
-#else
-#define mdbx_assert_enabled() (0)
-#endif /* assertions */
-
-#if !MDBX_DEBUG && defined(__ANDROID_API__)
-#define mdbx_assert_fail(env, msg, func, line)                                 \
-  __android_log_assert(msg, "mdbx", "%s:%u", func, line)
-#else
-void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
-                      int line);
-#endif
-
-#define mdbx_debug_extra(fmt, ...)                                             \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__);    \
-  } while (0)
-
-#define mdbx_debug_extra_print(fmt, ...)                                       \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_EXTRA))                                      \
-      mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__);               \
-  } while (0)
-
-#define mdbx_trace(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_TRACE))                                      \
-      mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_debug(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_DEBUG))                                      \
-      mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_verbose(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_VERBOSE))                                    \
-      mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n",           \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_notice(fmt, ...)                                                  \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_NOTICE))                                     \
-      mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n",            \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_warning(fmt, ...)                                                 \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_WARN))                                       \
-      mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n",              \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_error(fmt, ...)                                                   \
-  do {                                                                         \
-    if (mdbx_log_enabled(MDBX_LOG_ERROR))                                      \
-      mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n",             \
-                     __VA_ARGS__);                                             \
-  } while (0)
-
-#define mdbx_fatal(fmt, ...)                                                   \
-  mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
-
-#define mdbx_ensure_msg(env, expr, msg)                                        \
-  do {                                                                         \
-    if (unlikely(!(expr)))                                                     \
-      mdbx_assert_fail(env, msg, __func__, __LINE__);                          \
-  } while (0)
-
-#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr)
-
-/* assert(3) variant in environment context */
-#define mdbx_assert(env, expr)                                                 \
-  do {                                                                         \
-    if (mdbx_assert_enabled())                                                 \
-      mdbx_ensure(env, expr);                                                  \
-  } while (0)
-
-/* assert(3) variant in cursor context */
-#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr)
-
-/* assert(3) variant in transaction context */
-#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr)
-
-#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
-#undef assert
-#define assert(expr) mdbx_assert(NULL, expr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* Cache coherence and mmap invalidation */
-
-#if MDBX_CPU_WRITEBACK_INCOHERENT
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier()
-#else
-#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
-#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
-
-MDBX_MAYBE_UNUSED static __inline void
-mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
-#if MDBX_MMAP_INCOHERENT_FILE_WRITE
-  char *const begin = (char *)(-pagesize & (intptr_t)addr);
-  char *const end =
-      (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1));
-  int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0;
-  mdbx_assert(nullptr, err == 0);
-  (void)err;
-#else
-  (void)pagesize;
-#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
-
-#if MDBX_MMAP_INCOHERENT_CPU_CACHE
-#ifdef DCACHE
-  /* MIPS has cache coherency issues.
-   * Note: for any nbytes >= on-chip cache size, entire is flushed. */
-  cacheflush(addr, nbytes, DCACHE);
-#else
-#error "Oops, cacheflush() not available"
-#endif /* DCACHE */
-#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
-
-#if !MDBX_MMAP_INCOHERENT_FILE_WRITE && !MDBX_MMAP_INCOHERENT_CPU_CACHE
-  (void)addr;
-  (void)nbytes;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-/* Internal prototypes */
-
-MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked,
-                                                 int *dead);
-MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key,
-                                       MDBX_reader *begin, MDBX_reader *end);
-MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key);
-
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
-MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
-
-#endif /* !__cplusplus */
-
-#define MDBX_IS_ERROR(rc)                                                      \
-  ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
-
-/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10)
-
-/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
-#define DDBI(mc)                                                               \
-  (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
-
-/* Key size which fits in a DKBUF (debug key buffer). */
-#define DKBUF_MAX 511
-#define DKBUF char _kbuf[DKBUF_MAX * 4 + 2]
-#define DKEY(x) mdbx_dump_val(x, _kbuf, DKBUF_MAX * 2 + 1)
-#define DVAL(x) mdbx_dump_val(x, _kbuf + DKBUF_MAX * 2 + 1, DKBUF_MAX * 2 + 1)
-
-#if MDBX_DEBUG
-#define DKBUF_DEBUG DKBUF
-#define DKEY_DEBUG(x) DKEY(x)
-#define DVAL_DEBUG(x) DVAL(x)
-#else
-#define DKBUF_DEBUG ((void)(0))
-#define DKEY_DEBUG(x) ("-")
-#define DVAL_DEBUG(x) ("-")
-#endif
-
-/* An invalid page number.
- * Mainly used to denote an empty tree. */
-#define P_INVALID (~(pgno_t)0)
-
-/* Test if the flags f are set in a flag word w. */
-#define F_ISSET(w, f) (((w) & (f)) == (f))
-
-/* Round n up to an even number. */
-#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
-
-/* Default size of memory map.
- * This is certainly too small for any actual applications. Apps should
- * always set the size explicitly using mdbx_env_set_geometry(). */
-#define DEFAULT_MAPSIZE MEGABYTE
-
-/* Number of slots in the reader table.
- * This value was chosen somewhat arbitrarily. The 61 is a prime number,
- * and such readers plus a couple mutexes fit into single 4KB page.
- * Applications should set the table size using mdbx_env_set_maxreaders(). */
-#define DEFAULT_READERS 61
-
-/* Test if a page is a leaf page */
-#define IS_LEAF(p) (((p)->mp_flags & P_LEAF) != 0)
-/* Test if a page is a LEAF2 page */
-#define IS_LEAF2(p) unlikely(((p)->mp_flags & P_LEAF2) != 0)
-/* Test if a page is a branch page */
-#define IS_BRANCH(p) (((p)->mp_flags & P_BRANCH) != 0)
-/* Test if a page is an overflow page */
-#define IS_OVERFLOW(p) unlikely(((p)->mp_flags & P_OVERFLOW) != 0)
-/* Test if a page is a sub page */
-#define IS_SUBP(p) (((p)->mp_flags & P_SUBP) != 0)
-
-#define PAGETYPE(p) ((p)->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW))
-
-/* Header for a single key/data pair within a page.
- * Used in pages of type P_BRANCH and P_LEAF without P_LEAF2.
- * We guarantee 2-byte alignment for 'MDBX_node's.
- *
- * Leaf node flags describe node contents.  F_BIGDATA says the node's
- * data part is the page number of an overflow page with actual data.
- * F_DUPDATA and F_SUBDATA can be combined giving duplicate data in
- * a sub-page/sub-database, and named databases (just F_SUBDATA). */
-typedef struct MDBX_node {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-  union {
-    uint32_t mn_dsize;
-    uint32_t mn_pgno32;
-  };
-  uint8_t mn_flags; /* see mdbx_node flags */
-  uint8_t mn_extra;
-  uint16_t mn_ksize; /* key size */
-#else
-  uint16_t mn_ksize; /* key size */
-  uint8_t mn_extra;
-  uint8_t mn_flags; /* see mdbx_node flags */
-  union {
-    uint32_t mn_pgno32;
-    uint32_t mn_dsize;
-  };
-#endif /* __BYTE_ORDER__ */
-
-  /* mdbx_node Flags */
-#define F_BIGDATA 0x01 /* data put on overflow page */
-#define F_SUBDATA 0x02 /* data is a sub-database */
-#define F_DUPDATA 0x04 /* data has duplicates */
-
-  /* valid flags for mdbx_node_add() */
-#define NODE_ADD_FLAGS (F_DUPDATA | F_SUBDATA | MDBX_RESERVE | MDBX_APPEND)
-
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) ||              \
-    (!defined(__cplusplus) && defined(_MSC_VER))
-  uint8_t mn_data[] /* key and data are appended here */;
-#endif /* C99 */
-} MDBX_node;
-
-#define DB_PERSISTENT_FLAGS                                                    \
-  (MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED |          \
-   MDBX_INTEGERDUP | MDBX_REVERSEDUP)
-
-/* mdbx_dbi_open() flags */
-#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
-
-#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
-#define DB_INTERNAL_FLAGS DB_VALID
-
-#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
-#error "Oops, some flags overlapped or wrong"
-#endif
-
-/* max number of pages to commit in one writev() call */
-#define MDBX_COMMIT_PAGES 64
-#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */
-#undef MDBX_COMMIT_PAGES
-#define MDBX_COMMIT_PAGES IOV_MAX
-#endif
-
-/*
- *                /
- *                | -1, a < b
- * CMP2INT(a,b) = <  0, a == b
- *                |  1, a > b
- *                \
- */
-#ifndef __e2k__
-/* LY: fast enough on most systems */
-#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
-#else
-/* LY: more parallelable on VLIW Elbrus */
-#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
-#endif
-
-/* Do not spill pages to disk if txn is getting full, may fail instead */
-#define MDBX_NOSPILL 0x8000
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-int64pgno(int64_t i64) {
-  if (likely(i64 >= (int64_t)MIN_PAGENO && i64 <= (int64_t)MAX_PAGENO + 1))
-    return (pgno_t)i64;
-  return (i64 < (int64_t)MIN_PAGENO) ? MIN_PAGENO : MAX_PAGENO;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_add(size_t base, size_t augend) {
-  assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
-  return int64pgno(base + augend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
-pgno_sub(size_t base, size_t subtrahend) {
-  assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
-         subtrahend < MAX_PAGENO);
-  return int64pgno(base - subtrahend);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
-is_powerof2(size_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-floor_powerof2(size_t value, size_t granularity) {
-  assert(is_powerof2(granularity));
-  return value & ~(granularity - 1);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
-ceil_powerof2(size_t value, size_t granularity) {
-  return floor_powerof2(value + granularity - 1, granularity);
-}
-
-MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
-log2n_powerof2(size_t value) {
-  assert(value > 0 && value < INT32_MAX && is_powerof2(value));
-  assert((value & -(int32_t)value) == value);
-#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
-  return __builtin_ctzl(value);
-#elif defined(_MSC_VER)
-  unsigned long index;
-  _BitScanForward(&index, (unsigned long)value);
-  return index;
-#else
-  static const uint8_t debruijn_ctz32[32] = {
-      0,  1,  28, 2,  29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4,  8,
-      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6,  11, 5,  10, 9};
-  return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27];
-#endif
-}
-
-/* Only a subset of the mdbx_env flags can be changed
- * at runtime. Changing other flags requires closing the
- * environment and re-opening it with the new flags. */
-#define ENV_CHANGEABLE_FLAGS                                                   \
-  (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_DEPRECATED_MAPASYNC |             \
-   MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
-#define ENV_CHANGELESS_FLAGS                                                   \
-  (MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
-   MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
-#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
-
-#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
-MDBX_MAYBE_UNUSED static void static_checks(void) {
-  STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
-                    "Oops, MDBX_MAX_DBI or CORE_DBS?");
-  STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
-                        ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
-                         (ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
-                    "Oops, some flags overlapped or wrong");
-  STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
-                    "Oops, some flags overlapped or wrong");
-}
-#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size)                             \
-  do {                                                                         \
-    mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),          \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_POISON_MEMORY_REGION(addr, size);                                     \
-  } while (0)
-
-#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size)                           \
-  do {                                                                         \
-    mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr),        \
-               (size_t)(size), __LINE__);                                      \
-    ASAN_UNPOISON_MEMORY_REGION(addr, size);                                   \
-  } while (0)
-
-#if defined(_WIN32) || defined(_WIN64)
-/*
- * POSIX getopt for Windows
- *
- * AT&T Public License
- *
- * Code given out at the 1985 UNIFORUM conference in Dallas.
- */
-
-/*----------------------------------------------------------------------------*/
-/* Microsoft compiler generates a lot of warning for self includes... */
-
-#ifdef _MSC_VER
-#pragma warning(push, 1)
-#pragma warning(disable : 4548) /* expression before comma has no effect;      \
-                                   expected expression with side - effect */
-#pragma warning(disable : 4530) /* C++ exception handler used, but unwind      \
-                                 * semantics are not enabled. Specify /EHsc */
-#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling  \
-                                 * mode specified; termination on exception is \
-                                 * not guaranteed. Specify /EHsc */
-#if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-#endif /* _MSC_VER (warnings) */
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-/*----------------------------------------------------------------------------*/
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *opts) {
-  static int sp = 1;
-  int c;
-  const char *cp;
-
-  if (sp == 1) {
-    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
-      return EOF;
-    else if (strcmp(argv[optind], "--") == 0) {
-      optind++;
-      return EOF;
-    }
-  }
-  optopt = c = argv[optind][sp];
-  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
-    fprintf(stderr, "%s: %s -- %c\n", argv[0], "illegal option", c);
-    if (argv[optind][++sp] == '\0') {
-      optind++;
-      sp = 1;
-    }
-    return '?';
-  }
-  if (*++cp == ':') {
-    if (argv[optind][sp + 1] != '\0')
-      optarg = &argv[optind++][sp + 1];
-    else if (++optind >= argc) {
-      fprintf(stderr, "%s: %s -- %c\n", argv[0], "option requires an argument",
-              c);
-      sp = 1;
-      return '?';
-    } else
-      optarg = argv[optind++];
-    sp = 1;
-  } else {
-    if (argv[optind][++sp] == '\0') {
-      sp = 1;
-      optind++;
-    }
-    optarg = NULL;
-  }
-  return c;
-}
-
-static volatile BOOL user_break;
-static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
-  (void)dwCtrlType;
-  user_break = true;
-  return true;
-}
-
-#else /* WINDOWS */
-
-static volatile sig_atomic_t user_break;
-static void signal_handler(int sig) {
-  (void)sig;
-  user_break = 1;
-}
-
-#endif /* !WINDOWS */
-
-static void print_stat(MDBX_stat *ms) {
-  printf("  Pagesize: %u\n", ms->ms_psize);
-  printf("  Tree depth: %u\n", ms->ms_depth);
-  printf("  Branch pages: %" PRIu64 "\n", ms->ms_branch_pages);
-  printf("  Leaf pages: %" PRIu64 "\n", ms->ms_leaf_pages);
-  printf("  Overflow pages: %" PRIu64 "\n", ms->ms_overflow_pages);
-  printf("  Entries: %" PRIu64 "\n", ms->ms_entries);
-}
-
-static void usage(const char *prog) {
-  fprintf(stderr,
-          "usage: %s [-V] [-q] [-e] [-f[f[f]]] [-r[r]] [-a|-s name] dbpath\n"
-          "  -V\t\tprint version and exit\n"
-          "  -q\t\tbe quiet\n"
-          "  -p\t\tshow statistics of page operations for current session\n"
-          "  -e\t\tshow whole DB info\n"
-          "  -f\t\tshow GC info\n"
-          "  -r\t\tshow readers\n"
-          "  -a\t\tprint stat of main DB and all subDBs\n"
-          "  -s name\tprint stat of only the specified named subDB\n"
-          "  \t\tby default print stat of only the main DB\n",
-          prog);
-  exit(EXIT_FAILURE);
-}
-
-static int reader_list_func(void *ctx, int num, int slot, mdbx_pid_t pid,
-                            mdbx_tid_t thread, uint64_t txnid, uint64_t lag,
-                            size_t bytes_used, size_t bytes_retained) {
-  (void)ctx;
-  if (num == 1)
-    printf("Reader Table\n"
-           "   #\tslot\t%6s %*s %20s %10s %13s %13s\n",
-           "pid", (int)sizeof(size_t) * 2, "thread", "txnid", "lag", "used",
-           "retained");
-
-  printf(" %3d)\t[%d]\t%6" PRIdSIZE " %*" PRIxPTR, num, slot, (size_t)pid,
-         (int)sizeof(size_t) * 2, (uintptr_t)thread);
-  if (txnid)
-    printf(" %20" PRIu64 " %10" PRIu64 " %12.1fM %12.1fM\n", txnid, lag,
-           bytes_used / 1048576.0, bytes_retained / 1048576.0);
-  else
-    printf(" %20s %10s %13s %13s\n", "-", "0", "0", "0");
-
-  return user_break ? MDBX_RESULT_TRUE : MDBX_RESULT_FALSE;
-}
-
-const char *prog;
-bool quiet = false;
-static void error(const char *func, int rc) {
-  if (!quiet)
-    fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc,
-            mdbx_strerror(rc));
-}
-
-int main(int argc, char *argv[]) {
-  int opt, rc;
-  MDBX_env *env;
-  MDBX_txn *txn;
-  MDBX_dbi dbi;
-  MDBX_envinfo mei;
-  prog = argv[0];
-  char *envname;
-  char *subname = nullptr;
-  bool alldbs = false, envinfo = false, pgop = false;
-  int freinfo = 0, rdrinfo = 0;
-
-  if (argc < 2)
-    usage(prog);
-
-  while ((opt = getopt(argc, argv,
-                       "V"
-                       "q"
-                       "p"
-                       "a"
-                       "e"
-                       "f"
-                       "n"
-                       "r"
-                       "s:")) != EOF) {
-    switch (opt) {
-    case 'V':
-      printf("mdbx_stat version %d.%d.%d.%d\n"
-             " - source: %s %s, commit %s, tree %s\n"
-             " - anchor: %s\n"
-             " - build: %s for %s by %s\n"
-             " - flags: %s\n"
-             " - options: %s\n",
-             mdbx_version.major, mdbx_version.minor, mdbx_version.release,
-             mdbx_version.revision, mdbx_version.git.describe,
-             mdbx_version.git.datetime, mdbx_version.git.commit,
-             mdbx_version.git.tree, mdbx_sourcery_anchor, mdbx_build.datetime,
-             mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
-             mdbx_build.options);
-      return EXIT_SUCCESS;
-    case 'q':
-      quiet = true;
-      break;
-    case 'p':
-      pgop = true;
-      break;
-    case 'a':
-      if (subname)
-        usage(prog);
-      alldbs = true;
-      break;
-    case 'e':
-      envinfo = true;
-      break;
-    case 'f':
-      freinfo += 1;
-      break;
-    case 'n':
-      break;
-    case 'r':
-      rdrinfo += 1;
-      break;
-    case 's':
-      if (alldbs)
-        usage(prog);
-      subname = optarg;
-      break;
-    default:
-      usage(prog);
-    }
-  }
-
-  if (optind != argc - 1)
-    usage(prog);
-
-#if defined(_WIN32) || defined(_WIN64)
-  SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
-#else
-#ifdef SIGPIPE
-  signal(SIGPIPE, signal_handler);
-#endif
-#ifdef SIGHUP
-  signal(SIGHUP, signal_handler);
-#endif
-  signal(SIGINT, signal_handler);
-  signal(SIGTERM, signal_handler);
-#endif /* !WINDOWS */
-
-  envname = argv[optind];
-  envname = argv[optind];
-  if (!quiet) {
-    printf("mdbx_stat %s (%s, T-%s)\nRunning for %s...\n",
-           mdbx_version.git.describe, mdbx_version.git.datetime,
-           mdbx_version.git.tree, envname);
-    fflush(nullptr);
-  }
-
-  rc = mdbx_env_create(&env);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_create", rc);
-    return EXIT_FAILURE;
-  }
-
-  if (alldbs || subname) {
-    rc = mdbx_env_set_maxdbs(env, 2);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_env_set_maxdbs", rc);
-      goto env_close;
-    }
-  }
-
-  rc = mdbx_env_open(env, envname, MDBX_RDONLY, 0);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_env_open", rc);
-    goto env_close;
-  }
-
-  rc = mdbx_txn_begin(env, nullptr, MDBX_TXN_RDONLY, &txn);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_txn_begin", rc);
-    goto txn_abort;
-  }
-
-  if (envinfo || freinfo || pgop) {
-    rc = mdbx_env_info_ex(env, txn, &mei, sizeof(mei));
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_env_info_ex", rc);
-      goto txn_abort;
-    }
-  } else {
-    /* LY: zap warnings from gcc */
-    memset(&mei, 0, sizeof(mei));
-  }
-
-  if (pgop) {
-    printf("Page Operations (for current session):\n");
-    printf("      New: %8" PRIu64 "\t// quantity of a new pages added\n",
-           mei.mi_pgop_stat.newly);
-    printf("      CoW: %8" PRIu64
-           "\t// quantity of pages copied for altering\n",
-           mei.mi_pgop_stat.cow);
-    printf("    Clone: %8" PRIu64 "\t// quantity of parent's dirty pages "
-           "clones for nested transactions\n",
-           mei.mi_pgop_stat.clone);
-    printf("    Split: %8" PRIu64
-           "\t// page splits during insertions or updates\n",
-           mei.mi_pgop_stat.split);
-    printf("    Merge: %8" PRIu64
-           "\t// page merges during deletions or updates\n",
-           mei.mi_pgop_stat.merge);
-    printf("    Spill: %8" PRIu64 "\t// quantity of spilled/ousted `dirty` "
-           "pages during large transactions\n",
-           mei.mi_pgop_stat.spill);
-    printf("  Unspill: %8" PRIu64 "\t// quantity of unspilled/redone `dirty` "
-           "pages during large transactions\n",
-           mei.mi_pgop_stat.unspill);
-    printf("      WOP: %8" PRIu64
-           "\t// number of explicit write operations (not a pages) to a disk\n",
-           mei.mi_pgop_stat.wops);
-  }
-
-  if (envinfo) {
-    printf("Environment Info\n");
-    printf("  Pagesize: %u\n", mei.mi_dxb_pagesize);
-    if (mei.mi_geo.lower != mei.mi_geo.upper) {
-      printf("  Dynamic datafile: %" PRIu64 "..%" PRIu64 " bytes (+%" PRIu64
-             "/-%" PRIu64 "), %" PRIu64 "..%" PRIu64 " pages (+%" PRIu64
-             "/-%" PRIu64 ")\n",
-             mei.mi_geo.lower, mei.mi_geo.upper, mei.mi_geo.grow,
-             mei.mi_geo.shrink, mei.mi_geo.lower / mei.mi_dxb_pagesize,
-             mei.mi_geo.upper / mei.mi_dxb_pagesize,
-             mei.mi_geo.grow / mei.mi_dxb_pagesize,
-             mei.mi_geo.shrink / mei.mi_dxb_pagesize);
-      printf("  Current mapsize: %" PRIu64 " bytes, %" PRIu64 " pages \n",
-             mei.mi_mapsize, mei.mi_mapsize / mei.mi_dxb_pagesize);
-      printf("  Current datafile: %" PRIu64 " bytes, %" PRIu64 " pages\n",
-             mei.mi_geo.current, mei.mi_geo.current / mei.mi_dxb_pagesize);
-#if defined(_WIN32) || defined(_WIN64)
-      if (mei.mi_geo.shrink && mei.mi_geo.current != mei.mi_geo.upper)
-        printf("                    WARNING: Due Windows system limitations a "
-               "file couldn't\n                    be truncated while database "
-               "is opened. So, the size of\n                    database file "
-               "may by large than the database itself,\n                    "
-               "until it will be closed or reopened in read-write mode.\n");
-#endif
-    } else {
-      printf("  Fixed datafile: %" PRIu64 " bytes, %" PRIu64 " pages\n",
-             mei.mi_geo.current, mei.mi_geo.current / mei.mi_dxb_pagesize);
-    }
-    printf("  Last transaction ID: %" PRIu64 "\n", mei.mi_recent_txnid);
-    printf("  Latter reader transaction ID: %" PRIu64 " (%" PRIi64 ")\n",
-           mei.mi_latter_reader_txnid,
-           mei.mi_latter_reader_txnid - mei.mi_recent_txnid);
-    printf("  Max readers: %u\n", mei.mi_maxreaders);
-    printf("  Number of reader slots uses: %u\n", mei.mi_numreaders);
-  }
-
-  if (rdrinfo) {
-    rc = mdbx_reader_list(env, reader_list_func, nullptr);
-    if (MDBX_IS_ERROR(rc)) {
-      error("mdbx_reader_list", rc);
-      goto txn_abort;
-    }
-    if (rc == MDBX_RESULT_TRUE)
-      printf("Reader Table is empty\n");
-    else if (rc == MDBX_SUCCESS && rdrinfo > 1) {
-      int dead;
-      rc = mdbx_reader_check(env, &dead);
-      if (MDBX_IS_ERROR(rc)) {
-        error("mdbx_reader_check", rc);
-        goto txn_abort;
-      }
-      if (rc == MDBX_RESULT_TRUE) {
-        printf("  %d stale readers cleared.\n", dead);
-        rc = mdbx_reader_list(env, reader_list_func, nullptr);
-        if (rc == MDBX_RESULT_TRUE)
-          printf("  Now Reader Table is empty\n");
-      } else
-        printf("  No stale readers.\n");
-    }
-    if (!(subname || alldbs || freinfo))
-      goto txn_abort;
-  }
-
-  if (freinfo) {
-    printf("Garbage Collection\n");
-    dbi = 0;
-    MDBX_cursor *cursor;
-    rc = mdbx_cursor_open(txn, dbi, &cursor);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_cursor_open", rc);
-      goto txn_abort;
-    }
-
-    MDBX_stat mst;
-    rc = mdbx_dbi_stat(txn, dbi, &mst, sizeof(mst));
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_dbi_stat", rc);
-      goto txn_abort;
-    }
-    print_stat(&mst);
-
-    pgno_t pages = 0, *iptr;
-    pgno_t reclaimable = 0;
-    MDBX_val key, data;
-    while (MDBX_SUCCESS ==
-           (rc = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT))) {
-      if (user_break) {
-        rc = MDBX_EINTR;
-        break;
-      }
-      iptr = data.iov_base;
-      const pgno_t number = *iptr++;
-
-      pages += number;
-      if (envinfo && mei.mi_latter_reader_txnid > *(txnid_t *)key.iov_base)
-        reclaimable += number;
-
-      if (freinfo > 1) {
-        char *bad = "";
-        pgno_t prev =
-            MDBX_PNL_ASCENDING ? NUM_METAS - 1 : (pgno_t)mei.mi_last_pgno + 1;
-        pgno_t span = 1;
-        for (unsigned i = 0; i < number; ++i) {
-          pgno_t pg = iptr[i];
-          if (MDBX_PNL_DISORDERED(prev, pg))
-            bad = " [bad sequence]";
-          prev = pg;
-          while (i + span < number &&
-                 iptr[i + span] == (MDBX_PNL_ASCENDING ? pgno_add(pg, span)
-                                                       : pgno_sub(pg, span)))
-            ++span;
-        }
-        printf("    Transaction %" PRIaTXN ", %" PRIaPGNO
-               " pages, maxspan %" PRIaPGNO "%s\n",
-               *(txnid_t *)key.iov_base, number, span, bad);
-        if (freinfo > 2) {
-          for (unsigned i = 0; i < number; i += span) {
-            const pgno_t pg = iptr[i];
-            for (span = 1;
-                 i + span < number &&
-                 iptr[i + span] == (MDBX_PNL_ASCENDING ? pgno_add(pg, span)
-                                                       : pgno_sub(pg, span));
-                 ++span)
-              ;
-            if (span > 1)
-              printf("     %9" PRIaPGNO "[%" PRIaPGNO "]\n", pg, span);
-            else
-              printf("     %9" PRIaPGNO "\n", pg);
-          }
-        }
-      }
-    }
-    mdbx_cursor_close(cursor);
-    cursor = nullptr;
-
-    switch (rc) {
-    case MDBX_SUCCESS:
-    case MDBX_NOTFOUND:
-      break;
-    case MDBX_EINTR:
-      if (!quiet)
-        fprintf(stderr, "Interrupted by signal/user\n");
-      goto txn_abort;
-    default:
-      error("mdbx_cursor_get", rc);
-      goto txn_abort;
-    }
-
-    if (envinfo) {
-      uint64_t value = mei.mi_mapsize / mei.mi_dxb_pagesize;
-      double percent = value / 100.0;
-      printf("Page Usage\n");
-      printf("  Total: %" PRIu64 " 100%%\n", value);
-
-      value = mei.mi_geo.current / mei.mi_dxb_pagesize;
-      printf("  Backed: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = mei.mi_last_pgno + 1;
-      printf("  Allocated: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = mei.mi_mapsize / mei.mi_dxb_pagesize - (mei.mi_last_pgno + 1);
-      printf("  Remained: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = mei.mi_last_pgno + 1 - pages;
-      printf("  Used: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = pages;
-      printf("  GC: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = pages - reclaimable;
-      printf("  Retained: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = reclaimable;
-      printf("  Reclaimable: %" PRIu64 " %.1f%%\n", value, value / percent);
-
-      value = mei.mi_mapsize / mei.mi_dxb_pagesize - (mei.mi_last_pgno + 1) +
-              reclaimable;
-      printf("  Available: %" PRIu64 " %.1f%%\n", value, value / percent);
-    } else
-      printf("  GC: %" PRIaPGNO " pages\n", pages);
-  }
-
-  rc = mdbx_dbi_open(txn, subname, MDBX_DB_ACCEDE, &dbi);
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_open", rc);
-    goto txn_abort;
-  }
-
-  MDBX_stat mst;
-  rc = mdbx_dbi_stat(txn, dbi, &mst, sizeof(mst));
-  if (unlikely(rc != MDBX_SUCCESS)) {
-    error("mdbx_dbi_stat", rc);
-    goto txn_abort;
-  }
-  printf("Status of %s\n", subname ? subname : "Main DB");
-  print_stat(&mst);
-
-  if (alldbs) {
-    MDBX_cursor *cursor;
-    rc = mdbx_cursor_open(txn, dbi, &cursor);
-    if (unlikely(rc != MDBX_SUCCESS)) {
-      error("mdbx_cursor_open", rc);
-      goto txn_abort;
-    }
-
-    MDBX_val key;
-    while (MDBX_SUCCESS ==
-           (rc = mdbx_cursor_get(cursor, &key, nullptr, MDBX_NEXT_NODUP))) {
-      MDBX_dbi subdbi;
-      if (memchr(key.iov_base, '\0', key.iov_len))
-        continue;
-      subname = mdbx_malloc(key.iov_len + 1);
-      memcpy(subname, key.iov_base, key.iov_len);
-      subname[key.iov_len] = '\0';
-      rc = mdbx_dbi_open(txn, subname, MDBX_DB_ACCEDE, &subdbi);
-      if (rc == MDBX_SUCCESS)
-        printf("Status of %s\n", subname);
-      mdbx_free(subname);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        if (rc == MDBX_INCOMPATIBLE)
-          continue;
-        error("mdbx_dbi_open", rc);
-        goto txn_abort;
-      }
-
-      rc = mdbx_dbi_stat(txn, subdbi, &mst, sizeof(mst));
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_dbi_stat", rc);
-        goto txn_abort;
-      }
-      print_stat(&mst);
-
-      rc = mdbx_dbi_close(env, subdbi);
-      if (unlikely(rc != MDBX_SUCCESS)) {
-        error("mdbx_dbi_close", rc);
-        goto txn_abort;
-      }
-    }
-    mdbx_cursor_close(cursor);
-    cursor = nullptr;
-  }
-
-  switch (rc) {
-  case MDBX_SUCCESS:
-  case MDBX_NOTFOUND:
-    break;
-  case MDBX_EINTR:
-    if (!quiet)
-      fprintf(stderr, "Interrupted by signal/user\n");
-    break;
-  default:
-    if (unlikely(rc != MDBX_SUCCESS))
-      error("mdbx_cursor_get", rc);
-  }
-
-  mdbx_dbi_close(env, dbi);
-txn_abort:
-  mdbx_txn_abort(txn);
-env_close:
-  mdbx_env_close(env);
-
-  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/3rdparty/libmdbx/ntdll.def b/3rdparty/libmdbx/ntdll.def
deleted file mode 100644
index f974ea63803120da94ef5ea6882cfed8ce01c713..0000000000000000000000000000000000000000
--- a/3rdparty/libmdbx/ntdll.def
+++ /dev/null
@@ -1,1246 +0,0 @@
-LIBRARY ntdll
-EXPORTS
-CsrAllocateCaptureBuffer
-CsrAllocateMessagePointer
-CsrCaptureMessageBuffer
-CsrCaptureMessageMultiUnicodeStringsInPlace
-CsrCaptureMessageString
-CsrCaptureTimeout
-CsrClientCallServer
-CsrClientConnectToServer
-CsrFreeCaptureBuffer
-CsrGetProcessId
-CsrIdentifyAlertableThread
-CsrSetPriorityClass
-DbgBreakPoint
-DbgPrint
-DbgPrintEx
-DbgPrintReturnControlC
-DbgPrompt
-DbgQueryDebugFilterState
-DbgSetDebugFilterState
-DbgUiConnectToDbg
-DbgUiContinue
-DbgUiConvertStateChangeStructure
-DbgUiDebugActiveProcess
-DbgUiGetThreadDebugObject
-DbgUiIssueRemoteBreakin
-DbgUiRemoteBreakin
-DbgUiSetThreadDebugObject
-DbgUiStopDebugging
-DbgUiWaitStateChange
-DbgUserBreakPoint
-KiRaiseUserExceptionDispatcher
-KiUserApcDispatcher
-KiUserCallbackDispatcher
-KiUserExceptionDispatcher
-LdrAccessResource
-LdrAddRefDll
-LdrDisableThreadCalloutsForDll
-LdrEnumResources
-LdrEnumerateLoadedModules
-LdrFindEntryForAddress
-LdrFindResourceDirectory_U
-LdrFindResourceEx_U
-LdrFindResource_U
-LdrFlushAlternateResourceModules
-LdrGetDllHandle
-LdrGetDllHandleEx
-LdrGetProcedureAddress
-LdrInitShimEngineDynamic
-LdrInitializeThunk
-LdrLoadAlternateResourceModule
-LdrLoadDll
-LdrLockLoaderLock
-LdrProcessRelocationBlock
-LdrQueryImageFileExecutionOptions
-LdrQueryProcessModuleInformation
-LdrSetAppCompatDllRedirectionCallback
-LdrSetDllManifestProber
-LdrShutdownProcess
-LdrShutdownThread
-LdrUnloadAlternateResourceModule
-LdrUnloadDll
-LdrUnlockLoaderLock
-LdrVerifyImageMatchesChecksum
-NlsAnsiCodePage
-NlsMbCodePageTag
-NlsMbOemCodePageTag
-NtAcceptConnectPort
-NtAccessCheck
-NtAccessCheckAndAuditAlarm
-NtAccessCheckByType
-NtAccessCheckByTypeAndAuditAlarm
-NtAccessCheckByTypeResultList
-NtAccessCheckByTypeResultListAndAuditAlarm
-NtAccessCheckByTypeResultListAndAuditAlarmByHandle
-NtAddAtom
-NtAddBootEntry
-NtAdjustGroupsToken
-NtAdjustPrivilegesToken
-NtAlertResumeThread
-NtAlertThread
-NtAllocateLocallyUniqueId
-NtAllocateUserPhysicalPages
-NtAllocateUuids
-NtAllocateVirtualMemory
-NtAreMappedFilesTheSame
-NtAssignProcessToJobObject
-NtCallbackReturn
-NtCancelIoFile
-NtCancelTimer
-NtClearEvent
-NtClose
-NtCloseObjectAuditAlarm
-NtCompactKeys
-NtCompareTokens
-NtCompleteConnectPort
-NtCompressKey
-NtConnectPort
-NtContinue
-NtCreateDebugObject
-NtCreateDirectoryObject
-NtCreateEvent
-NtCreateEventPair
-NtCreateFile
-NtCreateIoCompletion
-NtCreateJobObject
-NtCreateJobSet
-NtCreateKey
-NtCreateKeyedEvent
-NtCreateMailslotFile
-NtCreateMutant
-NtCreateNamedPipeFile
-NtCreatePagingFile
-NtCreatePort
-NtCreateProcess
-NtCreateProcessEx
-NtCreateProfile
-NtCreateSection
-NtCreateSemaphore
-NtCreateSymbolicLinkObject
-NtCreateThread
-NtCreateTimer
-NtCreateToken
-NtCreateWaitablePort
-NtDebugActiveProcess
-NtDebugContinue
-NtDelayExecution
-NtDeleteAtom
-NtDeleteBootEntry
-NtDeleteFile
-NtDeleteKey
-NtDeleteObjectAuditAlarm
-NtDeleteValueKey
-NtDeviceIoControlFile
-NtDisplayString
-NtDuplicateObject
-NtDuplicateToken
-NtEnumerateBootEntries
-NtEnumerateKey
-NtEnumerateSystemEnvironmentValuesEx
-NtEnumerateValueKey
-NtExtendSection
-NtFilterToken
-NtFindAtom
-NtFlushBuffersFile
-NtFlushInstructionCache
-NtFlushKey
-NtFlushVirtualMemory
-NtFlushWriteBuffer
-NtFreeUserPhysicalPages
-NtFreeVirtualMemory
-NtFsControlFile
-NtGetContextThread
-NtGetDevicePowerState
-NtGetWriteWatch
-NtImpersonateAnonymousToken
-NtImpersonateClientOfPort
-NtImpersonateThread
-NtInitializeRegistry
-NtInitiatePowerAction
-NtIsProcessInJob
-NtIsSystemResumeAutomatic
-NtListenPort
-NtLoadDriver
-NtLoadKey
-NtLoadKey2
-NtLockFile
-NtLockProductActivationKeys
-NtLockRegistryKey
-NtLockVirtualMemory
-NtMakePermanentObject
-NtMakeTemporaryObject
-NtMapUserPhysicalPages
-NtMapUserPhysicalPagesScatter
-NtMapViewOfSection
-NtModifyBootEntry
-NtNotifyChangeDirectoryFile
-NtNotifyChangeKey
-NtNotifyChangeMultipleKeys
-NtOpenDirectoryObject
-NtOpenEvent
-NtOpenEventPair
-NtOpenFile
-NtOpenIoCompletion
-NtOpenJobObject
-NtOpenKey
-NtOpenKeyedEvent
-NtOpenMutant
-NtOpenObjectAuditAlarm
-NtOpenProcess
-NtOpenProcessToken
-NtOpenProcessTokenEx
-NtOpenSection
-NtOpenSemaphore
-NtOpenSymbolicLinkObject
-NtOpenThread
-NtOpenThreadToken
-NtOpenThreadTokenEx
-NtOpenTimer
-NtPlugPlayControl
-NtPowerInformation
-NtPrivilegeCheck
-NtPrivilegeObjectAuditAlarm
-NtPrivilegedServiceAuditAlarm
-NtProtectVirtualMemory
-NtPulseEvent
-NtQueryAttributesFile
-NtQueryBootEntryOrder
-NtQueryBootOptions
-NtQueryDebugFilterState
-NtQueryDefaultLocale
-NtQueryDefaultUILanguage
-NtQueryDirectoryFile
-NtQueryDirectoryObject
-NtQueryEaFile
-NtQueryEvent
-NtQueryFullAttributesFile
-NtQueryInformationAtom
-NtQueryInformationFile
-NtQueryInformationJobObject
-NtQueryInformationPort
-NtQueryInformationProcess
-NtQueryInformationThread
-NtQueryInformationToken
-NtQueryInstallUILanguage
-NtQueryIntervalProfile
-NtQueryIoCompletion
-NtQueryKey
-NtQueryMultipleValueKey
-NtQueryMutant
-NtQueryObject
-NtQueryOpenSubKeys
-NtQueryPerformanceCounter
-NtQueryPortInformationProcess
-NtQueryQuotaInformationFile
-NtQuerySection
-NtQuerySecurityObject
-NtQuerySemaphore
-NtQuerySymbolicLinkObject
-NtQuerySystemEnvironmentValue
-NtQuerySystemEnvironmentValueEx
-NtQuerySystemInformation
-NtQuerySystemTime
-NtQueryTimer
-NtQueryTimerResolution
-NtQueryValueKey
-NtQueryVirtualMemory
-NtQueryVolumeInformationFile
-NtQueueApcThread
-NtRaiseException
-NtRaiseHardError
-NtReadFile
-NtReadFileScatter
-NtReadRequestData
-NtReadVirtualMemory
-NtRegisterThreadTerminatePort
-NtReleaseKeyedEvent
-NtReleaseMutant
-NtReleaseSemaphore
-NtRemoveIoCompletion
-NtRemoveProcessDebug
-NtRenameKey
-NtReplaceKey
-NtReplyPort
-NtReplyWaitReceivePort
-NtReplyWaitReceivePortEx
-NtReplyWaitReplyPort
-NtRequestPort
-NtRequestWaitReplyPort
-NtResetEvent
-NtResetWriteWatch
-NtRestoreKey
-NtResumeProcess
-NtResumeThread
-NtSaveKey
-NtSaveKeyEx
-NtSaveMergedKeys
-NtSecureConnectPort
-NtSetBootEntryOrder
-NtSetBootOptions
-NtSetContextThread
-NtSetDebugFilterState
-NtSetDefaultHardErrorPort
-NtSetDefaultLocale
-NtSetDefaultUILanguage
-NtSetEaFile
-NtSetEvent
-NtSetEventBoostPriority
-NtSetHighEventPair
-NtSetHighWaitLowEventPair
-NtSetInformationDebugObject
-NtSetInformationFile
-NtSetInformationJobObject
-NtSetInformationKey
-NtSetInformationObject
-NtSetInformationProcess
-NtSetInformationThread
-NtSetInformationToken
-NtSetIntervalProfile
-NtSetIoCompletion
-NtSetLdtEntries
-NtSetLowEventPair
-NtSetLowWaitHighEventPair
-NtSetQuotaInformationFile
-NtSetSecurityObject
-NtSetSystemEnvironmentValue
-NtSetSystemEnvironmentValueEx
-NtSetSystemInformation
-NtSetSystemPowerState
-NtSetSystemTime
-NtSetThreadExecutionState
-NtSetTimer
-NtSetTimerResolution
-NtSetUuidSeed
-NtSetValueKey
-NtSetVolumeInformationFile
-NtShutdownSystem
-NtSignalAndWaitForSingleObject
-NtStartProfile
-NtStopProfile
-NtSuspendProcess
-NtSuspendThread
-NtSystemDebugControl
-NtTerminateJobObject
-NtTerminateProcess
-NtTerminateThread
-NtTestAlert
-NtTraceEvent
-NtTranslateFilePath
-NtUnloadDriver
-NtUnloadKey
-NtUnloadKeyEx
-NtUnlockFile
-NtUnlockVirtualMemory
-NtUnmapViewOfSection
-NtVdmControl
-NtWaitForDebugEvent
-NtWaitForKeyedEvent
-NtWaitForMultipleObjects
-NtWaitForSingleObject
-NtWaitHighEventPair
-NtWaitLowEventPair
-NtWriteFile
-NtWriteFileGather
-NtWriteRequestData
-NtWriteVirtualMemory
-NtYieldExecution
-PfxFindPrefix
-PfxInitialize
-PfxInsertPrefix
-PfxRemovePrefix
-RtlAbortRXact
-RtlAbsoluteToSelfRelativeSD
-RtlAcquirePebLock
-RtlAcquireResourceExclusive
-RtlAcquireResourceShared
-RtlActivateActivationContext
-RtlActivateActivationContextEx
-RtlActivateActivationContextUnsafeFast
-RtlAddAccessAllowedAce
-RtlAddAccessAllowedAceEx
-RtlAddAccessAllowedObjectAce
-RtlAddAccessDeniedAce
-RtlAddAccessDeniedAceEx
-RtlAddAccessDeniedObjectAce
-RtlAddAce
-RtlAddActionToRXact
-RtlAddAtomToAtomTable
-RtlAddAttributeActionToRXact
-RtlAddAuditAccessAce
-RtlAddAuditAccessAceEx
-RtlAddAuditAccessObjectAce
-RtlAddCompoundAce
-RtlAddRefActivationContext
-RtlAddRefMemoryStream
-RtlAddVectoredExceptionHandler
-RtlAddressInSectionTable
-RtlAdjustPrivilege
-RtlAllocateAndInitializeSid
-RtlAllocateHandle
-RtlAllocateHeap
-RtlAnsiCharToUnicodeChar
-RtlAnsiStringToUnicodeSize
-RtlAnsiStringToUnicodeString
-RtlAppendAsciizToString
-RtlAppendPathElement
-RtlAppendStringToString
-RtlAppendUnicodeStringToString
-RtlAppendUnicodeToString
-RtlApplicationVerifierStop
-RtlApplyRXact
-RtlApplyRXactNoFlush
-RtlAreAllAccessesGranted
-RtlAreAnyAccessesGranted
-RtlAreBitsClear
-RtlAreBitsSet
-RtlAssert
-RtlCancelTimer
-RtlCaptureContext
-RtlCaptureStackBackTrace
-RtlCharToInteger
-RtlCheckForOrphanedCriticalSections
-RtlCheckRegistryKey
-RtlClearAllBits
-RtlClearBits
-RtlCloneMemoryStream
-RtlCommitMemoryStream
-RtlCompactHeap
-RtlCompareMemory
-RtlCompareMemoryUlong
-RtlCompareString
-RtlCompareUnicodeString
-RtlCompressBuffer
-RtlComputeCrc32
-RtlComputeImportTableHash
-RtlComputePrivatizedDllName_U
-RtlConsoleMultiByteToUnicodeN
-RtlConvertExclusiveToShared
-RtlConvertSharedToExclusive
-RtlConvertSidToUnicodeString
-RtlConvertToAutoInheritSecurityObject
-RtlCopyLuid
-RtlCopyLuidAndAttributesArray
-RtlCopyMemoryStreamTo
-RtlCopyOutOfProcessMemoryStreamTo
-RtlCopySecurityDescriptor
-RtlCopySid
-RtlCopySidAndAttributesArray
-RtlCopyString
-RtlCopyUnicodeString
-RtlCreateAcl
-RtlCreateActivationContext
-RtlCreateAndSetSD
-RtlCreateAtomTable
-RtlCreateBootStatusDataFile
-RtlCreateEnvironment
-RtlCreateHeap
-RtlCreateProcessParameters
-RtlCreateQueryDebugBuffer
-RtlCreateRegistryKey
-RtlCreateSecurityDescriptor
-RtlCreateServiceSid
-RtlCreateSystemVolumeInformationFolder
-RtlCreateTagHeap
-RtlCreateTimer
-RtlCreateTimerQueue
-RtlCreateUnicodeString
-RtlCreateUnicodeStringFromAsciiz
-RtlCreateUserProcess
-RtlCreateUserSecurityObject
-RtlCreateUserThread
-RtlCustomCPToUnicodeN
-RtlCutoverTimeToSystemTime
-RtlDeNormalizeProcessParams
-RtlDeactivateActivationContext
-RtlDeactivateActivationContextUnsafeFast
-RtlDebugPrintTimes
-RtlDecodePointer
-RtlDecodeSystemPointer
-RtlDecompressBuffer
-RtlDecompressFragment
-RtlDefaultNpAcl
-RtlDelete
-RtlDeleteAce
-RtlDeleteAtomFromAtomTable
-RtlDeleteCriticalSection
-RtlDeleteElementGenericTable
-RtlDeleteElementGenericTableAvl
-RtlDeleteNoSplay
-RtlDeleteRegistryValue
-RtlDeleteResource
-RtlDeleteSecurityObject
-RtlDeleteTimer
-RtlDeleteTimerQueue
-RtlDeleteTimerQueueEx
-RtlDeregisterWait
-RtlDeregisterWaitEx
-RtlDestroyAtomTable
-RtlDestroyEnvironment
-RtlDestroyHandleTable
-RtlDestroyHeap
-RtlDestroyProcessParameters
-RtlDestroyQueryDebugBuffer
-RtlDetermineDosPathNameType_U
-RtlDllShutdownInProgress
-RtlDnsHostNameToComputerName
-RtlDoesFileExists_U
-RtlDosApplyFileIsolationRedirection_Ustr
-RtlDosPathNameToNtPathName_U
-RtlDosSearchPath_U
-RtlDosSearchPath_Ustr
-RtlDowncaseUnicodeChar
-RtlDowncaseUnicodeString
-RtlDumpResource
-RtlDuplicateUnicodeString
-RtlEmptyAtomTable
-RtlEnableEarlyCriticalSectionEventCreation
-RtlEncodePointer
-RtlEncodeSystemPointer
-RtlEnterCriticalSection
-RtlEnumProcessHeaps
-RtlEnumerateGenericTable
-RtlEnumerateGenericTableAvl
-RtlEnumerateGenericTableLikeADirectory
-RtlEnumerateGenericTableWithoutSplaying
-RtlEnumerateGenericTableWithoutSplayingAvl
-RtlEqualComputerName
-RtlEqualDomainName
-RtlEqualLuid
-RtlEqualPrefixSid
-RtlEqualSid
-RtlEqualString
-RtlEqualUnicodeString
-RtlEraseUnicodeString
-RtlExitUserThread
-RtlExpandEnvironmentStrings_U
-RtlFillMemory
-RtlFinalReleaseOutOfProcessMemoryStream
-RtlFindActivationContextSectionGuid
-RtlFindActivationContextSectionString
-RtlFindCharInUnicodeString
-RtlFindClearBits
-RtlFindClearBitsAndSet
-RtlFindClearRuns
-RtlFindLastBackwardRunClear
-RtlFindLeastSignificantBit
-RtlFindLongestRunClear
-RtlFindMessage
-RtlFindMostSignificantBit
-RtlFindNextForwardRunClear
-RtlFindSetBits
-RtlFindSetBitsAndClear
-RtlFirstEntrySList
-RtlFirstFreeAce
-RtlFlushSecureMemoryCache
-RtlFormatCurrentUserKeyPath
-RtlFormatMessage
-RtlFreeAnsiString
-RtlFreeHandle
-RtlFreeHeap
-RtlFreeOemString
-RtlFreeSid
-RtlFreeThreadActivationContextStack
-RtlFreeUnicodeString
-RtlGUIDFromString
-RtlGenerate8dot3Name
-RtlGetAce
-RtlGetActiveActivationContext
-RtlGetCallersAddress
-RtlGetCompressionWorkSpaceSize
-RtlGetControlSecurityDescriptor
-RtlGetCurrentDirectory_U
-RtlGetCurrentPeb
-RtlGetDaclSecurityDescriptor
-RtlGetElementGenericTable
-RtlGetElementGenericTableAvl
-RtlGetFrame
-RtlGetFullPathName_U
-RtlGetGroupSecurityDescriptor
-RtlGetLastNtStatus
-RtlGetLastWin32Error
-RtlGetLengthWithoutLastFullDosOrNtPathElement
-RtlGetLengthWithoutTrailingPathSeperators
-RtlGetLongestNtPathLength
-RtlGetNativeSystemInformation
-RtlGetNtGlobalFlags
-RtlGetNtProductType
-RtlGetNtVersionNumbers
-RtlGetOwnerSecurityDescriptor
-RtlGetProcessHeaps
-RtlGetSaclSecurityDescriptor
-RtlGetSecurityDescriptorRMControl
-RtlGetSetBootStatusData
-RtlGetUnloadEventTrace
-RtlGetUserInfoHeap
-RtlGetVersion
-RtlHashUnicodeString
-RtlIdentifierAuthoritySid
-RtlImageDirectoryEntryToData
-RtlImageNtHeader
-RtlImageRvaToSection
-RtlImageRvaToVa
-RtlImpersonateSelf
-RtlInitAnsiString
-RtlInitCodePageTable
-RtlInitMemoryStream
-RtlInitNlsTables
-RtlInitOutOfProcessMemoryStream
-RtlInitString
-RtlInitUnicodeString
-RtlInitUnicodeStringEx
-RtlInitializeAtomPackage
-RtlInitializeBitMap
-RtlInitializeContext
-RtlInitializeCriticalSection
-RtlInitializeCriticalSectionAndSpinCount
-RtlInitializeGenericTable
-RtlInitializeGenericTableAvl
-RtlInitializeHandleTable
-RtlInitializeRXact
-RtlInitializeResource
-RtlInitializeSListHead
-RtlInitializeSid
-RtlInsertElementGenericTable
-RtlInsertElementGenericTableAvl
-RtlInt64ToUnicodeString
-RtlIntegerToChar
-RtlIntegerToUnicodeString
-RtlInterlockedFlushSList
-RtlInterlockedPopEntrySList
-RtlInterlockedPushEntrySList
-RtlInterlockedPushListSList
-RtlIpv4AddressToStringA
-RtlIpv4AddressToStringExA
-RtlIpv4AddressToStringExW
-RtlIpv4AddressToStringW
-RtlIpv4StringToAddressA
-RtlIpv4StringToAddressExA
-RtlIpv4StringToAddressExW
-RtlIpv4StringToAddressW
-RtlIpv6AddressToStringA
-RtlIpv6AddressToStringExA
-RtlIpv6AddressToStringExW
-RtlIpv6AddressToStringW
-RtlIpv6StringToAddressA
-RtlIpv6StringToAddressExA
-RtlIpv6StringToAddressExW
-RtlIpv6StringToAddressW
-RtlIsActivationContextActive
-RtlIsDosDeviceName_U
-RtlIsGenericTableEmpty
-RtlIsGenericTableEmptyAvl
-RtlIsNameLegalDOS8Dot3
-RtlIsTextUnicode
-RtlIsThreadWithinLoaderCallout
-RtlIsValidHandle
-RtlIsValidIndexHandle
-RtlLargeIntegerToChar
-RtlLeaveCriticalSection
-RtlLengthRequiredSid
-RtlLengthSecurityDescriptor
-RtlLengthSid
-RtlLocalTimeToSystemTime
-RtlLockBootStatusData
-RtlLockHeap
-RtlLockMemoryStreamRegion
-RtlLogStackBackTrace
-RtlLookupAtomInAtomTable
-RtlLookupElementGenericTable
-RtlLookupElementGenericTableAvl
-RtlMakeSelfRelativeSD
-RtlMapGenericMask
-RtlMapSecurityErrorToNtStatus
-RtlMoveMemory
-RtlMultiAppendUnicodeStringBuffer
-RtlMultiByteToUnicodeN
-RtlMultiByteToUnicodeSize
-RtlNewInstanceSecurityObject
-RtlNewSecurityGrantedAccess
-RtlNewSecurityObject
-RtlNewSecurityObjectEx
-RtlNewSecurityObjectWithMultipleInheritance
-RtlNormalizeProcessParams
-RtlNtPathNameToDosPathName
-RtlNtStatusToDosError
-RtlNtStatusToDosErrorNoTeb
-RtlNumberGenericTableElements
-RtlNumberGenericTableElementsAvl
-RtlNumberOfClearBits
-RtlNumberOfSetBits
-RtlOemStringToUnicodeSize
-RtlOemStringToUnicodeString
-RtlOemToUnicodeN
-RtlOpenCurrentUser
-RtlPcToFileHeader
-RtlPinAtomInAtomTable
-RtlPopFrame
-RtlPrefixString
-RtlPrefixUnicodeString
-RtlProtectHeap
-RtlPushFrame
-RtlQueryAtomInAtomTable
-RtlQueryDepthSList
-RtlQueryEnvironmentVariable_U
-RtlQueryHeapInformation
-RtlQueryInformationAcl
-RtlQueryInformationActivationContext
-RtlQueryInformationActiveActivationContext
-RtlQueryInterfaceMemoryStream
-RtlQueryProcessBackTraceInformation
-RtlQueryProcessDebugInformation
-RtlQueryProcessHeapInformation
-RtlQueryProcessLockInformation
-RtlQueryRegistryValues
-RtlQuerySecurityObject
-RtlQueryTagHeap
-RtlQueryTimeZoneInformation
-RtlQueueApcWow64Thread
-RtlQueueWorkItem
-RtlRaiseException
-RtlRaiseStatus
-RtlRandom
-RtlRandomEx
-RtlReAllocateHeap
-RtlReadMemoryStream
-RtlReadOutOfProcessMemoryStream
-RtlRealPredecessor
-RtlRealSuccessor
-RtlRegisterSecureMemoryCacheCallback
-RtlRegisterWait
-RtlReleaseActivationContext
-RtlReleaseMemoryStream
-RtlReleasePebLock
-RtlReleaseResource
-RtlRemoteCall
-RtlRemoveVectoredExceptionHandler
-RtlResetRtlTranslations
-RtlRestoreLastWin32Error
-RtlRevertMemoryStream
-RtlRunDecodeUnicodeString
-RtlRunEncodeUnicodeString
-RtlSecondsSince1970ToTime
-RtlSecondsSince1980ToTime
-RtlSeekMemoryStream
-RtlSelfRelativeToAbsoluteSD
-RtlSelfRelativeToAbsoluteSD2
-RtlSetAllBits
-RtlSetAttributesSecurityDescriptor
-RtlSetBits
-RtlSetControlSecurityDescriptor
-RtlSetCriticalSectionSpinCount
-RtlSetCurrentDirectory_U
-RtlSetCurrentEnvironment
-RtlSetDaclSecurityDescriptor
-RtlSetEnvironmentVariable
-RtlSetGroupSecurityDescriptor
-RtlSetHeapInformation
-RtlSetInformationAcl
-RtlSetIoCompletionCallback
-RtlSetLastWin32Error
-RtlSetLastWin32ErrorAndNtStatusFromNtStatus
-RtlSetMemoryStreamSize
-RtlSetOwnerSecurityDescriptor
-RtlSetProcessIsCritical
-RtlSetSaclSecurityDescriptor
-RtlSetSecurityDescriptorRMControl
-RtlSetSecurityObject
-RtlSetSecurityObjectEx
-RtlSetThreadIsCritical
-RtlSetThreadPoolStartFunc
-RtlSetTimeZoneInformation
-RtlSetTimer
-RtlSetUserFlagsHeap
-RtlSetUserValueHeap
-RtlSizeHeap
-RtlSplay
-RtlStartRXact
-RtlStatMemoryStream
-RtlStringFromGUID
-RtlSubAuthorityCountSid
-RtlSubAuthoritySid
-RtlSubtreePredecessor
-RtlSubtreeSuccessor
-RtlSystemTimeToLocalTime
-RtlTimeFieldsToTime
-RtlTimeToElapsedTimeFields
-RtlTimeToSecondsSince1970
-RtlTimeToSecondsSince1980
-RtlTimeToTimeFields
-RtlTraceDatabaseAdd
-RtlTraceDatabaseCreate
-RtlTraceDatabaseDestroy
-RtlTraceDatabaseEnumerate
-RtlTraceDatabaseFind
-RtlTraceDatabaseLock
-RtlTraceDatabaseUnlock
-RtlTraceDatabaseValidate
-RtlTryEnterCriticalSection
-RtlUnhandledExceptionFilter
-RtlUnhandledExceptionFilter2
-RtlUnicodeStringToAnsiSize
-RtlUnicodeStringToAnsiString
-RtlUnicodeStringToCountedOemString
-RtlUnicodeStringToInteger
-RtlUnicodeStringToOemSize
-RtlUnicodeStringToOemString
-RtlUnicodeToCustomCPN
-RtlUnicodeToMultiByteN
-RtlUnicodeToMultiByteSize
-RtlUnicodeToOemN
-RtlUniform
-RtlUnlockBootStatusData
-RtlUnlockHeap
-RtlUnlockMemoryStreamRegion
-RtlUnwind
-RtlUpcaseUnicodeChar
-RtlUpcaseUnicodeString
-RtlUpcaseUnicodeStringToAnsiString
-RtlUpcaseUnicodeStringToCountedOemString
-RtlUpcaseUnicodeStringToOemString
-RtlUpcaseUnicodeToCustomCPN
-RtlUpcaseUnicodeToMultiByteN
-RtlUpcaseUnicodeToOemN
-RtlUpdateTimer
-RtlUpperChar
-RtlUpperString
-RtlValidAcl
-RtlValidRelativeSecurityDescriptor
-RtlValidSecurityDescriptor
-RtlValidSid
-RtlValidateHeap
-RtlValidateProcessHeaps
-RtlValidateUnicodeString
-RtlVerifyVersionInfo
-RtlWalkFrameChain
-RtlWalkHeap
-RtlWriteMemoryStream
-RtlWriteRegistryValue
-RtlZeroHeap
-RtlZeroMemory
-RtlZombifyActivationContext
-RtlpApplyLengthFunction
-RtlpEnsureBufferSize
-RtlpNotOwnerCriticalSection
-RtlpNtCreateKey
-RtlpNtEnumerateSubKey
-RtlpNtMakeTemporaryKey
-RtlpNtOpenKey
-RtlpNtQueryValueKey
-RtlpNtSetValueKey
-RtlpUnWaitCriticalSection
-RtlpWaitForCriticalSection
-RtlxAnsiStringToUnicodeSize
-RtlxOemStringToUnicodeSize
-RtlxUnicodeStringToAnsiSize
-RtlxUnicodeStringToOemSize
-VerSetConditionMask
-ZwAcceptConnectPort
-ZwAccessCheck
-ZwAccessCheckAndAuditAlarm
-ZwAccessCheckByType
-ZwAccessCheckByTypeAndAuditAlarm
-ZwAccessCheckByTypeResultList
-ZwAccessCheckByTypeResultListAndAuditAlarm
-ZwAccessCheckByTypeResultListAndAuditAlarmByHandle
-ZwAddAtom
-ZwAddBootEntry
-ZwAdjustGroupsToken
-ZwAdjustPrivilegesToken
-ZwAlertResumeThread
-ZwAlertThread
-ZwAllocateLocallyUniqueId
-ZwAllocateUserPhysicalPages
-ZwAllocateUuids
-ZwAllocateVirtualMemory
-ZwAreMappedFilesTheSame
-ZwAssignProcessToJobObject
-ZwCallbackReturn
-ZwCancelIoFile
-ZwCancelTimer
-ZwClearEvent
-ZwClose
-ZwCloseObjectAuditAlarm
-ZwCompactKeys
-ZwCompareTokens
-ZwCompleteConnectPort
-ZwCompressKey
-ZwConnectPort
-ZwContinue
-ZwCreateDebugObject
-ZwCreateDirectoryObject
-ZwCreateEvent
-ZwCreateEventPair
-ZwCreateFile
-ZwCreateIoCompletion
-ZwCreateJobObject
-ZwCreateJobSet
-ZwCreateKey
-ZwCreateKeyedEvent
-ZwCreateMailslotFile
-ZwCreateMutant
-ZwCreateNamedPipeFile
-ZwCreatePagingFile
-ZwCreatePort
-ZwCreateProcess
-ZwCreateProcessEx
-ZwCreateProfile
-ZwCreateSection
-ZwCreateSemaphore
-ZwCreateSymbolicLinkObject
-ZwCreateThread
-ZwCreateTimer
-ZwCreateToken
-ZwCreateWaitablePort
-ZwDebugActiveProcess
-ZwDebugContinue
-ZwDelayExecution
-ZwDeleteAtom
-ZwDeleteBootEntry
-ZwDeleteFile
-ZwDeleteKey
-ZwDeleteObjectAuditAlarm
-ZwDeleteValueKey
-ZwDeviceIoControlFile
-ZwDisplayString
-ZwDuplicateObject
-ZwDuplicateToken
-ZwEnumerateBootEntries
-ZwEnumerateKey
-ZwEnumerateSystemEnvironmentValuesEx
-ZwEnumerateValueKey
-ZwExtendSection
-ZwFilterToken
-ZwFindAtom
-ZwFlushBuffersFile
-ZwFlushInstructionCache
-ZwFlushKey
-ZwFlushVirtualMemory
-ZwFlushWriteBuffer
-ZwFreeUserPhysicalPages
-ZwFreeVirtualMemory
-ZwFsControlFile
-ZwGetContextThread
-ZwGetDevicePowerState
-ZwGetWriteWatch
-ZwImpersonateAnonymousToken
-ZwImpersonateClientOfPort
-ZwImpersonateThread
-ZwInitializeRegistry
-ZwInitiatePowerAction
-ZwIsProcessInJob
-ZwIsSystemResumeAutomatic
-ZwListenPort
-ZwLoadDriver
-ZwLoadKey
-ZwLoadKey2
-ZwLockFile
-ZwLockProductActivationKeys
-ZwLockRegistryKey
-ZwLockVirtualMemory
-ZwMakePermanentObject
-ZwMakeTemporaryObject
-ZwMapUserPhysicalPages
-ZwMapUserPhysicalPagesScatter
-ZwMapViewOfSection
-ZwModifyBootEntry
-ZwNotifyChangeDirectoryFile
-ZwNotifyChangeKey
-ZwNotifyChangeMultipleKeys
-ZwOpenDirectoryObject
-ZwOpenEvent
-ZwOpenEventPair
-ZwOpenFile
-ZwOpenIoCompletion
-ZwOpenJobObject
-ZwOpenKey
-ZwOpenKeyedEvent
-ZwOpenMutant
-ZwOpenObjectAuditAlarm
-ZwOpenProcess
-ZwOpenProcessToken
-ZwOpenProcessTokenEx
-ZwOpenSection
-ZwOpenSemaphore
-ZwOpenSymbolicLinkObject
-ZwOpenThread
-ZwOpenThreadToken
-ZwOpenThreadTokenEx
-ZwOpenTimer
-ZwPlugPlayControl
-ZwPowerInformation
-ZwPrivilegeCheck
-ZwPrivilegeObjectAuditAlarm
-ZwPrivilegedServiceAuditAlarm
-ZwProtectVirtualMemory
-ZwPulseEvent
-ZwQueryAttributesFile
-ZwQueryBootEntryOrder
-ZwQueryBootOptions
-ZwQueryDebugFilterState
-ZwQueryDefaultLocale
-ZwQueryDefaultUILanguage
-ZwQueryDirectoryFile
-ZwQueryDirectoryObject
-ZwQueryEaFile
-ZwQueryEvent
-ZwQueryFullAttributesFile
-ZwQueryInformationAtom
-ZwQueryInformationFile
-ZwQueryInformationJobObject
-ZwQueryInformationPort
-ZwQueryInformationProcess
-ZwQueryInformationThread
-ZwQueryInformationToken
-ZwQueryInstallUILanguage
-ZwQueryIntervalProfile
-ZwQueryIoCompletion
-ZwQueryKey
-ZwQueryMultipleValueKey
-ZwQueryMutant
-ZwQueryObject
-ZwQueryOpenSubKeys
-ZwQueryPerformanceCounter
-ZwQueryPortInformationProcess
-ZwQueryQuotaInformationFile
-ZwQuerySection
-ZwQuerySecurityObject
-ZwQuerySemaphore
-ZwQuerySymbolicLinkObject
-ZwQuerySystemEnvironmentValue
-ZwQuerySystemEnvironmentValueEx
-ZwQuerySystemInformation
-ZwQuerySystemTime
-ZwQueryTimer
-ZwQueryTimerResolution
-ZwQueryValueKey
-ZwQueryVirtualMemory
-ZwQueryVolumeInformationFile
-ZwQueueApcThread
-ZwRaiseException
-ZwRaiseHardError
-ZwReadFile
-ZwReadFileScatter
-ZwReadRequestData
-ZwReadVirtualMemory
-ZwRegisterThreadTerminatePort
-ZwReleaseKeyedEvent
-ZwReleaseMutant
-ZwReleaseSemaphore
-ZwRemoveIoCompletion
-ZwRemoveProcessDebug
-ZwRenameKey
-ZwReplaceKey
-ZwReplyPort
-ZwReplyWaitReceivePort
-ZwReplyWaitReceivePortEx
-ZwReplyWaitReplyPort
-ZwRequestPort
-ZwRequestWaitReplyPort
-ZwResetEvent
-ZwResetWriteWatch
-ZwRestoreKey
-ZwResumeProcess
-ZwResumeThread
-ZwSaveKey
-ZwSaveKeyEx
-ZwSaveMergedKeys
-ZwSecureConnectPort
-ZwSetBootEntryOrder
-ZwSetBootOptions
-ZwSetContextThread
-ZwSetDebugFilterState
-ZwSetDefaultHardErrorPort
-ZwSetDefaultLocale
-ZwSetDefaultUILanguage
-ZwSetEaFile
-ZwSetEvent
-ZwSetEventBoostPriority
-ZwSetHighEventPair
-ZwSetHighWaitLowEventPair
-ZwSetInformationDebugObject
-ZwSetInformationFile
-ZwSetInformationJobObject
-ZwSetInformationKey
-ZwSetInformationObject
-ZwSetInformationProcess
-ZwSetInformationThread
-ZwSetInformationToken
-ZwSetIntervalProfile
-ZwSetIoCompletion
-ZwSetLdtEntries
-ZwSetLowEventPair
-ZwSetLowWaitHighEventPair
-ZwSetQuotaInformationFile
-ZwSetSecurityObject
-ZwSetSystemEnvironmentValue
-ZwSetSystemEnvironmentValueEx
-ZwSetSystemInformation
-ZwSetSystemPowerState
-ZwSetSystemTime
-ZwSetThreadExecutionState
-ZwSetTimer
-ZwSetTimerResolution
-ZwSetUuidSeed
-ZwSetValueKey
-ZwSetVolumeInformationFile
-ZwShutdownSystem
-ZwSignalAndWaitForSingleObject
-ZwStartProfile
-ZwStopProfile
-ZwSuspendProcess
-ZwSuspendThread
-ZwSystemDebugControl
-ZwTerminateJobObject
-ZwTerminateProcess
-ZwTerminateThread
-ZwTestAlert
-ZwTraceEvent
-ZwTranslateFilePath
-ZwUnloadDriver
-ZwUnloadKey
-ZwUnloadKeyEx
-ZwUnlockFile
-ZwUnlockVirtualMemory
-ZwUnmapViewOfSection
-ZwVdmControl
-ZwWaitForDebugEvent
-ZwWaitForKeyedEvent
-ZwWaitForMultipleObjects
-ZwWaitForSingleObject
-ZwWaitHighEventPair
-ZwWaitLowEventPair
-ZwWriteFile
-ZwWriteFileGather
-ZwWriteRequestData
-ZwWriteVirtualMemory
-ZwYieldExecution
-__isascii
-__iscsym
-__iscsymf
-__toascii
-_alldiv
-_alldvrm
-_allmul
-_allrem
-_allshl
-_allshr
-_atoi64
-_aulldiv
-_aulldvrm
-_aullrem
-_aullshr
-_fltused
-_i64toa
-_i64tow
-_itoa
-_itow
-_lfind
-_ltoa
-_ltow
-_memccpy
-_memicmp
-_snprintf
-_snwprintf
-_splitpath
-_strcmpi
-_stricmp
-_strlwr
-_strnicmp
-_strupr
-_ui64toa
-_ui64tow
-_ultoa
-_ultow
-_vsnprintf
-_vsnwprintf
-_wcsicmp
-_wcslwr
-_wcsnicmp
-_wcsupr
-_wtoi
-_wtoi64
-_wtol
-abs
-atan
-atoi
-atol
-bsearch
-ceil
-cos
-fabs
-floor
-isalnum
-isalpha
-iscntrl
-isdigit
-isgraph
-islower
-isprint
-ispunct
-isspace
-isupper
-iswalpha
-iswctype
-iswdigit
-iswlower
-iswspace
-iswxdigit
-isxdigit
-labs
-log
-mbstowcs
-memchr
-memcmp
-memcpy
-memmove
-memset
-pow
-qsort
-sin
-sprintf
-sqrt
-sscanf
-strcat
-strchr
-strcmp
-strcpy
-strcspn
-strlen
-strncat
-strncmp
-strncpy
-strpbrk
-strrchr
-strspn
-strstr
-strtol
-strtoul
-swprintf
-tan
-tolower
-toupper
-towlower
-towupper
-vDbgPrintEx
-vDbgPrintExWithPrefix
-vsprintf
-wcscat
-wcschr
-wcscmp
-wcscpy
-wcscspn
-wcslen
-wcsncat
-wcsncmp
-wcsncpy
-wcspbrk
-wcsrchr
-wcsspn
-wcsstr
-wcstol
-wcstombs
-wcstoul
-__C_specific_handler
-_except_handler4_common
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d922c8554160c15fbfa5f3bce24a387badf9b8f..887d8d16536e6c00bf68e4690040cdb310ea2b56 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,12 +66,9 @@ if (CELLFRAME_MODULES MATCHES "test-framework")
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_test)
 endif()
 
-
-    add_subdirectory(3rdparty/crc32c_adler)             # https://github.com/fonic/crc32c_adler
-    include_directories(3rdparty/crc32c_adler)
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} crc32c_adler)
-
-
+add_subdirectory(3rdparty/crc32c_adler)             # https://github.com/fonic/crc32c_adler
+include_directories(3rdparty/crc32c_adler)
+set(CELLFRAME_LIBS ${CELLFRAME_LIBS} crc32c_adler)
 
 if(BUILD_TESTS)
     include(cmake/OS_Detection.cmake)
@@ -106,7 +103,7 @@ endif()
 # General chain libs
 if (CELLFRAME_MODULES MATCHES "chains")
     message("[+] Module 'chains'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_common dap_chain dap_chain_global_db dap_chain_wallet)
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_common dap_chain dap_global_db dap_chain_wallet)
 endif()
 
 # Networking
@@ -237,12 +234,4 @@ endif()
 
 set(CELLFRAME_LIBS ${CELLFRAME_LIBS} crc32c_adler)
 
-
-
-target_link_libraries(${PROJECT_NAME} ${CELLFRAME_LIBS} crc32c_adler)
-#if(BUILD_DAP_TESTS)
-#    file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/main_test.py
-#            DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
-#    enable_testing()
-    #add_subdirectory(test)
-#endif()
+target_link_libraries(${PROJECT_NAME} ${CELLFRAME_LIBS})
diff --git a/dap-sdk b/dap-sdk
index 70151d1c362d4e9669358991c5ac70ad24e33a9a..2e12edb4fff37fcadadd6414643e9fbeb3e8a574 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 70151d1c362d4e9669358991c5ac70ad24e33a9a
+Subproject commit 2e12edb4fff37fcadadd6414643e9fbeb3e8a574
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index 8c5b31bc5fd794240c41594d178e94329c764e43..5b2c9751855e2352bf26fe28f0ef0a2926c16a69 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -8,7 +8,6 @@ if (CELLFRAME_MODULES MATCHES "chains")
     add_subdirectory(chain)
     add_subdirectory(chain/btc_rpc)
     add_subdirectory(wallet)
-    add_subdirectory(global-db)
 endif()
 
 # Distributed Hash Tables (DHT)
diff --git a/modules/chain/CMakeLists.txt b/modules/chain/CMakeLists.txt
index e3fc6f7f2c7e18c8d543ade7fc944d5f07839067..3602ee72433be5b9898892d5c8f738eb61f44855 100644
--- a/modules/chain/CMakeLists.txt
+++ b/modules/chain/CMakeLists.txt
@@ -14,7 +14,7 @@ endif()
 #find_package(PkgConfig REQUIRED)
 #pkg_search_module(GLIB REQUIRED glib-2.0)
 
-target_link_libraries(${PROJECT_NAME} dap_chain_common dap_chain_global_db ${GLIB_LDFLAGS})
+target_link_libraries(${PROJECT_NAME} dap_chain_common dap_global_db ${GLIB_LDFLAGS})
 target_include_directories(${PROJECT_NAME} INTERFACE . include/ ${GLIB_INCLUDE_DIRS})
 target_include_directories(${PROJECT_NAME} PUBLIC include)
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/uthash/src)
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 06002250774057809a3703f22cd50a762d6ec3e1..c039306961f1d54958508ce9a2bfbd0da048543c 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -1539,10 +1539,9 @@ static void s_threshold_txs_proc( dap_ledger_t *a_ledger)
  * @param a_arg
  */
 static bool s_load_cache_gdb_loaded_balances_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
-                                             const char * a_group, const char * a_key,
-                                             const size_t a_values_total,  const size_t a_values_shift,
-                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
-                                             void * a_arg)
+                                                      const char * a_group, const char * a_key,
+                                                      const size_t a_values_total, const size_t a_values_count,
+                                                      dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_ledger_t * l_ledger = (dap_ledger_t*) a_arg;
     dap_ledger_private_t * l_ledger_pvt = PVT(l_ledger);
@@ -1580,11 +1579,10 @@ static bool s_load_cache_gdb_loaded_balances_callback(dap_global_db_context_t *
  * @param a_values
  * @param a_arg
  */
-static bool s_load_cache_gdb_loaded_spent_txs_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
-                                             const char * a_group, const char * a_key,
-                                             const size_t a_values_total,  const size_t a_values_shift,
-                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
-                                             void * a_arg)
+static bool s_load_cache_gdb_loaded_spent_txs_callback(dap_global_db_context_t *a_global_db_context, int a_rc,
+                                                       const char *a_group, const char *a_key,
+                                                       const size_t a_values_total, const size_t a_values_count,
+                                                       dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_ledger_t * l_ledger = (dap_ledger_t*) a_arg;
     dap_ledger_private_t * l_ledger_pvt = PVT(l_ledger);
@@ -1614,11 +1612,10 @@ static bool s_load_cache_gdb_loaded_spent_txs_callback(dap_global_db_context_t *
  * @param a_values
  * @param a_arg
  */
-static bool s_load_cache_gdb_loaded_txs_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
-                                             const char * a_group, const char * a_key,
-                                             const size_t a_values_total,  const size_t a_values_shift,
-                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
-                                             void * a_arg)
+static bool s_load_cache_gdb_loaded_txs_callback(dap_global_db_context_t *a_global_db_context, int a_rc,
+                                                 const char *a_group, const char *a_key,
+                                                 const size_t a_values_total,  const size_t a_values_count,
+                                                 dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_ledger_t * l_ledger = (dap_ledger_t*) a_arg;
     dap_ledger_private_t * l_ledger_pvt = PVT(l_ledger);
@@ -1638,10 +1635,9 @@ static bool s_load_cache_gdb_loaded_txs_callback(dap_global_db_context_t * a_glo
 }
 
 static bool s_load_cache_gdb_loaded_stake_lock_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
-                                             const char * a_group, const char * a_key,
-                                             const size_t a_values_total,  const size_t a_values_shift,
-                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
-                                             void * a_arg)
+                                                        const char * a_group, const char * a_key,
+                                                        const size_t a_values_total, const size_t a_values_count,
+                                                        dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_ledger_t *l_ledger = (dap_ledger_t *) a_arg;
     dap_ledger_private_t *l_ledger_pvt = PVT(l_ledger);
@@ -1680,10 +1676,9 @@ static bool s_load_cache_gdb_loaded_stake_lock_callback(dap_global_db_context_t
  * @return Always true thats means to clear up a_values
  */
 static bool s_load_cache_gdb_loaded_emissions_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
-                                             const char * a_group, const char * a_key,
-                                             const size_t a_values_total,  const size_t a_values_shift,
-                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
-                                             void * a_arg)
+                                                       const char * a_group, const char * a_key,
+                                                       const size_t a_values_total, const size_t a_values_count,
+                                                       dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_ledger_t * l_ledger = (dap_ledger_t*) a_arg;
     dap_ledger_private_t * l_ledger_pvt = PVT(l_ledger);
@@ -1710,7 +1705,7 @@ static bool s_load_cache_gdb_loaded_emissions_callback(dap_global_db_context_t *
     }
 
     char* l_gdb_group = dap_chain_ledger_get_gdb_group(l_ledger, DAP_CHAIN_LEDGER_STAKE_LOCK_STR);
-    dap_global_db_get_all(l_gdb_group,0, s_load_cache_gdb_loaded_txs_callback, l_ledger);
+    dap_global_db_get_all(l_gdb_group,0, s_load_cache_gdb_loaded_stake_lock_callback, l_ledger);
     DAP_DELETE(l_gdb_group);
     return true;
 
@@ -1730,10 +1725,9 @@ static bool s_load_cache_gdb_loaded_emissions_callback(dap_global_db_context_t *
  * @param a_arg
  */
 static bool s_load_cache_gdb_loaded_tokens_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
-                                             const char * a_group, const char * a_key,
-                                             const size_t a_values_total,  const size_t a_values_shift,
-                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
-                                             void * a_arg)
+                                                    const char * a_group, const char * a_key,
+                                                    const size_t a_values_total, const size_t a_values_count,
+                                                    dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_ledger_t * l_ledger = (dap_ledger_t*) a_arg;
     dap_ledger_private_t * l_ledger_pvt = PVT(l_ledger);
@@ -1776,9 +1770,7 @@ static bool s_load_cache_gdb_loaded_tokens_callback(dap_global_db_context_t * a_
 void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
 {
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
-
     char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TOKENS_STR);
-    size_t l_objs_count = 0;
 
     pthread_mutex_lock(& l_ledger_pvt->load_mutex);
     dap_global_db_get_all(l_gdb_group,0,s_load_cache_gdb_loaded_tokens_callback, a_ledger);
@@ -2703,8 +2695,6 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     if (a_list_tx_out)
         *a_list_tx_out = l_list_tx_out;
 
-    dap_list_t* l_list_tx_out_cond = NULL;
-
     // sum of values in 'out' items from the previous transactions
     dap_chain_ledger_tokenizer_t *l_values_from_prev_tx = NULL, *l_values_from_cur_tx = NULL,
                                  *l_value_cur = NULL, *l_tmp = NULL, *l_res = NULL;
@@ -2941,8 +2931,9 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
             break;
         }
-        if (s_debug_more && !a_from_threshold)
-            log_it(L_INFO,"Previous transaction was found for hash %s",l_tx_prev_hash_str);
+        bound_item->item_out = l_item_out;
+        l_token = l_item_out->cache_data.token_ticker;
+        debug_if(s_debug_more && !a_from_threshold, L_INFO, "Previous transaction was found for hash %s",l_tx_prev_hash_str);
         bound_item->tx_prev = l_tx_prev;
 
         // 2. Check if out in previous transaction has spent
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net.c b/modules/channel/chain-net/dap_stream_ch_chain_net.c
index 335eef1d45485778cafcb3b3296d4b5ab9ab4947..04a6991b8bbed305cd4c7e17c6c0bb24fb7d7266 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net.c
@@ -47,7 +47,7 @@
 #include "uthash.h"
 #include "dap_http_client.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 #include "dap_stream.h"
 #include "dap_stream_ch_pkt.h"
 #include "dap_stream_ch_proc.h"
diff --git a/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h b/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
index acb4cd61391cfc997f85e819375bf0de95d8bbe5..30163c46ae8e9c0ee07fcc2e6ad90efab7018075 100644
--- a/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
+++ b/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
@@ -4,7 +4,7 @@
 
 #include "dap_chain_common.h"
 #include "dap_chain.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 #include "dap_chain_node_client.h"
 #include "dap_list.h"
 // #include "dap_stream_ch_chain_pkt.h"
diff --git a/modules/channel/chain/CMakeLists.txt b/modules/channel/chain/CMakeLists.txt
index fa08c680949d1096948850602083007537f2fa01..9114276651bb4885574331e01d35115a61737480 100644
--- a/modules/channel/chain/CMakeLists.txt
+++ b/modules/channel/chain/CMakeLists.txt
@@ -6,7 +6,7 @@ file(GLOB DAP_STREAM_CH_CHAIN_HDRS include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_STREAM_CH_CHAIN_SRCS} ${DAP_STREAM_CH_CHAIN_HDRS})
 
-target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_global_db dap_stream dap_stream_ch)
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_global_db dap_stream dap_stream_ch)
 
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 5203deaab1d82a03e72d505176dd9363cfa84390..69e3d419cf68e05f3efd94ccf29c7849dcd26606 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -57,7 +57,7 @@
 #include "dap_chain_cell.h"
 
 #include "dap_global_db.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 
 #include "dap_stream.h"
 #include "dap_stream_pkt.h"
@@ -118,9 +118,10 @@ static bool s_sync_out_gdb_proc_callback(dap_proc_thread_t *a_thread, void *a_ar
 static bool s_sync_in_chains_callback(dap_proc_thread_t *a_thread, void *a_arg);
 
 static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg);
-static bool s_gdb_in_pkt_proc_set_raw_callback(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_current,  const size_t a_values_shift,
-                                               const size_t a_values_count, dap_store_obj_t * a_values, void * a_arg);
-
+static bool s_gdb_in_pkt_proc_set_raw_callback(dap_global_db_context_t *a_global_db_context, int a_rc,
+                                               const char *a_group, const char *a_key,
+                                               const size_t a_values_total, const size_t a_values_count,
+                                               dap_store_obj_t *a_values, void *a_arg);
 static void s_gdb_in_pkt_error_worker_callback(dap_worker_t *a_thread, void *a_arg);
 static void s_free_log_list_gdb ( dap_stream_ch_chain_t * a_ch_chain);
 
@@ -312,8 +313,8 @@ static bool s_sync_out_chains_proc_callback(dap_proc_thread_t *a_thread, void *a
     //pthread_rwlock_rdlock(&l_chain->atoms_rwlock);
     l_sync_request->chain.request_atom_iter = l_chain->callback_atom_iter_create(l_chain, l_sync_request->request_hdr.cell_id, 1);
     size_t l_first_size = 0;
-    dap_chain_atom_ptr_t l_iter = l_chain->callback_atom_iter_get_first(l_sync_request->chain.request_atom_iter, &l_first_size);
-    if (l_iter && l_first_size) {
+    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_sync_request->chain.request_atom_iter, &l_first_size);
+    if (l_atom && l_first_size) {
         // first packet
         dap_chain_hash_fast_t l_hash_from = l_sync_request->request.hash_from;
         if (!dap_hash_fast_is_blank(&l_hash_from)) {
@@ -321,7 +322,6 @@ static bool s_sync_out_chains_proc_callback(dap_proc_thread_t *a_thread, void *a
                                                           &l_hash_from, &l_first_size);
         }
         //pthread_rwlock_unlock(&l_chain->atoms_rwlock);
-        l_sync_request->chain.request_atom_iter = NULL;
         dap_proc_thread_worker_exec_callback_inter(a_thread, l_sync_request->worker->id, s_sync_out_chains_first_worker_callback, l_sync_request );
     } else {
         //pthread_rwlock_unlock(&l_chain->atoms_rwlock);
@@ -824,8 +824,8 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
 
             // Record is pinned or not
             bool l_is_pinned_cur = false;
-            if (dap_chain_global_db_driver_is(l_obj->group, l_obj->key)) {
-                dap_store_obj_t *l_read_obj = dap_chain_global_db_driver_read(l_obj->group, l_obj->key, NULL);
+            if (dap_global_db_driver_is(l_obj->group, l_obj->key)) {
+                dap_store_obj_t *l_read_obj = dap_global_db_driver_read(l_obj->group, l_obj->key, NULL);
                 if (l_read_obj) {
                     l_sync_request->timestamp_cur = l_read_obj->timestamp;
                     l_is_pinned_cur = l_read_obj->flags & RECORD_PINNED;
@@ -874,8 +874,10 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
  * @param a_values
  * @param a_arg
  */
-static bool s_gdb_in_pkt_proc_set_raw_callback(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_current,  const size_t a_values_shift,
-                                               const size_t a_values_count, dap_store_obj_t * a_values, void * a_arg)
+static bool s_gdb_in_pkt_proc_set_raw_callback(dap_global_db_context_t *a_global_db_context, int a_rc,
+                                               const char *a_group, const char *a_key,
+                                               const size_t a_values_total, const size_t a_values_count,
+                                               dap_store_obj_t *a_values, void *a_arg)
 {
 
     struct sync_request *l_sync_req = (struct sync_request*) a_arg;
diff --git a/modules/channel/chain/include/dap_stream_ch_chain.h b/modules/channel/chain/include/dap_stream_ch_chain.h
index 519381ef606cad56a891988c7c882b3a9eb73841..f6e681a2741e9ee0c7d573ce04bbfdcece058b08 100644
--- a/modules/channel/chain/include/dap_stream_ch_chain.h
+++ b/modules/channel/chain/include/dap_stream_ch_chain.h
@@ -32,7 +32,7 @@
 #include "dap_list.h"
 #include "dap_stream_ch_chain_pkt.h"
 #include "uthash.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 
 typedef struct dap_stream_ch_chain dap_stream_ch_chain_t;
 typedef void (*dap_stream_ch_chain_callback_packet_t)(dap_stream_ch_chain_t*, uint8_t a_pkt_type,
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index ddbd99d53b56f1879b8135d13dbf1a31877f38f5..f82d50fffaf4dea89671ffa7d7d0e8d1cf34f11e 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -451,7 +451,9 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id
                     (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT) ||
                     (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_OLD) ||
                     (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_COND) ||
-                    (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_EXT)) {
+                    (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_EXT) ||
+                    (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN) ||
+                    (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN_COND)) {
                 if(a_item_idx)
                     *a_item_idx = l_item_idx;
                 if(a_item_out_size)
diff --git a/modules/consensus/block-ton/dap_chain_cs_block_ton.c b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
index e49adde197cb06184f206caf4b47a6907838f9d6..ad9e989cc1d7414f71744b4bec7b432ebc914693 100644
--- a/modules/consensus/block-ton/dap_chain_cs_block_ton.c
+++ b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
@@ -412,8 +412,10 @@ static bool s_session_send_votefor(s_session_send_votefor_data_t *a_data){
  * @param a_values
  * @param a_arg
  */
-static bool s_session_round_start_callback_load_session_store_coordinator_state_proc(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
+static bool s_session_round_start_callback_load_session_store_coordinator_state_proc(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                                                                     const char * a_group, const char * a_key,
+                                                                                     const size_t a_values_total, const size_t a_values_count,
+                                                                                     dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_chain_cs_block_ton_session_t * l_session = (dap_chain_cs_block_ton_session_t *) a_arg;
     dap_list_t *l_list_candidate = NULL;
@@ -852,8 +854,10 @@ static void s_session_round_clear(dap_chain_cs_block_ton_session_t *a_session)
  * @param a_values
  * @param a_arg
  */
-static bool s_session_round_finish_callback_load_store(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
+static bool s_session_round_finish_callback_load_store(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                                       const char * a_group, const char * a_key,
+                                                       const size_t a_values_total, const size_t a_values_count,
+                                                       dap_global_db_obj_t *a_values, void *a_arg)
 
 {
     dap_chain_cs_block_ton_session_t *l_session = (dap_chain_cs_block_ton_session_t *)a_arg;
@@ -980,8 +984,10 @@ struct vote_for_load_store_args
  * @param a_values
  * @param a_arg
  */
-static bool s_session_packet_in_callback_vote_for_load_store (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                          const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
+static bool s_session_packet_in_callback_vote_for_load_store(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                                             const char * a_group, const char * a_key,
+                                                             const size_t a_values_total, const size_t a_values_count,
+                                                             dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_chain_cs_block_ton_session_t * l_session = ((struct vote_for_load_store_args *) a_arg)->session;
     dap_chain_hash_fast_t * l_candidate_hash = &((struct vote_for_load_store_args *) a_arg)->candidate_hash;
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index 986cd1ee38545ecac54fa71db3031c35cbae89fc..8d377c630b77066522c357b98b03dfed5bb48497 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -42,7 +42,7 @@
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_driver.h"
+#include "dap_global_db_driver.h"
 #include "dap_chain_cs.h"
 #include "dap_chain_cs_dag.h"
 #include "dap_chain_cs_dag_event.h"
@@ -393,8 +393,10 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
  * @param a_values
  * @param a_arg
  */
-static bool s_poa_round_check_callback_round_clean(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
+static bool s_poa_round_check_callback_round_clean(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                                   const char * a_group, const char * a_key,
+                                                   const size_t a_values_total, const size_t a_values_count,
+                                                   dap_global_db_obj_t *a_values, void *a_arg)
 {
     dap_chain_cs_dag_t *l_dag = (dap_chain_cs_dag_t *)a_arg;
     dap_chain_cs_dag_poa_t *l_poa = DAP_CHAIN_CS_DAG_POA(l_dag);
@@ -518,11 +520,10 @@ static dap_chain_cs_dag_event_round_item_t *s_round_event_choose_dup(dap_list_t
  * @param a_is_pinned
  * @param a_arg
  */
-static bool s_callback_round_event_to_chain_callback_get_round_item(dap_global_db_context_t *a_global_db_context, int a_rc,
-                                                                    const char *a_group, const char *a_key,
-                                                                    const size_t a_values_total, const size_t a_values_shift,
-                                                                    const size_t a_values_count, dap_store_obj_t *a_values,
-                                                                    void *a_arg)
+static bool s_callback_round_event_to_chain_callback_get_round_item(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                                                    const char * a_group, const char * a_key,
+                                                                    const size_t a_values_total, const size_t a_values_count,
+                                                                    dap_store_obj_t *a_values, void *a_arg)
 {
     if (a_rc != DAP_GLOBAL_DB_RC_SUCCESS)
         return true;
diff --git a/modules/consensus/none/CMakeLists.txt b/modules/consensus/none/CMakeLists.txt
index ddf73b014ea1143a5a1c663582a517c424137c7c..cd45b3e9cdb5dfb5e77b5ce5aaf5d2c93a5068db 100644
--- a/modules/consensus/none/CMakeLists.txt
+++ b/modules/consensus/none/CMakeLists.txt
@@ -6,6 +6,6 @@ file(GLOB DAP_CHAIN_CS_NO_CONSENSUS_HDR include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_CS_NO_CONSENSUS_SRC} ${DAP_CHAIN_CS_NO_CONSENSUS_HDR})
 
-target_link_libraries(${PROJECT_NAME} dap_core dap_chain dap_chain_global_db dap_chain_mempool dap_chain_net)
+target_link_libraries(${PROJECT_NAME} dap_core dap_chain dap_global_db dap_chain_mempool dap_chain_net)
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/consensus/none/dap_chain_cs_none.c b/modules/consensus/none/dap_chain_cs_none.c
index c7c5e58d1f3bcdf8ce91bd0928630de0186a4dcc..38025b81041a3d9be7d8b48e02651d7dbcf571b8 100644
--- a/modules/consensus/none/dap_chain_cs_none.c
+++ b/modules/consensus/none/dap_chain_cs_none.c
@@ -2,7 +2,7 @@
  * Authors:
  * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvindap_chain_global_dbblockchain
+ * Kelvin Project https://github.com/kelvindap_global_dbblockchain
  * Copyright  (c) 2019
  * All rights reserved.
 
@@ -36,7 +36,7 @@
 #include "dap_chain_cell.h"
 #include "dap_chain_ledger.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_driver.h"
+#include "dap_global_db_driver.h"
 #include "dap_chain_cs.h"
 #include "dap_chain_cs_none.h"
 
@@ -184,7 +184,7 @@ int dap_chain_gdb_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     }
 
     // Add group prefix that will be tracking all changes
-    dap_chain_global_db_add_sync_group(l_net->pub.name, "chain-gdb", s_history_callback_notify, l_gdb);
+    dap_global_db_add_sync_group(l_net->pub.name, "chain-gdb", s_history_callback_notify, l_gdb);
 
     // load ledger
     l_gdb_priv->is_load_mode = true;
@@ -281,8 +281,10 @@ const char* dap_chain_gdb_get_group(dap_chain_t * a_chain)
  * @param a_values
  * @param a_arg
  */
-static bool s_ledger_load_callback(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
+static bool s_ledger_load_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                   const char * a_group, const char * a_key,
+                                   const size_t a_values_total, const size_t a_values_count,
+                                   dap_global_db_obj_t *a_values, void *a_arg)
 {
     assert(a_arg);
     dap_chain_t * l_chain = (dap_chain_t *) a_arg;
diff --git a/modules/global-db/CMakeLists.txt b/modules/global-db/CMakeLists.txt
deleted file mode 100644
index 43fc3fb4c4dc4af5f829a92e8f85feb9e5994d44..0000000000000000000000000000000000000000
--- a/modules/global-db/CMakeLists.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-cmake_minimum_required(VERSION 3.1)
-project (dap_chain_global_db C)
-
-file(GLOB DAP_CHAIN_GLOBAL_DB_SRC
-    dap_global_db.c
-    dap_global_db_sync.c
-    dap_chain_global_db_driver_cdb.c
-    dap_chain_global_db_driver_sqlite.c
-    dap_chain_global_db_remote.c
-    dap_chain_global_db_driver.c
-    dap_chain_global_db_driver_pgsql.c
-)
-file(GLOB DAP_CHAIN_GLOBAL_DB_HDR
-    include/dap_global_db.h
-    include/dap_global_db_sync.h
-    include/dap_global_db.h
-    include/dap_chain_global_db_remote.h
-    include/dap_chain_global_db_driver.h
-    include/dap_chain_global_db_driver_pgsql.h
-    include/dap_chain_global_db_driver_cdb.h
-    include/dap_chain_global_db_driver_sqlite.h
-)
-
-add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/cuttdb ${CMAKE_CURRENT_BINARY_DIR}/../../3rdparty/cuttdb)
-if (BUILD_WITH_GDB_DRIVER_MDBX)
-add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/libmdbx ${CMAKE_CURRENT_BINARY_DIR}/../../3rdparty/libmdbx EXCLUDE_FROM_ALL)
-endif()
-
-set(DAP_CHAIN_GLOBAL_DB_LIBS dap_core dap_io dap_crypto dap_chain dap_chain_net sqlite3 dap_cuttdb json-c)
-
-if(BUILD_WITH_GDB_DRIVER_MDBX)
-    file(GLOB DAP_CHAIN_GLOBAL_DB_SRC ${DAP_CHAIN_GLOBAL_DB_SRC} dap_chain_global_db_driver_mdbx.c)
-    file(GLOB DAP_CHAIN_GLOBAL_DB_HRR ${DAP_CHAIN_GLOBAL_DB_HDR} include/dap_chain_global_db_driver_mdbx.h)
-
-    set(DAP_CHAIN_GLOBAL_DB_LIBS ${DAP_CHAIN_GLOBAL_DB_LIBS} mdbx-static)
-    add_definitions ("-DDAP_CHAIN_GDB_ENGINE_MDBX")
-endif()
-
-if(BUILD_WITH_GDB_DRIVER_PGSQL)
-    set(DAP_CHAIN_GLOBAL_DB_LIBS ${DAP_CHAIN_GLOBAL_DB_LIBS} pq)
-    add_definitions ("-DDAP_CHAIN_GDB_ENGINE_PGSQL")
-endif()
-
-add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_GLOBAL_DB_SRC} ${DAP_CHAIN_GLOBAL_DB_HDR})
-
-target_link_libraries(${PROJECT_NAME} ${DAP_CHAIN_GLOBAL_DB_LIBS})
-
-target_include_directories(${PROJECT_NAME} INTERFACE .)
-target_include_directories(${PROJECT_NAME} PUBLIC include)
-target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/uthash/src)
-
diff --git a/modules/global-db/dap_chain_global_db_driver.c b/modules/global-db/dap_chain_global_db_driver.c
deleted file mode 100644
index cbfb270450ec65dcf327577d85e59de956a2440f..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_chain_global_db_driver.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Authors:
- * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2019
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- *
- *  MODIFICATION HISTORY:
- *
- *      24-FEB-2022 RRL Added Async I/O functionality for DB request processing
- *
- *      15-MAR-2022 RRL Some cosmetic changes to reduce a diagnostic output.
- */
-
-#include <stddef.h>
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include "dap_worker.h"
-#include "dap_file_utils.h"
-#include "dap_strfuncs.h"
-#include "dap_hash.h"
-#include "dap_proc_queue.h"
-#include "dap_events.h"
-#include "dap_list.h"
-#include "dap_common.h"
-#include "dap_global_db.h"
-
-#include "dap_chain_global_db_driver_sqlite.h"
-#include "dap_chain_global_db_driver_cdb.h"
-
-#ifdef DAP_CHAIN_GDB_ENGINE_MDBX
-#include "dap_chain_global_db_driver_mdbx.h"
-#endif
-
-#ifdef DAP_CHAIN_GDB_ENGINE_PGSQL
-#include "dap_chain_global_db_driver_pgsql.h"
-#endif
-
-#include "dap_chain_global_db_driver.h"
-
-#define LOG_TAG "db_driver"
-
-// A selected database driver.
-static char s_used_driver [32];                                             /* Name of the driver */
-
-
-static dap_db_driver_callbacks_t s_drv_callback;                            /* A set of interface routines for the selected
-                                                                            DB Driver at startup time */
-
-int s_db_drvmode_async = 0;                                            /* Set a kind of processing requests to DB:
-                                                                            <> 0 - Async mode should be used */
-
-static pthread_mutex_t s_db_reqs_list_lock = PTHREAD_MUTEX_INITIALIZER;     /* Lock to coordinate access to the <s_db_reqs_queue> */
-static dap_slist_t s_db_reqs_list = {0};                                    /* A queue of request to DB - maintained in */
-
-
-/**
- * @brief Initializes a database driver.
- * @note You should Call this function before using the driver.
- * @param driver_name a string determining a type of database driver:
- * "сdb", "sqlite" ("sqlite3") or "pgsql"
- * @param a_filename_db a path to a database file
- * @return Returns 0, if successful; otherwise <0.
- */
-int dap_db_driver_init(const char *a_driver_name, const char *a_filename_db, int a_mode_async)
-{
-int l_ret = -1;
-
-    if (s_used_driver[0] )
-        dap_db_driver_deinit();
-
-    s_db_drvmode_async = a_mode_async;
-
-    // Fill callbacks with zeros
-    memset(&s_drv_callback, 0, sizeof(dap_db_driver_callbacks_t));
-
-    if ( s_db_drvmode_async )                                               /* Set a kind of processing requests to DB: <> 0 - Async mode should be used */
-    {
-        s_db_reqs_list.head = s_db_reqs_list.tail = NULL;
-        s_db_reqs_list.nr = 0;
-    }
-
-    // Setup driver name
-    strncpy( s_used_driver, a_driver_name, sizeof(s_used_driver) - 1);
-
-    dap_mkdir_with_parents(a_filename_db);
-
-    // Compose path
-    char l_db_path_ext[strlen(a_driver_name) + strlen(a_filename_db) + 6];
-    dap_snprintf(l_db_path_ext, sizeof(l_db_path_ext), "%s/gdb-%s", a_filename_db, a_driver_name);
-
-   // Check for engine
-    if(!dap_strcmp(s_used_driver, "ldb"))
-        l_ret = -1;
-    else if(!dap_strcmp(s_used_driver, "sqlite") || !dap_strcmp(s_used_driver, "sqlite3") )
-        l_ret = dap_db_driver_sqlite_init(l_db_path_ext, &s_drv_callback);
-    else if(!dap_strcmp(s_used_driver, "cdb"))
-        l_ret = dap_db_driver_cdb_init(l_db_path_ext, &s_drv_callback);
-#ifdef DAP_CHAIN_GDB_ENGINE_MDBX
-    else if(!dap_strcmp(s_used_driver, "mdbx"))
-        l_ret = dap_db_driver_mdbx_init(l_db_path_ext, &s_drv_callback);
-#endif
-
-#ifdef DAP_CHAIN_GDB_ENGINE_PGSQL
-    else if(!dap_strcmp(s_used_driver, "pgsql"))
-        l_ret = dap_db_driver_pgsql_init(l_db_path_ext, &s_drv_callback);
-#endif
-    else
-        log_it(L_ERROR, "Unknown global_db driver \"%s\"", a_driver_name);
-
-    return l_ret;
-}
-
-/**
- * @brief Deinitializes a database driver.
- * @note You should call this function after using the driver.
- * @return (none)
- */
-void dap_db_driver_deinit(void)
-{
-    log_it(L_NOTICE, "DeInit for %s ...", s_used_driver);
-
-    if ( s_db_drvmode_async )                                               /* Let's finishing outstanding DB request ... */
-    {
-        for ( int i = 7; i-- && s_db_reqs_list.nr; )
-        {
-            log_it(L_WARNING, "Let's finished outstanding DB requests (%d) ... ",  s_db_reqs_list.nr);
-            for ( int j = 3; (j = sleep(j)); );                             /* Hibernate for 3 seconds ... */
-        }
-
-        log_it(L_INFO, "Number of outstanding DB requests: %d",  s_db_reqs_list.nr);
-    }
-
-    // deinit driver
-    if(s_drv_callback.deinit)
-        s_drv_callback.deinit();
-
-    s_used_driver [ 0 ] = '\0';
-}
-
-/**
- * @brief Flushes a database cahce to disk.
- * @return Returns 0, if successful; otherwise <0.
- */
-int dap_db_driver_flush(void)
-{
-    return s_db_drvmode_async ? 0 : s_drv_callback.flush();
-}
-
-/**
- * @brief Copies objects from a_store_obj.
- * @param a_store_obj a pointer to the source objects
- * @param a_store_count a number of objects
- * @return A pointer to the copied objects.
- */
-dap_store_obj_t* dap_store_obj_copy(dap_store_obj_t *a_store_obj, size_t a_store_count)
-{
-dap_store_obj_t *l_store_obj, *l_store_obj_dst, *l_store_obj_src;
-
-    if(!a_store_obj || !a_store_count)
-        return NULL;
-
-    if ( !(l_store_obj = DAP_NEW_SIZE(dap_store_obj_t, sizeof(dap_store_obj_t) * a_store_count)) )
-         return NULL;
-
-    l_store_obj_dst = l_store_obj;
-    l_store_obj_src = a_store_obj;
-
-    for( int i =  a_store_count; i--; l_store_obj_dst++, l_store_obj_src++)
-    {
-        memcpy(l_store_obj_dst, l_store_obj_src, sizeof(*l_store_obj_dst));
-
-        l_store_obj_dst->group = dap_strdup(l_store_obj_src->group);
-        l_store_obj_dst->key = dap_strdup(l_store_obj_src->key);
-        if(l_store_obj_src->value &&l_store_obj_src->value_len){
-            l_store_obj_dst->value = DAP_DUP_SIZE(l_store_obj_src->value, l_store_obj_src->value_len);
-        }
-
-        // Why to do if we did memcpy() before?
-        //l_store_obj_dst->callback_proc_thread = l_store_obj_src->callback_proc_thread;
-        //l_store_obj_dst->callback_proc_thread_arg = l_store_obj_src->callback_proc_thread_arg;
-    }
-
-    return l_store_obj;
-}
-
-/**
- * @brief Deallocates memory of objects.
- * @param a_store_obj a pointer to objects
- * @param a_store_count a number of objects
- * @return (none)
- */
-void dap_store_obj_free(dap_store_obj_t *a_store_obj, size_t a_store_count)
-{
-    if(!a_store_obj || !a_store_count)
-        return;
-
-    dap_store_obj_t *l_store_obj_cur = a_store_obj;
-
-    for ( ; a_store_count--; l_store_obj_cur++ ) {
-        DAP_DEL_Z(l_store_obj_cur->group);
-        DAP_DEL_Z(l_store_obj_cur->key);
-        DAP_DEL_Z(l_store_obj_cur->value);
-    }
-    DAP_DEL_Z(a_store_obj);
-}
-
-/**
- * @brief Applies objects to database.
- * @param a_store an pointer to the objects
- * @param a_store_count a number of objectss
- * @return Returns 0, if successful.
- */
-static inline  int s_dap_chain_global_db_driver_apply_do(dap_store_obj_t *a_store_obj, size_t a_store_count)
-{
-int l_ret;
-dap_store_obj_t *l_store_obj_cur;
-
-    if(!a_store_obj || !a_store_count)
-        return -1;
-
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "[%p] Process DB Request ...", a_store_obj);
-
-    l_store_obj_cur = a_store_obj;                                          /* We have to  use a power of the address's incremental arithmetic */
-    l_ret = 0;                                                              /* Preset return code to OK */
-
-    if (a_store_count > 1 && s_drv_callback.transaction_start)
-        s_drv_callback.transaction_start();
-
-    if(s_drv_callback.apply_store_obj)
-        for(int i = a_store_count; (!l_ret) && (i--); l_store_obj_cur++) {
-            if ( 1 == (l_ret = s_drv_callback.apply_store_obj(l_store_obj_cur)) )
-                log_it(L_INFO, "[%p] Item is missing (may be already deleted) %s/%s", a_store_obj, l_store_obj_cur->group, l_store_obj_cur->key);
-            else if (l_ret < 0)
-                log_it(L_ERROR, "[%p] Can't write item %s/%s (code %d)", a_store_obj, l_store_obj_cur->group, l_store_obj_cur->key, l_ret);
-        }
-
-    if(a_store_count > 1 && s_drv_callback.transaction_end)
-        s_drv_callback.transaction_end();
-
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "[%p] Finished DB Request (code %d)", a_store_obj, l_ret);
-    return l_ret;
-}
-
-static bool s_dap_driver_req_exec (struct dap_proc_thread *a_dap_thd __attribute__((unused)),
-                                   void *arg __attribute__((unused)) )
-{
-int l_ret;
-dap_store_obj_t *l_store_obj_cur;
-dap_worker_t        *l_dap_worker;
-size_t l_store_obj_cnt;
-
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "Entering, %d entries in the queue ...",  s_db_reqs_list.nr);
-
-    if ( (l_ret = pthread_mutex_lock(&s_db_reqs_list_lock)) )               /* Get exclusive access to the request list */
-         return log_it(L_ERROR, "Cannot lock request queue, errno=%d",l_ret), 0;
-
-    if ( !s_db_reqs_list.nr )                                               /* Nothing to do ?! Just exit */
-    {
-        pthread_mutex_unlock(&s_db_reqs_list_lock);
-        return  1;                                                          /* 1 - Don't call it again */
-    }
-
-    if ( (l_ret = dap_slist_get4head (&s_db_reqs_list, (void **)  &l_store_obj_cur, &l_store_obj_cnt)) )
-    {
-        pthread_mutex_unlock(&s_db_reqs_list_lock);
-        log_it(L_ERROR, "DB Request list is in incosistence state (code %d)", l_ret);
-        return  1;                                                          /* 1 - Don't call it again */
-    }
-
-    /* So at this point we are ready to do work in the DB */
-    s_dap_chain_global_db_driver_apply_do(l_store_obj_cur, l_store_obj_cnt);
-
-    pthread_mutex_unlock(&s_db_reqs_list_lock);
-
-
-    /* Is there a callback  ? */
-    if ( s_db_drvmode_async && l_store_obj_cur->callback_proc_thread )
-        {
-        /* Enqueue "Exec Complete" callback routine */
-        l_dap_worker = dap_events_worker_get_auto ();
-
-        if ( (l_ret = dap_proc_queue_add_callback(l_dap_worker,
-                                                  l_store_obj_cur->callback_proc_thread,
-                                                  l_store_obj_cur->callback_proc_thread_arg   ) ) )
-            log_it(L_ERROR, "[%p] Enqueue completion callback for item %s/%s (code %d)", l_store_obj_cur,
-                   l_store_obj_cur->group, l_store_obj_cur->key, l_ret);
-        }
-
-    dap_store_obj_free (l_store_obj_cur, l_store_obj_cnt);                  /* Release a memory !!! */
-
-    return  1;  /* 1 - Don't call it again */
-}
-
-
-/**
- * @brief Applies objects to database.
- * @param a_store an pointer to the objects
- * @param a_store_count a number of objectss
- * @return Returns 0, if successful.
- */
-int dap_chain_global_db_driver_apply(dap_store_obj_t *a_store_obj, size_t a_store_count)
-{
-int l_ret;
-dap_store_obj_t *l_store_obj_cur;
-dap_worker_t        *l_dap_worker;
-
-    if(!a_store_obj || !a_store_count)
-        return -1;
-
-    if ( !s_db_drvmode_async )
-        return s_dap_chain_global_db_driver_apply_do(a_store_obj, a_store_count);
-
-
-
-
-
-    /* Async mode - put request into the list for deffered processing */
-    l_ret = -ENOMEM;                                                    /* Preset return code to non-OK  */
-
-    pthread_mutex_lock(&s_db_reqs_list_lock);                           /* Get exclusive access to the request list */
-
-    if ( !(l_store_obj_cur = dap_store_obj_copy(a_store_obj, a_store_count)) )
-        l_ret = - ENOMEM, log_it(L_ERROR, "[%p] No memory for DB Request for item %s/%s", a_store_obj, a_store_obj->group, a_store_obj->key);
-    else if ( (l_ret = dap_slist_add2tail (&s_db_reqs_list, l_store_obj_cur, a_store_count)) )
-        log_it(L_ERROR, "[%p] Can't enqueue DB request for item %s/%s (code %d)", a_store_obj, a_store_obj->group, a_store_obj->key, l_ret);
-
-    pthread_mutex_unlock(&s_db_reqs_list_lock);
-
-    if ( !l_ret )
-        {                                                                /* So finaly enqueue an execution routine */
-        if ( !(l_dap_worker = dap_events_worker_get_auto ()) )
-            l_ret = -EBUSY, log_it(L_ERROR, "[%p] Error process DB request for %s/%s, dap_events_worker_get_auto()->NULL", a_store_obj, l_store_obj_cur->group, l_store_obj_cur->key);
-        else l_ret = dap_proc_queue_add_callback(l_dap_worker, s_dap_driver_req_exec, NULL);
-        }
-
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "[%p] DB Request has been enqueued (code %d)", l_store_obj_cur, l_ret);
-
-    return  l_ret;
-}
-
-
-
-
-
-
-/**
- * @brief Adds objects to a database.
- * @param a_store_obj objects to be added
- * @param a_store_count a number of added objects
- * @return Returns 0 if sucseesful.
- */
-int dap_chain_global_db_driver_add(pdap_store_obj_t a_store_obj, size_t a_store_count)
-{
-dap_store_obj_t *l_store_obj_cur = a_store_obj;
-
-    for(int i = a_store_count; i--; l_store_obj_cur++)
-        l_store_obj_cur->type = DAP_DB$K_OPTYPE_ADD;
-
-    return dap_chain_global_db_driver_apply(a_store_obj, a_store_count);
-}
-
-/**
- * @brief Deletes objects from a database.
- * @param a_store_obj objects to be deleted
- * @param a_store_count a number of deleted objects
- * @return Returns 0 if sucseesful.
- */
-int dap_chain_global_db_driver_delete(pdap_store_obj_t a_store_obj, size_t a_store_count)
-{
-dap_store_obj_t *l_store_obj_cur = a_store_obj;
-
-    for(int i = a_store_count; i--; l_store_obj_cur++)
-        l_store_obj_cur->type = DAP_DB$K_OPTYPE_DEL;
-
-    return dap_chain_global_db_driver_apply(a_store_obj, a_store_count);
-}
-
-/**
- * @brief Gets a number of stored objects in a database by a_group and id.
- * @param a_group the group name string
- * @param a_id id
- * @return Returns a number of objects.
- */
-size_t dap_chain_global_db_driver_count(const char *a_group, uint64_t id)
-{
-    size_t l_count_out = 0;
-    // read the number of items
-    if(s_drv_callback.read_count_store)
-        l_count_out = s_drv_callback.read_count_store(a_group, id);
-    return l_count_out;
-}
-
-/**
- * @brief Gets a list of group names matching the pattern.
- * Check whether the groups match the pattern a_group_mask, which is a shell wildcard pattern
- * patterns: [] {} [!] * ? https://en.wikipedia.org/wiki/Glob_(programming).
- * @param a_group_mask the group mask string
- * @return If successful, returns the list of group names, otherwise NULL.
- */
-dap_list_t *dap_chain_global_db_driver_get_groups_by_mask(const char *a_group_mask)
-{
-    dap_list_t *l_list = NULL;
-    if(s_drv_callback.get_groups_by_mask)
-        l_list = s_drv_callback.get_groups_by_mask(a_group_mask);
-    return l_list;
-}
-
-
-/**
- * @brief Reads last object in the database.
- * @param a_group the group name
- * @return If successful, a pointer to the object, otherwise NULL.
- */
-dap_store_obj_t* dap_chain_global_db_driver_read_last(const char *a_group)
-{
-    dap_store_obj_t *l_ret = NULL;
-    // read records using the selected database engine
-    if(s_drv_callback.read_last_store_obj)
-        l_ret = s_drv_callback.read_last_store_obj(a_group);
-    return l_ret;
-}
-
-/**
- * @brief Reads several objects from a database by a_group and id.
- * @param a_group the group name string
- * @param a_id id
- * @param a_count_out[in] a number of objects to be read, if 0 - no limits
- * @param a_count_out[out] a count of objects that were read
- * @return If successful, a pointer to an objects, otherwise NULL.
- */
-dap_store_obj_t* dap_chain_global_db_driver_cond_read(const char *a_group, uint64_t id, size_t *a_count_out)
-{
-    dap_store_obj_t *l_ret = NULL;
-    // read records using the selected database engine
-    if(s_drv_callback.read_cond_store_obj)
-        l_ret = s_drv_callback.read_cond_store_obj(a_group, id, a_count_out);
-    return l_ret;
-}
-
-/**
- * @brief Reads several objects from a database by a_group and a_key.
- * If a_key is NULL, reads whole group.
- * @param a_group a group name string
- * @param a_key  an object key string. If equal NULL, it means reading the whole group
- * @param a_count_out[in] a number of objects to be read, if 0 - no limits
- * @param a_count_out[out] a number of objects that were read
- * @return If successful, a pointer to an objects, otherwise NULL.
- */
-dap_store_obj_t* dap_chain_global_db_driver_read(const char *a_group, const char *a_key, size_t *a_count_out)
-{
-    dap_store_obj_t *l_ret = NULL;
-    // read records using the selected database engine
-    if(s_drv_callback.read_store_obj)
-        l_ret = s_drv_callback.read_store_obj(a_group, a_key, a_count_out);
-    return l_ret;
-}
-
-/**
- * @brief Checks if an object is in a database by a_group and a_key.
- * @param a_group a group name string
- * @param a_key a object key string
- * @return Returns true if it is, false otherwise.
- */
-bool dap_chain_global_db_driver_is(const char *a_group, const char *a_key)
-{
-    bool l_ret = NULL;
-    // read records using the selected database engine
-    if(s_drv_callback.is_obj && a_group && a_key)
-        return s_drv_callback.is_obj(a_group, a_key);
-    else
-        return false;
-}
diff --git a/modules/global-db/dap_chain_global_db_driver_cdb.c b/modules/global-db/dap_chain_global_db_driver_cdb.c
deleted file mode 100644
index 7a1a55dfae7a49f15b7695c76913a7dba612b34b..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_chain_global_db_driver_cdb.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * Authors:
- * Konstantin Papizh <konstantin.papizh@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2019
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stddef.h>
-#include <string.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <uthash.h>
-#include <pthread.h>
-#include <errno.h>
-#include <stdatomic.h>
-
-#define _GNU_SOURCE
-
-#include "dap_global_db.h"
-#include "dap_chain_global_db_driver_cdb.h"
-#include "dap_common.h"
-#include "dap_hash.h"
-#include "dap_strfuncs.h" // #include <dap_fnmatch.h>
-#include "dap_file_utils.h"
-
-#define LOG_TAG "dap_chain_global_db_cdb"
-
-/** Struct for a item */
-typedef struct _obj_arg {
-    pdap_store_obj_t o;
-    uint64_t q;
-    uint64_t n;
-    uint64_t id;
-} obj_arg, *pobj_arg;
-
-/** Struct for a CDB instanse */
-typedef struct _cdb_instance {
-    CDB *cdb;
-    char *local_group;
-    uint64_t id;
-    UT_hash_handle hh;
-} cdb_instance, *pcdb_instance;
-
-/** A path to a CDB file. */
-static char s_cdb_path[MAX_PATH];
-
-/** A pointer to a CDB instance. */
-static pcdb_instance s_cdb = NULL;
-/** A mutex for working with a CDB instanse. */
-static pthread_mutex_t cdb_mutex = PTHREAD_MUTEX_INITIALIZER;
-/** A read-write lock for working with a CDB instanse. */
-static pthread_rwlock_t cdb_rwlock = PTHREAD_RWLOCK_INITIALIZER;
-
-/**
- * @brief Serialize key and val to a item
- * key -> key
- * val[0..8] => id
- * val[..] => value_len
- * val[..] => value
- * val[..] => timestamp
- * @param a_obj a pointer to a item
- * @param key a key
- * @param val a serialize string
- */
-static void cdb_serialize_val_to_dap_store_obj(pdap_store_obj_t a_obj, const char *key, const char *val) {
-    if (!key) {
-        return;
-    }
-    int offset = 0;
-    a_obj->key = dap_strdup(key);
-    a_obj->id = dap_hex_to_uint(val, sizeof(uint64_t));
-    offset += sizeof(uint64_t);
-    a_obj->flags = dap_hex_to_uint(val + offset, sizeof(uint8_t));
-    offset += sizeof(uint8_t);
-    a_obj->value_len = dap_hex_to_uint(val + offset, sizeof(uint64_t));
-    offset += sizeof(uint64_t);
-    if (a_obj->value_len) {
-        a_obj->value = DAP_NEW_SIZE(uint8_t, a_obj->value_len);
-        memcpy((byte_t *)a_obj->value, val + offset, a_obj->value_len);
-    }
-    offset += a_obj->value_len;
-    a_obj->timestamp = dap_hex_to_uint(val + offset, sizeof(uint64_t));
-}
-
-/** A callback function designed for finding a last item */
-bool dap_cdb_get_last_obj_iter_callback(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid) {
-    UNUSED(ksize);
-    UNUSED(val);
-    UNUSED(vsize);
-    UNUSED(expire);
-    UNUSED(oid);
-
-    if (--((pobj_arg)arg)->q == 0) {
-        cdb_serialize_val_to_dap_store_obj((pdap_store_obj_t)(((pobj_arg)arg)->o), key, val);
-        return false;
-    }
-    return true;
-}
-
-//** A callback function designed for finding a some items */
-bool dap_cdb_get_some_obj_iter_callback(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid) {
-    UNUSED(ksize);
-    UNUSED(val);
-    UNUSED(vsize);
-    UNUSED(expire);
-    UNUSED(oid);
-
-    pdap_store_obj_t l_obj = (pdap_store_obj_t)((pobj_arg)arg)->o;
-    cdb_serialize_val_to_dap_store_obj(&l_obj[((pobj_arg)arg)->n - ((pobj_arg)arg)->q], key, val);
-    if (--((pobj_arg)arg)->q == 0) {
-        return false;
-    }
-    return true;
-}
-
-//** A callback function designed for finding a some items by conditionals */
-bool dap_cdb_get_cond_obj_iter_callback(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid) {
-    UNUSED(ksize);
-    UNUSED(val);
-    UNUSED(vsize);
-    UNUSED(expire);
-    UNUSED(oid);
-
-    if (dap_hex_to_uint(val, sizeof(uint64_t)) < ((pobj_arg)arg)->id) {
-        return true;
-    }
-    pdap_store_obj_t l_obj = (pdap_store_obj_t)((pobj_arg)arg)->o;
-    cdb_serialize_val_to_dap_store_obj(&l_obj[((pobj_arg)arg)->n - ((pobj_arg)arg)->q], key, val);
-    if (--((pobj_arg)arg)->q == 0) {
-        return false;
-    }
-    return true;
-}
-
-//** A callback function designed for counting items*/
-bool dap_cdb_get_count_iter_callback(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid) {
-    UNUSED(ksize);
-    UNUSED(val);
-    UNUSED(vsize);
-    UNUSED(expire);
-    UNUSED(oid);
-    UNUSED(key);
-
-    if (dap_hex_to_uint(val, sizeof(uint64_t)) < ((pobj_arg)arg)->id) {
-        return true;
-    }
-    if (--((pobj_arg)arg)->q == 0) {
-        return false;
-    }
-    return true;
-}
-
-/**
- * @brief Initiates a CDB with main hash table size: 1000000,
- * record cache: 128Mb, index page cache: 1024Mb.
- * @param a_group a group name
- * @param a_flags should be combination of CDB_CREAT / CDB_TRUNC / CDB_PAGEWARMUP
-   CDB_PAGEWARMUP
- * @return A pointer to CDB, if success. NULL, if error.
- */
-pcdb_instance dap_cdb_init_group(const char *a_group, int a_flags) {
-    pcdb_instance l_cdb_i = NULL;
-    char l_cdb_path[MAX_PATH + 2];
-
-    pthread_mutex_lock(&cdb_mutex);
-    HASH_FIND_STR(s_cdb, a_group, l_cdb_i);
-    if (a_flags & CDB_TRUNC) {
-        if (!l_cdb_i)
-            goto FIN;
-        cdb_close(l_cdb_i->cdb);
-    }
-    if (!(a_flags & CDB_TRUNC)) {
-        if (l_cdb_i)
-            goto FIN;
-        l_cdb_i = DAP_NEW(cdb_instance);
-        l_cdb_i->local_group = dap_strdup(a_group);
-        l_cdb_i->cdb = cdb_new();
-    }
-    memset(l_cdb_path, '\0', sizeof(l_cdb_path));
-    dap_snprintf(l_cdb_path, sizeof(l_cdb_path), "%s/%s", s_cdb_path, a_group);
-    cdb_options l_opts = { 100000, 256, 1024 };
-    if (cdb_option(l_cdb_i->cdb, l_opts.hsize, l_opts.pcacheMB, l_opts.rcacheMB) != CDB_SUCCESS) {
-        log_it(L_ERROR, "Options are inacceptable: \"%s\"", cdb_errmsg(cdb_errno(l_cdb_i->cdb)));
-        goto ERR;
-    }
-    if (cdb_open(l_cdb_i->cdb, l_cdb_path, a_flags) != CDB_SUCCESS) {
-        log_it(L_ERROR, "An error occured while opening CDB: \"%s\"", cdb_errmsg(cdb_errno(l_cdb_i->cdb)));
-        goto ERR;
-    }
-    if (!(a_flags & CDB_TRUNC)) {
-        CDBSTAT l_cdb_stat;
-        cdb_stat(l_cdb_i->cdb, &l_cdb_stat);
-        if (l_cdb_stat.rnum > 0 || !(a_flags & CDB_CREAT)) {
-            void *l_iter = cdb_iterate_new(l_cdb_i->cdb, 0);
-            obj_arg l_arg;
-            l_arg.o = DAP_NEW_Z(dap_store_obj_t);
-            l_arg.q = l_cdb_stat.rnum;
-            cdb_iterate(l_cdb_i->cdb, dap_cdb_get_last_obj_iter_callback, (void*)&l_arg, l_iter);
-            cdb_iterate_destroy(l_cdb_i->cdb, l_iter);
-            l_cdb_i->id = l_arg.o->id;
-            //log_it(L_INFO, "Group \"%s\" found"             , l_cdb_i->local_group);
-            //log_it(L_INFO, "Records: %-24u"                 , l_cdb_stat.rnum);
-            //log_it(L_INFO, "Average read latency: %-24u"    , l_cdb_stat.rlatcy);
-            //log_it(L_INFO, "Average write latency: %-24u"   , l_cdb_stat.wlatcy);
-            //log_it(L_INFO, "Last id: %-24u"                 , l_cdb_i->id);
-            dap_store_obj_free_one(l_arg.o);
-        } else {
-            log_it(L_INFO, "Group \"%s\" created", l_cdb_i->local_group);
-            l_cdb_i->id = 0;
-        }
-        HASH_ADD_KEYPTR(hh, s_cdb, l_cdb_i->local_group, strlen(l_cdb_i->local_group), l_cdb_i);
-    } else {
-        log_it(L_INFO, "Group \"%s\" truncated", l_cdb_i->local_group);
-        DAP_DELETE(l_cdb_i->local_group);
-        cdb_destroy(l_cdb_i->cdb);
-        HASH_DEL(s_cdb, l_cdb_i);
-        DAP_DEL_Z(l_cdb_i);
-    }
-
-FIN:
-    pthread_mutex_unlock(&cdb_mutex);
-    return l_cdb_i;
-ERR:
-    cdb_destroy(l_cdb_i->cdb);
-    DAP_DELETE(l_cdb_i->local_group);
-    DAP_DELETE(l_cdb_i);
-    pthread_mutex_unlock(&cdb_mutex);
-    return NULL;
-}
-
-/**
- * @brief Initiates a CDB with callback fuctions.
- * @param a_cdb_path a path to CDB. Saved in s_cdb_path
- * @param a_drv_callback a struct for callback functions
- * @param a_db_drvmode_async
- * @return 0 if success, -1 if сouldn't open db directory, -2 if dap_cdb_init_group() returns NULL.
- */
-int dap_db_driver_cdb_init(const char *a_cdb_path, dap_db_driver_callbacks_t *a_drv_callback)
-{
-int l_rc;
-struct dirent *d;
-DIR *dir;
-
-    for (l_rc = 0; *a_cdb_path && ((size_t)l_rc < sizeof(s_cdb_path)); )
-         s_cdb_path[l_rc++] = *(a_cdb_path++);                              /* Copy path to CDB root to local storage, calculate length */
-
-    if(s_cdb_path[l_rc - 1] == '/')                                         /* Truncate terminal '/' if need */
-        s_cdb_path[--l_rc] = '\0';
-
-    dap_mkdir_with_parents(s_cdb_path);
-
-    if ( !(dir = opendir(s_cdb_path)) )
-        return log_it(L_ERROR, "Couldn't open db directory '%s', errno=%d", s_cdb_path, errno), -errno;
-
-    while ( (d = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-        if (d->d_type != DT_DIR)
-            continue;
-#elif defined(DAP_OS_LINUX)
-        struct _stat buf;
-        int res = _stat(d->d_name, &buf);
-        if (!S_ISDIR(buf.st_mode) || !res) {
-            continue;
-        }
-#elif defined (DAP_OS_BSD)
-        struct stat buf;
-        int res = stat(d->d_name, &buf);
-        if (!S_ISDIR(buf.st_mode) || !res) {
-            continue;
-        }
-#endif
-        if ( (d->d_name[0] == '.') || !dap_strcmp(d->d_name, ".."))
-            continue;
-
-        pcdb_instance l_cdb_i = dap_cdb_init_group(d->d_name, CDB_PAGEWARMUP);
-        if (!l_cdb_i) {
-            dap_db_driver_cdb_deinit();
-            closedir(dir);
-            return -2;
-        }
-    }
-
-    a_drv_callback->read_last_store_obj = dap_db_driver_cdb_read_last_store_obj;
-    a_drv_callback->apply_store_obj     = dap_db_driver_cdb_apply_store_obj;
-    a_drv_callback->read_store_obj      = dap_db_driver_cdb_read_store_obj;
-    a_drv_callback->read_cond_store_obj = dap_db_driver_cdb_read_cond_store_obj;
-    a_drv_callback->read_count_store    = dap_db_driver_cdb_read_count_store;
-    a_drv_callback->get_groups_by_mask  = dap_db_driver_cdb_get_groups_by_mask;
-    a_drv_callback->is_obj              = dap_db_driver_cdb_is_obj;
-    a_drv_callback->deinit              = dap_db_driver_cdb_deinit;
-    a_drv_callback->flush               = dap_db_driver_cdb_flush;
-
-    closedir(dir);
-
-    return CDB_SUCCESS;
-}
-
-/**
- * @brief Gets CDB by a_group.
- * @param a_group a group name
- * @return if CDB is found, a pointer to CDB, otherwise NULL.
- */
-pcdb_instance dap_cdb_get_db_by_group(const char *a_group) {
-    pcdb_instance l_cdb_i = NULL;
-    pthread_rwlock_rdlock(&cdb_rwlock);
-    HASH_FIND_STR(s_cdb, a_group, l_cdb_i);
-    pthread_rwlock_unlock(&cdb_rwlock);
-    return l_cdb_i;
-}
-
-/**
- * @brief Creates a directory on the path s_cdb_path/a_group.
- * @param a_group the group name
- * @return 0
- */
-int dap_cdb_add_group(const char *a_group) {
-    char l_cdb_path[MAX_PATH + 2];
-    memset(l_cdb_path, '\0', sizeof(l_cdb_path));
-    dap_snprintf(l_cdb_path, sizeof(l_cdb_path), "%s/%s", s_cdb_path, a_group);
-#ifdef _WIN32
-    mkdir(l_cdb_path);
-#else
-    mkdir(l_cdb_path, 0755);
-#endif
-    return 0;
-}
-
-/**
- * @brief Deinitialize CDB.
- * @return 0
- */
-int dap_db_driver_cdb_deinit() {
-    pcdb_instance cur_cdb, tmp;
-    pthread_rwlock_wrlock(&cdb_rwlock);
-    HASH_ITER(hh, s_cdb, cur_cdb, tmp) {
-        DAP_DELETE(cur_cdb->local_group);
-        cdb_destroy(cur_cdb->cdb);
-        HASH_DEL(s_cdb, cur_cdb);
-        DAP_DELETE(cur_cdb);
-    }
-    pthread_rwlock_unlock(&cdb_rwlock);
-
-    return CDB_SUCCESS;
-}
-
-/**
- * @brief Flushing CDB to the disk.
- * @return 0
- */
-int dap_db_driver_cdb_flush(void) {
-    int ret = 0;
-    log_it(L_DEBUG, "Flushing CDB to disk");
-    cdb_instance *cur_cdb, *tmp;
-    pthread_rwlock_rdlock(&cdb_rwlock);
-    HASH_ITER(hh, s_cdb, cur_cdb, tmp) {
-        cdb_flushalldpage(cur_cdb->cdb);
-    }
-    pthread_rwlock_unlock(&cdb_rwlock);
-    log_it(L_DEBUG, "All data dumped");
-    return ret;
-}
-
-/**
- * @brief Read last store item from CDB.
- * @param a_group a group name
- * @return If successful, a pointer to item, otherwise NULL.
- */
-dap_store_obj_t *dap_db_driver_cdb_read_last_store_obj(const char* a_group) {
-    if (!a_group) {
-        return NULL;
-    }
-    pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_group);
-    if (!l_cdb_i) {
-        return NULL;
-    }
-    CDB *l_cdb = l_cdb_i->cdb;
-    CDBSTAT l_cdb_stat;
-    cdb_stat(l_cdb, &l_cdb_stat);
-    if (!l_cdb_stat.rnum)
-        return NULL;
-    void *l_iter = cdb_iterate_new(l_cdb, 0);
-    obj_arg l_arg;
-    l_arg.o = DAP_NEW_Z(dap_store_obj_t);
-    l_arg.q = l_cdb_stat.rnum;
-    cdb_iterate(l_cdb, dap_cdb_get_last_obj_iter_callback, (void*)&l_arg, l_iter);
-    cdb_iterate_destroy(l_cdb, l_iter);
-    l_arg.o->group = dap_strdup(a_group);
-    return l_arg.o;
-}
-
-/**
- * @brief Checks if CDB has a_key
- * @param a_group the group name
- * @param a_key the key
- * @return true or false
- */
-bool dap_db_driver_cdb_is_obj(const char *a_group, const char *a_key)
-{
-    bool l_ret = false;
-    if(!a_group) {
-        return false;
-    }
-    pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_group);
-    if(!l_cdb_i) {
-        return false;
-    }
-    CDB *l_cdb = l_cdb_i->cdb;
-    if(a_key) {
-        //int l_vsize;
-        if(!cdb_is(l_cdb, a_key, (int) dap_strlen(a_key)))
-            l_ret = true;
-    }
-    return l_ret;
-}
-
-/**
- * @brief Gets items from CDB by a_group and a_key. If a_key=NULL then gets a_count_out items.
- * @param a_group the group name
- * @param a_key the key or NULL
- * @param a_count_out IN. Count of read items. OUT Count of items was read
- * @return If successful, pointer to items; otherwise NULL.
- */
-dap_store_obj_t *dap_db_driver_cdb_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out) {
-    if (!a_group) {
-        return NULL;
-    }
-    pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_group);
-    if (!l_cdb_i) {
-        return NULL;
-    }
-    CDB *l_cdb = l_cdb_i->cdb;
-    dap_store_obj_t *l_obj = NULL;
-    if (a_key) {
-        char *l_value;
-        int l_vsize;
-        cdb_get(l_cdb, a_key, (int)strlen(a_key), (void**)&l_value, &l_vsize);
-        if (!l_value) {
-            return NULL;
-        }
-        l_obj = DAP_NEW_Z(dap_store_obj_t);
-        cdb_serialize_val_to_dap_store_obj(l_obj, a_key, l_value);
-        l_obj->group = dap_strdup(a_group);
-        cdb_free_val((void**)&l_value);
-        if(a_count_out) {
-            *a_count_out = 1;
-        }
-    } else {
-        uint64_t l_count_out = 0;
-        if(a_count_out) {
-            l_count_out = *a_count_out;
-        }
-        CDBSTAT l_cdb_stat;
-        cdb_stat(l_cdb, &l_cdb_stat);
-        if ((l_count_out == 0) || (l_count_out > l_cdb_stat.rnum)) {
-            l_count_out = l_cdb_stat.rnum;
-        }
-        obj_arg l_arg;
-        l_arg.o = DAP_NEW_Z_SIZE(dap_store_obj_t, l_count_out * sizeof(dap_store_obj_t));
-        l_arg.q = l_count_out;
-        l_arg.n = l_count_out;
-        void *l_iter = cdb_iterate_new(l_cdb, 0);
-        /*l_count_out = */cdb_iterate(l_cdb, dap_cdb_get_some_obj_iter_callback, (void*)&l_arg, l_iter);
-        cdb_iterate_destroy(l_cdb, l_iter);
-        if(a_count_out) {
-            *a_count_out = l_count_out;
-        }
-        for (uint64_t i = 0; i < l_count_out; ++i) {
-            l_arg.o[i].group = dap_strdup(a_group);
-        }
-        l_obj = l_arg.o;
-    }
-    return l_obj;
-}
-
-/**
- * @brief Gets items from CDB by a_group and a_id.
- * @param a_group the group name
- * @param a_id id
- * @param a_count_out[in] a count of items
- * @param a_count[out] a count of items were got
- * @return If successful, pointer to items, otherwise NULL.
- */
-dap_store_obj_t* dap_db_driver_cdb_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out) {
-    if (!a_group) {
-        return NULL;
-    }
-    pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_group);
-    if (!l_cdb_i) {
-        return NULL;
-    }
-    CDB *l_cdb = l_cdb_i->cdb;
-    uint64_t l_count_out = 0;
-    if(a_count_out) {
-        l_count_out = *a_count_out;
-    }
-    CDBSTAT l_cdb_stat;
-    cdb_stat(l_cdb, &l_cdb_stat);
-
-    if (l_count_out == 0 || l_count_out > l_cdb_stat.rnum) {
-        l_count_out = l_cdb_stat.rnum;
-    }
-    obj_arg l_arg;
-    l_arg.o = DAP_NEW_Z_SIZE(dap_store_obj_t, l_count_out * sizeof(dap_store_obj_t));
-    l_arg.n = l_count_out;
-    l_arg.q = l_count_out;
-    l_arg.id = a_id;
-    void *l_iter = cdb_iterate_new(l_cdb, 0);
-    /*l_count_out = */cdb_iterate(l_cdb, dap_cdb_get_cond_obj_iter_callback, (void*)&l_arg, l_iter);
-    cdb_iterate_destroy(l_cdb, l_iter);
-    if (l_arg.q > 0) {
-        l_count_out = l_arg.n - l_arg.q;
-        void *tmp = DAP_REALLOC(l_arg.o, l_count_out * sizeof(dap_store_obj_t));
-        if (!tmp && l_count_out) {
-            log_it(L_CRITICAL, "Couldn't re-allocate memory for portion of store objects!");
-            DAP_DELETE(l_arg.o);
-            return NULL;
-        }
-        l_arg.o = tmp;
-    }
-    if(a_count_out) {
-        *a_count_out = l_count_out;
-    }
-    for (uint64_t i = 0; i < l_count_out; ++i) {
-        l_arg.o[i].group = dap_strdup(a_group);
-    }
-    return l_arg.o;
-}
-
-/**
- * @brief Reads count of items in CDB by a_group and a_id.
- * @param a_group the group name
- * @param a_id id
- * @return If successful, count of store items; otherwise 0.
- */
-size_t dap_db_driver_cdb_read_count_store(const char *a_group, uint64_t a_id)
-{
-    if (!a_group) {
-        return 0;
-    }
-    pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_group);
-    if (!l_cdb_i) {
-        return 0;
-    }
-    CDB *l_cdb = l_cdb_i->cdb;
-    CDBSTAT l_cdb_stat;
-    cdb_stat(l_cdb, &l_cdb_stat);
-    obj_arg l_arg;
-    l_arg.q = l_cdb_stat.rnum;
-    l_arg.id = a_id;
-    void *l_iter = cdb_iterate_new(l_cdb, 0);
-    cdb_iterate(l_cdb, dap_cdb_get_count_iter_callback, (void*)&l_arg, l_iter);
-    cdb_iterate_destroy(l_cdb, l_iter);
-    return l_cdb_stat.rnum - l_arg.q;
-}
-
-/**
- * @brief Check whether the groups match the pattern a_group_mask, which is a shell wildcard pattern.
- * @param a_group_mask the mask
- * @return If successful, pointer to dap_list with group names; otherwise NULL.
- */
-dap_list_t* dap_db_driver_cdb_get_groups_by_mask(const char *a_group_mask)
-{
-    dap_list_t *l_ret_list = NULL;
-    if(!a_group_mask)
-        return NULL;
-    cdb_instance *cur_cdb, *tmp;
-    pthread_rwlock_rdlock(&cdb_rwlock);
-    HASH_ITER(hh, s_cdb, cur_cdb, tmp) {
-        char *l_table_name = cur_cdb->local_group;
-        if(!dap_fnmatch(a_group_mask, l_table_name, 0))
-            l_ret_list = dap_list_prepend(l_ret_list, dap_strdup(l_table_name));
-    }
-    pthread_rwlock_unlock(&cdb_rwlock);
-    return l_ret_list;
-}
-
-/**
- * @brief Adds or deletes item in CDB depending on a_store_obj->type.
- * @param a_store_obj a pointer to the item
- * @return 0 if success, <0 error.
- */
-int dap_db_driver_cdb_apply_store_obj(pdap_store_obj_t a_store_obj) {
-    if(!a_store_obj || !a_store_obj->group) {
-        return -1;
-    }
-    int ret = 0;
-    pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_store_obj->group);
-    if (!l_cdb_i) {
-        dap_cdb_add_group(a_store_obj->group);
-        l_cdb_i = dap_cdb_init_group(a_store_obj->group, CDB_CREAT | CDB_PAGEWARMUP);
-    }
-    if (!l_cdb_i) {
-        return -1;
-    }
-    if(a_store_obj->type == DAP_DB$K_OPTYPE_ADD) {
-        if(!a_store_obj->key) {
-            return -2;
-        };
-        int offset = 0;
-        char *l_val = DAP_NEW_Z_SIZE(char, sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint64_t) + a_store_obj->value_len + sizeof(uint64_t));
-        dap_uint_to_hex(l_val, ++l_cdb_i->id, sizeof(uint64_t));
-        offset += sizeof(uint64_t);
-        // Add flags
-        dap_uint_to_hex(l_val + offset, a_store_obj->flags, sizeof(uint8_t));
-        offset += sizeof(uint8_t);
-        // Add length of value
-        dap_uint_to_hex(l_val + offset, a_store_obj->value_len, sizeof(uint64_t));
-        offset += sizeof(uint64_t);
-        // Add value
-        if(a_store_obj->value && a_store_obj->value_len){
-            memcpy(l_val + offset, a_store_obj->value, a_store_obj->value_len);
-        }
-        offset += a_store_obj->value_len;
-        // Add a timestamp
-        dap_uint_to_hex(l_val + offset, a_store_obj->timestamp, sizeof(uint64_t));
-        offset += sizeof(uint64_t);
-        if (cdb_set2(l_cdb_i->cdb, a_store_obj->key, (int)strlen(a_store_obj->key), l_val, offset, CDB_INSERTCACHE | CDB_OVERWRITE, 0) != CDB_SUCCESS) {
-            log_it(L_ERROR, "Couldn't add record with key [%s] to CDB: \"%s\"", a_store_obj->key, cdb_errmsg(cdb_errno(l_cdb_i->cdb)));
-            ret = -1;
-        }
-        cdb_flushalldpage(l_cdb_i->cdb);
-        DAP_DELETE(l_val);
-    } else if(a_store_obj->type == DAP_DB$K_OPTYPE_DEL) {
-        if(a_store_obj->key) {
-            if(cdb_del(l_cdb_i->cdb, a_store_obj->key, (int) strlen(a_store_obj->key)) == -3)
-                ret = 1;
-        } else {
-            dap_cdb_init_group(a_store_obj->group, CDB_TRUNC | CDB_PAGEWARMUP);
-            ret = 0;
-        }
-    }
-    return ret;
-}
diff --git a/modules/global-db/dap_chain_global_db_driver_mdbx.c b/modules/global-db/dap_chain_global_db_driver_mdbx.c
deleted file mode 100644
index e307141db085afc17ce151622881b99f9954e1ed..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_chain_global_db_driver_mdbx.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-/*
- * AUTHORS:
- * Ruslan R. (The BadAss SysMan) Laishev  <ruslan.laishev@demlabs.net>
- * DeM Labs Ltd.   https://demlabs.net
- * Copyright  (c) 2022
- * All rights reserved.
-
- This file is part of DAP SDK the open source project
-
- DAP SDK is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-
-
-    DESCRIPTION: A database driver module provide an interface to MDBX API.
-        https://gitflic.ru/project/erthink/libmdbx
-        TG group: @libmdbx
-
-
-    MODIFICATION HISTORY:
-
-          4-MAY-2022    RRL Developing for actual version of the LibMDBX
-
-         12-MAY-2022    RRL Finished developing of preliminary version
-
-         19-MAY-2022    RRL Added routines' decsriptions
-
-           1-JUN-2022   RRL Introduced dap_assert()
-
-          18-JUL-2022   RRL Fixed unitialized l_obj_arr in the s_db_mdbx_read_store_obj()
- */
-
-#include <stddef.h>
-#include <string.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <uthash.h>
-#include <stdatomic.h>
-
-#define _GNU_SOURCE
-
-#include "dap_global_db.h"
-#include "dap_config.h"
-#include "dap_chain_global_db_driver_mdbx.h"
-#include "dap_hash.h"
-#include "dap_strfuncs.h"
-#include "dap_file_utils.h"
-#include "dap_common.h"
-
-#include "mdbx.h"                                                           /* LibMDBX API */
-#define LOG_TAG "dap_chain_global_db_mdbx"
-
-
-/** Struct for a MDBX DB context */
-typedef struct __db_ctx__ {
-        size_t  namelen;                                                    /* Group name length */
-        char name[DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX + 1];                   /* Group's name */
-
-        pthread_mutex_t dbi_mutex;                                          /* Coordinate access the MDBX's <dbi> */
-        MDBX_dbi    dbi;                                                    /* MDBX's internal context id */
-        MDBX_txn    *txn;                                                   /* Current MDBX's transaction */
-
-        UT_hash_handle hh;
-} dap_db_ctx_t;
-
-static pthread_mutex_t s_db_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;          /* A mutex  for working with a DB context */
-
-
-
-static dap_db_ctx_t *s_db_ctxs = NULL;                                      /* A hash table of <group/subDB/table> == <MDBX DB context> */
-static pthread_rwlock_t s_db_ctxs_rwlock = PTHREAD_RWLOCK_INITIALIZER;      /* A read-write lock for working with a <s_db_ctxs>. */
-
-static char s_db_path[MAX_PATH];                                            /* A root directory for the MDBX files */
-
-/* Forward declarations of action routines */
-static int              s_db_mdbx_deinit();
-static int              s_db_mdbx_flush(void);
-static int              s_db_mdbx_apply_store_obj (dap_store_obj_t *a_store_obj);
-static dap_store_obj_t  *s_db_mdbx_read_last_store_obj(const char* a_group);
-static bool s_db_mdbx_is_obj(const char *a_group, const char *a_key);
-static dap_store_obj_t  *s_db_mdbx_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out);
-static dap_store_obj_t  *s_db_mdbx_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out);
-static size_t           s_db_mdbx_read_count_store(const char *a_group, uint64_t a_id);
-static dap_list_t       *s_db_mdbx_get_groups_by_mask(const char *a_group_mask);
-
-
-static MDBX_env *s_mdbx_env;                                                /* MDBX's context area */
-static char s_subdir [] = "";                                               /* Name of subdir for the MDBX's database files */
-
-static char s_db_master_tbl [] = "MDBX$MASTER";                             /* A name of master table in the MDBX
-                                                                              to keep and maintains application level information */
-static MDBX_dbi s_db_master_dbi;                                            /* A handle of the MDBX' DBI of the master subDB */
-
-
-/*
- * Suffix structure is supposed to be added at end of MDBX record, so :
- * <value> + <suffix>
- */
-struct  __record_suffix__ {
-        uint64_t        mbz;                                                /* Must Be Zero ! */
-        uint64_t        id;                                                 /* An uniqe-like Id of the record - internaly created and maintained */
-        uint64_t        flags;                                              /* Flag of the record : see RECORD_FLAGS enums */
-        dap_time_t      ts;                                                 /* Timestamp of the record */
-};
-
-
-
-
-/*
- *   DESCRIPTION: A kind of replacement of the C RTL assert()
- *
- *   INPUTS:
- *
- *   OUTPUTS:
- *
- *   RETURNS:
- *      NONE
- */
-static inline void s_dap_assert_fail(int a_condition, const char *a_expr, const char *a_file, int a_line)
-{
-char    buf[255];
-int     buflen;
-
-    if ( a_condition )
-        return;
-
-    buflen = snprintf(buf, sizeof(buf), "\n[%s:%d] <%s> expresion return false\n", a_file, a_line, a_expr);
-    write(STDOUT_FILENO, buf, buflen);
-    abort();
-}
-
-#define dap_assert(expr)  s_dap_assert_fail( (bool) (expr), #expr, __FILE__, __LINE__)
-
-
-#if     DAP_SYS_DEBUG   /* cmake ../ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-DDAP_SYS_DEBUG=1" */
-/*
- *  DESCRIPTION: Dump all records from the table . Is supposed to be used at debug time.
- *
- *  INPUTS:
- *      a_db_ctx:   DB context
- *
- *  OUTPUTS:
- *      NONE:
- *
- *  RETURNS:
- *      NONE
- */
-static void s_db_dump (dap_db_ctx_t *a_db_ctx)
-{
-int l_rc;
-MDBX_val    l_key_iov, l_data_iov;
-MDBX_cursor *l_cursor;
-char    l_buf[1024] = {0};
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &a_db_ctx->txn)) )
-        log_it(L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc));
-    else if ( MDBX_SUCCESS != (l_rc = mdbx_cursor_open(a_db_ctx->txn, a_db_ctx->dbi, &l_cursor)) )
-        log_it(L_ERROR, "mdbx_cursor_open: (%d) %s", l_rc, mdbx_strerror(l_rc));
-    else {
-        while ( !(l_rc = mdbx_cursor_get (l_cursor, &l_key_iov, &l_data_iov, MDBX_NEXT )) )
-            {
-            l_rc = dap_bin2hex (l_buf, l_data_iov.iov_base, min(l_data_iov.iov_len, 72) );
-
-            debug_if(g_dap_global_db_debug_more, L_DEBUG, "[0:%zu]: '%.*s' = [0:%zu]: '%.*s'",
-                    l_key_iov.iov_len, (int) l_key_iov.iov_len, (char *) l_key_iov.iov_base,
-                    l_data_iov.iov_len, l_rc, l_buf);
-            }
-    }
-
-    if (l_cursor)
-        mdbx_cursor_close(l_cursor);
-
-    if (a_db_ctx->txn)
-        mdbx_txn_abort(a_db_ctx->txn);
-}
-#endif     /* DAP_SYS_DEBUG */
-
-/*
- *   DESCRIPTION: Open or create (if a_flag=MDBX_CREATE) a DB context for a given group.
- *      Initialize an MDBX's internal context for the subDB (== a_group);
- *      Add new group/table name into the special MDBX subDB named MDBX$MASTER.
- *
- *   INPUTS:
- *      a_group:    A group name (in terms of MDBX it's subDB), ASCIZ
- *      a_flag:     A flag
- *
- *   IMPLICITE OUTPUTS:
- *
- *      s_db_ctxs:  Add new DB context into the hash table
- *
- *   OUTPUTS:
- *      NONE
- *
- *   RETURNS:
- *      A has been created DB Context
- *      NULL in case of error
- *
- */
-static dap_db_ctx_t *s_cre_db_ctx_for_group(const char *a_group, int a_flags)
-{
-int l_rc;
-dap_db_ctx_t *l_db_ctx, *l_db_ctx2;
-uint64_t l_seq;
-MDBX_val    l_key_iov, l_data_iov;
-
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "Init group/table '%s', flags: %#x ...", a_group, a_flags);
-
-
-    dap_assert( !pthread_rwlock_rdlock(&s_db_ctxs_rwlock) );                /* Get RD lock for lookup only */
-    HASH_FIND_STR(s_db_ctxs, a_group, l_db_ctx);                            /* Is there exist context for the group ? */
-    dap_assert( !pthread_rwlock_unlock(&s_db_ctxs_rwlock) );
-
-    if ( l_db_ctx )                                                         /* Found! Good job - return DB context */
-        return  log_it(L_INFO, "Found DB context: %p for group: '%s'", l_db_ctx, a_group), l_db_ctx;
-
-
-    /* So , at this point we are going to create (if not exist)  'table' for new group */
-
-    if ( (l_rc = strlen(a_group)) >(int) DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX )                /* Check length of the group name */
-        return  log_it(L_ERROR, "Group name '%s' is too long (%d>%lu)", a_group, l_rc, DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX), NULL;
-
-    if ( !(l_db_ctx = DAP_NEW_Z(dap_db_ctx_t)) )                            /* Allocate zeroed memory for new DB context */
-        return  log_it(L_ERROR, "Cannot allocate DB context for '%s', errno=%d", a_group, errno), NULL;
-
-    memcpy(l_db_ctx->name,  a_group, l_db_ctx->namelen = l_rc);             /* Store group name in the DB context */
-    dap_assert ( !pthread_mutex_init(&l_db_ctx->dbi_mutex, NULL));
-
-    /*
-    ** Start transaction, create table, commit.
-    */
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, 0, &l_db_ctx->txn)) )
-        return  log_it(L_CRITICAL, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-
-    if  ( MDBX_SUCCESS != (l_rc = mdbx_dbi_open(l_db_ctx->txn, a_group, a_flags, &l_db_ctx->dbi)) )
-        return  log_it(L_CRITICAL, "mdbx_dbi_open: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-
-    /* MDBX sequence is started from zero, zero is not so good for our case,
-     * so we just increment a current (may be is not zero) sequence for <dbi>
-     */
-    mdbx_dbi_sequence (l_db_ctx->txn, l_db_ctx->dbi, &l_seq, 1);
-
-    /*
-     * Save new subDB name into the master table
-     */
-    l_data_iov.iov_base =  l_key_iov.iov_base = l_db_ctx->name;
-    l_data_iov.iov_len = l_key_iov.iov_len = l_db_ctx->namelen;
-    l_data_iov.iov_len += 1;    /* Count '\0' */
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_put(l_db_ctx->txn, s_db_master_dbi, &l_key_iov, &l_data_iov, MDBX_NOOVERWRITE ))
-         && (l_rc != MDBX_KEYEXIST) )
-    {
-        log_it (L_ERROR, "mdbx_put: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-        if ( MDBX_SUCCESS != (l_rc = mdbx_txn_abort(l_db_ctx->txn)) )
-            return  log_it(L_CRITICAL, "mdbx_txn_abort: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-    }
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_commit(l_db_ctx->txn)) )
-        return  log_it(L_CRITICAL, "mdbx_txn_commit: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-
-    /*
-    ** Add new DB Context for the group into the hash for quick access
-    */
-    dap_assert( !pthread_rwlock_wrlock(&s_db_ctxs_rwlock) );                /* Get WR lock for the hash-table */
-
-    l_db_ctx2 = NULL;
-    HASH_FIND_STR(s_db_ctxs, a_group, l_db_ctx2);                           /* Check for existence of group again!!! */
-
-    if ( !l_db_ctx2)                                                        /* Still not exist - fine, add new record */
-        HASH_ADD_KEYPTR(hh, s_db_ctxs, l_db_ctx->name, l_db_ctx->namelen, l_db_ctx);
-
-    dap_assert( !pthread_rwlock_unlock(&s_db_ctxs_rwlock) );
-
-    if ( l_db_ctx2 )                                                        /* Release unnecessary new context */
-        DAP_DEL_Z(l_db_ctx);
-
-    return l_db_ctx2 ? l_db_ctx2 : l_db_ctx;
-}
-
-
-
-/*
- *  DESCRIPTION: Action routine - cleanup this module's internal contexts, DB contexts hash table,
- *      close MDBX context. After call this routine any DB operation of this module is impossible.
- *      You must/can perfroms initialization.
- *
- *  INPUTS:
- *      NONE
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS:
- *      0   - SUCCESS
- */
-
-static  int s_db_mdbx_deinit(void)
-{
-    dap_db_ctx_t *l_db_ctx = NULL, *l_tmp;
-
-    dap_assert ( !pthread_rwlock_wrlock(&s_db_ctxs_rwlock) );               /* Prelock for WR */
-
-    HASH_ITER(hh, s_db_ctxs, l_db_ctx, l_tmp)                               /* run over the hash table of the DB contexts */
-    {
-
-        dap_assert( !pthread_mutex_lock(&l_db_ctx->dbi_mutex) );
-        if (l_db_ctx->txn)                                                  /* Commit, close table */
-            mdbx_txn_commit(l_db_ctx->txn);
-
-        if (l_db_ctx->dbi)
-            mdbx_dbi_close(s_mdbx_env, l_db_ctx->dbi);
-
-        dap_assert( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-        HASH_DEL(s_db_ctxs, l_db_ctx);                                      /* Delete DB context from the hash-table */
-        DAP_DELETE(l_db_ctx);                                               /* Release memory of DB context area */
-    }
-
-    if (s_mdbx_env)
-        mdbx_env_close(s_mdbx_env);                                         /* Finaly close MDBX DB */
-
-    dap_assert ( !pthread_rwlock_unlock(&s_db_ctxs_rwlock) );
-
-    return 0;
-}
-
-/*
- *  DESCRIPTION: Performs an initial module internal context creation and setup,
- *      Fill dispatch procedure table (a_drv_callback) by entries of this module;
- *      Create MDBX data files on the specified path, open MDBX context area;
- *      Load from the MDBX$MASTER table names of groups - create DB context
- *
- *      This is a first routine before any other calls of action routines in this module !!!
- *
- *
- *  INPUTS:
- *      a_mdbx_path:    A root directory for the MDBX database files
- *      a_drv_callback
- *
- *  IMPLICITE OUTPUTS:
- *      s_mdbx_env
- *
- *  RETURNS:
- *      0       - SUCCESS
- *      0>      - <errno>
- */
-
-int     dap_db_driver_mdbx_init(const char *a_mdbx_path, dap_db_driver_callbacks_t *a_drv_dpt)
-{
-int l_rc;
-MDBX_txn    *l_txn;
-MDBX_cursor *l_cursor;
-MDBX_val    l_key_iov, l_data_iov;
-dap_slist_t l_slist = {0};
-char        *l_cp;
-size_t     l_upper_limit_of_db_size = 16;
-
-    /*
-     * [resources]
-     * mdbx_upper_limit_of_db_size=32
-     */
-    l_upper_limit_of_db_size = dap_config_get_item_uint32_default ( g_config,  "resources", "mdbx_upper_limit_of_db_size", l_upper_limit_of_db_size);
-    l_upper_limit_of_db_size  *= 1024*1024*1024ULL;
-    log_it(L_INFO, "Set MDBX Upper Limit of DB Size to %zu octets", l_upper_limit_of_db_size);
-
-    snprintf(s_db_path, sizeof(s_db_path), "%s/%s", a_mdbx_path, s_subdir );/* Make a path to MDBX root */
-    dap_mkdir_with_parents(s_db_path);                                      /* Create directory for the MDBX storage */
-
-    log_it(L_NOTICE, "Directory '%s' will be used as an location for MDBX database files", s_db_path);
-    s_mdbx_env = NULL;
-    if ( MDBX_SUCCESS != (l_rc = mdbx_env_create(&s_mdbx_env)) )
-        return  log_it(L_CRITICAL, "mdbx_env_create: (%d) %s", l_rc, mdbx_strerror(l_rc)), -ENOENT;
-
-#if 0
-    if ( g_dap_global_db_debug_more )
-        mdbx_setup_debug	(	MDBX_LOG_VERBOSE, 0, 0);
-#endif
-
-
-    log_it(L_NOTICE, "Set maximum number of local groups: %lu", DAP_GLOBAL_DB_GROUPS_COUNT_MAX);
-    dap_assert ( !(l_rc =  mdbx_env_set_maxdbs (s_mdbx_env, DAP_GLOBAL_DB_GROUPS_COUNT_MAX)) );/* Set maximum number of the file-tables (MDBX subDB)
-                                                                              according to number of supported groups */
-
-
-                                                                            /* We set "unlim" for all MDBX characteristics at the moment */
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_env_set_geometry(s_mdbx_env, -1, -1, l_upper_limit_of_db_size, -1, -1, -1)) )
-        return  log_it (L_CRITICAL, "mdbx_env_set_geometry (%s): (%d) %s", s_db_path, l_rc, mdbx_strerror(l_rc)),  -EINVAL;
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_env_open(s_mdbx_env, s_db_path, MDBX_CREATE |  MDBX_COALESCE | MDBX_LIFORECLAIM, 0664)) )
-        return  log_it (L_CRITICAL, "mdbx_env_open (%s): (%d) %s", s_db_path, l_rc, mdbx_strerror(l_rc)),  -EINVAL;
-
-    /*
-     * Since MDBX don't maintain a list of subDB with public API, we will use a "MASTER Table",
-     * be advised that this MASTER teble is not maintained accurately!!!
-     *
-     * So, Create (If)/Open a master DB (table) to keep  list of subDBs (group/table/subDB name)
-    */
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, 0, &l_txn)) )
-        return  log_it(L_CRITICAL, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), -EIO;
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_dbi_open(l_txn, s_db_master_tbl, MDBX_CREATE, &s_db_master_dbi)) )
-        return  log_it(L_CRITICAL, "mdbx_dbi_open: (%d) %s", l_rc, mdbx_strerror(l_rc)), -EIO;
-
-    dap_assert ( MDBX_SUCCESS == (l_rc = mdbx_txn_commit (l_txn)) );
-
-    /*
-     * Run over records in the  MASTER table to get subDB names
-     */
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &l_txn)) )
-        log_it(L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc));
-    else if ( MDBX_SUCCESS != (l_rc = mdbx_cursor_open(l_txn, s_db_master_dbi, &l_cursor)) )
-        log_it(L_ERROR, "mdbx_cursor_open: (%d) %s", l_rc, mdbx_strerror(l_rc));
-    else{
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "--- List of stored groups ---");
-
-        for ( int i = 0;  !(l_rc = mdbx_cursor_get (l_cursor, &l_key_iov, &l_data_iov, MDBX_NEXT )); i++ )
-            {
-            debug_if(g_dap_global_db_debug_more, L_DEBUG, "MDBX SubDB #%03d [0:%zu]: '%.*s' = [0:%zu]: '%.*s'", i,
-                    l_key_iov.iov_len, (int) l_key_iov.iov_len, (char *) l_key_iov.iov_base,
-                    l_data_iov.iov_len, (int) l_data_iov.iov_len, (char *) l_data_iov.iov_base);
-
-            /* Form a simple list of the group/table name to be used after */
-            l_cp = dap_strdup(l_data_iov.iov_base);                         /* We expect an ASCIZ string as the table name */
-            l_data_iov.iov_len = strlen(l_cp);
-            dap_slist_add2tail(&l_slist, l_cp, l_data_iov.iov_len);
-            }
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "--- End-Of-List  ---");
-        }
-
-    dap_assert ( MDBX_SUCCESS == mdbx_txn_commit (l_txn) );
-
-
-    /* Run over the list and create/open group/tables and DB context ... */
-    while ( !dap_slist_get4head (&l_slist, &l_data_iov.iov_base, &l_data_iov.iov_len) )
-    {
-        s_cre_db_ctx_for_group(l_data_iov.iov_base, MDBX_CREATE);
-        DAP_DELETE(l_data_iov.iov_base);
-    }
-
-    /*
-    ** Fill the Driver Interface Table
-    */
-    a_drv_dpt->apply_store_obj     = s_db_mdbx_apply_store_obj;
-    a_drv_dpt->read_last_store_obj = s_db_mdbx_read_last_store_obj;
-
-    a_drv_dpt->read_store_obj      = s_db_mdbx_read_store_obj;
-    a_drv_dpt->read_cond_store_obj = s_db_mdbx_read_cond_store_obj;
-    a_drv_dpt->read_count_store    = s_db_mdbx_read_count_store;
-    a_drv_dpt->get_groups_by_mask  = s_db_mdbx_get_groups_by_mask;
-    a_drv_dpt->is_obj              = s_db_mdbx_is_obj;
-    a_drv_dpt->deinit              = s_db_mdbx_deinit;
-    a_drv_dpt->flush               = s_db_mdbx_flush;
-
-    /*
-     * MDBX support transactions but on the current circuimstance we will not get
-     * advantages of using DB Driver level BEGIN/END transactions
-     */
-    a_drv_dpt->transaction_start   = NULL;
-    a_drv_dpt->transaction_end     = NULL;
-
-    return MDBX_SUCCESS;
-}
-
-/*
- *  DESCRIPTION: Get a DB context for the specified group/table name
- *      from the DB context hash table. This context is just pointer to the DB Context
- *      structure, so don't modify it.
- *
- *  INPUTS:
- *      a_group:    Group/table name to be looked for DB context
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS
- *      address of DB Context
- *      NULL    - no DB context has been craeted for the group
- *
- */
-static  dap_db_ctx_t  *s_get_db_ctx_for_group(const char *a_group)
-{
-dap_db_ctx_t *l_db_ctx = NULL;
-
-    dap_assert ( !pthread_rwlock_rdlock(&s_db_ctxs_rwlock) );
-    HASH_FIND_STR(s_db_ctxs, a_group, l_db_ctx);
-    dap_assert ( !pthread_rwlock_unlock(&s_db_ctxs_rwlock) );
-
-    if ( !l_db_ctx )
-        debug_if(g_dap_global_db_debug_more, L_WARNING, "No DB context for the group '%s'", a_group);
-
-    return l_db_ctx;
-}
-
-/*
- *  DESCRIPTION: Action routine - perform flushing action. Actualy MDBX internaly maintain processes of the flushing
- *      and other things related to  data integrity.
- *
- *  INPUTS:
- *      NONE
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS:
- *      0 - SUCCESS
- */
-static  int s_db_mdbx_flush(void)
-{
-    return  log_it(L_DEBUG, "Flushing resident part of the MDBX to disk"), 0;
-}
-
-/*
- *  DESCRIPTION: Action routine - lookup in the group/table a last stored record (with the bigest Id).
- *      We mainatain internaly <id> of record (it's just sequence),
- *      so actualy we need to performs a full scan of the table to reach a record with the bigest <id>.
- *      In case of success create and return <store_object> for the has been found records.
- *
- *  INPUTS:
- *      a_group:    A group/table name to be scanned
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS:
- *      An address to the <store object> with the record
- *      NULL - table is empty
- */
-dap_store_obj_t *s_db_mdbx_read_last_store_obj(const char* a_group)
-{
-int l_rc;
-dap_db_ctx_t *l_db_ctx;
-MDBX_val    l_key={0}, l_data={0}, l_last_data={0}, l_last_key={0};
-MDBX_cursor *l_cursor = NULL;
-struct  __record_suffix__   *l_suff;
-uint64_t    l_id;
-dap_store_obj_t *l_obj;
-
-    if (!a_group)                                                           /* Sanity check */
-        return NULL;
-
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_group)) )                    /* Get DB Context for group/table */
-        return NULL;
-
-    dap_assert ( !pthread_mutex_lock(&l_db_ctx->dbi_mutex) );
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &l_db_ctx->txn)) )
-    {
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-        return  log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-    }
-
-    do {
-        l_cursor = NULL;
-        l_id  = 0;
-        l_last_key = l_last_data = (MDBX_val) {0, 0};
-
-        if ( MDBX_SUCCESS != (l_rc = mdbx_cursor_open(l_db_ctx->txn, l_db_ctx->dbi, &l_cursor)) ) {
-          log_it (L_ERROR, "mdbx_cursor_open: (%d) %s", l_rc, mdbx_strerror(l_rc));
-          break;
-        }
-
-        /* Iterate cursor to retrieve records from DB - select a <key> and <data> pair
-        ** with maximal <id>
-        */
-        while ( MDBX_SUCCESS == (l_rc = mdbx_cursor_get(l_cursor, &l_key, &l_data, MDBX_NEXT)) )
-        {
-            l_suff = (struct __record_suffix__ *) (l_data.iov_base + l_data.iov_len - sizeof(struct __record_suffix__));
-            if ( l_id < l_suff->id )
-            {
-                l_id = l_suff->id;
-                l_last_key = l_key;                                         /* <l_last_key> point to real key area in the MDBX DB */
-                l_last_data = l_data;                                       /* <l_last_data> point to real data area in the MDBX DB */
-            }
-        }
-
-    } while (0);
-
-    if (l_cursor)                                                           /* Release uncesessary MDBX cursor area,
-                                                                              but keep transaction !!! */
-        mdbx_cursor_close(l_cursor);
-
-
-
-
-
-    if ( !(l_last_key.iov_len || l_data.iov_len) )                          /* Not found anything  - return NULL */
-    {
-        mdbx_txn_commit(l_db_ctx->txn);
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-        return  NULL;
-    }
-
-    /* Found ! Allocate memory for  <store object>  and <value> */
-    if ( (l_obj = DAP_CALLOC(1, sizeof( dap_store_obj_t ))) )
-    {
-
-        if ( !(l_obj->key = DAP_CALLOC(1, l_last_key.iov_len + 1)) )
-            l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object key, errno=%d", errno);
-        else if ( (l_obj->value = DAP_CALLOC(1, (l_data.iov_len + 1)  - sizeof(struct __record_suffix__))) )
-            {
-
-            /* Fill the <store obj> by data from the retrieved record */
-            l_obj->key_len = l_key.iov_len;
-            memcpy((char *) l_obj->key, l_key.iov_base, l_obj->key_len);
-
-            l_obj->value_len = l_data.iov_len - sizeof(struct __record_suffix__);
-            if(l_last_data.iov_base)
-                        memcpy(l_obj->value, l_last_data.iov_base, l_obj->value_len);
-
-            l_suff = (struct __record_suffix__ *) (l_data.iov_base + l_obj->value_len);
-            if(l_suff) {
-                l_obj->id = l_suff->id;
-                l_obj->timestamp = l_suff->ts;
-                l_obj->flags = l_suff->flags;
-            }
-            dap_assert ( (l_obj->group = dap_strdup(a_group)) );
-        }
-        else l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object value, errno=%d", errno);
-    }
-    else l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object, errno=%d", errno);
-
-    mdbx_txn_commit(l_db_ctx->txn);
-    dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-    return  l_obj;
-}
-
-/*
- *  DESCRIPTION: An action routine to check a presence specified key in the group/table
- *
- *  INPUTS:
- *      a_group:    A group/table to looking in
- *      a_key:      A key of record to looked for
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS
- *      1   -   SUCCESS, record is exist
- *      0   - Record-No-Found
- */
-bool     s_db_mdbx_is_obj(const char *a_group, const char *a_key)
-{
-int l_rc, l_rc2;
-dap_db_ctx_t *l_db_ctx;
-MDBX_val    l_key, l_data;
-
-    if (!a_group || !a_key)                                                           /* Sanity check */
-        return 0;
-
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_group)) )                    /* Get DB Context for group/table */
-        return 0;
-
-    dap_assert ( !pthread_mutex_lock(&l_db_ctx->dbi_mutex) );
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &l_db_ctx->txn)) )
-    {
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-        return  log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), 0;
-    }
-
-    l_key.iov_base = (void *) a_key;                                        /* Fill IOV for MDBX key */
-    l_key.iov_len =  strlen(a_key);
-
-    l_rc = mdbx_get(l_db_ctx->txn, l_db_ctx->dbi, &l_key, &l_data);
-
-    if ( MDBX_SUCCESS != (l_rc2 = mdbx_txn_commit(l_db_ctx->txn)) )
-        log_it (L_ERROR, "mdbx_txn_commit: (%d) %s", l_rc2, mdbx_strerror(l_rc2));
-
-    dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-    return ( l_rc == MDBX_SUCCESS );    /*0 - RNF, 1 - SUCCESS */
-}
-
-/*
- *  DESCRIPTION: Action routine to read record with a give <id > from the table
- *
- *  INPUTS:
- *      a_group:    A group/table name to be looked in
- *      a_id:       An id of record to be looked for
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS:
- *      An address to the <store object> with the record
- *      NULL - table is empty
- */
-
-
-int     s_make_store_obj (const char    *a_group,
-                            MDBX_val    *a_key,
-                            MDBX_val    *a_data,
-                    dap_store_obj_t     **a_obj
-                            )
-{
-dap_store_obj_t *l_obj;
-size_t  len;
-int     rc;
-struct  __record_suffix__   *l_suff;
-
-    len = dap_strlen(a_group);
-    rc = -1;                                                                /* ERROR */
-
-    if ( (l_obj = DAP_CALLOC(1, sizeof(dap_store_obj_t))) )
-        if ( (l_obj->value = DAP_CALLOC(1, (a_data->iov_len + 1)  - sizeof(struct __record_suffix__))) )
-            if ( (l_obj->key = DAP_CALLOC(1, a_key->iov_len + 1)) )
-                if ( (l_obj->group = DAP_CALLOC(1, len + 1)) )
-                {
-                    /* Fill the <store obj> by data from the retrieved record */
-                    l_obj->key_len = a_key->iov_len;
-                    memcpy((char *) l_obj->key, a_key->iov_base, l_obj->key_len);
-
-                    l_obj->value_len = a_data->iov_len - sizeof(struct __record_suffix__);
-                    memcpy(l_obj->value, a_data->iov_base, l_obj->value_len);
-
-                    l_obj->group_len = len;
-                    memcpy(l_obj->group, a_group, l_obj->group_len);
-
-                    l_suff = (struct __record_suffix__ *) (a_data->iov_base + l_obj->value_len);
-                    l_obj->id = l_suff->id;
-                    l_obj->timestamp = l_suff->ts;
-                    l_obj->flags = l_suff->flags;
-
-                    rc = 0;                                                 /* SUCCESS */
-                }
-                else    log_it (L_ERROR, "Cannot allocate a memory for store object group, errno=%d", errno);
-            else    log_it (L_ERROR, "Cannot allocate a memory for store object key, errno=%d", errno);
-        else    log_it (L_ERROR, "Cannot allocate a memory for store object value, errno=%d", errno);
-    else    log_it (L_ERROR, "Cannot allocate a memory for store object, errno=%d", errno);
-
-
-    if ( rc && l_obj )                                                      /* Check final status and do cleanup on error */
-    {
-        DAP_DEL_Z(l_obj->group);
-        DAP_DEL_Z(l_obj->key);
-        DAP_DEL_Z(l_obj->value);
-        DAP_DEL_Z(l_obj);
-    }
-
-    *a_obj = l_obj;
-
-    return  rc;
-}
-
-
-
-static dap_store_obj_t  *s_db_mdbx_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out)
-{
-int l_rc = 0;
-dap_db_ctx_t *l_db_ctx = NULL;
-MDBX_val    l_key = {0}, l_data = {0};
-MDBX_cursor *l_cursor;
-struct  __record_suffix__   *l_suff = NULL;
-dap_store_obj_t *l_obj = NULL, *l_obj_arr = NULL;
-size_t  l_cnt = 0, l_count_out = 0;
-
-    if (!a_group)                                                           /* Sanity check */
-        return NULL;
-
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_group)) )                    /* Get DB Context for group/table */
-        return NULL;
-
-    dap_assert ( !pthread_mutex_lock(&l_db_ctx->dbi_mutex));
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &l_db_ctx->txn)) )
-    {
-        dap_assert( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-        return  log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-    }
-
-
-    /* Limit a number of objects to be returned */
-    l_count_out = (a_count_out && *a_count_out) ? *a_count_out : DAP_GLOBAL_DB_MAX_OBJS;
-    l_count_out = MIN(l_count_out, DAP_GLOBAL_DB_MAX_OBJS);
-
-    l_cursor = NULL;
-    l_obj = l_obj_arr = NULL;
-
-
-    do  {
-        /* Initialize MDBX cursor context area */
-        if ( MDBX_SUCCESS != (l_rc = mdbx_cursor_open(l_db_ctx->txn, l_db_ctx->dbi, &l_cursor)) ) {
-          log_it (L_ERROR, "mdbx_cursor_open: (%d) %s", l_rc, mdbx_strerror(l_rc));
-          break;
-        }
-
-
-        /* Iterate cursor to retrieve records from DB */
-        l_cnt = 0;
-        if(a_count_out)
-            *a_count_out = l_cnt;
-        for (int i = l_count_out; i && (MDBX_SUCCESS == (l_rc = mdbx_cursor_get(l_cursor, &l_key, &l_data, MDBX_NEXT))); i--)
-        {
-            l_suff = (struct __record_suffix__ *) (l_data.iov_base + l_data.iov_len - sizeof(struct __record_suffix__));
-            if ( l_suff->id < a_id )
-                continue;
-
-            /*
-             * Expand a memory for new <store object> structure
-             */
-            if ( !(l_obj = DAP_REALLOC(l_obj_arr, (1 + l_cnt) * sizeof(dap_store_obj_t))) )
-            {
-                log_it(L_ERROR, "Cannot expand area to keep %zu <store objects>", l_cnt);
-                break;
-            }
-
-            l_cnt++;
-
-            l_obj_arr = l_obj;
-            l_obj = l_obj_arr + (l_cnt - 1);                                /* Point <l_obj> to last array's element */
-            memset(l_obj, 0, sizeof(dap_store_obj_t));
-
-            if ( !(l_obj->key = DAP_CALLOC(1, l_key.iov_len + 1)) )
-                l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object key, errno=%d", errno);
-
-            else if ( (l_obj->value = DAP_CALLOC(1, (l_data.iov_len + 1)  - sizeof(struct __record_suffix__))) )
-            {
-                /* Fill the <store obj> by data from the retreived record */
-                l_obj->key_len = l_key.iov_len;
-                memcpy((char *) l_obj->key, l_key.iov_base, l_obj->key_len);
-
-                l_obj->value_len = l_data.iov_len - sizeof(struct __record_suffix__);
-                memcpy(l_obj->value, l_data.iov_base, l_obj->value_len);
-
-                l_obj->id = l_suff->id;
-                l_obj->timestamp = l_suff->ts;
-                l_obj->flags = l_suff->flags;
-
-                dap_assert ( (l_obj->group = dap_strdup(a_group)) );
-                l_obj->group_len = strlen(l_obj->group);
-            }
-            else l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object value, errno=%d", errno);
-        }
-
-
-        if ( (MDBX_SUCCESS != l_rc) && (l_rc != MDBX_NOTFOUND) ) {
-          log_it (L_ERROR, "mdbx_cursor_get: (%d) %s", l_rc, mdbx_strerror(l_rc)), l_rc = MDBX_SUCCESS;
-          break;
-        }
-
-    } while (0);
-
-    if (l_cursor)
-        mdbx_cursor_close(l_cursor);
-
-    mdbx_txn_commit(l_db_ctx->txn);
-    dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-    if(a_count_out)
-        *a_count_out = l_cnt;
-    return l_obj_arr;
-}
-
-/*
- *  DESCRIPTION: Action routine to retrieve a number of records for specified record's id.
- *
- *  INPUTS:
- *      a_group:    A table/group name to be scanned
- *      a_id:       An id of record to be looked for
- *
- *  RETURNS:
- *      count of has been found record
- */
-size_t  s_db_mdbx_read_count_store(const char *a_group, uint64_t a_id)
-{
-int l_rc, l_count_out;
-dap_db_ctx_t *l_db_ctx;
-MDBX_val    l_key, l_data;
-MDBX_cursor *l_cursor;
-struct  __record_suffix__   *l_suff;
-MDBX_stat   l_stat;
-
-    if (!a_group)                                                           /* Sanity check */
-        return 0;
-
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_group)) )                    /* Get DB Context for group/table */
-        return 0;
-
-    dap_assert ( !pthread_mutex_lock(&l_db_ctx->dbi_mutex) );
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &l_db_ctx->txn)) )
-    {
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-        return  log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), 0;
-    }
-
-    if ( a_id <= 1 )                                                        /* Retrieve a total number of records in the table */
-    {
-        if ( MDBX_SUCCESS != (l_rc = mdbx_dbi_stat	(l_db_ctx->txn, l_db_ctx->dbi, &l_stat, sizeof(MDBX_stat))) )
-            log_it (L_ERROR, "mdbx_dbi_stat: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-        mdbx_txn_commit(l_db_ctx->txn);
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-        return  ( l_rc == MDBX_SUCCESS ) ? l_stat.ms_entries : 0;
-    }
-
-
-
-
-    /*
-     * Count a number of records with id = a_id, a_id+1 ...
-     */
-    l_cursor = NULL;
-    l_count_out = 0;
-
-    do {
-
-        if ( MDBX_SUCCESS != (l_rc = mdbx_cursor_open(l_db_ctx->txn, l_db_ctx->dbi, &l_cursor)) ) {
-            log_it (L_ERROR, "mdbx_cursor_open: (%d) %s", l_rc, mdbx_strerror(l_rc));
-            break;
-        }
-
-                                                                            /* Iterate cursor to retrieve records from DB */
-        while ( MDBX_SUCCESS == (l_rc = mdbx_cursor_get(l_cursor, &l_key, &l_data, MDBX_NEXT)) ) {
-            l_suff = (struct __record_suffix__ *) (l_data.iov_base + l_data.iov_len - sizeof(struct __record_suffix__));
-            l_count_out += (l_suff->id >= a_id );
-        }
-
-    } while (0);
-
-    if (l_cursor)
-        mdbx_cursor_close(l_cursor);
-
-    mdbx_txn_commit(l_db_ctx->txn);
-    dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-    return  l_count_out;
-}
-
-/*
- *  DESCRIPTION: Action routine - returns a list of group/table names in DB contexts hash table is matched
- *      to specified pattern.
- *
- *  INPUTS:
- *      a_group_mask:   A pattern string
- *
- *  OUTPUTS:
- *      NONE
- *
- *  RETURNS:
- *      list of has been found groups
- */
-
-static dap_list_t  *s_db_mdbx_get_groups_by_mask(const char *a_group_mask)
-{
-dap_list_t *l_ret_list;
-dap_db_ctx_t *l_db_ctx, *l_db_ctx2;
-
-    if(!a_group_mask)
-        return NULL;
-
-    l_ret_list = NULL;
-
-    dap_assert ( !pthread_rwlock_rdlock(&s_db_ctxs_rwlock) );
-
-    HASH_ITER(hh, s_db_ctxs, l_db_ctx, l_db_ctx2) {
-        if (!dap_fnmatch(a_group_mask, l_db_ctx->name, 0) )                 /* Name match a pattern/mask ? */
-            l_ret_list = dap_list_prepend(l_ret_list, dap_strdup(l_db_ctx->name)); /* Add group name to output list */
-    }
-
-    dap_assert ( !pthread_rwlock_unlock(&s_db_ctxs_rwlock) );
-
-    return l_ret_list;
-}
-
-
-/*
- *  DESCRIPTION:  Action routine - insert/delete a record with data from the <store_object>  to/from database.
- *      Be advised that we performs a transaction processing to ensure DB consistency
- *
- *  INPUTS:
- *      a_store_obj:    An object with data to be stored
- *
- *  OUTPUTS:
- *      NONE:
- *
- *  RETURNS:
- *      0   - SUCCESS
- *      0>  - <errno>
- */
-static  int s_db_mdbx_apply_store_obj (dap_store_obj_t *a_store_obj)
-{
-int     l_rc = 0, l_rc2;
-dap_db_ctx_t *l_db_ctx;
-MDBX_val    l_key, l_data;
-char    *l_val;
-struct  __record_suffix__   *l_suff;
-
-    if ( !a_store_obj || !a_store_obj->group)                               /* Sanity checks ... */
-        return -EINVAL;
-
-
-
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_store_obj->group)) ) {       /* Get a DB context for the group */
-                                                                            /* Group is not found ? Try to create table for new group */
-        if ( !(l_db_ctx = s_cre_db_ctx_for_group(a_store_obj->group, MDBX_CREATE)) )
-            return  log_it(L_WARNING, "Cannot create DB context for the group '%s'", a_store_obj->group), -EIO;
-
-        log_it(L_NOTICE, "DB context for the group '%s' has been created", a_store_obj->group);
-
-        if ( a_store_obj->type == DAP_DB$K_OPTYPE_DEL )                     /* Nothing to do anymore */
-            return  0;
-    }
-
-
-    /* At this point we have got the DB Context for the table/group
-     * so we are can performs a main work
-     */
-
-    dap_assert ( !pthread_mutex_lock(&l_db_ctx->dbi_mutex) );
-
-
-    if (a_store_obj->type == DAP_DB$K_OPTYPE_ADD ) {
-        if( !a_store_obj->key )
-        {
-            dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-            return -ENOENT;
-        }
-
-        l_key.iov_base = (void *) a_store_obj->key;                         /* Fill IOV for MDBX key */
-        l_key.iov_len =  a_store_obj->key_len ? a_store_obj->key_len : strnlen(a_store_obj->key, DAP_GLOBAL_DB_KEY_MAX);
-
-        /*
-         * Now we are ready  to form a record in next format:
-         * <value> + <suffix>
-         */
-        l_rc = a_store_obj->value_len + sizeof(struct  __record_suffix__); /* Compute a length of the area to keep value+suffix */
-
-        if ( !(l_val = DAP_NEW_Z_SIZE(char, l_rc)) )
-        {
-            dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-            return  log_it(L_ERROR, "Cannot allocate memory for new records, %d octets, errno=%d", l_rc, errno), -errno;
-        }
-
-        l_data.iov_base = l_val;                                            /* Fill IOV for MDBX data */
-        l_data.iov_len = l_rc;
-
-        /*
-         * Fill suffix's fields
-        */
-        l_suff = (struct __record_suffix__ *) (l_val + a_store_obj->value_len);
-        l_suff->flags = a_store_obj->flags;
-        l_suff->ts = a_store_obj->timestamp;
-
-        memcpy(l_val, a_store_obj->value, a_store_obj->value_len);          /* Put <value> into the record */
-
-        /* So, finaly: BEGIN transaction, do INSERT, COMMIT or ABORT ... */
-        if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, 0, &l_db_ctx->txn)) )
-        {
-            dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-            return  DAP_FREE(l_val), log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), -EIO;
-        }
-
-
-                                                                            /* Generate <sequence number> for new record */
-        if ( MDBX_SUCCESS != mdbx_dbi_sequence	(l_db_ctx->txn, l_db_ctx->dbi, &l_suff->id, 1) )
-        {
-            log_it (L_CRITICAL, "mdbx_dbi_sequence: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-            if ( MDBX_SUCCESS != (l_rc = mdbx_txn_abort(l_db_ctx->txn)) )
-                log_it (L_ERROR, "mdbx_txn_abort: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-            mdbx_txn_abort(l_db_ctx->txn);
-            dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-            return  DAP_FREE(l_val), -EIO;
-        }
-
-
-
-        if ( MDBX_SUCCESS != (l_rc = mdbx_put(l_db_ctx->txn, l_db_ctx->dbi, &l_key, &l_data, 0)) )
-        {
-            log_it (L_ERROR, "mdbx_put: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-            if ( MDBX_SUCCESS != (l_rc2 = mdbx_txn_abort(l_db_ctx->txn)) )
-                log_it (L_ERROR, "mdbx_txn_abort: (%d) %s", l_rc2, mdbx_strerror(l_rc2));
-        }
-        else if ( MDBX_SUCCESS != (l_rc = mdbx_txn_commit(l_db_ctx->txn)) )
-            log_it (L_ERROR, "mdbx_txn_commit: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-        return DAP_FREE(l_val), (( l_rc == MDBX_SUCCESS ) ? 0 : -EIO);
-    } /* DAP_DB$K_OPTYPE_ADD */
-
-
-
-    if (a_store_obj->type == DAP_DB$K_OPTYPE_DEL)  {
-        if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, 0, &l_db_ctx->txn)) )
-        {
-            dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-            return  log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), -ENOENT;
-        }
-
-        l_rc2 = 0;
-
-        if ( a_store_obj->key ) {                                           /* Delete record */
-                l_key.iov_base = (void *) a_store_obj->key;
-                l_key.iov_len =  a_store_obj->key_len ? a_store_obj->key_len : strnlen(a_store_obj->key, DAP_GLOBAL_DB_KEY_MAX);
-
-                if ( MDBX_SUCCESS != (l_rc = mdbx_del(l_db_ctx->txn, l_db_ctx->dbi, &l_key, NULL))
-                     && ( l_rc != MDBX_NOTFOUND) )
-                    l_rc2 = -EIO, log_it (L_ERROR, "mdbx_del: (%d) %s", l_rc, mdbx_strerror(l_rc));
-            }
-        else {                                                              /* Truncate only  table */
-                if ( MDBX_SUCCESS != (l_rc = mdbx_drop(l_db_ctx->txn, l_db_ctx->dbi, 0))
-                     && ( l_rc != MDBX_NOTFOUND) )
-                    l_rc2 = -EIO, log_it (L_ERROR, "mdbx_drop: (%d) %s", l_rc, mdbx_strerror(l_rc));
-            }
-
-
-        l_rc = (l_rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : l_rc;               /* Not found ?! It's Okay !!! */
-
-
-
-        if ( l_rc != MDBX_SUCCESS ) {                                       /* Check result of mdbx_drop/del */
-            if ( MDBX_SUCCESS != (l_rc = mdbx_txn_abort(l_db_ctx->txn)) )
-                l_rc2 = -EIO, log_it (L_ERROR, "mdbx_txn_abort: (%d) %s", l_rc, mdbx_strerror(l_rc));
-        }
-        else if ( MDBX_SUCCESS != (l_rc = mdbx_txn_commit(l_db_ctx->txn)) )
-            l_rc2 = -EIO, log_it (L_ERROR, "mdbx_txn_commit: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-        return ( l_rc2 == MDBX_SUCCESS ) ? 0 : -EIO;
-    } /* DAP_DB$K_OPTYPE_DEL */
-
-
-    dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-    log_it (L_ERROR, "Unhandle/unknown DB opcode (%d/%#x)", a_store_obj->type, a_store_obj->type);
-
-    return  -EIO;
-}
-
-
-
-
-
-
-
-
-/*
- *  DESCRIPTION: Action routine - retrieve from specified group/table a record with the given key,
- *      theoreticaly we can return a set of records - but actualy we don't allow dupplicates in the DB,
- *      so count of records is always == 1.
- *
- *  INPUTS:
- *      a_group:    A group/table name to lokkind in
- *      a_key:      A key's record to looked for
- *
- *  OUTPUTS:
- *      a_count_out
- *
- *  RETURNS
- *      Array of store objects
- */
-
-static dap_store_obj_t *s_db_mdbx_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out)
-{
-int l_rc, l_rc2;
-uint64_t l_count_out;
-dap_db_ctx_t *l_db_ctx;
-dap_store_obj_t *l_obj, *l_obj_arr;
-MDBX_val    l_key, l_data;
-MDBX_cursor *l_cursor;
-MDBX_stat   l_stat;
-struct  __record_suffix__   *l_suff;
-
-
-    if (!a_group)                                                           /* Sanity check */
-        return NULL;
-
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_group)) )                    /* Get DB Context for group/table */
-        return NULL;
-
-
-    dap_assert ( !pthread_mutex_lock(&l_db_ctx->dbi_mutex) );
-
-    if ( MDBX_SUCCESS != (l_rc = mdbx_txn_begin(s_mdbx_env, NULL, MDBX_TXN_RDONLY, &l_db_ctx->txn)) )
-    {
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-        return  log_it (L_ERROR, "mdbx_txn_begin: (%d) %s", l_rc, mdbx_strerror(l_rc)), NULL;
-    }
-
-
-    if ( a_count_out )
-        *a_count_out = 0;
-
-    /*
-     *  Perfroms a find/get a record with the given key
-     */
-    if ( a_key )
-    {
-        l_key.iov_base = (void *) a_key;                                    /* Fill IOV for MDBX key */
-        l_key.iov_len =  strlen(a_key);
-        l_obj = NULL;
-
-        if ( MDBX_SUCCESS == (l_rc = mdbx_get(l_db_ctx->txn, l_db_ctx->dbi, &l_key, &l_data)) )
-        {
-            /* Found ! Make new <store_obj> */
-            if ( !s_make_store_obj (a_group, &l_key, &l_data, &l_obj) )
-            {
-                if ( a_count_out )
-                    *a_count_out = 1;
-            }
-        } else if ( l_rc != MDBX_NOTFOUND )
-            log_it (L_ERROR, "mdbx_get: (%d) %s", l_rc, mdbx_strerror(l_rc));
-
-
-        mdbx_txn_commit(l_db_ctx->txn);
-        dap_assert ( !pthread_mutex_unlock(&l_db_ctx->dbi_mutex) );
-
-        return ( l_rc == MDBX_SUCCESS ) ? l_obj : NULL;
-    }
-
-
-    /*
-    ** If a_key is NULL - retrieve a requested number of records from the table
-    */
-    do  {
-        l_count_out = (a_count_out && *a_count_out)? *a_count_out : DAP_GLOBAL_DB_MAX_OBJS;/* Limit a number of objects to be returned */
-        l_cursor = NULL;
-        l_obj = l_obj_arr = NULL;
-
-        /*
-         * Retrieve statistic for group/table, we need to compute a number of records can be retreived
-         */
-        l_rc2 = 0;
-        if ( MDBX_SUCCESS != (l_rc = mdbx_dbi_stat	(l_db_ctx->txn, l_db_ctx->dbi, &l_stat, sizeof(MDBX_stat))) ) {
-            log_it (L_ERROR, "mdbx_dbi_stat: (%d) %s", l_rc2, mdbx_strerror(l_rc2));
-            break;
-        }
-        else if ( !l_stat.ms_entries )                                      /* Nothing to retrieve , table contains no record */
-            break;
-
-        if ( !(  l_count_out = min(l_stat.ms_entries, l_count_out)) ) {
-            debug_if(g_dap_global_db_debug_more, L_WARNING, "No object (-s) to be retrieved from the group '%s'", a_group);
-            break;
-        }
-
-        /*
-         * Allocate memory for array[l_count_out] of returned objects
-        */
-        l_rc2 = l_count_out * sizeof(dap_store_obj_t);
-        if ( !(l_obj_arr = (dap_store_obj_t *) DAP_NEW_Z_SIZE(char, l_rc2)) ) {
-            log_it(L_ERROR, "Cannot allocate %zu octets for %"DAP_UINT64_FORMAT_U" store objects", l_count_out * sizeof(dap_store_obj_t), l_count_out);
-            break;
-        }
-
-                                                                            /* Initialize MDBX cursor context area */
-        if ( MDBX_SUCCESS != (l_rc = mdbx_cursor_open(l_db_ctx->txn, l_db_ctx->dbi, &l_cursor)) ) {
-          log_it (L_ERROR, "mdbx_cursor_open: (%d) %s", l_rc, mdbx_strerror(l_rc));
-          break;
-        }
-
-
-                                                                            /* Iterate cursor to retrieve records from DB */
-        l_obj = l_obj_arr;
-        for (int i = l_count_out;
-             i && (MDBX_SUCCESS == (l_rc = mdbx_cursor_get(l_cursor, &l_key, &l_data, MDBX_NEXT))); i--,  l_obj++)
-        {
-            if ( !(l_obj->key = DAP_CALLOC(1, l_key.iov_len + 1)) )
-                l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object key, errno=%d", errno);
-
-            else if ( (l_obj->value = DAP_CALLOC(1, (l_data.iov_len + 1)  - sizeof(struct __record_suffix__))) )
-                {
-                /* Fill the <store obj> by data from the retreived record */
-                l_obj->key_len = l_key.iov_len + 1;
-                memcpy((char *) l_obj->key, l_key.iov_base, l_obj->key_len);
-
-                l_obj->value_len = l_data.iov_len - sizeof(struct __record_suffix__);
-                memcpy(l_obj->value, l_data.iov_base, l_obj->value_len);
-
-                l_suff = (struct __record_suffix__ *) (l_data.iov_base + l_obj->value_len);
-                l_obj->id = l_suff->id;
-                l_obj->timestamp = l_suff->ts;
-                l_obj->flags = l_suff->flags;
-
-                dap_assert ( (l_obj->group = dap_strdup(a_group)) );
-                l_obj->group_len = strlen(l_obj->group);
-
-                if ( a_count_out )
-                    *a_count_out += 1;
-                }
-            else l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object value, errno=%d", errno);
-        }
-
-
-        if ( (MDBX_SUCCESS != l_rc) && (l_rc != MDBX_NOTFOUND) ) {
-          log_it (L_ERROR, "mdbx_cursor_get: (%d) %s", l_rc, mdbx_strerror(l_rc)), l_rc = MDBX_SUCCESS;
-          break;
-        }
-
-    } while (0);
-
-
-    if (l_cursor)
-        mdbx_cursor_close(l_cursor);
-
-    mdbx_txn_commit(l_db_ctx->txn);
-    pthread_mutex_unlock(&l_db_ctx->dbi_mutex);
-
-    return l_obj_arr;
-}
diff --git a/modules/global-db/dap_chain_global_db_driver_pgsql.c b/modules/global-db/dap_chain_global_db_driver_pgsql.c
deleted file mode 100644
index b3e8dbfde60d67f9648ae5dce4c52ff24ec28ea2..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_chain_global_db_driver_pgsql.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * Authors:
- * Roman Khlopkov <roman.khlopkov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * CellFrame       https://cellframe.net
- * Sources         https://gitlab.demlabs.net/cellframe
- * Copyright  (c) 2017-2021
- * All rights reserved.
-
- This file is part of CellFrame SDK the open source project
-
-    CellFrame SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    CellFrame SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stddef.h>
-#include <string.h>
-#include <pthread.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "dap_chain_global_db_driver_pgsql.h"
-#include "dap_common.h"
-#include "dap_hash.h"
-#include "dap_file_utils.h"
-#include "dap_strfuncs.h"
-#include "dap_file_utils.h"
-
-#ifdef DAP_CHAIN_GDB_ENGINE_PGSQL
-#include <pwd.h>
-
-#define LOG_TAG "db_pgsql"
-
-struct dap_pgsql_conn_pool_item {
-    PGconn *conn;
-    int busy;
-};
-
-static PGconn *s_trans_conn = NULL;
-static struct dap_pgsql_conn_pool_item s_conn_pool[DAP_PGSQL_POOL_COUNT];
-static pthread_rwlock_t s_db_rwlock = PTHREAD_RWLOCK_INITIALIZER;
-
-static PGconn *s_pgsql_get_connection(void)
-{
-    if (pthread_rwlock_wrlock(&s_db_rwlock) == EDEADLK) {
-        return s_trans_conn;
-    }
-    PGconn *l_ret = NULL;
-    for (int i = 0; i < DAP_PGSQL_POOL_COUNT; i++) {
-        if (!s_conn_pool[i].busy) {
-            l_ret = s_conn_pool[i].conn;
-            s_conn_pool[i].busy = 1;
-            break;
-        }
-    }
-    pthread_rwlock_unlock(&s_db_rwlock);
-    return l_ret;
-}
-
-static void s_pgsql_free_connection(PGconn *a_conn)
-{
-    if (pthread_rwlock_wrlock(&s_db_rwlock) == EDEADLK) {
-        return;
-    }
-    for (int i = 0; i < DAP_PGSQL_POOL_COUNT; i++) {
-        if (s_conn_pool[i].conn == a_conn) {
-            s_conn_pool[i].busy = 0;
-			break;
-        }
-    }
-    pthread_rwlock_unlock(&s_db_rwlock);
-}
-
-/**
- * @brief Initializes a PostgreSQL database.
- * @param a_filename_dir a path to the database file
- * @param a_drv_callback a pointer to a structure of callback functions 
- * @return If successful returns 0, else a error code <0.
- */
-int dap_db_driver_pgsql_init(const char *a_filename_dir, dap_db_driver_callbacks_t *a_drv_callback)
-{
-    dap_hash_fast_t l_dir_hash;
-    dap_hash_fast(a_filename_dir, strlen(a_filename_dir), &l_dir_hash);
-    char l_db_name[DAP_PGSQL_DBHASHNAME_LEN + 1];
-    dap_htoa64(l_db_name, l_dir_hash.raw, DAP_PGSQL_DBHASHNAME_LEN);
-    l_db_name[DAP_PGSQL_DBHASHNAME_LEN] = '\0';
-    if (!dap_dir_test(a_filename_dir) || !readdir(opendir(a_filename_dir))) {
-        // Create PostgreSQL database
-        const char *l_base_conn_str = "dbname = postgres";
-        PGconn *l_base_conn = PQconnectdb(l_base_conn_str);
-        if (PQstatus(l_base_conn) != CONNECTION_OK) {
-            log_it(L_ERROR, "Can't init PostgreSQL database: \"%s\"", PQerrorMessage(l_base_conn));
-            PQfinish(l_base_conn);
-            return -2;
-        }
-        char *l_query_str = dap_strdup_printf("DROP DATABASE IF EXISTS \"%s\"", l_db_name);
-        PGresult *l_res = PQexec(l_base_conn, l_query_str);
-        DAP_DELETE(l_query_str);
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            log_it(L_ERROR, "Drop database failed: \"%s\"", PQresultErrorMessage(l_res));
-            PQclear(l_res);
-            PQfinish(l_base_conn);
-            return -3;
-        }
-        PQclear(l_res);
-        l_query_str = dap_strdup_printf("DROP TABLESPACE IF EXISTS \"%s\"", l_db_name);
-        l_res = PQexec(l_base_conn, l_query_str);
-        DAP_DELETE(l_query_str);
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            log_it(L_ERROR, "Drop tablespace failed with message: \"%s\"", PQresultErrorMessage(l_res));
-            PQclear(l_res);
-            PQfinish(l_base_conn);
-            return -4;
-        }
-        PQclear(l_res);
-        // Check paths and create them if nessesary
-        if (!dap_dir_test(a_filename_dir)) {
-            log_it(L_NOTICE, "No directory %s, trying to create...", a_filename_dir);
-            dap_mkdir_with_parents(a_filename_dir);
-            if (!dap_dir_test(a_filename_dir)) {
-                char l_errbuf[255];
-                l_errbuf[0] = '\0';
-                strerror_r(errno, l_errbuf, sizeof(l_errbuf));
-                log_it(L_ERROR, "Can't create directory, error code %d, error string \"%s\"", errno, l_errbuf);
-                return -1;
-            }
-            log_it(L_NOTICE,"Directory created");
-            chown(a_filename_dir, getpwnam("postgres")->pw_uid, -1);
-        }
-        l_query_str = dap_strdup_printf("CREATE TABLESPACE \"%s\" LOCATION '%s'", l_db_name, a_filename_dir);
-        l_res = PQexec(l_base_conn, l_query_str);
-        DAP_DELETE(l_query_str);
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            log_it(L_ERROR, "Create tablespace failed with message: \"%s\"", PQresultErrorMessage(l_res));
-            PQclear(l_res);
-            PQfinish(l_base_conn);
-            return -5;
-        }
-        chmod(a_filename_dir, S_IRWXU | S_IRWXG | S_IRWXO);
-        PQclear(l_res);
-        l_query_str = dap_strdup_printf("CREATE DATABASE \"%s\" WITH TABLESPACE \"%s\"", l_db_name, l_db_name);
-        l_res = PQexec(l_base_conn, l_query_str);
-        DAP_DELETE(l_query_str);
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            log_it(L_ERROR, "Create database failed with message: \"%s\"", PQresultErrorMessage(l_res));
-            PQclear(l_res);
-            PQfinish(l_base_conn);
-            return -6;
-        }
-        PQclear(l_res);
-        PQfinish(l_base_conn);
-    }
-    // Create connection pool for the DAP database
-    char *l_conn_str = dap_strdup_printf("dbname = %s", l_db_name);
-    for (int i = 0; i < DAP_PGSQL_POOL_COUNT; i++) {
-        s_conn_pool[i].conn = PQconnectdb(l_conn_str);
-        s_conn_pool[i].busy = 0;
-        if (PQstatus(s_conn_pool[i].conn) != CONNECTION_OK) {
-            log_it(L_ERROR, "Can't connect PostgreSQL database: \"%s\"", PQerrorMessage(s_conn_pool[i].conn));
-            DAP_DELETE(l_conn_str);
-            for (int j = 0; j <= i; j++)
-                PQfinish(s_conn_pool[j].conn);
-            return -7;
-        }
-    }
-    DAP_DELETE(l_conn_str);
-    pthread_rwlock_init(&s_db_rwlock, 0);
-    a_drv_callback->transaction_start = dap_db_driver_pgsql_start_transaction;
-    a_drv_callback->transaction_end = dap_db_driver_pgsql_end_transaction;
-    a_drv_callback->apply_store_obj = dap_db_driver_pgsql_apply_store_obj;
-    a_drv_callback->read_store_obj = dap_db_driver_pgsql_read_store_obj;
-    a_drv_callback->read_cond_store_obj = dap_db_driver_pgsql_read_cond_store_obj;
-    a_drv_callback->read_last_store_obj = dap_db_driver_pgsql_read_last_store_obj;
-    a_drv_callback->get_groups_by_mask  = dap_db_driver_pgsql_get_groups_by_mask;
-    a_drv_callback->read_count_store = dap_db_driver_pgsql_read_count_store;
-    a_drv_callback->is_obj = dap_db_driver_pgsql_is_obj;
-    a_drv_callback->deinit = dap_db_driver_pgsql_deinit;
-    a_drv_callback->flush = dap_db_driver_pgsql_flush;
-    return 0;
-}
-
-/**
- * @brief Deinitializes a PostgreSQL database.
- * 
- * @return Returns 0 if successful.
- */
-int dap_db_driver_pgsql_deinit(void)
-{
-    pthread_rwlock_wrlock(&s_db_rwlock);
-    for (int j = 0; j < DAP_PGSQL_POOL_COUNT; j++)
-        PQfinish(s_conn_pool[j].conn);
-    pthread_rwlock_unlock(&s_db_rwlock);
-    pthread_rwlock_destroy(&s_db_rwlock);
-    return 0;
-}
-
-/**
- * @brief Starts a transaction in a PostgreSQL database.
- * 
- * @return Returns 0 if successful, otherwise -1.
- */
-int dap_db_driver_pgsql_start_transaction(void)
-{
-    s_trans_conn = s_pgsql_get_connection();
-    if (!s_trans_conn)
-        return -1;
-    pthread_rwlock_wrlock(&s_db_rwlock);
-    PGresult *l_res = PQexec(s_trans_conn, "BEGIN");
-    if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-        log_it(L_ERROR, "Begin transaction failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        pthread_rwlock_unlock(&s_db_rwlock);
-        s_pgsql_free_connection(s_trans_conn);
-        s_trans_conn = NULL;
-    }
-    return 0;
-}
-
-/**
- * @brief Ends a transaction in a PostgreSQL database.
- * 
- * @return Returns 0 if successful, otherwise -1.
- */
-int dap_db_driver_pgsql_end_transaction(void)
-{
-    if (!s_trans_conn)
-        return -1;
-    PGresult *l_res = PQexec(s_trans_conn, "COMMIT");
-    if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-        log_it(L_ERROR, "End transaction failed with message: \"%s\"", PQresultErrorMessage(l_res));
-    }
-    pthread_rwlock_unlock(&s_db_rwlock);
-    s_pgsql_free_connection(s_trans_conn);
-    s_trans_conn = NULL;
-    return 0;
-}
-
-/**
- * @brief Creates a table in a PostgreSQL database.
- * 
- * @param a_table_name a table name string
- * @param a_conn a pointer to the connection object
- * @return Returns 0 if successful, otherwise -1.
- */
-static int s_pgsql_create_group_table(const char *a_table_name, PGconn *a_conn)
-{
-    if (!a_table_name)
-        return -1;
-    int l_ret = 0;
-    char *l_query_str = dap_strdup_printf("CREATE TABLE \"%s\""
-                                          "(obj_id BIGSERIAL PRIMARY KEY, obj_ts BIGINT, "
-                                          "obj_key TEXT UNIQUE, obj_val BYTEA)",
-                                          a_table_name);
-    PGresult *l_res = PQexec(a_conn, l_query_str);
-    DAP_DELETE(l_query_str);
-    if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-        log_it(L_ERROR, "Create table failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        l_ret = -3;
-    }
-    PQclear(l_res);
-    return l_ret;
-}
-
-/**
- * @brief Applies an object to a PostgreSQL database.
- * 
- * @param a_store_obj a pointer to the object structure
- * @return Returns 0 if successful, else a error code less than zero.
- */
-int dap_db_driver_pgsql_apply_store_obj(dap_store_obj_t *a_store_obj)
-{
-    if (!a_store_obj || !a_store_obj->group)
-        return -1;
-    char *l_query_str = NULL;
-    int l_ret = 0;
-    PGresult *l_res = NULL;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return -2;
-    }
-    if (a_store_obj->type == 'a') {
-        const char *l_param_vals[2];
-        time_t l_ts_to_store = htobe64(a_store_obj->timestamp);
-        l_param_vals[0] = (const char *)&l_ts_to_store;
-        l_param_vals[1] = (const char *)a_store_obj->value;
-        int l_param_lens[2] = {sizeof(time_t), a_store_obj->value_len};
-        int l_param_formats[2] = {1, 1};
-        l_query_str = dap_strdup_printf("INSERT INTO \"%s\" (obj_ts, obj_key, obj_val) VALUES ($1, '%s', $2) "
-                                        "ON CONFLICT (obj_key) DO UPDATE SET "
-                                        "obj_id = EXCLUDED.obj_id, obj_ts = EXCLUDED.obj_ts, obj_val = EXCLUDED.obj_val;",
-                                        a_store_obj->group,  a_store_obj->key);
-
-        // execute add request
-        l_res = PQexecParams(l_conn, l_query_str, 2, NULL, l_param_vals, l_param_lens, l_param_formats, 0);
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            if (s_trans_conn) { //we shouldn't fail within a transaacion
-                dap_db_driver_pgsql_end_transaction();
-                dap_db_driver_pgsql_start_transaction();
-                l_conn = s_pgsql_get_connection();
-            }
-            if (s_pgsql_create_group_table(a_store_obj->group, l_conn) == 0) {
-                PQclear(l_res);
-                l_res = PQexecParams(l_conn, l_query_str, 2, NULL, l_param_vals, l_param_lens, l_param_formats, 0);
-            }
-            if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-                log_it(L_ERROR, "Add object failed with message: \"%s\"", PQresultErrorMessage(l_res));
-                l_ret = -3;
-            }
-        }
-    } else if (a_store_obj->type == 'd') {
-        // delete one record
-        if (a_store_obj->key)
-            l_query_str = dap_strdup_printf("DELETE FROM \"%s\" WHERE obj_key = '%s'",
-                                            a_store_obj->group, a_store_obj->key);
-        // remove all group
-        else
-            l_query_str = dap_strdup_printf("DROP TABLE \"%s\"", a_store_obj->group);
-        // execute delete request
-        l_res = PQexec(l_conn, l_query_str);
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            const char *l_err = PQresultErrorField(l_res, PG_DIAG_SQLSTATE);
-            if (!l_err || strcmp(l_err, PGSQL_INVALID_TABLE)) {
-                log_it(L_ERROR, "Delete object failed with message: \"%s\"", PQresultErrorMessage(l_res));
-                l_ret = -4;
-            }
-        }
-    }
-    else {
-        log_it(L_ERROR, "Unknown store_obj type '0x%x'", a_store_obj->type);
-        s_pgsql_free_connection(l_conn);
-        return -5;
-    }
-    DAP_DELETE(l_query_str);
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    return l_ret;
-}
-
-/**
- * @brief Fills a object from a row
- * @param a_group a group name string
- * @param a_obj a pointer to the object
- * @param a_res a pointer to the result structure
- * @param a_row a row number
- * @return (none)
- */
-static void s_pgsql_fill_object(const char *a_group, dap_store_obj_t *a_obj, PGresult *a_res, int a_row)
-{
-    a_obj->group = dap_strdup(a_group);
-
-    for (int i = 0; i < PQnfields(a_res); i++) {
-        if (i == PQfnumber(a_res, "obj_id")) {
-            a_obj->id = be64toh(*(uint64_t *)PQgetvalue(a_res, a_row, i));
-        } else if (i == PQfnumber(a_res, "obj_ts")) {
-            a_obj->timestamp = be64toh(*(time_t *)PQgetvalue(a_res, a_row, i));
-        } else if ((i == PQfnumber(a_res, "obj_key"))) {
-            a_obj->key = dap_strdup(PQgetvalue(a_res, a_row, i));
-        } else if ((i == PQfnumber(a_res, "obj_val"))) {
-            a_obj->value_len = PQgetlength(a_res, a_row, i);
-            a_obj->value = DAP_DUP_SIZE(PQgetvalue(a_res, a_row, i), a_obj->value_len);
-        }
-    }
-}
-
-/**
- * @brief Reads some objects from a PostgreSQL database by a_group and a_key.
- * @param a_group a group name string
- * @param a_key an object key string, if equals NULL reads the whole group
- * @param a_count_out[in] a number of objects to be read, if equals 0 reads with no limits
- * @param a_count_out[out] a number of objects that were read
- * @return If successful, a pointer to an objects, otherwise a null pointer.
- */
-dap_store_obj_t *dap_db_driver_pgsql_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out)
-{
-    if (!a_group)
-        return NULL;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return NULL;
-    }
-    char *l_query_str;
-    if (a_key) {
-       l_query_str = dap_strdup_printf("SELECT * FROM \"%s\" WHERE obj_key = '%s'", a_group, a_key);
-    } else {
-        if (a_count_out && *a_count_out)
-            l_query_str = dap_strdup_printf("SELECT * FROM \"%s\" ORDER BY obj_id ASC LIMIT %d", a_group, *a_count_out);
-        else
-            l_query_str = dap_strdup_printf("SELECT * FROM \"%s\" ORDER BY obj_id ASC", a_group);
-    }
-
-    PGresult *l_res = PQexecParams(l_conn, l_query_str, 0, NULL, NULL, NULL, NULL, 1);
-    DAP_DELETE(l_query_str);
-    if (PQresultStatus(l_res) != PGRES_TUPLES_OK) {
-        const char *l_err = PQresultErrorField(l_res, PG_DIAG_SQLSTATE);
-        if (!l_err || strcmp(l_err, PGSQL_INVALID_TABLE))
-            log_it(L_ERROR, "Read objects failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        PQclear(l_res);
-        s_pgsql_free_connection(l_conn);
-        return NULL;
-    }
-
-    // parse reply
-    size_t l_count = PQntuples(l_res);
-    dap_store_obj_t *l_obj = l_count ? DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(dap_store_obj_t) * l_count) : NULL;
-    for (int i = 0; i < l_count; i++) {
-        // fill currrent item
-        dap_store_obj_t *l_obj_cur = l_obj + i;
-        s_pgsql_fill_object(a_group, l_obj_cur, l_res, i);
-    }
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    if (a_count_out)
-        *a_count_out = l_count;
-    return l_obj;
-}
-
-/**
- * @brief Reads a last object from a PostgreSQL database.
- * @param a_group a group name string
- * @return Returns a pointer to the object if successful, otherwise a null pointer.
- */
-dap_store_obj_t *dap_db_driver_pgsql_read_last_store_obj(const char *a_group)
-{
-    if (!a_group)
-        return NULL;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return NULL;
-    }
-    char *l_query_str = dap_strdup_printf("SELECT * FROM \"%s\" ORDER BY obj_id DESC LIMIT 1", a_group);
-    PGresult *l_res = PQexecParams(l_conn, l_query_str, 0, NULL, NULL, NULL, NULL, 1);
-    DAP_DELETE(l_query_str);
-    if (PQresultStatus(l_res) != PGRES_TUPLES_OK) {
-        const char *l_err = PQresultErrorField(l_res, PG_DIAG_SQLSTATE);
-        if (!l_err || strcmp(l_err, PGSQL_INVALID_TABLE))
-            log_it(L_ERROR, "Read last object failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        PQclear(l_res);
-        s_pgsql_free_connection(l_conn);
-        return NULL;
-    }
-    dap_store_obj_t *l_obj = NULL;
-    if (PQntuples(l_res)) {
-        l_obj = DAP_NEW_Z(dap_store_obj_t);
-        s_pgsql_fill_object(a_group, l_obj, l_res, 0);
-    }
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    return l_obj;
-}
-
-/**
- * @brief Reads some objects from a PostgreSQL database by conditions.
- * @param a_group a group name string
- * @param a_id id
- * @param a_count_out[in] a number of objects to be read, if equals 0 reads with no limits
- * @param a_count_out[out] a number of objects that were read 
- * @return If successful, a pointer to an objects, otherwise a null pointer. 
- */
-dap_store_obj_t *dap_db_driver_pgsql_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out)
-{
-    if (!a_group)
-        return NULL;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return NULL;
-    }
-    char *l_query_str;
-    if (a_count_out && *a_count_out)
-        l_query_str = dap_strdup_printf("SELECT * FROM \"%s\" WHERE obj_id >= '%"DAP_UINT64_FORMAT_U"' "
-                                        "ORDER BY obj_id ASC LIMIT %d", a_group, a_id, *a_count_out);
-    else
-        l_query_str = dap_strdup_printf("SELECT * FROM \"%s\" WHERE obj_id >= '%"DAP_UINT64_FORMAT_U"' "
-                                        "ORDER BY obj_id ASC", a_group, a_id);
-    PGresult *l_res = PQexecParams(l_conn, l_query_str, 0, NULL, NULL, NULL, NULL, 1);
-    DAP_DELETE(l_query_str);
-    if (PQresultStatus(l_res) != PGRES_TUPLES_OK) {
-        const char *l_err = PQresultErrorField(l_res, PG_DIAG_SQLSTATE);
-        if (!l_err || strcmp(l_err, PGSQL_INVALID_TABLE))
-            log_it(L_ERROR, "Conditional read objects failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        PQclear(l_res);
-        s_pgsql_free_connection(l_conn);
-        return NULL;
-    }
-
-    // parse reply
-    size_t l_count = PQntuples(l_res);
-    dap_store_obj_t *l_obj = l_count ? DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(dap_store_obj_t) * l_count) : NULL;
-    for (int i = 0; i < l_count; i++) {
-        // fill currrent item
-        dap_store_obj_t *l_obj_cur = l_obj + i;
-        s_pgsql_fill_object(a_group, l_obj_cur, l_res, i);
-    }
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    if (a_count_out)
-        *a_count_out = l_count;
-    return l_obj;
-}
-
-/**
- * @brief Gets a list of group names from a PostgreSQL database by a_group_mask.
- * @param a_group_mask a group name mask
- * @return Returns a pointer to a list of group names if successful, otherwise a null pointer.
- */
-dap_list_t *dap_db_driver_pgsql_get_groups_by_mask(const char *a_group_mask)
-{
-    if (!a_group_mask)
-        return NULL;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return NULL;
-    }
-    const char *l_query_str = "SELECT tablename FROM pg_catalog.pg_tables WHERE "
-                              "schemaname != 'information_schema' AND schemaname != 'pg_catalog'";
-    PGresult *l_res = PQexec(l_conn, l_query_str);
-    if (PQresultStatus(l_res) != PGRES_TUPLES_OK) {
-        log_it(L_ERROR, "Read tables failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        PQclear(l_res);
-        s_pgsql_free_connection(l_conn);
-        return NULL;
-    }
-
-    dap_list_t *l_ret_list = NULL;
-    for (int i = 0; i < PQntuples(l_res); i++) {
-        char *l_table_name = (char *)PQgetvalue(l_res, i, 0);
-        if(!dap_fnmatch(a_group_mask, l_table_name, 0))
-            l_ret_list = dap_list_prepend(l_ret_list, dap_strdup(l_table_name));
-    }
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    return l_ret_list;
-}
-
-/**
- * @brief Reads a number of objects from a PostgreSQL database by a_group and a_id.
- * @param a_group a group name string
- * @param a_id id starting from which the quantity is calculated
- * @return Returns a number of objects.
- */
-size_t dap_db_driver_pgsql_read_count_store(const char *a_group, uint64_t a_id)
-{
-    if (!a_group)
-        return 0;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return 0;
-    }
-    char *l_query_str = dap_strdup_printf("SELECT count(*) FROM \"%s\" WHERE obj_id >= '%"DAP_UINT64_FORMAT_U"'",
-                                          a_group, a_id);
-    PGresult *l_res = PQexecParams(l_conn, l_query_str, 0, NULL, NULL, NULL, NULL, 1);
-    DAP_DELETE(l_query_str);
-    if (PQresultStatus(l_res) != PGRES_TUPLES_OK) {
-        const char *l_err = PQresultErrorField(l_res, PG_DIAG_SQLSTATE);
-        if (!l_err || strcmp(l_err, PGSQL_INVALID_TABLE))
-            log_it(L_ERROR, "Count objects failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        PQclear(l_res);
-        s_pgsql_free_connection(l_conn);
-        return 0;
-    }
-    size_t l_ret = be64toh(*(uint64_t *)PQgetvalue(l_res, 0, 0));
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    return l_ret;
-}
-
-/**
- * @brief Checks if an object is in a PostgreSQL database by a_group and a_key.
- * @param a_group a group name string
- * @param a_key a object key string
- * @return Returns true if it is, false it's not.
- */
-bool dap_db_driver_pgsql_is_obj(const char *a_group, const char *a_key)
-{
-    if (!a_group)
-        return NULL;
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return NULL;
-    }
-    char *l_query_str = dap_strdup_printf("SELECT EXISTS(SELECT * FROM \"%s\" WHERE obj_key = '%s')", a_group, a_key);
-    PGresult *l_res = PQexecParams(l_conn, l_query_str, 0, NULL, NULL, NULL, NULL, 1);
-    DAP_DELETE(l_query_str);
-    if (PQresultStatus(l_res) != PGRES_TUPLES_OK) {
-        const char *l_err = PQresultErrorField(l_res, PG_DIAG_SQLSTATE);
-        if (!l_err || strcmp(l_err, PGSQL_INVALID_TABLE))
-            log_it(L_ERROR, "Existance check of object failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        PQclear(l_res);
-        s_pgsql_free_connection(l_conn);
-        return 0;
-    }
-    int l_ret = *PQgetvalue(l_res, 0, 0);
-    PQclear(l_res);
-    s_pgsql_free_connection(l_conn);
-    return l_ret;
-}
-
-/**
- * @brief Flushes a PostgreSQ database cahce to disk.
- * @return Returns 0 if successful, else a error code less than zero.
- */
-int dap_db_driver_pgsql_flush()
-{
-    PGconn *l_conn = s_pgsql_get_connection();
-    if (!l_conn) {
-        log_it(L_ERROR, "Can't pick PostgreSQL connection from pool");
-        return -4;
-    }
-    int l_ret = 0;
-    PGresult *l_res = PQexec(l_conn, "CHECKPOINT");
-    if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-        log_it(L_ERROR, "Flushing database on disk failed with message: \"%s\"", PQresultErrorMessage(l_res));
-        l_ret = -5;
-    }
-    PQclear(l_res);
-    if (!l_ret) {
-        PGresult *l_res = PQexec(l_conn, "VACUUM");
-        if (PQresultStatus(l_res) != PGRES_COMMAND_OK) {
-            log_it(L_ERROR, "Vaccuming database failed with message: \"%s\"", PQresultErrorMessage(l_res));
-            l_ret = -6;
-        }
-        PQclear(l_res);
-    }
-    s_pgsql_free_connection(l_conn);
-    return l_ret;
-}
-#endif
diff --git a/modules/global-db/dap_chain_global_db_driver_sqlite.c b/modules/global-db/dap_chain_global_db_driver_sqlite.c
deleted file mode 100644
index ed2772d08484b30627339b248d6660307a61bd94..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_chain_global_db_driver_sqlite.c
+++ /dev/null
@@ -1,1204 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * CellFrame       https://cellframe.net
- * Sources         https://gitlab.demlabs.net/cellframe
- * Copyright  (c) 2017-2019
- * All rights reserved.
-
- This file is part of CellFrame SDK the open source project
-
-    CellFrame SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    CellFrame SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <sqlite3.h>
-#include <stddef.h>
-#include <string.h>
-#include <pthread.h>
-#include <errno.h>
-#include <stdatomic.h>
-
-#ifdef DAP_OS_UNIX
-#include <unistd.h>
-#endif
-#include "dap_chain_global_db_driver_sqlite.h"
-#include "dap_common.h"
-#include "dap_hash.h"
-#include "dap_file_utils.h"
-#include "dap_strfuncs.h"
-#include "dap_file_utils.h"
-
-#define LOG_TAG "db_sqlite"
-
-static struct conn_pool_item {
-            void    *flink;                                                 /* Forward link to next element in the simple list */
-            sqlite3 *conn;                                                  /* SQLITE connection context itself */
-            int     idx;                                                    /* Just index, no more */
-        atomic_flag busy;                                                   /* "Context is busy" flag */
-        atomic_ullong  usage;                                                  /* Usage counter */
-} s_conn_pool [DAP_SQLITE_POOL_COUNT];                                      /* Preallocate a storage for the SQLITE connections  */
-
-
-static struct conn_pool_item *s_trans = NULL;                               /* SQL context of outstanding  transaction */
-static pthread_mutex_t s_trans_mtx = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t s_trans_cnd = PTHREAD_COND_INITIALIZER;
-
-extern  int g_dap_global_db_debug_more;                                     /* Enable extensible debug output */
-
-static char s_filename_db [MAX_PATH];
-
-static pthread_mutex_t s_conn_free_mtx = PTHREAD_MUTEX_INITIALIZER;         /* Lock to coordinate access to the free connections pool */
-static pthread_cond_t s_conn_free_cnd = PTHREAD_COND_INITIALIZER;           /* To signaling to waites of the free connection */
-
-
-static pthread_mutex_t s_db_mtx = PTHREAD_MUTEX_INITIALIZER;
-
-// Value of one field in the table
-typedef struct _sqlite_value_
-{
-    int32_t len,
-            type;
-    /*
-     #define SQLITE_INTEGER  1
-     #define SQLITE_FLOAT    2
-     #define SQLITE_TEXT     3
-     #define SQLITE_BLOB     4
-     #define SQLITE_NULL     5
-     */
-
-    union {
-        int         val_int;
-        long long   val_int64;
-        double      val_float;
-        const char *val_str;
-        const unsigned char *val_blob;
-    } val;
-} SQLITE_VALUE;
-
-// Content of one row in the table
-typedef struct _sqlite_row_value_
-{
-    int count; // number of columns in a row
-    int reserv;
-    SQLITE_VALUE *val; // array of field values
-} SQLITE_ROW_VALUE;
-
-/**
- * @brief Closes a SQLite database.
- *
- * @param l_db a pointer to an instance of SQLite database structure
- * @return (none)
- */
-static inline void s_dap_db_driver_sqlite_close(sqlite3 *l_db)
-{
-    if(l_db)
-        sqlite3_close(l_db);
-}
-
-/**
- * @brief  Releases memory allocated by sqlite3_mprintf()
- *
- * @param memory a pointer to a string
- * @return (none)
- */
-static inline void s_dap_db_driver_sqlite_free(char *memory)
-{
-    if(memory)
-        sqlite3_free(memory);
-}
-
-#define DAP_DB$K_RTR4CONN   3                                               /* A number of attempts get DB connection */
-#define DAP_DB$K_TMO4CONN   3                                               /* A number of seconds to wait for connection */
-
-static inline struct conn_pool_item *s_sqlite_get_connection(void)
-{
-int     l_rc;
-struct conn_pool_item *l_conn;
-struct timespec tmo = {0};
-
-    if ( (l_rc = pthread_mutex_lock(&s_db_mtx)) == EDEADLK )                /* Get the mutex */
-        return s_trans;                                                     /* DEADLOCK is detected ? Return pointer to current transaction */
-    else if ( l_rc )
-        return  log_it(L_ERROR, "Cannot get free SQLITE connection, errno=%d", l_rc), NULL;
-
-    pthread_mutex_unlock(&s_db_mtx);
-
-    for (int i = DAP_DB$K_RTR4CONN; i--; )
-    {
-        /* Run over connection list, try to get a free connection */
-        l_conn = s_conn_pool;
-        for (int j = DAP_SQLITE_POOL_COUNT; j--; l_conn++)
-        {
-            if ( !(l_rc = atomic_flag_test_and_set (&l_conn->busy)) )       /* Test-and-set ... */
-                {
-                                                                            /* l_rc == 0 - so connection was free, */
-                                                                            /* we got free connection, so get out */
-
-                atomic_fetch_add(&l_conn->usage, 1);
-                if (g_dap_global_db_debug_more )
-                    log_it(L_DEBUG, "Alloc l_conn: @%p/%p, usage: %llu", l_conn, l_conn->conn, l_conn->usage);
-                return  l_conn;
-                }
-        }
-
-        log_it(L_INFO, "No free SQLITE connection, wait %d seconds ...", DAP_DB$K_TMO4CONN);
-
-        /* No free connection at the moment, so, prepare to wait a condition ... */
-
-        clock_gettime(CLOCK_REALTIME, &tmo);
-        tmo.tv_sec += DAP_DB$K_TMO4CONN;
-
-        pthread_mutex_lock(&s_conn_free_mtx);
-        l_rc = pthread_cond_timedwait (&s_conn_free_cnd, &s_conn_free_mtx, &tmo);
-        pthread_mutex_unlock(&s_conn_free_mtx);
-
-        log_it(L_DEBUG, "pthread_cond_timedwait()->%d, errno=%d", l_rc, errno);
-    }
-
-    return  log_it(L_ERROR, "No free SQLITE connection"), NULL;
-}
-
-static inline int s_sqlite_free_connection(struct conn_pool_item *a_conn)
-{
-int     l_rc;
-
-    if (g_dap_global_db_debug_more)
-        log_it(L_DEBUG, "Free  l_conn: @%p/%p, usage: %llu", a_conn, a_conn->conn, a_conn->usage);
-
-    atomic_flag_clear(&a_conn->busy);                                       /* Clear busy flag */
-
-    l_rc = pthread_mutex_lock (&s_conn_free_mtx);                           /* Send a signal to waiters to wake-up */
-    l_rc = pthread_cond_signal(&s_conn_free_cnd);
-    l_rc = pthread_mutex_unlock(&s_conn_free_mtx);
-
-    return  0;
-}
-
-/**
- * @brief Deinitializes a SQLite database.
- *
- * @return Returns 0 if successful.
- */
-int dap_db_driver_sqlite_deinit(void)
-{
-        pthread_mutex_lock(&s_db_mtx);
-        for (int i = 0; i < DAP_SQLITE_POOL_COUNT; i++) {
-            if (s_conn_pool[i].conn) {
-                s_dap_db_driver_sqlite_close(s_conn_pool[i].conn);
-                atomic_flag_clear (&s_conn_pool[i].busy);
-            }
-        }
-        pthread_mutex_unlock(&s_db_mtx);
-        //s_db = NULL;
-        return sqlite3_shutdown();
-}
-
-// An additional function for SQLite to convert byte to number
-static void s_byte_to_bin(sqlite3_context *l_context, int a_argc, sqlite3_value **a_argv)
-{
-    const unsigned char *l_text;
-    if(a_argc != 1)
-        sqlite3_result_null(l_context);
-    l_text = (const unsigned char *) sqlite3_value_blob(a_argv[0]);
-    if(l_text && l_text[0]) {
-        int l_result = (int) l_text[0];
-        sqlite3_result_int(l_context, l_result);
-        return;
-    }
-    sqlite3_result_null(l_context);
-}
-
-/**
- * @brief Opens a SQLite database and adds byte_to_bin function.
- *
- * @param a_filename_utf8 a SQLite database file name
- * @param a_flags database access flags (SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
- * @param a_error_message[out] an error message that's received from the SQLite database
- * @return Returns a pointer to an instance of SQLite database structure.
- */
-sqlite3* dap_db_driver_sqlite_open(const char *a_filename_utf8, int a_flags, char **a_error_message)
-{
-    sqlite3 *l_db = NULL;
-
-    int l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_NOMUTEX, NULL);
-    // if unable to open the database file
-    if(l_rc == SQLITE_CANTOPEN) {
-        log_it(L_WARNING,"No database on path %s, creating one from scratch", a_filename_utf8);
-        if(l_db)
-            sqlite3_close(l_db);
-        // try to create database
-        l_rc = sqlite3_open_v2(a_filename_utf8, &l_db, a_flags | SQLITE_OPEN_NOMUTEX| SQLITE_OPEN_CREATE, NULL);
-    }
-
-    if(l_rc != SQLITE_OK) {
-        log_it(L_CRITICAL,"Can't open database on path %s (code %d: \"%s\" )", a_filename_utf8, l_rc, sqlite3_errstr(l_rc));
-        if(a_error_message)
-            *a_error_message = sqlite3_mprintf("Can't open database: %s\n", sqlite3_errmsg(l_db));
-        sqlite3_close(l_db);
-        return NULL;
-    }
-    // added user functions
-    sqlite3_create_function(l_db, "byte_to_bin", 1, SQLITE_UTF8, NULL, &s_byte_to_bin, NULL, NULL);
-    return l_db;
-}
-
-
-/**
- * @brief Executes SQL statements.
- *
- * @param l_db a pointer to an instance of SQLite database structure
- * @param l_query the SQL statement
- * @param l_error_message[out] an error message that's received from the SQLite database
- * @return Returns 0 if successful.
- */
-static int s_dap_db_driver_sqlite_exec(sqlite3 *l_db, const char *l_query, char **l_error_message)
-{
-char *l_errmsg = NULL;
-int     l_rc;
-struct  timespec tmo = {0, 500 * 1024 * 1024 /* ~0.5 sec */}, delta;
-
-    for ( int i = 7; i--; )
-    {                                                                       /* Ok or error (exclude SQL_LOCKED) - just exit from loop? */
-        if ( SQLITE_LOCKED != (l_rc = sqlite3_exec(l_db, l_query, NULL, 0, &l_errmsg))
-             && (l_rc != SQLITE_BUSY) )
-            break;
-
-        if (g_dap_global_db_debug_more )
-            log_it(L_WARNING, "SQL error: \"%s\"%d, dap_db_driver_sqlite_exec(%p, %s), retry ...", sqlite3_errmsg(l_db),l_rc, l_db, l_query);
-
-        for ( delta = tmo; nanosleep(&delta, &delta); );                        /* Wait some time ... */
-    }
-
-
-    if ( l_rc != SQLITE_OK)
-    {
-        if ( l_rc != SQLITE_CONSTRAINT )
-            log_it(L_ERROR, "SQL error: \"%s\"%d, dap_db_driver_sqlite_exec(%p, %s), retry ...", sqlite3_errmsg(l_db),l_rc, l_db, l_query);
-
-        if(l_error_message && l_errmsg)
-            *l_error_message = sqlite3_mprintf("SQL error %d: %s", l_rc, l_errmsg);
-    }
-
-    if(l_errmsg)
-        sqlite3_free(l_errmsg);
-
-    return l_rc;
-}
-
-/**
- * @brief Creates a table and unique index in the s_db database.
- *
- * @param a_table_name a table name string
- * @return Returns 0 if successful, otherwise -1.
- */
-static int s_dap_db_driver_sqlite_create_group_table(const char *a_table_name)
-{
-int l_rc;
-struct conn_pool_item     *l_conn;
-char    *l_error_message, l_query[512];
-
-    if( !a_table_name )
-        return  -EINVAL;
-
-    if ( !(l_conn = s_sqlite_get_connection()) )
-        return log_it(L_ERROR, "Error create group table '%s'", a_table_name), -ENOENT;
-
-    dap_snprintf(l_query, sizeof(l_query) - 1,
-                    "CREATE TABLE IF NOT EXISTs '%s'(id INTEGER NOT NULL PRIMARY KEY, key TEXT KEY, hash BLOB, ts INTEGER KEY, value BLOB)",
-                    a_table_name);
-
-    if ( (l_rc = s_dap_db_driver_sqlite_exec(l_conn->conn, (const char*) l_query, &l_error_message)) != SQLITE_OK) {
-        log_it(L_ERROR, "SQL error: \"%s\"%d, dap_db_driver_sqlite_exec(%p, %s), retry ...", sqlite3_errmsg(l_conn->conn),l_rc, l_conn->conn, l_query);
-        s_dap_db_driver_sqlite_free(l_error_message);
-        s_sqlite_free_connection(l_conn);
-        return -1;
-    }
-
-    // create unique index - key
-    dap_snprintf(l_query, sizeof(l_query) - 1,
-                 "CREATE UNIQUE INDEX IF NOT EXISTS 'idx_key_%s' ON '%s' (key)", a_table_name,
-                a_table_name);
-
-    if ( (l_rc = s_dap_db_driver_sqlite_exec(l_conn->conn, (const char*) l_query, &l_error_message)) != SQLITE_OK) {
-        log_it(L_ERROR, "SQL error: \"%s\"%d, dap_db_driver_sqlite_exec(%p, %s), retry ...", sqlite3_errmsg(l_conn->conn),l_rc, l_conn->conn, l_query);
-        s_dap_db_driver_sqlite_free(l_error_message);
-        s_sqlite_free_connection(l_conn);
-        return -1;
-    }
-
-    s_sqlite_free_connection(l_conn);
-    return 0;
-}
-
-/**
- * @brief Prepares a SQL query for a database
- * @param db a pointer to an instance of SQLite database structure.
- * @param query the query
- * @param l_res[out] a pointer to a pointer to a structure with result
- * @param l_error_message[out] an error message that's received from the SQLite database
- * @return Returns 0 if successful,
- */
-static int s_dap_db_driver_sqlite_query(sqlite3 *db, char *query, sqlite3_stmt **l_res, char **l_error_message)
-{
-    const char *pzTail; // OUT: Pointer to unused portion of zSql
-    int l_rc = sqlite3_prepare_v2(db, query, -1, l_res, &pzTail);
-    if(l_rc != SQLITE_OK)
-    {
-        if(l_error_message)
-        {
-            const char *zErrMsg = sqlite3_errmsg(db);
-            if(zErrMsg)
-                *l_error_message = sqlite3_mprintf("SQL Query error: %s\n", zErrMsg);
-        }
-        return l_rc;
-    }
-    return l_rc;
-}
-
-/**
- * @brief Releases memory allocated for a row.
- *
- * @param row a database row
- * @return (none)
- */
-static void s_dap_db_driver_sqlite_row_free(SQLITE_ROW_VALUE *row)
-{
-    if(row) {
-        // delete the whole string
-        sqlite3_free(row->val);
-        // delete structure
-        sqlite3_free(row);
-    }
-}
-
-
-/**
- * @brief Fetches a result values from a query to l_row_out
- *
- * @param l_res a pointer to a prepared statement structure
- * @param l_row_out a pointer to a pointer to a row structure
- * @return Returns SQLITE_ROW(100) or SQLITE_DONE(101) or SQLITE_BUSY(5)
- */
-static int s_dap_db_driver_sqlite_fetch_array(sqlite3_stmt *l_res, SQLITE_ROW_VALUE **l_row_out)
-{
-    SQLITE_ROW_VALUE *l_row = NULL;
-    // go to next the string
-    int l_rc = sqlite3_step(l_res);
-    if(l_rc == SQLITE_ROW) // SQLITE_ROW(100) or SQLITE_DONE(101) or SQLITE_BUSY(5)
-    {
-        int l_iCol; // number of the column in the row
-        // allocate memory for a row with data
-        l_row = (SQLITE_ROW_VALUE*) sqlite3_malloc(sizeof(SQLITE_ROW_VALUE));
-        int l_count = sqlite3_column_count(l_res); // get the number of columns
-        // allocate memory for all columns
-        l_row->val = (SQLITE_VALUE*) sqlite3_malloc(l_count * (int)sizeof(SQLITE_VALUE));
-        if(l_row->val)
-        {
-            l_row->count = l_count; // number of columns
-            for(l_iCol = 0; l_iCol < l_row->count; l_iCol++)
-                    {
-                SQLITE_VALUE *cur_val = l_row->val + l_iCol;
-                cur_val->len = sqlite3_column_bytes(l_res, l_iCol); // how many bytes will be needed
-                cur_val->type = sqlite3_column_type(l_res, l_iCol); // field type
-                if(cur_val->type == SQLITE_INTEGER)
-                    cur_val->val.val_int64 = sqlite3_column_int64(l_res, l_iCol);
-                else if(cur_val->type == SQLITE_FLOAT)
-                    cur_val->val.val_float = sqlite3_column_double(l_res, l_iCol);
-                else if(cur_val->type == SQLITE_BLOB)
-                    cur_val->val.val_blob = (const unsigned char*) sqlite3_column_blob(l_res, l_iCol);
-                else if(cur_val->type == SQLITE_TEXT)
-                    cur_val->val.val_str = (const char*) sqlite3_column_text(l_res, l_iCol); //sqlite3_mprintf("%s",sqlite3_column_text(l_res,iCol));
-                else
-                    cur_val->val.val_str = NULL;
-            }
-        }
-        else
-            l_row->count = 0; // number of columns
-    }
-    if(l_row_out)
-        *l_row_out = l_row;
-    else
-        s_dap_db_driver_sqlite_row_free(l_row);
-
-
-    return l_rc;
-}
-
-
-/**
- * @brief Destroys a prepared statement structure
- *
- * @param l_res a pointer to the statement structure
- * @return Returnes true if successful, otherwise false.
- */
-static int s_dap_db_driver_sqlite_query_free(sqlite3_stmt *l_res)
-{
-
-    if(!l_res)
-        return -EINVAL;
-
-    return  -sqlite3_finalize(l_res);
-
-}
-
-/**
- * @brief Convers a byte array into a hexadecimal string
- *
- * @param blob a byte array
- * @param len a length of byte array
- * @return Returns a hexadecimal string
- */
-static char* s_dap_db_driver_get_string_from_blob(const uint8_t *blob, int len)
-{
-    char *str_out;
-
-    if(!blob)
-        return NULL;
-
-    if ( !(str_out = (char*) sqlite3_malloc(len * 2 + 1)) )
-        return NULL;
-
-    dap_bin2hex(str_out, (const void*)blob, (size_t)len);
-    str_out[len * 2] = 0;
-    return str_out;
-}
-
-
-/**
- * @brief Executes a VACUUM statement in a database.
- *
- * @param l_db a a pointer to an instance of SQLite database structure
- * @return Returns 0 if successful.
- */
-int s_dap_db_driver_sqlite_vacuum(sqlite3 *l_db)
-{
-    if(!l_db)
-        return -1;
-
-    return  s_dap_db_driver_sqlite_exec(l_db, "VACUUM", NULL);
-}
-
-/**
- * @brief Starts a transaction in s_db database.
- *
- * @return Returns 0 if successful, otherwise -1.
- */
-static int s_dap_db_driver_sqlite_start_transaction(void)
-{
-int l_rc;
-
-    /* Try to lock */
-    if ( EDEADLK == (l_rc = pthread_mutex_lock(&s_trans_mtx)) ) {
-        /* DEADLOCK ?! - so transaction is already active ... */
-        log_it(L_DEBUG, "Active TX l_conn: @%p/%p", s_trans, s_trans->conn);
-        return  0;
-    }
-
-    if ( ! (s_trans = s_sqlite_get_connection()) )
-        return  -666;
-
-    if ( g_dap_global_db_debug_more )
-        log_it(L_DEBUG, "Start TX l_conn: @%p/%p", s_trans, s_trans->conn);
-
-    pthread_mutex_lock(&s_db_mtx);
-    l_rc = s_dap_db_driver_sqlite_exec(s_trans->conn, "BEGIN", NULL);
-    pthread_mutex_unlock(&s_db_mtx);
-
-    if ( l_rc != SQLITE_OK ) {
-        pthread_mutex_unlock(&s_trans_mtx);
-        s_sqlite_free_connection(s_trans);
-        s_trans = NULL;
-        }
-
-    return  ( l_rc == SQLITE_OK ) ? 0 : -l_rc;
-}
-
-/**
- * @brief Ends a transaction in s_db database.
- *
- * @return Returns 0 if successful, otherwise -1.
- */
-static int s_dap_db_driver_sqlite_end_transaction(void)
-{
-int l_rc;
-struct conn_pool_item *l_conn;
-
-    if ( !s_trans)
-        return  log_it(L_ERROR, "No active TX!"), -666;
-
-    l_conn = s_trans;
-    s_trans = NULL;                                                         /* Zeroing current TX's context until
-                                                                              it's protected by the mutex ! */
-
-    if ( g_dap_global_db_debug_more )
-        log_it(L_DEBUG, "End TX l_conn: @%p/%p", l_conn, l_conn->conn);
-
-    pthread_mutex_unlock(&s_trans_mtx);                                     /* Free TX context to other ... */
-
-    pthread_mutex_lock(&s_db_mtx);
-    l_rc = s_dap_db_driver_sqlite_exec(l_conn->conn, "COMMIT", NULL);
-    pthread_mutex_unlock(&s_db_mtx);
-
-    s_sqlite_free_connection(l_conn);
-
-    return  ( l_rc == SQLITE_OK ) ? 0 : -l_rc;
-}
-
-
-/**
- * @brief Replaces '_' char with '.' char in a_table_name.
- *
- * @param a_table_name a table name string
- * @return Returns a group name string with the replaced character
- */
-static inline char *s_sqlite_make_group_name(const char *a_table_name)
-{
-    char *l_table_name = dap_strdup(a_table_name), *l_str;
-
-    for ( l_str = l_table_name; (l_str = strchr(l_str, '_')); l_str++)
-        *l_str = '.';
-
-    return l_table_name;
-}
-
-/**
- * @brief Replaces '.' char with '_' char in a_group_name.
- *
- * @param a_group_name a group name string
- * @return Returns a table name string with the replaced character
- */
-static inline char *s_sqlite_make_table_name(const char *a_group_name)
-{
-    char *l_group_name = dap_strdup(a_group_name), *l_str;
-
-    for ( l_str = l_group_name; (l_str = strchr(l_str, '.')); l_str++)
-        *l_str = '_';
-
-    return l_group_name;
-}
-
-/**
- * @brief Applies an object to a database.
- *
- * @param a_store_obj a pointer to the object structure
- * @return Returns 0 if successful.
- */
-int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj)
-{
-    if(!a_store_obj || !a_store_obj->group )
-        return -1;
-
-    char *l_query = NULL;
-    char *l_error_message = NULL;
-
-    char *l_table_name = s_sqlite_make_table_name(a_store_obj->group);
-
-    if(a_store_obj->type == DAP_DB$K_OPTYPE_ADD) {
-        if(!a_store_obj->key)
-            return -1;
-        char *l_blob_value = s_dap_db_driver_get_string_from_blob(a_store_obj->value, (int)a_store_obj->value_len);
-        //add one record
-        l_query = sqlite3_mprintf("INSERT INTO '%s' values(NULL, '%s', x'', '%lld', x'%s')",
-                                           l_table_name, a_store_obj->key, a_store_obj->timestamp, l_blob_value);
-        s_dap_db_driver_sqlite_free(l_blob_value);
-    }
-    else if (a_store_obj->type == DAP_DB$K_OPTYPE_DEL) {
-        //delete one record
-        if (a_store_obj->key) {
-            l_query = sqlite3_mprintf("DELETE FROM '%s' where key = '%s'",
-                                      l_table_name, a_store_obj->key);
-        } else {
-            // remove all group
-            l_query = sqlite3_mprintf("DROP TABLE IF EXISTS '%s'", l_table_name);
-        }
-    }
-    else {
-        log_it(L_ERROR, "Unknown store_obj type '0x%x'", a_store_obj->type);
-        return -1;
-    }
-    // execute request
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-
-    if( !l_conn )
-        return -666;
-
-    int l_ret = s_dap_db_driver_sqlite_exec(l_conn->conn, l_query, &l_error_message);
-
-    if(l_ret == SQLITE_ERROR) {
-        s_dap_db_driver_sqlite_free(l_error_message);
-        l_error_message = NULL;
-        // create table
-        s_dap_db_driver_sqlite_create_group_table(l_table_name);
-        // repeat request
-        l_ret = s_dap_db_driver_sqlite_exec(l_conn->conn, l_query, &l_error_message);
-
-    }
-    // entry with the same hash is already present
-    if(l_ret == SQLITE_CONSTRAINT) {
-        s_dap_db_driver_sqlite_free(l_error_message);
-        l_error_message = NULL;
-        //replace one record
-        char *l_blob_value = s_dap_db_driver_get_string_from_blob(a_store_obj->value, (int)a_store_obj->value_len);
-        char *l_query_replace = sqlite3_mprintf("REPLACE INTO '%s' values(NULL, '%s', x'', '%lld', x'%s')",
-                                   l_table_name, a_store_obj->key, a_store_obj->timestamp, l_blob_value);
-        s_dap_db_driver_sqlite_free(l_blob_value);
-        l_ret = s_dap_db_driver_sqlite_exec(l_conn->conn, l_query_replace, &l_error_message);
-        s_dap_db_driver_sqlite_free(l_query_replace);
-
-    }
-    // missing database
-    if(l_ret != SQLITE_OK) {
-        log_it(L_ERROR, "sqlite apply error: %s", l_error_message);
-        s_dap_db_driver_sqlite_free(l_error_message);
-        l_ret = -1;
-    }
-    s_sqlite_free_connection(l_conn);
-    s_dap_db_driver_sqlite_free(l_query);
-    DAP_DELETE(l_table_name);
-    return l_ret;
-}
-
-/**
- * @brief Fills a object from a row
- *
- * @param a_group a group name string
- * @param a_obj a pointer to the object
- * @param a_row a ponter to the row structure
- */
-static void fill_one_item(const char *a_group, dap_store_obj_t *a_obj, SQLITE_ROW_VALUE *a_row)
-{
-    a_obj->group = dap_strdup(a_group);
-
-    for(int l_iCol = 0; l_iCol < a_row->count; l_iCol++) {
-        SQLITE_VALUE *l_cur_val = a_row->val + l_iCol;
-        switch (l_iCol) {
-        case 0:
-            if(l_cur_val->type == SQLITE_INTEGER)
-                a_obj->id = (uint64_t)l_cur_val->val.val_int64;
-            break; // id
-        case 1:
-            if(l_cur_val->type == SQLITE_INTEGER)
-                a_obj->timestamp = l_cur_val->val.val_int64;
-            break; // ts
-        case 2:
-            if(l_cur_val->type == SQLITE_TEXT)
-                a_obj->key = dap_strdup(l_cur_val->val.val_str);
-            break; // key
-        case 3:
-            if(l_cur_val->type == SQLITE_BLOB)
-            {
-                a_obj->value_len = (size_t) l_cur_val->len;
-                a_obj->value = DAP_NEW_SIZE(uint8_t, a_obj->value_len);
-                memcpy((byte_t *)a_obj->value, l_cur_val->val.val_blob, a_obj->value_len);
-            }
-            break; // value
-        }
-    }
-
-}
-
-/**
- * @brief Reads a last object from the s_db database.
- *
- * @param a_group a group name string
- * @return Returns a pointer to the object.
- */
-dap_store_obj_t* dap_db_driver_sqlite_read_last_store_obj(const char *a_group)
-{
-dap_store_obj_t *l_obj = NULL;
-char *l_error_message = NULL;
-sqlite3_stmt *l_res;
-struct conn_pool_item *l_conn;
-
-    if(!a_group)
-        return NULL;
-
-    if ( !(l_conn = s_sqlite_get_connection()) )
-        return NULL;
-
-    char * l_table_name = s_sqlite_make_table_name(a_group);
-    char *l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id DESC LIMIT 1", l_table_name);
-    int l_ret = s_dap_db_driver_sqlite_query(l_conn->conn, l_str_query, &l_res, &l_error_message);
-
-    sqlite3_free(l_str_query);
-    DAP_DEL_Z(l_table_name);
-
-    if(l_ret != SQLITE_OK) {
-        //log_it(L_ERROR, "read last l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        s_dap_db_driver_sqlite_free(l_error_message);
-        s_sqlite_free_connection(l_conn);
-        return NULL;
-    }
-
-    SQLITE_ROW_VALUE *l_row = NULL;
-    l_ret = s_dap_db_driver_sqlite_fetch_array(l_res, &l_row);
-    if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE)
-    {
-        //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-    }
-    if(l_ret == SQLITE_ROW && l_row) {
-        l_obj = DAP_NEW_Z(dap_store_obj_t);
-        fill_one_item(a_group, l_obj, l_row);
-    }
-    s_dap_db_driver_sqlite_row_free(l_row);
-    s_dap_db_driver_sqlite_query_free(l_res);
-
-    s_sqlite_free_connection(l_conn);
-
-    return l_obj;
-}
-
-/**
- * @brief Reads some objects from a database by conditions
- *
- * @param a_group a group name string
- * @param a_id id
- * @param a_count_out[in] a number of objects to be read, if equals 0 reads with no limits
- * @param a_count_out[out] a number of objects that were read
- * @return If successful, a pointer to an objects, otherwise NULL.
- */
-dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out)
-{
-    dap_store_obj_t *l_obj = NULL;
-    char *l_error_message = NULL;
-    sqlite3_stmt *l_res;
-    if(!a_group)
-        return NULL;
-
-    char * l_table_name = s_sqlite_make_table_name(a_group);
-    // no limit
-    int l_count_out = 0;
-    if(a_count_out)
-        l_count_out = (int)*a_count_out;
-    char *l_str_query = NULL;
-    if (l_count_out) {
-        l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC LIMIT %d",
-                l_table_name, a_id, l_count_out);
-    } else {
-        l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC",
-                l_table_name, a_id);
-    }
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-    if(!l_conn) {
-        if (l_str_query) sqlite3_free(l_str_query);
-        return NULL;
-    }
-
-    int l_ret = s_dap_db_driver_sqlite_query(l_conn->conn, l_str_query, &l_res, &l_error_message);
-    sqlite3_free(l_str_query);
-    DAP_DEL_Z(l_table_name);
-
-    if(l_ret != SQLITE_OK) {
-        //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        s_dap_db_driver_sqlite_free(l_error_message);
-        s_sqlite_free_connection(l_conn);
-        return NULL;
-    }
-
-    //int b = qlite3_column_count(s_db);
-    SQLITE_ROW_VALUE *l_row = NULL;
-    l_count_out = 0;
-    int l_count_sized = 0;
-    do {
-        l_ret = s_dap_db_driver_sqlite_fetch_array(l_res, &l_row);
-        if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE)
-        {
-           // log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        }
-        if(l_ret == SQLITE_ROW && l_row) {
-            // realloc memory
-            if(l_count_out >= l_count_sized) {
-                l_count_sized += 10;
-                l_obj = DAP_REALLOC(l_obj, sizeof(dap_store_obj_t) * (uint64_t)l_count_sized);
-                memset(l_obj + l_count_out, 0, sizeof(dap_store_obj_t) * (uint64_t)(l_count_sized - l_count_out));
-            }
-            // fill current item
-            dap_store_obj_t *l_obj_cur = l_obj + l_count_out;
-            fill_one_item(a_group, l_obj_cur, l_row);
-            l_count_out++;
-        }
-        s_dap_db_driver_sqlite_row_free(l_row);
-    } while(l_row);
-
-    s_dap_db_driver_sqlite_query_free(l_res);
-    s_sqlite_free_connection(l_conn);
-
-    if(a_count_out)
-        *a_count_out = (size_t)l_count_out;
-
-    return l_obj;
-}
-
-/**
- * @brief Reads some objects from a SQLite database by a_group, a_key.
- * @param a_group a group name string
- * @param a_key an object key string, if equals NULL reads the whole group
- * @param a_count_out[in] a number of objects to be read, if equals 0 reads with no limits
- * @param a_count_out[out] a number of objects that were read
- * @return If successful, a pointer to an objects, otherwise NULL.
- */
-dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out)
-{
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-
-    if(!a_group || !l_conn)
-        return NULL;
-
-    dap_store_obj_t *l_obj = NULL;
-    sqlite3_stmt *l_res;
-    char * l_table_name = s_sqlite_make_table_name(a_group);
-    // no limit
-    uint64_t l_count_out = 0;
-    if(a_count_out)
-        l_count_out = *a_count_out;
-    char *l_str_query;
-    if (a_key) {
-        if (l_count_out) {
-            l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE key='%s' ORDER BY id ASC LIMIT %d",
-                    l_table_name, a_key, l_count_out);
-        } else {
-            l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE key='%s' ORDER BY id ASC",
-                    l_table_name, a_key);
-        }
-    } else {
-        if (l_count_out) {
-            l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id ASC LIMIT %d",
-                    l_table_name, l_count_out);
-        } else {
-            l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id ASC", l_table_name);
-        }
-    }
-    int l_ret = s_dap_db_driver_sqlite_query(l_conn->conn, l_str_query, &l_res, NULL);
-
-    sqlite3_free(l_str_query);
-    DAP_DEL_Z(l_table_name);
-    if(l_ret != SQLITE_OK) {
-        //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        s_sqlite_free_connection(l_conn);
-        return NULL;
-    }
-
-    //int b = qlite3_column_count(s_db);
-    SQLITE_ROW_VALUE *l_row = NULL;
-    l_count_out = 0;
-    uint64_t l_count_sized = 0;
-    do {
-        l_ret = s_dap_db_driver_sqlite_fetch_array(l_res, &l_row);
-        if(l_ret != SQLITE_ROW && l_ret != SQLITE_DONE)
-        {
-           // log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        }
-        if(l_ret == SQLITE_ROW && l_row) {
-            // realloc memory
-            if(l_count_out >= l_count_sized) {
-                l_count_sized += 10;
-                l_obj = DAP_REALLOC(l_obj, sizeof(dap_store_obj_t) * l_count_sized);
-                memset(l_obj + l_count_out, 0, sizeof(dap_store_obj_t) * (l_count_sized - l_count_out));
-            }
-            // fill currrent item
-            dap_store_obj_t *l_obj_cur = l_obj + l_count_out;
-            fill_one_item(a_group, l_obj_cur, l_row);
-            l_count_out++;
-        }
-        s_dap_db_driver_sqlite_row_free(l_row);
-    } while(l_row);
-
-    s_dap_db_driver_sqlite_query_free(l_res);
-    s_sqlite_free_connection(l_conn);
-
-    if(a_count_out)
-        *a_count_out = l_count_out;
-
-    return l_obj;
-}
-
-/**
- * @brief Gets a list of group names from a s_db database by a_group_mask.
- *
- * @param a_group_mask a group name mask
- * @return Returns a pointer to a list of group names.
- */
-dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask)
-{
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-
-    if(!a_group_mask || !l_conn)
-        return NULL;
-
-    sqlite3_stmt *l_res;
-    const char *l_str_query = "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%'";
-    dap_list_t *l_ret_list = NULL;
-    int l_ret = s_dap_db_driver_sqlite_query(l_conn->conn, (char *)l_str_query, &l_res, NULL);
-    if(l_ret != SQLITE_OK) {
-        //log_it(L_ERROR, "Get tables l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        s_sqlite_free_connection(l_conn);
-        return NULL;
-    }
-    char * l_mask = s_sqlite_make_table_name(a_group_mask);
-    SQLITE_ROW_VALUE *l_row = NULL;
-    while (s_dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) {
-        char *l_table_name = (char *)l_row->val->val.val_str;
-        if(!dap_fnmatch(l_mask, l_table_name, 0))
-            l_ret_list = dap_list_prepend(l_ret_list, s_sqlite_make_group_name(l_table_name));
-        s_dap_db_driver_sqlite_row_free(l_row);
-    }
-    s_dap_db_driver_sqlite_query_free(l_res);
-
-    s_sqlite_free_connection(l_conn);
-
-    return l_ret_list;
-}
-
-/**
- * @brief Reads a number of objects from a s_db database by a_group and a_id
- *
- * @param a_group a group name string
- * @param a_id id starting from which the quantity is calculated
- * @return Returns a number of objects.
- */
-size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id)
-{
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-
-    if(!a_group || !l_conn)
-        return 0;
-
-    sqlite3_stmt *l_res;
-
-    char * l_table_name = s_sqlite_make_table_name(a_group);
-    char *l_str_query = sqlite3_mprintf("SELECT COUNT(*) FROM '%s' WHERE id>='%lld'", l_table_name, a_id);
-    int l_ret = s_dap_db_driver_sqlite_query(l_conn->conn, l_str_query, &l_res, NULL);
-    sqlite3_free(l_str_query);
-    DAP_DEL_Z(l_table_name);
-
-    if(l_ret != SQLITE_OK) {
-        //log_it(L_ERROR, "Count l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        s_sqlite_free_connection(l_conn);
-        return 0;
-    }
-    size_t l_ret_val = 0;
-    SQLITE_ROW_VALUE *l_row = NULL;
-    if (s_dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) {
-        l_ret_val = (size_t)l_row->val->val.val_int64;
-        s_dap_db_driver_sqlite_row_free(l_row);
-    }
-    s_dap_db_driver_sqlite_query_free(l_res);
-
-    s_sqlite_free_connection(l_conn);
-
-    return l_ret_val;
-}
-
-/**
- * @brief Checks if an object is in a s_db database by a_group and a_key.
- *
- * @param a_group a group name string
- * @param a_key a object key string
- * @return Returns true if it is, false it's not.
- */
-bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key)
-{
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-
-    if(!a_group || !l_conn)
-        return 0;
-
-    sqlite3_stmt *l_res;
-
-    char * l_table_name = s_sqlite_make_table_name(a_group);
-    char *l_str_query = sqlite3_mprintf("SELECT EXISTS(SELECT * FROM '%s' WHERE key='%s')", l_table_name, a_key);
-    int l_ret = s_dap_db_driver_sqlite_query(l_conn->conn, l_str_query, &l_res, NULL);
-    sqlite3_free(l_str_query);
-    DAP_DEL_Z(l_table_name);
-
-    if(l_ret != SQLITE_OK) {
-        //log_it(L_ERROR, "Exists l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        s_sqlite_free_connection(l_conn);
-        return false;
-    }
-    bool l_ret_val = false;
-    SQLITE_ROW_VALUE *l_row = NULL;
-    if (s_dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) {
-        l_ret_val = (size_t)l_row->val->val.val_int64;
-        s_dap_db_driver_sqlite_row_free(l_row);
-    }
-    s_dap_db_driver_sqlite_query_free(l_res);
-
-    s_sqlite_free_connection(l_conn);
-
-    return l_ret_val;
-}
-
-
-
-/**
- * @brief Executes a PRAGMA statement.
- *
- * @param a_db a pointer to an instance of SQLite database structure
- * @param a_param a PRAGMA name
- * @param a_mode a PRAGMA value
- * @return Returns true if successful, otherwise false.
- */
-static int s_dap_db_driver_sqlite_set_pragma(sqlite3 *a_db, char *a_param, char *a_mode)
-{
-char    l_query [512];
-int     l_rc;
-
-    if(!a_param || !a_mode)
-        return  log_it(L_ERROR, "%s - no param or mode\n", __PRETTY_FUNCTION__), false;
-
-    snprintf(l_query, sizeof(l_query) - 1, "PRAGMA %s = %s", a_param, a_mode);
-    l_rc = s_dap_db_driver_sqlite_exec(a_db, l_query, NULL); // default synchronous=FULL
-
-    return  (l_rc == SQLITE_OK);
-}
-
-
-
-/**
- * @brief Flushes a SQLite database cahce to disk.
- * @note The function closes and opens the database
- *
- * @return Returns 0 if successful.
- */
-static int s_dap_db_driver_sqlite_flush()
-{
-    struct conn_pool_item *l_conn = s_sqlite_get_connection();
-
-    char *l_error_message = NULL;
-
-    log_it(L_DEBUG, "Start flush sqlite data base.");
-
-    if(!(l_conn = s_sqlite_get_connection()) )
-        return -666;
-
-    s_dap_db_driver_sqlite_close(l_conn->conn);
-
-    if ( !(l_conn->conn = dap_db_driver_sqlite_open(s_filename_db, SQLITE_OPEN_READWRITE, &l_error_message)) ) {
-        log_it(L_ERROR, "Can't init sqlite err: \"%s\"", l_error_message? l_error_message: "UNKNOWN");
-        s_dap_db_driver_sqlite_free(l_error_message);
-        return -3;
-    }
-
-#ifndef _WIN32
-    sync();
-#endif
-
-    if(!s_dap_db_driver_sqlite_set_pragma(l_conn->conn, "synchronous", "NORMAL")) // 0 | OFF | 1 | NORMAL | 2 | FULL
-        log_it(L_WARNING, "Can't set new synchronous mode\n");
-    if(!s_dap_db_driver_sqlite_set_pragma(l_conn->conn, "journal_mode", "OFF")) // DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF
-        log_it(L_WARNING, "Can't set new journal mode\n");
-
-    if(!s_dap_db_driver_sqlite_set_pragma(l_conn->conn, "page_size", "1024")) // DELETE | TRUNCATE | PERSIST | MEMORY | WAL | OFF
-        log_it(L_WARNING, "Can't set page_size\n");
-
-    return 0;
-}
-
-
-
-
-/**
- * @brief Initializes a SQLite database.
- * @note no thread safe
- * @param a_filename_db a path to the database file
- * @param a_drv_callback a pointer to a structure of callback functions
- * @return If successful returns 0, else a code < 0.
- */
-int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks_t *a_drv_callback)
-{
-int     l_ret = -1, l_errno = errno;
-sqlite3 *l_conn;
-char l_errbuf[255] = {0}, *l_error_message = NULL;
-
-
-    if ( sqlite3_threadsafe() && !sqlite3_config(SQLITE_CONFIG_SERIALIZED) )
-        l_ret = sqlite3_initialize();
-
-    if ( l_ret != SQLITE_OK ) {
-        log_it(L_ERROR, "Can't init sqlite err=%d (%s)", l_ret, sqlite3_errstr(l_ret));
-        return -2;
-    }
-
-    // Check paths and create them if nessesary
-    char * l_filename_dir = dap_path_get_dirname(a_filename_db);
-    strncpy(s_filename_db, a_filename_db, sizeof(s_filename_db) );
-
-    if ( !dap_dir_test(l_filename_dir) ){
-        log_it(L_NOTICE, "No directory %s, trying to create...",l_filename_dir);
-
-        int l_mkdir_ret = dap_mkdir_with_parents(l_filename_dir);
-        l_errno = errno;
-
-        if(!dap_dir_test(l_filename_dir)){
-            strerror_r(l_errno,l_errbuf,sizeof(l_errbuf));
-            log_it(L_ERROR, "Can't create directory, error code %d, error string \"%s\"", l_mkdir_ret, l_errbuf);
-            DAP_DELETE(l_filename_dir);
-            return -l_errno;
-        }else
-            log_it(L_NOTICE, "Directory created");
-    }
-
-    DAP_DEL_Z(l_filename_dir);
-
-    /* Create a pool of connection */
-    for (int i = 0; i < DAP_SQLITE_POOL_COUNT; i++)
-    {
-        if ( !(l_conn = dap_db_driver_sqlite_open(a_filename_db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, &l_error_message)) )
-        {
-            log_it(L_ERROR, "Can't init SQL connection context #%d err: \"%s\"", i, l_error_message);
-
-            s_dap_db_driver_sqlite_free(l_error_message);
-            l_ret = -3;
-            for(int ii = i - 1; ii >= 0; ii--) {
-                s_dap_db_driver_sqlite_close(s_conn_pool[ii].conn);
-            }
-            goto end;
-        }
-
-        s_conn_pool[i].conn = l_conn;
-        s_conn_pool[i].idx = i;
-
-        atomic_store(&s_conn_pool[i].usage, 0);
-
-        log_it(L_DEBUG, "SQL connection context #%d is created @%p", i, l_conn);
-
-        if(!s_dap_db_driver_sqlite_set_pragma(l_conn, "synchronous", "NORMAL"))
-            log_it(L_ERROR, "can't set new synchronous mode\n");
-        if(!s_dap_db_driver_sqlite_set_pragma(l_conn, "journal_mode", "OFF"))
-            log_it(L_ERROR, "can't set new journal mode\n");
-        if(!s_dap_db_driver_sqlite_set_pragma(l_conn, "page_size", "4096"))
-            log_it(L_ERROR, "can't set page_size\n");
-    }
-
-    // *PRAGMA page_size = bytes; // page size DB; it is reasonable to make it equal to the size of the disk cluster 4096
-    // *PRAGMA cache_size = -kibibytes; // by default it is equal to 2000 pages of database
-    //
-    a_drv_callback->apply_store_obj = dap_db_driver_sqlite_apply_store_obj;
-    a_drv_callback->read_store_obj = dap_db_driver_sqlite_read_store_obj;
-    a_drv_callback->read_cond_store_obj = dap_db_driver_sqlite_read_cond_store_obj;
-    a_drv_callback->read_last_store_obj = dap_db_driver_sqlite_read_last_store_obj;
-    a_drv_callback->transaction_start = s_dap_db_driver_sqlite_start_transaction;
-    a_drv_callback->transaction_end = s_dap_db_driver_sqlite_end_transaction;
-    a_drv_callback->get_groups_by_mask  = dap_db_driver_sqlite_get_groups_by_mask;
-    a_drv_callback->read_count_store = dap_db_driver_sqlite_read_count_store;
-    a_drv_callback->is_obj = dap_db_driver_sqlite_is_obj;
-    a_drv_callback->deinit = dap_db_driver_sqlite_deinit;
-    a_drv_callback->flush = s_dap_db_driver_sqlite_flush;
-
-end:
-    return l_ret;
-}
diff --git a/modules/global-db/dap_chain_global_db_remote.c b/modules/global-db/dap_chain_global_db_remote.c
deleted file mode 100644
index fae3fe9e0376659ed2406fe3e729f7ab276fd486..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_chain_global_db_remote.c
+++ /dev/null
@@ -1,797 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-
-#include "dap_global_db.h"
-#include "dap_chain_global_db_remote.h"
-#include "dap_common.h"
-#include "dap_strfuncs.h"
-#include "dap_string.h"
-#include "dap_chain.h"
-#include "dap_time.h"
-
-#define LOG_TAG "dap_chain_global_db_remote"
-
-// Default time of a node address expired in hours
-#define NODE_TIME_EXPIRED_DEFAULT 720
-
-/**
- * @brief A function for a thread for reading a log list
- *
- * @param arg a pointer to the log list structure
- * @return Returns NULL.
- */
-static void *s_list_thread_proc(void *arg)
-{
-    dap_db_log_list_t *l_dap_db_log_list = (dap_db_log_list_t *)arg;
-    uint32_t l_time_store_lim_hours = dap_config_get_item_uint32_default(g_config, "resources", "dap_global_db_time_store_limit", 72);
-    uint64_t l_limit_time = l_time_store_lim_hours ? dap_nanotime_now() - dap_nanotime_from_sec(l_time_store_lim_hours * 3600) : 0;
-    for (dap_list_t *l_groups = l_dap_db_log_list->groups; l_groups; l_groups = dap_list_next(l_groups)) {
-        dap_db_log_list_group_t *l_group_cur = (dap_db_log_list_group_t *)l_groups->data;
-        char *l_del_group_name_replace = NULL;
-        char l_obj_type;
-        if (!dap_fnmatch("*.del", l_group_cur->name, 0)) {
-            l_obj_type = DAP_DB$K_OPTYPE_DEL;
-            size_t l_del_name_len = strlen(l_group_cur->name) - 4; //strlen(".del");
-            l_del_group_name_replace = DAP_NEW_SIZE(char, l_del_name_len + 1);
-            memcpy(l_del_group_name_replace, l_group_cur->name, l_del_name_len);
-            l_del_group_name_replace[l_del_name_len] = '\0';
-        } else {
-            l_obj_type = DAP_DB$K_OPTYPE_ADD;
-        }
-        uint64_t l_item_start = l_group_cur->last_id_synced + 1;
-        dap_nanotime_t l_time_now = dap_nanotime_now();
-        while (l_group_cur->count && l_dap_db_log_list->is_process) { // Number of records to be synchronized
-            size_t l_item_count = min(64, l_group_cur->count);
-            dap_store_obj_t *l_objs = dap_global_db_get_all_raw_sync(l_group_cur->name, l_item_start, &l_item_count);
-            pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
-            if (!l_dap_db_log_list->is_process){
-                pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-                if(l_objs)
-                    dap_store_obj_free(l_objs, l_item_count);
-                return NULL;
-            }
-            pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-
-            // go to next group
-            if (!l_objs)
-                break;
-            // set new start pos = lastitem pos + 1
-            l_item_start = l_objs[l_item_count - 1].id + 1;
-            l_group_cur->count -= l_item_count;
-            dap_list_t *l_list = NULL;
-            for (size_t i = 0; i < l_item_count; i++) {
-                dap_store_obj_t *l_obj_cur = l_objs + i;
-                if (!l_obj_cur)
-                    continue;
-                l_obj_cur->type = l_obj_type;
-                if (l_obj_cur->timestamp >> 32 == 0 ||
-                        l_obj_cur->timestamp > l_time_now ||
-                        l_obj_cur->group == NULL) {
-                    dap_chain_global_db_driver_delete(l_obj_cur, 1);
-                    continue;       // the object is broken
-                }
-                if (l_obj_type == DAP_DB$K_OPTYPE_DEL) {
-                    if (l_limit_time && l_obj_cur->timestamp < l_limit_time) {
-                        dap_chain_global_db_driver_delete(l_obj_cur, 1);
-                        continue;
-                    }
-                    DAP_DELETE((char *)l_obj_cur->group);
-                    l_obj_cur->group = dap_strdup(l_del_group_name_replace);
-                }
-                dap_db_log_list_obj_t *l_list_obj = DAP_NEW_Z(dap_db_log_list_obj_t);
-                uint64_t l_cur_id = l_obj_cur->id;
-                l_obj_cur->id = 0;
-                dap_global_db_pkt_t *l_pkt = dap_store_packet_single(l_obj_cur);
-                dap_hash_fast(l_pkt->data, l_pkt->data_size, &l_list_obj->hash);
-                dap_store_packet_change_id(l_pkt, l_cur_id);
-                l_list_obj->pkt = l_pkt;
-                l_list = dap_list_append(l_list, l_list_obj);
-            }
-            dap_store_obj_free(l_objs, l_item_count);
-            pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
-            // add l_list to list_write
-            l_dap_db_log_list->list_write = dap_list_concat(l_dap_db_log_list->list_write, l_list);
-            // init read list if it ended already
-            if(!l_dap_db_log_list->list_read)
-                l_dap_db_log_list->list_read = l_list;
-            pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-        }
-        DAP_DEL_Z(l_del_group_name_replace);
-        if (!l_dap_db_log_list->is_process)
-            return NULL;
-    }
-
-    pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
-    l_dap_db_log_list->is_process = false;
-    pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-    return NULL;
-}
-
-/**
- * @brief Starts a thread that readding a log list
- * @note instead dap_db_log_get_list()
- *
- * @param l_net net for sync
- * @param a_addr a pointer to the structure
- * @param a_flags flags
- * @return Returns a pointer to the log list structure if successful, otherwise NULL pointer.
- */
-dap_db_log_list_t* dap_db_log_list_start(dap_chain_net_t *l_net, dap_chain_node_addr_t a_addr, int a_flags)
-{
-#ifdef GDB_SYNC_ALWAYS_FROM_ZERO
-    a_flags |= F_DB_LOG_SYNC_FROM_ZERO;
-#endif
-
-    const char *l_net_name = NULL;
-    if(l_net && l_net->pub.name && l_net->pub.name[0]!='\0') {
-        l_net_name = l_net->pub.name;
-    }
-
-    //log_it(L_DEBUG, "Start loading db list_write...");
-    dap_db_log_list_t *l_dap_db_log_list = DAP_NEW_Z(dap_db_log_list_t);
-    // Add groups for the selected network only
-    dap_list_t *l_groups_masks = dap_chain_db_get_sync_groups(l_net_name);
-    if (a_flags & F_DB_LOG_ADD_EXTRA_GROUPS) {
-        dap_list_t *l_extra_groups_masks = dap_chain_db_get_sync_extra_groups(l_net_name);
-        l_groups_masks = dap_list_concat(l_groups_masks, l_extra_groups_masks);
-    }
-    dap_list_t *l_groups_names = NULL;
-    for (dap_list_t *l_cur_mask = l_groups_masks; l_cur_mask; l_cur_mask = dap_list_next(l_cur_mask)) {
-        char *l_cur_mask_data = ((dap_sync_group_item_t *)l_cur_mask->data)->group_mask;
-        l_groups_names = dap_list_concat(l_groups_names, dap_chain_global_db_driver_get_groups_by_mask(l_cur_mask_data));
-    }
-    dap_list_free(l_groups_masks);
-
-    static int16_t s_size_ban_list = -1;
-    static char **s_ban_list = NULL;
-
-    static int16_t s_size_white_list = -1;
-    static char **s_white_list = NULL;
-    static char **s_white_list_del = NULL;
-
-    if (s_size_ban_list == -1)
-        s_ban_list = dap_config_get_array_str(g_config, "stream_ch_chain", "ban_list_sync_groups", (uint16_t *)&s_size_ban_list);
-    if (s_size_white_list == -1) {
-        s_white_list = dap_config_get_array_str(g_config, "stream_ch_chain", "white_list_sync_groups", (uint16_t *)&s_size_white_list);
-        if (s_size_white_list > 0) {
-            s_white_list_del = DAP_NEW_SIZE(char *, s_size_white_list * sizeof(char *));
-            for (int i = 0; i < s_size_white_list; i++) {
-                s_white_list_del[i] = dap_strdup_printf("%s.del", s_white_list[i]);
-            }
-        }
-    }
-
-    /* delete if not condition */
-    if (s_size_white_list > 0) {
-        for (dap_list_t *l_group = l_groups_names; l_group; ) {
-            bool l_found = false;
-            for (int i = 0; i < s_size_white_list; i++) {
-                if (!dap_fnmatch(s_white_list[i], l_group->data, FNM_NOESCAPE) ||
-                        !dap_fnmatch(s_white_list_del[i], l_group->data, FNM_NOESCAPE)) {
-                    l_found = true;
-                    break;
-                }
-            }
-            if (!l_found) {
-                dap_list_t *l_tmp = l_group->next;
-                l_groups_names = dap_list_delete_link(l_groups_names, l_group);
-                l_group = l_tmp;
-            } else
-                l_group = dap_list_next(l_group);
-        }
-    } else if (s_size_ban_list > 0) {
-        for (dap_list_t *l_group = l_groups_names; l_group; ) {
-            bool l_found = false;
-            for (int i = 0; i < s_size_ban_list; i++) {
-                if (!dap_fnmatch(s_ban_list[i], l_group->data, FNM_NOESCAPE)) {
-                    dap_list_t *l_tmp = l_group->next;
-                    l_groups_names = dap_list_delete_link(l_groups_names, l_group);
-                    l_group = l_tmp;
-                    l_found = true;
-                    break;
-                }
-            }
-            if (l_found) continue;
-            l_group = dap_list_next(l_group);
-        }
-    }
-
-    l_dap_db_log_list->groups = l_groups_names; // repalce name of group with group item
-    for (dap_list_t *l_group = l_dap_db_log_list->groups; l_group; l_group = dap_list_next(l_group)) {
-        dap_db_log_list_group_t *l_sync_group = DAP_NEW_Z(dap_db_log_list_group_t);
-        l_sync_group->name = (char *)l_group->data;
-        if (a_flags & F_DB_LOG_SYNC_FROM_ZERO)
-            l_sync_group->last_id_synced = 0;
-        else
-            l_sync_group->last_id_synced = dap_db_get_last_id_remote(a_addr.uint64, l_sync_group->name);
-        l_sync_group->count = dap_chain_global_db_driver_count(l_sync_group->name, l_sync_group->last_id_synced + 1);
-        l_dap_db_log_list->items_number += l_sync_group->count;
-        l_group->data = (void *)l_sync_group;
-    }
-    l_dap_db_log_list->items_rest = l_dap_db_log_list->items_number;
-    if (!l_dap_db_log_list->items_number) {
-        DAP_DELETE(l_dap_db_log_list);
-        return NULL;
-    }
-    l_dap_db_log_list->is_process = true;
-    pthread_mutex_init(&l_dap_db_log_list->list_mutex, NULL);
-    pthread_create(&l_dap_db_log_list->thread, NULL, s_list_thread_proc, l_dap_db_log_list);
-    return l_dap_db_log_list;
-}
-
-/**
- * @brief Gets a number of objects from a log list.
- *
- * @param a_db_log_list a pointer to the log list structure
- * @return Returns the number if successful, otherwise 0.
- */
-size_t dap_db_log_list_get_count(dap_db_log_list_t *a_db_log_list)
-{
-    if(!a_db_log_list)
-        return 0;
-    size_t l_items_number;
-    pthread_mutex_lock(&a_db_log_list->list_mutex);
-    l_items_number = a_db_log_list->items_number;
-    pthread_mutex_unlock(&a_db_log_list->list_mutex);
-    return l_items_number;
-}
-
-/**
- * @brief Gets a number of rest objects from a log list.
- *
- * @param a_db_log_list a pointer to the log list structure
- * @return Returns the number if successful, otherwise 0.
- */
-size_t dap_db_log_list_get_count_rest(dap_db_log_list_t *a_db_log_list)
-{
-    if(!a_db_log_list)
-        return 0;
-    size_t l_items_rest;
-    pthread_mutex_lock(&a_db_log_list->list_mutex);
-    l_items_rest = a_db_log_list->items_rest;
-    pthread_mutex_unlock(&a_db_log_list->list_mutex);
-    return l_items_rest;
-}
-
-/**
- * @brief Gets an object from a list.
- *
- * @param a_db_log_list a pointer to the log list
- * @return Returns a pointer to the object.
- */
-dap_db_log_list_obj_t *dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
-{
-    if (!a_db_log_list)
-        return NULL;
-    pthread_mutex_lock(&a_db_log_list->list_mutex);
-    int l_is_process = a_db_log_list->is_process;
-    // check next item
-    dap_list_t *l_list = a_db_log_list->list_read;
-    if (l_list){
-        a_db_log_list->list_read = dap_list_next(a_db_log_list->list_read);
-        a_db_log_list->items_rest--;
-    }
-    pthread_mutex_unlock(&a_db_log_list->list_mutex);
-    //log_it(L_DEBUG, "get item n=%d", a_db_log_list->items_number - a_db_log_list->items_rest);
-    return l_list ? (dap_db_log_list_obj_t *)l_list->data : DAP_INT_TO_POINTER(l_is_process);
-}
-
-void dap_db_log_list_rewind(dap_db_log_list_t *a_db_log_list)
-{
-    if (!a_db_log_list)
-        return;
-    a_db_log_list->list_read = a_db_log_list->list_write;
-    a_db_log_list->items_rest = a_db_log_list->items_number;
-}
-
-/**
- * @brief Deallocates memory of a list item
- *
- * @param a_item a pointer to the list item
- * @returns (none)
- */
-void dap_db_log_list_delete_item(void *a_item)
-{
-    dap_db_log_list_obj_t *l_list_item = (dap_db_log_list_obj_t *)a_item;
-    DAP_DELETE(l_list_item->pkt);
-    DAP_DELETE(l_list_item);
-}
-
-/**
- * @brief Deallocates memory of a log list.
- *
- * @param a_db_log_list a pointer to the log list structure
- * @returns (none)
- */
-void dap_db_log_list_delete(dap_db_log_list_t *a_db_log_list)
-{
-    if(!a_db_log_list)
-        return;
-    // stop thread if it has created
-    if(a_db_log_list->thread) {
-        pthread_mutex_lock(&a_db_log_list->list_mutex);
-        a_db_log_list->is_process = false;
-        pthread_mutex_unlock(&a_db_log_list->list_mutex);
-        pthread_join(a_db_log_list->thread, NULL);
-    }
-    dap_list_free_full(a_db_log_list->groups, NULL);
-    dap_list_free_full(a_db_log_list->list_write, (dap_callback_destroyed_t)dap_db_log_list_delete_item);
-    pthread_mutex_destroy(&a_db_log_list->list_mutex);
-    DAP_DELETE(a_db_log_list);
-}
-
-/**
- * @brief Sets a current node adress.
- * @param a_address a current node adress
- * @param a_net_name a net name string
- * @return True if success, otherwise false
- */
-static bool dap_db_set_cur_node_addr_common(uint64_t a_address, char *a_net_name, time_t a_expire_time)
-{
-char	l_key [DAP_GLOBAL_DB_KEY_MAX];
-bool	l_ret;
-
-    if(!a_net_name)
-        return false;
-
-    dap_snprintf(l_key, sizeof(l_key) - 1, "cur_node_addr_%s", a_net_name);
-
-    if ( (l_ret = dap_global_db_set(DAP_GLOBAL_DB_LOCAL_GENERAL, l_key, &a_address, sizeof(a_address),
-                                    true, NULL, NULL)) == 0 ) {
-        dap_snprintf(l_key, sizeof(l_key) - 1, "cur_node_addr_%s_time", a_net_name);
-        l_ret = dap_global_db_set(DAP_GLOBAL_DB_LOCAL_GENERAL, l_key, &a_expire_time, sizeof(time_t),
-                                   true, NULL, NULL);
-    }
-
-    return l_ret;
-}
-
-/**
- * @brief Sets an adress of a current node and no expire time.
- *
- * @param a_address an adress of a current node
- * @param a_net_name a net name string
- * @return Returns true if siccessful, otherwise false
- */
-bool dap_db_set_cur_node_addr(uint64_t a_address, char *a_net_name )
-{
-    return dap_db_set_cur_node_addr_common(a_address,a_net_name,0);
-}
-
-/**
- * @brief Sets an address of a current node and expire time.
- *
- * @param a_address an address of a current node
- * @param a_net_name a net name string
- * @return Returns true if successful, otherwise false
- */
-bool dap_db_set_cur_node_addr_exp(uint64_t a_address, char *a_net_name )
-{
-    return dap_db_set_cur_node_addr_common(a_address,a_net_name, time(NULL));
-}
-
-/**
- * @brief Gets an adress of current node by a net name.
- *
- * @param a_net_name a net name string
- * @return Returns an adress if successful, otherwise 0.
- */
-uint64_t dap_chain_net_get_cur_node_addr_gdb_sync(char *a_net_name)
-{
-char	l_key[DAP_GLOBAL_DB_KEY_MAX], l_key_time[DAP_GLOBAL_DB_KEY_MAX];
-uint8_t *l_node_addr_data, *l_node_time_data;
-size_t l_node_addr_len = 0, l_node_time_len = 0;
-uint64_t l_node_addr_ret = 0;
-time_t l_node_time = 0;
-
-    if(!a_net_name)
-        return 0;
-
-    dap_snprintf(l_key, sizeof(l_key) - 1, "cur_node_addr_%s", a_net_name);
-    dap_snprintf(l_key_time, sizeof(l_key_time) - 1, "cur_node_addr_%s_time", a_net_name);
-
-    l_node_addr_data = dap_global_db_get_sync(DAP_GLOBAL_DB_LOCAL_GENERAL, l_key, &l_node_addr_len, NULL, NULL);
-    l_node_time_data = dap_global_db_get_sync(DAP_GLOBAL_DB_LOCAL_GENERAL, l_key_time, &l_node_time_len, NULL, NULL);
-
-    if(l_node_addr_data && (l_node_addr_len == sizeof(uint64_t)) )
-        l_node_addr_ret = *( (uint64_t *) l_node_addr_data );
-
-    if(l_node_time_data && (l_node_time_len == sizeof(time_t)) )
-        l_node_time = *( (time_t *) l_node_time_data );
-
-    DAP_DELETE(l_node_addr_data);
-    DAP_DELETE(l_node_time_data);
-
-    // time delta in seconds
-    static int64_t addr_time_expired = -1;
-    // read time-expired
-
-    if(addr_time_expired == -1) {
-        dap_string_t *l_cfg_path = dap_string_new("network/");
-        dap_string_append(l_cfg_path, a_net_name);
-        dap_config_t *l_cfg;
-
-        if((l_cfg = dap_config_open(l_cfg_path->str)) == NULL) {
-            log_it(L_ERROR, "Can't open default network config");
-            addr_time_expired = 0;
-        } else {
-            addr_time_expired = 3600 *
-                    dap_config_get_item_int64_default(l_cfg, "general", "node-addr-expired",
-                    NODE_TIME_EXPIRED_DEFAULT);
-        }
-        dap_string_free(l_cfg_path, true);
-    }
-
-    time_t l_dt = time(NULL) - l_node_time;
-    //NODE_TIME_EXPIRED
-    if(l_node_time && l_dt > addr_time_expired) {
-        l_node_addr_ret = 0;
-    }
-
-    return l_node_addr_ret;
-}
-
-/**
- * @brief Sets last id of a remote node.
- *
- * @param a_node_addr a node adress
- * @param a_id id
- * @param a_group a group name string
- * @return Returns true if successful, otherwise false.
- */
-bool dap_db_set_last_id_remote(uint64_t a_node_addr, uint64_t a_id, char *a_group)
-{
-char	l_key[DAP_GLOBAL_DB_KEY_MAX];
-
-    dap_snprintf(l_key, sizeof(l_key) - 1, "%"DAP_UINT64_FORMAT_U"%s", a_node_addr, a_group);
-    return dap_global_db_set(GROUP_LOCAL_NODE_LAST_ID,l_key, &a_id, sizeof(uint64_t), true, NULL, NULL ) == 0;
-}
-
-/**
- * @brief Gets last id of a remote node.
- *
- * @param a_node_addr a node adress
- * @param a_group a group name string
- * @return Returns id if successful, otherwise 0.
- */
-uint64_t dap_db_get_last_id_remote(uint64_t a_node_addr, char *a_group)
-{
-    char *l_node_addr_str = dap_strdup_printf("%"DAP_UINT64_FORMAT_U"%s", a_node_addr, a_group);
-    size_t l_id_len = 0;
-    byte_t *l_id = dap_global_db_get_sync(GROUP_LOCAL_NODE_LAST_ID, l_node_addr_str, &l_id_len, NULL, NULL);
-    uint64_t l_ret_id = 0;
-    if (l_id) {
-        if (l_id_len == sizeof(uint64_t))
-            memcpy(&l_ret_id, l_id, l_id_len);
-        DAP_DELETE(l_id);
-    }
-    DAP_DELETE(l_node_addr_str);
-    return l_ret_id;
-}
-
-/**
- * @brief Sets the last hash of a remote node.
- *
- * @param a_node_addr a node adress
- * @param a_chain a pointer to the chain stucture
- * @param a_hash a
- * @return true
- * @return false
- */
-bool dap_db_set_last_hash_remote(uint64_t a_node_addr, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_hash)
-{
-char	l_key[DAP_GLOBAL_DB_KEY_MAX];
-
-    dap_snprintf(l_key, sizeof(l_key) - 1, "%"DAP_UINT64_FORMAT_U"%s%s", a_node_addr, a_chain->net_name, a_chain->name);
-    return dap_global_db_set(GROUP_LOCAL_NODE_LAST_ID, l_key, a_hash, sizeof(dap_chain_hash_fast_t), true, NULL, NULL ) == 0;
-}
-
-/**
- * @brief Gets the last hash of a remote node.
- *
- * @param a_node_addr a node adress
- * @param a_chain a pointer to a chain structure
- * @return Returns a hash if successful.
- */
-dap_chain_hash_fast_t *dap_db_get_last_hash_remote(uint64_t a_node_addr, dap_chain_t *a_chain)
-{
-    char *l_node_chain_str = dap_strdup_printf("%ju%s%s", a_node_addr, a_chain->net_name, a_chain->name);
-    size_t l_hash_len = 0;
-    byte_t *l_hash = dap_global_db_get_sync(GROUP_LOCAL_NODE_LAST_ID,(const char*)l_node_chain_str, &l_hash_len,
-                                                 NULL, NULL);
-    DAP_DELETE(l_node_chain_str);
-    return (dap_chain_hash_fast_t *)l_hash;
-}
-
-/**
- * @brief Gets a size of an object.
- *
- * @param store_obj a pointer to the object
- * @return Returns the size.
- */
-static size_t dap_db_get_size_pdap_store_obj_t(pdap_store_obj_t store_obj)
-{
-    size_t size = sizeof(uint32_t) + 2 * sizeof(uint16_t) +
-            3 * sizeof(uint64_t) + dap_strlen(store_obj->group) +
-            dap_strlen(store_obj->key) + store_obj->value_len;
-    return size;
-}
-
-/**
- * @brief Multiples data into a_old_pkt structure from a_new_pkt structure.
- * @param a_old_pkt a pointer to the old object
- * @param a_new_pkt a pointer to the new object
- * @return Returns a pointer to the multiple object
- */
-dap_global_db_pkt_t *dap_store_packet_multiple(dap_global_db_pkt_t *a_old_pkt, dap_global_db_pkt_t *a_new_pkt)
-{
-    if (!a_new_pkt)
-        return a_old_pkt;
-    if (a_old_pkt)
-        a_old_pkt = (dap_global_db_pkt_t *)DAP_REALLOC(a_old_pkt,
-                                                       a_old_pkt->data_size + a_new_pkt->data_size + sizeof(dap_global_db_pkt_t));
-    else
-        a_old_pkt = DAP_NEW_Z_SIZE(dap_global_db_pkt_t, a_new_pkt->data_size + sizeof(dap_global_db_pkt_t));
-    memcpy(a_old_pkt->data + a_old_pkt->data_size, a_new_pkt->data, a_new_pkt->data_size);
-    a_old_pkt->data_size += a_new_pkt->data_size;
-    a_old_pkt->obj_count++;
-    return a_old_pkt;
-}
-
-/**
- * @brief Changes id in a packed structure.
- *
- * @param a_pkt a pointer to the packed structure
- * @param a_id id
- * @return (none)
- */
-void dap_store_packet_change_id(dap_global_db_pkt_t *a_pkt, uint64_t a_id)
-{
-    uint16_t l_gr_len = *(uint16_t*)(a_pkt->data + sizeof(uint32_t));
-    size_t l_id_offset = sizeof(uint32_t) + sizeof(uint16_t) + l_gr_len;
-    memcpy(a_pkt->data + l_id_offset, &a_id, sizeof(uint64_t));
-}
-
-/**
- * @brief Serializes an object into a packed structure.
- * @param a_store_obj a pointer to the object to be serialized
- * @return Returns a pointer to the packed sructure if successful, otherwise NULL.
- */
-dap_global_db_pkt_t *dap_store_packet_single(dap_store_obj_t *a_store_obj)
-{
-int len;
-unsigned char *pdata;
-
-    if (!a_store_obj)
-        return NULL;
-
-    uint32_t l_data_size_out = dap_db_get_size_pdap_store_obj_t(a_store_obj);
-    dap_global_db_pkt_t *l_pkt = DAP_NEW_SIZE(dap_global_db_pkt_t, l_data_size_out + sizeof(dap_global_db_pkt_t));
-
-    /* Fill packet header */
-    l_pkt->data_size = l_data_size_out;
-    l_pkt->obj_count = 1;
-    l_pkt->timestamp = 0;
-
-    /* Put serialized data into the payload part of the packet */
-    pdata = l_pkt->data;
-    *( (uint32_t *) pdata) =  a_store_obj->type;                pdata += sizeof(uint32_t);
-
-    len = dap_strlen(a_store_obj->group);
-    *( (uint16_t *) pdata) = (uint16_t) len;                    pdata += sizeof(uint16_t);
-    memcpy(pdata, a_store_obj->group, len);                     pdata += len;
-
-    *( (uint64_t *) pdata) = a_store_obj->id;                   pdata += sizeof(uint64_t);
-    *( (uint64_t *) pdata) = a_store_obj->timestamp;            pdata += sizeof(uint64_t);
-
-    len = dap_strlen(a_store_obj->key);
-    *( (uint16_t *) pdata) = (uint16_t) len;                    pdata += sizeof(uint16_t);
-    memcpy(pdata, a_store_obj->key, len);                       pdata += len;
-
-    *( (uint64_t *) pdata) = a_store_obj->value_len;            pdata += sizeof(uint64_t);
-    memcpy(pdata, a_store_obj->value, a_store_obj->value_len);  pdata += a_store_obj->value_len;
-
-    assert( (uint32_t)(pdata - l_pkt->data) == l_data_size_out);
-    return l_pkt;
-}
-
-/**
- * @brief Deserializes some objects from a packed structure into an array of objects.
- * @param pkt a pointer to the serialized packed structure
- * @param store_obj_count[out] a number of deserialized objects in the array
- * @return Returns a pointer to the first object in the array, if successful; otherwise NULL.
- */
-#if 0
-dap_store_obj_t *dap_global_db_pkt_deserialize(const dap_global_db_pkt_t *a_pkt, size_t *a_store_obj_count)
-{
-    if(!a_pkt || a_pkt->data_size < sizeof(dap_global_db_pkt_t))
-        return NULL;
-    uint64_t l_offset = 0;
-    uint32_t l_count = a_pkt->obj_count, l_cur_count;
-    uint64_t l_size = l_count <= UINT16_MAX ? l_count * sizeof(struct dap_store_obj) : 0;
-    dap_store_obj_t *l_store_obj = l_size? DAP_NEW_Z_SIZE(dap_store_obj_t, l_size) : NULL;
-    if (!l_store_obj || !l_size) {
-        log_it(L_ERROR, "Invalid size: can't allocate %"DAP_UINT64_FORMAT_U" bytes", l_size);
-        DAP_DEL_Z(l_store_obj)
-        return NULL;
-    }
-    for(l_cur_count = 0; l_cur_count < l_count; ++l_cur_count) {
-        dap_store_obj_t *l_obj = l_store_obj + l_cur_count;
-        uint16_t l_str_length;
-
-        uint32_t l_type;
-        if (l_offset+sizeof (uint32_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'type' field"); break;} // Check for buffer boundries
-        memcpy(&l_type, a_pkt->data + l_offset, sizeof(uint32_t));
-        l_obj->type = l_type;
-        l_offset += sizeof(uint32_t);
-
-        if (l_offset+sizeof (uint16_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'group_length' field"); break;} // Check for buffer boundries
-        memcpy(&l_str_length, a_pkt->data + l_offset, sizeof(uint16_t));
-        l_offset += sizeof(uint16_t);
-
-        if (l_offset + l_str_length > a_pkt->data_size || !l_str_length) {log_it(L_ERROR, "Broken GDB element: can't read 'group' field"); break;} // Check for buffer boundries
-        l_obj->group = DAP_NEW_Z_SIZE(char, l_str_length + 1);
-        memcpy(l_obj->group, a_pkt->data + l_offset, l_str_length);
-        l_offset += l_str_length;
-
-        if (l_offset+sizeof (uint64_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'id' field");
-                                                           DAP_DEL_Z(l_obj->group); break;} // Check for buffer boundries
-        memcpy(&l_obj->id, a_pkt->data + l_offset, sizeof(uint64_t));
-        l_offset += sizeof(uint64_t);
-
-        if (l_offset+sizeof (uint64_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'timestamp' field");
-                                                           DAP_DEL_Z(l_obj->group); break;} // Check for buffer boundries
-        memcpy(&l_obj->timestamp, a_pkt->data + l_offset, sizeof(uint64_t));
-        l_offset += sizeof(uint64_t);
-
-        if (l_offset+sizeof (uint16_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'key_length' field");
-                                                           DAP_DEL_Z(l_obj->group); break;} // Check for buffer boundries
-        memcpy(&l_str_length, a_pkt->data + l_offset, sizeof(uint16_t));
-        l_offset += sizeof(uint16_t);
-
-        if (l_offset + l_str_length > a_pkt->data_size || !l_str_length) {log_it(L_ERROR, "Broken GDB element: can't read 'key' field: len %s",
-                                                                                 l_str_length ? "OVER" : "NULL");
-                                                                          DAP_DEL_Z(l_obj->group); break;} // Check for buffer boundries
-        l_obj->key = DAP_NEW_Z_SIZE(char, l_str_length + 1);
-        memcpy((char *)l_obj->key, a_pkt->data + l_offset, l_str_length);
-        l_offset += l_str_length;
-
-        if (l_offset+sizeof (uint64_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'value_length' field");
-                                                           DAP_DEL_Z(l_obj->group); DAP_DEL_Z(l_obj->key); break;} // Check for buffer boundries
-        memcpy(&l_obj->value_len, a_pkt->data + l_offset, sizeof(uint64_t));
-        l_offset += sizeof(uint64_t);
-
-        if (l_offset + l_obj->value_len > a_pkt->data_size || !l_obj->value_len) {log_it(L_ERROR, "Broken GDB element: can't read 'value' field");
-                                                          DAP_DEL_Z(l_obj->group); DAP_DEL_Z(l_obj->key);break;} // Check for buffer boundries
-        l_obj->value = DAP_NEW_Z_SIZE(uint8_t, l_obj->value_len);
-        memcpy((char*)l_obj->value, a_pkt->data + l_offset, l_obj->value_len);
-        l_offset += l_obj->value_len;
-    }
-    if (a_pkt->data_size != l_offset) {
-        if (l_store_obj)
-            dap_store_obj_free(l_store_obj, l_cur_count);
-        return NULL;
-    }
-    // Return the number of completely filled dap_store_obj_t structures
-    // because l_cur_count may be less than l_count due to too little memory
-    if(a_store_obj_count)
-        *a_store_obj_count = l_cur_count;
-    return l_store_obj;
-}
-
-#endif
-
-
-
-
-
-
-dap_store_obj_t *dap_global_db_pkt_deserialize(const dap_global_db_pkt_t *a_pkt, size_t *a_store_obj_count)
-{
-uint32_t l_count, l_cur_count;
-uint64_t l_offset, l_size ;
-unsigned char *pdata, *pdata_end;
-dap_store_obj_t *l_store_obj_arr, *l_obj;
-
-    if(!a_pkt || a_pkt->data_size < sizeof(dap_global_db_pkt_t))
-        return NULL;
-
-    l_count = a_pkt->obj_count;
-    l_offset = 0;
-    l_size = l_count <= UINT16_MAX ? l_count * sizeof(struct dap_store_obj) : 0;
-
-    l_store_obj_arr = DAP_NEW_Z_SIZE(dap_store_obj_t, l_size);
-
-    if (!l_store_obj_arr || !l_size)
-    {
-        log_it(L_ERROR, "Invalid size: can't allocate %"DAP_UINT64_FORMAT_U" bytes, errno=%d", l_size, errno);
-        DAP_DEL_Z(l_store_obj_arr)
-        return NULL;
-    }
-
-
-
-    pdata = (unsigned char *) a_pkt->data;                                  /* Set <pdata> to begin of payload */
-    pdata_end = pdata + a_pkt->data_size;                                   /* Set <pdata_end> to end of payload area
-                                                                              will be used to prevent out-of-buffer case */
-    l_obj = l_store_obj_arr;
-
-    for ( l_cur_count = l_count ; l_cur_count; l_cur_count--, l_obj++ )
-    {
-        if ( (pdata  + sizeof (uint32_t)) > pdata_end )                     /* Check for buffer boundaries */
-            {log_it(L_ERROR, "Broken GDB element: can't read 'type' field"); break;}
-        l_obj->type = *((uint32_t *) pdata);
-        pdata += sizeof(uint32_t);
-
-
-        if ( (pdata  + sizeof (uint16_t)) > pdata_end )
-            {log_it(L_ERROR, "Broken GDB element: can't read 'group_length' field"); break;}
-        l_obj->group_len = *((uint16_t *) pdata);
-        pdata += sizeof(uint16_t);
-
-        if ( !l_obj->group_len )
-            {log_it(L_ERROR, "Broken GDB element: 'group_len' field is zero"); break;}
-
-
-        if ( (pdata + l_obj->group_len) > pdata_end )
-            {log_it(L_ERROR, "Broken GDB element: can't read 'group' field"); break;}
-        l_obj->group = DAP_NEW_Z_SIZE(char, l_obj->group_len + 1);
-        memcpy(l_obj->group, pdata, l_obj->group_len);
-        pdata += l_obj->group_len;
-
-
-
-        if ( (pdata + sizeof (uint64_t)) > pdata_end )
-            {log_it(L_ERROR, "Broken GDB element: can't read 'id' field"); break;}
-        l_obj->id = *((uint64_t *) pdata);
-        pdata += sizeof(uint64_t);
-
-
-
-        if ( (pdata + sizeof (uint64_t)) > pdata_end )
-            {log_it(L_ERROR, "Broken GDB element: can't read 'timestamp' field");  break;}
-        l_obj->timestamp = *((uint64_t *) pdata);
-        pdata += sizeof(uint64_t);
-
-
-        if ( (pdata + sizeof (uint16_t)) > pdata_end)
-            {log_it(L_ERROR, "Broken GDB element: can't read 'key_length' field"); break;}
-        l_obj->key_len = *((uint16_t *) pdata);
-        pdata += sizeof(uint16_t);
-
-        if ( !l_obj->key_len )
-            {log_it(L_ERROR, "Broken GDB element: 'key_length' field is zero"); break;}
-
-        if ((pdata + l_obj->key_len) > pdata_end)
-            {log_it(L_ERROR, "Broken GDB element: 'key_length' field is out from allocated memory"); break;}
-
-        l_obj->key_byte = DAP_NEW_SIZE(byte_t, l_obj->key_len + 1);
-        memcpy( l_obj->key_byte, pdata, l_obj->key_len);
-        l_obj->key_byte[l_obj->key_len] = '\0';
-        pdata += l_obj->key_len;
-
-
-        if ( (pdata + sizeof (uint64_t)) > pdata_end )
-            {log_it(L_ERROR, "Broken GDB element: can't read 'value_length' field"); break;}
-        l_obj->value_len = *((uint64_t *) pdata);
-        pdata += sizeof(uint64_t);
-
-        if (l_obj->value_len) {
-            if ( (pdata + l_obj->value_len) > pdata_end )
-                {log_it(L_ERROR, "Broken GDB element: can't read 'value' field"); break;}
-            l_obj->value = DAP_NEW_SIZE(uint8_t, l_obj->value_len);
-            memcpy(l_obj->value, pdata, l_obj->value_len);
-            pdata += l_obj->value_len;
-        }
-    }
-
-    assert(pdata <= pdata_end);
-
-    // Return the number of completely filled dap_store_obj_t structures
-    // because l_cur_count may be less than l_count due to too little memory
-    if (a_store_obj_count)
-        *a_store_obj_count = l_count;
-
-    return l_store_obj_arr;
-}
-
diff --git a/modules/global-db/dap_global_db.c b/modules/global-db/dap_global_db.c
deleted file mode 100644
index 61f5a5baa6453c8890aa85fe53150e57768b2f76..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_global_db.c
+++ /dev/null
@@ -1,2053 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Demlabs Ltd.   https://demlabs.net
- * Copyright  (c) 2022
- * All rights reserved.
-
- This file is part of DAP SDK the open source project
-
-    DAP SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#include "uthash.h"
-#include "dap_common.h"
-#include "dap_config.h"
-#include "dap_strfuncs.h"
-#include "dap_file_utils.h"
-#include "dap_chain_common.h"
-#include "dap_time.h"
-#include "dap_context.h"
-#include "dap_worker.h"
-#include "dap_stream_worker.h"
-#include "dap_proc_thread.h"
-#define LOG_TAG "dap_global_db"
-
-#include "dap_global_db.h"
-#include "dap_global_db_sync.h"
-#include "dap_chain_global_db_driver.h"
-
-int g_dap_global_db_debug_more = false;                                         /* Enable extensible debug output */
-
-
-// Queue I/O message op code
-enum queue_io_msg_opcode{
-    MSG_OPCODE_UNDEFINED = 0,
-    MSG_OPCODE_GET,
-    MSG_OPCODE_GET_RAW,
-    MSG_OPCODE_GET_DEL_TS,
-    MSG_OPCODE_GET_LAST,
-    MSG_OPCODE_GET_LAST_RAW,
-    MSG_OPCODE_GET_ALL,
-    MSG_OPCODE_GET_ALL_RAW,
-    MSG_OPCODE_SET,
-    MSG_OPCODE_SET_RAW,
-    MSG_OPCODE_SET_MULTIPLE,
-    MSG_OPCODE_PIN,
-    MSG_OPCODE_UNPIN,
-    MSG_OPCODE_DELETE,
-    MSG_OPCODE_FLUSH,
-    MSG_OPCODE_CONTEXT_EXEC
-};
-
-
-// Queue i/o message
-struct queue_io_msg{
-    enum queue_io_msg_opcode opcode; // Opcode
-
-    // For each message opcode we have only one callback
-    union{
-        dap_global_db_callback_t             callback;
-        dap_global_db_callback_result_t      callback_result;
-        dap_global_db_callback_result_raw_t  callback_result_raw;
-        dap_global_db_callback_results_t     callback_results;
-        dap_global_db_callback_results_raw_t callback_results_raw;
-    };
-    // Custom argument passed to the callback
-    void *  callback_arg;
-    union{
-        struct{ // Raw request
-            dap_store_obj_t * values_raw;
-            uint64_t values_raw_total;
-            uint64_t values_raw_shift;
-        };
-        struct{ //deserialized requests
-            // Different variant of message params
-            union{
-                // values for multile set
-                struct{
-                    dap_global_db_obj_t * values;
-                    size_t values_count;
-                };
-
-                // Values for get multiple request
-                struct{
-                    uint64_t values_shift; // For multiple records request here stores next request id
-                    uint64_t values_total; // Total values
-                    size_t values_page_size; // Maximum size of results page request. 0 means unlimited
-                    // TODO implement processing of this value
-                };
-
-                // Value for singe request
-                struct{
-                    void *  value;
-                    size_t  value_length;
-                    bool    value_is_pinned;
-                };
-
-            };
-            char * group;  // Group
-            char * key; // Key
-        };
-    };
-
-};
-
-
-
-static uint32_t s_global_db_version = 0; // Current GlobalDB version
-static pthread_cond_t s_check_db_cond = PTHREAD_COND_INITIALIZER; // Check version condition
-static pthread_mutex_t s_check_db_mutex = PTHREAD_MUTEX_INITIALIZER; // Check version condition mutex
-static int s_check_db_ret = 0; // Check version return value
-
-static const char * s_storage_path = NULL; // GlobalDB storage path
-static const char * s_driver_name = NULL; // GlobalDB driver name
-
-static dap_context_t * s_context = NULL;  // GlobalDB own context
-static struct dap_global_db_context * s_context_global_db = NULL; // GlobalDB own context custom extension
-
-// Version check& update functiosn
-static int s_check_db_version();
-static void s_check_db_version_callback_get (dap_global_db_context_t * a_global_db_context, int a_errno, const char * a_group, const char * a_key,
-                                             const void * a_value, const size_t a_value_len,
-                                             dap_nanotime_t value_ts,bool a_is_pinned, void * a_arg);
-static void s_check_db_version_callback_set (dap_global_db_context_t * a_global_db_context, int a_errno, const char * a_group, const char * a_key,
-                                             const void * a_value, const size_t a_value_len,
-                                             dap_nanotime_t value_ts,bool a_is_pinned, void * a_arg);
-
-// GlobalDB context start/stop callbacks
-static void s_context_callback_started( dap_context_t * a_context, void *a_arg);
-static void s_context_callback_stopped( dap_context_t * a_context, void *a_arg);
-
-
-// Opcode to string
-static const char *s_msg_opcode_to_str(enum queue_io_msg_opcode a_opcode);
-
-// Queue i/o processing callback
-static void s_queue_io_callback( dap_events_socket_t * a_es, void * a_arg);
-
-// Queue i/o message processing functions
-static bool s_msg_opcode_get(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_get_raw(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_get_del_ts(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_get_last(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_get_last_raw(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_get_all(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_get_all_raw(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_set(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_set_raw(struct queue_io_msg * a_msg);
-
-static bool s_msg_opcode_set_multiple_zc(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_pin(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_unpin(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_delete(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_flush(struct queue_io_msg * a_msg);
-static bool s_msg_opcode_context_exec(struct queue_io_msg * a_msg);
-
-// Free memor for queue i/o message
-static void s_queue_io_msg_delete( struct queue_io_msg * a_msg);
-
-// Delete history add and del
-static int s_record_del_history_add( char *a_key, char *a_group, uint64_t a_timestamp);
-static int s_record_del_history_del( const char *a_key,  const char *a_group);
-
-// Call notificators
-static void s_change_notify(dap_store_obj_t * a_store_obj, char a_opcode);
-
-
-
-
-
-/**
- * @brief dap_global_db_init
- * @param a_path
- * @param a_driver
- * @return
- */
-int dap_global_db_init(const char * a_storage_path, const char * a_driver_name)
-{
-    int l_rc = 0;
-    static bool s_is_check_version = false;
-
-    dap_global_db_sync_init();
-
-    if ( a_storage_path == NULL && s_storage_path == NULL ){
-        log_it(L_CRITICAL, "Can't initialize GlobalDB without storage path");
-    }
-
-    if ( a_driver_name == NULL && s_driver_name == NULL ){
-        log_it(L_CRITICAL, "Can't initialize GlobalDB without driver name");
-    }
-
-    // For reinitialization it could be NULL but s_storage_path and s_driver_name have to be defined before
-
-    if(a_storage_path)
-        s_storage_path = dap_strdup(a_storage_path);
-
-    if(a_driver_name)
-        s_driver_name = dap_strdup(a_driver_name);
-
-    // Debug config
-    g_dap_global_db_debug_more = dap_config_get_item_bool_default(g_config, "resources", "debug_more", false);
-
-
-    // Driver initalization
-    if( (l_rc = dap_db_driver_init(s_driver_name, s_storage_path, true))  )
-        return  log_it(L_CRITICAL, "Hadn't initialized DB driver \"%s\" on path \"%s\", code: %d",
-                       s_driver_name, s_storage_path, l_rc), l_rc;
-
-    // Create and run its own context
-    if(s_context == NULL){
-        s_context = dap_context_new(DAP_CONTEXT_TYPE_GLOBAL_DB);
-        s_context->_inheritor = s_context_global_db = DAP_NEW_Z(struct dap_global_db_context);
-        s_context_global_db->context = s_context;
-        if (dap_context_run(s_context, -1, DAP_CONTEXT_POLICY_DEFAULT, 0, DAP_CONTEXT_FLAG_WAIT_FOR_STARTED,
-                            s_context_callback_started, s_context_callback_stopped, NULL) != 0 ){
-            l_rc = -2;
-            goto lb_return;
-        }
-    }
-
-    // Check version and update if need it
-    if(!s_is_check_version){
-
-        s_is_check_version = true;
-
-        if ( (l_rc = s_check_db_version()) )
-            return  log_it(L_ERROR, "GlobalDB version changed, please export or remove old version!"), l_rc;
-    }
-
-lb_return:
-    if (l_rc == 0 )
-        log_it(L_NOTICE, "GlobalDB initialized");
-    else
-        log_it(L_CRITICAL, "GlobalDB wasn't initialized, code %d", l_rc);
-
-    return l_rc;
-}
-
-/**
- * @brief dap_global_db_deinit
- */
-void dap_global_db_deinit()
-{
-    dap_db_driver_deinit();
-    dap_global_db_sync_deinit();
-}
-
-/**
- * @brief dap_global_db_get
- * @details Get record value from GlobalDB group by key
- * @param a_group
- * @param a_key
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->callback_result = a_callback;
-    l_msg->callback_arg = a_arg;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get request for %s:%s", a_group, a_key);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_get
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get(struct queue_io_msg * a_msg)
-{
-    size_t l_count_records = 0;
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read( a_msg->group,
-                                                                     a_msg->key,
-                                                                     &l_count_records);
-    if(l_store_obj != NULL && l_count_records>=1){
-        if(a_msg->callback_result)
-            a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_SUCCESS, l_store_obj->group, l_store_obj->key,
-                               l_store_obj->value, l_store_obj->value_len, l_store_obj->timestamp,
-                               l_store_obj->flags & RECORD_PINNED, a_msg->callback_arg );
-        dap_store_obj_free(l_store_obj,l_count_records);
-    }else if(a_msg->callback_result)
-        a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_NO_RESULTS, a_msg->group, a_msg->key,
-                               NULL, 0, 0,0, a_msg->callback_arg );
-    return true;
-}
-
-/**
- * @brief dap_global_db_get_raw
- * @param a_group
- * @param a_key
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get_raw(const char * a_group, const char *a_key,dap_global_db_callback_result_raw_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET_RAW;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->callback_result_raw = a_callback;
-    l_msg->callback_arg = a_arg;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get_raw request for %s:%s", a_group, a_key);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_get_raw
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get_raw(struct queue_io_msg * a_msg)
-{
-    bool l_store_obj_delete = true;
-    size_t l_count_records = 0;
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read( a_msg->group,
-                                                                     a_msg->key,
-                                                                     &l_count_records);
-
-
-    if(a_msg->callback_result_raw)
-        l_store_obj_delete = a_msg->callback_result_raw (s_context_global_db,
-                                                         l_store_obj ? DAP_GLOBAL_DB_RC_SUCCESS:
-                                                                       DAP_GLOBAL_DB_RC_NO_RESULTS, l_store_obj,
-                                                          a_msg->callback_arg );
-    if (l_store_obj && l_store_obj_delete)
-        dap_store_obj_free(l_store_obj,l_count_records);
-    return true;
-}
-
-/**
- * @brief dap_global_db_get_del_ts
- * @param a_group
- * @param a_key
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get_del_ts(const char * a_group, const char *a_key,dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET_DEL_TS;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->callback_result = a_callback;
-    l_msg->callback_arg = a_arg;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get_del_ts request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get_del_ts request for \"%s\" group \"%s\" key" , a_group, a_key);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_get_del_ts
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get_del_ts(struct queue_io_msg * a_msg)
-{
-    uint64_t l_timestamp = 0;
-    dap_store_obj_t l_store_obj_del = { 0 };
-    char l_group[DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX];
-    size_t l_count_out = 0;
-    dap_store_obj_t *l_obj;
-
-    if(a_msg->key && a_msg->group){
-        l_store_obj_del.key = a_msg->key;
-        dap_snprintf(l_group, sizeof(l_group) - 1,  "%s.del", a_msg->group);
-        l_store_obj_del.group = l_group;
-
-        if (dap_chain_global_db_driver_is(l_store_obj_del.group, l_store_obj_del.key))
-        {
-            if ( (l_obj = dap_chain_global_db_driver_read(l_store_obj_del.group, l_store_obj_del.key, &l_count_out)) )
-            {
-                if ( (l_count_out > 1) )
-                    log_it(L_WARNING, "Got more then 1 records (%zu) for group '%s'", l_count_out, l_group);
-
-                l_timestamp = l_obj->timestamp;
-                dap_store_obj_free(l_obj, l_count_out);
-            }
-        }
-    }
-
-    if(l_timestamp){
-        if(a_msg->callback_result)
-            a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_SUCCESS, a_msg->group, a_msg->key,
-                               NULL, 0, l_timestamp,
-                               false, a_msg->callback_arg );
-    }else if(a_msg->callback_result)
-        a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_NO_RESULTS, a_msg->group, a_msg->key,
-                               NULL, 0, 0,0, a_msg->callback_arg );
-    return true;
-}
-
-/**
- * @brief dap_global_db_get_last
- * @details Get the last value in GlobalDB group
- * @param a_group
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get_last(const char * a_group, dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get_last");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET_LAST;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get_last request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get_last request for \"%s\" group", a_group);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_get_last
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get_last(struct queue_io_msg * a_msg)
-{
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read_last(a_msg->group);
-    if(l_store_obj){
-        if(a_msg->callback_result)
-            a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_SUCCESS, l_store_obj->group, l_store_obj->key,
-                               l_store_obj->value, l_store_obj->value_len, l_store_obj->timestamp,
-                               l_store_obj->flags & RECORD_PINNED, a_msg->callback_arg );
-        dap_store_obj_free(l_store_obj,1);
-    }else if(a_msg->callback_result)
-        a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_NO_RESULTS, a_msg->group, a_msg->key,
-                               NULL, 0, 0,0, a_msg->callback_arg );
-    return true;
-}
-
-/**
- * @brief dap_global_db_get_last_raw
- * @param a_group
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get_last_raw(const char * a_group, dap_global_db_callback_result_raw_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get_last");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET_LAST_RAW;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result_raw = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get_last request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get_last request for \"%s\" group", a_group);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_get_last_raw
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get_last_raw(struct queue_io_msg * a_msg)
-{
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read_last(a_msg->group);
-    bool l_store_obj_delete = true;
-    if(l_store_obj){
-        if(a_msg->callback_result)
-            l_store_obj_delete = a_msg->callback_result_raw(s_context_global_db, DAP_GLOBAL_DB_RC_SUCCESS, l_store_obj, a_msg->callback_arg );
-        if(l_store_obj_delete)
-            dap_store_obj_free(l_store_obj,1);
-    }else if(a_msg->callback_result)
-        a_msg->callback_result_raw(s_context_global_db, DAP_GLOBAL_DB_RC_NO_RESULTS, NULL, a_msg->callback_arg );
-    return true;
-}
-
-
-
-/**
- * @brief dap_global_db_get_all Get all records from the group
- * @param a_group
- * @param a_results_page_size
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get_all(const char * a_group,size_t a_results_page_size, dap_global_db_callback_results_t a_callback, void * a_arg )
-{
-    // TODO make usable a_results_page_size
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get_all");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET_ALL;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_results = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get_all request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get_all request for \"%s\" group", a_group);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_get_all
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get_all(struct queue_io_msg * a_msg)
-{
-    size_t l_values_count = 0;
-    if(! a_msg->values_total){ // First msg process
-        a_msg->values_total = dap_chain_global_db_driver_count(a_msg->group,0);
-    }
-    dap_store_obj_t *l_store_objs = dap_chain_global_db_driver_cond_read(a_msg->group, a_msg->values_shift , &l_values_count);
-    dap_global_db_obj_t *l_objs = NULL;
-    debug_if(g_dap_global_db_debug_more, L_DEBUG,"Get all request from group %s recieved %zu values from total %zu",a_msg->group,
-             l_values_count, a_msg->value_length );
-    // Form objs from store_objs
-    if(l_store_objs){
-        l_objs = DAP_NEW_Z_SIZE(dap_global_db_obj_t,sizeof(dap_global_db_obj_t)*l_values_count);
-        for(size_t i = 0; i < l_values_count; i++){
-            l_objs[i].id = l_store_objs[i].id;
-            l_objs[i].is_pinned = l_store_objs[i].flags & RECORD_PINNED;
-            l_objs[i].key = dap_strdup(l_store_objs[i].key);
-            l_objs[i].value = DAP_DUP_SIZE(l_store_objs[i].value, l_store_objs[i].value_len);
-            l_objs[i].value_len = l_store_objs[i].value_len;
-            l_objs[i].timestamp = l_store_objs[i].timestamp;
-        }
-    }
-
-    bool l_delete_objs = true;
-    // Call callback if present
-    if(a_msg->callback_results)
-        l_delete_objs = a_msg->callback_results(s_context_global_db,  l_objs? DAP_GLOBAL_DB_RC_SUCCESS:DAP_GLOBAL_DB_RC_NO_RESULTS
-                                , a_msg->group, a_msg->key,
-                    a_msg->values_total,a_msg->values_shift, l_values_count,
-                                 l_objs, a_msg->callback_arg );
-    // Clean memory
-    if(l_store_objs)
-        dap_store_obj_free(l_store_objs,l_values_count);
-    if(l_objs && l_delete_objs)
-        dap_global_db_objs_delete(l_objs,l_values_count);
-
-    // Here we also check if the reply was with zero values. To prevent endless loop we don't resend query request in such cases
-    if(a_msg->values_total && l_values_count){
-        // Check for values_shift overflow and update it
-        if( a_msg->values_shift < (UINT64_MAX - l_values_count) &&
-                l_values_count + a_msg->values_shift <= a_msg->values_total ){
-            a_msg->values_shift += l_values_count;
-
-        }else{
-            log_it(L_WARNING, "Values overflow, can't grow up, values_shift:%"DAP_UINT64_FORMAT_U"   values_total:%"DAP_UINT64_FORMAT_U"  values_current:%zu",  a_msg->values_shift, a_msg->values_total, l_values_count );
-            a_msg->values_shift += a_msg->values_total;
-        }
-
-        if(a_msg->values_shift < a_msg->values_total  ){ // Have to process callback again
-            int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,a_msg);
-            debug_if(g_dap_global_db_debug_more, L_NOTICE, "Resending get all request values_shift:%"DAP_UINT64_FORMAT_U"   values_total:%"DAP_UINT64_FORMAT_U"  values_current:%zu",  a_msg->values_shift, a_msg->values_total, l_values_count );
-            if ( l_ret ){
-                log_it(L_ERROR,"Can't resend i/o message for opcode GET_ALL after value shift %"
-                       DAP_UINT64_FORMAT_U" (total values %" DAP_UINT64_FORMAT_U") error code %d", a_msg->values_shift, a_msg->values_total, l_ret);
-            }else
-                return false; // Don't delete it because it just sent again to the queue
-        }
-    }
-    return true; // All values are sent
-}
-
-/**
- * @brief dap_global_db_get_all_raw
- * @param a_group
- * @param a_first_id
- * @param a_results_page_size
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_get_all_raw(const char * a_group, uint64_t a_first_id,size_t a_results_page_size, dap_global_db_callback_results_raw_t a_callback, void * a_arg )
-{
-    // TODO make usable a_results_page_size
-
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_get_all");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_GET_ALL_RAW ;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->values_raw_shift = a_first_id;
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_results_raw = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec get_all_raw request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent get_all request for \"%s\" group", a_group);
-    return l_ret;
-}
-
-/**
- * @brief Get all records in raw format inside GlobalDB context
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_get_all_raw(struct queue_io_msg * a_msg)
-{
-    size_t l_values_count = 0;
-    if(! a_msg->values_total){ // First msg process
-        a_msg->values_raw_total = dap_chain_global_db_driver_count(a_msg->group,0);
-    }
-    uint64_t l_values_raw_shift = a_msg->values_raw_shift;
-    dap_store_obj_t *l_store_objs = dap_chain_global_db_driver_cond_read(a_msg->group, l_values_raw_shift , &l_values_count);
-    bool l_store_objs_delete = true;
-    debug_if(g_dap_global_db_debug_more, L_DEBUG,"Get all raw request from group %s recieved %zu values from total %"DAP_UINT64_FORMAT_U,a_msg->group,
-             l_values_count, a_msg->values_raw_total );
-    // Call callback if present
-    if(a_msg->callback_results_raw)
-        l_store_objs_delete = a_msg->callback_results_raw(s_context_global_db,  l_store_objs? DAP_GLOBAL_DB_RC_SUCCESS:DAP_GLOBAL_DB_RC_NO_RESULTS
-                                , a_msg->group, a_msg->key,l_values_count, a_msg->values_raw_shift,
-                                 a_msg->values_raw_total,
-                                 l_store_objs, a_msg->callback_arg );
-    // Clean memory
-    if(l_store_objs && l_store_objs_delete)
-        dap_store_obj_free(l_store_objs,l_values_count);
-
-    // Here we also check if the reply was with zero values. To prevent endless loop we don't resend query request in such cases
-
-    if( a_msg->values_raw_total && l_values_count){
-        // Check for values_shift overflow and update it
-        if( a_msg->values_raw_total && l_values_count && a_msg->values_raw_shift< UINT64_MAX - l_values_count &&
-                l_values_count + a_msg->values_raw_shift <= a_msg->values_raw_total ){
-            l_values_raw_shift =  (a_msg->values_raw_shift += l_values_count);
-
-        } else{
-            log_it(L_WARNING, "Values overflow, can't grow up, values_raw_shift:%"DAP_UINT64_FORMAT_U"   values_raw_total:%"DAP_UINT64_FORMAT_U"  values_raw_current:%zu",
-                   l_values_raw_shift, a_msg->values_raw_total, l_values_count );
-            l_values_raw_shift = (a_msg->values_raw_shift = a_msg->values_raw_total);
-        }
-
-        if( a_msg->values_raw_total && l_values_count && a_msg->values_raw_shift < a_msg->values_raw_total){ // Have to process callback again
-            int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,a_msg);
-            debug_if(g_dap_global_db_debug_more, L_NOTICE, "Resending get all request values_raw_shift:%"DAP_UINT64_FORMAT_U"   values_raw_total:%"DAP_UINT64_FORMAT_U"  values_raw_current:%zu",  a_msg->values_raw_shift, a_msg->values_raw_total, l_values_count );
-
-            if ( l_ret ){
-                log_it(L_ERROR,"Can't resend i/o message for opcode GET_ALL_RAW after value shift %"
-                       DAP_UINT64_FORMAT_U" error code %d", a_msg->values_shift,l_ret);
-            }else
-                return false; // Don't delete it because it just sent again to the queue
-        }
-    }
-    return true; // All values are sent
-
-}
-
-
-/**
- * @brief Set GlobalDB record, identified with group and key
- * @param a_group Group name
- * @param a_key Key string
- * @param a_value Value data's pointer
- * @param a_value_length Value data's length
- * @param a_pin_value Pin value or not
- * @param a_callback  Callback executed after request processing
- * @param a_arg Argument passed to the callback
- * @return 0 if success, error code if not
- */
-int dap_global_db_set(const char * a_group, const char *a_key, const void * a_value, const size_t a_value_length, bool a_pin_value, dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_set");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_SET;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->value = DAP_DUP_SIZE(a_value, a_value_length);
-    l_msg->value_length = a_value_length;
-    l_msg->value_is_pinned = a_pin_value;
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec set request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent sent request for \"%s\" group \"%s\" key" , a_group, a_key);
-
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_set
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_set(struct queue_io_msg * a_msg)
-{
-    dap_store_obj_t l_store_data = { 0 };
-    dap_nanotime_t l_ts_now = dap_nanotime_now();
-    l_store_data.key = a_msg->key ;
-    l_store_data.flags =a_msg->value_is_pinned ? RECORD_PINNED : 0 ;
-    l_store_data.value_len = a_msg->value_length;
-    l_store_data.value =  a_msg->value;
-    l_store_data.group = (char*) a_msg->group;
-    l_store_data.timestamp = l_ts_now;
-
-    int l_res = dap_chain_global_db_driver_add(&l_store_data, 1);
-
-    if (l_res == 0){
-        s_record_del_history_del( a_msg->group, a_msg->key);
-        if(a_msg->callback_result){
-            a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_SUCCESS, a_msg->group, a_msg->key,
-                                   a_msg->value, a_msg->value_length, l_ts_now,
-                                   a_msg->value_is_pinned , a_msg->callback_arg );
-        }
-        s_change_notify(&l_store_data, DAP_DB$K_OPTYPE_ADD);
-
-    }else{
-        log_it(L_ERROR, "Save error for %s:%s code %d", a_msg->group,a_msg->key, l_res);
-        if(a_msg->callback_result)
-            a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_ERROR , a_msg->group, a_msg->key,
-                                   a_msg->value, a_msg->value_length, l_ts_now,
-                                   a_msg->value_is_pinned , a_msg->callback_arg );
-    }
-    if(a_msg->value)
-        DAP_DELETE(a_msg->value);
-    return true;
-}
-
-/**
- * @brief dap_global_db_set_unsafe
- * @param a_global_db_context
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_length
- * @param a_pin_value
- * @return
- */
-int dap_global_db_set_unsafe(dap_global_db_context_t * a_global_db_context, const char * a_group, const char *a_key, const void * a_value, const size_t a_value_length, bool a_pin_value )
-{
-    dap_store_obj_t l_store_data = { 0 };
-    dap_nanotime_t l_ts_now = dap_nanotime_now();
-    l_store_data.key = (char *)a_key ;
-    l_store_data.flags = a_pin_value ? RECORD_PINNED : 0 ;
-    l_store_data.value_len =  a_value_length;
-    l_store_data.value = (uint8_t *)a_value;
-    l_store_data.group = (char*) a_group;
-    l_store_data.timestamp = l_ts_now;
-
-    int l_res = dap_chain_global_db_driver_add(&l_store_data, 1);
-    if(l_res == 0 ){
-        s_record_del_history_del( a_group, a_key);
-        s_change_notify(&l_store_data, DAP_DB$K_OPTYPE_ADD);
-    }
-    return l_res;
-}
-
-
-/**
- * @brief dap_global_db_set_raw
- * @param a_store_objs
- * @param a_store_objs_count
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_set_raw(dap_store_obj_t * a_store_objs, size_t a_store_objs_count, dap_global_db_callback_results_raw_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_set");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_SET_RAW;
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_results_raw = a_callback;
-
-    l_msg->values_raw = dap_store_obj_copy(a_store_objs,a_store_objs_count) ;
-    l_msg->values_raw_total = a_store_objs_count;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec set_raw request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent set_raw request for %zu objects" , a_store_objs_count);
-    return l_ret;
-
-}
-
-/**
- * @brief s_msg_opcode_set_raw
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_set_raw(struct queue_io_msg * a_msg)
-{
-    int l_ret = -1;
-    size_t i=0;
-    if(a_msg->values_raw_total>0){
-        l_ret = dap_chain_global_db_driver_add(a_msg->values_raw,a_msg->values_raw_total);
-        int l_res_del = 0;
-        if(l_ret == 0) {
-            for(;  i < a_msg->values_raw_total ; i++ ) {
-                if (a_msg->values_raw[i].type == DAP_DB$K_OPTYPE_ADD)
-                    l_res_del = s_record_del_history_del(a_msg->values_raw[i].key , a_msg->values_raw[i].group);
-                else if (a_msg->values_raw[i].type == DAP_DB$K_OPTYPE_DEL)
-                    l_res_del = s_record_del_history_add((char*)a_msg->values_raw[i].key, a_msg->values_raw[i].group,
-                                                         a_msg->values_raw[i].timestamp);
-                if (!l_res_del) {
-                    s_change_notify(&a_msg->values_raw[i] , a_msg->values_raw[i].type);
-                }
-            }
-        }else
-            log_it(L_ERROR,"Can't save raw gdb data, code %d ", l_ret);
-    }
-    if(a_msg->callback_results_raw){
-        a_msg->callback_results_raw (s_context_global_db,  l_ret==0 ? DAP_GLOBAL_DB_RC_SUCCESS:
-                                        DAP_GLOBAL_DB_RC_ERROR, a_msg->group, a_msg->key,
-                               a_msg->values_raw_total, 0, a_msg->values_raw_total, a_msg->values_raw ,
-                                a_msg->callback_arg );
-    }
-    dap_store_obj_free(a_msg->values_raw, a_msg->values_raw_total);
-    return true;
-}
-
-/**
- * @brief dap_global_db_set_multiple_zc Set multiple values, without duplication (zero copy, values are freed after set callback execution )
- * @param a_group
- * @param a_values
- * @param a_values_count
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_set_multiple_zc(const char * a_group, dap_global_db_obj_t * a_values, size_t a_values_count, dap_global_db_callback_results_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_set");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_SET_MULTIPLE;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->values = a_values;
-    l_msg->values_count = a_values_count;
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_results = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec set_multiple request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent set_multiple request for \"%s\" group with %zu values" , a_group, a_values_count);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_set_multiple
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_set_multiple_zc(struct queue_io_msg * a_msg)
-{
-    int l_ret = -1;
-    size_t i=0;
-    if(a_msg->values_count>0){
-        dap_store_obj_t l_store_obj;
-        l_ret = 0;
-        for(;  i < a_msg->values_count && l_ret == 0  ; i++ ) {
-            memset(&l_store_obj,0,sizeof(l_store_obj));
-            l_store_obj.type = DAP_DB$K_OPTYPE_ADD;
-            l_store_obj.flags = a_msg->values[i].is_pinned;
-            l_store_obj.key =  a_msg->values[i].key;
-            l_store_obj.group = a_msg->group;
-            l_store_obj.value = a_msg->values[i].value;
-            l_store_obj.value_len = a_msg->values[i].value_len;
-            l_store_obj.timestamp = a_msg->values[i].timestamp;
-            s_record_del_history_del(a_msg->values[i].key, a_msg->group);
-            l_ret = dap_chain_global_db_driver_add(&l_store_obj,1);
-            s_change_notify(&l_store_obj , DAP_DB$K_OPTYPE_ADD);
-
-        }
-    }
-    bool l_delete_values = true;
-    if(a_msg->callback_results){
-        l_delete_values = a_msg->callback_results(s_context_global_db,  l_ret==0 ? DAP_GLOBAL_DB_RC_SUCCESS:
-                                        DAP_GLOBAL_DB_RC_ERROR, a_msg->group, a_msg->key,
-                               i, 0, a_msg->values_count, a_msg->values ,
-                                a_msg->callback_arg );
-    }
-    dap_global_db_objs_delete( a_msg->values, a_msg->values_count);
-
-    return true;
-}
-
-/**
- * @brief dap_global_db_pin
- * @param a_group
- * @param a_key
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_pin(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_pin");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_PIN;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec pin request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent pin request for \"%s\" group \"%s\" key" , a_group, a_key);
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_pin
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_pin(struct queue_io_msg * a_msg)
-{
-    size_t l_count_records = 0;
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read( a_msg->group,
-                                                                     a_msg->key,
-                                                                     &l_count_records);
-    if(l_store_obj != NULL && l_count_records>=1){
-        l_store_obj->flags |= RECORD_PINNED;
-        int l_res = dap_chain_global_db_driver_add(l_store_obj,1);
-        if(l_res == 0){
-            s_record_del_history_del(a_msg->key, a_msg->group);
-            s_change_notify(l_store_obj , l_store_obj->type );
-        }else
-            log_it(L_ERROR,"Can't save pinned gdb data, code %d ", l_res);
-
-        if(a_msg->callback_result)
-            a_msg->callback_result(s_context_global_db, l_res == 0? DAP_GLOBAL_DB_RC_SUCCESS : DAP_GLOBAL_DB_RC_ERROR, l_store_obj->group, l_store_obj->key,
-                               l_store_obj->value, l_store_obj->value_len, l_store_obj->timestamp,
-                               l_store_obj->flags & RECORD_PINNED, a_msg->callback_arg );
-        dap_store_obj_free(l_store_obj,l_count_records);
-    }else if(a_msg->callback_result)
-        a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_NO_RESULTS, a_msg->group, a_msg->key,
-                               NULL, 0, 0,0, a_msg->callback_arg );
-    return true;
-}
-
-/**
- * @brief dap_global_db_unpin
- * @param a_group
- * @param a_key
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_unpin(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_unpin");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_UNPIN;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec unpin request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent unpin request for \"%s\" group \"%s\" key" , a_group, a_key);
-
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_unpin
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_unpin(struct queue_io_msg * a_msg)
-{
-    size_t l_count_records = 0;
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read( a_msg->group,
-                                                                     a_msg->key,
-                                                                     &l_count_records);
-    if(l_store_obj != NULL && l_count_records>=1){
-        l_store_obj->flags ^= RECORD_PINNED;
-        int l_res = dap_chain_global_db_driver_add(l_store_obj,1);
-        if(l_res == 0){
-            s_record_del_history_del(a_msg->key, a_msg->group);
-            s_change_notify(l_store_obj , l_store_obj->type );
-        }else
-            log_it(L_ERROR,"Can't save pinned gdb data, code %d ", l_res);
-
-        if(a_msg->callback_result)
-            a_msg->callback_result(s_context_global_db, l_res == 0? DAP_GLOBAL_DB_RC_SUCCESS : DAP_GLOBAL_DB_RC_ERROR, l_store_obj->group, l_store_obj->key,
-                               l_store_obj->value, l_store_obj->value_len, l_store_obj->timestamp,
-                               l_store_obj->flags & RECORD_PINNED, a_msg->callback_arg );
-        dap_store_obj_free(l_store_obj,l_count_records);
-    }else if(a_msg->callback_result)
-        a_msg->callback_result(s_context_global_db, DAP_GLOBAL_DB_RC_NO_RESULTS, a_msg->group, a_msg->key,
-                               NULL, 0, 0,0, a_msg->callback_arg );
-    return true;
-}
-
-/**
- * @brief dap_global_db_delete
- * @param a_group
- * @param a_key
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_del(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_delete");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_DELETE;
-    l_msg->group = dap_strdup(a_group);
-    l_msg->key = dap_strdup(a_key);
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec del request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }else
-        debug_if(g_dap_global_db_debug_more, L_DEBUG, "Have sent del request for \"%s\" group \"%s\" key" , a_group, a_key);
-
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_delete
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_delete(struct queue_io_msg * a_msg)
-{
-
-    int l_res = dap_global_db_del_unsafe(s_context_global_db, a_msg->group, a_msg->key);
-
-    if(a_msg->callback_result){
-        a_msg->callback_result(s_context_global_db,  l_res==0 ? DAP_GLOBAL_DB_RC_SUCCESS:
-                                        DAP_GLOBAL_DB_RC_ERROR,
-                                a_msg->group, a_msg->key,
-                               NULL, 0, 0 , false, a_msg->callback_arg );
-    }
-
-    return true;
-}
-
-/**
- * @brief Deallocates memory of an objs array.
- * @param objs a pointer to the first object of the array
- * @param a_count a number of objects in the array
- * @return (none)
- */
-void dap_global_db_objs_delete(dap_global_db_obj_t *a_objs, size_t a_count)
-{
-dap_global_db_obj_t *l_obj;
-
-    if ( !a_objs || !a_count )                                              /* Sanity checks */
-        return;
-
-    for(l_obj = a_objs; a_count--; l_obj++)                                 /* Run over array's elements */
-    {
-        DAP_DELETE(l_obj->key);
-        DAP_DELETE(l_obj->value);
-    }
-
-    DAP_DELETE(a_objs);                                                     /* Finaly kill the the array */
-}
-
-/**
- * @brief The objs_get struct
- */
-struct objs_get{
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    dap_global_db_obj_t * objs;
-    size_t objs_count;
-};
-
-/**
- * @brief s_objs_get_callback
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_values_total
- * @param a_values_shift
- * @param a_values_count
- * @param a_values
- * @param a_arg
- */
-static bool s_objs_get_callback (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
-{
-    struct objs_get * l_args = (struct objs_get *) a_arg;
-    l_args->objs = a_values;
-    l_args->objs_count = a_values_count;
-    pthread_mutex_lock(&l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_cond_broadcast(&l_args->cond);
-    return false;
-}
-
-/**
- * @brief Sync (blocking) function for retrieving of list of GDB content
- * @param a_group
- * @param a_fist_id
- * @param a_objs_count
- * @return Group's objects
- */
-dap_global_db_obj_t* dap_global_db_get_all_sync(const char *a_group, size_t *a_objs_count)
-{
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "get_all sync call executes for group \"%s\"", a_group);
-    struct objs_get * l_args = DAP_NEW_Z(struct objs_get);
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-    dap_global_db_get_all(a_group, 0,s_objs_get_callback, l_args);
-    pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    dap_global_db_obj_t * l_ret = l_args->objs;
-    if(l_args->objs_count)
-        *a_objs_count = l_args->objs_count;
-    DAP_DELETE(l_args);
-    return l_ret;
-}
-
-
-/**
- * @brief The objs_set struct
- */
-struct sync_op_result{
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    int result;
-};
-
-/**
- * @brief s_objs_set_callback
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_len
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_sync_op_result_callback (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_len, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    struct sync_op_result * l_args = (struct sync_op_result *) a_arg;
-    l_args->result = a_rc;
-    pthread_mutex_lock(&l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_cond_broadcast(&l_args->cond);
-}
-
-/**
- * @brief Put value into the GlobalDB and waits for result
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_length
- * @param a_pin_value
- * @return 0 if success others if not
- */
-int dap_global_db_set_sync(const char * a_group, const char *a_key, const void * a_value, const size_t a_value_length, bool a_pin_value )
-{
-    struct sync_op_result * l_args = DAP_NEW_Z(struct sync_op_result);
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "set sync call executes for group \"%s\" key \"%s\"", a_group, a_key);
-
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-    dap_global_db_set(a_group, a_key,a_value,a_value_length, a_pin_value, s_sync_op_result_callback, l_args);
-    pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    int l_ret = l_args->result ;
-    DAP_DELETE(l_args);
-    return l_ret;
-}
-
-/**
- * @brief dap_global_db_pin_sync
- * @param a_group
- * @param a_key
- * @return
- */
-int dap_global_db_pin_sync(const char * a_group, const char *a_key)
-{
-    struct sync_op_result * l_args = DAP_NEW_Z(struct sync_op_result);
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "pin sync call executes for group \"%s\" key \"%s\"", a_group, a_key);
-
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-    dap_global_db_pin(a_group, a_key, s_sync_op_result_callback, l_args);
-    pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    int l_ret = l_args->result ;
-    DAP_DELETE(l_args);
-    return l_ret;
-}
-
-/**
- * @brief dap_global_db_unpin_sync
- * @param a_group
- * @param a_key
- * @return
- */
-int dap_global_db_unpin_sync(const char * a_group, const char *a_key)
-{
-    struct sync_op_result * l_args = DAP_NEW_Z(struct sync_op_result);
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "pin sync call executes for group \"%s\" key \"%s\"", a_group, a_key);
-
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-    dap_global_db_unpin(a_group, a_key, s_sync_op_result_callback, l_args);
-    pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    int l_ret = l_args->result ;
-    DAP_DELETE(l_args);
-    return l_ret;
-}
-
-/**
- * @brief dap_global_db_del_sync
- * @param a_group
- * @param a_key
- * @return
- */
-int dap_global_db_del_sync(const char * a_group, const char *a_key )
-{
-    struct sync_op_result * l_args = DAP_NEW_Z(struct sync_op_result);
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-    if (dap_global_db_del(a_group, a_key, s_sync_op_result_callback, l_args) == 0)
-        pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    else
-        l_args->result = -777;
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    int l_ret = l_args->result ;
-    DAP_DELETE(l_args);
-    return l_ret;
-}
-
-/**
- * @brief The store_obj_get struct
- */
-struct store_obj_get{
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    byte_t * data;
-    size_t data_size;
-    dap_nanotime_t ts;
-    bool is_pinned;
-};
-
-/**
- * @brief s_store_obj_get_callback
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_size
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_store_obj_get_callback (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key,
-                                 const void * a_value, const size_t a_value_size, dap_nanotime_t a_value_ts,
-                                 bool a_is_pinned, void * a_arg)
-{
-    struct store_obj_get * l_args = (struct store_obj_get *) a_arg;
-    assert(l_args);
-
-    if( a_value && a_value_size){
-        l_args->data = DAP_DUP_SIZE(a_value, a_value_size);
-        l_args->data_size = a_value_size;
-        l_args->ts = a_value_ts;
-        l_args->is_pinned = a_is_pinned;
-    }
-
-    pthread_mutex_lock(&l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_cond_broadcast(&l_args->cond);
-}
-
-/**
- * @brief dap_global_db_gr_get_sync
- * @param a_group
- * @param a_key
- * @param a_data_size
- * @param a_is_pinned
- * @param a_ts
- * @return
- */
-byte_t* dap_global_db_get_sync(const char * a_group,const char *a_key, size_t *a_data_size, bool *a_is_pinned, dap_nanotime_t * a_ts)
-{
-    struct store_obj_get * l_args = DAP_NEW_Z(struct store_obj_get);
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-
-
-
-    dap_global_db_get(a_group,a_key, s_store_obj_get_callback, l_args);
-    pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    byte_t * l_ret = l_args->data;
-    if( l_ret ){
-        if( a_data_size)
-            *a_data_size = l_args->data_size;
-        if( a_is_pinned)
-            *a_is_pinned = l_args->is_pinned;
-        if( a_ts)
-            *a_ts = l_args->ts;
-    }
-    DAP_DELETE(l_args);
-    return l_ret;
-}
-
-
-/**
- * @brief The store_objs_get struct
- */
-struct store_objs_get{
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    dap_store_obj_t * objs;
-    size_t objs_count;
-};
-
-static bool s_get_all_raw_sync_callback (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_store_obj_t * a_values, void * a_arg)
-{
-    struct store_objs_get * l_args = (struct store_objs_get *) a_arg;
-    l_args->objs = a_values;
-    l_args->objs_count = a_values_count;
-    pthread_mutex_lock(&l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_cond_broadcast(&l_args->cond);
-    return false;
-}
-
-dap_store_obj_t* dap_global_db_get_all_raw_sync(const char *a_group, uint64_t a_first_id, size_t *a_objs_count)
-{
-    struct store_objs_get * l_args = DAP_NEW_Z(struct store_objs_get);
-    debug_if(g_dap_global_db_debug_more, L_DEBUG, "get_all_raw sync call executes for group %s", a_group);
-
-    pthread_mutex_init(&l_args->mutex,NULL);
-    pthread_cond_init(&l_args->cond,NULL);
-    pthread_mutex_lock(&l_args->mutex);
-    dap_global_db_get_all_raw(a_group, a_first_id,0,s_get_all_raw_sync_callback, l_args);
-    pthread_cond_wait(&l_args->cond, &l_args->mutex);
-    pthread_mutex_unlock(&l_args->mutex);
-    pthread_mutex_destroy(&l_args->mutex);
-    pthread_cond_destroy(&l_args->cond);
-
-    dap_store_obj_t * l_ret = l_args->objs;
-    if(l_args->objs_count)
-        *a_objs_count = l_args->objs_count;
-    DAP_DELETE(l_args);
-    return l_ret;
-
-}
-
-/**
- * @brief dap_global_db_context_current
- * @return
- */
-dap_global_db_context_t * dap_global_db_context_current()
-{
-    dap_context_t * l_context = dap_context_current();
-    if(l_context->type == DAP_CONTEXT_TYPE_GLOBAL_DB)
-        return (dap_global_db_context_t *) l_context->_inheritor;
-    else
-        return NULL;
-
-}
-/**
- * @brief dap_global_db_del_unsafe
- * @param a_group
- * @param a_key
- * @return
- */
-int dap_global_db_del_unsafe(dap_global_db_context_t * a_global_db_context, const char * a_group, const char *a_key)
-{
-    dap_store_obj_t l_store_obj = {0};
-
-    l_store_obj.key = dap_strdup(a_key);
-    l_store_obj.group = dap_strdup(a_group);
-
-    int l_res = dap_chain_global_db_driver_delete(&l_store_obj, 1);
-
-    if (a_key) {
-        if (l_res >= 0) {
-            // add to Del group
-            l_res = s_record_del_history_add(l_store_obj.group, (char *)l_store_obj.key, dap_nanotime_now() );
-        }
-        // do not add to history if l_res=1 (already deleted)
-        if (!l_res) {
-            l_store_obj.key = l_store_obj.key;
-            s_change_notify(&l_store_obj, DAP_DB$K_OPTYPE_DEL);
-        }
-    }
-    DAP_DELETE(l_store_obj.key);
-    DAP_DELETE(l_store_obj.group);
-    return l_res;
-}
-
-/**
- * @brief dap_global_db_flush_sync
- * @return
- */
-int dap_global_db_flush_sync()
-{
-    return dap_db_driver_flush();
-}
-
-/**
- * @brief dap_global_db_flush
- * @param a_callback
- * @param a_arg
- * @return
- */
-int dap_global_db_flush( dap_global_db_callback_result_t a_callback, void * a_arg )
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_delete");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_FLUSH;
-    l_msg->callback_arg = a_arg;
-    l_msg->callback_result = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec flush request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }
-    return l_ret;
-}
-
-/**
- * @brief s_msg_opcode_flush
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_flush(struct queue_io_msg * a_msg)
-{
-    int l_res = dap_db_driver_flush();
-    if(a_msg->callback_result){
-        a_msg->callback_result(s_context_global_db,  l_res==0 ? DAP_GLOBAL_DB_RC_SUCCESS:
-                                        DAP_GLOBAL_DB_RC_ERROR,
-                                NULL,NULL,NULL, 0, 0 , false, a_msg->callback_arg );
-    }
-    return true;
-}
-
-/**
- * @brief Execute callback in GlobalDB context
- * @param a_callback  Callback function
- * @param arg Custom argument
- * @return 0 if success, others if not
- */
-int dap_global_db_context_exec (dap_global_db_callback_t a_callback, void * a_arg)
-{
-    if(s_context_global_db == NULL){
-        log_it(L_ERROR, "GlobalDB context is not initialized, can't call dap_global_db_context_exec");
-        return -666;
-    }
-    struct queue_io_msg * l_msg = DAP_NEW_Z(struct queue_io_msg);
-    l_msg->opcode = MSG_OPCODE_CONTEXT_EXEC;
-    l_msg->callback_arg = a_arg;
-    l_msg->callback = a_callback;
-
-    int l_ret = dap_events_socket_queue_ptr_send(s_context_global_db->queue_io,l_msg);
-    if (l_ret != 0){
-        log_it(L_ERROR, "Can't exec context_exec request, code %d", l_ret);
-        s_queue_io_msg_delete(l_msg);
-    }
-    return l_ret;
-
-}
-
-/**
- * @brief Execute callback in GlobalDB context
- * @param a_msg
- * @return
- */
-static bool s_msg_opcode_context_exec(struct queue_io_msg * a_msg)
-{
-    if(a_msg->callback)
-        a_msg->callback(s_context_global_db, a_msg->callback_arg );
-    return true;
-}
-
-/**
- * @brief s_msg_opcode_to_str
- * @param a_opcode
- * @return
- */
-static const char *s_msg_opcode_to_str(enum queue_io_msg_opcode a_opcode)
-{
-    switch(a_opcode){
-        case MSG_OPCODE_GET:            return "GET";
-        case MSG_OPCODE_GET_RAW:        return "GET_RAW";
-        case MSG_OPCODE_GET_LAST:       return "GET_LAST";
-        case MSG_OPCODE_GET_DEL_TS:     return "GET_DEL_TS";
-        case MSG_OPCODE_GET_LAST_RAW:   return "GET_LAST_RAW";
-        case MSG_OPCODE_GET_ALL:        return "GET_ALL";
-        case MSG_OPCODE_GET_ALL_RAW:    return "GET_ALL_RAW";
-        case MSG_OPCODE_SET:            return "SET";
-        case MSG_OPCODE_SET_MULTIPLE:   return "SET_MULTIPLE";
-        case MSG_OPCODE_SET_RAW:        return "SET_RAW";
-        case MSG_OPCODE_PIN:            return "PIN";
-        case MSG_OPCODE_UNPIN:          return "UNPIN";
-        case MSG_OPCODE_DELETE:         return "DELETE";
-        case MSG_OPCODE_FLUSH:          return "FLUSH";
-        case MSG_OPCODE_CONTEXT_EXEC:   return "CONTEXT_EXEC";
-        default:                        return "UNKNOWN";
-    }
-}
-
-/**
- * @brief s_queue_io_callback
- * @details Queue I/O process callback
- * @param a_es
- * @param a_arg
- */
-static void s_queue_io_callback( dap_events_socket_t * a_es, void * a_arg)
-{
-    (void) a_es;
-    struct queue_io_msg * l_msg = (struct queue_io_msg *) a_arg;
-    bool l_msg_delete = false; // if msg resent again it shouldn't be deleted in the end of callback
-    assert(l_msg);
-
-    debug_if(g_dap_global_db_debug_more, L_NOTICE, "Received GlobalDB I/O message with opcode %s", s_msg_opcode_to_str(l_msg->opcode) );
-
-    switch(l_msg->opcode){
-        case MSG_OPCODE_GET:          l_msg_delete = s_msg_opcode_get(l_msg); break;
-        case MSG_OPCODE_GET_RAW:      l_msg_delete = s_msg_opcode_get_raw(l_msg); break;
-        case MSG_OPCODE_GET_LAST:     l_msg_delete = s_msg_opcode_get_last(l_msg); break;
-        case MSG_OPCODE_GET_LAST_RAW: l_msg_delete = s_msg_opcode_get_last_raw(l_msg); break;
-        case MSG_OPCODE_GET_DEL_TS:   l_msg_delete = s_msg_opcode_get_del_ts(l_msg); break;
-        case MSG_OPCODE_GET_ALL:      l_msg_delete = s_msg_opcode_get_all(l_msg); break;
-        case MSG_OPCODE_GET_ALL_RAW:  l_msg_delete = s_msg_opcode_get_all_raw(l_msg); break;
-        case MSG_OPCODE_SET:          l_msg_delete = s_msg_opcode_set(l_msg); break;
-        case MSG_OPCODE_SET_MULTIPLE: l_msg_delete = s_msg_opcode_set_multiple_zc(l_msg); break;
-        case MSG_OPCODE_SET_RAW:      l_msg_delete = s_msg_opcode_set_raw(l_msg); break;
-        case MSG_OPCODE_PIN:          l_msg_delete = s_msg_opcode_pin(l_msg); break;
-        case MSG_OPCODE_UNPIN:        l_msg_delete = s_msg_opcode_unpin(l_msg); break;
-        case MSG_OPCODE_DELETE:       l_msg_delete = s_msg_opcode_delete(l_msg); break;
-        case MSG_OPCODE_FLUSH:        l_msg_delete = s_msg_opcode_flush(l_msg); break;
-        case MSG_OPCODE_CONTEXT_EXEC: l_msg_delete = s_msg_opcode_context_exec(l_msg); break;
-        default:{
-            log_it(L_WARNING, "Message with undefined opcode %d received in queue_io",
-                   l_msg->opcode);
-        }
-    }
-    if( l_msg_delete )
-        s_queue_io_msg_delete(l_msg);
-}
-
-
-/**
- * @brief Adds data to the history log
- *
- * @param a_store_data a pointer to an object
- * @return (none)
- */
-static void s_change_notify(dap_store_obj_t * a_store_obj, char a_opcode)
-{
-dap_list_t *l_items_list = dap_global_db_get_sync_groups_all();
-    while (l_items_list) {
-        for (dap_list_t *it = dap_global_db_get_sync_groups_all(); it; it = it->next) {
-            dap_sync_group_item_t *l_sync_group_item = (dap_sync_group_item_t *)it->data;
-            if (dap_fnmatch(l_sync_group_item->group_mask, a_store_obj->group, 0))
-                continue;
-            if(l_sync_group_item->callback_notify) {
-                 l_sync_group_item->callback_notify(l_sync_group_item->callback_arg,
-                            a_opcode,
-                            a_store_obj->group, a_store_obj->key,
-                            a_store_obj->value, a_store_obj->value_len);
-            }
-            return;
-        }
-        l_items_list = (l_items_list ==  dap_global_db_get_sync_groups_all()) ?
-                    dap_global_db_get_sync_groups_extra_all() : NULL;
-    }
-}
-
-
-/*
-* @brief s_record_del_history_del Deletes info about the deleted object from the database
-* @param a_key an object key string, looked like "0x8FAFBD00B..."
-* @param a_group a group name string, for example "kelvin-testnet.nodes"
-* @return If successful, returns true; otherwise, false.
-*/
-static int s_record_del_history_del( const char *a_group, const char *a_key)
-{
-dap_store_obj_t store_data = {0};
-char	l_group[DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX];
-int	l_res = 0;
-
-   if(!a_key)
-       return -1;
-
-   store_data.key =( char*) a_key;
-   dap_snprintf(l_group, sizeof(l_group) - 1, "%s.del", a_group);
-   store_data.group = l_group;
-
-   if ( dap_chain_global_db_driver_is(store_data.group, store_data.key) )
-       l_res = dap_chain_global_db_driver_delete(&store_data, 1);
-
-   return  l_res;
-}
-
-/**
- * @brief s_record_del_history_add Adds info about the deleted entry to the database.
- * @param a_key an object key string
- * @param a_group a group name string
- * @param a_timestamp an object time stamp
- * @return True if successful, false otherwise.
- */
-static int s_record_del_history_add( char *a_key, char *a_group, uint64_t a_timestamp)
-{
-dap_store_obj_t store_data = {0};
-char	l_group[DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX];
-int l_res = -1;
-
-    store_data.key = a_key;
-    // group = parent group + '.del'
-    dap_snprintf(l_group, sizeof(l_group) - 1, "%s.del", a_group);
-    store_data.group = l_group;
-    store_data.timestamp = a_timestamp;
-
-    l_res = dap_chain_global_db_driver_add(&store_data, 1);
-
-    return  l_res;
-}
-
-/**
- * @brief s_queue_io_msg_delete
- * @param a_msg
- */
-static void s_queue_io_msg_delete( struct queue_io_msg * a_msg)
-{
-    switch(a_msg->opcode){
-        case MSG_OPCODE_GET:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        case MSG_OPCODE_GET_RAW:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        case MSG_OPCODE_GET_DEL_TS:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        case MSG_OPCODE_GET_LAST:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-        break;
-        case MSG_OPCODE_GET_LAST_RAW:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-        break;
-        case MSG_OPCODE_GET_ALL:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-        break;
-        case MSG_OPCODE_GET_ALL_RAW:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-        break;
-        case MSG_OPCODE_SET:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        case MSG_OPCODE_SET_RAW:
-        break;
-        case MSG_OPCODE_SET_MULTIPLE:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-        break;
-        case MSG_OPCODE_PIN:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        case MSG_OPCODE_UNPIN:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        case MSG_OPCODE_DELETE:
-            if (a_msg->group)
-                DAP_DELETE(a_msg->group);
-            if (a_msg->key)
-                DAP_DELETE(a_msg->key);
-        break;
-        default:;
-    }
-
-   DAP_DELETE(a_msg);
-}
-
-
-/**
- * @brief s_context_callback_started
- * @details GlobalDB context started
- * @param a_context
- * @param a_arg
- */
-static void s_context_callback_started( dap_context_t * a_context, void *a_arg)
-{
-    // Init its own queue
-    s_context_global_db->queue_io = dap_context_create_queue(a_context, s_queue_io_callback);
-
-    // Create arrays of inputs for connection with workers and proc threads
-    s_context_global_db->queue_worker_io_input = DAP_NEW_Z_SIZE(dap_events_socket_t*, sizeof(dap_events_socket_t*) *
-                                                                dap_events_thread_get_count() );
-    s_context_global_db->queue_worker_ch_io_input = DAP_NEW_Z_SIZE(dap_events_socket_t*, sizeof(dap_events_socket_t*) *
-                                                                dap_events_thread_get_count() );
-    s_context_global_db->queue_worker_callback_input = DAP_NEW_Z_SIZE(dap_events_socket_t*, sizeof(dap_events_socket_t*) *
-                                                                dap_events_thread_get_count() );
-
-    s_context_global_db->queue_proc_thread_callback_input = DAP_NEW_Z_SIZE(dap_events_socket_t*, sizeof(dap_events_socket_t*) *
-                                                                dap_events_thread_get_count() );
-
-    // Fullful arrays with queue inputs
-    for (uint32_t i = 0; i < dap_events_thread_get_count(); i++){
-        dap_worker_t * l_worker = dap_events_worker_get(i);
-        dap_stream_worker_t * l_stream_worker = DAP_STREAM_WORKER(l_worker);
-        dap_proc_thread_t *l_proc_thread = dap_proc_thread_get(i);
-        assert(l_worker);
-        assert(l_proc_thread);
-
-        // Input for I/O operations on worker
-        s_context_global_db->queue_worker_io_input[i] =
-                dap_events_socket_queue_ptr_create_input( l_worker->queue_es_io);
-        dap_context_add( a_context, s_context_global_db->queue_worker_io_input[i]);
-
-        // Input for ch I/O operations on worker
-        s_context_global_db->queue_worker_ch_io_input[i] =
-                dap_events_socket_queue_ptr_create_input( l_stream_worker->queue_ch_io );
-        dap_context_add( a_context, s_context_global_db->queue_worker_ch_io_input[i]);
-
-        // Input for callback queue on worker
-        s_context_global_db->queue_worker_callback_input[i] =
-                dap_events_socket_queue_ptr_create_input( l_worker->queue_callback);
-        dap_context_add( a_context, s_context_global_db->queue_worker_callback_input[i]);
-
-        // Input for callback queue on proc thread
-        s_context_global_db->queue_proc_thread_callback_input[i] =
-                dap_events_socket_queue_ptr_create_input( l_proc_thread->proc_queue->esocket );
-        dap_context_add( a_context, s_context_global_db->queue_proc_thread_callback_input[i]);
-    }
-}
-
-
-/**
- * @brief s_context_callback_stopped
- * @details Stop and destroy callback for GlobalDB context
- * @param a_context
- * @param a_arg
- */
-static void s_context_callback_stopped( dap_context_t * a_context, void *a_arg)
-{
-    // Fullful arrays with queue inputs
-    for (uint32_t i = 0; i < dap_events_thread_get_count(); i++){
-        dap_events_socket_remove_and_delete_unsafe(s_context_global_db->queue_worker_io_input[i], true);
-        dap_events_socket_remove_and_delete_unsafe(s_context_global_db->queue_worker_callback_input[i], true);
-        dap_events_socket_remove_and_delete_unsafe(s_context_global_db->queue_proc_thread_callback_input[i], true);
-    }
-    DAP_DELETE(s_context_global_db->queue_worker_io_input);
-    DAP_DELETE(s_context_global_db->queue_worker_callback_input);
-    DAP_DELETE(s_context_global_db->queue_proc_thread_callback_input);
-    dap_events_socket_remove_and_delete_unsafe(s_context_global_db->queue_io, false);
-}
-
-
-
-
-/**
- * @brief s_check_db_version
- * @return
- */
-static int s_check_db_version()
-{
-    int l_ret;
-    pthread_mutex_lock(&s_check_db_mutex);
-    l_ret = dap_global_db_get(DAP_GLOBAL_DB_LOCAL_GENERAL, "gdb_version",s_check_db_version_callback_get, NULL);
-    if (l_ret == 0){
-        pthread_cond_wait(&s_check_db_cond, &s_check_db_mutex);
-        l_ret = s_check_db_ret;
-    }else{
-        log_it(L_CRITICAL, "Can't process get gdb_version request, code %d", l_ret);
-    }
-    pthread_mutex_unlock(&s_check_db_mutex);
-    return l_ret;
-}
-
-/**
- * @brief s_check_db_version_callback_get
- * @details Notify callback on reading GlobalDB version
- * @param a_errno
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_len
- * @param a_arg
- */
-static void s_check_db_version_callback_get (dap_global_db_context_t * a_global_db_context, int a_errno, const char * a_group, const char * a_key,
-                                             const void * a_value, const size_t a_value_len,
-                                             dap_nanotime_t value_ts, bool a_is_pinned, void * a_arg)
-{
-    int res = 0;
-
-
-    if(a_errno != 0){ // No DB at all
-        log_it(L_NOTICE, "No GlobalDB version at all, creating the new GlobalDB from scratch");
-        s_global_db_version = DAP_GLOBAL_DB_VERSION;
-        if ( (res = dap_global_db_set(DAP_GLOBAL_DB_LOCAL_GENERAL, "gdb_version", &s_global_db_version, sizeof(uint16_t),false,
-                          s_check_db_version_callback_set, NULL) ) != 0){
-            log_it(L_NOTICE, "Can't set GlobalDB version, code %d", res);
-            goto lb_exit;
-        }
-        return; // In this case the condition broadcast should happens in s_check_db_version_callback_set()
-
-    }
-
-    if (a_value_len == sizeof(uint16_t))
-        s_global_db_version = *(uint16_t *)a_value;
-
-    if( s_global_db_version < DAP_GLOBAL_DB_VERSION) {
-        log_it(L_NOTICE, "GlobalDB version %u, but %u required. The current database will be recreated",
-               s_global_db_version, DAP_GLOBAL_DB_VERSION);
-        dap_global_db_deinit();
-        // Database path
-        const char *l_storage_path = dap_config_get_item_str(g_config, "resources", "dap_global_db_path");
-        // Delete database
-        if(dap_file_test(l_storage_path) || dap_dir_test(l_storage_path)) {
-            // Backup filename: backup_global_db_ver.X_DATE_TIME.zip
-            char now[255];
-            time_t t = time(NULL);
-            strftime(now, 200, "%y.%m.%d-%H_%M_%S", localtime(&t));
-#ifdef DAP_BUILD_WITH_ZIP
-            char *l_output_file_name = dap_strdup_printf("backup_%s_ver.%d_%s.zip", dap_path_get_basename(l_storage_path), l_gdb_version, now);
-            char *l_output_file_path = dap_build_filename(l_storage_path, "../", l_output_file_name, NULL);
-            // Create backup as ZIP file
-            if(dap_zip_directory(l_storage_path, l_output_file_path)) {
-#else
-            char *l_output_file_name = dap_strdup_printf("backup_%s_ver.%d_%s.tar", dap_path_get_basename(s_storage_path), s_global_db_version, now);
-            char *l_output_file_path = dap_build_filename(l_storage_path, "../", l_output_file_name, NULL);
-            // Create backup as TAR file
-            if(dap_tar_directory(l_storage_path, l_output_file_path)) {
-#endif
-                // Delete database file or directory
-                dap_rm_rf(l_storage_path);
-            }
-            else {
-                log_it(L_ERROR, "Can't backup GlobalDB version %d", s_global_db_version);
-                res = -2;
-                goto lb_exit;
-            }
-            DAP_DELETE(l_output_file_name);
-            DAP_DELETE(l_output_file_path);
-        }
-        // Reinitialize database
-        res = dap_global_db_init(NULL, NULL);
-        // Save current db version
-        if(!res) {
-            s_global_db_version = DAP_GLOBAL_DB_VERSION;
-            if ( (res = dap_global_db_set(DAP_GLOBAL_DB_LOCAL_GENERAL, "gdb_version", &s_global_db_version, sizeof(uint16_t),false,
-                              s_check_db_version_callback_set, NULL) ) != 0){
-                log_it(L_NOTICE, "Can't set GlobalDB version, code %d", res);
-                goto lb_exit;
-            }
-            return; // In this case the condition broadcast should happens in s_check_db_version_callback_set()
-        }
-    } else if(s_global_db_version > DAP_GLOBAL_DB_VERSION) {
-        log_it(L_ERROR, "GlobalDB version %d is newer than supported version %d", s_global_db_version, DAP_GLOBAL_DB_VERSION);
-        res = -1;
-        goto lb_exit;
-    }
-    else {
-        log_it(L_NOTICE, "GlobalDB version %d", s_global_db_version);
-    }
-lb_exit:
-    s_check_db_ret = res;
-    pthread_mutex_lock(&s_check_db_mutex); //    To be sure thats we're on pthread_cond_wait() line
-    pthread_cond_broadcast(&s_check_db_cond);
-    pthread_mutex_unlock(&s_check_db_mutex); //  in calling thread
-}
-
-/**
- * @brief s_check_db_version_callback_set
- * @details GlobalDB version update callback
- * @param a_errno
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_len
- * @param a_arg
- */
-static void s_check_db_version_callback_set (dap_global_db_context_t * a_global_db_context,int a_errno, const char * a_group, const char * a_key,
-                                             const void * a_value, const size_t a_value_len,
-                                             dap_nanotime_t value_ts, bool a_is_pinned, void * a_arg)
-{
-    int l_res = 0;
-    if(a_errno != 0){
-        log_it(L_ERROR, "Can't process request for DB version, error code %d", a_errno);
-        l_res = a_errno;
-        goto lb_exit;
-    }
-
-    log_it(L_NOTICE, "GlobalDB version updated to %d", s_global_db_version);
-
-lb_exit:
-    s_check_db_ret = l_res;
-    pthread_mutex_lock(&s_check_db_mutex); //  in calling thread
-    pthread_cond_broadcast(&s_check_db_cond);
-    pthread_mutex_unlock(&s_check_db_mutex); //  in calling thread
-}
diff --git a/modules/global-db/dap_global_db_sync.c b/modules/global-db/dap_global_db_sync.c
deleted file mode 100644
index edea5ea2bdbff5cf289411b08fff62de152f96ce..0000000000000000000000000000000000000000
--- a/modules/global-db/dap_global_db_sync.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Demlabs Ltd.   https://demlabs.net
- * Copyright  (c) 2022
- * All rights reserved.
-
- This file is part of DAP SDK the open source project
-
-    DAP SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#include "dap_common.h"
-#include "dap_list.h"
-#include "dap_strfuncs.h"
-#include "dap_fnmatch.h"
-#include "dap_global_db.h"
-#include "dap_global_db_sync.h"
-
-#define LOG_TAG "dap_global_db_sync"
-
-static dap_list_t *s_sync_group_items = NULL;
-static dap_list_t *s_sync_group_extra_items = NULL;
-
-static void s_clear_sync_grp(void *a_elm);
-static int s_db_add_sync_group(dap_list_t **a_grp_list, dap_sync_group_item_t *a_item);
-
-void dap_global_db_sync_init()
-{
-
-}
-
-/**
- * @brief Deinitialize a database.
- * @note You should call this function at the end.
- * @return (none)
- */
-void dap_global_db_sync_deinit()
-{
-    dap_list_free_full(s_sync_group_items, s_clear_sync_grp);
-    dap_list_free_full(s_sync_group_extra_items, s_clear_sync_grp);
-    s_sync_group_extra_items = s_sync_group_items = NULL;
-}
-
-/**
- * @brief Adds a group name for synchronization.
- * @param a_net_name a net name string, for all net a_net_name=null
- * @param a_group_prefix a prefix of the group name
- * @param a_callback a callback function
- * @param a_arg a pointer to an argument
- * @return (none)
- */
-void dap_chain_global_db_add_sync_group(const char *a_net_name, const char *a_group_prefix, dap_global_db_obj_callback_notify_t a_callback, void *a_arg)
-{
-    dap_sync_group_item_t *l_item = DAP_NEW_Z(dap_sync_group_item_t);
-    l_item->net_name = dap_strdup(a_net_name);
-    l_item->group_mask = dap_strdup_printf("%s.*", a_group_prefix);
-    l_item->callback_notify = a_callback;
-    l_item->callback_arg = a_arg;
-    s_db_add_sync_group(&s_sync_group_items, l_item);
-}
-
-/**
- * @brief Adds a group name for synchronization with especially node addresses.
- * @param a_net_name a net name string, for all net a_net_name=null
- * @param a_group_mask a group mask string
- * @param a_callback a callabck function
- * @param a_arg a pointer to an argument
- * @return (none)
- */
-void dap_chain_global_db_add_sync_extra_group(const char *a_net_name, const char *a_group_mask, dap_global_db_obj_callback_notify_t a_callback, void *a_arg)
-{
-    dap_sync_group_item_t* l_item = DAP_NEW_Z(dap_sync_group_item_t);
-    l_item->net_name = dap_strdup(a_net_name);
-    l_item->group_mask = dap_strdup(a_group_mask);
-    l_item->callback_notify = a_callback;
-    l_item->callback_arg = a_arg;
-    s_db_add_sync_group(&s_sync_group_extra_items, l_item);
-}
-
-/**
- * @brief Gets a list of a group mask for s_sync_group_items.
- * @param a_net_name a net name string, for all net a_net_name=null
- * @return Returns a pointer to a list of a group mask.
- */
-dap_list_t* dap_chain_db_get_sync_groups(const char *a_net_name)
-{
-    if(!a_net_name)
-        return dap_list_copy(s_sync_group_items);
-
-    dap_list_t *l_list_out = NULL;
-    dap_list_t *l_list_group = s_sync_group_items;
-    while(l_list_group) {
-        if(!dap_strcmp(a_net_name, ((dap_sync_group_item_t*) l_list_group->data)->net_name)) {
-            l_list_out = dap_list_append(l_list_out, l_list_group->data);
-        }
-        l_list_group = dap_list_next(l_list_group);
-    }
-    return l_list_out;
-}
-
-/**
- * @brief Gets a list of a group mask for s_sync_group_items.
- * @param a_net_name a net name string, for all net a_net_name=null
- * @return Returns a pointer to a list of a group mask.
- */
-dap_list_t* dap_chain_db_get_sync_extra_groups(const char *a_net_name)
-{
-    if(!a_net_name)
-        return dap_list_copy(s_sync_group_extra_items);
-
-    dap_list_t *l_list_out = NULL;
-    dap_list_t *l_list_group = s_sync_group_extra_items;
-    while(l_list_group) {
-        if(!dap_strcmp(a_net_name, ((dap_sync_group_item_t*) l_list_group->data)->net_name)) {
-            l_list_out = dap_list_append(l_list_out, l_list_group->data);
-        }
-        l_list_group = dap_list_next(l_list_group);
-    }
-    return l_list_out;
-}
-
-/**
- * @brief dap_global_db_get_sync_groups_all
- * @return
- */
-dap_list_t * dap_global_db_get_sync_groups_all()
-{
-    return s_sync_group_items;
-}
-
-/**
- * @brief dap_global_db_get_sync_groups_extra_all
- * @return
- */
-dap_list_t * dap_global_db_get_sync_groups_extra_all()
-{
-    return s_sync_group_extra_items;
-}
-
-/**
- * @brief s_clear_sync_grp
- * @param a_elm
- */
-static void s_clear_sync_grp(void *a_elm)
-{
-    dap_sync_group_item_t *l_item = (dap_sync_group_item_t *)a_elm;
-    DAP_DELETE(l_item->group_mask);
-    DAP_DELETE(l_item);
-}
-
-/**
- * @brief s_db_add_sync_group
- * @param a_grp_list
- * @param a_item
- * @return
- */
-static int s_db_add_sync_group(dap_list_t **a_grp_list, dap_sync_group_item_t *a_item)
-{
-    for (dap_list_t *it = *a_grp_list; it; it = it->next) {
-        dap_sync_group_item_t *l_item = (dap_sync_group_item_t *)it->data;
-        if (!dap_strcmp(l_item->group_mask, a_item->group_mask) && !dap_strcmp(l_item->net_name, a_item->net_name)) {
-            log_it(L_WARNING, "Group mask '%s' already present in the list, ignore it", a_item->group_mask);
-            s_clear_sync_grp(a_item);
-            return -1;
-        }
-    }
-    *a_grp_list = dap_list_append(*a_grp_list, a_item);
-    return 0;
-}
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
deleted file mode 100644
index b3235a6ccbcd525bfc490807750f3e1b5eca4385..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <time.h>
-
-#include "dap_chain_global_db_driver.h"
-#include "dap_common.h"
-#include "dap_config.h"
-#include "dap_list.h"
-#include "dap_chain_common.h"
-#include "dap_global_db.h"
-#include "dap_global_db_sync.h"
-
-
-
diff --git a/modules/global-db/include/dap_chain_global_db_driver.h b/modules/global-db/include/dap_chain_global_db_driver.h
deleted file mode 100644
index d17c29da500695cbfcceac323b83fff8e064cbb0..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db_driver.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Authors:
- * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2019
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-
-    MODIFICATION HISTORY:
-        08-MAY-2022 RRL Added <ctx> field to the DB Driver interface table is called as <dap_db_driver_callbacks_t>;
-                        a set of limits - see DAP$K/SZ constant definitions;
-                        added lengths for the character fields.
- */
-
-#pragma once
-
-#include "dap_time.h"
-#include "dap_list.h"
-#include "dap_global_db.h"
-#include <stddef.h>
-#include <stdint.h>
-
-#define DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX   128UL                               /* A maximum size of group name */
-#define DAP_GLOBAL_DB_GROUPS_COUNT_MAX      1024UL                              /* A maximum number of groups */
-#define DAP_GLOBAL_DB_KEY_MAX               512UL                               /* A limit for the key's length in DB */
-#define DAP_GLOBAL_DB_MAX_OBJS              8192UL                              /* A maximum number of objects to be returned by
-                                                                                    read_srore_obj() */
-
-enum RECORD_FLAGS {
-    RECORD_COMMON = 0,    // 0000
-    RECORD_PINNED = 1,    // 0001
-};
-
-
-
-
-typedef int (*dap_db_driver_write_callback_t)(dap_store_obj_t*);
-typedef dap_store_obj_t* (*dap_db_driver_read_callback_t)(const char *,const char *, size_t *);
-typedef dap_store_obj_t* (*dap_db_driver_read_cond_callback_t)(const char *,uint64_t , size_t *);
-typedef dap_store_obj_t* (*dap_db_driver_read_last_callback_t)(const char *);
-typedef size_t (*dap_db_driver_read_count_callback_t)(const char *,uint64_t);
-typedef dap_list_t* (*dap_db_driver_get_groups_callback_t)(const char *);
-typedef bool (*dap_db_driver_is_obj_callback_t)(const char *, const char *);
-typedef int (*dap_db_driver_callback_t)(void);
-
-typedef struct dap_db_driver_callbacks {
-    dap_db_driver_write_callback_t      apply_store_obj;                    /* Performs an DB's action like: INSERT/DELETE/UPDATE for the given
-                                                                              'store object' */
-    dap_db_driver_read_callback_t       read_store_obj;                     /* Retreive 'store object' from DB */
-    dap_db_driver_read_last_callback_t  read_last_store_obj;
-    dap_db_driver_read_cond_callback_t  read_cond_store_obj;
-    dap_db_driver_read_count_callback_t read_count_store;
-
-    dap_db_driver_get_groups_callback_t get_groups_by_mask;                 /* Return a list of tables/groups has been matched to pattern */
-
-    dap_db_driver_is_obj_callback_t     is_obj;                             /* Check for existence of a record in the table/group for
-                                                                              a given <key> */
-
-    dap_db_driver_callback_t            transaction_start;                  /* Allocate DB context for consequtive operations */
-    dap_db_driver_callback_t            transaction_end;                    /* Release DB context at end of DB consequtive operations */
-
-    dap_db_driver_callback_t            deinit;
-    dap_db_driver_callback_t            flush;
-} dap_db_driver_callbacks_t;
-
-
-int     dap_db_driver_init(const char *driver_name, const char *a_filename_db, int a_mode_async);
-void    dap_db_driver_deinit(void);
-
-dap_store_obj_t* dap_store_obj_copy(dap_store_obj_t *a_store_obj, size_t a_store_count);
-void    dap_store_obj_free(dap_store_obj_t *a_store_obj, size_t a_store_count);
-DAP_STATIC_INLINE void dap_store_obj_free_one(dap_store_obj_t *a_store_obj) { return dap_store_obj_free(a_store_obj, 1); }
-int     dap_db_driver_flush(void);
-
-int dap_chain_global_db_driver_apply(dap_store_obj_t *a_store_obj, size_t a_store_count);
-int dap_chain_global_db_driver_add(pdap_store_obj_t a_store_obj, size_t a_store_count);
-int dap_chain_global_db_driver_delete(pdap_store_obj_t a_store_obj, size_t a_store_count);
-dap_store_obj_t* dap_chain_global_db_driver_read_last(const char *a_group);
-dap_store_obj_t* dap_chain_global_db_driver_cond_read(const char *a_group, uint64_t id, size_t *a_count_out);
-dap_store_obj_t* dap_chain_global_db_driver_read(const char *a_group, const char *a_key, size_t *count_out);
-bool dap_chain_global_db_driver_is(const char *a_group, const char *a_key);
-size_t dap_chain_global_db_driver_count(const char *a_group, uint64_t id);
-dap_list_t* dap_chain_global_db_driver_get_groups_by_mask(const char *a_group_mask);
diff --git a/modules/global-db/include/dap_chain_global_db_driver_cdb.h b/modules/global-db/include/dap_chain_global_db_driver_cdb.h
deleted file mode 100644
index 948d0ada5f1473735006fb61a178ea4dc1a48388..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db_driver_cdb.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Authors:
- * Konstantin Papizh <konstantin.papizh@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2019
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-//#include "cuttdb.h"
-#include "cdb_core.h"
-#include "dap_chain_global_db_driver.h"
-#define UNUSED(x) (void)(x)
-
-typedef struct _cdb_options {
-    int hsize;      // Main hash table size, 1%-10% of total records, immutable
-    int rcacheMB;   // Record cache in MBytes
-    int pcacheMB;   // Index page cache in MBytes
-} cdb_options, *pcdb_options;
-
-typedef struct _cdb_record {
-    char *key;
-    char *val;
-} cdb_record, *pcdb_record;
-
-int dap_db_driver_cdb_init(const char *, dap_db_driver_callbacks_t *);
-int dap_db_driver_cdb_deinit();
-int dap_db_driver_cdb_flush(void);
-
-int dap_db_driver_cdb_apply_store_obj(pdap_store_obj_t);
-
-dap_store_obj_t *dap_db_driver_cdb_read_last_store_obj(const char*);
-dap_store_obj_t *dap_db_driver_cdb_read_store_obj(const char*, const char*, size_t*);
-size_t dap_db_driver_cdb_read_count_store(const char *a_group, uint64_t a_id);
-dap_list_t* dap_db_driver_cdb_get_groups_by_mask(const char *a_group_mask);
-dap_store_obj_t* dap_db_driver_cdb_read_cond_store_obj(const char*, uint64_t, size_t*);
-bool dap_db_driver_cdb_is_obj(const char *a_group, const char *a_key);
diff --git a/modules/global-db/include/dap_chain_global_db_driver_mdbx.h b/modules/global-db/include/dap_chain_global_db_driver_mdbx.h
deleted file mode 100644
index d35ea6e78d92d1c065ab26eea886b2f02c16325d..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db_driver_mdbx.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Authors:
- * Gerasimov Dmitriy <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Ltd.   https://demlabs.net
- * Copyright  (c) 2021
- * All rights reserved.
-
- This file is part of DAP SDK the open source project
-
- DAP SDK is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "dap_chain_global_db_driver.h"
-
-int dap_db_driver_mdbx_init(const char*, dap_db_driver_callbacks_t *a_drv_dpt);
diff --git a/modules/global-db/include/dap_chain_global_db_driver_pgsql.h b/modules/global-db/include/dap_chain_global_db_driver_pgsql.h
deleted file mode 100644
index 78fb58e3dabc39d33ca5e4ddabd42f8dc513adef..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db_driver_pgsql.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include "dap_chain_global_db_driver.h"
-#ifdef DAP_CHAIN_GDB_ENGINE_PGSQL
-#include "/usr/include/postgresql/libpq-fe.h"
-#endif
-
-#define DAP_PGSQL_DBHASHNAME_LEN    8
-#define DAP_PGSQL_POOL_COUNT        16
-#define PGSQL_INVALID_TABLE         "42P01"
-
-int dap_db_driver_pgsql_init(const char *a_filename_dir, dap_db_driver_callbacks_t *a_drv_callback);
-int dap_db_driver_pgsql_deinit();
-int dap_db_driver_pgsql_start_transaction(void);
-int dap_db_driver_pgsql_end_transaction(void);
-int dap_db_driver_pgsql_apply_store_obj(dap_store_obj_t *a_store_obj);
-dap_store_obj_t *dap_db_driver_pgsql_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out);
-dap_store_obj_t *dap_db_driver_pgsql_read_last_store_obj(const char *a_group);
-dap_store_obj_t *dap_db_driver_pgsql_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out);
-dap_list_t *dap_db_driver_pgsql_get_groups_by_mask(const char *a_group_mask);
-size_t dap_db_driver_pgsql_read_count_store(const char *a_group, uint64_t a_id);
-bool dap_db_driver_pgsql_is_obj(const char *a_group, const char *a_key);
-int dap_db_driver_pgsql_flush();
diff --git a/modules/global-db/include/dap_chain_global_db_driver_sqlite.h b/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
deleted file mode 100644
index 500d67ed0f123948cd016acc71728d21c40ed6c7..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * CellFrame       https://cellframe.net
- * Sources         https://gitlab.demlabs.net/cellframe
- * Copyright  (c) 2017-2019
- * All rights reserved.
-
- This file is part of CellFrame SDK the open source project
-
-    CellFrame SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    CellFrame SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <sqlite3.h>
-#include "dap_chain_global_db_driver.h"
-
-#define DAP_SQLITE_POOL_COUNT                   16
-
-int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks_t *a_drv_callback);
-int dap_db_driver_sqlite_deinit(void);
diff --git a/modules/global-db/include/dap_chain_global_db_remote.h b/modules/global-db/include/dap_chain_global_db_remote.h
deleted file mode 100644
index d6dfc094bae752a521fc517e277f73a43a698bb7..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_chain_global_db_remote.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-#include <time.h>
-#include "dap_chain.h"
-#include "dap_chain_common.h"
-#include "dap_chain_net.h"
-#include "dap_chain_global_db_driver.h"
-#include "dap_global_db.h"
-
-#define F_DB_LOG_ADD_EXTRA_GROUPS   1
-#define F_DB_LOG_SYNC_FROM_ZERO     2
-
-#define GROUP_LOCAL_NODE_LAST_ID    "local.node.last_id"
-#define GROUP_LOCAL_NODE_ADDR       "local.node-addr"
-
-
-#define GDB_SYNC_ALWAYS_FROM_ZERO       // For debug purposes
-// for dap_db_log_list_xxx()
-
-typedef struct dap_global_db_pkt {
-    dap_nanotime_t timestamp;
-    uint64_t data_size;
-    uint32_t obj_count;
-    uint8_t data[];
-}__attribute__((packed)) dap_global_db_pkt_t;
-
-typedef struct dap_db_log_list_group {
-    char *name;
-    uint64_t last_id_synced;
-    uint64_t count;
-} dap_db_log_list_group_t;
-
-typedef struct dap_db_log_list_obj {
-    dap_global_db_pkt_t *pkt;
-    dap_hash_fast_t hash;
-} dap_db_log_list_obj_t;
-
-typedef struct dap_db_log_list {
-    dap_list_t *list_write; // writed list
-    dap_list_t *list_read; // readed list (inside list_write)
-    bool is_process;
-    size_t items_rest; // rest items to read from list_read
-    size_t items_number; // total items in list_write after reading from db
-    dap_list_t *groups;
-    pthread_t thread;
-    pthread_mutex_t list_mutex;
-} dap_db_log_list_t;
-
-// Set addr for current node
-bool dap_db_set_cur_node_addr(uint64_t a_address, char *a_net_name);
-bool dap_db_set_cur_node_addr_exp(uint64_t a_address, char *a_net_name );
-uint64_t dap_chain_net_get_cur_node_addr_gdb_sync(char *a_net_name);
-
-// Set last id for remote node
-bool dap_db_set_last_id_remote(uint64_t a_node_addr, uint64_t a_id, char *a_group);
-// Get last id for remote node
-uint64_t dap_db_get_last_id_remote(uint64_t a_node_addr, char *a_group);
-// Set last hash for chain for remote node
-bool dap_db_set_last_hash_remote(uint64_t a_node_addr, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_hash);
-// Get last hash for chain for remote node
-dap_chain_hash_fast_t *dap_db_get_last_hash_remote(uint64_t a_node_addr, dap_chain_t *a_chain);
-
-dap_global_db_pkt_t *dap_store_packet_single(dap_store_obj_t *a_store_obj);
-dap_global_db_pkt_t *dap_store_packet_multiple(dap_global_db_pkt_t *a_old_pkt, dap_global_db_pkt_t *a_new_pkt);
-dap_store_obj_t *dap_global_db_pkt_deserialize(const dap_global_db_pkt_t *a_pkt, size_t *a_objs_count);
-
-char *dap_store_packet_get_group(dap_global_db_pkt_t *a_pkt);
-uint64_t dap_store_packet_get_id(dap_global_db_pkt_t *a_pkt);
-void dap_store_packet_change_id(dap_global_db_pkt_t *a_pkt, uint64_t a_id);
-
-dap_db_log_list_t* dap_db_log_list_start(dap_chain_net_t *l_net, dap_chain_node_addr_t a_addr, int a_flags);
-size_t dap_db_log_list_get_count(dap_db_log_list_t *a_db_log_list);
-size_t dap_db_log_list_get_count_rest(dap_db_log_list_t *a_db_log_list);
-dap_db_log_list_obj_t *dap_db_log_list_get(dap_db_log_list_t *a_db_log_list);
-void dap_db_log_list_delete(dap_db_log_list_t *a_db_log_list);
-void dap_db_log_list_rewind(dap_db_log_list_t *a_db_log_list);
diff --git a/modules/global-db/include/dap_global_db.h b/modules/global-db/include/dap_global_db.h
deleted file mode 100644
index e83c3d28ab5d5a5ae046ac4f426611f225ba6940..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_global_db.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Demlabs Ltd.   https://demlabs.net
- * Copyright  (c) 2022
- * All rights reserved.
-
- This file is part of DAP SDK the open source project
-
-    DAP SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#pragma once
-#include <stddef.h>
-#include <stdbool.h>
-#include "dap_common.h"
-#include "dap_time.h"
-#include "dap_context.h"
-#include "dap_proc_queue.h"
-
-#define DAP_GLOBAL_DB_VERSION               2
-#define DAP_GLOBAL_DB_LOCAL_GENERAL         "local.general"
-
-// GlobalDB own context custom extension
-typedef struct dap_global_db_context
-{
-    dap_events_socket_t * queue_io; // I/O queue for GlobalDB i/o requests
-
-    dap_events_socket_t ** queue_worker_callback_input; // Worker callback queue input
-    dap_events_socket_t ** queue_worker_io_input; // Worker io queue input
-    dap_events_socket_t ** queue_worker_ch_io_input; // Worker ch io queue input
-    dap_events_socket_t ** queue_proc_thread_callback_input; // Worker callback queue input
-
-    dap_context_t * context; // parent pointer
-} dap_global_db_context_t;
-
-#define DAP_CONTEXT_TYPE_GLOBAL_DB   100
-
-enum    {
-    DAP_DB$K_OPTYPE_ADD  = 0x61,    /* 'a', */                              /* Operation Type = INSERT/ADD */
-    DAP_DB$K_OPTYPE_DEL  = 0x64,    /* 'd', */                              /*  -- // -- DELETE */
-    DAP_DB$K_OPTYPE_RETR = 0x72,    /* 'r', */                              /*  -- // -- RETRIEVE/GET */
-};
-
-typedef struct dap_store_obj {
-    uint64_t id;
-    dap_nanotime_t timestamp;
-    uint32_t type;                                                          /* Operation type: ADD/DELETE, see DAP_DB$K_OPTYPE_* constants */
-    uint8_t flags;                                                          /* RECORD_FLAGS */
-
-    char *group;
-    uint64_t group_len;
-
-    union {
-        const char *key;
-        byte_t * key_byte;
-    };
-    uint64_t key_len;
-
-    uint8_t *value;
-    uint64_t value_len;
-
-    dap_proc_queue_callback_t callback_proc_thread;                                           /* (Async mode only!) A call back to be called on request completion */
-    void *callback_proc_thread_arg;                                                     /* (Async mode only!) An argument of the callback rotine */
-} dap_store_obj_t, *pdap_store_obj_t;
-
-typedef struct dap_global_db_obj {
-    uint64_t id;
-    char *key;
-    dap_nanotime_t timestamp;
-    uint8_t *value;
-    size_t value_len;
-    bool is_pinned;
-
-} DAP_ALIGN_PACKED dap_global_db_obj_t;
-
-typedef void (*dap_global_db_callback_t) (dap_global_db_context_t * a_global_db_context, void * a_arg);
-
-/**
- *  @brief callback for single result
- *  @arg a_rc DAP_GLOBAL_DB_RC_SUCCESS if success others if not
- */
-typedef void (*dap_global_db_callback_result_t) (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value,
-                                                 const size_t a_value_size, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg);
-
-/**
- *  @brief callback for single raw result
- *  @arg a_rc DAP_GLOBAL_DB_RC_SUCCESS if success others if not
- *  @return true if we need to free a_store_obj, false otherwise.
- */
-typedef bool (*dap_global_db_callback_result_raw_t) (dap_global_db_context_t * a_global_db_context,int a_rc, dap_store_obj_t * a_store_obj, void * a_arg);
-
-
-/**
- *  @brief callback for multiple result, with pagination
- *  @arg a_rc DAP_GLOBAL_DB_RC_SUCCESS if success others if not
- *  @arg a_values_total Total values number
- *  @arg a_values_shift Current shift from beginning of values set
- *  @arg a_values_count Current number of items in a_values
- *  @arg a_values Current items (page of items)
- *  @arg a_arg Custom argument
- *  @return true if we need to free a_store_obj, false otherwise.
- */
-typedef bool (*dap_global_db_callback_results_t) (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key,
-                                                  const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg);
-/**
- *  @brief callback for multiple raw result, with pagination
- *  @arg a_rc DAP_GLOBAL_DB_RC_SUCCESS if success other sif not
- *  @arg a_values_total Total values number
- *  @arg a_values_shift Current shift from beginning of values set
- *  @arg a_values_count Current number of items in a_values
- *  @arg a_values Current items (page of items)
- *  @return true if we need to free a_store_obj, false otherwise.
- */
-typedef bool (*dap_global_db_callback_results_raw_t) (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key,
-                                                      const size_t a_values_current,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_store_obj_t * a_values, void * a_arg);
-// Return codes
-#define DAP_GLOBAL_DB_RC_SUCCESS         0
-#define DAP_GLOBAL_DB_RC_NO_RESULTS     -1
-#define DAP_GLOBAL_DB_RC_ERROR           -666
-
-extern int g_dap_global_db_debug_more;
-
-int dap_global_db_init(const char * a_path, const char * a_driver);
-void dap_global_db_deinit();
-
-
-// === Async functions ===
-int dap_global_db_get(const char * a_group, const char *a_key,dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_get_raw(const char * a_group, const char *a_key,dap_global_db_callback_result_raw_t a_callback, void * a_arg );
-
-int dap_global_db_get_del_ts(const char * a_group, const char *a_key,dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_get_last(const char * a_group, dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_get_last_raw(const char * a_group, dap_global_db_callback_result_raw_t a_callback, void * a_arg );
-int dap_global_db_get_all(const char * a_group, size_t l_results_page_size, dap_global_db_callback_results_t a_callback, void * a_arg );
-int dap_global_db_get_all_raw(const char * a_group, uint64_t a_first_id, size_t l_results_page_size, dap_global_db_callback_results_raw_t a_callback, void * a_arg );
-
-int dap_global_db_set(const char * a_group, const char *a_key, const void * a_value, const size_t a_value_length, bool a_pin_value, dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_set_raw(dap_store_obj_t * a_store_objs, size_t a_store_objs_count, dap_global_db_callback_results_raw_t a_callback, void * a_arg );
-
-// Set multiple. In callback writes total processed objects to a_values_total and a_values_count to the a_values_count as well
-int dap_global_db_set_multiple_zc(const char * a_group, dap_global_db_obj_t * a_values, size_t a_values_count, dap_global_db_callback_results_t a_callback, void * a_arg );
-int dap_global_db_pin(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_unpin(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_del(const char * a_group, const char *a_key, dap_global_db_callback_result_t a_callback, void * a_arg );
-int dap_global_db_flush( dap_global_db_callback_result_t a_callback, void * a_arg );
-
-// For context unification sometimes we need to exec inside GlobalDB context
-
-int dap_global_db_context_exec (dap_global_db_callback_t a_callback, void * a_arg);
-
-
-// Clear global_db_obj array
-void dap_global_db_objs_delete(dap_global_db_obj_t *a_objs, size_t a_count);
-
-// === Sync functions ===
-
-dap_global_db_obj_t* dap_global_db_get_all_sync(const char *a_group, size_t *a_objs_count);
-dap_store_obj_t* dap_global_db_get_all_raw_sync(const char *a_group, uint64_t a_first_id, size_t *a_objs_count);
-int dap_global_db_set_sync(const char * a_group, const char *a_key, const void * a_value, const size_t a_value_length, bool a_pin_value );
-int dap_global_db_pin_sync(const char * a_group, const char *a_key);
-int dap_global_db_unpin_sync(const char * a_group, const char *a_key);
-
-byte_t* dap_global_db_get_sync(const char * a_group,const char *a_key, size_t *a_data_size, bool *a_is_pinned, dap_nanotime_t * a_ts);
-int dap_global_db_del_sync(const char * a_group, const char *a_key);
-int dap_global_db_flush_sync();
-
-// ==== Unsafe functions (for own context call only) ===
-dap_global_db_context_t * dap_global_db_context_current();
-int dap_global_db_del_unsafe(dap_global_db_context_t * a_global_db_context, const char * a_group, const char *a_key);
-int dap_global_db_set_unsafe(dap_global_db_context_t * a_global_db_context, const char * a_group, const char *a_key, const void * a_value, const size_t a_value_length, bool a_pin_value );
-
diff --git a/modules/global-db/include/dap_global_db_sync.h b/modules/global-db/include/dap_global_db_sync.h
deleted file mode 100644
index 4b132e3e0ce6e0b48dbccdd1ea990626454c79a4..0000000000000000000000000000000000000000
--- a/modules/global-db/include/dap_global_db_sync.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Demlabs Ltd.   https://demlabs.net
- * Copyright  (c) 2022
- * All rights reserved.
-
- This file is part of DAP SDK the open source project
-
-    DAP SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#pragma once
-#include <stddef.h>
-#include <dap_list.h>
-typedef void (*dap_global_db_obj_callback_notify_t) (void * a_arg, const char a_op_code, const char * a_group,
-                                                     const char * a_key, const void * a_value, const size_t a_value_len);
-
-// Callback table item
-typedef struct dap_sync_group_item {
-    char *group_mask;
-    char *net_name;
-    dap_global_db_obj_callback_notify_t callback_notify;
-    void * callback_arg;
-} dap_sync_group_item_t;
-
-void dap_global_db_sync_init();
-void dap_global_db_sync_deinit();
-
-/**
- * Setup callbacks and filters
- */
-// Add group name that will be synchronized
-void dap_chain_global_db_add_sync_group(const char *a_net_name, const char *a_group_prefix, dap_global_db_obj_callback_notify_t a_callback, void *a_arg);
-void dap_chain_global_db_add_sync_extra_group(const char *a_net_name, const char *a_group_mask, dap_global_db_obj_callback_notify_t a_callback, void *a_arg);
-dap_list_t *dap_chain_db_get_sync_groups(const char *a_net_name);
-dap_list_t *dap_chain_db_get_sync_extra_groups(const char *a_net_name);
-dap_list_t * dap_global_db_get_sync_groups_all();
-dap_list_t * dap_global_db_get_sync_groups_extra_all();
diff --git a/modules/mempool/CMakeLists.txt b/modules/mempool/CMakeLists.txt
index 95fc039743247a984eed5068182cc11958ac4d6c..42a266f33071d3f7125f2369c13c5a05803073ab 100644
--- a/modules/mempool/CMakeLists.txt
+++ b/modules/mempool/CMakeLists.txt
@@ -6,6 +6,6 @@ file(GLOB DAP_CHAIN_MEMPOOL_HDR include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_MEMPOOL_SRC} ${DAP_CHAIN_MEMPOOL_HDR})
 
-target_link_libraries(${PROJECT_NAME} dap_http_server dap_client dap_chain_net dap_chain_global_db dap_core)
+target_link_libraries(${PROJECT_NAME} dap_http_server dap_client dap_chain_net dap_global_db dap_core)
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index 1fe3d74b3a470c33b1fa7fcf140a7ba4c63ed637..dea1a1816f2bd222c965b0d1ba5862f83694ad4b 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -67,7 +67,7 @@
 
 #define LOG_TAG "dap_chain_mempool"
 
-static bool s_tx_create_massive_gdb_save_callback( dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
+static bool s_tx_create_massive_gdb_save_callback( dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,
                                                    const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg);
 
 int dap_datum_mempool_init(void)
@@ -461,7 +461,7 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
  * @param a_values
  * @param a_arg
  */
-static bool s_tx_create_massive_gdb_save_callback (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
+static bool s_tx_create_massive_gdb_save_callback (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,
                                                    const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
 
 {
diff --git a/modules/net/CMakeLists.txt b/modules/net/CMakeLists.txt
index d54d45da2705c42468cc2e9f73c32be903548cf0..3782bc07f981e18f88a331c8acbac5f5297764cf 100644
--- a/modules/net/CMakeLists.txt
+++ b/modules/net/CMakeLists.txt
@@ -38,16 +38,16 @@ add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRCS} ${DAP_CHAIN_NET_HEADERS
 
 if(WIN32)
   target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_io dap_notify_srv dap_cli_server dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_wallet dap_chain_net_srv dap_stream_ch_chain_voting
-                            dap_chain_mempool dap_chain_global_db dap_chain_cs_none)
+                            dap_chain_mempool dap_global_db dap_chain_cs_none)
 endif()
 
 if(LINUX)
     target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_io dap_notify_srv dap_cli_server dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_stream_ch_chain_voting dap_chain
-      dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_chain_global_db dap_chain_cs_none
+      dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_global_db dap_chain_cs_none
       resolv )
 elseif(BSD)
     target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_io dap_notify_srv dap_cli_server dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_stream_ch_chain_voting dap_chain
-      dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_chain_global_db dap_chain_cs_none )
+      dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_global_db dap_chain_cs_none )
 endif()
 
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index ec020ed75a6f71f883e5cb13f857fc4c40ae2425..cb37f7a51c499b03d435761c888b70ef13bdb34a 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -100,7 +100,7 @@
 #include "dap_chain_cs_none.h"
 #include "dap_client_http.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 
 #include "dap_stream_ch_chain_net_pkt.h"
 #include "dap_stream_ch_chain_net.h"
@@ -129,7 +129,7 @@ struct balancer_link_request {
     dap_chain_net_t *net;
     dap_worker_t *worker;
     bool from_http;
-    bool link_replace;
+    int link_replace_tries;
 };
 
 struct net_link {
@@ -270,10 +270,8 @@ static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, c
 static void s_chain_callback_notify(void * a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, void *a_atom, size_t a_atom_size);
 static int s_cli_net(int argc, char ** argv, char **str_reply);
 static uint8_t *s_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash);
-static bool s_balancer_start_dns_request(dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_info, bool a_link_replace);
-static bool s_balancer_start_http_request(dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_info, bool a_link_replace);
 static void s_prepare_links_from_balancer(dap_chain_net_t *a_net);
-static bool s_new_balancer_link_request(dap_chain_net_t *a_net);
+static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_replace_tries);
 
 static bool s_seed_mode = false;
 
@@ -642,7 +640,7 @@ static void s_chain_callback_notify(void *a_arg, dap_chain_t *a_chain, dap_chain
 }
 
 /**
- * @brief added like callback in dap_chain_global_db_add_sync_group
+ * @brief added like callback in dap_global_db_add_sync_group
  *
  * @param a_arg arguments. Can be network object (dap_chain_net_t)
  * @param a_op_code object type (f.e. l_net->type from dap_store_obj)
@@ -868,6 +866,21 @@ static void s_node_link_callback_connected(dap_chain_node_client_t * a_node_clie
 
 }
 
+static bool s_start_free_link(dap_chain_net_t *a_net)
+{
+    struct net_link *l_link, *l_link_tmp;
+    HASH_ITER(hh,  PVT(a_net)->net_links, l_link, l_link_tmp) {
+        if (l_link->link == NULL) {  // We have a free prepared link
+            dap_chain_node_client_t *l_client_new = dap_chain_net_client_create_n_connect(
+                                                              a_net, l_link->link_info);
+            l_link->link = l_client_new;
+            l_link->client_uuid = l_client_new->uuid;
+            return true;
+        }
+    }
+    return false;
+}
+
 /**
  * @brief s_node_link_callback_disconnected
  * @param a_node_client
@@ -888,23 +901,16 @@ static void s_node_link_callback_disconnected(dap_chain_node_client_t *a_node_cl
         pthread_rwlock_wrlock(&l_net_pvt->uplinks_lock);
         s_net_link_remove(l_net_pvt, a_node_client->uuid, l_net_pvt->only_static_links);
         a_node_client->keep_connection = false;
-        struct net_link *l_link, *l_link_tmp;
-        HASH_ITER(hh, l_net_pvt->net_links, l_link, l_link_tmp) {
-            if (l_link->link == NULL) {  // We have a free prepared link
-                dap_chain_node_client_t *l_client_new = dap_chain_net_client_create_n_connect(
-                                                                  l_net, l_link->link_info);
-                l_link->link = l_client_new;
-                l_link->client_uuid = l_client_new->uuid;
-                pthread_rwlock_unlock(&l_net_pvt->uplinks_lock);
-                return;
-            }
-        }     
+        if (s_start_free_link(l_net)) {
+            pthread_rwlock_unlock(&l_net_pvt->uplinks_lock);
+            return;
+        }
         if (!l_net_pvt->only_static_links) {
             size_t l_current_links_prepared = HASH_COUNT(l_net_pvt->net_links);
             for (size_t i = l_current_links_prepared; i < l_net_pvt->max_links_count ; i++) {
                 dap_chain_node_info_t *l_link_node_info = s_get_balancer_link_from_cfg(l_net);
                 if (l_link_node_info) {
-                    if (!s_balancer_start_dns_request(l_net, l_link_node_info, true))
+                    if (!s_new_balancer_link_request(l_net, 1))
                         log_it(L_ERROR, "Can't process node info dns request");
                     DAP_DELETE(l_link_node_info);
                 }
@@ -1003,8 +1009,8 @@ static void s_net_links_complete_and_start(dap_chain_net_t *a_net, dap_worker_t
             // Try to get links from HTTP balancer
             l_net_pvt->balancer_http = true;
             s_prepare_links_from_balancer(a_net);
-             pthread_rwlock_unlock(&l_net_pvt->balancer_lock);
-             return;
+            pthread_rwlock_unlock(&l_net_pvt->balancer_lock);
+            return;
         }
         if (HASH_COUNT(l_net_pvt->net_links) < l_net_pvt->max_links_count)
             s_fill_links_from_root_aliases(a_net);  // Comlete the sentence
@@ -1038,9 +1044,9 @@ static void s_net_balancer_link_prepare_success(dap_worker_t * a_worker, dap_cha
     int l_res = s_net_link_add(l_net, a_node_info);
     if (l_res < 0) {    // Can't add this link
         debug_if(s_debug_more, L_DEBUG, "Can't add link "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-        if (l_balancer_request->link_replace)
+        if (l_balancer_request->link_replace_tries)
             // Just try a new one
-            s_new_balancer_link_request(l_net);
+            s_new_balancer_link_request(l_net, l_balancer_request->link_replace_tries);
     } else if (l_res == 0) {
         struct json_object *l_json = s_net_states_json_collect(l_net);
         char l_err_str[128] = { };
@@ -1052,19 +1058,23 @@ static void s_net_balancer_link_prepare_success(dap_worker_t * a_worker, dap_cha
         json_object_put(l_json);
         debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" successfully added",
                                                NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-        if (l_balancer_request->link_replace &&
+        if (l_balancer_request->link_replace_tries &&
                 s_net_get_active_links_count(l_net) < PVT(l_net)->required_links_count) {
             // Auto-start new link
-            debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" started",
-                                                   NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-            dap_chain_node_client_t *l_client = dap_chain_net_client_create_n_connect(l_net, a_node_info);
-            struct net_link *l_new_link = s_net_link_find(l_net, a_node_info);
-            l_new_link->link = l_client;
-            l_new_link->client_uuid = l_client->uuid;
+            pthread_rwlock_rdlock(&PVT(l_net)->states_lock);
+            if (PVT(l_net)->state_target != NET_STATE_OFFLINE) {
+                debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" started",
+                                                       NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
+                dap_chain_node_client_t *l_client = dap_chain_net_client_create_n_connect(l_net, a_node_info);
+                struct net_link *l_new_link = s_net_link_find(l_net, a_node_info);
+                l_new_link->link = l_client;
+                l_new_link->client_uuid = l_client->uuid;
+            }
+            pthread_rwlock_unlock(&PVT(l_net)->states_lock);
         }
     } else
         debug_if(s_debug_more, L_DEBUG, "Maximum prepared links reached");
-    if (!l_balancer_request->link_replace)
+    if (!l_balancer_request->link_replace_tries)
         s_net_links_complete_and_start(l_net, a_worker);
     DAP_DELETE(l_balancer_request->link_info);
     DAP_DELETE(l_balancer_request);
@@ -1094,10 +1104,10 @@ static void s_net_balancer_link_prepare_error(dap_worker_t * a_worker, void * a_
     json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
     dap_notify_server_send_mt(json_object_get_string(l_json));
     json_object_put(l_json);
-    if (!l_balancer_request->link_replace)
+    if (!l_balancer_request->link_replace_tries)
         s_net_links_complete_and_start(l_net, a_worker);
     else
-        s_new_balancer_link_request(l_net);
+        s_new_balancer_link_request(l_net, l_balancer_request->link_replace_tries);
     DAP_DELETE(l_node_info);
     DAP_DELETE(l_balancer_request);
 }
@@ -1108,7 +1118,8 @@ void s_net_http_link_prepare_success(void *a_response, size_t a_response_size, v
     struct balancer_link_request *l_balancer_request = (struct balancer_link_request *)a_arg;
     if (a_response_size != sizeof(dap_chain_node_info_t)) {
         log_it(L_ERROR, "Invalid balancer response size %zu (expect %zu)", a_response_size, sizeof(dap_chain_node_info_t));
-        s_new_balancer_link_request(l_balancer_request->net);
+        s_new_balancer_link_request(l_balancer_request->net, l_balancer_request->link_replace_tries);
+        DAP_DELETE(l_balancer_request);
         return;
     }
     s_net_balancer_link_prepare_success(l_balancer_request->worker, (dap_chain_node_info_t *)a_response, a_arg);
@@ -1126,83 +1137,78 @@ void s_net_http_link_prepare_error(int a_error_code, void *a_arg)
  * @param a_link_node_info node parameters
  * @return list of dap_chain_node_info_t
  */
-static bool s_balancer_start_dns_request(dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_info, bool a_link_replace)
+static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_replace_tries)
 {
-    char l_node_addr_str[INET_ADDRSTRLEN] = { };
-    inet_ntop(AF_INET, &a_link_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_DEBUG, "Start balancer DNS request to %s", l_node_addr_str);
     dap_chain_net_pvt_t *l_net_pvt = a_net ? PVT(a_net) : NULL;
-    if(!l_net_pvt)
+    if (!l_net_pvt)
         return false;
-    struct balancer_link_request *l_balancer_request = DAP_NEW_Z(struct balancer_link_request);
-    l_balancer_request->net = a_net;
-    l_balancer_request->link_info = DAP_DUP(a_link_node_info);
-    l_balancer_request->link_replace = a_link_replace;
-    if (dap_chain_node_info_dns_request(a_link_node_info->hdr.ext_addr_v4,
-            a_link_node_info->hdr.ext_port,
-            a_net->pub.name,
-            s_net_balancer_link_prepare_success,
-            s_net_balancer_link_prepare_error,
-            l_balancer_request)) {
-        log_it(L_ERROR, "Can't process balancer link DNS request");
-        DAP_DELETE(l_balancer_request->link_info);
-        DAP_DELETE(l_balancer_request);
+    pthread_rwlock_rdlock(&l_net_pvt->states_lock);
+    if (l_net_pvt->state_target == NET_STATE_OFFLINE) {
+        pthread_rwlock_unlock(&l_net_pvt->states_lock);
         return false;
     }
-    l_net_pvt->balancer_link_requests++;
-    return true;
-}
-
-static bool s_balancer_start_http_request(dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_info, bool a_link_replace)
-{
-    char l_node_addr_str[INET_ADDRSTRLEN] = { };
-    inet_ntop(AF_INET, &a_link_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_DEBUG, "Start balancer HTTP request to %s", l_node_addr_str);
-    dap_chain_net_pvt_t *l_net_pvt = a_net ? PVT(a_net) : NULL;
-    if (!l_net_pvt)
+    pthread_rwlock_unlock(&l_net_pvt->states_lock);
+    dap_chain_node_info_t *l_link_node_info = s_get_balancer_link_from_cfg(a_net);
+    if (a_link_replace_tries >= 5) {
+        // network problems, make static links
+        s_fill_links_from_root_aliases(a_net);
+        pthread_rwlock_wrlock(&l_net_pvt->uplinks_lock);
+        s_start_free_link(a_net);
+        pthread_rwlock_unlock(&l_net_pvt->uplinks_lock);
+        return false;
+    }
+    if (!l_link_node_info)
         return false;
+    char l_node_addr_str[INET_ADDRSTRLEN] = {};
+    inet_ntop(AF_INET, &l_link_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
+    log_it(L_DEBUG, "Start balancer %s request to %s", PVT(a_net)->balancer_http ? "HTTP" : "DNS", l_node_addr_str);
     struct balancer_link_request *l_balancer_request = DAP_NEW_Z(struct balancer_link_request);
-    l_balancer_request->from_http = true;
     l_balancer_request->net = a_net;
-    l_balancer_request->link_info = DAP_DUP(a_link_node_info);
+    l_balancer_request->link_info = l_link_node_info;
     l_balancer_request->worker = dap_events_worker_get_auto();
-    l_balancer_request->link_replace = a_link_replace;
-    char *l_request = dap_strdup_printf("%s/%s?version=1,method=r,net=%s",
-                                           DAP_UPLINK_PATH_BALANCER,
-                                           DAP_BALANCER_URI_HASH,
-                                           a_net->pub.name);
-    if (dap_client_http_request(l_balancer_request->worker, l_node_addr_str, a_link_node_info->hdr.ext_port,
-                                        "GET", "text/text", l_request,
-                                        NULL, 0, NULL,
-                                        s_net_http_link_prepare_success, s_net_http_link_prepare_error,
-                                        l_balancer_request, NULL)) {
-        log_it(L_ERROR, "Can't process balancer link HTTP request");
+    if (a_link_replace_tries)
+        l_balancer_request->link_replace_tries = a_link_replace_tries + 1;
+    int ret;
+    if (PVT(a_net)->balancer_http) {
+        l_balancer_request->from_http = true;
+        char *l_request = dap_strdup_printf("%s/%s?version=1,method=r,net=%s",
+                                                DAP_UPLINK_PATH_BALANCER,
+                                                DAP_BALANCER_URI_HASH,
+                                                a_net->pub.name);
+        ret = dap_client_http_request(l_balancer_request->worker,
+                                                l_node_addr_str,
+                                                l_link_node_info->hdr.ext_port,
+                                                "GET",
+                                                "text/text",
+                                                l_request,
+                                                NULL,
+                                                0,
+                                                NULL,
+                                                s_net_http_link_prepare_success,
+                                                s_net_http_link_prepare_error,
+                                                l_balancer_request,
+                                                NULL);
+    } else {
+        l_link_node_info->hdr.ext_port = DNS_LISTEN_PORT;
+        ret = dap_chain_node_info_dns_request(l_balancer_request->worker,
+                                                l_link_node_info->hdr.ext_addr_v4,
+                                                l_link_node_info->hdr.ext_port,
+                                                a_net->pub.name,
+                                                s_net_balancer_link_prepare_success,
+                                                s_net_balancer_link_prepare_error,
+                                                l_balancer_request);
+    }
+    if (ret) {
+        log_it(L_ERROR, "Can't process balancer link %s request", PVT(a_net)->balancer_http ? "HTTP" : "DNS");
         DAP_DELETE(l_balancer_request->link_info);
         DAP_DELETE(l_balancer_request);
-        DAP_DELETE(l_request);
         return false;
     }
-    DAP_DELETE(l_request);
-    l_net_pvt->balancer_link_requests++;
+    if (!a_link_replace_tries)
+        l_net_pvt->balancer_link_requests++;
     return true;
 }
 
-static bool s_new_balancer_link_request(dap_chain_net_t *a_net)
-{
-    bool ret = false;
-    dap_chain_node_info_t *l_link_node_info = s_get_balancer_link_from_cfg(a_net);
-    if (l_link_node_info) {
-        if (PVT(a_net)->balancer_http)
-            ret = s_balancer_start_http_request(a_net, l_link_node_info, true);
-        else {
-            l_link_node_info->hdr.ext_port = DNS_LISTEN_PORT;
-            ret = s_balancer_start_dns_request(a_net, l_link_node_info, true);
-        }
-        DAP_DELETE(l_link_node_info);
-    }
-    return ret;
-}
-
 static void s_prepare_links_from_balancer(dap_chain_net_t *a_net)
 {
     // Get list of the unique links for l_net
@@ -1214,7 +1220,7 @@ static void s_prepare_links_from_balancer(dap_chain_net_t *a_net)
         if (!l_link_node_info)
             continue;
         // Start connect to link hubs
-        s_new_balancer_link_request(a_net);
+        s_new_balancer_link_request(a_net, 0);
         l_cur_links_count++;
     }
 }
@@ -1325,9 +1331,11 @@ static bool s_net_states_proc(dap_proc_thread_t *a_thread, void *a_arg)
                break;
             }
             // Get DNS request result from root nodes as synchronization links
-            if (!l_net_pvt->only_static_links)
+            if (!l_net_pvt->only_static_links) {
+                pthread_rwlock_unlock(&l_net_pvt->states_lock);
                 s_prepare_links_from_balancer(l_net);
-            else {
+                pthread_rwlock_wrlock(&l_net_pvt->states_lock);
+            } else {
                 log_it(L_ATT, "Not use bootstrap addresses, fill seed nodelist from root aliases");
                 // Add other root nodes as synchronization links
                 s_fill_links_from_root_aliases(l_net);
@@ -1384,7 +1392,7 @@ int s_net_list_compare_uuids(const void *a_uuid1, const void *a_uuid2)
 bool dap_chain_net_sync_trylock(dap_chain_net_t *a_net, dap_chain_node_client_t *a_client)
 {
     dap_chain_net_pvt_t *l_net_pvt = PVT(a_net);
-    int a_err = pthread_rwlock_wrlock(&l_net_pvt->uplinks_lock);
+    int a_err = pthread_rwlock_rdlock(&l_net_pvt->uplinks_lock);
     bool l_found = false;
     if (l_net_pvt->active_link) {
         struct net_link *l_link, *l_link_tmp;
@@ -2248,8 +2256,8 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
         l_net->pub.gdb_groups_prefix = dap_strdup (
                     dap_config_get_item_str_default(l_cfg , "general" , "gdb_groups_prefix",
                                                     dap_config_get_item_str(l_cfg , "general" , "name" ) ) );
-        dap_chain_global_db_add_sync_group(l_net->pub.name, "global", s_gbd_history_callback_notify, l_net);
-        dap_chain_global_db_add_sync_group(l_net->pub.name, l_net->pub.gdb_groups_prefix, s_gbd_history_callback_notify, l_net);
+        dap_global_db_add_sync_group(l_net->pub.name, "global", s_gbd_history_callback_notify, l_net);
+        dap_global_db_add_sync_group(l_net->pub.name, l_net->pub.gdb_groups_prefix, s_gbd_history_callback_notify, l_net);
 
         l_net->pub.gdb_nodes = dap_strdup_printf("%s.nodes",l_net->pub.gdb_groups_prefix);
         l_net->pub.gdb_nodes_aliases = dap_strdup_printf("%s.nodes.aliases",l_net->pub.gdb_groups_prefix);
@@ -2298,7 +2306,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
         if (l_gdb_sync_groups && l_gdb_sync_groups_count > 0) {
             for(uint16_t i = 0; i < l_gdb_sync_groups_count; i++) {
                 // add group to special sync
-                dap_chain_global_db_add_sync_extra_group(l_net->pub.name, l_gdb_sync_groups[i], s_gbd_history_callback_notify, l_net);
+                dap_global_db_add_sync_extra_group(l_net->pub.name, l_gdb_sync_groups[i], s_gbd_history_callback_notify, l_net);
             }
         }
 
@@ -3115,7 +3123,7 @@ bool dap_chain_net_get_flag_sync_from_zero( dap_chain_net_t * a_net)
 }
 
 
-bool s_proc_mempool_callback_load(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
+bool s_proc_mempool_callback_load(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,
                                                   const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
 {
     dap_chain_t * l_chain = (dap_chain_t*) a_arg;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index a8ce008a4056a1edc585a46803473aaf9252ede3..8b744f73348042dbf367056fc93091f1117b5c7a 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -69,6 +69,7 @@
 #include "dap_chain_wallet.h"
 #include "dap_chain_node.h"
 #include "dap_global_db.h"
+#include "dap_global_db_driver.h"
 #include "dap_chain_node_client.h"
 #include "dap_chain_node_cli_cmd.h"
 #include "dap_chain_node_cli_cmd_tx.h"
@@ -95,7 +96,7 @@
 #include "dap_chain_ledger.h"
 #include "dap_chain_mempool.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 
 #include "dap_stream_ch_chain_net.h"
 #include "dap_stream_ch_chain.h"
@@ -257,13 +258,13 @@ static bool node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_inf
     //memcpy(l_node_info, a_node_info, l_node_info_size );
 
     //size_t data_len_out = 0;
-    //dap_chain_node_info_t *a_node_info1 = dap_chain_global_db_gr_get(a_key, &data_len_out, a_net->pub.gdb_nodes);
+    //dap_chain_node_info_t *a_node_info1 = dap_global_db_gr_get(a_key, &data_len_out, a_net->pub.gdb_nodes);
 
     bool res = dap_global_db_set_sync(a_net->pub.gdb_nodes, a_key, (uint8_t *) a_node_info, l_node_info_size,
                                  true) == 0;
 
     //data_len_out = 0;
-    //dap_chain_node_info_t *a_node_info2 = dap_chain_global_db_gr_get(a_key, &data_len_out, a_net->pub.gdb_nodes);
+    //dap_chain_node_info_t *a_node_info2 = dap_global_db_gr_get(a_key, &data_len_out, a_net->pub.gdb_nodes);
     //DAP_DELETE(a_key);
     //DAP_DELETE(a_value);
     return res;
@@ -5295,7 +5296,7 @@ int cmd_gdb_export(int argc, char ** argv, char ** a_str_reply)
     struct json_object *l_json = json_object_new_array();
     dap_list_t *l_groups_list = l_parsed_groups_list
             ? l_parsed_groups_list
-            : dap_chain_global_db_driver_get_groups_by_mask("*");
+            : dap_global_db_driver_get_groups_by_mask("*");
     for (dap_list_t *l_list = l_groups_list; l_list; l_list = dap_list_next(l_list)) {
         size_t l_store_obj_count = 0;
         char *l_group_name = (char *)l_list->data;
@@ -5410,7 +5411,7 @@ int cmd_gdb_import(int argc, char ** argv, char ** a_str_reply)
             dap_enc_base64_decode(l_value_str, strlen(l_value_str), l_val, DAP_ENC_DATA_TYPE_B64);
             l_group_store[j].value  = (uint8_t*)l_val;
         }
-        if (dap_chain_global_db_driver_apply(l_group_store, l_records_count)) {
+        if (dap_global_db_driver_apply(l_group_store, l_records_count)) {
             log_it(L_CRITICAL, "An error occured on importing group %s...", l_group_name);
         } else {
             log_it(L_INFO, "Imported %zu records of group %s", l_records_count, l_group_name);
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 5e574edbf96933c917e34e0731d6b3fd0534974d..faa6313fbdd53862a693cedcd726e5620974d088 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -56,7 +56,7 @@
 #include "dap_uuid.h"
 #include "dap_client.h"
 #include "dap_client_pvt.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 #include "dap_chain.h"
 #include "dap_chain_cell.h"
 #include "dap_chain_net_srv.h"
diff --git a/modules/net/dap_chain_node_dns_client.c b/modules/net/dap_chain_node_dns_client.c
index 1601f8087bb460b56600bee6a33653268f2f68a5..c86d9e282635e355d5fbb753ed297879cf6e2874 100644
--- a/modules/net/dap_chain_node_dns_client.c
+++ b/modules/net/dap_chain_node_dns_client.c
@@ -186,7 +186,7 @@ static void s_dns_client_esocket_worker_assign_callback(dap_events_socket_t * a_
  * @param a_callback_error
  * @param a_callbacks_arg
  */
-int dap_chain_node_info_dns_request(struct in_addr a_addr, uint16_t a_port, char *a_name,
+int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_addr, uint16_t a_port, char *a_name,
                            dap_dns_client_node_info_request_success_callback_t a_callback_success,
                            dap_dns_client_node_info_request_error_callback_t a_callback_error,void * a_callbacks_arg)
 {
@@ -238,8 +238,7 @@ int dap_chain_node_info_dns_request(struct in_addr a_addr, uint16_t a_port, char
     l_esocket->remote_addr.sin_addr = a_addr;
     l_esocket->_inheritor = l_dns_client;
 
-    dap_worker_t * l_worker = dap_events_worker_get_auto();
-    dap_events_socket_assign_on_worker_mt(l_esocket,l_worker);
+    dap_events_socket_assign_on_worker_mt(l_esocket, a_worker);
     return 0;
 }
 
diff --git a/modules/net/dap_chain_node_dns_server.c b/modules/net/dap_chain_node_dns_server.c
index 6b04324e136d5822d88220bbdc1a18a3094f8a5f..7ed8fea2822e41a1262efc404947b15571961a7f 100644
--- a/modules/net/dap_chain_node_dns_server.c
+++ b/modules/net/dap_chain_node_dns_server.c
@@ -32,7 +32,7 @@
 #include "dap_chain_node.h"
 #include "dap_string.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_remote.h"
+#include "dap_global_db_remote.h"
 #include "dap_chain_net_balancer.h"
 
 #define LOG_TAG "dap_chain_node_dns_server"
diff --git a/modules/net/include/dap_chain_node_dns_client.h b/modules/net/include/dap_chain_node_dns_client.h
index ca5f719b00dc6214324a0f893c2ad220d05a91fd..aee9ec1293cd87a8b0d8ff9f88288d917387df6b 100644
--- a/modules/net/include/dap_chain_node_dns_client.h
+++ b/modules/net/include/dap_chain_node_dns_client.h
@@ -40,9 +40,9 @@ typedef struct _dap_dns_buf_t {
 typedef void (*dap_dns_client_node_info_request_success_callback_t) (dap_worker_t *a_worker, dap_chain_node_info_t *a_result, void *a_arg);
 typedef void (*dap_dns_client_node_info_request_error_callback_t) (dap_worker_t *a_worker, void *a_arg, int a_errno);
 
-int dap_chain_node_info_dns_request(struct in_addr a_addr, uint16_t a_port, char *a_name,
+int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_addr, uint16_t a_port, char *a_name,
                            dap_dns_client_node_info_request_success_callback_t a_callback_success,
-                           dap_dns_client_node_info_request_error_callback_t a_callback_error,void * a_callback_arg);
+                           dap_dns_client_node_info_request_error_callback_t a_callback_error, void * a_callback_arg);
 
 dap_chain_node_info_t *dap_dns_resolve_hostname(char *str);
 
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 23bec9c32f4b37b6f0fc23c22726dde8ea9ded58..85480272b0ed1bd2b42b0573b70776528046cdab 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -622,7 +622,7 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const
                 }
                 /*dap_chain_hash_fast_t l_pkey_hash;
                 if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) {
-                    dap_chain_global_db_gr_del(dap_strdup(a_key), a_group);
+                    dap_global_db_gr_del(dap_strdup(a_key), a_group);
                     DAP_DELETE(l_gdb_group_str);
                     return;
                 }
@@ -631,7 +631,7 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const
                 uint128_t l_balance = dap_chain_ledger_calc_balance(l_net->pub.ledger, &l_addr, l_order->price_ticker);
                 uint64_t l_solvency = dap_chain_uint128_to(l_balance);
                 if (l_solvency < l_order->price && !dap_chain_net_srv_stake_key_delegated(&l_addr)) {
-                    dap_chain_global_db_gr_del(dap_strdup(a_key), a_group);
+                    dap_global_db_gr_del(dap_strdup(a_key), a_group);
                 }*/
             }
         }
diff --git a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
index cde50a6232ac6fb3fd002f447e5a0503877cbd78..5fae0fbe77461e1d71ad0a1e3cd053fa2fc93dd7 100644
--- a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
+++ b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
@@ -24,7 +24,6 @@
 
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_stake_lock.h"
-#include "dap_chain_global_db.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_mempool.h"
 #include "dap_chain_wallet.h"
diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c
index a6a3a14fb60101f8d6a95e4e41e20b8955a32435..72bc6fe573c676a81ec092ac0154ed434b814578 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client.c
@@ -268,7 +268,7 @@ static dap_chain_hash_fast_t* dap_chain_net_vpn_client_tx_cond_hash(dap_chain_ne
     if(l_tx_cond_hash)
         return l_tx_cond_hash;
 
-    //l_pkey_b64 = (char*) dap_chain_global_db_gr_get(dap_strdup("client_pkey"), &l_gdb_group_size, l_gdb_group);
+    //l_pkey_b64 = (char*) dap_global_db_gr_get(dap_strdup("client_pkey"), &l_gdb_group_size, l_gdb_group);
     dap_enc_key_t *l_enc_key = NULL;
     if(a_wallet) {
         l_enc_key = dap_chain_wallet_get_key(a_wallet, 0);
@@ -302,7 +302,7 @@ static dap_chain_hash_fast_t* dap_chain_net_vpn_client_tx_cond_hash(dap_chain_ne
      uint8_t *l_pub_key_data = dap_enc_key_serealize_pub_key(l_cert->enc_key, &l_pub_key_data_size);
      // save pub key
      if(l_pub_key_data && l_pub_key_data_size > 0){
-     if(dap_chain_global_db_gr_set(dap_strdup("client_pkey"), l_pub_key_data, l_pub_key_data_size,
+     if(dap_global_db_gr_set(dap_strdup("client_pkey"), l_pub_key_data, l_pub_key_data_size,
      l_gdb_group)){
      l_pkey_b64 = l_pub_key_data;
      l_pkey_b64_size = l_pub_key_data_size;
diff --git a/modules/type/dag/CMakeLists.txt b/modules/type/dag/CMakeLists.txt
index f77a32ffac6a681c92b26e62e90c7dd84a6c9a45..9dd3c3f2ef89b9b8e30e9f151704a00fb836b73e 100644
--- a/modules/type/dag/CMakeLists.txt
+++ b/modules/type/dag/CMakeLists.txt
@@ -5,7 +5,7 @@ file(GLOB DAP_CHAIN_DAG_SRCS *.c)
 file(GLOB DAP_CHAIN_DAG_HEADERS include/*.h)
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_DAG_SRCS} ${DAP_CHAIN_DAG_HEADERS})
 
-target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_net dap_chain_global_db)
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_net dap_global_db)
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/uthash/src)
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 6f1728dd57801f3be868f92cfedd35c5c5b50276..ab08847c8465fc1224e944edebc1377ea6a25f13 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -48,7 +48,7 @@
 #include "dap_chain_cs.h"
 #include "dap_chain_cs_dag.h"
 #include "dap_global_db.h"
-#include "dap_chain_global_db_driver.h"
+#include "dap_global_db_driver.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd.h"
 #include "dap_chain_cell.h"
@@ -279,7 +279,7 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     l_dag->gdb_group_events_round_new = dap_strdup_printf("%s.%s", l_gdb_group, l_round_new_str);
     DAP_DELETE(l_gdb_group);
     DAP_DELETE(l_round_new_str);
-    dap_chain_global_db_add_sync_extra_group(l_net->pub.name, l_dag->gdb_group_events_round_new, s_history_callback_round_notify, l_dag);
+    dap_global_db_add_sync_extra_group(l_net->pub.name, l_dag->gdb_group_events_round_new, s_history_callback_round_notify, l_dag);
     l_dag->broadcast_disable = false;
     byte_t *l_current_round = dap_global_db_get_sync(l_gdb_group, DAG_ROUND_CURRENT_KEY, NULL, NULL, NULL);
     l_dag->round_current = l_current_round? *(uint64_t *)l_current_round : 0;
diff --git a/modules/wallet/dap_chain_wallet.c b/modules/wallet/dap_chain_wallet.c
index fd7e2aceff5130323258b323293a7cba3223ec00..41978b18e4a617a4702e9d8286f89cff146d41f5 100644
--- a/modules/wallet/dap_chain_wallet.c
+++ b/modules/wallet/dap_chain_wallet.c
@@ -65,8 +65,10 @@
 
 #define LOG_TAG "dap_chain_wallet"
 
+#ifndef DAP_OS_WINDOWS
                                                                             /* An argument for open()/create() */
 static const mode_t s_fileprot =  ( S_IREAD | S_IWRITE) | (S_IREAD >> 3) | (S_IREAD >> 6) ;
+#endif
 static char s_wallet_ext [] = ".dwallet";
 
 
@@ -113,10 +115,10 @@ char *c_wallets_path;
 
     /* Sanity checks ... */
     if ( a_name_len > DAP_WALLET$SZ_NAME )
-        return  log_it(L_ERROR, "Wallet's name is too long (%d > %d)",  a_name_len, DAP_WALLET$SZ_NAME), -EINVAL;
+        return  log_it(L_ERROR, "Wallet's name is too long (%zd > %d)",  a_name_len, DAP_WALLET$SZ_NAME), -EINVAL;
 
     if ( a_pass_len > DAP_WALLET$SZ_PASS )
-        return  log_it(L_ERROR, "Wallet's password is too long (%d > %d)",  a_pass_len, DAP_WALLET$SZ_PASS), -EINVAL;
+        return  log_it(L_ERROR, "Wallet's password is too long (%zd > %d)",  a_pass_len, DAP_WALLET$SZ_PASS), -EINVAL;
 
 
     memcpy(l_rec.name, a_name, l_rec.name_len = a_name_len);            /* Prefill local record fields */
@@ -206,10 +208,10 @@ struct timespec l_now;
 
     /* Sanity checks ... */
     if ( a_name_len > DAP_WALLET$SZ_NAME )
-        return  log_it(L_ERROR, "Wallet's name is too long (%d > %d)",  a_name_len, DAP_WALLET$SZ_NAME), -EINVAL;
+        return  log_it(L_ERROR, "Wallet's name is too long (%zd > %d)",  a_name_len, DAP_WALLET$SZ_NAME), -EINVAL;
 
     if ( *a_pass_len < DAP_WALLET$SZ_PASS )
-        return  log_it(L_ERROR, "Wallet's buffer for password is too small (%d < %d)",  *a_pass_len, DAP_WALLET$SZ_PASS), -EINVAL;
+        return  log_it(L_ERROR, "Wallet's buffer for password is too small (%zd < %d)",  *a_pass_len, DAP_WALLET$SZ_PASS), -EINVAL;
 
 
     clock_gettime(CLOCK_REALTIME, &l_now);
@@ -268,7 +270,7 @@ int     l_rc, l_rc2;
 dap_chain_wallet_n_pass_t   *l_prec;
 
     if ( a_name_len > DAP_WALLET$SZ_NAME )
-        return  log_it(L_ERROR, "Wallet's name is too long (%d > %d)",  a_name_len, DAP_WALLET$SZ_NAME), -EINVAL;
+        return  log_it(L_ERROR, "Wallet's name is too long (%zd > %d)",  a_name_len, DAP_WALLET$SZ_NAME), -EINVAL;
 
     if ( (l_rc = pthread_rwlock_wrlock(&s_wallet_n_pass_lock)) )        /* Lock for WR access */
         return  log_it(L_ERROR, "Error locking Wallet table, errno=%d", l_rc), -l_rc;
@@ -280,7 +282,7 @@ dap_chain_wallet_n_pass_t   *l_prec;
     if ( l_prec )
     {
         if ( !l_prec->pass_len )                                        /* Password is zero - has been reset probably */
-            log_it(L_WARNING, "The Wallet %.*s is not active", a_name_len, a_name);
+            log_it(L_WARNING, "The Wallet %.*s is not active", (int)a_name_len, a_name);
 
         else if ( (l_prec->pass_len != a_pass_len)                      /* Check that passwords is equivalent */
              || memcmp(l_prec->pass, a_pass, l_prec->pass_len) )
@@ -295,15 +297,6 @@ dap_chain_wallet_n_pass_t   *l_prec;
     return  l_rc;
 }
 
-
-
-
-
-
-
-
-
-
 /**
  * @brief dap_chain_wallet_init
  * @return
@@ -334,15 +327,17 @@ size_t l_len;
      */
     while( (l_dir_entry = readdir(l_dir)))
     {
+#ifndef DAP_OS_WINDOWS
         if ( l_dir_entry->d_type !=  DT_REG )                           /* Skip unrelated entries */
             continue;
-
+#endif
         l_len = strlen(l_dir_entry->d_name);                            /* Check for *.dwallet */
 
         if ( (l_len > 8) && (strcmp(l_dir_entry->d_name + l_len - (sizeof(s_wallet_ext) - 1), s_wallet_ext) == 0) )
         {
-            dap_snprintf(l_fspec, sizeof(l_fspec) - 1, "%s/%s", c_wallets_path, l_dir_entry->d_name);
-
+            int ret = dap_snprintf(l_fspec, sizeof(l_fspec) - 1, "%s/%s", c_wallets_path, l_dir_entry->d_name);
+            if (ret < 0)
+                continue;
             if ( (l_wallet = dap_chain_wallet_open_file(l_fspec, NULL)) )
                 dap_chain_wallet_close(l_wallet);
         }
@@ -412,12 +407,10 @@ int l_rc, l_wallet_name_len, l_pass_len;
         return  log_it(L_ERROR, "Wallet's password is too long ( > %d)", DAP_WALLET$SZ_PASS), NULL;
 
     if ( !(l_wallet = DAP_NEW_Z(dap_chain_wallet_t)) )
-         return log_it(L_ERROR, "Memory allocation error, errno=&d", errno), NULL;
+         return log_it(L_ERROR, "Memory allocation error, errno=%d", errno), NULL;
 
     if ( !(l_wallet->_internal = l_wallet_internal = DAP_NEW_Z(dap_chain_wallet_internal_t)) )
-        return DAP_DELETE(l_wallet), log_it(L_ERROR, "Memory allocation error, errno=&d", errno), NULL;
-
-
+        return DAP_DELETE(l_wallet), log_it(L_ERROR, "Memory allocation error, errno=%d", errno), NULL;
 
     strncpy(l_wallet->name, a_wallet_name, DAP_WALLET$SZ_NAME);
     l_wallet_internal->certs_count = 1;
@@ -585,6 +578,7 @@ dap_enc_key_t* dap_chain_wallet_get_key( dap_chain_wallet_t * a_wallet,uint32_t
 int dap_chain_wallet_save(dap_chain_wallet_t * a_wallet, const char *a_pass)
 {
 DAP_CHAIN_WALLET_INTERNAL_LOCAL (a_wallet);                                 /* Declare l_wallet_internal */
+#ifndef DAP_OS_WINDOWS
 int l_fd = -1, l_rc = 0, l_len = 0;
 dap_chain_wallet_file_hdr_t l_file_hdr = {0};
 dap_chain_wallet_cert_hdr_t l_wallet_cert_hdr = {0};
@@ -698,7 +692,7 @@ struct iovec l_iov [ WALLET$SZ_IOV_NR ];
 
     if ( l_enc_key )
         dap_enc_key_delete(l_enc_key);
-
+#endif
 
 
 #ifdef  DAP_SYS_DEBUG                                                       /* @RRL: For debug purpose only!!! */