Skip to content

Commit c811cd8

Browse files
committed
mdbx: avoid extra-growth of DB instead of GC-reclaiming in a rare specific cases (v0.13.10-55-g0e259437).
2026-01-23 mdbx: update ChangeLog. 2026-01-20 mdbx: add backlog-adj trick to gc-put. 2026-01-20 mdbx: avoid extra-growth of DB instead of reclaim GC. 2026-01-20 mdbx: fix `histogram_reduce()` (backport). 2026-01-20 mdbx-test: backport `extra/txn` from `master` branch. 2026-01-20 mdbx-test-cmake: remove copy destinations via fixtures. 2026-01-20 mdbx++: fix `second_range_mask` inside `slice::is_printable()` (backport).
1 parent 4c1dfb9 commit c811cd8

File tree

10 files changed

+83
-45
lines changed

10 files changed

+83
-45
lines changed

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ Fixes:
3939

4040
- Fixed extra msync/fsync operations during GC reclaiming in a full database.
4141

42+
- Fixed suboptimal reducing/merging of histogram items in an output of mdbx_chk tool.
43+
44+
- Added backlog-adjustment trick to avoid extra-growth of DB instead of reclaim GC in a rare specific cases.
45+
In the 0.14.x version series, this mechanism has been completely updated.
46+
However, for version 0.13.11, this inelegant modification done in order to reduce the risk of regression.
47+
4248
Other:
4349

4450
- Clarification and addition of documentation.

VERSION.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "git_describe": "v0.13.10-48-gade27cfc", "git_timestamp": "2026-01-17T00:28:51+03:00", "git_tree": "634dea88bd00c8046d1118eb024443675acdd704", "git_commit": "ade27cfc487a70f61421996d2682be46a4d305b5", "semver": "0.13.10.48" }
1+
{ "git_describe": "v0.13.10-55-g0e259437", "git_timestamp": "2026-01-23T00:10:08+03:00", "git_tree": "c8db16cb900cb846176ee0b37a94eaa557bdeb5d", "git_commit": "0e259437202d086a51ded0ad65f3662cda26b1e9", "semver": "0.13.10.55" }

mdbx.c

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#define xMDBX_ALLOY 1 /* alloyed build */
66

7-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
7+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
88

99
#define LIBMDBX_INTERNALS
1010
#define MDBX_DEPRECATED
@@ -5831,7 +5831,7 @@ typedef struct gc_update_context {
58315831
unsigned loop;
58325832
pgno_t prev_first_unallocated;
58335833
bool dense;
5834-
size_t reserve_adj;
5834+
size_t reserve_adj, backlog_adj;
58355835
size_t retired_stored;
58365836
size_t amount, reserved, cleaned_slot, reused_slot, fill_idx;
58375837
txnid_t cleaned_id, rid;
@@ -14329,7 +14329,7 @@ static void histogram_reduce(struct MDBX_chk_histogram *p) {
1432914329
p->ranges[min_i].count += p->ranges[min_i + 1].count;
1433014330
if (min_i < last)
1433114331
// перемещаем хвост
14332-
memmove(p->ranges + min_i, p->ranges + min_i + 1, (last - min_i) * sizeof(p->ranges[0]));
14332+
memmove(p->ranges + min_i + 1, p->ranges + min_i + 2, (last - min_i) * sizeof(p->ranges[0]));
1433314333
// обнуляем последний элемент и продолжаем
1433414334
p->ranges[last].count = 0;
1433514335
}
@@ -22755,7 +22755,7 @@ next_gc:;
2275522755
const meta_ptr_t recent = meta_recent(env, &txn->tw.troika);
2275622756
const meta_ptr_t prefer_steady = meta_prefer_steady(env, &txn->tw.troika);
2275722757
if ((flags & ALLOC_UNIMPORTANT) == 0 && recent.ptr_c != prefer_steady.ptr_c && prefer_steady.is_steady &&
22758-
detent == prefer_steady.txnid + 1) {
22758+
detent == prefer_steady.txnid) {
2275922759
DEBUG("gc-kick-steady: recent %" PRIaTXN "-%s, steady %" PRIaTXN "-%s, detent %" PRIaTXN, recent.txnid,
2276022760
durable_caption(recent.ptr_c), prefer_steady.txnid, durable_caption(prefer_steady.ptr_c), detent);
2276122761
const pgno_t autosync_threshold = atomic_load32(&env->lck->autosync_threshold, mo_Relaxed);
@@ -22798,8 +22798,9 @@ next_gc:;
2279822798
eASSERT(env, ret.err != MDBX_RESULT_TRUE);
2279922799
if (unlikely(ret.err != MDBX_SUCCESS))
2280022800
goto fail;
22801-
eASSERT(env, prefer_steady.ptr_c != meta_prefer_steady(env, &txn->tw.troika).ptr_c);
22802-
goto retry_gc_refresh_oldest;
22801+
if (prefer_steady.ptr_c != meta_prefer_steady(env, &txn->tw.troika).ptr_c)
22802+
goto retry_gc_refresh_oldest;
22803+
eASSERT(env, env->incore);
2280322804
}
2280422805
}
2280522806

