mdbxmou 0.3.11 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +113 -11
  2. package/deps/libmdbx/ChangeLog.md +44 -0
  3. package/deps/libmdbx/SECURITY.md +18 -0
  4. package/deps/libmdbx/VERSION.json +1 -1
  5. package/deps/libmdbx/mdbx.c +121 -63
  6. package/deps/libmdbx/mdbx.c++ +2 -2
  7. package/deps/libmdbx/mdbx_chk.c +2 -2
  8. package/deps/libmdbx/mdbx_copy.c +2 -2
  9. package/deps/libmdbx/mdbx_drop.c +2 -2
  10. package/deps/libmdbx/mdbx_dump.c +5 -5
  11. package/deps/libmdbx/mdbx_load.c +24 -23
  12. package/deps/libmdbx/mdbx_stat.c +2 -3
  13. package/lib/async.d.mts +6 -4
  14. package/lib/types.d.ts +17 -2
  15. package/package.json +2 -1
  16. package/src/async/envmou_keys.cpp +1 -1
  17. package/src/async/envmou_query.cpp +14 -13
  18. package/src/convmou.cpp +17 -0
  19. package/src/convmou.hpp +4 -8
  20. package/src/cursormou.cpp +2 -1
  21. package/src/cursormou.hpp +1 -0
  22. package/src/dbimou.cpp +71 -18
  23. package/src/dbimou.hpp +3 -1
  24. package/src/modulemou.cpp +14 -0
  25. package/src/querymou.cpp +15 -15
  26. package/src/querymou.hpp +3 -1
  27. package/src/txnmou.cpp +3 -3
  28. package/src/typemou.hpp +85 -5
  29. package/src/valuemou.hpp +62 -83
  30. package/deps/libmdbx/.github/workflows/ci-android.yml +0 -38
  31. package/deps/libmdbx/.github/workflows/ci-mingw.yml +0 -40
  32. package/deps/libmdbx/.github/workflows/ci-posix.yml +0 -34
  33. package/deps/libmdbx/.github/workflows/ci-wincxx.yml +0 -45
  34. package/deps/libmdbx/.github/workflows/ci-windows.yml +0 -32
  35. package/deps/libmdbx/ci.sh +0 -86
  36. package/deps/libmdbx/packages/archlinux/.SRCINFO +0 -16
  37. package/deps/libmdbx/packages/archlinux/PKGBUILD +0 -38
  38. package/deps/libmdbx/packages/buildroot/0001-package-libmdbx.patch +0 -75
@@ -4,7 +4,7 @@
4
4
 
5
5
  #define xMDBX_ALLOY 1 /* alloyed build */
6
6
 
7
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
7
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
8
8
 
9
9
  #define LIBMDBX_INTERNALS
10
10
  #define MDBX_DEPRECATED
@@ -1485,7 +1485,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1485
1485
  #define MMAP_OPTION_SEMAPHORE 2
1486
1486
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1487
1487
  const pathchar_t *pathname4logging);
1488
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1488
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1489
1489
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1490
1490
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1491
1491
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -3634,6 +3634,9 @@ MDBX_MAYBE_UNUSED static
3634
3634
 
3635
3635
  /* Internal prototypes */
3636
3636
 
3637
+ MDBX_INTERNAL int MDBX_PRINTF_ARGS(2, 3) bad_page(const page_t *mp, const char *fmt, ...);
3638
+ MDBX_INTERNAL void MDBX_PRINTF_ARGS(2, 3) poor_page(const page_t *mp, const char *fmt, ...);
3639
+
3637
3640
  /* audit.c */
3638
3641
  MDBX_INTERNAL int audit_ex(MDBX_txn *txn, size_t retired_stored, bool dont_filter_gc);
3639
3642
 
