Apply InnoDB snapshot innodb-5.1-ss1751.

Bug #16979: AUTO_INC lock in InnoDB works a table level lock
  Add a table level counter that tracks the number of AUTOINC locks that are
  pending and/or granted on a table. We peek at this value to determine whether
  a transaction doing a simple INSERT in innodb_autoinc_lock_mode = 1, needs to
  acquire the AUTOINC lock or not. This change is related to Bug# 16979.
Bug #27950: Duplicate entry error in auto-inc after mysqld restart
  We check whether the AUTOINC sub-system has been initialized (first) by
  holding the AUTOINC mutex and if initialization is required then we
  initialize using our normal procedure.
parent 159d5b71
...@@ -211,6 +211,7 @@ dict_boot(void) ...@@ -211,6 +211,7 @@ dict_boot(void)
dict_table_t* table; dict_table_t* table;
dict_index_t* index; dict_index_t* index;
dict_hdr_t* dict_hdr; dict_hdr_t* dict_hdr;
mem_heap_t* heap;
mtr_t mtr; mtr_t mtr;
mtr_start(&mtr); mtr_start(&mtr);
...@@ -218,6 +219,8 @@ dict_boot(void) ...@@ -218,6 +219,8 @@ dict_boot(void)
/* Create the hash tables etc. */ /* Create the hash tables etc. */
dict_init(); dict_init();
heap = mem_heap_create(450);
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
/* Get the dictionary header */ /* Get the dictionary header */
...@@ -244,19 +247,20 @@ dict_boot(void) ...@@ -244,19 +247,20 @@ dict_boot(void)
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0); 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, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "N_COLS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "MIX_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "MIX_LEN", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "CLUSTER_NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
table->id = DICT_TABLES_ID; table->id = DICT_TABLES_ID;
dict_table_add_to_cache(table); dict_table_add_to_cache(table, heap);
dict_sys->sys_tables = table; dict_sys->sys_tables = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_TABLES", "CLUST_IND", index = dict_mem_index_create("SYS_TABLES", "CLUST_IND",
DICT_HDR_SPACE, DICT_HDR_SPACE,
...@@ -283,18 +287,19 @@ dict_boot(void) ...@@ -283,18 +287,19 @@ dict_boot(void)
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0); 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, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "MTYPE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "MTYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "PRTYPE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "PRTYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "LEN", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "LEN", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "PREC", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "PREC", DATA_INT, 0, 4);
table->id = DICT_COLUMNS_ID; table->id = DICT_COLUMNS_ID;
dict_table_add_to_cache(table); dict_table_add_to_cache(table, heap);
dict_sys->sys_columns = table; dict_sys->sys_columns = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND", index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND",
DICT_HDR_SPACE, DICT_HDR_SPACE,
...@@ -311,13 +316,13 @@ dict_boot(void) ...@@ -311,13 +316,13 @@ dict_boot(void)
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0); 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, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "N_FIELDS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "N_FIELDS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "PAGE_NO", 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 */ /* The '+ 2' below comes from the 2 system fields */
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2 #if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2
...@@ -331,8 +336,9 @@ dict_boot(void) ...@@ -331,8 +336,9 @@ dict_boot(void)
#endif #endif
table->id = DICT_INDEXES_ID; table->id = DICT_INDEXES_ID;
dict_table_add_to_cache(table); dict_table_add_to_cache(table, heap);
dict_sys->sys_indexes = table; dict_sys->sys_indexes = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND", index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND",
DICT_HDR_SPACE, DICT_HDR_SPACE,
...@@ -349,13 +355,14 @@ dict_boot(void) ...@@ -349,13 +355,14 @@ dict_boot(void)
/*-------------------------*/ /*-------------------------*/
table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0); 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, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, "COL_NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0);
table->id = DICT_FIELDS_ID; table->id = DICT_FIELDS_ID;
dict_table_add_to_cache(table); dict_table_add_to_cache(table, heap);
dict_sys->sys_fields = table; dict_sys->sys_fields = table;
mem_heap_free(heap);
index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND", index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
DICT_HDR_SPACE, DICT_HDR_SPACE,
......
...@@ -960,7 +960,7 @@ dict_create_table_step( ...@@ -960,7 +960,7 @@ dict_create_table_step(
if (node->state == TABLE_ADD_TO_CACHE) { 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; err = DB_SUCCESS;
} }
......
...@@ -423,7 +423,8 @@ dict_load_columns( ...@@ -423,7 +423,8 @@ dict_load_columns(
ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC")); 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); btr_pcur_move_to_next_user_rec(&pcur, &mtr);
} }
...@@ -746,7 +747,7 @@ dict_load_table( ...@@ -746,7 +747,7 @@ dict_load_table(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
heap = mem_heap_create(1000); heap = mem_heap_create(32000);
mtr_start(&mtr); mtr_start(&mtr);
...@@ -852,7 +853,9 @@ err_exit: ...@@ -852,7 +853,9 @@ err_exit:
dict_load_columns(table, heap); 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); dict_load_indexes(table, heap);
......
...@@ -95,6 +95,10 @@ dict_mem_table_create( ...@@ -95,6 +95,10 @@ dict_mem_table_create(
default to 1 here.*/ default to 1 here.*/
table->autoinc_increment = 1; 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 #ifdef UNIV_DEBUG
table->magic_n = DICT_TABLE_MAGIC_N; table->magic_n = DICT_TABLE_MAGIC_N;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
......
...@@ -92,11 +92,15 @@ extern "C" { ...@@ -92,11 +92,15 @@ extern "C" {
#include "../storage/innobase/include/ha_prototypes.h" #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, static long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb, innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb,
innobase_additional_mem_pool_size, innobase_file_io_threads, innobase_additional_mem_pool_size, innobase_file_io_threads,
innobase_lock_wait_timeout, innobase_force_recovery, 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; static long long innobase_buffer_pool_size, innobase_log_file_size;
...@@ -1928,110 +1932,6 @@ retry: ...@@ -1928,110 +1932,6 @@ retry:
DBUG_RETURN(0); 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. */ Rolls back a transaction or the latest SQL statement. */
static static
...@@ -3353,24 +3253,46 @@ ha_innobase::innobase_autoinc_lock(void) ...@@ -3353,24 +3253,46 @@ ha_innobase::innobase_autoinc_lock(void)
{ {
ulint error = DB_SUCCESS; ulint error = DB_SUCCESS;
if (thd_sql_command(user_thd) == SQLCOM_INSERT) { switch (innobase_autoinc_lock_mode) {
case AUTOINC_NO_LOCKING:
/* Acquire only the AUTOINC mutex. */
dict_table_autoinc_lock(prebuilt->table); dict_table_autoinc_lock(prebuilt->table);
break;
/* We peek at the dict_table_t::auto_inc_lock to check if case AUTOINC_NEW_STYLE_LOCKING:
another statement has locked it */ /* For simple (single/multi) row INSERTs, we fallback to the
if (prebuilt->trx->auto_inc_lock != NULL) { old style only if another transaction has already acquired
/* Release the mutex to avoid deadlocks */ the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
dict_table_autoinc_unlock(prebuilt->table); etc. type of statement. */
if (thd_sql_command(user_thd) == SQLCOM_INSERT) {
dict_table_t* table = prebuilt->table;
goto acquire_auto_inc_lock; /* 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 { } else {
acquire_auto_inc_lock: break;
}
}
/* Fall through to old style locking. */
case AUTOINC_OLD_STYLE_LOCKING:
error = row_lock_table_autoinc_for_mysql(prebuilt); error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error == DB_SUCCESS) { if (error == DB_SUCCESS) {
/* Acquire the AUTOINC mutex. */
dict_table_autoinc_lock(prebuilt->table); dict_table_autoinc_lock(prebuilt->table);
} }
break;
default:
ut_error;
} }
return(ulong(error)); return(ulong(error));
...@@ -3610,6 +3532,7 @@ no_commit: ...@@ -3610,6 +3532,7 @@ no_commit:
if (auto_inc > prebuilt->last_value) { if (auto_inc > prebuilt->last_value) {
set_max_autoinc: set_max_autoinc:
ut_a(prebuilt->table->autoinc_increment > 0);
auto_inc += prebuilt->table->autoinc_increment; auto_inc += prebuilt->table->autoinc_increment;
innobase_set_max_autoinc(auto_inc); innobase_set_max_autoinc(auto_inc);
...@@ -3884,6 +3807,14 @@ ha_innobase::delete_row( ...@@ -3884,6 +3807,14 @@ ha_innobase::delete_row(
if (table->found_next_number_field && record == table->record[0]) { if (table->found_next_number_field && record == table->record[0]) {
ulonglong dummy = 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); error = innobase_get_auto_increment(&dummy);
if (error == DB_SUCCESS) { if (error == DB_SUCCESS) {
...@@ -3891,6 +3822,9 @@ ha_innobase::delete_row( ...@@ -3891,6 +3822,9 @@ ha_innobase::delete_row(
} else { } else {
goto error_exit; goto error_exit;
} }
} else {
dict_table_autoinc_unlock(prebuilt->table);
}
} }
if (!prebuilt->upd_node) { if (!prebuilt->upd_node) {
...@@ -7411,13 +7345,24 @@ ha_innobase::get_auto_increment( ...@@ -7411,13 +7345,24 @@ ha_innobase::get_auto_increment(
*nb_reserved_values = prebuilt->trx->n_autoinc_rows; *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 */ /* Compute the last value in the interval */
prebuilt->last_value = *first_value + (*nb_reserved_values * increment); prebuilt->last_value = *first_value +
(*nb_reserved_values * increment);
ut_a(prebuilt->last_value >= *first_value); ut_a(prebuilt->last_value >= *first_value);
/* Update the table autoinc variable */ /* Update the table autoinc variable */
dict_table_autoinc_update(prebuilt->table, prebuilt->last_value); 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 /* The increment to be used to increase the AUTOINC value, we use
this in write_row() and update_row() to increase the autoinc counter this in write_row() and update_row() to increase the autoinc counter
...@@ -8080,6 +8025,17 @@ static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, ...@@ -8080,6 +8025,17 @@ static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path,
"Path to individual files and their sizes.", "Path to individual files and their sizes.",
NULL, NULL, NULL); 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[]= { static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(autoextend_increment),
...@@ -8118,6 +8074,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { ...@@ -8118,6 +8074,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(table_locks), MYSQL_SYSVAR(table_locks),
MYSQL_SYSVAR(thread_concurrency), MYSQL_SYSVAR(thread_concurrency),
MYSQL_SYSVAR(thread_sleep_delay), MYSQL_SYSVAR(thread_sleep_delay),
MYSQL_SYSVAR(autoinc_lock_mode),
NULL NULL
}; };
......
...@@ -315,11 +315,11 @@ struct dict_table_struct{ ...@@ -315,11 +315,11 @@ struct dict_table_struct{
unsigned n_cols:10;/* number of columns */ unsigned n_cols:10;/* number of columns */
dict_col_t* cols; /* array of column descriptions */ dict_col_t* cols; /* array of column descriptions */
const char* col_names; const char* col_names;
/* n_def column names packed in an /* Column names packed in a character string
"name1\0name2\0...nameN\0" array. until "name1\0name2\0...nameN\0". Until
n_def reaches n_cols, this is allocated with the string contains n_cols, it will be
ut_malloc, and the final size array is allocated from a temporary heap. The final
allocated through the table's heap. */ string will be allocated from table->heap. */
hash_node_t name_hash; /* hash chain node */ hash_node_t name_hash; /* hash chain node */
hash_node_t id_hash; /* hash chain node */ hash_node_t id_hash; /* hash chain node */
UT_LIST_BASE_NODE_T(dict_index_t) UT_LIST_BASE_NODE_T(dict_index_t)
...@@ -416,6 +416,16 @@ struct dict_table_struct{ ...@@ -416,6 +416,16 @@ struct dict_table_struct{
/* The increment step of the auto increment /* The increment step of the auto increment
column. Value must be greater than or equal column. Value must be greater than or equal
to 1 */ 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 #ifdef UNIV_DEBUG
ulint magic_n;/* magic number */ ulint magic_n;/* magic number */
# define DICT_TABLE_MAGIC_N 76333786 # define DICT_TABLE_MAGIC_N 76333786
......
...@@ -271,15 +271,19 @@ mem_heap_free_heap_top( ...@@ -271,15 +271,19 @@ mem_heap_free_heap_top(
ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); ut_ad(mem_block_get_start(block) <= mem_block_get_free(block));
/* In the debug version erase block from top up */ /* 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 */ /* Update allocated memory count */
mutex_enter(&mem_hash_mutex); mutex_enter(&mem_hash_mutex);
mem_current_allocated_memory -= (total_size - size); mem_current_allocated_memory -= (total_size - size);
mutex_exit(&mem_hash_mutex); mutex_exit(&mem_hash_mutex);
#else /* UNIV_MEM_DEBUG */
#endif 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 /* If free == start, we may free the block if it is not the first
one */ one */
......
...@@ -231,7 +231,7 @@ rw_lock_s_lock_func( ...@@ -231,7 +231,7 @@ rw_lock_s_lock_func(
owns an s-lock here, it may end up in a deadlock with another thread 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 which requests an x-lock here. Therefore, we will forbid recursive
s-locking of a latch: the following assert will warn the programmer 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 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 the threads which have s-locked a latch. This would use some CPU
time. */ time. */
......
...@@ -482,31 +482,6 @@ struct trx_struct{ ...@@ -482,31 +482,6 @@ struct trx_struct{
ib_longlong mysql_log_offset;/* if MySQL binlog is used, this field ib_longlong mysql_log_offset;/* if MySQL binlog is used, this field
contains the end offset of the binlog contains the end offset of the binlog
entry */ 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 os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated
with this transaction object */ with this transaction object */
ulint mysql_process_no;/* since in Linux, 'top' reports ulint mysql_process_no;/* since in Linux, 'top' reports
......
...@@ -3386,6 +3386,10 @@ lock_table_create( ...@@ -3386,6 +3386,10 @@ lock_table_create(
ut_ad(table && trx); ut_ad(table && trx);
ut_ad(mutex_own(&kernel_mutex)); 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) { if (type_mode == LOCK_AUTO_INC) {
/* Only one trx can have the lock on the table /* Only one trx can have the lock on the table
at a time: we may use the memory preallocated at a time: we may use the memory preallocated
...@@ -3436,6 +3440,9 @@ lock_table_remove_low( ...@@ -3436,6 +3440,9 @@ lock_table_remove_low(
if (lock == trx->auto_inc_lock) { if (lock == trx->auto_inc_lock) {
trx->auto_inc_lock = NULL; 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); UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
......
...@@ -517,8 +517,9 @@ mlog_parse_index( ...@@ -517,8 +517,9 @@ mlog_parse_index(
n = mach_read_from_2(ptr); n = mach_read_from_2(ptr);
ptr += 2; ptr += 2;
n_uniq = mach_read_from_2(ptr); n_uniq = mach_read_from_2(ptr);
ptr += 2;
ut_ad(n_uniq <= n); ut_ad(n_uniq <= n);
if (end_ptr < ptr + (n + 1) * 2) { if (end_ptr < ptr + n * 2) {
return(NULL); return(NULL);
} }
} else { } else {
...@@ -531,18 +532,18 @@ mlog_parse_index( ...@@ -531,18 +532,18 @@ mlog_parse_index(
ind->table = table; ind->table = table;
ind->n_uniq = (unsigned int) n_uniq; ind->n_uniq = (unsigned int) n_uniq;
if (n_uniq != n) { if (n_uniq != n) {
ut_a(n_uniq + DATA_ROLL_PTR <= n);
ind->type = DICT_CLUSTERED; ind->type = DICT_CLUSTERED;
} }
/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
ind->cached = TRUE;
if (comp) { if (comp) {
for (i = 0; i < n; i++) { 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 high-order bit of len is the NOT NULL flag;
the rest is 0 or 0x7fff for variable-length fields, the rest is 0 or 0x7fff for variable-length fields,
and 1..0x7ffe for fixed-length fields. */ and 1..0x7ffe for fixed-length fields. */
dict_mem_table_add_col( dict_mem_table_add_col(
table, "DUMMY", table, NULL, NULL,
((len + 1) & 0x7fff) <= 1 ((len + 1) & 0x7fff) <= 1
? DATA_BINARY : DATA_FIXBINARY, ? DATA_BINARY : DATA_FIXBINARY,
len & 0x8000 ? DATA_NOT_NULL : 0, len & 0x8000 ? DATA_NOT_NULL : 0,
...@@ -552,8 +553,23 @@ mlog_parse_index( ...@@ -552,8 +553,23 @@ mlog_parse_index(
dict_table_get_nth_col(table, i), dict_table_get_nth_col(table, i),
0); 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; *index = ind;
return(ptr); return(ptr);
} }
...@@ -1640,7 +1640,8 @@ pars_create_table( ...@@ -1640,7 +1640,8 @@ pars_create_table(
while (column) { while (column) {
dtype = dfield_get_type(que_node_get_val(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); dtype->prtype, dtype->len);
column->resolved = TRUE; column->resolved = TRUE;
column->token_type = SYM_COLUMN; column->token_type = SYM_COLUMN;
......
...@@ -907,7 +907,7 @@ srv_init(void) ...@@ -907,7 +907,7 @@ srv_init(void)
/* create dummy table and index for old-style infimum and supremum */ /* create dummy table and index for old-style infimum and supremum */
table = dict_mem_table_create("SYS_DUMMY1", table = dict_mem_table_create("SYS_DUMMY1",
DICT_HDR_SPACE, 1, 0); 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); DATA_ENGLISH | DATA_NOT_NULL, 8);
srv_sys->dummy_ind1 = dict_mem_index_create( srv_sys->dummy_ind1 = dict_mem_index_create(
...@@ -918,7 +918,7 @@ srv_init(void) ...@@ -918,7 +918,7 @@ srv_init(void)
/* create dummy table and index for new-style infimum and supremum */ /* create dummy table and index for new-style infimum and supremum */
table = dict_mem_table_create("SYS_DUMMY2", table = dict_mem_table_create("SYS_DUMMY2",
DICT_HDR_SPACE, 1, DICT_TF_COMPACT); 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); DATA_ENGLISH | DATA_NOT_NULL, 8);
srv_sys->dummy_ind2 = dict_mem_index_create( srv_sys->dummy_ind2 = dict_mem_index_create(
"SYS_DUMMY2", "SYS_DUMMY2", DICT_HDR_SPACE, 0, 1); "SYS_DUMMY2", "SYS_DUMMY2", DICT_HDR_SPACE, 0, 1);
......
...@@ -646,6 +646,7 @@ trx_sys_update_mysql_binlog_offset( ...@@ -646,6 +646,7 @@ trx_sys_update_mysql_binlog_offset(
MLOG_4BYTES, mtr); MLOG_4BYTES, mtr);
} }
#ifdef UNIV_HOTBACKUP
/********************************************************************* /*********************************************************************
Prints to stderr the MySQL binlog info in the system header if the Prints to stderr the MySQL binlog info in the system header if the
magic number shows it valid. */ magic number shows it valid. */
...@@ -677,6 +678,7 @@ trx_sys_print_mysql_binlog_offset_from_page( ...@@ -677,6 +678,7 @@ trx_sys_print_mysql_binlog_offset_from_page(
+ TRX_SYS_MYSQL_LOG_NAME); + TRX_SYS_MYSQL_LOG_NAME);
} }
} }
#endif /* UNIV_HOTBACKUP */
/********************************************************************* /*********************************************************************
Stores the MySQL binlog offset info in the trx system header if Stores the MySQL binlog offset info in the trx system header if
......
...@@ -139,11 +139,6 @@ trx_create( ...@@ -139,11 +139,6 @@ trx_create(
trx->mysql_log_file_name = NULL; trx->mysql_log_file_name = NULL;
trx->mysql_log_offset = 0; 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); mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO);
...@@ -325,11 +320,6 @@ trx_free( ...@@ -325,11 +320,6 @@ trx_free(
trx_undo_arr_free(trx->undo_no_arr); 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->signals) == 0);
ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0); ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
...@@ -809,14 +799,6 @@ trx_commit_off_kernel( ...@@ -809,14 +799,6 @@ trx_commit_off_kernel(
trx->mysql_log_file_name = NULL; 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 /* The following call commits the mini-transaction, making the
whole transaction committed in the file-based world, at this whole transaction committed in the file-based world, at this
log sequence number. The transaction becomes 'durable' when log sequence number. The transaction becomes 'durable' when
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment