From 68afad078a8a8d2aa3c9d1e4298e670678b0dbc7 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 1 Apr 2010 15:19:38 +0400 Subject: [PATCH] Applying InnoDB snapshot Detailed revision comments: r6425 | marko | 2010-01-12 13:47:11 +0200 (Tue, 12 Jan 2010) | 45 lines branches/zip: Merge revisions 6350:6424 from branches/5.1: ------------------------------------------------------------------------ r6421 | jyang | 2010-01-12 07:59:16 +0200 (Tue, 12 Jan 2010) | 8 lines Changed paths: M /branches/5.1/row/row0mysql.c branches/5.1: Fix bug #49238: Creating/Dropping a temporary table while at 1023 transactions will cause assert. Handle possible DB_TOO_MANY_CONCURRENT_TRXS when deleting metadata in row_drop_table_for_mysql(). rb://220, approved by Marko ------------------------------------------------------------------------ r6422 | marko | 2010-01-12 11:34:27 +0200 (Tue, 12 Jan 2010) | 3 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc M /branches/5.1/handler/ha_innodb.h branches/5.1: Non-functional change: Make innobase_get_int_col_max_value() a static function. It does not access any fields of class ha_innobase. ------------------------------------------------------------------------ r6424 | marko | 2010-01-12 12:22:19 +0200 (Tue, 12 Jan 2010) | 16 lines Changed paths: M /branches/5.1/handler/ha_innodb.cc M /branches/5.1/handler/ha_innodb.h branches/5.1: In innobase_initialize_autoinc(), do not attempt to read the maximum auto-increment value from the table if innodb_force_recovery is set to at least 4, so that writes are disabled. (Bug #46193) innobase_get_int_col_max_value(): Move the function definition before ha_innobase::innobase_initialize_autoinc(), because that function now calls this function. ha_innobase::innobase_initialize_autoinc(): Change the return type to void. Do not attempt to read the maximum auto-increment value from the table if innodb_force_recovery is set to at least 4. Issue ER_AUTOINC_READ_FAILED to the client when the auto-increment value cannot be read. rb://144 by Sunny, revised by Marko ------------------------------------------------------------------------ --- storage/innodb_plugin/ChangeLog | 15 +- storage/innodb_plugin/handler/ha_innodb.cc | 239 ++++++++++++--------- storage/innodb_plugin/handler/ha_innodb.h | 3 +- storage/innodb_plugin/row/row0mysql.c | 32 ++- 4 files changed, 171 insertions(+), 118 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index dddf37e2334..334c8b5a8cc 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,6 +1,19 @@ +2010-01-12 The InnoDB Team + + * handler/ha_innodb.cc, handler/ha_innodb.h: + Fix Bug #46193 crash when accessing tables after enabling + innodb_force_recovery option + +2010-01-12 The InnoDB Team + + * row/row0mysql.c: + Fix Bug#49238 Creating/Dropping a temporary table while at 1023 + transactions will cause assert. + 2009-12-02 The InnoDB Team - * srv/srv0start.c: Display the zlib version number at startup. + * srv/srv0start.c: + Display the zlib version number at startup. InnoDB compressed tables use zlib, and the implementation depends on the zlib function compressBound(), whose definition was slightly changed in zlib version 1.2.3.1 in 2006. MySQL bundles zlib 1.2.3 diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 9c214bab3de..95b0d331076 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -3006,59 +3006,150 @@ normalize_table_name( } /********************************************************************//** +Get the upper limit of the MySQL integral and floating-point type. +@return maximum allowed value for the field */ +static +ulonglong +innobase_get_int_col_max_value( +/*===========================*/ + const Field* field) /*!< in: MySQL field */ +{ + ulonglong max_value = 0; + + switch(field->key_type()) { + /* TINY */ + case HA_KEYTYPE_BINARY: + max_value = 0xFFULL; + break; + case HA_KEYTYPE_INT8: + max_value = 0x7FULL; + break; + /* SHORT */ + case HA_KEYTYPE_USHORT_INT: + max_value = 0xFFFFULL; + break; + case HA_KEYTYPE_SHORT_INT: + max_value = 0x7FFFULL; + break; + /* MEDIUM */ + case HA_KEYTYPE_UINT24: + max_value = 0xFFFFFFULL; + break; + case HA_KEYTYPE_INT24: + max_value = 0x7FFFFFULL; + break; + /* LONG */ + case HA_KEYTYPE_ULONG_INT: + max_value = 0xFFFFFFFFULL; + break; + case HA_KEYTYPE_LONG_INT: + max_value = 0x7FFFFFFFULL; + break; + /* BIG */ + case HA_KEYTYPE_ULONGLONG: + max_value = 0xFFFFFFFFFFFFFFFFULL; + break; + case HA_KEYTYPE_LONGLONG: + max_value = 0x7FFFFFFFFFFFFFFFULL; + break; + case HA_KEYTYPE_FLOAT: + /* We use the maximum as per IEEE754-2008 standard, 2^24 */ + max_value = 0x1000000ULL; + break; + case HA_KEYTYPE_DOUBLE: + /* We use the maximum as per IEEE754-2008 standard, 2^53 */ + max_value = 0x20000000000000ULL; + break; + default: + ut_error; + } + + return(max_value); +} + +/************************************************************************ 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. -@return DB_SUCCESS or error code */ +ha_innobase::open(). Therefore there's no need for a covering lock. */ UNIV_INTERN -ulint +void ha_innobase::innobase_initialize_autoinc() /*======================================*/ { - dict_index_t* index; ulonglong auto_inc; - const char* col_name; - ulint error; - - 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); - - switch (error) { - case DB_SUCCESS: - - /* At the this stage we don't know the increment - or the offset, so use default inrement of 1. */ - ++auto_inc; - break; - - case DB_RECORD_NOT_FOUND: - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: MySQL and InnoDB data " - "dictionaries are out of sync.\n" - "InnoDB: Unable to find the AUTOINC column %s in the " - "InnoDB table %s.\n" - "InnoDB: We set the next AUTOINC column value to the " - "maximum possible value,\n" - "InnoDB: in effect disabling the AUTOINC next value " - "generation.\n" - "InnoDB: You can either set the next AUTOINC value " - "explicitly using ALTER TABLE\n" - "InnoDB: or fix the data dictionary by recreating " - "the table.\n", - col_name, index->table->name); + const Field* field = table->found_next_number_field; + if (field != NULL) { + auto_inc = innobase_get_int_col_max_value(field); + } else { + /* We have no idea what's been passed in to us as the + autoinc column. We set it to the MAX_INT of our table + autoinc type. */ auto_inc = 0xFFFFFFFFFFFFFFFFULL; - break; - default: - return(error); + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Unable to determine the AUTOINC " + "column name\n"); + } + + if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { + /* If the recovery level is set so high that writes + are disabled we force the AUTOINC counter to the MAX + value effectively disabling writes to the table. + Secondly, we avoid reading the table in case the read + results in failure due to a corrupted table/index. + + We will not return an error to the client, so that the + tables can be dumped with minimal hassle. If an error + were returned in this case, the first attempt to read + the table would fail and subsequent SELECTs would succeed. */ + } else if (field == NULL) { + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + } else { + dict_index_t* index; + const char* col_name; + ulonglong read_auto_inc; + ulint err; + + update_thd(ha_thd()); + col_name = field->field_name; + index = innobase_get_index(table->s->next_number_index); + + /* Execute SELECT MAX(col_name) FROM TABLE; */ + err = row_search_max_autoinc(index, col_name, &read_auto_inc); + + switch (err) { + case DB_SUCCESS: + /* At the this stage we do not know the increment + or the offset, so use a default increment of 1. */ + auto_inc = read_auto_inc + 1; + break; + + case DB_RECORD_NOT_FOUND: + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: MySQL and InnoDB data " + "dictionaries are out of sync.\n" + "InnoDB: Unable to find the AUTOINC column " + "%s in the InnoDB table %s.\n" + "InnoDB: We set the next AUTOINC column " + "value to the maximum possible value,\n" + "InnoDB: in effect disabling the AUTOINC " + "next value generation.\n" + "InnoDB: You can either set the next " + "AUTOINC value explicitly using ALTER TABLE\n" + "InnoDB: or fix the data dictionary by " + "recreating the table.\n", + col_name, index->table->name); + + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + break; + default: + /* row_search_max_autoinc() should only return + one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */ + ut_error; + } } dict_table_autoinc_initialize(prebuilt->table, auto_inc); - - return(DB_SUCCESS); } /*****************************************************************//** @@ -3265,8 +3356,6 @@ retry: /* 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 @@ -3275,8 +3364,7 @@ retry: autoinc value from a previous MySQL open. */ if (dict_table_autoinc_read(prebuilt->table) == 0) { - error = innobase_initialize_autoinc(); - ut_a(error == DB_SUCCESS); + innobase_initialize_autoinc(); } dict_table_autoinc_unlock(prebuilt->table); @@ -4092,67 +4180,6 @@ skip_field: } } -/********************************************************************//** -Get the upper limit of the MySQL integral and floating-point type. */ -UNIV_INTERN -ulonglong -ha_innobase::innobase_get_int_col_max_value( -/*========================================*/ - const Field* field) -{ - ulonglong max_value = 0; - - switch(field->key_type()) { - /* TINY */ - case HA_KEYTYPE_BINARY: - max_value = 0xFFULL; - break; - case HA_KEYTYPE_INT8: - max_value = 0x7FULL; - break; - /* SHORT */ - case HA_KEYTYPE_USHORT_INT: - max_value = 0xFFFFULL; - break; - case HA_KEYTYPE_SHORT_INT: - max_value = 0x7FFFULL; - break; - /* MEDIUM */ - case HA_KEYTYPE_UINT24: - max_value = 0xFFFFFFULL; - break; - case HA_KEYTYPE_INT24: - max_value = 0x7FFFFFULL; - break; - /* LONG */ - case HA_KEYTYPE_ULONG_INT: - max_value = 0xFFFFFFFFULL; - break; - case HA_KEYTYPE_LONG_INT: - max_value = 0x7FFFFFFFULL; - break; - /* BIG */ - case HA_KEYTYPE_ULONGLONG: - max_value = 0xFFFFFFFFFFFFFFFFULL; - break; - case HA_KEYTYPE_LONGLONG: - max_value = 0x7FFFFFFFFFFFFFFFULL; - break; - case HA_KEYTYPE_FLOAT: - /* We use the maximum as per IEEE754-2008 standard, 2^24 */ - max_value = 0x1000000ULL; - break; - case HA_KEYTYPE_DOUBLE: - /* We use the maximum as per IEEE754-2008 standard, 2^53 */ - max_value = 0x20000000000000ULL; - break; - default: - ut_error; - } - - return(max_value); -} - /********************************************************************//** This special handling is really to overcome the limitations of MySQL's binlogging. We need to eliminate the non-determinism that will arise in diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h index 31e88ed8530..0e366a1eb2c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.h +++ b/storage/innodb_plugin/handler/ha_innodb.h @@ -91,9 +91,8 @@ class ha_innobase: public handler ulint innobase_reset_autoinc(ulonglong auto_inc); ulint innobase_get_autoinc(ulonglong* value); ulint innobase_update_autoinc(ulonglong auto_inc); - ulint innobase_initialize_autoinc(); + void innobase_initialize_autoinc(); dict_index_t* innobase_get_index(uint keynr); - ulonglong innobase_get_int_col_max_value(const Field* field); /* Init values for the class: */ public: diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 7a43d0f3b92..e9fd12e9747 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -3255,19 +3255,13 @@ check_next_foreign: "END;\n" , FALSE, trx); - if (err != DB_SUCCESS) { - ut_a(err == DB_OUT_OF_FILE_SPACE); - - err = DB_MUST_GET_MORE_FILE_SPACE; - - row_mysql_handle_errors(&err, trx, NULL, NULL); - - ut_error; - } else { + switch (err) { ibool is_temp; const char* name_or_path; mem_heap_t* heap; + case DB_SUCCESS: + heap = mem_heap_create(200); /* Clone the name, in case it has been allocated @@ -3333,7 +3327,27 @@ check_next_foreign: } mem_heap_free(heap); + break; + + case DB_TOO_MANY_CONCURRENT_TRXS: + /* Cannot even find a free slot for the + the undo log. We can directly exit here + and return the DB_TOO_MANY_CONCURRENT_TRXS + error. */ + break; + + case DB_OUT_OF_FILE_SPACE: + err = DB_MUST_GET_MORE_FILE_SPACE; + + row_mysql_handle_errors(&err, trx, NULL, NULL); + + /* Fall through to raise error */ + + default: + /* No other possible error returns */ + ut_error; } + funct_exit: if (locked_dictionary) {