Skip to content

Commit 62f13ad

Browse files
committed
Validation of condition indices.
1 parent 4039167 commit 62f13ad

File tree

2 files changed

+142
-22
lines changed

2 files changed

+142
-22
lines changed

src/jrd/validation.cpp

Lines changed: 128 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,8 +1077,12 @@ void Validation::cleanup()
10771077

10781078
delete vdr_idx_records;
10791079
vdr_idx_records = NULL;
1080+
1081+
for (auto& item : vdr_cond_idx)
1082+
delete item.m_recs;
10801083
}
10811084

1085+
10821086
ULONG Validation::getInfo(UCHAR item)
10831087
{
10841088
ULONG ret = 0;
@@ -1552,8 +1556,8 @@ Validation::RTN Validation::walk_chain(jrd_rel* relation, const rhd* header,
15521556

15531557
if (page->dpg_relation != relation->rel_id)
15541558
{
1555-
release_page(&window);
1556-
return corrupt(VAL_DATA_PAGE_CONFUSED, relation, page_number, page->dpg_sequence);
1559+
release_page(&window);
1560+
return corrupt(VAL_DATA_PAGE_CONFUSED, relation, page_number, page->dpg_sequence);
15571561
}
15581562

15591563
vdr_rel_chain_counter++;
@@ -1740,6 +1744,12 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
17401744
RecordNumber number((SINT64)sequence * dbb->dbb_max_records);
17411745
int primary_versions = 0;
17421746
bool marked = false;
1747+
MemoryPool* pool = vdr_tdbb->getDefaultPool();
1748+
1749+
// Expression of condition index could try to read current data page when evaluated.
1750+
// Thus we collect all record numbers and will evaluate conditions expressions after
1751+
// releasing data page, to avoid deadlocks.
1752+
HalfStaticArray<FB_UINT64, 64> recnums;
17431753

17441754
for (const data_page::dpg_repeat* line = page->dpg_rpt; line < end; line++, number.increment())
17451755
{
@@ -1762,7 +1772,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
17621772
if (header->rhd_flags & rhd_chain)
17631773
{
17641774
vdr_rel_backversion_counter++;
1765-
PBM_SET(vdr_tdbb->getDefaultPool(), &vdr_backversion_pages, page_number);
1775+
PBM_SET(pool, &vdr_backversion_pages, page_number);
17661776
}
17671777

17681778
// Record the existance of a primary version of a record
@@ -1776,7 +1786,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
17761786
// state of the lone primary record version. Unless it is already deleted.
17771787

17781788
if (header->rhd_b_page)
1779-
RBM_SET(vdr_tdbb->getDefaultPool(), &vdr_rel_records, number.getValue());
1789+
RBM_SET(pool, &vdr_rel_records, number.getValue());
17801790
else if ((header->rhd_flags & rhd_deleted) == 0)
17811791
{
17821792
const TraNumber transaction = Ods::getTraNum(header);
@@ -1785,7 +1795,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
17851795
tra_committed : TRA_fetch_state(vdr_tdbb, transaction);
17861796

17871797
if (state == tra_committed || state == tra_limbo)
1788-
RBM_SET(vdr_tdbb->getDefaultPool(), &vdr_rel_records, number.getValue());
1798+
RBM_SET(pool, &vdr_rel_records, number.getValue());
17891799
}
17901800

17911801
primary_versions++;
@@ -1821,6 +1831,12 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
18211831
vdr_fixed++;
18221832
}
18231833
}
1834+
1835+
if (!(header->rhd_flags & (rhd_chain | rhd_fragment | rhd_blob | rhd_damaged)) &&
1836+
(vdr_flags & VDR_records) && vdr_cond_idx.hasData())
1837+
{
1838+
recnums.add(number.getValue());
1839+
}
18241840
}
18251841
#ifdef DEBUG_VAL_VERBOSE
18261842
else if (VAL_debug_level)
@@ -1848,6 +1864,42 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
18481864

18491865
release_page(&window);
18501866

