summaryrefslogtreecommitdiff
path: root/innobase
diff options
context:
space:
mode:
authorunknown <heikki@donna.mysql.fi>2002-01-28 22:18:49 +0200
committerunknown <heikki@donna.mysql.fi>2002-01-28 22:18:49 +0200
commitac540e96a915c30034a4fc03ef65b60b8392f664 (patch)
treeaa7f771761883b28925048ff5e37e2eb85d77c00 /innobase
parent2aa572433b9ce47a511958ce263c8400c2e81ac3 (diff)
downloadmariadb-git-ac540e96a915c30034a4fc03ef65b60b8392f664.tar.gz
Many files:
Merge InnoDB-.48 sql/ha_innobase.cc: Merge InnoDB-.48 innobase/include/dict0dict.h: Merge InnoDB-.48 innobase/include/dict0mem.h: Merge InnoDB-.48 innobase/include/mem0dbg.h: Merge InnoDB-.48 innobase/include/mem0mem.h: Merge InnoDB-.48 innobase/include/que0que.h: Merge InnoDB-.48 innobase/include/row0mysql.h: Merge InnoDB-.48 innobase/include/srv0srv.h: Merge InnoDB-.48 innobase/include/trx0sys.h: Merge InnoDB-.48 innobase/include/trx0trx.h: Merge InnoDB-.48 innobase/include/mem0mem.ic: Merge InnoDB-.48 innobase/dict/dict0dict.c: Merge InnoDB-.48 innobase/dict/dict0mem.c: Merge InnoDB-.48 innobase/log/log0recv.c: Merge InnoDB-.48 innobase/mem/mem0dbg.c: Merge InnoDB-.48 innobase/mem/mem0mem.c: Merge InnoDB-.48 innobase/pars/lexyy.c: Merge InnoDB-.48 innobase/que/que0que.c: Merge InnoDB-.48 innobase/rem/rem0rec.c: Merge InnoDB-.48 innobase/row/row0mysql.c: Merge InnoDB-.48 innobase/row/row0sel.c: Merge InnoDB-.48 innobase/srv/srv0srv.c: Merge InnoDB-.48 innobase/sync/sync0arr.c: Merge InnoDB-.48 innobase/trx/trx0sys.c: Merge InnoDB-.48 innobase/trx/trx0trx.c: Merge InnoDB-.48 innobase/trx/trx0undo.c: Merge InnoDB-.48
Diffstat (limited to 'innobase')
-rw-r--r--innobase/dict/dict0dict.c32
-rw-r--r--innobase/dict/dict0mem.c3
-rw-r--r--innobase/include/dict0dict.h14
-rw-r--r--innobase/include/dict0mem.h6
-rw-r--r--innobase/include/mem0dbg.h14
-rw-r--r--innobase/include/mem0mem.h97
-rw-r--r--innobase/include/mem0mem.ic57
-rw-r--r--innobase/include/que0que.h5
-rw-r--r--innobase/include/row0mysql.h7
-rw-r--r--innobase/include/srv0srv.h26
-rw-r--r--innobase/include/trx0sys.h35
-rw-r--r--innobase/include/trx0trx.h22
-rw-r--r--innobase/log/log0recv.c20
-rw-r--r--innobase/mem/mem0dbg.c94
-rw-r--r--innobase/mem/mem0mem.c32
-rw-r--r--innobase/pars/lexyy.c2
-rw-r--r--innobase/que/que0que.c40
-rw-r--r--innobase/rem/rem0rec.c11
-rw-r--r--innobase/row/row0mysql.c223
-rw-r--r--innobase/row/row0sel.c11
-rw-r--r--innobase/srv/srv0srv.c124
-rw-r--r--innobase/sync/sync0arr.c11
-rw-r--r--innobase/trx/trx0sys.c111
-rw-r--r--innobase/trx/trx0trx.c13
-rw-r--r--innobase/trx/trx0undo.c19
25 files changed, 846 insertions, 183 deletions
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 9e32be9e02d..95f9b54c914 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -196,6 +196,38 @@ dict_mutex_exit_for_mysql(void)
}
/************************************************************************
+Increments the count of open MySQL handles to a table. */
+
+void
+dict_table_increment_handle_count(
+/*==============================*/
+ dict_table_t* table) /* in: table */
+{
+ mutex_enter(&(dict_sys->mutex));
+
+ table->n_mysql_handles_opened++;
+
+ mutex_exit(&(dict_sys->mutex));
+}
+
+/************************************************************************
+Decrements the count of open MySQL handles to a table. */
+
+void
+dict_table_decrement_handle_count(
+/*==============================*/
+ dict_table_t* table) /* in: table */
+{
+ mutex_enter(&(dict_sys->mutex));
+
+ ut_a(table->n_mysql_handles_opened > 0);
+
+ table->n_mysql_handles_opened--;
+
+ mutex_exit(&(dict_sys->mutex));
+}
+
+/************************************************************************
Gets the nth column of a table. */
dict_col_t*
diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c
index 019d6ef334f..1f9a44aca35 100644
--- a/innobase/dict/dict0mem.c
+++ b/innobase/dict/dict0mem.c
@@ -59,6 +59,9 @@ dict_mem_table_create(
table->n_def = 0;
table->n_cols = n_cols + DATA_N_SYS_COLS;
table->mem_fix = 0;
+
+ table->n_mysql_handles_opened = 0;
+
table->cached = FALSE;
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h
index ae313398c99..79d67ecae15 100644
--- a/innobase/include/dict0dict.h
+++ b/innobase/include/dict0dict.h
@@ -26,6 +26,20 @@ Created 1/8/1996 Heikki Tuuri
#include "ut0byte.h"
#include "trx0types.h"
+/************************************************************************
+Increments the count of open MySQL handles to a table. */
+
+void
+dict_table_increment_handle_count(
+/*==============================*/
+ dict_table_t* table); /* in: table */
+/************************************************************************
+Decrements the count of open MySQL handles to a table. */
+
+void
+dict_table_decrement_handle_count(
+/*==============================*/
+ dict_table_t* table); /* in: table */
/**************************************************************************
Inits the data dictionary module. */
diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h
index 2f00ccfcf32..5ef0103087a 100644
--- a/innobase/include/dict0mem.h
+++ b/innobase/include/dict0mem.h
@@ -307,6 +307,12 @@ struct dict_table_struct{
ulint mem_fix;/* count of how many times the table
and its indexes has been fixed in memory;
currently NOT used */
+ ulint n_mysql_handles_opened;
+ /* count of how many handles MySQL has opened
+ to this table; dropping of the table is
+ NOT allowed until this count gets to zero;
+ MySQL does NOT itself check the number of
+ open handles at drop */
ibool cached; /* TRUE if the table object has been added
to the dictionary cache */
lock_t* auto_inc_lock;/* a buffer for an auto-inc lock
diff --git a/innobase/include/mem0dbg.h b/innobase/include/mem0dbg.h
index dda37626198..0b1aa53d694 100644
--- a/innobase/include/mem0dbg.h
+++ b/innobase/include/mem0dbg.h
@@ -10,11 +10,14 @@ Created 6/9/1994 Heikki Tuuri
/* In the debug version each allocated field is surrounded with
check fields whose sizes are given below */
+#ifdef UNIV_MEM_DEBUG
#define MEM_FIELD_HEADER_SIZE ut_calc_align(2 * sizeof(ulint),\
UNIV_MEM_ALIGNMENT)
#define MEM_FIELD_TRAILER_SIZE sizeof(ulint)
+#else
+#define MEM_FIELD_HEADER_SIZE 0
+#endif
-#define MEM_BLOCK_MAGIC_N 764741
/* Space needed when allocating for a user a field of
length N. The space is allocated only in multiples of
@@ -115,3 +118,12 @@ ibool
mem_validate(void);
/*===============*/
/* out: TRUE if ok */
+/****************************************************************
+Tries to find neigboring memory allocation blocks and dumps to stderr
+the neighborhood of a given pointer. */
+
+void
+mem_analyze_corruption(
+/*===================*/
+ byte* ptr); /* in: pointer to place of possible corruption */
+
diff --git a/innobase/include/mem0mem.h b/innobase/include/mem0mem.h
index 95024cf8011..57fac93d3ac 100644
--- a/innobase/include/mem0mem.h
+++ b/innobase/include/mem0mem.h
@@ -61,58 +61,41 @@ mem_init(
/******************************************************************
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
-#ifdef UNIV_MEM_DEBUG
+
#define mem_heap_create(N) mem_heap_create_func(\
(N), NULL, MEM_HEAP_DYNAMIC,\
IB__FILE__, __LINE__)
-#else
-#define mem_heap_create(N) mem_heap_create_func(N, NULL, MEM_HEAP_DYNAMIC)
-#endif
/******************************************************************
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
-#ifdef UNIV_MEM_DEBUG
+
#define mem_heap_create_in_buffer(N) mem_heap_create_func(\
(N), NULL, MEM_HEAP_BUFFER,\
IB__FILE__, __LINE__)
-#else
-#define mem_heap_create_in_buffer(N) mem_heap_create_func(N, NULL,\
- MEM_HEAP_BUFFER)
-#endif
/******************************************************************
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
-#ifdef UNIV_MEM_DEBUG
+
#define mem_heap_create_in_btr_search(N) mem_heap_create_func(\
(N), NULL, MEM_HEAP_BTR_SEARCH |\
MEM_HEAP_BUFFER,\
IB__FILE__, __LINE__)
-#else
-#define mem_heap_create_in_btr_search(N) mem_heap_create_func(N, NULL,\
- MEM_HEAP_BTR_SEARCH | MEM_HEAP_BUFFER)
-#endif
/******************************************************************
Use this macro instead of the corresponding function! Macro for fast
memory heap creation. An initial block of memory B is given by the
caller, N is its size, and this memory block is not freed by
mem_heap_free. See the parameter comment in mem_heap_create_func below. */
-#ifdef UNIV_MEM_DEBUG
+
#define mem_heap_fast_create(N, B) mem_heap_create_func(\
(N), (B), MEM_HEAP_DYNAMIC,\
IB__FILE__, __LINE__)
-#else
-#define mem_heap_fast_create(N, B) mem_heap_create_func(N, (B),\
- MEM_HEAP_DYNAMIC)
-#endif
+
/******************************************************************
Use this macro instead of the corresponding function! Macro for memory
heap freeing. */
-#ifdef UNIV_MEM_DEBUG
+
#define mem_heap_free(heap) mem_heap_free_func(\
(heap), IB__FILE__, __LINE__)
-#else
-#define mem_heap_free(heap) mem_heap_free_func(heap)
-#endif
/*********************************************************************
NOTE: Use the corresponding macros instead of this function. Creates a
memory heap which allocates memory from dynamic space. For debugging
@@ -139,11 +122,9 @@ mem_heap_create_func(
block is not unintentionally erased
(if allocated in the stack), before
the memory heap is explicitly freed. */
- ulint type /* in: MEM_HEAP_DYNAMIC or MEM_HEAP_BUFFER */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
+ ulint type, /* in: MEM_HEAP_DYNAMIC or MEM_HEAP_BUFFER */
+ char* file_name, /* in: file name where created */
ulint line /* in: line where created */
- #endif
);
/*********************************************************************
NOTE: Use the corresponding macro instead of this function.
@@ -152,11 +133,9 @@ UNIV_INLINE
void
mem_heap_free_func(
/*===============*/
- mem_heap_t* heap /* in, own: heap to be freed */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where freed */
- ulint line /* in: line where freed */
- #endif
+ mem_heap_t* heap, /* in, own: heap to be freed */
+ char* file_name, /* in: file name where freed */
+ ulint line /* in: line where freed */
);
/*******************************************************************
Allocates n bytes of memory from a memory heap. */
@@ -220,25 +199,18 @@ UNIV_INLINE
ulint
mem_heap_get_size(
/*==============*/
- mem_heap_t* heap); /* in: heap */
+ mem_heap_t* heap); /* in: heap */
/******************************************************************
Use this macro instead of the corresponding function!
Macro for memory buffer allocation */
-#ifdef UNIV_MEM_DEBUG
-#define mem_alloc(N) mem_alloc_func(\
- (N), IB__FILE__, __LINE__)
-#else
-#define mem_alloc(N) mem_alloc_func(N)
-#endif
+
+#define mem_alloc(N) mem_alloc_func((N), IB__FILE__, __LINE__)
/******************************************************************
Use this macro instead of the corresponding function!
Macro for memory buffer allocation */
-#ifdef UNIV_MEM_DEBUG
+
#define mem_alloc_noninline(N) mem_alloc_func_noninline(\
(N), IB__FILE__, __LINE__)
-#else
-#define mem_alloc_noninline(N) mem_alloc_func_noninline(N)
-#endif
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
Allocates a single buffer of memory from the dynamic memory of
@@ -250,11 +222,9 @@ mem_alloc_func(
/*===========*/
/* out, own: free storage, NULL
if did not succeed */
- ulint n /* in: desired number of bytes */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
- ulint line /* in: line where created */
- #endif
+ ulint n, /* in: desired number of bytes */
+ char* file_name, /* in: file name where created */
+ ulint line /* in: line where created */
);
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
@@ -267,21 +237,15 @@ mem_alloc_func_noninline(
/*=====================*/
/* out, own: free storage, NULL if did not
succeed */
- ulint n /* in: desired number of bytes */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
+ ulint n, /* in: desired number of bytes */
+ char* file_name, /* in: file name where created */
ulint line /* in: line where created */
- #endif
);
/******************************************************************
Use this macro instead of the corresponding function!
Macro for memory buffer freeing */
-#ifdef UNIV_MEM_DEBUG
-#define mem_free(PTR) mem_free_func(\
- (PTR), IB__FILE__, __LINE__)
-#else
-#define mem_free(PTR) mem_free_func(PTR)
-#endif
+
+#define mem_free(PTR) mem_free_func((PTR), IB__FILE__, __LINE__)
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
Frees a single buffer of storage from
@@ -290,11 +254,9 @@ UNIV_INLINE
void
mem_free_func(
/*==========*/
- void* ptr /* in, own: buffer to be freed */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
- ulint line /* in: line where created */
- #endif
+ void* ptr, /* in, own: buffer to be freed */
+ char* file_name, /* in: file name where created */
+ ulint line /* in: line where created */
);
/*******************************************************************
Implements realloc. */
@@ -304,7 +266,9 @@ mem_realloc(
/*========*/
/* out, own: free storage, NULL if did not succeed */
void* buf, /* in: pointer to an old buffer */
- ulint n); /* in: desired number of bytes */
+ ulint n, /* in: desired number of bytes */
+ char* file_name,/* in: file name where called */
+ ulint line); /* in: line where called */
/*#######################################################################*/
@@ -336,8 +300,13 @@ struct mem_block_info_struct {
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 */
};
+#define MEM_BLOCK_MAGIC_N 764741555
+#define MEM_FREED_BLOCK_MAGIC_N 547711122
+
/* Header size for a memory heap block */
#define MEM_BLOCK_HEADER_SIZE ut_calc_align(sizeof(mem_block_info_t),\
UNIV_MEM_ALIGNMENT)
diff --git a/innobase/include/mem0mem.ic b/innobase/include/mem0mem.ic
index edc3ab17f2a..a7abb93d91d 100644
--- a/innobase/include/mem0mem.ic
+++ b/innobase/include/mem0mem.ic
@@ -24,8 +24,10 @@ mem_heap_create_block(
if init_block is not NULL, its size in bytes */
void* init_block, /* in: init block in fast create, type must be
MEM_HEAP_DYNAMIC */
- ulint type); /* in: type of heap: MEM_HEAP_DYNAMIC or
+ ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC or
MEM_HEAP_BUFFER */
+ char* file_name,/* in: file name where created */
+ ulint line); /* in: line where created */
/**********************************************************************
Frees a block from a memory heap. */
@@ -392,21 +394,20 @@ mem_heap_create_func(
block is not unintentionally erased
(if allocated in the stack), before
the memory heap is explicitly freed. */
- ulint type /* in: MEM_HEAP_DYNAMIC, or MEM_HEAP_BUFFER
+ ulint type, /* in: MEM_HEAP_DYNAMIC, or MEM_HEAP_BUFFER
possibly ORed to MEM_HEAP_BTR_SEARCH */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
+ char* file_name, /* in: file name where created */
ulint line /* in: line where created */
- #endif
)
{
mem_block_t* block;
if (n > 0) {
- block = mem_heap_create_block(NULL, n, init_block, type);
+ block = mem_heap_create_block(NULL, n, init_block, type,
+ file_name, line);
} else {
block = mem_heap_create_block(NULL, MEM_BLOCK_START_SIZE,
- init_block, type);
+ init_block, type, file_name, line);
}
ut_ad(block);
@@ -438,11 +439,9 @@ UNIV_INLINE
void
mem_heap_free_func(
/*===============*/
- mem_heap_t* heap /* in, own: heap to be freed */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where freed */
+ mem_heap_t* heap, /* in, own: heap to be freed */
+ char* file_name, /* in: file name where freed */
ulint line /* in: line where freed */
- #endif
)
{
mem_block_t* block;
@@ -488,14 +487,12 @@ mem_alloc_func(
/*===========*/
/* out, own: free storage, NULL if did not
succeed */
- ulint n /* in: desired number of bytes */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
+ ulint n, /* in: desired number of bytes */
+ char* file_name, /* in: file name where created */
ulint line /* in: line where created */
- #endif
)
{
- #ifndef UNIV_MEM_DEBUG
+#ifdef notdefined
void* buf;
buf = mem_area_alloc(n, mem_comm_pool);
@@ -505,7 +502,7 @@ mem_alloc_func(
#endif
return(buf);
- #else
+#else
mem_heap_t* heap;
void* buf;
@@ -524,11 +521,11 @@ mem_alloc_func(
buf = mem_heap_alloc(heap, n);
- ut_ad((byte*)heap == (byte*)buf - MEM_BLOCK_HEADER_SIZE
+ ut_a((byte*)heap == (byte*)buf - MEM_BLOCK_HEADER_SIZE
- MEM_FIELD_HEADER_SIZE);
return(buf);
- #endif
+#endif
}
/*******************************************************************
@@ -539,26 +536,22 @@ UNIV_INLINE
void
mem_free_func(
/*==========*/
- void* ptr /* in, own: buffer to be freed */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
+ void* ptr, /* in, own: buffer to be freed */
+ char* file_name, /* in: file name where created */
ulint line /* in: line where created */
- #endif
)
{
- #ifndef UNIV_MEM_DEBUG
+#ifdef notdefined
mem_area_free(ptr, mem_comm_pool);
- #else
-
+#else
mem_heap_t* heap;
heap = (mem_heap_t*)((byte*)ptr - MEM_BLOCK_HEADER_SIZE
- MEM_FIELD_HEADER_SIZE);
mem_heap_free_func(heap, file_name, line);
-
- #endif
+#endif
}
/*********************************************************************
@@ -567,7 +560,7 @@ UNIV_INLINE
ulint
mem_heap_get_size(
/*==============*/
- mem_heap_t* heap) /* in: heap */
+ mem_heap_t* heap) /* in: heap */
{
mem_block_t* block;
ulint size = 0;
@@ -597,9 +590,11 @@ mem_realloc(
/*========*/
/* out, own: free storage, NULL if did not succeed */
void* buf, /* in: pointer to an old buffer */
- ulint n) /* in: desired number of bytes */
+ ulint n, /* in: desired number of bytes */
+ char* file_name,/* in: file name where called */
+ ulint line) /* in: line where called */
{
mem_free(buf);
- return(mem_alloc(n));
+ return(mem_alloc_func(n, file_name, line));
}
diff --git a/innobase/include/que0que.h b/innobase/include/que0que.h
index 4cbd888ba1d..cdaeeae1fde 100644
--- a/innobase/include/que0que.h
+++ b/innobase/include/que0que.h
@@ -327,6 +327,8 @@ mutex with the exceptions named below */
struct que_thr_struct{
que_common_t common; /* type: QUE_NODE_THR */
+ ulint magic_n; /* magic number to catch memory
+ corruption */
que_node_t* child; /* graph child node */
que_t* graph; /* graph where this node belongs */
ibool is_active; /* TRUE if the thread has been set
@@ -357,6 +359,9 @@ struct que_thr_struct{
thus far */
};
+#define QUE_THR_MAGIC_N 8476583
+#define QUE_THR_MAGIC_FREED 123461526
+
/* Query graph fork node: its fields are protected by the kernel mutex */
struct que_fork_struct{
que_common_t common; /* type: QUE_NODE_FORK */
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 32354219e64..0346299bb10 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -323,11 +323,18 @@ struct mysql_row_templ_struct {
/* After fetching this many rows, we start caching them in fetch_cache */
#define MYSQL_FETCH_CACHE_THRESHOLD 4
+#define ROW_PREBUILT_ALLOCATED 78540783
+#define ROW_PREBUILT_FREED 26423527
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
handle used within MySQL; these are used to save CPU time. */
struct row_prebuilt_struct {
+ ulint magic_n; /* this magic number is set to
+ ROW_PREBUILT_ALLOCATED when created
+ and to ROW_PREBUILT_FREED when the
+ struct has been freed; used in
+ debugging */
dict_table_t* table; /* Innobase table handle */
trx_t* trx; /* current transaction handle */
ibool sql_stat_start; /* TRUE when we start processing of
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 1a37460569b..05989c6410e 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -17,6 +17,8 @@ Created 10/10/1995 Heikki Tuuri
#include "que0types.h"
#include "trx0types.h"
+/* Buffer which can be used in printing fatal error messages */
+extern char srv_fatal_errbuf[];
/* When this event is set the lock timeout and InnoDB monitor
thread starts running */
@@ -261,15 +263,27 @@ This lets a thread enter InnoDB regardless of the number of threads inside
InnoDB. This must be called when a thread ends a lock wait. */
void
-srv_conc_force_enter_innodb(void);
-/*=============================*/
+srv_conc_force_enter_innodb(
+/*========================*/
+ trx_t* trx); /* in: transaction object associated with the
+ thread */
/*************************************************************************
-This must be called when a thread exits InnoDB. This must also be called
-when a thread goes to wait for a lock. */
+This must be called when a thread exits InnoDB in a lock wait or at the
+end of an SQL statement. */
void
-srv_conc_exit_innodb(void);
-/*======================*/
+srv_conc_force_exit_innodb(
+/*=======================*/
+ trx_t* trx); /* in: transaction object associated with the
+ thread */
+/*************************************************************************
+This must be called when a thread exits InnoDB. */
+
+void
+srv_conc_exit_innodb(
+/*=================*/
+ trx_t* trx); /* in: transaction object associated with the
+ thread */
/*******************************************************************
Puts a MySQL OS thread to wait for a lock to be released. */
diff --git a/innobase/include/trx0sys.h b/innobase/include/trx0sys.h
index 0295cd6abff..f2eded697ec 100644
--- a/innobase/include/trx0sys.h
+++ b/innobase/include/trx0sys.h
@@ -218,6 +218,22 @@ trx_in_trx_list(
/*============*/
/* out: TRUE if is in */
trx_t* in_trx);/* in: trx */
+/*********************************************************************
+Updates the offset information about the end of the MySQL binlog entry
+which corresponds to the transaction just being committed. */
+
+void
+trx_sys_update_mysql_binlog_offset(
+/*===============================*/
+ trx_t* trx, /* in: transaction being committed */
+ mtr_t* mtr); /* in: mtr */
+/*********************************************************************
+Prints to stderr the MySQL binlog offset info in the trx system header if
+the magic number shows it valid. */
+
+void
+trx_sys_print_mysql_binlog_offset(void);
+/*===================================*/
/* The automatically created system rollback segment has this id */
#define TRX_SYS_SYSTEM_RSEG_ID 0
@@ -236,7 +252,7 @@ therefore 256 */
/* Transaction system header; protected by trx_sys->mutex */
/*-------------------------------------------------------------*/
-#define TRX_SYS_TRX_ID_STORE 0 /* The maximum trx id or trx number
+#define TRX_SYS_TRX_ID_STORE 0 /* the maximum trx id or trx number
modulo TRX_SYS_TRX_ID_UPDATE_MARGIN
written to a file page by any
transaction; the assignment of
@@ -252,6 +268,23 @@ therefore 256 */
segment specification slots */
/*-------------------------------------------------------------*/
+#define TRX_SYS_MYSQL_LOG_NAME_LEN 32
+#define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344
+
+/* The offset of the MySQL binlog offset info on the trx system header page */
+#define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 300)
+#define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows
+ if we have valid data in the
+ MySQL binlog info; the value
+ is ..._MAGIC_N if yes */
+#define TRX_SYS_MYSQL_LOG_NAME 4 /* MySQL log file name */
+#define TRX_SYS_MYSQL_LOG_OFFSET_HIGH (4 + TRX_SYS_MYSQL_LOG_NAME_LEN)
+ /* high 4 bytes of the offset
+ within that file */
+#define TRX_SYS_MYSQL_LOG_OFFSET_LOW (8 + TRX_SYS_MYSQL_LOG_NAME_LEN)
+ /* low 4 bytes of the offset
+ within that file */
+
/* The offset of the doublewrite buffer header on the trx system header page */
#define TRX_SYS_DOUBLEWRITE (UNIV_PAGE_SIZE - 200)
/*-------------------------------------------------------------*/
diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h
index 58cef01b376..d67628b8bad 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -290,10 +290,20 @@ struct trx_struct{
table */
dulint table_id; /* table id if the preceding field is
TRUE */
+ /*------------------------------*/
void* mysql_thd; /* MySQL thread handle corresponding
to this trx, or NULL */
+ char* mysql_log_file_name;
+ /* If MySQL binlog is used, this field
+ contains a pointer to the latest file
+ name; this is NULL if binlog is not
+ used */
+ ib_longlong mysql_log_offset;/* If MySQL binlog is used, this field
+ contains the end offset of the binlog
+ entry */
os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated
with this transaction object */
+ /*------------------------------*/
ulint n_mysql_tables_in_use; /* number of Innobase tables
used in the processing of the current
SQL statement in MySQL */
@@ -314,6 +324,18 @@ struct trx_struct{
calls from MySQL; this is intended
to reduce contention on the search
latch */
+ /*------------------------------*/
+ ibool declared_to_be_inside_innodb;
+ /* this is TRUE if we have declared
+ this transaction in
+ srv_conc_enter_innodb to be inside the
+ InnoDB engine */
+ ulint n_tickets_to_enter_innodb;
+ /* this can be > 0 only when
+ declared_to_... is TRUE; when we come
+ to srv_conc_innodb_enter, if the value
+ here is > 0, we decrement this by 1 */
+ /*------------------------------*/
lock_t* auto_inc_lock; /* possible auto-inc lock reserved by
the transaction; note that it is also
in the lock list trx_locks */
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index 5cd5850d1a1..7be172685ae 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -51,6 +51,8 @@ recv_sys_t* recv_sys = NULL;
ibool recv_recovery_on = FALSE;
ibool recv_recovery_from_backup_on = FALSE;
+ibool recv_needed_recovery = FALSE;
+
/* If the following is TRUE, the buffer pool file pages must be invalidated
after recovery and no ibuf operations are allowed; this becomes TRUE if
the log record hash table becomes too full, and log records must be merged
@@ -1020,7 +1022,7 @@ loop:
if (!has_printed) {
fprintf(stderr,
"InnoDB: Starting an apply batch of log records to the database...\n"
-"InnoDB: Progress in percents:");
+"InnoDB: Progress in percents: ");
has_printed = TRUE;
}
@@ -2032,12 +2034,16 @@ recv_recovery_from_checkpoint_start(
if (ut_dulint_cmp(checkpoint_lsn, max_flushed_lsn) != 0
|| ut_dulint_cmp(checkpoint_lsn, min_flushed_lsn) != 0) {
+ recv_needed_recovery = TRUE;
+
+ ut_print_timestamp(stderr);
+
fprintf(stderr,
- "InnoDB: Database was not shut down normally.\n"
- "InnoDB: Starting recovery from log files...\n");
+ " InnoDB: Database was not shut down normally.\n"
+ "InnoDB: Starting recovery from log files...\n");
fprintf(stderr,
- "InnoDB: Starting log scan based on checkpoint at\n"
- "InnoDB: log sequence number %lu %lu\n",
+ "InnoDB: Starting log scan based on checkpoint at\n"
+ "InnoDB: log sequence number %lu %lu\n",
ut_dulint_get_high(checkpoint_lsn),
ut_dulint_get_low(checkpoint_lsn));
}
@@ -2199,6 +2205,10 @@ recv_recovery_from_checkpoint_finish(void)
"InnoDB: Log records applied to the database\n");
}
+ if (recv_needed_recovery) {
+ trx_sys_print_mysql_binlog_offset();
+ }
+
/* Free the resources of the recovery system */
recv_recovery_on = FALSE;
diff --git a/innobase/mem/mem0dbg.c b/innobase/mem/mem0dbg.c
index 0d71708b906..f8f62dffa8b 100644
--- a/innobase/mem/mem0dbg.c
+++ b/innobase/mem/mem0dbg.c
@@ -808,7 +808,7 @@ mem_validate_no_assert(void)
}
mutex_exit(&mem_hash_mutex);
-
+
return(error);
#else
@@ -832,3 +832,95 @@ mem_validate(void)
return(TRUE);
}
+
+/****************************************************************
+Tries to find neigboring memory allocation blocks and dumps to stderr
+the neighborhood of a given pointer. */
+
+void
+mem_analyze_corruption(
+/*===================*/
+ byte* ptr) /* in: pointer to place of possible corruption */
+{
+ byte* p;
+ ulint i;
+ ulint dist;
+
+ ut_sprintf_buf(srv_fatal_errbuf, ptr - 250, 500);
+ fprintf(stderr,
+ "InnoDB: Apparent memory corruption: mem dump %s\n", srv_fatal_errbuf);
+
+ fprintf(stderr,
+ "InnoDB: Scanning backward trying to find previous allocated mem blocks\n");
+
+ p = ptr;
+ dist = 0;
+
+ for (i = 0; i < 10; i++) {
+ for (;;) {
+ if (((ulint)p) % 4 == 0) {
+
+ if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
+ fprintf(stderr,
+ "Mem block at - %lu, file %s, line %lu\n",
+ dist, p + sizeof(ulint),
+ *(ulint*)(p + 8 + sizeof(ulint)));
+
+ break;
+ }
+
+ if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
+ fprintf(stderr,
+ "Freed mem block at - %lu, file %s, line %lu\n",
+ dist, p + sizeof(ulint),
+ *(ulint*)(p + 8 + sizeof(ulint)));
+
+ break;
+ }
+ }
+
+ p--;
+ dist++;
+ }
+
+ p--;
+ dist++;
+ }
+
+ fprintf(stderr,
+ "InnoDB: Scanning forward trying to find next allocated mem blocks\n");
+
+ p = ptr;
+ dist = 0;
+
+ for (i = 0; i < 10; i++) {
+ for (;;) {
+ if (((ulint)p) % 4 == 0) {
+
+ if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
+ fprintf(stderr,
+ "Mem block at + %lu, file %s, line %lu\n",
+ dist, p + sizeof(ulint),
+ *(ulint*)(p + 8 + sizeof(ulint)));
+
+ break;
+ }
+
+ if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
+ fprintf(stderr,
+ "Freed mem block at + %lu, file %s, line %lu\n",
+ dist, p + sizeof(ulint),
+ *(ulint*)(p + 8 + sizeof(ulint)));
+
+ break;
+ }
+ }
+
+ p++;
+ dist++;
+ }
+
+ p++;
+ dist++;
+ }
+}
diff --git a/innobase/mem/mem0mem.c b/innobase/mem/mem0mem.c
index 19a2c0d61a7..58fb618e2db 100644
--- a/innobase/mem/mem0mem.c
+++ b/innobase/mem/mem0mem.c
@@ -14,8 +14,9 @@ Created 6/9/1994 Heikki Tuuri
#include "mach0data.h"
#include "buf0buf.h"
-#include "mem0dbg.c"
#include "btr0sea.h"
+#include "srv0srv.h"
+#include "mem0dbg.c"
/*
THE MEMORY MANAGEMENT
@@ -85,18 +86,12 @@ mem_alloc_func_noninline(
/*=====================*/
/* out, own: free storage, NULL if did not
succeed */
- ulint n /* in: desired number of bytes */
- #ifdef UNIV_MEM_DEBUG
- ,char* file_name, /* in: file name where created */
+ ulint n, /* in: desired number of bytes */
+ char* file_name, /* in: file name where created */
ulint line /* in: line where created */
- #endif
)
{
- return(mem_alloc_func(n
-#ifdef UNIV_MEM_DEBUG
- , file_name, line
-#endif
- ));
+ return(mem_alloc_func(n, file_name, line));
}
/*******************************************************************
@@ -113,8 +108,10 @@ mem_heap_create_block(
if init_block is not NULL, its size in bytes */
void* init_block, /* in: init block in fast create, type must be
MEM_HEAP_DYNAMIC */
- ulint type) /* in: type of heap: MEM_HEAP_DYNAMIC, or
+ ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC, or
MEM_HEAP_BUFFER possibly ORed to MEM_HEAP_BTR_SEARCH */
+ char* file_name,/* in: file name where created */
+ ulint line) /* in: line where created */
{
mem_block_t* block;
ulint len;
@@ -164,7 +161,11 @@ mem_heap_create_block(
}
block->magic_n = MEM_BLOCK_MAGIC_N;
-
+ ut_memcpy(&(block->file_name), file_name + ut_strlen(file_name) - 7,
+ 7);
+ block->file_name[7]='\0';
+ block->line = line;
+
mem_block_set_len(block, len);
mem_block_set_type(block, type);
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
@@ -223,8 +224,8 @@ mem_heap_add_block(
new_size = n;
}
- new_block = mem_heap_create_block(heap, new_size, NULL, heap->type);
-
+ new_block = mem_heap_create_block(heap, new_size, NULL, heap->type,
+ heap->file_name, heap->line);
if (new_block == NULL) {
return(NULL);
@@ -255,7 +256,8 @@ mem_heap_block_free(
type = heap->type;
len = block->len;
init_block = block->init_block;
-
+ block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
+
#ifdef UNIV_MEM_DEBUG
/* In the debug version we set the memory to a random combination
of hex 0xDE and 0xAD. */
diff --git a/innobase/pars/lexyy.c b/innobase/pars/lexyy.c
index 67bd12afa60..10bdcdd0990 100644
--- a/innobase/pars/lexyy.c
+++ b/innobase/pars/lexyy.c
@@ -7373,7 +7373,7 @@ void *ptr;
unsigned int size;
#endif
{
- return (void *) mem_realloc( ptr, size );
+ return (void *) mem_realloc( ptr, size, __FILE__, __LINE__ );
}
#ifdef YY_USE_PROTOS
diff --git a/innobase/que/que0que.c b/innobase/que/que0que.c
index 96e505f8b80..97843311d21 100644
--- a/innobase/que/que0que.c
+++ b/innobase/que/que0que.c
@@ -183,6 +183,8 @@ que_thr_create(
thr->common.type = QUE_NODE_THR;
thr->common.parent = parent;
+ thr->magic_n = QUE_THR_MAGIC_N;
+
thr->graph = parent->graph;
thr->state = QUE_THR_COMMAND_WAIT;
@@ -485,7 +487,6 @@ que_graph_free_recursive(
tab_node_t* cre_tab;
ind_node_t* cre_ind;
-
if (node == NULL) {
return;
@@ -509,6 +510,16 @@ que_graph_free_recursive(
thr = node;
+ if (thr->magic_n != QUE_THR_MAGIC_N) {
+ fprintf(stderr,
+ "que_thr struct appears corrupt; magic n %lu\n",
+ thr->magic_n);
+ mem_analyze_corruption((byte*)thr);
+ ut_a(0);
+ }
+
+ thr->magic_n = QUE_THR_MAGIC_FREED;
+
que_graph_free_recursive(thr->child);
break;
@@ -606,6 +617,10 @@ que_graph_free_recursive(
break;
default:
+ fprintf(stderr,
+ "que_node struct appears corrupt; type %lu\n",
+ que_node_get_type(node));
+ mem_analyze_corruption((byte*)node);
ut_a(0);
}
}
@@ -1068,20 +1083,29 @@ que_thr_stop_for_mysql(
mutex_exit(&kernel_mutex);
}
-
/**************************************************************************
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
the n_active_thrs counters of the query graph and transaction if thr was
not active. */
+
void
que_thr_move_to_run_state_for_mysql(
/*================================*/
que_thr_t* thr, /* in: an query thread */
trx_t* trx) /* in: transaction */
{
+ if (thr->magic_n != QUE_THR_MAGIC_N) {
+ fprintf(stderr,
+ "que_thr struct appears corrupt; magic n %lu\n", thr->magic_n);
+
+ mem_analyze_corruption((byte*)thr);
+
+ ut_a(0);
+ }
+
if (!thr->is_active) {
- (thr->graph)->n_active_thrs++;
+ thr->graph->n_active_thrs++;
trx->n_active_thrs++;
@@ -1097,6 +1121,7 @@ que_thr_move_to_run_state_for_mysql(
/**************************************************************************
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
select, when there is no error or lock wait. */
+
void
que_thr_stop_for_mysql_no_error(
/*============================*/
@@ -1105,6 +1130,15 @@ que_thr_stop_for_mysql_no_error(
{
ut_ad(thr->state == QUE_THR_RUNNING);
+ if (thr->magic_n != QUE_THR_MAGIC_N) {
+ fprintf(stderr,
+ "que_thr struct appears corrupt; magic n %lu\n", thr->magic_n);
+
+ mem_analyze_corruption((byte*)thr);
+
+ ut_a(0);
+ }
+
thr->state = QUE_THR_COMPLETED;
thr->is_active = FALSE;
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index 749e19575bc..3889f62afa2 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -105,6 +105,17 @@ rec_get_nth_field(
ut_ad(rec && len);
ut_ad(n < rec_get_n_fields(rec));
+ if (n > 1024) {
+ fprintf(stderr, "Error: trying to access field %lu in rec\n",
+ n);
+ ut_a(0);
+ }
+
+ if (rec == NULL) {
+ fprintf(stderr, "Error: rec is NULL pointer\n");
+ ut_a(0);
+ }
+
if (rec_get_1byte_offs_flag(rec)) {
os = rec_1_get_field_start_offs(rec, n);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 9622a7cee32..c0f527017e0 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("innodb_monitor");
if (namelen >= keywordlen
@@ -1118,6 +1211,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());
@@ -1126,6 +1221,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 */
@@ -1189,6 +1296,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);
@@ -1197,6 +1306,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 */
@@ -1251,6 +1372,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());
@@ -1427,11 +1549,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;
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index 2cccc217621..663a544faac 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -2492,6 +2492,17 @@ row_search_for_mysql(
ut_ad(sync_thread_levels_empty_gen(FALSE));
+ 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);
+ }
+
/* printf("Match mode %lu\n search tuple ", match_mode);
dtuple_print(search_tuple);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index d77db335366..d75783fe425 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -50,6 +50,9 @@ Created 10/8/1995 Heikki Tuuri
#include "dict0load.h"
#include "srv0start.h"
+/* Buffer which can be used in printing fatal error messages */
+char srv_fatal_errbuf[5000];
+
/* The following counter is incremented whenever there is some user activity
in the server */
ulint srv_activity_count = 0;
@@ -132,6 +135,9 @@ lint srv_conc_n_threads = 0; /* number of OS threads currently
thread increments this, but a thread
waiting for a lock decrements this
temporarily */
+ulint srv_conc_n_waiting_threads = 0; /* number of OS threads waiting in the
+ FIFO for a permission to enter InnoDB
+ */
typedef struct srv_conc_slot_struct srv_conc_slot_t;
struct srv_conc_slot_struct{
@@ -152,6 +158,11 @@ UT_LIST_BASE_NODE_T(srv_conc_slot_t) srv_conc_queue; /* queue of threads
waiting to get in */
srv_conc_slot_t srv_conc_slots[OS_THREAD_MAX_N]; /* array of wait
slots */
+
+/* Number of times a thread is allowed to enter InnoDB within the same
+SQL query after it has once got the ticket at srv_conc_enter_innodb */
+#define SRV_FREE_TICKETS_TO_ENTER 500
+
/*-----------------------*/
/* If the following is set TRUE then we do not run purge and insert buffer
merge to completion before shutdown */
@@ -1627,6 +1638,8 @@ srv_general_init(void)
thr_local_init();
}
+/*======================= InnoDB Server FIFO queue =======================*/
+
/*************************************************************************
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. */
@@ -1640,11 +1653,29 @@ srv_conc_enter_innodb(
srv_conc_slot_t* slot;
ulint i;
+ if (srv_thread_concurrency >= 500) {
+ /* Disable the concurrency check */
+
+ return;
+ }
+
+ /* If trx has 'free tickets' to enter the engine left, then use one
+ such ticket */
+
+ if (trx->n_tickets_to_enter_innodb > 0) {
+ trx->n_tickets_to_enter_innodb--;
+
+ return;
+ }
+
os_fast_mutex_lock(&srv_conc_mutex);
if (srv_conc_n_threads < (lint)srv_thread_concurrency) {
- srv_conc_n_threads++;
+ srv_conc_n_threads++;
+ trx->declared_to_be_inside_innodb = TRUE;
+ trx->n_tickets_to_enter_innodb = SRV_FREE_TICKETS_TO_ENTER;
+
os_fast_mutex_unlock(&srv_conc_mutex);
return;
@@ -1665,6 +1696,8 @@ srv_conc_enter_innodb(
thread enter */
srv_conc_n_threads++;
+ trx->declared_to_be_inside_innodb = TRUE;
+ trx->n_tickets_to_enter_innodb = 0;
os_fast_mutex_unlock(&srv_conc_mutex);
@@ -1684,6 +1717,8 @@ srv_conc_enter_innodb(
os_event_reset(slot->event);
+ srv_conc_n_waiting_threads++;
+
os_fast_mutex_unlock(&srv_conc_mutex);
/* Go to wait for the event; when a thread leaves InnoDB it will
@@ -1693,6 +1728,8 @@ srv_conc_enter_innodb(
os_fast_mutex_lock(&srv_conc_mutex);
+ srv_conc_n_waiting_threads--;
+
/* NOTE that the thread which released this thread already
incremented the thread counter on behalf of this thread */
@@ -1700,6 +1737,9 @@ srv_conc_enter_innodb(
UT_LIST_REMOVE(srv_conc_queue, srv_conc_queue, slot);
+ trx->declared_to_be_inside_innodb = TRUE;
+ trx->n_tickets_to_enter_innodb = SRV_FREE_TICKETS_TO_ENTER;
+
os_fast_mutex_unlock(&srv_conc_mutex);
}
@@ -1708,29 +1748,52 @@ This lets a thread enter InnoDB regardless of the number of threads inside
InnoDB. This must be called when a thread ends a lock wait. */
void
-srv_conc_force_enter_innodb(void)
-/*=============================*/
+srv_conc_force_enter_innodb(
+/*========================*/
+ trx_t* trx) /* in: transaction object associated with the
+ thread */
{
+ if (srv_thread_concurrency >= 500) {
+
+ return;
+ }
+
os_fast_mutex_lock(&srv_conc_mutex);
srv_conc_n_threads++;
+ trx->declared_to_be_inside_innodb = TRUE;
+ trx->n_tickets_to_enter_innodb = 0;
os_fast_mutex_unlock(&srv_conc_mutex);
}
/*************************************************************************
-This must be called when a thread exits InnoDB. This must also be called
-when a thread goes to wait for a lock. */
+This must be called when a thread exits InnoDB in a lock wait or at the
+end of an SQL statement. */
void
-srv_conc_exit_innodb(void)
-/*======================*/
+srv_conc_force_exit_innodb(
+/*=======================*/
+ trx_t* trx) /* in: transaction object associated with the
+ thread */
{
srv_conc_slot_t* slot = NULL;
+ if (srv_thread_concurrency >= 500) {
+
+ return;
+ }
+
+ if (trx->declared_to_be_inside_innodb == FALSE) {
+
+ return;
+ }
+
os_fast_mutex_lock(&srv_conc_mutex);
srv_conc_n_threads--;
+ trx->declared_to_be_inside_innodb = FALSE;
+ trx->n_tickets_to_enter_innodb = 0;
if (srv_conc_n_threads < (lint)srv_thread_concurrency) {
/* Look for a slot where a thread is waiting and no other
@@ -1760,6 +1823,38 @@ srv_conc_exit_innodb(void)
}
/*************************************************************************
+This must be called when a thread exits InnoDB. */
+
+void
+srv_conc_exit_innodb(
+/*=================*/
+ trx_t* trx) /* in: transaction object associated with the
+ thread */
+{
+ srv_conc_slot_t* slot = NULL;
+
+ if (srv_thread_concurrency >= 500) {
+
+ return;
+ }
+
+ if (trx->n_tickets_to_enter_innodb > 0) {
+ /* We will pretend the thread is still inside InnoDB though it
+ now leaves the InnoDB engine. In this way we save
+ a lot of semaphore operations. srv_conc_force_exit_innodb is
+ used to declare the thread definitely outside InnoDB. It
+ should be called when there is a lock wait or an SQL statement
+ ends. */
+
+ return;
+ }
+
+ srv_conc_force_exit_innodb(trx);
+}
+
+/*========================================================================*/
+
+/*************************************************************************
Normalizes init parameter values to use units we use inside InnoDB. */
static
ulint
@@ -1905,7 +2000,7 @@ srv_suspend_mysql_thread(
other thread holding a lock which this thread waits for must be
allowed to enter, sooner or later */
- srv_conc_exit_innodb();
+ srv_conc_force_exit_innodb(thr_get_trx(thr));
/* Wait for the release */
@@ -1913,7 +2008,7 @@ srv_suspend_mysql_thread(
/* Return back inside InnoDB */
- srv_conc_force_enter_innodb();
+ srv_conc_force_enter_innodb(thr_get_trx(thr));
mutex_enter(&kernel_mutex);
@@ -2052,8 +2147,9 @@ loop:
"ROW OPERATIONS\n"
"--------------\n");
printf(
- "%ld queries inside InnoDB; main thread: %s\n",
- srv_conc_n_threads, srv_main_thread_op_info);
+ "%ld queries inside InnoDB, %ld queries in queue; main thread: %s\n",
+ srv_conc_n_threads, srv_conc_n_waiting_threads,
+ srv_main_thread_op_info);
printf(
"Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n",
srv_n_rows_inserted,
@@ -2315,6 +2411,12 @@ loop:
srv_main_thread_op_info = "sleeping";
os_thread_sleep(1000000);
+ /* ALTER TABLE in MySQL requires on Unix that the table handler
+ can drop tables lazily after there no longer are SELECT
+ queries to them. */
+
+/* row_drop_tables_for_mysql_in_background(); */
+
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
goto suspend_thread;
diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c
index c41754316d0..7788b104120 100644
--- a/innobase/sync/sync0arr.c
+++ b/innobase/sync/sync0arr.c
@@ -913,6 +913,17 @@ sync_array_print_long_waits(void)
noticed = TRUE;
}
+
+ if (cell->wait_object != NULL
+ && difftime(time(NULL), cell->reservation_time) > 420) {
+
+ fprintf(stderr,
+"InnoDB: Error: semaphore wait has lasted > 420 seconds\n"
+"InnoDB: We intentionally crash the server, because it appears to be hung.\n"
+ );
+
+ ut_a(0);
+ }
}
if (noticed) {
diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c
index e79e4594637..b29ffb4b3bf 100644
--- a/innobase/trx/trx0sys.c
+++ b/innobase/trx/trx0sys.c
@@ -389,6 +389,115 @@ trx_sys_flush_max_trx_id(void)
mtr_commit(&mtr);
}
+/*********************************************************************
+Updates the offset information about the end of the MySQL binlog entry
+which corresponds to the transaction just being committed. */
+
+void
+trx_sys_update_mysql_binlog_offset(
+/*===============================*/
+ trx_t* trx, /* in: transaction being committed */
+ mtr_t* mtr) /* in: mtr */
+{
+ trx_sysf_t* sys_header;
+ char namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN];
+
+ ut_ad(mutex_own(&kernel_mutex));
+ ut_ad(trx->mysql_log_file_name);
+
+ memset(namebuf, ' ', TRX_SYS_MYSQL_LOG_NAME_LEN - 1);
+ namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN - 1] = '\0';
+
+ /* Copy the whole MySQL log file name to the buffer, or only the
+ last characters, if it does not fit */
+
+ if (ut_strlen(trx->mysql_log_file_name)
+ > TRX_SYS_MYSQL_LOG_NAME_LEN - 1) {
+ ut_memcpy(namebuf, trx->mysql_log_file_name
+ + ut_strlen(trx->mysql_log_file_name)
+ - (TRX_SYS_MYSQL_LOG_NAME_LEN - 1),
+ TRX_SYS_MYSQL_LOG_NAME_LEN - 1);
+ } else {
+ ut_memcpy(namebuf, trx->mysql_log_file_name,
+ 1 + ut_strlen(trx->mysql_log_file_name));
+ }
+
+ namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN - 1] = '\0';
+
+ sys_header = trx_sysf_get(mtr);
+
+ if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
+ != TRX_SYS_MYSQL_LOG_MAGIC_N) {
+
+ mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD,
+ TRX_SYS_MYSQL_LOG_MAGIC_N,
+ MLOG_4BYTES, mtr);
+ }
+
+ if (0 != ut_memcmp(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_NAME,
+ namebuf, TRX_SYS_MYSQL_LOG_NAME_LEN)) {
+
+ mlog_write_string(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_NAME,
+ namebuf, TRX_SYS_MYSQL_LOG_NAME_LEN, mtr);
+ }
+
+ if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0
+ || (trx->mysql_log_offset >> 32) > 0) {
+
+ mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_OFFSET_HIGH,
+ (ulint)(trx->mysql_log_offset >> 32),
+ MLOG_4BYTES, mtr);
+ }
+
+ mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_OFFSET_LOW,
+ (ulint)(trx->mysql_log_offset & 0xFFFFFFFF),
+ MLOG_4BYTES, mtr);
+
+ trx->mysql_log_file_name = NULL;
+}
+
+/*********************************************************************
+Prints to stderr the MySQL binlog offset info in the trx system header if
+the magic number shows it valid. */
+
+void
+trx_sys_print_mysql_binlog_offset(void)
+/*===================================*/
+{
+ trx_sysf_t* sys_header;
+ mtr_t mtr;
+
+ mtr_start(&mtr);
+
+ sys_header = trx_sysf_get(&mtr);
+
+ if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
+ != TRX_SYS_MYSQL_LOG_MAGIC_N) {
+
+ mtr_commit(&mtr);
+
+ return;
+ }
+
+ fprintf(stderr,
+ "InnoDB: Last MySQL binlog file offset %lu %lu, file name %s\n",
+ mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
+ mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
+ + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
+ sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME);
+
+ mtr_commit(&mtr);
+}
+
/********************************************************************
Looks for a free slot for a rollback segment in the trx system file copy. */
@@ -519,7 +628,7 @@ trx_sys_init_at_db_start(void)
"InnoDB: %lu uncommitted transaction(s) which must be rolled back\n",
UT_LIST_GET_LEN(trx_sys->trx_list));
- fprintf(stderr, "Trx id counter is %lu %lu\n",
+ fprintf(stderr, "InnoDB: Trx id counter is %lu %lu\n",
ut_dulint_get_high(trx_sys->max_trx_id),
ut_dulint_get_low(trx_sys->max_trx_id));
}
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 18c80819245..43cca5b62b3 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -76,6 +76,9 @@ trx_create(
trx->n_mysql_tables_in_use = 0;
trx->mysql_n_tables_locked = 0;
+ trx->mysql_log_file_name = NULL;
+ trx->mysql_log_offset = 0;
+
trx->ignore_duplicates_in_insert = FALSE;
mutex_create(&(trx->undo_mutex));
@@ -111,6 +114,9 @@ trx_create(
trx->has_search_latch = FALSE;
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
+ trx->declared_to_be_inside_innodb = FALSE;
+ trx->n_tickets_to_enter_innodb = 0;
+
trx->auto_inc_lock = NULL;
trx->read_view_heap = mem_heap_create(256);
@@ -568,6 +574,13 @@ trx_commit_off_kernel(
mutex_exit(&(rseg->mutex));
+ /* Update the latest MySQL binlog name and offset info
+ in trx sys header if MySQL binlogging is on */
+
+ if (trx->mysql_log_file_name) {
+ trx_sys_update_mysql_binlog_offset(trx, &mtr);
+ }
+
/* If we did not take the shortcut, the following call
commits the mini-transaction, making the whole transaction
committed in the file-based world at this log sequence number;
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index 8b83163bfc2..b5341871228 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -1310,9 +1310,10 @@ trx_undo_mem_init_for_reuse(
{
ut_ad(mutex_own(&((undo->rseg)->mutex)));
- if (undo->id >= TRX_RSEG_N_SLOTS) {
- fprintf(stderr,
- "InnoDB: Error: undo->id is %lu\n", undo->id);
+ if (undo->id >= TRX_RSEG_N_SLOTS) {
+ fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", undo->id);
+
+ mem_analyze_corruption((byte*)undo);
ut_a(0);
}
@@ -1399,7 +1400,7 @@ trx_undo_create(
/************************************************************************
Reuses a cached undo log. */
-UNIV_INLINE
+static
trx_undo_t*
trx_undo_reuse_cached(
/*==================*/
@@ -1442,6 +1443,12 @@ trx_undo_reuse_cached(
ut_ad(undo->size == 1);
ut_ad(undo->hdr_page_no == undo->top_page_no);
+ if (undo->id >= TRX_RSEG_N_SLOTS) {
+ fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", undo->id);
+ mem_analyze_corruption((byte*)undo);
+ ut_a(0);
+ }
+
undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
if (type == TRX_UNDO_INSERT) {
@@ -1572,8 +1579,8 @@ trx_undo_set_state_at_finish(
ut_ad(trx && undo && mtr);
if (undo->id >= TRX_RSEG_N_SLOTS) {
- fprintf(stderr,
- "InnoDB: Error: undo->id is %lu\n", undo->id);
+ fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", undo->id);
+ mem_analyze_corruption((byte*)undo);
ut_a(0);
}