mirror of
https://github.com/isar/libmdbx.git
synced 2025-05-12 16:27:46 +08:00
mdbx: доработки gc_handle_dense()
для экстремально-редких случаев.
This commit is contained in:
parent
402a8e62be
commit
76e2544cc0
@ -1330,9 +1330,9 @@ __cold static int chk_handle_gc(MDBX_chk_scope_t *const scope, MDBX_chk_table_t
|
|||||||
(number + 1) * sizeof(pgno_t), data->iov_len);
|
(number + 1) * sizeof(pgno_t), data->iov_len);
|
||||||
number = data->iov_len / sizeof(pgno_t) - 1;
|
number = data->iov_len / sizeof(pgno_t) - 1;
|
||||||
} else if (data->iov_len - (number + 1) * sizeof(pgno_t) >=
|
} else if (data->iov_len - (number + 1) * sizeof(pgno_t) >=
|
||||||
/* LY: allow gap up to one page. it is ok
|
/* LY: allow gap up to two page. it is ok
|
||||||
* and better than shink-and-retry inside gc_update() */
|
* and better than shink-and-retry inside gc_update() */
|
||||||
usr->env->ps)
|
usr->env->ps * 2)
|
||||||
chk_object_issue(scope, "entry", txnid, "extra idl space",
|
chk_object_issue(scope, "entry", txnid, "extra idl space",
|
||||||
"%" PRIuSIZE " < %" PRIuSIZE " (minor, not a trouble)", (number + 1) * sizeof(pgno_t),
|
"%" PRIuSIZE " < %" PRIuSIZE " (minor, not a trouble)", (number + 1) * sizeof(pgno_t),
|
||||||
data->iov_len);
|
data->iov_len);
|
||||||
|
@ -716,8 +716,8 @@ __hot static pgno_t repnl_get_sequence(MDBX_txn *txn, const size_t num, uint8_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gc_repnl_has_span(MDBX_txn *txn, const size_t num) {
|
bool gc_repnl_has_span(const MDBX_txn *txn, const size_t num) {
|
||||||
return (num > 1) ? repnl_get_sequence(txn, num, ALLOC_RESERVE) != 0 : !MDBX_PNL_IS_EMPTY(txn->wr.repnl);
|
return (num > 1) ? repnl_get_sequence((MDBX_txn *)txn, num, ALLOC_RESERVE) != 0 : !MDBX_PNL_IS_EMPTY(txn->wr.repnl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline pgr_t page_alloc_finalize(MDBX_env *const env, MDBX_txn *const txn, const MDBX_cursor *const mc,
|
static inline pgr_t page_alloc_finalize(MDBX_env *const env, MDBX_txn *const txn, const MDBX_cursor *const mc,
|
||||||
|
177
src/gc-put.c
177
src/gc-put.c
@ -20,6 +20,10 @@ void gc_put_destroy(gcu_t *ctx) {
|
|||||||
rkl_destroy(&ctx->sequel);
|
rkl_destroy(&ctx->sequel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t gc_chunk_pages(const MDBX_txn *txn, const size_t chunk) {
|
||||||
|
return largechunk_npages(txn->env, gc_chunk_bytes(chunk));
|
||||||
|
}
|
||||||
|
|
||||||
static int gc_peekid(const MDBX_val *key, txnid_t *id) {
|
static int gc_peekid(const MDBX_val *key, txnid_t *id) {
|
||||||
if (likely(key->iov_len == sizeof(txnid_t))) {
|
if (likely(key->iov_len == sizeof(txnid_t))) {
|
||||||
*id = unaligned_peek_u64(4, key->iov_base);
|
*id = unaligned_peek_u64(4, key->iov_base);
|
||||||
@ -397,7 +401,7 @@ static int gc_store_retired(MDBX_txn *txn, gcu_t *ctx) {
|
|||||||
const size_t chunk_hi = ((left_before | 3) > ctx->goodchunk && ctx->bigfoot < (MAX_TXNID - UINT32_MAX))
|
const size_t chunk_hi = ((left_before | 3) > ctx->goodchunk && ctx->bigfoot < (MAX_TXNID - UINT32_MAX))
|
||||||
? ctx->goodchunk
|
? ctx->goodchunk
|
||||||
: (left_before | 3);
|
: (left_before | 3);
|
||||||
data.iov_len = (chunk_hi + 1) * sizeof(pgno_t);
|
data.iov_len = gc_chunk_bytes(chunk_hi);
|
||||||
err = cursor_put(&ctx->cursor, &key, &data, MDBX_RESERVE);
|
err = cursor_put(&ctx->cursor, &key, &data, MDBX_RESERVE);
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
return err;
|
return err;
|
||||||
@ -630,11 +634,13 @@ typedef struct sr_context {
|
|||||||
* двигаясь по гистограмме от больших элементов к меньшим. */
|
* двигаясь по гистограмме от больших элементов к меньшим. */
|
||||||
static bool consume_remaining(const sr_context_t *const ct, sr_state_t *const st, size_t len) {
|
static bool consume_remaining(const sr_context_t *const ct, sr_state_t *const st, size_t len) {
|
||||||
pgno_t *const solution = ct->solution->array;
|
pgno_t *const solution = ct->solution->array;
|
||||||
size_t per_chunk = ct->first_page + ct->other_pages * (len - 1);
|
while (len > ct->factor)
|
||||||
|
solution[--len] = 0;
|
||||||
solution[len - 1] = 0;
|
solution[len - 1] = 0;
|
||||||
if (unlikely(0 >= (int)st->left_volume))
|
if (unlikely(0 >= (int)st->left_volume))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
size_t per_chunk = ct->first_page + ct->other_pages * (len - 1);
|
||||||
while (st->hist.end > 0 && st->left_slots > 0) {
|
while (st->hist.end > 0 && st->left_slots > 0) {
|
||||||
if (st->hist.array[st->hist.end - 1]) {
|
if (st->hist.array[st->hist.end - 1]) {
|
||||||
solution[len - 1] += 1;
|
solution[len - 1] += 1;
|
||||||
@ -678,8 +684,7 @@ static bool solve_recursive(const sr_context_t *const ct, sr_state_t *const st,
|
|||||||
}
|
}
|
||||||
assert(local.left_slots > n);
|
assert(local.left_slots > n);
|
||||||
local.left_slots -= n;
|
local.left_slots -= n;
|
||||||
assert(local.left_volume >= n * per_chunk);
|
local.left_volume = (local.left_volume > n * per_chunk) ? local.left_volume - n * per_chunk : 0;
|
||||||
local.left_volume -= n * per_chunk;
|
|
||||||
}
|
}
|
||||||
if (!solve_recursive(ct, &local, len - 1)) {
|
if (!solve_recursive(ct, &local, len - 1)) {
|
||||||
lo = n + 1;
|
lo = n + 1;
|
||||||
@ -707,8 +712,7 @@ static int gc_dense_solve(MDBX_txn *txn, gcu_t *ctx, gc_dense_histogram_t *const
|
|||||||
return MDBX_PROBLEM;
|
return MDBX_PROBLEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sr_context_t ct = {.factor = largechunk_npages(
|
const sr_context_t ct = {.factor = gc_chunk_pages(txn, (st.left_volume + st.left_slots - 1) / st.left_slots),
|
||||||
txn->env, ((st.left_volume + st.left_slots - 1) / st.left_slots + 1) * sizeof(pgno_t)),
|
|
||||||
.first_page = /* на первой странице */ txn->env->maxgc_large1page +
|
.first_page = /* на первой странице */ txn->env->maxgc_large1page +
|
||||||
/* сама страница также будет израсходована */ 1,
|
/* сама страница также будет израсходована */ 1,
|
||||||
.other_pages = /* на второй и последующих страницах */ txn->env->ps / sizeof(pgno_t) +
|
.other_pages = /* на второй и последующих страницах */ txn->env->ps / sizeof(pgno_t) +
|
||||||
@ -745,7 +749,7 @@ static int gc_dense_solve(MDBX_txn *txn, gcu_t *ctx, gc_dense_histogram_t *const
|
|||||||
// int gc_solve_test(MDBX_txn *txn, gcu_t *ctx) {
|
// int gc_solve_test(MDBX_txn *txn, gcu_t *ctx) {
|
||||||
// gc_dense_histogram_t r;
|
// gc_dense_histogram_t r;
|
||||||
// gc_dense_histogram_t *const solution = &r;
|
// gc_dense_histogram_t *const solution = &r;
|
||||||
|
//
|
||||||
// sr_state_t st = {.left_slots = 5,
|
// sr_state_t st = {.left_slots = 5,
|
||||||
// .left_volume = 8463,
|
// .left_volume = 8463,
|
||||||
// .hist = {.end = 31, .array = {6493, 705, 120, 14, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
// .hist = {.end = 31, .array = {6493, 705, 120, 14, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||||
@ -755,23 +759,21 @@ static int gc_dense_solve(MDBX_txn *txn, gcu_t *ctx, gc_dense_histogram_t *const
|
|||||||
// ERROR("%s/%d: %s", "MDBX_PROBLEM", MDBX_PROBLEM, "recursive-solving preconditions violated");
|
// ERROR("%s/%d: %s", "MDBX_PROBLEM", MDBX_PROBLEM, "recursive-solving preconditions violated");
|
||||||
// return MDBX_PROBLEM;
|
// return MDBX_PROBLEM;
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// const sr_context_t ct = {.factor = largechunk_npages(
|
// const sr_context_t ct = {.factor = gc_chunk_pages(txn, (st.left_volume + st.left_slots - 1) / st.left_slots),
|
||||||
// txn->env, ((st.left_volume + st.left_slots - 1) / st.left_slots + 1) *
|
|
||||||
// sizeof(pgno_t)),
|
|
||||||
// .first_page = /* на первой странице */ txn->env->maxgc_large1page +
|
// .first_page = /* на первой странице */ txn->env->maxgc_large1page +
|
||||||
// /* сама страница также будет израсходована */ 1,
|
// /* сама страница также будет израсходована */ 1,
|
||||||
// .other_pages = /* на второй и последующих страницах */ txn->env->ps / sizeof(pgno_t) +
|
// .other_pages = /* на второй и последующих страницах */ txn->env->ps / sizeof(pgno_t) +
|
||||||
// /* каждая страница также будет израсходована */ 1,
|
// /* каждая страница также будет израсходована */ 1,
|
||||||
// .solution = solution};
|
// .solution = solution};
|
||||||
|
//
|
||||||
// memset(solution, 0, sizeof(*solution));
|
// memset(solution, 0, sizeof(*solution));
|
||||||
// if (solve_recursive(&ct, &st, st.hist.end)) {
|
// if (solve_recursive(&ct, &st, st.hist.end)) {
|
||||||
// const pgno_t *end = ARRAY_END(solution->array);
|
// const pgno_t *end = ARRAY_END(solution->array);
|
||||||
// while (end > solution->array && end[-1] == 0)
|
// while (end > solution->array && end[-1] == 0)
|
||||||
// --end;
|
// --end;
|
||||||
// solution->end = (unsigned)(end - solution->array);
|
// solution->end = (unsigned)(end - solution->array);
|
||||||
|
//
|
||||||
// /* проверяем решение */
|
// /* проверяем решение */
|
||||||
// size_t items = 0, volume = 0;
|
// size_t items = 0, volume = 0;
|
||||||
// for (size_t i = 0, chunk = ct.first_page; i < solution->end; ++i) {
|
// for (size_t i = 0, chunk = ct.first_page; i < solution->end; ++i) {
|
||||||
@ -779,7 +781,7 @@ static int gc_dense_solve(MDBX_txn *txn, gcu_t *ctx, gc_dense_histogram_t *const
|
|||||||
// volume += solution->array[i] * chunk;
|
// volume += solution->array[i] * chunk;
|
||||||
// chunk += ct.other_pages;
|
// chunk += ct.other_pages;
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// if (unlikely(volume < (size_t)ctx->return_left || items > rkl_len(&ctx->ready4reuse))) {
|
// if (unlikely(volume < (size_t)ctx->return_left || items > rkl_len(&ctx->ready4reuse))) {
|
||||||
// assert(!"recursive-solving failure");
|
// assert(!"recursive-solving failure");
|
||||||
// ERROR("%s/%d: %s", "MDBX_PROBLEM", MDBX_PROBLEM, "recursive-solving failure");
|
// ERROR("%s/%d: %s", "MDBX_PROBLEM", MDBX_PROBLEM, "recursive-solving failure");
|
||||||
@ -787,7 +789,7 @@ static int gc_dense_solve(MDBX_txn *txn, gcu_t *ctx, gc_dense_histogram_t *const
|
|||||||
// }
|
// }
|
||||||
// return MDBX_RESULT_TRUE;
|
// return MDBX_RESULT_TRUE;
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// /* решение НЕ найдено */
|
// /* решение НЕ найдено */
|
||||||
// return MDBX_RESULT_FALSE;
|
// return MDBX_RESULT_FALSE;
|
||||||
// }
|
// }
|
||||||
@ -962,7 +964,7 @@ static inline int gc_reserve4return(MDBX_txn *txn, gcu_t *ctx, const size_t chun
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
MDBX_val key = {.iov_base = &reservation_id, .iov_len = sizeof(reservation_id)};
|
MDBX_val key = {.iov_base = &reservation_id, .iov_len = sizeof(reservation_id)};
|
||||||
MDBX_val data = {.iov_base = nullptr, .iov_len = (chunk_hi + 1) * sizeof(pgno_t)};
|
MDBX_val data = {.iov_base = nullptr, .iov_len = gc_chunk_bytes(chunk_hi)};
|
||||||
TRACE("%s: reserved +%zu...+%zu [%zu...%zu), err %d", dbg_prefix(ctx), chunk_lo, chunk_hi,
|
TRACE("%s: reserved +%zu...+%zu [%zu...%zu), err %d", dbg_prefix(ctx), chunk_lo, chunk_hi,
|
||||||
ctx->return_reserved_lo + 1, ctx->return_reserved_hi + chunk_hi + 1, err);
|
ctx->return_reserved_lo + 1, ctx->return_reserved_hi + chunk_hi + 1, err);
|
||||||
gc_prepare_stockpile4update(txn, ctx);
|
gc_prepare_stockpile4update(txn, ctx);
|
||||||
@ -974,15 +976,28 @@ static inline int gc_reserve4return(MDBX_txn *txn, gcu_t *ctx, const size_t chun
|
|||||||
memset(data.iov_base, 0, data.iov_len);
|
memset(data.iov_base, 0, data.iov_len);
|
||||||
ctx->return_reserved_lo += chunk_lo;
|
ctx->return_reserved_lo += chunk_lo;
|
||||||
ctx->return_reserved_hi += chunk_hi;
|
ctx->return_reserved_hi += chunk_hi;
|
||||||
|
if (unlikely(!rkl_empty(&txn->wr.gc.reclaimed))) {
|
||||||
|
NOTICE("%s: restart since %zu slot(s) reclaimed (reserved %zu...%zu of %zu)", dbg_prefix(ctx),
|
||||||
|
rkl_len(&txn->wr.gc.reclaimed), ctx->return_reserved_lo, ctx->return_reserved_hi,
|
||||||
|
MDBX_PNL_GETSIZE(txn->wr.repnl));
|
||||||
|
return MDBX_RESULT_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t adjust_chunk(const gcu_t *const ctx, const size_t chunk) {
|
static size_t dense_chunk_outlay(const MDBX_txn *txn, const size_t chunk) {
|
||||||
const MDBX_env *const env = ctx->cursor.txn->env;
|
size_t need_span = gc_chunk_pages(txn, chunk);
|
||||||
size_t hi = chunk, lo = chunk - largechunk_npages(env, (chunk + 1) * sizeof(pgno_t)), adjusted = lo;
|
return gc_repnl_has_span(txn, need_span) ? need_span : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t dense_adjust_chunk(const MDBX_txn *txn, const size_t chunk) {
|
||||||
|
size_t adjusted = chunk;
|
||||||
|
if (chunk > txn->env->maxgc_large1page) {
|
||||||
|
size_t hi = chunk + 1, lo = chunk - gc_chunk_pages(txn, chunk) - 1;
|
||||||
while (lo < hi) {
|
while (lo < hi) {
|
||||||
adjusted = (hi + lo) / 2;
|
adjusted = (hi + lo) / 2;
|
||||||
size_t probe = chunk - largechunk_npages(env, (adjusted + 1) * sizeof(pgno_t));
|
size_t probe = chunk - dense_chunk_outlay(txn, adjusted);
|
||||||
if (probe > adjusted)
|
if (probe > adjusted)
|
||||||
lo = adjusted + 1;
|
lo = adjusted + 1;
|
||||||
else if (probe < adjusted)
|
else if (probe < adjusted)
|
||||||
@ -990,9 +1005,16 @@ static size_t adjust_chunk(const gcu_t *const ctx, const size_t chunk) {
|
|||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return adjusted;
|
return adjusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t dense_adjust_amount(const MDBX_txn *const txn, size_t amount) {
|
||||||
|
const size_t gap = 2 + txn->dbs[FREE_DBI].height;
|
||||||
|
const size_t snubber = txn->env->ps / sizeof(pgno_t) / 2;
|
||||||
|
return ((amount + gap < txn->env->maxgc_large1page) ? txn->env->maxgc_large1page : amount + snubber);
|
||||||
|
}
|
||||||
|
|
||||||
static int gc_handle_dense(MDBX_txn *txn, gcu_t *ctx, size_t left_min, size_t left_max) {
|
static int gc_handle_dense(MDBX_txn *txn, gcu_t *ctx, size_t left_min, size_t left_max) {
|
||||||
/* Крайне маловероятная ситуация, в текущем понимании не возможная при нормальной/ожидаемой работе всех
|
/* Крайне маловероятная ситуация, в текущем понимании не возможная при нормальной/ожидаемой работе всех
|
||||||
* актуальных версий движка. Тем не менее, сюда мы можем попасть при использовании БД с содержимым GC
|
* актуальных версий движка. Тем не менее, сюда мы можем попасть при использовании БД с содержимым GC
|
||||||
@ -1027,76 +1049,92 @@ static int gc_handle_dense(MDBX_txn *txn, gcu_t *ctx, size_t left_min, size_t le
|
|||||||
if (!rkl_empty(&ctx->ready4reuse)) {
|
if (!rkl_empty(&ctx->ready4reuse)) {
|
||||||
gc_dense_hist(txn, ctx);
|
gc_dense_hist(txn, ctx);
|
||||||
gc_dense_histogram_t solution;
|
gc_dense_histogram_t solution;
|
||||||
|
if (ctx->loop == 1 || ctx->loop % 3 == 0)
|
||||||
|
left_max = dense_adjust_amount(txn, left_max);
|
||||||
ctx->return_left = left_max;
|
ctx->return_left = left_max;
|
||||||
err = gc_dense_solve(txn, ctx, &solution);
|
err = gc_dense_solve(txn, ctx, &solution);
|
||||||
if (err == MDBX_RESULT_FALSE /* решение НЕ найдено */ && left_max != left_min) {
|
if (err == MDBX_RESULT_FALSE /* решение НЕ найдено */ && left_max != left_min) {
|
||||||
|
if (ctx->loop == 1 || ctx->loop % 3 == 0)
|
||||||
|
left_min = dense_adjust_amount(txn, left_min);
|
||||||
|
if (left_max != left_min) {
|
||||||
ctx->return_left = left_min;
|
ctx->return_left = left_min;
|
||||||
err = gc_dense_solve(txn, ctx, &solution);
|
err = gc_dense_solve(txn, ctx, &solution);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (err == MDBX_RESULT_TRUE /* решение найдено */) {
|
if (err == MDBX_RESULT_TRUE /* решение найдено */) {
|
||||||
for (size_t i = solution.end; i > 0; --i)
|
for (size_t i = solution.end; i > 0; --i)
|
||||||
for (pgno_t n = 0; n < solution.array[i - 1]; ++n) {
|
for (pgno_t n = 0; n < solution.array[i - 1]; ++n) {
|
||||||
size_t chunk_hi = txn->env->maxgc_large1page + txn->env->ps / sizeof(pgno_t) * (i - 1);
|
size_t span = i;
|
||||||
size_t chunk_lo = chunk_hi - txn->env->maxgc_large1page + ctx->goodchunk;
|
size_t chunk_hi = txn->env->maxgc_large1page + txn->env->ps / sizeof(pgno_t) * (span - 1);
|
||||||
if (chunk_hi > left_max)
|
if (chunk_hi > left_max) {
|
||||||
chunk_hi = left_max;
|
chunk_hi = left_max;
|
||||||
if (chunk_lo > left_min)
|
span = gc_chunk_pages(txn, chunk_hi);
|
||||||
chunk_lo = left_min;
|
}
|
||||||
|
size_t chunk_lo = chunk_hi - txn->env->maxgc_large1page + ctx->goodchunk;
|
||||||
TRACE("%s: dense-chunk (seq-len %zu, %d of %d) %zu...%zu, gc-per-ovpage %u", dbg_prefix(ctx), i, n + 1,
|
TRACE("%s: dense-chunk (seq-len %zu, %d of %d) %zu...%zu, gc-per-ovpage %u", dbg_prefix(ctx), i, n + 1,
|
||||||
solution.array[i - 1], chunk_lo, chunk_hi, txn->env->maxgc_large1page);
|
solution.array[i - 1], chunk_lo, chunk_hi, txn->env->maxgc_large1page);
|
||||||
|
size_t amount = MDBX_PNL_GETSIZE(txn->wr.repnl);
|
||||||
err = gc_reserve4return(txn, ctx, chunk_lo, chunk_hi);
|
err = gc_reserve4return(txn, ctx, chunk_lo, chunk_hi);
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
return err;
|
return err;
|
||||||
const size_t amount = MDBX_PNL_GETSIZE(txn->wr.repnl);
|
|
||||||
|
const size_t now = MDBX_PNL_GETSIZE(txn->wr.repnl);
|
||||||
|
if (span < amount - now - txn->dbs[FREE_DBI].height || span > amount - now + txn->dbs[FREE_DBI].height)
|
||||||
|
TRACE("dense-%s-reservation: miss %zu (expected) != %zi (got)", "solve", span, amount - now);
|
||||||
|
amount = now;
|
||||||
if (ctx->return_reserved_hi >= amount)
|
if (ctx->return_reserved_hi >= amount)
|
||||||
return rkl_empty(&txn->wr.gc.reclaimed) ? MDBX_SUCCESS
|
return MDBX_SUCCESS;
|
||||||
: MDBX_RESULT_TRUE /* нужно чистить переработанные записи */;
|
left_max = dense_adjust_amount(txn, amount) - ctx->return_reserved_lo;
|
||||||
left_min = amount - ctx->return_reserved_hi;
|
|
||||||
left_max = amount - ctx->return_reserved_lo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (rkl_len(&txn->wr.gc.comeback))
|
} else if (rkl_len(&txn->wr.gc.comeback)) {
|
||||||
|
NOTICE("%s: restart since %zu slot(s) comemack non-dense (reserved %zu...%zu of %zu)", dbg_prefix(ctx),
|
||||||
|
rkl_len(&txn->wr.gc.comeback), ctx->return_reserved_lo, ctx->return_reserved_hi,
|
||||||
|
MDBX_PNL_GETSIZE(txn->wr.repnl));
|
||||||
return /* повтор цикла */ MDBX_RESULT_TRUE;
|
return /* повтор цикла */ MDBX_RESULT_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (err == MDBX_RESULT_FALSE /* решение НЕ найдено, либо нет идентификаторов */) {
|
if (err == MDBX_RESULT_FALSE /* решение НЕ найдено, либо нет идентификаторов */) {
|
||||||
if (ctx->return_left > txn->env->maxgc_large1page) {
|
if (ctx->return_left > txn->env->maxgc_large1page) {
|
||||||
err = gc_reclaim_slot(txn, ctx);
|
err = gc_reclaim_slot(txn, ctx);
|
||||||
if (err == MDBX_NOTFOUND)
|
if (err == MDBX_NOTFOUND)
|
||||||
err = gc_reserve4retired(txn, ctx,
|
err = gc_reserve4retired(txn, ctx, gc_chunk_pages(txn, dense_adjust_chunk(txn, ctx->return_left)));
|
||||||
1 + (ctx->return_left - txn->env->maxgc_large1page) / (txn->env->ps / sizeof(pgno_t)));
|
if (err != MDBX_NOTFOUND && err != MDBX_SUCCESS)
|
||||||
if (err != MDBX_NOTFOUND) {
|
|
||||||
if (err != MDBX_SUCCESS)
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (ctx->loop == 1 && !rkl_empty(&txn->wr.gc.comeback))
|
|
||||||
return MDBX_RESULT_TRUE;
|
|
||||||
|
|
||||||
const size_t per_page = txn->env->ps / sizeof(pgno_t);
|
const size_t per_page = txn->env->ps / sizeof(pgno_t);
|
||||||
|
size_t amount = MDBX_PNL_GETSIZE(txn->wr.repnl);
|
||||||
do {
|
do {
|
||||||
if (!rkl_empty(&txn->wr.gc.reclaimed) || rkl_empty(&ctx->ready4reuse))
|
if (rkl_empty(&ctx->ready4reuse)) {
|
||||||
|
NOTICE("%s: restart since no slot(s) available (reserved %zu...%zu of %zu)", dbg_prefix(ctx),
|
||||||
|
ctx->return_reserved_lo, ctx->return_reserved_hi, amount);
|
||||||
return MDBX_RESULT_TRUE;
|
return MDBX_RESULT_TRUE;
|
||||||
const size_t amount = MDBX_PNL_GETSIZE(txn->wr.repnl);
|
}
|
||||||
const size_t reserved = (ctx->return_reserved_hi - ctx->return_reserved_lo > per_page) ? ctx->return_reserved_hi
|
const size_t left = dense_adjust_amount(txn, amount) - ctx->return_reserved_hi;
|
||||||
: ctx->return_reserved_lo;
|
|
||||||
const size_t slots = rkl_len(&ctx->ready4reuse);
|
const size_t slots = rkl_len(&ctx->ready4reuse);
|
||||||
const size_t left = amount - reserved;
|
|
||||||
const size_t base = (left + slots - 1) / slots;
|
const size_t base = (left + slots - 1) / slots;
|
||||||
const size_t adjusted = adjust_chunk(ctx, base);
|
const size_t adjusted = dense_adjust_chunk(txn, base);
|
||||||
const size_t predicted = (adjusted > txn->env->maxgc_large1page &&
|
TRACE("dense-reservation: reserved %zu...%zu of %zu, left %zu slot(s) and %zu pnl, step: %zu base,"
|
||||||
!gc_repnl_has_span(txn, largechunk_npages(txn->env, (adjusted + 1) * sizeof(pgno_t))))
|
" %zu adjusted",
|
||||||
? base
|
ctx->return_reserved_lo, ctx->return_reserved_hi, amount, slots, left, base, adjusted);
|
||||||
: adjusted;
|
|
||||||
const size_t chunk_hi =
|
const size_t chunk_hi =
|
||||||
(predicted > txn->env->maxgc_large1page)
|
(adjusted > txn->env->maxgc_large1page)
|
||||||
? txn->env->maxgc_large1page + ceil_powerof2(base - txn->env->maxgc_large1page, per_page)
|
? txn->env->maxgc_large1page + ceil_powerof2(adjusted - txn->env->maxgc_large1page, per_page)
|
||||||
: txn->env->maxgc_large1page;
|
: txn->env->maxgc_large1page;
|
||||||
const size_t chunk_lo =
|
const size_t chunk_lo =
|
||||||
(adjusted > txn->env->maxgc_large1page)
|
(adjusted > txn->env->maxgc_large1page)
|
||||||
? txn->env->maxgc_large1page + floor_powerof2(adjusted - txn->env->maxgc_large1page, per_page)
|
? txn->env->maxgc_large1page + floor_powerof2(adjusted - txn->env->maxgc_large1page, per_page)
|
||||||
: adjusted;
|
: adjusted;
|
||||||
err = gc_reserve4return(txn, ctx, chunk_lo, chunk_hi);
|
err = gc_reserve4return(txn, ctx, chunk_lo, chunk_hi);
|
||||||
} while (err == MDBX_SUCCESS && ctx->return_reserved_hi < MDBX_PNL_GETSIZE(txn->wr.repnl));
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
|
return err;
|
||||||
|
const size_t now = MDBX_PNL_GETSIZE(txn->wr.repnl);
|
||||||
|
if (base - adjusted + txn->dbs[FREE_DBI].height < amount - now ||
|
||||||
|
base - adjusted > amount - now + txn->dbs[FREE_DBI].height)
|
||||||
|
TRACE("dense-%s-reservation: miss %zu (expected) != %zi (got)", "unsolve", base - adjusted, amount - now);
|
||||||
|
amount = now;
|
||||||
|
} while (ctx->return_reserved_hi < amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
@ -1240,17 +1278,17 @@ static int gc_fill_returned(MDBX_txn *txn, gcu_t *ctx) {
|
|||||||
MDBX_val data = {.iov_base = nullptr, .iov_len = 0};
|
MDBX_val data = {.iov_base = nullptr, .iov_len = 0};
|
||||||
int err = cursor_seek(&ctx->cursor, &key, &data, MDBX_SET_KEY).err;
|
int err = cursor_seek(&ctx->cursor, &key, &data, MDBX_SET_KEY).err;
|
||||||
if (likely(err == MDBX_SUCCESS)) {
|
if (likely(err == MDBX_SUCCESS)) {
|
||||||
tASSERT(txn, data.iov_len >= MDBX_PNL_SIZEOF(txn->wr.repnl));
|
|
||||||
if (unlikely(data.iov_len - MDBX_PNL_SIZEOF(txn->wr.repnl) >= txn->env->ps)) {
|
|
||||||
NOTICE("too long comeback-reserve @%" PRIaTXN ", have %zu bytes, need %zu bytes", id, data.iov_len,
|
|
||||||
MDBX_PNL_SIZEOF(txn->wr.repnl));
|
|
||||||
return MDBX_RESULT_TRUE;
|
|
||||||
}
|
|
||||||
/* coverity[var_deref_model] */
|
|
||||||
memcpy(data.iov_base, txn->wr.repnl, MDBX_PNL_SIZEOF(txn->wr.repnl));
|
|
||||||
pgno_t *const from = MDBX_PNL_BEGIN(txn->wr.repnl), *const to = MDBX_PNL_END(txn->wr.repnl);
|
pgno_t *const from = MDBX_PNL_BEGIN(txn->wr.repnl), *const to = MDBX_PNL_END(txn->wr.repnl);
|
||||||
TRACE("%s: fill %zu [ %zu:%" PRIaPGNO "...%zu:%" PRIaPGNO "] @%" PRIaTXN " (%s)", dbg_prefix(ctx),
|
TRACE("%s: fill %zu [ %zu:%" PRIaPGNO "...%zu:%" PRIaPGNO "] @%" PRIaTXN " (%s)", dbg_prefix(ctx),
|
||||||
MDBX_PNL_GETSIZE(txn->wr.repnl), from - txn->wr.repnl, from[0], to - txn->wr.repnl, to[-1], id, "at-once");
|
MDBX_PNL_GETSIZE(txn->wr.repnl), from - txn->wr.repnl, from[0], to - txn->wr.repnl, to[-1], id, "at-once");
|
||||||
|
tASSERT(txn, data.iov_len >= gc_chunk_bytes(MDBX_PNL_GETSIZE(txn->wr.repnl)));
|
||||||
|
if (unlikely(data.iov_len - gc_chunk_bytes(MDBX_PNL_GETSIZE(txn->wr.repnl)) >= txn->env->ps * 2)) {
|
||||||
|
NOTICE("too long %s-comeback-reserve @%" PRIaTXN ", have %zu bytes, need %zu bytes", "single", id, data.iov_len,
|
||||||
|
gc_chunk_bytes(MDBX_PNL_GETSIZE(txn->wr.repnl)));
|
||||||
|
return MDBX_RESULT_TRUE;
|
||||||
|
}
|
||||||
|
/* coverity[var_deref_model] */
|
||||||
|
memcpy(data.iov_base, txn->wr.repnl, gc_chunk_bytes(MDBX_PNL_GETSIZE(txn->wr.repnl)));
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1301,25 +1339,24 @@ static int gc_fill_returned(MDBX_txn *txn, gcu_t *ctx) {
|
|||||||
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;
|
||||||
|
pgno_t *const from = src, *const to = src + chunk;
|
||||||
|
TRACE("%s: fill +%zu (surplus %zu) [ %zu:%" PRIaPGNO "...%zu:%" PRIaPGNO "] @%" PRIaTXN " (%s)", dbg_prefix(ctx),
|
||||||
|
chunk, chunk_hi - chunk, from - txn->wr.repnl, from[0], to - txn->wr.repnl, to[-1], id, "series");
|
||||||
|
TRACE("%s: left %zu, surplus %zu, slots %zu", dbg_prefix(ctx), amount - (stored + chunk), surplus,
|
||||||
|
rkl_left(&iter, is_lifo(txn)));
|
||||||
tASSERT(txn, chunk > 0 && chunk <= chunk_hi && chunk <= left);
|
tASSERT(txn, chunk > 0 && chunk <= chunk_hi && chunk <= left);
|
||||||
if (unlikely(data.iov_len - (chunk + 1) * sizeof(pgno_t) >= txn->env->ps)) {
|
if (unlikely(data.iov_len - gc_chunk_bytes(chunk) >= txn->env->ps)) {
|
||||||
NOTICE("too long comeback-reserve @%" PRIaTXN ", have %zu bytes, need %zu bytes", id, data.iov_len,
|
NOTICE("too long %s-comeback-reserve @%" PRIaTXN ", have %zu bytes, need %zu bytes", "multi", id, data.iov_len,
|
||||||
(chunk + 1) * sizeof(pgno_t));
|
gc_chunk_bytes(chunk));
|
||||||
return MDBX_RESULT_TRUE;
|
return MDBX_RESULT_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pgno_t *const dst = data.iov_base;
|
|
||||||
pgno_t *const src = MDBX_PNL_BEGIN(txn->wr.repnl) + left - chunk;
|
|
||||||
/* coverity[var_deref_op] */
|
/* coverity[var_deref_op] */
|
||||||
*dst = (pgno_t)chunk;
|
*dst = (pgno_t)chunk;
|
||||||
memcpy(dst + 1, src, chunk * sizeof(pgno_t));
|
memcpy(dst + 1, src, chunk * sizeof(pgno_t));
|
||||||
stored += chunk;
|
stored += chunk;
|
||||||
|
|
||||||
pgno_t *const from = src, *const to = src + chunk;
|
|
||||||
TRACE("%s: fill +%zu (surplus %zu) [ %zu:%" PRIaPGNO "...%zu:%" PRIaPGNO "] @%" PRIaTXN " (%s)", dbg_prefix(ctx),
|
|
||||||
chunk, chunk_hi - chunk, from - txn->wr.repnl, from[0], to - txn->wr.repnl, to[-1], id, "series");
|
|
||||||
TRACE("%s: left %zu, surplus %zu, slots %zu", dbg_prefix(ctx), amount - stored, surplus,
|
|
||||||
rkl_left(&iter, is_lifo(txn)));
|
|
||||||
} while (stored < amount);
|
} while (stored < amount);
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
6
src/gc.h
6
src/gc.h
@ -65,7 +65,11 @@ MDBX_NOTHROW_PURE_FUNCTION static inline size_t gc_stockpile(const MDBX_txn *txn
|
|||||||
return MDBX_PNL_GETSIZE(txn->wr.repnl) + txn->wr.loose_count;
|
return MDBX_PNL_GETSIZE(txn->wr.repnl) + txn->wr.loose_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
MDBX_INTERNAL bool gc_repnl_has_span(MDBX_txn *txn, const size_t num);
|
MDBX_NOTHROW_PURE_FUNCTION static inline size_t gc_chunk_bytes(const size_t chunk) {
|
||||||
|
return (chunk + 1) * sizeof(pgno_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDBX_INTERNAL bool gc_repnl_has_span(const MDBX_txn *txn, const size_t num);
|
||||||
|
|
||||||
static inline bool gc_is_reclaimed(const MDBX_txn *txn, const txnid_t id) {
|
static inline bool gc_is_reclaimed(const MDBX_txn *txn, const txnid_t id) {
|
||||||
return rkl_contain(&txn->wr.gc.reclaimed, id) || rkl_contain(&txn->wr.gc.comeback, id);
|
return rkl_contain(&txn->wr.gc.reclaimed, id) || rkl_contain(&txn->wr.gc.comeback, id);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user