@@ -22826,14 +22827,11 @@ next_gc:;
2282622827

2282722828
no_gc:
2282822829
eASSERT(env, pgno == 0);
22829-
#ifndef MDBX_ENABLE_BACKLOG_DEPLETED
22830-
#define MDBX_ENABLE_BACKLOG_DEPLETED 0
22831-
#endif /* MDBX_ENABLE_BACKLOG_DEPLETED*/
22832-
if (MDBX_ENABLE_BACKLOG_DEPLETED && unlikely(!(txn->flags & txn_gc_drained))) {
22830+
if (unlikely(!(txn->flags & txn_gc_drained))) {
2283322831
ret.err = MDBX_BACKLOG_DEPLETED;
2283422832
goto fail;
2283522833
}
22836-
if (flags & ALLOC_RESERVE) {
22834+
if (flags & (ALLOC_RESERVE | ALLOC_UNIMPORTANT)) {
2283722835
ret.err = MDBX_NOTFOUND;
2283822836
goto fail;
2283922837
}
@@ -23041,16 +23039,18 @@ static int prepare_backlog(MDBX_txn *txn, gcu_t *ctx) {
2304123039
const size_t for_tree_after_touch = for_rebalance + for_split;
2304223040
const size_t for_all_before_touch = for_repnl + for_tree_before_touch;
2304323041
const size_t for_all_after_touch = for_repnl + for_tree_after_touch;
23042+
const size_t enough_before_touch = for_all_before_touch + ctx->backlog_adj;
23043+
const size_t enough_after_touch = for_all_after_touch + ctx->backlog_adj;
2304423044

23045-
if (likely(for_repnl < 2 && backlog_size(txn) > for_all_before_touch) &&
23045+
if (likely(for_repnl < 2 && backlog_size(txn) > enough_before_touch) &&
2304623046
(ctx->cursor.top < 0 || is_modifable(txn, ctx->cursor.pg[ctx->cursor.top])))
2304723047
return MDBX_SUCCESS;
2304823048

23049-
TRACE(">> retired-stored %zu, left %zi, backlog %zu, need %zu (4list %zu, "
23049+
TRACE(">> retired-stored %zu, left %zi, backlog %zu, adj %zu, need %zu (4list %zu, "
2305023050
"4split %zu, "
2305123051
"4cow %zu, 4tree %zu)",
23052-
ctx->retired_stored, retired_left, backlog_size(txn), for_all_before_touch, for_repnl, for_split, for_cow,
23053-
for_tree_before_touch);
23052+
ctx->retired_stored, retired_left, backlog_size(txn), ctx->backlog_adj, enough_before_touch, for_repnl,
23053+
for_split, for_cow, for_tree_before_touch);
2305423054

2305523055
int err = touch_gc(ctx);
2305623056
TRACE("== after-touch, backlog %zu, err %d", backlog_size(txn), err);
@@ -23069,12 +23069,12 @@ static int prepare_backlog(MDBX_txn *txn, gcu_t *ctx) {
2306923069
cASSERT(&ctx->cursor, backlog_size(txn) >= for_repnl || err != MDBX_SUCCESS);
2307023070
}
2307123071

23072-
while (backlog_size(txn) < for_all_after_touch && err == MDBX_SUCCESS)
23072+
while (backlog_size(txn) < enough_after_touch && err == MDBX_SUCCESS)
2307323073
err = gc_alloc_ex(&ctx->cursor, 0, ALLOC_RESERVE | ALLOC_UNIMPORTANT).err;
2307423074

23075-
TRACE("<< backlog %zu, err %d, gc: height %u, branch %zu, leaf %zu, large "
23075+
TRACE("<< backlog %zu, err %d, adj %zu, gc: height %u, branch %zu, leaf %zu, large "
2307623076
"%zu, entries %zu",
23077-
backlog_size(txn), err, txn->dbs[FREE_DBI].height, (size_t)txn->dbs[FREE_DBI].branch_pages,
23077+
backlog_size(txn), err, ctx->backlog_adj, txn->dbs[FREE_DBI].height, (size_t)txn->dbs[FREE_DBI].branch_pages,
2307823078
(size_t)txn->dbs[FREE_DBI].leaf_pages, (size_t)txn->dbs[FREE_DBI].large_pages,
2307923079
(size_t)txn->dbs[FREE_DBI].items);
2308023080
tASSERT(txn, err != MDBX_NOTFOUND || (txn->flags & txn_gc_drained) != 0);
@@ -23489,6 +23489,7 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2348923489
* But page numbers cannot disappear from txn->tw.retired_pages[]. */
2349023490
retry_clean_adj:
2349123491
ctx->reserve_adj = 0;
23492+
ctx->backlog_adj = 0;
2349223493
retry:
2349323494
ctx->loop += !(ctx->prev_first_unallocated > txn->geo.first_unallocated);
2349423495
TRACE(">> restart, loop %u", ctx->loop);
@@ -23503,8 +23504,13 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2350323504

2350423505
if (unlikely(ctx->dense || ctx->prev_first_unallocated > txn->geo.first_unallocated)) {
2350523506
rc = clean_stored_retired(txn, ctx);
23506-
if (unlikely(rc != MDBX_SUCCESS))
23507+
if (unlikely(rc != MDBX_SUCCESS)) {
23508+
if (rc == MDBX_BACKLOG_DEPLETED) {
23509+
ctx->backlog_adj += ctx->backlog_adj + 1;
23510+
goto retry;
23511+
}
2350723512
goto bailout;
23513+
}
2350823514
}
2350923515

2351023516
ctx->prev_first_unallocated = txn->geo.first_unallocated;
@@ -23546,8 +23552,13 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2354623552
TRACE("%s: cleanup-reclaimed-id [%zu]%" PRIaTXN, dbg_prefix(ctx), ctx->cleaned_slot, ctx->cleaned_id);
2354723553
tASSERT(txn, *txn->cursors == &ctx->cursor);
2354823554
rc = cursor_del(&ctx->cursor, 0);
23549-
if (unlikely(rc != MDBX_SUCCESS))
23555+
if (unlikely(rc != MDBX_SUCCESS)) {
23556+
if (rc == MDBX_BACKLOG_DEPLETED) {
23557+
ctx->backlog_adj += ctx->backlog_adj + 1;
23558+
goto retry;
23559+
}
2355023560
goto bailout;
23561+
}
2355123562
} while (ctx->cleaned_slot < MDBX_PNL_GETSIZE(txn->tw.gc.retxl));
2355223563
txl_sort(txn->tw.gc.retxl);
2355323564
}
@@ -23585,8 +23596,13 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2358523596
TRACE("%s: cleanup-reclaimed-id %" PRIaTXN, dbg_prefix(ctx), ctx->cleaned_id);
2358623597
tASSERT(txn, *txn->cursors == &ctx->cursor);
2358723598
rc = cursor_del(&ctx->cursor, 0);
23588-
if (unlikely(rc != MDBX_SUCCESS))
23599+
if (unlikely(rc != MDBX_SUCCESS)) {
23600+
if (rc == MDBX_BACKLOG_DEPLETED) {
23601+
ctx->backlog_adj += ctx->backlog_adj + 1;
23602+
goto retry;
23603+
}
2358923604
goto bailout;
23605+
}
2359023606
}
2359123607
}
2359223608

@@ -23631,8 +23647,13 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2363123647
if (ctx->retired_stored < MDBX_PNL_GETSIZE(txn->tw.retired_pages)) {
2363223648
/* store retired-list into GC */
2363323649
rc = gcu_retired(txn, ctx);
23634-
if (unlikely(rc != MDBX_SUCCESS))
23650+
if (unlikely(rc != MDBX_SUCCESS)) {
23651+
if (rc == MDBX_BACKLOG_DEPLETED) {
23652+
ctx->backlog_adj += ctx->backlog_adj + 1;
23653+
goto retry;
23654+
}
2363523655
goto bailout;
23656+
}
2363623657
continue;
2363723658
}
2363823659

@@ -23661,6 +23682,7 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2366123682
continue;
2366223683
if (likely(rc == MDBX_RESULT_TRUE))
2366323684
goto retry;
23685+
eASSERT(env, rc != MDBX_BACKLOG_DEPLETED);
2366423686
goto bailout;
2366523687
}
2366623688
tASSERT(txn, rid_result.err == MDBX_SUCCESS);
@@ -23738,8 +23760,13 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2373823760
prepare_backlog(txn, ctx);
2373923761
rc = cursor_put(&ctx->cursor, &key, &data, MDBX_RESERVE | MDBX_NOOVERWRITE);
2374023762
tASSERT(txn, pnl_check_allocated(txn->tw.repnl, txn->geo.first_unallocated - MDBX_ENABLE_REFUND));
23741-
if (unlikely(rc != MDBX_SUCCESS))
23763+
if (unlikely(rc != MDBX_SUCCESS)) {
23764+
if (rc == MDBX_BACKLOG_DEPLETED) {
23765+
ctx->backlog_adj += ctx->backlog_adj + 1;
23766+
goto retry;
23767+
}
2374223768
goto bailout;
23769+
}
2374323770

