summaryrefslogtreecommitdiff
path: root/innobase/row/row0mysql.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/row/row0mysql.c')
-rw-r--r--innobase/row/row0mysql.c223
1 files changed, 186 insertions, 37 deletions
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 50ec88c595d..00184c13ae9 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -242,10 +242,14 @@ row_create_prebuilt(
ulint ref_len;
ulint i;
+ dict_table_increment_handle_count(table);
+
heap = mem_heap_create(128);
prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
+ prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
+
prebuilt->table = table;
prebuilt->trx = NULL;
@@ -294,7 +298,7 @@ row_create_prebuilt(
prebuilt->blob_heap = NULL;
prebuilt->old_vers_heap = NULL;
-
+
return(prebuilt);
}
@@ -308,6 +312,19 @@ row_prebuilt_free(
{
ulint i;
+ if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
+ 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);
+
+ mem_analyze_corruption((byte*)prebuilt);
+
+ ut_a(0);
+ }
+
+ prebuilt->magic_n = ROW_PREBUILT_FREED;
+
btr_pcur_free_for_mysql(prebuilt->pcur);
btr_pcur_free_for_mysql(prebuilt->clust_pcur);
@@ -341,6 +358,8 @@ row_prebuilt_free(
}
}
+ dict_table_decrement_handle_count(prebuilt->table);
+
mem_heap_free(prebuilt->heap);
}
@@ -356,6 +375,28 @@ row_update_prebuilt_trx(
handle */
trx_t* trx) /* in: transaction handle */
{
+ if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
+ 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);
+
+ mem_analyze_corruption((byte*)prebuilt);
+
+ ut_a(0);
+ }
+
+ if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
+ fprintf(stderr,
+ "InnoDB: Error: trying to use a corrupt\n"
+ "InnoDB: table handle. Magic n %lu, table name %s\n",
+ prebuilt->magic_n, prebuilt->table->name);
+
+ mem_analyze_corruption((byte*)prebuilt);
+
+ ut_a(0);
+ }
+
prebuilt->trx = trx;
if (prebuilt->ins_graph) {
@@ -563,6 +604,17 @@ row_insert_for_mysql(
ut_ad(trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
+ if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
+ 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);
+
+ mem_analyze_corruption((byte*)prebuilt);
+
+ ut_a(0);
+ }
+
if (srv_created_new_raw || srv_force_recovery) {
fprintf(stderr,
"InnoDB: A new raw disk partition was initialized or\n"
@@ -748,6 +800,17 @@ row_update_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
UT_NOT_USED(mysql_rec);
+ if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
+ 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);
+
+ mem_analyze_corruption((byte*)prebuilt);
+
+ ut_a(0);
+ }
+
if (srv_created_new_raw || srv_force_recovery) {
fprintf(stderr,
"InnoDB: A new raw disk partition was initialized or\n"
@@ -782,38 +845,6 @@ row_update_for_mysql(
generated for the table: MySQL does not know anything about
the row id used as the clustered index key */
-#ifdef notdefined
- /* We have to search for the correct cursor position */
-
- ref_len = dict_index_get_n_unique(clust_index);
-
- heap = mem_heap_create(450);
-
- row_tuple = dtuple_create(heap, dict_table_get_n_cols(table));
- dict_table_copy_types(row_tuple, table);
-
- if (prebuilt->ins_upd_rec_buff == NULL) {
- prebuilt->ins_upd_rec_buff = mem_heap_alloc(prebuilt->heap,
- prebuilt->mysql_row_len);
- }
-
- row_mysql_convert_row_to_innobase(row_tuple, prebuilt, mysql_rec);
-
- search_tuple = dtuple_create(heap, ref_len);
-
- row_build_row_ref_from_row(search_tuple, table, row_tuple);
-
- mtr_start(&mtr);
-
- btr_pcur_open_with_no_init(clust_index, search_tuple, PAGE_CUR_LE,
- BTR_SEARCH_LEAF, node->pcur, 0, &mtr);
-
- btr_pcur_store_position(node->pcur, &mtr);
-
- mtr_commit(&mtr);
-
- mem_heap_free(heap);
-#endif
savept = trx_savept_take(trx);
thr = que_fork_get_first_thr(prebuilt->upd_graph);
@@ -923,6 +954,50 @@ row_get_mysql_key_number_for_index(
}
/*************************************************************************
+Recovers an orphaned tmp table inside InnoDB by renaming it. In the table
+name #sql becomes rsql, and "_recover_innodb_tmp_table" is catenated to
+the end of name. table->name should be of the form
+"dbname/rsql..._recover_innodb_tmp_table". This renames a table whose
+name is "#sql..." */
+static
+int
+row_mysql_recover_tmp_table(
+/*========================*/
+ /* out: error code or DB_SUCCESS */
+ dict_table_t* table, /* in: table definition */
+ trx_t* trx) /* in: transaction handle */
+{
+ char* ptr;
+ char old_name[1000];
+
+ ut_memcpy(old_name, table->name, ut_strlen(table->name) + 1);
+
+ ptr = old_name;
+
+ for (;;) {
+ if (ptr >= old_name + ut_strlen(table->name) - 6) {
+ trx_commit_for_mysql(trx);
+
+ return(DB_ERROR);
+ }
+
+ if (0 == ut_memcmp(ptr, "/rsql", 5)) {
+ ptr++;
+ *ptr = '#';
+
+ break;
+ }
+
+ ptr++;
+ }
+
+ old_name[ut_strlen(table->name)
+ - ut_strlen("_recover_innodb_tmp_table")] = '\0';
+
+ return(row_rename_table_for_mysql(old_name, table->name, trx));
+}
+
+/*************************************************************************
Does a table creation operation for MySQL. If the name of the created
table ends to characters INNODB_MONITOR, then this also starts
printing of monitor output by the master thread. */
@@ -976,6 +1051,24 @@ row_create_table_for_mysql(
namelen = ut_strlen(table->name);
+ keywordlen = ut_strlen("_recover_innodb_tmp_table");
+
+ if (namelen >= keywordlen
+ && 0 == ut_memcmp(table->name + namelen - keywordlen,
+ "_recover_innodb_tmp_table", keywordlen)) {
+
+ /* MySQL prevents accessing of tables whose name begins
+ with #sql, that is temporary tables. If mysqld crashes in
+ the middle of an ALTER TABLE, we may get an orphaned
+ #sql-table in the tablespace. We have here a special
+ mechanism to recover such tables by renaming them to
+ rsql... */
+
+ return(row_mysql_recover_tmp_table(table, trx));
+ }
+
+ namelen = ut_strlen(table->name);
+
keywordlen = ut_strlen((char *) "innodb_monitor");
if (namelen >= keywordlen
@@ -1120,6 +1213,8 @@ row_create_index_for_mysql(
ind_node_t* node;
mem_heap_t* heap;
que_thr_t* thr;
+ ulint namelen;
+ ulint keywordlen;
ulint err;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
@@ -1128,6 +1223,18 @@ row_create_index_for_mysql(
trx_start_if_not_started(trx);
+ namelen = ut_strlen(index->table_name);
+
+ keywordlen = ut_strlen("_recover_innodb_tmp_table");
+
+ if (namelen >= keywordlen
+ && 0 == ut_memcmp(
+ index->table_name + namelen - keywordlen,
+ "_recover_innodb_tmp_table", keywordlen)) {
+
+ return(DB_SUCCESS);
+ }
+
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
@@ -1191,6 +1298,8 @@ row_table_add_foreign_constraints(
char* name) /* in: table full name in the normalized form
database_name/table_name */
{
+ ulint namelen;
+ ulint keywordlen;
ulint err;
ut_a(sql_string);
@@ -1199,6 +1308,18 @@ row_table_add_foreign_constraints(
trx_start_if_not_started(trx);
+ namelen = ut_strlen(name);
+
+ keywordlen = ut_strlen("_recover_innodb_tmp_table");
+
+ if (namelen >= keywordlen
+ && 0 == ut_memcmp(
+ name + namelen - keywordlen,
+ "_recover_innodb_tmp_table", keywordlen)) {
+
+ return(DB_SUCCESS);
+ }
+
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
@@ -1253,6 +1374,7 @@ row_drop_table_for_mysql(
ulint len;
ulint namelen;
ulint keywordlen;
+ ulint rounds = 0;
char buf[10000];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
@@ -1432,11 +1554,38 @@ row_drop_table_for_mysql(
/* 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);
+
+ mutex_enter(&(dict_sys->mutex));
+
+ rw_lock_x_lock(&(dict_foreign_key_check_lock));
+
+ rw_lock_s_lock(&(purge_sys->purge_is_running));
- /* TODO: check that MySQL prevents users from accessing the table
- after this function row_drop_table_for_mysql has been called:
- otherwise anyone with an open handle to the table could, for example,
- come to read the table! Monty said that it prevents. */
+ rounds++;
+
+ if (rounds > 120) {
+ fprintf(stderr,
+"InnoDB: Warning: queries to table %s have not ended but we continue anyway\n",
+ name);
+ } else {
+ goto loop;
+ }
+ }
trx->dict_operation = TRUE;
trx->table_id = table->id;