diff options
author | unknown <monty@hundin.mysql.fi> | 2002-02-11 13:48:59 +0200 |
---|---|---|
committer | unknown <monty@hundin.mysql.fi> | 2002-02-11 13:48:59 +0200 |
commit | a68e9ccd2d25a4dc309a5df2c0b3693cc6e682b3 (patch) | |
tree | ada172b5dc5dccd546e301548aac618812e19814 /innobase/row | |
parent | 4e97f5c3e207ddbfbc26b21bf05053ca20f9ba91 (diff) | |
parent | 7a93e9bed192f3f1bfeaaf315abafe0391f74e82 (diff) | |
download | mariadb-git-a68e9ccd2d25a4dc309a5df2c0b3693cc6e682b3.tar.gz |
merge with 3.23.48
BUILD/FINISH.sh:
Auto merged
BUILD/SETUP.sh:
Auto merged
BUILD/compile-alpha:
Auto merged
BUILD/compile-pentium-gcov:
Auto merged
BUILD/compile-pentium-gprof:
Auto merged
BUILD/compile-pentium:
Auto merged
BitKeeper/deleted/.del-my_new.cc:
Delete: mysys/my_new.cc
Build-tools/Do-compile:
Auto merged
acconfig.h:
Auto merged
acinclude.m4:
Auto merged
Docs/manual.texi:
Auto merged
bdb/dist/configure.in:
Auto merged
client/Makefile.am:
Auto merged
innobase/btr/btr0cur.c:
Auto merged
innobase/buf/buf0lru.c:
Auto merged
innobase/dict/dict0crea.c:
Auto merged
innobase/fil/fil0fil.c:
Auto merged
innobase/include/srv0srv.h:
Auto merged
innobase/rem/rem0cmp.c:
Auto merged
innobase/srv/srv0srv.c:
Auto merged
innobase/srv/srv0start.c:
Auto merged
innobase/trx/trx0purge.c:
Auto merged
myisam/myisampack.c:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/t/join.test:
Auto merged
mysys/Makefile.am:
Auto merged
scripts/Makefile.am:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/handler.cc:
Auto merged
sql/my_lock.c:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_table.cc:
Auto merged
support-files/my-huge.cnf.sh:
Auto merged
support-files/my-large.cnf.sh:
Auto merged
support-files/my-medium.cnf.sh:
Auto merged
support-files/my-small.cnf.sh:
Auto merged
configure.in:
merge
innobase/row/row0mysql.c:
merge
innobase/trx/trx0trx.c:
merge
mysql-test/r/innodb.result:
merge
mysql-test/r/join.result:
merge
sql/ha_innodb.cc:
merge
sql/slave.cc:
merge
Diffstat (limited to 'innobase/row')
-rw-r--r-- | innobase/row/row0mysql.c | 274 |
1 files changed, 235 insertions, 39 deletions
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 00184c13ae9..292f8c0c6c8 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -26,6 +26,19 @@ Created 9/17/2000 Heikki Tuuri #include "trx0purge.h" #include "lock0lock.h" #include "rem0cmp.h" +#include "log0log.h" + +/* List of tables we should drop in background. ALTER TABLE in MySQL requires +that the table handler can drop the table in background when there are no +queries to it any more. Protected by the kernel mutex. */ +typedef struct row_mysql_drop_struct row_mysql_drop_t; +struct row_mysql_drop_struct{ + char* table_name; + UT_LIST_NODE_T(row_mysql_drop_t) row_mysql_drop_list; +}; + +UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list; +ibool row_mysql_drop_list_inited = FALSE; /*********************************************************************** Reads a MySQL format variable-length field (like VARCHAR) length and @@ -172,10 +185,22 @@ handle_new_error: trx_general_rollback_for_mysql(trx, TRUE, savept); } } else if (err == DB_TOO_BIG_RECORD) { + if (savept) { + /* Roll back the latest, possibly incomplete + insertion or update */ + + trx_general_rollback_for_mysql(trx, TRUE, savept); + } /* MySQL will roll back the latest SQL statement */ } else if (err == DB_ROW_IS_REFERENCED || err == DB_NO_REFERENCED_ROW || err == DB_CANNOT_ADD_CONSTRAINT) { + if (savept) { + /* Roll back the latest, possibly incomplete + insertion or update */ + + trx_general_rollback_for_mysql(trx, TRUE, savept); + } /* MySQL will roll back the latest SQL statement */ } else if (err == DB_LOCK_WAIT) { @@ -200,6 +225,12 @@ handle_new_error: trx_general_rollback_for_mysql(trx, FALSE, NULL); } else if (err == DB_OUT_OF_FILE_SPACE) { + if (savept) { + /* Roll back the latest, possibly incomplete + insertion or update */ + + trx_general_rollback_for_mysql(trx, TRUE, savept); + } /* MySQL will roll back the latest SQL statement */ } else if (err == DB_MUST_GET_MORE_FILE_SPACE) { @@ -375,13 +406,13 @@ row_update_prebuilt_trx( handle */ trx_t* trx) /* in: transaction handle */ { - if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { + if (trx->magic_n != TRX_MAGIC_N) { fprintf(stderr, - "InnoDB: Error: trying to free a corrupt\n" - "InnoDB: table handle. Magic n %lu, table name %s\n", - prebuilt->magic_n, prebuilt->table->name); + "InnoDB: Error: trying to use a corrupt\n" + "InnoDB: trx handle. Magic n %lu\n", + trx->magic_n); - mem_analyze_corruption((byte*)prebuilt); + mem_analyze_corruption((byte*)trx); ut_a(0); } @@ -1172,8 +1203,11 @@ row_create_table_for_mysql( row_drop_table_for_mysql(table->name, trx, TRUE); } else { ut_a(err == DB_DUPLICATE_KEY); + + ut_print_timestamp(stderr); + fprintf(stderr, - "InnoDB: Error: table %s already exists in InnoDB internal\n" + " InnoDB: Error: table %s already exists in InnoDB internal\n" "InnoDB: data dictionary. Have you deleted the .frm file\n" "InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n" "InnoDB: for InnoDB tables in MySQL version <= 3.23.43?\n" @@ -1352,6 +1386,164 @@ row_table_add_foreign_constraints( } /************************************************************************* +Drops a table for MySQL as a background operation. MySQL relies on Unix +in ALTER TABLE to the fact that the table handler does not remove the +table before all handles to it has been removed. Furhermore, the MySQL's +call to drop table must be non-blocking. Therefore we do the drop table +as a background operation, which is taken care of by the master thread +in srv0srv.c. */ +static +int +row_drop_table_for_mysql_in_background( +/*===================================*/ + /* out: error code or DB_SUCCESS */ + char* name) /* in: table name */ +{ + ulint error; + trx_t* trx; + + trx = trx_allocate_for_background(); + +/* fprintf(stderr, "InnoDB: Dropping table %s in background drop list\n", + name); */ + /* Drop the table in InnoDB */ + + error = row_drop_table_for_mysql(name, trx, FALSE); + + if (error != DB_SUCCESS) { + fprintf(stderr, + "InnoDB: Error: Dropping table %s in background drop list failed\n", + name); + } + + /* Flush the log to reduce probability that the .frm files and + the InnoDB data dictionary get out-of-sync if the user runs + with innodb_flush_log_at_trx_commit = 0 */ + + log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + + trx_commit_for_mysql(trx); + + trx_free_for_background(trx); + + return(DB_SUCCESS); +} + +/************************************************************************* +The master thread in srv0srv.c calls this regularly to drop tables which +we must drop in background after queries to them have ended. Such lazy +dropping of tables is needed in ALTER TABLE on Unix. */ + +ulint +row_drop_tables_for_mysql_in_background(void) +/*=========================================*/ + /* out: how many tables dropped + + remaining tables in list */ +{ + row_mysql_drop_t* drop; + dict_table_t* table; + ulint n_tables; + ulint n_tables_dropped = 0; +loop: + mutex_enter(&kernel_mutex); + + if (!row_mysql_drop_list_inited) { + + UT_LIST_INIT(row_mysql_drop_list); + row_mysql_drop_list_inited = TRUE; + } + + drop = UT_LIST_GET_FIRST(row_mysql_drop_list); + + n_tables = UT_LIST_GET_LEN(row_mysql_drop_list); + + mutex_exit(&kernel_mutex); + + if (drop == NULL) { + + return(n_tables + n_tables_dropped); + } + + mutex_enter(&(dict_sys->mutex)); + table = dict_table_get_low(drop->table_name); + mutex_exit(&(dict_sys->mutex)); + + if (table->n_mysql_handles_opened > 0) { + + return(n_tables + n_tables_dropped); + } + + n_tables_dropped++; + + row_drop_table_for_mysql_in_background(drop->table_name); + + mutex_enter(&kernel_mutex); + + UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop); + + mem_free(drop->table_name); + + mem_free(drop); + + mutex_exit(&kernel_mutex); + + goto loop; +} + +/************************************************************************* +Get the background drop list length. NOTE: the caller must own the kernel +mutex! */ + +ulint +row_get_background_drop_list_len_low(void) +/*======================================*/ + /* out: how many tables in list */ +{ + ut_ad(mutex_own(&kernel_mutex)); + + if (!row_mysql_drop_list_inited) { + + UT_LIST_INIT(row_mysql_drop_list); + row_mysql_drop_list_inited = TRUE; + } + + return(UT_LIST_GET_LEN(row_mysql_drop_list)); +} + +/************************************************************************* +Adds a table to the list of tables which the master thread drops in +background. We need this on Unix because in ALTER TABLE MySQL may call +drop table even if the table has running queries on it. */ +static +void +row_add_table_to_background_drop_list( +/*==================================*/ + dict_table_t* table) /* in: table */ +{ + row_mysql_drop_t* drop; + + drop = mem_alloc(sizeof(row_mysql_drop_t)); + + drop->table_name = mem_alloc(1 + ut_strlen(table->name)); + + ut_memcpy(drop->table_name, table->name, 1 + ut_strlen(table->name)); + + mutex_enter(&kernel_mutex); + + if (!row_mysql_drop_list_inited) { + + UT_LIST_INIT(row_mysql_drop_list); + row_mysql_drop_list_inited = TRUE; + } + + UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop); + +/* fprintf(stderr, "InnoDB: Adding table %s to background drop list\n", + drop->table_name); */ + mutex_exit(&kernel_mutex); +} + +/************************************************************************* Drops a table for MySQL. If the name of the dropped table ends to characters INNODB_MONITOR, then this also stops printing of monitor output by the master thread. */ @@ -1541,9 +1733,10 @@ row_drop_table_for_mysql( if (!table) { err = DB_TABLE_NOT_FOUND; + ut_print_timestamp(stderr); fprintf(stderr, - "InnoDB: Error: table %s does not exist in the InnoDB internal\n" + " InnoDB: Error: table %s does not exist in the InnoDB internal\n" "InnoDB: data dictionary though MySQL is trying to drop it.\n" "InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: MySQL database directory from another database?\n", @@ -1551,42 +1744,19 @@ row_drop_table_for_mysql( goto funct_exit; } - /* Remove any locks there are on the table or its records */ - - lock_reset_all_on_table(table); -loop: if (table->n_mysql_handles_opened > 0) { - rw_lock_s_unlock(&(purge_sys->purge_is_running)); - - rw_lock_x_unlock(&(dict_foreign_key_check_lock)); - - mutex_exit(&(dict_sys->mutex)); - - if (rounds > 60) { - fprintf(stderr, - "InnoDB: waiting for queries to table %s to end before dropping it\n", - name); - } - os_thread_sleep(1000000); + row_add_table_to_background_drop_list(table); - mutex_enter(&(dict_sys->mutex)); - - rw_lock_x_lock(&(dict_foreign_key_check_lock)); - - rw_lock_s_lock(&(purge_sys->purge_is_running)); + err = DB_SUCCESS; - rounds++; - - if (rounds > 120) { - fprintf(stderr, -"InnoDB: Warning: queries to table %s have not ended but we continue anyway\n", - name); - } else { - goto loop; - } + goto funct_exit; } + /* Remove any locks there are on the table or its records */ + + lock_reset_all_on_table(table); + trx->dict_operation = TRUE; trx->table_id = table->id; @@ -1622,6 +1792,8 @@ funct_exit: trx->op_info = (char *) ""; + srv_wake_master_thread(); + return((int) err); } @@ -1793,7 +1965,31 @@ row_rename_table_for_mysql( err = trx->error_state; if (err != DB_SUCCESS) { - row_mysql_handle_errors(&err, trx, thr, NULL); + if (err == DB_DUPLICATE_KEY) { + ut_print_timestamp(stderr); + + fprintf(stderr, + " InnoDB: Error: table %s exists in the InnoDB internal data\n" + "InnoDB: dictionary though MySQL is trying rename table %s to it.\n" + "InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n", + new_name, old_name); + + fprintf(stderr, + "InnoDB: If table %s is a temporary table #sql..., then it can be that\n" + "InnoDB: there are still queries running on the table, and it will be\n" + "InnoDB: dropped automatically when the queries end.\n", new_name); + + fprintf(stderr, + "InnoDB: You can drop the orphaned table inside InnoDB by\n" + "InnoDB: creating an InnoDB table with the same name in another\n" + "InnoDB: database and moving the .frm file to the current database.\n" + "InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n" + "InnoDB: succeed.\n"); + } + + trx->error_state = DB_SUCCESS; + trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx->error_state = DB_SUCCESS; } else { ut_a(dict_table_rename_in_cache(table, new_name)); } @@ -1950,7 +2146,7 @@ row_check_table_for_mysql( ulint ret = DB_SUCCESS; prebuilt->trx->op_info = (char *) "checking table"; - + index = dict_table_get_first_index(table); while (index != NULL) { |