mdbx: доработка/оптимизация page_retire_ex().

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2022-11-28 01:20:36 +03:00
parent 7685b4080e
commit 05804e2f30

View File

@ -3238,9 +3238,9 @@ static int __must_check_result page_check(MDBX_cursor *const mc,
static int __must_check_result cursor_check(MDBX_cursor *mc); static int __must_check_result cursor_check(MDBX_cursor *mc);
static int __must_check_result cursor_check_updating(MDBX_cursor *mc); static int __must_check_result cursor_check_updating(MDBX_cursor *mc);
static int __must_check_result cursor_del(MDBX_cursor *mc); static int __must_check_result cursor_del(MDBX_cursor *mc);
static int __must_check_result delete (MDBX_txn *txn, MDBX_dbi dbi, static int __must_check_result delete(MDBX_txn *txn, MDBX_dbi dbi,
const MDBX_val *key, const MDBX_val *key, const MDBX_val *data,
const MDBX_val *data, unsigned flags); unsigned flags);
#define SIBLING_LEFT 0 #define SIBLING_LEFT 0
#define SIBLING_RIGHT 2 #define SIBLING_RIGHT 2
static int __must_check_result cursor_sibling(MDBX_cursor *mc, int dir); static int __must_check_result cursor_sibling(MDBX_cursor *mc, int dir);
@ -4140,8 +4140,14 @@ static int page_retire_ex(MDBX_cursor *mc, const pgno_t pgno,
* So for flexibility and avoid extra internal dependencies we just * So for flexibility and avoid extra internal dependencies we just
* fallback to reading if dirty list was not allocated yet. */ * fallback to reading if dirty list was not allocated yet. */
size_t di = 0, si = 0, npages = 1; size_t di = 0, si = 0, npages = 1;
bool is_frozen = false, is_spilled = false, is_shadowed = false, enum page_status {
is_modifable = false; unknown,
frozen,
spilled,
shadowed,
modifable
} status = unknown;
if (unlikely(!mp)) { if (unlikely(!mp)) {
if (ASSERT_ENABLED() && pageflags) { if (ASSERT_ENABLED() && pageflags) {
pgr_t check; pgr_t check;
@ -4153,7 +4159,7 @@ static int page_retire_ex(MDBX_cursor *mc, const pgno_t pgno,
tASSERT(txn, !(pageflags & P_FROZEN) || IS_FROZEN(txn, check.page)); tASSERT(txn, !(pageflags & P_FROZEN) || IS_FROZEN(txn, check.page));
} }
if (pageflags & P_FROZEN) { if (pageflags & P_FROZEN) {
is_frozen = true; status = frozen;
if (ASSERT_ENABLED()) { if (ASSERT_ENABLED()) {
for (MDBX_txn *scan = txn; scan; scan = scan->mt_parent) { for (MDBX_txn *scan = txn; scan; scan = scan->mt_parent) {
tASSERT(txn, !txn->tw.spilled.list || !search_spilled(scan, pgno)); tASSERT(txn, !txn->tw.spilled.list || !search_spilled(scan, pgno));
@ -4165,25 +4171,25 @@ static int page_retire_ex(MDBX_cursor *mc, const pgno_t pgno,
if ((di = dpl_exist(txn, pgno)) != 0) { if ((di = dpl_exist(txn, pgno)) != 0) {
mp = txn->tw.dirtylist->items[di].ptr; mp = txn->tw.dirtylist->items[di].ptr;
tASSERT(txn, IS_MODIFIABLE(txn, mp)); tASSERT(txn, IS_MODIFIABLE(txn, mp));
is_modifable = true; status = modifable;
goto status_done; goto status_done;
} }
if ((si = search_spilled(txn, pgno)) != 0) { if ((si = search_spilled(txn, pgno)) != 0) {
is_spilled = true; status = spilled;
goto status_done; goto status_done;
} }
for (MDBX_txn *parent = txn->mt_parent; parent; for (MDBX_txn *parent = txn->mt_parent; parent;
parent = parent->mt_parent) { parent = parent->mt_parent) {
if (dpl_exist(parent, pgno)) { if (dpl_exist(parent, pgno)) {
is_shadowed = true; status = shadowed;
goto status_done; goto status_done;
} }
if (search_spilled(parent, pgno)) { if (search_spilled(parent, pgno)) {
is_spilled = true; status = spilled;
goto status_done; goto status_done;
} }
} }
is_frozen = true; status = frozen;
goto status_done; goto status_done;
} }
@ -4195,27 +4201,27 @@ static int page_retire_ex(MDBX_cursor *mc, const pgno_t pgno,
pageflags = mp->mp_flags; pageflags = mp->mp_flags;
} }
is_frozen = IS_FROZEN(txn, mp); if (IS_FROZEN(txn, mp)) {
if (!is_frozen) { status = frozen;
is_modifable = IS_MODIFIABLE(txn, mp);
is_shadowed = IS_SHADOWED(txn, mp);
is_spilled = IS_SPILLED(txn, mp) && !(txn->mt_flags & MDBX_WRITEMAP);
if (is_modifable) {
tASSERT(txn, !is_spilled);
tASSERT(txn, !txn->tw.spilled.list || !search_spilled(txn, pgno));
tASSERT(txn, debug_dpl_find(txn, pgno) == mp || txn->mt_parent ||
(txn->mt_flags & MDBX_WRITEMAP));
} else {
tASSERT(txn, !debug_dpl_find(txn, pgno));
}
di = (is_modifable && txn->tw.dirtylist) ? dpl_exist(txn, pgno) : 0;
si = is_spilled ? search_spilled(txn, pgno) : 0;
tASSERT(txn, !is_modifable || di || (txn->mt_flags & MDBX_WRITEMAP));
} else {
tASSERT(txn, !IS_MODIFIABLE(txn, mp)); tASSERT(txn, !IS_MODIFIABLE(txn, mp));
tASSERT(txn, !IS_SPILLED(txn, mp)); tASSERT(txn, !IS_SPILLED(txn, mp));
tASSERT(txn, !IS_SHADOWED(txn, mp)); tASSERT(txn, !IS_SHADOWED(txn, mp));
tASSERT(txn, !debug_dpl_find(txn, pgno));
tASSERT(txn, !txn->tw.spilled.list || !search_spilled(txn, pgno));
} else if (IS_MODIFIABLE(txn, mp)) {
status = modifable;
di = txn->tw.dirtylist ? dpl_exist(txn, pgno) : 0;
tASSERT(txn, (txn->mt_flags & MDBX_WRITEMAP) || !IS_SPILLED(txn, mp));
tASSERT(txn, !txn->tw.spilled.list || !search_spilled(txn, pgno));
} else if (IS_SHADOWED(txn, mp)) {
status = shadowed;
tASSERT(txn, !txn->tw.spilled.list || !search_spilled(txn, pgno));
tASSERT(txn, !debug_dpl_find(txn, pgno));
} else {
tASSERT(txn, IS_SPILLED(txn, mp));
status = spilled;
si = search_spilled(txn, pgno);
tASSERT(txn, !debug_dpl_find(txn, pgno));
} }
status_done: status_done:
@ -4239,7 +4245,7 @@ status_done:
mc->mc_db->md_overflow_pages -= (pgno_t)npages; mc->mc_db->md_overflow_pages -= (pgno_t)npages;
} }
if (is_frozen) { if (status == frozen) {
retire: retire:
DEBUG("retire %zu page %" PRIaPGNO, npages, pgno); DEBUG("retire %zu page %" PRIaPGNO, npages, pgno);
rc = pnl_append_range(false, &txn->tw.retired_pages, pgno, npages); rc = pnl_append_range(false, &txn->tw.retired_pages, pgno, npages);
@ -4252,7 +4258,7 @@ status_done:
* нераспределенного "хвоста" БД сдвигается только при их коммите. */ * нераспределенного "хвоста" БД сдвигается только при их коммите. */
if (MDBX_ENABLE_REFUND && unlikely(pgno + npages == txn->mt_next_pgno)) { if (MDBX_ENABLE_REFUND && unlikely(pgno + npages == txn->mt_next_pgno)) {
const char *kind = nullptr; const char *kind = nullptr;
if (is_modifable) { if (status == modifable) {
/* Страница испачкана в этой транзакции, но до этого могла быть /* Страница испачкана в этой транзакции, но до этого могла быть
* аллоцирована, испачкана и пролита в одной из родительских транзакций. * аллоцирована, испачкана и пролита в одной из родительских транзакций.
* Её МОЖНО вытолкнуть в нераспределенный хвост. */ * Её МОЖНО вытолкнуть в нераспределенный хвост. */
@ -4264,6 +4270,7 @@ status_done:
* и запачкана в этой или одной из родительских транзакций. * и запачкана в этой или одной из родительских транзакций.
* Её МОЖНО вытолкнуть в нераспределенный хвост. */ * Её МОЖНО вытолкнуть в нераспределенный хвост. */
kind = "spilled"; kind = "spilled";
tASSERT(txn, status == spilled);
spill_remove(txn, si, npages); spill_remove(txn, si, npages);
} else { } else {
/* Страница аллоцирована, запачкана и возможно пролита в одной /* Страница аллоцирована, запачкана и возможно пролита в одной
@ -4276,18 +4283,18 @@ status_done:
parent = parent->mt_parent) { parent = parent->mt_parent) {
if (search_spilled(parent, pgno)) { if (search_spilled(parent, pgno)) {
kind = "parent-spilled"; kind = "parent-spilled";
tASSERT(txn, is_spilled); tASSERT(txn, status == spilled);
break; break;
} }
if (mp == debug_dpl_find(parent, pgno)) { if (mp == debug_dpl_find(parent, pgno)) {
kind = "parent-dirty"; kind = "parent-dirty";
tASSERT(txn, !is_spilled); tASSERT(txn, status == shadowed);
break; break;
} }
} }
tASSERT(txn, kind != nullptr); tASSERT(txn, kind != nullptr);
} }
tASSERT(txn, is_spilled || is_shadowed || (mp && IS_SHADOWED(txn, mp))); tASSERT(txn, status == spilled || status == shadowed);
} }
DEBUG("refunded %zu %s page %" PRIaPGNO, npages, kind, pgno); DEBUG("refunded %zu %s page %" PRIaPGNO, npages, kind, pgno);
txn->mt_next_pgno = pgno; txn->mt_next_pgno = pgno;
@ -4295,7 +4302,7 @@ status_done:
return MDBX_SUCCESS; return MDBX_SUCCESS;
} }
if (is_modifable) { if (status == modifable) {
if (di) { if (di) {
/* Dirty page from this transaction */ /* Dirty page from this transaction */
/* If suitable we can reuse it through loose list */ /* If suitable we can reuse it through loose list */
@ -4392,7 +4399,7 @@ status_done:
goto reclaim; goto reclaim;
} }
if (is_shadowed) { if (status == shadowed) {
/* Dirty page MUST BE a clone from (one of) parent transaction(s). */ /* Dirty page MUST BE a clone from (one of) parent transaction(s). */
if (ASSERT_ENABLED()) { if (ASSERT_ENABLED()) {
const MDBX_page *parent_dp = nullptr; const MDBX_page *parent_dp = nullptr;
@ -19569,8 +19576,8 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
return delete (txn, dbi, key, data, 0); return delete (txn, dbi, key, data, 0);
} }
static int delete (MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, static int delete(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
const MDBX_val *data, unsigned flags) { const MDBX_val *data, unsigned flags) {
MDBX_cursor_couple cx; MDBX_cursor_couple cx;
MDBX_cursor_op op; MDBX_cursor_op op;
MDBX_val rdata; MDBX_val rdata;