diff --git sql/handler.h sql/handler.h index cf18c87..b7f84a3 100644 --- sql/handler.h +++ 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 sql/sql_table.cc sql/sql_table.cc index b2f9ee7..5990e1b 100644 --- sql/sql_table.cc +++ 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 storage/innobase/btr/btr0btr.cc storage/innobase/btr/btr0btr.cc index 8666023..17e3224 100644 --- storage/innobase/btr/btr0btr.cc +++ 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,7 @@ 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 +1336,7 @@ 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 +4089,7 @@ 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 storage/innobase/dict/dict0dict.cc storage/innobase/dict/dict0dict.cc index 088eeb9..542cd9a 100644 --- storage/innobase/dict/dict0dict.cc +++ 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 storage/innobase/dict/dict0mem.cc storage/innobase/dict/dict0mem.cc index 60daeea..298ce34 100644 --- storage/innobase/dict/dict0mem.cc +++ 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 storage/innobase/handler/ha_innodb.cc storage/innobase/handler/ha_innodb.cc index 11e47d2..07d6ee6 100644 --- storage/innobase/handler/ha_innodb.cc +++ 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 storage/innobase/handler/handler0alter.cc storage/innobase/handler/handler0alter.cc index 9d0ea66..870e7a9 100644 --- storage/innobase/handler/handler0alter.cc +++ 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 storage/innobase/include/btr0btr.h storage/innobase/include/btr0btr.h index 0d879d7..918f252 100644 --- storage/innobase/include/btr0btr.h +++ 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 storage/innobase/include/dict0dict.h storage/innobase/include/dict0dict.h index ce709a2..edaac11 100644 --- storage/innobase/include/dict0dict.h +++ 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 storage/innobase/include/dict0mem.h storage/innobase/include/dict0mem.h index eb25902..cedd9c1 100644 --- storage/innobase/include/dict0mem.h +++ 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 storage/innobase/include/page0page.h storage/innobase/include/page0page.h index c28d148..bcd85ce 100644 --- storage/innobase/include/page0page.h +++ 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 storage/innobase/include/srv0srv.h storage/innobase/include/srv0srv.h index 3e35334..a38bb27 100644 --- storage/innobase/include/srv0srv.h +++ 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 storage/innobase/row/row0import.cc storage/innobase/row/row0import.cc index b753574..93b685e 100644 --- storage/innobase/row/row0import.cc +++ 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 storage/innobase/row/row0mysql.cc storage/innobase/row/row0mysql.cc index 68c71fa..83deab8 100644 --- storage/innobase/row/row0mysql.cc +++ 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 storage/innobase/srv/srv0srv.cc storage/innobase/srv/srv0srv.cc index 4b0de1c..79fa2d3 100644 --- storage/innobase/srv/srv0srv.cc +++ 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 storage/innobase/srv/srv0start.cc storage/innobase/srv/srv0start.cc index f350252..c6763c8 100644 --- storage/innobase/srv/srv0start.cc +++ 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 - ...