From 800c96f22fd62022ff82c2e21b16c436c570a2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 2 May 2025 17:59:30 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B7=D0=B5=D1=80=D0=B2=D0=B0=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=82=D0=B5=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=20=D0=B2=20GC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В экстремальных случаях, масштабирование одного операнда и 32-бит не хватает для предотвращения потери значимости расчетного коэффициента. Поэтому здесь реализован переход на фиксированную точку 32-точка-32 с одним 64-битным делением и двумя полными умножениями 32*32->64. Для 32-битных систем можно сделать чуть легче, заменив 64-битую арифметику масштабированием (адаптивным сдвигом) обоих операндов, но пока не вижу в этом смысла. --- src/gc-put.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/gc-put.c b/src/gc-put.c index 8cfaa77e..a6c3a1ed 100644 --- a/src/gc-put.c +++ b/src/gc-put.c @@ -1295,12 +1295,10 @@ static int gc_fill_returned(MDBX_txn *txn, gcu_t *ctx) { rkl_iter_t iter = rkl_iterator(&txn->wr.gc.comeback, is_lifo(txn)); size_t surplus = ctx->return_reserved_hi - amount, stored = 0; - const size_t scale = 32 - ceil_log2n(ctx->return_reserved_hi), half4rounding = (1 << scale) / 2 - 1; - tASSERT(txn, scale > 3 && scale < 32); - const size_t factor = (surplus << scale) / ctx->return_reserved_hi; - TRACE("%s: amount %zu, slots %zu, surplus %zu (%zu..%zu), factor %.5f (sharp %.7f)", dbg_prefix(ctx), amount, slots, - surplus, ctx->return_reserved_lo, ctx->return_reserved_hi, factor / (double)(1 << scale), - surplus / (double)ctx->return_reserved_lo); + const uint64_t factor = ((uint64_t)surplus << 32) / ctx->return_reserved_hi; + TRACE("%s: amount %zu, slots %zu, surplus %zu (%zu..%zu), factor %.6f (%" PRIu64 " >> 32, sharp %.12f)", + dbg_prefix(ctx), amount, slots, surplus, ctx->return_reserved_lo, ctx->return_reserved_hi, + factor / (double)UINT32_MAX, factor, surplus / (double)ctx->return_reserved_hi); do { const size_t left = amount - stored; tASSERT(txn, left > 0 && left <= amount); @@ -1324,20 +1322,17 @@ static int gc_fill_returned(MDBX_txn *txn, gcu_t *ctx) { const size_t left_slots = rkl_left(&iter, is_lifo(txn)); if (surplus && left_slots) { /* Единственный путь выполнения (набор условий) когда нужно распределять избыток резерва. */ - size_t hole = (chunk_hi * factor + half4rounding) >> scale; + const size_t hole = (size_t)((chunk_hi * factor) >> 32); tASSERT(txn, hole < chunk_hi && hole <= surplus); chunk = chunk_hi - hole; - tASSERT(txn, chunk > 0 && chunk <= chunk_hi); - const intptr_t estimate_balance = - (((left + surplus - chunk_hi) * factor + half4rounding) >> scale) - (surplus - hole); - if (MDBX_HAVE_CMOV || estimate_balance) { - chunk -= estimate_balance < 0 && chunk > 1; - chunk += estimate_balance > 0 && hole > 0 && surplus > hole; - } + tASSERT(txn, chunk > 0 && chunk <= chunk_hi && surplus >= hole); + tASSERT(txn, surplus - hole >= (left + surplus - chunk_hi) * factor >> 32); + if (chunk > 1 && surplus - hole > (left + surplus - chunk_hi) * factor >> 32) + chunk -= 1; } tASSERT(txn, chunk <= chunk_hi && surplus >= chunk_hi - chunk && chunk <= left); - surplus -= chunk_hi - chunk; } + surplus -= chunk_hi - chunk; pgno_t *const dst = data.iov_base; pgno_t *const src = MDBX_PNL_BEGIN(txn->wr.repnl) + left - chunk;