WL#3138: Maria - fast "SELECT COUNT(*) FROM t;" and "CHECKSUM TABLE t"

Added argument to maria_end_bulk_insert() to know if the table will be deleted after the operation
Fixed wrong call to strmake
Don't call bulk insert in case of inserting only one row (speed optimization as starting/stopping bulk insert
Allow storing year 2155 in year field
When running with purify/valgrind avoid copying structures over themself
Added hook 'trnnam_end_trans_hook' that is called when transaction ends
Added trn->used_tables that is used to an entry for all tables used by transaction
Fixed that ndb doesn't crash on duplicate key error when start_bulk_insert/end_bulk_insert are not called


include/maria.h:
  Added argument to maria_end_bulk_insert() to know if the table will be deleted after the operation
include/my_tree.h:
  Added macro 'reset_free_element()' to be able to ignore calls to the external free function.
  Is used to optimize end-bulk-insert in case of failures, in which case we don't want write the remaining keys in the tree
mysql-test/install_test_db.sh:
  Upgrade to new mysql_install_db options
mysql-test/r/maria-mvcc.result:
  New tests
mysql-test/r/maria.result:
  New tests
mysql-test/suite/ndb/r/ndb_auto_increment.result:
  Fixed error message now when bulk insert is not always called
mysql-test/suite/ndb/t/ndb_auto_increment.test:
  Fixed error message now when bulk insert is not always called
mysql-test/t/maria-mvcc.test:
  Added testing of versioning of count(*)
mysql-test/t/maria-page-checksum.test:
  Added comment
mysql-test/t/maria.test:
  More tests
mysys/hash.c:
  Code style change
sql/field.cc:
  Allow storing year 2155 in year field
sql/ha_ndbcluster.cc:
  Added new argument to end_bulk_insert() to signal if the bulk insert should ignored
sql/ha_ndbcluster.h:
  Added new argument to end_bulk_insert() to signal if the bulk insert should ignored
sql/ha_partition.cc:
  Added new argument to end_bulk_insert() to signal if the bulk insert should ignored
sql/ha_partition.h:
  Added new argument to end_bulk_insert() to signal if the bulk insert should ignored
sql/handler.cc:
  Don't call get_dup_key() if there is no table object. This can happen if the handler generates a duplicate key error on commit
sql/handler.h:
  Added new argument to end_bulk_insert() to signal if the bulk insert should ignored (ie, the table will be deleted)
sql/item.cc:
  Style fix
  Removed compiler warning
sql/log_event.cc:
  Added new argument to ha_end_bulk_insert()
sql/log_event_old.cc:
  Added new argument to ha_end_bulk_insert()
sql/mysqld.cc:
  Removed compiler warning
sql/protocol.cc:
  Added DBUG
sql/sql_class.cc:
  Added DBUG
  Fixed wrong call to strmake
sql/sql_insert.cc:
  Don't call bulk insert in case of inserting only one row (speed optimization as starting/stopping bulk insert involves a lot of if's)
  Added new argument to ha_end_bulk_insert()
sql/sql_load.cc:
  Added new argument to ha_end_bulk_insert()
sql/sql_parse.cc:
  Style fixes
  Avoid goto in common senario
sql/sql_select.cc:
  When running with purify/valgrind avoid copying structures over themself.  This is not a real bug in itself, but it's a waste of cycles and causes valgrind warnings
sql/sql_select.h:
  Avoid copying structures over themself.  This is not a real bug in itself, but it's a waste of cycles and causes valgrind warnings
sql/sql_table.cc:
  Call HA_EXTRA_PREPARE_FOR_DROP if table created by ALTER TABLE is going to be dropped
  Added new argument to ha_end_bulk_insert()
storage/archive/ha_archive.cc:
  Added new argument to end_bulk_insert()
storage/archive/ha_archive.h:
  Added new argument to end_bulk_insert()
storage/federated/ha_federated.cc:
  Added new argument to end_bulk_insert()
storage/federated/ha_federated.h:
  Added new argument to end_bulk_insert()
storage/maria/Makefile.am:
  Added ma_state.c and ma_state.h
storage/maria/ha_maria.cc:
  Versioning of count(*) and checksum
  - share->state.state is now assumed to be correct, not handler->state
  - Call _ma_setup_live_state() in external lock to get count(*)/checksum versioning. In case of
    not versioned and not concurrent insertable table, file->s->state.state contains the correct state information
  
  Other things:
  - file->s -> share
  - Added DBUG_ASSERT() for unlikely case
  - Optimized end_bulk_insert() to not write anything if table is going to be deleted (as in failed alter table)
  - Indentation changes in external_lock becasue of removed 'goto' caused a big conflict even if very little was changed
storage/maria/ha_maria.h:
  New argument to end_bulk_insert()
storage/maria/ma_blockrec.c:
  Update for versioning of count(*) and checksum
  Keep share->state.state.data_file_length up to date (not info->state->data_file_length)
  Moved _ma_block_xxxx_status() and maria_versioning() functions to ma_state.c
storage/maria/ma_check.c:
  Update and use share->state.state instead of info->state
  info->s to share
  Update info->state at end of repair
  Call _ma_reset_state() to update share->state_history at end of repair
storage/maria/ma_checkpoint.c:
  Call _ma_remove_not_visible_states() on checkpoint to clean up not visible state history from tables
storage/maria/ma_close.c:
  Remember state history for running transaction even if table is closed
storage/maria/ma_commit.c:
  Ensure we always call trnman_commit_trn() even if other calls fails. If we don't do that, the translog and state structures will not be freed
storage/maria/ma_delete.c:
  Versioning of count(*) and checksum:
  - Always update info->state->checksum and info->state->records
storage/maria/ma_delete_all.c:
  Versioning of count(*) and checksum:
  - Ensure that share->state.state is updated, as here is where we store the primary information
storage/maria/ma_dynrec.c:
  Use lock_key_trees instead of concurrent_insert to check if trees should be locked.
  This allows us to lock trees both for concurrent_insert and for index versioning.
storage/maria/ma_extra.c:
  Versioning of count(*) and checksum:
  - Use share->state.state instead of info->state
  - share->concurrent_insert -> share->non_transactional_concurrent_insert
  - Don't update share->state.state from info->state if transactional table
  
  Optimization:
  - Don't flush io_cache or bitmap if we are using FLUSH_IGNORE_CHANGED