@@ -4658,8 +4661,35 @@ MDBX_INTERNAL int __must_check_result node_read_bigdata(MDBX_cursor *mc, const n
4658
4661
  static inline int __must_check_result node_read(MDBX_cursor *mc, const node_t *node, MDBX_val *data, const page_t *mp) {
4659
4662
  data->iov_len = node_ds(node);
4660
4663
  data->iov_base = node_data(node);
4661
- if (likely(node_flags(node) != N_BIG))
4664
+ if (likely(node_flags(node) != N_BIG)) {
4665
+ #if 0
4666
+ /* This is an example of a code that checks out-of-bounds by an incorrect/bad/crafted node.
4667
+ * Such checks look useful, but they are unreasonable really:
4668
+ * - an each such check catches some damage case of the structure, apparently in one of the hot execution paths,
4669
+ * but LEAVES several dozen more aside;
4670
+ * - the overhead increases slightly,
4671
+ * but there is also NO CERTAINTY that all or most of the corruption cases will be solved;
4672
+ * - libmdbx already has a fairly complete page content validation mode by MDBX_VALIDATION, which leads
4673
+ * calling the page_check() for each page from all page_get_xxx() variants, excepts page_get_unchecked();
4674
+ * = So, the MDBX_VALIDATION must be used to work with untrusted data,
4675
+ * but such checks are not necessary for trusted data.
4676
+ *
4677
+ * Thus, libmdbx allows a user, if necessary, to enable control of the database structure at the cost of reduced
4678
+ * performance. On the other hand, such approach allows not to lose productivity unnecessarily.
4679
+ *
4680
+ * Related issues:
4681
+ * - https://sourcecraft.dev/dqdkfa/libmdbx/issues/290
4682
+ * - https://github.com/Mithril-mine/libmdbx/pull/306
4683
+ */
4684
+ const char *data_end = ptr_disp(data->iov_base, data->iov_len);
4685
+ const char *page_tail = (const char *)((intptr_t)mp | /* Using the OR operation to get the tail of a real page
4686
+ in case here is a dupsort nested sub-page even. */
4687
+ (intptr_t)(mc->txn->env->ps - 1));
4688
+ if (!MDBX_DISABLE_VALIDATION && unlikely(data_end > page_tail))
4689
+ return bad_page(mp, "node-data (size %zu bytes) beyond the end of page", data->iov_len);
4690
+ #endif /* code example */
4662
4691
  return MDBX_SUCCESS;
4692
+ }
4663
4693
  return node_read_bigdata(mc, node, data, mp);
4664
4694
  }
4665
4695
 
@@ -6166,10 +6196,6 @@ MDBX_INTERNAL int __must_check_result page_split(MDBX_cursor *mc, const MDBX_val
6166
6196
 
6167
6197
  /*----------------------------------------------------------------------------*/
6168
6198
 
6169
- MDBX_INTERNAL int MDBX_PRINTF_ARGS(2, 3) bad_page(const page_t *mp, const char *fmt, ...);
6170
-
6171
- MDBX_INTERNAL void MDBX_PRINTF_ARGS(2, 3) poor_page(const page_t *mp, const char *fmt, ...);
6172
-
6173
6199
  MDBX_NOTHROW_PURE_FUNCTION static inline bool is_frozen(const MDBX_txn *txn, const page_t *mp) {
6174
6200
  return mp->txnid < txn->txnid;
6175
6201
  }
@@ -9266,8 +9292,8 @@ __cold int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest, siz
9266
9292
  if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
9267
9293
  return LOG_IFERR(MDBX_EINVAL);
9268
9294
 
9269
- dest->ms_psize = txn->env->ps;
9270
9295
  stat_get(&txn->dbs[dbi], dest, bytes);
9296
+ dest->ms_psize = txn->env->ps;
9271
9297
  return MDBX_SUCCESS;
9272
9298
  }
9273
9299
 
@@ -9316,6 +9342,7 @@ __cold int mdbx_enumerate_tables(const MDBX_txn *txn, MDBX_table_enum_func *func
9316
9342
 
9317
9343
  MDBX_stat stat;
9318
9344
  stat_get(tree, &stat, sizeof(stat));
9345
+ stat.ms_psize = txn->env->ps;
9319
9346
  rc = func(ctx, txn, &name, tree->flags, &stat, dbi);
9320
9347
  if (rc != MDBX_SUCCESS)
9321
9348
  goto bailout;
@@ -11262,7 +11289,7 @@ __cold const char *mdbx_liberr2str(int errnum) {
11262
11289
  nullptr /* MDBX_TLS_FULL (-30789): unused in MDBX */,
11263
11290
  "MDBX_TXN_FULL: Transaction has too many dirty pages,"
11264
11291
  " i.e transaction is too big",
11265
- "MDBX_CURSOR_FULL: Cursor stack limit reachedn - this usually indicates"
11292
+ "MDBX_CURSOR_FULL: Cursor stack limit reached - this usually indicates"
11266
11293
  " corruption, i.e branch-pages loop",
11267
11294
  "MDBX_PAGE_FULL: Internal error - Page has no more space",
11268
11295
  "MDBX_UNABLE_EXTEND_MAPSIZE: Database engine was unable to extend"
@@ -13834,11 +13861,11 @@ typedef struct MDBX_chk_internal {
13834
13861
  bool got_break;
13835
13862
  bool write_locked;
13836
13863
  uint8_t scope_depth;
13864
+ pgno_t last_nested_root;
13837
13865
 
13838
13866
  MDBX_chk_table_t table_gc, table_main;
13839
13867
  int16_t *pagemap;
13840
13868
  MDBX_chk_table_t *last_lookup;
13841
- const void *last_nested;
13842
13869
  MDBX_chk_scope_t scope_stack[12];
13843
13870
  MDBX_chk_table_t *table[MDBX_MAX_DBI + CORE_DBS];
13844
13871
 
@@ -14526,8 +14553,7 @@ __cold static int chk_pgvisitor(const size_t pgno, const unsigned npages, void *
14526
14553
  chk_v2a(chk, &tbl->name), tbl->flags, deep);
14527
14554
  nested = nullptr;
14528
14555
  }
14529
- } else
14530
- chk->last_nested = nullptr;
14556
+ }
14531
14557
 
14532
14558
  const char *pagetype_caption;
14533
14559
  bool branch = false;
@@ -14580,9 +14606,9 @@ __cold static int chk_pgvisitor(const size_t pgno, const unsigned npages, void *
14580
14606
  } else {
14581
14607
  pagetype_caption = (pagetype == page_leaf) ? "nested-leaf" : "nested-leaf-dupfix";
14582
14608
  tbl->pages.nested_leaf += 1;
14583
- if (chk->last_nested != nested) {
14609
+ if (chk->last_nested_root != nested->root) {
14584
14610
  histogram_acc(height, &tbl->histogram.nested_tree);
14585
- chk->last_nested = nested;
14611
+ chk->last_nested_root = nested->root;
14586
14612
  }
14587
14613
  if (height != nested->height)
14588
14614
  chk_object_issue(scope, "page", pgno, "wrong nested-tree height", "actual %i != %i dupsort-node %s", height,
@@ -17626,7 +17652,7 @@ __hot int cursor_del(MDBX_cursor *mc, unsigned flags) {
17626
17652
  /* will subtract the final entry later */
17627
17653
  mc->tree->items -= mc->subcur->nested_tree.items - 1;
17628
17654
  } else {
17629
- if (!(node_flags(node) & N_TREE)) {
17655
+ if ((node_flags(node) & N_TREE) == 0) {
17630
17656
  page_t *sp = node_data(node);
17631
17657
  cASSERT(mc, is_subpage(sp));
17632
17658
  sp->txnid = mp->txnid;
@@ -17641,6 +17667,11 @@ __hot int cursor_del(MDBX_cursor *mc, unsigned flags) {
17641
17667
  /* update table info */
17642
17668
  mc->subcur->nested_tree.mod_txnid = mc->txn->txnid;
17643
17669
  memcpy(node_data(node), &mc->subcur->nested_tree, sizeof(tree_t));
17670
+ /* fix other sub-DB cursors pointed at the same sub-tree */
17671
+ for (MDBX_cursor *m2 = mc->txn->cursors[cursor_dbi(mc)]; m2; m2 = m2->next) {
17672
+ if (is_related(mc, m2) && m2->pg[mc->top] == mp && m2->ki[mc->top] == mc->ki[mc->top])
17673
+ m2->subcur->nested_tree = mc->subcur->nested_tree;
17674
+ }
17644
17675
  } else {
17645
17676
  /* shrink sub-page */
17646
17677
  node = node_shrink(mp, mc->ki[mc->top], node);
@@ -17651,16 +17682,17 @@ __hot int cursor_del(MDBX_cursor *mc, unsigned flags) {
17651
17682
  continue;
17652
17683
  const node_t *inner = node;
17653
17684
  if (unlikely(m2->ki[mc->top] >= page_numkeys(mp))) {
17654
- m2->flags = z_poor_mark;
17685
+ m2->flags |= z_eof_hard | z_eof_soft | z_after_delete;
17655
17686
  m2->subcur->nested_tree.root = 0;
17656
17687
  m2->subcur->cursor.top_and_flags = z_inner | z_poor_mark;
17657
17688
  continue;
17658
17689
  }
17659
17690
  if (m2->ki[mc->top] != mc->ki[mc->top]) {
17660
17691
  inner = page_node(mp, m2->ki[mc->top]);
17661
- if (node_flags(inner) & N_TREE)
17692
+ if (node_flags(inner) != N_DUP)
17662
17693
  continue;
17663
- }
17694
+ } else
17695
+ m2->subcur->nested_tree = mc->subcur->nested_tree;
17664
17696
  m2->subcur->cursor.pg[0] = node_data(inner);
17665
17697
  }
17666
17698
  }
@@ -19771,7 +19803,7 @@ __cold int dxb_read_header(MDBX_env *env, meta_t *dest, const int lck_exclusive,
19771
19803
  if (dest->pagesize == 0 ||
19772
19804
  (env->stuck_meta < 0 && !(meta_is_steady(dest) || meta_weak_acceptable(env, dest, lck_exclusive)))) {
19773
19805
  ERROR("%s", "no usable meta-pages, database is corrupted");
19774
- if (rc == MDBX_SUCCESS) {
19806
+ if (!MDBX_IS_ERROR(rc)) {
19775
19807
  /* TODO: try to restore the database by fully checking b-tree structure
19776
19808
  * for the each meta page, if the corresponding option was given */
19777
19809
  return MDBX_CORRUPTED;
@@ -20485,14 +20517,14 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
20485
20517
  meta_troika_dump(env, &troika);
20486
20518
  return MDBX_CORRUPTED;
20487
20519
  }
20520
+
20521
+ purge_meta_head:
20488
20522
  if (env->flags & MDBX_RDONLY) {
20489
20523
  ERROR("%s and rollback needed: (from head %" PRIaTXN " to steady %" PRIaTXN ")%s",
20490
20524
  "opening after an unclean shutdown", recent.txnid, prefer_steady.txnid, ", but unable in read-only mode");
20491
20525
  meta_troika_dump(env, &troika);
20492
20526
  return MDBX_WANNA_RECOVERY;
20493
20527
  }
20494
-
20495
- purge_meta_head:
20496
20528
  NOTICE("%s and doing automatic rollback: "
20497
20529
  "purge%s meta[%u] with%s txnid %" PRIaTXN,
20498
20530
  "opening after an unclean shutdown", last_valid ? "" : " invalid", pgno, last_valid ? " weak" : "",
@@ -20550,7 +20582,13 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
20550
20582
  header.geometry.lower, header.geometry.now, header.geometry.upper, pv2pages(header.geometry.shrink_pv),
20551
20583
  pv2pages(header.geometry.grow_pv), next_txnid);
20552
20584
 
20553
- ENSURE(env, header.unsafe_txnid == recent.txnid);
20585
+ if (unlikely(header.unsafe_txnid != recent.txnid)) {
20586
+ const pgno_t recent_pgno = bytes2pgno(env, ptr_dist(recent.ptr_c, env->dxb_mmap.base));
20587
+ ERROR("meta[%u] recent steady txnid %" PRIaTXN " != header txnid %" PRIaTXN
20588
+ ", this is too unexpected and requires manual analysis.",
20589
+ recent_pgno, recent.txnid, header.unsafe_txnid);
20590
+ return MDBX_PROBLEM;
20591
+ }
20554
20592
  meta_set_txnid(env, &header, next_txnid);
20555
20593
  err = dxb_sync_locked(env, env->flags | txn_shrink_allowed, &header, &troika);
20556
20594
  if (err) {
@@ -26842,6 +26880,7 @@ __cold int meta_validate(MDBX_env *env, meta_t *const meta, const page_t *const
26842
26880
  }
26843
26881
 
26844
26882
  const uint64_t used_bytes = meta->geometry.first_unallocated * (uint64_t)meta->pagesize;
26883
+ const uint64_t dxbsize_pages = env->dxb_mmap.filesize / (uint64_t)meta->pagesize;
26845
26884
  if (unlikely(used_bytes > env->dxb_mmap.filesize)) {
26846
26885
  /* Here could be a race with DB-shrinking performed by other process */
26847
26886
  int err = osal_filesize(env->lazy_fd, &env->dxb_mmap.filesize);
@@ -26884,11 +26923,16 @@ __cold int meta_validate(MDBX_env *env, meta_t *const meta, const page_t *const
26884
26923
  }
26885
26924
  }
26886
26925
 
26926
+ /* It has already been verified above that the size of the allocated space does not exceed the file size. */
26887
26927
  pgno_t geo_upper = meta->geometry.upper;
26888
26928
  uint64_t mapsize_max = geo_upper * (uint64_t)meta->pagesize;
26889
26929
  STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
26890
26930
  if (unlikely(mapsize_max > MAX_MAPSIZE ||
26891
- (MAX_PAGENO + 1) < ceil_powerof2((size_t)mapsize_max, globals.sys_pagesize) / (size_t)meta->pagesize)) {
26931
+ (MAX_PAGENO + 1) < ceil_powerof2((/* допустимо, так как уже проверили что mapsize_max <= MAX_MAPSIZE,
26932
+ * а следовательно mapsize_max помещается в size_t */
26933
+ size_t)mapsize_max,
26934
+ globals.sys_allocation_granularity) /
26935
+ meta->pagesize)) {
26892
26936
  if (mapsize_max > MAX_MAPSIZE64) {
26893
26937
  WARNING("meta[%u] has invalid max-mapsize (%" PRIu64 "), skip it", meta_number, mapsize_max);
26894
26938
  return MDBX_VERSION_MISMATCH;
@@ -26899,30 +26943,40 @@ __cold int meta_validate(MDBX_env *env, meta_t *const meta, const page_t *const
26899
26943
  "but size of used space still acceptable (%" PRIu64 ")",
26900
26944
  meta_number, mapsize_max, used_bytes);
26901
26945
  geo_upper = (pgno_t)((mapsize_max = MAX_MAPSIZE) / meta->pagesize);
26902
- if (geo_upper > MAX_PAGENO + 1) {
26946
+ if (geo_upper > MAX_PAGENO + 1)
26903
26947
  geo_upper = MAX_PAGENO + 1;
26904
- mapsize_max = geo_upper * (uint64_t)meta->pagesize;
26905
- }
26948
+ }
26949
+
26950
+ if (geo_upper < meta->geometry.first_unallocated) {
26951
+ WARNING("meta[%u] has too less max-mapsize (%" PRIu64 "), "
26952
+ "but size of allocated space still acceptable (%" PRIu64 ")",
26953
+ meta_number, mapsize_max, used_bytes);
26954
+ geo_upper = meta->geometry.first_unallocated;
26955
+ }
26956
+ if (meta->geometry.upper != geo_upper) {
26906
26957
  WARNING("meta[%u] consider get-%s pageno is %" PRIaPGNO " instead of wrong %" PRIaPGNO
26907
26958
  ", will be corrected on next commit(s)",
26908
26959
  meta_number, "upper", geo_upper, meta->geometry.upper);
26909
26960
  meta->geometry.upper = geo_upper;
26961
+ mapsize_max = geo_upper * (uint64_t)meta->pagesize;
26910
26962
  }
26911
26963
 
26912
26964
  /* LY: check and silently put geometry.now into [geo.lower...geo.upper].
26913
26965
  *
26914
- * Copy-with-compaction by old version of libmdbx could produce DB-file
26915
- * less than meta.geo.lower bound, in case actual filling is low or no data
26916
- * at all. This is not a problem as there is no damage or loss of data.
26917
- * Therefore it is better not to consider such situation as an error, but
26918
- * silently correct it. */
26966
+ * It has already been verified above that the size of the allocated space does not exceed the file size.
26967
+ *
26968
+ * Copy-with-compaction by old version of libmdbx could produce DB-file less than meta.geo.lower bound, in case actual
26969
+ * 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
26970
+ * better not to consider such situation as an error, but silently correct it. */
26919
26971
  pgno_t geo_now = meta->geometry.now;
26920
26972
  if (geo_now < geo_lower)
26921
26973
  geo_now = geo_lower;
26922
- if (geo_now > geo_upper && meta->geometry.first_unallocated <= geo_upper)
26974
+ if (geo_now < dxbsize_pages)
26975
+ geo_now = dxbsize_pages;
26976
+ if (geo_now > geo_upper)
26923
26977
  geo_now = geo_upper;
26924
26978
 
26925
- if (unlikely(meta->geometry.first_unallocated > geo_now)) {
26979
+ if (unlikely(/* paranoid */ meta->geometry.first_unallocated > geo_now)) {
26926
26980
  WARNING("meta[%u] next-pageno (%" PRIaPGNO ") is beyond end-pgno (%" PRIaPGNO "), skip it", meta_number,
26927
26981
  meta->geometry.first_unallocated, geo_now);
26928
26982
  return MDBX_CORRUPTED;
@@ -26941,7 +26995,7 @@ __cold int meta_validate(MDBX_env *env, meta_t *const meta, const page_t *const
26941
26995
  WARNING("meta[%u] has false-empty %s, skip it", meta_number, "GC");
26942
26996
  return MDBX_CORRUPTED;
26943
26997
  }
26944
- } else if (unlikely(meta->trees.gc.root >= meta->geometry.first_unallocated)) {
26998
+ } else if (unlikely(meta->trees.gc.root >= meta->geometry.first_unallocated || meta->trees.gc.root < NUM_METAS)) {
26945
26999
  WARNING("meta[%u] has invalid %s-root %" PRIaPGNO ", skip it", meta_number, "GC", meta->trees.gc.root);
26946
27000
  return MDBX_CORRUPTED;
26947
27001
  }
@@ -26953,7 +27007,7 @@ __cold int meta_validate(MDBX_env *env, meta_t *const meta, const page_t *const
26953
27007
  WARNING("meta[%u] has false-empty %s", meta_number, "MainDB");
26954
27008
  return MDBX_CORRUPTED;
26955
27009
  }
26956
- } else if (unlikely(meta->trees.main.root >= meta->geometry.first_unallocated)) {
27010
+ } else if (unlikely(meta->trees.main.root >= meta->geometry.first_unallocated || meta->trees.main.root < NUM_METAS)) {
26957
27011
  WARNING("meta[%u] has invalid %s-root %" PRIaPGNO ", skip it", meta_number, "MainDB", meta->trees.main.root);
26958
27012
  return MDBX_CORRUPTED;
26959
27013
  }
@@ -29774,7 +29828,7 @@ int osal_check_fs_local(mdbx_filehandle_t handle, int flags) {
29774
29828
  #endif /* ST/MNT_LOCAL */
29775
29829
 
29776
29830
  #ifdef ST_EXPORTED
29777
- if ((st_flags & ST_EXPORTED) != 0 && !(flags & (MDBX_RDONLY | MDBX_EXCLUSIVE))))
29831
+ if ((st_flags & ST_EXPORTED) != 0 && !(flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)))
29778
29832
  return MDBX_RESULT_TRUE;
29779
29833
  #elif defined(MNT_EXPORTED)
29780
29834
  if ((mnt_flags & MNT_EXPORTED) != 0 && !(flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)))
@@ -29982,7 +30036,7 @@ int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit
29982
30036
  return MDBX_SUCCESS;
29983
30037
  }
29984
30038
 
29985
- int osal_munmap(osal_mmap_t *map) {
30039
+ void osal_munmap(osal_mmap_t *map) {
29986
30040
  VALGRIND_MAKE_MEM_NOACCESS(map->base, map->current);
29987
30041
  /* Unpoisoning is required for ASAN to avoid false-positive diagnostic
29988
30042
  * when this memory will re-used by malloc or another mmapping.
@@ -29990,22 +30044,21 @@ int osal_munmap(osal_mmap_t *map) {
29990
30044
  MDBX_ASAN_UNPOISON_MEMORY_REGION(map->base,
29991
30045
  (map->filesize && map->filesize < map->limit) ? map->filesize : map->limit);
29992
30046
  #if defined(_WIN32) || defined(_WIN64)
29993
- if (map->section)
30047
+ if (map->section) {
29994
30048
  NtClose(map->section);
29995
- NTSTATUS rc = NtUnmapViewOfSection(GetCurrentProcess(), map->base);
29996
- if (!NT_SUCCESS(rc))
29997
- osal_ntstatus2errcode(rc);
29998
- #else
29999
- if (unlikely(munmap(map->base, map->limit))) {
30000
- assert(errno != 0);
30001
- return errno;
30049
+ map->section = 0;
30002
30050
  }
30051
+ NTSTATUS err = NtUnmapViewOfSection(GetCurrentProcess(), map->base);
30052
+ if (!NT_SUCCESS(err))
30053
+ ERROR("Unexpected NtUnmapViewOfSection(%p, %zi) error %d", map->base, map->limit, osal_ntstatus2errcode(err));
30054
+ #else
30055
+ if (unlikely(munmap(map->base, map->limit)))
30056
+ ERROR("Unexpected munmap(%p, %zi) error %d", map->base, map->limit, errno);
30003
30057
  #endif /* ! Windows */
30004
30058
 
30005
30059
  map->limit = 0;
30006
30060
  map->current = 0;
30007
30061
  map->base = nullptr;
30008
- return MDBX_SUCCESS;
30009
30062
  }
30010
30063
 
30011
30064
  int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit) {
@@ -30978,10 +31031,12 @@ __cold static bin128_t osal_bootid(void) {
30978
31031
  case KSTAT_DATA_UINT32:
30979
31032
  bootid_collect(&uuid, &kn->value, sizeof(int32_t));
30980
31033
  got_boottime = true;
31034
+ break;
30981
31035
  case KSTAT_DATA_INT64:
30982
31036
  case KSTAT_DATA_UINT64:
30983
31037
  bootid_collect(&uuid, &kn->value, sizeof(int64_t));
30984
31038
  got_boottime = true;
31039
+ break;
30985
31040
  }
30986
31041
  }
30987
31042
  }
@@ -34831,8 +34886,8 @@ static int page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) {
34831
34886
  cASSERT(cdst, cdst->top > 0);
34832
34887
  page_t *const top_page = cdst->pg[cdst->top];
34833
34888
  const indx_t top_indx = cdst->ki[cdst->top];
34834
- const int save_top = cdst->top;
34835
34889
  const uint16_t save_height = cdst->tree->height;
34890
+ const int save_top = cdst->top;
34836
34891
  cursor_pop(cdst);
34837
34892
  rc = tree_rebalance(cdst);
34838
34893
  if (unlikely(rc != MDBX_SUCCESS))
@@ -34852,9 +34907,10 @@ static int page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) {
34852
34907
  }
34853
34908
 
34854
34909
  cASSERT(cdst, page_numkeys(top_page) == dst_nkeys + src_nkeys);
34855
-
34910
+ const int new_top = save_top - save_height + cdst->tree->height;
34856
34911
  if (unlikely(pagetype != page_type(top_page))) {
34857
34912
  /* LY: LEAF-page becomes BRANCH, unable restore cursor's stack */
34913
+ ERROR("unexpected top-page type 0x%x, expect 0x%x", page_type(top_page), pagetype);
34858
34914
  goto bailout;
34859
34915
  }
34860
34916
 
@@ -34865,9 +34921,10 @@ static int page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) {
34865
34921
  return MDBX_SUCCESS;
34866
34922
  }
34867
34923
 
34868
- const int new_top = save_top - save_height + cdst->tree->height;
34869
34924
  if (unlikely(new_top < 0 || new_top >= cdst->tree->height)) {
34870
34925
  /* LY: out of range, unable restore cursor's stack */
34926
+ ERROR("cursor top-new %i is out of range %u..%u (top-before %i, height-before %i, height-new %i)", new_top, 0,
34927
+ cdst->tree->height, save_top, save_height, cdst->tree->height);
34871
34928
  goto bailout;
34872
34929
  }
34873
34930
 
@@ -34880,10 +34937,7 @@ static int page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) {
34880
34937
  return MDBX_SUCCESS;
34881
34938
  }
34882
34939
 
34883
- page_t *const stub_page = (page_t *)(~(uintptr_t)top_page);
34884
- const indx_t stub_indx = top_indx;
34885
- if (save_height > cdst->tree->height && ((cdst->pg[save_top] == top_page && cdst->ki[save_top] == top_indx) ||
34886
- (cdst->pg[save_top] == stub_page && cdst->ki[save_top] == stub_indx))) {
34940
+ if (save_height > cdst->tree->height && cdst->pg[save_top] == top_page && cdst->ki[save_top] == top_indx) {
34887
34941
  /* LY: restore cursor stack */
34888
34942
  cdst->pg[new_top] = top_page;
34889
34943
  cdst->ki[new_top] = top_indx;
@@ -34898,7 +34952,12 @@ static int page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) {
34898
34952
  }
34899
34953
 
34900
34954
  bailout:
34901
- /* LY: unable restore cursor's stack */
34955
+ ERROR("unable restore %scursor stack after merge; "
34956
+ " new: height %i top %i top-idx %i top-page %p;"
34957
+ " before: height %i top %i, top-indx %i top-page %p",
34958
+ is_inner(cdst) ? "sub-" : "", cdst->tree->height, new_top, cdst->ki[save_top],
34959
+ __Wpedantic_format_voidptr(cdst->pg[save_top]), save_height, save_top, top_indx,
34960
+ __Wpedantic_format_voidptr(top_page));
34902
34961
  be_poor(cdst);
34903
34962
  return MDBX_CURSOR_FULL;
34904
34963
  }
@@ -35233,18 +35292,17 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne
35233
35292
 
35234
35293
  cASSERT(mc, !is_branch(mp) || newindx > 0);
35235
35294
  MDBX_val sepkey = {nullptr, 0};
35236
- /* It is reasonable and possible to split the page at the begin */
35295
+ /* It is reasonable and possible to split the page at the begin? */
35237
35296
  if (unlikely(newindx < minkeys)) {
35238
35297
  split_indx = minkeys;
35239
35298
  if (newindx == 0 && !(naf & MDBX_SPLIT_REPLACE)) {
35240
35299
  split_indx = 0;
35241
- /* Checking for ability of splitting by the left-side insertion
35242
- * of a pure page with the new key */
35243
- for (intptr_t i = 0; i < mc->top; ++i)
35300
+ /* Checking for ability of splitting by the left-side insertion of a pure page with the new key. */
35301
+ for (intptr_t i = mc->top; --i >= 0;)
35244
35302
  if (mc->ki[i]) {
35245
35303
  sepkey = get_key(page_node(mc->pg[i], mc->ki[i]));
35246
- if (mc->clc->k.cmp(newkey, &sepkey) >= 0)
35247
- split_indx = minkeys;
35304
+ eASSERT(env, mc->clc->k.cmp(newkey, &sepkey) >= 0);
35305
+ split_indx = minkeys;
35248
35306
  break;
35249
35307
  }
35250
35308
  if (split_indx == 0) {
@@ -37598,11 +37656,11 @@ __dll_export
37598
37656
  const struct MDBX_version_info mdbx_version = {
37599
37657
  0,
37600
37658
  13,
37601
- 11,
37659
+ 12,
37602
37660
  0,
37603
37661
  "", /* pre-release suffix of SemVer
37604
- 0.13.11 */
37605
- {"2026-01-30T16:04:44+03:00", "34a88ae65e76bbf3b9bcb0c2106dec18d2c067da", "b862eb08b77eccd4b8e8367a3276ffdea0d73de5", "v0.13.11-0-gb862eb08"},
37662
+ 0.13.12 */
37663
+ {"2026-04-30T16:36:24+03:00", "f5574b87cc64fa7a3a6b21ba33809258498d5f17", "f619d43dfbc36cbc9a1832503ce43f2e5223996e", "v0.13.12-0-gf619d43d"},
37606
37664
  sourcery};
37607
37665
 
37608
37666
  __dll_export
@@ -2,7 +2,7 @@
2
2
  /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
3
3
  /* clang-format off */
4
4
 
5
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
5
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
6
6
 
7
7
  #define LIBMDBX_INTERNALS
8
8
  #define MDBX_DEPRECATED
@@ -1483,7 +1483,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1483
1483
  #define MMAP_OPTION_SEMAPHORE 2
1484
1484
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1485
1485
  const pathchar_t *pathname4logging);
1486
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1486
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1487
1487
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1488
1488
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1489
1489
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -18,7 +18,7 @@
18
18
  /// \copyright SPDX-License-Identifier: Apache-2.0
19
19
  /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
20
20
 
21
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
21
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
22
22
 
23
23
  #define LIBMDBX_INTERNALS
24
24
  #define MDBX_DEPRECATED
@@ -1499,7 +1499,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1499
1499
  #define MMAP_OPTION_SEMAPHORE 2
1500
1500
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1501
1501
  const pathchar_t *pathname4logging);
1502
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1502
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1503
1503
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1504
1504
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1505
1505
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -18,7 +18,7 @@
18
18
  /// \copyright SPDX-License-Identifier: Apache-2.0
19
19
  /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
20
20
 
21
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
21
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
22
22
 
23
23
  #define LIBMDBX_INTERNALS
24
24
  #define MDBX_DEPRECATED
@@ -1499,7 +1499,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1499
1499
  #define MMAP_OPTION_SEMAPHORE 2
1500
1500
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1501
1501
  const pathchar_t *pathname4logging);
1502
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1502
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1503
1503
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1504
1504
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1505
1505
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -18,7 +18,7 @@
18
18
  /// \copyright SPDX-License-Identifier: Apache-2.0
19
19
  /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
20
20
 
21
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
21
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
22
22
 
23
23
  #define LIBMDBX_INTERNALS
24
24
  #define MDBX_DEPRECATED
@@ -1499,7 +1499,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1499
1499
  #define MMAP_OPTION_SEMAPHORE 2
1500
1500
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1501
1501
  const pathchar_t *pathname4logging);
1502
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1502
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1503
1503
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1504
1504
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1505
1505
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -18,7 +18,7 @@
18
18
  /// \copyright SPDX-License-Identifier: Apache-2.0
19
19
  /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
20
20
 
21
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
21
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
22
22
 
23
23
  #define LIBMDBX_INTERNALS
24
24
  #define MDBX_DEPRECATED
@@ -1499,7 +1499,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1499
1499
  #define MMAP_OPTION_SEMAPHORE 2
1500
1500
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1501
1501
  const pathchar_t *pathname4logging);
1502
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1502
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1503
1503
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1504
1504
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1505
1505
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -3449,10 +3449,10 @@ static int dump_tbl(MDBX_txn *txn, MDBX_dbi dbi, char *name) {
3449
3449
  if (mode & GLOBAL) {
3450
3450
  mode -= GLOBAL;
3451
3451
  if (info.mi_geo.upper != info.mi_geo.lower)
3452
- printf("geometry=l%" PRIu64 ",c%" PRIu64 ",u%" PRIu64 ",s%" PRIu64 ",g%" PRIu64 "\n", info.mi_geo.lower,
3453
- info.mi_geo.current, info.mi_geo.upper, info.mi_geo.shrink, info.mi_geo.grow);
3452
+ printf("geometry=l%" PRIu64 ",u%" PRIu64 ",s%" PRIu64 ",g%" PRIu64 "\n", info.mi_geo.lower, info.mi_geo.upper,
3453
+ info.mi_geo.shrink, info.mi_geo.grow);
3454
3454
  printf("mapsize=%" PRIu64 "\n", info.mi_geo.upper);
3455
- printf("maxreaders=%u\n", info.mi_maxreaders);
3455
+ /* printf("maxreaders=%u\n", info.mi_maxreaders); */
3456
3456
 
3457
3457
  MDBX_canary canary;
3458
3458
  rc = mdbx_canary_get(txn, &canary);
@@ -18,7 +18,7 @@
18
18
  /// \copyright SPDX-License-Identifier: Apache-2.0
19
19
  /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
20
20
 
21
- #define MDBX_BUILD_SOURCERY 90c8567c0f319539000cf161230c67f127fd9cbcb5d35ad5b3b076b78b5dc48d_v0_13_11_0_gb862eb08
21
+ #define MDBX_BUILD_SOURCERY a575a490fc080ca11e89ff6db9f0bd38aa830959905998cac0e45274b9e6bb0e_v0_13_12_0_gf619d43d
22
22
 
23
23
  #define LIBMDBX_INTERNALS
24
24
  #define MDBX_DEPRECATED
@@ -1499,7 +1499,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
1499
1499
  #define MMAP_OPTION_SEMAPHORE 2
1500
1500
  MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
1501
1501
  const pathchar_t *pathname4logging);
1502
- MDBX_INTERNAL int osal_munmap(osal_mmap_t *map);
1502
+ MDBX_INTERNAL void osal_munmap(osal_mmap_t *map);
1503
1503
  #define MDBX_MRESIZE_MAY_MOVE 0x00000100
1504
1504
  #define MDBX_MRESIZE_MAY_UNMAP 0x00000200
1505
1505
  MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit);
@@ -3611,6 +3611,9 @@ static int readhdr(void) {
3611
3611
  "%s: line %" PRIiSIZE ": ignore values %s"
3612
3612
  " for '%s' in non-global context\n",
3613
3613
  prog, lineno, str, "geometry");
3614
+ } else if (sscanf(str, "l%" PRIu64 ",u%" PRIu64 ",s%" PRIu64 ",g%" PRIu64, &envinfo.mi_geo.lower,
3615
+ &envinfo.mi_geo.upper, &envinfo.mi_geo.shrink, &envinfo.mi_geo.grow) == 4) {
3616
+ envinfo.mi_geo.current = (uint64_t)INT64_C(-1);
3614
3617
  } else if (sscanf(str, "l%" PRIu64 ",c%" PRIu64 ",u%" PRIu64 ",s%" PRIu64 ",g%" PRIu64, &envinfo.mi_geo.lower,
3615
3618
  &envinfo.mi_geo.current, &envinfo.mi_geo.upper, &envinfo.mi_geo.shrink,
3616
3619
  &envinfo.mi_geo.grow) != 5) {
@@ -3929,29 +3932,27 @@ int main(int argc, char *argv[]) {
3929
3932
  }
3930
3933
  }
3931
3934
 
3932
- if (envinfo.mi_geo.current | envinfo.mi_mapsize) {
3933
- if (envinfo.mi_geo.current) {
3934
- err = mdbx_env_set_geometry(env, (intptr_t)envinfo.mi_geo.lower, (intptr_t)envinfo.mi_geo.current,
3935
- (intptr_t)envinfo.mi_geo.upper, (intptr_t)envinfo.mi_geo.shrink,
3936
- (intptr_t)envinfo.mi_geo.grow,
3937
- envinfo.mi_dxb_pagesize ? (intptr_t)envinfo.mi_dxb_pagesize : -1);
3938
- } else {
3939
- if (envinfo.mi_mapsize > MAX_MAPSIZE) {
3940
- if (!quiet)
3941
- fprintf(stderr,
3942
- "Database size is too large for current system (mapsize=%" PRIu64
3943
- " is great than system-limit %zu)\n",
3944
- envinfo.mi_mapsize, (size_t)MAX_MAPSIZE);
3945
- goto bailout;
3946
- }
3947
- err = mdbx_env_set_geometry(env, (intptr_t)envinfo.mi_mapsize, (intptr_t)envinfo.mi_mapsize,
3948
- (intptr_t)envinfo.mi_mapsize, 0, 0,
3949
- envinfo.mi_dxb_pagesize ? (intptr_t)envinfo.mi_dxb_pagesize : -1);
3950
- }
3951
- if (unlikely(err != MDBX_SUCCESS)) {
3952
- error("mdbx_env_set_geometry", err);
3935
+ err = MDBX_SUCCESS;
3936
+ if (envinfo.mi_geo.lower | envinfo.mi_geo.upper | envinfo.mi_geo.shrink | envinfo.mi_geo.grow) {
3937
+ err = mdbx_env_set_geometry(env, (intptr_t)envinfo.mi_geo.lower, (intptr_t)envinfo.mi_geo.current,
3938
+ (intptr_t)envinfo.mi_geo.upper, (intptr_t)envinfo.mi_geo.grow,
3939
+ (intptr_t)envinfo.mi_geo.shrink,
3940
+ envinfo.mi_dxb_pagesize ? (intptr_t)envinfo.mi_dxb_pagesize : -1);
3941
+ } else if (envinfo.mi_mapsize) {
3942
+ if (envinfo.mi_mapsize > MAX_MAPSIZE) {
3943
+ if (!quiet)
3944
+ fprintf(stderr,
3945
+ "Database size is too large for current system (mapsize=%" PRIu64 " is great than system-limit %zu)\n",
3946
+ envinfo.mi_mapsize, (size_t)MAX_MAPSIZE);
3953
3947
  goto bailout;
3954
3948
  }
3949
+ err = mdbx_env_set_geometry(env, (intptr_t)envinfo.mi_mapsize, (intptr_t)envinfo.mi_mapsize,
3950
+ (intptr_t)envinfo.mi_mapsize, 0, 0,
3951
+ envinfo.mi_dxb_pagesize ? (intptr_t)envinfo.mi_dxb_pagesize : -1);
3952
+ }
3953
+ if (unlikely(err != MDBX_SUCCESS)) {
3954
+ error("mdbx_env_set_geometry", err);
3955
+ goto bailout;
3955
3956
  }
3956
3957
 
3957
3958
  err = mdbx_env_open(env, envname, envflags, 0664);