|
|
@ -32,7 +32,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* TODO list for the InnoDB handler in 5.0:
|
|
|
|
/* TODO list for the InnoDB handler in 5.0:
|
|
|
|
- Remove the flag trx->active_trans and look at trx->conc_state
|
|
|
|
- Remove the flag trx->active_flag & TRX_ACTIVE_IN_MYSQL and look
|
|
|
|
|
|
|
|
at trx->conc_state
|
|
|
|
- fix savepoint functions to use savepoint storage area
|
|
|
|
- fix savepoint functions to use savepoint storage area
|
|
|
|
- Find out what kind of problems the OS X case-insensitivity causes to
|
|
|
|
- Find out what kind of problems the OS X case-insensitivity causes to
|
|
|
|
table and database names; should we 'normalize' the names like we do
|
|
|
|
table and database names; should we 'normalize' the names like we do
|
|
|
@ -102,8 +103,6 @@ bool check_global_access(THD *thd, ulong want_access);
|
|
|
|
|
|
|
|
|
|
|
|
/** to protect innobase_open_files */
|
|
|
|
/** to protect innobase_open_files */
|
|
|
|
static pthread_mutex_t innobase_share_mutex;
|
|
|
|
static pthread_mutex_t innobase_share_mutex;
|
|
|
|
/** to force correct commit order in binlog */
|
|
|
|
|
|
|
|
static pthread_mutex_t prepare_commit_mutex;
|
|
|
|
|
|
|
|
static ulong commit_threads = 0;
|
|
|
|
static ulong commit_threads = 0;
|
|
|
|
static pthread_mutex_t commit_threads_m;
|
|
|
|
static pthread_mutex_t commit_threads_m;
|
|
|
|
static pthread_cond_t commit_cond;
|
|
|
|
static pthread_cond_t commit_cond;
|
|
|
@ -197,6 +196,7 @@ static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
|
|
|
|
static INNOBASE_SHARE *get_share(const char *table_name);
|
|
|
|
static INNOBASE_SHARE *get_share(const char *table_name);
|
|
|
|
static void free_share(INNOBASE_SHARE *share);
|
|
|
|
static void free_share(INNOBASE_SHARE *share);
|
|
|
|
static int innobase_close_connection(handlerton *hton, THD* thd);
|
|
|
|
static int innobase_close_connection(handlerton *hton, THD* thd);
|
|
|
|
|
|
|
|
static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all);
|
|
|
|
static int innobase_commit(handlerton *hton, THD* thd, bool all);
|
|
|
|
static int innobase_commit(handlerton *hton, THD* thd, bool all);
|
|
|
|
static int innobase_rollback(handlerton *hton, THD* thd, bool all);
|
|
|
|
static int innobase_rollback(handlerton *hton, THD* thd, bool all);
|
|
|
|
static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd,
|
|
|
|
static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd,
|
|
|
@ -1320,7 +1320,6 @@ innobase_trx_init(
|
|
|
|
trx_t* trx) /*!< in/out: InnoDB transaction handle */
|
|
|
|
trx_t* trx) /*!< in/out: InnoDB transaction handle */
|
|
|
|
{
|
|
|
|
{
|
|
|
|
DBUG_ENTER("innobase_trx_init");
|
|
|
|
DBUG_ENTER("innobase_trx_init");
|
|
|
|
DBUG_ASSERT(EQ_CURRENT_THD(thd));
|
|
|
|
|
|
|
|
DBUG_ASSERT(thd == trx->mysql_thd);
|
|
|
|
DBUG_ASSERT(thd == trx->mysql_thd);
|
|
|
|
|
|
|
|
|
|
|
|
trx->check_foreigns = !thd_test_options(
|
|
|
|
trx->check_foreigns = !thd_test_options(
|
|
|
@ -1369,8 +1368,6 @@ check_trx_exists(
|
|
|
|
{
|
|
|
|
{
|
|
|
|
trx_t*& trx = thd_to_trx(thd);
|
|
|
|
trx_t*& trx = thd_to_trx(thd);
|
|
|
|
|
|
|
|
|
|
|
|
ut_ad(EQ_CURRENT_THD(thd));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (trx == NULL) {
|
|
|
|
if (trx == NULL) {
|
|
|
|
trx = innobase_trx_allocate(thd);
|
|
|
|
trx = innobase_trx_allocate(thd);
|
|
|
|
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
|
|
|
|
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
|
|
|
@ -1636,10 +1633,10 @@ innobase_query_caching_of_table_permitted(
|
|
|
|
/* The call of row_search_.. will start a new transaction if it is
|
|
|
|
/* The call of row_search_.. will start a new transaction if it is
|
|
|
|
not yet started */
|
|
|
|
not yet started */
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->active_trans == 0) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
innobase_register_trx_and_stmt(innodb_hton_ptr, thd);
|
|
|
|
innobase_register_trx_and_stmt(innodb_hton_ptr, thd);
|
|
|
|
trx->active_trans = 1;
|
|
|
|
trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (row_search_check_if_query_cache_permitted(trx, norm_name)) {
|
|
|
|
if (row_search_check_if_query_cache_permitted(trx, norm_name)) {
|
|
|
@ -1909,11 +1906,11 @@ ha_innobase::init_table_handle_for_HANDLER(void)
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
|
|
|
|
|
|
|
|
if (prebuilt->trx->active_trans == 0) {
|
|
|
|
if ((prebuilt->trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
innobase_register_trx_and_stmt(ht, user_thd);
|
|
|
|
innobase_register_trx_and_stmt(ht, user_thd);
|
|
|
|
|
|
|
|
|
|
|
|
prebuilt->trx->active_trans = 1;
|
|
|
|
prebuilt->trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We did the necessary inits in this function, no need to repeat them
|
|
|
|
/* We did the necessary inits in this function, no need to repeat them
|
|
|
@ -1964,6 +1961,8 @@ innobase_init(
|
|
|
|
innobase_hton->savepoint_set=innobase_savepoint;
|
|
|
|
innobase_hton->savepoint_set=innobase_savepoint;
|
|
|
|
innobase_hton->savepoint_rollback=innobase_rollback_to_savepoint;
|
|
|
|
innobase_hton->savepoint_rollback=innobase_rollback_to_savepoint;
|
|
|
|
innobase_hton->savepoint_release=innobase_release_savepoint;
|
|
|
|
innobase_hton->savepoint_release=innobase_release_savepoint;
|
|
|
|
|
|
|
|
innobase_hton->prepare_ordered=NULL;
|
|
|
|
|
|
|
|
innobase_hton->commit_ordered=innobase_commit_ordered;
|
|
|
|
innobase_hton->commit=innobase_commit;
|
|
|
|
innobase_hton->commit=innobase_commit;
|
|
|
|
innobase_hton->rollback=innobase_rollback;
|
|
|
|
innobase_hton->rollback=innobase_rollback;
|
|
|
|
innobase_hton->prepare=innobase_xa_prepare;
|
|
|
|
innobase_hton->prepare=innobase_xa_prepare;
|
|
|
@ -2268,7 +2267,6 @@ innobase_change_buffering_inited_ok:
|
|
|
|
|
|
|
|
|
|
|
|
innobase_open_tables = hash_create(200);
|
|
|
|
innobase_open_tables = hash_create(200);
|
|
|
|
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
|
|
|
|
|
|
|
|
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_cond_init(&commit_cond, NULL);
|
|
|
|
pthread_cond_init(&commit_cond, NULL);
|
|
|
@ -2323,7 +2321,6 @@ innobase_end(
|
|
|
|
my_free(internal_innobase_data_file_path,
|
|
|
|
my_free(internal_innobase_data_file_path,
|
|
|
|
MYF(MY_ALLOW_ZERO_PTR));
|
|
|
|
MYF(MY_ALLOW_ZERO_PTR));
|
|
|
|
pthread_mutex_destroy(&innobase_share_mutex);
|
|
|
|
pthread_mutex_destroy(&innobase_share_mutex);
|
|
|
|
pthread_mutex_destroy(&prepare_commit_mutex);
|
|
|
|
|
|
|
|
pthread_mutex_destroy(&commit_threads_m);
|
|
|
|
pthread_mutex_destroy(&commit_threads_m);
|
|
|
|
pthread_mutex_destroy(&commit_cond_m);
|
|
|
|
pthread_mutex_destroy(&commit_cond_m);
|
|
|
|
pthread_cond_destroy(&commit_cond);
|
|
|
|
pthread_cond_destroy(&commit_cond);
|
|
|
@ -2422,14 +2419,118 @@ innobase_start_trx_and_assign_read_view(
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->active_trans == 0) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0) {
|
|
|
|
innobase_register_trx_and_stmt(hton, thd);
|
|
|
|
innobase_register_trx_and_stmt(hton, thd);
|
|
|
|
trx->active_trans = 1;
|
|
|
|
trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
|
|
innobase_commit_ordered_2(
|
|
|
|
|
|
|
|
/*============*/
|
|
|
|
|
|
|
|
trx_t* trx, /*!< in: Innodb transaction */
|
|
|
|
|
|
|
|
THD* thd) /*!< in: MySQL thread handle */
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ulonglong tmp_pos;
|
|
|
|
|
|
|
|
DBUG_ENTER("innobase_commit_ordered");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We need current binlog position for ibbackup to work.
|
|
|
|
|
|
|
|
Note, the position is current because commit_ordered is guaranteed
|
|
|
|
|
|
|
|
to be called in same sequenece as writing to binlog. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
if (innobase_commit_concurrency > 0) {
|
|
|
|
|
|
|
|
pthread_mutex_lock(&commit_cond_m);
|
|
|
|
|
|
|
|
commit_threads++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (commit_threads > innobase_commit_concurrency) {
|
|
|
|
|
|
|
|
commit_threads--;
|
|
|
|
|
|
|
|
pthread_cond_wait(&commit_cond,
|
|
|
|
|
|
|
|
&commit_cond_m);
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&commit_cond_m);
|
|
|
|
|
|
|
|
goto retry;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&commit_cond_m);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mysql_bin_log_commit_pos(thd, &tmp_pos, &(trx->mysql_log_file_name));
|
|
|
|
|
|
|
|
trx->mysql_log_offset = (ib_int64_t) tmp_pos;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Don't do write + flush right now. For group commit
|
|
|
|
|
|
|
|
to work we want to do the flush in the innobase_commit()
|
|
|
|
|
|
|
|
method, which runs without holding any locks. */
|
|
|
|
|
|
|
|
trx->flush_log_later = TRUE;
|
|
|
|
|
|
|
|
innobase_commit_low(trx);
|
|
|
|
|
|
|
|
trx->flush_log_later = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (innobase_commit_concurrency > 0) {
|
|
|
|
|
|
|
|
pthread_mutex_lock(&commit_cond_m);
|
|
|
|
|
|
|
|
commit_threads--;
|
|
|
|
|
|
|
|
pthread_cond_signal(&commit_cond);
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&commit_cond_m);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************//**
|
|
|
|
|
|
|
|
Perform the first, fast part of InnoDB commit.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Doing it in this call ensures that we get the same commit order here
|
|
|
|
|
|
|
|
as in binlog and any other participating transactional storage engines.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note that we want to do as little as really needed here, as we run
|
|
|
|
|
|
|
|
under a global mutex. The expensive fsync() is done later, in
|
|
|
|
|
|
|
|
innobase_commit(), without a lock so group commit can take place.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note also that this method can be called from a different thread than
|
|
|
|
|
|
|
|
the one handling the rest of the transaction. */
|
|
|
|
|
|
|
|
static
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
|
|
innobase_commit_ordered(
|
|
|
|
|
|
|
|
/*============*/
|
|
|
|
|
|
|
|
handlerton *hton, /*!< in: Innodb handlerton */
|
|
|
|
|
|
|
|
THD* thd, /*!< in: MySQL thread handle of the user for whom
|
|
|
|
|
|
|
|
the transaction should be committed */
|
|
|
|
|
|
|
|
bool all) /*!< in: TRUE - commit transaction
|
|
|
|
|
|
|
|
FALSE - the current SQL statement ended */
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
trx_t* trx;
|
|
|
|
|
|
|
|
DBUG_ENTER("innobase_commit_ordered");
|
|
|
|
|
|
|
|
DBUG_ASSERT(hton == innodb_hton_ptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
trx = check_trx_exists(thd);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Since we will reserve the kernel mutex, we must not be holding the
|
|
|
|
|
|
|
|
search system latch, or we will disobey the latching order. But we
|
|
|
|
|
|
|
|
already released it in innobase_xa_prepare() (if not before), so just
|
|
|
|
|
|
|
|
have an assert here.*/
|
|
|
|
|
|
|
|
ut_ad(!trx->has_search_latch);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0
|
|
|
|
|
|
|
|
&& trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
|
|
|
|
/* We cannot throw error here; instead we will catch this error
|
|
|
|
|
|
|
|
again in innobase_commit() and report it from there. */
|
|
|
|
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* commit_ordered is only called when committing the whole transaction
|
|
|
|
|
|
|
|
(or an SQL statement when autocommit is on). */
|
|
|
|
|
|
|
|
DBUG_ASSERT(all ||
|
|
|
|
|
|
|
|
(!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
innobase_commit_ordered_2(trx, thd);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
trx->active_flag |= TRX_ACTIVE_COMMIT_ORDERED;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************//**
|
|
|
|
/*****************************************************************//**
|
|
|
|
Commits a transaction in an InnoDB database or marks an SQL statement
|
|
|
|
Commits a transaction in an InnoDB database or marks an SQL statement
|
|
|
|
ended.
|
|
|
|
ended.
|
|
|
@ -2455,11 +2556,12 @@ innobase_commit(
|
|
|
|
/* Since we will reserve the kernel mutex, we have to release
|
|
|
|
/* Since we will reserve the kernel mutex, we have to release
|
|
|
|
the search system latch first to obey the latching order. */
|
|
|
|
the search system latch first to obey the latching order. */
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->has_search_latch) {
|
|
|
|
if (trx->has_search_latch &&
|
|
|
|
|
|
|
|
(trx->active_flag & TRX_ACTIVE_COMMIT_ORDERED) == 0) {
|
|
|
|
trx_search_latch_release_if_reserved(trx);
|
|
|
|
trx_search_latch_release_if_reserved(trx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The flag trx->active_trans is set to 1 in
|
|
|
|
/* The flag TRX_ACTIVE_IN_MYSQL in trx->active_flag is set in
|
|
|
|
|
|
|
|
|
|
|
|
1. ::external_lock(),
|
|
|
|
1. ::external_lock(),
|
|
|
|
2. ::start_stmt(),
|
|
|
|
2. ::start_stmt(),
|
|
|
@ -2469,81 +2571,33 @@ innobase_commit(
|
|
|
|
6. innobase_start_trx_and_assign_read_view(),
|
|
|
|
6. innobase_start_trx_and_assign_read_view(),
|
|
|
|
7. ::transactional_table_lock()
|
|
|
|
7. ::transactional_table_lock()
|
|
|
|
|
|
|
|
|
|
|
|
and it is only set to 0 in a commit or a rollback. If it is 0 we know
|
|
|
|
and it is only cleared in a commit or a rollback. If it is unset we know
|
|
|
|
there cannot be resources to be freed and we could return immediately.
|
|
|
|
there cannot be resources to be freed and we could return immediately.
|
|
|
|
For the time being, we play safe and do the cleanup though there should
|
|
|
|
For the time being, we play safe and do the cleanup though there should
|
|
|
|
be nothing to clean up. */
|
|
|
|
be nothing to clean up. */
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->active_trans == 0
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0
|
|
|
|
&& trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
&& trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
|
|
|
|
|
|
|
|
sql_print_error("trx->active_trans == 0, but"
|
|
|
|
sql_print_error("trx->active_flag & TRX_ACTIVE_IN_MYSQL== 0,"
|
|
|
|
" trx->conc_state != TRX_NOT_STARTED");
|
|
|
|
" but trx->conc_state != TRX_NOT_STARTED");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (all
|
|
|
|
if (all
|
|
|
|
|| (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
|
|
|
|
|| (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Run the fast part of commit if we did not already. */
|
|
|
|
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_COMMIT_ORDERED) == 0) {
|
|
|
|
|
|
|
|
innobase_commit_ordered_2(trx, thd);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We were instructed to commit the whole transaction, or
|
|
|
|
/* We were instructed to commit the whole transaction, or
|
|
|
|
this is an SQL statement end and autocommit is on */
|
|
|
|
this is an SQL statement end and autocommit is on */
|
|
|
|
|
|
|
|
|
|
|
|
/* We need current binlog position for ibbackup to work.
|
|
|
|
/* We did the first part already in innobase_commit_ordered(),
|
|
|
|
Note, the position is current because of
|
|
|
|
Now finish by doing a write + flush of logs. */
|
|
|
|
prepare_commit_mutex */
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
if (innobase_commit_concurrency > 0) {
|
|
|
|
|
|
|
|
pthread_mutex_lock(&commit_cond_m);
|
|
|
|
|
|
|
|
commit_threads++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (commit_threads > innobase_commit_concurrency) {
|
|
|
|
|
|
|
|
commit_threads--;
|
|
|
|
|
|
|
|
pthread_cond_wait(&commit_cond,
|
|
|
|
|
|
|
|
&commit_cond_m);
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&commit_cond_m);
|
|
|
|
|
|
|
|
goto retry;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&commit_cond_m);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The following calls to read the MySQL binary log
|
|
|
|
|
|
|
|
file name and the position return consistent results:
|
|
|
|
|
|
|
|
1) Other InnoDB transactions cannot intervene between
|
|
|
|
|
|
|
|
these calls as we are holding prepare_commit_mutex.
|
|
|
|
|
|
|
|
2) Binary logging of other engines is not relevant
|
|
|
|
|
|
|
|
to InnoDB as all InnoDB requires is that committing
|
|
|
|
|
|
|
|
InnoDB transactions appear in the same order in the
|
|
|
|
|
|
|
|
MySQL binary log as they appear in InnoDB logs.
|
|
|
|
|
|
|
|
3) A MySQL log file rotation cannot happen because
|
|
|
|
|
|
|
|
MySQL protects against this by having a counter of
|
|
|
|
|
|
|
|
transactions in prepared state and it only allows
|
|
|
|
|
|
|
|
a rotation when the counter drops to zero. See
|
|
|
|
|
|
|
|
LOCK_prep_xids and COND_prep_xids in log.cc. */
|
|
|
|
|
|
|
|
trx->mysql_log_file_name = mysql_bin_log_file_name();
|
|
|
|
|
|
|
|
trx->mysql_log_offset = (ib_int64_t) mysql_bin_log_file_pos();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Don't do write + flush right now. For group commit
|
|
|
|
|
|
|
|
to work we want to do the flush after releasing the
|
|
|
|
|
|
|
|
prepare_commit_mutex. */
|
|
|
|
|
|
|
|
trx->flush_log_later = TRUE;
|
|
|
|
|
|
|
|
innobase_commit_low(trx);
|
|
|
|
|
|
|
|
trx->flush_log_later = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (innobase_commit_concurrency > 0) {
|
|
|
|
|
|
|
|
pthread_mutex_lock(&commit_cond_m);
|
|
|
|
|
|
|
|
commit_threads--;
|
|
|
|
|
|
|
|
pthread_cond_signal(&commit_cond);
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&commit_cond_m);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->active_trans == 2) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&prepare_commit_mutex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now do a write + flush of logs. */
|
|
|
|
|
|
|
|
trx_commit_complete_for_mysql(trx);
|
|
|
|
trx_commit_complete_for_mysql(trx);
|
|
|
|
trx->active_trans = 0;
|
|
|
|
trx->active_flag = 0;
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
/* We just mark the SQL statement ended and do not do a
|
|
|
|
/* We just mark the SQL statement ended and do not do a
|
|
|
@ -2616,7 +2670,7 @@ innobase_rollback(
|
|
|
|
|| !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
|
|
|
|
|| !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
|
|
|
|
|
|
|
|
|
|
|
|
error = trx_rollback_for_mysql(trx);
|
|
|
|
error = trx_rollback_for_mysql(trx);
|
|
|
|
trx->active_trans = 0;
|
|
|
|
trx->active_flag = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
error = trx_rollback_last_sql_stat_for_mysql(trx);
|
|
|
|
error = trx_rollback_last_sql_stat_for_mysql(trx);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -2760,7 +2814,7 @@ innobase_savepoint(
|
|
|
|
innobase_release_stat_resources(trx);
|
|
|
|
innobase_release_stat_resources(trx);
|
|
|
|
|
|
|
|
|
|
|
|
/* cannot happen outside of transaction */
|
|
|
|
/* cannot happen outside of transaction */
|
|
|
|
DBUG_ASSERT(trx->active_trans);
|
|
|
|
DBUG_ASSERT(trx->active_flag & TRX_ACTIVE_IN_MYSQL);
|
|
|
|
|
|
|
|
|
|
|
|
/* TODO: use provided savepoint data area to store savepoint data */
|
|
|
|
/* TODO: use provided savepoint data area to store savepoint data */
|
|
|
|
char name[64];
|
|
|
|
char name[64];
|
|
|
@ -2790,11 +2844,11 @@ innobase_close_connection(
|
|
|
|
|
|
|
|
|
|
|
|
ut_a(trx);
|
|
|
|
ut_a(trx);
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->active_trans == 0
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0
|
|
|
|
&& trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
&& trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
|
|
|
|
|
|
|
|
sql_print_error("trx->active_trans == 0, but"
|
|
|
|
sql_print_error("trx->active_flag & TRX_ACTIVE_IN_MYSQL == 0,"
|
|
|
|
" trx->conc_state != TRX_NOT_STARTED");
|
|
|
|
" but trx->conc_state != TRX_NOT_STARTED");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -4691,7 +4745,7 @@ no_commit:
|
|
|
|
/* Altering to InnoDB format */
|
|
|
|
/* Altering to InnoDB format */
|
|
|
|
innobase_commit(ht, user_thd, 1);
|
|
|
|
innobase_commit(ht, user_thd, 1);
|
|
|
|
/* Note that this transaction is still active. */
|
|
|
|
/* Note that this transaction is still active. */
|
|
|
|
prebuilt->trx->active_trans = 1;
|
|
|
|
prebuilt->trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
/* We will need an IX lock on the destination table. */
|
|
|
|
/* We will need an IX lock on the destination table. */
|
|
|
|
prebuilt->sql_stat_start = TRUE;
|
|
|
|
prebuilt->sql_stat_start = TRUE;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -4707,7 +4761,7 @@ no_commit:
|
|
|
|
locks, so they have to be acquired again. */
|
|
|
|
locks, so they have to be acquired again. */
|
|
|
|
innobase_commit(ht, user_thd, 1);
|
|
|
|
innobase_commit(ht, user_thd, 1);
|
|
|
|
/* Note that this transaction is still active. */
|
|
|
|
/* Note that this transaction is still active. */
|
|
|
|
prebuilt->trx->active_trans = 1;
|
|
|
|
prebuilt->trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
/* Re-acquire the table lock on the source table. */
|
|
|
|
/* Re-acquire the table lock on the source table. */
|
|
|
|
row_lock_table_for_mysql(prebuilt, src_table, mode);
|
|
|
|
row_lock_table_for_mysql(prebuilt, src_table, mode);
|
|
|
|
/* We will need an IX lock on the destination table. */
|
|
|
|
/* We will need an IX lock on the destination table. */
|
|
|
@ -8498,10 +8552,10 @@ ha_innobase::start_stmt(
|
|
|
|
trx->detailed_error[0] = '\0';
|
|
|
|
trx->detailed_error[0] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
if (trx->active_trans == 0) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
innobase_register_trx_and_stmt(ht, thd);
|
|
|
|
innobase_register_trx_and_stmt(ht, thd);
|
|
|
|
trx->active_trans = 1;
|
|
|
|
trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
innobase_register_stmt(ht, thd);
|
|
|
|
innobase_register_stmt(ht, thd);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -8599,10 +8653,10 @@ ha_innobase::external_lock(
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the MySQL flag to mark that there is an active
|
|
|
|
/* Set the MySQL flag to mark that there is an active
|
|
|
|
transaction */
|
|
|
|
transaction */
|
|
|
|
if (trx->active_trans == 0) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
innobase_register_trx_and_stmt(ht, thd);
|
|
|
|
innobase_register_trx_and_stmt(ht, thd);
|
|
|
|
trx->active_trans = 1;
|
|
|
|
trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
} else if (trx->n_mysql_tables_in_use == 0) {
|
|
|
|
} else if (trx->n_mysql_tables_in_use == 0) {
|
|
|
|
innobase_register_stmt(ht, thd);
|
|
|
|
innobase_register_stmt(ht, thd);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -8681,7 +8735,7 @@ ha_innobase::external_lock(
|
|
|
|
prebuilt->used_in_HANDLER = FALSE;
|
|
|
|
prebuilt->used_in_HANDLER = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
|
|
|
|
if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
|
|
|
|
if (trx->active_trans != 0) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) != 0) {
|
|
|
|
innobase_commit(ht, thd, TRUE);
|
|
|
|
innobase_commit(ht, thd, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -8762,10 +8816,10 @@ ha_innobase::transactional_table_lock(
|
|
|
|
/* MySQL is setting a new transactional table lock */
|
|
|
|
/* MySQL is setting a new transactional table lock */
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
/* Set the MySQL flag to mark that there is an active transaction */
|
|
|
|
if (trx->active_trans == 0) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
innobase_register_trx_and_stmt(ht, thd);
|
|
|
|
innobase_register_trx_and_stmt(ht, thd);
|
|
|
|
trx->active_trans = 1;
|
|
|
|
trx->active_flag |= TRX_ACTIVE_IN_MYSQL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (THDVAR(thd, table_locks) && thd_in_lock_tables(thd)) {
|
|
|
|
if (THDVAR(thd, table_locks) && thd_in_lock_tables(thd)) {
|
|
|
@ -9821,10 +9875,11 @@ innobase_xa_prepare(
|
|
|
|
|
|
|
|
|
|
|
|
innobase_release_stat_resources(trx);
|
|
|
|
innobase_release_stat_resources(trx);
|
|
|
|
|
|
|
|
|
|
|
|
if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
if ((trx->active_flag & TRX_ACTIVE_IN_MYSQL) == 0 &&
|
|
|
|
|
|
|
|
trx->conc_state != TRX_NOT_STARTED) {
|
|
|
|
|
|
|
|
|
|
|
|
sql_print_error("trx->active_trans == 0, but trx->conc_state != "
|
|
|
|
sql_print_error("trx->active_flag & TRX_ACTIVE_IN_MYSQL == 0, but"
|
|
|
|
"TRX_NOT_STARTED");
|
|
|
|
" trx->conc_state != TRX_NOT_STARTED");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (all
|
|
|
|
if (all
|
|
|
@ -9833,7 +9888,7 @@ innobase_xa_prepare(
|
|
|
|
/* We were instructed to prepare the whole transaction, or
|
|
|
|
/* We were instructed to prepare the whole transaction, or
|
|
|
|
this is an SQL statement end and autocommit is on */
|
|
|
|
this is an SQL statement end and autocommit is on */
|
|
|
|
|
|
|
|
|
|
|
|
ut_ad(trx->active_trans);
|
|
|
|
ut_ad(trx->active_flag & TRX_ACTIVE_IN_MYSQL);
|
|
|
|
|
|
|
|
|
|
|
|
error = (int) trx_prepare_for_mysql(trx);
|
|
|
|
error = (int) trx_prepare_for_mysql(trx);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -9857,32 +9912,6 @@ innobase_xa_prepare(
|
|
|
|
|
|
|
|
|
|
|
|
srv_active_wake_master_thread();
|
|
|
|
srv_active_wake_master_thread();
|
|
|
|
|
|
|
|
|
|
|
|
if (thd_sql_command(thd) != SQLCOM_XA_PREPARE &&
|
|
|
|
|
|
|
|
(all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* For ibbackup to work the order of transactions in binlog
|
|
|
|
|
|
|
|
and InnoDB must be the same. Consider the situation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
thread1> prepare; write to binlog; ...
|
|
|
|
|
|
|
|
<context switch>
|
|
|
|
|
|
|
|
thread2> prepare; write to binlog; commit
|
|
|
|
|
|
|
|
thread1> ... commit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To ensure this will not happen we're taking the mutex on
|
|
|
|
|
|
|
|
prepare, and releasing it on commit.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: only do it for normal commits, done via ha_commit_trans.
|
|
|
|
|
|
|
|
If 2pc protocol is executed by external transaction
|
|
|
|
|
|
|
|
coordinator, it will be just a regular MySQL client
|
|
|
|
|
|
|
|
executing XA PREPARE and XA COMMIT commands.
|
|
|
|
|
|
|
|
In this case we cannot know how many minutes or hours
|
|
|
|
|
|
|
|
will be between XA PREPARE and XA COMMIT, and we don't want
|
|
|
|
|
|
|
|
to block for undefined period of time. */
|
|
|
|
|
|
|
|
pthread_mutex_lock(&prepare_commit_mutex);
|
|
|
|
|
|
|
|
trx->active_trans = 2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(error);
|
|
|
|
return(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|