summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@narttu.mysql.fi>2008-05-29 21:39:25 +0300
committerunknown <monty@narttu.mysql.fi>2008-05-29 21:39:25 +0300
commitf83bd712ae864ed2fa2271247e56fc1f444c9801 (patch)
treed7dd11206d6de4fc93a1a73a66f7a15f32bb92d3
parent5ca17f0dc6235f03d9cbfcae087ac41d57fa4940 (diff)
parent5099033c26826fd2625b6424134999853e33a29d (diff)
downloadmariadb-git-f83bd712ae864ed2fa2271247e56fc1f444c9801.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-maria
into mysql.com:/home/my/mysql-maria mysql-test/r/maria.result: Auto merged mysql-test/suite/ndb/r/ndb_auto_increment.result: Auto merged mysql-test/t/maria.test: Auto merged mysys/hash.c: Auto merged mysys/thr_lock.c: Auto merged sql/field.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/ha_ndbcluster.h: Auto merged sql/ha_partition.cc: Auto merged sql/ha_partition.h: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/log_event.cc: Auto merged sql/log_event_old.cc: Auto merged sql/mysqld.cc: Auto merged sql/protocol.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_yacc.yy: Auto merged storage/csv/ha_tina.cc: Auto merged storage/federated/ha_federated.cc: Auto merged storage/maria/Makefile.am: Auto merged storage/maria/ma_check.c: Auto merged storage/maria/ma_control_file.c: Auto merged storage/maria/ma_delete_all.c: Auto merged storage/maria/ma_dynrec.c: Auto merged storage/maria/ma_init.c: Auto merged storage/maria/ma_key_recover.c: Auto merged storage/maria/ma_open.c: Auto merged storage/maria/ma_page.c: Auto merged storage/maria/ma_range.c: Auto merged storage/maria/ma_recovery.c: Auto merged storage/maria/ma_test1.c: Auto merged storage/maria/maria_read_log.c: Auto merged storage/maria/unittest/ma_test_all-t: Auto merged storage/maria/unittest/ma_test_loghandler_multigroup-t.c: Auto merged storage/maria/unittest/ma_test_recovery.pl: Auto merged storage/myisam/ha_myisam.cc: Auto merged storage/myisam/myisamdef.h: Auto merged include/my_base.h: Manual merge where error code are kept same as in 5.1 mysys/my_handler.c: No changes sql/item.cc: Manual merge sql/sql_class.cc: Manual merge sql/sql_insert.cc: Manual merge storage/maria/ha_maria.cc: Manual merge storage/maria/ma_blockrec.c: Manual merge storage/maria/ma_delete.c: Manual merge storage/maria/ma_write.c: Manual merge
-rw-r--r--include/maria.h5
-rw-r--r--include/my_base.h3
-rw-r--r--include/my_tree.h5
-rw-r--r--include/myisamchk.h5
-rw-r--r--include/thr_lock.h3
-rw-r--r--mysql-test/install_test_db.sh2
-rw-r--r--mysql-test/r/maria-mvcc.result140
-rw-r--r--mysql-test/r/maria-page-checksum.result1
-rw-r--r--mysql-test/r/maria.result14
-rw-r--r--mysql-test/suite/ndb/r/ndb_auto_increment.result2
-rw-r--r--mysql-test/suite/ndb/t/ndb_auto_increment.test2
-rw-r--r--mysql-test/t/maria-mvcc.test87
-rw-r--r--mysql-test/t/maria-page-checksum.test11
-rw-r--r--mysql-test/t/maria.test8
-rw-r--r--mysys/hash.c2
-rw-r--r--mysys/thr_lock.c102
-rw-r--r--sql/field.cc2
-rw-r--r--sql/ha_ndbcluster.cc6
-rw-r--r--sql/ha_ndbcluster.h2
-rw-r--r--sql/ha_partition.cc5
-rw-r--r--sql/ha_partition.h2
-rw-r--r--sql/handler.cc11
-rw-r--r--sql/handler.h6
-rw-r--r--sql/item.cc16
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_insert.cc14
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc19
-rw-r--r--sql/sql_select.cc23
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/sql_table.cc4
-rw-r--r--sql/sql_yacc.yy10
-rw-r--r--storage/archive/ha_archive.cc2
-rw-r--r--storage/archive/ha_archive.h2
-rw-r--r--storage/csv/ha_tina.cc2
-rw-r--r--storage/federated/ha_federated.cc4
-rw-r--r--storage/federated/ha_federated.h2
-rw-r--r--storage/maria/Makefile.am13
-rw-r--r--storage/maria/ha_maria.cc241
-rw-r--r--storage/maria/ha_maria.h2
-rw-r--r--storage/maria/ma_blockrec.c317
-rw-r--r--storage/maria/ma_blockrec.h14
-rw-r--r--storage/maria/ma_check.c381
-rw-r--r--storage/maria/ma_checkpoint.c8
-rw-r--r--storage/maria/ma_close.c21
-rw-r--r--storage/maria/ma_commit.c14
-rw-r--r--storage/maria/ma_control_file.c10
-rw-r--r--storage/maria/ma_control_file.h3
-rw-r--r--storage/maria/ma_delete.c8
-rw-r--r--storage/maria/ma_delete_all.c16
-rw-r--r--storage/maria/ma_dynrec.c12
-rw-r--r--storage/maria/ma_extra.c36
-rw-r--r--storage/maria/ma_info.c10
-rw-r--r--storage/maria/ma_init.c23
-rw-r--r--storage/maria/ma_key_recover.c4
-rw-r--r--storage/maria/ma_locking.c157
-rw-r--r--storage/maria/ma_open.c89
-rw-r--r--storage/maria/ma_page.c18
-rw-r--r--storage/maria/ma_range.c13
-rw-r--r--storage/maria/ma_recovery.c14
-rw-r--r--storage/maria/ma_rkey.c6
-rw-r--r--storage/maria/ma_rnext.c4
-rw-r--r--storage/maria/ma_rnext_same.c10
-rw-r--r--storage/maria/ma_rprev.c7
-rw-r--r--storage/maria/ma_rsame.c4
-rw-r--r--storage/maria/ma_sort.c7
-rw-r--r--storage/maria/ma_state.c478
-rw-r--r--storage/maria/ma_state.h75
-rw-r--r--storage/maria/ma_static.c1
-rw-r--r--storage/maria/ma_test1.c15
-rw-r--r--storage/maria/ma_test2.c12
-rwxr-xr-xstorage/maria/ma_test_recovery2
-rw-r--r--storage/maria/ma_update.c27
-rw-r--r--storage/maria/ma_write.c37
-rw-r--r--storage/maria/maria_chk.c32
-rw-r--r--storage/maria/maria_def.h45
-rw-r--r--storage/maria/maria_pack.c13
-rw-r--r--storage/maria/maria_read_log.c2
-rw-r--r--storage/maria/trnman.c108
-rw-r--r--storage/maria/trnman.h5
-rw-r--r--storage/maria/trnman_public.h7
-rw-r--r--storage/maria/unittest/ma_control_file-t.c2
-rwxr-xr-xstorage/maria/unittest/ma_test_all-t20
-rw-r--r--storage/maria/unittest/ma_test_loghandler-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_first_lsn-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_max_lsn-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_multigroup-t.c4
-rw-r--r--storage/maria/unittest/ma_test_loghandler_multithread-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_noflush-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_nologs-t.c4
-rw-r--r--storage/maria/unittest/ma_test_loghandler_pagecache-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_purge-t.c2
-rw-r--r--storage/maria/unittest/ma_test_recovery.expected168
-rwxr-xr-xstorage/maria/unittest/ma_test_recovery.pl54
-rw-r--r--storage/myisam/ha_myisam.cc6
-rw-r--r--storage/myisam/ha_myisam.h2
-rw-r--r--storage/myisam/mi_locking.c2
-rw-r--r--storage/myisam/myisamdef.h2
102 files changed, 2316 insertions, 835 deletions
diff --git a/include/maria.h b/include/maria.h
index b216affa3fc..57726fb92bf 100644
--- a/include/maria.h
+++ b/include/maria.h
@@ -391,6 +391,7 @@ typedef struct st_maria_sort_param
/* functions in maria_check */
void maria_chk_init(HA_CHECK *param);
+void maria_chk_init_for_check(HA_CHECK *param, MARIA_HA *info);
int maria_chk_status(HA_CHECK *param, MARIA_HA *info);
int maria_chk_del(HA_CHECK *param, MARIA_HA *info, ulonglong test_flag);
int maria_chk_size(HA_CHECK *param, MARIA_HA *info);
@@ -426,12 +427,14 @@ my_bool maria_test_if_sort_rep(MARIA_HA *info, ha_rows rows, ulonglong key_map,
int maria_init_bulk_insert(MARIA_HA *info, ulong cache_size, ha_rows rows);
void maria_flush_bulk_insert(MARIA_HA *info, uint inx);
-void maria_end_bulk_insert(MARIA_HA *info);
+void maria_end_bulk_insert(MARIA_HA *info, my_bool table_will_be_deleted);
int maria_assign_to_pagecache(MARIA_HA *info, ulonglong key_map,
PAGECACHE *key_cache);
void maria_change_pagecache(PAGECACHE *old_key_cache,
PAGECACHE *new_key_cache);
int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves);
+void maria_versioning(MARIA_HA *info, my_bool versioning);
+void maria_ignore_trids(MARIA_HA *info);
/* fulltext functions */
FT_INFO *maria_ft_init_search(uint,void *, uint, uchar *, uint,
diff --git a/include/my_base.h b/include/my_base.h
index ca9b875ebfa..da5670644e7 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -445,7 +445,8 @@ enum ha_base_keytype {
#define HA_ERR_INITIALIZATION 174 /* Error during initialization */
#define HA_ERR_FILE_TOO_SHORT 175 /* File too short */
#define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */
-#define HA_ERR_LAST 176 /* Copy of last error nr */
+#define HA_ERR_ROW_NOT_VISIBLE 177
+#define HA_ERR_LAST 177 /* Copy of last error nr */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
diff --git a/include/my_tree.h b/include/my_tree.h
index 24bbdd54019..e387b25d431 100644
--- a/include/my_tree.h
+++ b/include/my_tree.h
@@ -66,8 +66,8 @@ void init_tree(TREE *tree, ulong default_alloc_size, ulong memory_limit,
tree_element_free free_element, void *custom_arg);
void delete_tree(TREE*);
void reset_tree(TREE*);
- /* similar to delete tree, except we do not my_free() blocks in mem_root
- */
+
+ /* similar to delete tree, except we do not my_free() blocks in mem_root */
#define is_tree_inited(tree) ((tree)->root != 0)
/* Functions on leafs */
@@ -86,6 +86,7 @@ void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs,
int r_offs);
ha_rows tree_record_pos(TREE *tree, const void *key,
enum ha_rkey_function search_flag, void *custom_arg);
+#define reset_free_element(tree) (tree)->free= 0
#define TREE_ELEMENT_EXTRA_SIZE (sizeof(TREE_ELEMENT) + sizeof(void*))
diff --git a/include/myisamchk.h b/include/myisamchk.h
index 29f523558aa..f4651b81f8b 100644
--- a/include/myisamchk.h
+++ b/include/myisamchk.h
@@ -134,6 +134,11 @@ typedef struct st_handler_check_param
ha_checksum tmp_record_checksum;
ulonglong org_key_map;
ulonglong testflag;
+
+ /* Following is used to check if rows are visible */
+ ulonglong max_trid, max_found_trid;
+ ulonglong not_visible_rows_found;
+
size_t use_buffers, read_buffer_length, write_buffer_length;
size_t sort_buffer_length, sort_key_blocks;
ulong rec_per_key_part[HA_MAX_KEY_SEG * HA_MAX_POSSIBLE_KEY];
diff --git a/include/thr_lock.h b/include/thr_lock.h
index a4ca6e6ddf2..821c1bf2949 100644
--- a/include/thr_lock.h
+++ b/include/thr_lock.h
@@ -123,11 +123,12 @@ typedef struct st_thr_lock {
/* write_lock_count is incremented for write locks and reset on read locks */
ulong write_lock_count;
uint read_no_write_count;
- void (*get_status)(void*, int); /* When one gets a lock */
+ void (*get_status)(void*, my_bool); /* When one gets a lock */
void (*copy_status)(void*,void*);
void (*update_status)(void*); /* Before release of write */
void (*restore_status)(void*); /* Before release of read */
my_bool (*check_status)(void *);
+ my_bool allow_multiple_concurrent_insert;
} THR_LOCK;
diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh
index e4df8f619cc..855ec4351e3 100644
--- a/mysql-test/install_test_db.sh
+++ b/mysql-test/install_test_db.sh
@@ -102,7 +102,7 @@ basedir=.
EXTRA_ARG="--windows"
fi
-INSTALL_CMD="$scriptdir/mysql_install_db --no-defaults $EXTRA_ARG --basedir=$basedir --datadir=mysql-test/$ldata --srcdir=."
+INSTALL_CMD="$scriptdir/mysql_install_db --no-defaults $EXTRA_ARG --datadir=mysql-test/$ldata --srcdir=."
echo "running $INSTALL_CMD"
cd ..
diff --git a/mysql-test/r/maria-mvcc.result b/mysql-test/r/maria-mvcc.result
new file mode 100644
index 00000000000..b80f07cd9d2
--- /dev/null
+++ b/mysql-test/r/maria-mvcc.result
@@ -0,0 +1,140 @@
+set global maria_page_checksum=1;
+drop table if exists t1;
+create table t1 (i int) engine=maria;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+lock tables t1 write concurrent;
+insert into t1 values (1);
+insert into t1 values (2);
+/* should see 1 and 2 */
+select i from t1;
+i
+1
+2
+select count(*) from t1;
+count(*)
+2
+/* should see nothing */
+select i from t1;
+i
+select count(*) from t1;
+count(*)
+0
+lock tables t1 write concurrent;
+insert into t1 values (3);
+insert into t1 values (4);
+/* should see 3 and 4 */
+select i from t1;
+i
+3
+4
+select count(*) from t1;
+count(*)
+2
+unlock tables;
+lock tables t1 write concurrent;
+insert into t1 values (5);
+/* should see 3, 4 and 5 */
+select i from t1;
+i
+3
+4
+5
+select count(*) from t1;
+count(*)
+3
+lock tables t1 write concurrent;
+/* should see 3, 4 */
+select i from t1;
+i
+3
+4
+select count(*) from t1;
+count(*)
+2
+insert into t1 values (6);
+/* Should see 1, 2, 6 */
+select i from t1;
+i
+1
+2
+6
+select count(*) from t1;
+count(*)
+3
+unlock tables;
+lock tables t1 write concurrent;
+/* Should see 1, 2, 3, 4 and 6 */
+select i from t1;
+i
+1
+2
+3
+4
+6
+select count(*) from t1;
+count(*)
+5
+/* should see 3, 4, 5 */
+select i from t1;
+i
+3
+4
+5
+select count(*) from t1;
+count(*)
+3
+unlock tables;
+/* should see 1, 2, 3, 4, 5, 6 */
+select i from t1;
+i
+1
+2
+3
+4
+5
+6
+select count(*) from t1;
+count(*)
+6
+unlock tables;
+/* should see 1, 2, 3, 4, 5, 6 */
+select i from t1;
+i
+1
+2
+3
+4
+5
+6
+select count(*) from t1;
+count(*)
+6
+insert into t1 values (7);
+/* should see 3, 4, 7 */
+select i from t1;
+i
+3
+4
+7
+select count(*) from t1;
+count(*)
+3
+unlock tables;
+/* should see 1, 2, 3, 4, 5, 6, 7 */
+select i from t1;
+i
+1
+2
+3
+4
+5
+6
+7
+select count(*) from t1;
+count(*)
+7
+drop table t1;
diff --git a/mysql-test/r/maria-page-checksum.result b/mysql-test/r/maria-page-checksum.result
index 1a7ec2e3fdd..d7ab1fc4ba3 100644
--- a/mysql-test/r/maria-page-checksum.result
+++ b/mysql-test/r/maria-page-checksum.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
select @@global.maria_page_checksum;
@@global.maria_page_checksum
1
diff --git a/mysql-test/r/maria.result b/mysql-test/r/maria.result
index 5487024f073..a9f10a7ec4d 100644
--- a/mysql-test/r/maria.result
+++ b/mysql-test/r/maria.result
@@ -355,6 +355,9 @@ INSERT into t2 values (1,1,1), (2,2,2);
optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 1 b 1 b A 5 NULL NULL YES BTREE
@@ -2101,6 +2104,11 @@ test.t2 check status OK
select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8
1 a 256 256 4096 4096
+drop table t2;
+create table t2 (primary key (auto)) engine=maria row_format=dynamic select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
+check table t2;
+Table Op Msg_type Msg_text
+test.t2 check status OK
drop table t1,t2;
CREATE TABLE t1 (seq int, s1 int, s2 blob);
insert into t1 values (1, 1, MD5(1));
@@ -2236,6 +2244,12 @@ t
9999-12-31 23:59:59
2003-01-00 00:00:00
2003-00-00 00:00:00
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
delete from t1 where t > 0;
optimize table t1;
Table Op Msg_type Msg_text
diff --git a/mysql-test/suite/ndb/r/ndb_auto_increment.result b/mysql-test/suite/ndb/r/ndb_auto_increment.result
index 78612b35113..9f16f1ae477 100644
--- a/mysql-test/suite/ndb/r/ndb_auto_increment.result
+++ b/mysql-test/suite/ndb/r/ndb_auto_increment.result
@@ -416,7 +416,7 @@ a
insert into t1 values (35);
insert into t1 values (NULL);
insert into t1 values (NULL);
-ERROR 23000: Duplicate entry '35' for key 'PRIMARY'
+Got one of the listed errors
select * from t1 order by a;
a
1
diff --git a/mysql-test/suite/ndb/t/ndb_auto_increment.test b/mysql-test/suite/ndb/t/ndb_auto_increment.test
index 14e7ae7ca7b..33021331e44 100644
--- a/mysql-test/suite/ndb/t/ndb_auto_increment.test
+++ b/mysql-test/suite/ndb/t/ndb_auto_increment.test
@@ -276,7 +276,7 @@ connection server1;
insert into t1 values (35);
insert into t1 values (NULL);
connection server2;
---error ER_DUP_ENTRY
+--error ER_DUP_ENTRY, ER_DUP_KEY
insert into t1 values (NULL);
select * from t1 order by a;
diff --git a/mysql-test/t/maria-mvcc.test b/mysql-test/t/maria-mvcc.test
new file mode 100644
index 00000000000..f2946d9462f
--- /dev/null
+++ b/mysql-test/t/maria-mvcc.test
@@ -0,0 +1,87 @@
+#
+# Testing insert and select on a table with two threads
+# using locking
+#
+
+-- source include/have_maria.inc
+set global maria_page_checksum=1;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+connect (con1,localhost,root,,);
+connection con1;
+
+create table t1 (i int) engine=maria;
+show create table t1;
+lock tables t1 write concurrent;
+insert into t1 values (1);
+insert into t1 values (2);
+/* should see 1 and 2 */
+select i from t1;
+select count(*) from t1;
+
+connect (con2,localhost,root,,);
+connection con2;
+/* should see nothing */
+select i from t1;
+select count(*) from t1;
+lock tables t1 write concurrent;
+insert into t1 values (3);
+insert into t1 values (4);
+/* should see 3 and 4 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+lock tables t1 write concurrent;
+insert into t1 values (5);
+/* should see 3, 4 and 5 */
+select i from t1;
+select count(*) from t1;
+
+connect (con3,localhost,root,,);
+connection con3;
+lock tables t1 write concurrent;
+/* should see 3, 4 */
+select i from t1;
+select count(*) from t1;
+
+connection con1;
+insert into t1 values (6);
+/* Should see 1, 2, 6 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+lock tables t1 write concurrent;
+/* Should see 1, 2, 3, 4 and 6 */
+select i from t1;
+select count(*) from t1;
+
+connection con2;
+/* should see 3, 4, 5 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+/* should see 1, 2, 3, 4, 5, 6 */
+select i from t1;
+select count(*) from t1;
+
+connection con1;
+unlock tables;
+/* should see 1, 2, 3, 4, 5, 6 */
+select i from t1;
+select count(*) from t1;
+
+connection con3;
+insert into t1 values (7);
+/* should see 3, 4, 7 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+/* should see 1, 2, 3, 4, 5, 6, 7 */
+select i from t1;
+select count(*) from t1;
+
+connection default;
+drop table t1;
diff --git a/mysql-test/t/maria-page-checksum.test b/mysql-test/t/maria-page-checksum.test
index 7bed7393d2d..6c7c5afc2a5 100644
--- a/mysql-test/t/maria-page-checksum.test
+++ b/mysql-test/t/maria-page-checksum.test
@@ -1,3 +1,14 @@
+#
+# This can't be run with --extern as we are acccessing the tables in the
+# database directly
+#
+
+-- source include/have_maria.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
select @@global.maria_page_checksum;
--echo # iteration 1
diff --git a/mysql-test/t/maria.test b/mysql-test/t/maria.test
index a2b08860060..bea9521dcf6 100644
--- a/mysql-test/t/maria.test
+++ b/mysql-test/t/maria.test
@@ -1,5 +1,5 @@
#
-# Testing of potential probelms in Maria
+# Testing of potential problems in Maria
# This code was initially taken from myisam.test
#
@@ -377,6 +377,7 @@ INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,
create table t2 (a int not null, b int, c int, key(b), key(c), key(a));
INSERT into t2 values (1,1,1), (2,2,2);
optimize table t1;
+check table t1;
show index from t1;
explain select * from t1,t2 where t1.a=t2.a;
explain select * from t1,t2 force index(a) where t1.a=t2.a;
@@ -1352,6 +1353,9 @@ insert into t1 values (10,1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','on
create table t2 (primary key (auto)) engine=maria row_format=page select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
check table t1,t2;
select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
+drop table t2;
+create table t2 (primary key (auto)) engine=maria row_format=dynamic select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
+check table t2;
drop table t1,t2;
# Test UPDATE with small BLOB which fits on head page
@@ -1449,6 +1453,8 @@ drop table t1, t2, t3;
create table t1 (t datetime) engine=maria;
insert into t1 values (101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030100000000),(20030000000000);
select * from t1;
+optimize table t1;
+check table t1;
delete from t1 where t > 0;
optimize table t1;
check table t1;
diff --git a/mysys/hash.c b/mysys/hash.c
index 9166ae6f788..3a9f05a3e0b 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -319,7 +319,7 @@ my_bool my_hash_insert(HASH *info,const uchar *record)
LINT_INIT(ptr_to_rec);
LINT_INIT(ptr_to_rec2);
- if (HASH_UNIQUE & info->flags)
+ if (info->flags & HASH_UNIQUE)
{
uchar *key= (uchar*) hash_key(info, record, &idx, 1);
if (hash_search(info, key, idx))
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index e2db389dca6..d6877c8c998 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -69,9 +69,11 @@ get_status:
for concurrent reads.
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
-TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
-multiple read locks.
+TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same
+time as multiple read locks.
+In addition, if lock->allow_multiple_concurrent_insert is set then there can
+be any number of TL_WRITE_CONCURRENT_INSERT locks aktive at the same time.
*/
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
@@ -152,7 +154,8 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
}
if (same_owner &&
!thr_lock_owner_equal(data->owner, first_owner) &&
- last_lock_type != TL_WRITE_ALLOW_WRITE)
+ last_lock_type != TL_WRITE_ALLOW_WRITE &&
+ last_lock_type != TL_WRITE_CONCURRENT_INSERT)
{
fprintf(stderr,
"Warning: Found locks from different threads in %s: %s\n",
@@ -205,7 +208,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
THR_LOCK_DATA *data;
for (data=lock->read.data ; data ; data=data->next)
{
- if ((int) data->type == (int) TL_READ_NO_INSERT)
+ if (data->type == TL_READ_NO_INSERT)
count++;
/* Protect against infinite loop. */
DBUG_ASSERT(count <= lock->read_no_write_count);
@@ -254,7 +257,22 @@ static void check_locks(THR_LOCK *lock, const char *where,
}
}
else
- { /* Have write lock */
+ {
+ /* We have at least one write lock */
+ if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
+ {
+ THR_LOCK_DATA *data;
+ for (data=lock->write.data->next ; data ; data=data->next)
+ {
+ if (data->type != TL_WRITE_CONCURRENT_INSERT)
+ {
+ fprintf(stderr,
+ "Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write locks\n",
+ where);
+ break;
+ }
+ }
+ }
if (lock->write_wait.data)
{
if (!allow_no_locks &&
@@ -515,7 +533,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
/* Request for READ lock */
if (lock->write.data)
{
- /* We can allow a read lock even if there is already a write lock
+ /*
+ We can allow a read lock even if there is already a write lock
on the table in one the following cases:
- This thread alread have a write lock on the table
- The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
@@ -559,11 +578,11 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
(*lock->read.last)=data; /* Add to running FIFO */
data->prev=lock->read.last;
lock->read.last= &data->next;
- if (lock->get_status)
- (*lock->get_status)(data->status_param, 0);
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count++;
check_locks(lock,"read lock with no write locks",0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, 0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -627,16 +646,18 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
The following test will not work if the old lock was a
TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
the same thread, but this will never happen within MySQL.
+
+ The idea is to allow us to get a lock at once if we already have
+ a write lock or if there is no pending write locks and if all
+ write locks are of the same type and are either
+ TL_WRITE_ALLOW_WRITE or TL_WRITE_CONCURRENT_INSERT
*/
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
- (lock_type == TL_WRITE_ALLOW_WRITE &&
- !lock->write_wait.data &&
- lock->write.data->type == TL_WRITE_ALLOW_WRITE))
+ (!lock->write_wait.data && lock_type == lock->write.data->type &&
+ (lock_type == TL_WRITE_ALLOW_WRITE ||
+ (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ lock->allow_multiple_concurrent_insert))))
{
- /*
- We have already got a write lock or all locks are
- TL_WRITE_ALLOW_WRITE
- */
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
(ulong) lock->write_wait.data,
lock->write.data->type));
@@ -645,8 +666,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
data->prev=lock->write.last;
lock->write.last= &data->next;
check_locks(lock,"second write lock",0);
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param,
+ lock_type == TL_WRITE_CONCURRENT_INSERT);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -679,8 +701,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
(*lock->write.last)=data; /* Add as current write lock */
data->prev=lock->write.last;
lock->write.last= &data->next;
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, concurrent_insert);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, concurrent_insert);
check_locks(lock,"only write lock",0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
@@ -810,7 +832,6 @@ static void wake_up_waiters(THR_LOCK *lock)
{
THR_LOCK_DATA *data;
enum thr_lock_type lock_type;
-
DBUG_ENTER("wake_up_waiters");
if (!lock->write.data) /* If no active write locks */
@@ -1373,8 +1394,8 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
{
if (!lock->read.data) /* No read locks */
{ /* We have the lock */
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, 0);
pthread_mutex_unlock(&lock->mutex);
DBUG_RETURN(0);
}
@@ -1512,7 +1533,7 @@ struct st_test {
enum thr_lock_type lock_type;
};
-THR_LOCK locks[5]; /* 4 locks */
+THR_LOCK locks[6]; /* Number of locks +1 */
struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
@@ -1532,9 +1553,20 @@ struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
-struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
- test_7,test_8,test_9,test_10,test_11,test_12,
- test_13,test_14,test_15,test_16};
+struct st_test test_17[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_18[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_19[] = {{5,TL_READ}};
+struct st_test test_20[] = {{5,TL_READ_NO_INSERT}};
+struct st_test test_21[] = {{5,TL_WRITE}};
+
+
+struct st_test *tests[]=
+{
+ test_0, test_1, test_2, test_3, test_4, test_5, test_6, test_7, test_8,
+ test_9, test_10, test_11, test_12, test_13, test_14, test_15, test_16,
+ test_17, test_18, test_19, test_20, test_21
+};
+
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
sizeof(test_1)/sizeof(struct st_test),
sizeof(test_2)/sizeof(struct st_test),
@@ -1551,7 +1583,12 @@ int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
sizeof(test_13)/sizeof(struct st_test),
sizeof(test_14)/sizeof(struct st_test),
sizeof(test_15)/sizeof(struct st_test),
- sizeof(test_16)/sizeof(struct st_test)
+ sizeof(test_16)/sizeof(struct st_test),
+ sizeof(test_17)/sizeof(struct st_test),
+ sizeof(test_18)/sizeof(struct st_test),
+ sizeof(test_19)/sizeof(struct st_test),
+ sizeof(test_20)/sizeof(struct st_test),
+ sizeof(test_21)/sizeof(struct st_test)
};
@@ -1595,7 +1632,6 @@ static void *test_thread(void *arg)
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
-
thr_lock_info_init(&lock_info);
thr_lock_owner_init(&owner, &lock_info);
for (i=0; i < lock_counts[param] ; i++)
@@ -1641,7 +1677,8 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
{
pthread_t tid;
pthread_attr_t thr_attr;
- int i,*param,error;
+ int *param,error;
+ uint i;
MY_INIT(argv[0]);
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
DBUG_PUSH(argv[1]+2);
@@ -1661,13 +1698,14 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
exit(1);
}
- for (i=0 ; i < (int) array_elements(locks) ; i++)
+ for (i=0 ; i < array_elements(locks) ; i++)
{
thr_lock_init(locks+i);
locks[i].check_status= test_check_status;
locks[i].update_status=test_update_status;
locks[i].copy_status= test_copy_status;
locks[i].get_status= test_get_status;
+ locks[i].allow_multiple_concurrent_insert= 1;
}
if ((error=pthread_attr_init(&thr_attr)))
{
@@ -1693,7 +1731,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
#ifdef HAVE_THR_SETCONCURRENCY
VOID(thr_setconcurrency(2));
#endif
- for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
+ for (i=0 ; i < array_elements(lock_counts) ; i++)
{
param=(int*) malloc(sizeof(int));
*param=i;
@@ -1725,7 +1763,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
}
if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
- for (i=0 ; i < (int) array_elements(locks) ; i++)
+ for (i=0 ; i < array_elements(locks) ; i++)
thr_lock_delete(locks+i);
#ifdef EXTRA_DEBUG
if (found_errors)
diff --git a/sql/field.cc b/sql/field.cc
index f955cf15eb9..6b29314501f 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5391,7 +5391,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
int Field_year::store(double nr)
{
- if (nr < 0.0 || nr >= 2155.0)
+ if (nr < 0.0 || nr > 2155.0)
{
(void) Field_year::store((longlong) -1, FALSE);
return 1;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 1cfe403407e..4e1300c044c 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -4230,11 +4230,11 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
/**
End of an insert.
*/
-int ha_ndbcluster::end_bulk_insert()
+int ha_ndbcluster::end_bulk_insert(bool abort)
{
int error= 0;
-
DBUG_ENTER("end_bulk_insert");
+
// Check if last inserts need to be flushed
if (m_bulk_insert_not_flushed)
{
@@ -4586,7 +4586,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
Thd_ndb *thd_ndb= get_thd_ndb(thd);
Ndb *ndb= thd_ndb->ndb;
- DBUG_PRINT("enter", ("this: 0x%lx thd: 0x%lx thd_ndb: %lx "
+ DBUG_PRINT("enter", ("this: 0x%lx thd: 0x%lx thd_ndb: 0x%lx "
"thd_ndb->lock_count: %d",
(long) this, (long) thd, (long) thd_ndb,
thd_ndb->lock_count));
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index a17323d3fd6..f3651ebeca9 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -322,7 +322,7 @@ class ha_ndbcluster: public handler
double scan_time();
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
static Thd_ndb* seize_thd_ndb();
static void release_thd_ndb(Thd_ndb* thd_ndb);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 3045d5d73a9..c90f82d24a1 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -3025,13 +3025,14 @@ void ha_partition::start_bulk_insert(ha_rows rows)
SYNOPSIS
end_bulk_insert()
+ abort 1 if table will be deleted (error condition)
RETURN VALUE
>0 Error code
0 Success
*/
-int ha_partition::end_bulk_insert()
+int ha_partition::end_bulk_insert(bool abort)
{
int error= 0;
handler **file;
@@ -3041,7 +3042,7 @@ int ha_partition::end_bulk_insert()
do
{
int tmp;
- if ((tmp= (*file)->ha_end_bulk_insert()))
+ if ((tmp= (*file)->ha_end_bulk_insert(abort)))
error= tmp;
} while (*(++file));
DBUG_RETURN(error);
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index ac00581fae0..5a8caaeb209 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -315,7 +315,7 @@ public:
virtual int delete_row(const uchar * buf);
virtual int delete_all_rows(void);
virtual void start_bulk_insert(ha_rows rows);
- virtual int end_bulk_insert();
+ virtual int end_bulk_insert(bool);
virtual bool is_fatal_error(int error, uint flags)
{
diff --git a/sql/handler.cc b/sql/handler.cc
index 1fee2012542..f637ebfb02e 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2527,11 +2527,14 @@ void handler::print_error(int error, myf errflag)
break;
case HA_ERR_FOUND_DUPP_KEY:
{
- uint key_nr=get_dup_key(error);
- if ((int) key_nr >= 0)
+ if (table)
{
- print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
- DBUG_VOID_RETURN;
+ uint key_nr=get_dup_key(error);
+ if ((int) key_nr >= 0)
+ {
+ print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
+ DBUG_VOID_RETURN;
+ }
}
textno=ER_DUP_KEY;
break;
diff --git a/sql/handler.h b/sql/handler.h
index 63923733c4d..b2234dc4b75 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1216,10 +1216,10 @@ public:
estimation_rows_to_insert= rows;
start_bulk_insert(rows);
}
- int ha_end_bulk_insert()
+ int ha_end_bulk_insert(bool abort)
{
estimation_rows_to_insert= 0;
- return end_bulk_insert();
+ return end_bulk_insert(abort);
}
int ha_bulk_update_row(const uchar *old_data, uchar *new_data,
uint *dup_key_found);
@@ -1844,7 +1844,7 @@ private:
virtual int repair(THD* thd, HA_CHECK_OPT* check_opt)
{ return HA_ADMIN_NOT_IMPLEMENTED; }
virtual void start_bulk_insert(ha_rows rows) {}
- virtual int end_bulk_insert() { return 0; }
+ virtual int end_bulk_insert(bool abort) { return 0; }
virtual int index_read(uchar * buf, const uchar * key, uint key_len,
enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
diff --git a/sql/item.cc b/sql/item.cc
index f2dc1238ff0..9d75e55c9a3 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1468,7 +1468,9 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
if (collation == &my_charset_bin)
{
if (derivation <= dt.derivation)
- ; // Do nothing
+ {
+ /* Do nothing */
+ }
else
{
set(dt);
@@ -1480,15 +1482,11 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
set(dt);
}
- else
- {
- // Do nothing
- }
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
left_is_superset(this, &dt))
{
- // Do nothing
+ /* Do nothing */
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
left_is_superset(&dt, this))
@@ -1499,7 +1497,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
derivation < dt.derivation &&
dt.derivation >= DERIVATION_SYSCONST)
{
- // Do nothing;
+ /* Do nothing */
}
else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
dt.derivation < derivation &&
@@ -1516,7 +1514,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
}
else if (derivation < dt.derivation)
{
- // Do nothing
+ /* Do nothing */
}
else if (dt.derivation < derivation)
{
@@ -1526,7 +1524,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
if (collation == dt.collation)
{
- // Do nothing
+ /* Do nothing */
}
else
{
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 944d99d7a74..32cf735ea3f 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -7612,7 +7612,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *
ultimately. Still todo: fix
*/
}
- if ((local_error= m_table->file->ha_end_bulk_insert()))
+ if ((local_error= m_table->file->ha_end_bulk_insert(0)))
{
m_table->file->print_error(local_error, MYF(0));
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 808356a05c7..3596b21cb30 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -962,7 +962,7 @@ int Write_rows_log_event_old::do_after_row_operations(TABLE *table, int error)
fires bug#27077
todo: explain or fix
*/
- if ((local_error= table->file->ha_end_bulk_insert()))
+ if ((local_error= table->file->ha_end_bulk_insert(0)))
{
table->file->print_error(local_error, MYF(0));
}
@@ -2633,7 +2633,7 @@ Write_rows_log_event_old::do_after_row_operations(const Slave_reporting_capabili
fires bug#27077
todo: explain or fix
*/
- if ((local_error= m_table->file->ha_end_bulk_insert()))
+ if ((local_error= m_table->file->ha_end_bulk_insert(0)))
{
m_table->file->print_error(local_error, MYF(0));
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9dadd15bfbe..a19cde65e2b 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2890,7 +2890,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
}
}
to_error_log:
- if (!thd || MyFlags & ME_NOREFRESH)
+ if (!thd || (MyFlags & ME_NOREFRESH))
(*func)("%s: %s", my_progname_short, str); /* purecov: inspected */
DBUG_RETURN(0);
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 5fe56724d08..c98ad72fffe 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -383,6 +383,7 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
void net_end_statement(THD *thd)
{
+ DBUG_ENTER("net_end_statement");
DBUG_ASSERT(! thd->main_da.is_sent);
/* Can not be true, but do not take chances in production. */
@@ -419,6 +420,7 @@ void net_end_statement(THD *thd)
break;
}
thd->main_da.is_sent= TRUE;
+ DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fb08b2e81b3..3ca0fef4b50 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -369,6 +369,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
void
Diagnostics_area::reset_diagnostics_area()
{
+ DBUG_ENTER("reset_diagnostics_area");
#ifdef DBUG_OFF
can_overwrite_status= FALSE;
/** Don't take chances in production */
@@ -382,6 +383,7 @@ Diagnostics_area::reset_diagnostics_area()
is_sent= FALSE;
/** Tiny reset in debug mode to see garbage right away */
m_status= DA_EMPTY;
+ DBUG_VOID_RETURN;
}
@@ -395,6 +397,7 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
ulonglong last_insert_id_arg,
const char *message_arg)
{
+ DBUG_ENTER("set_ok_status");
DBUG_ASSERT(! is_set());
/*
In production, refuse to overwrite an error or a custom response
@@ -412,6 +415,7 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
else
m_message[0]= '\0';
m_status= DA_OK;
+ DBUG_VOID_RETURN;
}
@@ -422,8 +426,8 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
void
Diagnostics_area::set_eof_status(THD *thd)
{
- /** Only allowed to report eof if has not yet reported an error */
-
+ DBUG_ENTER("set_eof_status");
+ /* Only allowed to report eof if has not yet reported an error */
DBUG_ASSERT(! is_set());
/*
In production, refuse to overwrite an error or a custom response
@@ -441,6 +445,7 @@ Diagnostics_area::set_eof_status(THD *thd)
m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
m_status= DA_EOF;
+ DBUG_VOID_RETURN;
}
/**
@@ -451,6 +456,7 @@ void
Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
const char *message_arg)
{
+ DBUG_ENTER("set_error_status");
/*
Only allowed to report error if has not yet reported a success
The only exception is when we flush the message to the client,
@@ -467,9 +473,10 @@ Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
#endif
m_sql_errno= sql_errno_arg;
- strmake(m_message, message_arg, sizeof(m_message) - 1);
+ strmake(m_message, message_arg, sizeof(m_message)-1);
m_status= DA_ERROR;
+ DBUG_VOID_RETURN;
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index dbfe3cc6d79..61ce6b04832 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -559,6 +559,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
bool transactional_table, joins_freed= FALSE;
bool changed;
bool was_insert_delayed= (table_list->lock_type == TL_WRITE_DELAYED);
+ bool using_bulk_insert= 0;
uint value_count;
ulong counter = 1;
ulonglong id;
@@ -724,8 +725,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
{
if (duplic != DUP_ERROR || ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- if (!thd->prelocked_mode)
+ if (!thd->prelocked_mode && values_list.elements > 1)
+ {
+ using_bulk_insert= 1;
table->file->ha_start_bulk_insert(values_list.elements);
+ }
}
thd->abort_on_warning= (!ignore && (thd->variables.sql_mode &
@@ -840,7 +844,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
auto_inc values from the delayed_insert thread as they share TABLE.
*/
table->file->ha_release_auto_increment();
- if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+ if (using_bulk_insert && table->file->ha_end_bulk_insert(0) && !error)
{
table->file->print_error(my_errno,MYF(0));
error=1;
@@ -1173,7 +1177,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
bool res= 0;
table_map map= 0;
DBUG_ENTER("mysql_prepare_insert");
- DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
+ DBUG_PRINT("enter", ("table_list 0x%lx table 0x%lx view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
/* INSERT should have a SELECT or VALUES clause */
@@ -3133,7 +3137,7 @@ bool select_insert::send_eof()
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
- error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0;
+ error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert(0) : 0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
@@ -3208,7 +3212,7 @@ void select_insert::abort() {
before.
*/
if (!thd->prelocked_mode)
- table->file->ha_end_bulk_insert();
+ table->file->ha_end_bulk_insert(0);
/*
If at least one row has been inserted/modified and will stay in
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 5c77848722d..49015fb3e2a 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -393,7 +393,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
error= read_sep_field(thd, info, table_list, fields_vars,
set_fields, set_values, read_info,
*enclosed, skip_lines, ignore);
- if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+ if (!thd->prelocked_mode && table->file->ha_end_bulk_insert(0) && !error)
{
table->file->print_error(my_errno, MYF(0));
error= 1;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 712bdc85ae3..7cc2c928521 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2600,10 +2600,12 @@ end_with_restore_list:
#endif /* HAVE_REPLICATION */
case SQLCOM_ALTER_TABLE:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
{
ulong priv=0;
ulong priv_needed= ALTER_ACL;
+
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+
/*
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
so we have to use a copy of this structure to make execution
@@ -2613,7 +2615,7 @@ end_with_restore_list:
HA_CREATE_INFO create_info(lex->create_info);
Alter_info alter_info(lex->alter_info, thd->mem_root);
- if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ if (thd->is_fatal_error) /* OOM creating a copy of alter_info */
goto error;
/*
We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
@@ -4695,11 +4697,6 @@ create_sp_error:
if (!(sql_command_flags[lex->sql_command] & CF_HAS_ROW_COUNT))
thd->row_count_func= -1;
- goto finish;
-
-error:
- res= TRUE;
-
finish:
if (need_start_waiting)
{
@@ -4710,6 +4707,11 @@ finish:
start_waiting_global_read_lock(thd);
}
DBUG_RETURN(res || thd->is_error());
+
+error:
+ thd_proc_info(thd, "query end");
+ res= TRUE;
+ goto finish;
}
@@ -7420,6 +7422,7 @@ bool parse_sql(THD *thd,
Lex_input_stream *lip,
Object_creation_ctx *creation_ctx)
{
+ bool mysql_parse_status;
DBUG_ASSERT(thd->m_lip == NULL);
/* Backup creation context. */
@@ -7435,7 +7438,7 @@ bool parse_sql(THD *thd,
/* Parse the query. */
- bool mysql_parse_status= MYSQLparse(thd) != 0;
+ mysql_parse_status= MYSQLparse(thd) != 0;
/* Check that if MYSQLparse() failed, thd->is_error() is set. */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a6e7cc33b51..5b6e779ec1b 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1798,7 +1798,10 @@ JOIN::exec()
curr_join->having= curr_join->tmp_having= 0; // Allready done
/* Change sum_fields reference to calculated fields in tmp_table */
- curr_join->all_fields= *curr_all_fields;
+#ifdef HAVE_purify
+ if (curr_join != this)
+#endif
+ curr_join->all_fields= *curr_all_fields;
if (!items1)
{
items1= items0 + all_fields.elements;
@@ -1816,8 +1819,13 @@ JOIN::exec()
fields_list.elements, all_fields))
DBUG_VOID_RETURN;
}
- curr_join->tmp_all_fields1= tmp_all_fields1;
- curr_join->tmp_fields_list1= tmp_fields_list1;
+#ifdef HAVE_purify
+ if (curr_join != this)
+#endif
+ {
+ curr_join->tmp_all_fields1= tmp_all_fields1;
+ curr_join->tmp_fields_list1= tmp_fields_list1;
+ }
curr_join->items1= items1;
}
curr_all_fields= &tmp_all_fields1;
@@ -2021,8 +2029,13 @@ JOIN::exec()
tmp_table_param.save_copy_field= curr_join->tmp_table_param.copy_field;
tmp_table_param.save_copy_field_end=
curr_join->tmp_table_param.copy_field_end;
- curr_join->tmp_all_fields3= tmp_all_fields3;
- curr_join->tmp_fields_list3= tmp_fields_list3;
+#ifdef HAVE_purify
+ if (curr_join != this)
+#endif
+ {
+ curr_join->tmp_all_fields3= tmp_all_fields3;
+ curr_join->tmp_fields_list3= tmp_fields_list3;
+ }
}
else
{
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 687ce575ebd..3c3b728f980 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -459,7 +459,8 @@ public:
group_optimized_away= 0;
all_fields= fields_arg;
- fields_list= fields_arg;
+ if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
+ fields_list= fields_arg;
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.init();
tmp_table_param.end_write_records= HA_POS_ERROR;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index bc4e6dfbbcc..fbce42fd452 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -7179,7 +7179,9 @@ err:
free_io_cache(from);
delete [] copy;
- if (errpos >= 3 && to->file->ha_end_bulk_insert() && error <= 0)
+ if (error > 0)
+ to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+ if (errpos >= 3 && to->file->ha_end_bulk_insert(error > 1) && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
error=1;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 58483a33582..c23049017e2 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -11215,6 +11215,16 @@ table_lock:
lock_option:
READ_SYM { $$= TL_READ_NO_INSERT; }
| WRITE_SYM { $$= TL_WRITE_DEFAULT; }
+ | WRITE_SYM CONCURRENT
+ {
+#ifdef HAVE_QUERY_CACHE
+ if (Lex->sphead != 0)
+ $$= TL_WRITE_DEFAULT;
+ else
+#endif
+ $$= TL_WRITE_CONCURRENT_INSERT;
+ }
+
| LOW_PRIORITY WRITE_SYM { $$= TL_WRITE_LOW_PRIORITY; }
| READ_SYM LOCAL_SYM { $$= TL_READ; }
;
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index 967e315d4a4..6c6a34e75ec 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -1511,7 +1511,7 @@ void ha_archive::start_bulk_insert(ha_rows rows)
Other side of start_bulk_insert, is end_bulk_insert. Here we turn off the bulk insert
flag, and set the share dirty so that the next select will call sync for us.
*/
-int ha_archive::end_bulk_insert()
+int ha_archive::end_bulk_insert(bool table_will_be_deleted)
{
DBUG_ENTER("ha_archive::end_bulk_insert");
bulk_insert= FALSE;
diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h
index ab630ed22fd..22f8302982d 100644
--- a/storage/archive/ha_archive.h
+++ b/storage/archive/ha_archive.h
@@ -134,7 +134,7 @@ public:
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int repair(THD* thd, HA_CHECK_OPT* check_opt);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool table_will_be_deleted);
enum row_type get_row_type() const
{
return ROW_TYPE_COMPRESSED;
diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc
index c4c40c436cd..c7eaf67c749 100644
--- a/storage/csv/ha_tina.cc
+++ b/storage/csv/ha_tina.cc
@@ -734,7 +734,7 @@ const char **ha_tina::bas_ext() const
for CSV engine. For more details see mysys/thr_lock.c
*/
-void tina_get_status(void* param, int concurrent_insert)
+void tina_get_status(void* param, my_bool concurrent_insert)
{
ha_tina *tina= (ha_tina*) param;
tina->get_status();
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index 5702b2f3514..23faaa9185a 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -1985,12 +1985,12 @@ void ha_federated::start_bulk_insert(ha_rows rows)
@retval != 0 Error occured at remote server. Also sets my_errno.
*/
-int ha_federated::end_bulk_insert()
+int ha_federated::end_bulk_insert(bool abort)
{
int error= 0;
DBUG_ENTER("ha_federated::end_bulk_insert");
- if (bulk_insert.str && bulk_insert.length)
+ if (!abort && bulk_insert.str && bulk_insert.length)
{
if (real_query(bulk_insert.str, bulk_insert.length))
error= stash_remote_error();
diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h
index 1974f9936fc..d2a86794904 100644
--- a/storage/federated/ha_federated.h
+++ b/storage/federated/ha_federated.h
@@ -205,7 +205,7 @@ public:
int close(void); // required
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
int write_row(uchar *buf);
int update_row(const uchar *old_data, uchar *new_data);
int delete_row(const uchar *buf);
diff --git a/storage/maria/Makefile.am b/storage/maria/Makefile.am
index 35f91fa2e4b..2f16d49ef5b 100644
--- a/storage/maria/Makefile.am
+++ b/storage/maria/Makefile.am
@@ -71,9 +71,9 @@ noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h \
ma_ft_eval.h trnman.h lockman.h tablockman.h \
ma_control_file.h ha_maria.h ma_blockrec.h \
ma_loghandler.h ma_loghandler_lsn.h ma_pagecache.h \
- ma_checkpoint.h ma_recovery.h ma_commit.h \
- trnman_public.h ma_check_standalone.h ma_key_recover.h \
- ma_recovery_util.h
+ ma_checkpoint.h ma_recovery.h ma_commit.h ma_state.h \
+ trnman_public.h ma_check_standalone.h \
+ ma_key_recover.h ma_recovery_util.h
ma_test1_DEPENDENCIES= $(LIBRARIES)
ma_test1_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
$(top_builddir)/storage/myisam/libmyisam.a \
@@ -115,7 +115,7 @@ ma_sp_test_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ma_rnext.c ma_rnext_same.c \
ma_search.c ma_page.c ma_key_recover.c ma_key.c \
- ma_locking.c \
+ ma_locking.c ma_state.c \
ma_rrnd.c ma_scan.c ma_cache.c \
ma_statrec.c ma_packrec.c ma_dynrec.c \
ma_blockrec.c ma_bitmap.c \
@@ -129,12 +129,13 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ma_keycache.c ma_preload.c ma_ft_parser.c \
ma_ft_update.c ma_ft_boolean_search.c \
ma_ft_nlq_search.c ft_maria.c ma_sort.c \
- ha_maria.cc trnman.c lockman.c tablockman.c \
+ trnman.c lockman.c tablockman.c \
ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \
ma_sp_key.c ma_control_file.c ma_loghandler.c \
ma_pagecache.c ma_pagecaches.c \
ma_checkpoint.c ma_recovery.c ma_commit.c \
- ma_pagecrc.c ma_recovery_util.c
+ ma_pagecrc.c ma_recovery_util.c \
+ ha_maria.cc
CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA?
SUFFIXES = .sh
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 4a6bf0e25f0..0c2efac2ee7 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -969,7 +969,8 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
0)))))
return HA_ADMIN_ALREADY_DONE;
- error= maria_chk_status(&param, file); // Not fatal
+ maria_chk_init_for_check(&param, file);
+ (void) maria_chk_status(&param, file); // Not fatal
error= maria_chk_size(&param, file);
if (!error)
error|= maria_chk_del(&param, file, param.testflag);
@@ -1297,6 +1298,14 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
DBUG_RETURN(HA_ADMIN_FAILED);
}
+ /*
+ If transactions was not enabled for a transactional table then
+ file->s->status is not up to date. This is needed for repair_by_sort
+ to work
+ */
+ if (share->base.born_transactional && !share->now_transactional)
+ _ma_copy_nontrans_state_information(file);
+
param.db_name= table->s->db.str;
param.table_name= table->alias;
param.tmpfile_createflag= O_RDWR | O_TRUNC;
@@ -1304,7 +1313,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
param.thd= thd;
param.tmpdir= &mysql_tmpdir_list;
param.out_flag= 0;
- strmov(fixed_name, file->s->open_file_name);
+ strmov(fixed_name, share->open_file_name);
// Don't lock tables if we have used LOCK TABLE
if (!thd->locked_tables &&
@@ -1315,7 +1324,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
}
if (!do_optimize ||
- ((file->s->data_file_type == BLOCK_RECORD) ?
+ ((share->data_file_type == BLOCK_RECORD) ?
(share->state.changed & STATE_NOT_OPTIMIZED_ROWS) :
(file->state->del || share->state.split != file->state->records)) &&
(!(param.testflag & T_QUICK) ||
@@ -1334,7 +1343,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
statistics_done= 1;
/* TODO: Remove BLOCK_RECORD test when parallel works with blocks */
if (THDVAR(thd,repair_threads) > 1 &&
- file->s->data_file_type != BLOCK_RECORD)
+ share->data_file_type != BLOCK_RECORD)
{
char buf[40];
/* TODO: respect maria_repair_threads variable */
@@ -1396,18 +1405,17 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
/*
- the following 'if', thought conceptually wrong,
- is a useful optimization nevertheless.
+ repair updates share->state.state. Ensure that file->state is up to date
*/
- if (file->state != &file->s->state.state)
- file->s->state.state= *file->state;
- if (file->s->base.auto_key)
+ if (file->state != &share->state.state)
+ *file->state= share->state.state;
+ if (share->base.auto_key)
_ma_update_auto_increment_key(&param, file, 1);
if (optimize_done)
error= maria_update_state_info(&param, file,
- UPDATE_TIME | UPDATE_OPEN_COUNT |
- (local_testflag &
- T_STATISTICS ? UPDATE_STAT : 0));
+ UPDATE_TIME | UPDATE_OPEN_COUNT |
+ (local_testflag &
+ T_STATISTICS ? UPDATE_STAT : 0));
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
HA_STATUS_CONST);
if (rows != file->state->records && !(param.testflag & T_VERY_SILENT))
@@ -1667,6 +1675,8 @@ int ha_maria::enable_indexes(uint mode)
{
sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
my_errno, param.db_name, param.table_name);
+ /* This should never fail normally */
+ DBUG_ASSERT(0);
/* Repairing by sort failed. Now try standard repair method. */
param.testflag &= ~(T_REP_BY_SORT | T_QUICK);
error= (repair(thd, param, 0) != HA_ADMIN_OK);
@@ -1807,14 +1817,14 @@ void ha_maria::start_bulk_insert(ha_rows rows)
!= 0 Error
*/
-int ha_maria::end_bulk_insert()
+int ha_maria::end_bulk_insert(bool table_will_be_deleted)
{
int err;
DBUG_ENTER("ha_maria::end_bulk_insert");
- maria_end_bulk_insert(file);
+ maria_end_bulk_insert(file, table_will_be_deleted);
if ((err= maria_extra(file, HA_EXTRA_NO_CACHE, 0)))
goto end;
- if (can_enable_indexes)
+ if (can_enable_indexes && !table_will_be_deleted)
err= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
end:
if (bulk_insert_single_undo != BULK_INSERT_NONE)
@@ -2198,77 +2208,95 @@ int ha_maria::external_lock(THD *thd, int lock_type)
external_lock(F_UNLCK) will happen and we can then allow the user to
create transactional temporary tables.
*/
- if (!file->s->base.born_transactional)
- goto skip_transaction;
- if (lock_type != F_UNLCK)
+ if (file->s->base.born_transactional)
{
- if (!trn) /* no transaction yet - open it now */
- {
- trn= trnman_new_trn(& thd->mysys_var->mutex,
- & thd->mysys_var->suspend,
- thd->thread_stack + STACK_DIRECTION *
- (my_thread_stack_size - STACK_MIN_SIZE));
- if (unlikely(!trn))
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
-
- DBUG_PRINT("info", ("THD_TRN set to 0x%lx", (ulong)trn));
- THD_TRN= trn;
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
- trans_register_ha(thd, TRUE, maria_hton);
- }
- file->trn= trn;
- if (!trnman_increment_locked_tables(trn))
+ /* Transactional table */
+ if (lock_type != F_UNLCK)
{
- trans_register_ha(thd, FALSE, maria_hton);
- trnman_new_statement(trn);
+ /* Start of new statement */
+ if (!trn) /* no transaction yet - open it now */
+ {
+ trn= trnman_new_trn(& thd->mysys_var->mutex,
+ & thd->mysys_var->suspend,
+ thd->thread_stack + STACK_DIRECTION *
+ (my_thread_stack_size - STACK_MIN_SIZE));
+ if (unlikely(!trn))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ THD_TRN= trn;
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ trans_register_ha(thd, TRUE, maria_hton);
+ }
+ file->trn= trn;
+ if (!trnman_increment_locked_tables(trn))
+ {
+ trans_register_ha(thd, FALSE, maria_hton);
+ trnman_new_statement(trn);
+ }
+
+ if (file->s->lock.get_status)
+ {
+ if (_ma_setup_live_state(file))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ else
+ {
+ /*
+ Copy the current state. This may have been wrong if the same file
+ was used several times in the last statement. This should only
+ happen for temporary tables.
+ */
+ *file->state= file->s->state.state;
+ }
+
+ if (!thd->transaction.on)
+ {
+ /*
+ No need to log REDOs/UNDOs. If this is an internal temporary table
+ which will be renamed to a permanent table (like in ALTER TABLE),
+ the rename happens after unlocking so will be durable (and the table
+ will get its create_rename_lsn).
+ Note: if we wanted to enable users to have an old backup and apply
+ tons of archived logs to roll-forward, we could then not disable
+ REDOs/UNDOs in this case.
+ */
+ DBUG_PRINT("info", ("Disabling logging for table"));
+ _ma_tmp_disable_logging_for_table(file, TRUE);
+ }
}
- if (!thd->transaction.on)
+ else
{
+ /* End of transaction */
+
/*
- No need to log REDOs/UNDOs. If this is an internal temporary table
- which will be renamed to a permanent table (like in ALTER TABLE),
- the rename happens after unlocking so will be durable (and the table
- will get its create_rename_lsn).
- Note: if we wanted to enable users to have an old backup and apply
- tons of archived logs to roll-forward, we could then not disable
- REDOs/UNDOs in this case.
+ We always re-enable, don't rely on thd->transaction.on as it is
+ sometimes reset to true after unlocking (see mysql_truncate() for a
+ partitioned table based on Maria).
*/
- DBUG_PRINT("info", ("Disabling logging for table"));
- _ma_tmp_disable_logging_for_table(file, TRUE);
- }
- }
- else
- {
- /*
- We always re-enable, don't rely on thd->transaction.on as it is
- sometimes reset to true after unlocking (see mysql_truncate() for a
- partitioned table based on Maria).
- */
- if (_ma_reenable_logging_for_table(file, TRUE))
- DBUG_RETURN(1);
- /** @todo zero file->trn also in commit and rollback */
- file->trn= NULL;
- if (trn && trnman_has_locked_tables(trn))
- {
- if (!trnman_decrement_locked_tables(trn))
+ if (_ma_reenable_logging_for_table(file, TRUE))
+ DBUG_RETURN(1);
+ /** @todo zero file->trn also in commit and rollback */
+ file->trn= 0;
+ if (trn && trnman_has_locked_tables(trn))
{
- /* autocommit ? rollback a transaction */
-#ifdef MARIA_CANNOT_ROLLBACK
- if (ma_commit(trn))
- DBUG_RETURN(1);
- THD_TRN= 0;
-#else
- if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ if (!trnman_decrement_locked_tables(trn))
{
- trnman_rollback_trn(trn);
- DBUG_PRINT("info", ("THD_TRN set to 0x0"));
+ /* autocommit ? rollback a transaction */
+#ifdef MARIA_CANNOT_ROLLBACK
+ if (ma_commit(trn))
+ DBUG_RETURN(1);
THD_TRN= 0;
- }
+#else
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ {
+ trnman_rollback_trn(trn);
+ DBUG_PRINT("info", ("THD_TRN set to 0x0"));
+ THD_TRN= 0;
+ }
#endif
+ }
}
}
- }
-skip_transaction:
+ } /* if transactional table */
DBUG_RETURN(maria_lock_database(file, !table->s->tmp_table ?
lock_type : ((lock_type == F_UNLCK) ?
F_UNLCK : F_EXTRA_LCK)));
@@ -2787,7 +2815,7 @@ static int ha_maria_init(void *p)
maria_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
- res= maria_init() || ma_control_file_open(TRUE) ||
+ res= maria_init() || ma_control_file_open(TRUE, TRUE) ||
!init_pagecache(maria_pagecache,
(size_t) pagecache_buffer_size, pagecache_division_limit,
pagecache_age_threshold, maria_block_size, 0) ||
@@ -2844,50 +2872,39 @@ my_bool ha_maria::register_query_cache_table(THD *thd, char *table_name,
*/
*engine_data= 0;
- if (file->s->concurrent_insert)
- {
- /*
- If a concurrent INSERT has happened just before the currently
- processed SELECT statement, the total size of the table is
- unknown.
-
- To determine if the table size is known, the current thread's snap
- shot of the table size with the actual table size are compared.
+ /*
+ If a concurrent INSERT has happened just before the currently processed
+ SELECT statement, the total size of the table is unknown.
- If the table size is unknown the SELECT statement can't be cached.
+ To determine if the table size is known, the current thread's snap shot of
+ the table size with the actual table size are compared.
- When concurrent inserts are disabled at table open, mi_open()
- does not assign a get_status() function. In this case the local
- ("current") status is never updated. We would wrongly think that
- we cannot cache the statement.
- */
- ulonglong actual_data_file_length;
- ulonglong current_data_file_length;
+ If the table size is unknown the SELECT statement can't be cached.
+ */
- /*
- POSIX visibility rules specify that "2. Whatever memory values a
- thread can see when it unlocks a mutex <...> can also be seen by any
- thread that later locks the same mutex". In this particular case,
- concurrent insert thread had modified the data_file_length in
- MYISAM_SHARE before it has unlocked (or even locked)
- structure_guard_mutex. So, here we're guaranteed to see at least that
- value after we've locked the same mutex. We can see a later value
- (modified by some other thread) though, but it's ok, as we only want
- to know if the variable was changed, the actual new value doesn't matter
- */
- actual_data_file_length= file->s->state.state.data_file_length;
- current_data_file_length= file->save_state.data_file_length;
+ /*
+ POSIX visibility rules specify that "2. Whatever memory values a
+ thread can see when it unlocks a mutex <...> can also be seen by any
+ thread that later locks the same mutex". In this particular case,
+ concurrent insert thread had modified the data_file_length in
+ MYISAM_SHARE before it has unlocked (or even locked)
+ structure_guard_mutex. So, here we're guaranteed to see at least that
+ value after we've locked the same mutex. We can see a later value
+ (modified by some other thread) though, but it's ok, as we only want
+ to know if the variable was changed, the actual new value doesn't matter
+ */
+ actual_data_file_length= file->s->state.state.data_file_length;
+ current_data_file_length= file->state->data_file_length;
- if (!file->s->now_transactional &&
- current_data_file_length != actual_data_file_length)
- {
- /* Don't cache current statement. */
- DBUG_RETURN(FALSE);
- }
+ if (file->s->non_transactional_concurrent_insert &&
+ current_data_file_length != actual_data_file_length)
+ {
+ /* Don't cache current statement. */
+ return FALSE;
}
/* It is ok to try to cache current statement. */
- DBUG_RETURN(TRUE);
+ return TRUE;
}
#endif
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
index 28acb8a93ca..7cb506d89f9 100644
--- a/storage/maria/ha_maria.h
+++ b/storage/maria/ha_maria.h
@@ -122,7 +122,7 @@ public:
int enable_indexes(uint mode);
int indexes_are_disabled(void);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
ha_rows records_in_range(uint inx, key_range * min_key, key_range * max_key);
void update_create_info(HA_CREATE_INFO * create_info);
int create(const char *name, TABLE * form, HA_CREATE_INFO * create_info);
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index 8623835d108..d8248f5570b 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 Michael Widenius
+/* Copyright (C) 2007-2008 Michael Widenius
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -345,11 +345,11 @@ static uchar *store_page_range(uchar *to, MARIA_BITMAP_BLOCK *block,
uint block_size, ulong length,
uint *tot_ranges);
static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
- LEX_STRING *log_parts,
+ LEX_CUSTRING *log_parts,
uint *log_parts_count);
static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
const uchar *newrec,
- LEX_STRING *log_parts,
+ LEX_CUSTRING *log_parts,
uint *log_parts_count);
/****************************************************************************
@@ -518,7 +518,8 @@ my_bool _ma_init_block_record(MARIA_HA *info)
MYF(MY_WME))))
goto err;
- row->base_length= new_row->base_length= share->base_length;
+ info->row_base_length= share->base_length;
+ info->row_flag= share->base.default_row_flag;
/*
We need to reserve 'EXTRA_LENGTH_FIELDS' number of parts in
@@ -723,6 +724,7 @@ my_bool enough_free_entries(uchar *buff, uint block_size, uint wanted_entries)
@brief Extend a record area to fit a given size block
@fn extend_area_on_page()
+ @param info Handler if head page and 0 if tail page
@param buff Page buffer
@param dir Pointer to dir entry in buffer
@param rownr Row number we working on
@@ -753,7 +755,8 @@ my_bool enough_free_entries(uchar *buff, uint block_size, uint wanted_entries)
@retval 1 error (wrong info in block)
*/
-static my_bool extend_area_on_page(uchar *buff, uchar *dir,
+static my_bool extend_area_on_page(MARIA_HA *info,
+ uchar *buff, uchar *dir,
uint rownr, uint block_size,
uint request_length,
uint *empty_space, uint *ret_offset,
@@ -831,7 +834,9 @@ static my_bool extend_area_on_page(uchar *buff, uchar *dir,
int2store(dir, rec_offset);
/* Reset length, as this may be a deleted block */
int2store(dir+2, 0);
- _ma_compact_block_page(buff, block_size, rownr, 1);
+ _ma_compact_block_page(buff, block_size, rownr, 1,
+ info ? info->trn->min_read_from: 0,
+ info ? info->s->base.min_block_length : 0);
rec_offset= uint2korr(dir);
length= uint2korr(dir+2);
if (length < request_length)
@@ -934,7 +939,8 @@ static uint empty_space_on_page(uchar *buff, uint block_size)
*/
static inline my_bool
-make_space_for_directory(uchar *buff, uint block_size, uint max_entry,
+make_space_for_directory(MARIA_HA *info,
+ uchar *buff, uint block_size, uint max_entry,
uint count, uchar *first_dir, uint *empty_space,
uint *first_pos)
{
@@ -952,7 +958,9 @@ make_space_for_directory(uchar *buff, uint block_size, uint max_entry,
if ((uint) (first_dir - buff) < *first_pos + length_needed)
{
/* Create place for directory */
- _ma_compact_block_page(buff, block_size, max_entry - 1, 0);
+ _ma_compact_block_page(buff, block_size, max_entry - 1, 0,
+ info ? info->trn->min_read_from : 0,
+ info ? info->s->base.min_block_length : 0);
*first_pos= (uint2korr(first_dir) + uint2korr(first_dir + 2));
*empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
if (*empty_space < length_needed)
@@ -982,6 +990,7 @@ make_space_for_directory(uchar *buff, uint block_size, uint max_entry,
SYNOPSIS
find_free_position()
+ info Handler if head page and 0 otherwise
buff Page
block_size Size of page
res_rownr Store index to free position here
@@ -1013,7 +1022,8 @@ make_space_for_directory(uchar *buff, uint block_size, uint max_entry,
# Pointer to directory entry on page
*/
-static uchar *find_free_position(uchar *buff, uint block_size, uint *res_rownr,
+static uchar *find_free_position(MARIA_HA *info,
+ uchar *buff, uint block_size, uint *res_rownr,
uint *res_length, uint *empty_space)
{
uint max_entry, free_entry;
@@ -1062,7 +1072,7 @@ static uchar *find_free_position(uchar *buff, uint block_size, uint *res_rownr,
if (max_entry == MAX_ROWS_PER_PAGE)
DBUG_RETURN(0);
- if (make_space_for_directory(buff, block_size, max_entry, 1,
+ if (make_space_for_directory(info, buff, block_size, max_entry, 1,
first_dir, empty_space, &first_pos))
DBUG_RETURN(0);
@@ -1082,6 +1092,7 @@ static uchar *find_free_position(uchar *buff, uint block_size, uint *res_rownr,
@brief Enlarge page directory to hold more entries
@fn extend_directory()
+ @param info Handler if head page and 0 otherwise
@param buff Page buffer
@param block_size Block size
@param max_entry Number of directory entries on page
@@ -1100,8 +1111,9 @@ static uchar *find_free_position(uchar *buff, uint block_size, uint *res_rownr,
@retval 1 error (No data on page, fatal error)
*/
-static my_bool extend_directory(uchar *buff, uint block_size, uint max_entry,
- uint new_entry, uint *empty_space)
+static my_bool extend_directory(MARIA_HA *info, uchar *buff, uint block_size,
+ uint max_entry, uint new_entry,
+ uint *empty_space)
{
uint length, first_pos;
uchar *dir, *first_dir;
@@ -1114,7 +1126,7 @@ static my_bool extend_directory(uchar *buff, uint block_size, uint max_entry,
*/
first_dir= dir_entry_pos(buff, block_size, max_entry) + DIR_ENTRY_SIZE;
- if (make_space_for_directory(buff, block_size, max_entry,
+ if (make_space_for_directory(info, buff, block_size, max_entry,
new_entry - max_entry + 1,
first_dir, empty_space, &first_pos))
DBUG_RETURN(1);
@@ -1303,7 +1315,7 @@ static void calc_record_size(MARIA_HA *info, const uchar *record,
}
row->field_lengths_length= (uint) (field_length_data - row->field_lengths);
/*
- - row->base_length is base information we must have on a page in first
+ - info->row_base_length is base information we must have on a page in first
extent:
- flag byte (1) + is_nulls_extended (0 | 1) + null_bytes + pack_bytes +
table_checksum (0 | 1)
@@ -1315,7 +1327,7 @@ static void calc_record_size(MARIA_HA *info, const uchar *record,
- head_length is the amount of data for the head page
(ie, all fields except blobs)
*/
- row->min_length= (row->base_length +
+ row->min_length= (info->row_base_length +
(share->base.max_field_lengths ?
size_to_store_key_length(row->field_lengths_length) :
0));
@@ -1340,9 +1352,6 @@ static void calc_record_size(MARIA_HA *info, const uchar *record,
Move up all rows to start of page.
Move blocks that are directly after each other with one memmove.
- TODO LATER
- Remove TRANSID from rows that are visible to all transactions
-
SYNOPSIS
_ma_compact_block_page()
buff Page to compact
@@ -1350,14 +1359,17 @@ static void calc_record_size(MARIA_HA *info, const uchar *record,
rownr Put empty data after this row
extend_block If 1, extend the block at 'rownr' to cover the
whole block.
+ min_read_from If <> 0, remove all trid's that are less than this
*/
void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
- my_bool extend_block)
+ my_bool extend_block, TrID min_read_from,
+ uint min_row_length)
{
uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
uint page_pos, next_free_pos, start_of_found_block, diff, end_of_found_block;
+ uint freed_size= 0;
uchar *dir, *end;
DBUG_ENTER("_ma_compact_block_page");
DBUG_PRINT("enter", ("rownr: %u", rownr));
@@ -1379,13 +1391,29 @@ void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
uint row_length= uint2korr(end + 2);
DBUG_ASSERT(offset >= page_pos);
DBUG_ASSERT(buff + offset + row_length <= dir);
+ DBUG_ASSERT(row_length >= min_row_length || row_length == 0);
+
+ /* Row length can be zero if row is to be deleted */
+ if (min_read_from && row_length && (buff[offset] & ROW_FLAG_TRANSID))
+ {
+ TrID transid= transid_korr(buff+offset+1);
+ if (transid < min_read_from)
+ {
+ /* Remove transid from row by moving the start point of the row up */
+ buff[offset + TRANSID_SIZE]= buff[offset] & ~ROW_FLAG_TRANSID;
+ offset+= TRANSID_SIZE;
+ freed_size+= TRANSID_SIZE;
+ row_length-= TRANSID_SIZE;
+ int2store(end+2, row_length);
+ }
+ }
if (offset != next_free_pos)
{
uint length= (next_free_pos - start_of_found_block);
/*
- There was empty space before this and prev block
- Check if we have to move previous block up to page start
+ There was empty space before this and prev block
+ Check if we have to move previous block up to page start
*/
if (page_pos != start_of_found_block)
{
@@ -1399,6 +1427,27 @@ void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
}
int2store(end, offset - diff); /* correct current pos */
next_free_pos= offset + row_length;
+
+ if (unlikely(row_length < min_row_length) && row_length)
+ {
+ /*
+ This can only happen in the case we compacted transid and
+ the row become 'too short'
+
+ Move the current row down to it's right place and extend it
+ with 0.
+ */
+ DBUG_ASSERT(page_pos != start_of_found_block);
+ uint row_diff= min_row_length - row_length;
+ uint length= (next_free_pos - start_of_found_block);
+ bmove(buff + page_pos, buff + start_of_found_block, length);
+ bzero(buff+ page_pos + length, row_diff);
+ page_pos+= min_row_length;
+ int2store(end+2, min_row_length);
+ freed_size-= row_diff;
+ next_free_pos= start_of_found_block= page_pos;
+ diff= 0;
+ }
}
}
if (page_pos != start_of_found_block)
@@ -1419,11 +1468,53 @@ void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
for (dir= buff + end_of_found_block ; dir <= end ; dir+= DIR_ENTRY_SIZE)
{
uint offset= uint2korr(dir);
- uint row_length= uint2korr(dir + 2);
- uint row_end= offset + row_length;
+ uint row_length;
+ uint row_end;
if (!offset)
continue;
- DBUG_ASSERT(offset >= start_of_found_block && row_end <= next_free_pos);
+ row_length= uint2korr(dir + 2);
+ row_end= offset + row_length;
+ DBUG_ASSERT(offset >= start_of_found_block &&
+ row_end <= next_free_pos && row_length >= min_row_length);
+
+ if (min_read_from && (buff[offset] & ROW_FLAG_TRANSID))
+ {
+ TrID transid= transid_korr(buff + offset+1);
+ if (transid < min_read_from)
+ {
+ /* Remove transid from row */
+ buff[offset + TRANSID_SIZE]= buff[offset] & ~ROW_FLAG_TRANSID;
+ offset+= TRANSID_SIZE;
+ row_length-= TRANSID_SIZE;
+ int2store(dir+2, row_length);
+ }
+ if (unlikely(row_length < min_row_length))
+ {
+ /*
+ This can only happen in the case we compacted transid and
+ the row become 'too short'
+ */
+ uint row_diff= min_row_length - row_length;
+ if (next_free_pos < row_end + row_diff)
+ {
+ /*
+ Not enough space for extending next block with enough
+ end 0's. Move current data down to get place for them
+ */
+ uint move_down= row_diff - (next_free_pos - row_end);
+ bmove(buff + offset - move_down, buff + offset, row_length);
+ offset-= move_down;
+ }
+ /*
+ Extend the next block with 0, which will be part of current
+ row when the blocks are joined together later
+ */
+ bzero(buff + next_free_pos - row_diff, row_diff);
+ next_free_pos-= row_diff;
+ int2store(dir+2, min_row_length);
+ }
+ row_end= offset + row_length;
+ }
if (row_end != next_free_pos)
{
@@ -1441,6 +1532,7 @@ void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
int2store(dir, offset + diff); /* correct current pos */
next_free_pos= offset;
}
+
if (page_pos != end_of_found_block)
{
uint length= (end_of_found_block - next_free_pos);
@@ -1455,16 +1547,15 @@ void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
{
if (extend_block)
{
- /* Extend last block cover whole page */
+ /* Extend last block to cover whole page */
uint length= ((uint) (dir - buff) - start_of_found_block);
int2store(dir+2, length);
}
else
{
- /*
- TODO:
- Update (buff + EMPTY_SPACE_OFFSET) if we remove transid from rows
- */
+ /* Add length gained from freed transaction id's to this page */
+ uint length= uint2korr(buff+ EMPTY_SPACE_OFFSET) + freed_size;
+ int2store(buff + EMPTY_SPACE_OFFSET, length);
}
buff[PAGE_TYPE_OFFSET]&= ~(uchar) PAGE_CAN_BE_COMPACTED;
}
@@ -1590,7 +1681,8 @@ static my_bool get_head_or_tail_page(MARIA_HA *info,
goto crashed;
DBUG_ASSERT((res->buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type);
- if (!(dir= find_free_position(res->buff, block_size, &res->rownr,
+ if (!(dir= find_free_position(page_type == HEAD_PAGE ? info : 0,
+ res->buff, block_size, &res->rownr,
&res->length, &res->empty_space)))
goto crashed;
@@ -1598,7 +1690,11 @@ static my_bool get_head_or_tail_page(MARIA_HA *info,
{
if (res->empty_space + res->length >= length)
{
- _ma_compact_block_page(res->buff, block_size, res->rownr, 1);
+ _ma_compact_block_page(res->buff, block_size, res->rownr, 1,
+ page_type == HEAD_PAGE ?
+ info->trn->min_read_from : 0,
+ page_type == HEAD_PAGE ?
+ share->base.min_block_length : 0);
/* All empty space are now after current position */
dir= dir_entry_pos(res->buff, block_size, res->rownr);
res->length= res->empty_space= uint2korr(dir+2);
@@ -1685,8 +1781,8 @@ static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info,
max_entry= (uint) buff[DIR_COUNT_OFFSET];
if (max_entry <= rownr)
{
- if (extend_directory(buff, block_size, max_entry, rownr,
- &res->empty_space))
+ if (extend_directory(page_type == HEAD_PAGE ? info : 0, buff, block_size,
+ max_entry, rownr, &res->empty_space))
goto err;
}
@@ -1701,7 +1797,8 @@ static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info,
}
#endif
- if (extend_area_on_page(buff, dir, rownr, block_size, length,
+ if (extend_area_on_page(page_type == HEAD_PAGE ? info : 0, buff, dir,
+ rownr, block_size, length,
&res->empty_space, &rec_offset, &max_length))
goto err;
@@ -1837,7 +1934,7 @@ static my_bool write_tail(MARIA_HA *info,
/* Increase data file size, if extended */
position= (my_off_t) block->page * block_size;
- if (info->state->data_file_length <= position)
+ if (share->state.state.data_file_length <= position)
{
/*
We are modifying a state member before writing the UNDO; this is a WAL
@@ -1845,7 +1942,7 @@ static my_bool write_tail(MARIA_HA *info,
data_file_length after writing any log record (FILE_ID/REDO/UNDO) (see
collect_tables()).
*/
- info->state->data_file_length= position + block_size;
+ _ma_set_share_data_file_length(share, position + block_size);
}
if (block_is_read)
@@ -1923,8 +2020,8 @@ static my_bool write_full_pages(MARIA_HA *info,
sub_blocks= block->sub_blocks;
position= (my_off_t) (page + page_count) * block_size;
- if (info->state->data_file_length < position)
- info->state->data_file_length= position;
+ if (share->state.state.data_file_length < position)
+ _ma_set_share_data_file_length(share, position);
/* Increase data file size, if extended */
@@ -1947,8 +2044,8 @@ static my_bool write_full_pages(MARIA_HA *info,
(ulong) block->page, (ulong) block->page_count));
position= (page + page_count + 1) * block_size;
- if (info->state->data_file_length < position)
- info->state->data_file_length= position;
+ if (share->state.state.data_file_length < position)
+ _ma_set_share_data_file_length(share, position);
}
lsn_store(buff, lsn);
buff[PAGE_TYPE_OFFSET]= (uchar) BLOB_PAGE;
@@ -2407,7 +2504,7 @@ static my_bool write_block_record(MARIA_HA *info,
end_of_data= data + row_pos->length;
/* Write header */
- flag= share->base.default_row_flag;
+ flag= info->row_flag;
row_extents_in_use= 0;
if (unlikely(row->total_length > row_pos->length))
{
@@ -2420,6 +2517,12 @@ static my_bool write_block_record(MARIA_HA *info,
}
/* For now we have only a minimum header */
*data++= (uchar) flag;
+ if (flag & ROW_FLAG_TRANSID)
+ {
+ transid_store(data, info->trn->trid);
+ data+= TRANSID_SIZE;
+ }
+
if (unlikely(flag & ROW_FLAG_NULLS_EXTENDED))
*data++= (uchar) (share->base.null_bytes -
share->base.original_null_bytes);
@@ -2900,8 +3003,8 @@ static my_bool write_block_record(MARIA_HA *info,
/* Increase data file size, if extended */
position= (my_off_t) head_block->page * block_size;
- if (info->state->data_file_length <= position)
- info->state->data_file_length= position + block_size;
+ if (share->state.state.data_file_length <= position)
+ _ma_set_share_data_file_length(share, position + block_size);
if (head_block_is_read)
{
@@ -3048,7 +3151,7 @@ static my_bool write_block_record(MARIA_HA *info,
lsn= LSN_IMPOSSIBLE;
if (share->now_transactional)
{
- LEX_STRING *log_array= info->log_row_parts;
+ LEX_CUSTRING *log_array= info->log_row_parts;
if (undo_lsn != LSN_ERROR)
{
@@ -3103,7 +3206,7 @@ static my_bool write_block_record(MARIA_HA *info,
log_array[TRANSLOG_INTERNAL_PARTS +
0].length,
TRANSLOG_INTERNAL_PARTS + 1,
- (LEX_CUSTRING *)log_array,
+ log_array,
log_data + LSN_STORE_SIZE, &checksum_delta))
goto disk_err;
}
@@ -3141,7 +3244,7 @@ static my_bool write_block_record(MARIA_HA *info,
row_length),
TRANSLOG_INTERNAL_PARTS + 2 +
row_parts_count,
- (LEX_CUSTRING *)log_array,
+ log_array,
log_data + LSN_STORE_SIZE,
&checksum_delta))
goto disk_err;
@@ -3477,7 +3580,7 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
*/
block.org_bitmap_value= _ma_free_size_to_head_pattern(&share->bitmap,
org_empty_size);
- if (extend_area_on_page(buff, dir, rownr, block_size,
+ if (extend_area_on_page(info, buff, dir, rownr, block_size,
new_row->total_length, &org_empty_size,
&rec_offset, &length))
goto err;
@@ -3528,7 +3631,9 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
(new_row->total_length <= head_length &&
org_empty_size + head_length >= new_row->total_length)))
{
- _ma_compact_block_page(buff, block_size, rownr, 1);
+ _ma_compact_block_page(buff, block_size, rownr, 1,
+ info->trn->min_read_from,
+ share->base.min_block_length);
org_empty_size= 0;
head_length= uint2korr(dir + 2);
}
@@ -3626,7 +3731,7 @@ static my_bool _ma_update_at_original_place(MARIA_HA *info,
of the row
*/
empty_size= org_empty_size;
- if (extend_area_on_page(buff, dir, rownr, block_size,
+ if (extend_area_on_page(info, buff, dir, rownr, block_size,
length_on_head_page, &empty_size,
&rec_offset, &length))
goto err;
@@ -3657,8 +3762,13 @@ static my_bool _ma_update_at_original_place(MARIA_HA *info,
_ma_bitmap_get_page_bits(info, &info->s->bitmap, page));
block->used|= BLOCKUSED_USE_ORG_BITMAP;
+ /*
+ We have to use <= below as the new_row may be smaller than the original
+ row as the new row doesn't have transaction id
+ */
+
DBUG_ASSERT(blocks->count > 1 ||
- max(new_row->total_length, share->base.min_block_length) ==
+ max(new_row->total_length, share->base.min_block_length) <=
length_on_head_page);
if ((res= write_block_record(info, oldrec, record, new_row, blocks,
@@ -4026,7 +4136,7 @@ my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record)
0].length + row_length +
extents_length),
TRANSLOG_INTERNAL_PARTS + 2 + row_parts_count,
- (LEX_CUSTRING *)info->log_row_parts,
+ info->log_row_parts,
log_data + LSN_STORE_SIZE,
&checksum_delta))
goto err;
@@ -4202,7 +4312,8 @@ static uchar *read_next_extent(MARIA_HA *info, MARIA_EXTENT_CURSOR *extent,
if (!buff)
{
/* check if we tried to read over end of file (ie: bad data in record) */
- if ((extent->page + 1) * share->block_size > info->state->data_file_length)
+ if ((extent->page + 1) * share->block_size >
+ share->state.state.data_file_length)
goto crashed;
DBUG_RETURN(0);
}
@@ -4358,6 +4469,15 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record,
cur_row->full_page_count= cur_row->tail_count= 0;
cur_row->blob_length= 0;
+ if (flag & ROW_FLAG_TRANSID)
+ {
+ cur_row->trid= transid_korr(data+1);
+ if (!info->trn)
+ DBUG_RETURN(my_errno= HA_ERR_WRONG_IN_RECORD); /* File crashed */
+ if (!trnman_can_read_from(info->trn, cur_row->trid))
+ DBUG_RETURN(my_errno= HA_ERR_ROW_NOT_VISIBLE);
+ }
+
/* Skip trans header (for now, until we have MVCC csupport) */
data+= total_header_size[(flag & PRECALC_HEADER_BITMASK)];
if (flag & ROW_FLAG_NULLS_EXTENDED)
@@ -4981,10 +5101,11 @@ int _ma_scan_block_record(MARIA_HA *info, uchar *record,
restart_record_read:
/* Find next row in current page */
- if (likely(record_pos < info->scan.number_of_rows))
+ while (likely(record_pos < info->scan.number_of_rows))
{
uint length, offset;
uchar *data, *end_of_data;
+ int error;
while (!(offset= uint2korr(info->scan.dir)))
{
@@ -5014,7 +5135,10 @@ restart_record_read:
}
#endif
DBUG_PRINT("info", ("rowid: %lu", (ulong) info->cur_row.lastpos));
- DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data));
+ error= _ma_read_block_record2(info, record, data, end_of_data);
+ if (error != HA_ERR_ROW_NOT_VISIBLE)
+ DBUG_RETURN(error);
+ record_pos++;
}
/* Find next head page in current bitmap */
@@ -5094,7 +5218,7 @@ restart_bitmap_scan:
/* Read next bitmap */
info->scan.bitmap_page+= share->bitmap.pages_covered;
filepos= (my_off_t) info->scan.bitmap_page * block_size;
- if (unlikely(filepos >= info->state->data_file_length))
+ if (unlikely(filepos >= share->state.state.data_file_length))
{
DBUG_PRINT("info", ("Found end of file"));
DBUG_RETURN((my_errno= HA_ERR_END_OF_FILE));
@@ -5253,7 +5377,7 @@ static ulong ma_get_length(const uchar **packet)
*/
static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
- LEX_STRING *log_parts,
+ LEX_CUSTRING *log_parts,
uint *log_parts_count)
{
MARIA_SHARE *share= info->s;
@@ -5261,14 +5385,13 @@ static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
uchar *field_lengths= info->cur_row.field_lengths;
size_t row_length;
MARIA_ROW *cur_row= &info->cur_row;
- LEX_STRING *start_log_parts;
+ LEX_CUSTRING *start_log_parts;
DBUG_ENTER("fill_insert_undo_parts");
start_log_parts= log_parts;
/* Store null bits */
- /* We cast "const uchar*" to char* but won't change its pointed content */
- log_parts->str= (char*)record;
+ log_parts->str= record;
log_parts->length= share->base.null_bytes;
row_length= log_parts->length;
log_parts++;
@@ -5433,7 +5556,7 @@ static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
const uchar *newrec,
- LEX_STRING *log_parts,
+ LEX_CUSTRING *log_parts,
uint *log_parts_count)
{
MARIA_SHARE *share= info->s;
@@ -5444,7 +5567,7 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
uchar *new_field_lengths= new_row->field_lengths;
size_t row_length= 0;
uint field_lengths;
- LEX_STRING *start_log_parts;
+ LEX_CUSTRING *start_log_parts;
my_bool new_column_is_empty;
DBUG_ENTER("fill_update_undo_parts");
@@ -5461,8 +5584,7 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
{
/* Store changed null bits */
*field_data++= (uchar) 255; /* Special case */
- /* We cast "const uchar*" to char* but won't change its pointed content */
- log_parts->str= (char*) oldrec;
+ log_parts->str= oldrec;
log_parts->length= share->base.null_bytes;
row_length= log_parts->length;
log_parts++;
@@ -5601,8 +5723,7 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
(start_field_data -
ma_calc_length_for_store_length(field_lengths)));
ma_store_length((uchar *) start_log_parts->str, field_lengths);
- start_log_parts->length= (size_t) ((char*) field_data -
- start_log_parts->str);
+ start_log_parts->length= (size_t) (field_data - start_log_parts->str);
row_length+= start_log_parts->length;
DBUG_RETURN(row_length);
}
@@ -5672,7 +5793,6 @@ my_bool write_hook_for_undo(enum translog_record_type type
if (unlikely(LSN_WITH_FLAGS_TO_LSN(trn->first_undo_lsn) == 0))
trn->first_undo_lsn=
trn->undo_lsn | LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
- DBUG_ASSERT(tbl_info->state == &tbl_info->s->state.state);
return 0;
/*
when we implement purging, we will specialize this hook: UNDO_PURGE
@@ -5694,14 +5814,13 @@ my_bool write_hook_for_redo_delete_all(enum translog_record_type type
__attribute__ ((unused)),
LSN *lsn, void *hook_arg)
{
- DBUG_ASSERT(tbl_info->state == &tbl_info->s->state.state);
_ma_reset_status(tbl_info);
return write_hook_for_redo(type, trn, tbl_info, lsn, hook_arg);
}
/**
- @brief Upates "records" and "checksum" and calls the generic UNDO hook
+ @brief Updates "records" and "checksum" and calls the generic UNDO hook
@return Operation status, always 0 (success)
*/
@@ -5848,10 +5967,10 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
STATE_NOT_MOVABLE);
end_of_page= (page + 1) * share->block_size;
- if (end_of_page > info->state->data_file_length)
+ if (end_of_page > share->state.state.data_file_length)
{
DBUG_PRINT("info", ("Enlarging data file from %lu to %lu",
- (ulong) info->state->data_file_length,
+ (ulong) share->state.state.data_file_length,
(ulong) end_of_page));
/*
New page at end of file. Note that the test above is also positive if
@@ -5918,8 +6037,8 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
goto crashed_file;
make_empty_page(info, buff, page_type, 0);
empty_space= block_size - PAGE_HEADER_SIZE - PAGE_SUFFIX_SIZE;
- (void) extend_directory(buff, block_size, 0, rownr,
- &empty_space);
+ (void) extend_directory(page_type == HEAD_PAGE ? info: 0, buff,
+ block_size, 0, rownr, &empty_space);
rec_offset= PAGE_HEADER_SIZE;
dir= dir_entry_pos(buff, block_size, rownr);
empty_space+= uint2korr(dir+2);
@@ -5936,11 +6055,12 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
if (max_entry <= rownr)
{
/* Add directory entry first in directory and data last on page */
- if (extend_directory(buff, block_size, max_entry, rownr,
- &empty_space))
+ if (extend_directory(page_type == HEAD_PAGE ? info : 0, buff,
+ block_size, max_entry, rownr, &empty_space))
goto crashed_file;
}
- if (extend_area_on_page(buff, dir, rownr, block_size,
+ if (extend_area_on_page(page_type == HEAD_PAGE ? info : 0, buff,
+ dir, rownr, block_size,
(uint) data_length, &empty_space,
&rec_offset, &length))
goto crashed_file;
@@ -5982,7 +6102,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
case we extended the file. We could not do it earlier: bitmap code tests
data_file_length to know if it has to create a new page or not.
*/
- set_if_bigger(info->state->data_file_length, end_of_page);
+ set_if_bigger(share->state.state.data_file_length, end_of_page);
DBUG_RETURN(result);
crashed_file:
@@ -6312,13 +6432,13 @@ uint _ma_apply_redo_insert_row_blobs(MARIA_HA *info,
continue;
if (((page + 1) * share->block_size) >
- info->state->data_file_length)
+ share->state.state.data_file_length)
{
/* New page or half written page at end of file */
DBUG_PRINT("info", ("Enlarging data file from %lu to %lu",
- (ulong) info->state->data_file_length,
+ (ulong) share->state.state.data_file_length,
(ulong) ((page + 1 ) * share->block_size)));
- info->state->data_file_length= (page + 1) * share->block_size;
+ share->state.state.data_file_length= (page + 1) * share->block_size;
buff= info->keyread_buff;
info->keyread_buff_used= 1;
make_empty_page(info, buff, BLOB_PAGE, 0);
@@ -6485,7 +6605,7 @@ err:
/** Execute undo of a row delete (insert the row back where it was) */
my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
- uchar *header, size_t header_length
+ const uchar *header, size_t header_length
__attribute__((unused)))
{
MARIA_SHARE *share= info->s;
@@ -6543,16 +6663,17 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
null_bits= header;
header+= share->base.null_bytes;
- row.empty_bits= header;
+ /* This will not be changed */
+ row.empty_bits= (uchar*) header;
header+= share->base.pack_bytes;
if (share->base.max_field_lengths)
{
row.field_lengths_length= uint2korr(header);
- row.field_lengths= header + 2 ;
+ row.field_lengths= (uchar*) header + 2 ;
header+= 2 + row.field_lengths_length;
}
if (share->base.blobs)
- row.blob_length= ma_get_length((const uchar**)&header);
+ row.blob_length= ma_get_length((uchar**) &header);
/* We need to build up a record (without blobs) in rec_buff */
if (!(record= my_malloc(share->base.reclength, MYF(MY_WME))))
@@ -6663,7 +6784,7 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
DBUG_ASSERT(0);
}
}
- row.head_length= (row.base_length +
+ row.head_length= (info->row_base_length +
share->base.fixed_not_null_fields_length +
row.field_lengths_length +
size_to_store_key_length(row.field_lengths_length) +
@@ -6728,7 +6849,8 @@ err:
*/
my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
- uchar *header, size_t header_length
+ const uchar *header,
+ size_t header_length
__attribute__((unused)))
{
MARIA_SHARE *share= info->s;
@@ -6766,8 +6888,8 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
Set header to point to old field values, generated by
fill_update_undo_parts()
*/
- field_length_header= ma_get_length((const uchar**)&header);
- field_length_data= header;
+ field_length_header= ma_get_length((uchar**) &header);
+ field_length_data= (uchar*) header;
header+= field_length_header;
field_length_data_end= header;
@@ -6933,3 +7055,24 @@ maria_page_get_lsn(uchar *page,
#endif
return lsn_korr(page);
}
+
+
+/**
+ @brief Enable reading of all rows, ignoring versioning
+
+ @note
+ This is mainly useful in single user applications, like maria_pack,
+ where we want to be able to read all rows without having to read the
+ transaction id from the control file
+*/
+
+void maria_ignore_trids(MARIA_HA *info)
+{
+ if (info->s->base.born_transactional)
+ {
+ if (!info->trn)
+ info->trn= &dummy_transaction_object;
+ /* Ignore transaction id when row is read */
+ info->trn->min_read_from= ~(TrID) 0;
+ }
+}
diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h
index 05c5b99e8d0..36d61852086 100644
--- a/storage/maria/ma_blockrec.h
+++ b/storage/maria/ma_blockrec.h
@@ -63,14 +63,13 @@
#define PAGE_TYPE_MASK 7
enum en_page_type { UNALLOCATED_PAGE, HEAD_PAGE, TAIL_PAGE, BLOB_PAGE, MAX_PAGE_TYPE };
+#define PAGE_CAN_BE_COMPACTED 128 /* Bit in PAGE_TYPE */
#define PAGE_TYPE_OFFSET LSN_SIZE
#define DIR_COUNT_OFFSET (LSN_SIZE+PAGE_TYPE_SIZE)
#define DIR_FREE_OFFSET (DIR_COUNT_OFFSET+DIR_COUNT_SIZE)
#define EMPTY_SPACE_OFFSET (DIR_FREE_OFFSET+DIR_FREE_SIZE)
-#define PAGE_CAN_BE_COMPACTED 128 /* Bit in PAGE_TYPE */
-
/* Bits used for flag uchar (one byte, first in record) */
#define ROW_FLAG_TRANSID 1
#define ROW_FLAG_VER_PTR 2
@@ -174,7 +173,8 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info);
my_bool _ma_compare_block_record(register MARIA_HA *info,
register const uchar *record);
void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
- my_bool extend_block);
+ my_bool extend_block, TrID min_read_from,
+ uint min_row_length);
TRANSLOG_ADDRESS
maria_page_get_lsn(uchar *page, pgcache_page_no_t page_no, uchar* data_ptr);
@@ -243,9 +243,9 @@ my_bool _ma_apply_redo_bitmap_new_page(MARIA_HA *info, LSN lsn,
my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
const uchar *header);
my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
- uchar *header, size_t length);
+ const uchar *header, size_t length);
my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
- uchar *header, size_t length);
+ const uchar *header, size_t length);
my_bool _ma_apply_undo_bulk_insert(MARIA_HA *info, LSN undo_lsn);
my_bool write_hook_for_redo(enum translog_record_type type,
@@ -272,3 +272,7 @@ my_bool write_hook_for_undo_bulk_insert(enum translog_record_type type,
my_bool write_hook_for_file_id(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
void *hook_arg);
+void _ma_block_get_status(void* param, my_bool concurrent_insert);
+void _ma_block_update_status(void *param);
+void _ma_block_restore_status(void *param);
+my_bool _ma_block_check_status(void *param);
diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c
index 4db12c3a16c..0844c932ab2 100644
--- a/storage/maria/ma_check.c
+++ b/storage/maria/ma_check.c
@@ -99,8 +99,11 @@ static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file);
static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
MARIA_HA *info);
static TrID max_trid_in_system(void);
+static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid);
+/* Initialize check param with default values */
+
void maria_chk_init(HA_CHECK *param)
{
bzero((uchar*) param,sizeof(*param));
@@ -121,9 +124,30 @@ void maria_chk_init(HA_CHECK *param)
param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
}
+
+/* Initialize check param and maria handler for check of table */
+
+void maria_chk_init_for_check(HA_CHECK *param, MARIA_HA *info)
+{
+ param->not_visible_rows_found= 0;
+ param->max_found_trid= 0;
+
+ /*
+ Set up transaction handler so that we can see all rows. When rows is read
+ we will check the found id against param->max_tried
+ */
+ if (!ma_control_file_inited())
+ param->max_trid= 0; /* Give warning for first trid found */
+ else
+ param->max_trid= max_trid_in_system();
+
+ maria_ignore_trids(info);
+}
+
+
/* Check the status flags for the table */
-int maria_chk_status(HA_CHECK *param, register MARIA_HA *info)
+int maria_chk_status(HA_CHECK *param, MARIA_HA *info)
{
MARIA_SHARE *share= info->s;
@@ -177,7 +201,7 @@ int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
puts("- check record delete-chain");
next_link=share->state.dellink;
- if (info->state->del == 0)
+ if (share->state.state.del == 0)
{
if (test_flag & T_VERBOSE)
{
@@ -189,13 +213,13 @@ int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
if (test_flag & T_VERBOSE)
printf("Recordlinks: ");
empty=0;
- for (i= info->state->del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
+ for (i= share->state.state.del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
{
if (*_ma_killed_ptr(param))
DBUG_RETURN(1);
if (test_flag & T_VERBOSE)
printf(" %9s",llstr(next_link,buff));
- if (next_link >= info->state->data_file_length)
+ if (next_link >= share->state.state.data_file_length)
goto wrong;
if (my_pread(info->dfile.file, (uchar*) buff, delete_link_length,
next_link,MYF(MY_NABP)))
@@ -232,28 +256,28 @@ int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
empty+=share->base.pack_reclength;
}
}
- if (info->state->del && (test_flag & T_VERBOSE))
+ if (share->state.state.del && (test_flag & T_VERBOSE))
puts("\n");
- if (empty != info->state->empty)
+ if (empty != share->state.state.empty)
{
_ma_check_print_warning(param,
"Found %s deleted space in delete link chain. Should be %s",
llstr(empty,buff2),
- llstr(info->state->empty,buff));
+ llstr(share->state.state.empty,buff));
}
if (next_link != HA_OFFSET_ERROR)
{
_ma_check_print_error(param,
"Found more than the expected %s deleted rows in delete link chain",
- llstr(info->state->del, buff));
+ llstr(share->state.state.del, buff));
goto wrong;
}
if (i != 0)
{
_ma_check_print_error(param,
"Found %s deleted rows in delete link chain. Should be %s",
- llstr(info->state->del - i, buff2),
- llstr(info->state->del, buff));
+ llstr(share->state.state.del - i, buff2),
+ llstr(share->state.state.del, buff));
goto wrong;
}
}
@@ -283,7 +307,7 @@ static int check_k_link(HA_CHECK *param, register MARIA_HA *info,
if (next_link == HA_OFFSET_ERROR)
DBUG_RETURN(0); /* Avoid printing empty line */
- records= (ha_rows) (info->state->key_file_length / block_size);
+ records= (ha_rows) (share->state.state.key_file_length / block_size);
while (next_link != HA_OFFSET_ERROR && records > 0)
{
if (*_ma_killed_ptr(param))
@@ -292,13 +316,13 @@ static int check_k_link(HA_CHECK *param, register MARIA_HA *info,
printf("%16s",llstr(next_link,llbuff));
/* Key blocks must lay within the key file length entirely. */
- if (next_link + block_size > info->state->key_file_length)
+ if (next_link + block_size > share->state.state.key_file_length)
{
/* purecov: begin tested */
_ma_check_print_error(param, "Invalid key block position: %s "
"key block size: %u file_length: %s",
llstr(next_link, llbuff), block_size,
- llstr(info->state->key_file_length, llbuff2));
+ llstr(share->state.state.key_file_length, llbuff2));
DBUG_RETURN(1);
/* purecov: end */
}
@@ -372,7 +396,7 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
_ma_check_print_error(param, "Failed to flush data or index file");
size= my_seek(share->kfile.file, 0L, MY_SEEK_END, MYF(MY_THREADSAFE));
- if ((skr=(my_off_t) info->state->key_file_length) != size)
+ if ((skr=(my_off_t) share->state.state.key_file_length) != size)
{
/* Don't give error if file generated by mariapack */
if (skr > size && maria_is_any_key_active(share->state.key_map))
@@ -389,26 +413,26 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
}
if (!(param->testflag & T_VERY_SILENT) &&
! (share->options & HA_OPTION_COMPRESS_RECORD) &&
- ulonglong2double(info->state->key_file_length) >
+ ulonglong2double(share->state.state.key_file_length) >
ulonglong2double(share->base.margin_key_file_length)*0.9)
_ma_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
- llstr(info->state->key_file_length,buff),
+ llstr(share->state.state.key_file_length,buff),
llstr(share->base.max_key_file_length-1,buff));
size= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
- skr=(my_off_t) info->state->data_file_length;
+ skr=(my_off_t) share->state.state.data_file_length;
if (share->options & HA_OPTION_COMPRESS_RECORD)
skr+= MEMMAP_EXTRA_MARGIN;
#ifdef USE_RELOC
- if (info->data_file_type == STATIC_RECORD &&
+ if (share->data_file_type == STATIC_RECORD &&
skr < (my_off_t) share->base.reloc*share->base.min_pack_length)
skr=(my_off_t) share->base.reloc*share->base.min_pack_length;
#endif
if (skr != size)
{
- info->state->data_file_length=size; /* Skip other errors */
if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
{
+ share->state.state.data_file_length=size; /* Skip other errors */
error=1;
_ma_check_print_error(param,"Size of datafile is: %-9s Should be: %s",
llstr(size,buff), llstr(skr,buff2));
@@ -423,10 +447,10 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
}
if (!(param->testflag & T_VERY_SILENT) &&
!(share->options & HA_OPTION_COMPRESS_RECORD) &&
- ulonglong2double(info->state->data_file_length) >
+ ulonglong2double(share->state.state.data_file_length) >
(ulonglong2double(share->base.max_data_file_length)*0.9))
_ma_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
- llstr(info->state->data_file_length,buff),
+ llstr(share->state.state.data_file_length,buff),
llstr(share->base.max_data_file_length-1,buff2));
DBUG_RETURN(error);
} /* maria_chk_size */
@@ -464,8 +488,8 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
init_checksum=param->record_checksum;
old_record_checksum=0;
if (share->data_file_type == STATIC_RECORD)
- old_record_checksum= (calc_checksum(info->state->records +
- info->state->del-1) *
+ old_record_checksum= (calc_checksum(share->state.state.records +
+ share->state.state.del-1) *
share->base.pack_reclength);
rec_per_key_part= param->new_rec_per_key_part;
for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
@@ -494,7 +518,7 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
full_text_keys++;
if (share->state.key_root[key] == HA_OFFSET_ERROR)
{
- if (info->state->records != 0 && !(keyinfo->flag & HA_FULLTEXT))
+ if (share->state.state.records != 0 && !(keyinfo->flag & HA_FULLTEXT))
_ma_check_print_error(param, "Key tree %u is empty", key + 1);
goto do_stat;
}
@@ -518,10 +542,10 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
DBUG_RETURN(-1);
if(!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL)))
{
- if (keys != info->state->records)
+ if (keys != share->state.state.records)
{
_ma_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
- llstr(info->state->records,buff2));
+ llstr(share->state.state.records,buff2));
if (!(param->testflag & T_INFO))
DBUG_RETURN(-1);
result= -1;
@@ -601,7 +625,7 @@ do_stat:
maria_update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
param->notnull_count: NULL,
- (ulonglong)info->state->records);
+ (ulonglong)share->state.state.records);
}
if (param->testflag & T_INFO)
{
@@ -615,7 +639,7 @@ do_stat:
else if (all_totaldata != 0L && maria_is_any_key_active(share->state.key_map))
puts("");
}
- if (param->key_file_blocks != info->state->key_file_length &&
+ if (param->key_file_blocks != share->state.state.key_file_length &&
share->state.key_map == ~(ulonglong) 0)
_ma_check_print_warning(param, "Some data are unreferenced in keyfile");
if (found_keys != full_text_keys)
@@ -633,10 +657,11 @@ static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
ha_checksum *key_checksum, uint level)
{
char llbuff[22],llbuff2[22];
+ MARIA_SHARE *share= info->s;
DBUG_ENTER("chk_index_down");
/* Key blocks must lay within the key file length entirely. */
- if (page + keyinfo->block_length > info->state->key_file_length)
+ if (page + keyinfo->block_length > share->state.state.key_file_length)
{
/* purecov: begin tested */
/* Give it a chance to fit in the real file size. */
@@ -645,12 +670,13 @@ static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
_ma_check_print_error(param, "Invalid key block position: %s "
"key block size: %u file_length: %s",
llstr(page, llbuff), keyinfo->block_length,
- llstr(info->state->key_file_length, llbuff2));
+ llstr(share->state.state.key_file_length, llbuff2));
if (page + keyinfo->block_length > max_length)
goto err;
/* Fix the remembered key file length. */
- info->state->key_file_length= (max_length &
- ~ (my_off_t) (keyinfo->block_length - 1));
+ share->state.state.key_file_length= (max_length &
+ ~ (my_off_t) (keyinfo->block_length -
+ 1));
/* purecov: end */
}
@@ -917,7 +943,7 @@ static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
}
/* fall through */
}
- if (record >= info->state->data_file_length)
+ if (record >= share->state.state.data_file_length)
{
#ifndef DBUG_OFF
char llbuff2[22], llbuff3[22];
@@ -925,7 +951,7 @@ static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
_ma_check_print_error(param,"Found key at page %s that points to record outside datafile",llstr(page,llbuff));
DBUG_PRINT("test",("page: %s record: %s filelength: %s",
llstr(page,llbuff),llstr(record,llbuff2),
- llstr(info->state->data_file_length,llbuff3)));
+ llstr(share->state.state.data_file_length,llbuff3)));
DBUG_DUMP("key",(uchar*) key,key_length);
DBUG_DUMP("new_in_page", old_keypos, (uint) (keypos-old_keypos));
goto err;
@@ -1102,7 +1128,7 @@ static int check_static_record(HA_CHECK *param, MARIA_HA *info, int extend,
char llbuff[22];
pos= 0;
- while (pos < info->state->data_file_length)
+ while (pos < share->state.state.data_file_length)
{
if (*_ma_killed_ptr(param))
return -1;
@@ -1149,7 +1175,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
LINT_INIT(to);
pos= 0;
- while (pos < info->state->data_file_length)
+ while (pos < share->state.state.data_file_length)
{
my_bool got_error= 0;
int flag;
@@ -1204,9 +1230,9 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
DBUG_RETURN(1);
}
if ((block_info.next_filepos != HA_OFFSET_ERROR &&
- block_info.next_filepos >= info->state->data_file_length) ||
+ block_info.next_filepos >= share->state.state.data_file_length) ||
(block_info.prev_filepos != HA_OFFSET_ERROR &&
- block_info.prev_filepos >= info->state->data_file_length))
+ block_info.prev_filepos >= share->state.state.data_file_length))
{
_ma_check_print_error(param,"Delete link points outside datafile at %s",
llstr(pos,llbuff));
@@ -1224,7 +1250,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
llstr(start_block,llbuff));
DBUG_RETURN(1);
}
- if (info->state->data_file_length < block_info.filepos+
+ if (share->state.state.data_file_length < block_info.filepos+
block_info.block_len)
{
_ma_check_print_error(param,
@@ -1298,7 +1324,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
got_error=1;
break;
}
- if (info->state->data_file_length < block_info.next_filepos)
+ if (share->state.state.data_file_length < block_info.next_filepos)
{
_ma_check_print_error(param,
"Found next-recordlink that points outside datafile at %s",
@@ -1367,7 +1393,7 @@ static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend,
DBUG_ENTER("check_compressed_record");
pos= share->pack.header_length; /* Skip header */
- while (pos < info->state->data_file_length)
+ while (pos < share->state.state.data_file_length)
{
if (*_ma_killed_ptr(param))
DBUG_RETURN(-1);
@@ -1600,19 +1626,22 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
if (length < share->base.min_block_length)
{
_ma_check_print_error(param,
- "Page %9s: Row %3u is too short (%d bytes)",
- llstr(page, llbuff), row, length);
+ "Page %9s: Row %3u is too short "
+ "(%d of min %d bytes)",
+ llstr(page, llbuff), row, length,
+ (uint) share->base.min_block_length);
DBUG_RETURN(1);
}
flag= (uint) (uchar) page_buff[pos];
if (flag & ~(ROW_FLAG_ALL))
_ma_check_print_error(param,
- "Page %9s: Row %3u has wrong flag: %d",
+ "Page %9s: Row %3u has wrong flag: %u",
llstr(page, llbuff), row, flag);
DBUG_PRINT("info", ("rowid: %s page: %lu row: %u",
llstr(ma_recordpos(page, row), llbuff),
(ulong) page, row));
+ info->cur_row.trid= 0;
if (_ma_read_block_record2(info, record, page_buff+pos,
page_buff+pos+length))
{
@@ -1623,6 +1652,10 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
DBUG_RETURN(1);
continue;
}
+ set_if_bigger(param->max_found_trid, info->cur_row.trid);
+ if (info->cur_row.trid > param->max_trid)
+ _ma_check_print_not_visible_error(param, info->cur_row.trid);
+
if (share->calc_checksum)
{
ha_checksum checksum= (*share->calc_checksum)(info, record);
@@ -1711,10 +1744,10 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
full_page_count= tail_count= 0;
param->full_page_count= param->tail_count= 0;
param->used= param->link_used= 0;
- param->splits= info->state->data_file_length / block_size;
+ param->splits= share->state.state.data_file_length / block_size;
for (pos= 0, page= 0;
- pos < info->state->data_file_length;
+ pos < share->state.state.data_file_length;
pos+= block_size, page++)
{
uint row_count, real_row_count, empty_space, page_type, bitmap_pattern;
@@ -1954,12 +1987,12 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
{
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
}
- if (param->records != info->state->records)
+ if (param->records != share->state.state.records)
{
_ma_check_print_error(param,
"Record-count is not ok; found %-10s Should be: %s",
llstr(param->records,llbuff),
- llstr(info->state->records,llbuff2));
+ llstr(share->state.state.records,llbuff2));
error=1;
}
else if (param->record_checksum &&
@@ -1969,7 +2002,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
"Key pointers and record positions doesn't match");
error=1;
}
- else if (param->glob_crc != info->state->checksum &&
+ else if (param->glob_crc != share->state.state.checksum &&
(share->options &
(HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
{
@@ -1992,18 +2025,18 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
}
}
- if (param->del_length != info->state->empty)
+ if (param->del_length != share->state.state.empty)
{
_ma_check_print_warning(param,
"Found %s deleted space. Should be %s",
llstr(param->del_length,llbuff2),
- llstr(info->state->empty,llbuff));
+ llstr(share->state.state.empty,llbuff));
}
/* Skip following checks for BLOCK RECORD as they don't make any sence */
if (share->data_file_type != BLOCK_RECORD)
{
if (param->used + param->empty + param->del_length !=
- info->state->data_file_length)
+ share->state.state.data_file_length)
{
_ma_check_print_warning(param,
"Found %s record data and %s unused data and %s deleted data",
@@ -2014,14 +2047,14 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
"Total %s Should be: %s",
llstr((param->used+param->empty +
param->del_length), llbuff),
- llstr(info->state->data_file_length,llbuff2));
+ llstr(share->state.state.data_file_length,llbuff2));
}
- if (param->del_blocks != info->state->del)
+ if (param->del_blocks != share->state.state.del)
{
_ma_check_print_warning(param,
"Found %10s deleted blocks Should be: %s",
llstr(param->del_blocks,llbuff),
- llstr(info->state->del,llbuff2));
+ llstr(share->state.state.del,llbuff2));
}
if (param->splits != share->state.split)
{
@@ -2070,6 +2103,11 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
llstr(param->empty, llbuff),llstr(param->link_used, llbuff2));
if (param->lost)
printf("Lost space: %12s", llstr(param->lost, llbuff));
+ if (param->max_found_trid)
+ {
+ printf("Max trans. id: %11s\n",
+ llstr(param->max_found_trid, llbuff));
+ }
}
my_free((uchar*) record,MYF(0));
DBUG_RETURN (error);
@@ -2188,7 +2226,7 @@ static int initialize_variables_for_repair(HA_CHECK *param,
sort_info->filelength= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
if ((param->testflag & T_CREATE_MISSING_KEYS) ||
sort_info->org_data_file_type == COMPRESSED_RECORD)
- sort_info->max_records= info->state->records;
+ sort_info->max_records= share->state.state.records;
else
{
ulong rec_length;
@@ -2196,6 +2234,16 @@ static int initialize_variables_for_repair(HA_CHECK *param,
share->base.min_block_length);
sort_info->max_records= (ha_rows) (sort_info->filelength / rec_length);
}
+
+ /* Set up transaction handler so that we can see all rows */
+ if (!ma_control_file_inited())
+ param->max_trid= 0; /* Give warning for first trid found */
+ else
+ param->max_trid= max_trid_in_system();
+
+ maria_ignore_trids(info);
+ /* Don't write transid's during repair */
+ maria_versioning(info, 0);
return 0;
}
@@ -2308,7 +2356,7 @@ static int maria_drop_all_indexes(HA_CHECK *param, MARIA_HA *info,
share->state.key_del= HA_OFFSET_ERROR;
/* Reset index file length to end of index file header. */
- info->state->key_file_length= share->base.keystart;
+ share->state.state.key_file_length= share->base.keystart;
end:
DBUG_RETURN(0);
@@ -2357,7 +2405,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
got_error= 1;
new_file= -1;
- start_records= info->state->records;
+ start_records= share->state.state.records;
if (!(param->testflag & T_SILENT))
{
printf("- recovering (with keycache) MARIA-table '%s'\n",name);
@@ -2448,9 +2496,9 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
sort_param.master=1;
sort_info.max_records= ~(ha_rows) 0;
- del=info->state->del;
- info->state->records=info->state->del=share->state.split=0;
- info->state->empty=0;
+ del= share->state.state.del;
+ share->state.state.records= share->state.state.del= share->state.split= 0;
+ share->state.state.empty= 0;
if (param->testflag & T_CREATE_MISSING_KEYS)
maria_set_all_keys_active(share->state.key_map, share->base.keys);
@@ -2492,7 +2540,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
/* purecov: begin tested */
if (block_record)
{
- sort_info.new_info->state->records--;
+ sort_info.new_info->s->state.state.records--;
if ((*sort_info.new_info->s->write_record_abort)(sort_info.new_info))
{
_ma_check_print_error(param,"Couldn't delete duplicate row");
@@ -2519,7 +2567,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
{
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
}
- if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
+ if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
{
_ma_check_print_warning(param,
"Can't change size of indexfile, error: %d",
@@ -2527,7 +2575,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
goto err;
}
- if (rep_quick && del+sort_info.dupp != info->state->del)
+ if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
@@ -2539,9 +2587,9 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
- if (sort_info.new_info->state->records+1 < start_records)
+ if (sort_info.new_info->s->state.state.records+1 < start_records)
{
- info->state->records=start_records;
+ share->state.state.records= start_records;
goto err;
}
}
@@ -2560,7 +2608,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
if (!rep_quick)
{
- sort_info.new_info->state->data_file_length= sort_param.filepos;
+ sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
if (sort_info.new_info != sort_info.info)
{
MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
@@ -2592,15 +2640,15 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
}
else
{
- info->state->data_file_length= sort_param.max_pos;
+ share->state.state.data_file_length= sort_param.max_pos;
}
if (param->testflag & T_CALC_CHECKSUM)
- info->state->checksum= param->glob_crc;
+ share->state.state.checksum= param->glob_crc;
if (!(param->testflag & T_SILENT))
{
- if (start_records != info->state->records)
- printf("Data records: %s\n", llstr(info->state->records,llbuff));
+ if (start_records != share->state.state.records)
+ printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
}
if (sort_info.dupp)
_ma_check_print_warning(param,
@@ -2610,11 +2658,12 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
got_error= 0;
/* If invoked by external program that uses thr_lock */
if (&share->state.state != info->state)
- memcpy(&share->state.state, info->state, sizeof(*info->state));
+ *info->state= *info->state_start= share->state.state;
err:
if (scan_inited)
maria_scan_end(sort_info.info);
+ _ma_reset_state(info);
VOID(end_io_cache(&param->read_cache));
VOID(end_io_cache(&sort_info.new_info->rec_cache));
@@ -2906,7 +2955,7 @@ int maria_sort_index(HA_CHECK *param, register MARIA_HA *info, char *name)
share->tot_locks= r_locks+w_locks;
share->state= old_state; /* Restore old state */
- info->state->key_file_length=param->new_file_pos;
+ share->state.state.key_file_length=param->new_file_pos;
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
for (key=0 ; key < share->base.keys ; key++)
share->state.key_root[key]=index_pos[key];
@@ -3139,11 +3188,11 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
/* Go through the record file */
for (page= 1, pos= block_size;
- pos < info->state->data_file_length;
+ pos < share->state.state.data_file_length;
pos+= block_size, page++)
{
uchar *buff;
- uint page_type;
+ enum en_page_type page_type;
/* Ignore bitmap pages */
if ((page % share->bitmap.pages_covered) == 0)
@@ -3159,8 +3208,8 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
llstr(pos, llbuff), my_errno);
goto err;
}
- page_type= buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK;
- switch ((enum en_page_type) page_type) {
+ page_type= (enum en_page_type) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK);
+ switch (page_type) {
case UNALLOCATED_PAGE:
if (zero_lsn)
bzero(buff, block_size);
@@ -3192,7 +3241,10 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
if (max_entry != 0)
{
dir= dir_entry_pos(buff, block_size, max_entry - 1);
- _ma_compact_block_page(buff, block_size, max_entry -1, 0);
+ _ma_compact_block_page(buff, block_size, max_entry -1, 0,
+ page_type == HEAD_PAGE ? ~(TrID) 0 : 0,
+ page_type == HEAD_PAGE ?
+ share->base.min_block_length : 0);
/* Zerofille the not used part */
offset= uint2korr(dir) + uint2korr(dir+2);
@@ -3367,7 +3419,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
got_error= 1;
new_file= -1;
- start_records= info->state->records;
+ start_records= share->state.state.records;
if (!(param->testflag & T_SILENT))
{
printf("- recovering (with sort) MARIA-table '%s'\n",name);
@@ -3468,7 +3520,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
sort_param.tmpdir=param->tmpdir;
sort_param.master =1;
- del=info->state->del;
+ del=share->state.state.del;
rec_per_key_part= param->new_rec_per_key_part;
for (sort_param.key=0 ; sort_param.key < share->base.keys ;
@@ -3510,8 +3562,8 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (keyseg[i].flag & HA_NULL_PART)
sort_param.key_length++;
}
- info->state->records=info->state->del=share->state.split=0;
- info->state->empty=0;
+ share->state.state.records=share->state.state.del=share->state.split=0;
+ share->state.state.empty=0;
if (sort_param.keyinfo->flag & HA_FULLTEXT)
{
@@ -3589,15 +3641,14 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
free_root(&sort_param.wordroot, MYF(0));
/* Set for next loop */
- sort_info.max_records= (ha_rows) sort_info.new_info->state->records;
-
+ sort_info.max_records= (ha_rows) sort_info.new_info->s->state.state.records;
if (param->testflag & T_STATISTICS)
maria_update_key_parts(sort_param.keyinfo, rec_per_key_part,
sort_param.unique,
(param->stats_method ==
MI_STATS_METHOD_IGNORE_NULLS ?
sort_param.notnull : NULL),
- (ulonglong) info->state->records);
+ (ulonglong) share->state.state.records);
maria_set_key_active(share->state.key_map, sort_param.key);
DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key));
@@ -3618,17 +3669,17 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
- if (info->state->records+1 < start_records)
+ if (share->state.state.records+1 < start_records)
{
_ma_check_print_error(param,
"Rows lost; Aborting because safe repair was "
"requested");
- info->state->records=start_records;
+ share->state.state.records=start_records;
goto err;
}
}
- sort_info.new_info->state->data_file_length= sort_param.filepos;
+ sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
if (sort_info.new_info != sort_info.info)
{
MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
@@ -3667,11 +3718,11 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
org_header_length= share->pack.header_length;
sort_info.org_data_file_type= share->data_file_type;
- sort_info.filelength= info->state->data_file_length;
+ sort_info.filelength= share->state.state.data_file_length;
sort_param.fix_datafile=0;
}
else
- info->state->data_file_length=sort_param.max_pos;
+ share->state.state.data_file_length=sort_param.max_pos;
param->read_cache.file= info->dfile.file; /* re-init read cache */
reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
@@ -3683,7 +3734,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
}
- if (rep_quick && del+sort_info.dupp != info->state->del)
+ if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
@@ -3695,7 +3746,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
- my_off_t skr= (info->state->data_file_length +
+ my_off_t skr= (share->state.state.data_file_length +
(sort_info.org_data_file_type == COMPRESSED_RECORD) ?
MEMMAP_EXTRA_MARGIN : 0);
#ifdef USE_RELOC
@@ -3711,30 +3762,31 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
}
if (param->testflag & T_CALC_CHECKSUM)
- info->state->checksum=param->glob_crc;
+ share->state.state.checksum=param->glob_crc;
- if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
+ if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
_ma_check_print_warning(param,
"Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT))
{
- if (start_records != info->state->records)
- printf("Data records: %s\n", llstr(info->state->records,llbuff));
+ if (start_records != share->state.state.records)
+ printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
}
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0;
-
+ /* If invoked by external program that uses thr_lock */
if (&share->state.state != info->state)
- memcpy(&share->state.state, info->state, sizeof(*info->state));
+ *info->state= *info->state_start= share->state.state;
err:
if (scan_inited)
maria_scan_end(sort_info.info);
+ _ma_reset_state(info);
VOID(end_io_cache(&sort_info.new_info->rec_cache));
VOID(end_io_cache(&param->read_cache));
@@ -3860,7 +3912,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
got_error= 1;
new_file= -1;
- start_records= info->state->records;
+ start_records= share->state.state.records;
if (!(param->testflag & T_SILENT))
{
printf("- parallel recovering (with sort) MARIA-table '%s'\n",name);
@@ -3965,7 +4017,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
/*
+1 below is required hack for parallel repair mode.
- The info->state->records value, that is compared later
+ The share->state.state.records value, that is compared later
to sort_info.max_records and cannot exceed it, is
increased in sort_key_write. In maria_repair_by_sort, sort_key_write
is called after sort_key_read, where the comparison is performed,
@@ -3977,7 +4029,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
*/
sort_info.max_records++;
- del=info->state->del;
+ del=share->state.state.del;
if (!(sort_param=(MARIA_SORT_PARAM *)
my_malloc((uint) share->base.keys *
@@ -3989,8 +4041,8 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
}
total_key_length=0;
rec_per_key_part= param->new_rec_per_key_part;
- info->state->records=info->state->del=share->state.split=0;
- info->state->empty=0;
+ share->state.state.records=share->state.state.del=share->state.split=0;
+ share->state.state.empty=0;
for (i=key=0, istep=1 ; key < share->base.keys ;
rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
@@ -4164,16 +4216,16 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
- if (info->state->records+1 < start_records)
+ if (share->state.state.records+1 < start_records)
{
- info->state->records=start_records;
+ share->state.state.records=start_records;
goto err;
}
}
- share->state.state.data_file_length= info->state->data_file_length=
+ share->state.state.data_file_length= share->state.state.data_file_length=
sort_param->filepos;
/* Only whole records */
- share->state.version=(ulong) time((time_t*) 0);
+ share->state.version= (ulong) time((time_t*) 0);
/*
Exchange the data file descriptor of the table, so that we use the
new file from now on.
@@ -4183,9 +4235,9 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
share->pack.header_length=(ulong) new_header_length;
}
else
- info->state->data_file_length=sort_param->max_pos;
+ share->state.state.data_file_length=sort_param->max_pos;
- if (rep_quick && del+sort_info.dupp != info->state->del)
+ if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
@@ -4196,7 +4248,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
- my_off_t skr= (info->state->data_file_length +
+ my_off_t skr= (share->state.state.data_file_length +
(sort_info.org_data_file_type == COMPRESSED_RECORD) ?
MEMMAP_EXTRA_MARGIN : 0);
#ifdef USE_RELOC
@@ -4211,28 +4263,30 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
my_errno);
}
if (param->testflag & T_CALC_CHECKSUM)
- info->state->checksum=param->glob_crc;
+ share->state.state.checksum=param->glob_crc;
- if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
+ if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
_ma_check_print_warning(param,
"Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT))
{
- if (start_records != info->state->records)
- printf("Data records: %s\n", llstr(info->state->records,llbuff));
+ if (start_records != share->state.state.records)
+ printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
}
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0;
-
+ /* If invoked by external program that uses thr_lock */
if (&share->state.state != info->state)
- memcpy(&share->state.state, info->state, sizeof(*info->state));
+ *info->state= *info->state_start= share->state.state;
err:
+ _ma_reset_state(info);
+
/*
Destroy the write cache. The master thread did already detach from
the share by remove_io_thread() or it was not yet started (if the
@@ -4311,7 +4365,7 @@ static int sort_key_read(MARIA_SORT_PARAM *sort_param, uchar *key)
if ((error=sort_get_next_record(sort_param)))
DBUG_RETURN(error);
- if (info->state->records == sort_info->max_records)
+ if (info->s->state.state.records == sort_info->max_records)
{
_ma_check_print_error(sort_info->param,
"Key %d - Found too many records; Can't continue",
@@ -4464,9 +4518,16 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
Scan on clean table.
It requires a reliable data_file_length so we set it.
*/
- info->state->data_file_length= sort_info->filelength;
+ share->state.state.data_file_length= sort_info->filelength;
+ info->cur_row.trid= 0;
flag= _ma_scan_block_record(info, sort_param->record,
info->cur_row.nextpos, 1);
+ set_if_bigger(param->max_found_trid, info->cur_row.trid);
+ if (info->cur_row.trid > param->max_trid)
+ {
+ _ma_check_print_not_visible_error(param, info->cur_row.trid);
+ flag= HA_ERR_ROW_NOT_VISIBLE;
+ }
}
share->page_type= save_page_type;
if (!flag)
@@ -4496,7 +4557,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
}
if (flag == HA_ERR_END_OF_FILE)
{
- sort_param->max_pos= info->state->data_file_length;
+ sort_param->max_pos= share->state.state.data_file_length;
DBUG_RETURN(-1);
}
/* Retry only if wrong record, not if disk error */
@@ -4534,8 +4595,8 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
}
if (!sort_param->fix_datafile && sort_param->master)
{
- info->state->del++;
- info->state->empty+=share->base.pack_reclength;
+ share->state.state.del++;
+ share->state.state.empty+=share->base.pack_reclength;
}
}
case DYNAMIC_RECORD:
@@ -4639,9 +4700,9 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
{
if ((block_info.next_filepos != HA_OFFSET_ERROR &&
block_info.next_filepos >=
- info->state->data_file_length) ||
+ share->state.state.data_file_length) ||
(block_info.prev_filepos != HA_OFFSET_ERROR &&
- block_info.prev_filepos >= info->state->data_file_length))
+ block_info.prev_filepos >= share->state.state.data_file_length))
{
if (!searching)
_ma_check_print_info(param,
@@ -4689,8 +4750,8 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
if (!sort_param->fix_datafile && sort_param->master &&
(b_type & BLOCK_DELETED))
{
- info->state->empty+=block_info.block_len;
- info->state->del++;
+ share->state.state.empty+=block_info.block_len;
+ share->state.state.del++;
share->state.split++;
}
if (found_record)
@@ -4964,7 +5025,7 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
HA_OFFSET_ERROR)
DBUG_RETURN(1);
/* Pointer to end of file */
- sort_param->filepos= info->state->data_file_length;
+ sort_param->filepos= share->state.state.data_file_length;
break;
case STATIC_RECORD:
if (my_b_write(&info->rec_cache,sort_param->record,
@@ -5043,12 +5104,12 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
}
if (sort_param->master)
{
- info->state->records++;
+ share->state.state.records++;
if ((param->testflag & T_WRITE_LOOP) &&
- (info->state->records % WRITE_COUNT) == 0)
+ (share->state.state.records % WRITE_COUNT) == 0)
{
char llbuff[22];
- printf("%s\r", llstr(info->state->records,llbuff));
+ printf("%s\r", llstr(share->state.state.records,llbuff));
VOID(fflush(stdout));
}
}
@@ -5346,7 +5407,7 @@ static int sort_insert_key(MARIA_SORT_PARAM *sort_param,
_ma_store_page_used(share, anc_buff, key_block->last_length);
bzero(anc_buff+key_block->last_length,
keyinfo->block_length- key_block->last_length);
- key_file_length=info->state->key_file_length;
+ key_file_length=share->state.state.key_file_length;
if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) == HA_OFFSET_ERROR)
DBUG_RETURN(1);
_ma_fast_unlock_key_del(info);
@@ -5445,7 +5506,7 @@ static int sort_delete_record(MARIA_SORT_PARAM *sort_param)
_ma_check_print_error(param,"Got error %d when deleting record",
my_errno);
row_info->dfile.file= old_file; /* restore actual value */
- row_info->state->records--;
+ row_info->s->state.state.records--;
DBUG_RETURN(error);
} /* sort_delete_record */
@@ -5472,7 +5533,7 @@ int _ma_flush_pending_blocks(MARIA_SORT_PARAM *sort_param)
length= _ma_get_page_used(info->s, key_block->buff);
if (nod_flag)
_ma_kpointer(info,key_block->end_pos,filepos);
- key_file_length=info->state->key_file_length;
+ key_file_length= info->s->state.state.key_file_length;
bzero(key_block->buff+length, keyinfo->block_length-length);
if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
HA_OFFSET_ERROR)
@@ -5707,16 +5768,16 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
/* We are modifing */
(*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
VOID(_ma_readinfo(*org_info,F_WRLCK,0));
- (*org_info)->state->records=info.state->records;
+ (*org_info)->s->state.state.records= info.state->records;
if (share.state.create_time)
(*org_info)->s->state.create_time=share.state.create_time;
- (*org_info)->s->state.unique=(*org_info)->this_unique=
- share.state.unique;
- (*org_info)->state->checksum=info.state->checksum;
- (*org_info)->state->del=info.state->del;
- (*org_info)->s->state.dellink=share.state.dellink;
- (*org_info)->state->empty=info.state->empty;
- (*org_info)->state->data_file_length=info.state->data_file_length;
+ (*org_info)->s->state.unique= (*org_info)->this_unique= share.state.unique;
+ (*org_info)->s->state.state.checksum= info.state->checksum;
+ (*org_info)->s->state.state.del= info.state->del;
+ (*org_info)->s->state.dellink= share.state.dellink;
+ (*org_info)->s->state.state.empty= info.state->empty;
+ (*org_info)->s->state.state.data_file_length= info.state->data_file_length;
+ *(*org_info)->state= (*org_info)->s->state.state;
if (maria_update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
UPDATE_OPEN_COUNT))
goto end;
@@ -5767,9 +5828,9 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
if (update & UPDATE_STAT)
{
uint i, key_parts= mi_uint2korr(share->state.header.key_parts);
- share->state.records_at_analyze= info->state->records;
+ share->state.records_at_analyze= share->state.state.records;
share->state.changed&= ~STATE_NOT_ANALYZED;
- if (info->state->records)
+ if (share->state.state.records)
{
for (i=0; i<key_parts; i++)
{
@@ -5784,16 +5845,8 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
{
share->state.check_time= (long) time((time_t*) 0);
if (!share->state.create_time)
- share->state.create_time=share->state.check_time;
+ share->state.create_time= share->state.check_time;
}
- /*
- When tables are locked we haven't synched the share state and the
- real state for a while so we better do it here before synching
- the share state to disk. Only when table is write locked is it
- necessary to perform this synch.
- */
- if (info->lock_type == F_WRLCK)
- share->state.state= *info->state;
if (_ma_state_info_write(share, 1|2))
goto err;
share->changed=0;
@@ -6018,7 +6071,7 @@ void maria_disable_non_unique_index(MARIA_HA *info, ha_rows rows)
MARIA_KEYDEF *key=share->keyinfo;
uint i;
- DBUG_ASSERT(info->state->records == 0 &&
+ DBUG_ASSERT(share->state.state.records == 0 &&
(!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES));
for (i=0 ; i < share->base.keys ; i++,key++)
{
@@ -6102,7 +6155,7 @@ static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file)
DBUG_RETURN(1);
/* Take into account any bitmap page created above: */
- param->filepos= new_info->state->data_file_length;
+ param->filepos= new_info->s->state.state.data_file_length;
/* Use new virtual functions for key generation */
info->s->keypos_to_recpos= new_info->s->keypos_to_recpos;
@@ -6473,3 +6526,25 @@ static TrID max_trid_in_system(void)
/* 'id' may be far bigger, if last shutdown is old */
return max(id, max_trid_in_control_file);
}
+
+
+static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid)
+{
+ char buff[22], buff2[22];
+ if (!param->not_visible_rows_found++)
+ {
+ if (!ma_control_file_inited())
+ {
+ _ma_check_print_warning(param,
+ "Found row with transaction id %s but no maria_control_file was specified. The table may be corrupted",
+ llstr(used_trid, buff));
+ }
+ else
+ {
+ _ma_check_print_error(param,
+ "Found row with transaction id %s when max transaction id according to maria_control_file is %s",
+ llstr(used_trid, buff),
+ llstr(param->max_trid, buff2));
+ }
+ }
+}
diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c
index 282d16bb604..36db37f0d4d 100644
--- a/storage/maria/ma_checkpoint.c
+++ b/storage/maria/ma_checkpoint.c
@@ -1053,6 +1053,14 @@ static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon)
}
DBUG_ASSERT(share->pagecache == maria_pagecache);
}
+ /*
+ Clean up any unused states.
+ TODO: Only do this call if there has been # (10?) ended transactions
+ since last call.
+ */
+ share->state_history= _ma_remove_not_visible_states(share->state_history,
+ 0, 0);
+
if (share->in_checkpoint & MARIA_CHECKPOINT_SHOULD_FREE_ME)
{
/* maria_close() left us to free the share */
diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c
index 1f8b5880115..8fe2334f5e7 100644
--- a/storage/maria/ma_close.c
+++ b/storage/maria/ma_close.c
@@ -128,6 +128,27 @@ int maria_close(register MARIA_HA *info)
}
else
share_can_be_freed= TRUE;
+
+ /* Remember share->history for future opens */
+ share->state_history= _ma_remove_not_visible_states(share->state_history,
+ 1, 0);
+ if (share->state_history)
+ {
+ MARIA_STATE_HISTORY_CLOSED *history;
+ /*
+ Here we ignore the unlikely case that we don't have memory to
+ store the case. In the worst case what happens is that any transaction
+ that tries to access this table will get a wrong status information.
+ */
+ if ((history= (MARIA_STATE_HISTORY_CLOSED *)
+ my_malloc(sizeof(*history), MYF(MY_WME))))
+ {
+ history->create_rename_lsn= share->state.create_rename_lsn;
+ history->state_history= share->state_history;
+ if (my_hash_insert(&maria_stored_state, (uchar*) history))
+ my_free(history, MYF(0));
+ }
+ }
}
pthread_mutex_unlock(&THR_LOCK_maria);
pthread_mutex_unlock(&share->intern_lock);
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
index 2d36293b697..e7c82d651c5 100644
--- a/storage/maria/ma_commit.c
+++ b/storage/maria/ma_commit.c
@@ -49,6 +49,8 @@ int ma_commit(TRN *trn)
if crash happens between the two, trn will be rolled back which is an
issue (transaction's updates were made visible to other transactions).
So we need to go the first way.
+
+ Note that we have to use | here to ensure that all calls are made.
*/
/*
@@ -56,11 +58,13 @@ int ma_commit(TRN *trn)
needed only when we support XA.
*/
res= (translog_write_record(&commit_lsn, LOGREC_COMMIT,
- trn, NULL, 0,
- sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL, NULL) ||
- translog_flush(commit_lsn) ||
+ trn, NULL, 0,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) |
+ translog_flush(commit_lsn) |
trnman_commit_trn(trn));
+
+
/*
Note: if trnman_commit_trn() fails above, we have already
written the COMMIT record, so Checkpoint and Recovery will see the
@@ -96,7 +100,6 @@ int maria_commit(MARIA_HA *info)
@retval # Error code.
*/
-
int maria_begin(MARIA_HA *info)
{
DBUG_ENTER("maria_begin");
@@ -116,3 +119,4 @@ int maria_begin(MARIA_HA *info)
}
DBUG_RETURN(0);
}
+
diff --git a/storage/maria/ma_control_file.c b/storage/maria/ma_control_file.c
index 78a78c41192..e6018a4b847 100644
--- a/storage/maria/ma_control_file.c
+++ b/storage/maria/ma_control_file.c
@@ -251,7 +251,8 @@ static int lock_control_file(const char *name)
@retval 1 Error (in which case the file is left closed)
*/
-CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing)
+CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
+ my_bool print_error)
{
uchar buffer[CF_MAX_SIZE];
char name[FN_REFLEN], errmsg_buff[256];
@@ -424,9 +425,10 @@ ok:
DBUG_RETURN(0);
err:
- my_printf_error(HA_ERR_INITIALIZATION,
- "Error when trying to use maria control file '%s': %s", 0,
- name, errmsg);
+ if (print_error)
+ my_printf_error(HA_ERR_INITIALIZATION,
+ "Got error '%s' when trying to use maria control file "
+ "'%s'", 0, errmsg, name);
ma_control_file_end(); /* will unlock file if needed */
DBUG_RETURN(error);
}
diff --git a/storage/maria/ma_control_file.h b/storage/maria/ma_control_file.h
index 54c15b3c9f6..52001cd4a4c 100644
--- a/storage/maria/ma_control_file.h
+++ b/storage/maria/ma_control_file.h
@@ -61,7 +61,8 @@ typedef enum enum_control_file_error {
} CONTROL_FILE_ERROR;
C_MODE_START
-CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing);
+CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
+ my_bool print_error);
int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno, TrID trid);
int ma_control_file_end(void);
my_bool ma_control_file_inited(void);
diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c
index 097e94ee3df..91106142204 100644
--- a/storage/maria/ma_delete.c
+++ b/storage/maria/ma_delete.c
@@ -108,11 +108,8 @@ int maria_delete(MARIA_HA *info,const uchar *record)
if ((*share->delete_record)(info, record))
goto err; /* Remove record from database */
- if (!share->now_transactional)
- {
- info->state->checksum-= info->cur_row.checksum;
- info->state->records--;
- }
+ info->state->checksum-= info->cur_row.checksum;
+ info->state->records--;
info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED;
share->state.changed|= (STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_MOVABLE |
STATE_NOT_ZEROFILLED);
@@ -1400,7 +1397,6 @@ int _ma_write_undo_key_delete(MARIA_HA *info, uint keynr,
struct st_msg_to_write_hook_for_undo_key msg;
enum translog_record_type log_type= LOGREC_UNDO_KEY_DELETE;
- info->key_delete_undo_lsn[keynr]= info->trn->undo_lsn;
lsn_store(log_data, info->trn->undo_lsn);
key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, keynr);
log_pos= log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE;
diff --git a/storage/maria/ma_delete_all.c b/storage/maria/ma_delete_all.c
index 07d54d853a0..6f0b30ea979 100644
--- a/storage/maria/ma_delete_all.c
+++ b/storage/maria/ma_delete_all.c
@@ -97,13 +97,12 @@ int maria_delete_all_rows(MARIA_HA *info)
if (_ma_flush_table_files(info, MARIA_FLUSH_DATA|MARIA_FLUSH_INDEX,
FLUSH_IGNORE_CHANGED, FLUSH_IGNORE_CHANGED) ||
my_chsize(info->dfile.file, 0, 0, MYF(MY_WME)) ||
- my_chsize(share->kfile.file, share->base.keystart, 0, MYF(MY_WME)) )
+ my_chsize(share->kfile.file, share->base.keystart, 0, MYF(MY_WME)))
goto err;
if (_ma_initialize_data_file(share, info->dfile.file))
goto err;
-
if (log_record)
{
/*
@@ -161,14 +160,17 @@ void _ma_reset_status(MARIA_HA *info)
MARIA_STATE_INFO *state= &share->state;
uint i;
- info->state->records= info->state->del= state->split= 0;
+ state->split= 0;
+ state->state.records= state->state.del= 0;
state->changed= 0; /* File is optimized */
state->dellink= HA_OFFSET_ERROR;
state->sortkey= (ushort) ~0;
- info->state->key_file_length= share->base.keystart;
- info->state->data_file_length= 0;
- info->state->empty= info->state->key_empty= 0;
- info->state->checksum= 0;
+ state->state.key_file_length= share->base.keystart;
+ state->state.data_file_length= 0;
+ state->state.empty= state->state.key_empty= 0;
+ state->state.checksum= 0;
+
+ *info->state= state->state;
/* Drop the delete key chain. */
state->key_del= HA_OFFSET_ERROR;
diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c
index 03dbb27cab1..c09ebc0a230 100644
--- a/storage/maria/ma_dynrec.c
+++ b/storage/maria/ma_dynrec.c
@@ -136,7 +136,7 @@ size_t _ma_mmap_pread(MARIA_HA *info, uchar *Buffer,
size_t Count, my_off_t offset, myf MyFlags)
{
DBUG_PRINT("info", ("maria_read with mmap %d\n", info->dfile.file));
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_rdlock(&info->s->mmap_lock);
/*
@@ -149,13 +149,13 @@ size_t _ma_mmap_pread(MARIA_HA *info, uchar *Buffer,
if (info->s->mmaped_length >= offset + Count)
{
memcpy(Buffer, info->s->file_map + offset, Count);
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_unlock(&info->s->mmap_lock);
return 0;
}
else
{
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_unlock(&info->s->mmap_lock);
return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
}
@@ -191,7 +191,7 @@ size_t _ma_mmap_pwrite(MARIA_HA *info, const uchar *Buffer,
size_t Count, my_off_t offset, myf MyFlags)
{
DBUG_PRINT("info", ("maria_write with mmap %d\n", info->dfile.file));
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_rdlock(&info->s->mmap_lock);
/*
@@ -204,14 +204,14 @@ size_t _ma_mmap_pwrite(MARIA_HA *info, const uchar *Buffer,
if (info->s->mmaped_length >= offset + Count)
{
memcpy(info->s->file_map + offset, Buffer, Count);
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_unlock(&info->s->mmap_lock);
return 0;
}
else
{
info->s->nonmmaped_inserts++;
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_unlock(&info->s->mmap_lock);
return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
}
diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c
index 4a379ebab46..c9373b770bc 100644
--- a/storage/maria/ma_extra.c
+++ b/storage/maria/ma_extra.c
@@ -105,7 +105,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
cache_size= (extra_arg ? *(ulong*) extra_arg :
my_default_record_cache_size);
if (!(init_io_cache(&info->rec_cache, info->dfile.file,
- (uint) min(info->state->data_file_length+1,
+ (uint) min(share->state.state.data_file_length+1,
cache_size),
READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK),
MYF(share->write_flag & MY_WAIT_IF_FULL))))
@@ -113,7 +113,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
info->opt_flag|= READ_CACHE_USED;
info->update&= ~HA_STATE_ROW_CHANGED;
}
- if (share->concurrent_insert)
+ if (share->non_transactional_concurrent_insert)
info->rec_cache.end_of_file= info->state->data_file_length;
}
break;
@@ -124,7 +124,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
(pbool) (info->lock_type != F_UNLCK),
(pbool) test(info->update & HA_STATE_ROW_CHANGED));
info->update&= ~HA_STATE_ROW_CHANGED;
- if (share->concurrent_insert)
+ if (share->non_transactional_concurrent_insert)
info->rec_cache.end_of_file= info->state->data_file_length;
}
break;
@@ -143,7 +143,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
(READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) &&
!share->state.header.uniques)
if (!(init_io_cache(&info->rec_cache, info->dfile.file, cache_size,
- WRITE_CACHE,info->state->data_file_length,
+ WRITE_CACHE,share->state.state.data_file_length,
(pbool) (info->lock_type != F_UNLCK),
MYF(share->write_flag & MY_WAIT_IF_FULL))))
{
@@ -258,7 +258,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
share->state.open_count++;
}
}
- share->state.state= *info->state;
+ if (!share->now_transactional)
+ share->state.state= *info->state;
/*
That state write to disk must be done, even for transactional tables;
indeed the table's share is going to be lost (there was a
@@ -546,27 +547,36 @@ int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
enum flush_type flush_type_for_data,
enum flush_type flush_type_for_index)
{
+ int error= 0;
MARIA_SHARE *share= info->s;
/* flush data file first because it's more critical */
if (flush_data_or_index & MARIA_FLUSH_DATA)
{
if ((info->opt_flag & WRITE_CACHE_USED) &&
+ flush_type_for_data != FLUSH_IGNORE_CHANGED &&
flush_io_cache(&info->rec_cache))
- goto err;
+ error= 1;
if (share->data_file_type == BLOCK_RECORD)
{
- if(_ma_bitmap_flush(share) ||
- flush_pagecache_blocks(share->pagecache, &info->dfile,
- flush_type_for_data))
- goto err;
+ if (flush_type_for_data != FLUSH_IGNORE_CHANGED)
+ {
+ if (_ma_bitmap_flush(share))
+ error= 1;
+ }
+ else
+ info->s->bitmap.changed= 0;
+ if (flush_pagecache_blocks(share->pagecache, &info->dfile,
+ flush_type_for_data))
+ error= 1;
}
}
if ((flush_data_or_index & MARIA_FLUSH_INDEX) &&
flush_pagecache_blocks(share->pagecache, &share->kfile,
flush_type_for_index))
- goto err;
- return 0;
-err:
+ error= 1;
+ if (!error)
+ return 0;
+
maria_print_error(info->s, HA_ERR_CRASHED);
maria_mark_crashed(info);
return 1;
diff --git a/storage/maria/ma_info.c b/storage/maria/ma_info.c
index 02857892d05..1bb351bfbb5 100644
--- a/storage/maria/ma_info.c
+++ b/storage/maria/ma_info.c
@@ -50,15 +50,15 @@ int maria_status(MARIA_HA *info, register MARIA_INFO *x, uint flag)
if (flag & HA_STATUS_VARIABLE)
{
x->records = info->state->records;
- x->deleted = info->state->del;
- x->delete_length = info->state->empty;
- x->data_file_length =info->state->data_file_length;
- x->index_file_length=info->state->key_file_length;
+ x->deleted = share->state.state.del;
+ x->delete_length = share->state.state.empty;
+ x->data_file_length = share->state.state.data_file_length;
+ x->index_file_length= share->state.state.key_file_length;
x->keys = share->state.header.keys;
x->check_time = share->state.check_time;
x->mean_reclength = x->records ?
- (ulong) ((x->data_file_length - x->delete_length) /x ->records) :
+ (ulong) ((x->data_file_length - x->delete_length) /x->records) :
(ulong) share->min_pack_length;
}
if (flag & HA_STATUS_ERRKEY)
diff --git a/storage/maria/ma_init.c b/storage/maria/ma_init.c
index 6edb0155aec..f81afda2141 100644
--- a/storage/maria/ma_init.c
+++ b/storage/maria/ma_init.c
@@ -20,6 +20,25 @@
#include "ma_blockrec.h"
#include "trnman_public.h"
#include "ma_checkpoint.h"
+#include <hash.h>
+
+void history_state_free(MARIA_STATE_HISTORY_CLOSED *closed_history)
+{
+ MARIA_STATE_HISTORY *history, *next;
+
+ /*
+ Free all active history
+ In case of maria_open() this list should be empty as the history is moved
+ to handler->share.
+ */
+ for (history= closed_history->state_history; history ; history= next)
+ {
+ next= history->next;
+ my_free(history, MYF(0));
+ }
+ my_free(closed_history, MYF(0));
+}
+
/*
Initialize maria
@@ -42,8 +61,11 @@ int maria_init(void)
maria_inited= TRUE;
pthread_mutex_init(&THR_LOCK_maria,MY_MUTEX_INIT_SLOW);
_ma_init_block_record_data();
+ trnman_end_trans_hook= _ma_trnman_end_trans_hook;
my_handler_error_register();
}
+ hash_init(&maria_stored_state, &my_charset_bin, 32,
+ 0, sizeof(LSN), 0, (hash_free_key) history_state_free, 0);
return 0;
}
@@ -73,5 +95,6 @@ void maria_end(void)
end_pagecache(maria_pagecache, TRUE);
ma_control_file_end();
pthread_mutex_destroy(&THR_LOCK_maria);
+ hash_free(&maria_stored_state);
}
}
diff --git a/storage/maria/ma_key_recover.c b/storage/maria/ma_key_recover.c
index 2876956e84b..5bb61fbeb97 100644
--- a/storage/maria/ma_key_recover.c
+++ b/storage/maria/ma_key_recover.c
@@ -636,9 +636,9 @@ uint _ma_apply_redo_index_new_page(MARIA_HA *info, LSN lsn,
share->state.key_root[key_nr]= file_size - share->block_size;
}
- if (file_size > info->state->key_file_length)
+ if (file_size > share->state.state.key_file_length)
{
- info->state->key_file_length= file_size;
+ share->state.state.key_file_length= file_size;
buff= info->keyread_buff;
info->keyread_buff_used= 1;
unlock_method= PAGECACHE_LOCK_WRITE;
diff --git a/storage/maria/ma_locking.c b/storage/maria/ma_locking.c
index 6d33a4f67e4..4ec242fd927 100644
--- a/storage/maria/ma_locking.c
+++ b/storage/maria/ma_locking.c
@@ -14,10 +14,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
- locking of isam-tables.
- reads info from a isam-table. Must be first request before doing any furter
- calls to any isamfunktion. Is used to allow many process use the same
- isamdatabase.
+ Locking of Maria-tables.
+ Must be first request before doing any furter calls to any Maria function.
+ Is used to allow many process use the same non transactional Maria table
*/
#include "ma_ftdefs.h"
@@ -57,12 +56,14 @@ int maria_lock_database(MARIA_HA *info, int lock_type)
if (info->lock_type == F_RDLCK)
{
count= --share->r_locks;
- _ma_restore_status(info);
+ if (share->lock_restore_status)
+ (*share->lock_restore_status)(info);
}
else
{
count= --share->w_locks;
- _ma_update_status(info);
+ if (share->lock.update_status)
+ (*share->lock.update_status)(info);
}
--share->tot_locks;
if (info->lock_type == F_WRLCK && !share->w_locks)
@@ -91,16 +92,16 @@ int maria_lock_database(MARIA_HA *info, int lock_type)
if (share->changed && !share->w_locks)
{
#ifdef HAVE_MMAP
- if ((info->s->mmaped_length !=
- info->s->state.state.data_file_length) &&
- (info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
+ if ((share->mmaped_length !=
+ share->state.state.data_file_length) &&
+ (share->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
{
- if (info->s->concurrent_insert)
- rw_wrlock(&info->s->mmap_lock);
- _ma_remap_file(info, info->s->state.state.data_file_length);
- info->s->nonmmaped_inserts= 0;
- if (info->s->concurrent_insert)
- rw_unlock(&info->s->mmap_lock);
+ if (share->lock_key_trees)
+ rw_wrlock(&share->mmap_lock);
+ _ma_remap_file(info, share->state.state.data_file_length);
+ share->nonmmaped_inserts= 0;
+ if (share->lock_key_trees)
+ rw_unlock(&share->mmap_lock);
}
#endif
#ifdef EXTERNAL_LOCKING
@@ -212,7 +213,7 @@ int maria_lock_database(MARIA_HA *info, int lock_type)
VOID(_ma_test_if_changed(info));
info->lock_type=lock_type;
- info->invalidator=info->s->invalidator;
+ info->invalidator=share->invalidator;
share->w_locks++;
share->tot_locks++;
break;
@@ -242,128 +243,6 @@ int maria_lock_database(MARIA_HA *info, int lock_type)
/****************************************************************************
- The following functions are called by thr_lock() in threaded applications
-****************************************************************************/
-
-/*
- Create a copy of the current status for the table
-
- SYNOPSIS
- _ma_get_status()
- param Pointer to Myisam handler
- concurrent_insert Set to 1 if we are going to do concurrent inserts
- (THR_WRITE_CONCURRENT_INSERT was used)
-*/
-
-void _ma_get_status(void* param, int concurrent_insert)
-{
- MARIA_HA *info=(MARIA_HA*) param;
- DBUG_ENTER("_ma_get_status");
- DBUG_PRINT("info",("key_file: %ld data_file: %ld concurrent_insert: %d",
- (long) info->s->state.state.key_file_length,
- (long) info->s->state.state.data_file_length,
- concurrent_insert));
-#ifndef DBUG_OFF
- if (info->state->key_file_length > info->s->state.state.key_file_length ||
- info->state->data_file_length > info->s->state.state.data_file_length)
- DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
- (long) info->state->key_file_length,
- (long) info->state->data_file_length));
-#endif
- info->save_state=info->s->state.state;
- info->state= &info->save_state;
- info->append_insert_at_end= concurrent_insert;
- DBUG_VOID_RETURN;
-}
-
-
-void _ma_update_status(void* param)
-{
- MARIA_HA *info=(MARIA_HA*) param;
- /*
- Because someone may have closed the table we point at, we only
- update the state if its our own state. This isn't a problem as
- we are always pointing at our own lock or at a read lock.
- (This is enforced by thr_multi_lock.c)
- */
- if (info->state == &info->save_state)
- {
- MARIA_SHARE *share= info->s;
-#ifndef DBUG_OFF
- DBUG_PRINT("info",("updating status: key_file: %ld data_file: %ld",
- (long) info->state->key_file_length,
- (long) info->state->data_file_length));
- if (info->state->key_file_length < share->state.state.key_file_length ||
- info->state->data_file_length < share->state.state.data_file_length)
- DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
- (long) share->state.state.key_file_length,
- (long) share->state.state.data_file_length));
-#endif
- /*
- we are going to modify the state without lock's log, this would break
- recovery if done with a transactional table.
- */
- DBUG_ASSERT(!info->s->base.born_transactional);
- share->state.state= *info->state;
- info->state= &share->state.state;
- }
- info->append_insert_at_end= 0;
-}
-
-
-void _ma_restore_status(void *param)
-{
- MARIA_HA *info= (MARIA_HA*) param;
- info->state= &info->s->state.state;
- info->append_insert_at_end= 0;
-}
-
-
-void _ma_copy_status(void* to,void *from)
-{
- ((MARIA_HA*) to)->state= &((MARIA_HA*) from)->save_state;
-}
-
-
-/*
- Check if should allow concurrent inserts
-
- IMPLEMENTATION
- Allow concurrent inserts if we don't have a hole in the table or
- if there is no active write lock and there is active read locks and
- maria_concurrent_insert == 2. In this last case the new
- row('s) are inserted at end of file instead of filling up the hole.
-
- The last case is to allow one to inserts into a heavily read-used table
- even if there is holes.
-
- NOTES
- If there is a an rtree indexes in the table, concurrent inserts are
- disabled in maria_open()
-
- RETURN
- 0 ok to use concurrent inserts
- 1 not ok
-*/
-
-my_bool _ma_check_status(void *param)
-{
- MARIA_HA *info=(MARIA_HA*) param;
- /*
- The test for w_locks == 1 is here because this thread has already done an
- external lock (in other words: w_locks == 1 means no other threads has
- a write lock)
- */
- DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u",
- (long) info->s->state.dellink, (uint) info->s->r_locks,
- (uint) info->s->w_locks));
- return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
- (maria_concurrent_insert == 2 && info->s->r_locks &&
- info->s->w_locks == 1));
-}
-
-
-/****************************************************************************
** functions to read / write the state
****************************************************************************/
@@ -389,7 +268,7 @@ int _ma_readinfo(register MARIA_HA *info __attribute__ ((unused)),
}
if (check_keybuffer)
VOID(_ma_test_if_changed(info));
- info->invalidator=info->s->invalidator;
+ info->invalidator=share->invalidator;
}
else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
{
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index 3a29d0f8d67..5807002f70b 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -91,6 +91,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode,
int save_errno;
uint errpos;
MARIA_HA info,*m_info;
+ MARIA_STATUS_INFO *state_dummy;
my_bitmap_map *changed_fields_bitmap;
DBUG_ENTER("maria_clone_internal");
@@ -118,12 +119,9 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode,
&info.first_mbr_key, share->base.max_key_length,
&info.maria_rtree_recursion_state,
share->have_rtree ? 1024 : 0,
- &info.key_write_undo_lsn,
- (uint) (sizeof(LSN) * share->base.keys),
- &info.key_delete_undo_lsn,
- (uint) (sizeof(LSN) * share->base.keys),
&changed_fields_bitmap,
bitmap_buffer_size(share->base.fields),
+ &state_dummy, sizeof(*state_dummy),
NullS))
goto err;
errpos= 6;
@@ -180,9 +178,18 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode,
maria_delay_key_write)
share->delay_key_write=1;
- info.state= &share->state.state; /* Change global values by default */
if (!share->base.born_transactional) /* For transactional ones ... */
+ {
info.trn= &dummy_transaction_object; /* ... force crash if no trn given */
+ info.state= &share->state.state; /* Change global values by default */
+ }
+ else
+ {
+ info.state= state_dummy;
+ *info.state= share->state.state; /* Initial values */
+ }
+ info.state_start= info.state; /* Initial values */
+
pthread_mutex_unlock(&share->intern_lock);
/* Allocate buffer for one record */
@@ -763,7 +770,31 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
_ma_setup_functions(share);
if ((*share->once_init)(share, info.dfile.file))
goto err;
-
+ if (share->now_transactional)
+ {
+ /* Setup initial state that is visible for all */
+ MARIA_STATE_HISTORY_CLOSED *history;
+ if ((history= (MARIA_STATE_HISTORY_CLOSED *)
+ hash_search(&maria_stored_state,
+ (uchar*) &share->state.create_rename_lsn, 0)))
+ {
+ /* Move history from hash to share */
+ share->state_history=
+ _ma_remove_not_visible_states(history->state_history, 0, 0);
+ history->state_history= 0;
+ (void) hash_delete(&maria_stored_state, (uchar*) history);
+ }
+ else
+ {
+ /* Table is not part of any active transaction; Create new history */
+ if (!(share->state_history= (MARIA_STATE_HISTORY *)
+ my_malloc(sizeof(*share->state_history), MYF(MY_WME))))
+ goto err;
+ share->state_history->trid= 0; /* Visibly by all */
+ share->state_history->state= share->state.state;
+ share->state_history->next= 0;
+ }
+ }
#ifdef THREAD
thr_lock_init(&share->lock);
VOID(pthread_mutex_init(&share->intern_lock, MY_MUTEX_INIT_FAST));
@@ -778,28 +809,34 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
}
else if (maria_concurrent_insert)
{
- share->concurrent_insert=
+ share->non_transactional_concurrent_insert=
((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
- HA_OPTION_COMPRESS_RECORD |
- HA_OPTION_TEMP_COMPRESS_RECORD)) ||
+ HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD)) ||
(open_flags & HA_OPEN_TMP_TABLE) ||
share->data_file_type == BLOCK_RECORD ||
share->have_rtree) ? 0 : 1;
- if (share->concurrent_insert)
+ if (share->non_transactional_concurrent_insert ||
+ (!share->temporary && share->now_transactional && !share->base.keys))
{
- share->lock.get_status=_ma_get_status;
- share->lock.copy_status=_ma_copy_status;
- /**
- @todo RECOVERY
- INSERT DELAYED and concurrent inserts are currently disabled for
- transactional tables; when enabled again, we should re-evaluate
- what problems the call to _ma_update_status() by
- thr_reschedule_write_lock() can do (it may hurt Checkpoint as it
- would be without intern_lock, and it modifies the state).
- */
- share->lock.update_status=_ma_update_status;
- share->lock.restore_status=_ma_restore_status;
- share->lock.check_status=_ma_check_status;
+ share->lock_key_trees= 1;
+ if (share->data_file_type == BLOCK_RECORD)
+ {
+ share->lock.get_status= _ma_block_get_status;
+ share->lock.update_status= _ma_block_update_status;
+ share->lock.check_status= _ma_block_check_status;
+ share->lock.allow_multiple_concurrent_insert= 1;
+ share->lock_restore_status= 0;
+ }
+ else
+ {
+ share->lock.get_status= _ma_get_status;
+ share->lock.copy_status= _ma_copy_status;
+ share->lock.update_status= _ma_update_status;
+ share->lock.restore_status=_ma_restore_status;
+ share->lock.check_status= _ma_check_status;
+ share->lock_restore_status= _ma_restore_status;
+ }
}
}
#endif
@@ -1714,17 +1751,21 @@ int maria_enable_indexes(MARIA_HA *info)
{
int error= 0;
MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_enable_indexes");
if ((share->state.state.data_file_length !=
(share->data_file_type == BLOCK_RECORD ? share->block_size : 0)) ||
(share->state.state.key_file_length != share->base.keystart))
{
+ DBUG_PRINT("error", ("data_file_length: %lu key_file_length: %lu",
+ (ulong) share->state.state.data_file_length,
+ (ulong) share->state.state.key_file_length));
maria_print_error(info->s, HA_ERR_CRASHED);
error= HA_ERR_CRASHED;
}
else
maria_set_all_keys_active(share->state.key_map, share->base.keys);
- return error;
+ DBUG_RETURN(error);
}
diff --git a/storage/maria/ma_page.c b/storage/maria/ma_page.c
index 9b2fd6b126c..24a97409aa3 100644
--- a/storage/maria/ma_page.c
+++ b/storage/maria/ma_page.c
@@ -101,13 +101,13 @@ int _ma_write_keypage(register MARIA_HA *info,
uint page_length, nod;
_ma_get_used_and_nod(share, buff, page_length, nod);
if (pos < share->base.keystart ||
- pos+block_size > info->state->key_file_length ||
+ pos+block_size > share->state.state.key_file_length ||
(pos & (maria_block_size-1)))
{
DBUG_PRINT("error",("Trying to write inside key status region: "
"key_start: %lu length: %lu page: %lu",
(long) share->base.keystart,
- (long) info->state->key_file_length,
+ (long) share->state.state.key_file_length,
(long) pos));
my_errno=EINVAL;
DBUG_ASSERT(0);
@@ -304,14 +304,18 @@ my_off_t _ma_new(register MARIA_HA *info, int level,
if (_ma_lock_key_del(info, 1))
{
- if (info->state->key_file_length >=
- share->base.max_key_file_length - block_size)
+ pthread_mutex_lock(&share->intern_lock);
+ pos= share->state.state.key_file_length;
+ if (pos >= share->base.max_key_file_length - block_size)
{
my_errno=HA_ERR_INDEX_FILE_FULL;
+ pthread_mutex_unlock(&share->intern_lock);
DBUG_RETURN(HA_OFFSET_ERROR);
}
- pos= info->state->key_file_length;
- info->state->key_file_length+= block_size;
+ share->state.state.key_file_length+= block_size;
+ /* Following is for not transactional tables */
+ info->state->key_file_length= share->state.state.key_file_length;
+ pthread_mutex_unlock(&share->intern_lock);
(*page_link)->changed= 0;
(*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
}
@@ -342,7 +346,7 @@ my_off_t _ma_new(register MARIA_HA *info, int level,
(current_key_del != 0) &&
((current_key_del == HA_OFFSET_ERROR) ||
(current_key_del <=
- (info->state->key_file_length - block_size))));
+ (share->state.state.key_file_length - block_size))));
#endif
}
diff --git a/storage/maria/ma_range.c b/storage/maria/ma_range.c
index 5769095606a..24e3d65714c 100644
--- a/storage/maria/ma_range.c
+++ b/storage/maria/ma_range.c
@@ -48,6 +48,7 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
key_range *max_key)
{
ha_rows start_pos,end_pos,res;
+ MARIA_SHARE *share= info->s;
DBUG_ENTER("maria_records_in_range");
if ((inx = _ma_check_index(info,inx)) < 0)
@@ -56,10 +57,10 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
if (fast_ma_readinfo(info))
DBUG_RETURN(HA_POS_ERROR);
info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED);
- if (info->s->concurrent_insert)
- rw_rdlock(&info->s->key_root_lock[inx]);
+ if (share->lock_key_trees)
+ rw_rdlock(&share->key_root_lock[inx]);
- switch(info->s->keyinfo[inx].key_alg){
+ switch(share->keyinfo[inx].key_alg){
#ifdef HAVE_RTREE_KEYS
case HA_KEY_ALG_RTREE:
{
@@ -81,7 +82,7 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
res= HA_POS_ERROR;
break;
}
- key_buff= info->lastkey+info->s->base.max_key_length;
+ key_buff= info->lastkey+share->base.max_key_length;
start_key_len= _ma_pack_key(info,inx, key_buff,
min_key->key, min_key->keypart_map,
(HA_KEYSEG**) 0);
@@ -107,8 +108,8 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
res=HA_POS_ERROR;
}
- if (info->s->concurrent_insert)
- rw_unlock(&info->s->key_root_lock[inx]);
+ if (share->lock_key_trees)
+ rw_unlock(&share->key_root_lock[inx]);
fast_ma_writeinfo(info);
/**
diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c
index 886d0797437..2e162b4e07d 100644
--- a/storage/maria/ma_recovery.c
+++ b/storage/maria/ma_recovery.c
@@ -2726,6 +2726,13 @@ static void prepare_table_for_close(MARIA_HA *info, TRANSLOG_ADDRESS horizon)
share->state.is_of_horizon= horizon;
_ma_state_info_write_sub(share->kfile.file, &share->state, 1);
}
+
+ /*
+ Ensure that info->state is up to date as
+ _ma_renable_logging_for_table() is depending on this
+ */
+ *info->state= info->s->state.state;
+
/*
This leaves PAGECACHE_PLAIN_PAGE pages into the cache, while the table is
going to switch back to transactional. So the table will be a mix of
@@ -3227,6 +3234,13 @@ my_bool _ma_reenable_logging_for_table(MARIA_HA *info, my_bool flush_pages)
if ((share->now_transactional= share->base.born_transactional))
{
share->page_type= PAGECACHE_LSN_PAGE;
+
+ /*
+ Copy state information that where updated while the table was used
+ in not transactional mode
+ */
+ _ma_copy_nontrans_state_information(info);
+
if (flush_pages)
{
/*
diff --git a/storage/maria/ma_rkey.c b/storage/maria/ma_rkey.c
index e6033cdc4a8..27584e3db0b 100644
--- a/storage/maria/ma_rkey.c
+++ b/storage/maria/ma_rkey.c
@@ -69,7 +69,7 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
if (fast_ma_readinfo(info))
goto err;
- if (share->concurrent_insert)
+ if (share->lock_key_trees)
rw_rdlock(&share->key_root_lock[inx]);
nextflag=maria_read_vec[search_flag];
@@ -93,7 +93,7 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
if (!_ma_search(info, keyinfo, key_buff, use_key_length,
maria_read_vec[search_flag],
info->s->state.key_root[inx]) &&
- share->concurrent_insert)
+ share->non_transactional_concurrent_insert)
{
/*
Found a key, but it might not be usable. We cannot use rows that
@@ -156,7 +156,7 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
}
}
}
- if (share->concurrent_insert)
+ if (share->lock_key_trees)
rw_unlock(&share->key_root_lock[inx]);
if (info->cur_row.lastpos == HA_OFFSET_ERROR)
diff --git a/storage/maria/ma_rnext.c b/storage/maria/ma_rnext.c
index fcc0f1f6a90..0aab055e999 100644
--- a/storage/maria/ma_rnext.c
+++ b/storage/maria/ma_rnext.c
@@ -39,7 +39,7 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
if (fast_ma_readinfo(info))
DBUG_RETURN(my_errno);
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_rdlock(&info->s->key_root_lock[inx]);
changed= _ma_test_if_changed(info);
if (!flag)
@@ -82,7 +82,7 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
}
}
- if (info->s->concurrent_insert)
+ if (info->s->non_transactional_concurrent_insert)
{
if (!error)
{
diff --git a/storage/maria/ma_rnext_same.c b/storage/maria/ma_rnext_same.c
index 9f2ada701a7..ffb84e04776 100644
--- a/storage/maria/ma_rnext_same.c
+++ b/storage/maria/ma_rnext_same.c
@@ -39,11 +39,10 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
if (fast_ma_readinfo(info))
DBUG_RETURN(my_errno);
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_rdlock(&info->s->key_root_lock[inx]);
- switch (keyinfo->key_alg)
- {
+ switch (keyinfo->key_alg) {
#ifdef HAVE_RTREE_KEYS
case HA_KEY_ALG_RTREE:
if ((error=maria_rtree_find_next(info,inx,
@@ -79,11 +78,12 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
break;
}
/* Skip rows that are inserted by other threads since we got a lock */
- if (info->cur_row.lastpos < info->state->data_file_length)
+ if (!info->s->non_transactional_concurrent_insert ||
+ info->cur_row.lastpos < info->state->data_file_length)
break;
}
}
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_unlock(&info->s->key_root_lock[inx]);
/* Don't clear if database-changed */
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
diff --git a/storage/maria/ma_rprev.c b/storage/maria/ma_rprev.c
index c41c88c154b..39383f662f8 100644
--- a/storage/maria/ma_rprev.c
+++ b/storage/maria/ma_rprev.c
@@ -39,7 +39,7 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
if (fast_ma_readinfo(info))
DBUG_RETURN(my_errno);
changed= _ma_test_if_changed(info);
- if (share->concurrent_insert)
+ if (share->lock_key_trees)
rw_rdlock(&share->key_root_lock[inx]);
if (!flag)
error= _ma_search_last(info, share->keyinfo+inx,
@@ -52,7 +52,7 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
error= _ma_search(info,share->keyinfo+inx,info->lastkey,
USE_WHOLE_KEY, flag, share->state.key_root[inx]);
- if (share->concurrent_insert)
+ if (share->non_transactional_concurrent_insert)
{
if (!error)
{
@@ -66,8 +66,9 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
break;
}
}
- rw_unlock(&share->key_root_lock[inx]);
}
+ if (share->lock_key_trees)
+ rw_unlock(&share->key_root_lock[inx]);
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_PREV_FOUND;
if (error)
diff --git a/storage/maria/ma_rsame.c b/storage/maria/ma_rsame.c
index 2e4d5a60ed8..015a3816392 100644
--- a/storage/maria/ma_rsame.c
+++ b/storage/maria/ma_rsame.c
@@ -54,12 +54,12 @@ int maria_rsame(MARIA_HA *info, uchar *record, int inx)
info->lastinx=inx;
info->lastkey_length= _ma_make_key(info,(uint) inx,info->lastkey,record,
info->cur_row.lastpos);
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_rdlock(&info->s->key_root_lock[inx]);
VOID(_ma_search(info,info->s->keyinfo+inx,info->lastkey, USE_WHOLE_KEY,
SEARCH_SAME,
info->s->state.key_root[inx]));
- if (info->s->concurrent_insert)
+ if (info->s->lock_key_trees)
rw_unlock(&info->s->key_root_lock[inx]);
}
diff --git a/storage/maria/ma_sort.c b/storage/maria/ma_sort.c
index cf5ab2d3723..d7c50d03790 100644
--- a/storage/maria/ma_sort.c
+++ b/storage/maria/ma_sort.c
@@ -532,9 +532,10 @@ int _ma_thr_write_keys(MARIA_SORT_PARAM *sort_param)
}
if (!got_error && param->testflag & T_STATISTICS)
maria_update_key_parts(sinfo->keyinfo, rec_per_key_part, sinfo->unique,
- param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
- sinfo->notnull: NULL,
- (ulonglong) info->state->records);
+ param->stats_method ==
+ MI_STATS_METHOD_IGNORE_NULLS ?
+ sinfo->notnull : NULL,
+ (ulonglong) share->state.state.records);
}
my_free((uchar*) sinfo->sort_keys,MYF(0));
my_free(sinfo->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
diff --git a/storage/maria/ma_state.c b/storage/maria/ma_state.c
new file mode 100644
index 00000000000..6adaf6818cc
--- /dev/null
+++ b/storage/maria/ma_state.c
@@ -0,0 +1,478 @@
+/* Copyright (C) 2008 Sun AB and Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Functions to maintain live statistics for Maria transactional tables
+ and versioning for not transactional tables
+
+ See WL#3138; Maria - fast "SELECT COUNT(*) FROM t;" and "CHECKSUM TABLE t"
+ for details about live number of rows and live checksums
+
+ TODO
+ - Allocate MA_USED_TABLES and MA_HISTORY_STATE from a global pool (to
+ avoid calls to malloc()
+ - In trnamn_end_trans_hook(), don't call _ma_remove_not_visible_states()
+ every time. One could for example call it if there has been more than
+ 10 ended transactions since last time it was called.
+*/
+
+#include <maria_def.h>
+#include "trnman.h"
+#include <ma_blockrec.h>
+
+/**
+ @brief Setup initial start-of-transaction state for a table
+
+ @fn _ma_setup_live_state
+ @param info Maria handler
+
+ @notes
+ This function ensures that trn->used_tables contains a list of
+ start and live states for tables that are part of the transaction
+ and that info->state points to the current live state for the table.
+
+ @TODO
+ Change trn->table_list to a hash and share->state_history to a binary tree
+
+ @return
+ @retval 0 ok
+ @retval 1 error (out of memory)
+*/
+
+my_bool _ma_setup_live_state(MARIA_HA *info)
+{
+ TRN *trn= info->trn;
+ MARIA_SHARE *share= info->s;
+ MARIA_USED_TABLES *tables;
+ MARIA_STATE_HISTORY *history;
+ DBUG_ENTER("_ma_setup_live_state");
+
+ for (tables= (MARIA_USED_TABLES*) info->trn->used_tables;
+ tables;
+ tables= tables->next)
+ {
+ if (tables->share == share)
+ {
+ /* Table is already used by transaction */
+ goto end;
+ }
+ }
+ /* Table was not used before, create new table state entry */
+ if (!(tables= (MARIA_USED_TABLES*) my_malloc(sizeof(*tables),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(1);
+ tables->next= trn->used_tables;
+ trn->used_tables= tables;
+ tables->share= share;
+
+ pthread_mutex_lock(&share->intern_lock);
+ share->in_trans++;
+ history= share->state_history;
+
+ /*
+ We must keep share locked to ensure that we don't access a history
+ link that is deleted by concurrently running checkpoint.
+
+ It's enough to compare trids here (instead of calling
+ tranman_can_read_from) as history->trid is a commit_trid
+ */
+ DBUG_PRINT("QQ", ("trn->trid: 0x%lu", (long) trn->trid));
+ while (trn->trid < history->trid)
+ history= history->next;
+ DBUG_PRINT("QQ", ("his->trid: 0x%lu", (long) history->trid));
+ pthread_mutex_unlock(&share->intern_lock);
+ /* The current item can't be deleted as it's the first one visible for us */
+ tables->state_start= tables->state_current= history->state;
+ DBUG_PRINT("info", ("records: %ld", (ulong) tables->state_start.records));
+
+end:
+ info->state_start= &tables->state_start;
+ info->state= &tables->state_current;
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Remove states that are not visible by anyone
+
+ @fn _ma_remove_not_visible_states()
+ @param org_history List to history
+ @param all 1 if we should delete the first state if it's
+ visible for all. For the moment this is only used
+ on close() of table.
+
+ @notes
+ The assumption is that items in the history list is ordered by
+ commit_trid.
+
+ A state is not visible anymore if there is no new transaction
+ that has been started between the commit_trid's of two states
+
+ As long as some states exists, we keep the newest = (last commit)
+ state as first state in the history. This is to allow us to just move
+ the history from the global list to the share when we open the table.
+
+ @return
+ @retval Pointer to new history list
+*/
+
+MARIA_STATE_HISTORY
+*_ma_remove_not_visible_states(MARIA_STATE_HISTORY *org_history,
+ my_bool all,
+ my_bool trnman_is_locked)
+{
+ TrID last_trid;
+ MARIA_STATE_HISTORY *history, **parent, *next;
+ DBUG_ENTER("_ma_remove_not_visible_states");
+
+ if (!org_history)
+ DBUG_RETURN(0); /* Not versioned table */
+
+ last_trid= org_history->trid;
+ parent= &org_history->next;
+ for (history= org_history->next; history; history= next)
+ {
+ next= history->next;
+ if (!trnman_exists_active_transactions(history->trid, last_trid,
+ trnman_is_locked))
+ {
+ my_free(history, MYF(0));
+ continue;
+ }
+ *parent= history;
+ parent= &history->next;
+ last_trid= history->trid;
+ }
+ *parent= 0;
+
+ if (all && parent == &org_history->next)
+ {
+ /* There is only one state left. Delete this if it's visible for all */
+ if (last_trid < trnman_get_min_trid())
+ {
+ my_free(org_history, MYF(0));
+ org_history= 0;
+ }
+ }
+ DBUG_RETURN(org_history);
+}
+
+/*
+ Free state history information from share->history and reset information
+ to current state.
+
+ @notes
+ Used after repair as then all rows are visible for everyone
+*/
+
+void _ma_reset_state(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_STATE_HISTORY *history= share->state_history;
+
+ if (history)
+ {
+ MARIA_STATE_HISTORY *next;
+
+ /* Set the current history to current state */
+ share->state_history->state= share->state.state;
+ for (history= history->next ; history ; history= next)
+ {
+ next= history->next;
+ my_free(history, MYF(0));
+ }
+ share->state_history->next= 0;
+ share->state_history->trid= 0; /* Visibile for all */
+ }
+}
+
+
+/****************************************************************************
+ The following functions are called by thr_lock() in threaded applications
+ for not transactional tables
+****************************************************************************/
+
+/*
+ Create a copy of the current status for the table
+
+ SYNOPSIS
+ _ma_get_status()
+ param Pointer to Myisam handler
+ concurrent_insert Set to 1 if we are going to do concurrent inserts
+ (THR_WRITE_CONCURRENT_INSERT was used)
+*/
+
+void _ma_get_status(void* param, my_bool concurrent_insert)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ DBUG_ENTER("_ma_get_status");
+ DBUG_PRINT("info",("key_file: %ld data_file: %ld concurrent_insert: %d",
+ (long) info->s->state.state.key_file_length,
+ (long) info->s->state.state.data_file_length,
+ concurrent_insert));
+#ifndef DBUG_OFF
+ if (info->state->key_file_length > info->s->state.state.key_file_length ||
+ info->state->data_file_length > info->s->state.state.data_file_length)
+ DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+#endif
+ info->state_save= info->s->state.state;
+ info->state= &info->state_save;
+ info->append_insert_at_end= concurrent_insert;
+ DBUG_VOID_RETURN;
+}
+
+
+void _ma_update_status(void* param)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ /*
+ Because someone may have closed the table we point at, we only
+ update the state if its our own state. This isn't a problem as
+ we are always pointing at our own lock or at a read lock.
+ (This is enforced by thr_multi_lock.c)
+ */
+ if (info->state == &info->state_save)
+ {
+ MARIA_SHARE *share= info->s;
+#ifndef DBUG_OFF
+ DBUG_PRINT("info",("updating status: key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+ if (info->state->key_file_length < share->state.state.key_file_length ||
+ info->state->data_file_length < share->state.state.data_file_length)
+ DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
+ (long) share->state.state.key_file_length,
+ (long) share->state.state.data_file_length));
+#endif
+ /*
+ we are going to modify the state without lock's log, this would break
+ recovery if done with a transactional table.
+ */
+ DBUG_ASSERT(!info->s->base.born_transactional);
+ share->state.state= *info->state;
+ info->state= &share->state.state;
+ }
+ info->append_insert_at_end= 0;
+}
+
+
+void _ma_restore_status(void *param)
+{
+ MARIA_HA *info= (MARIA_HA*) param;
+ info->state= &info->s->state.state;
+ info->append_insert_at_end= 0;
+}
+
+
+void _ma_copy_status(void* to, void *from)
+{
+ ((MARIA_HA*) to)->state= &((MARIA_HA*) from)->state_save;
+}
+
+
+/**
+ @brief Check if should allow concurrent inserts
+
+ @implementation
+ Allow concurrent inserts if we don't have a hole in the table or
+ if there is no active write lock and there is active read locks and
+ maria_concurrent_insert == 2. In this last case the new
+ row('s) are inserted at end of file instead of filling up the hole.
+
+ The last case is to allow one to inserts into a heavily read-used table
+ even if there is holes.
+
+ @notes
+ If there is a an rtree indexes in the table, concurrent inserts are
+ disabled in maria_open()
+
+ @return
+ @retval 0 ok to use concurrent inserts
+ @retval 1 not ok
+*/
+
+my_bool _ma_check_status(void *param)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ /*
+ The test for w_locks == 1 is here because this thread has already done an
+ external lock (in other words: w_locks == 1 means no other threads has
+ a write lock)
+ */
+ DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u",
+ (long) info->s->state.dellink, (uint) info->s->r_locks,
+ (uint) info->s->w_locks));
+ return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
+ (maria_concurrent_insert == 2 && info->s->r_locks &&
+ info->s->w_locks == 1));
+}
+
+
+/**
+ @brief write hook at end of trans to store status for all used table
+*/
+
+my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
+ my_bool active_transactions)
+{
+ my_bool error= 0;
+ MARIA_USED_TABLES *tables, *next;
+
+ for (tables= (MARIA_USED_TABLES*) trn->used_tables;
+ tables;
+ tables= next)
+ {
+ next= tables->next;
+ if (commit)
+ {
+ MARIA_SHARE *share= tables->share;
+ MARIA_STATE_HISTORY *history;
+
+ pthread_mutex_lock(&share->intern_lock);
+ if (active_transactions &&
+ trnman_exists_active_transactions(share->state_history->trid,
+ trn->commit_trid, 1))
+ {
+ if (!(history= my_malloc(sizeof(*history), MYF(MY_WME))))
+ {
+ pthread_mutex_unlock(&share->intern_lock);
+ my_free(tables, MYF(0));
+ error= 1;
+ continue;
+ }
+ history->state= share->state_history->state;
+ history->next= share->state_history;
+ share->state_history= history;
+ }
+ else
+ {
+ /* Previous history can't be seen by anyone, reuse old memory */
+ history= share->state_history;
+ }
+
+ history->state.records+= (tables->state_current.records -
+ tables->state_start.records);
+ history->state.checksum+= (tables->state_current.checksum -
+ tables->state_start.checksum);
+ history->trid= trn->commit_trid;
+
+ if (history->next)
+ {
+ /* Remove not visible states */
+ share->state_history= _ma_remove_not_visible_states(history, 0, 1);
+ }
+ share->in_trans--;
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ my_free(tables, MYF(0));
+ }
+ trn->used_tables= 0;
+ return error;
+}
+
+
+/****************************************************************************
+ The following functions are called by thr_lock() in threaded applications
+ for transactional tables.
+****************************************************************************/
+
+/*
+ Create a copy of the current status for the table
+
+ SYNOPSIS
+ _ma_get_status()
+ param Pointer to Myisam handler
+ concurrent_insert Set to 1 if we are going to do concurrent inserts
+ (THR_WRITE_CONCURRENT_INSERT was used)
+*/
+
+void _ma_block_get_status(void* param, my_bool concurrent_insert)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ DBUG_ENTER("_ma_block_get_status");
+ DBUG_PRINT("info", ("concurrent_insert %d", concurrent_insert));
+ info->row_base_length= info->s->base_length;
+ info->row_flag= info->s->base.default_row_flag;
+ if (concurrent_insert)
+ {
+ info->row_flag|= ROW_FLAG_TRANSID;
+ info->row_base_length+= TRANSID_SIZE;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void _ma_block_update_status(void *param __attribute__((unused)))
+{
+}
+
+void _ma_block_restore_status(void *param __attribute__((unused)))
+{
+}
+
+
+/**
+ Check if should allow concurrent inserts
+
+ @return
+ @retval 0 ok to use concurrent inserts
+ @retval 1 not ok
+*/
+
+my_bool _ma_block_check_status(void *param __attribute__((unused)))
+{
+ return (my_bool) 0;
+}
+
+
+/**
+ Enable/disable versioning
+*/
+
+void maria_versioning(MARIA_HA *info, my_bool versioning)
+{
+ /* For now, this is a hack */
+ _ma_block_get_status((void*) info, versioning);
+}
+
+
+/**
+ Update data_file_length to new length
+
+ NOTES
+ Only used by block records
+*/
+
+void _ma_set_share_data_file_length(MARIA_SHARE *share, ulonglong new_length)
+{
+ pthread_mutex_lock(&share->intern_lock);
+ if (share->state.state.data_file_length < new_length)
+ share->state.state.data_file_length= new_length;
+ pthread_mutex_unlock(&share->intern_lock);
+}
+
+
+/**
+ Copy state information that where updated while the table was used
+ in not transactional mode
+*/
+
+void _ma_copy_nontrans_state_information(MARIA_HA *info)
+{
+ info->s->state.state.records= info->state->records;
+ info->s->state.state.checksum= info->state->checksum;
+}
diff --git a/storage/maria/ma_state.h b/storage/maria/ma_state.h
new file mode 100644
index 00000000000..eab206633f9
--- /dev/null
+++ b/storage/maria/ma_state.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 2008 Sun AB & Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Struct to store tables in use by one transaction */
+
+typedef struct st_maria_status_info
+{
+ ha_rows records; /* Rows in table */
+ ha_rows del; /* Removed rows */
+ my_off_t empty; /* lost space in datafile */
+ my_off_t key_empty; /* lost space in indexfile */
+ my_off_t key_file_length;
+ my_off_t data_file_length;
+ ha_checksum checksum;
+} MARIA_STATUS_INFO;
+
+
+typedef struct st_used_tables {
+ struct st_used_tables *next;
+ struct st_maria_share *share;
+ MARIA_STATUS_INFO state_current;
+ MARIA_STATUS_INFO state_start;
+} MARIA_USED_TABLES;
+
+
+/* Struct to store commit state at different times */
+
+typedef struct st_state_history {
+ struct st_state_history *next;
+ TrID trid;
+ MARIA_STATUS_INFO state;
+} MARIA_STATE_HISTORY;
+
+
+/* struct to remember history for closed tables */
+
+typedef struct st_state_history_closed {
+ LSN create_rename_lsn;
+ MARIA_STATE_HISTORY *state_history;
+} MARIA_STATE_HISTORY_CLOSED;
+
+
+my_bool _ma_setup_live_state(MARIA_HA *info);
+MARIA_STATE_HISTORY *_ma_remove_not_visible_states(MARIA_STATE_HISTORY
+ *org_history,
+ my_bool all,
+ my_bool trman_is_locked);
+void _ma_reset_state(MARIA_HA *info);
+void _ma_get_status(void* param, my_bool concurrent_insert);
+void _ma_update_status(void* param);
+void _ma_restore_status(void *param);
+void _ma_copy_status(void* to, void *from);
+my_bool _ma_check_status(void *param);
+void _ma_block_get_status(void* param, my_bool concurrent_insert);
+void _ma_block_update_status(void *param);
+void _ma_block_restore_status(void *param);
+my_bool _ma_block_check_status(void *param);
+void maria_versioning(MARIA_HA *info, my_bool versioning);
+void _ma_set_share_data_file_length(struct st_maria_share *share,
+ ulonglong new_length);
+void _ma_copy_nontrans_state_information(MARIA_HA *info);
+my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
+ my_bool active_transactions);
diff --git a/storage/maria/ma_static.c b/storage/maria/ma_static.c
index 07f593d5be2..34bf08a9cb2 100644
--- a/storage/maria/ma_static.c
+++ b/storage/maria/ma_static.c
@@ -52,6 +52,7 @@ PAGECACHE maria_log_pagecache_var;
PAGECACHE *maria_log_pagecache= &maria_log_pagecache_var;
MY_TMPDIR *maria_tmpdir; /* Tempdir for redo */
char *maria_data_root;
+HASH maria_stored_state;
/**
@brief when transactionality does not matter we can use this transaction
diff --git a/storage/maria/ma_test1.c b/storage/maria/ma_test1.c
index bd373c4ad4b..471db7937f0 100644
--- a/storage/maria/ma_test1.c
+++ b/storage/maria/ma_test1.c
@@ -43,6 +43,7 @@ static uint unique_key=HA_NOSAME;
static uint die_in_middle_of_transaction;
static my_bool pagecacheing, null_fields, silent, skip_update, opt_unique;
static my_bool verbose, skip_delete, transactional;
+static my_bool opt_versioning= 0;
static MARIA_COLUMNDEF recinfo[4];
static MARIA_KEYDEF keyinfo[10];
static HA_KEYSEG keyseg[10];
@@ -76,7 +77,7 @@ int main(int argc,char *argv[])
if (maria_init() ||
(init_pagecache(maria_pagecache, maria_block_size * 16, 0, 0,
maria_block_size, MY_WME) == 0) ||
- ma_control_file_open(TRUE) ||
+ ma_control_file_open(TRUE, TRUE) ||
(init_pagecache(maria_log_pagecache,
TRANSLOG_PAGECACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
@@ -209,6 +210,8 @@ static int run_test(const char *filename)
if (maria_begin(file))
goto err;
+ if (opt_versioning)
+ maria_versioning(file, 1);
my_errno=0;
row_count=deleted=0;
for (i=49 ; i>=1 ; i-=2 )
@@ -338,6 +341,8 @@ static int run_test(const char *filename)
goto err;
if (maria_begin(file))
goto err;
+ if (opt_versioning)
+ maria_versioning(file, 1);
if (!skip_delete)
{
if (!silent)
@@ -766,7 +771,7 @@ static struct my_option my_long_options[] =
"Test in transactional mode. (Only works with block format)",
(uchar**) &transactional, (uchar**) &transactional, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
- {"unique", 'C', "Undocumented", (uchar**) &opt_unique,
+ {"unique", 'E', "Check unique handling", (uchar**) &opt_unique,
(uchar**) &opt_unique, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"update-rows", 'u', "Max number of rows to update", (uchar**) &update_count,
(uchar**) &update_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
@@ -774,6 +779,9 @@ static struct my_option my_long_options[] =
(uchar**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Print version number and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"versioning", 'C', "Use row versioning (only works with block format)",
+ (uchar**) &opt_versioning, (uchar**) &opt_versioning, 0, GET_BOOL,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -871,7 +879,8 @@ static void get_options(int argc, char *argv[])
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
exit(ho_error);
-
+ if (transactional)
+ record_type= BLOCK_RECORD;
return;
} /* get options */
diff --git a/storage/maria/ma_test2.c b/storage/maria/ma_test2.c
index 7d7eaf997b6..d3b5cca70c5 100644
--- a/storage/maria/ma_test2.c
+++ b/storage/maria/ma_test2.c
@@ -44,6 +44,7 @@ static int silent= 0, opt_quick_mode= 0, transactional= 0, skip_update= 0;
static int die_in_middle_of_transaction= 0, pack_fields= 1;
static int pack_seg= HA_SPACE_PACK, pack_type= HA_PACK_KEY, remove_count= -1;
static int create_flag= 0, srand_arg= 0, checkpoint= 0;
+static my_bool opt_versioning= 0;
static uint use_blob= 0, update_count= 0;
static ulong pagecache_size=8192*32;
static enum data_file_type record_type= DYNAMIC_RECORD;
@@ -83,7 +84,7 @@ int main(int argc, char *argv[])
if (maria_init() ||
(init_pagecache(maria_pagecache, pagecache_size, 0, 0,
maria_block_size, MY_WME) == 0) ||
- ma_control_file_open(TRUE) ||
+ ma_control_file_open(TRUE, TRUE) ||
(init_pagecache(maria_log_pagecache,
TRANSLOG_PAGECACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
@@ -230,6 +231,8 @@ int main(int argc, char *argv[])
if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
goto err;
maria_begin(file);
+ if (opt_versioning)
+ maria_versioning(file, 1);
if (testflag == 1)
goto end;
if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
@@ -1136,12 +1139,15 @@ static void get_options(int argc, char **argv)
case 'g':
skip_update= TRUE;
break;
+ case 'C':
+ opt_versioning= 1;
+ break;
case '?':
case 'I':
case 'V':
- printf("%s Ver 1.1 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ printf("%s Ver 1.2 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
puts("By Monty, for testing Maria\n");
- printf("Usage: %s [-?AbBcDIKLPRqSsTVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] [-t#]\n",
+ printf("Usage: %s [-?AbBcCDIKLPRqSsTVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] [-t#]\n",
progname);
exit(0);
case '#':
diff --git a/storage/maria/ma_test_recovery b/storage/maria/ma_test_recovery
index 69fd9778a24..0b20264c434 100755
--- a/storage/maria/ma_test_recovery
+++ b/storage/maria/ma_test_recovery
@@ -5,4 +5,4 @@
# This file is deprecated and has been replaced with ma_test_recovery.pl
-unittest/ma_test_recovery.pl
+unittest/ma_test_recovery.pl $@
diff --git a/storage/maria/ma_update.c b/storage/maria/ma_update.c
index 09d95b758f3..4a1ba63c6af 100644
--- a/storage/maria/ma_update.c
+++ b/storage/maria/ma_update.c
@@ -42,7 +42,7 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
{
DBUG_RETURN(my_errno=EACCES);
}
- if (info->state->key_file_length >= share->base.margin_key_file_length)
+ if (share->state.state.key_file_length >= share->base.margin_key_file_length)
{
DBUG_RETURN(my_errno=HA_ERR_INDEX_FILE_FULL);
}
@@ -144,24 +144,12 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
*/
info->cur_row.checksum= (*share->calc_checksum)(info, newrec);
info->new_row.checksum= (*share->calc_checksum)(info, oldrec);
- if (!share->now_transactional)
- info->state->checksum+= info->cur_row.checksum - info->new_row.checksum;
- }
- {
- /*
- Don't update index file if data file is not extended and no status
- information changed
- */
- MARIA_STATUS_INFO state;
- ha_rows org_split;
- my_off_t org_delete_link;
-
- memcpy((char*) &state, (char*) info->state, sizeof(state));
- org_split= share->state.split;
- org_delete_link= share->state.dellink;
- if ((*share->update_record)(info, pos, oldrec, newrec))
- goto err;
+ info->state->checksum+= info->cur_row.checksum - info->new_row.checksum;
}
+
+ if ((*share->update_record)(info, pos, oldrec, newrec))
+ goto err;
+
if (auto_key_changed & !share->now_transactional)
{
const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
@@ -171,8 +159,7 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
}
/*
- We can't yet have HA_STATE_AKTIV here, as block_record dosn't support
- it
+ We can't yet have HA_STATE_AKTIV here, as block_record dosn't support it
*/
info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | key_changed);
share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
diff --git a/storage/maria/ma_write.c b/storage/maria/ma_write.c
index c8dac8f407c..9695a3d3bab 100644
--- a/storage/maria/ma_write.c
+++ b/storage/maria/ma_write.c
@@ -68,6 +68,10 @@ static my_bool _ma_log_key_middle(MARIA_HA *info, my_off_t page,
/*
@brief Default handler for returing position to new row
+
+ @note
+ This is only called for non transactional tables and not for block format
+ which is why we use info->state here.
*/
MARIA_RECORD_POS _ma_write_init_default(MARIA_HA *info,
@@ -95,7 +99,7 @@ int maria_write(MARIA_HA *info, uchar *record)
int save_errno;
MARIA_RECORD_POS filepos;
uchar *buff;
- my_bool lock_tree= share->concurrent_insert;
+ my_bool lock_tree= share->lock_key_trees;
my_bool fatal_error;
DBUG_ENTER("maria_write");
DBUG_PRINT("enter",("index_file: %d data_file: %d",
@@ -114,12 +118,12 @@ int maria_write(MARIA_HA *info, uchar *record)
if (share->base.reloc == (ha_rows) 1 &&
share->base.records == (ha_rows) 1 &&
- info->state->records == (ha_rows) 1)
+ share->state.state.records == (ha_rows) 1)
{ /* System file */
my_errno=HA_ERR_RECORD_FILE_FULL;
goto err2;
}
- if (info->state->key_file_length >= share->base.margin_key_file_length)
+ if (share->state.state.key_file_length >= share->base.margin_key_file_length)
{
my_errno=HA_ERR_INDEX_FILE_FULL;
goto err2;
@@ -202,8 +206,7 @@ int maria_write(MARIA_HA *info, uchar *record)
{
if ((*share->write_record)(info,record))
goto err;
- if (!share->now_transactional)
- info->state->checksum+= info->cur_row.checksum;
+ info->state->checksum+= info->cur_row.checksum;
}
if (!share->now_transactional)
{
@@ -214,8 +217,8 @@ int maria_write(MARIA_HA *info, uchar *record)
set_if_bigger(share->state.auto_increment,
ma_retrieve_auto_increment(key, keyseg->type));
}
- info->state->records++;
}
+ info->state->records++;
info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
HA_STATE_ROW_CHANGED);
share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
@@ -394,9 +397,8 @@ static int _ma_ck_write_btree_with_log(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
error= _ma_ck_real_write_btree(info, keyinfo, key, key_length, &new_root,
comp_flag);
if (!error && share->now_transactional)
- error=
- _ma_write_undo_key_insert(info, keyinfo, key_buff, key_length,
- root, new_root, &lsn);
+ error= _ma_write_undo_key_insert(info, keyinfo, key_buff, key_length,
+ root, new_root, &lsn);
else
{
*root= new_root;
@@ -529,7 +531,7 @@ static int w_search(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
if (flag == 0)
{
uint tmp_key_length;
- /* get position to record with duplicated key */
+ /* get position to record with duplicated key */
tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
if (tmp_key_length)
dup_key_pos= _ma_dpos(info,0,keybuff+tmp_key_length);
@@ -1478,7 +1480,7 @@ static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
switch (mode) {
case free_init:
- if (share->concurrent_insert)
+ if (share->lock_key_trees)
{
rw_wrlock(&share->key_root_lock[param->keynr]);
share->keyinfo[param->keynr].version++;
@@ -1491,7 +1493,7 @@ static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
return _ma_ck_write_btree(param->info, param->keynr, lastkey,
keylen - share->rec_reflength);
case free_end:
- if (share->concurrent_insert)
+ if (share->lock_key_trees)
rw_unlock(&share->key_root_lock[param->keynr]);
return 0;
}
@@ -1570,7 +1572,7 @@ void maria_flush_bulk_insert(MARIA_HA *info, uint inx)
}
}
-void maria_end_bulk_insert(MARIA_HA *info)
+void maria_end_bulk_insert(MARIA_HA *info, my_bool abort)
{
DBUG_ENTER("maria_end_bulk_insert");
if (info->bulk_insert)
@@ -1578,11 +1580,15 @@ void maria_end_bulk_insert(MARIA_HA *info)
uint i;
for (i=0 ; i < info->s->base.keys ; i++)
{
- if (is_tree_inited(& info->bulk_insert[i]))
+ if (is_tree_inited(&info->bulk_insert[i]))
+ {
+ if (abort)
+ reset_free_element(&info->bulk_insert[i]);
delete_tree(&info->bulk_insert[i]);
+ }
}
my_free(info->bulk_insert, MYF(0));
- info->bulk_insert=0;
+ info->bulk_insert= 0;
}
DBUG_VOID_RETURN;
}
@@ -1605,7 +1611,6 @@ int _ma_write_undo_key_insert(MARIA_HA *info,
struct st_msg_to_write_hook_for_undo_key msg;
/* Save if we need to write a clr record */
- info->key_write_undo_lsn[keyinfo->key_nr]= info->trn->undo_lsn;
lsn_store(log_data, info->trn->undo_lsn);
key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
keyinfo->key_nr);
diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c
index 55db8e6308d..b64a7379c50 100644
--- a/storage/maria/maria_chk.c
+++ b/storage/maria/maria_chk.c
@@ -106,14 +106,21 @@ int main(int argc, char **argv)
error=0;
maria_init();
+ if (ma_control_file_open(FALSE, opt_require_control_file) &&
+ (opt_require_control_file ||
+ (opt_transaction_logging && (check_param.testflag & T_REP_ANY))))
+ {
+ error= 1;
+ goto end;
+ }
+
/*
If we are doing a repair, user may want to store this repair into the log
so that the log has a complete history and can be used to replay.
*/
if (opt_transaction_logging && (check_param.testflag & T_REP_ANY))
{
- if (ma_control_file_open(FALSE) ||
- init_pagecache(maria_log_pagecache,
+ if (init_pagecache(maria_log_pagecache,
TRANSLOG_PAGECACHE_SIZE, 0, 0,
TRANSLOG_PAGE_SIZE, MY_WME) == 0 ||
translog_init(opt_log_dir, TRANSLOG_FILE_SIZE,
@@ -127,14 +134,6 @@ int main(int argc, char **argv)
goto end;
}
}
- else
- {
- if (ma_control_file_open(FALSE) && opt_require_control_file)
- {
- error= 1;
- goto end;
- }
- }
while (--argc >= 0)
{
@@ -1237,9 +1236,10 @@ static int maria_chk(HA_CHECK *param, char *filename)
printf("Data records: %7s Deleted blocks: %7s\n",
llstr(info->state->records,llbuff),
llstr(info->state->del,llbuff2));
- error =maria_chk_status(param,info);
+ maria_chk_init_for_check(param, info);
+ error= maria_chk_status(param,info);
maria_intersect_keys_active(share->state.key_map, param->keys_in_use);
- error =maria_chk_size(param,info);
+ error|= maria_chk_size(param,info);
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
error|=maria_chk_del(param, info,param->testflag);
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
@@ -1327,7 +1327,15 @@ end2:
T_ZEROFILL)))
error= write_log_record(param);
+ if (param->not_visible_rows_found && (param->testflag & T_VERBOSE))
+ {
+ char buff[22];
+ printf("Max transaction id found: %s\n",
+ llstr(param->max_found_trid, buff));
+ }
+
VOID(fflush(stdout)); VOID(fflush(stderr));
+
if (param->error_printed)
{
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h
index 5b5503fb02c..1ee30c39a57 100644
--- a/storage/maria/maria_def.h
+++ b/storage/maria/maria_def.h
@@ -25,8 +25,10 @@
#else
#include <my_no_pthread.h>
#endif
+#include <hash.h>
#include "ma_loghandler.h"
#include "ma_control_file.h"
+#include "ma_state.h"
/* For testing recovery */
#ifdef TO_BE_REMOVED
@@ -51,17 +53,6 @@ struct st_transaction;
#define CRC_SIZE 4
-typedef struct st_maria_status_info
-{
- ha_rows records; /* Rows in table */
- ha_rows del; /* Removed rows */
- my_off_t empty; /* lost space in datafile */
- my_off_t key_empty; /* lost space in indexfile */
- my_off_t key_file_length;
- my_off_t data_file_length;
- ha_checksum checksum;
-} MARIA_STATUS_INFO;
-
typedef struct st_maria_state_info
{
struct
@@ -269,8 +260,8 @@ typedef struct st_maria_share
{ /* Shared between opens */
MARIA_STATE_INFO state;
MARIA_BASE_INFO base;
- MARIA_KEYDEF ft2_keyinfo; /* Second-level ft-key
- definition */
+ MARIA_STATE_HISTORY *state_history;
+ MARIA_KEYDEF ft2_keyinfo; /* Second-level ft-key definition */
MARIA_KEYDEF *keyinfo; /* Key definitions */
MARIA_UNIQUEDEF *uniqueinfo; /* unique definitions */
HA_KEYSEG *keyparts; /* key part info */
@@ -356,6 +347,7 @@ typedef struct st_maria_share
File data_file; /* Shared data file */
int mode; /* mode of file on open */
uint reopen; /* How many times reopened */
+ uint in_trans; /* Number of references by trn */
uint w_locks, r_locks, tot_locks; /* Number of read/write locks */
uint block_size; /* block_size of keyfile & data file*/
/* Fixed length part of a packed row in BLOCK_RECORD format */
@@ -370,7 +362,9 @@ typedef struct st_maria_share
my_bool changed, /* If changed since lock */
global_changed, /* If changed since open */
- not_flushed, concurrent_insert;
+ not_flushed;
+ my_bool lock_key_trees; /* If we have to lock trees on read */
+ my_bool non_transactional_concurrent_insert;
my_bool delay_key_write;
my_bool have_rtree;
/**
@@ -383,6 +377,7 @@ typedef struct st_maria_share
my_bool used_key_del; /* != 0 if key_del is locked */
#ifdef THREAD
THR_LOCK lock;
+ void (*lock_restore_status)(void *);
pthread_mutex_t intern_lock; /* Locking for use with _locking */
pthread_cond_t intern_cond;
rw_lock_t *key_root_lock;
@@ -432,10 +427,11 @@ typedef struct st_maria_row
MARIA_RECORD_POS *tail_positions;
ha_checksum checksum;
LSN orig_undo_lsn; /* Lsn at start of row insert */
+ TrID trid; /* Transaction id for current row */
uchar *empty_bits, *field_lengths;
uint *null_field_lengths; /* All null field lengths */
ulong *blob_lengths; /* Length for each blob */
- ulong base_length, min_length, normal_length, char_length, varchar_length;
+ ulong min_length, normal_length, char_length, varchar_length;
ulong blob_length, head_length, total_length;
size_t extents_buffer_length; /* Size of 'extents' buffer */
uint field_lengths_length; /* Length of data in field_lengths */
@@ -460,7 +456,8 @@ struct st_maria_handler
{
MARIA_SHARE *s; /* Shared between open:s */
struct st_transaction *trn; /* Pointer to active transaction */
- MARIA_STATUS_INFO *state, save_state;
+ MARIA_STATUS_INFO *state, state_save;
+ MARIA_STATUS_INFO *state_start; /* State at start of transaction */
MARIA_ROW cur_row; /* The active row that we just read */
MARIA_ROW new_row; /* Storage for a row during update */
MARIA_BLOCK_SCAN scan, *scan_save;
@@ -470,12 +467,10 @@ struct st_maria_handler
DYNAMIC_ARRAY pinned_pages;
/* accumulate indexfile changes between write's */
TREE *bulk_insert;
- LEX_STRING *log_row_parts; /* For logging */
+ LEX_CUSTRING *log_row_parts; /* For logging */
DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
MEM_ROOT ft_memroot; /* used by the parser */
MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */
- LSN *key_write_undo_lsn; /* Pointer to undo for each key */
- LSN *key_delete_undo_lsn; /* Pointer to undo for each key */
uchar *buff; /* page buffer */
uchar *keyread_buff; /* Buffer for last key read */
uchar *lastkey, *lastkey2; /* Last used search key */
@@ -510,6 +505,8 @@ struct st_maria_handler
IO_CACHE rec_cache; /* When cacheing records */
LIST open_list;
MY_BITMAP changed_fields;
+ ulong row_base_length; /* Length of row header */
+ uint row_flag; /* Flag to store in row header */
uint opt_flag; /* Optim. for space/speed */
uint update; /* If file changed since open */
int lastinx; /* Last used index */
@@ -608,9 +605,9 @@ struct st_maria_handler
#define _ma_store_keynr(share, x, nr) x[(share)->keypage_header - KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE - KEYPAGE_USED_SIZE]= (nr)
#define _ma_get_keynr(share, x) ((uchar) x[(share)->keypage_header - KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE - KEYPAGE_USED_SIZE])
#define _ma_store_transid(buff, transid) \
- int6store((buff) + LSN_STORE_SIZE, (transid))
+ transid_store((buff) + LSN_STORE_SIZE, (transid))
#define _ma_korr_transid(buff) \
- uint6korr((buff) + LSN_STORE_SIZE)
+ transid_korr((buff) + LSN_STORE_SIZE)
#define _ma_get_keypage_flag(share,x) x[(share)->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_FLAG_SIZE]
#define _ma_store_keypage_flag(share,x,flag) x[(share)->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_FLAG_SIZE]= (flag)
@@ -732,7 +729,7 @@ extern uint maria_quick_table_bits;
extern char *maria_data_root;
extern uchar maria_zero_string[];
extern my_bool maria_inited;
-
+extern HASH maria_stored_state;
/* This is used by _ma_calc_xxx_key_length och _ma_store_key */
typedef struct st_maria_s_param
@@ -1042,11 +1039,12 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
const uchar *record, MARIA_RECORD_POS pos);
my_bool _ma_unique_comp(MARIA_UNIQUEDEF *def, const uchar *a, const uchar *b,
my_bool null_are_equal);
-void _ma_get_status(void *param, int concurrent_insert);
+void _ma_get_status(void *param, my_bool concurrent_insert);
void _ma_update_status(void *param);
void _ma_restore_status(void *param);
void _ma_copy_status(void *to, void *from);
my_bool _ma_check_status(void *param);
+void _ma_restore_status(void *param);
void _ma_reset_status(MARIA_HA *maria);
int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos);
void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos);
@@ -1148,4 +1146,5 @@ extern my_bool maria_flush_log_for_page(uchar *page,
extern my_bool maria_flush_log_for_page_none(uchar *page,
pgcache_page_no_t page_no,
uchar *data_ptr);
+void maria_concurrent_inserts(MARIA_HA *info, my_bool concurrent_insert);
extern PAGECACHE *maria_log_pagecache;
diff --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c
index 6902f131f5b..b363d34a692 100644
--- a/storage/maria/maria_pack.c
+++ b/storage/maria/maria_pack.c
@@ -166,10 +166,10 @@ static int flush_buffer(ulong neaded_length);
static void end_file_buffer(void);
static void write_bits(ulonglong value, uint bits);
static void flush_bits(void);
-static int save_state(MARIA_HA *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length,
- ha_checksum crc);
-static int save_state_mrg(File file,PACK_MRG_INFO *isam_file,my_off_t new_length,
- ha_checksum crc);
+static int save_state(MARIA_HA *isam_file,PACK_MRG_INFO *mrg,
+ my_off_t new_length, ha_checksum crc);
+static int save_state_mrg(File file,PACK_MRG_INFO *isam_file,
+ my_off_t new_length, ha_checksum crc);
static int mrg_close(PACK_MRG_INFO *mrg);
static int mrg_rrnd(PACK_MRG_INFO *info,uchar *buf);
static void mrg_reset(PACK_MRG_INFO *mrg);
@@ -435,6 +435,7 @@ static MARIA_HA *open_maria_file(char *name,int mode)
DBUG_RETURN(0);
}
VOID(maria_lock_database(isam_file,F_WRLCK));
+ maria_ignore_trids(isam_file);
DBUG_RETURN(isam_file);
}
@@ -1083,7 +1084,7 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
}
else if (error != HA_ERR_RECORD_DELETED)
{
- VOID(fprintf(stderr, "Got error %d while reading rows", error));
+ VOID(fprintf(stderr, "Got error %d while reading rows\n", error));
break;
}
@@ -2997,7 +2998,7 @@ static int save_state(MARIA_HA *isam_file,PACK_MRG_INFO *mrg,
for (key=0 ; key < share->base.keys ; key++)
share->state.key_root[key]= HA_OFFSET_ERROR;
share->state.key_del= HA_OFFSET_ERROR;
- isam_file->state->checksum=crc; /* Save crc here */
+ share->state.state.checksum= crc; /* Save crc in file */
share->changed=1; /* Force write of header */
share->state.open_count=0;
share->global_changed=0;
diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c
index 5c9a8e235a3..54806ccc852 100644
--- a/storage/maria/maria_read_log.c
+++ b/storage/maria/maria_read_log.c
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
goto err;
}
/* we don't want to create a control file, it MUST exist */
- if (ma_control_file_open(FALSE))
+ if (ma_control_file_open(FALSE, TRUE))
{
fprintf(stderr, "Can't open control file (%d)\n", errno);
goto err;
diff --git a/storage/maria/trnman.c b/storage/maria/trnman.c
index 24497faac50..1c2385e9476 100644
--- a/storage/maria/trnman.c
+++ b/storage/maria/trnman.c
@@ -51,6 +51,10 @@ static TRN **short_trid_to_active_trn;
/* locks for short_trid_to_active_trn and pool */
static my_atomic_rwlock_t LOCK_short_trid_to_trn, LOCK_pool;
+static my_bool default_trnman_end_trans_hook(TRN *, my_bool, my_bool);
+
+my_bool (*trnman_end_trans_hook)(TRN *, my_bool, my_bool)=
+ default_trnman_end_trans_hook;
/*
Simple interface functions
@@ -78,6 +82,16 @@ void trnman_reset_locked_tables(TRN *trn, uint locked_tables)
}
+static my_bool
+default_trnman_end_trans_hook(TRN *trn __attribute__ ((unused)),
+ my_bool commit __attribute__ ((unused)),
+ my_bool active_transactions
+ __attribute__ ((unused)))
+{
+ return 0;
+}
+
+
/*
NOTE
Just as short_id doubles as loid, this function doubles as
@@ -315,10 +329,17 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond,
pthread_mutex_unlock(&LOCK_trn_list);
if (unlikely(!trn->min_read_from))
- trn->min_read_from= trn->trid;
+ {
+ /*
+ We are the only transaction. Set min_read_from so that we can read
+ our own rows
+ */
+ trn->min_read_from= trn->trid + 1;
+ }
trn->commit_trid= 0;
trn->rec_lsn= trn->undo_lsn= trn->first_undo_lsn= 0;
+ trn->used_tables= 0;
trn->locks.mutex= mutex;
trn->locks.cond= cond;
@@ -336,6 +357,9 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond,
*/
set_short_trid(trn);
+ DBUG_PRINT("exit", ("trn: x%lx trid: 0x%lu",
+ (ulong) trn, (ulong) trn->trid));
+
DBUG_RETURN(trn);
}
@@ -356,7 +380,7 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond,
0 ok
1 error
*/
-int trnman_end_trn(TRN *trn, my_bool commit)
+my_bool trnman_end_trn(TRN *trn, my_bool commit)
{
int res= 1;
TRN *free_me= 0;
@@ -429,8 +453,7 @@ int trnman_end_trn(TRN *trn, my_bool commit)
if (res)
{
/*
- res == 1 means the condition in the if() above
- was false.
+ res == 1 means the condition in the if() above was false.
res == -1 means lf_hash_insert failed
*/
trn->next= free_me;
@@ -440,8 +463,10 @@ int trnman_end_trn(TRN *trn, my_bool commit)
{
committed_list_max.prev= trn->prev->next= trn;
}
+ if ((*trnman_end_trans_hook)(trn, commit,
+ active_list_min.next != &active_list_max))
+ res= -1;
trnman_active_transactions--;
- DBUG_PRINT("info", ("pthread_mutex_unlock LOCK_trn_list"));
pthread_mutex_unlock(&LOCK_trn_list);
/* the rest is done outside of a critical section */
@@ -534,9 +559,19 @@ int trnman_can_read_from(TRN *trn, TrID trid)
LF_REQUIRE_PINS(3);
if (trid < trn->min_read_from)
- return 1; /* can read */
- if (trid > trn->trid)
- return 0; /* cannot read */
+ return 1; /* Row is visible by all transactions in the system */
+
+ if (trid >= trn->trid)
+ {
+ /*
+ We have now two cases
+ trid > trn->trid, in which case the row is from a new transaction
+ and not visible, in which case we should return 0.
+ trid == trn->trid in which case the row is from the current transaction
+ and we should return 1
+ */
+ return trid == trn->trid;
+ }
found= lf_hash_search(&trid_to_committed_trn, trn->pins, &trid, sizeof(trid));
if (found == NULL)
@@ -748,8 +783,29 @@ TRN *trnman_get_any_trn()
/**
+ Returns the minimum existing transaction id.
+*/
+
+TrID trnman_get_min_trid()
+{
+ TrID min_read_from;
+ if (short_trid_to_active_trn == NULL)
+ {
+ /* Transaction manager not initialize; Probably called from maria_chk */
+ return ~(TrID) 0;
+ }
+
+ pthread_mutex_lock(&LOCK_trn_list);
+ min_read_from= active_list_min.next->min_read_from;
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return min_read_from;
+}
+
+
+/**
Returns maximum transaction id given to a transaction so far.
*/
+
TrID trnman_get_max_trid()
{
TrID id;
@@ -760,3 +816,39 @@ TrID trnman_get_max_trid()
pthread_mutex_unlock(&LOCK_trn_list);
return id;
}
+
+/**
+ Check if there exist an active transaction between two commit_id's
+
+ @todo
+ Improve speed of this.
+ - Store transactions in tree or skip list
+ - Have function to copying all active transaction id's to b-tree
+ and use b-tree for checking states. This could be a big win
+ for checkpoint that will call this function for a lot of objects.
+
+ @return
+ 0 No transaction exists
+ 1 There is at least on active transaction in the given range
+*/
+
+my_bool trnman_exists_active_transactions(TrID min_id, TrID max_id,
+ my_bool trnman_is_locked)
+{
+ TRN *trn;
+ my_bool ret= 0;
+
+ if (!trnman_is_locked)
+ pthread_mutex_lock(&LOCK_trn_list);
+ for (trn= active_list_min.next; trn != &active_list_max; trn= trn->next)
+ {
+ if (trn->trid > min_id && trn->trid < max_id)
+ {
+ ret= 1;
+ break;
+ }
+ }
+ if (!trnman_is_locked)
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return ret;
+}
diff --git a/storage/maria/trnman.h b/storage/maria/trnman.h
index fce02d9ab89..870add214df 100644
--- a/storage/maria/trnman.h
+++ b/storage/maria/trnman.h
@@ -42,9 +42,10 @@ C_MODE_START
struct st_transaction
{
LOCK_OWNER locks; /* must be the first! see short_trid_to_TRN() */
- LF_PINS *pins;
+ LF_PINS *pins;
+ void *used_tables; /* Tables used by transaction */
+ TRN *next, *prev;
TrID trid, min_read_from, commit_trid;
- TRN *next, *prev;
LSN rec_lsn, undo_lsn;
LSN_WITH_FLAGS first_undo_lsn;
uint locked_tables;
diff --git a/storage/maria/trnman_public.h b/storage/maria/trnman_public.h
index c732e5c4093..0005e556eb1 100644
--- a/storage/maria/trnman_public.h
+++ b/storage/maria/trnman_public.h
@@ -33,11 +33,13 @@ typedef struct st_transaction TRN;
extern uint trnman_active_transactions, trnman_allocated_transactions;
extern TRN dummy_transaction_object;
+extern my_bool (*trnman_end_trans_hook)(TRN *trn, my_bool commit,
+ my_bool active_transactions);
int trnman_init(TrID);
void trnman_destroy(void);
TRN *trnman_new_trn(pthread_mutex_t *, pthread_cond_t *, void *);
-int trnman_end_trn(TRN *trn, my_bool commit);
+my_bool trnman_end_trn(TRN *trn, my_bool commit);
#define trnman_commit_trn(T) trnman_end_trn(T, TRUE)
#define trnman_abort_trn(T) trnman_end_trn(T, FALSE)
#define trnman_rollback_trn(T) trnman_end_trn(T, FALSE)
@@ -55,7 +57,10 @@ uint trnman_has_locked_tables(TRN *trn);
void trnman_reset_locked_tables(TRN *trn, uint locked_tables);
TRN *trnman_recreate_trn_from_recovery(uint16 shortid, TrID longid);
TRN *trnman_get_any_trn(void);
+TrID trnman_get_min_trid(void);
TrID trnman_get_max_trid(void);
+my_bool trnman_exists_active_transactions(TrID min_id, TrID max_id,
+ my_bool trnman_is_locked);
#define TRANSID_SIZE 6
#define transid_store(dst, id) int6store(dst,id)
#define transid_korr(P) uint6korr(P)
diff --git a/storage/maria/unittest/ma_control_file-t.c b/storage/maria/unittest/ma_control_file-t.c
index f968abd9c1b..f076615fef7 100644
--- a/storage/maria/unittest/ma_control_file-t.c
+++ b/storage/maria/unittest/ma_control_file-t.c
@@ -110,7 +110,7 @@ static CONTROL_FILE_ERROR local_ma_control_file_open(void)
{
CONTROL_FILE_ERROR error;
error_handler_hook= my_ignore_message;
- error= ma_control_file_open(TRUE);
+ error= ma_control_file_open(TRUE, TRUE);
error_handler_hook= default_error_handler_hook;
return error;
}
diff --git a/storage/maria/unittest/ma_test_all-t b/storage/maria/unittest/ma_test_all-t
index 14821c137a2..d64662cb9ac 100755
--- a/storage/maria/unittest/ma_test_all-t
+++ b/storage/maria/unittest/ma_test_all-t
@@ -88,9 +88,9 @@ sub run_tests
# make the unit test fail during 'make test'. $nr_tests must be right.
#
- $nr_tests+= run_check_tests(0, 0, 0, 0, 1) * 4; #
- $nr_tests+= run_repair_tests(0, 0, 0, 0, 1) * 4; # called 4 times
- $nr_tests+= run_pack_tests(0, 0, 0, 0, 1) * 4; #
+ $nr_tests+= run_check_tests(0, 0, 0, 0, 1) * 5; #
+ $nr_tests+= run_repair_tests(0, 0, 0, 0, 1) * 5; # called 4 times
+ $nr_tests+= run_pack_tests(0, 0, 0, 0, 1) * 5; #
$nr_tests+= run_tests_on_warnings_and_errors(0, 0, 0, 1);
$nr_tests+= run_ma_test_recovery(0, 1);
$nr_tests+= run_tests_on_clrs(0, 0, 1);
@@ -186,6 +186,19 @@ sub run_tests
run_repair_tests($suffix, $opt_silent, "-M -T", $opt_verbose, 0);
run_pack_tests($suffix, $opt_silent, "-M -T", $opt_verbose, 0);
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with block row format, transactions and versioning\n";
+ }
+ run_check_tests($suffix, $opt_silent, "-M -T -C", $opt_verbose, 0);
+ run_repair_tests($suffix, $opt_silent, "-M -T -C", $opt_verbose, 0);
+ run_pack_tests($suffix, $opt_silent, "-M -T -C", $opt_verbose, 0);
+
+
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with warnings and recovery\n";
+ }
run_tests_on_warnings_and_errors($suffix, $opt_silent, $opt_verbose, 0);
run_ma_test_recovery($opt_verbose, 0);
run_tests_on_clrs($suffix, $opt_verbose, 0);
@@ -524,7 +537,6 @@ sub ok
if ($verbose)
{
print " " x (62 - $len);
- print " ";
}
$err= $?;
if ((!$err && !$expected_error) ||
diff --git a/storage/maria/unittest/ma_test_loghandler-t.c b/storage/maria/unittest/ma_test_loghandler-t.c
index 34b2ce682d5..1e8b4938e4f 100644
--- a/storage/maria/unittest/ma_test_loghandler-t.c
+++ b/storage/maria/unittest/ma_test_loghandler-t.c
@@ -196,7 +196,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
index d8ae57634e4..a56f7d64118 100644
--- a/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
@@ -67,7 +67,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
index 9cbf05825ce..238a9ec9cbb 100644
--- a/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
@@ -64,7 +64,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
index 6deee2a54e7..421aa5ffb29 100644
--- a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
@@ -263,7 +263,7 @@ int main(int argc __attribute__((unused)), char *argv[])
bzero(long_tr_id, 6);
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
@@ -430,7 +430,7 @@ int main(int argc __attribute__((unused)), char *argv[])
end_pagecache(&pagecache, 1);
ma_control_file_end();
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE,TRUE))
{
fprintf(stderr, "pass2: Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_multithread-t.c b/storage/maria/unittest/ma_test_loghandler_multithread-t.c
index 3a278c8d03b..ba612fab6a6 100644
--- a/storage/maria/unittest/ma_test_loghandler_multithread-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_multithread-t.c
@@ -283,7 +283,7 @@ int main(int argc __attribute__((unused)),
my_thread_global_init();
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_noflush-t.c b/storage/maria/unittest/ma_test_loghandler_noflush-t.c
index e07b96ee5d1..54294936cc3 100644
--- a/storage/maria/unittest/ma_test_loghandler_noflush-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_noflush-t.c
@@ -70,7 +70,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_nologs-t.c b/storage/maria/unittest/ma_test_loghandler_nologs-t.c
index 9241279703d..e126ff31f3a 100644
--- a/storage/maria/unittest/ma_test_loghandler_nologs-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_nologs-t.c
@@ -67,7 +67,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
@@ -140,7 +140,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
}
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_pagecache-t.c b/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
index c937d56925b..16f672d66ca 100644
--- a/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
@@ -95,7 +95,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_loghandler_purge-t.c b/storage/maria/unittest/ma_test_loghandler_purge-t.c
index 4602ec88548..0c3be2f2428 100644
--- a/storage/maria/unittest/ma_test_loghandler_purge-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_purge-t.c
@@ -67,7 +67,7 @@ int main(int argc __attribute__((unused)), char *argv[])
}
#endif
- if (ma_control_file_open(TRUE))
+ if (ma_control_file_open(TRUE, TRUE))
{
fprintf(stderr, "Can't init control file (%d)\n", errno);
exit(1);
diff --git a/storage/maria/unittest/ma_test_recovery.expected b/storage/maria/unittest/ma_test_recovery.expected
index 9da7b662395..b95575173ee 100644
--- a/storage/maria/unittest/ma_test_recovery.expected
+++ b/storage/maria/unittest/ma_test_recovery.expected
@@ -15,6 +15,14 @@ TEST WITH ma_test2 -s -M -T -c -b65000 -d800
applying log
testing idempotency
applying log
+TEST WITH ma_test1 -s -M -T -c -C
+applying log
+testing idempotency
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -d500 -C
+applying log
+testing idempotency
+applying log
Testing the REDO AND UNDO PHASE
TEST WITH ma_test1 -s -M -T -c -N --testflag=1 (commit at end)
TEST WITH ma_test1 -s -M -T -c -N --testflag=2 --test-undo=1 (additional aborted work)
@@ -35,6 +43,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=1 (additional aborted work)
@@ -122,6 +140,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=2 (additional aborted work)
@@ -209,6 +237,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=3 (additional aborted work)
@@ -296,6 +334,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=4 (additional aborted work)
@@ -383,6 +431,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=1 (additional aborted work)
@@ -470,6 +528,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=2 (additional aborted work)
@@ -557,6 +625,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=3 (additional aborted work)
@@ -644,6 +722,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=4 (additional aborted work)
@@ -731,6 +819,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=1 (additional aborted work)
@@ -818,6 +916,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=2 (additional aborted work)
@@ -905,6 +1013,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=3 (additional aborted work)
@@ -992,6 +1110,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=4 (additional aborted work)
@@ -1079,6 +1207,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=1 (additional aborted work)
@@ -1166,6 +1304,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=2 (additional aborted work)
@@ -1253,6 +1401,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=3 (additional aborted work)
@@ -1340,6 +1498,16 @@ testing idempotency
applying log
testing applying of CLRs to recreate table
applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
Terminating after inserts
TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=4 (additional aborted work)
diff --git a/storage/maria/unittest/ma_test_recovery.pl b/storage/maria/unittest/ma_test_recovery.pl
index a58ec748c3b..86658572da7 100755
--- a/storage/maria/unittest/ma_test_recovery.pl
+++ b/storage/maria/unittest/ma_test_recovery.pl
@@ -12,6 +12,8 @@ $VER= "1.2";
$opt_version= 0;
$opt_help= 0;
+$opt_verbose= 0;
+$opt_abort_on_error=0;
my $silent= "-s";
my $maria_path; # path to "storage/maria"
@@ -34,7 +36,7 @@ sub main
{
my ($res, $table);
- if (!GetOptions("help","version"))
+ if (!GetOptions("abort-on-error", "help", "version", "verbose"))
{
$flag_exit= 1;
}
@@ -87,7 +89,10 @@ sub main
my @t= ("ma_test1$suffix $silent -M -T -c",
"ma_test2$suffix $silent -L -K -W -P -M -T -c -d500",
"ma_test2$suffix $silent -M -T -c -b65000",
- "ma_test2$suffix $silent -M -T -c -b65000 -d800");
+ "ma_test2$suffix $silent -M -T -c -b65000 -d800",
+ "ma_test1$suffix $silent -M -T -c -C",
+ "ma_test2$suffix $silent -L -K -W -P -M -T -c -d500 -C"
+ );
foreach my $prog (@t)
{
@@ -95,7 +100,7 @@ sub main
my $prog_no_suffix= $prog;
$prog_no_suffix=~ s/$suffix// if ($suffix);
print MY_LOG "TEST WITH $prog_no_suffix\n";
- $res= `$maria_exe_path/$prog`;
+ $res= my_exec("$maria_exe_path/$prog");
print MY_LOG $res;
# derive table's name from program's name
if ($prog =~ m/ma_(test[0-9]+).*/)
@@ -105,8 +110,8 @@ sub main
$com= "$maria_exe_path/maria_chk$suffix -dvv $table ";
$com.= "| grep -v \"Creation time:\" | grep -v \"file length\" ";
$com.= "> $tmp/maria_chk_message.good.txt 2>&1";
- `$com`;
- my $checksum=`$maria_exe_path/maria_chk$suffix -dss $table`;
+ my_exec($com);
+ my $checksum= my_exec("$maria_exe_path/maria_chk$suffix -dss $table");
move("$table.MAD", "$tmp/$table-good.MAD") ||
die "Can't move $table.MAD to $tmp/$table-good.MAD\n";
move("$table.MAI", "$tmp/$table-good.MAI") ||
@@ -138,6 +143,9 @@ sub main
"ma_test1$suffix $silent -M -T -c -N blob -H2",
"--testflag=3",
"--testflag=4 --test-undo=",
+ "ma_test1$suffix $silent -M -T -c -N blob -H2 --versioning",
+ "--testflag=3",
+ "--testflag=4 --test-undo=",
"ma_test1$suffix $silent -M -T -c -N blob -H2",
"--testflag=2",
"--testflag=3 --test-undo=",
@@ -171,7 +179,7 @@ sub main
my $prog_no_suffix= $prog;
$prog_no_suffix=~ s/$suffix// if ($suffix);
print MY_LOG "TEST WITH $prog_no_suffix $commit_run_args (commit at end)\n";
- $res= `$maria_exe_path/$prog $commit_run_args`;
+ $res= my_exec("$maria_exe_path/$prog $commit_run_args");
print MY_LOG $res;
# derive table's name from program's name
if ($prog =~ m/ma_(test[0-9]+).*/)
@@ -181,16 +189,16 @@ sub main
$com= "$maria_exe_path/maria_chk$suffix -dvv $table ";
$com.= "| grep -v \"Creation time:\" | grep -v \"file length\" ";
$com.= "> $tmp/maria_chk_message.good.txt 2>&1";
- $res= `$com`;
+ $res= my_exec($com);
print MY_LOG $res;
- $checksum= `$maria_exe_path/maria_chk$suffix -dss $table`;
+ $checksum= my_exec("$maria_exe_path/maria_chk$suffix -dss $table");
move("$table.MAD", "$tmp/$table-good.MAD") ||
die "Can't move $table.MAD to $tmp/$table-good.MAD\n";
move("$table.MAI", "$tmp/$table-good.MAI") ||
die "Can't move $table.MAI to $tmp/$table-good.MAI\n";
unlink <maria_log.* maria_log_control>;
print MY_LOG "TEST WITH $prog_no_suffix $abort_run_args$test_undo[$j] (additional aborted work)\n";
- $res= `$maria_exe_path/$prog $abort_run_args$test_undo[$j]`;
+ $res= my_exec("$maria_exe_path/$prog $abort_run_args$test_undo[$j]");
print MY_LOG $res;
copy("$table.MAD", "$tmp/$table-before_undo.MAD") ||
die "Can't copy $table.MAD to $tmp/$table-before_undo.MAD\n";
@@ -273,6 +281,11 @@ sub check_table_is_same
# Data/key file length is random in ma_test2 (as it uses srand() which
# may differ between machines).
+ if ($opt_verbose)
+ {
+ print "checking if table $table has changed\n";
+ }
+
$com= "$maria_exe_path/maria_chk$suffix -dvv $table | grep -v \"Creation time:\" ";
$com.= "| grep -v \"file length\"> $tmp/maria_chk_message.txt 2>&1";
$res= `$com`;
@@ -328,7 +341,7 @@ sub apply_log
$log_md5.= md5_conv($_);
}
print MY_LOG "applying log\n";
- `$maria_exe_path/maria_read_log$suffix -a > $tmp/maria_read_log_$table.txt`;
+ my_exec("$maria_exe_path/maria_read_log$suffix -a > $tmp/maria_read_log_$table.txt");
foreach (<maria_log.*>)
{
$log_md5_2.= md5_conv($_);
@@ -416,6 +429,23 @@ sub physical_cmp
}
+sub my_exec
+{
+ my($command)= @_;
+ my $res;
+ if ($opt_verbose)
+ {
+ print "$command\n";
+ }
+ $res= `$command`;
+ if ($? != 0 && $opt_abort_on_error)
+ {
+ exit(1);
+ }
+ return $res;
+}
+
+
####
#### usage
####
@@ -431,7 +461,11 @@ Run various maria recovery tests and print the results
Options
--help Show this help and exit.
+
+--abort-on-error Abort at once in case of error.
+--verbose Show commands while there are executing.
--version Show version number and exit.
+
EOF
exit(0);
}
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 40ccf51b7af..8c8f3e6495d 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -1530,12 +1530,12 @@ void ha_myisam::start_bulk_insert(ha_rows rows)
!= 0 Error
*/
-int ha_myisam::end_bulk_insert()
+int ha_myisam::end_bulk_insert(bool abort)
{
mi_end_bulk_insert(file);
int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
- return err ? err : can_enable_indexes ?
- enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0;
+ return (err || abort ? err : can_enable_indexes ?
+ enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0);
}
diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h
index 076e31c07e8..606d5ca354f 100644
--- a/storage/myisam/ha_myisam.h
+++ b/storage/myisam/ha_myisam.h
@@ -107,7 +107,7 @@ class ha_myisam: public handler
int enable_indexes(uint mode);
int indexes_are_disabled(void);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
void update_create_info(HA_CREATE_INFO *create_info);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c
index ad23a42ab83..2edeefad45f 100644
--- a/storage/myisam/mi_locking.c
+++ b/storage/myisam/mi_locking.c
@@ -281,7 +281,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
(THR_WRITE_CONCURRENT_INSERT was used)
*/
-void mi_get_status(void* param, int concurrent_insert)
+void mi_get_status(void* param, my_bool concurrent_insert)
{
MI_INFO *info=(MI_INFO*) param;
DBUG_ENTER("mi_get_status");
diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index b0b9226749d..db6344e14f8 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/myisam/myisamdef.h
@@ -700,7 +700,7 @@ int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
const uchar *record, my_off_t pos);
int mi_unique_comp(MI_UNIQUEDEF *def, const uchar *a, const uchar *b,
my_bool null_are_equal);
-void mi_get_status(void *param, int concurrent_insert);
+void mi_get_status(void *param, my_bool concurrent_insert);
void mi_update_status(void *param);
void mi_restore_status(void *param);
void mi_copy_status(void *to, void *from);