2374423771
zeroize_reserved(env, data);
2374523772
ctx->reserved += chunk;
@@ -23830,8 +23857,13 @@ int gc_update(MDBX_txn *txn, gcu_t *ctx) {
2383023857
chunk = left;
2383123858
}
2383223859
rc = cursor_put(&ctx->cursor, &key, &data, MDBX_CURRENT | MDBX_RESERVE);
23833-
if (unlikely(rc != MDBX_SUCCESS))
23860+
if (unlikely(rc != MDBX_SUCCESS)) {
23861+
if (rc == MDBX_BACKLOG_DEPLETED) {
23862+
ctx->backlog_adj += ctx->backlog_adj + 1;
23863+
goto retry;
23864+
}
2383423865
goto bailout;
23866+
}
2383523867
zeroize_reserved(env, data);
2383623868

2383723869
if (unlikely(txn->tw.loose_count || ctx->amount != MDBX_PNL_GETSIZE(txn->tw.repnl))) {
@@ -37565,10 +37597,10 @@ __dll_export
3756537597
0,
3756637598
13,
3756737599
10,
37568-
48,
37600+
55,
3756937601
"", /* pre-release suffix of SemVer
37570-
0.13.10.48 */
37571-
{"2026-01-17T00:28:51+03:00", "634dea88bd00c8046d1118eb024443675acdd704", "ade27cfc487a70f61421996d2682be46a4d305b5", "v0.13.10-48-gade27cfc"},
37602+
0.13.10.55 */
37603+
{"2026-01-23T00:10:08+03:00", "c8db16cb900cb846176ee0b37a94eaa557bdeb5d", "0e259437202d086a51ded0ad65f3662cda26b1e9", "v0.13.10-55-g0e259437"},
3757237604
sourcery};
3757337605

