@@ -1077,8 +1077,12 @@ void Validation::cleanup()
1077
1077
1078
1078
delete vdr_idx_records;
1079
1079
vdr_idx_records = NULL ;
1080
+
1081
+ for (auto & item : vdr_cond_idx)
1082
+ delete item.m_recs ;
1080
1083
}
1081
1084
1085
+
1082
1086
ULONG Validation::getInfo (UCHAR item)
1083
1087
{
1084
1088
ULONG ret = 0 ;
@@ -1552,8 +1556,8 @@ Validation::RTN Validation::walk_chain(jrd_rel* relation, const rhd* header,
1552
1556
1553
1557
if (page->dpg_relation != relation->rel_id )
1554
1558
{
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 );
1557
1561
}
1558
1562
1559
1563
vdr_rel_chain_counter++;
@@ -1740,6 +1744,12 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
1740
1744
RecordNumber number ((SINT64)sequence * dbb->dbb_max_records );
1741
1745
int primary_versions = 0 ;
1742
1746
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;
1743
1753
1744
1754
for (const data_page::dpg_repeat* line = page->dpg_rpt ; line < end; line++, number.increment ())
1745
1755
{
@@ -1762,7 +1772,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
1762
1772
if (header->rhd_flags & rhd_chain)
1763
1773
{
1764
1774
vdr_rel_backversion_counter++;
1765
- PBM_SET (vdr_tdbb-> getDefaultPool () , &vdr_backversion_pages, page_number);
1775
+ PBM_SET (pool , &vdr_backversion_pages, page_number);
1766
1776
}
1767
1777
1768
1778
// 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,
1776
1786
// state of the lone primary record version. Unless it is already deleted.
1777
1787
1778
1788
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 ());
1780
1790
else if ((header->rhd_flags & rhd_deleted) == 0 )
1781
1791
{
1782
1792
const TraNumber transaction = Ods::getTraNum (header);
@@ -1785,7 +1795,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
1785
1795
tra_committed : TRA_fetch_state (vdr_tdbb, transaction);
1786
1796
1787
1797
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 ());
1789
1799
}
1790
1800
1791
1801
primary_versions++;
@@ -1821,6 +1831,12 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
1821
1831
vdr_fixed++;
1822
1832
}
1823
1833
}
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
+ }
1824
1840
}
1825
1841
#ifdef DEBUG_VAL_VERBOSE
1826
1842
else if (VAL_debug_level)
@@ -1848,6 +1864,42 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
1848
1864
1849
1865
release_page (&window);
1850
1866
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
+
1851
1903
#ifdef DEBUG_VAL_VERBOSE
1852
1904
if (VAL_debug_level)
1853
1905
fprintf (stdout, " ------------------------------------\n " );
@@ -1947,18 +1999,19 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_
1947
1999
1948
2000
const bool unique = (root_page.irt_rpt [id].irt_flags & (irt_unique | idx_primary));
1949
2001
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);
1950
2003
1951
2004
temporary_key nullKey, *null_key = 0 ;
1952
2005
if (unique)
1953
2006
{
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
-
1958
2007
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
+ }
1962
2015
1963
2016
null_key = &nullKey;
1964
2017
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_
2340
2393
// have a corrupt index
2341
2394
if (vdr_flags & VDR_records)
2342
2395
{
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);
2344
2410
2345
2411
if (accessor.getFirst ())
2346
2412
{
@@ -2530,8 +2596,6 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence)
2530
2596
// Walk the data pages (someday we may optionally walk pages with "large objects"
2531
2597
2532
2598
ULONG seq = sequence * dbb->dbb_dp_per_pp ;
2533
-
2534
-
2535
2599
UCHAR* bits = (UCHAR*) (page->ppg_page + dbb->dbb_dp_per_pp );
2536
2600
bool marked = false ;
2537
2601
USHORT slot = 0 ;
@@ -2541,7 +2605,25 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence)
2541
2605
{
2542
2606
UCHAR new_pp_bits = 0 ;
2543
2607
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
+
2544
2618
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
+
2545
2627
if (result != rtn_ok && (vdr_flags & VDR_repair))
2546
2628
{
2547
2629
if (!marked)
@@ -2987,6 +3069,17 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
2987
3069
release_page (&window);
2988
3070
}
2989
3071
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
+
2990
3083
// Walk pointer and selected data pages associated with relation
2991
3084
2992
3085
vdr_rel_backversion_counter = 0 ;
@@ -3010,7 +3103,8 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
3010
3103
}
3011
3104
3012
3105
// Walk indices for the relation
3013
- walk_root (relation);
3106
+ if (idxRootOk)
3107
+ walk_root (relation, false );
3014
3108
3015
3109
lckGC.release ();
3016
3110
@@ -3087,7 +3181,7 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
3087
3181
}
3088
3182
3089
3183
3090
- Validation::RTN Validation::walk_root (jrd_rel* relation)
3184
+ Validation::RTN Validation::walk_root (jrd_rel* relation, bool getInfo )
3091
3185
{
3092
3186
/* *************************************
3093
3187
*
@@ -3096,7 +3190,8 @@ Validation::RTN Validation::walk_root(jrd_rel* relation)
3096
3190
**************************************
3097
3191
*
3098
3192
* 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.
3100
3195
*
3101
3196
**************************************/
3102
3197
@@ -3108,7 +3203,7 @@ Validation::RTN Validation::walk_root(jrd_rel* relation)
3108
3203
3109
3204
index_root_page* page = 0 ;
3110
3205
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);
3112
3207
3113
3208
for (USHORT i = 0 ; i < page->irt_count ; i++)
3114
3209
{
@@ -3133,6 +3228,20 @@ Validation::RTN Validation::walk_root(jrd_rel* relation)
3133
3228
continue ;
3134
3229
}
3135
3230
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
+
3136
3245
output (" Index %d (%s)\n " , i + 1 , index.c_str ());
3137
3246
walk_index (relation, *page, i);
3138
3247
}
0 commit comments