storage/maria/ma_info.c:
  Get most state information from current state
storage/maria/ma_init.c:
  Add hash table and free function to store states for closed tables
  Install hook for transaction commit/rollback to update history state
storage/maria/ma_key_recover.c:
  Versioning of count(*) and checksum:
  - Use share->state.state instead of info->state
storage/maria/ma_locking.c:
  Versioning of count(*) and checksum:
  - Call virtual functions (if exists) to restore/update status
  - Move _ma_xxx_status() functions to ma_state.c
  
  info->s -> share
storage/maria/ma_open.c:
  Versioning of count(*) and checksum:
  - For not transactional tables, set info->state to point to new allocated state structure.
  - Initialize new info->state_start variable that points to state at start of transaction
  - Copy old history states from hash table (maria_stored_states) first time the table is opened
  - Split flag share->concurrent_insert to non_transactional_concurrent_insert & lock_key_tree
  - For now, only enable versioning of tables without keys (to be fixed in soon!)
  - Added new virtual function to restore status in maria_lock_database)
  
  More DBUG
storage/maria/ma_page.c:
  Versioning of count(*) and checksum:
  - Use share->state.state instead of info->state
  - Modify share->state.state.key_file_length under share->intern_lock
storage/maria/ma_range.c:
  Versioning of count(*) and checksum:
  - Lock trees based on share->lock_key_trees
  
  info->s -> share
storage/maria/ma_recovery.c:
  Versioning of count(*) and checksum:
  - Use share->state.state instead of info->state
  - Update state information on close and when reenabling logging
storage/maria/ma_rkey.c:
  Versioning of count(*) and checksum:
  - Lock trees based on share->lock_key_trees
storage/maria/ma_rnext.c:
  Versioning of count(*) and checksum:
  - Lock trees based on share->lock_key_trees
storage/maria/ma_rnext_same.c:
  Versioning of count(*) and checksum:
  - Lock trees based on share->lock_key_trees
  - Only skip rows based on file length if non_transactional_concurrent_insert is set
storage/maria/ma_rprev.c:
  Versioning of count(*) and checksum:
  - Lock trees based on share->lock_key_trees
storage/maria/ma_rsame.c:
  Versioning of count(*) and checksum:
  - Lock trees based on share->lock_key_trees
storage/maria/ma_sort.c:
  Use share->state.state instead of info->state
  Fixed indentation
storage/maria/ma_static.c:
  Added maria_stored_state
storage/maria/ma_update.c:
  Versioning of count(*) and checksum:
  - Always update info->state->checksum and info->state->records
  - Remove optimization for index file update as it doesn't work for transactional tables
storage/maria/ma_write.c:
  Versioning of count(*) and checksum:
  - Always update info->state->checksum and info->state->records
storage/maria/maria_def.h:
  Move MARIA_STATUS_INFO to ma_state.h
  
  Changes to MARIA_SHARE:
  - Added state_history to store count(*)/checksum states
  - Added in_trans as counter if table is used by running transactions
  - Split concurrent_insert into lock_key_trees and on_transactional_concurrent_insert.
  - Added virtual function lock_restore_status
  
  Changes to MARIA_HA:
  - save_state -> state_save
  - Added state_start to store state at start of transaction
storage/maria/maria_pack.c:
  Versioning of count(*) and checksum:
  - Use share->state.state instead of info->state
  
  Indentation fixes
storage/maria/trnman.c:
  Added hook 'trnnam_end_trans_hook' that is called when transaction ends
  Added trn->used_tables that is used to an entry for all tables used by transaction
  More DBUG
  Changed return type of trnman_end_trn() to my_bool
  Added trnman_get_min_trid() to get minimum trid in use.
  Added trnman_exists_active_transactions() to check if there exist a running transaction started between two commit id
storage/maria/trnman.h:
  Added 'used_tables'
  Moved all pointers into same groups to get better memory alignment
storage/maria/trnman_public.h:
  Added prototypes for new functions and variables
  Chagned return type of trnman_end_trn() to my_bool
storage/myisam/ha_myisam.cc:
  Added argument to end_bulk_insert() if operation should be aborted
storage/myisam/ha_myisam.h:
  Added argument to end_bulk_insert() if operation should be aborted
storage/maria/ma_state.c:
  Functions to handle state of count(*) and checksum
storage/maria/ma_state.h:
  Structures and declarations to handle state of count(*) and checksum
This commit is contained in:
unknown 2008-05-29 18:33:33 +03:00
parent 126c1228f5
commit 5099033c26
72 changed files with 1411 additions and 665 deletions

View File

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

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

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

@ -1,3 +1,4 @@
set global maria_page_checksum=1;
drop table if exists t1;
create table t1 (i int) engine=maria;
show create table t1;
@ -13,9 +14,15 @@ 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);
@ -24,6 +31,9 @@ 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);
@ -33,6 +43,18 @@ 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;
@ -40,6 +62,9 @@ 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 */
@ -50,12 +75,18 @@ i
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;
@ -66,6 +97,9 @@ i
4
5
6
select count(*) from t1;
count(*)
6
unlock tables;
/* should see 1, 2, 3, 4, 5, 6 */
select i from t1;
@ -76,4 +110,31 @@ i
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

@ -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
@ -2100,6 +2103,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));
@ -2242,6 +2250,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

@ -4,6 +4,7 @@
#
-- source include/have_maria.inc
set global maria_page_checksum=1;
--disable_warnings
drop table if exists t1;
@ -19,41 +20,68 @@ 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,8 @@
#
# This can't be run with --extern as we are acccessing the tables in the
# database directly
#
-- source include/have_maria.inc
--disable_warnings

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
@ -1461,6 +1465,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

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

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

@ -4258,11 +4258,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)
{
@ -4578,7 +4578,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

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

@ -2999,13 +2999,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;
@ -3015,7 +3016,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

@ -2116,11 +2116,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

@ -1115,10 +1115,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);
@ -1736,7 +1736,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