1867+
// Safe moment to evaluate condition indices expressions for collected records
1868+
// and build pre-index bitmaps of passed record numbers.
1869+
1870+
if (recnums.hasData())
1871+
{
1872+
// Use system transaction to get most recently committed record version.
1873+
1874+
jrd_tra* sysTran = vdr_tdbb->getAttachment()->getSysTransaction();
1875+
AutoSetRestore2<jrd_tra*, thread_db> setTran(vdr_tdbb,
1876+
&thread_db::getTransaction,
1877+
&thread_db::setTransaction,
1878+
sysTran);
1879+
1880+
record_param rpb;
1881+
rpb.rpb_relation = relation;
1882+
1883+
for (auto& recno : recnums)
1884+
{
1885+
rpb.rpb_number.setValue(recno);
1886+
1887+
if (VIO_get(vdr_tdbb, &rpb, sysTran, pool))
1888+
{
1889+
for (auto& getInfo : vdr_cond_idx)
1890+
{
1891+
if (getInfo.m_desc.idx_flags & idx_condition)
1892+
{
1893+
if (BTR_check_condition(vdr_tdbb, &getInfo.m_desc, rpb.rpb_record))
1894+
RBM_SET(pool, &getInfo.m_recs, recno);
1895+
}
1896+
}
1897+
}
1898+
}
1899+
1900+
delete rpb.rpb_record;
1901+
}
1902+
18511903
#ifdef DEBUG_VAL_VERBOSE
18521904
if (VAL_debug_level)
18531905
fprintf(stdout, "------------------------------------\n");
@@ -1947,18 +1999,19 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_
19471999

19482000
const bool unique = (root_page.irt_rpt[id].irt_flags & (irt_unique | idx_primary));
19492001
const bool descending = (root_page.irt_rpt[id].irt_flags & irt_descending);
2002+
const bool condition = (root_page.irt_rpt[id].irt_flags & irt_condition);
19502003

19512004
temporary_key nullKey, *null_key = 0;
19522005
if (unique)
19532006
{
1954-
const bool isExpression = root_page.irt_rpt[id].irt_flags & irt_expression;
1955-
if (isExpression)
1956-
root_page.irt_rpt[id].irt_flags &= ~irt_expression;
1957-
19582007
index_desc idx;
1959-
BTR_description(vdr_tdbb, relation, &root_page, &idx, id);
1960-
if (isExpression)
1961-
root_page.irt_rpt[id].irt_flags |= irt_expression;
2008+
{
2009+
// No need to evaluate index expression and/or condition
2010+
AutoSetRestoreFlag<UCHAR> flags(&root_page.irt_rpt[id].irt_flags,
2011+
irt_expression | irt_condition, false);
2012+
2013+
BTR_description(vdr_tdbb, relation, &root_page, &idx, id);
2014+
}
19622015

19632016
null_key = &nullKey;
19642017
BTR_make_null_key(vdr_tdbb, &idx, null_key);
@@ -2340,7 +2393,20 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_
23402393
// have a corrupt index
23412394
if (vdr_flags & VDR_records)
23422395
{
2343-
RecordBitmap::Accessor accessor(vdr_rel_records);
2396+
RecordBitmap* bm_records = vdr_rel_records;
2397+
2398+
if (condition)
2399+
{
2400+
for (auto getInfo : vdr_cond_idx)
2401+
{
2402+
if (getInfo.m_desc.idx_id == id)
2403+
{
2404+
bm_records = getInfo.m_recs;
2405+
break;
2406+
}
2407+
}
2408+
}
2409+
RecordBitmap::Accessor accessor(bm_records);
23442410

23452411
if (accessor.getFirst())
23462412
{
@@ -2530,8 +2596,6 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence)
25302596
// Walk the data pages (someday we may optionally walk pages with "large objects"
25312597

25322598
ULONG seq = sequence * dbb->dbb_dp_per_pp;
2533-
2534-
25352599
UCHAR* bits = (UCHAR*) (page->ppg_page + dbb->dbb_dp_per_pp);
25362600
bool marked = false;
25372601
USHORT slot = 0;
@@ -2541,7 +2605,25 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence)
25412605
{
25422606
UCHAR new_pp_bits = 0;
25432607

2608+
// If walk_data_page() below going to evaluate conditions expressions,
2609+
// pointer page should be released to avoid deadlocks.
2610+
2611+
const bool releasePP = vdr_cond_idx.hasData();
2612+
if (releasePP)
2613+
{
2614+
release_page(&window);
2615+
marked = false;
2616+
}
2617+
25442618
const RTN result = walk_data_page(relation, *pages, seq, new_pp_bits);
2619+
2620+
if (releasePP)
2621+
{
2622+
fetch_page(false, (*vector)[sequence], pag_pointer, &window, &page);
2623+
bits = (UCHAR*) (page->ppg_page + dbb->dbb_dp_per_pp);
2624+
pages = &page->ppg_page[slot];
2625+
}
2626+
25452627
if (result != rtn_ok && (vdr_flags & VDR_repair))
25462628
{
25472629
if (!marked)
@@ -2987,6 +3069,17 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
29873069
release_page(&window);
29883070
}
29893071

3072+
// If we going to check records, get getInfo about conditional indices before
3073+
// walking relation. System relations have no conditional indices.
3074+
3075+
for (auto& item : vdr_cond_idx)
3076+
delete item.m_recs;
3077+
3078+
vdr_cond_idx.clear();
3079+
3080+
const bool idxRootOk = (vdr_flags & VDR_records) && !relation->isSystem() ?
3081+
walk_root(relation, true) == rtn_ok : true;
3082+
29903083
// Walk pointer and selected data pages associated with relation
29913084

29923085
vdr_rel_backversion_counter = 0;
@@ -3010,7 +3103,8 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
30103103
}
30113104

30123105
// Walk indices for the relation
3013-
walk_root(relation);
3106+
if (idxRootOk)
3107+
walk_root(relation, false);
30143108

30153109
lckGC.release();
30163110

@@ -3087,7 +3181,7 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
30873181
}
30883182

