diff options
author | unknown <tsmith@ramayana.hindu.god> | 2007-08-27 18:41:29 -0600 |
---|---|---|
committer | unknown <tsmith@ramayana.hindu.god> | 2007-08-27 18:41:29 -0600 |
commit | 95834a51f4b960f24d3c9366bbfd8aee6c73da4e (patch) | |
tree | 4ea0d53b571ea92d6f4e8f541494cb56da25f9bf /storage | |
parent | 235e75209d1f0f552bfc60d74502124217f8d310 (diff) | |
parent | 61e988e712ed82542ebc1d867a21e71f3103a0f7 (diff) | |
download | mariadb-git-95834a51f4b960f24d3c9366bbfd8aee6c73da4e.tar.gz |
Merge ramayana.hindu.god:/home/tsmith/m/bk/51-target22-X
into ramayana.hindu.god:/home/tsmith/m/bk/maint/51
configure.in:
Auto merged
mysql-test/r/innodb.result:
Auto merged
mysql-test/r/partition_pruning.result:
Auto merged
mysql-test/r/select.result:
Auto merged
mysql-test/suite/rpl/include/rpl_mixed_ddl.inc:
Auto merged
mysql-test/suite/rpl/include/rpl_mixed_dml.inc:
Auto merged
mysql-test/suite/rpl/r/rpl_timezone.result:
Auto merged
mysql-test/suite/rpl/t/rpl_relayspace.test:
Auto merged
mysql-test/suite/rpl/t/rpl_timezone.test:
Auto merged
mysql-test/t/select.test:
Auto merged
netware/BUILD/compile-netware-END:
Auto merged
netware/Makefile.am:
Auto merged
sql/field.cc:
Auto merged
sql/ha_partition.cc:
Auto merged
sql/ha_partition.h:
Auto merged
sql/item.cc:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_view.cc:
Auto merged
sql/time.cc:
Auto merged
storage/innobase/handler/ha_innodb.cc:
Auto merged
storage/innobase/log/log0recv.c:
Auto merged
storage/innobase/srv/srv0srv.c:
Auto merged
storage/innobase/trx/trx0trx.c:
Auto merged
mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result:
manual merge (use remote)
mysql-test/suite/rpl/t/disabled.def:
Manual merge - both rpl_innodb_mixed_ddl and rpl_innodb_mixed_dml
are fixed, and should be run as part of the rpl suite.
Diffstat (limited to 'storage')
26 files changed, 950 insertions, 650 deletions
diff --git a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c index f8849008854..5f9aaf71e18 100644 --- a/storage/innobase/dict/dict0boot.c +++ b/storage/innobase/dict/dict0boot.c @@ -211,6 +211,7 @@ dict_boot(void) dict_table_t* table; dict_index_t* index; dict_hdr_t* dict_hdr; + mem_heap_t* heap; mtr_t mtr; mtr_start(&mtr); @@ -218,6 +219,8 @@ dict_boot(void) /* Create the hash tables etc. */ dict_init(); + heap = mem_heap_create(450); + mutex_enter(&(dict_sys->mutex)); /* Get the dictionary header */ @@ -244,19 +247,20 @@ dict_boot(void) /*-------------------------*/ table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0); - dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "N_COLS", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "MIX_ID", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "MIX_LEN", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "CLUSTER_NAME", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4); table->id = DICT_TABLES_ID; - dict_table_add_to_cache(table); + dict_table_add_to_cache(table, heap); dict_sys->sys_tables = table; + mem_heap_empty(heap); index = dict_mem_index_create("SYS_TABLES", "CLUST_IND", DICT_HDR_SPACE, @@ -283,18 +287,19 @@ dict_boot(void) /*-------------------------*/ table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0); - dict_mem_table_add_col(table, "TABLE_ID", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "MTYPE", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "PRTYPE", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "LEN", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "PREC", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "MTYPE", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "PRTYPE", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "LEN", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "PREC", DATA_INT, 0, 4); table->id = DICT_COLUMNS_ID; - dict_table_add_to_cache(table); + dict_table_add_to_cache(table, heap); dict_sys->sys_columns = table; + mem_heap_empty(heap); index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND", DICT_HDR_SPACE, @@ -311,13 +316,13 @@ dict_boot(void) /*-------------------------*/ table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0); - dict_mem_table_add_col(table, "TABLE_ID", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "N_FIELDS", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "PAGE_NO", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "N_FIELDS", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4); /* The '+ 2' below comes from the 2 system fields */ #if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2 @@ -331,8 +336,9 @@ dict_boot(void) #endif table->id = DICT_INDEXES_ID; - dict_table_add_to_cache(table); + dict_table_add_to_cache(table, heap); dict_sys->sys_indexes = table; + mem_heap_empty(heap); index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND", DICT_HDR_SPACE, @@ -349,13 +355,14 @@ dict_boot(void) /*-------------------------*/ table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0); - dict_mem_table_add_col(table, "INDEX_ID", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4); - dict_mem_table_add_col(table, "COL_NAME", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); + dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0); table->id = DICT_FIELDS_ID; - dict_table_add_to_cache(table); + dict_table_add_to_cache(table, heap); dict_sys->sys_fields = table; + mem_heap_free(heap); index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND", DICT_HDR_SPACE, diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 51146c3c24c..4116230347d 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -960,7 +960,7 @@ dict_create_table_step( if (node->state == TABLE_ADD_TO_CACHE) { - dict_table_add_to_cache(node->table); + dict_table_add_to_cache(node->table, node->heap); err = DB_SUCCESS; } diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index e2a9535dc8b..595dfb06ee5 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -410,14 +410,27 @@ dict_table_get_col_name( ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); s = table->col_names; - - for (i = 0; i < col_nr; i++) { - s += strlen(s) + 1; + if (s) { + for (i = 0; i < col_nr; i++) { + s += strlen(s) + 1; + } } return(s); } + +/************************************************************************ +Acquire the autoinc lock.*/ + +void +dict_table_autoinc_lock( +/*====================*/ + dict_table_t* table) +{ + mutex_enter(&table->autoinc_mutex); +} + /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ @@ -428,54 +441,8 @@ dict_table_autoinc_initialize( dict_table_t* table, /* in: table */ ib_longlong value) /* in: next value to assign to a row */ { - mutex_enter(&(table->autoinc_mutex)); - table->autoinc_inited = TRUE; table->autoinc = value; - - mutex_exit(&(table->autoinc_mutex)); -} - -/************************************************************************ -Gets the next autoinc value (== autoinc counter value), 0 if not yet -initialized. If initialized, increments the counter by 1. */ - -ib_longlong -dict_table_autoinc_get( -/*===================*/ - /* out: value for a new row, or 0 */ - dict_table_t* table) /* in: table */ -{ - ib_longlong value; - - mutex_enter(&(table->autoinc_mutex)); - - if (!table->autoinc_inited) { - - value = 0; - } else { - value = table->autoinc; - table->autoinc = table->autoinc + 1; - } - - mutex_exit(&(table->autoinc_mutex)); - - return(value); -} - -/************************************************************************ -Decrements the autoinc counter value by 1. */ - -void -dict_table_autoinc_decrement( -/*=========================*/ - dict_table_t* table) /* in: table */ -{ - mutex_enter(&(table->autoinc_mutex)); - - table->autoinc = table->autoinc - 1; - - mutex_exit(&(table->autoinc_mutex)); } /************************************************************************ @@ -490,32 +457,6 @@ dict_table_autoinc_read( { ib_longlong value; - mutex_enter(&(table->autoinc_mutex)); - - if (!table->autoinc_inited) { - - value = 0; - } else { - value = table->autoinc; - } - - mutex_exit(&(table->autoinc_mutex)); - - return(value); -} - -/************************************************************************ -Peeks the autoinc counter value, 0 if not yet initialized. Does not -increment the counter. The read not protected by any mutex! */ - -ib_longlong -dict_table_autoinc_peek( -/*====================*/ - /* out: value of the counter */ - dict_table_t* table) /* in: table */ -{ - ib_longlong value; - if (!table->autoinc_inited) { value = 0; @@ -527,7 +468,7 @@ dict_table_autoinc_peek( } /************************************************************************ -Updates the autoinc counter if the value supplied is equal or bigger than the +Updates the autoinc counter if the value supplied is greater than the current value. If not inited, does nothing. */ void @@ -537,15 +478,21 @@ dict_table_autoinc_update( dict_table_t* table, /* in: table */ ib_longlong value) /* in: value which was assigned to a row */ { - mutex_enter(&(table->autoinc_mutex)); + if (table->autoinc_inited && value > table->autoinc) { - if (table->autoinc_inited) { - if (value >= table->autoinc) { - table->autoinc = value + 1; - } + table->autoinc = value; } +} - mutex_exit(&(table->autoinc_mutex)); +/************************************************************************ +Release the autoinc lock.*/ + +void +dict_table_autoinc_unlock( +/*======================*/ + dict_table_t* table) /* in: release autoinc lock for this table */ +{ + mutex_exit(&table->autoinc_mutex); } /************************************************************************ @@ -842,28 +789,18 @@ dict_table_get( } /************************************************************************** -Adds a table object to the dictionary cache. */ +Adds system columns to a table object. */ void -dict_table_add_to_cache( -/*====================*/ - dict_table_t* table) /* in: table */ +dict_table_add_system_columns( +/*==========================*/ + dict_table_t* table, /* in/out: table */ + mem_heap_t* heap) /* in: temporary heap */ { - ulint fold; - ulint id_fold; - ulint i; - ulint row_len; - ut_ad(table); - ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(table->cached == FALSE); - - fold = ut_fold_string(table->name); - id_fold = ut_fold_dulint(table->id); - - table->cached = TRUE; + ut_ad(!table->cached); /* NOTE: the system columns MUST be added in the following order (so that they can be indexed by the numerical value of DATA_ROW_ID, @@ -871,19 +808,19 @@ dict_table_add_to_cache( The clustered index will not always physically contain all system columns. */ - dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS, + dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS, DATA_ROW_ID | DATA_NOT_NULL, DATA_ROW_ID_LEN); #if DATA_ROW_ID != 0 #error "DATA_ROW_ID != 0" #endif - dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS, + dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS, DATA_TRX_ID | DATA_NOT_NULL, DATA_TRX_ID_LEN); #if DATA_TRX_ID != 1 #error "DATA_TRX_ID != 1" #endif - dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS, + dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS, DATA_ROLL_PTR | DATA_NOT_NULL, DATA_ROLL_PTR_LEN); #if DATA_ROLL_PTR != 2 @@ -895,10 +832,34 @@ dict_table_add_to_cache( #if DATA_N_SYS_COLS != 3 #error "DATA_N_SYS_COLS != 3" #endif +} + +/************************************************************************** +Adds a table object to the dictionary cache. */ + +void +dict_table_add_to_cache( +/*====================*/ + dict_table_t* table, /* in: table */ + mem_heap_t* heap) /* in: temporary heap */ +{ + ulint fold; + ulint id_fold; + ulint i; + ulint row_len; /* The lower limit for what we consider a "big" row */ #define BIG_ROW_SIZE 1024 + ut_ad(mutex_own(&(dict_sys->mutex))); + + dict_table_add_system_columns(table, heap); + + table->cached = TRUE; + + fold = ut_fold_string(table->name); + id_fold = ut_fold_dulint(table->id); + row_len = 0; for (i = 0; i < table->n_def; i++) { ulint col_len = dict_col_get_max_size( diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index ba2e25cf031..1ff1fd54cec 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -423,7 +423,8 @@ dict_load_columns( ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC")); - dict_mem_table_add_col(table, name, mtype, prtype, col_len); + dict_mem_table_add_col(table, heap, name, + mtype, prtype, col_len); btr_pcur_move_to_next_user_rec(&pcur, &mtr); } @@ -746,7 +747,7 @@ dict_load_table( ut_ad(mutex_own(&(dict_sys->mutex))); - heap = mem_heap_create(1000); + heap = mem_heap_create(32000); mtr_start(&mtr); @@ -852,7 +853,9 @@ err_exit: dict_load_columns(table, heap); - dict_table_add_to_cache(table); + dict_table_add_to_cache(table, heap); + + mem_heap_empty(heap); dict_load_indexes(table, heap); diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index 9aa49dee745..f4012c11973 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -90,6 +90,15 @@ dict_mem_table_create( mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); table->autoinc_inited = FALSE; + + /* The actual increment value will be set by MySQL, we simply + default to 1 here.*/ + table->autoinc_increment = 1; + + /* The number of transactions that are either waiting on the + AUTOINC lock or have been granted the lock. */ + table->n_waiting_or_granted_auto_inc_locks = 0; + #ifdef UNIV_DEBUG table->magic_n = DICT_TABLE_MAGIC_N; #endif /* UNIV_DEBUG */ @@ -108,18 +117,11 @@ dict_mem_table_free( ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); mutex_free(&(table->autoinc_mutex)); - - if (table->col_names && (table->n_def < table->n_cols)) { - ut_free((void*)table->col_names); - } - mem_heap_free(table->heap); } /******************************************************************** -Add 'name' to end of the col_names array (see dict_table_t::col_names). Call -ut_free on col_names (if not NULL), allocate new array (if heap, from it, -otherwise with ut_malloc), and copy col_names + name to it. */ +Append 'name' to 'col_names' (@see dict_table_t::col_names). */ static const char* dict_add_col_name( @@ -129,21 +131,19 @@ dict_add_col_name( NULL */ ulint cols, /* in: number of existing columns */ const char* name, /* in: new column name */ - mem_heap_t* heap) /* in: heap, or NULL */ + mem_heap_t* heap) /* in: heap */ { - ulint i; - ulint old_len; - ulint new_len; - ulint total_len; - const char* s; - char* res; + ulint old_len; + ulint new_len; + ulint total_len; + char* res; - ut_a(((cols == 0) && !col_names) || ((cols > 0) && col_names)); - ut_a(*name); + ut_ad(!cols == !col_names); /* Find out length of existing array. */ if (col_names) { - s = col_names; + const char* s = col_names; + ulint i; for (i = 0; i < cols; i++) { s += strlen(s) + 1; @@ -157,11 +157,7 @@ dict_add_col_name( new_len = strlen(name) + 1; total_len = old_len + new_len; - if (heap) { - res = mem_heap_alloc(heap, total_len); - } else { - res = ut_malloc(total_len); - } + res = mem_heap_alloc(heap, total_len); if (old_len > 0) { memcpy(res, col_names, old_len); @@ -169,10 +165,6 @@ dict_add_col_name( memcpy(res + old_len, name, new_len); - if (col_names) { - ut_free((char*)col_names); - } - return(res); } @@ -183,7 +175,8 @@ void dict_mem_table_add_col( /*===================*/ dict_table_t* table, /* in: table */ - const char* name, /* in: column name */ + mem_heap_t* heap, /* in: temporary memory heap, or NULL */ + const char* name, /* in: column name, or NULL */ ulint mtype, /* in: main datatype */ ulint prtype, /* in: precise type */ ulint len) /* in: precision */ @@ -191,21 +184,32 @@ dict_mem_table_add_col( dict_col_t* col; ulint mbminlen; ulint mbmaxlen; - mem_heap_t* heap; + ulint i; - ut_ad(table && name); + ut_ad(table); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + ut_ad(!heap == !name); - table->n_def++; + i = table->n_def++; - heap = table->n_def < table->n_cols ? NULL : table->heap; - table->col_names = dict_add_col_name(table->col_names, - table->n_def - 1, - name, heap); + if (name) { + if (UNIV_UNLIKELY(table->n_def == table->n_cols)) { + heap = table->heap; + } + if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) { + /* All preceding column names are empty. */ + char* s = mem_heap_alloc(heap, table->n_def); + memset(s, 0, table->n_def); + table->col_names = s; + } - col = (dict_col_t*) dict_table_get_nth_col(table, table->n_def - 1); + table->col_names = dict_add_col_name(table->col_names, + i, name, heap); + } - col->ind = table->n_def - 1; + col = (dict_col_t*) dict_table_get_nth_col(table, i); + + col->ind = i; col->ord_part = 0; col->mtype = (unsigned int) mtype; @@ -318,7 +322,7 @@ dict_mem_index_add_field( { dict_field_t* field; - ut_ad(index && name); + ut_ad(index); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); index->n_def++; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 05447f75e95..355b924ce4b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -62,12 +62,6 @@ static bool innodb_inited = 0; */ static handlerton *innodb_hton_ptr; -/* Store MySQL definition of 'byte': in Linux it is char while InnoDB -uses unsigned char; the header univ.i which we include next defines -'byte' as a macro which expands to 'unsigned char' */ - -typedef uchar mysql_byte; - #define INSIDE_HA_INNOBASE_CC /* Include necessary InnoDB headers */ @@ -98,11 +92,15 @@ extern "C" { #include "../storage/innobase/include/ha_prototypes.h" } +static const long AUTOINC_OLD_STYLE_LOCKING = 0; +static const long AUTOINC_NEW_STYLE_LOCKING = 1; +static const long AUTOINC_NO_LOCKING = 2; + static long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb, innobase_additional_mem_pool_size, innobase_file_io_threads, innobase_lock_wait_timeout, innobase_force_recovery, - innobase_open_files; + innobase_open_files, innobase_autoinc_lock_mode; static long long innobase_buffer_pool_size, innobase_log_file_size; @@ -148,7 +146,7 @@ static HASH innobase_open_tables; bool nw_panic = FALSE; #endif -static mysql_byte* innobase_get_key(INNOBASE_SHARE *share, size_t *length, +static uchar* innobase_get_key(INNOBASE_SHARE *share, size_t *length, my_bool not_used __attribute__((unused))); static INNOBASE_SHARE *get_share(const char *table_name); static void free_share(INNOBASE_SHARE *share); @@ -1918,6 +1916,8 @@ retry: trx_mark_sql_stat_end(trx); } + trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */ + if (trx->declared_to_be_inside_innodb) { /* Release our possible ticket in the FIFO */ @@ -1931,110 +1931,6 @@ retry: DBUG_RETURN(0); } -#if 0 -/* TODO: put the -MySQL-4.1 functionality back to 5.0. This is needed to get InnoDB Hot Backup -to work. */ - -/********************************************************************* -This is called when MySQL writes the binlog entry for the current -transaction. Writes to the InnoDB tablespace info which tells where the -MySQL binlog entry for the current transaction ended. Also commits the -transaction inside InnoDB but does NOT flush InnoDB log files to disk. -To flush you have to call innobase_commit_complete(). We have separated -flushing to eliminate the bottleneck of LOCK_log in log.cc which disabled -InnoDB's group commit capability. */ -static -int -innobase_report_binlog_offset_and_commit( -/*=====================================*/ - /* out: 0 */ - handlerton *hton, /* in: Innodb handlerton */ - THD* thd, /* in: user thread */ - void* trx_handle, /* in: InnoDB trx handle */ - char* log_file_name, /* in: latest binlog file name */ - my_off_t end_offset) /* in: the offset in the binlog file - up to which we wrote */ -{ - trx_t* trx; - - trx = (trx_t*)trx_handle; - - ut_a(trx != NULL); - - trx->mysql_log_file_name = log_file_name; - trx->mysql_log_offset = (ib_longlong)end_offset; - - trx->flush_log_later = TRUE; - - innobase_commit(hton, thd, TRUE); - - trx->flush_log_later = FALSE; - - return(0); -} - -/*********************************************************************** -This function stores the binlog offset and flushes logs. */ -static -void -innobase_store_binlog_offset_and_flush_log( -/*=======================================*/ - char* binlog_name, /* in: binlog name */ - longlong offset) /* in: binlog offset */ -{ - mtr_t mtr; - - assert(binlog_name != NULL); - - /* Start a mini-transaction */ - mtr_start_noninline(&mtr); - - /* Update the latest MySQL binlog name and offset info - in trx sys header */ - - trx_sys_update_mysql_binlog_offset( - binlog_name, - offset, - TRX_SYS_MYSQL_LOG_INFO, &mtr); - - /* Commits the mini-transaction */ - mtr_commit(&mtr); - - /* Synchronous flush of the log buffer to disk */ - log_buffer_flush_to_disk(); -} - -/********************************************************************* -This is called after MySQL has written the binlog entry for the current -transaction. Flushes the InnoDB log files to disk if required. */ -static -int -innobase_commit_complete( -/*=====================*/ - /* out: 0 */ - THD* thd) /* in: user thread */ -{ - trx_t* trx; - - trx = thd_to_trx(thd); - - if (trx && trx->active_trans) { - - trx->active_trans = 0; - - if (UNIV_UNLIKELY(srv_flush_log_at_trx_commit == 0)) { - - return(0); - } - - trx_commit_complete_for_mysql(trx); - } - - return(0); -} -#endif - /********************************************************************* Rolls back a transaction or the latest SQL statement. */ static @@ -2414,7 +2310,7 @@ ha_innobase::open( upd_and_key_val_buff_len = table->s->reclength + table->s->max_key_length + MAX_REF_PARTS * 3; - if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME), + if (!(uchar*) my_multi_malloc(MYF(MY_WME), &upd_buff, upd_and_key_val_buff_len, &key_val_buff, upd_and_key_val_buff_len, NullS)) { @@ -2848,8 +2744,8 @@ inline uint innobase_read_from_2_little_endian( /*===============================*/ - /* out: value */ - const mysql_byte* buf) /* in: from where to read */ + /* out: value */ + const uchar* buf) /* in: from where to read */ { return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))); } @@ -2865,7 +2761,7 @@ ha_innobase::store_key_val_for_row( char* buff, /* in/out: buffer for the key value (in MySQL format) */ uint buff_len,/* in: buffer length */ - const mysql_byte* record)/* in: row in MySQL format */ + const uchar* record)/* in: row in MySQL format */ { KEY* key_info = table->key_info + keynr; KEY_PART_INFO* key_part = key_info->key_part; @@ -3062,7 +2958,7 @@ ha_innobase::store_key_val_for_row( CHARSET_INFO* cs; ulint true_len; ulint key_len; - const mysql_byte* src_start; + const uchar* src_start; int error=0; enum_field_types real_type; @@ -3342,18 +3238,125 @@ skip_field: } /************************************************************************ +This special handling is really to overcome the limitations of MySQL's +binlogging. We need to eliminate the non-determinism that will arise in +INSERT ... SELECT type of statements, since MySQL binlog only stores the +min value of the autoinc interval. Once that is fixed we can get rid of +the special lock handling.*/ + +ulong +ha_innobase::innobase_autoinc_lock(void) +/*====================================*/ + /* out: DB_SUCCESS if all OK else + error code */ +{ + ulint error = DB_SUCCESS; + + switch (innobase_autoinc_lock_mode) { + case AUTOINC_NO_LOCKING: + /* Acquire only the AUTOINC mutex. */ + dict_table_autoinc_lock(prebuilt->table); + break; + + case AUTOINC_NEW_STYLE_LOCKING: + /* For simple (single/multi) row INSERTs, we fallback to the + old style only if another transaction has already acquired + the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT + etc. type of statement. */ + if (thd_sql_command(user_thd) == SQLCOM_INSERT) { + dict_table_t* table = prebuilt->table; + + /* Acquire the AUTOINC mutex. */ + dict_table_autoinc_lock(table); + + /* We need to check that another transaction isn't + already holding the AUTOINC lock on the table. */ + if (table->n_waiting_or_granted_auto_inc_locks) { + /* Release the mutex to avoid deadlocks. */ + dict_table_autoinc_unlock(table); + } else { + break; + } + } + /* Fall through to old style locking. */ + + case AUTOINC_OLD_STYLE_LOCKING: + error = row_lock_table_autoinc_for_mysql(prebuilt); + + if (error == DB_SUCCESS) { + + /* Acquire the AUTOINC mutex. */ + dict_table_autoinc_lock(prebuilt->table); + } + break; + + default: + ut_error; + } + + return(ulong(error)); +} + +/************************************************************************ +Reset the autoinc value in the table.*/ + +ulong +ha_innobase::innobase_reset_autoinc( +/*================================*/ + /* out: DB_SUCCESS if all went well + else error code */ + ulonglong autoinc) /* in: value to store */ +{ + ulint error; + + error = innobase_autoinc_lock(); + + if (error == DB_SUCCESS) { + + dict_table_autoinc_initialize(prebuilt->table, autoinc); + + dict_table_autoinc_unlock(prebuilt->table); + } + + return(ulong(error)); +} + +/************************************************************************ +Store the autoinc value in the table. The autoinc value is only set if +it's greater than the existing autoinc value in the table.*/ + +ulong +ha_innobase::innobase_set_max_autoinc( +/*==================================*/ + /* out: DB_SUCCES if all went well + else error code */ + ulonglong auto_inc) /* in: value to store */ +{ + ulint error; + + error = innobase_autoinc_lock(); + + if (error == DB_SUCCESS) { + + dict_table_autoinc_update(prebuilt->table, auto_inc); + + dict_table_autoinc_unlock(prebuilt->table); + } + + return(ulong(error)); +} + +/************************************************************************ Stores a row in an InnoDB database, to the table specified in this handle. */ int ha_innobase::write_row( /*===================*/ - /* out: error code */ - mysql_byte* record) /* in: a row in MySQL format */ + /* out: error code */ + uchar* record) /* in: a row in MySQL format */ { - int error; - longlong auto_inc; - longlong dummy; + int error = 0; ibool auto_inc_used= FALSE; ulint sql_command; trx_t* trx = thd_to_trx(user_thd); @@ -3452,62 +3455,20 @@ no_commit: num_write_row++; + /* This is the case where the table has an auto-increment column */ if (table->next_number_field && record == table->record[0]) { - /* This is the case where the table has an - auto-increment column */ - - /* Initialize the auto-inc counter if it has not been - initialized yet */ - if (0 == dict_table_autoinc_peek(prebuilt->table)) { - - /* This call initializes the counter */ - error = innobase_read_and_init_auto_inc(&dummy); - - if (error) { - /* Deadlock or lock wait timeout */ - - goto func_exit; - } - - /* We have to set sql_stat_start to TRUE because - the above call probably has called a select, and - has reset that flag; row_insert_for_mysql has to - know to set the IX intention lock on the table, - something it only does at the start of each - statement */ - - prebuilt->sql_stat_start = TRUE; - } - - /* We have to use the transactional lock mechanism on the - auto-inc counter of the table to ensure that replication and - roll-forward of the binlog exactly imitates also the given - auto-inc values. The lock is released at each SQL statement's - end. This lock also prevents a race where two threads would - call ::get_auto_increment() simultaneously. */ - - error = row_lock_table_autoinc_for_mysql(prebuilt); - - if (error != DB_SUCCESS) { - /* Deadlock or lock wait timeout */ - - error = convert_error_code_to_mysql(error, user_thd); + if ((error = update_auto_increment())) { goto func_exit; } - /* We must use the handler code to update the auto-increment - value to be sure that we increment it correctly. */ - - if ((error= update_auto_increment())) - goto func_exit; - auto_inc_used = 1; - + auto_inc_used = TRUE; } if (prebuilt->mysql_template == NULL - || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) { + || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) { + /* Build the template used in converting quickly between the two database formats */ @@ -3518,40 +3479,64 @@ no_commit: error = row_insert_for_mysql((byte*) record, prebuilt); - if (error == DB_SUCCESS && auto_inc_used) { + /* Handle duplicate key errors */ + if (auto_inc_used) { + ulonglong auto_inc; - /* Fetch the value that was set in the autoincrement field */ + /* Note the number of rows processed for this statement, used + by get_auto_increment() to determine the number of AUTO-INC + values to reserve. This is only useful for a mult-value INSERT + and is a statement level counter.*/ + if (trx->n_autoinc_rows > 0) { + --trx->n_autoinc_rows; + } + /* Get the value that MySQL attempted to store in the table.*/ auto_inc = table->next_number_field->val_int(); - if (auto_inc != 0) { - /* This call will update the counter according to the - value that was inserted in the table */ + switch (error) { + case DB_DUPLICATE_KEY: - dict_table_autoinc_update(prebuilt->table, auto_inc); - } - } + /* A REPLACE command and LOAD DATA INFILE REPLACE + handle a duplicate key error themselves, but we + must update the autoinc counter if we are performing + those statements. */ - /* A REPLACE command and LOAD DATA INFILE REPLACE handle a duplicate - key error themselves, and we must update the autoinc counter if we are - performing those statements. */ + switch (sql_command) { + case SQLCOM_LOAD: + if ((trx->duplicates + & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) { - if (error == DB_DUPLICATE_KEY && auto_inc_used - && (sql_command == SQLCOM_REPLACE - || sql_command == SQLCOM_REPLACE_SELECT - || (sql_command == SQLCOM_INSERT - && ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == TRX_DUP_IGNORE)) - || (sql_command == SQLCOM_LOAD - && ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == (TRX_DUP_IGNORE | TRX_DUP_REPLACE))))) { + goto set_max_autoinc; + } + break; - auto_inc = table->next_number_field->val_int(); + case SQLCOM_REPLACE: + case SQLCOM_INSERT_SELECT: + case SQLCOM_REPLACE_SELECT: + goto set_max_autoinc; + break; - if (auto_inc != 0) { - dict_table_autoinc_update(prebuilt->table, auto_inc); + default: + break; + } + + break; + + case DB_SUCCESS: + /* If the actual value inserted is greater than + the upper limit of the interval, then we try and + update the table upper limit. Note: last_value + will be 0 if get_auto_increment() was not called.*/ + + if (auto_inc > prebuilt->last_value) { +set_max_autoinc: + ut_a(prebuilt->table->autoinc_increment > 0); + auto_inc += prebuilt->table->autoinc_increment; + + innobase_set_max_autoinc(auto_inc); + } + break; } } @@ -3559,8 +3544,6 @@ no_commit: error = convert_error_code_to_mysql(error, user_thd); - /* Tell InnoDB server that there might be work for - utility threads: */ func_exit: innobase_active_small(); @@ -3576,16 +3559,16 @@ calc_row_difference( /*================*/ /* out: error number or 0 */ upd_t* uvect, /* in/out: update vector */ - mysql_byte* old_row, /* in: old row in MySQL format */ - mysql_byte* new_row, /* in: new row in MySQL format */ + uchar* old_row, /* in: old row in MySQL format */ + uchar* new_row, /* in: new row in MySQL format */ struct st_table* table, /* in: table in MySQL data dictionary */ - mysql_byte* upd_buff, /* in: buffer to use */ + uchar* upd_buff, /* in: buffer to use */ ulint buff_len, /* in: buffer length */ row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */ THD* thd) /* in: user thread */ { - mysql_byte* original_upd_buff = upd_buff; + uchar* original_upd_buff = upd_buff; Field* field; enum_field_types field_mysql_type; uint n_fields; @@ -3729,8 +3712,8 @@ int ha_innobase::update_row( /*====================*/ /* out: error number or 0 */ - const mysql_byte* old_row,/* in: old row in MySQL format */ - mysql_byte* new_row)/* in: new row in MySQL format */ + const uchar* old_row, /* in: old row in MySQL format */ + uchar* new_row) /* in: new row in MySQL format */ { upd_t* uvect; int error = 0; @@ -3752,7 +3735,7 @@ ha_innobase::update_row( /* Build an update vector from the modified fields in the rows (uses upd_buff of the handle) */ - calc_row_difference(uvect, (mysql_byte*) old_row, new_row, table, + calc_row_difference(uvect, (uchar*) old_row, new_row, table, upd_buff, (ulint)upd_and_key_val_buff_len, prebuilt, user_thd); @@ -3765,6 +3748,32 @@ ha_innobase::update_row( error = row_update_for_mysql((byte*) old_row, prebuilt); + /* We need to do some special AUTOINC handling for the following case: + + INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ... + + We need to use the AUTOINC counter that was actually used by + MySQL in the UPDATE statement, which can be different from the + value used in the INSERT statement.*/ + + if (error == DB_SUCCESS + && table->next_number_field + && new_row == table->record[0] + && thd_sql_command(user_thd) == SQLCOM_INSERT + && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) + == TRX_DUP_IGNORE) { + + longlong auto_inc; + + auto_inc = table->next_number_field->val_int(); + + if (auto_inc != 0) { + auto_inc += prebuilt->table->autoinc_increment; + + innobase_set_max_autoinc(auto_inc); + } + } + innodb_srv_conc_exit_innodb(trx); error = convert_error_code_to_mysql(error, user_thd); @@ -3783,8 +3792,8 @@ Deletes a row given as the parameter. */ int ha_innobase::delete_row( /*====================*/ - /* out: error number or 0 */ - const mysql_byte* record) /* in: a row in MySQL format */ + /* out: error number or 0 */ + const uchar* record) /* in: a row in MySQL format */ { int error = 0; trx_t* trx = thd_to_trx(user_thd); @@ -3793,6 +3802,30 @@ ha_innobase::delete_row( ut_a(prebuilt->trx == trx); + /* Only if the table has an AUTOINC column */ + if (table->found_next_number_field && record == table->record[0]) { + ulonglong dummy = 0; + + /* First check whether the AUTOINC sub-system has been + initialized using the AUTOINC mutex. If not then we + do it the "proper" way, by acquiring the heavier locks. */ + dict_table_autoinc_lock(prebuilt->table); + + if (!prebuilt->table->autoinc_inited) { + dict_table_autoinc_unlock(prebuilt->table); + + error = innobase_get_auto_increment(&dummy); + + if (error == DB_SUCCESS) { + dict_table_autoinc_unlock(prebuilt->table); + } else { + goto error_exit; + } + } else { + dict_table_autoinc_unlock(prebuilt->table); + } + } + if (!prebuilt->upd_node) { row_get_prebuilt_update_vector(prebuilt); } @@ -3807,6 +3840,7 @@ ha_innobase::delete_row( innodb_srv_conc_exit_innodb(trx); +error_exit: error = convert_error_code_to_mysql(error, user_thd); /* Tell the InnoDB server that there might be work for @@ -4010,9 +4044,9 @@ ha_innobase::index_read( /*====================*/ /* out: 0, HA_ERR_KEY_NOT_FOUND, or error number */ - mysql_byte* buf, /* in/out: buffer for the returned + uchar* buf, /* in/out: buffer for the returned row */ - const mysql_byte* key_ptr,/* in: key value; if this is NULL + const uchar* key_ptr, /* in: key value; if this is NULL we position the cursor at the start or end of index; this can also contain an InnoDB row id, in @@ -4109,54 +4143,78 @@ row with the current key value or prefix. */ int ha_innobase::index_read_last( /*=========================*/ - /* out: 0, HA_ERR_KEY_NOT_FOUND, or an - error code */ - mysql_byte* buf, /* out: fetched row */ - const mysql_byte* key_ptr, /* in: key value, or a prefix of a full - key value */ - uint key_len) /* in: length of the key val or prefix - in bytes */ + /* out: 0, HA_ERR_KEY_NOT_FOUND, or an + error code */ + uchar* buf, /* out: fetched row */ + const uchar* key_ptr,/* in: key value, or a prefix of a full + key value */ + uint key_len)/* in: length of the key val or prefix + in bytes */ { return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST)); } /************************************************************************ -Changes the active index of a handle. */ +Get the index for a handle. Does not change active index.*/ -int -ha_innobase::change_active_index( -/*=============================*/ - /* out: 0 or error code */ - uint keynr) /* in: use this index; MAX_KEY means always clustered - index, even if it was internally generated by - InnoDB */ +dict_index_t* +ha_innobase::innobase_get_index( +/*============================*/ + /* out: NULL or index instance. */ + uint keynr) /* in: use this index; MAX_KEY means always + clustered index, even if it was internally + generated by InnoDB */ { - KEY* key=0; - DBUG_ENTER("change_active_index"); + KEY* key = 0; + dict_index_t* index = 0; + + DBUG_ENTER("innobase_get_index"); ha_statistic_increment(&SSV::ha_read_key_count); ut_ad(user_thd == ha_thd()); ut_a(prebuilt->trx == thd_to_trx(user_thd)); - active_index = keynr; - if (keynr != MAX_KEY && table->s->keys > 0) { - key = table->key_info + active_index; + key = table->key_info + keynr; - prebuilt->index = dict_table_get_index_noninline( + index = dict_table_get_index_noninline( prebuilt->table, key->name); } else { - prebuilt->index = dict_table_get_first_index_noninline( - prebuilt->table); + index = dict_table_get_first_index_noninline(prebuilt->table); } - if (!prebuilt->index) { + if (!index) { sql_print_error( "Innodb could not find key n:o %u with name %s " "from dict cache for table %s", keynr, key ? key->name : "NULL", prebuilt->table->name); + } + + DBUG_RETURN(index); +} + +/************************************************************************ +Changes the active index of a handle. */ + +int +ha_innobase::change_active_index( +/*=============================*/ + /* out: 0 or error code */ + uint keynr) /* in: use this index; MAX_KEY means always clustered + index, even if it was internally generated by + InnoDB */ +{ + DBUG_ENTER("change_active_index"); + + ut_ad(user_thd == ha_thd()); + ut_a(prebuilt->trx == thd_to_trx(user_thd)); + active_index = keynr; + + prebuilt->index = innobase_get_index(keynr); + + if (!prebuilt->index) { DBUG_RETURN(1); } @@ -4187,10 +4245,10 @@ int ha_innobase::index_read_idx( /*========================*/ /* out: error number or 0 */ - mysql_byte* buf, /* in/out: buffer for the returned + uchar* buf, /* in/out: buffer for the returned row */ uint keynr, /* in: use this index */ - const mysql_byte* key, /* in: key value; if this is NULL + const uchar* key, /* in: key value; if this is NULL we position the cursor at the start or end of index */ uint key_len, /* in: key value length */ @@ -4213,7 +4271,7 @@ ha_innobase::general_fetch( /*=======================*/ /* out: 0, HA_ERR_END_OF_FILE, or error number */ - mysql_byte* buf, /* in/out: buffer for next row in MySQL + uchar* buf, /* in/out: buffer for next row in MySQL format */ uint direction, /* in: ROW_SEL_NEXT or ROW_SEL_PREV */ uint match_mode) /* in: 0, ROW_SEL_EXACT, or @@ -4260,7 +4318,7 @@ ha_innobase::index_next( /*====================*/ /* out: 0, HA_ERR_END_OF_FILE, or error number */ - mysql_byte* buf) /* in/out: buffer for next row in MySQL + uchar* buf) /* in/out: buffer for next row in MySQL format */ { ha_statistic_increment(&SSV::ha_read_next_count); @@ -4276,8 +4334,8 @@ ha_innobase::index_next_same( /*=========================*/ /* out: 0, HA_ERR_END_OF_FILE, or error number */ - mysql_byte* buf, /* in/out: buffer for the row */ - const mysql_byte* key, /* in: key value */ + uchar* buf, /* in/out: buffer for the row */ + const uchar* key, /* in: key value */ uint keylen) /* in: key value length */ { ha_statistic_increment(&SSV::ha_read_next_count); @@ -4292,10 +4350,8 @@ positioned using index_read. */ int ha_innobase::index_prev( /*====================*/ - /* out: 0, HA_ERR_END_OF_FILE, or error - number */ - mysql_byte* buf) /* in/out: buffer for previous row in MySQL - format */ + /* out: 0, HA_ERR_END_OF_FILE, or error number */ + uchar* buf) /* in/out: buffer for previous row in MySQL format */ { ha_statistic_increment(&SSV::ha_read_prev_count); @@ -4309,9 +4365,8 @@ corresponding row to buf. */ int ha_innobase::index_first( /*=====================*/ - /* out: 0, HA_ERR_END_OF_FILE, - or error code */ - mysql_byte* buf) /* in/out: buffer for the row */ + /* out: 0, HA_ERR_END_OF_FILE, or error code */ + uchar* buf) /* in/out: buffer for the row */ { int error; @@ -4336,8 +4391,8 @@ corresponding row to buf. */ int ha_innobase::index_last( /*====================*/ - /* out: 0, HA_ERR_END_OF_FILE, or error code */ - mysql_byte* buf) /* in/out: buffer for the row */ + /* out: 0, HA_ERR_END_OF_FILE, or error code */ + uchar* buf) /* in/out: buffer for the row */ { int error; @@ -4406,7 +4461,7 @@ int ha_innobase::rnd_next( /*==================*/ /* out: 0, HA_ERR_END_OF_FILE, or error number */ - mysql_byte* buf)/* in/out: returns the row in this buffer, + uchar* buf) /* in/out: returns the row in this buffer, in MySQL format */ { int error; @@ -4433,14 +4488,12 @@ Fetches a row from the table based on a row reference. */ int ha_innobase::rnd_pos( /*=================*/ - /* out: 0, HA_ERR_KEY_NOT_FOUND, - or error code */ - mysql_byte* buf, /* in/out: buffer for the row */ - mysql_byte* pos) /* in: primary key value of the row in the - MySQL format, or the row id if the clustered - index was internally generated by InnoDB; - the length of data in pos has to be - ref_length */ + /* out: 0, HA_ERR_KEY_NOT_FOUND, or error code */ + uchar* buf, /* in/out: buffer for the row */ + uchar* pos) /* in: primary key value of the row in the + MySQL format, or the row id if the clustered + index was internally generated by InnoDB; the + length of data in pos has to be ref_length */ { int error; uint keynr = active_index; @@ -4493,7 +4546,7 @@ was positioned the last time. */ void ha_innobase::position( /*==================*/ - const mysql_byte* record) /* in: row in MySQL format */ + const uchar* record) /* in: row in MySQL format */ { uint len; @@ -4635,7 +4688,7 @@ create_table_def( } } - dict_mem_table_add_col(table, + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, dtype_form_prtype( @@ -4999,7 +5052,10 @@ ha_innobase::create( maximum value in the column. */ 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_unlock(innobase_table); } /* Tell the InnoDB server that there might be work for @@ -5350,7 +5406,7 @@ ha_innobase::records_in_range( { KEY* key; dict_index_t* index; - mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc( + uchar* key_val_buff2 = (uchar*) my_malloc( table->s->reclength + table->s->max_key_length + 100, MYF(MY_FAE)); @@ -5392,7 +5448,7 @@ ha_innobase::records_in_range( (ulint)upd_and_key_val_buff_len, index, (byte*) (min_key ? min_key->key : - (const mysql_byte*) 0), + (const uchar*) 0), (ulint) (min_key ? min_key->length : 0), prebuilt->trx); @@ -5400,7 +5456,7 @@ ha_innobase::records_in_range( range_end, (byte*) key_val_buff2, buff2_len, index, (byte*) (max_key ? max_key->key : - (const mysql_byte*) 0), + (const uchar*) 0), (ulint) (max_key ? max_key->length : 0), prebuilt->trx); @@ -6800,12 +6856,12 @@ bool innobase_show_status(handlerton *hton, THD* thd, locking. ****************************************************************************/ -static mysql_byte* innobase_get_key(INNOBASE_SHARE* share, size_t *length, +static uchar* innobase_get_key(INNOBASE_SHARE* share, size_t *length, my_bool not_used __attribute__((unused))) { *length=share->table_name_length; - return (mysql_byte*) share->table_name; + return (uchar*) share->table_name; } static INNOBASE_SHARE* get_share(const char* table_name) @@ -6815,7 +6871,7 @@ static INNOBASE_SHARE* get_share(const char* table_name) uint length=(uint) strlen(table_name); if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables, - (mysql_byte*) table_name, + (uchar*) table_name, length))) { share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1, @@ -6826,7 +6882,7 @@ static INNOBASE_SHARE* get_share(const char* table_name) strmov(share->table_name,table_name); if (my_hash_insert(&innobase_open_tables, - (mysql_byte*) share)) { + (uchar*) share)) { pthread_mutex_unlock(&innobase_share_mutex); my_free(share,0); @@ -6848,7 +6904,7 @@ static void free_share(INNOBASE_SHARE* share) pthread_mutex_lock(&innobase_share_mutex); if (!--share->use_count) { - hash_delete(&innobase_open_tables, (mysql_byte*) share); + hash_delete(&innobase_open_tables, (uchar*) share); thr_lock_delete(&share->lock); pthread_mutex_destroy(&share->mutex); my_free(share, MYF(0)); @@ -7069,15 +7125,15 @@ the value of the auto-inc counter. */ int ha_innobase::innobase_read_and_init_auto_inc( /*=========================================*/ - /* out: 0 or error code: deadlock or lock wait - timeout */ - longlong* ret) /* out: auto-inc value */ + /* out: 0 or error code: + deadlock or lock wait timeout */ + longlong* value) /* out: the autoinc value */ { longlong auto_inc; - ulint old_select_lock_type; - ibool trx_was_not_started = FALSE; ibool stmt_start; - int error; + int mysql_error = 0; + dict_table_t* innodb_table = prebuilt->table; + ibool trx_was_not_started = FALSE; ut_a(prebuilt); ut_a(prebuilt->table); @@ -7098,103 +7154,47 @@ ha_innobase::innobase_read_and_init_auto_inc( trx_search_latch_release_if_reserved(prebuilt->trx); - auto_inc = dict_table_autoinc_read(prebuilt->table); - - if (auto_inc != 0) { - /* Already initialized */ - *ret = auto_inc; - - error = 0; - - goto func_exit_early; - } + dict_table_autoinc_lock(prebuilt->table); - error = row_lock_table_autoinc_for_mysql(prebuilt); - - if (error != DB_SUCCESS) { - error = convert_error_code_to_mysql(error, user_thd); - - goto func_exit_early; - } - - /* Check again if someone has initialized the counter meanwhile */ auto_inc = dict_table_autoinc_read(prebuilt->table); - if (auto_inc != 0) { - *ret = auto_inc; - - error = 0; - - goto func_exit_early; + /* Was the AUTOINC counter reset during normal processing, if + so then we simply start count from 1. No need to go to the index.*/ + if (auto_inc == 0 && innodb_table->autoinc_inited) { + ++auto_inc; + dict_table_autoinc_initialize(innodb_table, auto_inc); } - (void) extra(HA_EXTRA_KEYREAD); - index_init(table->s->next_number_index, 1); + if (auto_inc == 0) { + dict_index_t* index; + ulint error = DB_SUCCESS; + const char* autoinc_col_name; - /* Starting from 5.0.9, we use a consistent read to read the auto-inc - column maximum value. This eliminates the spurious deadlocks caused - by the row X-lock that we previously used. Note the following flaw - in our algorithm: if some other user meanwhile UPDATEs the auto-inc - column, our consistent read will not return the largest value. We - accept this flaw, since the deadlocks were a bigger trouble. */ + ut_a(!innodb_table->autoinc_inited); - /* Fetch all the columns in the key */ + index = innobase_get_index(table->s->next_number_index); - prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; - - old_select_lock_type = prebuilt->select_lock_type; - prebuilt->select_lock_type = LOCK_NONE; - - /* Eliminate an InnoDB error print that happens when we try to SELECT - from a table when no table has been locked in ::external_lock(). */ - prebuilt->trx->n_mysql_tables_in_use++; - - error = index_last(table->record[1]); + autoinc_col_name = table->found_next_number_field->field_name; - prebuilt->trx->n_mysql_tables_in_use--; - prebuilt->select_lock_type = old_select_lock_type; + error = row_search_max_autoinc( + index, autoinc_col_name, &auto_inc); - if (error) { - if (error == HA_ERR_END_OF_FILE) { - /* The table was empty, initialize to 1 */ - auto_inc = 1; - - error = 0; + if (error == DB_SUCCESS) { + ++auto_inc; + dict_table_autoinc_initialize(innodb_table, auto_inc); } else { - /* This should not happen in a consistent read */ - sql_print_error("Consistent read of auto-inc column " - "returned %lu", (ulong) error); - auto_inc = -1; + fprintf(stderr, " InnoDB error: Couldn't read the " + "max AUTOINC value from index (%s).\n", + index->name); - goto func_exit; + mysql_error = 1; } - } else { - /* Initialize to max(col) + 1; we use - 'found_next_number_field' below because MySQL in SHOW TABLE - STATUS does not seem to set 'next_number_field'. The comment - in table.h says that 'next_number_field' is set when it is - 'active'. - Since 5.1 MySQL enforces that we announce fields which we will - read; as we only do a val_*() call, dbug_tmp_use_all_columns() - with read_set is sufficient. */ - - my_bitmap_map *old_map; - old_map= dbug_tmp_use_all_columns(table, table->read_set); - auto_inc = (longlong) table->found_next_number_field-> - val_int_offset(table->s->rec_buff_length) + 1; - dbug_tmp_restore_column_map(table->read_set, old_map); } - dict_table_autoinc_initialize(prebuilt->table, auto_inc); - -func_exit: - (void) extra(HA_EXTRA_NO_KEYREAD); + *value = auto_inc; - index_end(); + dict_table_autoinc_unlock(prebuilt->table); - *ret = auto_inc; - -func_exit_early: /* Since MySQL does not seem to call autocommit after SHOW TABLE STATUS (even if we would register the trx here), we commit our transaction here if it was started here. This is to eliminate a @@ -7209,6 +7209,63 @@ func_exit_early: prebuilt->sql_stat_start = stmt_start; + return(mysql_error); +} + +/******************************************************************************* +Read the next autoinc value, initialize the table if it's not initialized. +On return if there is no error then the tables AUTOINC lock is locked.*/ + +ulong +ha_innobase::innobase_get_auto_increment( + ulonglong* value) /* out: autoinc value */ +{ + ulint error; + + do { + error = innobase_autoinc_lock(); + + if (error == DB_SUCCESS) { + ib_longlong autoinc; + + /* Determine the first value of the interval */ + autoinc = dict_table_autoinc_read(prebuilt->table); + + /* We need to initialize the AUTO-INC value, for + that we release all locks.*/ + if (autoinc <= 0) { + trx_t* trx; + + trx = prebuilt->trx; + dict_table_autoinc_unlock(prebuilt->table); + + if (trx->auto_inc_lock) { + /* If we had reserved the AUTO-INC + lock in this SQL statement we release + it before retrying.*/ + row_unlock_table_autoinc_for_mysql(trx); + } + + /* Just to make sure */ + ut_a(!trx->auto_inc_lock); + + int mysql_error; + + mysql_error = innobase_read_and_init_auto_inc( + &autoinc); + + if (!mysql_error) { + /* Should have read the proper value */ + ut_a(autoinc > 0); + } else { + error = DB_ERROR; + } + } else { + *value = (ulonglong) autoinc; + } + } + } while (*value == 0 && error == DB_SUCCESS); + return(error); } @@ -7220,37 +7277,98 @@ auto-inc counter in *first_value, and ULONGLONG_MAX in *nb_reserved_values (as we have a table-level lock). offset, increment, nb_desired_values are ignored. *first_value is set to -1 if error (deadlock or lock wait timeout) */ -void ha_innobase::get_auto_increment( +void +ha_innobase::get_auto_increment( /*=================================*/ - ulonglong offset, /* in */ - ulonglong increment, /* in */ - ulonglong nb_desired_values, /* in */ - ulonglong *first_value, /* out */ - ulonglong *nb_reserved_values) /* out */ + ulonglong offset, /* in: */ + ulonglong increment, /* in: table autoinc increment */ + ulonglong nb_desired_values, /* in: number of values reqd */ + ulonglong *first_value, /* out: the autoinc value */ + ulonglong *nb_reserved_values) /* out: count of reserved values */ { - longlong nr; - int error; + ulint error; + ulonglong autoinc = 0; /* Prepare prebuilt->trx in the table handle */ update_thd(ha_thd()); - error = innobase_read_and_init_auto_inc(&nr); + error = innobase_get_auto_increment(&autoinc); - if (error) { - /* This should never happen in the current (5.0.6) code, since - we call this function only after the counter has been - initialized. */ + if (error != DB_SUCCESS) { + /* This should never happen in the code > ver 5.0.6, + since we call this function only after the counter + has been initialized. */ ut_print_timestamp(stderr); - sql_print_error("Error %lu in ::get_auto_increment()", - (ulong) error); - *first_value= (~(ulonglong) 0); + sql_print_error("Error %lu in ::get_auto_increment()", error); + + *first_value = (~(ulonglong) 0); return; } - *first_value= (ulonglong) nr; - /* table-level autoinc lock reserves up to +inf */ - *nb_reserved_values= ULONGLONG_MAX; + /* This is a hack, since nb_desired_values seems to be accurate only + for the first call to get_auto_increment() for multi-row INSERT and + meaningless for other statements e.g, LOAD etc. Subsequent calls to + this method for the same statement results in different values which + don't make sense. Therefore we store the value the first time we are + called and count down from that as rows are written (see write_row()). + + We make one exception, if the *first_value is precomputed by MySQL + we use that value. And set the number of reserved values to 1 if + this is the first time we were called for the SQL statement, this + will force MySQL to call us for the next value. If we are in the + middle of a multi-row insert we preserve the existing counter.*/ + if (*first_value == 0) { + + /* Called for the first time ? */ + if (prebuilt->trx->n_autoinc_rows == 0) { + + prebuilt->trx->n_autoinc_rows = nb_desired_values; + + /* It's possible for nb_desired_values to be 0: + e.g., INSERT INTO T1(C) SELECT C FROM T2; */ + if (nb_desired_values == 0) { + + ++prebuilt->trx->n_autoinc_rows; + } + } + + *first_value = autoinc; + + } else if (prebuilt->trx->n_autoinc_rows == 0) { + + prebuilt->trx->n_autoinc_rows = 1; + } + + ut_a(prebuilt->trx->n_autoinc_rows > 0); + + *nb_reserved_values = prebuilt->trx->n_autoinc_rows; + + /* With old style AUTOINC locking we only update the table's + AUTOINC counter after attempting to insert the row. */ + if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) { + + /* Compute the last value in the interval */ + prebuilt->last_value = *first_value + + (*nb_reserved_values * increment); + + ut_a(prebuilt->last_value >= *first_value); + + /* Update the table autoinc variable */ + dict_table_autoinc_update( + prebuilt->table, prebuilt->last_value); + } else { + /* This will force write_row() into attempting an update + of the table's AUTOINC counter. */ + prebuilt->last_value = 0; + } + + /* The increment to be used to increase the AUTOINC value, we use + this in write_row() and update_row() to increase the autoinc counter + for columns that are filled by the user.*/ + prebuilt->table->autoinc_increment = increment; + + dict_table_autoinc_unlock(prebuilt->table); } /* See comment in handler.h */ @@ -7271,7 +7389,7 @@ ha_innobase::reset_auto_increment(ulonglong value) DBUG_RETURN(error); } - dict_table_autoinc_initialize(prebuilt->table, value); + innobase_reset_autoinc(value); DBUG_RETURN(0); } @@ -7298,9 +7416,9 @@ ha_innobase::cmp_ref( /*=================*/ /* out: < 0 if ref1 < ref2, 0 if equal, else > 0 */ - const mysql_byte* ref1, /* in: an (internal) primary key value in the + const uchar* ref1, /* in: an (internal) primary key value in the MySQL key value format */ - const mysql_byte* ref2) /* in: an (internal) primary key value in the + const uchar* ref2) /* in: an (internal) primary key value in the MySQL key value format */ { enum_field_types mysql_type; @@ -7557,6 +7675,7 @@ innobase_xa_prepare( row_unlock_table_autoinc_for_mysql(trx); } + /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement */ @@ -7905,6 +8024,17 @@ static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, "Path to individual files and their sizes.", NULL, NULL, NULL); +static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode, + PLUGIN_VAR_RQCMDARG, + "The AUTOINC lock modes supported by InnoDB:\n" + " 0 => Old style AUTOINC locking (for backward compatibility)\n" + " 1 => New style AUTOINC locking\n" + " 2 => No AUTOINC locking (unsafe for SBR)", + NULL, NULL, + AUTOINC_NEW_STYLE_LOCKING, /* Default setting */ + AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */ + AUTOINC_NO_LOCKING, 0); /* Maximum value */ + static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(autoextend_increment), @@ -7943,6 +8073,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(table_locks), MYSQL_SYSVAR(thread_concurrency), MYSQL_SYSVAR(thread_sleep_delay), + MYSQL_SYSVAR(autoinc_lock_mode), NULL }; diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 270b000dfc4..fe5ebd57990 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -32,7 +32,10 @@ typedef struct st_innobase_share { } INNOBASE_SHARE; +struct dict_index_struct; struct row_prebuilt_struct; + +typedef struct dict_index_struct dict_index_t; typedef struct row_prebuilt_struct row_prebuilt_t; /* The class defining a handle to an Innodb table */ @@ -70,6 +73,11 @@ class ha_innobase: public handler int change_active_index(uint keynr); int general_fetch(uchar* buf, uint direction, uint match_mode); int innobase_read_and_init_auto_inc(longlong* ret); + ulong innobase_autoinc_lock(); + ulong innobase_set_max_autoinc(ulonglong auto_inc); + ulong innobase_reset_autoinc(ulonglong auto_inc); + ulong innobase_get_auto_increment(ulonglong* value); + dict_index_t* innobase_get_index(uint keynr); /* Init values for the class: */ public: diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 4e291924e0e..44972356304 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -462,7 +462,8 @@ ibuf_data_init_for_space( page_t* root; page_t* header_page; mtr_t mtr; - char buf[50]; + char* buf; + mem_heap_t* heap; dict_table_t* table; dict_index_t* index; ulint n_used; @@ -516,16 +517,20 @@ ibuf_data_init_for_space( ibuf_exit(); + heap = mem_heap_create(450); + buf = mem_heap_alloc(heap, 50); + sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space); /* use old-style record format for the insert buffer */ table = dict_mem_table_create(buf, space, 2, 0); - dict_mem_table_add_col(table, "PAGE_NO", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, "TYPES", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_BINARY, 0, 0); + dict_mem_table_add_col(table, heap, "TYPES", DATA_BINARY, 0, 0); table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space); - dict_table_add_to_cache(table); + dict_table_add_to_cache(table, heap); + mem_heap_free(heap); index = dict_mem_index_create( buf, "CLUST_IND", space, @@ -1139,7 +1144,7 @@ ibuf_dummy_index_add_col( ulint len) /* in: length of the column */ { ulint i = index->table->n_def; - dict_mem_table_add_col(index->table, "DUMMY", + dict_mem_table_add_col(index->table, NULL, NULL, dtype_get_mtype(type), dtype_get_prtype(type), dtype_get_len(type)); @@ -1161,11 +1166,6 @@ ibuf_dummy_index_free( dict_mem_table_free(table); } -void -dict_index_print_low( -/*=================*/ - dict_index_t* index); /* in: index */ - /************************************************************************* Builds the entry to insert into a non-clustered index when we have the corresponding record in an ibuf index. */ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index eb31043ecc3..2f038b21e8e 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -171,6 +171,13 @@ dict_col_name_is_reserved( /* out: TRUE if name is reserved */ const char* name); /* in: column name */ /************************************************************************ +Acquire the autoinc lock.*/ + +void +dict_table_autoinc_lock( +/*====================*/ + dict_table_t* table); /* in: table */ +/************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ @@ -180,22 +187,6 @@ dict_table_autoinc_initialize( dict_table_t* table, /* in: table */ ib_longlong value); /* in: next value to assign to a row */ /************************************************************************ -Gets the next autoinc value (== autoinc counter value), 0 if not yet -initialized. If initialized, increments the counter by 1. */ - -ib_longlong -dict_table_autoinc_get( -/*===================*/ - /* out: value for a new row, or 0 */ - dict_table_t* table); /* in: table */ -/************************************************************************ -Decrements the autoinc counter value by 1. */ - -void -dict_table_autoinc_decrement( -/*=========================*/ - dict_table_t* table); /* in: table */ -/************************************************************************ Reads the next autoinc value (== autoinc counter value), 0 if not yet initialized. */ @@ -205,15 +196,6 @@ dict_table_autoinc_read( /* out: value for a new row, or 0 */ dict_table_t* table); /* in: table */ /************************************************************************ -Peeks the autoinc counter value, 0 if not yet initialized. Does not -increment the counter. The read not protected by any mutex! */ - -ib_longlong -dict_table_autoinc_peek( -/*====================*/ - /* out: value of the counter */ - dict_table_t* table); /* in: table */ -/************************************************************************ Updates the autoinc counter if the value supplied is equal or bigger than the current value. If not inited, does nothing. */ @@ -223,13 +205,29 @@ dict_table_autoinc_update( dict_table_t* table, /* in: table */ ib_longlong value); /* in: value which was assigned to a row */ +/************************************************************************ +Release the autoinc lock.*/ + +void +dict_table_autoinc_unlock( +/*======================*/ + dict_table_t* table); /* in: table */ +/************************************************************************** +Adds system columns to a table object. */ + +void +dict_table_add_system_columns( +/*==========================*/ + dict_table_t* table, /* in/out: table */ + mem_heap_t* heap); /* in: temporary heap */ /************************************************************************** Adds a table object to the dictionary cache. */ void dict_table_add_to_cache( /*====================*/ - dict_table_t* table); /* in: table */ + dict_table_t* table, /* in: table */ + mem_heap_t* heap); /* in: temporary heap */ /************************************************************************** Removes a table object from the dictionary cache. */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 647035c2fff..a05bc513efd 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -72,7 +72,8 @@ void dict_mem_table_add_col( /*===================*/ dict_table_t* table, /* in: table */ - const char* name, /* in: column name */ + mem_heap_t* heap, /* in: temporary memory heap, or NULL */ + const char* name, /* in: column name, or NULL */ ulint mtype, /* in: main datatype */ ulint prtype, /* in: precise type */ ulint len); /* in: precision */ @@ -314,11 +315,11 @@ struct dict_table_struct{ unsigned n_cols:10;/* number of columns */ dict_col_t* cols; /* array of column descriptions */ const char* col_names; - /* n_def column names packed in an - "name1\0name2\0...nameN\0" array. until - n_def reaches n_cols, this is allocated with - ut_malloc, and the final size array is - allocated through the table's heap. */ + /* Column names packed in a character string + "name1\0name2\0...nameN\0". Until + the string contains n_cols, it will be + allocated from a temporary heap. The final + string will be allocated from table->heap. */ hash_node_t name_hash; /* hash chain node */ hash_node_t id_hash; /* hash chain node */ UT_LIST_BASE_NODE_T(dict_index_t) @@ -410,6 +411,21 @@ struct dict_table_struct{ SELECT MAX(auto inc column) */ ib_longlong autoinc;/* autoinc counter value to give to the next inserted row */ + + ib_longlong autoinc_increment; + /* The increment step of the auto increment + column. Value must be greater than or equal + to 1 */ + ulong n_waiting_or_granted_auto_inc_locks; + /* This counter is used to track the number + of granted and pending autoinc locks on this + table. This value is set after acquiring the + kernel mutex but we peek the contents to + determine whether other transactions have + acquired the AUTOINC lock or not. Of course + only one transaction can be granted the + lock but there can be multiple waiters. */ + #ifdef UNIV_DEBUG ulint magic_n;/* magic number */ # define DICT_TABLE_MAGIC_N 76333786 diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 059c459c374..8b08b6284f6 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -609,7 +609,7 @@ lock_validate(void); /* out: TRUE if ok */ /************************************************************************* Return approximate number or record locks (bits set in the bitmap) for -this transaction. Since delete-marked records maybe removed, the +this transaction. Since delete-marked records may be removed, the record count will not be precise. */ ulint diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic index e59443da73d..adae9ad8a33 100644 --- a/storage/innobase/include/mem0mem.ic +++ b/storage/innobase/include/mem0mem.ic @@ -271,15 +271,19 @@ mem_heap_free_heap_top( ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); /* In the debug version erase block from top up */ - - mem_erase_buf(old_top, (byte*)block + block->len - old_top); + { + ulint len = (byte*)block + block->len - old_top; + mem_erase_buf(old_top, len); + UNIV_MEM_FREE(old_top, len); + } /* Update allocated memory count */ mutex_enter(&mem_hash_mutex); mem_current_allocated_memory -= (total_size - size); mutex_exit(&mem_hash_mutex); - -#endif +#else /* UNIV_MEM_DEBUG */ + UNIV_MEM_FREE(old_top, (byte*)block + block->len - old_top); +#endif /* UNIV_MEM_DEBUG */ /* If free == start, we may free the block if it is not the first one */ diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 1448efe94fe..aabb7f5f047 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -670,6 +670,7 @@ struct row_prebuilt_struct { to this heap */ mem_heap_t* old_vers_heap; /* memory heap where a previous version is built in consistent read */ + ulonglong last_value; /* last value of AUTO-INC interval */ ulint magic_n2; /* this should be the same as magic_n */ }; diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h index 96273a18cd5..4bde648f18e 100644 --- a/storage/innobase/include/row0sel.h +++ b/storage/innobase/include/row0sel.h @@ -171,7 +171,17 @@ row_search_check_if_query_cache_permitted( trx_t* trx, /* in: transaction object */ const char* norm_name); /* in: concatenation of database name, '/' char, table name */ +/*********************************************************************** +Read the max AUTOINC value from an index. */ +ulint +row_search_max_autoinc( +/*===================*/ + /* out: DB_SUCCESS if all OK else + error code */ + dict_index_t* index, /* in: index to search */ + const char* col_name, /* in: autoinc column name */ + ib_longlong* value); /* out: AUTOINC value read */ /* A structure for caching column values for prefetched rows */ struct sel_buf_struct{ diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index f8b5367739a..b41593d0a96 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -231,7 +231,7 @@ rw_lock_s_lock_func( owns an s-lock here, it may end up in a deadlock with another thread which requests an x-lock here. Therefore, we will forbid recursive s-locking of a latch: the following assert will warn the programmer - of the possibility of a tjis kind of deadlock. If we want to implement + of the possibility of this kind of a deadlock. If we want to implement safe recursive s-locking, we should keep in a list the thread ids of the threads which have s-locked a latch. This would use some CPU time. */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 2459e76c4c1..5017c15aaf0 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -482,31 +482,6 @@ struct trx_struct{ ib_longlong mysql_log_offset;/* if MySQL binlog is used, this field contains the end offset of the binlog entry */ - const char* mysql_master_log_file_name; - /* if the database server is a MySQL - replication slave, we have here the - master binlog name up to which - replication has processed; otherwise - this is a pointer to a null - character */ - ib_longlong mysql_master_log_pos; - /* if the database server is a MySQL - replication slave, this is the - position in the log file up to which - replication has processed */ - /* A MySQL variable mysql_thd->synchronous_repl tells if we have - to use synchronous replication. See ha_innodb.cc. */ - char* repl_wait_binlog_name;/* NULL, or if synchronous MySQL - replication is used, the binlog name - up to which we must communicate the - binlog to the slave, before returning - from a commit; this is the same as - mysql_log_file_name, but we allocate - and copy the name to a separate buffer - here */ - ib_longlong repl_wait_binlog_pos;/* see above at - repl_wait_binlog_name */ - os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated with this transaction object */ ulint mysql_process_no;/* since in Linux, 'top' reports @@ -681,6 +656,9 @@ struct trx_struct{ trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log records which are currently processed by a rollback operation */ + ulint n_autoinc_rows; /* no. of AUTO-INC rows required for + an SQL statement. This is useful for + multi-row INSERTs */ /*------------------------------*/ char detailed_error[256]; /* detailed error message for last error, or empty. */ diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index 90c16f4fad5..e56895bc142 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -63,7 +63,7 @@ ut_test_malloc( /* out: TRUE if succeeded */ ulint n); /* in: try to allocate this many bytes */ /************************************************************************** -Frees a memory bloock allocated with ut_malloc. */ +Frees a memory block allocated with ut_malloc. */ void ut_free( diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index f43752fb5fc..39cbf83e58e 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -3386,6 +3386,10 @@ lock_table_create( ut_ad(table && trx); ut_ad(mutex_own(&kernel_mutex)); + if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) { + ++table->n_waiting_or_granted_auto_inc_locks; + } + if (type_mode == LOCK_AUTO_INC) { /* Only one trx can have the lock on the table at a time: we may use the memory preallocated @@ -3436,6 +3440,9 @@ lock_table_remove_low( if (lock == trx->auto_inc_lock) { trx->auto_inc_lock = NULL; + + ut_a(table->n_waiting_or_granted_auto_inc_locks > 0); + --table->n_waiting_or_granted_auto_inc_locks; } UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock); diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index ce2fc3ed535..aef58b7b576 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -115,7 +115,7 @@ dulint recv_max_page_lsn; Initialize crash recovery environment. Can be called iff recv_needed_recovery == FALSE. */ static -void +void recv_init_crash_recovery(void); /*===========================*/ @@ -2450,7 +2450,7 @@ void recv_init_crash_recovery(void) /*==========================*/ { - ut_a(!recv_needed_recovery); + ut_a(!recv_needed_recovery); recv_needed_recovery = TRUE; @@ -2481,7 +2481,6 @@ recv_init_crash_recovery(void) "InnoDB: buffer...\n"); trx_sys_doublewrite_init_or_restore_pages(TRUE); } - } /************************************************************ @@ -2805,7 +2804,7 @@ recv_recovery_from_checkpoint_start( recv_synchronize_groups(up_to_date_group); if (!recv_needed_recovery) { - ut_a(ut_dulint_cmp(checkpoint_lsn, + ut_a(ut_dulint_cmp(checkpoint_lsn, recv_sys->recovered_lsn) == 0); } else { diff --git a/storage/innobase/mtr/mtr0log.c b/storage/innobase/mtr/mtr0log.c index f9704dc2d20..e5d572bbfa7 100644 --- a/storage/innobase/mtr/mtr0log.c +++ b/storage/innobase/mtr/mtr0log.c @@ -517,8 +517,9 @@ mlog_parse_index( n = mach_read_from_2(ptr); ptr += 2; n_uniq = mach_read_from_2(ptr); + ptr += 2; ut_ad(n_uniq <= n); - if (end_ptr < ptr + (n + 1) * 2) { + if (end_ptr < ptr + n * 2) { return(NULL); } } else { @@ -531,18 +532,18 @@ mlog_parse_index( ind->table = table; ind->n_uniq = (unsigned int) n_uniq; if (n_uniq != n) { + ut_a(n_uniq + DATA_ROLL_PTR <= n); ind->type = DICT_CLUSTERED; } - /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ - ind->cached = TRUE; if (comp) { for (i = 0; i < n; i++) { - ulint len = mach_read_from_2(ptr += 2); + ulint len = mach_read_from_2(ptr); + ptr += 2; /* The high-order bit of len is the NOT NULL flag; the rest is 0 or 0x7fff for variable-length fields, and 1..0x7ffe for fixed-length fields. */ dict_mem_table_add_col( - table, "DUMMY", + table, NULL, NULL, ((len + 1) & 0x7fff) <= 1 ? DATA_BINARY : DATA_FIXBINARY, len & 0x8000 ? DATA_NOT_NULL : 0, @@ -552,8 +553,23 @@ mlog_parse_index( dict_table_get_nth_col(table, i), 0); } - ptr += 2; + dict_table_add_system_columns(table, table->heap); + if (n_uniq != n) { + /* Identify DB_TRX_ID and DB_ROLL_PTR in the index. */ + ut_a(DATA_TRX_ID_LEN + == dict_index_get_nth_col(ind, DATA_TRX_ID - 1 + + n_uniq)->len); + ut_a(DATA_ROLL_PTR_LEN + == dict_index_get_nth_col(ind, DATA_ROLL_PTR - 1 + + n_uniq)->len); + ind->fields[DATA_TRX_ID - 1 + n_uniq].col + = &table->cols[n + DATA_TRX_ID]; + ind->fields[DATA_ROLL_PTR - 1 + n_uniq].col + = &table->cols[n + DATA_ROLL_PTR]; + } } + /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ + ind->cached = TRUE; *index = ind; return(ptr); } diff --git a/storage/innobase/pars/pars0pars.c b/storage/innobase/pars/pars0pars.c index 16530494a96..89f6f862995 100644 --- a/storage/innobase/pars/pars0pars.c +++ b/storage/innobase/pars/pars0pars.c @@ -1640,7 +1640,8 @@ pars_create_table( while (column) { dtype = dfield_get_type(que_node_get_val(column)); - dict_mem_table_add_col(table, column->name, dtype->mtype, + dict_mem_table_add_col(table, table->heap, + column->name, dtype->mtype, dtype->prtype, dtype->len); column->resolved = TRUE; column->token_type = SYM_COLUMN; diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index d51b7e1e0b5..b8d201e3da2 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -655,6 +655,8 @@ row_create_prebuilt( prebuilt->old_vers_heap = NULL; + prebuilt->last_value = 0; + return(prebuilt); } @@ -2894,6 +2896,8 @@ next_rec: dict_table_change_id_in_cache(table, new_id); } + /* MySQL calls ha_innobase::reset_auto_increment() which does + the same thing. */ dict_table_autoinc_initialize(table, 0); dict_update_statistics(table); diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index e70b3b8671f..ee79bc94906 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -4519,3 +4519,169 @@ row_search_check_if_query_cache_permitted( return(ret); } + +/*********************************************************************** +Read the AUTOINC column from the current row. */ +static +ib_longlong +row_search_autoinc_read_column( +/*===========================*/ + /* out: value read from the column */ + dict_index_t* index, /* in: index to read from */ + const rec_t* rec, /* in: current rec */ + ulint col_no, /* in: column number */ + ibool unsigned_type) /* in: signed or unsigned flag */ +{ + ulint len; + byte* ptr; + const byte* data; + ib_longlong value; + mem_heap_t* heap = NULL; + byte dest[sizeof(value)]; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + + *offsets_ = sizeof offsets_ / sizeof *offsets_; + + /* TODO: We have to cast away the const of rec for now. This needs + to be fixed later.*/ + offsets = rec_get_offsets( + (rec_t*) rec, index, offsets, ULINT_UNDEFINED, &heap); + + /* TODO: We have to cast away the const of rec for now. This needs + to be fixed later.*/ + data = rec_get_nth_field((rec_t*)rec, offsets, col_no, &len); + + ut_a(len != UNIV_SQL_NULL); + ut_a(len <= sizeof value); + + /* Convert integer data from Innobase to a little-endian format, + sign bit restored to normal */ + + for (ptr = dest + len; ptr != dest; ++data) { + --ptr; + *ptr = *data; + } + + if (!unsigned_type) { + dest[len - 1] ^= 128; + } + + /* The assumption here is that the AUTOINC value can't be negative.*/ + switch (len) { + case 8: + value = *(ib_longlong*) ptr; + break; + + case 4: + value = *(ib_uint32_t*) ptr; + break; + + case 2: + value = *(uint16 *) ptr; + break; + + case 1: + value = *ptr; + break; + + default: + ut_error; + } + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + ut_a(value >= 0); + + return(value); +} + +/*********************************************************************** +Get the last row. */ +static +const rec_t* +row_search_autoinc_get_rec( +/*=======================*/ + /* out: current rec or NULL */ + btr_pcur_t* pcur, /* in: the current cursor */ + mtr_t* mtr) /* in: mini transaction */ +{ + do { + const rec_t* rec = btr_pcur_get_rec(pcur); + + if (page_rec_is_user_rec(rec)) { + return(rec); + } + } while (btr_pcur_move_to_prev(pcur, mtr)); + + return(NULL); +} + +/*********************************************************************** +Read the max AUTOINC value from an index. */ + +ulint +row_search_max_autoinc( +/*===================*/ + /* out: DB_SUCCESS if all OK else + error code, DB_RECORD_NOT_FOUND if + column name can't be found in index */ + dict_index_t* index, /* in: index to search */ + const char* col_name, /* in: name of autoinc column */ + ib_longlong* value) /* out: AUTOINC value read */ +{ + ulint i; + ulint n_cols; + dict_field_t* dfield = NULL; + ulint error = DB_SUCCESS; + + n_cols = dict_index_get_n_ordering_defined_by_user(index); + + /* Search the index for the AUTOINC column name */ + for (i = 0; i < n_cols; ++i) { + dfield = dict_index_get_nth_field(index, i); + + if (strcmp(col_name, dfield->name) == 0) { + break; + } + } + + *value = 0; + + /* Must find the AUTOINC column name */ + if (i < n_cols && dfield) { + mtr_t mtr; + btr_pcur_t pcur; + + mtr_start(&mtr); + + /* Open at the high/right end (FALSE), and INIT + cursor (TRUE) */ + btr_pcur_open_at_index_side( + FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); + + if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) { + const rec_t* rec; + + rec = row_search_autoinc_get_rec(&pcur, &mtr); + + if (rec != NULL) { + ibool unsigned_type = ( + dfield->col->prtype & DATA_UNSIGNED); + + *value = row_search_autoinc_read_column( + index, rec, i, unsigned_type); + } + } + + btr_pcur_close(&pcur); + + mtr_commit(&mtr); + } else { + error = DB_RECORD_NOT_FOUND; + } + + return(error); +} diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 8f8c9386f41..82b55789be2 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -907,7 +907,7 @@ srv_init(void) /* create dummy table and index for old-style infimum and supremum */ table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0); - dict_mem_table_add_col(table, "DUMMY", DATA_CHAR, + dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR, DATA_ENGLISH | DATA_NOT_NULL, 8); srv_sys->dummy_ind1 = dict_mem_index_create( @@ -918,7 +918,7 @@ srv_init(void) /* create dummy table and index for new-style infimum and supremum */ table = dict_mem_table_create("SYS_DUMMY2", DICT_HDR_SPACE, 1, DICT_TF_COMPACT); - dict_mem_table_add_col(table, "DUMMY", DATA_CHAR, + dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR, DATA_ENGLISH | DATA_NOT_NULL, 8); srv_sys->dummy_ind2 = dict_mem_index_create( "SYS_DUMMY2", "SYS_DUMMY2", DICT_HDR_SPACE, 0, 1); diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c index 144721150b6..40348dd4199 100644 --- a/storage/innobase/trx/trx0sys.c +++ b/storage/innobase/trx/trx0sys.c @@ -646,6 +646,7 @@ trx_sys_update_mysql_binlog_offset( MLOG_4BYTES, mtr); } +#ifdef UNIV_HOTBACKUP /********************************************************************* Prints to stderr the MySQL binlog info in the system header if the magic number shows it valid. */ @@ -677,6 +678,7 @@ trx_sys_print_mysql_binlog_offset_from_page( + TRX_SYS_MYSQL_LOG_NAME); } } +#endif /* UNIV_HOTBACKUP */ /********************************************************************* Stores the MySQL binlog offset info in the trx system header if diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index b312e008cd2..a278ad51984 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -139,11 +139,6 @@ trx_create( trx->mysql_log_file_name = NULL; trx->mysql_log_offset = 0; - trx->mysql_master_log_file_name = ""; - trx->mysql_master_log_pos = 0; - - trx->repl_wait_binlog_name = NULL; - trx->repl_wait_binlog_pos = 0; mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO); @@ -195,6 +190,8 @@ trx_create( memset(&trx->xid, 0, sizeof(trx->xid)); trx->xid.formatID = -1; + trx->n_autoinc_rows = 0; + trx_reset_new_rec_lock_info(trx); return(trx); @@ -323,11 +320,6 @@ trx_free( trx_undo_arr_free(trx->undo_no_arr); } - if (trx->repl_wait_binlog_name != NULL) { - - mem_free(trx->repl_wait_binlog_name); - } - ut_a(UT_LIST_GET_LEN(trx->signals) == 0); ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0); @@ -807,14 +799,6 @@ trx_commit_off_kernel( trx->mysql_log_file_name = NULL; } - if (trx->mysql_master_log_file_name[0] != '\0') { - /* This database server is a MySQL replication slave */ - trx_sys_update_mysql_binlog_offset( - trx->mysql_master_log_file_name, - trx->mysql_master_log_pos, - TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); - } - /* The following call commits the mini-transaction, making the whole transaction committed in the file-based world, at this log sequence number. The transaction becomes 'durable' when |