3757437606
__dll_export

mdbx.c++

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
33
/* clang-format off */
44

5-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
5+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
66

77
#define LIBMDBX_INTERNALS
88
#define MDBX_DEPRECATED
@@ -3668,16 +3668,16 @@ __cold void error::throw_exception() const {
36683668

36693669
bool slice::is_printable(bool disable_utf8) const noexcept {
36703670
enum : byte {
3671-
LS = 4, // shift for UTF8 sequence length
3672-
P_ = 1 << LS, // printable ASCII flag
3673-
X_ = 1 << (LS - 1), // printable extended ASCII flag
3674-
N_ = 0, // non-printable ASCII
3675-
second_range_mask = P_ - 1, // mask for range flag
3676-
r80_BF = 0, // flag for UTF8 2nd byte range
3677-
rA0_BF = 1, // flag for UTF8 2nd byte range
3678-
r80_9F = 2, // flag for UTF8 2nd byte range
3679-
r90_BF = 3, // flag for UTF8 2nd byte range
3680-
r80_8F = 4, // flag for UTF8 2nd byte range
3671+
LS = 4, // shift for UTF8 sequence length
3672+
P_ = 1 << LS, // printable ASCII flag
3673+
X_ = 1 << (LS - 1), // printable extended ASCII flag
3674+
N_ = 0, // non-printable ASCII
3675+
r80_BF = 0, // flag for UTF8 2nd byte range
3676+
rA0_BF = 1, // flag for UTF8 2nd byte range
3677+
r80_9F = 2, // flag for UTF8 2nd byte range
3678+
r90_BF = 3, // flag for UTF8 2nd byte range
3679+
r80_8F = 4, // flag for UTF8 2nd byte range
3680+
second_range_mask = 7, // mask for range flag
36813681

36823682
// valid utf-8 byte sequences
36833683
// http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94

mdbx_chk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/// \copyright SPDX-License-Identifier: Apache-2.0
1919
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
2020

21-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
21+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
2222

2323
#define LIBMDBX_INTERNALS
2424
#define MDBX_DEPRECATED

mdbx_copy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/// \copyright SPDX-License-Identifier: Apache-2.0
1919
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
2020

21-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
21+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
2222

2323
#define LIBMDBX_INTERNALS
2424
#define MDBX_DEPRECATED

mdbx_drop.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/// \copyright SPDX-License-Identifier: Apache-2.0
1919
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
2020

21-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
21+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
2222

2323
#define LIBMDBX_INTERNALS
2424
#define MDBX_DEPRECATED

mdbx_dump.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/// \copyright SPDX-License-Identifier: Apache-2.0
1919
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
2020

21-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
21+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
2222

2323
#define LIBMDBX_INTERNALS
2424
#define MDBX_DEPRECATED

mdbx_load.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/// \copyright SPDX-License-Identifier: Apache-2.0
1919
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
2020

21-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
21+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
2222

2323
#define LIBMDBX_INTERNALS
2424
#define MDBX_DEPRECATED

mdbx_stat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/// \copyright SPDX-License-Identifier: Apache-2.0
1919
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
2020

21-
#define MDBX_BUILD_SOURCERY 7c3db6b50efa53fccd19c2645565587fe14e39e3bd30b53c395ab00678ba17e3_v0_13_10_48_gade27cfc
21+
#define MDBX_BUILD_SOURCERY ca20edfe05b881496cbe6bd6058b8d40e4651ff0e65bbb46039de12d02995bb8_v0_13_10_55_g0e259437
2222

2323
#define LIBMDBX_INTERNALS
2424
#define MDBX_DEPRECATED

0 commit comments

Comments
 (0)