summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorTimothy Smith <timothy.smith@sun.com>2008-12-14 13:59:50 -0700
committerTimothy Smith <timothy.smith@sun.com>2008-12-14 13:59:50 -0700
commitd29aaf893c1290f60807c3e77646bbb1c9db5ee0 (patch)
tree12359686279f53c74e5d78218a691324b40730cb /storage
parent5e421fb8fe54b51979761b49416cc463b4eaf652 (diff)
downloadmariadb-git-d29aaf893c1290f60807c3e77646bbb1c9db5ee0.tar.gz
Apply InnoDB snapshot innodb-5.1-ss2858, part 15. Fixes
Bug #39830: Table autoinc value not updated on first insert. Bug #35498: Cannot get table test/table1 auto-inccounter value in ::info Bug #36411: Failed to read auto-increment value from storage engine" in 5.1.24 auto-inc Detailed revision comments: r2854 | sunny | 2008-10-23 08:30:32 +0300 (Thu, 23 Oct 2008) | 13 lines branches/5.1: Backport changes from branches/zip r2725 Simplify the autoinc initialization code. This removes the non-determinism related to reading the table's autoinc value for the first time. This change has also reduced the sizeof dict_table_t by sizeof(ibool) bytes because we don't need the dict_table_t::autoinc_inited field anymore. rb://16
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/dict/dict0dict.c25
-rw-r--r--storage/innobase/dict/dict0mem.c2
-rw-r--r--storage/innobase/handler/ha_innodb.cc295
-rw-r--r--storage/innobase/handler/ha_innodb.h10
-rw-r--r--storage/innobase/include/dict0dict.h11
-rw-r--r--storage/innobase/include/dict0mem.h4
-rw-r--r--storage/innobase/row/row0mysql.c2
7 files changed, 137 insertions, 212 deletions
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
index 7bc700c4268..c7a57d6a2b8 100644
--- a/storage/innobase/dict/dict0dict.c
+++ b/storage/innobase/dict/dict0dict.c
@@ -422,8 +422,7 @@ dict_table_autoinc_lock(
}
/************************************************************************
-Initializes the autoinc counter. It is not an error to initialize an already
-initialized counter. */
+Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
@@ -433,7 +432,6 @@ dict_table_autoinc_initialize(
{
ut_ad(mutex_own(&table->autoinc_mutex));
- table->autoinc_inited = TRUE;
table->autoinc = value;
}
@@ -447,32 +445,25 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
dict_table_t* table) /* in: table */
{
- ib_longlong value;
-
ut_ad(mutex_own(&table->autoinc_mutex));
- if (!table->autoinc_inited) {
-
- value = 0;
- } else {
- value = table->autoinc;
- }
-
- return(value);
+ return(table->autoinc);
}
/************************************************************************
Updates the autoinc counter if the value supplied is greater than the
-current value. If not inited, does nothing. */
+current value. */
void
-dict_table_autoinc_update(
-/*======================*/
+dict_table_autoinc_update_if_greater(
+/*=================================*/
dict_table_t* table, /* in: table */
ib_ulonglong value) /* in: value which was assigned to a row */
{
- if (table->autoinc_inited && value > table->autoinc) {
+ ut_ad(mutex_own(&table->autoinc_mutex));
+
+ if (value > table->autoinc) {
table->autoinc = value;
}
diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c
index f9935b8db19..168771ca307 100644
--- a/storage/innobase/dict/dict0mem.c
+++ b/storage/innobase/dict/dict0mem.c
@@ -89,7 +89,7 @@ dict_mem_table_create(
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
- table->autoinc_inited = FALSE;
+ table->autoinc = 0;
/* The number of transactions that are either waiting on the
AUTOINC lock or have been granted the lock. */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index ab4d4e96cef..bf777b982db 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -953,7 +953,9 @@ innobase_next_autoinc(
/* Should never be 0. */
ut_a(increment > 0);
- if (offset <= 1) {
+ if (max_value <= current) {
+ next_value = max_value;
+ } else if (offset <= 1) {
/* Offset 0 and 1 are the same, because there must be at
least one node in the system. */
if (max_value - current <= increment) {
@@ -978,6 +980,8 @@ innobase_next_autoinc(
} else {
next_value *= increment;
+ ut_a(max_value >= next_value);
+
/* Check for overflow. */
if (max_value - next_value <= offset) {
next_value = max_value;
@@ -987,6 +991,8 @@ innobase_next_autoinc(
}
}
+ ut_a(next_value <= max_value);
+
return(next_value);
}
@@ -2343,6 +2349,44 @@ normalize_table_name(
#endif
}
+/************************************************************************
+Set the autoinc column max value. This should only be called once from
+ha_innobase::open(). Therefore there's no need for a covering lock. */
+
+ulong
+ha_innobase::innobase_initialize_autoinc()
+/*======================================*/
+{
+ dict_index_t* index;
+ ulonglong auto_inc;
+ const char* col_name;
+ ulint error = DB_SUCCESS;
+ dict_table_t* innodb_table = prebuilt->table;
+
+ col_name = table->found_next_number_field->field_name;
+ index = innobase_get_index(table->s->next_number_index);
+
+ /* Execute SELECT MAX(col_name) FROM TABLE; */
+ error = row_search_max_autoinc(index, col_name, &auto_inc);
+
+ if (error == DB_SUCCESS) {
+
+ /* At the this stage we dont' know the increment
+ or the offset, so use default inrement of 1. */
+ ++auto_inc;
+
+ dict_table_autoinc_initialize(innodb_table, auto_inc);
+
+ } else {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
+ "the MAX(%s) autoinc value from the "
+ "index (%s).\n", error, col_name, index->name);
+ }
+
+ return(ulong(error));
+}
+
/*********************************************************************
Creates and opens a handle to a table which already exists in an InnoDB
database. */
@@ -2534,6 +2578,26 @@ retry:
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ /* Only if the table has an AUTOINC column. */
+ if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
+ ulint error;
+
+ dict_table_autoinc_lock(prebuilt->table);
+
+ /* Since a table can already be "open" in InnoDB's internal
+ data dictionary, we only init the autoinc counter once, the
+ first time the table is loaded. We can safely reuse the
+ autoinc value from a previous MySQL open. */
+ if (dict_table_autoinc_read(prebuilt->table) == 0) {
+
+ error = innobase_initialize_autoinc();
+ /* Should always succeed! */
+ ut_a(error == DB_SUCCESS);
+ }
+
+ dict_table_autoinc_unlock(prebuilt->table);
+ }
+
DBUG_RETURN(0);
}
@@ -3401,7 +3465,7 @@ 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)
+ha_innobase::innobase_lock_autoinc(void)
/*====================================*/
/* out: DB_SUCCESS if all OK else
error code */
@@ -3466,7 +3530,7 @@ ha_innobase::innobase_reset_autoinc(
{
ulint error;
- error = innobase_autoinc_lock();
+ error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
@@ -3491,11 +3555,11 @@ ha_innobase::innobase_set_max_autoinc(
{
ulint error;
- error = innobase_autoinc_lock();
+ error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
- dict_table_autoinc_update(prebuilt->table, auto_inc);
+ dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
dict_table_autoinc_unlock(prebuilt->table);
}
@@ -3705,7 +3769,7 @@ no_commit:
update the table upper limit. Note: last_value
will be 0 if get_auto_increment() was not called.*/
- if (auto_inc < col_max_value
+ if (auto_inc <= col_max_value
&& auto_inc > prebuilt->autoinc_last_value) {
set_max_autoinc:
ut_a(prebuilt->autoinc_increment > 0);
@@ -3965,7 +4029,7 @@ ha_innobase::update_row(
col_max_value = innobase_get_int_col_max_value(
table->next_number_field);
- if (auto_inc < col_max_value && auto_inc != 0) {
+ if (auto_inc <= col_max_value && auto_inc != 0) {
ulonglong need;
ulonglong offset;
@@ -4020,30 +4084,6 @@ ha_innobase::delete_row(
ha_statistic_increment(&SSV::ha_delete_count);
- /* 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);
}
@@ -4058,7 +4098,6 @@ 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
@@ -6135,16 +6174,7 @@ ha_innobase::info(
}
if (flag & HA_STATUS_AUTO && table->found_next_number_field) {
- ulonglong auto_inc;
-
- if (innobase_read_and_init_auto_inc(&auto_inc) != 0) {
- sql_print_error("Cannot get table %s auto-inc"
- "counter value in ::info\n",
- ib_table->name);
- auto_inc = 0;
- }
-
- stats.auto_increment_value = auto_inc;
+ stats.auto_increment_value = innobase_peek_autoinc();
}
prebuilt->trx->op_info = (char*)"";
@@ -7475,157 +7505,59 @@ ha_innobase::store_lock(
return(to);
}
-/***********************************************************************
-This function initializes the auto-inc counter if it has not been
-initialized yet. This function does not change the value of the auto-inc
-counter if it already has been initialized. In parameter ret returns
-the value of the auto-inc counter. */
+/*******************************************************************************
+Read the next autoinc value. Acquire the relevant locks before reading
+the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
+on return and all relevant locks acquired. */
-int
-ha_innobase::innobase_read_and_init_auto_inc(
-/*=========================================*/
- /* out: 0 or generic MySQL
- error code */
- ulonglong* value) /* out: the autoinc value */
+ulong
+ha_innobase::innobase_get_autoinc(
+/*==============================*/
+ /* out: DB_SUCCESS or error code */
+ ulonglong* value) /* out: autoinc value */
{
- ulonglong auto_inc;
- ibool stmt_start;
- int mysql_error = 0;
- dict_table_t* innodb_table = prebuilt->table;
- ibool trx_was_not_started = FALSE;
-
- ut_a(prebuilt);
- ut_a(prebuilt->table);
-
- /* Remember if we are in the beginning of an SQL statement.
- This function must not change that flag. */
- stmt_start = prebuilt->sql_stat_start;
-
- /* Prepare prebuilt->trx in the table handle */
- update_thd(ha_thd());
-
- if (prebuilt->trx->conc_state == TRX_NOT_STARTED) {
- trx_was_not_started = TRUE;
- }
-
- /* In case MySQL calls this in the middle of a SELECT query, release
- possible adaptive hash latch to avoid deadlocks of threads */
-
- trx_search_latch_release_if_reserved(prebuilt->trx);
-
- dict_table_autoinc_lock(prebuilt->table);
-
- auto_inc = dict_table_autoinc_read(prebuilt->table);
-
- /* 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);
- }
-
- if (auto_inc == 0) {
- dict_index_t* index;
- const char* autoinc_col_name;
-
- ut_a(!innodb_table->autoinc_inited);
-
- index = innobase_get_index(table->s->next_number_index);
-
- autoinc_col_name = table->found_next_number_field->field_name;
-
- prebuilt->autoinc_error = row_search_max_autoinc(
- index, autoinc_col_name, &auto_inc);
-
- if (prebuilt->autoinc_error == DB_SUCCESS) {
- if (auto_inc < ~0x0ULL) {
- ++auto_inc;
- }
- dict_table_autoinc_initialize(innodb_table, auto_inc);
- } else {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
- "the max AUTOINC value from the index (%s).\n",
- prebuilt->autoinc_error, index->name);
-
- mysql_error = 1;
- }
- }
-
- *value = auto_inc;
-
- dict_table_autoinc_unlock(prebuilt->table);
+ *value = 0;
+
+ prebuilt->autoinc_error = innobase_lock_autoinc();
- /* 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
- dangling transaction. If the user had AUTOCOMMIT=0, then SHOW
- TABLE STATUS does leave a dangling transaction if the user does not
- himself call COMMIT. */
+ if (prebuilt->autoinc_error == DB_SUCCESS) {
- if (trx_was_not_started) {
+ /* Determine the first value of the interval */
+ *value = dict_table_autoinc_read(prebuilt->table);
- innobase_commit_low(prebuilt->trx);
+ /* It should have been initialized during open. */
+ ut_a(*value != 0);
}
-
- prebuilt->sql_stat_start = stmt_start;
-
- return(mysql_error);
+
+ return(ulong(prebuilt->autoinc_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.*/
+/***********************************************************************
+This function reads the global auto-inc counter. It doesn't use the
+AUTOINC lock even if the lock mode is set to TRADITIONAL. */
-ulint
-ha_innobase::innobase_get_auto_increment(
-/*=====================================*/
- ulonglong* value) /* out: autoinc value */
+ulonglong
+ha_innobase::innobase_peek_autoinc()
+/*================================*/
+ /* out: the autoinc value */
{
- *value = 0;
-
- /* Note: If the table is not initialized when we attempt the
- read below. We initialize the table's auto-inc counter and
- always do a reread of the AUTOINC value. */
- do {
- /* We need to send the correct error code to the client
- because handler::get_auto_increment() doesn't allow a way
- to return the specific error for why it failed. */
- prebuilt->autoinc_error = innobase_autoinc_lock();
-
- if (prebuilt->autoinc_error == DB_SUCCESS) {
- ulonglong 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;
+ ulonglong auto_inc;
+ dict_table_t* innodb_table;
- trx = prebuilt->trx;
- dict_table_autoinc_unlock(prebuilt->table);
+ ut_a(prebuilt != NULL);
+ ut_a(prebuilt->table != NULL);
- /* If we had reserved the AUTO-INC
- lock in this SQL statement we release
- it before retrying.*/
- row_unlock_table_autoinc_for_mysql(trx);
+ innodb_table = prebuilt->table;
- /* Just to make sure */
- ut_a(!trx->auto_inc_lock);
+ dict_table_autoinc_lock(innodb_table);
- /* Will set prebuilt->autoinc_error if there
- is a problem during init. */
- innobase_read_and_init_auto_inc(&autoinc);
+ auto_inc = dict_table_autoinc_read(innodb_table);
- } else {
- *value = autoinc;
- }
- }
- } while (*value == 0 && prebuilt->autoinc_error == DB_SUCCESS);
+ ut_a(auto_inc > 0);
- return(prebuilt->autoinc_error);
+ dict_table_autoinc_unlock(innodb_table);
+
+ return(auto_inc);
}
/*******************************************************************************
@@ -7652,7 +7584,7 @@ ha_innobase::get_auto_increment(
/* Prepare prebuilt->trx in the table handle */
update_thd(ha_thd());
- error = innobase_get_auto_increment(&autoinc);
+ error = innobase_get_autoinc(&autoinc);
if (error != DB_SUCCESS) {
*first_value = (~(ulonglong) 0);
@@ -7717,7 +7649,7 @@ ha_innobase::get_auto_increment(
ut_a(prebuilt->autoinc_last_value >= *first_value);
/* Update the table autoinc variable */
- dict_table_autoinc_update(
+ dict_table_autoinc_update_if_greater(
prebuilt->table, prebuilt->autoinc_last_value);
} else {
/* This will force write_row() into attempting an update
@@ -7755,6 +7687,11 @@ ha_innobase::reset_auto_increment(
DBUG_RETURN(error);
}
+ /* The next value can never be 0. */
+ if (value == 0) {
+ value = 1;
+ }
+
innobase_reset_autoinc(value);
DBUG_RETURN(0);
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 95890e2215d..8ca72ee1a60 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -72,13 +72,15 @@ class ha_innobase: public handler
int update_thd(THD* thd);
int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode);
- int innobase_read_and_init_auto_inc(ulonglong* ret);
- ulong innobase_autoinc_lock();
+ ulong innobase_lock_autoinc();
+ ulonglong innobase_peek_autoinc();
ulong innobase_set_max_autoinc(ulonglong auto_inc);
ulong innobase_reset_autoinc(ulonglong auto_inc);
- ulong innobase_get_auto_increment(ulonglong* value);
+ ulong innobase_get_autoinc(ulonglong* value);
+ ulong innobase_update_autoinc(ulonglong auto_inc);
+ ulong innobase_initialize_autoinc();
dict_index_t* innobase_get_index(uint keynr);
- ulonglong innobase_get_int_col_max_value(const Field* field);
+ ulonglong innobase_get_int_col_max_value(const Field* field);
/* Init values for the class: */
public:
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index f60775c8c2f..7d5ff09c7a6 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -178,8 +178,7 @@ 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. */
+Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
@@ -196,12 +195,12 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
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. */
+Updates the autoinc counter if the value supplied is greater than the
+current value. */
void
-dict_table_autoinc_update(
-/*======================*/
+dict_table_autoinc_update_if_greater(
+/*=================================*/
dict_table_t* table, /* in: table */
ib_ulonglong value); /* in: value which was assigned to a row */
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 6e5435493cb..ac28fdb1bae 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -405,10 +405,6 @@ struct dict_table_struct{
mutex_t autoinc_mutex;
/* mutex protecting the autoincrement
counter */
- ibool autoinc_inited;
- /* TRUE if the autoinc counter has been
- inited; MySQL gets the init value by executing
- SELECT MAX(auto inc column) */
ib_ulonglong autoinc;/* autoinc counter value to give to the
next inserted row */
ulong n_waiting_or_granted_auto_inc_locks;
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index 2d1cf22e4e7..d76af54b420 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -2910,7 +2910,7 @@ next_rec:
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
dict_table_autoinc_lock(table);
- dict_table_autoinc_initialize(table, 0);
+ dict_table_autoinc_initialize(table, 1);
dict_table_autoinc_unlock(table);
dict_update_statistics(table);