Commit 8b833274 authored by Michael Widenius's avatar Michael Widenius

Merge with 1.0.11-7 Pre-GA - 2010-09-09

Updated results for failing test cases (In all cases the estimated number of rows was different)
parent 6b1c78e7
...@@ -388,7 +388,7 @@ Table Op Msg_type Msg_text ...@@ -388,7 +388,7 @@ Table Op Msg_type Msg_text
test.t1 analyze status OK test.t1 analyze status OK
explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a)); explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a));
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL a 5 NULL 21 100.00 Using where; Using index 1 SIMPLE t1 index NULL a 5 NULL 5 100.00 Using where; Using index
Warnings: Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or `test`.`t1`.`a`) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where `test`.`t1`.`a` having `test`.`t1`.`a` Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or `test`.`t1`.`a`) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where `test`.`t1`.`a` having `test`.`t1`.`a`
drop table t1; drop table t1;
...@@ -1384,52 +1384,52 @@ Table Op Msg_type Msg_text ...@@ -1384,52 +1384,52 @@ Table Op Msg_type Msg_text
test.t2 analyze status OK test.t2 analyze status OK
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 1 SIMPLE t4 ALL NULL NULL NULL NULL 12
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 1 SIMPLE t4 ALL NULL NULL NULL NULL 12
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where 1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where 1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
companynr companynr companynr companynr
37 36 37 36
...@@ -1437,7 +1437,7 @@ companynr companynr ...@@ -1437,7 +1437,7 @@ companynr companynr
explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where; Using join buffer 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer
select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008;
fld1 companynr fld3 period fld1 companynr fld3 period
038008 37 reporters 1008 038008 37 reporters 1008
...@@ -1511,7 +1511,7 @@ count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) ...@@ -1511,7 +1511,7 @@ count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1)
70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069 70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069
explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>"";
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 100.00 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 100.00 Using where
Warnings: Warnings:
Note 1003 select count(0) AS `count(*)`,min(`test`.`t2`.`fld4`) AS `min(fld4)`,max(`test`.`t2`.`fld4`) AS `max(fld4)`,sum(`test`.`t2`.`fld1`) AS `sum(fld1)`,avg(`test`.`t2`.`fld1`) AS `avg(fld1)`,std(`test`.`t2`.`fld1`) AS `std(fld1)`,variance(`test`.`t2`.`fld1`) AS `variance(fld1)` from `test`.`t2` where ((`test`.`t2`.`companynr` = 34) and (`test`.`t2`.`fld4` <> '')) Note 1003 select count(0) AS `count(*)`,min(`test`.`t2`.`fld4`) AS `min(fld4)`,max(`test`.`t2`.`fld4`) AS `max(fld4)`,sum(`test`.`t2`.`fld1`) AS `sum(fld1)`,avg(`test`.`t2`.`fld1`) AS `avg(fld1)`,std(`test`.`t2`.`fld1`) AS `std(fld1)`,variance(`test`.`t2`.`fld1`) AS `variance(fld1)` from `test`.`t2` where ((`test`.`t2`.`companynr` = 34) and (`test`.`t2`.`fld4` <> ''))
select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3;
...@@ -1955,7 +1955,7 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -1955,7 +1955,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
explain select fld3 from t2 where fld1=fld1; explain select fld3 from t2 where fld1=fld1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199
select companynr,fld1 from t2 HAVING fld1=250501 or fld1=250502; select companynr,fld1 from t2 HAVING fld1=250501 or fld1=250502;
companynr fld1 companynr fld1
34 250501 34 250501
...@@ -2007,7 +2007,7 @@ count(*) ...@@ -2007,7 +2007,7 @@ count(*)
4181 4181
explain select min(fld1),max(fld1),count(*) from t2; explain select min(fld1),max(fld1),count(*) from t2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL fld1 4 NULL 1200 Using index 1 SIMPLE t2 index NULL fld1 4 NULL 1199 Using index
select min(fld1),max(fld1),count(*) from t2; select min(fld1),max(fld1),count(*) from t2;
min(fld1) max(fld1) count(*) min(fld1) max(fld1) count(*)
0 1232609 1199 0 1232609 1199
...@@ -2093,9 +2093,9 @@ show full columns from t2 from test like 's%'; ...@@ -2093,9 +2093,9 @@ show full columns from t2 from test like 's%';
Field Type Collation Null Key Default Extra Privileges Comment Field Type Collation Null Key Default Extra Privileges Comment
show keys from t2; show keys from t2;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t2 0 PRIMARY 1 auto A 1200 NULL NULL BTREE t2 0 PRIMARY 1 auto A 1199 NULL NULL BTREE
t2 0 fld1 1 fld1 A 1200 NULL NULL BTREE t2 0 fld1 1 fld1 A 1199 NULL NULL BTREE
t2 1 fld3 1 fld3 A 1200 NULL NULL BTREE t2 1 fld3 1 fld3 A 1199 NULL NULL BTREE
drop table t4, t3, t2, t1; drop table t4, t3, t2, t1;
DO 1; DO 1;
DO benchmark(100,1+1),1,1; DO benchmark(100,1+1),1,1;
......
PBXT Release Notes PBXT Release Notes
================== ==================
+------- 1.0.11 Pre-GA - 2010-05-11 ------- 1.0.11-7 Pre-GA - 2010-09-09
RN336: Compiled and tested with MySQL 5.1.50.
RN335: Fixed bug #523994: Deleting all records does not update table statistics.
RN334: Made a change to reduce the time that only temporary tables exist during the ALTER TABLE and REPAIR TABLE statements. This increases the chance of recovery if a crash occurs during these operations.
RN333: Log name of table when PBXT recovers an index on startup. If an error occurs during index recovery, the index is set to "repair pending".
RN332: Fixed an inifinite loop when a record in a row is corrupt. Added logging and set the table to "repair pending" in this case.
RN331: Fixed bug #626890: Crash on truncate table operation.
RN330: Added additional checks for corruption of the index free list.
------- 1.0.11-6 Pre-GA - 2010-07-08
RN329: Fixed bug #601245: make fails. PBXT did not compile if the partition engine was disabled in the MySQL build.
------- 1.0.11-5 Pre-GA - 2010-06-18
RN328: Fixed bug #595478: Compile fails (1.0.11-4).
------- 1.0.11-4 Pre-GA - 2010-06-15
RN327: Fixed a bug that caused a crash during delete on the index. The crash occurred due to memory overwrite when a long key is promoted after a shorter key is deleted, and the difference causes a node size overflow.
------- 1.0.11-3 Pre-GA - 2010-06-11
RN326: Fixed bug #587740: pbxt-1.0.11-pre2-ga first time create partition table error. This was not a new bug. The problem was the PBXT system table's .frm files are corrupted when the first PBXT table created is a partition table.
RN325: Fixed the "to-sweep" column output in xtstat.
------- 1.0.11-2 Pre-GA - 2010-05-26
RN324: Fixed bug #584070:pbxt-1.0.11-pre-ga does not work with mysql 5.1.47. This bug fix removes a hack which was done to avoid running into the LOCK_plugin lock.
------- 1.0.11-1 Pre-GA - 2010-05-19
RN323: Detect corruption of a key length in an index page. This bug fix avoids a possible crash due to index page corruption.
------- 1.0.11 Pre-GA - 2010-05-11
RN322: Creating a table the references a non-existing table can now only be done if you set: foreign_key_checks = 0. Also fixed a failure when creating tables with recursive foreign key declarations. RN322: Creating a table the references a non-existing table can now only be done if you set: foreign_key_checks = 0. Also fixed a failure when creating tables with recursive foreign key declarations.
......
...@@ -40,8 +40,8 @@ libpbxt_la_LDFLAGS = -module ...@@ -40,8 +40,8 @@ libpbxt_la_LDFLAGS = -module
# These are the warning Drizzle uses: # These are the warning Drizzle uses:
# DRIZZLE_WARNINGS = -W -Wall -Wextra -pedantic -Wundef -Wredundant-decls -Wno-strict-aliasing -Wno-long-long -Wno-unused-parameter # DRIZZLE_WARNINGS = -W -Wall -Wextra -pedantic -Wundef -Wredundant-decls -Wno-strict-aliasing -Wno-long-long -Wno-unused-parameter
libpbxt_la_CXXFLAGS = -shared $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN libpbxt_la_CXXFLAGS = $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN
libpbxt_la_CFLAGS = -shared $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN -std=c99 libpbxt_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN -std=c99
EXTRA_LIBRARIES = libpbxt.a EXTRA_LIBRARIES = libpbxt.a
noinst_LIBRARIES = libpbxt.a noinst_LIBRARIES = libpbxt.a
......
...@@ -667,6 +667,9 @@ xtPublic void xt_ind_init(XTThreadPtr self, size_t cache_size) ...@@ -667,6 +667,9 @@ xtPublic void xt_ind_init(XTThreadPtr self, size_t cache_size)
#ifdef XT_USE_DIRECT_IO_ON_INDEX #ifdef XT_USE_DIRECT_IO_ON_INDEX
block->cb_data = buffer; block->cb_data = buffer;
buffer += XT_INDEX_PAGE_SIZE; buffer += XT_INDEX_PAGE_SIZE;
#endif
#ifdef CHECK_BLOCK_TRAILERS
XT_SET_DISK_4(block->cp_check, 0xDEADBEEF);
#endif #endif
ind_cac_globals.cg_free_list = block; ind_cac_globals.cg_free_list = block;
block++; block++;
...@@ -684,6 +687,19 @@ xtPublic void xt_ind_init(XTThreadPtr self, size_t cache_size) ...@@ -684,6 +687,19 @@ xtPublic void xt_ind_init(XTThreadPtr self, size_t cache_size)
cont_(a); cont_(a);
} }
#ifdef CHECK_BLOCK_TRAILERS
xtPublic void check_block_trailers()
{
XTIndBlockPtr block;
block = ind_cac_globals.cg_blocks;
for (u_int i=0; i<ind_cac_globals.cg_block_count; i++) {
ASSERT_NS(XT_GET_DISK_4(block->cp_check) == 0xDEADBEEF);
block++;
}
}
#endif
xtPublic void xt_ind_exit(XTThreadPtr self) xtPublic void xt_ind_exit(XTThreadPtr self)
{ {
#ifdef XT_USE_MYSYS #ifdef XT_USE_MYSYS
...@@ -1283,7 +1299,7 @@ static XTIndBlockPtr ind_cac_fetch(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNod ...@@ -1283,7 +1299,7 @@ static XTIndBlockPtr ind_cac_fetch(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNod
* Conditionally count the number of deleted entries in the index: * Conditionally count the number of deleted entries in the index:
* We do this before other threads can read the block. * We do this before other threads can read the block.
*/ */
if (ind->mi_lazy_delete && read_data) if (ind && ind->mi_lazy_delete && read_data)
xt_ind_count_deleted_items(ot->ot_table, ind, block); xt_ind_count_deleted_items(ot->ot_table, ind, block);
/* Add to the hash table: */ /* Add to the hash table: */
...@@ -1357,6 +1373,9 @@ xtPublic xtBool xt_ind_write(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID ad ...@@ -1357,6 +1373,9 @@ xtPublic xtBool xt_ind_write(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID ad
IDX_CAC_UNLOCK(seg, ot->ot_thread); IDX_CAC_UNLOCK(seg, ot->ot_thread);
#ifdef XT_TRACK_INDEX_UPDATES #ifdef XT_TRACK_INDEX_UPDATES
ot->ot_ind_changed++; ot->ot_ind_changed++;
#endif
#ifdef CHECK_BLOCK_TRAILERS
check_block_trailers();
#endif #endif
return OK; return OK;
} }
......
...@@ -33,6 +33,7 @@ struct XTIdxReadBuffer; ...@@ -33,6 +33,7 @@ struct XTIdxReadBuffer;
#ifdef DEBUG #ifdef DEBUG
//#define XT_USE_CACHE_DEBUG_SIZES //#define XT_USE_CACHE_DEBUG_SIZES
//#define CHECK_BLOCK_TRAILERS
#endif #endif
#ifdef XT_USE_CACHE_DEBUG_SIZES #ifdef XT_USE_CACHE_DEBUG_SIZES
...@@ -116,6 +117,9 @@ typedef struct XTIndBlock { ...@@ -116,6 +117,9 @@ typedef struct XTIndBlock {
#else #else
xtWord1 cb_data[XT_INDEX_PAGE_SIZE]; xtWord1 cb_data[XT_INDEX_PAGE_SIZE];
#endif #endif
#ifdef CHECK_BLOCK_TRAILERS
xtWord1 cp_check[4];
#endif
} XTIndBlockRec, *XTIndBlockPtr; } XTIndBlockRec, *XTIndBlockPtr;
typedef struct XTIndReference { typedef struct XTIndReference {
...@@ -177,6 +181,10 @@ xtBool xt_ind_copy_on_write(XTIndReferencePtr iref); ...@@ -177,6 +181,10 @@ xtBool xt_ind_copy_on_write(XTIndReferencePtr iref);
XTIndHandlePtr xt_ind_get_handle(struct XTOpenTable *ot, XTIndexPtr ind, XTIndReferencePtr iref); XTIndHandlePtr xt_ind_get_handle(struct XTOpenTable *ot, XTIndexPtr ind, XTIndReferencePtr iref);
void xt_ind_release_handle(XTIndHandlePtr handle, xtBool have_lock, XTThreadPtr thread); void xt_ind_release_handle(XTIndHandlePtr handle, xtBool have_lock, XTThreadPtr thread);
#ifdef CHECK_BLOCK_TRAILERS
extern void check_block_trailers();
#endif
#ifdef DEBUG #ifdef DEBUG
//#define DEBUG_CHECK_IND_CACHE //#define DEBUG_CHECK_IND_CACHE
#endif #endif
......
...@@ -117,6 +117,7 @@ typedef struct XTDatabase : public XTHeap { ...@@ -117,6 +117,7 @@ typedef struct XTDatabase : public XTHeap {
XTSortedListPtr db_table_by_id; XTSortedListPtr db_table_by_id;
XTSortedListPtr db_table_paths; /* A list of table paths used by this database. */ XTSortedListPtr db_table_paths; /* A list of table paths used by this database. */
xtBool db_multi_path; xtBool db_multi_path;
XTSortedListPtr db_error_list; /* A list of errors already reported. */
/* The open table pool: */ /* The open table pool: */
XTAllTablePoolsRec db_ot_pool; XTAllTablePoolsRec db_ot_pool;
......
...@@ -396,7 +396,7 @@ void XTToken::expectNumber(XTThreadPtr self) ...@@ -396,7 +396,7 @@ void XTToken::expectNumber(XTThreadPtr self)
struct charset_info_st; struct charset_info_st;
class XTTokenizer { class XTTokenizer {
struct charset_info_st *tkn_charset; MX_CONST_CHARSET_INFO *tkn_charset;
char *tkn_cstring; char *tkn_cstring;
char *tkn_curr_pos; char *tkn_curr_pos;
XTToken *tkn_current; XTToken *tkn_current;
...@@ -1324,7 +1324,7 @@ void XTParseTable::parseDropIndex(XTThreadPtr self) ...@@ -1324,7 +1324,7 @@ void XTParseTable::parseDropIndex(XTThreadPtr self)
class XTCreateTable : public XTParseTable { class XTCreateTable : public XTParseTable {
public: public:
bool ct_convert; bool ct_convert;
struct charset_info_st *ct_charset; MX_CONST_CHARSET_INFO *ct_charset;
XTPathStrPtr ct_tab_path; XTPathStrPtr ct_tab_path;
u_int ct_contraint_no; u_int ct_contraint_no;
XTDDTable *ct_curr_table; XTDDTable *ct_curr_table;
...@@ -2039,11 +2039,6 @@ void XTDDTableRef::deleteAllRows(XTThreadPtr self) ...@@ -2039,11 +2039,6 @@ void XTDDTableRef::deleteAllRows(XTThreadPtr self)
if (!(ot = xt_db_open_table_using_tab(tr_fkey->co_table->dt_table, self))) if (!(ot = xt_db_open_table_using_tab(tr_fkey->co_table->dt_table, self)))
xt_throw(self); xt_throw(self);
/* {FREE-ROWS-BAD} */
/*
row_count = ((xtInt8) ot->ot_table->tab_row_eof_id) - 1;
row_count -= (xtInt8) ot->ot_table->tab_row_fnum;
*/
/* Check if there are any rows in the referencing table: */ /* Check if there are any rows in the referencing table: */
if (!xt_tab_seq_init(ot)) if (!xt_tab_seq_init(ot))
goto failed; goto failed;
......
...@@ -1249,7 +1249,7 @@ xtBool XTDataLogBuffer::dlb_write_thru_log(xtLogID XT_NDEBUG_UNUSED(log_id), xtL ...@@ -1249,7 +1249,7 @@ xtBool XTDataLogBuffer::dlb_write_thru_log(xtLogID XT_NDEBUG_UNUSED(log_id), xtL
*/ */
dlb_data_log->dlf_log_eof += size; dlb_data_log->dlf_log_eof += size;
#ifdef DEBUG #ifdef DEBUG
if ((ulonglong) (log_offset + size) > (ulonglong) dlb_max_write_offset) if (log_offset + (xtLogOffset) size > (xtLogOffset) dlb_max_write_offset)
dlb_max_write_offset = log_offset + size; dlb_max_write_offset = log_offset + size;
#endif #endif
dlb_flush_required = TRUE; dlb_flush_required = TRUE;
...@@ -1291,7 +1291,7 @@ xtBool XTDataLogBuffer::dlb_append_log(xtLogID XT_NDEBUG_UNUSED(log_id), xtLogOf ...@@ -1291,7 +1291,7 @@ xtBool XTDataLogBuffer::dlb_append_log(xtLogID XT_NDEBUG_UNUSED(log_id), xtLogOf
if (!xt_pwrite_file(dlb_data_log->dlf_log_file, log_offset, size, data, &thread->st_statistics.st_data, thread)) if (!xt_pwrite_file(dlb_data_log->dlf_log_file, log_offset, size, data, &thread->st_statistics.st_data, thread))
return FAILED; return FAILED;
#ifdef DEBUG #ifdef DEBUG
if ((ulonglong) (log_offset + size) > (ulonglong) dlb_max_write_offset) if (log_offset + (xtLogOffset) size > (xtLogOffset) dlb_max_write_offset)
dlb_max_write_offset = log_offset + size; dlb_max_write_offset = log_offset + size;
#endif #endif
dlb_flush_required = TRUE; dlb_flush_required = TRUE;
...@@ -1734,8 +1734,8 @@ static xtBool dl_collect_garbage(XTThreadPtr self, XTDatabaseHPtr db, XTDataLogF ...@@ -1734,8 +1734,8 @@ static xtBool dl_collect_garbage(XTThreadPtr self, XTDatabaseHPtr db, XTDataLogF
xtLogOffset src_log_offset; xtLogOffset src_log_offset;
xtLogID curr_log_id; xtLogID curr_log_id;
xtLogOffset curr_log_offset; xtLogOffset curr_log_offset;
xtLogID dest_log_id= 0; xtLogID dest_log_id = 0;
xtLogOffset dest_log_offset= 0; xtLogOffset dest_log_offset = 0;
off_t garbage_count = 0; off_t garbage_count = 0;
memset(&cs, 0, sizeof(XTCompactorStateRec)); memset(&cs, 0, sizeof(XTCompactorStateRec));
......
...@@ -1622,7 +1622,11 @@ int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char * ...@@ -1622,7 +1622,11 @@ int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char *
COLUMN_FORMAT_TYPE_FIXED, COLUMN_FORMAT_TYPE_FIXED,
#endif #endif
NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/, NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/,
NULL /*interval_list*/, info->field_charset, 0 /*uint_geom_type*/)) NULL /*interval_list*/, info->field_charset, 0 /*uint_geom_type*/
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID > 50200
, NULL /*vcol_info*/, NULL /* create options */
#endif
))
#endif #endif
goto error; goto error;
...@@ -1654,8 +1658,17 @@ int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char * ...@@ -1654,8 +1658,17 @@ int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char *
if (mysql_create_table_no_lock(thd, db, name, &create_info, &table_proto, &stmt->alter_info, 1, 0)) if (mysql_create_table_no_lock(thd, db, name, &create_info, &table_proto, &stmt->alter_info, 1, 0))
goto error; goto error;
#else #else
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *part_info;
part_info = thd->work_part_info;
thd->work_part_info = NULL;
#endif
if (mysql_create_table_no_lock(thd, db, name, &mylex.create_info, &mylex.alter_info, 1, 0)) if (mysql_create_table_no_lock(thd, db, name, &mylex.create_info, &mylex.alter_info, 1, 0))
goto error; goto error;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info = part_info;
#endif
#endif #endif
noerror: noerror:
......
...@@ -1232,6 +1232,11 @@ static int pbxt_init(void *p) ...@@ -1232,6 +1232,11 @@ static int pbxt_init(void *p)
THD *thd = NULL; THD *thd = NULL;
#ifndef DRIZZLED #ifndef DRIZZLED
#if MYSQL_VERSION_ID < 50147
/* A hack which is no longer required after 5.1.46 */
extern myxt_mutex_t LOCK_plugin;
#endif
/* {MYSQL QUIRK} /* {MYSQL QUIRK}
* I have to release this lock for PBXT recovery to * I have to release this lock for PBXT recovery to
* work, because it needs to open .frm files. * work, because it needs to open .frm files.
...@@ -1248,8 +1253,7 @@ static int pbxt_init(void *p) ...@@ -1248,8 +1253,7 @@ static int pbxt_init(void *p)
* Only real problem, 2 threads try to load the same * Only real problem, 2 threads try to load the same
* plugin at the same time. * plugin at the same time.
*/ */
#if MYSQL_VERSION_ID <= 50146 #if MYSQL_VERSION_ID < 50147
extern myxt_mutex_t LOCK_plugin;
myxt_mutex_unlock(&LOCK_plugin); myxt_mutex_unlock(&LOCK_plugin);
#endif #endif
#endif #endif
...@@ -1285,8 +1289,10 @@ static int pbxt_init(void *p) ...@@ -1285,8 +1289,10 @@ static int pbxt_init(void *p)
if (thd) if (thd)
myxt_destroy_thread(thd, FALSE); myxt_destroy_thread(thd, FALSE);
#if MYSQL_VERSION_ID <= 50146 && !defined(DRIZZLED) #ifndef DRIZZLED
#if MYSQL_VERSION_ID < 50147
myxt_mutex_lock(&LOCK_plugin); myxt_mutex_lock(&LOCK_plugin);
#endif
#endif #endif
} }
#endif #endif
...@@ -1948,8 +1954,13 @@ xtPublic int ha_pbxt::reopen() ...@@ -1948,8 +1954,13 @@ xtPublic int ha_pbxt::reopen()
* selectity of the indices, as soon as the number of rows * selectity of the indices, as soon as the number of rows
* exceeds 200 (see [**]) * exceeds 200 (see [**])
*/ */
#ifdef XT_ROW_COUNT_CORRECTED
/* {CORRECTED-ROW-COUNT} */
pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) < 150;
#else
/* {FREE-ROWS-BAD} */ /* {FREE-ROWS-BAD} */
pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) < 150; pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) < 150;
#endif
} }
/* I am not doing this anymore because it was only required /* I am not doing this anymore because it was only required
...@@ -2006,7 +2017,7 @@ static int pbxt_statistics_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) ...@@ -2006,7 +2017,7 @@ static int pbxt_statistics_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
xt_ha_open_database_of_table(self, (XTPathStrPtr) NULL); xt_ha_open_database_of_table(self, (XTPathStrPtr) NULL);
} }
err = myxt_statistics_fill_table(self, thd, tables, cond, system_charset_info); err = myxt_statistics_fill_table(self, thd, tables, cond, (void*) system_charset_info);
} }
catch_(a) { catch_(a) {
err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE);
...@@ -2296,6 +2307,36 @@ void ha_pbxt::internal_close(THD *thd, struct XTThread *self) ...@@ -2296,6 +2307,36 @@ void ha_pbxt::internal_close(THD *thd, struct XTThread *self)
*/ */
if (!thd || thd_sql_command(thd) == SQLCOM_FLUSH) // FLUSH TABLES if (!thd || thd_sql_command(thd) == SQLCOM_FLUSH) // FLUSH TABLES
xt_sync_flush_table(self, ot); xt_sync_flush_table(self, ot);
else {
/* This change is a result of a problem mentioned by Arjen.
* REPAIR and ALTER lead to the following sequence:
* 1. tab -- copy --> tmp1
* 2. tab -- rename --> tmp2
* 3. tmp1 -- rename --> tab
* 4. delete tmp2
*
* PBXT flushes a table before rename.
* In the sequence above results in a table flush in step 3 which can
* take a very long time.
*
* The problem is, during this time frame we have only temp tables.
* A crash in this state leaves the database in a bad state.
*
* To reduce the time in this state, the flush needs to be done
* elsewhere. The code below causes the flish to occur after
* step 1:
*/
switch (thd_sql_command(thd)) {
case SQLCOM_REPAIR:
case SQLCOM_RENAME_TABLE:
case SQLCOM_OPTIMIZE:
case SQLCOM_ANALYZE:
case SQLCOM_ALTER_TABLE:
case SQLCOM_CREATE_INDEX:
xt_sync_flush_table(self, ot);
break;
}
}
} }
freer_(); // xt_db_return_table_to_pool(ot); freer_(); // xt_db_return_table_to_pool(ot);
} }
...@@ -2356,9 +2397,15 @@ int ha_pbxt::open(const char *table_path, int XT_UNUSED(mode), uint XT_UNUSED(te ...@@ -2356,9 +2397,15 @@ int ha_pbxt::open(const char *table_path, int XT_UNUSED(mode), uint XT_UNUSED(te
#else #else
xt_tab_load_row_pointers(self, pb_open_tab); xt_tab_load_row_pointers(self, pb_open_tab);
#endif #endif
xt_ind_set_index_selectivity(pb_open_tab, self); xt_ind_set_index_selectivity(pb_open_tab, self);
#ifdef XT_ROW_COUNT_CORRECTED
/* {CORRECTED-ROW-COUNT} */
pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) < 150;
#else
/* {FREE-ROWS-BAD} */ /* {FREE-ROWS-BAD} */
pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) < 150; pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) < 150;
#endif
} }
init_auto_increment(0); init_auto_increment(0);
...@@ -3929,6 +3976,8 @@ int ha_pbxt::info(uint flag) ...@@ -3929,6 +3976,8 @@ int ha_pbxt::info(uint flag)
if ((ot = pb_open_tab)) { if ((ot = pb_open_tab)) {
if (flag & HA_STATUS_VARIABLE) { if (flag & HA_STATUS_VARIABLE) {
register XTTableHPtr tab = ot->ot_table;
/* {FREE-ROWS-BAD} /* {FREE-ROWS-BAD}
* Free row count is not reliable, so ignore it. * Free row count is not reliable, so ignore it.
* The problem is if tab_row_fnum > tab_row_eof_id - 1 then * The problem is if tab_row_fnum > tab_row_eof_id - 1 then
...@@ -3955,11 +4004,26 @@ int ha_pbxt::info(uint flag) ...@@ -3955,11 +4004,26 @@ int ha_pbxt::info(uint flag)
* the actual number of vectors. But it must assume that it has at * the actual number of vectors. But it must assume that it has at
* least EXTRA_RECORDS vectors. * least EXTRA_RECORDS vectors.
*/ */
stats.deleted = /* ot->ot_table->tab_row_fnum */ 0; #ifdef XT_ROW_COUNT_CORRECTED
stats.records = (ha_rows) (ot->ot_table->tab_row_eof_id - 1 /* - stats.deleted */); if (tab->tab_row_eof_id <= tab->tab_row_fnum ||
stats.data_file_length = xt_rec_id_to_rec_offset(ot->ot_table, ot->ot_table->tab_rec_eof_id); (!tab->tab_row_free_id && tab->tab_row_fnum))
stats.index_file_length = xt_ind_node_to_offset(ot->ot_table, ot->ot_table->tab_ind_eof); xt_tab_check_free_lists(NULL, ot, false, true);
stats.delete_length = ot->ot_table->tab_rec_fnum * ot->ot_rec_size; stats.records = (ha_rows) tab->tab_row_eof_id - 1;
if (stats.records >= tab->tab_row_fnum) {
stats.deleted = tab->tab_row_fnum;
stats.records -= stats.deleted;
}
else {
stats.deleted = 0;
stats.records = 2;
}
#else
stats.deleted = /* tab->tab_row_fnum */ 0;
stats.records = (ha_rows) (tab->tab_row_eof_id - 1 /* - stats.deleted */);
#endif
stats.data_file_length = xt_rec_id_to_rec_offset(tab, tab->tab_rec_eof_id);
stats.index_file_length = xt_ind_node_to_offset(tab, tab->tab_ind_eof);
stats.delete_length = tab->tab_rec_fnum * ot->ot_rec_size;
//check_time = info.check_time; //check_time = info.check_time;
stats.mean_rec_length = (ulong) ot->ot_rec_size; stats.mean_rec_length = (ulong) ot->ot_rec_size;
} }
...@@ -4584,13 +4648,24 @@ xtPublic int ha_pbxt::external_lock(THD *thd, int lock_type) ...@@ -4584,13 +4648,24 @@ xtPublic int ha_pbxt::external_lock(THD *thd, int lock_type)
} }
if (pb_share->sh_recalc_selectivity) { if (pb_share->sh_recalc_selectivity) {
#ifdef XT_ROW_COUNT_CORRECTED
/* {CORRECTED-ROW-COUNT} */
if ((pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) >= 200)
#else
/* {FREE-ROWS-BAD} */ /* {FREE-ROWS-BAD} */
if ((pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) >= 200) { if ((pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) >= 200)
#endif
{
/* [**] */ /* [**] */
pb_share->sh_recalc_selectivity = FALSE; pb_share->sh_recalc_selectivity = FALSE;
xt_ind_set_index_selectivity(pb_open_tab, self); xt_ind_set_index_selectivity(pb_open_tab, self);
#ifdef XT_ROW_COUNT_CORRECTED
/* {CORRECTED-ROW-COUNT} */
pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) < 150;
#else
/* {FREE-ROWS-BAD} */ /* {FREE-ROWS-BAD} */
pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) < 150; pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 /* - pb_share->sh_table->tab_row_fnum */) < 150;
#endif
} }
} }
} }
...@@ -4638,6 +4713,17 @@ xtPublic int ha_pbxt::external_lock(THD *thd, int lock_type) ...@@ -4638,6 +4713,17 @@ xtPublic int ha_pbxt::external_lock(THD *thd, int lock_type)
goto complete; goto complete;
} }
cont_(a); cont_(a);
/* Occurs if you do:
* truncate table t1;
* truncate table t1;
*/
if (!pb_open_tab) {
if ((err = reopen())) {
pb_ex_in_use = 0;
goto complete;
}
}
} }
else { else {
pb_ex_in_use = 1; pb_ex_in_use = 1;
...@@ -6076,6 +6162,40 @@ mysql_declare_plugin(pbxt) ...@@ -6076,6 +6162,40 @@ mysql_declare_plugin(pbxt)
drizzle_declare_plugin_end; drizzle_declare_plugin_end;
#else #else
mysql_declare_plugin_end; mysql_declare_plugin_end;
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID > 50200
maria_declare_plugin(pbxt)
{ /* PBXT */
MYSQL_STORAGE_ENGINE_PLUGIN,
&pbxt_storage_engine,
"PBXT",
"Paul McCullagh, PrimeBase Technologies GmbH",
"High performance, multi-versioning transactional engine",
PLUGIN_LICENSE_GPL,
pbxt_init, /* Plugin Init */
pbxt_end, /* Plugin Deinit */
0x0001 /* 0.1 */,
NULL, /* status variables */
pbxt_system_variables, /* system variables */
"1.0.11-7 Pre-GA", /* string version */
MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */
},
{ /* PBXT_STATISTICS */
MYSQL_INFORMATION_SCHEMA_PLUGIN,
&pbxt_statitics,
"PBXT_STATISTICS",
"Paul McCullagh, PrimeBase Technologies GmbH",
"PBXT internal system statitics",
PLUGIN_LICENSE_GPL,
pbxt_init_statistics, /* plugin init */
pbxt_exit_statistics, /* plugin deinit */
0x0005,
NULL, /* status variables */
NULL, /* system variables */
"1.0.11-7 Pre-GA", /* string version */
MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */
}
maria_declare_plugin_end;
#endif
#endif #endif
#if defined(XT_WIN) && defined(XT_COREDUMP) #if defined(XT_WIN) && defined(XT_COREDUMP)
......
...@@ -272,10 +272,17 @@ static xtBool idx_new_branch(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID *a ...@@ -272,10 +272,17 @@ static xtBool idx_new_branch(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID *a
} }
if ((XT_NODE_ID(wrote_pos) = XT_NODE_ID(tab->tab_ind_free))) { if ((XT_NODE_ID(wrote_pos) = XT_NODE_ID(tab->tab_ind_free))) {
xtIndexNodeID next_node;
/* Use the block on the free list: */ /* Use the block on the free list: */
if (!xt_ind_read_bytes(ot, ind, wrote_pos, sizeof(XTIndFreeBlockRec), (xtWord1 *) &free_block)) if (!xt_ind_read_bytes(ot, NULL, wrote_pos, sizeof(XTIndFreeBlockRec), (xtWord1 *) &free_block))
goto failed;
XT_NODE_ID(next_node) = (xtIndexNodeID) XT_GET_DISK_8(free_block.if_next_block_8);
if (XT_NODE_ID(next_node) >= XT_NODE_ID(tab->tab_ind_eof)) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, tab->tab_name);
goto failed; goto failed;
XT_NODE_ID(tab->tab_ind_free) = (xtIndexNodeID) XT_GET_DISK_8(free_block.if_next_block_8); }
XT_NODE_ID(tab->tab_ind_free) = XT_NODE_ID(next_node);
xt_unlock_mutex_ns(&tab->tab_ind_lock); xt_unlock_mutex_ns(&tab->tab_ind_lock);
*address = wrote_pos; *address = wrote_pos;
TRACK_BLOCK_ALLOC(wrote_pos); TRACK_BLOCK_ALLOC(wrote_pos);
...@@ -1415,6 +1422,11 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt ...@@ -1415,6 +1422,11 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt
if (idx_is_item_deleted(iref.ir_branch, &item->i_pos)) if (idx_is_item_deleted(iref.ir_branch, &item->i_pos))
iref.ir_block->cp_del_count--; iref.ir_block->cp_del_count--;
} }
if (item->i_pos.i_total_size + item_size - item->i_pos.i_item_size <= XT_INDEX_PAGE_DATA_SIZE) {
/* The new item is larger than the old, this can result
* in overflow of the node!
*/
memmove(&iref.ir_branch->tb_data[item->i_pos.i_item_offset + item_size], memmove(&iref.ir_branch->tb_data[item->i_pos.i_item_offset + item_size],
&iref.ir_branch->tb_data[item->i_pos.i_item_offset + item->i_pos.i_item_size], &iref.ir_branch->tb_data[item->i_pos.i_item_offset + item->i_pos.i_item_size],
item->i_pos.i_total_size - item->i_pos.i_item_offset - item->i_pos.i_item_size); item->i_pos.i_total_size - item->i_pos.i_item_offset - item->i_pos.i_item_size);
...@@ -1430,15 +1442,25 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt ...@@ -1430,15 +1442,25 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt
iref.ir_updated = TRUE; iref.ir_updated = TRUE;
#ifdef DEBUG #ifdef DEBUG
if (ind->mi_lazy_delete)
ASSERT_NS(item->i_pos.i_total_size <= XT_INDEX_PAGE_DATA_SIZE); ASSERT_NS(item->i_pos.i_total_size <= XT_INDEX_PAGE_DATA_SIZE);
#endif #endif
if (item->i_pos.i_total_size <= XT_INDEX_PAGE_DATA_SIZE)
return xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref); return xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref);
}
/* The node has overflowed!! */ /* The node has overflowed!! */
result.sr_item = item->i_pos; result.sr_item = item->i_pos;
memcpy(ot->ot_ind_wbuf.tb_data, iref.ir_branch->tb_data, item->i_pos.i_item_offset); // First part of the buffer
memcpy(&ot->ot_ind_wbuf.tb_data[item->i_pos.i_item_offset], item_buf, item_size); // The new item
memcpy(&ot->ot_ind_wbuf.tb_data[item->i_pos.i_item_offset + item_size],
&iref.ir_branch->tb_data[item->i_pos.i_item_offset + item->i_pos.i_item_size],
item->i_pos.i_total_size - item->i_pos.i_item_offset - item->i_pos.i_item_size);
item->i_pos.i_total_size += item_size - item->i_pos.i_item_size;
item->i_pos.i_item_size = item_size;
XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_LEAF_SIZE(item->i_pos.i_total_size));
IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2));
ASSERT_NS(item->i_pos.i_total_size > XT_INDEX_PAGE_DATA_SIZE && item->i_pos.i_total_size <= XT_INDEX_PAGE_DATA_SIZE*2);
/* Adjust the stack (we want the parents of the delete node): */ /* Adjust the stack (we want the parents of the delete node): */
for (;;) { for (;;) {
if (idx_pop(stack) == item) if (idx_pop(stack) == item)
...@@ -1448,7 +1470,7 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt ...@@ -1448,7 +1470,7 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt
/* We assume that value can be overwritten (which is the case) */ /* We assume that value can be overwritten (which is the case) */
key_value.sv_flags = XT_SEARCH_WHOLE_KEY; key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
key_value.sv_key = key_buf; key_value.sv_key = key_buf;
if (!idx_get_middle_branch_item(ot, ind, iref.ir_branch, &key_value, &result)) if (!idx_get_middle_branch_item(ot, ind, &ot->ot_ind_wbuf, &key_value, &result))
goto failed_1; goto failed_1;
if (!idx_new_branch(ot, ind, &new_branch)) if (!idx_new_branch(ot, ind, &new_branch))
...@@ -1456,7 +1478,6 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt ...@@ -1456,7 +1478,6 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt
/* Split the node: */ /* Split the node: */
new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size; new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size;
// TODO: Are 2 buffers now required?
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE]; new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE];
memmove(new_branch_ptr->tb_data, &iref.ir_branch->tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size); memmove(new_branch_ptr->tb_data, &iref.ir_branch->tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size);
...@@ -1466,10 +1487,10 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt ...@@ -1466,10 +1487,10 @@ static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackIt
goto failed_2; goto failed_2;
/* Change the size of the old branch: */ /* Change the size of the old branch: */
XT_SET_DISK_2(iref.ir_branch->tb_size_2, XT_MAKE_NODE_SIZE(result.sr_item.i_item_offset)); XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_NODE_SIZE(result.sr_item.i_item_offset));
IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(iref.ir_branch->tb_size_2)); IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2));
memcpy(iref.ir_branch, &ot->ot_ind_wbuf, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset);
iref.ir_updated = TRUE; iref.ir_updated = TRUE;
xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref); xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref);
/* Insert the new branch into the parent node, using the new middle key value: */ /* Insert the new branch into the parent node, using the new middle key value: */
...@@ -2071,6 +2092,11 @@ xtPublic xtBool xt_idx_insert(XTOpenTablePtr ot, XTIndexPtr ind, xtRowID row_id, ...@@ -2071,6 +2092,11 @@ xtPublic xtBool xt_idx_insert(XTOpenTablePtr ot, XTIndexPtr ind, xtRowID row_id,
if (!idx_new_branch(ot, ind, &new_branch)) if (!idx_new_branch(ot, ind, &new_branch))
goto failed_1; goto failed_1;
if (XT_NODE_ID(current) == XT_NODE_ID(new_branch)) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
goto failed_1;
}
/* Copy and write the rest of the data to the new node: */ /* Copy and write the rest of the data to the new node: */
new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size; new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size;
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE]; new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE];
...@@ -2723,6 +2749,10 @@ xtPublic xtBool xt_idx_search(XTOpenTablePtr ot, XTIndexPtr ind, register XTIdxS ...@@ -2723,6 +2749,10 @@ xtPublic xtBool xt_idx_search(XTOpenTablePtr ot, XTIndexPtr ind, register XTIdxS
#endif #endif
ASSERT_NS(iref.ir_xlock == 2); ASSERT_NS(iref.ir_xlock == 2);
ASSERT_NS(iref.ir_updated == 2); ASSERT_NS(iref.ir_updated == 2);
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
failed: failed:
...@@ -2874,6 +2904,10 @@ xtPublic xtBool xt_idx_search_prev(XTOpenTablePtr ot, XTIndexPtr ind, register X ...@@ -2874,6 +2904,10 @@ xtPublic xtBool xt_idx_search_prev(XTOpenTablePtr ot, XTIndexPtr ind, register X
//idx_check_index(ot, ind, TRUE); //idx_check_index(ot, ind, TRUE);
//idx_check_on_key(ot); //idx_check_on_key(ot);
#endif #endif
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
failed: failed:
...@@ -2964,6 +2998,10 @@ xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind, ...@@ -2964,6 +2998,10 @@ xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind,
if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) { if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) {
XT_INDEX_UNLOCK(ind, ot); XT_INDEX_UNLOCK(ind, ot);
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
} }
...@@ -3071,6 +3109,10 @@ xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind, ...@@ -3071,6 +3109,10 @@ xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind,
ot->ot_curr_rec_id = 0; ot->ot_curr_rec_id = 0;
ot->ot_curr_row_id = 0; ot->ot_curr_row_id = 0;
XT_INDEX_UNLOCK(ind, ot); XT_INDEX_UNLOCK(ind, ot);
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
} }
...@@ -3112,6 +3154,10 @@ xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind, ...@@ -3112,6 +3154,10 @@ xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind,
ot->ot_curr_row_id = result.sr_row_id; ot->ot_curr_row_id = result.sr_row_id;
ot->ot_ind_state = result.sr_item; ot->ot_ind_state = result.sr_item;
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
failed: failed:
...@@ -3178,6 +3224,10 @@ xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind, ...@@ -3178,6 +3224,10 @@ xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind,
if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) { if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) {
XT_INDEX_UNLOCK(ind, ot); XT_INDEX_UNLOCK(ind, ot);
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
} }
...@@ -3274,6 +3324,10 @@ xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind, ...@@ -3274,6 +3324,10 @@ xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind,
ot->ot_curr_row_id = 0; ot->ot_curr_row_id = 0;
XT_INDEX_UNLOCK(ind, ot); XT_INDEX_UNLOCK(ind, ot);
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
unlock_check_on_key: unlock_check_on_key:
...@@ -3302,6 +3356,10 @@ xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind, ...@@ -3302,6 +3356,10 @@ xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind,
ot->ot_curr_rec_id = result.sr_rec_id; ot->ot_curr_rec_id = result.sr_rec_id;
ot->ot_curr_row_id = result.sr_row_id; ot->ot_curr_row_id = result.sr_row_id;
ot->ot_ind_state = result.sr_item; ot->ot_ind_state = result.sr_item;
if (ind->mi_key_corrupted) {
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name);
return FAILED;
}
return OK; return OK;
failed: failed:
...@@ -3648,7 +3706,7 @@ xtPublic void xt_check_indices(XTOpenTablePtr ot) ...@@ -3648,7 +3706,7 @@ xtPublic void xt_check_indices(XTOpenTablePtr ot)
track_block_exists(current); track_block_exists(current);
#endif #endif
printf("%d ", (int) XT_NODE_ID(current)); printf("%d ", (int) XT_NODE_ID(current));
if (!xt_ind_read_bytes(ot, *ind, current, sizeof(XTIndFreeBlockRec), (xtWord1 *) &free_block)) { if (!xt_ind_read_bytes(ot, NULL, current, sizeof(XTIndFreeBlockRec), (xtWord1 *) &free_block)) {
xt_log_and_clear_exception_ns(); xt_log_and_clear_exception_ns();
break; break;
} }
...@@ -4141,11 +4199,18 @@ void XTIndexLogPool::ilp_init(struct XTThread *self, struct XTDatabase *db, size ...@@ -4141,11 +4199,18 @@ void XTIndexLogPool::ilp_init(struct XTThread *self, struct XTDatabase *db, size
if (!ilp_open_log(&il, log_id, FALSE, self)) if (!ilp_open_log(&il, log_id, FALSE, self))
goto failed; goto failed;
if (il->il_tab_id && il->il_log_eof) { if (il->il_tab_id && il->il_log_eof) {
char table_name[XT_IDENTIFIER_NAME_SIZE*3+3];
if (!il->il_open_table(&ot)) if (!il->il_open_table(&ot))
goto failed; goto failed;
if (ot) { if (ot) {
if (!il->il_apply_log(ot)) xt_tab_make_table_name(ot->ot_table, table_name, sizeof(table_name));
goto failed; xt_logf(XT_NT_INFO, "PBXT: Recovering index, table: %s, bytes to read: %llu\n", table_name, (u_llong) il->il_log_eof);
if (!il->il_apply_log(ot)) {
/* If recovery of an index fails, then it is corrupt! */
xt_tab_disable_index(ot->ot_table, XT_INDEX_CORRUPTED);
xt_log_and_clear_exception_ns();
}
ot->ot_thread = self; ot->ot_thread = self;
il->il_close_table(ot); il->il_close_table(ot);
} }
...@@ -4468,8 +4533,7 @@ xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot) ...@@ -4468,8 +4533,7 @@ xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot)
/* Corrupt log?! */ /* Corrupt log?! */
if (il_buffer_len < req_size) { if (il_buffer_len < req_size) {
xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of)); xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of));
xt_log_and_clear_exception_ns(); return FAILED;
return OK;
} }
if (!xt_pread_file(il_of, offset, il_buffer_len, il_buffer_len, il_buffer, NULL, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) if (!xt_pread_file(il_of, offset, il_buffer_len, il_buffer_len, il_buffer, NULL, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread))
return FAILED; return FAILED;
...@@ -4548,8 +4612,7 @@ xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot) ...@@ -4548,8 +4612,7 @@ xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot)
/* Corrupt log?! */ /* Corrupt log?! */
if (il_buffer_len < req_size) { if (il_buffer_len < req_size) {
xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of)); xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of));
xt_log_and_clear_exception_ns(); return FAILED;
return OK;
} }
if (!xt_pread_file(il_of, offset, il_buffer_len, il_buffer_len, il_buffer, NULL, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) if (!xt_pread_file(il_of, offset, il_buffer_len, il_buffer_len, il_buffer, NULL, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread))
return FAILED; return FAILED;
...@@ -4597,8 +4660,7 @@ xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot) ...@@ -4597,8 +4660,7 @@ xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot)
break; break;
default: default:
xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of)); xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of));
xt_log_and_clear_exception_ns(); return FAILED;
return OK;
} }
} }
......
...@@ -312,7 +312,7 @@ typedef struct XTIndex { ...@@ -312,7 +312,7 @@ typedef struct XTIndex {
u_int mi_flags; u_int mi_flags;
u_int mi_key_size; u_int mi_key_size;
u_int mi_max_items; /* The maximum number of items that can fit in a leaf node. */ u_int mi_max_items; /* The maximum number of items that can fit in a leaf node. */
xtBool mi_low_byte_first; xtBool mi_key_corrupted; /* Set to TRUE if a currupted index key is detected. */
xtBool mi_fix_key; xtBool mi_fix_key;
xtBool mi_lazy_delete; /* TRUE if index entries are "lazy deleted". */ xtBool mi_lazy_delete; /* TRUE if index entries are "lazy deleted". */
u_int mi_single_type; /* Used when the index contains a single field. */ u_int mi_single_type; /* Used when the index contains a single field. */
......
...@@ -1088,7 +1088,10 @@ xtPublic u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *key_buf) ...@@ -1088,7 +1088,10 @@ xtPublic u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *key_buf)
} }
end: end:
return (xtWord1 *) key_data - key_buf; u_int ilen = (xtWord1 *) key_data - key_buf;
if (ilen > XT_INDEX_MAX_KEY_SIZE)
ind->mi_key_corrupted = TRUE;
return ilen;
} }
/* Derived from ha_key_cmp */ /* Derived from ha_key_cmp */
...@@ -2183,7 +2186,8 @@ static XTIndexPtr my_create_index(XTThreadPtr self, TABLE *table_arg, u_int idx, ...@@ -2183,7 +2186,8 @@ static XTIndexPtr my_create_index(XTThreadPtr self, TABLE *table_arg, u_int idx,
xt_spinlock_init_with_autoname(self, &ind->mi_dirty_lock); xt_spinlock_init_with_autoname(self, &ind->mi_dirty_lock);
ind->mi_index_no = idx; ind->mi_index_no = idx;
ind->mi_flags = (index->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL | HA_UNIQUE_CHECK)); ind->mi_flags = (index->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL | HA_UNIQUE_CHECK));
ind->mi_low_byte_first = TS(table_arg)->db_low_byte_first; //ind->mi_low_byte_first = TS(table_arg)->db_low_byte_first;
ind->mi_key_corrupted = FALSE;
ind->mi_fix_key = TRUE; ind->mi_fix_key = TRUE;
ind->mi_select_total = 0; ind->mi_select_total = 0;
ind->mi_subset_of = 0; ind->mi_subset_of = 0;
......
...@@ -69,17 +69,17 @@ void myxt_free_dictionary(XTThreadPtr self, XTDictionary *dic); ...@@ -69,17 +69,17 @@ void myxt_free_dictionary(XTThreadPtr self, XTDictionary *dic);
void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic); void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic);
XTDDTable *myxt_create_table_from_table(XTThreadPtr self, STRUCT_TABLE *my_tab); XTDDTable *myxt_create_table_from_table(XTThreadPtr self, STRUCT_TABLE *my_tab);
void myxt_static_convert_identifier(XTThreadPtr self, struct charset_info_st *cs, char *from, char *to, size_t to_len); void myxt_static_convert_identifier(XTThreadPtr self, MX_CONST_CHARSET_INFO *cs, char *from, char *to, size_t to_len);
char *myxt_convert_identifier(XTThreadPtr self, struct charset_info_st *cs, char *from); char *myxt_convert_identifier(XTThreadPtr self, MX_CONST_CHARSET_INFO *cs, char *from);
void myxt_static_convert_table_name(XTThreadPtr self, char *from, char *to, size_t to_len); void myxt_static_convert_table_name(XTThreadPtr self, char *from, char *to, size_t to_len);
void myxt_static_convert_file_name(char *from, char *to, size_t to_len); void myxt_static_convert_file_name(char *from, char *to, size_t to_len);
char *myxt_convert_table_name(XTThreadPtr self, char *from); char *myxt_convert_table_name(XTThreadPtr self, char *from);
int myxt_strcasecmp(char * a, char *b); int myxt_strcasecmp(char * a, char *b);
int myxt_isspace(struct charset_info_st *cs, char a); int myxt_isspace(MX_CONST_CHARSET_INFO *cs, char a);
int myxt_ispunct(struct charset_info_st *cs, char a); int myxt_ispunct(MX_CONST_CHARSET_INFO *cs, char a);
int myxt_isdigit(struct charset_info_st *cs, char a); int myxt_isdigit(MX_CONST_CHARSET_INFO *cs, char a);
struct charset_info_st *myxt_getcharset(bool convert); MX_CONST_CHARSET_INFO *myxt_getcharset(bool convert);
void *myxt_create_thread(); void *myxt_create_thread();
void myxt_destroy_thread(void *thread, xtBool end_threads); void myxt_destroy_thread(void *thread, xtBool end_threads);
......
...@@ -1359,6 +1359,57 @@ static xtBool xres_sync_operations(XTThreadPtr self, XTDatabaseHPtr db, XTWriter ...@@ -1359,6 +1359,57 @@ static xtBool xres_sync_operations(XTThreadPtr self, XTDatabaseHPtr db, XTWriter
return op_synced; return op_synced;
} }
#ifdef XT_CORRECT_TABLE_FREE_COUNT
#define CORRECT_COUNT TRUE
#else
#define CORRECT_COUNT FALSE
#endif
#ifdef XT_CHECK_RECORD_FREE_COUNT
#define CHECK_RECS TRUE
#else
#define CHECK_RECS FALSE
#endif
#if defined(XT_CHECK_RECORD_FREE_COUNT) || defined(XT_CHECK_ROW_FREE_COUNT)
#define RECOVER_FREE_COUNTS
#endif
#ifdef RECOVER_FREE_COUNTS
/* {CORRECTED-ROW-COUNT}
* This error can be repeated by crashing the server during
* high activitity, after flush table writes the table header
*
* On recovery, the free count "from the future" is used as
* the starting point for subsequent allocation and frees.
* The count is wrong after that point.
*
* The recovery of the count only works correctly if a
* checkpoint is complete successfully after that table
* header is flushed. Basically the writing of the table
* header should be synchronsized with the writing of the
* end of the checkpoint.
*
* Another solution would be to log the count, along with
* the allocate and free commannds.
*
* The 3rd solution is the one used here. The count is corrected
* after recovery.
*/
static void xres_recover_table_free_counts(XTThreadPtr self, XTDatabaseHPtr db, XTWriterStatePtr ws)
{
u_int edx;
XTTableEntryPtr te_ptr;
XTTableHPtr tab;
xt_enum_tables_init(&edx);
while ((te_ptr = xt_enum_tables_next(self, db, &edx))) {
if ((tab = te_ptr->te_table)) {
if (xres_open_table(self, ws, te_ptr->te_tab_id))
xt_tab_check_free_lists(self, ws->ws_ot, CHECK_RECS, CORRECT_COUNT);
}
}
}
#endif
/* /*
* Operations from the log are applied in sequence order. * Operations from the log are applied in sequence order.
* If the operations are out of sequence, they are buffered * If the operations are out of sequence, they are buffered
...@@ -2175,6 +2226,13 @@ xtBool XTXactRestart::xres_restart(XTThreadPtr self, xtLogID *log_id, xtLogOffse ...@@ -2175,6 +2226,13 @@ xtBool XTXactRestart::xres_restart(XTThreadPtr self, xtLogID *log_id, xtLogOffse
/* This is true because if no transaction was placed in RAM then /* This is true because if no transaction was placed in RAM then
* the next transaction in RAM will have the next ID: */ * the next transaction in RAM will have the next ID: */
db->db_xn_min_ram_id = db->db_xn_curr_id + 1; db->db_xn_min_ram_id = db->db_xn_curr_id + 1;
#ifdef RECOVER_FREE_COUNTS
if (xres_cp_log_id != *log_id || xres_cp_log_offset != *log_offset) {
/* Recovery took place, correct the row count! */
xres_recover_table_free_counts(self, db, &ws);
}
#endif
} }
failed: failed:
......
...@@ -380,7 +380,7 @@ xtPublic void xt_int8_to_byte_size(xtInt8 value, char *string) ...@@ -380,7 +380,7 @@ xtPublic void xt_int8_to_byte_size(xtInt8 value, char *string)
/* Version number must also be set in configure.in! */ /* Version number must also be set in configure.in! */
xtPublic c_char *xt_get_version(void) xtPublic c_char *xt_get_version(void)
{ {
return "1.0.11 Pre-GA"; return "1.0.11-7 Pre-GA";
} }
/* Copy and URL decode! */ /* Copy and URL decode! */
......
...@@ -78,6 +78,65 @@ ...@@ -78,6 +78,65 @@
#define XT_MAX_TABLE_FILE_NAME_SIZE (XT_TABLE_NAME_SIZE+6+40) #define XT_MAX_TABLE_FILE_NAME_SIZE (XT_TABLE_NAME_SIZE+6+40)
/*
* -----------------------------------------------------------------------
* Handle Error Detected in a Table
*/
struct XTTableError {
xtTableID ter_tab_id;
xtRecordID ter_rec_id;
};
static int tab_comp_tab_error(XTThreadPtr XT_UNUSED(self), register const void *XT_UNUSED(thunk), register const void *a, register const void *b)
{
XTTableError *ter_a = ((XTTableError *) a);
XTTableError *ter_b = (XTTableError *) b;
if (ter_a->ter_tab_id < ter_b->ter_tab_id)
return -1;
if (ter_a->ter_tab_id == ter_b->ter_tab_id) {
if (ter_a->ter_rec_id < ter_b->ter_rec_id)
return -1;
if (ter_a->ter_rec_id == ter_b->ter_rec_id)
return 0;
return 1;
}
return 1;
}
static xtBool tab_record_corrupt(XTOpenTablePtr ot, xtRowID row_id, xtRecordID rec_id, bool not_valid, int where)
{
XTTableHPtr tab = ot->ot_table;
XTDatabaseHPtr db = tab->tab_db;
XTTableError ter;
XTTableError *ter_ptr;
ter.ter_tab_id = tab->tab_id;
ter.ter_rec_id = rec_id;
xt_sl_lock_ns(db->db_error_list, ot->ot_thread);
if (!(ter_ptr = (XTTableError *) xt_sl_find(NULL, db->db_error_list, &ter))) {
xtBool ok;
char table_name[XT_IDENTIFIER_NAME_SIZE*3+3];
ok = xt_sl_insert(NULL, db->db_error_list, &ter, &ter);
xt_sl_unlock_ns(db->db_error_list);
if (!ok)
return FAILED;
xt_tab_set_table_repair_pending(tab);
xt_tab_make_table_name(tab, table_name, sizeof(table_name));
xt_logf(XT_NT_ERROR, "#%d Table %s: row %llu, record %llu, is %s, REPAIR TABLE required.\n", where,
table_name,
(u_llong) row_id,
(u_llong) rec_id,
not_valid ? "not valid" : "free");
}
else
xt_sl_unlock_ns(db->db_error_list);
return OK;
}
/* /*
* ----------------------------------------------------------------------- * -----------------------------------------------------------------------
* Compare paths: * Compare paths:
...@@ -425,6 +484,7 @@ xtPublic void xt_tab_init_db(XTThreadPtr self, XTDatabaseHPtr db) ...@@ -425,6 +484,7 @@ xtPublic void xt_tab_init_db(XTThreadPtr self, XTDatabaseHPtr db)
db->db_tables = xt_new_hashtable(self, tab_list_comp, tab_list_hash, tab_list_free, TRUE, TRUE); db->db_tables = xt_new_hashtable(self, tab_list_comp, tab_list_hash, tab_list_free, TRUE, TRUE);
db->db_table_by_id = xt_new_sortedlist(self, sizeof(XTTableEntryRec), 20, 20, tab_comp_by_id, db, tab_free_by_id, FALSE, FALSE); db->db_table_by_id = xt_new_sortedlist(self, sizeof(XTTableEntryRec), 20, 20, tab_comp_by_id, db, tab_free_by_id, FALSE, FALSE);
db->db_table_paths = xt_new_sortedlist(self, sizeof(XTTablePathPtr), 20, 20, tab_comp_path, db, tab_free_path, FALSE, FALSE); db->db_table_paths = xt_new_sortedlist(self, sizeof(XTTablePathPtr), 20, 20, tab_comp_path, db, tab_free_path, FALSE, FALSE);
db->db_error_list = xt_new_sortedlist(self, sizeof(XTTableError), 20, 20, tab_comp_tab_error, db, NULL, TRUE, FALSE);
if (db->db_multi_path) { if (db->db_multi_path) {
XTOpenFilePtr of; XTOpenFilePtr of;
...@@ -649,6 +709,10 @@ xtPublic void xt_tab_exit_db(XTThreadPtr self, XTDatabaseHPtr db) ...@@ -649,6 +709,10 @@ xtPublic void xt_tab_exit_db(XTThreadPtr self, XTDatabaseHPtr db)
xt_free_sortedlist(self, db->db_table_paths); xt_free_sortedlist(self, db->db_table_paths);
db->db_table_paths = NULL; db->db_table_paths = NULL;
} }
if (db->db_error_list) {
xt_free_sortedlist(self, db->db_error_list);
db->db_error_list = NULL;
}
} }
static void tab_check_table(XTThreadPtr self, XTTableHPtr XT_UNUSED(tab)) static void tab_check_table(XTThreadPtr self, XTTableHPtr XT_UNUSED(tab))
...@@ -1713,6 +1777,116 @@ xtPublic void xt_drop_table(XTThreadPtr self, XTPathStrPtr tab_name, xtBool drop ...@@ -1713,6 +1777,116 @@ xtPublic void xt_drop_table(XTThreadPtr self, XTPathStrPtr tab_name, xtBool drop
exit_(); exit_();
} }
xtPublic void xt_tab_check_free_lists(XTThreadPtr self, XTOpenTablePtr ot, bool check_recs, bool correct_count)
{
char table_name[XT_IDENTIFIER_NAME_SIZE*3+3];
register XTTableHPtr tab = ot->ot_table;
xtRowID prev_row_id;
xtRowID row_id;
xtRefID next_row_id;
u_llong free_count;
xt_tab_make_table_name(tab, table_name, sizeof(table_name));
if (check_recs) {
xtRecordID prev_rec_id;
xtRecordID rec_id;
XTTabRecExtDRec rec_buf;
xt_lock_mutex_ns(&tab->tab_rec_lock);
/* Checking the free list: */
prev_rec_id = 0;
free_count = 0;
rec_id = tab->tab_rec_free_id;
while (rec_id) {
if (rec_id >= tab->tab_rec_eof_id) {
xt_logf(XT_NT_ERROR, "Table %s: invalid reference on free list: %llu, ", table_name, (u_llong) rec_id);
if (prev_rec_id)
xt_logf(XT_NT_ERROR, "reference by: %llu\n", (u_llong) prev_rec_id);
else
xt_logf(XT_NT_ERROR, "reference by list head pointer\n");
xt_tab_set_table_repair_pending(tab);
break;
}
if (!xt_tab_get_rec_data(ot, rec_id, XT_REC_FIX_HEADER_SIZE, (xtWord1 *) &rec_buf)) {
if (self)
xt_throw(self);
else
xt_log_and_clear_warning(ot->ot_thread);
break;
}
if ((rec_buf.tr_rec_type_1 & XT_TAB_STATUS_MASK) != XT_TAB_STATUS_FREED)
xt_logf(XT_NT_INFO, "Table %s: record, %llu, on free list is not free\n", table_name, (u_llong) rec_id);
free_count++;
prev_rec_id = rec_id;
rec_id = XT_GET_DISK_4(rec_buf.tr_prev_rec_id_4);
}
if (free_count != tab->tab_rec_fnum) {
if (correct_count) {
tab->tab_rec_fnum = free_count;
tab->tab_head_rec_fnum = free_count;
tab->tab_flush_pending = TRUE;
xt_logf(XT_NT_INFO, "Table %s: free record count (%llu) has been set to the number of records on the list: %llu\n", table_name, (u_llong) tab->tab_rec_fnum, (u_llong) free_count);
}
else
xt_logf(XT_NT_INFO, "Table %s: free record count (%llu) differs from the number of records on the list: %llu\n", table_name, (u_llong) tab->tab_rec_fnum, (u_llong) free_count);
}
xt_unlock_mutex_ns(&tab->tab_rec_lock);
}
/* Check the row free list: */
xt_lock_mutex_ns(&tab->tab_row_lock);
prev_row_id = 0;
free_count = 0;
row_id = tab->tab_row_free_id;
while (row_id) {
if (row_id >= tab->tab_row_eof_id) {
xt_logf(XT_NT_ERROR, "Table %s: invalid reference on free row: %llu, ", table_name, (u_llong) row_id);
if (prev_row_id)
xt_logf(XT_NT_ERROR, "reference by: %llu\n", (u_llong) prev_row_id);
else
xt_logf(XT_NT_ERROR, "reference by list head pointer\n");
xt_tab_set_table_repair_pending(tab);
break;
}
if (!tab->tab_rows.xt_tc_read_4(ot->ot_row_file, row_id, &next_row_id, ot->ot_thread)) {
if (self)
xt_throw(self);
else
xt_log_and_clear_warning(ot->ot_thread);
break;
}
free_count++;
prev_row_id = row_id;
row_id = next_row_id;
}
if (free_count != tab->tab_row_fnum) {
if (correct_count) {
/* tab_row_fnum is the current value, and tab_head_row_fnum is the value on
* disk. tab_head_row_fnum is set by the writer as the changes are applied
* to the database.
*
* This is the value then stored in the header of the file. This value
* is in sync with other changes to the file.
*
* So the fact that I am setting both value means this will not work at
* runtime, unless all changes have been applied by the writer.
*
* The correct way to do this at run time would be to add the change to the
* transaction log, so that it is applied by the writer.
*/
tab->tab_row_fnum = free_count;
tab->tab_head_row_fnum = free_count;
tab->tab_flush_pending = TRUE;
xt_logf(XT_NT_INFO, "Table %s: free row count (%llu) has been set to the number of rows on the list: %llu\n", table_name, (u_llong) tab->tab_row_fnum, (u_llong) free_count);
}
else
xt_logf(XT_NT_INFO, "Table %s: free row count (%llu) differs from the number of rows on the list: %llu\n", table_name, (u_llong) tab->tab_row_fnum, (u_llong) free_count);
}
xt_unlock_mutex_ns(&tab->tab_row_lock);
}
/* /*
* Record buffer size: * Record buffer size:
* ------------------- * -------------------
...@@ -2010,7 +2184,7 @@ xtPublic void xt_check_table(XTThreadPtr self, XTOpenTablePtr ot) ...@@ -2010,7 +2184,7 @@ xtPublic void xt_check_table(XTThreadPtr self, XTOpenTablePtr ot)
prec_id = rec_id; prec_id = rec_id;
rec_id = XT_GET_DISK_4(rec_buf->tr_prev_rec_id_4); rec_id = XT_GET_DISK_4(rec_buf->tr_prev_rec_id_4);
} }
if (free_count2 < free_rec_count) if (free_count2 != free_rec_count)
xt_logf(XT_INFO, "Table %s: not all free blocks (%llu) on free list: %llu\n", tab->tab_name, (u_llong) free_rec_count, (u_llong) free_count2); xt_logf(XT_INFO, "Table %s: not all free blocks (%llu) on free list: %llu\n", tab->tab_name, (u_llong) free_rec_count, (u_llong) free_count2);
freer_(); // xt_unlock_mutex_ns(&tab->tab_rec_lock); freer_(); // xt_unlock_mutex_ns(&tab->tab_rec_lock);
...@@ -2042,6 +2216,29 @@ xtPublic void xt_check_table(XTThreadPtr self, XTOpenTablePtr ot) ...@@ -2042,6 +2216,29 @@ xtPublic void xt_check_table(XTThreadPtr self, XTOpenTablePtr ot)
rec_id++; rec_id++;
} }
prec_id = 0;
free_count2 = 0;
row_id = tab->tab_row_free_id;
while (row_id) {
if (row_id >= tab->tab_row_eof_id) {
xt_logf(XT_INFO, "Table %s: invalid reference on free row: %llu, ", tab->tab_name, (u_llong) row_id);
if (prec_id)
xt_logf(XT_INFO, "reference by: %llu\n", (u_llong) prec_id);
else
xt_logf(XT_INFO, "reference by list head pointer\n");
break;
}
if (!tab->tab_rows.xt_tc_read_4(ot->ot_row_file, row_id, &ref_id, self)) {
xt_log_and_clear_exception(self);
break;
}
free_count2++;
prec_id = row_id;
row_id = ref_id;
}
if (free_count2 != tab->tab_row_fnum)
xt_logf(XT_INFO, "Table %s: free row count (%llu) differs from the number of row on the list: %llu\n", tab->tab_name, (u_llong) tab->tab_row_fnum, (u_llong) free_count2);
freer_(); // xt_unlock_mutex(&tab->tab_row_lock); freer_(); // xt_unlock_mutex(&tab->tab_row_lock);
#ifdef CHECK_INDEX_ON_CHECK_TABLE #ifdef CHECK_INDEX_ON_CHECK_TABLE
...@@ -3117,10 +3314,18 @@ static int tab_visible(register XTOpenTablePtr ot, XTTabRecHeadDPtr rec_head, xt ...@@ -3117,10 +3314,18 @@ static int tab_visible(register XTOpenTablePtr ot, XTTabRecHeadDPtr rec_head, xt
#endif #endif
break; break;
case XT_XN_REREAD: case XT_XN_REREAD:
/* {RETRY-READ}
* TODO: This is not as "correct" as it could be.
* Such records should be considered to be aborted,
* and removed from the list.
*/
if (invalid_rec != var_rec_id) { if (invalid_rec != var_rec_id) {
invalid_rec = var_rec_id; invalid_rec = var_rec_id;
goto retry_3; goto retry_3;
} }
if (!tab_record_corrupt(ot, row_id, var_rec_id, true, 1))
goto failed;
/* Assume end of list. */ /* Assume end of list. */
#ifdef XT_CRASH_DEBUG #ifdef XT_CRASH_DEBUG
/* Should not happen! */ /* Should not happen! */
...@@ -3308,6 +3513,8 @@ xtPublic int xt_tab_visible(XTOpenTablePtr ot) ...@@ -3308,6 +3513,8 @@ xtPublic int xt_tab_visible(XTOpenTablePtr ot)
/* Avoid infinite loop: */ /* Avoid infinite loop: */
if (read_again) { if (read_again) {
/* Should not happen! */ /* Should not happen! */
if (!tab_record_corrupt(ot, row_id, ot->ot_curr_rec_id, true, 2))
return XT_ERR;
#ifdef XT_CRASH_DEBUG #ifdef XT_CRASH_DEBUG
/* Generate a core dump! */ /* Generate a core dump! */
xt_crash_me(); xt_crash_me();
...@@ -3364,6 +3571,8 @@ xtPublic int xt_tab_read_record(register XTOpenTablePtr ot, xtWord1 *buffer) ...@@ -3364,6 +3571,8 @@ xtPublic int xt_tab_read_record(register XTOpenTablePtr ot, xtWord1 *buffer)
/* Avoid infinite loop: */ /* Avoid infinite loop: */
if (read_again) { if (read_again) {
/* Should not happen! */ /* Should not happen! */
if (!tab_record_corrupt(ot, XT_GET_DISK_4(((XTTabRecHeadDPtr) ot->ot_row_rbuffer)->tr_row_id_4), ot->ot_curr_rec_id, true, 3))
return XT_ERR;
#ifdef XT_CRASH_DEBUG #ifdef XT_CRASH_DEBUG
/* Generate a core dump! */ /* Generate a core dump! */
xt_crash_me(); xt_crash_me();
...@@ -3580,6 +3789,7 @@ xtPublic xtBool xt_tab_free_row(XTOpenTablePtr ot, XTTableHPtr tab, xtRowID row_ ...@@ -3580,6 +3789,7 @@ xtPublic xtBool xt_tab_free_row(XTOpenTablePtr ot, XTTableHPtr tab, xtRowID row_
} }
tab->tab_row_free_id = row_id; tab->tab_row_free_id = row_id;
tab->tab_row_fnum++; tab->tab_row_fnum++;
ASSERT_NS(tab->tab_row_fnum < tab->tab_row_eof_id);
xt_unlock_mutex_ns(&tab->tab_row_lock); xt_unlock_mutex_ns(&tab->tab_row_lock);
if (!xt_xlog_modify_table(tab->tab_id, XT_LOG_ENT_ROW_FREED, op_seq, 0, row_id, sizeof(XTTabRowRefDRec), (xtWord1 *) &free_row, ot->ot_thread)) if (!xt_xlog_modify_table(tab->tab_id, XT_LOG_ENT_ROW_FREED, op_seq, 0, row_id, sizeof(XTTabRowRefDRec), (xtWord1 *) &free_row, ot->ot_thread))
...@@ -3776,7 +3986,7 @@ xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 ...@@ -3776,7 +3986,7 @@ xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1
xt_lock_mutex_ns(&tab->tab_db->db_co_ext_lock); xt_lock_mutex_ns(&tab->tab_db->db_co_ext_lock);
if (!xt_tab_get_rec_data(ot, rec_id, XT_REC_EXT_HEADER_SIZE, ot->ot_row_rbuffer)) { if (!xt_tab_get_rec_data(ot, rec_id, XT_REC_EXT_HEADER_SIZE, ot->ot_row_rbuffer)) {
xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock); xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock);
return FAILED; return XT_ERR;
} }
xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock); xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock);
...@@ -3824,7 +4034,7 @@ xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 ...@@ -3824,7 +4034,7 @@ xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1
XT_SET_DISK_4(free_rec->rf_next_rec_id_4, prev_rec_id); XT_SET_DISK_4(free_rec->rf_next_rec_id_4, prev_rec_id);
if (!xt_tab_put_rec_data(ot, rec_id, sizeof(XTTabRecFreeDRec), ot->ot_row_rbuffer, &op_seq)) { if (!xt_tab_put_rec_data(ot, rec_id, sizeof(XTTabRecFreeDRec), ot->ot_row_rbuffer, &op_seq)) {
xt_unlock_mutex_ns(&tab->tab_rec_lock); xt_unlock_mutex_ns(&tab->tab_rec_lock);
return FAILED; return XT_ERR;
} }
tab->tab_rec_free_id = rec_id; tab->tab_rec_free_id = rec_id;
ASSERT_NS(tab->tab_rec_free_id < tab->tab_rec_eof_id); ASSERT_NS(tab->tab_rec_free_id < tab->tab_rec_eof_id);
...@@ -3832,7 +4042,9 @@ xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 ...@@ -3832,7 +4042,9 @@ xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1
xt_unlock_mutex_ns(&tab->tab_rec_lock); xt_unlock_mutex_ns(&tab->tab_rec_lock);
free_rec->rf_rec_type_1 = old_rec_type; free_rec->rf_rec_type_1 = old_rec_type;
return xt_xlog_modify_table(tab->tab_id, XT_LOG_ENT_REC_REMOVED_BI, op_seq, (xtRecordID) new_rec_type, rec_id, rec_size, ot->ot_row_rbuffer, ot->ot_thread); if (!xt_xlog_modify_table(tab->tab_id, XT_LOG_ENT_REC_REMOVED_BI, op_seq, (xtRecordID) new_rec_type, rec_id, rec_size, ot->ot_row_rbuffer, ot->ot_thread))
return XT_ERR;
return OK;
} }
static xtRowID tab_new_row(XTOpenTablePtr ot, XTTableHPtr tab) static xtRowID tab_new_row(XTOpenTablePtr ot, XTTableHPtr tab)
...@@ -3851,6 +4063,7 @@ static xtRowID tab_new_row(XTOpenTablePtr ot, XTTableHPtr tab) ...@@ -3851,6 +4063,7 @@ static xtRowID tab_new_row(XTOpenTablePtr ot, XTTableHPtr tab)
return 0; return 0;
} }
tab->tab_row_free_id = next_row_id; tab->tab_row_free_id = next_row_id;
ASSERT_NS(tab->tab_row_fnum > 0);
tab->tab_row_fnum--; tab->tab_row_fnum--;
} }
else { else {
...@@ -4170,9 +4383,12 @@ static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordI ...@@ -4170,9 +4383,12 @@ static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordI
return FAILED; return FAILED;
if (XT_REC_IS_CLEAN(var_head.tr_rec_type_1)) if (XT_REC_IS_CLEAN(var_head.tr_rec_type_1))
goto locked; goto locked;
if (XT_REC_IS_FREE(var_head.tr_rec_type_1)) if (XT_REC_IS_FREE(var_head.tr_rec_type_1)) {
/* Should not happen: */ /* Should not happen: */
if (!tab_record_corrupt(ot, row_id, var_rec_id, false, 4))
return FAILED;
goto record_invalid; goto record_invalid;
}
xn_id = XT_GET_DISK_4(var_head.tr_xact_id_4); xn_id = XT_GET_DISK_4(var_head.tr_xact_id_4);
switch (xt_xn_status(ot, xn_id, var_rec_id)) { switch (xt_xn_status(ot, xn_id, var_rec_id)) {
case XT_XN_VISIBLE: case XT_XN_VISIBLE:
...@@ -4195,6 +4411,8 @@ static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordI ...@@ -4195,6 +4411,8 @@ static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordI
XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread);
goto retry; goto retry;
case XT_XN_REREAD: case XT_XN_REREAD:
if (!tab_record_corrupt(ot, row_id, var_rec_id, true, 5))
return FAILED;
goto record_invalid; goto record_invalid;
} }
var_rec_id = XT_GET_DISK_4(var_head.tr_prev_rec_id_4); var_rec_id = XT_GET_DISK_4(var_head.tr_prev_rec_id_4);
...@@ -4206,9 +4424,10 @@ static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordI ...@@ -4206,9 +4424,10 @@ static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordI
return FAILED; return FAILED;
record_invalid: record_invalid:
/* {RETRY-READ} */
/* Prevent an infinite loop due to a bad record: */ /* Prevent an infinite loop due to a bad record: */
if (invalid_rec != var_rec_id) { if (invalid_rec != var_rec_id) {
var_rec_id = invalid_rec; invalid_rec = var_rec_id;
goto retry; goto retry;
} }
/* The record is invalid, it will be "overwritten"... */ /* The record is invalid, it will be "overwritten"... */
...@@ -4280,9 +4499,12 @@ xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXact ...@@ -4280,9 +4499,12 @@ xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXact
#ifdef TRACE_VARIATIONS_IN_DUP_CHECK #ifdef TRACE_VARIATIONS_IN_DUP_CHECK
t_type="Re-read"; t_type="Re-read";
#endif #endif
/* {RETRY-READ} */
/* Avoid infinite loop: */ /* Avoid infinite loop: */
if (invalid_rec == rec_id) { if (invalid_rec == rec_id) {
/* Should not happen! */ /* Should not happen! */
if (!tab_record_corrupt(ot, XT_GET_DISK_4(rec_head.tr_row_id_4), rec_id, true, 6))
goto failed;
#ifdef XT_CRASH_DEBUG #ifdef XT_CRASH_DEBUG
/* Generate a core dump! */ /* Generate a core dump! */
xt_crash_me(); xt_crash_me();
...@@ -4327,7 +4549,7 @@ xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXact ...@@ -4327,7 +4549,7 @@ xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXact
if (XT_REC_IS_FREE(rec_head.tr_rec_type_1)) { if (XT_REC_IS_FREE(rec_head.tr_rec_type_1)) {
/* Should not happen: */ /* Should not happen: */
if (invalid_rec != var_rec_id) { if (invalid_rec != var_rec_id) {
var_rec_id = invalid_rec; invalid_rec = var_rec_id;
goto retry; goto retry;
} }
/* Assume end of list. */ /* Assume end of list. */
...@@ -4364,11 +4586,14 @@ xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXact ...@@ -4364,11 +4586,14 @@ xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXact
} }
break; break;
case XT_XN_REREAD: case XT_XN_REREAD:
/* {RETRY-READ} */
if (invalid_rec != var_rec_id) { if (invalid_rec != var_rec_id) {
var_rec_id = invalid_rec; invalid_rec = var_rec_id;
goto retry; goto retry;
} }
/* Assume end of list. */ /* Assume end of list. */
if (!tab_record_corrupt(ot, row_id, invalid_rec, true, 7))
goto failed;
#ifdef XT_CRASH_DEBUG #ifdef XT_CRASH_DEBUG
/* Should not happen! */ /* Should not happen! */
xt_crash_me(); xt_crash_me();
...@@ -5068,6 +5293,8 @@ xtPublic xtBool xt_tab_seq_next(XTOpenTablePtr ot, xtWord1 *buffer, xtBool *eof) ...@@ -5068,6 +5293,8 @@ xtPublic xtBool xt_tab_seq_next(XTOpenTablePtr ot, xtWord1 *buffer, xtBool *eof)
ot->ot_on_page = FALSE; ot->ot_on_page = FALSE;
goto next_page; goto next_page;
} }
if (!tab_record_corrupt(ot, XT_GET_DISK_4(((XTTabRecHeadDPtr) buff_ptr)->tr_row_id_4), invalid_rec, true, 8))
return XT_ERR;
#ifdef XT_CRASH_DEBUG #ifdef XT_CRASH_DEBUG
/* Should not happen! */ /* Should not happen! */
xt_crash_me(); xt_crash_me();
...@@ -5240,7 +5467,7 @@ static xtBool tab_exec_repair_pending(XTDatabaseHPtr db, int what, char *table_n ...@@ -5240,7 +5467,7 @@ static xtBool tab_exec_repair_pending(XTDatabaseHPtr db, int what, char *table_n
return FALSE; return FALSE;
} }
static void tab_make_table_name(XTTableHPtr tab, char *table_name, size_t size) xtPublic void xt_tab_make_table_name(XTTableHPtr tab, char *table_name, size_t size)
{ {
char *nptr; char *nptr;
...@@ -5316,7 +5543,7 @@ xtPublic xtBool xt_tab_is_table_repair_pending(XTTableHPtr tab) ...@@ -5316,7 +5543,7 @@ xtPublic xtBool xt_tab_is_table_repair_pending(XTTableHPtr tab)
{ {
char table_name[XT_IDENTIFIER_NAME_SIZE*3+3]; char table_name[XT_IDENTIFIER_NAME_SIZE*3+3];
tab_make_table_name(tab, table_name, sizeof(table_name)); xt_tab_make_table_name(tab, table_name, sizeof(table_name));
return tab_exec_repair_pending(tab->tab_db, REP_FIND, table_name); return tab_exec_repair_pending(tab->tab_db, REP_FIND, table_name);
} }
...@@ -5326,7 +5553,7 @@ xtPublic void xt_tab_table_repaired(XTTableHPtr tab) ...@@ -5326,7 +5553,7 @@ xtPublic void xt_tab_table_repaired(XTTableHPtr tab)
char table_name[XT_IDENTIFIER_NAME_SIZE*3+3]; char table_name[XT_IDENTIFIER_NAME_SIZE*3+3];
tab->tab_repair_pending = FALSE; tab->tab_repair_pending = FALSE;
tab_make_table_name(tab, table_name, sizeof(table_name)); xt_tab_make_table_name(tab, table_name, sizeof(table_name));
tab_exec_repair_pending(tab->tab_db, REP_DEL, table_name); tab_exec_repair_pending(tab->tab_db, REP_DEL, table_name);
} }
} }
...@@ -5337,7 +5564,7 @@ xtPublic void xt_tab_set_table_repair_pending(XTTableHPtr tab) ...@@ -5337,7 +5564,7 @@ xtPublic void xt_tab_set_table_repair_pending(XTTableHPtr tab)
char table_name[XT_IDENTIFIER_NAME_SIZE*3+3]; char table_name[XT_IDENTIFIER_NAME_SIZE*3+3];
tab->tab_repair_pending = TRUE; tab->tab_repair_pending = TRUE;
tab_make_table_name(tab, table_name, sizeof(table_name)); xt_tab_make_table_name(tab, table_name, sizeof(table_name));
tab_exec_repair_pending(tab->tab_db, REP_ADD, table_name); tab_exec_repair_pending(tab->tab_db, REP_ADD, table_name);
} }
} }
...@@ -507,6 +507,7 @@ int xt_tab_compare_names(const char *n1, const char *n2); ...@@ -507,6 +507,7 @@ int xt_tab_compare_names(const char *n1, const char *n2);
int xt_tab_compare_paths(char *n1, char *n2); int xt_tab_compare_paths(char *n1, char *n2);
void xt_tab_init_db(struct XTThread *self, struct XTDatabase *db); void xt_tab_init_db(struct XTThread *self, struct XTDatabase *db);
void xt_tab_exit_db(struct XTThread *self, struct XTDatabase *db); void xt_tab_exit_db(struct XTThread *self, struct XTDatabase *db);
void xt_tab_check_free_lists(struct XTThread *self, XTOpenTablePtr ot, bool check_recs, bool correct_count);
void xt_check_tables(struct XTThread *self); void xt_check_tables(struct XTThread *self);
char *xt_tab_file_to_name(size_t size, char *tab_name, char *file_name); char *xt_tab_file_to_name(size_t size, char *tab_name, char *file_name);
...@@ -572,6 +573,7 @@ xtBool xt_tab_get_rec_data(register XTOpenTablePtr ot, xtRecordID rec_id, siz ...@@ -572,6 +573,7 @@ xtBool xt_tab_get_rec_data(register XTOpenTablePtr ot, xtRecordID rec_id, siz
void xt_tab_disable_index(XTTableHPtr tab, u_int ind_error); void xt_tab_disable_index(XTTableHPtr tab, u_int ind_error);
void xt_tab_set_index_error(XTTableHPtr tab); void xt_tab_set_index_error(XTTableHPtr tab);
void xt_tab_make_table_name(XTTableHPtr tab, char *table_name, size_t size);
xtBool xt_tab_is_table_repair_pending(XTTableHPtr tab); xtBool xt_tab_is_table_repair_pending(XTTableHPtr tab);
void xt_tab_table_repaired(XTTableHPtr tab); void xt_tab_table_repaired(XTTableHPtr tab);
void xt_tab_set_table_repair_pending(XTTableHPtr tab); void xt_tab_set_table_repair_pending(XTTableHPtr tab);
......
...@@ -224,12 +224,17 @@ static void thr_log_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, ...@@ -224,12 +224,17 @@ static void thr_log_va(XTThreadPtr self, c_char *func, c_char *file, u_int line,
#else #else
/* Use the buffer, unless it is too small */ /* Use the buffer, unless it is too small */
va_list ap2; va_list ap2;
int bufsize;
va_copy(ap2, ap); va_copy(ap2, ap);
if (vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE, fmt, ap) >= DEFAULT_LOG_BUFFER_SIZE) { bufsize = vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE, fmt, ap);
if (vasprintf(&log_string, fmt, ap2) == -1) if (bufsize >= DEFAULT_LOG_BUFFER_SIZE) {
log_string = (char *) malloc(bufsize + 1);
if (vsnprintf(log_string, bufsize + 1, fmt, ap2) > bufsize) {
free(log_string);
log_string = NULL; log_string = NULL;
} }
}
else else
log_string = buffer; log_string = buffer;
#endif #endif
......
...@@ -1558,6 +1558,8 @@ xtPublic int xt_xn_status(XTOpenTablePtr ot, xtXactID xn_id, xtRecordID XT_UNUSE ...@@ -1558,6 +1558,8 @@ xtPublic int xt_xn_status(XTOpenTablePtr ot, xtXactID xn_id, xtRecordID XT_UNUSE
* Because we are only here because the record was valid but not * Because we are only here because the record was valid but not
* clean (you can confirm this by looking at the code that * clean (you can confirm this by looking at the code that
* calls this function). * calls this function).
*
* See {RETRY-READ}
*/ */
return XT_XN_REREAD; return XT_XN_REREAD;
} }
...@@ -1743,7 +1745,7 @@ xtPublic xtWord8 xt_xn_bytes_to_sweep(XTDatabaseHPtr db, XTThreadPtr thread) ...@@ -1743,7 +1745,7 @@ xtPublic xtWord8 xt_xn_bytes_to_sweep(XTDatabaseHPtr db, XTThreadPtr thread)
} }
else { else {
xn_log_id = x_log_id; xn_log_id = x_log_id;
x_log_offset = x_log_offset; xn_log_offset = x_log_offset;
} }
} }
xn_id++; xn_id++;
......
...@@ -397,6 +397,24 @@ typedef struct XTPathStr { ...@@ -397,6 +397,24 @@ typedef struct XTPathStr {
*/ */
#define XT_XLOG_FLUSH_FREQ 1000 #define XT_XLOG_FLUSH_FREQ 1000
/*
* Define here if you want to check (and correct) the table free list
* counts. The free list counts are not durable, because they are not
* written to the log.
*
* The row free count is most critical because it can be used to
* estimate the the of rows in the record.
*/
#define XT_CHECK_ROW_FREE_COUNT
#ifdef DEBUG
#define XT_CHECK_RECORD_FREE_COUNT
#endif
#define XT_CORRECT_TABLE_FREE_COUNT
#if defined(XT_CHECK_ROW_FREE_COUNT) && defined(XT_CORRECT_TABLE_FREE_COUNT)
#define XT_ROW_COUNT_CORRECTED
#endif
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* GLOBAL CONSTANTS * GLOBAL CONSTANTS
*/ */
...@@ -873,7 +891,11 @@ extern "C" void session_mark_transaction_to_rollback(Session *session, bool all) ...@@ -873,7 +891,11 @@ extern "C" void session_mark_transaction_to_rollback(Session *session, bool all)
#define MX_ULONGLONG_T ulonglong #define MX_ULONGLONG_T ulonglong
#define MX_LONGLONG_T longlong #define MX_LONGLONG_T longlong
#define MX_CHARSET_INFO CHARSET_INFO #define MX_CHARSET_INFO CHARSET_INFO
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID > 50200
#define MX_CONST_CHARSET_INFO const struct charset_info_st
#else
#define MX_CONST_CHARSET_INFO struct charset_info_st #define MX_CONST_CHARSET_INFO struct charset_info_st
#endif
#define MX_CONST #define MX_CONST
#define MX_BITMAP MY_BITMAP #define MX_BITMAP MY_BITMAP
#define MX_BIT_SIZE() n_bits #define MX_BIT_SIZE() n_bits
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment