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
This commit is contained in:
unknown 2008-05-29 21:39:25 +03:00
commit f83bd712ae
102 changed files with 2316 additions and 835 deletions

View file

@ -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,

View file

@ -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)

View file

@ -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*))

View file

@ -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];

View file

@ -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;

View file

@ -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 ..

View file

@ -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;

View file

@ -1,3 +1,4 @@
drop table if exists t1;
select @@global.maria_page_checksum;
@@global.maria_page_checksum
1

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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))

View file

@ -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)

View file

@ -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;

View file

@ -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));

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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;

View file

@ -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; }

View file

@ -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
{

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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. */

View file

@ -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
{

View file

@ -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;

View file

@ -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;

View file

@ -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; }
;

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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

View file

@ -969,7 +969,8 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
0)))))
return HA_ADMIN_ALREADY_DONE;
error= maria_chk_status(&param, file); // Not fatal
maria_chk_init_for_check(&param, file);
(void) maria_chk_status(&param, file); // Not fatal
error= maria_chk_size(&param, file);
if (!error)
error|= maria_chk_del(&param, file, param.testflag);
@ -1297,6 +1298,14 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
DBUG_RETURN(HA_ADMIN_FAILED);
}
/*
If transactions was not enabled for a transactional table then
file->s->status is not up to date. This is needed for repair_by_sort
to work
*/
if (share->base.born_transactional && !share->now_transactional)
_ma_copy_nontrans_state_information(file);
param.db_name= table->s->db.str;
param.table_name= table->alias;
param.tmpfile_createflag= O_RDWR | O_TRUNC;
@ -1304,7 +1313,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
param.thd= thd;
param.tmpdir= &mysql_tmpdir_list;
param.out_flag= 0;
strmov(fixed_name, file->s->open_file_name);
strmov(fixed_name, share->open_file_name);
// Don't lock tables if we have used LOCK TABLE
if (!thd->locked_tables &&
@ -1315,7 +1324,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
}
if (!do_optimize ||
((file->s->data_file_type == BLOCK_RECORD) ?
((share->data_file_type == BLOCK_RECORD) ?
(share->state.changed & STATE_NOT_OPTIMIZED_ROWS) :
(file->state->del || share->state.split != file->state->records)) &&
(!(param.testflag & T_QUICK) ||
@ -1334,7 +1343,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
statistics_done= 1;
/* TODO: Remove BLOCK_RECORD test when parallel works with blocks */
if (THDVAR(thd,repair_threads) > 1 &&
file->s->data_file_type != BLOCK_RECORD)
share->data_file_type != BLOCK_RECORD)
{
char buf[40];
/* TODO: respect maria_repair_threads variable */
@ -1396,18 +1405,17 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
/*
the following 'if', thought conceptually wrong,
is a useful optimization nevertheless.
repair updates share->state.state. Ensure that file->state is up to date
*/
if (file->state != &file->s->state.state)
file->s->state.state= *file->state;
if (file->s->base.auto_key)
if (file->state != &share->state.state)
*file->state= share->state.state;
if (share->base.auto_key)
_ma_update_auto_increment_key(&param, file, 1);
if (optimize_done)
error= maria_update_state_info(&param, file,
UPDATE_TIME | UPDATE_OPEN_COUNT |
(local_testflag &
T_STATISTICS ? UPDATE_STAT : 0));
UPDATE_TIME | UPDATE_OPEN_COUNT |
(local_testflag &
T_STATISTICS ? UPDATE_STAT : 0));
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
HA_STATUS_CONST);
if (rows != file->state->records && !(param.testflag & T_VERY_SILENT))
@ -1667,6 +1675,8 @@ int ha_maria::enable_indexes(uint mode)
{
sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
my_errno, param.db_name, param.table_name);
/* This should never fail normally */
DBUG_ASSERT(0);
/* Repairing by sort failed. Now try standard repair method. */
param.testflag &= ~(T_REP_BY_SORT | T_QUICK);
error= (repair(thd, param, 0) != HA_ADMIN_OK);
@ -1807,14 +1817,14 @@ void ha_maria::start_bulk_insert(ha_rows rows)
!= 0 Error
*/
int ha_maria::end_bulk_insert()
int ha_maria::end_bulk_insert(bool table_will_be_deleted)
{
int err;
DBUG_ENTER("ha_maria::end_bulk_insert");
maria_end_bulk_insert(file);
maria_end_bulk_insert(file, table_will_be_deleted);
if ((err= maria_extra(file, HA_EXTRA_NO_CACHE, 0)))
goto end;
if (can_enable_indexes)
if (can_enable_indexes && !table_will_be_deleted)
err= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
end:
if (bulk_insert_single_undo != BULK_INSERT_NONE)
@ -2198,77 +2208,95 @@ int ha_maria::external_lock(THD *thd, int lock_type)
external_lock(F_UNLCK) will happen and we can then allow the user to
create transactional temporary tables.
*/
if (!file->s->base.born_transactional)
goto skip_transaction;
if (lock_type != F_UNLCK)
if (file->s->base.born_transactional)
{
if (!trn) /* no transaction yet - open it now */
/* Transactional table */
if (lock_type != F_UNLCK)
{
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))
{
trans_register_ha(thd, FALSE, maria_hton);
trnman_new_statement(trn);
}
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);
}
}
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))
/* Start of new statement */
if (!trn) /* no transaction yet - open it now */
{
/* 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
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);
}
}
}
skip_transaction:
else
{
/* End of transaction */
/*
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= 0;
if (trn && trnman_has_locked_tables(trn))
{
if (!trnman_decrement_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)))
{
trnman_rollback_trn(trn);
DBUG_PRINT("info", ("THD_TRN set to 0x0"));
THD_TRN= 0;
}
#endif
}
}
}
} /* 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 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->state->data_file_length;
if (file->s->non_transactional_concurrent_insert &&
current_data_file_length != actual_data_file_length)
{
/*
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 the table size is unknown the SELECT statement can't be cached.
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;
/*
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;
if (!file->s->now_transactional &&
current_data_file_length != actual_data_file_length)
{
/* Don't cache current statement. */
DBUG_RETURN(FALSE);
}
/* Don't cache current statement. */
return FALSE;
}
/* It is ok to try to cache current statement. */
DBUG_RETURN(TRUE);
return TRUE;
}
#endif

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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);

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;
@ -241,128 +242,6 @@ int maria_lock_database(MARIA_HA *info, int lock_type)
} /* maria_lock_database */
/****************************************************************************
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)
{

View file

@ -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);
}

View file

@ -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
}

View file

@ -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);
/**

View file

@ -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)
{
/*

View file

@ -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)

View file

@ -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)
{

View file

@ -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);

View file

@ -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)

View file

@ -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]);
}

View file

@ -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));

478
storage/maria/ma_state.c Normal file
View file

@ -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;
}

75
storage/maria/ma_state.h Normal file
View file

@ -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);

View file

@ -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

View file

@ -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 */

View file

@ -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 '#':

View file

@ -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 $@

View file

@ -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;
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;
}
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;

View file

@ -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);

View file

@ -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))

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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)
@ -747,9 +782,30 @@ 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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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;
}

View file

@ -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) ||

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

Some files were not shown because too many files have changed in this diff Show more