diff --git a/src/core.c b/src/core.c index 25ceb060..744a7328 100644 --- a/src/core.c +++ b/src/core.c @@ -696,6 +696,8 @@ __cold static const char *pagetype_caption(const uint8_t type, return "dupfixed-leaf"; case P_LEAF | P_LEAF2 | P_SUBP: return "dupfixed-subleaf"; + case P_LEAF | P_LEAF2 | P_SUBP | P_LEGACY_DIRTY: + return "dupfixed-subleaf.legacy-dirty"; case P_OVERFLOW: return "large"; default: @@ -713,7 +715,7 @@ __cold static int MDBX_PRINTF_ARGS(2, 3) prev = mp; mdbx_debug_log(MDBX_LOG_ERROR, "badpage", 0, "corrupted %s-page #%u, mod-txnid %" PRIaTXN "\n", - pagetype_caption(PAGETYPE_EXTRA(mp), buf4unknown), + pagetype_caption(PAGETYPE_WHOLE(mp), buf4unknown), mp->mp_pgno, mp->mp_txnid); } @@ -728,7 +730,7 @@ __cold static int MDBX_PRINTF_ARGS(2, 3) /* Address of node i in page p */ MDBX_NOTHROW_PURE_FUNCTION static __always_inline MDBX_node * page_node(const MDBX_page *mp, unsigned i) { - assert(PAGETYPE(mp) == P_LEAF || PAGETYPE(mp) == P_BRANCH); + assert(PAGETYPE_COMPAT(mp) == P_LEAF || PAGETYPE_WHOLE(mp) == P_BRANCH); assert(page_numkeys(mp) > (unsigned)(i)); assert(mp->mp_ptrs[i] % 2 == 0); return (MDBX_node *)((char *)mp + mp->mp_ptrs[i] + PAGEHDRSZ); @@ -739,7 +741,7 @@ page_node(const MDBX_page *mp, unsigned i) { * There are no node headers, keys are stored contiguously. */ MDBX_NOTHROW_PURE_FUNCTION static __always_inline void * page_leaf2key(const MDBX_page *mp, unsigned i, size_t keysize) { - assert(PAGETYPE(mp) == (P_LEAF | P_LEAF2)); + assert(PAGETYPE_COMPAT(mp) == (P_LEAF | P_LEAF2)); assert(mp->mp_leaf2_ksize == keysize); (void)keysize; return (char *)mp + PAGEHDRSZ + (i * mp->mp_leaf2_ksize); @@ -4273,7 +4275,7 @@ MDBX_MAYBE_UNUSED static void mdbx_page_list(MDBX_page *mp) { MDBX_val key; DKBUF; - switch (PAGETYPE_EXTRA(mp)) { + switch (PAGETYPE_WHOLE(mp)) { case P_BRANCH: type = "Branch page"; break; @@ -4821,10 +4823,10 @@ static __inline void mdbx_page_wash(MDBX_txn *txn, const unsigned di, * to this txn's free list. */ static int mdbx_page_retire_ex(MDBX_cursor *mc, const pgno_t pgno, MDBX_page *mp /* maybe null */, - int pagetype /* maybe unknown/zero */) { + unsigned pageflags /* maybe unknown/zero */) { int rc; MDBX_txn *const txn = mc->mc_txn; - mdbx_tassert(txn, !mp || (mp->mp_pgno == pgno && PAGETYPE(mp) == pagetype)); + mdbx_tassert(txn, !mp || (mp->mp_pgno == pgno && mp->mp_flags == pageflags)); /* During deleting entire subtrees, it is reasonable and possible to avoid * reading leaf pages, i.e. significantly reduce hard page-faults & IOPs: @@ -4840,16 +4842,16 @@ static int mdbx_page_retire_ex(MDBX_cursor *mc, const pgno_t pgno, unsigned di = 0, si = 0, npages = 1; bool is_frozen = false, is_spilled = false, is_shadowed = false; if (unlikely(!mp)) { - if (mdbx_assert_enabled() && pagetype) { + if (mdbx_assert_enabled() && pageflags) { pgr_t check; check = page_get_any(mc, pgno, txn->mt_front); if (unlikely(check.err != MDBX_SUCCESS)) return check.err; - mdbx_tassert(txn, - (PAGETYPE(check.page) & ~P_LEAF2) == (pagetype & ~P_FROZEN)); - mdbx_tassert(txn, !(pagetype & P_FROZEN) || IS_FROZEN(txn, check.page)); + mdbx_tassert(txn, (check.page->mp_flags & ~P_LEAF2) == + (pageflags & ~P_FROZEN)); + mdbx_tassert(txn, !(pageflags & P_FROZEN) || IS_FROZEN(txn, check.page)); } - if (pagetype & P_FROZEN) { + if (pageflags & P_FROZEN) { is_frozen = true; if (mdbx_assert_enabled()) { for (MDBX_txn *scan = txn; scan; scan = scan->mt_parent) { @@ -4858,7 +4860,7 @@ static int mdbx_page_retire_ex(MDBX_cursor *mc, const pgno_t pgno, } } goto status_done; - } else if (pagetype && txn->tw.dirtylist) { + } else if (pageflags && txn->tw.dirtylist) { if ((di = mdbx_dpl_exist(txn, pgno)) != 0) { mp = txn->tw.dirtylist->items[di].ptr; mdbx_tassert(txn, IS_MODIFIABLE(txn, mp)); @@ -4887,8 +4889,8 @@ static int mdbx_page_retire_ex(MDBX_cursor *mc, const pgno_t pgno, if (unlikely(pg.err != MDBX_SUCCESS)) return pg.err; mp = pg.page; - mdbx_tassert(txn, !pagetype || PAGETYPE(mp) == pagetype); - pagetype = PAGETYPE(mp); + mdbx_tassert(txn, !pageflags || mp->mp_flags == pageflags); + pageflags = mp->mp_flags; } is_frozen = IS_FROZEN(txn, mp); @@ -4915,9 +4917,9 @@ static int mdbx_page_retire_ex(MDBX_cursor *mc, const pgno_t pgno, } status_done: - if (likely((pagetype & P_OVERFLOW) == 0)) { + if (likely((pageflags & P_OVERFLOW) == 0)) { STATIC_ASSERT(P_BRANCH == 1); - const bool is_branch = pagetype & P_BRANCH; + const bool is_branch = pageflags & P_BRANCH; if (unlikely(mc->mc_flags & C_SUB)) { MDBX_db *outer = mdbx_outer_db(mc); mdbx_cassert(mc, !is_branch || outer->md_branch_pages > 0); @@ -4927,8 +4929,8 @@ status_done: } mdbx_cassert(mc, !is_branch || mc->mc_db->md_branch_pages > 0); mc->mc_db->md_branch_pages -= is_branch; - mdbx_cassert(mc, (pagetype & P_LEAF) == 0 || mc->mc_db->md_leaf_pages > 0); - mc->mc_db->md_leaf_pages -= (pagetype & P_LEAF) != 0; + mdbx_cassert(mc, (pageflags & P_LEAF) == 0 || mc->mc_db->md_leaf_pages > 0); + mc->mc_db->md_leaf_pages -= (pageflags & P_LEAF) != 0; } else { npages = mp->mp_pages; mdbx_cassert(mc, mc->mc_db->md_overflow_pages >= npages); @@ -5113,7 +5115,7 @@ status_done: } static __inline int mdbx_page_retire(MDBX_cursor *mc, MDBX_page *mp) { - return mdbx_page_retire_ex(mc, mp->mp_pgno, mp, PAGETYPE(mp)); + return mdbx_page_retire_ex(mc, mp->mp_pgno, mp, mp->mp_flags); } struct mdbx_iov_ctx { @@ -14325,7 +14327,7 @@ static __noinline int node_read_bigdata(MDBX_cursor *mc, const MDBX_node *node, return lp.err; } - mdbx_cassert(mc, PAGETYPE_EXTRA(lp.page) == P_OVERFLOW); + mdbx_cassert(mc, PAGETYPE_WHOLE(lp.page) == P_OVERFLOW); data->iov_base = page_data(lp.page); if (!MDBX_DISABLE_VALIDATION) { const MDBX_env *env = mc->mc_txn->mt_env; @@ -15870,7 +15872,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, pgr_t lp = page_get_large(mc, pgno, mc->mc_pg[mc->mc_top]->mp_txnid); if (unlikely(lp.err != MDBX_SUCCESS)) return lp.err; - mdbx_cassert(mc, PAGETYPE_EXTRA(lp.page) == P_OVERFLOW); + mdbx_cassert(mc, PAGETYPE_WHOLE(lp.page) == P_OVERFLOW); /* Is the ov page from this txn (or a parent) and big enough? */ int ovpages = lp.page->mp_pages; @@ -16112,7 +16114,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, memcpy(olddata.iov_base, data->iov_base, data->iov_len); else { mdbx_cassert(mc, page_numkeys(mc->mc_pg[mc->mc_top]) == 1); - mdbx_cassert(mc, PAGETYPE(mc->mc_pg[mc->mc_top]) == P_LEAF); + mdbx_cassert(mc, PAGETYPE_COMPAT(mc->mc_pg[mc->mc_top]) == P_LEAF); mdbx_cassert(mc, node_ds(node) == 0); mdbx_cassert(mc, node_flags(node) == 0); mdbx_cassert(mc, key->iov_len < UINT16_MAX); @@ -16469,7 +16471,7 @@ static int __must_check_result mdbx_node_add_leaf2(MDBX_cursor *mc, key ? key->iov_len : 0, DKEY_DEBUG(key)); mdbx_cassert(mc, key); - mdbx_cassert(mc, PAGETYPE(mp) == (P_LEAF | P_LEAF2)); + mdbx_cassert(mc, PAGETYPE_COMPAT(mp) == (P_LEAF | P_LEAF2)); const unsigned ksize = mc->mc_db->md_xsize; mdbx_cassert(mc, ksize == key->iov_len); const unsigned nkeys = page_numkeys(mp); @@ -16506,7 +16508,7 @@ static int __must_check_result mdbx_node_add_branch(MDBX_cursor *mc, IS_SUBP(mp) ? "sub-" : "", mp->mp_pgno, indx, pgno, key ? key->iov_len : 0, DKEY_DEBUG(key)); - mdbx_cassert(mc, PAGETYPE(mp) == P_BRANCH); + mdbx_cassert(mc, PAGETYPE_WHOLE(mp) == P_BRANCH); STATIC_ASSERT(NODESIZE % 2 == 0); /* Move higher pointers up one slot. */ @@ -16551,7 +16553,7 @@ static int __must_check_result mdbx_node_add_leaf(MDBX_cursor *mc, IS_SUBP(mp) ? "sub-" : "", mp->mp_pgno, indx, data ? data->iov_len : 0, key ? key->iov_len : 0, DKEY_DEBUG(key)); mdbx_cassert(mc, key != NULL && data != NULL); - mdbx_cassert(mc, PAGETYPE(mp) == P_LEAF); + mdbx_cassert(mc, PAGETYPE_COMPAT(mp) == P_LEAF); mdbx_cassert(mc, page_room(mp) >= leaf_size(mc->mc_txn->mt_env, key, data)); MDBX_page *largepage = NULL; @@ -17312,19 +17314,19 @@ static int mdbx_node_move(MDBX_cursor *csrc, MDBX_cursor *cdst, bool fromleft) { MDBX_page *psrc = csrc->mc_pg[csrc->mc_top]; MDBX_page *pdst = cdst->mc_pg[cdst->mc_top]; - mdbx_cassert(csrc, PAGETYPE(psrc) == PAGETYPE(pdst)); + mdbx_cassert(csrc, PAGETYPE_WHOLE(psrc) == PAGETYPE_WHOLE(pdst)); mdbx_cassert(csrc, csrc->mc_dbi == cdst->mc_dbi); mdbx_cassert(csrc, csrc->mc_top == cdst->mc_top); - if (unlikely(PAGETYPE(psrc) != PAGETYPE(pdst))) { + if (unlikely(PAGETYPE_WHOLE(psrc) != PAGETYPE_WHOLE(pdst))) { bailout: mdbx_error("Wrong or mismatch pages's types (src %d, dst %d) to move node", - PAGETYPE(psrc), PAGETYPE(pdst)); + PAGETYPE_WHOLE(psrc), PAGETYPE_WHOLE(pdst)); csrc->mc_txn->mt_flags |= MDBX_TXN_ERROR; return MDBX_PROBLEM; } MDBX_val key4move; - switch (PAGETYPE(psrc)) { + switch (PAGETYPE_WHOLE(psrc)) { case P_BRANCH: { const MDBX_node *srcnode = page_node(psrc, csrc->mc_ki[csrc->mc_top]); mdbx_cassert(csrc, node_flags(srcnode) == 0); @@ -17481,7 +17483,7 @@ static int mdbx_node_move(MDBX_cursor *csrc, MDBX_cursor *cdst, bool fromleft) { mdbx_cassert(csrc, psrc == csrc->mc_pg[csrc->mc_top]); mdbx_cassert(cdst, pdst == cdst->mc_pg[cdst->mc_top]); - mdbx_cassert(csrc, PAGETYPE(psrc) == PAGETYPE(pdst)); + mdbx_cassert(csrc, PAGETYPE_WHOLE(psrc) == PAGETYPE_WHOLE(pdst)); { /* Adjust other cursors pointing to mp */ @@ -17626,7 +17628,7 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { mdbx_debug("merging page %" PRIaPGNO " into %" PRIaPGNO, psrc->mp_pgno, pdst->mp_pgno); - mdbx_cassert(csrc, PAGETYPE(psrc) == PAGETYPE(pdst)); + mdbx_cassert(csrc, PAGETYPE_WHOLE(psrc) == PAGETYPE_WHOLE(pdst)); mdbx_cassert(csrc, csrc->mc_dbi == cdst->mc_dbi && csrc->mc_db == cdst->mc_db); mdbx_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */ @@ -17636,7 +17638,7 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { mdbx_cassert(csrc, csrc->mc_snum < csrc->mc_db->md_depth || IS_LEAF(csrc->mc_pg[csrc->mc_db->md_depth - 1])); mdbx_cassert(cdst, page_room(pdst) >= page_used(cdst->mc_txn->mt_env, psrc)); - const int pagetype = PAGETYPE(psrc); + const int pagetype = PAGETYPE_WHOLE(psrc); /* Move all nodes from src to dst */ const unsigned dst_nkeys = page_numkeys(pdst); @@ -17795,14 +17797,15 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { if (IS_LEAF(cdst->mc_pg[cdst->mc_top])) { /* LY: don't touch cursor if top-page is a LEAF */ - mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) || - PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype); + mdbx_cassert(cdst, + IS_LEAF(cdst->mc_pg[cdst->mc_top]) || + PAGETYPE_WHOLE(cdst->mc_pg[cdst->mc_top]) == pagetype); return MDBX_SUCCESS; } mdbx_cassert(cdst, page_numkeys(top_page) == dst_nkeys + src_nkeys); - if (unlikely(pagetype != PAGETYPE(top_page))) { + if (unlikely(pagetype != PAGETYPE_WHOLE(top_page))) { /* LY: LEAF-page becomes BRANCH, unable restore cursor's stack */ goto bailout; } @@ -17810,8 +17813,9 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { if (top_page == cdst->mc_pg[cdst->mc_top]) { /* LY: don't touch cursor if prev top-page already on the top */ mdbx_cassert(cdst, cdst->mc_ki[cdst->mc_top] == top_indx); - mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) || - PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype); + mdbx_cassert(cdst, + IS_LEAF(cdst->mc_pg[cdst->mc_top]) || + PAGETYPE_WHOLE(cdst->mc_pg[cdst->mc_top]) == pagetype); return MDBX_SUCCESS; } @@ -17828,8 +17832,9 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { cdst->mc_top = (uint16_t)new_snum - 1; mdbx_cassert(cdst, cdst->mc_snum < cdst->mc_db->md_depth || IS_LEAF(cdst->mc_pg[cdst->mc_db->md_depth - 1])); - mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) || - PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype); + mdbx_cassert(cdst, + IS_LEAF(cdst->mc_pg[cdst->mc_top]) || + PAGETYPE_WHOLE(cdst->mc_pg[cdst->mc_top]) == pagetype); return MDBX_SUCCESS; } @@ -17849,8 +17854,9 @@ static int mdbx_page_merge(MDBX_cursor *csrc, MDBX_cursor *cdst) { cdst->mc_top = (uint16_t)new_snum - 1; mdbx_cassert(cdst, cdst->mc_snum < cdst->mc_db->md_depth || IS_LEAF(cdst->mc_pg[cdst->mc_db->md_depth - 1])); - mdbx_cassert(cdst, IS_LEAF(cdst->mc_pg[cdst->mc_top]) || - PAGETYPE(cdst->mc_pg[cdst->mc_top]) == pagetype); + mdbx_cassert(cdst, + IS_LEAF(cdst->mc_pg[cdst->mc_top]) || + PAGETYPE_WHOLE(cdst->mc_pg[cdst->mc_top]) == pagetype); return MDBX_SUCCESS; } @@ -17902,7 +17908,7 @@ static int mdbx_rebalance(MDBX_cursor *mc) { mdbx_cassert(mc, mc->mc_snum > 0); mdbx_cassert(mc, mc->mc_snum < mc->mc_db->md_depth || IS_LEAF(mc->mc_pg[mc->mc_db->md_depth - 1])); - const int pagetype = PAGETYPE(mc->mc_pg[mc->mc_top]); + const int pagetype = PAGETYPE_WHOLE(mc->mc_pg[mc->mc_top]); STATIC_ASSERT(P_BRANCH == 1); const unsigned minkeys = (pagetype & P_BRANCH) + 1; @@ -18004,7 +18010,7 @@ static int mdbx_rebalance(MDBX_cursor *mc) { } } mdbx_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]) || - PAGETYPE(mc->mc_pg[mc->mc_top]) == pagetype); + PAGETYPE_WHOLE(mc->mc_pg[mc->mc_top]) == pagetype); mdbx_cassert(mc, mc->mc_snum < mc->mc_db->md_depth || IS_LEAF(mc->mc_pg[mc->mc_db->md_depth - 1])); @@ -18041,7 +18047,8 @@ static int mdbx_rebalance(MDBX_cursor *mc) { &left, mc->mc_pg[mc->mc_top]->mp_txnid); if (unlikely(rc != MDBX_SUCCESS)) return rc; - mdbx_cassert(mc, PAGETYPE(left) == PAGETYPE(mc->mc_pg[mc->mc_top])); + mdbx_cassert(mc, + PAGETYPE_WHOLE(left) == PAGETYPE_WHOLE(mc->mc_pg[mc->mc_top])); } if (mn.mc_ki[pre_top] + 1u < page_numkeys(mn.mc_pg[pre_top])) { rc = page_get( @@ -18049,7 +18056,8 @@ static int mdbx_rebalance(MDBX_cursor *mc) { &right, mc->mc_pg[mc->mc_top]->mp_txnid); if (unlikely(rc != MDBX_SUCCESS)) return rc; - mdbx_cassert(mc, PAGETYPE(right) == PAGETYPE(mc->mc_pg[mc->mc_top])); + mdbx_cassert(mc, PAGETYPE_WHOLE(right) == + PAGETYPE_WHOLE(mc->mc_pg[mc->mc_top])); } mdbx_cassert(mc, left || right); @@ -18172,7 +18180,7 @@ __cold static int mdbx_page_check(MDBX_cursor *const mc, mdbx_cassert(mc, (mc->mc_checking & CC_LEAF2) == 0 || (mc->mc_flags & C_SUB) != 0); - const uint8_t type = PAGETYPE_EXTRA(mp); + const uint8_t type = PAGETYPE_WHOLE(mp); switch (type) { default: return bad_page(mp, "invalid type (%u)\n", type); @@ -18359,7 +18367,7 @@ __cold static int mdbx_page_check(MDBX_cursor *const mc, page_get_large(mc, node_largedata_pgno(node), mp->mp_txnid); if (unlikely(lp.err != MDBX_SUCCESS)) return lp.err; - mdbx_cassert(mc, PAGETYPE_EXTRA(lp.page) == P_OVERFLOW); + mdbx_cassert(mc, PAGETYPE_WHOLE(lp.page) == P_OVERFLOW); const unsigned npages = number_of_ovpages(env, dsize); if (unlikely(lp.page->mp_pages != npages)) { if (lp.page->mp_pages < npages) @@ -18413,7 +18421,8 @@ __cold static int mdbx_page_check(MDBX_cursor *const mc, continue; } else { const MDBX_page *const sp = (MDBX_page *)data; - switch (sp->mp_flags & /* ignore legacy P_DIRTY flag */ ~0x10) { + switch (sp->mp_flags & + /* ignore legacy P_DIRTY flag */ ~P_LEGACY_DIRTY) { case P_LEAF | P_SUBP: case P_LEAF | P_LEAF2 | P_SUBP: break; @@ -19170,7 +19179,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *const newkey, if (unlikely(pure_left | pure_right)) { mc->mc_pg[mc->mc_top] = sister; mc->mc_ki[mc->mc_top] = 0; - switch (PAGETYPE(sister)) { + switch (PAGETYPE_WHOLE(sister)) { case P_LEAF: { mdbx_cassert(mc, newpgno == 0 || newpgno == P_INVALID); rc = mdbx_node_add_leaf(mc, 0, newkey, newdata, nflags); @@ -19181,7 +19190,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *const newkey, rc = mdbx_node_add_leaf2(mc, 0, newkey); } break; default: - rc = bad_page(sister, "wrong page-type %u\n", PAGETYPE(sister)); + rc = bad_page(sister, "wrong page-type %u\n", PAGETYPE_WHOLE(sister)); } if (unlikely(rc != MDBX_SUCCESS)) goto done; @@ -19242,7 +19251,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *const newkey, flags = node_flags(node); } - switch (PAGETYPE(sister)) { + switch (PAGETYPE_WHOLE(sister)) { case P_BRANCH: { mdbx_cassert(mc, 0 == (uint16_t)flags); /* First branch index doesn't need key data. */ @@ -19259,7 +19268,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *const newkey, rc = mdbx_node_add_leaf2(mc, n, &rkey); } break; */ default: - rc = bad_page(sister, "wrong page-type %u\n", PAGETYPE(sister)); + rc = bad_page(sister, "wrong page-type %u\n", PAGETYPE_WHOLE(sister)); } if (unlikely(rc != MDBX_SUCCESS)) goto done; @@ -19561,11 +19570,11 @@ static int compacting_put_page(mdbx_compacting_ctx *ctx, const MDBX_page *mp, if (tail_bytes) { assert(head_bytes + tail_bytes <= ctx->mc_env->me_psize); assert(npages == 1 && - (PAGETYPE_EXTRA(mp) == P_BRANCH || PAGETYPE_EXTRA(mp) == P_LEAF)); + (PAGETYPE_WHOLE(mp) == P_BRANCH || PAGETYPE_WHOLE(mp) == P_LEAF)); } else { assert(head_bytes <= pgno2bytes(ctx->mc_env, npages)); - assert((npages == 1 && PAGETYPE_EXTRA(mp) == (P_LEAF | P_LEAF2)) || - PAGETYPE_EXTRA(mp) == P_OVERFLOW); + assert((npages == 1 && PAGETYPE_WHOLE(mp) == (P_LEAF | P_LEAF2)) || + PAGETYPE_WHOLE(mp) == P_OVERFLOW); } const pgno_t pgno = ctx->mc_next_pgno; @@ -21068,7 +21077,7 @@ static int mdbx_drop_tree(MDBX_cursor *mc, const bool may_have_subDBs) { for (unsigned i = 0; i < nkeys; i++) { MDBX_node *node = page_node(mp, i); if (node_flags(node) & F_BIGDATA) { - rc = mdbx_page_retire_ex(mc, node_largedata_pgno(node), NULL, 0); + rc = mdbx_page_retire_ex(mc, node_largedata_pgno(node), nullptr, 0); if (unlikely(rc != MDBX_SUCCESS)) goto bailout; if (!(may_have_subDBs | mc->mc_db->md_overflow_pages)) @@ -21089,7 +21098,7 @@ static int mdbx_drop_tree(MDBX_cursor *mc, const bool may_have_subDBs) { } else { mdbx_cassert(mc, mc->mc_snum < mc->mc_db->md_depth); mc->mc_checking |= CC_RETIRING; - const int pagetype = + const unsigned pagetype = (IS_FROZEN(txn, mp) ? P_FROZEN : 0) + ((mc->mc_snum + 1 == mc->mc_db->md_depth) ? P_LEAF : P_BRANCH); for (unsigned i = 0; i < nkeys; i++) { @@ -21097,7 +21106,7 @@ static int mdbx_drop_tree(MDBX_cursor *mc, const bool may_have_subDBs) { mdbx_tassert(txn, (node_flags(node) & (F_BIGDATA | F_SUBDATA | F_DUPDATA)) == 0); const pgno_t pgno = node_pgno(node); - rc = mdbx_page_retire_ex(mc, pgno, NULL, pagetype); + rc = mdbx_page_retire_ex(mc, pgno, nullptr, pagetype); if (unlikely(rc != MDBX_SUCCESS)) goto bailout; } @@ -21694,7 +21703,7 @@ __cold static int mdbx_walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno, pgr_t lp = page_get_large(ctx->mw_cursor, large_pgno, mp->mp_txnid); err = lp.err; if (err == MDBX_SUCCESS) { - mdbx_cassert(ctx->mw_cursor, PAGETYPE_EXTRA(lp.page) == P_OVERFLOW); + mdbx_cassert(ctx->mw_cursor, PAGETYPE_WHOLE(lp.page) == P_OVERFLOW); npages = lp.page->mp_pages; } @@ -21740,7 +21749,7 @@ __cold static int mdbx_walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno, size_t subalign_bytes = 0; MDBX_page_type_t subtype; - switch (sp->mp_flags & /* ignore legacy P_DIRTY flag */ ~0x10) { + switch (sp->mp_flags & /* ignore legacy P_DIRTY flag */ ~P_LEGACY_DIRTY) { case P_LEAF | P_SUBP: subtype = MDBX_subpage_leaf; break; diff --git a/src/internals.h b/src/internals.h index 185a5fac..25ba9dce 100644 --- a/src/internals.h +++ b/src/internals.h @@ -515,19 +515,18 @@ typedef struct MDBX_page { mp_txnid; /* txnid which created this page, maybe zero in legacy DB */ struct MDBX_page *mp_next; /* for in-memory list of freed pages */ }; - uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */ -#define P_BRANCH 0x01 /* branch page */ -#define P_LEAF 0x02 /* leaf page */ -#define P_OVERFLOW 0x04 /* overflow page */ -#define P_META 0x08 /* meta page */ -#define P_BAD 0x10 /* explicit flag for invalid/bad page */ -#define P_LEAF2 0x20 /* for MDBX_DUPFIXED records */ -#define P_SUBP 0x40 /* for MDBX_DUPSORT sub-pages */ -#define PAGETYPE_EXTRA(p) ((char)(p)->mp_flags) -#define PAGETYPE(p) (PAGETYPE_EXTRA(p) & ~P_SUBP) -#define P_SPILLED 0x2000 /* spilled in parent txn */ -#define P_LOOSE 0x4000 /* page was dirtied then freed, can be reused */ -#define P_FROZEN 0x8000 /* used for retire page with known status */ + uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */ +#define P_BRANCH 0x01 /* branch page */ +#define P_LEAF 0x02 /* leaf page */ +#define P_OVERFLOW 0x04 /* overflow page */ +#define P_META 0x08 /* meta page */ +#define P_LEGACY_DIRTY 0x10 /* legacy P_DIRTY flag prior to v0.10 958fd5b9 */ +#define P_BAD P_LEGACY_DIRTY /* explicit flag for invalid/bad page */ +#define P_LEAF2 0x20 /* for MDBX_DUPFIXED records */ +#define P_SUBP 0x40 /* for MDBX_DUPSORT sub-pages */ +#define P_SPILLED 0x2000 /* spilled in parent txn */ +#define P_LOOSE 0x4000 /* page was dirtied then freed, can be reused */ +#define P_FROZEN 0x8000 /* used for retire page with known status */ #define P_ILL_BITS \ ((uint16_t) ~(P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_SPILLED)) uint16_t mp_flags; @@ -546,6 +545,14 @@ typedef struct MDBX_page { #endif /* C99 */ } MDBX_page; +#define PAGETYPE_WHOLE(p) ((char)(p)->mp_flags) + +/* Drop legacy P_DIRTY flag for sub-pages for compatilibity */ +#define PAGETYPE_COMPAT(p) \ + (unlikely(PAGETYPE_WHOLE(p) & P_SUBP) \ + ? PAGETYPE_WHOLE(p) & ~(P_SUBP | P_LEGACY_DIRTY) \ + : PAGETYPE_WHOLE(p)) + /* Size of the page header, excluding dynamic data at the end */ #define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs)) @@ -1064,7 +1071,7 @@ struct MDBX_cursor { }; #define CHECK_LEAF_TYPE(mc, mp) \ - (((PAGETYPE_EXTRA(mp) ^ (mc)->mc_checking) & \ + (((PAGETYPE_WHOLE(mp) ^ (mc)->mc_checking) & \ (CC_BRANCH | CC_LEAF | CC_OVERFLOW | CC_LEAF2)) == 0) /* Context for sorted-dup records.