diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index a1a4aba..fdfa74c 100644 --- a/mysql-test/suite/innodb/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -1357,3 +1357,95 @@ t1 CREATE TABLE `t1` ( INSERT INTO t1 VALUES (); ERROR HY000: Failed to read auto-increment value from storage engine DROP TABLE t1; +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +SET @@INSERT_ID=1; +SHOW VARIABLES LIKE "%auto_inc%"; +Variable_name Value +auto_increment_increment 1 +auto_increment_offset 1 +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 'test.t1' +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(null); +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +c1 +1 +2 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +# restart: --innodb_autoinc_persistent=on +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES(null); +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +c1 +1 +2 +3 +4 +DELETE FROM t1 WHERE c1 in(3,4); +SELECT * FROM t1; +c1 +1 +2 +# restart: --innodb_autoinc_persistent=on +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +update t1 set c1=1000 where c1=1; +select * from t1; +c1 +2 +1000 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +# restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +insert into t1 values(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null); +select * from t1; +c1 +2 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +1000 +# restart: --innodb_autoinc_persistent=on innodb_autoinc_persistent_interval=10 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index 38038de..0778907 100644 --- a/mysql-test/suite/innodb/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -685,3 +685,76 @@ SHOW CREATE TABLE t1; --error 1467 INSERT INTO t1 VALUES (); DROP TABLE t1; + +# +# Test innodb_autoinc_persistent +# + +# Reset the AUTOINC session variables +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +SET @@INSERT_ID=1; +SHOW VARIABLES LIKE "%auto_inc%"; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(null); +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +SHOW CREATE TABLE t1; + + +--echo # restart: --innodb_autoinc_persistent=on +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server 10 +--source include/wait_until_disconnected.inc +# Do something while server is down +--enable_reconnect +# Write file to make mysql-test-run.pl start up the server again +--exec echo "restart: --innodb_autoinc_persistent=on" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--source include/wait_until_connected_again.inc +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES(null); +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +DELETE FROM t1 WHERE c1 in(3,4); +SELECT * FROM t1; + +--echo # restart: --innodb_autoinc_persistent=on +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server 10 +--source include/wait_until_disconnected.inc +# Do something while server is down +--enable_reconnect +# Write file to make mysql-test-run.pl start up the server again +--exec echo "restart: --innodb_autoinc_persistent=on" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--source include/wait_until_connected_again.inc +SHOW CREATE TABLE t1; + +update t1 set c1=1000 where c1=1; +select * from t1; +SHOW CREATE TABLE t1; + +--echo # restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10 +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server 10 +--source include/wait_until_disconnected.inc +# Do something while server is down +--enable_reconnect +# Write file to make mysql-test-run.pl start up the server again +--exec echo "restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--source include/wait_until_connected_again.inc +SHOW CREATE TABLE t1; +insert into t1 values(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null),(null); +select * from t1; + +--echo # restart: --innodb_autoinc_persistent=on innodb_autoinc_persistent_interval=10 +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--shutdown_server 10 +--source include/wait_until_disconnected.inc +# Do something while server is down +--enable_reconnect +# Write file to make mysql-test-run.pl start up the server again +--exec echo "restart: --innodb_autoinc_persistent=on --innodb_autoinc_persistent_interval=10" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--source include/wait_until_connected_again.inc +SHOW CREATE TABLE t1; + +DROP TABLE t1; diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 0951fee..590d8fc 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -24,6 +24,10 @@ IC_REDUCE_HINT_ENABLE IC_REDUCE_HINT_ENABLE INNODB_ADAPTIVE_TICKETS_ALGO INNODB_ADAPTIVE_TICKETS_ALGO +INNODB_AUTOINC_PERSISTENT +INNODB_AUTOINC_PERSISTENT +INNODB_AUTOINC_PERSISTENT_INTERVAL +INNODB_AUTOINC_PERSISTENT_INTERVAL INNODB_COLUMN_COMPRESSION_LEVEL INNODB_COLUMN_COMPRESSION_LEVEL INNODB_COLUMN_ZIP_MEM_USE_HEAP diff --git a/mysql-test/suite/sys_vars/r/innodb_autoinc_persistent.result b/mysql-test/suite/sys_vars/r/innodb_autoinc_persistent.result new file mode 100644 index 0000000..162e817 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_autoinc_persistent.result @@ -0,0 +1,17 @@ +SELECT COUNT(@@GLOBAL.innodb_autoinc_persistent); +COUNT(@@GLOBAL.innodb_autoinc_persistent) +1 +SET @@GLOBAL.innodb_autoinc_persistent=ON; +ERROR HY000: Variable 'innodb_autoinc_persistent' is a read only variable +Expected error 'Read-only variable' +SELECT COUNT(@@local.innodb_autoinc_persistent); +ERROR HY000: Variable 'innodb_autoinc_persistent' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_autoinc_persistent); +ERROR HY000: Variable 'innodb_autoinc_persistent' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT VARIABLE_NAME, VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME = 'innodb_autoinc_persistent'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_AUTOINC_PERSISTENT OFF diff --git a/mysql-test/suite/sys_vars/r/innodb_autoinc_persistent_interval.result b/mysql-test/suite/sys_vars/r/innodb_autoinc_persistent_interval.result new file mode 100644 index 0000000..4da43d8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_autoinc_persistent_interval.result @@ -0,0 +1,33 @@ +SET @start_global_value = @@global.innodb_autoinc_persistent_interval; +SELECT @start_global_value; +@start_global_value +1 +SELECT VARIABLE_NAME, VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME = 'innodb_autoinc_persistent_interval'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_AUTOINC_PERSISTENT_INTERVAL 1 +SELECT COUNT(@@local.innodb_autoinc_persistent_interval); +ERROR HY000: Variable 'innodb_autoinc_persistent_interval' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_autoinc_persistent_interval); +ERROR HY000: Variable 'innodb_autoinc_persistent_interval' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SET innodb_autoinc_persistent_interval = 100; +ERROR HY000: Variable 'innodb_autoinc_persistent_interval' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_autoinc_persistent_interval = 100; +SELECT @@global.innodb_autoinc_persistent_interval; +@@global.innodb_autoinc_persistent_interval +100 +SET global innodb_autoinc_persistent_interval = 0; +Warnings: +Warning 1292 Truncated incorrect innodb_autoinc_persistent_interv value: '0' +SET global innodb_autoinc_persistent_interval = 10001; +Warnings: +Warning 1292 Truncated incorrect innodb_autoinc_persistent_interv value: '10001' +SET @@global.innodb_autoinc_persistent_interval = 30.34; +ERROR 42000: Incorrect argument type to variable 'innodb_autoinc_persistent_interval' +SET @@global.innodb_autoinc_persistent_interval = @start_global_value; +SELECT @@global.innodb_autoinc_persistent_interval; +@@global.innodb_autoinc_persistent_interval +1 diff --git a/mysql-test/suite/sys_vars/t/innodb_autoinc_persistent.test b/mysql-test/suite/sys_vars/t/innodb_autoinc_persistent.test new file mode 100644 index 0000000..4aa1570 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_autoinc_persistent.test @@ -0,0 +1,28 @@ +# Variable name: innodb_autoinc_persistent +# Scope: Global +# Access type: Static +# Data type: boolen +# Default value: OFF + +--source include/have_innodb.inc + +SELECT COUNT(@@GLOBAL.innodb_autoinc_persistent); + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_autoinc_persistent=ON; +--echo Expected error 'Read-only variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_autoinc_persistent); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_autoinc_persistent); +--echo Expected error 'Variable is a GLOBAL variable' + +# Check the default value +SELECT VARIABLE_NAME, VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME = 'innodb_autoinc_persistent'; + + diff --git a/mysql-test/suite/sys_vars/t/innodb_autoinc_persistent_interval.test b/mysql-test/suite/sys_vars/t/innodb_autoinc_persistent_interval.test new file mode 100644 index 0000000..5e712d4 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_autoinc_persistent_interval.test @@ -0,0 +1,46 @@ +# Variable Name:innodb_autoinc_persistent_interval +# Scope: GLOBAL +# Access Type: Dynamic +# Data Type: Numeric +# Default Value: 1 +# Range: 1 - 10000 + + +--source include/have_innodb.inc +# Save initial value # +############################################################# +SET @start_global_value = @@global.innodb_autoinc_persistent_interval; +SELECT @start_global_value; + +# Check the default value +SELECT VARIABLE_NAME, VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME = 'innodb_autoinc_persistent_interval'; + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_autoinc_persistent_interval); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_autoinc_persistent_interval); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_GLOBAL_VARIABLE +SET innodb_autoinc_persistent_interval = 100; + +SET global innodb_autoinc_persistent_interval = 100; + +SELECT @@global.innodb_autoinc_persistent_interval; + +SET global innodb_autoinc_persistent_interval = 0; +SET global innodb_autoinc_persistent_interval = 10001; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.innodb_autoinc_persistent_interval = 30.34; + +#################################### +## Restore initial value # +##################################### + +SET @@global.innodb_autoinc_persistent_interval = @start_global_value; +SELECT @@global.innodb_autoinc_persistent_interval; diff --git a/sql/handler.h b/sql/handler.h index cf18c87..b7f84a3 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1050,6 +1050,7 @@ typedef struct st_ha_create_information const char *alias; ulonglong max_rows,min_rows; ulonglong auto_increment_value; + ulonglong auto_increment_increment; ulong table_options; ulong avg_row_length; ulong used_fields; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b2f9ee7..5990e1b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5296,6 +5296,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE; /* Reset auto-increment counter for the new table. */ local_create_info.auto_increment_value= 0; + local_create_info.auto_increment_increment= thd->variables.auto_increment_increment; /* Do not inherit values of DATA and INDEX DIRECTORY options from the original table. This is documented behavior. @@ -6884,6 +6885,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, /* Table has an autoincrement, copy value to new table */ table->file->info(HA_STATUS_AUTO); create_info->auto_increment_value= table->file->stats.auto_increment_value; + create_info->auto_increment_increment= thd->variables.auto_increment_increment; } if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) create_info->key_block_size= table->s->key_block_size; @@ -6924,6 +6926,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, !(used_fields & HA_CREATE_USED_AUTO)) { create_info->auto_increment_value=0; + create_info->auto_increment_increment= thd->variables.auto_increment_increment; create_info->used_fields|=HA_CREATE_USED_AUTO; } break; diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 8666023..173488d 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -763,6 +763,58 @@ btr_root_get( } /**************************************************************//** +Gets the auto-inc value from the root node of cluster index and x-latches it. +@return auto-inc value */ +UNIV_INTERN +ulonglong +btr_root_get_auto_inc( +/*=========*/ + dict_table_t* table) /*!< in: dict table */ +{ + ulonglong auto_inc; + dict_index_t* index; + mtr_t mtr; + page_t* root; + + /* get cluster index */ + index = dict_table_get_first_index(table); + + mtr_start(&mtr); + mtr_s_lock(dict_index_get_lock(index), &mtr); + root = btr_root_get(index, &mtr); + auto_inc= page_get_max_trx_id(root); + mtr_commit(&mtr); + + return (auto_inc); +} + + +/**************************************************************//** +set the auto-inc value to the root node of a cluster index. +*/ +UNIV_INTERN +void +btr_root_set_auto_inc( +/*=========*/ + dict_table_t* table, /*!< in: table */ + ulonglong value) /*!< in: auto_inc value */ +{ + dict_index_t* index; + buf_block_t* block; + mtr_t mtr; + + /* get cluster index */ + index = dict_table_get_first_index(table); + + mtr_start(&mtr); + mtr_s_lock(dict_index_get_lock(index), &mtr); + block = btr_root_block_get(index, RW_X_LATCH, &mtr); + /* we reuse trx_id positon, because trx_id is no necessary for cluester index */ + page_set_max_trx_id(block, buf_block_get_page_zip(block), value, &mtr); + mtr_commit(&mtr); +} + +/**************************************************************//** Gets the height of the B-tree (the level of the root, when the leaf level is assumed to be 0). The caller must hold an S or X latch on the index. @@ -1125,6 +1177,9 @@ btr_page_alloc_low( page_t* root; root = btr_root_get(index, mtr); + ut_ad(srv_autoinc_persistent || + !dict_index_is_clust(index) || + page_get_max_trx_id(root) == 0); if (level == 0) { seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; @@ -1283,6 +1338,9 @@ btr_page_free_low( } root = btr_root_get(index, mtr); + ut_ad(srv_autoinc_persistent || + !dict_index_is_clust(index) || + page_get_max_trx_id(root) == 0); if (level == 0) { seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; @@ -4035,6 +4093,9 @@ btr_print_size( mtr_start(&mtr); root = btr_root_get(index, &mtr); + ut_ad(srv_autoinc_persistent || + !dict_index_is_clust(index) || + page_get_max_trx_id(root) == 0); seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 088eeb9..542cd9a 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -202,7 +202,8 @@ void dict_table_remove_from_cache_low( /*=============================*/ dict_table_t* table, /*!< in, own: table */ - ibool lru_evict); /*!< in: TRUE if evicting from LRU */ + ibool lru_evict, /*!< in: TRUE if evicting from LRU */ + ibool autoinc_persistent);/*!< in, own: autoinc_persistent */ #ifdef UNIV_DEBUG /**********************************************************************//** Validate the dictionary table LRU list. @@ -566,11 +567,20 @@ void dict_table_autoinc_initialize( /*==========================*/ dict_table_t* table, /*!< in/out: table */ + ulonglong increment, /*!< in: auto increment value */ ib_uint64_t value) /*!< in: next value to assign to a row */ { ut_ad(mutex_own(&table->autoinc_mutex)); table->autoinc = value; + table->old_autoinc = table->autoinc; + if (dict_table_is_discarded(table)) + return; + if (srv_autoinc_persistent) + btr_root_set_auto_inc(table, (value + (srv_n_autoinc_interval - 1)* increment)); + else /* init value 0 when srv_autoinc_persistent=off */ + btr_root_set_auto_inc(table, 0); + } /************************************************************************ @@ -624,13 +634,18 @@ dict_table_autoinc_update_if_greater( /*=================================*/ dict_table_t* table, /*!< in/out: table */ + ulonglong increment, /*!< in: auto increment value */ ib_uint64_t value) /*!< in: value which was assigned to a row */ { ut_ad(mutex_own(&table->autoinc_mutex)); if (value > table->autoinc) { - table->autoinc = value; + if (srv_autoinc_persistent && + ((table->autoinc - table->old_autoinc)/increment >= srv_n_autoinc_interval)) { + table->old_autoinc = table->autoinc; + btr_root_set_auto_inc(table, (value + (srv_n_autoinc_interval - 1)* increment)); + } } } @@ -1258,7 +1273,7 @@ dict_make_room_in_cache( if (dict_table_can_be_evicted(table)) { - dict_table_remove_from_cache_low(table, TRUE); + dict_table_remove_from_cache_low(table, TRUE, TRUE); ++n_evicted; } @@ -1515,7 +1530,9 @@ dict_table_rename_in_cache( /* Remove table from the hash tables of tables */ HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, ut_fold_string(old_name), table); - + /* persist autoinc value when dict table move from dict cache */ + if (srv_autoinc_persistent && srv_n_autoinc_interval > 1 && table->autoinc > 0) + btr_root_set_auto_inc(table, table->autoinc); if (strlen(new_name) > strlen(table->name)) { /* We allocate MAX_FULL_NAME_LEN + 1 bytes here to avoid memory fragmentation, we assume a repeated calls of @@ -1794,8 +1811,9 @@ void dict_table_remove_from_cache_low( /*=============================*/ dict_table_t* table, /*!< in, own: table */ - ibool lru_evict) /*!< in: TRUE if table being evicted + ibool lru_evict, /*!< in: TRUE if table being evicted to make room in the table LRU list */ + ibool autoinc_persistent)/*!< in, own: autoinc_persistent */ { dict_foreign_t* foreign; dict_index_t* index; @@ -1833,6 +1851,14 @@ dict_table_remove_from_cache_low( foreign->referenced_index = NULL; } + /* persist autoinc value when dict table move from dict cache */ + if (autoinc_persistent && + srv_autoinc_persistent && + srv_n_autoinc_interval > 1 && + table->autoinc > 0) { + btr_root_set_auto_inc(table, table->autoinc); + } + /* Remove the indexes from the cache */ for (index = UT_LIST_GET_LAST(table->indexes); @@ -1902,7 +1928,8 @@ dict_table_remove_from_cache( /*=========================*/ dict_table_t* table) /*!< in, own: table */ { - dict_table_remove_from_cache_low(table, FALSE); + /* remove table from cache when exception set autoinc_persistent=FALSE */ + dict_table_remove_from_cache_low(table, FALSE, FALSE); } /****************************************************************//** diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 60daeea..298ce34 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -107,6 +107,7 @@ dict_mem_table_create( &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); table->autoinc = 0; + table->old_autoinc = 0; /* The number of transactions that are either waiting on the AUTOINC lock or have been granted the lock. */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 11e47d2..07d6ee6 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4697,6 +4697,14 @@ ha_innobase::innobase_initialize_autoinc() auto_inc = innobase_next_autoinc( read_auto_inc, 1, 1, 0, col_max_value); + if (srv_autoinc_persistent) { + ulonglong auto_inc_persistent; + auto_inc_persistent = btr_root_get_auto_inc(prebuilt->table); + /* auto_inc_persistent = 0 when srv_autoinc_persistent=off, + then we use SELECT MAX(col_name); */ + if (auto_inc_persistent > 0) + auto_inc = auto_inc_persistent; + } break; } @@ -4731,7 +4739,7 @@ ha_innobase::innobase_initialize_autoinc() } } - dict_table_autoinc_initialize(prebuilt->table, auto_inc); + dict_table_autoinc_initialize(prebuilt->table, prebuilt->autoinc_increment, auto_inc); } /*****************************************************************//** @@ -6502,7 +6510,7 @@ ha_innobase::innobase_reset_autoinc( if (error == DB_SUCCESS) { - dict_table_autoinc_initialize(prebuilt->table, autoinc); + dict_table_autoinc_initialize(prebuilt->table, prebuilt->autoinc_increment, autoinc); dict_table_autoinc_unlock(prebuilt->table); } @@ -6526,7 +6534,7 @@ ha_innobase::innobase_set_max_autoinc( if (error == DB_SUCCESS) { - dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc); + dict_table_autoinc_update_if_greater(prebuilt->table, prebuilt->autoinc_increment, auto_inc); dict_table_autoinc_unlock(prebuilt->table); } @@ -9834,7 +9842,7 @@ ha_innobase::create( auto_inc_value = create_info->auto_increment_value; dict_table_autoinc_lock(innobase_table); - dict_table_autoinc_initialize(innobase_table, auto_inc_value); + dict_table_autoinc_initialize(innobase_table, create_info->auto_increment_increment, auto_inc_value); dict_table_autoinc_unlock(innobase_table); } @@ -13258,7 +13266,7 @@ ha_innobase::get_auto_increment( } else { /* Update the table autoinc variable */ dict_table_autoinc_update_if_greater( - prebuilt->table, prebuilt->autoinc_last_value); + prebuilt->table, prebuilt->autoinc_increment, prebuilt->autoinc_last_value); } } else { /* This will force write_row() into attempting an update @@ -15802,6 +15810,18 @@ static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit, " or 2 (write at commit, flush once per second).", NULL, NULL, 1, 0, 2, 0); +/* when autoinc_persistent=on and autoinc_persistent_interval=1 the sever + * performance degradation less than 1% */ +static MYSQL_SYSVAR_BOOL(autoinc_persistent, srv_autoinc_persistent, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Innodb table's auto_increment max value whether persist in cluster btr root page, (default: off).", + NULL, NULL, FALSE); + +static MYSQL_SYSVAR_ULONG(autoinc_persistent_interval, srv_n_autoinc_interval, + PLUGIN_VAR_RQCMDARG, + "the interval of persist max auto increment value,(defualt:1).", + NULL, NULL, 1, 1, 10000, 0); + static MYSQL_SYSVAR_STR(flush_method, innobase_file_flush_method, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "With which method to flush data.", NULL, NULL, NULL); @@ -16591,6 +16611,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(force_load_corrupted), MYSQL_SYSVAR(locks_unsafe_for_binlog), MYSQL_SYSVAR(lock_wait_timeout), + MYSQL_SYSVAR(autoinc_persistent), + MYSQL_SYSVAR(autoinc_persistent_interval), #ifdef UNIV_LOG_ARCHIVE MYSQL_SYSVAR(log_arch_dir), MYSQL_SYSVAR(log_archive), diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 9d0ea66..870e7a9 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5718,7 +5718,7 @@ foreign_fail: dict_table_t* t = ctx->new_table; dict_table_autoinc_lock(t); - dict_table_autoinc_initialize(t, ctx->max_autoinc); + dict_table_autoinc_initialize(t, prebuilt->autoinc_increment, ctx->max_autoinc); dict_table_autoinc_unlock(t); } diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 0d879d7..918f252 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -246,6 +246,23 @@ btr_height_get( mtr_t* mtr) /*!< in/out: mini-transaction */ __attribute__((nonnull, warn_unused_result)); /**************************************************************//** +Gets the auto-inc value from the root node of a tree and x-latches +@return auto-inc value */ +UNIV_INTERN +ulonglong +btr_root_get_auto_inc( +/*=========*/ + dict_table_t* table); /*!< in: dict table */ +/**************************************************************//** +set the auto-inc value to the root node of a tree. +*/ +UNIV_INTERN +void +btr_root_set_auto_inc( +/*=========*/ + dict_table_t* table, /*!< in: table */ + ulonglong value); /*!< in: auto_inc value */ +/**************************************************************//** Gets a buffer page and declares its latching order level. */ UNIV_INLINE buf_block_t* diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index ce709a2..edaac11 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -307,6 +307,7 @@ void dict_table_autoinc_initialize( /*==========================*/ dict_table_t* table, /*!< in/out: table */ + ulonglong increment, /*!< in: auto increment value */ ib_uint64_t value) /*!< in: next value to assign to a row */ __attribute__((nonnull)); /********************************************************************//** @@ -328,6 +329,7 @@ dict_table_autoinc_update_if_greater( /*=================================*/ dict_table_t* table, /*!< in/out: table */ + ulonglong increment, /*!< in: auto increment value */ ib_uint64_t value) /*!< in: value which was assigned to a row */ __attribute__((nonnull)); /********************************************************************//** diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index eb25902..cedd9c1 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -977,6 +977,7 @@ struct dict_table_t{ counter */ ib_uint64_t autoinc;/*!< autoinc counter value to give to the next inserted row */ + ib_uint64_t old_autoinc;/* previous autoinc */ ulong n_waiting_or_granted_auto_inc_locks; /*!< This counter is used to track the number of granted and pending autoinc locks on this diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index c28d148..bcd85ce 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -70,7 +70,8 @@ typedef byte page_header_t; #define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified a record on the page; trx_id_t; defined only in secondary indexes and in the insert buffer - tree */ + tree. in cluster indexes, store table max auto_inc + value. */ #define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page header which are set in a page create */ /*----*/ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 3e35334..a38bb27 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -259,6 +259,8 @@ extern ib_uint64_t srv_log_file_size_requested; extern ulint srv_log_buffer_size; extern ulong srv_flush_log_at_trx_commit; extern uint srv_flush_log_at_timeout; +extern char srv_autoinc_persistent; +extern ulong srv_n_autoinc_interval; extern char srv_adaptive_flushing; /* If this flag is TRUE, then we will load the indexes' (and tables') metadata diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index b753574..93b685e 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1942,7 +1942,8 @@ PageConverter::update_index_page( btr_page_set_index_id( page, m_page_zip_ptr, m_index->m_srv_index->id, 0); - page_set_max_trx_id(block, m_page_zip_ptr, m_trx->id, 0); + if (dict_index_is_sec_or_ibuf(m_index->m_srv_index) && page_is_leaf(page)) + page_set_max_trx_id(block, m_page_zip_ptr, m_trx->id, 0); if (page_is_empty(block->frame)) { @@ -3795,7 +3796,7 @@ row_import_for_mysql( table_name, autoinc); dict_table_autoinc_lock(table); - dict_table_autoinc_initialize(table, autoinc); + dict_table_autoinc_initialize(table, prebuilt->autoinc_increment, autoinc); dict_table_autoinc_unlock(table); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 68c71fa..83deab8 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -4014,7 +4014,7 @@ next_rec: /* Reset auto-increment. */ dict_table_autoinc_lock(table); - dict_table_autoinc_initialize(table, 1); + dict_table_autoinc_initialize(table, 1, 1); dict_table_autoinc_unlock(table); trx_commit_for_mysql(trx); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 4b0de1c..79fa2d3 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -190,6 +190,8 @@ UNIV_INTERN ib_uint64_t srv_log_file_size_requested; UNIV_INTERN ulint srv_log_buffer_size = ULINT_MAX; UNIV_INTERN ulong srv_flush_log_at_trx_commit = 1; UNIV_INTERN uint srv_flush_log_at_timeout = 1; +UNIV_INTERN char srv_autoinc_persistent = FALSE; +UNIV_INTERN ulong srv_n_autoinc_interval = 1; UNIV_INTERN ulong srv_page_size = UNIV_PAGE_SIZE_DEF; UNIV_INTERN ulong srv_page_size_shift = UNIV_PAGE_SIZE_SHIFT_DEF; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index f350252..c6763c8 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2849,6 +2849,33 @@ srv_fts_close(void) } #endif +void +dict_table_persist_autoinc_at_shutdown() +{ + ulint i; + + /* Free the hash elements. We don't remove them from the table + because we are going to destroy the table anyway. */ + for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) { + dict_table_t* table; + + table = static_castHASH_GET_FIRST(dict_sys->table_hash, i); + + while (table) { + dict_table_t* prev_table = table; + + table = static_castHASH_GET_NEXT(name_hash, prev_table); +#ifdef UNIV_DEBUG + ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N); +#endif + /* persist autoinc value when dict table move from dict cache */ + if (prev_table->autoinc > 0) { + btr_root_set_auto_inc(prev_table, prev_table->autoinc); + } + } + } + } + /****************************************************************//** Shuts down the InnoDB database. @return DB_SUCCESS or error code */ @@ -2876,6 +2903,10 @@ innobase_shutdown_for_mysql(void) fts_optimize_end(); } + /* persist autoinc value when normal shutdown */ + if (srv_autoinc_persistent && srv_n_autoinc_interval > 1) + dict_table_persist_autoinc_at_shutdown(); + /* 1. Flush the buffer pool to disk, write the current lsn to the tablespace header(s), and copy all log data to archive. The step 1 is the real InnoDB shutdown. The remaining steps 2 - ...