8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:43:03 +01:00

Reworked index root page related code, added some debugging

This commit is contained in:
AlexPeshkoff 2025-01-17 20:29:41 +03:00
parent aaaa7ba427
commit 28bdd0bf99
5 changed files with 145 additions and 66 deletions

View File

@ -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

View File

@ -872,8 +872,8 @@ public:
rel_file = f;
}
void getRelLockKey(thread_db* tdbb, UCHAR* key);
PageNumber getIndexRootPage(thread_db* tdbb);
bool isSystem() const;
bool isTemporary() const;

View File

@ -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,7 +4688,7 @@ static ULONG fast_load(thread_db* tdbb,
}
static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const RelationPermanent* relation,
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);
}

View File

@ -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

View File

@ -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);
}