@ -1440,7 +1440,9 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
if (collation == &my_charset_bin)
{
if (derivation <= dt.derivation)
; // Do nothing
{
/* Do nothing */
}
else
{
set(dt);
@ -1452,13 +1454,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))
@ -1469,7 +1469,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 &&
@ -1486,7 +1486,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
}
else if (derivation < dt.derivation)
{
// Do nothing
/* Do nothing */
}
else if (dt.derivation < derivation)
{
@ -1496,7 +1496,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
if (collation == dt.collation)
{
// Do nothing
/* Do nothing */
}
else
{

View File

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

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

@ -385,6 +385,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. */
@ -421,6 +422,7 @@ void net_end_statement(THD *thd)
break;
}
thd->main_da.is_sent= TRUE;
DBUG_VOID_RETURN;
}

View File

@ -367,6 +367,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 */
@ -380,6 +381,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;
}
@ -393,6 +395,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());
/* Refuse to overwrite an error with an OK packet. */
if (is_error())
@ -407,6 +410,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;
}
@ -417,8 +421,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());
/* Refuse to overwrite an error with an EOF packet. */
if (is_error())
@ -433,6 +437,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;
}
/**
@ -443,6 +448,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,
@ -451,9 +457,10 @@ Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
DBUG_ASSERT(! is_set() || can_overwrite_status);
m_sql_errno= sql_errno_arg;
strmake(m_message, message_arg, sizeof(m_message));
strmake(m_message, message_arg, sizeof(m_message)-1);
m_status= DA_ERROR;
DBUG_VOID_RETURN;
}

View File

@ -555,6 +555,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;
@ -716,8 +717,12 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
values_list.elements, and - if nothing else - to initialize
the code to make the call of end_bulk_insert() below safe.
*/
if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode)
if (lock_type != TL_WRITE_DELAYED && !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 &
(MODE_STRICT_TRANS_TABLES |
@ -831,7 +836,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;
@ -1167,7 +1172,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 */
@ -3108,7 +3113,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);
@ -3195,7 +3200,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

@ -391,7 +391,7 @@ bool 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

@ -2612,10 +2612,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
@ -2625,7 +2627,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
@ -4692,11 +4694,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)
{
@ -4707,6 +4704,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;
}
@ -7366,6 +7368,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. */
@ -7381,7 +7384,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

@ -1818,7 +1818,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;
@ -1836,8 +1839,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;
@ -2041,8 +2049,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

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

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

@ -1961,12 +1961,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

@ -1280,6 +1280,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;
@ -1287,7 +1295,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 &&
@ -1298,7 +1306,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) ||
@ -1317,7 +1325,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 */
@ -1379,18 +1387,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))
@ -1650,6 +1657,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);
@ -1790,14 +1799,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)
@ -2181,77 +2190,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)));
@ -2849,7 +2876,7 @@ my_bool ha_maria::register_query_cache_table(THD *thd, char *table_name,
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;
current_data_file_length= file->state->data_file_length;
if (!file->s->now_transactional &&
current_data_file_length != actual_data_file_length)

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
@ -1934,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
@ -1942,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)
@ -2020,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 */
@ -2044,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;
@ -3003,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)
{
@ -4318,7 +4318,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);
}
@ -5223,7 +5224,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));
@ -5798,7 +5799,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
@ -5820,14 +5820,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)
*/
@ -5974,10 +5973,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
@ -6109,7 +6108,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:
@ -6439,13 +6438,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);
@ -7065,72 +7064,8 @@ maria_page_get_lsn(uchar *page,
}
/*****************************************************************************
Lock handling for concurrent insert
*****************************************************************************/
/*
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);
}
/**
Enable reading of all rows, ignoring versioning
@brief Enable reading of all rows, ignoring versioning
@note
This is mainly useful in single user applications, like maria_pack,

View File

@ -201,7 +201,7 @@ int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
puts("- check record delete-chain");
next_link=share->state.dellink;
if (info->state->del == 0)
if (share->state.state.del == 0)
{
if (test_flag & T_VERBOSE)
{
@ -213,13 +213,13 @@ int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
if (test_flag & T_VERBOSE)
printf("Recordlinks: ");
empty=0;
for (i= info->state->del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
for (i= share->state.state.del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
{
if (*_ma_killed_ptr(param))
DBUG_RETURN(1);
if (test_flag & T_VERBOSE)
printf(" %9s",llstr(next_link,buff));
if (next_link >= info->state->data_file_length)
if (next_link >= share->state.state.data_file_length)
goto wrong;
if (my_pread(info->dfile.file, (uchar*) buff, delete_link_length,
next_link,MYF(MY_NABP)))
@ -256,28 +256,28 @@ int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
empty+=share->base.pack_reclength;
}
}
if (info->state->del && (test_flag & T_VERBOSE))
if (share->state.state.del && (test_flag & T_VERBOSE))
puts("\n");
if (empty != info->state->empty)
if (empty != share->state.state.empty)
{
_ma_check_print_warning(param,
"Found %s deleted space in delete link chain. Should be %s",
llstr(empty,buff2),
llstr(info->state->empty,buff));
llstr(share->state.state.empty,buff));
}
if (next_link != HA_OFFSET_ERROR)
{
_ma_check_print_error(param,
"Found more than the expected %s deleted rows in delete link chain",
llstr(info->state->del, buff));
llstr(share->state.state.del, buff));
goto wrong;
}
if (i != 0)
{
_ma_check_print_error(param,
"Found %s deleted rows in delete link chain. Should be %s",
llstr(info->state->del - i, buff2),
llstr(info->state->del, buff));
llstr(share->state.state.del - i, buff2),
llstr(share->state.state.del, buff));
goto wrong;
}
}
@ -307,7 +307,7 @@ static int check_k_link(HA_CHECK *param, register MARIA_HA *info,
if (next_link == HA_OFFSET_ERROR)
DBUG_RETURN(0); /* Avoid printing empty line */
records= (ha_rows) (info->state->key_file_length / block_size);
records= (ha_rows) (share->state.state.key_file_length / block_size);
while (next_link != HA_OFFSET_ERROR && records > 0)
{
if (*_ma_killed_ptr(param))
@ -316,13 +316,13 @@ static int check_k_link(HA_CHECK *param, register MARIA_HA *info,
printf("%16s",llstr(next_link,llbuff));
/* Key blocks must lay within the key file length entirely. */
if (next_link + block_size > info->state->key_file_length)
if (next_link + block_size > share->state.state.key_file_length)
{
/* purecov: begin tested */
_ma_check_print_error(param, "Invalid key block position: %s "
"key block size: %u file_length: %s",
llstr(next_link, llbuff), block_size,
llstr(info->state->key_file_length, llbuff2));
llstr(share->state.state.key_file_length, llbuff2));
DBUG_RETURN(1);
/* purecov: end */
}
@ -396,7 +396,7 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
_ma_check_print_error(param, "Failed to flush data or index file");
size= my_seek(share->kfile.file, 0L, MY_SEEK_END, MYF(MY_THREADSAFE));
if ((skr=(my_off_t) info->state->key_file_length) != size)
if ((skr=(my_off_t) share->state.state.key_file_length) != size)
{
/* Don't give error if file generated by mariapack */
if (skr > size && maria_is_any_key_active(share->state.key_map))
@ -413,26 +413,26 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
}
if (!(param->testflag & T_VERY_SILENT) &&
! (share->options & HA_OPTION_COMPRESS_RECORD) &&
ulonglong2double(info->state->key_file_length) >
ulonglong2double(share->state.state.key_file_length) >
ulonglong2double(share->base.margin_key_file_length)*0.9)
_ma_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
llstr(info->state->key_file_length,buff),
llstr(share->state.state.key_file_length,buff),
llstr(share->base.max_key_file_length-1,buff));
size= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
skr=(my_off_t) info->state->data_file_length;
skr=(my_off_t) share->state.state.data_file_length;
if (share->options & HA_OPTION_COMPRESS_RECORD)
skr+= MEMMAP_EXTRA_MARGIN;
#ifdef USE_RELOC
if (info->data_file_type == STATIC_RECORD &&
if (share->data_file_type == STATIC_RECORD &&
skr < (my_off_t) share->base.reloc*share->base.min_pack_length)
skr=(my_off_t) share->base.reloc*share->base.min_pack_length;
#endif
if (skr != size)
{
info->state->data_file_length=size; /* Skip other errors */
if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
{
share->state.state.data_file_length=size; /* Skip other errors */
error=1;
_ma_check_print_error(param,"Size of datafile is: %-9s Should be: %s",
llstr(size,buff), llstr(skr,buff2));
@ -447,10 +447,10 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
}
if (!(param->testflag & T_VERY_SILENT) &&
!(share->options & HA_OPTION_COMPRESS_RECORD) &&
ulonglong2double(info->state->data_file_length) >
ulonglong2double(share->state.state.data_file_length) >
(ulonglong2double(share->base.max_data_file_length)*0.9))
_ma_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
llstr(info->state->data_file_length,buff),
llstr(share->state.state.data_file_length,buff),
llstr(share->base.max_data_file_length-1,buff2));
DBUG_RETURN(error);
} /* maria_chk_size */
@ -488,8 +488,8 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
init_checksum=param->record_checksum;
old_record_checksum=0;
if (share->data_file_type == STATIC_RECORD)
old_record_checksum= (calc_checksum(info->state->records +
info->state->del-1) *
old_record_checksum= (calc_checksum(share->state.state.records +
share->state.state.del-1) *
share->base.pack_reclength);
rec_per_key_part= param->new_rec_per_key_part;
for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
@ -518,7 +518,7 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
full_text_keys++;
if (share->state.key_root[key] == HA_OFFSET_ERROR)
{
if (info->state->records != 0 && !(keyinfo->flag & HA_FULLTEXT))
if (share->state.state.records != 0 && !(keyinfo->flag & HA_FULLTEXT))
_ma_check_print_error(param, "Key tree %u is empty", key + 1);
goto do_stat;
}
@ -542,10 +542,10 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
DBUG_RETURN(-1);
if(!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL)))
{
if (keys != info->state->records)
if (keys != share->state.state.records)
{
_ma_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
llstr(info->state->records,buff2));
llstr(share->state.state.records,buff2));
if (!(param->testflag & T_INFO))
DBUG_RETURN(-1);
result= -1;
@ -625,7 +625,7 @@ do_stat:
maria_update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
param->notnull_count: NULL,
(ulonglong)info->state->records);
(ulonglong)share->state.state.records);
}
if (param->testflag & T_INFO)
{
@ -639,7 +639,7 @@ do_stat:
else if (all_totaldata != 0L && maria_is_any_key_active(share->state.key_map))
puts("");
}
if (param->key_file_blocks != info->state->key_file_length &&
if (param->key_file_blocks != share->state.state.key_file_length &&
share->state.key_map == ~(ulonglong) 0)
_ma_check_print_warning(param, "Some data are unreferenced in keyfile");
if (found_keys != full_text_keys)
@ -657,10 +657,11 @@ static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
ha_checksum *key_checksum, uint level)
{
char llbuff[22],llbuff2[22];
MARIA_SHARE *share= info->s;
DBUG_ENTER("chk_index_down");
/* Key blocks must lay within the key file length entirely. */
if (page + keyinfo->block_length > info->state->key_file_length)
if (page + keyinfo->block_length > share->state.state.key_file_length)
{
/* purecov: begin tested */
/* Give it a chance to fit in the real file size. */
@ -669,12 +670,13 @@ static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
_ma_check_print_error(param, "Invalid key block position: %s "
"key block size: %u file_length: %s",
llstr(page, llbuff), keyinfo->block_length,
llstr(info->state->key_file_length, llbuff2));
llstr(share->state.state.key_file_length, llbuff2));
if (page + keyinfo->block_length > max_length)
goto err;
/* Fix the remembered key file length. */
info->state->key_file_length= (max_length &
~ (my_off_t) (keyinfo->block_length - 1));
share->state.state.key_file_length= (max_length &
~ (my_off_t) (keyinfo->block_length -
1));
/* purecov: end */
}
@ -941,7 +943,7 @@ static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
}
/* fall through */
}
if (record >= info->state->data_file_length)
if (record >= share->state.state.data_file_length)
{
#ifndef DBUG_OFF
char llbuff2[22], llbuff3[22];
@ -949,7 +951,7 @@ static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
_ma_check_print_error(param,"Found key at page %s that points to record outside datafile",llstr(page,llbuff));
DBUG_PRINT("test",("page: %s record: %s filelength: %s",
llstr(page,llbuff),llstr(record,llbuff2),
llstr(info->state->data_file_length,llbuff3)));
llstr(share->state.state.data_file_length,llbuff3)));
DBUG_DUMP("key",(uchar*) key,key_length);
DBUG_DUMP("new_in_page", old_keypos, (uint) (keypos-old_keypos));
goto err;
@ -1126,7 +1128,7 @@ static int check_static_record(HA_CHECK *param, MARIA_HA *info, int extend,
char llbuff[22];
pos= 0;
while (pos < info->state->data_file_length)
while (pos < share->state.state.data_file_length)
{
if (*_ma_killed_ptr(param))
return -1;
@ -1173,7 +1175,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
LINT_INIT(to);
pos= 0;
while (pos < info->state->data_file_length)
while (pos < share->state.state.data_file_length)
{
my_bool got_error= 0;
int flag;
@ -1228,9 +1230,9 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
DBUG_RETURN(1);
}
if ((block_info.next_filepos != HA_OFFSET_ERROR &&
block_info.next_filepos >= info->state->data_file_length) ||
block_info.next_filepos >= share->state.state.data_file_length) ||
(block_info.prev_filepos != HA_OFFSET_ERROR &&
block_info.prev_filepos >= info->state->data_file_length))
block_info.prev_filepos >= share->state.state.data_file_length))
{
_ma_check_print_error(param,"Delete link points outside datafile at %s",
llstr(pos,llbuff));
@ -1248,7 +1250,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
llstr(start_block,llbuff));
DBUG_RETURN(1);
}
if (info->state->data_file_length < block_info.filepos+
if (share->state.state.data_file_length < block_info.filepos+
block_info.block_len)
{
_ma_check_print_error(param,
@ -1322,7 +1324,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
got_error=1;
break;
}
if (info->state->data_file_length < block_info.next_filepos)
if (share->state.state.data_file_length < block_info.next_filepos)
{
_ma_check_print_error(param,
"Found next-recordlink that points outside datafile at %s",
@ -1391,7 +1393,7 @@ static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend,
DBUG_ENTER("check_compressed_record");
pos= share->pack.header_length; /* Skip header */
while (pos < info->state->data_file_length)
while (pos < share->state.state.data_file_length)
{
if (*_ma_killed_ptr(param))
DBUG_RETURN(-1);
@ -1742,10 +1744,10 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
full_page_count= tail_count= 0;
param->full_page_count= param->tail_count= 0;
param->used= param->link_used= 0;
param->splits= info->state->data_file_length / block_size;
param->splits= share->state.state.data_file_length / block_size;
for (pos= 0, page= 0;
pos < info->state->data_file_length;
pos < share->state.state.data_file_length;
pos+= block_size, page++)
{
uint row_count, real_row_count, empty_space, page_type, bitmap_pattern;
@ -1985,12 +1987,12 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
{
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
}
if (param->records != info->state->records)
if (param->records != share->state.state.records)
{
_ma_check_print_error(param,
"Record-count is not ok; found %-10s Should be: %s",
llstr(param->records,llbuff),
llstr(info->state->records,llbuff2));
llstr(share->state.state.records,llbuff2));
error=1;
}
else if (param->record_checksum &&
@ -2000,7 +2002,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
"Key pointers and record positions doesn't match");
error=1;
}
else if (param->glob_crc != info->state->checksum &&
else if (param->glob_crc != share->state.state.checksum &&
(share->options &
(HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
{
@ -2023,18 +2025,18 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
}
}
if (param->del_length != info->state->empty)
if (param->del_length != share->state.state.empty)
{
_ma_check_print_warning(param,
"Found %s deleted space. Should be %s",
llstr(param->del_length,llbuff2),
llstr(info->state->empty,llbuff));
llstr(share->state.state.empty,llbuff));
}
/* Skip following checks for BLOCK RECORD as they don't make any sence */
if (share->data_file_type != BLOCK_RECORD)
{
if (param->used + param->empty + param->del_length !=
info->state->data_file_length)
share->state.state.data_file_length)
{
_ma_check_print_warning(param,
"Found %s record data and %s unused data and %s deleted data",
@ -2045,14 +2047,14 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
"Total %s Should be: %s",
llstr((param->used+param->empty +
param->del_length), llbuff),
llstr(info->state->data_file_length,llbuff2));
llstr(share->state.state.data_file_length,llbuff2));
}
if (param->del_blocks != info->state->del)
if (param->del_blocks != share->state.state.del)
{
_ma_check_print_warning(param,
"Found %10s deleted blocks Should be: %s",
llstr(param->del_blocks,llbuff),
llstr(info->state->del,llbuff2));
llstr(share->state.state.del,llbuff2));
}
if (param->splits != share->state.split)
{
@ -2224,7 +2226,7 @@ static int initialize_variables_for_repair(HA_CHECK *param,
sort_info->filelength= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
if ((param->testflag & T_CREATE_MISSING_KEYS) ||
sort_info->org_data_file_type == COMPRESSED_RECORD)
sort_info->max_records= info->state->records;
sort_info->max_records= share->state.state.records;
else
{
ulong rec_length;
@ -2354,7 +2356,7 @@ static int maria_drop_all_indexes(HA_CHECK *param, MARIA_HA *info,
share->state.key_del= HA_OFFSET_ERROR;
/* Reset index file length to end of index file header. */
info->state->key_file_length= share->base.keystart;
share->state.state.key_file_length= share->base.keystart;
end:
DBUG_RETURN(0);
@ -2403,7 +2405,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
got_error= 1;
new_file= -1;
start_records= info->state->records;
start_records= share->state.state.records;
if (!(param->testflag & T_SILENT))
{
printf("- recovering (with keycache) MARIA-table '%s'\n",name);
@ -2494,9 +2496,9 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
sort_param.master=1;
sort_info.max_records= ~(ha_rows) 0;
del=info->state->del;
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
del= share->state.state.del;
share->state.state.records= share->state.state.del= share->state.split= 0;
share->state.state.empty= 0;
if (param->testflag & T_CREATE_MISSING_KEYS)
maria_set_all_keys_active(share->state.key_map, share->base.keys);
@ -2538,7 +2540,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
/* purecov: begin tested */
if (block_record)
{
sort_info.new_info->state->records--;
sort_info.new_info->s->state.state.records--;
if ((*sort_info.new_info->s->write_record_abort)(sort_info.new_info))
{
_ma_check_print_error(param,"Couldn't delete duplicate row");
@ -2565,7 +2567,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
{
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
}
if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
{
_ma_check_print_warning(param,
"Can't change size of indexfile, error: %d",
@ -2573,7 +2575,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
goto err;
}
if (rep_quick && del+sort_info.dupp != info->state->del)
if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
@ -2585,9 +2587,9 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
if (sort_info.new_info->state->records+1 < start_records)
if (sort_info.new_info->s->state.state.records+1 < start_records)
{
info->state->records=start_records;
share->state.state.records= start_records;
goto err;
}
}
@ -2606,7 +2608,7 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
if (!rep_quick)
{
sort_info.new_info->state->data_file_length= sort_param.filepos;
sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
if (sort_info.new_info != sort_info.info)
{
MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
@ -2638,15 +2640,15 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
}
else
{
info->state->data_file_length= sort_param.max_pos;
share->state.state.data_file_length= sort_param.max_pos;
}
if (param->testflag & T_CALC_CHECKSUM)
info->state->checksum= param->glob_crc;
share->state.state.checksum= param->glob_crc;
if (!(param->testflag & T_SILENT))
{
if (start_records != info->state->records)
printf("Data records: %s\n", llstr(info->state->records,llbuff));
if (start_records != share->state.state.records)
printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
}
if (sort_info.dupp)
_ma_check_print_warning(param,
@ -2656,11 +2658,12 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
got_error= 0;
/* If invoked by external program that uses thr_lock */
if (&share->state.state != info->state)
memcpy(&share->state.state, info->state, sizeof(*info->state));
*info->state= *info->state_start= share->state.state;
err:
if (scan_inited)
maria_scan_end(sort_info.info);
_ma_reset_state(info);
VOID(end_io_cache(&param->read_cache));
VOID(end_io_cache(&sort_info.new_info->rec_cache));
@ -2952,7 +2955,7 @@ int maria_sort_index(HA_CHECK *param, register MARIA_HA *info, char *name)
share->tot_locks= r_locks+w_locks;
share->state= old_state; /* Restore old state */
info->state->key_file_length=param->new_file_pos;
share->state.state.key_file_length=param->new_file_pos;
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
for (key=0 ; key < share->base.keys ; key++)
share->state.key_root[key]=index_pos[key];
@ -3185,7 +3188,7 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
/* Go through the record file */
for (page= 1, pos= block_size;
pos < info->state->data_file_length;
pos < share->state.state.data_file_length;
pos+= block_size, page++)
{
uchar *buff;
@ -3416,7 +3419,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
got_error= 1;
new_file= -1;
start_records= info->state->records;
start_records= share->state.state.records;
if (!(param->testflag & T_SILENT))
{
printf("- recovering (with sort) MARIA-table '%s'\n",name);
@ -3517,7 +3520,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
sort_param.tmpdir=param->tmpdir;
sort_param.master =1;
del=info->state->del;
del=share->state.state.del;
rec_per_key_part= param->new_rec_per_key_part;
for (sort_param.key=0 ; sort_param.key < share->base.keys ;
@ -3559,8 +3562,8 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (keyseg[i].flag & HA_NULL_PART)
sort_param.key_length++;
}
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
share->state.state.records=share->state.state.del=share->state.split=0;
share->state.state.empty=0;
if (sort_param.keyinfo->flag & HA_FULLTEXT)
{
@ -3638,15 +3641,14 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
free_root(&sort_param.wordroot, MYF(0));
/* Set for next loop */
sort_info.max_records= (ha_rows) sort_info.new_info->state->records;
sort_info.max_records= (ha_rows) sort_info.new_info->s->state.state.records;
if (param->testflag & T_STATISTICS)
maria_update_key_parts(sort_param.keyinfo, rec_per_key_part,
sort_param.unique,
(param->stats_method ==
MI_STATS_METHOD_IGNORE_NULLS ?
sort_param.notnull : NULL),
(ulonglong) info->state->records);
(ulonglong) share->state.state.records);
maria_set_key_active(share->state.key_map, sort_param.key);
DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key));
@ -3667,17 +3669,17 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
if (info->state->records+1 < start_records)
if (share->state.state.records+1 < start_records)
{
_ma_check_print_error(param,
"Rows lost; Aborting because safe repair was "
"requested");
info->state->records=start_records;
share->state.state.records=start_records;
goto err;
}
}
sort_info.new_info->state->data_file_length= sort_param.filepos;
sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
if (sort_info.new_info != sort_info.info)
{
MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
@ -3716,11 +3718,11 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
org_header_length= share->pack.header_length;
sort_info.org_data_file_type= share->data_file_type;
sort_info.filelength= info->state->data_file_length;
sort_info.filelength= share->state.state.data_file_length;
sort_param.fix_datafile=0;
}
else
info->state->data_file_length=sort_param.max_pos;
share->state.state.data_file_length=sort_param.max_pos;
param->read_cache.file= info->dfile.file; /* re-init read cache */
reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
@ -3732,7 +3734,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
}
if (rep_quick && del+sort_info.dupp != info->state->del)
if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
@ -3744,7 +3746,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
my_off_t skr= (info->state->data_file_length +
my_off_t skr= (share->state.state.data_file_length +
(sort_info.org_data_file_type == COMPRESSED_RECORD) ?
MEMMAP_EXTRA_MARGIN : 0);
#ifdef USE_RELOC
@ -3760,30 +3762,31 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
}
if (param->testflag & T_CALC_CHECKSUM)
info->state->checksum=param->glob_crc;
share->state.state.checksum=param->glob_crc;
if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
_ma_check_print_warning(param,
"Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT))
{
if (start_records != info->state->records)
printf("Data records: %s\n", llstr(info->state->records,llbuff));
if (start_records != share->state.state.records)
printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
}
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0;
/* If invoked by external program that uses thr_lock */
if (&share->state.state != info->state)
memcpy(&share->state.state, info->state, sizeof(*info->state));
*info->state= *info->state_start= share->state.state;
err:
if (scan_inited)
maria_scan_end(sort_info.info);
_ma_reset_state(info);
VOID(end_io_cache(&sort_info.new_info->rec_cache));
VOID(end_io_cache(&param->read_cache));
@ -3909,7 +3912,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
got_error= 1;
new_file= -1;
start_records= info->state->records;
start_records= share->state.state.records;
if (!(param->testflag & T_SILENT))
{
printf("- parallel recovering (with sort) MARIA-table '%s'\n",name);
@ -4014,7 +4017,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
/*
+1 below is required hack for parallel repair mode.
The info->state->records value, that is compared later
The share->state.state.records value, that is compared later
to sort_info.max_records and cannot exceed it, is
increased in sort_key_write. In maria_repair_by_sort, sort_key_write
is called after sort_key_read, where the comparison is performed,
@ -4026,7 +4029,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
*/
sort_info.max_records++;
del=info->state->del;
del=share->state.state.del;
if (!(sort_param=(MARIA_SORT_PARAM *)
my_malloc((uint) share->base.keys *
@ -4038,8 +4041,8 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
}
total_key_length=0;
rec_per_key_part= param->new_rec_per_key_part;
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
share->state.state.records=share->state.state.del=share->state.split=0;
share->state.state.empty=0;
for (i=key=0, istep=1 ; key < share->base.keys ;
rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
@ -4213,16 +4216,16 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
if (info->state->records+1 < start_records)
if (share->state.state.records+1 < start_records)
{
info->state->records=start_records;
share->state.state.records=start_records;
goto err;
}
}
share->state.state.data_file_length= info->state->data_file_length=
share->state.state.data_file_length= share->state.state.data_file_length=
sort_param->filepos;
/* Only whole records */
share->state.version=(ulong) time((time_t*) 0);
share->state.version= (ulong) time((time_t*) 0);
/*
Exchange the data file descriptor of the table, so that we use the
new file from now on.
@ -4232,9 +4235,9 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
share->pack.header_length=(ulong) new_header_length;
}
else
info->state->data_file_length=sort_param->max_pos;
share->state.state.data_file_length=sort_param->max_pos;
if (rep_quick && del+sort_info.dupp != info->state->del)
if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
@ -4245,7 +4248,7 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
my_off_t skr= (info->state->data_file_length +
my_off_t skr= (share->state.state.data_file_length +
(sort_info.org_data_file_type == COMPRESSED_RECORD) ?
MEMMAP_EXTRA_MARGIN : 0);
#ifdef USE_RELOC
@ -4260,28 +4263,30 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
my_errno);
}
if (param->testflag & T_CALC_CHECKSUM)
info->state->checksum=param->glob_crc;
share->state.state.checksum=param->glob_crc;
if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
_ma_check_print_warning(param,
"Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT))
{
if (start_records != info->state->records)
printf("Data records: %s\n", llstr(info->state->records,llbuff));
if (start_records != share->state.state.records)
printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
}
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0;
/* If invoked by external program that uses thr_lock */
if (&share->state.state != info->state)
memcpy(&share->state.state, info->state, sizeof(*info->state));
*info->state= *info->state_start= share->state.state;
err:
_ma_reset_state(info);
/*
Destroy the write cache. The master thread did already detach from
the share by remove_io_thread() or it was not yet started (if the
@ -4360,7 +4365,7 @@ static int sort_key_read(MARIA_SORT_PARAM *sort_param, uchar *key)
if ((error=sort_get_next_record(sort_param)))
DBUG_RETURN(error);
if (info->state->records == sort_info->max_records)
if (info->s->state.state.records == sort_info->max_records)
{
_ma_check_print_error(sort_info->param,
"Key %d - Found too many records; Can't continue",
@ -4504,7 +4509,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
Scan on clean table.
It requires a reliable data_file_length so we set it.
*/
info->state->data_file_length= sort_info->filelength;
share->state.state.data_file_length= sort_info->filelength;
info->cur_row.trid= 0;
flag= _ma_scan_block_record(info, sort_param->record,
info->cur_row.nextpos, 1);
@ -4542,7 +4547,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
}
if (flag == HA_ERR_END_OF_FILE)
{
sort_param->max_pos= info->state->data_file_length;
sort_param->max_pos= share->state.state.data_file_length;
DBUG_RETURN(-1);
}
/* Retry only if wrong record, not if disk error */
@ -4580,8 +4585,8 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
}
if (!sort_param->fix_datafile && sort_param->master)
{
info->state->del++;
info->state->empty+=share->base.pack_reclength;
share->state.state.del++;
share->state.state.empty+=share->base.pack_reclength;
}
}
case DYNAMIC_RECORD:
@ -4685,9 +4690,9 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
{
if ((block_info.next_filepos != HA_OFFSET_ERROR &&
block_info.next_filepos >=
info->state->data_file_length) ||
share->state.state.data_file_length) ||
(block_info.prev_filepos != HA_OFFSET_ERROR &&
block_info.prev_filepos >= info->state->data_file_length))
block_info.prev_filepos >= share->state.state.data_file_length))
{
if (!searching)
_ma_check_print_info(param,
@ -4735,8 +4740,8 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
if (!sort_param->fix_datafile && sort_param->master &&
(b_type & BLOCK_DELETED))
{
info->state->empty+=block_info.block_len;
info->state->del++;
share->state.state.empty+=block_info.block_len;
share->state.state.del++;
share->state.split++;
}
if (found_record)
@ -5010,7 +5015,7 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
HA_OFFSET_ERROR)
DBUG_RETURN(1);
/* Pointer to end of file */
sort_param->filepos= info->state->data_file_length;
sort_param->filepos= share->state.state.data_file_length;
break;
case STATIC_RECORD:
if (my_b_write(&info->rec_cache,sort_param->record,
@ -5089,12 +5094,12 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
}
if (sort_param->master)
{
info->state->records++;
share->state.state.records++;
if ((param->testflag & T_WRITE_LOOP) &&
(info->state->records % WRITE_COUNT) == 0)
(share->state.state.records % WRITE_COUNT) == 0)
{
char llbuff[22];
printf("%s\r", llstr(info->state->records,llbuff));
printf("%s\r", llstr(share->state.state.records,llbuff));
VOID(fflush(stdout));
}
}
@ -5392,7 +5397,7 @@ static int sort_insert_key(MARIA_SORT_PARAM *sort_param,
_ma_store_page_used(share, anc_buff, key_block->last_length);
bzero(anc_buff+key_block->last_length,
keyinfo->block_length- key_block->last_length);
key_file_length=info->state->key_file_length;
key_file_length=share->state.state.key_file_length;
if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) == HA_OFFSET_ERROR)
DBUG_RETURN(1);
_ma_fast_unlock_key_del(info);
@ -5491,7 +5496,7 @@ static int sort_delete_record(MARIA_SORT_PARAM *sort_param)
_ma_check_print_error(param,"Got error %d when deleting record",
my_errno);
row_info->dfile.file= old_file; /* restore actual value */
row_info->state->records--;
row_info->s->state.state.records--;
DBUG_RETURN(error);
} /* sort_delete_record */
@ -5518,7 +5523,7 @@ int _ma_flush_pending_blocks(MARIA_SORT_PARAM *sort_param)
length= _ma_get_page_used(info->s, key_block->buff);
if (nod_flag)
_ma_kpointer(info,key_block->end_pos,filepos);
key_file_length=info->state->key_file_length;
key_file_length= info->s->state.state.key_file_length;
bzero(key_block->buff+length, keyinfo->block_length-length);
if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
HA_OFFSET_ERROR)
@ -5753,16 +5758,16 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
/* We are modifing */
(*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
VOID(_ma_readinfo(*org_info,F_WRLCK,0));
(*org_info)->state->records=info.state->records;
(*org_info)->s->state.state.records= info.state->records;
if (share.state.create_time)
(*org_info)->s->state.create_time=share.state.create_time;
(*org_info)->s->state.unique=(*org_info)->this_unique=
share.state.unique;
(*org_info)->state->checksum=info.state->checksum;
(*org_info)->state->del=info.state->del;
(*org_info)->s->state.dellink=share.state.dellink;
(*org_info)->state->empty=info.state->empty;
(*org_info)->state->data_file_length=info.state->data_file_length;
(*org_info)->s->state.unique= (*org_info)->this_unique= share.state.unique;
(*org_info)->s->state.state.checksum= info.state->checksum;
(*org_info)->s->state.state.del= info.state->del;
(*org_info)->s->state.dellink= share.state.dellink;
(*org_info)->s->state.state.empty= info.state->empty;
(*org_info)->s->state.state.data_file_length= info.state->data_file_length;
*(*org_info)->state= (*org_info)->s->state.state;
if (maria_update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
UPDATE_OPEN_COUNT))
goto end;
@ -5813,9 +5818,9 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
if (update & UPDATE_STAT)
{
uint i, key_parts= mi_uint2korr(share->state.header.key_parts);
share->state.records_at_analyze= info->state->records;
share->state.records_at_analyze= share->state.state.records;
share->state.changed&= ~STATE_NOT_ANALYZED;
if (info->state->records)
if (share->state.state.records)
{
for (i=0; i<key_parts; i++)
{
@ -5830,16 +5835,8 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
{
share->state.check_time= (long) time((time_t*) 0);
if (!share->state.create_time)
share->state.create_time=share->state.check_time;
share->state.create_time= share->state.check_time;
}
/*
When tables are locked we haven't synched the share state and the
real state for a while so we better do it here before synching
the share state to disk. Only when table is write locked is it
necessary to perform this synch.
*/
if (info->lock_type == F_WRLCK)
share->state.state= *info->state;
if (_ma_state_info_write(share, 1|2))
goto err;
share->changed=0;
@ -6064,7 +6061,7 @@ void maria_disable_non_unique_index(MARIA_HA *info, ha_rows rows)
MARIA_KEYDEF *key=share->keyinfo;
uint i;
DBUG_ASSERT(info->state->records == 0 &&
DBUG_ASSERT(share->state.state.records == 0 &&
(!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES));
for (i=0 ; i < share->base.keys ; i++,key++)
{
@ -6148,7 +6145,7 @@ static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file)
DBUG_RETURN(1);
/* Take into account any bitmap page created above: */
param->filepos= new_info->state->data_file_length;
param->filepos= new_info->s->state.state.data_file_length;
/* Use new virtual functions for key generation */
info->s->keypos_to_recpos= new_info->s->keypos_to_recpos;

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

@ -111,11 +111,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);

View File

@ -91,13 +91,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)
{
/*
@ -156,14 +155,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

@ -626,9 +626,9 @@ uint _ma_apply_redo_index_new_page(MARIA_HA *info, LSN lsn,
cmp_translog_addr(lsn, share->state.is_of_horizon) >= 0)
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;
@ -1138,7 +1138,7 @@ void _ma_unlock_key_del(MARIA_HA *info)
MARIA_SHARE *share= info->s;
pthread_mutex_lock(&share->intern_lock);
share->used_key_del= 0;
share->state.key_del= info->s->current_key_del;
share->state.key_del= share->current_key_del;
pthread_mutex_unlock(&share->intern_lock);
pthread_cond_signal(&share->intern_cond);
}

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, 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->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");
@ -120,6 +121,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode,
share->have_rtree ? 1024 : 0,
&changed_fields_bitmap,
bitmap_buffer_size(share->base.fields),
&state_dummy, sizeof(*state_dummy),
NullS))
goto err;
errpos= 6;
@ -176,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 */
@ -759,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));
@ -774,22 +809,24 @@ 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)) ||
(open_flags & HA_OPEN_TMP_TABLE) ||
(share->data_file_type == BLOCK_RECORD &&
!share->now_transactional) ||
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_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
{
@ -798,6 +835,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
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;
}
}
}
@ -1705,17 +1743,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);
@ -299,14 +299,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;
}
@ -337,7 +341,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
@ -3226,6 +3233,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

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

@ -70,6 +70,10 @@ static my_bool _ma_log_key_middle(MARIA_HA *info, my_off_t page, uchar *buff,
/*
@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,
@ -97,7 +101,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",
@ -116,12 +120,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;
@ -204,8 +208,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)
{
@ -216,8 +219,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;
@ -578,7 +581,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);
@ -1521,7 +1524,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++;
@ -1534,7 +1537,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;
}
@ -1613,7 +1616,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)
@ -1621,11 +1624,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;
}

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;
@ -461,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;
@ -733,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
@ -1048,6 +1044,7 @@ 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);

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

@ -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
@ -325,6 +339,7 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond,
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;
@ -342,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);
}
@ -362,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;
@ -435,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;
@ -446,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 */
@ -763,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;
@ -776,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

@ -1511,12 +1511,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);