diff options
author | unknown <monty@narttu.mysql.fi> | 2008-05-29 21:39:25 +0300 |
---|---|---|
committer | unknown <monty@narttu.mysql.fi> | 2008-05-29 21:39:25 +0300 |
commit | f83bd712ae864ed2fa2271247e56fc1f444c9801 (patch) | |
tree | d7dd11206d6de4fc93a1a73a66f7a15f32bb92d3 | |
parent | 5ca17f0dc6235f03d9cbfcae087ac41d57fa4940 (diff) | |
parent | 5099033c26826fd2625b6424134999853e33a29d (diff) | |
download | mariadb-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
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(¶m, file); // Not fatal + maria_chk_init_for_check(¶m, file); + (void) maria_chk_status(¶m, file); // Not fatal error= maria_chk_size(¶m, file); if (!error) error|= maria_chk_del(¶m, file, param.testflag); @@ -1297,6 +1298,14 @@ int ha_maria::repair(THD *thd, HA_CHECK ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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(¶m, file, 1); if (optimize_done) error= maria_update_state_info(¶m, 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(¶m->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(¶m->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(¶m->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); |