diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 6e490f8365..e9978fd416 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -924,8 +924,9 @@ bool BTR_delete_index(thread_db* tdbb, WIN* window, USHORT id) { index_root_page::irt_repeat* irt_desc = root->irt_rpt + id; CCH_MARK(tdbb, window); - const PageNumber next(window->win_page.getPageSpaceID(), irt_desc->irt_root); - tree_exists = !irt_desc->isEmpty(); + const ULONG rootPage = irt_desc->getRoot(); + const PageNumber next(window->win_page.getPageSpaceID(), rootPage); + tree_exists = (rootPage != 0); // remove the pointer to the top-level index page before we delete it irt_desc->setEmpty(); @@ -961,11 +962,12 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, const index_root_page::irt_repeat* irt_desc = &root->irt_rpt[id]; - if (irt_desc->isEmpty()) + const ULONG rootPage = irt_desc->getRoot(); + if (!rootPage) return false; idx->idx_id = id; - idx->idx_root = irt_desc->irt_root; + idx->idx_root = rootPage; idx->idx_count = irt_desc->irt_keys; idx->idx_flags = irt_desc->irt_flags; idx->idx_runtime_flags = 0; @@ -1450,7 +1452,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) // update the index root page. Oh boy. index_root_page* root = (index_root_page*) CCH_FETCH(tdbb, root_window, LCK_write, pag_root); - window.win_page = root->irt_rpt[idx->idx_id].irt_root; + window.win_page = root->irt_rpt[idx->idx_id].getRoot(); bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); if (window.win_page.getPageNum() != idx->idx_root) @@ -1500,7 +1502,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) BUGCHECK(204); // msg 204 index inconsistent } - window.win_page = root->irt_rpt[idx->idx_id].irt_root; + window.win_page = root->irt_rpt[idx->idx_id].getRoot(); bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); key.key_length = ret_key.key_length; memcpy(key.key_data, ret_key.key_data, ret_key.key_length); @@ -2392,15 +2394,13 @@ void BTR_selectivity(thread_db* tdbb, jrd_rel* relation, USHORT id, SelectivityL if (!root) return; - if (id >= root->irt_count || root->irt_rpt[id].isEmpty()) + if (id >= root->irt_count || !root->irt_rpt[id].getRoot()) { CCH_RELEASE(tdbb, &window); return; } - ULONG page = root->irt_rpt[id].irt_root; - fb_assert(page); - + ULONG page = root->irt_rpt[id].getRoot(); const bool descending = (root->irt_rpt[id].irt_flags & irt_descending); const ULONG segments = root->irt_rpt[id].irt_keys; @@ -3335,7 +3335,7 @@ static USHORT compress_root(thread_db* tdbb, index_root_page* page) for (const index_root_page::irt_repeat* const end = root_idx + page->irt_count; root_idx < end; root_idx++) { - if (!root_idx->isEmpty()) + if (root_idx->getRoot()) { const USHORT len = root_idx->irt_keys * sizeof(irtd); p -= len; diff --git a/src/jrd/ods.h b/src/jrd/ods.h index 1d57c1aa4c..96519c334c 100644 --- a/src/jrd/ods.h +++ b/src/jrd/ods.h @@ -368,24 +368,26 @@ struct index_root_page USHORT irt_count; // Number of indices struct irt_repeat { + friend class index_root_page; // to allow offset check for private members + private: union { FB_UINT64 irt_transaction; // transaction in progress ULONG irt_root; // page number of index root }; + public: USHORT irt_desc; // offset to key descriptions USHORT irt_flags; // index flags UCHAR irt_keys; // number of keys in index TraNumber inProgress() const; - bool isEmpty() const; - bool isUsed() const; - - void setEmpty(); void setInProgress(TraNumber traNumber); - void clearInProgress(ULONG rootPage); + + ULONG getRoot() const; void setRoot(ULONG rootPage); + bool isUsed() const; + void setEmpty(); } irt_rpt[1]; static_assert(sizeof(struct irt_repeat) == 16, "struct irt_repeat size mismatch"); @@ -425,16 +427,6 @@ inline constexpr USHORT irt_primary = 16; inline constexpr USHORT irt_expression = 32; inline constexpr USHORT irt_condition = 64; -inline TraNumber index_root_page::irt_repeat::inProgress() const -{ - return (irt_flags & irt_in_progress) ? irt_transaction : 0; -} - -inline bool index_root_page::irt_repeat::isEmpty() const -{ - return (irt_flags & irt_in_progress) || (irt_root == 0); -} - inline bool index_root_page::irt_repeat::isUsed() const { return (irt_flags & irt_in_progress) || (irt_root != 0); @@ -443,15 +435,26 @@ inline bool index_root_page::irt_repeat::isUsed() const inline void index_root_page::irt_repeat::setEmpty() { irt_transaction = 0; + fb_assert(irt_root == 0); irt_flags = 0; } +inline TraNumber index_root_page::irt_repeat::inProgress() const +{ + return (irt_flags & irt_in_progress) ? irt_transaction : 0; +} + inline void index_root_page::irt_repeat::setInProgress(TraNumber traNumber) { irt_transaction = traNumber; irt_flags |= irt_in_progress; } +inline ULONG index_root_page::irt_repeat::getRoot() const +{ + return (irt_flags & irt_in_progress) ? 0 : irt_root; +} + inline void index_root_page::irt_repeat::setRoot(ULONG rootPage) { irt_root = rootPage; diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index e679a42cc4..dfdd5ec732 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -1976,12 +1976,10 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page* root_ **************************************/ Database* dbb = vdr_tdbb->getDatabase(); - if (root_page->irt_rpt[id].isEmpty()) + const ULONG page_number = root_page->irt_rpt[id].getRoot(); + if (!page_number) return rtn_ok; - const ULONG page_number = root_page->irt_rpt[id].irt_root; - fb_assert(page_number); - const bool unique = (root_page->irt_rpt[id].irt_flags & (irt_unique | idx_primary)); const bool descending = (root_page->irt_rpt[id].irt_flags & irt_descending); const bool condition = (root_page->irt_rpt[id].irt_flags & irt_condition); @@ -3211,13 +3209,13 @@ Validation::RTN Validation::walk_root(jrd_rel* relation, bool getInfo) if (!relPages->rel_index_root) return corrupt(VAL_INDEX_ROOT_MISSING, relation); - index_root_page* page = 0; + index_root_page* page = nullptr; WIN window(DB_PAGE_SPACE, -1); fetch_page(!getInfo, relPages->rel_index_root, pag_root, &window, &page); for (USHORT i = 0; i < page->irt_count; i++) { - if (page->irt_rpt[i].isEmpty()) + if (!page->irt_rpt[i].getRoot()) continue; MetaName index; diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index e89d8471b6..33d73183df 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -1566,11 +1566,12 @@ static void analyze_index( const dba_rel* relation, dba_idx* index) const index_root_page* index_root = (const index_root_page*) db_read(relation->rel_index_root); - if (index_root->irt_count <= index->idx_id || index_root->irt_rpt[index->idx_id].isEmpty()) + if (index_root->irt_count <= index->idx_id) return; - ULONG page = index_root->irt_rpt[index->idx_id].irt_root; - fb_assert(page); + ULONG page = index_root->irt_rpt[index->idx_id].getRoot(); + if (!page) + return; // CVC: The two const_cast's for bucket can go away if BTreeNode's functions // are overloaded for constness. They don't modify bucket and pointer's contents.