mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Many files:
Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/btr/btr0cur.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0crea.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0dict.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0load.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0mem.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/btr0btr.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/dict0mem.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/ibuf0ibuf.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/os0file.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/os0sync.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/row0mysql.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/row0upd.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/sync0sync.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/trx0sys.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/trx0trx.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/ibuf0ibuf.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/os0sync.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/sync0sync.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/trx0sys.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/lock/lock0lock.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/pars/pars0opt.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/que/que0que.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0ins.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0mysql.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0sel.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0upd.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/srv/srv0srv.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/sync/sync0sync.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/trx/trx0sys.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/trx/trx0trx.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys
This commit is contained in:
@ -228,6 +228,7 @@ btr_cur_search_to_nth_level(
|
||||
ulint insert_planned;
|
||||
ulint buf_mode;
|
||||
ulint estimate;
|
||||
ulint ignore_sec_unique;
|
||||
ulint root_height;
|
||||
#ifdef BTR_CUR_ADAPT
|
||||
btr_search_t* info;
|
||||
@ -246,7 +247,9 @@ btr_cur_search_to_nth_level(
|
||||
#endif
|
||||
insert_planned = latch_mode & BTR_INSERT;
|
||||
estimate = latch_mode & BTR_ESTIMATE;
|
||||
latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE);
|
||||
ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE;
|
||||
latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE
|
||||
| BTR_IGNORE_SEC_UNIQUE);
|
||||
|
||||
ut_ad(!insert_planned || (mode == PAGE_CUR_LE));
|
||||
|
||||
@ -343,7 +346,8 @@ btr_cur_search_to_nth_level(
|
||||
|
||||
rw_latch = latch_mode;
|
||||
|
||||
if (insert_planned && ibuf_should_try(index)) {
|
||||
if (insert_planned && ibuf_should_try(index,
|
||||
ignore_sec_unique)) {
|
||||
|
||||
/* Try insert to the insert buffer if the
|
||||
page is not in the buffer pool */
|
||||
@ -356,7 +360,6 @@ retry_page_get:
|
||||
buf_mode,
|
||||
IB__FILE__, __LINE__,
|
||||
mtr);
|
||||
|
||||
if (page == NULL) {
|
||||
/* This must be a search to perform an insert;
|
||||
try insert to the insert buffer */
|
||||
@ -365,7 +368,7 @@ retry_page_get:
|
||||
ut_ad(insert_planned);
|
||||
ut_ad(cursor->thr);
|
||||
|
||||
if (ibuf_should_try(index) &&
|
||||
if (ibuf_should_try(index, ignore_sec_unique) &&
|
||||
ibuf_insert(tuple, index, space, page_no,
|
||||
cursor->thr)) {
|
||||
/* Insertion to the insert buffer succeeded */
|
||||
|
@ -1201,7 +1201,8 @@ loop:
|
||||
ut_dulint_get_low(id),
|
||||
table->name,
|
||||
foreign->referenced_table_name,
|
||||
foreign->n_fields);
|
||||
foreign->n_fields
|
||||
+ (foreign->type << 24));
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
|
||||
|
@ -1648,7 +1648,7 @@ dict_foreign_find_index(
|
||||
->col->name;
|
||||
if (ut_strlen(columns[i]) !=
|
||||
ut_strlen(col_name)
|
||||
|| 0 != ut_memcmp(columns[i],
|
||||
|| 0 != ut_cmp_in_lower_case(columns[i],
|
||||
col_name,
|
||||
ut_strlen(col_name))) {
|
||||
break;
|
||||
@ -1853,8 +1853,9 @@ dict_scan_col(
|
||||
ibool* success,/* out: TRUE if success */
|
||||
dict_table_t* table, /* in: table in which the column is */
|
||||
dict_col_t** column, /* out: pointer to column if success */
|
||||
char** column_name)/* out: pointer to column->name if
|
||||
char** column_name,/* out: pointer to column->name if
|
||||
success */
|
||||
ulint* column_name_len)/* out: column name length */
|
||||
{
|
||||
dict_col_t* col;
|
||||
char* old_ptr;
|
||||
@ -1882,6 +1883,13 @@ dict_scan_col(
|
||||
ptr++;
|
||||
}
|
||||
|
||||
*column_name_len = (ulint)(ptr - old_ptr);
|
||||
|
||||
if (table == NULL) {
|
||||
*success = TRUE;
|
||||
*column = NULL;
|
||||
*column_name = old_ptr;
|
||||
} else {
|
||||
for (i = 0; i < dict_table_get_n_cols(table); i++) {
|
||||
|
||||
col = dict_table_get_nth_col(table, i);
|
||||
@ -1898,6 +1906,7 @@ dict_scan_col(
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*ptr == '`') {
|
||||
ptr++;
|
||||
@ -1914,14 +1923,18 @@ dict_scan_table_name(
|
||||
/*=================*/
|
||||
/* out: scanned to */
|
||||
char* ptr, /* in: scanned to */
|
||||
dict_table_t** table, /* out: table object or NULL if error */
|
||||
char* name) /* in: foreign key table name */
|
||||
dict_table_t** table, /* out: table object or NULL */
|
||||
char* name, /* in: foreign key table name */
|
||||
ibool* success,/* out: TRUE if ok name found */
|
||||
char* second_table_name)/* in/out: buffer where to store
|
||||
the referenced table name; must be at least
|
||||
2500 bytes */
|
||||
{
|
||||
char* dot_ptr = NULL;
|
||||
char* old_ptr;
|
||||
ulint i;
|
||||
char second_table_name[10000];
|
||||
|
||||
*success = FALSE;
|
||||
*table = NULL;
|
||||
|
||||
while (isspace(*ptr)) {
|
||||
@ -1947,7 +1960,7 @@ dict_scan_table_name(
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (ptr - old_ptr > 9000) {
|
||||
if (ptr - old_ptr > 2000) {
|
||||
return(old_ptr);
|
||||
}
|
||||
|
||||
@ -1978,6 +1991,8 @@ dict_scan_table_name(
|
||||
second_table_name[ptr - old_ptr] = '\0';
|
||||
}
|
||||
|
||||
*success = TRUE;
|
||||
|
||||
*table = dict_table_get_low(second_table_name);
|
||||
|
||||
if (*ptr == '`') {
|
||||
@ -2043,8 +2058,11 @@ dict_create_foreign_constraints(
|
||||
ibool success;
|
||||
ulint error;
|
||||
ulint i;
|
||||
dict_col_t* columns[1000];
|
||||
char* column_names[1000];
|
||||
ulint j;
|
||||
dict_col_t* columns[500];
|
||||
char* column_names[500];
|
||||
ulint column_name_lens[500];
|
||||
char referenced_table_name[2500];
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
@ -2090,7 +2108,7 @@ loop:
|
||||
/* Scan the columns in the first list */
|
||||
col_loop1:
|
||||
ptr = dict_scan_col(ptr, &success, table, columns + i,
|
||||
column_names + i);
|
||||
column_names + i, column_name_lens + i);
|
||||
if (!success) {
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
@ -2141,9 +2159,13 @@ col_loop1:
|
||||
1 + ut_strlen(columns[i]->name));
|
||||
}
|
||||
|
||||
ptr = dict_scan_table_name(ptr, &referenced_table, name);
|
||||
ptr = dict_scan_table_name(ptr, &referenced_table, name,
|
||||
&success, referenced_table_name);
|
||||
|
||||
if (!referenced_table) {
|
||||
/* Note that referenced_table can be NULL if the user has suppressed
|
||||
checking of foreign key constraints! */
|
||||
|
||||
if (!success || (!referenced_table && trx->check_foreigns)) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
@ -2161,7 +2183,7 @@ col_loop1:
|
||||
|
||||
col_loop2:
|
||||
ptr = dict_scan_col(ptr, &success, referenced_table, columns + i,
|
||||
column_names + i);
|
||||
column_names + i, column_name_lens + i);
|
||||
i++;
|
||||
|
||||
if (!success) {
|
||||
@ -2183,43 +2205,104 @@ col_loop2:
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "ON", &success);
|
||||
|
||||
if (!success) {
|
||||
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "DELETE", &success);
|
||||
|
||||
if (!success) {
|
||||
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "CASCADE", &success);
|
||||
|
||||
if (success) {
|
||||
|
||||
foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE;
|
||||
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "SET", &success);
|
||||
|
||||
if (!success) {
|
||||
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "NULL", &success);
|
||||
|
||||
if (success) {
|
||||
for (j = 0; j < foreign->n_fields; j++) {
|
||||
if ((dict_index_get_nth_type(
|
||||
foreign->foreign_index, j)->prtype)
|
||||
& DATA_NOT_NULL) {
|
||||
|
||||
/* It is not sensible to define SET NULL
|
||||
if the column is not allowed to be NULL! */
|
||||
|
||||
dict_foreign_free(foreign);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
}
|
||||
|
||||
foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
|
||||
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
try_find_index:
|
||||
/* Try to find an index which contains the columns as the first fields
|
||||
and in the right order, and the types are the same as in
|
||||
foreign->foreign_index */
|
||||
|
||||
index = dict_foreign_find_index(referenced_table, column_names, i,
|
||||
if (referenced_table) {
|
||||
index = dict_foreign_find_index(referenced_table,
|
||||
column_names, i,
|
||||
foreign->foreign_index);
|
||||
|
||||
if (!index) {
|
||||
dict_foreign_free(foreign);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
} else {
|
||||
ut_a(trx->check_foreigns == FALSE);
|
||||
index = NULL;
|
||||
}
|
||||
|
||||
foreign->referenced_index = index;
|
||||
foreign->referenced_table = referenced_table;
|
||||
|
||||
foreign->referenced_table_name = mem_heap_alloc(foreign->heap,
|
||||
1 + ut_strlen(referenced_table->name));
|
||||
1 + ut_strlen(referenced_table_name));
|
||||
|
||||
ut_memcpy(foreign->referenced_table_name, referenced_table->name,
|
||||
1 + ut_strlen(referenced_table->name));
|
||||
ut_memcpy(foreign->referenced_table_name, referenced_table_name,
|
||||
1 + ut_strlen(referenced_table_name));
|
||||
|
||||
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
|
||||
i * sizeof(void*));
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
foreign->referenced_col_names[i]
|
||||
= mem_heap_alloc(foreign->heap,
|
||||
1 + ut_strlen(columns[i]->name));
|
||||
ut_memcpy(
|
||||
foreign->referenced_col_names[i], columns[i]->name,
|
||||
1 + ut_strlen(columns[i]->name));
|
||||
1 + column_name_lens[i]);
|
||||
ut_memcpy(foreign->referenced_col_names[i], column_names[i],
|
||||
column_name_lens[i]);
|
||||
(foreign->referenced_col_names[i])[column_name_lens[i]] = '\0';
|
||||
}
|
||||
|
||||
/* We found an ok constraint definition: add to the lists */
|
||||
|
||||
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
|
||||
UT_LIST_ADD_LAST(referenced_list, referenced_table->referenced_list,
|
||||
|
||||
if (referenced_table) {
|
||||
UT_LIST_ADD_LAST(referenced_list,
|
||||
referenced_table->referenced_list,
|
||||
foreign);
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
|
||||
@ -3034,6 +3117,14 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
|
||||
buf2 += sprintf(buf2, ")");
|
||||
|
||||
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
|
||||
buf2 += sprintf(buf2, " ON DELETE CASCADE");
|
||||
}
|
||||
|
||||
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
|
||||
buf2 += sprintf(buf2, " ON DELETE SET NULL");
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
}
|
||||
|
||||
|
@ -947,6 +947,11 @@ dict_load_foreign(
|
||||
|
||||
ut_a(len == 4);
|
||||
|
||||
/* We store the type to the bits 24-31 of n_fields */
|
||||
|
||||
foreign->type = foreign->n_fields >> 24;
|
||||
foreign->n_fields = foreign->n_fields & 0xFFFFFF;
|
||||
|
||||
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1);
|
||||
|
||||
ut_memcpy(foreign->id, id, ut_strlen(id) + 1);
|
||||
|
@ -61,6 +61,7 @@ dict_mem_table_create(
|
||||
table->mem_fix = 0;
|
||||
|
||||
table->n_mysql_handles_opened = 0;
|
||||
table->n_foreign_key_checks_running = 0;
|
||||
|
||||
table->cached = FALSE;
|
||||
|
||||
@ -235,6 +236,7 @@ dict_mem_foreign_create(void)
|
||||
|
||||
foreign->id = NULL;
|
||||
|
||||
foreign->type = 0;
|
||||
foreign->foreign_table_name = NULL;
|
||||
foreign->foreign_table = NULL;
|
||||
foreign->foreign_col_names = NULL;
|
||||
|
@ -49,6 +49,12 @@ inserted to the index, at the searched position */
|
||||
/* This flag ORed to latch mode says that we do the search in query
|
||||
optimization */
|
||||
#define BTR_ESTIMATE 1024
|
||||
|
||||
/* This flag ORed to latch mode says that we can ignore possible
|
||||
UNIQUE definition on secondary indexes when we decide if we can use the
|
||||
insert buffer to speed up inserts */
|
||||
#define BTR_IGNORE_SEC_UNIQUE 2048
|
||||
|
||||
/******************************************************************
|
||||
Gets a buffer page and declares its latching order level. */
|
||||
UNIV_INLINE
|
||||
|
@ -249,6 +249,8 @@ struct dict_foreign_struct{
|
||||
this memory heap */
|
||||
char* id; /* id of the constraint as a
|
||||
null-terminated string */
|
||||
ulint type; /* 0 or DICT_FOREIGN_ON_DELETE_CASCADE
|
||||
or DICT_FOREIGN_ON_DELETE_SET_NULL */
|
||||
char* foreign_table_name;/* foreign table name */
|
||||
dict_table_t* foreign_table; /* table where the foreign key is */
|
||||
char** foreign_col_names;/* names of the columns in the
|
||||
@ -278,6 +280,9 @@ struct dict_foreign_struct{
|
||||
table */
|
||||
};
|
||||
|
||||
#define DICT_FOREIGN_ON_DELETE_CASCADE 1
|
||||
#define DICT_FOREIGN_ON_DELETE_SET_NULL 2
|
||||
|
||||
#define DICT_INDEX_MAGIC_N 76789786
|
||||
|
||||
/* Data structure for a database table */
|
||||
@ -313,6 +318,12 @@ struct dict_table_struct{
|
||||
NOT allowed until this count gets to zero;
|
||||
MySQL does NOT itself check the number of
|
||||
open handles at drop */
|
||||
ulint n_foreign_key_checks_running;
|
||||
/* count of how many foreign key check
|
||||
operations are currently being performed
|
||||
on the table: we cannot drop the table while
|
||||
there are foreign key checks running on
|
||||
it! */
|
||||
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
|
||||
@ -359,17 +370,16 @@ struct dict_table_struct{
|
||||
after database startup or table creation */
|
||||
ulint stat_modified_counter;
|
||||
/* when a row is inserted, updated, or deleted,
|
||||
we add the row length to this number; we
|
||||
calculate new estimates for the stat_...
|
||||
values for the table and the indexes at an
|
||||
interval of 2 GB or when about 1 / 16 of table
|
||||
has been modified; also
|
||||
when the estimate operation is called
|
||||
for MySQL SHOW TABLE STATUS; the counter is
|
||||
reset to zero at statistics calculation;
|
||||
this counter
|
||||
is not protected by any latch, because this
|
||||
is only used for heuristics */
|
||||
we add 1 to this number; we calculate new
|
||||
estimates for the stat_... values for the
|
||||
table and the indexes at an interval of 2 GB
|
||||
or when about 1 / 16 of table has been
|
||||
modified; also when the estimate operation is
|
||||
called for MySQL SHOW TABLE STATUS; the
|
||||
counter is reset to zero at statistics
|
||||
calculation; this counter is not protected by
|
||||
any latch, because this is only used for
|
||||
heuristics */
|
||||
/*----------------------*/
|
||||
mutex_t autoinc_mutex;
|
||||
/* mutex protecting the autoincrement
|
||||
|
@ -127,7 +127,11 @@ UNIV_INLINE
|
||||
ibool
|
||||
ibuf_should_try(
|
||||
/*============*/
|
||||
dict_index_t* index); /* in: index where to insert */
|
||||
dict_index_t* index, /* in: index where to insert */
|
||||
ulint ignore_sec_unique); /* in: if != 0, we should
|
||||
ignore UNIQUE constraint on
|
||||
a secondary index when we
|
||||
decide */
|
||||
/**********************************************************************
|
||||
Returns TRUE if the current OS thread is performing an insert buffer
|
||||
routine. */
|
||||
|
@ -81,10 +81,16 @@ UNIV_INLINE
|
||||
ibool
|
||||
ibuf_should_try(
|
||||
/*============*/
|
||||
dict_index_t* index) /* in: index where to insert */
|
||||
dict_index_t* index, /* in: index where to insert */
|
||||
ulint ignore_sec_unique) /* in: if != 0, we should
|
||||
ignore UNIQUE constraint on
|
||||
a secondary index when we
|
||||
decide */
|
||||
{
|
||||
if (!(index->type & (DICT_CLUSTERED | DICT_UNIQUE))
|
||||
if (!(index->type & DICT_CLUSTERED)
|
||||
&& (ignore_sec_unique || !(index->type & DICT_UNIQUE))
|
||||
&& ibuf->meter > IBUF_THRESHOLD) {
|
||||
|
||||
ibuf_flush_count++;
|
||||
|
||||
if (ibuf_flush_count % 8 == 0) {
|
||||
|
@ -341,6 +341,8 @@ os_aio_windows_handle(
|
||||
void** message2,
|
||||
ulint* type); /* out: OS_FILE_WRITE or ..._READ */
|
||||
#endif
|
||||
|
||||
/* Currently we do not use Posix async i/o */
|
||||
#ifdef POSIX_ASYNC_IO
|
||||
/**************************************************************************
|
||||
This function is only used in Posix asynchronous i/o. Waits for an aio
|
||||
|
@ -149,9 +149,9 @@ void
|
||||
os_mutex_free(
|
||||
/*==========*/
|
||||
os_mutex_t mutex); /* in: mutex to free */
|
||||
#ifndef _WIN32
|
||||
/**************************************************************
|
||||
Acquires ownership of a fast mutex. */
|
||||
Acquires ownership of a fast mutex. Currently in Windows this is the same
|
||||
as os_fast_mutex_lock! */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
os_fast_mutex_trylock(
|
||||
@ -160,7 +160,6 @@ os_fast_mutex_trylock(
|
||||
was reserved by another
|
||||
thread */
|
||||
os_fast_mutex_t* fast_mutex); /* in: mutex to acquire */
|
||||
#endif
|
||||
/**************************************************************
|
||||
Releases ownership of a fast mutex. */
|
||||
|
||||
|
@ -10,9 +10,9 @@ Created 9/6/1995 Heikki Tuuri
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/**************************************************************
|
||||
Acquires ownership of a fast mutex. */
|
||||
Acquires ownership of a fast mutex. Currently in Windows this is the same
|
||||
as os_fast_mutex_lock! */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
os_fast_mutex_trylock(
|
||||
@ -23,20 +23,11 @@ os_fast_mutex_trylock(
|
||||
os_fast_mutex_t* fast_mutex) /* in: mutex to acquire */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
int ret;
|
||||
EnterCriticalSection(fast_mutex);
|
||||
|
||||
/* TODO: TryEnterCriticalSection is probably not found from
|
||||
NT versions < 4! */
|
||||
ret = TryEnterCriticalSection(fast_mutex);
|
||||
|
||||
if (ret) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
#else
|
||||
return((ulint) pthread_mutex_trylock(fast_mutex));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -209,6 +209,27 @@ row_update_for_mysql(
|
||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
||||
handle */
|
||||
/*************************************************************************
|
||||
Creates an query graph node of 'update' type to be used in the MySQL
|
||||
interface. */
|
||||
|
||||
upd_node_t*
|
||||
row_create_update_node_for_mysql(
|
||||
/*=============================*/
|
||||
/* out, own: update node */
|
||||
dict_table_t* table, /* in: table to update */
|
||||
mem_heap_t* heap); /* in: mem heap from which allocated */
|
||||
/**************************************************************************
|
||||
Does a cascaded delete or set null in a foreign key operation. */
|
||||
|
||||
ulint
|
||||
row_update_cascade_for_mysql(
|
||||
/*=========================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
upd_node_t* node, /* in: update node used in the cascade
|
||||
or set null operation */
|
||||
dict_table_t* table); /* in: table where we do the operation */
|
||||
/*************************************************************************
|
||||
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. */
|
||||
|
@ -312,6 +312,11 @@ struct upd_node_struct{
|
||||
ibool in_mysql_interface;
|
||||
/* TRUE if the update node was created
|
||||
for the MySQL interface */
|
||||
upd_node_t* cascade_node;/* NULL or an update node template which
|
||||
is used to implement ON DELETE CASCADE
|
||||
or ... SET NULL for foreign keys */
|
||||
mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade
|
||||
node is created */
|
||||
sel_node_t* select; /* query graph subtree implementing a base
|
||||
table cursor: the rows returned will be
|
||||
updated */
|
||||
@ -322,6 +327,11 @@ struct upd_node_struct{
|
||||
of the MySQL interface */
|
||||
dict_table_t* table; /* table where updated */
|
||||
upd_t* update; /* update vector for the row */
|
||||
ulint update_n_fields;
|
||||
/* when this struct is used to implement
|
||||
a cascade operation for foreign keys, we store
|
||||
here the size of the buffer allocated for use
|
||||
as the update vector */
|
||||
sym_node_list_t columns;/* symbol table nodes for the columns
|
||||
to retrieve from the table */
|
||||
ibool has_clust_rec_x_lock;
|
||||
|
@ -359,12 +359,17 @@ V
|
||||
Memory pool mutex */
|
||||
|
||||
/* Latching order levels */
|
||||
|
||||
/* User transaction locks are higher than any of the latch levels below:
|
||||
no latches are allowed when a thread goes to wait for a normal table
|
||||
or row lock! */
|
||||
#define SYNC_USER_TRX_LOCK 9999
|
||||
#define SYNC_NO_ORDER_CHECK 3000 /* this can be used to suppress
|
||||
latching order checking */
|
||||
#define SYNC_LEVEL_NONE 2000 /* default: level not defined */
|
||||
#define SYNC_FOREIGN_KEY_CHECK 1001
|
||||
#define SYNC_DICT 1000
|
||||
#define SYNC_DICT_AUTOINC_MUTEX 999
|
||||
#define SYNC_FOREIGN_KEY_CHECK 998
|
||||
#define SYNC_PURGE_IS_RUNNING 997
|
||||
#define SYNC_DICT_HEADER 995
|
||||
#define SYNC_IBUF_HEADER 914
|
||||
@ -429,7 +434,7 @@ implementation of a mutual exclusion semaphore. */
|
||||
struct mutex_struct {
|
||||
ulint lock_word; /* This ulint is the target of the atomic
|
||||
test-and-set instruction in Win32 */
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||
os_fast_mutex_t
|
||||
os_fast_mutex; /* In other systems we use this OS mutex
|
||||
in place of lock_word */
|
||||
|
@ -53,7 +53,7 @@ mutex_test_and_set(
|
||||
1 */
|
||||
mutex_t* mutex) /* in: mutex */
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||
ulint res;
|
||||
ulint* lw; /* assembler code is used to ensure that
|
||||
lock_word is loaded from memory */
|
||||
@ -120,7 +120,7 @@ mutex_reset_lock_word(
|
||||
/*==================*/
|
||||
mutex_t* mutex) /* in: mutex */
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||
ulint* lw; /* assembler code is used to ensure that
|
||||
lock_word is loaded from memory */
|
||||
ut_ad(mutex);
|
||||
|
@ -259,7 +259,7 @@ therefore 256 */
|
||||
/* The offset of the transaction system header on the page */
|
||||
#define TRX_SYS FSEG_PAGE_DATA
|
||||
|
||||
/* Transaction system header; protected by trx_sys->mutex */
|
||||
/* Transaction system header */
|
||||
/*-------------------------------------------------------------*/
|
||||
#define TRX_SYS_TRX_ID_STORE 0 /* the maximum trx id or trx number
|
||||
modulo TRX_SYS_TRX_ID_UPDATE_MARGIN
|
||||
|
@ -93,7 +93,6 @@ trx_sysf_get(
|
||||
{
|
||||
trx_sysf_t* header;
|
||||
|
||||
ut_ad(mutex_own(&(kernel_mutex)));
|
||||
ut_ad(mtr);
|
||||
|
||||
header = TRX_SYS + buf_page_get(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
|
||||
|
@ -298,6 +298,17 @@ struct trx_struct{
|
||||
of view of concurrency control:
|
||||
TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY,
|
||||
... */
|
||||
ibool check_foreigns; /* normally TRUE, but if the user
|
||||
wants to suppress foreign key checks,
|
||||
(in table imports, for example) we
|
||||
set this FALSE */
|
||||
ibool check_unique_secondary;
|
||||
/* normally TRUE, but if the user
|
||||
wants to speed up inserts by
|
||||
suppressing unique key checks
|
||||
for secondary indexes when we decide
|
||||
if we can use the insert buffer for
|
||||
them, we set this FALSE */
|
||||
dulint id; /* transaction id */
|
||||
dulint no; /* transaction serialization number ==
|
||||
max trx id when the transaction is
|
||||
@ -328,6 +339,9 @@ struct trx_struct{
|
||||
/* how many tables the current SQL
|
||||
statement uses, except those
|
||||
in consistent read */
|
||||
ibool has_dict_foreign_key_check_lock;
|
||||
/* TRUE if the trx currently holds
|
||||
an s-lock on dict_foreign_... */
|
||||
ibool has_search_latch;
|
||||
/* TRUE if this trx has latched the
|
||||
search system latch in S-mode */
|
||||
|
@ -1534,6 +1534,8 @@ lock_rec_enqueue_waiting(
|
||||
|
||||
if (que_thr_stop(thr)) {
|
||||
|
||||
ut_a(0);
|
||||
|
||||
return(DB_QUE_THR_SUSPENDED);
|
||||
}
|
||||
|
||||
@ -2918,6 +2920,7 @@ lock_table_enqueue_waiting(
|
||||
stopped anyway */
|
||||
|
||||
if (que_thr_stop(thr)) {
|
||||
ut_a(0);
|
||||
|
||||
return(DB_QUE_THR_SUSPENDED);
|
||||
}
|
||||
|
@ -526,7 +526,8 @@ opt_search_plan_for_table(
|
||||
dict_index_t* best_index;
|
||||
ulint n_fields;
|
||||
ulint goodness;
|
||||
ulint last_op;
|
||||
ulint last_op = 75946965; /* Eliminate a Purify
|
||||
warning */
|
||||
ulint best_goodness;
|
||||
ulint best_last_op;
|
||||
ulint mix_id_pos;
|
||||
|
@ -555,6 +555,12 @@ que_graph_free_recursive(
|
||||
btr_pcur_free_for_mysql(upd->pcur);
|
||||
}
|
||||
|
||||
que_graph_free_recursive(upd->cascade_node);
|
||||
|
||||
if (upd->cascade_heap) {
|
||||
mem_heap_free(upd->cascade_heap);
|
||||
}
|
||||
|
||||
que_graph_free_recursive(upd->select);
|
||||
|
||||
mem_heap_free(upd->heap);
|
||||
@ -1110,9 +1116,6 @@ que_thr_move_to_run_state_for_mysql(
|
||||
trx->n_active_thrs++;
|
||||
|
||||
thr->is_active = TRUE;
|
||||
|
||||
ut_ad((thr->graph)->n_active_thrs == 1);
|
||||
ut_ad(trx->n_active_thrs == 1);
|
||||
}
|
||||
|
||||
thr->state = QUE_THR_RUNNING;
|
||||
|
@ -355,6 +355,223 @@ row_ins_dupl_error_with_rec(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Either deletes or sets the referencing columns SQL NULL in a child row.
|
||||
Used in ON DELETE ... clause for foreign keys when a parent row is
|
||||
deleted. */
|
||||
static
|
||||
ulint
|
||||
row_ins_foreign_delete_or_set_null(
|
||||
/*===============================*/
|
||||
/* out: DB_SUCCESS, DB_LOCK_WAIT,
|
||||
or error code */
|
||||
que_thr_t* thr, /* in: query thread whose run_node
|
||||
is an update node */
|
||||
dict_foreign_t* foreign, /* in: foreign key constraint whose
|
||||
type is != 0 */
|
||||
btr_pcur_t* pcur, /* in: cursor placed on a matching
|
||||
index record in the child table */
|
||||
mtr_t* mtr) /* in: mtr holding the latch of pcur
|
||||
page */
|
||||
{
|
||||
upd_node_t* node;
|
||||
upd_node_t* cascade;
|
||||
dict_table_t* table = foreign->foreign_table;
|
||||
dict_index_t* index;
|
||||
dict_index_t* clust_index;
|
||||
dtuple_t* ref;
|
||||
mem_heap_t* tmp_heap;
|
||||
rec_t* rec;
|
||||
rec_t* clust_rec;
|
||||
upd_t* update;
|
||||
ulint err;
|
||||
ulint i;
|
||||
char err_buf[1000];
|
||||
|
||||
ut_a(thr && foreign && pcur && mtr);
|
||||
|
||||
node = thr->run_node;
|
||||
|
||||
if (node->cascade_node == NULL) {
|
||||
/* Extend our query graph by creating a child to current
|
||||
update node. The child is used in the cascade or set null
|
||||
operation. */
|
||||
|
||||
node->cascade_heap = mem_heap_create(128);
|
||||
node->cascade_node = row_create_update_node_for_mysql(
|
||||
table, node->cascade_heap);
|
||||
que_node_set_parent(node->cascade_node, node);
|
||||
}
|
||||
|
||||
/* Initialize cascade_node to do the operation we want. Note that we
|
||||
use the SAME cascade node to do all foreign key operations of the
|
||||
SQL DELETE: the table of the cascade node may change if there are
|
||||
several child tables to the table where the delete is done! */
|
||||
|
||||
cascade = node->cascade_node;
|
||||
|
||||
cascade->table = table;
|
||||
|
||||
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE ) {
|
||||
cascade->is_delete = TRUE;
|
||||
} else {
|
||||
cascade->is_delete = FALSE;
|
||||
|
||||
if (foreign->n_fields > cascade->update_n_fields) {
|
||||
/* We have to make the update vector longer */
|
||||
|
||||
cascade->update = upd_create(foreign->n_fields,
|
||||
node->cascade_heap);
|
||||
cascade->update_n_fields = foreign->n_fields;
|
||||
}
|
||||
}
|
||||
|
||||
index = btr_pcur_get_btr_cur(pcur)->index;
|
||||
|
||||
rec = btr_pcur_get_rec(pcur);
|
||||
|
||||
if (index->type & DICT_CLUSTERED) {
|
||||
/* pcur is already positioned in the clustered index of
|
||||
the child table */
|
||||
|
||||
clust_index = index;
|
||||
clust_rec = rec;
|
||||
} else {
|
||||
/* We have to look for the record in the clustered index
|
||||
in the child table */
|
||||
|
||||
clust_index = dict_table_get_first_index(table);
|
||||
|
||||
tmp_heap = mem_heap_create(256);
|
||||
|
||||
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec,
|
||||
tmp_heap);
|
||||
btr_pcur_open_with_no_init(clust_index, ref,
|
||||
PAGE_CUR_LE, BTR_SEARCH_LEAF,
|
||||
cascade->pcur, 0, mtr);
|
||||
|
||||
mem_heap_free(tmp_heap);
|
||||
|
||||
clust_rec = btr_pcur_get_rec(cascade->pcur);
|
||||
}
|
||||
|
||||
if (!page_rec_is_user_rec(clust_rec)) {
|
||||
fprintf(stderr, "InnoDB: error in cascade of a foreign key op\n"
|
||||
"InnoDB: index %s table %s\n", index->name,
|
||||
index->table->name);
|
||||
|
||||
rec_sprintf(err_buf, 900, rec);
|
||||
fprintf(stderr, "InnoDB: record %s\n", err_buf);
|
||||
|
||||
rec_sprintf(err_buf, 900, clust_rec);
|
||||
fprintf(stderr, "InnoDB: clustered record %s\n", err_buf);
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Make a detailed bug report and send it\n");
|
||||
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
|
||||
|
||||
err = DB_SUCCESS;
|
||||
|
||||
goto nonstandard_exit_func;
|
||||
}
|
||||
|
||||
/* Set an X-lock on the row to delete or update in the child table */
|
||||
|
||||
err = lock_table(0, table, LOCK_IX, thr);
|
||||
|
||||
if (err == DB_SUCCESS) {
|
||||
err = lock_clust_rec_read_check_and_lock(0, clust_rec,
|
||||
clust_index, LOCK_X, thr);
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
goto nonstandard_exit_func;
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(clust_rec)) {
|
||||
/* This should never happen since we already have an S-lock
|
||||
on non-delete-marked clust_rec or secondary index record! */
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: error 2 in cascade of a foreign key op\n"
|
||||
"InnoDB: index %s table %s\n", index->name,
|
||||
index->table->name);
|
||||
|
||||
rec_sprintf(err_buf, 900, rec);
|
||||
fprintf(stderr, "InnoDB: record %s\n", err_buf);
|
||||
|
||||
rec_sprintf(err_buf, 900, clust_rec);
|
||||
fprintf(stderr, "InnoDB: clustered record %s\n", err_buf);
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Make a detailed bug report and send it\n");
|
||||
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
|
||||
|
||||
ut_a(0);
|
||||
|
||||
goto nonstandard_exit_func;
|
||||
}
|
||||
|
||||
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
|
||||
/* Build the appropriate update vector which sets
|
||||
foreign->n_fields first fields in rec to SQL NULL */
|
||||
|
||||
update = cascade->update;
|
||||
|
||||
update->info_bits = 0;
|
||||
update->n_fields = foreign->n_fields;
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
(update->fields + i)->field_no
|
||||
= dict_table_get_nth_col_pos(table,
|
||||
dict_index_get_nth_col_no(index, i));
|
||||
(update->fields + i)->exp = NULL;
|
||||
(update->fields + i)->new_val.len = UNIV_SQL_NULL;
|
||||
(update->fields + i)->new_val.data = NULL;
|
||||
(update->fields + i)->extern_storage = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store pcur position and initialize or store the cascade node
|
||||
pcur stored position */
|
||||
|
||||
btr_pcur_store_position(pcur, mtr);
|
||||
|
||||
if (index == clust_index) {
|
||||
btr_pcur_copy_stored_position(cascade->pcur, pcur);
|
||||
} else {
|
||||
btr_pcur_store_position(cascade->pcur, mtr);
|
||||
}
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON);
|
||||
|
||||
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
|
||||
|
||||
err = row_update_cascade_for_mysql(thr, cascade,
|
||||
foreign->foreign_table);
|
||||
mtr_start(mtr);
|
||||
|
||||
/* Restore pcur position */
|
||||
|
||||
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
|
||||
|
||||
return(err);
|
||||
|
||||
nonstandard_exit_func:
|
||||
|
||||
btr_pcur_store_position(pcur, mtr);
|
||||
|
||||
mtr_commit(mtr);
|
||||
mtr_start(mtr);
|
||||
|
||||
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Sets a shared lock on a record. Used in locking possible duplicate key
|
||||
records. */
|
||||
@ -416,6 +633,13 @@ row_ins_check_foreign_constraint(
|
||||
|
||||
ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED));
|
||||
|
||||
if (thr_get_trx(thr)->check_foreigns == FALSE) {
|
||||
/* The user has suppressed foreign key checks currently for
|
||||
this session */
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/* If any of the foreign key fields in entry is SQL NULL, we
|
||||
suppress the foreign key check: this is compatible with Oracle,
|
||||
for example */
|
||||
@ -501,11 +725,21 @@ row_ins_check_foreign_constraint(
|
||||
|
||||
if (check_ref) {
|
||||
err = DB_SUCCESS;
|
||||
} else {
|
||||
err = DB_ROW_IS_REFERENCED;
|
||||
}
|
||||
|
||||
break;
|
||||
} else if (foreign->type != 0) {
|
||||
err =
|
||||
row_ins_foreign_delete_or_set_null(
|
||||
thr, foreign, &pcur, &mtr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
err = DB_ROW_IS_REFERENCED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -534,6 +768,8 @@ next_rec:
|
||||
}
|
||||
}
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
/* Restore old value */
|
||||
@ -561,6 +797,10 @@ row_ins_check_foreign_constraints(
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
ulint err;
|
||||
trx_t* trx;
|
||||
ibool got_s_lock = FALSE;
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
|
||||
@ -569,16 +809,26 @@ row_ins_check_foreign_constraints(
|
||||
|
||||
if (foreign->referenced_table == NULL) {
|
||||
dict_table_get(foreign->referenced_table_name,
|
||||
thr_get_trx(thr));
|
||||
trx);
|
||||
}
|
||||
|
||||
if (!trx->has_dict_foreign_key_check_lock) {
|
||||
got_s_lock = TRUE;
|
||||
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
|
||||
trx->has_dict_foreign_key_check_lock = TRUE;
|
||||
}
|
||||
|
||||
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
||||
table, index, entry, thr);
|
||||
if (got_s_lock) {
|
||||
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
|
||||
trx->has_dict_foreign_key_check_lock = FALSE;
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return(err);
|
||||
}
|
||||
@ -869,6 +1119,7 @@ row_ins_index_entry_low(
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
btr_cur_t cursor;
|
||||
ulint ignore_sec_unique = 0;
|
||||
ulint modify;
|
||||
rec_t* insert_rec;
|
||||
rec_t* rec;
|
||||
@ -887,8 +1138,13 @@ row_ins_index_entry_low(
|
||||
the function will return in both low_match and up_match of the
|
||||
cursor sensible values */
|
||||
|
||||
if (!(thr_get_trx(thr)->check_unique_secondary)) {
|
||||
ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE;
|
||||
}
|
||||
|
||||
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
|
||||
mode | BTR_INSERT, &cursor, 0, &mtr);
|
||||
mode | BTR_INSERT | ignore_sec_unique,
|
||||
&cursor, 0, &mtr);
|
||||
|
||||
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
|
||||
/* The insertion was made to the insert buffer already during
|
||||
|
@ -499,29 +499,24 @@ UNIV_INLINE
|
||||
void
|
||||
row_update_statistics_if_needed(
|
||||
/*============================*/
|
||||
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
|
||||
dict_table_t* table) /* in: table */
|
||||
{
|
||||
ulint counter;
|
||||
|
||||
counter = prebuilt->table->stat_modified_counter;
|
||||
counter = table->stat_modified_counter;
|
||||
|
||||
/* Since the physical size of an InnoDB row is bigger than the
|
||||
MySQL row len, we put a safety factor 2 below */
|
||||
|
||||
counter += 2 * prebuilt->mysql_row_len;
|
||||
|
||||
prebuilt->table->stat_modified_counter = counter;
|
||||
table->stat_modified_counter = counter + 1;
|
||||
|
||||
/* Calculate new statistics if 1 / 16 of table has been modified
|
||||
since the last time a statistics batch was run, or if
|
||||
stat_modified_counter > 2 000 000 000 (to avoid wrap-around) */
|
||||
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
|
||||
We calculate statistics at most every 16th round, since we may have
|
||||
a counter table which is very small and updated very often. */
|
||||
|
||||
if (counter > 2000000000
|
||||
|| ((ib_longlong)counter >
|
||||
(UNIV_PAGE_SIZE * prebuilt->table->stat_clustered_index_size)
|
||||
/ 16)) {
|
||||
|| ((ib_longlong)counter > 16 + table->stat_n_rows / 16)) {
|
||||
|
||||
dict_update_statistics(prebuilt->table);
|
||||
dict_update_statistics(table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -712,7 +707,7 @@ run_again:
|
||||
prebuilt->table->stat_n_rows--;
|
||||
}
|
||||
|
||||
row_update_statistics_if_needed(prebuilt);
|
||||
row_update_statistics_if_needed(prebuilt->table);
|
||||
trx->op_info = "";
|
||||
|
||||
return((int) err);
|
||||
@ -745,6 +740,43 @@ row_prebuild_sel_graph(
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Creates an query graph node of 'update' type to be used in the MySQL
|
||||
interface. */
|
||||
|
||||
upd_node_t*
|
||||
row_create_update_node_for_mysql(
|
||||
/*=============================*/
|
||||
/* out, own: update node */
|
||||
dict_table_t* table, /* in: table to update */
|
||||
mem_heap_t* heap) /* in: mem heap from which allocated */
|
||||
{
|
||||
upd_node_t* node;
|
||||
|
||||
node = upd_node_create(heap);
|
||||
|
||||
node->in_mysql_interface = TRUE;
|
||||
node->is_delete = FALSE;
|
||||
node->searched_update = FALSE;
|
||||
node->select_will_do_update = FALSE;
|
||||
node->select = NULL;
|
||||
node->pcur = btr_pcur_create_for_mysql();
|
||||
node->table = table;
|
||||
|
||||
node->update = upd_create(dict_table_get_n_cols(table), heap);
|
||||
|
||||
node->update_n_fields = dict_table_get_n_cols(table);
|
||||
|
||||
UT_LIST_INIT(node->columns);
|
||||
node->has_clust_rec_x_lock = TRUE;
|
||||
node->cmpl_info = 0;
|
||||
|
||||
node->table_sym = NULL;
|
||||
node->col_assign_list = NULL;
|
||||
|
||||
return(node);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Gets pointer to a prebuilt update vector used in updates. If the update
|
||||
graph has not yet been built in the prebuilt struct, then this function
|
||||
@ -767,27 +799,10 @@ row_get_prebuilt_update_vector(
|
||||
/* Not called before for this handle: create an update node
|
||||
and query graph to the prebuilt struct */
|
||||
|
||||
node = upd_node_create(prebuilt->heap);
|
||||
node = row_create_update_node_for_mysql(table, prebuilt->heap);
|
||||
|
||||
prebuilt->upd_node = node;
|
||||
|
||||
node->in_mysql_interface = TRUE;
|
||||
node->is_delete = FALSE;
|
||||
node->searched_update = FALSE;
|
||||
node->select_will_do_update = FALSE;
|
||||
node->select = NULL;
|
||||
node->pcur = btr_pcur_create_for_mysql();
|
||||
node->table = table;
|
||||
|
||||
node->update = upd_create(dict_table_get_n_cols(table),
|
||||
prebuilt->heap);
|
||||
UT_LIST_INIT(node->columns);
|
||||
node->has_clust_rec_x_lock = TRUE;
|
||||
node->cmpl_info = 0;
|
||||
|
||||
node->table_sym = NULL;
|
||||
node->col_assign_list = NULL;
|
||||
|
||||
prebuilt->upd_graph =
|
||||
que_node_get_parent(
|
||||
pars_complete_graph_for_exec(node,
|
||||
@ -914,7 +929,7 @@ run_again:
|
||||
|
||||
que_thr_stop_for_mysql_no_error(thr, trx);
|
||||
|
||||
if (prebuilt->upd_node->is_delete) {
|
||||
if (node->is_delete) {
|
||||
if (prebuilt->table->stat_n_rows > 0) {
|
||||
prebuilt->table->stat_n_rows--;
|
||||
}
|
||||
@ -924,13 +939,66 @@ run_again:
|
||||
srv_n_rows_updated++;
|
||||
}
|
||||
|
||||
row_update_statistics_if_needed(prebuilt);
|
||||
row_update_statistics_if_needed(prebuilt->table);
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Does a cascaded delete or set null in a foreign key operation. */
|
||||
|
||||
ulint
|
||||
row_update_cascade_for_mysql(
|
||||
/*=========================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
upd_node_t* node, /* in: update node used in the cascade
|
||||
or set null operation */
|
||||
dict_table_t* table) /* in: table where we do the operation */
|
||||
{
|
||||
ulint err;
|
||||
trx_t* trx;
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
run_again:
|
||||
thr->run_node = node;
|
||||
thr->prev_node = node;
|
||||
|
||||
row_upd_step(thr);
|
||||
|
||||
err = trx->error_state;
|
||||
|
||||
if (err == DB_LOCK_WAIT) {
|
||||
que_thr_stop_for_mysql(thr);
|
||||
|
||||
row_mysql_handle_errors(&err, trx, thr, NULL);
|
||||
|
||||
goto run_again;
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
if (node->is_delete) {
|
||||
if (table->stat_n_rows > 0) {
|
||||
table->stat_n_rows--;
|
||||
}
|
||||
|
||||
srv_n_rows_deleted++;
|
||||
} else {
|
||||
srv_n_rows_updated++;
|
||||
}
|
||||
|
||||
row_update_statistics_if_needed(table);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a table is such that we automatically created a clustered
|
||||
index on it (on row id). */
|
||||
@ -1169,6 +1237,7 @@ row_create_table_for_mysql(
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
heap = mem_heap_create(512);
|
||||
@ -1221,6 +1290,8 @@ row_create_table_for_mysql(
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||
|
||||
trx->op_info = "";
|
||||
@ -1268,6 +1339,7 @@ row_create_index_for_mysql(
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
heap = mem_heap_create(512);
|
||||
@ -1298,6 +1370,7 @@ row_create_index_for_mysql(
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||
|
||||
@ -1353,6 +1426,7 @@ row_table_add_foreign_constraints(
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
trx->dict_operation = TRUE;
|
||||
@ -1377,6 +1451,7 @@ row_table_add_foreign_constraints(
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
@ -1471,7 +1546,8 @@ loop:
|
||||
goto already_dropped;
|
||||
}
|
||||
|
||||
if (table->n_mysql_handles_opened > 0) {
|
||||
if (table->n_mysql_handles_opened > 0
|
||||
|| table->n_foreign_key_checks_running > 0) {
|
||||
|
||||
return(n_tables + n_tables_dropped);
|
||||
}
|
||||
@ -1717,6 +1793,9 @@ row_drop_table_for_mysql(
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
if (!has_dict_mutex) {
|
||||
/* Prevent foreign key checks while we are dropping the table */
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
@ -1729,9 +1808,6 @@ row_drop_table_for_mysql(
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
/* Prevent foreign key checks while we are dropping the table */
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
|
||||
/* Prevent purge from running while we are dropping the table */
|
||||
rw_lock_s_lock(&(purge_sys->purge_is_running));
|
||||
|
||||
@ -1766,6 +1842,22 @@ row_drop_table_for_mysql(
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (table->n_foreign_key_checks_running > 0) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: You are trying to drop table %s\n"
|
||||
"InnoDB: though there are foreign key check running on it.\n"
|
||||
"InnoDB: Adding the table to the background drop queue.\n",
|
||||
table->name);
|
||||
|
||||
row_add_table_to_background_drop_list(table);
|
||||
|
||||
err = DB_SUCCESS;
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
/* Remove any locks there are on the table or its records */
|
||||
|
||||
lock_reset_all_on_table(table);
|
||||
@ -1793,10 +1885,9 @@ row_drop_table_for_mysql(
|
||||
funct_exit:
|
||||
rw_lock_s_unlock(&(purge_sys->purge_is_running));
|
||||
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
if (!has_dict_mutex) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
}
|
||||
|
||||
que_graph_free(graph);
|
||||
@ -1832,6 +1923,7 @@ row_drop_database_for_mysql(
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
loop:
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
while (table_name = dict_get_first_table_name_in_db(name)) {
|
||||
@ -1873,6 +1965,7 @@ loop:
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
@ -2009,6 +2102,7 @@ row_rename_table_for_mysql(
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
table = dict_table_get_low(old_name);
|
||||
@ -2090,6 +2184,7 @@ row_rename_table_for_mysql(
|
||||
}
|
||||
funct_exit:
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
|
@ -2114,12 +2114,18 @@ row_sel_store_mysql_rec(
|
||||
mem_heap_free(extern_field_heap);
|
||||
extern_field_heap = NULL;
|
||||
}
|
||||
} else {
|
||||
if (!templ->mysql_null_bit_mask) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to return an SQL NULL field in a non-null\n"
|
||||
"innoDB: column! Table name %s\n", prebuilt->table->name);
|
||||
} else {
|
||||
mysql_rec[templ->mysql_null_byte_offset] |=
|
||||
(byte) (templ->mysql_null_bit_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Builds a previous version of a clustered index record for a consistent read */
|
||||
|
@ -73,8 +73,7 @@ steps of query graph execution. */
|
||||
|
||||
/*************************************************************************
|
||||
Checks if index currently is mentioned as a referenced index in a foreign
|
||||
key constraint. This function also loads into the dictionary cache the
|
||||
possible referencing table. */
|
||||
key constraint. */
|
||||
static
|
||||
ibool
|
||||
row_upd_index_is_referenced(
|
||||
@ -85,44 +84,28 @@ row_upd_index_is_referenced(
|
||||
the referencing table has been dropped when
|
||||
we leave this function: this function is only
|
||||
for heuristic use! */
|
||||
dict_index_t* index) /* in: index */
|
||||
dict_index_t* index, /* in: index */
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
dict_table_t* table = index->table;
|
||||
dict_foreign_t* foreign;
|
||||
ulint phase = 1;
|
||||
|
||||
try_again:
|
||||
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (phase == 2) {
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
if (!trx->has_dict_foreign_key_check_lock) {
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->referenced_index == index) {
|
||||
if (foreign->foreign_table == NULL) {
|
||||
if (phase == 2) {
|
||||
dict_table_get_low(foreign->
|
||||
foreign_table_name);
|
||||
} else {
|
||||
phase = 2;
|
||||
rw_lock_s_unlock(
|
||||
&dict_foreign_key_check_lock);
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
|
||||
if (!trx->has_dict_foreign_key_check_lock) {
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
|
||||
if (phase == 2) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
@ -131,10 +114,8 @@ try_again:
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
if (!trx->has_dict_foreign_key_check_lock) {
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
|
||||
if (phase == 2) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
@ -160,8 +141,17 @@ row_upd_check_references_constraints(
|
||||
dict_foreign_t* foreign;
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* entry;
|
||||
trx_t* trx;
|
||||
rec_t* rec;
|
||||
ulint err;
|
||||
ibool got_s_lock = FALSE;
|
||||
|
||||
if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
rec = btr_pcur_get_rec(pcur);
|
||||
|
||||
@ -173,17 +163,61 @@ row_upd_check_references_constraints(
|
||||
|
||||
mtr_start(mtr);
|
||||
|
||||
if (!trx->has_dict_foreign_key_check_lock) {
|
||||
got_s_lock = TRUE;
|
||||
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
|
||||
trx->has_dict_foreign_key_check_lock = TRUE;
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->referenced_index == index) {
|
||||
if (foreign->foreign_table == NULL) {
|
||||
dict_table_get(foreign->foreign_table_name,
|
||||
trx);
|
||||
}
|
||||
|
||||
if (foreign->foreign_table) {
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
(foreign->foreign_table
|
||||
->n_foreign_key_checks_running)++;
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
/* NOTE that if the thread ends up waiting for a lock
|
||||
we will release dict_foreign_key_check_lock
|
||||
temporarily! But the counter on the table
|
||||
protects 'foreign' from being dropped while the check
|
||||
is running. */
|
||||
|
||||
err = row_ins_check_foreign_constraint(FALSE, foreign,
|
||||
table, index, entry, thr);
|
||||
|
||||
if (foreign->foreign_table) {
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
ut_a(foreign->foreign_table
|
||||
->n_foreign_key_checks_running > 0);
|
||||
|
||||
(foreign->foreign_table
|
||||
->n_foreign_key_checks_running)--;
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
if (got_s_lock) {
|
||||
rw_lock_s_unlock(
|
||||
&dict_foreign_key_check_lock);
|
||||
trx->has_dict_foreign_key_check_lock
|
||||
= FALSE;
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(err);
|
||||
@ -193,7 +227,11 @@ row_upd_check_references_constraints(
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
if (got_s_lock) {
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
trx->has_dict_foreign_key_check_lock = FALSE;
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(DB_SUCCESS);
|
||||
@ -222,6 +260,9 @@ upd_node_create(
|
||||
node->index = NULL;
|
||||
node->update = NULL;
|
||||
|
||||
node->cascade_heap = NULL;
|
||||
node->cascade_node = NULL;
|
||||
|
||||
node->select = NULL;
|
||||
|
||||
node->heap = mem_heap_create(128);
|
||||
@ -1027,7 +1068,7 @@ row_upd_sec_index_entry(
|
||||
|
||||
index = node->index;
|
||||
|
||||
check_ref = row_upd_index_is_referenced(index);
|
||||
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
|
||||
|
||||
heap = mem_heap_create(1024);
|
||||
|
||||
@ -1391,7 +1432,7 @@ row_upd_clust_step(
|
||||
|
||||
index = dict_table_get_first_index(node->table);
|
||||
|
||||
check_ref = row_upd_index_is_referenced(index);
|
||||
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
|
||||
|
||||
pcur = node->pcur;
|
||||
|
||||
|
@ -2017,15 +2017,18 @@ srv_suspend_mysql_thread(
|
||||
/*=====================*/
|
||||
/* out: TRUE if the lock wait timeout was
|
||||
exceeded */
|
||||
que_thr_t* thr) /* in: query thread associated with
|
||||
the MySQL OS thread */
|
||||
que_thr_t* thr) /* in: query thread associated with the MySQL
|
||||
OS thread */
|
||||
{
|
||||
srv_slot_t* slot;
|
||||
os_event_t event;
|
||||
double wait_time;
|
||||
trx_t* trx;
|
||||
|
||||
ut_ad(!mutex_own(&kernel_mutex));
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
os_event_set(srv_lock_timeout_thread_event);
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
@ -2061,10 +2064,21 @@ srv_suspend_mysql_thread(
|
||||
|
||||
srv_conc_force_exit_innodb(thr_get_trx(thr));
|
||||
|
||||
/* Release possible foreign key check latch */
|
||||
if (trx->has_dict_foreign_key_check_lock) {
|
||||
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
}
|
||||
|
||||
/* Wait for the release */
|
||||
|
||||
os_event_wait(event);
|
||||
|
||||
if (trx->has_dict_foreign_key_check_lock) {
|
||||
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
}
|
||||
|
||||
/* Return back inside InnoDB */
|
||||
|
||||
srv_conc_force_enter_innodb(thr_get_trx(thr));
|
||||
|
@ -220,7 +220,7 @@ mutex_create_func(
|
||||
char* cfile_name, /* in: file name where created */
|
||||
ulint cline) /* in: file line where created */
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||
mutex_reset_lock_word(mutex);
|
||||
#else
|
||||
os_fast_mutex_init(&(mutex->os_fast_mutex));
|
||||
@ -273,7 +273,7 @@ mutex_free(
|
||||
|
||||
mutex_exit(&mutex_list_mutex);
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||
os_fast_mutex_free(&(mutex->os_fast_mutex));
|
||||
#endif
|
||||
/* If we free the mutex protecting the mutex list (freeing is
|
||||
@ -1009,7 +1009,7 @@ sync_thread_add_level(
|
||||
} else if (level == SYNC_ANY_LATCH) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_ANY_LATCH));
|
||||
} else if (level == SYNC_TRX_SYS_HEADER) {
|
||||
ut_a(sync_thread_levels_contain(array, SYNC_KERNEL));
|
||||
ut_a(sync_thread_levels_g(array, SYNC_TRX_SYS_HEADER));
|
||||
} else if (level == SYNC_DOUBLEWRITE) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_DOUBLEWRITE));
|
||||
} else if (level == SYNC_BUF_BLOCK) {
|
||||
|
@ -438,7 +438,6 @@ trx_sys_update_mysql_binlog_offset(
|
||||
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);
|
||||
@ -524,7 +523,7 @@ trx_sys_print_mysql_binlog_offset(void)
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Last MySQL binlog file offset %lu %lu, file name %s\n",
|
||||
"InnoDB: Last MySQL binlog file position %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
|
||||
|
@ -71,6 +71,9 @@ trx_create(
|
||||
trx->type = TRX_USER;
|
||||
trx->conc_state = TRX_NOT_STARTED;
|
||||
|
||||
trx->check_foreigns = TRUE;
|
||||
trx->check_unique_secondary = TRUE;
|
||||
|
||||
trx->dict_operation = FALSE;
|
||||
|
||||
trx->mysql_thd = NULL;
|
||||
@ -113,6 +116,7 @@ trx_create(
|
||||
trx->lock_heap = mem_heap_create_in_buffer(256);
|
||||
UT_LIST_INIT(trx->trx_locks);
|
||||
|
||||
trx->has_dict_foreign_key_check_lock = FALSE;
|
||||
trx->has_search_latch = FALSE;
|
||||
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
||||
|
||||
@ -703,8 +707,7 @@ trx_commit_off_kernel(
|
||||
|
||||
/*-------------------------------------*/
|
||||
|
||||
/* Only in some performance tests the variable srv_flush..
|
||||
will be set to FALSE: */
|
||||
/* Most MySQL users run with srv_flush.. set to FALSE: */
|
||||
|
||||
if (srv_flush_log_at_trx_commit) {
|
||||
|
||||
|
Reference in New Issue
Block a user