From 28bdd0bf99a91bd67332dfdca173e6972598013b Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Fri, 17 Jan 2025 20:29:41 +0300 Subject: [PATCH] Reworked index root page related code, added some debugging --- src/jrd/Relation.cpp | 26 +++++++++ src/jrd/Relation.h | 4 +- src/jrd/btr.cpp | 135 ++++++++++++++++++++++++++++++++----------- src/jrd/btr_proto.h | 8 ++- src/jrd/idx.cpp | 38 ++++-------- 5 files changed, 145 insertions(+), 66 deletions(-) diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index 14bd1cae23..c648e890d0 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -531,6 +531,32 @@ Cached::Index* RelationPermanent::lookupIndex(thread_db* tdbb, MetaId id, Object } +PageNumber RelationPermanent::getIndexRootPage(thread_db* tdbb) +{ +/************************************** + * + * g e t _ r o o t _ p a g e + * + ************************************** + * + * Functional description + * Find the root page for a relation. + * + **************************************/ + SET_TDBB(tdbb); + + RelationPages* relPages = getPages(tdbb); + SLONG page = relPages->rel_index_root; + if (!page) + { + DPM_scan_pages(tdbb); + page = relPages->rel_index_root; + } + + return PageNumber(relPages->rel_pg_space_id, page); +} + + const char* IndexPermanent::c_name() const { // Here we use MetaName feature - pointers in it are DBB-lifetime stable diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 7fab2b81fb..4ab889e862 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -872,8 +872,8 @@ public: rel_file = f; } - - void getRelLockKey(thread_db* tdbb, UCHAR* key); + void getRelLockKey(thread_db* tdbb, UCHAR* key); + PageNumber getIndexRootPage(thread_db* tdbb); bool isSystem() const; bool isTemporary() const; diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 887ead371c..912727de7e 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -219,7 +219,7 @@ static void delete_tree(thread_db*, MetaId, MetaId, PageNumber, PageNumber); static DSC* eval(thread_db*, const ValueExprNode*, DSC*, bool*); static ULONG fast_load(thread_db*, IndexCreation&, SelectivityList&); -static index_root_page* fetch_root(thread_db*, WIN*, const RelationPermanent*, const RelationPages*); +static const index_root_page* fetch_root(thread_db*, WIN*, const RelationPermanent*, const RelationPages*); static UCHAR* find_node_start_point(btree_page*, temporary_key*, UCHAR*, USHORT*, bool, bool, bool = false, RecordNumber = NO_VALUE); @@ -250,6 +250,74 @@ static void update_selectivity(index_root_page*, MetaId, const SelectivityList&) static void checkForLowerKeySkip(bool&, const bool, const IndexNode&, const temporary_key&, const index_desc&, const IndexRetrieval*); +//#define DEBUG_INDEX_ROOT + +namespace { +#ifdef DEBUG_INDEX_ROOT + +class Flags +{ +public: + static const char* state(const index_root_page::irt_repeat& rpt) + { + if (!rpt.isUsed()) + return "Unused"; + switch (rpt.getState()) + { + case irt_in_progress: return "irt_in_progress"; + case irt_commit: return "irt_commit"; + case irt_drop: return "irt_drop"; + case irt_rollback: return "irt_rollback"; + case irt_normal: return "irt_normal"; + } + + return "** UNKNOWN **"; + } +}; + +void dumpIndexRoot(const char* up, const char* from, thread_db* tdbb, WIN* window, const index_root_page* root) +{ + if (root->irt_relation > 127) + { + auto* rel = MetadataCache::lookupRelation(tdbb, root->irt_relation, 0); + printf("\n%sFrom %s page=%" ULONGFORMAT " len=%d rel %s(%d)\n", + up, from, window->win_page.getPageNum(), root->irt_count, rel->c_name(), root->irt_relation); + for (MetaId i = 0; i < root->irt_count; ++i) + { + auto* idp = rel->lookupIndex(tdbb, i, 0); + auto& rpt = root->irt_rpt[i]; + printf("Index %d %s root %d tra % " SQUADFORMAT " %s\n", i, idp ? idp->getName().c_str() : "not-found", + rpt.getRoot(), rpt.getTransaction(), Flags::state(rpt)); + } + printf("\n"); + } +} + +#else + +void dumpIndexRoot(...) { } + +#endif +} + +index_root_page* BTR_fetch_root_for_update(const char* from, thread_db* tdbb, WIN* window) +{ + index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, window, LCK_write, pag_root); + + dumpIndexRoot("Upd", from, tdbb, window, root); + + return root; +} + +const index_root_page* BTR_fetch_root(const char* from, thread_db* tdbb, WIN* window) +{ + const index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, window, LCK_read, pag_root); + + dumpIndexRoot("", from, tdbb, window, root); + + return root; +} + // IndexRetrieval class @@ -409,7 +477,7 @@ void BTR_all(thread_db* tdbb, Cached::Relation* relation, IndexDescList& idxList WIN window(relPages->rel_pg_space_id, -1); - index_root_page* const root = fetch_root(tdbb, &window, relation, relPages); + const index_root_page* const root = fetch_root(tdbb, &window, relation, relPages); if (!root) return; @@ -505,9 +573,8 @@ void BTR_create(thread_db* tdbb, // Index is created. Go back to the index root page and update it to // point to the index. - RelationPages* const relPages = relation->getPages(tdbb); - WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); - index_root_page* const root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); + WIN window(getPermanent(relation)->getIndexRootPage(tdbb)); + index_root_page* const root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); CCH_MARK(tdbb, &window); switch(creation.forRollback) @@ -592,7 +659,7 @@ static void badState [[noreturn]] (const index_root_page::irt_repeat* irt_desc, } -void BTR_mark_index_for_delete(thread_db* tdbb, WIN* window, MetaId id) +void BTR_mark_index_for_delete(thread_db* tdbb, Cached::Relation* relation, MetaId id) { /************************************** * @@ -608,15 +675,15 @@ void BTR_mark_index_for_delete(thread_db* tdbb, WIN* window, MetaId id) const Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - // Get index descriptor. If index doesn't exist, just leave. - index_root_page* const root = (index_root_page*) window->win_buffer; + WIN window(relation->getIndexRootPage(tdbb)); + index_root_page* const root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); + // Get index descriptor. If index doesn't exist, just leave. if (id < root->irt_count) { index_root_page::irt_repeat* irt_desc = root->irt_rpt + id; - CCH_MARK(tdbb, window); - const PageNumber next(window->win_page.getPageSpaceID(), irt_desc->getRoot()); + CCH_MARK(tdbb, &window); jrd_tra* tra = tdbb->getTransaction(); fb_assert(tra); @@ -660,11 +727,11 @@ void BTR_mark_index_for_delete(thread_db* tdbb, WIN* window, MetaId id) } } - CCH_RELEASE(tdbb, window); + CCH_RELEASE(tdbb, &window); } -void BTR_activate_index(thread_db* tdbb, WIN* window, MetaId id) +void BTR_activate_index(thread_db* tdbb, Cached::Relation* relation, MetaId id) { /************************************** * @@ -680,15 +747,15 @@ void BTR_activate_index(thread_db* tdbb, WIN* window, MetaId id) const Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - // Get index descriptor. If index doesn't exist, just leave. - index_root_page* const root = (index_root_page*) window->win_buffer; + WIN window(relation->getIndexRootPage(tdbb)); + index_root_page* const root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); + // Get index descriptor. If index doesn't exist, just leave. if (id < root->irt_count) { index_root_page::irt_repeat* irt_desc = root->irt_rpt + id; - CCH_MARK(tdbb, window); - const PageNumber next(window->win_page.getPageSpaceID(), irt_desc->getRoot()); + CCH_MARK(tdbb, &window); jrd_tra* tra = tdbb->getTransaction(); fb_assert(tra); @@ -733,11 +800,11 @@ void BTR_activate_index(thread_db* tdbb, WIN* window, MetaId id) } } - CCH_RELEASE(tdbb, window); + CCH_RELEASE(tdbb, &window); } -bool BTR_description(thread_db* tdbb, Cached::Relation* relation, index_root_page* root, index_desc* idx, +bool BTR_description(thread_db* tdbb, Cached::Relation* relation, const index_root_page* root, index_desc* idx, MetaId id) { /************************************** @@ -1263,7 +1330,7 @@ btree_page* BTR_find_page(thread_db* tdbb, fb_assert(window->win_page.getPageSpaceID() == relPages->rel_pg_space_id); window->win_page = relPages->rel_index_root; - index_root_page* rpage = (index_root_page*) CCH_FETCH(tdbb, window, LCK_read, pag_root); + const index_root_page* rpage = BTR_fetch_root(FB_FUNCTION, tdbb, window); if (!BTR_description(tdbb, retrieval->getPermRelation(), rpage, idx, retrieval->irb_index)) { @@ -1373,7 +1440,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) // The top of the index has split. We need to make a new level and // update the index root page. Oh boy. - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, root_window, LCK_write, pag_root); + index_root_page* root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, root_window); window.win_page = root->irt_rpt[idx->idx_id].getRoot(); bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); @@ -1849,7 +1916,7 @@ bool BTR_lookup(thread_db* tdbb, Cached::Relation* relation, MetaId id, index_de SET_TDBB(tdbb); WIN window(relPages->rel_pg_space_id, -1); - index_root_page* const root = fetch_root(tdbb, &window, relation, relPages); + const index_root_page* const root = fetch_root(tdbb, &window, relation, relPages); if (!root) return false; @@ -2142,9 +2209,9 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa else id = idx->idx_id + 1; - index_root_page* root; + const index_root_page* root; if (window->win_bdb) - root = (index_root_page*) window->win_buffer; + root = (const index_root_page*) window->win_buffer; else { RelationPages* const relPages = transaction ? @@ -2205,8 +2272,8 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa if (rls) CCH_RELEASE(tdbb, window); - root = (index_root_page*) CCH_FETCH(tdbb, window, LCK_write, pag_root); - index_root_page::irt_repeat* irt_write = root->irt_rpt + id; + auto* root_write = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, window); + index_root_page::irt_repeat* irt_write = root_write->irt_rpt + id; const TraNumber descTrans = irt_write->getTransaction(); bool delIndex = false; @@ -2261,7 +2328,7 @@ bool BTR_next_index(thread_db* tdbb, Cached::Relation* relation, jrd_tra* transa else CCH_RELEASE(tdbb, window); - root = (index_root_page*) CCH_FETCH(tdbb, window, LCK_read, pag_root); + root = BTR_fetch_root(FB_FUNCTION, tdbb, window); if (delIndex) continue; @@ -2323,7 +2390,7 @@ void BTR_remove(thread_db* tdbb, WIN* root_window, index_insertion* insertion) CCH_RELEASE(tdbb, &window); CCH_RELEASE(tdbb, root_window); - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, root_window, LCK_write, pag_root); + index_root_page* root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, root_window); page = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); // get the page number of the child, and check to make sure @@ -2400,7 +2467,7 @@ void BTR_reserve_slot(thread_db* tdbb, IndexCreation& creation, IndexCreateLock& fb_assert((!use_idx_id) || (idx->idx_id <= dbb->dbb_max_idx)); WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); + index_root_page* root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); CCH_MARK(tdbb, &window); // check that we create no more indexes than will fit on a single root page @@ -2513,7 +2580,7 @@ void BTR_selectivity(thread_db* tdbb, Cached::Relation* relation, MetaId id, Sel RelationPages* relPages = relation->getPages(tdbb); WIN window(relPages->rel_pg_space_id, -1); - index_root_page* root = fetch_root(tdbb, &window, relation, relPages); + const index_root_page* root = fetch_root(tdbb, &window, relation, relPages); if (!root) return; @@ -2690,9 +2757,9 @@ void BTR_selectivity(thread_db* tdbb, Cached::Relation* relation, MetaId id, Sel // Store the selectivity on the root page window.win_page = relPages->rel_index_root; window.win_flags = 0; - root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); + auto* write_root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); CCH_MARK(tdbb, &window); - update_selectivity(root, id, selectivity); + update_selectivity(write_root, id, selectivity); CCH_RELEASE(tdbb, &window); } @@ -4621,8 +4688,8 @@ static ULONG fast_load(thread_db* tdbb, } -static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const RelationPermanent* relation, - const RelationPages* relPages) +static const index_root_page* fetch_root(thread_db* tdbb, WIN* window, const RelationPermanent* relation, + const RelationPages* relPages) { /************************************** * @@ -4651,7 +4718,7 @@ static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const RelationP window->win_page = relPages->rel_index_root; } - return (index_root_page*) CCH_FETCH(tdbb, window, LCK_read, pag_root); + return BTR_fetch_root(FB_FUNCTION, tdbb, window); } diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index 298288cb49..5cb8570ae0 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -30,11 +30,11 @@ #include "../jrd/exe.h" void BTR_all(Jrd::thread_db*, Jrd::Cached::Relation*, Jrd::IndexDescList&, Jrd::RelationPages*); -void BTR_activate_index(Jrd::thread_db*, Jrd::win*, MetaId); +void BTR_activate_index(Jrd::thread_db*, Jrd::Cached::Relation*, MetaId); void BTR_complement_key(Jrd::temporary_key*); void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&); bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, MetaId); -bool BTR_description(Jrd::thread_db*, Jrd::Cached::Relation*, Ods::index_root_page*, Jrd::index_desc*, MetaId); +bool BTR_description(Jrd::thread_db*, Jrd::Cached::Relation*, const Ods::index_root_page*, Jrd::index_desc*, MetaId); bool BTR_check_condition(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*); DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&); void BTR_evaluate(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*); @@ -50,11 +50,13 @@ bool BTR_lookup(Jrd::thread_db*, Jrd::Cached::Relation*, MetaId, Jrd::index_desc Jrd::idx_e BTR_make_key(Jrd::thread_db*, USHORT, const Jrd::ValueExprNode* const*, const Jrd::index_desc*, Jrd::temporary_key*, USHORT); void BTR_make_null_key(Jrd::thread_db*, const Jrd::index_desc*, Jrd::temporary_key*); -void BTR_mark_index_for_delete(Jrd::thread_db* tdbb, Jrd::win* window, MetaId id); +void BTR_mark_index_for_delete(Jrd::thread_db* tdbb, Jrd::Cached::Relation*, MetaId id); bool BTR_next_index(Jrd::thread_db*, Jrd::Cached::Relation*, Jrd::jrd_tra*, Jrd::index_desc*, Jrd::win*); void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*); void BTR_reserve_slot(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::IndexCreateLock&); void BTR_selectivity(Jrd::thread_db*, Jrd::Cached::Relation*, MetaId, Jrd::SelectivityList&); bool BTR_types_comparable(const dsc& target, const dsc& source); +Ods::index_root_page* BTR_fetch_root_for_update(const char* from, Jrd::thread_db* tdbb, Jrd::win* window); +const Ods::index_root_page* BTR_fetch_root(const char* from, Jrd::thread_db* tdbb, Jrd::win* window); #endif // JRD_BTR_PROTO_H diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index 4729ca82d6..932104bdd5 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -149,8 +149,7 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, Cached::Relation* v referenced_window.win_page = get_root_page(tdbb, getPermanent(referenced_relation)); referenced_window.win_flags = 0; - index_root_page* referenced_root = - (index_root_page*) CCH_FETCH(tdbb, &referenced_window, LCK_read, pag_root); + auto* referenced_root = BTR_fetch_root(FB_FUNCTION, tdbb, &referenced_window); index_desc referenced_idx; if (!BTR_description(tdbb, getPermanent(referenced_relation), referenced_root, &referenced_idx, index_id)) @@ -205,7 +204,7 @@ bool IDX_check_master_types(thread_db* tdbb, index_desc& idx, Cached::Relation* // get the index root page for the partner relation WIN window(get_root_page(tdbb, partner_relation)); - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_root); + auto* root = BTR_fetch_root(FB_FUNCTION, tdbb, &window); // get the description of the partner index const bool ok = BTR_description(tdbb, partner_relation, root, &partner_idx, idx.idx_primary_index); @@ -980,10 +979,7 @@ void IDX_create_index(thread_db* tdbb, void IDX_activate_index(thread_db* tdbb, Cached::Relation* relation, MetaId id) { - WIN window(get_root_page(tdbb, relation)); - CCH_FETCH(tdbb, &window, LCK_write, pag_root); - - BTR_activate_index(tdbb, &window, id); + BTR_activate_index(tdbb, relation, id); } @@ -1003,12 +999,10 @@ void IDX_delete_index(thread_db* tdbb, Cached::Relation* relation, MetaId id) signal_index_deletion(tdbb, relation, id); - WIN window(get_root_page(tdbb, relation)); - CCH_FETCH(tdbb, &window, LCK_write, pag_root); + BTR_mark_index_for_delete(tdbb, relation, id); - BTR_mark_index_for_delete(tdbb, &window, id); /* ?????????????????? - if ((getPermanent(relation)->rel_flags & REL_temp_conn) && (relation->getPages(tdbb)->rel_instance_id != 0) && + if ((relation->rel_flags & REL_temp_conn) && (relation->getPages(tdbb)->rel_instance_id != 0) && tree_exists) { IndexPermanent* idx_lock = relation->getIndexLock(tdbb, id); @@ -1037,14 +1031,14 @@ void IDX_delete_indices(thread_db* tdbb, RelationPermanent* relation, RelationPa fb_assert(relPages->rel_index_root); WIN window(relPages->rel_pg_space_id, relPages->rel_index_root); - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); + index_root_page* root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); // const bool is_temp = (relation->rel_flags & REL_temp_conn) && (relPages->rel_instance_id != 0); for (USHORT i = 0; i < root->irt_count; i++) { const bool tree_exists = BTR_delete_index(tdbb, &window, i); - root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_root); + root = BTR_fetch_root_for_update(FB_FUNCTION, tdbb, &window); /* !!!!!!!!!!!!!! if (is_temp && tree_exists) { @@ -1126,7 +1120,7 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going, WIN window(get_root_page(tdbb, getPermanent(rpb->rpb_relation))); - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_root); + auto* root = BTR_fetch_root(FB_FUNCTION, tdbb, &window); for (USHORT i = 0; i < root->irt_count; i++) { @@ -1206,7 +1200,7 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going, // Get rid of index node BTR_remove(tdbb, &window, &insertion); - root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_root); + root = BTR_fetch_root(FB_FUNCTION, tdbb, &window); if (stack1.hasMore(1)) BTR_description(tdbb, getPermanent(rpb->rpb_relation), root, &idx, i); @@ -1796,7 +1790,7 @@ static idx_e check_partner_index(thread_db* tdbb, // get the index root page for the partner relation WIN window(get_root_page(tdbb, getPermanent(partner_relation))); - index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_root); + auto* root = BTR_fetch_root(FB_FUNCTION, tdbb, &window); // get the description of the partner index @@ -1943,17 +1937,7 @@ static PageNumber get_root_page(thread_db* tdbb, Cached::Relation* relation) * Find the root page for a relation. * **************************************/ - SET_TDBB(tdbb); - - RelationPages* relPages = relation->getPages(tdbb); - SLONG page = relPages->rel_index_root; - if (!page) - { - DPM_scan_pages(tdbb); - page = relPages->rel_index_root; - } - - return PageNumber(relPages->rel_pg_space_id, page); + return relation->getIndexRootPage(tdbb); }