@@ -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+
10821086ULONG 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 }
0 commit comments