30893183

3090-
Validation::RTN Validation::walk_root(jrd_rel* relation)
3184+
Validation::RTN Validation::walk_root(jrd_rel* relation, bool getInfo)
30913185
{
30923186
/**************************************
30933187
*
@@ -3096,7 +3190,8 @@ Validation::RTN Validation::walk_root(jrd_rel* relation)
30963190
**************************************
30973191
*
30983192
* Functional description
3099-
* Walk index root page for a relation as well as any indices.
3193+
* Walk index root page for a relation. If getInfo is true
3194+
* get index metadata for condition indices, else walk every index.
31003195
*
31013196
**************************************/
31023197

@@ -3108,7 +3203,7 @@ Validation::RTN Validation::walk_root(jrd_rel* relation)
31083203

31093204
index_root_page* page = 0;
31103205
WIN window(DB_PAGE_SPACE, -1);
3111-
fetch_page(true, relPages->rel_index_root, pag_root, &window, &page);
3206+
fetch_page(!getInfo, relPages->rel_index_root, pag_root, &window, &page);
31123207

31133208
for (USHORT i = 0; i < page->irt_count; i++)
31143209
{
@@ -3133,6 +3228,20 @@ Validation::RTN Validation::walk_root(jrd_rel* relation)
31333228
continue;
31343229
}
31353230

3231+
if (getInfo)
3232+
{
3233+
if (page->irt_rpt[i].irt_flags & irt_condition)
3234+
{
3235+
// No need to evaluate index expression
3236+
AutoSetRestoreFlag<UCHAR> flag(&page->irt_rpt[i].irt_flags, irt_expression, false);
3237+
3238+
IdxInfo info;
3239+
if (BTR_description(vdr_tdbb, relation, page, &info.m_desc, i))
3240+
vdr_cond_idx.add(info);
3241+
}
3242+
continue;
3243+
}
3244+
31363245
output("Index %d (%s)\n", i + 1, index.c_str());
31373246
walk_index(relation, *page, i);
31383247
}

src/jrd/validation.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ class Validation
7979
rtn_eof
8080
};
8181

82+
struct IdxInfo
83+
{
84+
IdxInfo()
85+
: m_recs(nullptr)
86+
{}
87+
88+
index_desc m_desc;
89+
RecordBitmap* m_recs;
90+
};
91+
8292
enum VAL_ERRORS
8393
{
8494
VAL_PAG_WRONG_TYPE = 0,
@@ -142,11 +152,12 @@ class Validation
142152
int vdr_fixed;
143153
TraNumber vdr_max_transaction;
144154
FB_UINT64 vdr_rel_backversion_counter; // Counts slots w/rhd_chain
145-
PageBitmap* vdr_backversion_pages; // 1 bit per visited table page
155+
PageBitmap* vdr_backversion_pages; // 1 bit per visited table page
146156
FB_UINT64 vdr_rel_chain_counter; // Counts chains w/rdr_chain
147-
PageBitmap* vdr_chain_pages; // 1 bit per visited record chain page
157+
PageBitmap* vdr_chain_pages; // 1 bit per visited record chain page
148158
RecordBitmap* vdr_rel_records; // 1 bit per valid record
149159
RecordBitmap* vdr_idx_records; // 1 bit per index item
160+
Firebird::Array<IdxInfo> vdr_cond_idx; // one entry per condition index for current relation
150161
PageBitmap* vdr_page_bitmap;
151162
ULONG vdr_err_counts[VAL_MAX_ERROR];
152163

@@ -208,7 +219,7 @@ class Validation
208219
RTN walk_pointer_page(jrd_rel*, ULONG);
209220
RTN walk_record(jrd_rel*, const Ods::rhd*, USHORT, RecordNumber, bool);
210221
RTN walk_relation(jrd_rel*);
211-
RTN walk_root(jrd_rel*);
222+
RTN walk_root(jrd_rel*, bool);
212223
RTN walk_scns();
213224
RTN walk_tip(TraNumber);
214225
};

0 commit comments

Comments
 (0)