Commit a16f3360 authored by heikki@work.mysql.com's avatar heikki@work.mysql.com

btr0btr.c Add more documentation about B-tree latching

ha_innodb.cc	Remove gaps in auto-inc in multi-row inserts, more space for foreign key listings in SHOW TABLE STATUS, move resetting of active_trx to amore logical place
dict0dict.h	Remove gaps from auto-inc sequence if errors in multi-row insert
dict0dict.c	Remove gaps from auto-inc sequence if errors in multi-row insert
parent 516cc0bd
...@@ -22,6 +22,25 @@ Created 6/2/1994 Heikki Tuuri ...@@ -22,6 +22,25 @@ Created 6/2/1994 Heikki Tuuri
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
/* /*
Latching strategy of the InnoDB B-tree
--------------------------------------
A tree latch protects all non-leaf nodes of the tree. Each node of a tree
also has a latch of its own.
A B-tree operation normally first acquires an S-latch on the tree. It
searches down the tree and releases the tree latch when it has the
leaf node latch. To save CPU time we do not acquire any latch on
non-leaf nodes of the tree during a search, those pages are only bufferfixed.
If an operation needs to restructure the tree, it acquires an X-latch on
the tree before searching to a leaf node. If it needs, for example, to
split a leaf,
(1) InnoDB decides the split point in the leaf,
(2) allocates a new page,
(3) inserts the appropriate node pointer to the first non-leaf level,
(4) releases the tree X-latch,
(5) and then moves records from the leaf to the new allocated page.
Node pointers Node pointers
------------- -------------
Leaf pages of a B-tree contain the index records stored in the Leaf pages of a B-tree contain the index records stored in the
......
...@@ -308,29 +308,18 @@ dict_table_autoinc_get( ...@@ -308,29 +308,18 @@ dict_table_autoinc_get(
} }
/************************************************************************ /************************************************************************
Reads the autoinc counter value, 0 if not yet initialized. Does not Decrements the autoinc counter value by 1. */
increment the counter. */
ib_longlong void
dict_table_autoinc_read( dict_table_autoinc_decrement(
/*====================*/ /*=========================*/
/* out: value of the counter */
dict_table_t* table) /* in: table */ dict_table_t* table) /* in: table */
{ {
ib_longlong value;
mutex_enter(&(table->autoinc_mutex)); mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) { table->autoinc = table->autoinc - 1;
value = 0;
} else {
value = table->autoinc;
}
mutex_exit(&(table->autoinc_mutex)); mutex_exit(&(table->autoinc_mutex));
return(value);
} }
/************************************************************************ /************************************************************************
......
...@@ -114,13 +114,11 @@ dict_table_autoinc_get( ...@@ -114,13 +114,11 @@ dict_table_autoinc_get(
/* out: value for a new row, or 0 */ /* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */ dict_table_t* table); /* in: table */
/************************************************************************ /************************************************************************
Reads the autoinc counter value, 0 if not yet initialized. Does not Decrements the autoinc counter value by 1. */
increment the counter. */
ib_longlong void
dict_table_autoinc_read( dict_table_autoinc_decrement(
/*====================*/ /*=========================*/
/* out: value of the counter */
dict_table_t* table); /* in: table */ dict_table_t* table); /* in: table */
/************************************************************************ /************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not Peeks the autoinc counter value, 0 if not yet initialized. Does not
......
...@@ -405,8 +405,6 @@ ha_innobase::update_thd( ...@@ -405,8 +405,6 @@ ha_innobase::update_thd(
return(0); return(0);
} }
/* The code here appears for documentational purposes only. Not used
or tested yet. Will be used in 4.1. */
/********************************************************************* /*********************************************************************
Call this when you have opened a new table handle in HANDLER, before you Call this when you have opened a new table handle in HANDLER, before you
call index_read_idx() etc. Actually, we can let the cursor stay open even call index_read_idx() etc. Actually, we can let the cursor stay open even
...@@ -667,20 +665,20 @@ innobase_commit_low( ...@@ -667,20 +665,20 @@ innobase_commit_low(
/*================*/ /*================*/
trx_t* trx) /* in: transaction handle */ trx_t* trx) /* in: transaction handle */
{ {
if (current_thd->slave_thread) if (current_thd->slave_thread) {
{ /* Update the replication position info inside InnoDB */
/* Update the replication position info inside InnoDB */
#ifdef NEED_TO_BE_FIXED #ifdef NEED_TO_BE_FIXED
trx->mysql_relay_log_file_name= active_mi->rli.log_file_name; trx->mysql_relay_log_file_name = active_mi->rli.log_file_name;
trx->mysql_relay_log_pos= active_mi->rli.relay_log_pos; trx->mysql_relay_log_pos = active_mi->rli.relay_log_pos;
#endif #endif
trx->mysql_master_log_file_name= active_mi->rli.master_log_name; trx->mysql_master_log_file_name
trx->mysql_master_log_pos= ((ib_longlong) = active_mi->rli.master_log_name;
trx->mysql_master_log_pos = ((ib_longlong)
(active_mi->rli.master_log_pos + (active_mi->rli.master_log_pos +
active_mi->rli.event_len + active_mi->rli.event_len +
active_mi->rli.pending)); active_mi->rli.pending));
} }
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
} }
/********************************************************************* /*********************************************************************
...@@ -692,7 +690,8 @@ innobase_commit( ...@@ -692,7 +690,8 @@ innobase_commit(
/* out: 0 or error number */ /* out: 0 or error number */
THD* thd, /* in: MySQL thread handle of the user for whom THD* thd, /* in: MySQL thread handle of the user for whom
the transaction should be committed */ the transaction should be committed */
void* trx_handle)/* in: InnoDB trx handle or NULL: NULL means void* trx_handle)/* in: InnoDB trx handle or
&innodb_dummy_stmt_trx_handle: the latter means
that the current SQL statement ended, and we should that the current SQL statement ended, and we should
mark the start of a new statement with a savepoint */ mark the start of a new statement with a savepoint */
{ {
...@@ -716,6 +715,7 @@ innobase_commit( ...@@ -716,6 +715,7 @@ innobase_commit(
if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) {
innobase_commit_low(trx); innobase_commit_low(trx);
thd->transaction.all.innodb_active_trans=0;
} }
/* Release possible statement level resources */ /* Release possible statement level resources */
...@@ -772,7 +772,9 @@ innobase_rollback( ...@@ -772,7 +772,9 @@ innobase_rollback(
/* out: 0 or error number */ /* out: 0 or error number */
THD* thd, /* in: handle to the MySQL thread of the user THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */ whose transaction should be rolled back */
void* trx_handle)/* in: InnoDB trx handle or a dummy stmt handle */ void* trx_handle)/* in: InnoDB trx handle or a dummy stmt handle;
the latter means we roll back the latest SQL
statement */
{ {
int error = 0; int error = 0;
trx_t* trx; trx_t* trx;
...@@ -796,6 +798,7 @@ innobase_rollback( ...@@ -796,6 +798,7 @@ innobase_rollback(
if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) {
error = trx_rollback_for_mysql(trx); error = trx_rollback_for_mysql(trx);
thd->transaction.all.innodb_active_trans=0;
} else { } else {
error = trx_rollback_last_sql_stat_for_mysql(trx); error = trx_rollback_last_sql_stat_for_mysql(trx);
} }
...@@ -1190,11 +1193,11 @@ innobase_mysql_cmp( ...@@ -1190,11 +1193,11 @@ innobase_mysql_cmp(
ret = my_sortncmp((const char*) a, a_length, ret = my_sortncmp((const char*) a, a_length,
(const char*) b, b_length); (const char*) b, b_length);
if (ret < 0) { if (ret < 0) {
return(-1); return(-1);
} else if (ret > 0) { } else if (ret > 0) {
return(1); return(1);
} else { } else {
return(0); return(0);
} }
default: default:
assert(0); assert(0);
...@@ -1497,6 +1500,8 @@ ha_innobase::write_row( ...@@ -1497,6 +1500,8 @@ ha_innobase::write_row(
int error; int error;
longlong auto_inc; longlong auto_inc;
longlong dummy; longlong dummy;
ibool incremented_auto_inc_for_stat = FALSE;
ibool incremented_auto_inc_counter = FALSE;
DBUG_ENTER("ha_innobase::write_row"); DBUG_ENTER("ha_innobase::write_row");
...@@ -1567,6 +1572,7 @@ ha_innobase::write_row( ...@@ -1567,6 +1572,7 @@ ha_innobase::write_row(
assign sequential values from the counter. */ assign sequential values from the counter. */
auto_inc_counter_for_this_stat++; auto_inc_counter_for_this_stat++;
incremented_auto_inc_for_stat = TRUE;
auto_inc = auto_inc_counter_for_this_stat; auto_inc = auto_inc_counter_for_this_stat;
...@@ -1615,7 +1621,12 @@ ha_innobase::write_row( ...@@ -1615,7 +1621,12 @@ ha_innobase::write_row(
} }
} }
/* The following call gets the value of the auto-inc
counter of the table and increments it by 1 */
auto_inc = dict_table_autoinc_get(prebuilt->table); auto_inc = dict_table_autoinc_get(prebuilt->table);
incremented_auto_inc_counter = TRUE;
srv_conc_exit_innodb(prebuilt->trx); srv_conc_exit_innodb(prebuilt->trx);
/* We can give the new value for MySQL to place in /* We can give the new value for MySQL to place in
...@@ -1652,6 +1663,20 @@ ha_innobase::write_row( ...@@ -1652,6 +1663,20 @@ ha_innobase::write_row(
srv_conc_exit_innodb(prebuilt->trx); srv_conc_exit_innodb(prebuilt->trx);
if (error != DB_SUCCESS) {
/* If the insert did not succeed we restore the value of
the auto-inc counter we used; note that this behavior was
introduced only in version 4.0.4 */
if (incremented_auto_inc_counter) {
dict_autoinc_decrement(prebuilt->table);
}
if (incremented_auto_inc_for_stat) {
auto_inc_counter_for_this_stat--;
}
}
prebuilt->trx->ignore_duplicates_in_insert = FALSE; prebuilt->trx->ignore_duplicates_in_insert = FALSE;
error = convert_error_code_to_mysql(error, user_thd); error = convert_error_code_to_mysql(error, user_thd);
...@@ -3311,7 +3336,7 @@ ha_innobase::update_table_comment( ...@@ -3311,7 +3336,7 @@ ha_innobase::update_table_comment(
{ {
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
uint length = strlen(comment); uint length = strlen(comment);
char* str = my_malloc(length + 550, MYF(0)); char* str = my_malloc(length + 16500, MYF(0));
char* pos; char* pos;
/* Warning: since it is not sure that MySQL calls external_lock /* Warning: since it is not sure that MySQL calls external_lock
...@@ -3333,10 +3358,12 @@ ha_innobase::update_table_comment( ...@@ -3333,10 +3358,12 @@ ha_innobase::update_table_comment(
(pos,"InnoDB free: %lu kB", (pos,"InnoDB free: %lu kB",
(ulong) innobase_get_free_space())); (ulong) innobase_get_free_space()));
/* We assume 450 - length bytes of space to print info */ /* We assume 16000 - length bytes of space to print info; the limit
16000 bytes is arbitrary, and MySQL could handle at least 64000
bytes */
if (length < 450) { if (length < 16000) {
dict_print_info_on_foreign_keys(FALSE, pos, 450 - length, dict_print_info_on_foreign_keys(FALSE, pos, 16000 - length,
prebuilt->table); prebuilt->table);
} }
...@@ -3508,7 +3535,6 @@ ha_innobase::external_lock( ...@@ -3508,7 +3535,6 @@ ha_innobase::external_lock(
& (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
innobase_commit(thd, trx); innobase_commit(thd, trx);
thd->transaction.all.innodb_active_trans=0;
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment