summaryrefslogtreecommitdiff
path: root/innobase
diff options
context:
space:
mode:
authorunknown <monty@hundin.mysql.fi>2002-02-11 13:48:59 +0200
committerunknown <monty@hundin.mysql.fi>2002-02-11 13:48:59 +0200
commite0ccdc17a208abb21cf15e7fbbbc3b88b969e0ec (patch)
treeada172b5dc5dccd546e301548aac618812e19814 /innobase
parentaf932b5db200407cb250d6e398383e8db387e680 (diff)
parent501650c5b16a4c7cf7b673b19f9a2ae9c319e24f (diff)
downloadmariadb-git-e0ccdc17a208abb21cf15e7fbbbc3b88b969e0ec.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')
-rw-r--r--innobase/btr/btr0cur.c20
-rw-r--r--innobase/buf/buf0lru.c1
-rw-r--r--innobase/dict/dict0crea.c21
-rw-r--r--innobase/fil/fil0fil.c10
-rw-r--r--innobase/include/log0recv.h1
-rw-r--r--innobase/include/mem0mem.h19
-rw-r--r--innobase/include/mem0pool.h12
-rw-r--r--innobase/include/row0mysql.h20
-rw-r--r--innobase/include/srv0srv.h6
-rw-r--r--innobase/include/trx0trx.h17
-rw-r--r--innobase/log/log0recv.c3
-rw-r--r--innobase/mem/mem0mem.c54
-rw-r--r--innobase/mem/mem0pool.c36
-rw-r--r--innobase/rem/rem0cmp.c10
-rw-r--r--innobase/row/row0mysql.c274
-rw-r--r--innobase/srv/srv0srv.c97
-rw-r--r--innobase/srv/srv0start.c22
-rw-r--r--innobase/trx/trx0purge.c4
-rw-r--r--innobase/trx/trx0trx.c52
19 files changed, 596 insertions, 83 deletions
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c
index 9f3d02525d8..d6944ecadc8 100644
--- a/innobase/btr/btr0cur.c
+++ b/innobase/btr/btr0cur.c
@@ -2552,6 +2552,7 @@ btr_estimate_number_of_different_key_vals(
ulint total_external_size = 0;
ulint i;
ulint j;
+ ulint add_on;
mtr_t mtr;
n_cols = dict_index_get_n_unique(index);
@@ -2624,8 +2625,25 @@ btr_estimate_number_of_different_key_vals(
+ not_empty_flag)
/ (BTR_KEY_VAL_ESTIMATE_N_PAGES
+ total_external_size);
- }
+ /* If the tree is small, smaller than <
+ 10 * BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size, then
+ the above estimate is ok. For bigger trees it is common that we
+ do not see any borders between key values in the few pages
+ we pick. But still there may be BTR_KEY_VAL_ESTIMATE_N_PAGES
+ different key values, or even more. Let us try to approximate
+ that: */
+
+ add_on = index->stat_n_leaf_pages /
+ (10 * (BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size));
+
+ if (add_on > BTR_KEY_VAL_ESTIMATE_N_PAGES) {
+ add_on = BTR_KEY_VAL_ESTIMATE_N_PAGES;
+ }
+
+ index->stat_n_diff_key_vals[j] += add_on;
+ }
+
mem_free(n_diff);
}
diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c
index a3bb673dfc8..5ab045212c2 100644
--- a/innobase/buf/buf0lru.c
+++ b/innobase/buf/buf0lru.c
@@ -243,7 +243,6 @@ loop:
if (n_iterations > 30) {
ut_print_timestamp(stderr);
fprintf(stderr,
- " ***********************************************\n"
"InnoDB: Warning: difficult to find free blocks from\n"
"InnoDB: the buffer pool (%lu search iterations)! Consider\n"
"InnoDB: increasing the buffer pool size.\n",
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 7b9255b4e27..69b1e7c61fd 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -1235,16 +1235,23 @@ loop:
if (error != DB_SUCCESS) {
fprintf(stderr,
- "InnoDB: foreign constraint creation failed;\n"
+ "InnoDB: Foreign key constraint creation failed:\n"
"InnoDB: internal error number %lu\n", error);
- ut_a(error == DB_OUT_OF_FILE_SPACE);
-
- fprintf(stderr, "InnoDB: tablespace is full\n");
-
- trx_general_rollback_for_mysql(trx, FALSE, NULL);
+ if (error == DB_DUPLICATE_KEY) {
+ fprintf(stderr,
+ "InnoDB: Duplicate key error in system table %s index %s\n",
+ ((dict_index_t*)trx->error_info)->table_name,
+ ((dict_index_t*)trx->error_info)->name);
- error = DB_MUST_GET_MORE_FILE_SPACE;
+ fprintf(stderr, "%s\n", buf);
+
+ fprintf(stderr,
+ "InnoDB: Maybe the internal data dictionary of InnoDB is\n"
+ "InnoDB: out-of-sync from the .frm files of your tables.\n"
+ "InnoDB: See section 15.1 Troubleshooting data dictionary operations\n"
+ "InnoDB: at http://www.innodb.com/ibman.html\n");
+ }
return(error);
}
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index f1f2bc4fa17..727e52707e8 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -1088,7 +1088,15 @@ loop:
node = UT_LIST_GET_FIRST(space->chain);
for (;;) {
- ut_a(node);
+ if (node == NULL) {
+ fprintf(stderr,
+ "InnoDB: Error: trying to access page number %lu in space %lu\n"
+ "InnoDB: which is outside the tablespace bounds.\n"
+ "InnoDB: Byte offset %lu, len %lu, i/o type %lu\n",
+ block_offset, space_id, byte_offset, len, type);
+
+ ut_a(0);
+ }
if (node->size > block_offset) {
/* Found! */
diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h
index 51f14393d38..8f896756db9 100644
--- a/innobase/include/log0recv.h
+++ b/innobase/include/log0recv.h
@@ -258,6 +258,7 @@ struct recv_sys_struct{
extern recv_sys_t* recv_sys;
extern ibool recv_recovery_on;
extern ibool recv_no_ibuf_operations;
+extern ibool recv_needed_recovery;
/* States of recv_addr_struct */
#define RECV_NOT_PROCESSED 71
diff --git a/innobase/include/mem0mem.h b/innobase/include/mem0mem.h
index 57fac93d3ac..89c5428f054 100644
--- a/innobase/include/mem0mem.h
+++ b/innobase/include/mem0mem.h
@@ -269,13 +269,24 @@ mem_realloc(
ulint n, /* in: desired number of bytes */
char* file_name,/* in: file name where called */
ulint line); /* in: line where called */
+#ifdef MEM_PERIODIC_CHECK
+/**********************************************************************
+Goes through the list of all allocated mem blocks, checks their magic
+numbers, and reports possible corruption. */
+void
+mem_validate_all_blocks(void);
+/*=========================*/
+#endif
/*#######################################################################*/
/* The info header of a block in a memory heap */
struct mem_block_info_struct {
+ ulint magic_n;/* magic number for debugging */
+ char file_name[8];/* file name where the mem heap was created */
+ ulint line; /* line number where the mem heap was created */
UT_LIST_BASE_NODE_T(mem_block_t) base; /* In the first block in the
the list this is the base node of the list of blocks;
in subsequent blocks this is undefined */
@@ -299,9 +310,11 @@ struct mem_block_info_struct {
allocated buffer frame, which can be appended as a
free block to the heap, if we need more space;
otherwise, this is NULL */
- ulint magic_n;/* magic number for debugging */
- char file_name[8];/* file name where the mem heap was created */
- ulint line; /* line number where the mem heap was created */
+#ifdef MEM_PERIODIC_CHECK
+ UT_LIST_NODE_T(mem_block_t) mem_block_list;
+ /* List of all mem blocks allocated; protected
+ by the mem_comm_pool mutex */
+#endif
};
#define MEM_BLOCK_MAGIC_N 764741555
diff --git a/innobase/include/mem0pool.h b/innobase/include/mem0pool.h
index eb675b4a7f9..43707bd5f61 100644
--- a/innobase/include/mem0pool.h
+++ b/innobase/include/mem0pool.h
@@ -72,6 +72,18 @@ mem_pool_get_reserved(
/* out: reserved mmeory in bytes */
mem_pool_t* pool); /* in: memory pool */
/************************************************************************
+Reserves the mem pool mutex. */
+
+void
+mem_pool_mutex_enter(void);
+/*======================*/
+/************************************************************************
+Releases the mem pool mutex. */
+
+void
+mem_pool_mutex_exit(void);
+/*=====================*/
+/************************************************************************
Validates a memory pool. */
ibool
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 0346299bb10..48b6ba8a715 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -251,6 +251,24 @@ row_table_add_foreign_constraints(
char* name); /* in: table full name in the normalized form
database_name/table_name */
/*************************************************************************
+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 */
+/*************************************************************************
+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 */
+/*************************************************************************
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. */
@@ -426,7 +444,7 @@ struct row_prebuilt_struct {
fetched row in fetch_cache */
ulint n_fetch_cached; /* number of not yet fetched rows
in fetch_cache */
- mem_heap_t* blob_heap; /* in SELECTS BLOB fields are copied
+ mem_heap_t* blob_heap; /* in SELECTS BLOB fie lds are copied
to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 831b4979356..2b40852fe67 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -250,6 +250,12 @@ mutex, for performace reasons). */
void
srv_active_wake_master_thread(void);
/*===============================*/
+/***********************************************************************
+Wakes up the master thread if it is suspended or being suspended. */
+
+void
+srv_wake_master_thread(void);
+/*========================*/
/*************************************************************************
Puts an OS thread to wait if there are too many concurrent threads
(>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */
diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h
index d67628b8bad..26c9ace08b6 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -50,6 +50,13 @@ trx_allocate_for_mysql(void);
/*========================*/
/* out, own: transaction object */
/************************************************************************
+Creates a transaction object for background operations by the master thread. */
+
+trx_t*
+trx_allocate_for_background(void);
+/*=============================*/
+ /* out, own: transaction object */
+/************************************************************************
Frees a transaction object. */
void
@@ -63,6 +70,13 @@ void
trx_free_for_mysql(
/*===============*/
trx_t* trx); /* in, own: trx object */
+/************************************************************************
+Frees a transaction object of a background operation of the master thread. */
+
+void
+trx_free_for_background(
+/*====================*/
+ trx_t* trx); /* in, own: trx object */
/********************************************************************
Creates trx objects for transactions and initializes the trx list of
trx_sys at database start. Rollback segment and undo log lists must
@@ -266,11 +280,14 @@ struct trx_sig_struct{
transaction is waiting a reply */
};
+#define TRX_MAGIC_N 91118598
+
/* The transaction handle; every session has a trx object which is freed only
when the session is freed; in addition there may be session-less transactions
rolling back after a database recovery */
struct trx_struct{
+ ulint magic_n;
/* All the next fields are protected by the kernel mutex, except the
undo logs which are protected by undo_mutex */
char* op_info; /* English text describing the
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index 7be172685ae..29e87c7572b 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -1020,8 +1020,9 @@ loop:
if (recv_addr->state == RECV_NOT_PROCESSED) {
if (!has_printed) {
+ ut_print_timestamp(stderr);
fprintf(stderr,
-"InnoDB: Starting an apply batch of log records to the database...\n"
+" InnoDB: Starting an apply batch of log records to the database...\n"
"InnoDB: Progress in percents: ");
has_printed = TRUE;
}
diff --git a/innobase/mem/mem0mem.c b/innobase/mem/mem0mem.c
index 3e0a9c008f3..0680968a7eb 100644
--- a/innobase/mem/mem0mem.c
+++ b/innobase/mem/mem0mem.c
@@ -75,6 +75,14 @@ After freeing, all the blocks in the heap are set to random bytes
to help us discover errors which result from the use of
buffers in an already freed heap. */
+#ifdef MEM_PERIODIC_CHECK
+
+ibool mem_block_list_inited;
+/* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
+UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list;
+
+#endif
+
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
Allocates a single buffer of memory from the dynamic memory of
@@ -169,7 +177,19 @@ mem_heap_create_block(
7);
block->file_name[7]='\0';
block->line = line;
+
+#ifdef MEM_PERIODIC_CHECK
+ mem_pool_mutex_enter();
+
+ if (!mem_block_list_inited) {
+ mem_block_list_inited = TRUE;
+ UT_LIST_INIT(mem_block_list);
+ }
+ UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
+
+ mem_pool_mutex_exit();
+#endif
mem_block_set_len(block, len);
mem_block_set_type(block, type);
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
@@ -261,6 +281,13 @@ mem_heap_block_free(
UT_LIST_REMOVE(list, heap->base, block);
+#ifdef MEM_PERIODIC_CHECK
+ mem_pool_mutex_enter();
+
+ UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
+
+ mem_pool_mutex_exit();
+#endif
type = heap->type;
len = block->len;
init_block = block->init_block;
@@ -306,3 +333,30 @@ mem_heap_free_block_free(
heap->free_block = NULL;
}
}
+
+#ifdef MEM_PERIODIC_CHECK
+/**********************************************************************
+Goes through the list of all allocated mem blocks, checks their magic
+numbers, and reports possible corruption. */
+
+void
+mem_validate_all_blocks(void)
+/*=========================*/
+{
+ mem_block_t* block;
+
+ mem_pool_mutex_enter();
+
+ block = UT_LIST_GET_FIRST(mem_block_list);
+
+ while (block) {
+ if (block->magic_n != MEM_BLOCK_MAGIC_N) {
+ mem_analyze_corruption((byte*)block);
+ }
+
+ block = UT_LIST_GET_NEXT(mem_block_list, block);
+ }
+
+ mem_pool_mutex_exit();
+}
+#endif
diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c
index 48e7e686953..3681c8ef779 100644
--- a/innobase/mem/mem0pool.c
+++ b/innobase/mem/mem0pool.c
@@ -78,9 +78,9 @@ pool, and after that its locks will grow into the buffer pool. */
/* The smallest memory area total size */
#define MEM_AREA_MIN_SIZE (2 * MEM_AREA_EXTRA_SIZE)
+
/* Data structure for a memory pool. The space is allocated using the buddy
algorithm, where free list i contains areas of size 2 to power i. */
-
struct mem_pool_struct{
byte* buf; /* memory pool */
ulint size; /* memory common pool size */
@@ -99,6 +99,26 @@ mem_pool_t* mem_comm_pool = NULL;
ulint mem_out_of_mem_err_msg_count = 0;
/************************************************************************
+Reserves the mem pool mutex. */
+
+void
+mem_pool_mutex_enter(void)
+/*======================*/
+{
+ mutex_enter(&(mem_comm_pool->mutex));
+}
+
+/************************************************************************
+Releases the mem pool mutex. */
+
+void
+mem_pool_mutex_exit(void)
+/*=====================*/
+{
+ mutex_exit(&(mem_comm_pool->mutex));
+}
+
+/************************************************************************
Returns memory area size. */
UNIV_INLINE
ulint
@@ -240,15 +260,15 @@ mem_pool_fill_free_list(
if (mem_out_of_mem_err_msg_count % 1000000000 == 0) {
/* We do not print the message every time: */
+
+ ut_print_timestamp(stderr);
fprintf(stderr,
- "Innobase: Warning: out of memory in additional memory pool.\n");
- fprintf(stderr,
- "Innobase: Innobase will start allocating memory from the OS.\n");
- fprintf(stderr,
- "Innobase: You should restart the database with a bigger value in\n");
- fprintf(stderr,
- "Innobase: the MySQL .cnf file for innobase_additional_mem_pool_size.\n");
+ " InnoDB: Out of memory in additional memory pool.\n"
+ "InnoDB: InnoDB will start allocating memory from the OS.\n"
+ "InnoDB: You may get better performance if you configure a bigger\n"
+ "InnoDB: value in the MySQL my.cnf file for\n"
+ "InnoDB: innodb_additional_mem_pool_size.\n");
}
mem_out_of_mem_err_msg_count++;
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index 47b7021bf27..9a5a0eb6e8e 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -113,6 +113,16 @@ cmp_types_are_equal(
return(FALSE);
}
+ if (type1->mtype == DATA_INT
+ && (type1->prtype & DATA_UNSIGNED)
+ != (type2->prtype & DATA_UNSIGNED)) {
+ /* The storage format of an unsigned integer is different
+ from a signed integer: in a signed integer we OR
+ 0x8000... to the value of positive integers. */
+
+ return(FALSE);
+ }
+
if (type1->mtype == DATA_MYSQL
|| type1->mtype == DATA_VARMYSQL) {
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) {
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index cbc22b9b28a..c3d3ed53058 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -20,7 +20,7 @@ Windows 2000 will have something called thread pooling
Another possibility could be to use some very fast user space
thread library. This might confuse NT though.
-(c) 1995 InnoDB Oy
+(c) 1995 Innobase Oy
Created 10/8/1995 Heikki Tuuri
*******************************************************/
@@ -49,6 +49,7 @@ Created 10/8/1995 Heikki Tuuri
#include "btr0sea.h"
#include "dict0load.h"
#include "srv0start.h"
+#include "row0mysql.h"
/* Buffer which can be used in printing fatal error messages */
char srv_fatal_errbuf[5000];
@@ -91,8 +92,43 @@ ibool srv_log_archive_on = TRUE;
ulint srv_log_buffer_size = ULINT_MAX; /* size in database pages */
ibool srv_flush_log_at_trx_commit = TRUE;
-byte srv_latin1_ordering[256]; /* The sort order table of the latin1
- character set */
+byte srv_latin1_ordering[256] /* The sort order table of the latin1
+ character set. The following table is
+ the MySQL order as of Feb 10th, 2002 */
+= {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F
+, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
+, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
+, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
+, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F
+, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
+, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F
+, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
+, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F
+, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
+, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
+, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
+, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F
+, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
+, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F
+, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7
+, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF
+, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7
+, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF
+, 0x41, 0x41, 0x41, 0x41, 0x5C, 0x5B, 0x5C, 0x43
+, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49
+, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x5D, 0xD7
+, 0xD8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0xDF
+, 0x41, 0x41, 0x41, 0x41, 0x5C, 0x5B, 0x5C, 0x43
+, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49
+, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x5D, 0xF7
+, 0xD8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0xFF
+};
ibool srv_use_native_aio = FALSE;
@@ -1920,17 +1956,12 @@ srv_boot(void)
srv_init();
- /* Reserve the first slot for the current thread, i.e., the master
- thread */
-
- srv_table_reserve_slot(SRV_MASTER);
-
return(DB_SUCCESS);
}
/*************************************************************************
Reserves a slot in the thread table for the current MySQL OS thread.
-NOTE! The server mutex has to be reserved by the caller! */
+NOTE! The kernel mutex has to be reserved by the caller! */
static
srv_slot_t*
srv_table_reserve_slot_for_mysql(void)
@@ -1940,6 +1971,8 @@ srv_table_reserve_slot_for_mysql(void)
srv_slot_t* slot;
ulint i;
+ ut_ad(mutex_own(&kernel_mutex));
+
i = 0;
slot = srv_mysql_table + i;
@@ -2361,6 +2394,22 @@ srv_active_wake_master_thread(void)
}
}
+/***********************************************************************
+Wakes up the master thread if it is suspended or being suspended. */
+
+void
+srv_wake_master_thread(void)
+/*========================*/
+{
+ srv_activity_count++;
+
+ mutex_enter(&kernel_mutex);
+
+ srv_release_threads(SRV_MASTER, 1);
+
+ mutex_exit(&kernel_mutex);
+}
+
/*************************************************************************
The master thread controlling the server. */
@@ -2383,6 +2432,7 @@ srv_master_thread(
ulint n_bytes_merged;
ulint n_pages_flushed;
ulint n_bytes_archived;
+ ulint n_tables_to_drop;
ulint n_ios;
ulint n_ios_old;
ulint n_ios_very_old;
@@ -2424,7 +2474,11 @@ loop:
can drop tables lazily after there no longer are SELECT
queries to them. */
-/* row_drop_tables_for_mysql_in_background(); */
+ srv_main_thread_op_info = "doing background drop tables";
+
+ row_drop_tables_for_mysql_in_background();
+
+ srv_main_thread_op_info = "";
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
@@ -2475,6 +2529,11 @@ loop:
printf("Master thread wakes up!\n");
}
+#ifdef MEM_PERIODIC_CHECK
+ /* Check magic numbers of every allocated mem block once in 10
+ seconds */
+ mem_validate_all_blocks();
+#endif
/* If there were less than 200 i/os during the 10 second period,
we assume that there is free disk i/o capacity available, and it
makes sense to do a buffer pool flush. */
@@ -2531,6 +2590,12 @@ background_loop:
/* In this loop we run background operations when the server
is quiet and we also come here about once in 10 seconds */
+ srv_main_thread_op_info = "doing background drop tables";
+
+ n_tables_to_drop = row_drop_tables_for_mysql_in_background();
+
+ srv_main_thread_op_info = "";
+
srv_main_thread_op_info = "flushing buffer pool pages";
/* Flush a few oldest pages to make the checkpoint younger */
@@ -2616,11 +2681,13 @@ background_loop:
log_archive_do(FALSE, &n_bytes_archived);
if (srv_fast_shutdown && srv_shutdown_state > 0) {
- if (n_pages_flushed + n_bytes_archived != 0) {
+ if (n_tables_to_drop + n_pages_flushed
+ + n_bytes_archived != 0) {
goto background_loop;
}
- } else if (n_pages_purged + n_bytes_merged + n_pages_flushed
+ } else if (n_tables_to_drop +
+ n_pages_purged + n_bytes_merged + n_pages_flushed
+ n_bytes_archived != 0) {
goto background_loop;
}
@@ -2639,6 +2706,12 @@ suspend_thread:
mutex_enter(&kernel_mutex);
+ if (row_get_background_drop_list_len_low() > 0) {
+ mutex_exit(&kernel_mutex);
+
+ goto loop;
+ }
+
event = srv_suspend_thread();
mutex_exit(&kernel_mutex);
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 70c85d7fbeb..bbb48331811 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -271,13 +271,18 @@ open_or_create_log_file(
} else {
*log_file_created = TRUE;
+ ut_print_timestamp(stderr);
+
fprintf(stderr,
- "InnoDB: Log file %s did not exist: new to be created\n",
+ " InnoDB: Log file %s did not exist: new to be created\n",
name);
fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n",
name, srv_log_file_size
>> (20 - UNIV_PAGE_SIZE_SHIFT));
+ fprintf(stderr,
+ "InnoDB: Database physically writes the file full: wait...\n");
+
ret = os_file_set_size(name, files[i],
srv_calc_low32(srv_log_file_size),
srv_calc_high32(srv_log_file_size));
@@ -456,8 +461,9 @@ open_or_create_data_files(
one_created = TRUE;
if (i > 0) {
+ ut_print_timestamp(stderr);
fprintf(stderr,
- "InnoDB: Data file %s did not exist: new to be created\n",
+ " InnoDB: Data file %s did not exist: new to be created\n",
name);
} else {
fprintf(stderr,
@@ -466,8 +472,9 @@ open_or_create_data_files(
*create_new_db = TRUE;
}
+ ut_print_timestamp(stderr);
fprintf(stderr,
- "InnoDB: Setting file %s size to %lu MB\n",
+ " InnoDB: Setting file %s size to %lu MB\n",
name, (srv_data_file_sizes[i]
>> (20 - UNIV_PAGE_SIZE_SHIFT)));
@@ -911,6 +918,12 @@ innobase_start_or_create_for_mysql(void)
mtr_commit(&mtr);
}
+ if (recv_needed_recovery) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Flushing modified pages from the buffer pool...\n");
+ }
+
log_make_checkpoint_at(ut_dulint_max, TRUE);
if (!srv_log_archive_on) {
@@ -991,9 +1004,8 @@ innobase_shutdown_for_mysql(void)
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: shutting down a not properly started\n");
- ut_print_timestamp(stderr);
fprintf(stderr,
- " InnoDB: or created database!\n");
+ " InnoDB: or created database!\n");
}
return(DB_SUCCESS);
diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c
index 31a0c20ad14..97362d00b4b 100644
--- a/innobase/trx/trx0purge.c
+++ b/innobase/trx/trx0purge.c
@@ -226,9 +226,9 @@ trx_purge_sys_create(void)
value */
purge_sys->sess = sess_open(com_endpoint, (byte*)"purge_system", 13);
- purge_sys->trx = (purge_sys->sess)->trx;
+ purge_sys->trx = purge_sys->sess->trx;
- (purge_sys->trx)->type = TRX_PURGE;
+ purge_sys->trx->type = TRX_PURGE;
ut_a(trx_start_low(purge_sys->trx, ULINT_UNDEFINED));
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 315bb7030ee..607c80edd09 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -26,9 +26,9 @@ Created 3/26/1996 Heikki Tuuri
/* Copy of the prototype for innobase_mysql_print_thd: this
- copy must be equal to the one in mysql/sql/ha_innobase.cc ! */
-void innobase_mysql_print_thd(void* thd);
+copy must be equal to the one in mysql/sql/ha_innobase.cc ! */
+void innobase_mysql_print_thd(void* thd);
/* Dummy session used currently in MySQL interface */
sess_t* trx_dummy_sess = NULL;
@@ -64,6 +64,8 @@ trx_create(
trx = mem_alloc(sizeof(trx_t));
+ trx->magic_n = TRX_MAGIC_N;
+
trx->op_info = (char *) "";
trx->type = TRX_USER;
@@ -158,6 +160,32 @@ trx_allocate_for_mysql(void)
}
/************************************************************************
+Creates a transaction object for background operations by the master thread. */
+
+trx_t*
+trx_allocate_for_background(void)
+/*=============================*/
+ /* out, own: transaction object */
+{
+ trx_t* trx;
+
+ mutex_enter(&kernel_mutex);
+
+ /* Open a dummy session */
+
+ if (!trx_dummy_sess) {
+ trx_dummy_sess = sess_open(NULL, (byte*)"Dummy sess",
+ ut_strlen("Dummy sess"));
+ }
+
+ trx = trx_create(trx_dummy_sess);
+
+ mutex_exit(&kernel_mutex);
+
+ return(trx);
+}
+
+/************************************************************************
Releases the search latch if trx has reserved it. */
void
@@ -181,6 +209,11 @@ trx_free(
trx_t* trx) /* in, own: trx object */
{
ut_ad(mutex_own(&kernel_mutex));
+
+ ut_a(trx->magic_n == TRX_MAGIC_N);
+
+ trx->magic_n = 11112222;
+
ut_a(trx->conc_state == TRX_NOT_STARTED);
mutex_free(&(trx->undo_mutex));
@@ -242,6 +275,21 @@ trx_free_for_mysql(
mutex_exit(&kernel_mutex);
}
+/************************************************************************
+Frees a transaction object of a background operation of the master thread. */
+
+void
+trx_free_for_background(
+/*====================*/
+ trx_t* trx) /* in, own: trx object */
+{
+ mutex_enter(&kernel_mutex);
+
+ trx_free(trx);
+
+ mutex_exit(&kernel_mutex);
+}
+
/********************************************************************
Inserts the trx handle in the trx system trx list in the right position.
The list is sorted on the trx id so that the biggest id is at the list