summaryrefslogtreecommitdiff
path: root/storage/innobase/handler/ha_innodb.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/handler/ha_innodb.cc')
-rw-r--r--storage/innobase/handler/ha_innodb.cc993
1 files changed, 460 insertions, 533 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 0b4880b0205..46062850019 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -71,6 +71,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "buf0flu.h"
#include "buf0lru.h"
#include "dict0boot.h"
+#include "dict0load.h"
#include "btr0defragment.h"
#include "dict0crea.h"
#include "dict0dict.h"
@@ -78,8 +79,6 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "dict0stats_bg.h"
#include "fil0fil.h"
#include "fsp0fsp.h"
-#include "fsp0space.h"
-#include "fsp0sysspace.h"
#include "fts0fts.h"
#include "fts0plugin.h"
#include "fts0priv.h"
@@ -87,10 +86,8 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "ibuf0ibuf.h"
#include "lock0lock.h"
#include "log0crypt.h"
-#include "mem0mem.h"
#include "mtr0mtr.h"
#include "os0file.h"
-#include "os0thread.h"
#include "page0zip.h"
#include "pars0pars.h"
#include "rem0types.h"
@@ -134,6 +131,9 @@ void close_thread_tables(THD* thd);
#define tdc_size 400
#endif
+#include <mysql/plugin.h>
+#include <mysql/service_wsrep.h>
+
#include "ha_innodb.h"
#include "i_s.h"
#include "sync0sync.h"
@@ -141,31 +141,13 @@ void close_thread_tables(THD* thd);
#include <string>
#include <sstream>
-#include <mysql/plugin.h>
-#include <mysql/service_wsrep.h>
-
#ifdef WITH_WSREP
#include "dict0priv.h"
-#include "ut0byte.h"
#include <mysql/service_md5.h>
+#include "wsrep_sst.h"
extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
-static inline wsrep_ws_handle_t*
-wsrep_ws_handle(THD* thd, const trx_t* trx) {
- return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd),
- (wsrep_trx_id_t)trx->id);
-}
-
-extern TC_LOG* tc_log;
-extern void wsrep_cleanup_transaction(THD *thd);
-static int
-wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
- my_bool signal);
-static void
-wsrep_fake_trx_id(handlerton* hton, THD *thd);
-static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
-static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
#endif /* WITH_WSREP */
/** to force correct commit order in binlog */
@@ -251,10 +233,10 @@ void set_my_errno(int err)
errno = err;
}
-static uint mysql_fields(const TABLE *table)
+static uint omits_virtual_cols(const TABLE_SHARE &share)
{
- return table->s->frm_version < FRM_VER_EXPRESSSIONS
- ? table->s->stored_fields : table->s->fields;
+ return share.frm_version < FRM_VER_EXPRESSSIONS &&
+ share.virtual_fields;
}
/** Checks whether the file name belongs to a partition of a table.
@@ -273,7 +255,7 @@ is_partition(
/** Signal to shut down InnoDB (NULL if shutdown was signaled, or if
running in innodb_read_only mode, srv_read_only_mode) */
-st_my_thread_var *srv_running;
+std::atomic <st_my_thread_var *> srv_running;
/** Service thread that waits for the server shutdown and stops purge threads.
Purge workers have THDs that are needed to calculate virtual columns.
This THDs must be destroyed rather early in the server shutdown sequence.
@@ -293,23 +275,20 @@ thd_destructor_proxy(void *)
mysql_cond_init(PSI_NOT_INSTRUMENTED, &thd_destructor_cond, 0);
st_my_thread_var *myvar= _my_thread_var();
+ myvar->current_mutex = &thd_destructor_mutex;
+ myvar->current_cond = &thd_destructor_cond;
+
THD *thd= create_thd();
thd_proc_info(thd, "InnoDB shutdown handler");
- myvar->current_mutex = &thd_destructor_mutex;
- myvar->current_cond = &thd_destructor_cond;
mysql_mutex_lock(&thd_destructor_mutex);
- my_atomic_storeptr_explicit(reinterpret_cast<void**>(&srv_running),
- myvar,
- MY_MEMORY_ORDER_RELAXED);
+ srv_running.store(myvar, std::memory_order_relaxed);
/* wait until the server wakes the THD to abort and die */
- while (!srv_running->abort)
+ while (!myvar->abort)
mysql_cond_wait(&thd_destructor_cond, &thd_destructor_mutex);
mysql_mutex_unlock(&thd_destructor_mutex);
- my_atomic_storeptr_explicit(reinterpret_cast<void**>(&srv_running),
- NULL,
- MY_MEMORY_ORDER_RELAXED);
+ srv_running.store(NULL, std::memory_order_relaxed);
while (srv_fast_shutdown == 0 &&
(trx_sys.any_active_transactions() ||
@@ -1849,8 +1828,13 @@ thd_to_trx_id(
{
return(thd_to_trx(thd)->id);
}
-#endif /* WITH_WSREP */
+static int
+wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
+ my_bool signal);
+static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
+static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
+#endif /* WITH_WSREP */
/********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used
@@ -2914,8 +2898,9 @@ ha_innobase::ha_innobase(
| HA_CAN_EXPORT
| HA_CAN_RTREEKEYS
| HA_CAN_TABLES_WITHOUT_ROLLBACK
+ | HA_CAN_ONLINE_BACKUPS
| HA_CONCURRENT_OPTIMIZE
- | (srv_force_primary_key ? HA_WANTS_PRIMARY_KEY : 0)
+ | (srv_force_primary_key ? HA_REQUIRE_PRIMARY_KEY : 0)
),
m_start_of_scan(),
m_mysql_has_locked()
@@ -4161,13 +4146,12 @@ static int innodb_init(void* p)
innobase_hton->show_status = innobase_show_status;
innobase_hton->flags =
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS
- | HTON_NATIVE_SYS_VERSIONING;
+ | HTON_NATIVE_SYS_VERSIONING | HTON_WSREP_REPLICATION;
#ifdef WITH_WSREP
innobase_hton->abort_transaction=wsrep_abort_transaction;
innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint;
innobase_hton->get_checkpoint=innobase_wsrep_get_checkpoint;
- innobase_hton->fake_trx_id=wsrep_fake_trx_id;
#endif /* WITH_WSREP */
innobase_hton->tablefile_extensions = ha_innobase_exts;
@@ -4259,9 +4243,7 @@ static int innodb_init(void* p)
mysql_thread_create(thd_destructor_thread_key,
&thd_destructor_thread,
NULL, thd_destructor_proxy, NULL);
- while (!my_atomic_loadptr_explicit(reinterpret_cast<void**>
- (&srv_running),
- MY_MEMORY_ORDER_RELAXED))
+ while (!srv_running.load(std::memory_order_relaxed))
os_thread_sleep(20);
}
@@ -4341,17 +4323,15 @@ innobase_end(handlerton*, ha_panic_function)
}
}
- st_my_thread_var* running = reinterpret_cast<st_my_thread_var*>(
- my_atomic_loadptr_explicit(
- reinterpret_cast<void**>(&srv_running),
- MY_MEMORY_ORDER_RELAXED));
- if (!abort_loop && running) {
- // may be UNINSTALL PLUGIN statement
- running->abort = 1;
- mysql_cond_broadcast(running->current_cond);
- }
-
- if (!srv_read_only_mode) {
+ if (auto r = srv_running.load(std::memory_order_relaxed)) {
+ ut_ad(!srv_read_only_mode);
+ if (!abort_loop) {
+ // may be UNINSTALL PLUGIN statement
+ mysql_mutex_lock(r->current_mutex);
+ r->abort = 1;
+ mysql_cond_broadcast(r->current_cond);
+ mysql_mutex_unlock(r->current_mutex);
+ }
pthread_join(thd_destructor_thread, NULL);
}
@@ -4506,6 +4486,14 @@ innobase_commit_ordered_2(
trx->flush_log_later = true;
}
+#ifdef WITH_WSREP
+ /* If the transaction is not run in 2pc, we must assign wsrep
+ XID here in order to get it written in rollback segment. */
+ if (wsrep_on(thd)) {
+ thd_get_xid(thd, (MYSQL_XID*)trx->xid);
+ }
+#endif /* WITH_WSREP */
+
innobase_commit_low(trx);
if (!read_only) {
@@ -4708,6 +4696,15 @@ innobase_rollback(
dberr_t error;
+#ifdef WITH_WSREP
+ /* If trx was assigned wsrep XID in prepare phase and the
+ trx is being rolled back due to BF abort, clear XID in order
+ to avoid writing it to rollback segment out of order. The XID
+ will be reassigned when the transaction is replayed. */
+ if (wsrep_is_wsrep_xid(trx->xid)) {
+ trx->xid->null();
+ }
+#endif /* WITH_WSREP */
if (rollback_trx
|| !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
@@ -5113,7 +5110,7 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
{
DBUG_ENTER("innobase_kill_query");
#ifdef WITH_WSREP
- if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) {
+ if (wsrep_on(thd) && wsrep_thd_is_aborting(thd)) {
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
@@ -5443,6 +5440,26 @@ normalize_table_name_c_low(
}
}
+create_table_info_t::create_table_info_t(
+ THD* thd,
+ TABLE* form,
+ HA_CREATE_INFO* create_info,
+ char* table_name,
+ char* remote_path,
+ bool file_per_table,
+ trx_t* trx)
+ : m_thd(thd),
+ m_trx(trx),
+ m_form(form),
+ m_default_row_format(innodb_default_row_format),
+ m_create_info(create_info),
+ m_table_name(table_name), m_table(NULL),
+ m_drop_before_rollback(false),
+ m_remote_path(remote_path),
+ m_innodb_file_per_table(file_per_table)
+{
+}
+
/** Normalizes a table name string.
A normalized name consists of the database name catenated to '/'
and table name. For example: test/mytable.
@@ -6052,6 +6069,14 @@ initialize_auto_increment(dict_table_t* table, const Field* field)
int
ha_innobase::open(const char* name, int, uint)
{
+ /* TODO: If trx_rollback_recovered(bool all=false) is ever
+ removed, the first-time open() must hold (or acquire and release)
+ a table lock that conflicts with trx_resurrect_table_locks(),
+ to ensure that any recovered incomplete ALTER TABLE will have been
+ rolled back. Otherwise, dict_table_t::instant could be cleared by
+ the rollback invoking dict_index_t::clear_instant_alter() while
+ open table handles exist in client connections. */
+
dict_table_t* ib_table;
char norm_name[FN_REFLEN];
dict_err_ignore_t ignore_err = DICT_ERR_IGNORE_NONE;
@@ -6090,12 +6115,13 @@ no_such_table:
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
- size_t n_fields = mysql_fields(table);
+ size_t n_fields = omits_virtual_cols(*table_share)
+ ? table_share->stored_fields : table_share->fields;
size_t n_cols = dict_table_get_n_user_cols(ib_table)
+ dict_table_get_n_v_cols(ib_table)
- !!DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID);
- if (n_cols != n_fields) {
+ if (UNIV_UNLIKELY(n_cols != n_fields)) {
ib::warn() << "Table " << norm_name << " contains "
<< n_cols << " user"
" defined columns in InnoDB, but " << n_fields
@@ -7233,19 +7259,19 @@ static
const Field*
build_template_needs_field(
/*=======================*/
- ibool index_contains, /*!< in:
- dict_index_contains_col_or_prefix(
- index, i) */
- ibool read_just_key, /*!< in: TRUE when MySQL calls
+ bool index_contains, /*!< in:
+ dict_index_t::contains_col_or_prefix(
+ i) */
+ bool read_just_key, /*!< in: TRUE when MySQL calls
ha_innobase::extra with the
argument HA_EXTRA_KEYREAD; it is enough
to read just columns defined in
the index (i.e., no read of the
clustered index record necessary) */
- ibool fetch_all_in_key,
+ bool fetch_all_in_key,
/*!< in: true=fetch all fields in
the index */
- ibool fetch_primary_key_cols,
+ bool fetch_primary_key_cols,
/*!< in: true=fetch the
primary key columns */
dict_index_t* index, /*!< in: InnoDB index to use */
@@ -7255,6 +7281,10 @@ build_template_needs_field(
{
const Field* field = table->field[i];
+ if (innobase_is_v_fld(field) && omits_virtual_cols(*table->s)) {
+ return NULL;
+ }
+
if (!index_contains) {
if (read_just_key) {
/* If this is a 'key read', we do not need
@@ -7279,7 +7309,6 @@ build_template_needs_field(
if (fetch_primary_key_cols
&& dict_table_col_in_clustered_key(index->table, i - num_v)) {
/* This field is needed in the query */
-
return(field);
}
@@ -7303,11 +7332,11 @@ build_template_needs_field_in_icp(
bool is_virtual)
/*!< in: a virtual column or not */
{
- ut_ad(contains == dict_index_contains_col_or_prefix(index, i, is_virtual));
+ ut_ad(contains == index->contains_col_or_prefix(i, is_virtual));
return(index == prebuilt->index
? contains
- : dict_index_contains_col_or_prefix(prebuilt->index, i, is_virtual));
+ : prebuilt->index->contains_col_or_prefix(i, is_virtual));
}
/**************************************************************//**
@@ -7332,17 +7361,11 @@ build_template_field(
templ = prebuilt->mysql_template + prebuilt->n_template++;
UNIV_MEM_INVALID(templ, sizeof *templ);
-
- if (innobase_is_v_fld(field)) {
- templ->is_virtual = true;
- col = &dict_table_get_nth_v_col(index->table, v_no)->m_col;
- } else {
- templ->is_virtual = false;
- col = dict_table_get_nth_col(index->table, i);
- }
+ templ->is_virtual = innobase_is_v_fld(field);
if (!templ->is_virtual) {
templ->col_no = i;
+ col = dict_table_get_nth_col(index->table, i);
templ->clust_rec_field_no = dict_col_get_clust_pos(
col, clust_index);
/* If clustered index record field is not found, lets print out
@@ -7381,7 +7404,7 @@ build_template_field(
<< table->field[j]->field_name.str;
}
- ib::error() << "Clustered record field for column " << i
+ ib::fatal() << "Clustered record field for column " << i
<< " not found table n_user_defined "
<< clust_index->n_user_defined_cols
<< " index n_user_defined "
@@ -7398,8 +7421,6 @@ build_template_field(
<< table->s->stored_fields
<< " query "
<< innobase_get_stmt_unsafe(current_thd, &size);
-
- ut_a(templ->clust_rec_field_no != ULINT_UNDEFINED);
}
templ->rec_field_is_prefix = FALSE;
templ->rec_prefix_field_no = ULINT_UNDEFINED;
@@ -7417,6 +7438,8 @@ build_template_field(
&templ->rec_prefix_field_no);
}
} else {
+ ut_ad(!omits_virtual_cols(*table->s));
+ col = &dict_table_get_nth_v_col(index->table, v_no)->m_col;
templ->clust_rec_field_no = v_no;
templ->rec_prefix_field_no = ULINT_UNDEFINED;
@@ -7500,10 +7523,8 @@ ha_innobase::build_template(
{
dict_index_t* index;
dict_index_t* clust_index;
- ulint n_fields;
ibool fetch_all_in_key = FALSE;
ibool fetch_primary_key_cols = FALSE;
- ulint i;
if (m_prebuilt->select_lock_type == LOCK_X || m_prebuilt->table->no_rollback()) {
/* We always retrieve the whole clustered index record if we
@@ -7565,7 +7586,8 @@ ha_innobase::build_template(
m_prebuilt->pk_filter = NULL;
}
- n_fields = (ulint) mysql_fields(table);
+ const bool skip_virtual = omits_virtual_cols(*table_share);
+ const ulint n_fields = table_share->fields;
if (!m_prebuilt->mysql_template) {
m_prebuilt->mysql_template = (mysql_row_templ_t*)
@@ -7585,26 +7607,25 @@ ha_innobase::build_template(
/* Note that in InnoDB, i is the column number in the table.
MySQL calls columns 'fields'. */
+ ulint num_v = 0;
+
if ((active_index != MAX_KEY
&& active_index == pushed_idx_cond_keyno) ||
(pushed_rowid_filter && rowid_filter_is_active)) {
- ulint num_v = 0;
-
/* Push down an index condition or an end_range check. */
- for (i = 0; i < n_fields; i++) {
- ibool index_contains;
-
- if (innobase_is_v_fld(table->field[i])) {
- index_contains = dict_index_contains_col_or_prefix(
- index, num_v, true);
- if (index_contains)
- {
- m_prebuilt->n_template = 0;
- goto no_icp;
- }
- } else {
- index_contains = dict_index_contains_col_or_prefix(
- index, i - num_v, false);
+ for (ulint i = 0; i < n_fields; i++) {
+ const Field* field = table->field[i];
+ const bool is_v = innobase_is_v_fld(field);
+ if (is_v && skip_virtual) {
+ num_v++;
+ continue;
+ }
+ bool index_contains = index->contains_col_or_prefix(
+ is_v ? num_v : i - num_v, is_v);
+ if (is_v && index_contains) {
+ m_prebuilt->n_template = 0;
+ num_v = 0;
+ goto no_icp;
}
/* Test if an end_range or an index condition
@@ -7622,17 +7643,10 @@ ha_innobase::build_template(
the subset
field->part_of_key.is_set(active_index)
which would be acceptable if end_range==NULL. */
- bool is_v = innobase_is_v_fld(table->field[i]);
if (build_template_needs_field_in_icp(
index, m_prebuilt, index_contains,
is_v ? num_v : i - num_v, is_v)) {
- /* Needed in ICP */
- const Field* field;
- mysql_row_templ_t* templ;
-
- if (whole_row) {
- field = table->field[i];
- } else {
+ if (!whole_row) {
field = build_template_needs_field(
index_contains,
m_prebuilt->read_just_key,
@@ -7640,15 +7654,16 @@ ha_innobase::build_template(
fetch_primary_key_cols,
index, table, i, num_v);
if (!field) {
- if (innobase_is_v_fld(
- table->field[i])) {
+ if (is_v) {
num_v++;
}
continue;
}
}
- templ = build_template_field(
+ ut_ad(!is_v);
+
+ mysql_row_templ_t* templ= build_template_field(
m_prebuilt, clust_index, index,
table, field, i - num_v, 0);
@@ -7723,7 +7738,8 @@ ha_innobase::build_template(
< m_prebuilt->index->n_uniq);
*/
}
- if (innobase_is_v_fld(table->field[i])) {
+
+ if (is_v) {
num_v++;
}
}
@@ -7735,29 +7751,23 @@ ha_innobase::build_template(
/* Include the fields that are not needed in index condition
pushdown. */
- for (i = 0; i < n_fields; i++) {
+ for (ulint i = 0; i < n_fields; i++) {
mysql_row_templ_t* templ;
- ibool index_contains;
-
- if (innobase_is_v_fld(table->field[i])) {
- index_contains = dict_index_contains_col_or_prefix(
- index, num_v, true);
- } else {
- index_contains = dict_index_contains_col_or_prefix(
- index, i - num_v, false);
+ const Field* field = table->field[i];
+ const bool is_v = innobase_is_v_fld(field);
+ if (is_v && skip_virtual) {
+ num_v++;
+ continue;
}
- bool is_v = innobase_is_v_fld(table->field[i]);
+ bool index_contains = index->contains_col_or_prefix(
+ is_v ? num_v : i - num_v, is_v);
if (!build_template_needs_field_in_icp(
index, m_prebuilt, index_contains,
is_v ? num_v : i - num_v, is_v)) {
/* Not needed in ICP */
- const Field* field;
-
- if (whole_row) {
- field = table->field[i];
- } else {
+ if (!whole_row) {
field = build_template_needs_field(
index_contains,
m_prebuilt->read_just_key,
@@ -7765,7 +7775,7 @@ ha_innobase::build_template(
fetch_primary_key_cols,
index, table, i, num_v);
if (!field) {
- if (innobase_is_v_fld(table->field[i])) {
+ if (is_v) {
num_v++;
}
continue;
@@ -7775,8 +7785,9 @@ ha_innobase::build_template(
templ = build_template_field(
m_prebuilt, clust_index, index,
table, field, i - num_v, num_v);
+ ut_ad(templ->is_virtual == (ulint)is_v);
- if (templ->is_virtual) {
+ if (is_v) {
num_v++;
}
}
@@ -7787,24 +7798,29 @@ ha_innobase::build_template(
} else {
no_icp:
mysql_row_templ_t* templ;
- ulint num_v = 0;
/* No index condition pushdown */
m_prebuilt->idx_cond = NULL;
+ ut_ad(num_v == 0);
- for (i = 0; i < n_fields; i++) {
- const Field* field;
+ for (ulint i = 0; i < n_fields; i++) {
+ const Field* field = table->field[i];
+ const bool is_v = innobase_is_v_fld(field);
if (whole_row) {
+ if (is_v && skip_virtual) {
+ num_v++;
+ continue;
+ }
/* Even this is whole_row, if the seach is
on a virtual column, and read_just_key is
set, and field is not in this index, we
will not try to fill the value since they
are not stored in such index nor in the
cluster index. */
- if (innobase_is_v_fld(table->field[i])
+ if (is_v
&& m_prebuilt->read_just_key
- && !dict_index_contains_col_or_prefix(
- m_prebuilt->index, num_v, true))
+ && !m_prebuilt->index->contains_col_or_prefix(
+ num_v, true))
{
/* Turn off ROW_MYSQL_WHOLE_ROW */
m_prebuilt->template_type =
@@ -7812,23 +7828,15 @@ no_icp:
num_v++;
continue;
}
-
- field = table->field[i];
} else {
- ibool contain;
-
- if (!innobase_is_v_fld(table->field[i])) {
- contain = dict_index_contains_col_or_prefix(
- index, i - num_v,
- false);
- } else if (dict_index_is_clust(index)) {
+ if (is_v && index->is_primary()) {
num_v++;
continue;
- } else {
- contain = dict_index_contains_col_or_prefix(
- index, num_v, true);
}
+ bool contain = index->contains_col_or_prefix(
+ is_v ? num_v: i - num_v, is_v);
+
field = build_template_needs_field(
contain,
m_prebuilt->read_just_key,
@@ -7836,7 +7844,7 @@ no_icp:
fetch_primary_key_cols,
index, table, i, num_v);
if (!field) {
- if (innobase_is_v_fld(table->field[i])) {
+ if (is_v) {
num_v++;
}
continue;
@@ -7846,7 +7854,8 @@ no_icp:
templ = build_template_field(
m_prebuilt, clust_index, index,
table, field, i - num_v, num_v);
- if (templ->is_virtual) {
+ ut_ad(templ->is_virtual == (ulint)is_v);
+ if (is_v) {
num_v++;
}
}
@@ -7855,8 +7864,7 @@ no_icp:
if (index != clust_index && m_prebuilt->need_to_access_clustered) {
/* Change rec_field_no's to correspond to the clustered index
record */
- for (i = 0; i < m_prebuilt->n_template; i++) {
-
+ for (ulint i = 0; i < m_prebuilt->n_template; i++) {
mysql_row_templ_t* templ
= &m_prebuilt->mysql_template[i];
@@ -8110,9 +8118,9 @@ ha_innobase::write_row(
wsrep_thd_query(m_user_thd) :
(char *)"void");
error= DB_SUCCESS;
- wsrep_thd_set_conflict_state(
- m_user_thd, MUST_ABORT);
- innobase_srv_conc_exit_innodb(m_prebuilt);
+ wsrep_thd_self_abort(m_user_thd);
+ innobase_srv_conc_exit_innodb(
+ m_prebuilt);
/* jump straight to func exit over
* later wsrep hooks */
goto func_exit;
@@ -8182,10 +8190,14 @@ report_error:
#ifdef WITH_WSREP
if (!error_result
&& wsrep_on(m_user_thd)
- && wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE
+ && wsrep_thd_is_local(m_user_thd)
&& !wsrep_consistency_check(m_user_thd)
- && !wsrep_thd_ignore_table(m_user_thd)) {
- if (wsrep_append_keys(m_user_thd, false, record, NULL)) {
+ && (thd_sql_command(m_user_thd) != SQLCOM_CREATE_TABLE)
+ && (thd_sql_command(m_user_thd) != SQLCOM_LOAD ||
+ thd_binlog_format(m_user_thd) == BINLOG_FORMAT_ROW)) {
+ if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE,
+ record,
+ NULL)) {
DBUG_PRINT("wsrep", ("row key failed"));
error_result = HA_ERR_INTERNAL_ERROR;
goto wsrep_error;
@@ -8284,13 +8296,12 @@ calc_row_difference(
ulint n_changed = 0;
dfield_t dfield;
dict_index_t* clust_index;
- uint i;
ibool changes_fts_column = FALSE;
ibool changes_fts_doc_col = FALSE;
trx_t* const trx = prebuilt->trx;
doc_id_t doc_id = FTS_NULL_DOC_ID;
ulint num_v = 0;
- uint n_fields = mysql_fields(table);
+ const bool skip_virtual = omits_virtual_cols(*table->s);
ut_ad(!srv_read_only_mode);
@@ -8300,16 +8311,15 @@ calc_row_difference(
/* We use upd_buff to convert changed fields */
buf = (byte*) upd_buff;
- for (i = 0; i < n_fields; i++) {
+ for (uint i = 0; i < table->s->fields; i++) {
field = table->field[i];
- bool is_virtual = innobase_is_v_fld(field);
- dict_col_t* col;
-
- if (is_virtual) {
- col = &prebuilt->table->v_cols[num_v].m_col;
- } else {
- col = &prebuilt->table->cols[i - num_v];
+ const bool is_virtual = innobase_is_v_fld(field);
+ if (is_virtual && skip_virtual) {
+ continue;
}
+ dict_col_t* col = is_virtual
+ ? &prebuilt->table->v_cols[num_v].m_col
+ : &prebuilt->table->cols[i - num_v];
o_ptr = (const byte*) old_row + get_field_offset(table, field);
n_ptr = (const byte*) new_row + get_field_offset(table, field);
@@ -8665,33 +8675,25 @@ wsrep_calc_row_hash(
dictionary */
row_prebuilt_t* prebuilt) /*!< in: InnoDB prebuilt struct */
{
- Field* field;
- enum_field_types field_mysql_type;
- uint n_fields;
ulint len;
const byte* ptr;
- ulint col_type;
- uint i;
void *ctx = alloca(my_md5_context_size());
my_md5_init(ctx);
- n_fields = mysql_fields(table);
-
- for (i = 0; i < n_fields; i++) {
+ for (uint i = 0; i < table->s->fields; i++) {
byte null_byte=0;
byte true_byte=1;
- field = table->field[i];
+ const Field* field = table->field[i];
+ if (innobase_is_v_fld(field)) {
+ continue;
+ }
ptr = (const byte*) row + get_field_offset(table, field);
len = field->pack_length();
- field_mysql_type = field->type();
-
- col_type = prebuilt->table->cols[i].mtype;
-
- switch (col_type) {
+ switch (prebuilt->table->cols[i].mtype) {
case DATA_BLOB:
ptr = row_mysql_read_blob_ref(&len, ptr, len);
@@ -8701,7 +8703,7 @@ wsrep_calc_row_hash(
case DATA_VARCHAR:
case DATA_BINARY:
case DATA_VARMYSQL:
- if (field_mysql_type == MYSQL_TYPE_VARCHAR) {
+ if (field->type() == MYSQL_TYPE_VARCHAR) {
/* This is a >= 5.0.3 type true VARCHAR where
the real payload data length is stored in
1 or 2 bytes */
@@ -8881,13 +8883,17 @@ func_exit:
innobase_active_small();
#ifdef WITH_WSREP
- if (error == DB_SUCCESS &&
- wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
- wsrep_on(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd)) {
+ if (error == DB_SUCCESS
+ && wsrep_on(m_user_thd)
+ && wsrep_thd_is_local(m_user_thd)) {
+
DBUG_PRINT("wsrep", ("update row key"));
- if (wsrep_append_keys(m_user_thd, false, old_row, new_row)) {
+ if (wsrep_append_keys(m_user_thd,
+ wsrep_protocol_version >= 4
+ ? WSREP_SERVICE_KEY_UPDATE
+ : WSREP_SERVICE_KEY_EXCLUSIVE,
+ old_row, new_row)){
WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED");
DBUG_PRINT("wsrep", ("row key failed"));
err = HA_ERR_INTERNAL_ERROR;
@@ -8947,11 +8953,14 @@ ha_innobase::delete_row(
innobase_active_small();
#ifdef WITH_WSREP
- if (error == DB_SUCCESS &&
- wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
- wsrep_on(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd)) {
- if (wsrep_append_keys(m_user_thd, false, record, NULL)) {
+ if (error == DB_SUCCESS
+ && wsrep_on(m_user_thd)
+ && wsrep_thd_is_local(m_user_thd)
+ && !wsrep_thd_ignore_table(m_user_thd)) {
+
+ if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE,
+ record,
+ NULL)) {
DBUG_PRINT("wsrep", ("delete fail"));
error = (dberr_t) HA_ERR_INTERNAL_ERROR;
goto wsrep_error;
@@ -9374,7 +9383,6 @@ ha_innobase::innobase_get_index(
if (keynr != MAX_KEY && table->s->keys > 0) {
key = &table->key_info[keynr];
index = dict_table_get_index_on_name(ib_table, key->name.str);
- ut_ad(index);
} else {
index = dict_table_get_first_index(ib_table);
}
@@ -10135,6 +10143,22 @@ wsrep_dict_foreign_find_index(
ibool check_charsets,
ulint check_null);
+inline
+const char*
+wsrep_key_type_to_str(Wsrep_service_key_type type)
+{
+ switch (type) {
+ case WSREP_SERVICE_KEY_SHARED:
+ return "shared";
+ case WSREP_SERVICE_KEY_REFERENCE:
+ return "reference";
+ case WSREP_SERVICE_KEY_UPDATE:
+ return "update";
+ case WSREP_SERVICE_KEY_EXCLUSIVE:
+ return "exclusive";
+ };
+ return "unknown";
+}
extern dberr_t
wsrep_append_foreign_key(
@@ -10144,17 +10168,17 @@ wsrep_append_foreign_key(
const rec_t* rec, /*!<in: clustered index record */
dict_index_t* index, /*!<in: clustered index */
ibool referenced, /*!<in: is check for referenced table */
- ibool shared) /*!<in: is shared access */
+ Wsrep_service_key_type key_type) /*!< in: access type of this key
+ (shared, exclusive, reference...) */
{
ut_a(trx);
THD* thd = (THD*)trx->mysql_thd;
ulint rcode = DB_SUCCESS;
char cache_key[513] = {'\0'};
int cache_key_len=0;
- bool const copy = true;
if (!wsrep_on(trx->mysql_thd) ||
- wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
+ wsrep_thd_is_local(trx->mysql_thd) == false) {
return DB_SUCCESS;
}
@@ -10244,8 +10268,8 @@ wsrep_append_foreign_key(
if (rcode != DB_SUCCESS) {
WSREP_ERROR(
"FK key set failed: " ULINTPF
- " (" ULINTPF " " ULINTPF "), index: %s %s, %s",
- rcode, referenced, shared,
+ " (" ULINTPF "%s), index: %s %s, %s",
+ rcode, referenced, wsrep_key_type_to_str(key_type),
(index) ? index->name() : "void index",
(index && index->table) ? index->table->name.m_name :
"void table",
@@ -10264,7 +10288,7 @@ wsrep_append_foreign_key(
#ifdef WSREP_DEBUG_PRINT
ulint j;
fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
- cache_key, (shared) ? "shared" : "exclusive", len+1);
+ cache_key, wsrep_key_type_to_str(key_type), len+1);
for (j=0; j<len+1; j++) {
fprintf(stderr, " %hhX, ", key[j]);
}
@@ -10283,7 +10307,8 @@ wsrep_append_foreign_key(
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
- if (!wsrep_prepare_key(
+ if (!wsrep_prepare_key_for_innodb(
+ thd,
(const uchar*)cache_key,
cache_key_len + 1,
(const uchar*)key, len+1,
@@ -10294,17 +10319,7 @@ wsrep_append_foreign_key(
wsrep_thd_query(thd) : "void");
return DB_ERROR;
}
-
- wsrep_t *wsrep= get_wsrep();
-
- rcode = (int)wsrep->append_key(
- wsrep,
- wsrep_ws_handle(thd, trx),
- &wkey,
- 1,
- shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
- copy);
-
+ rcode = wsrep_thd_append_key(thd, &wkey, 1, key_type);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: " ULINTPF, rcode));
WSREP_ERROR("Appending cascaded fk row key failed: %s, "
@@ -10325,16 +10340,19 @@ wsrep_append_key(
TABLE_SHARE *table_share,
const char* key,
uint16_t key_len,
- bool shared
+ Wsrep_service_key_type key_type /*!< in: access type of this key
+ (shared, exclusive, semi...) */
)
{
DBUG_ENTER("wsrep_append_key");
- bool const copy = true;
+ DBUG_PRINT("enter",
+ ("thd: %lu trx: %lld", thd_get_thread_id(thd),
+ (long long)trx->id));
#ifdef WSREP_DEBUG_PRINT
- fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s\n Query: %s ",
- (shared) ? "Shared" : "Exclusive",
- thd_get_thread_id(thd), (long long)trx->id, key_len,
- table_share->table_name.str, wsrep_thd_query(thd));
+ fprintf(stderr, "%s conn %lu, trx " TRX_ID_FMT ", keylen %d, key %s.%s\n",
+ wsrep_key_type_to_str(key_type),
+ thd_get_thread_id(thd), trx->id, key_len,
+ table_share->table_name.str, key);
for (int i=0; i<key_len; i++) {
fprintf(stderr, "%hhX, ", key[i]);
}
@@ -10343,7 +10361,8 @@ wsrep_append_key(
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
- if (!wsrep_prepare_key(
+ if (!wsrep_prepare_key_for_innodb(
+ thd,
(const uchar*)table_share->table_cache_key.str,
table_share->table_cache_key.length,
(const uchar*)key, key_len,
@@ -10355,15 +10374,7 @@ wsrep_append_key(
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
}
- wsrep_t *wsrep= get_wsrep();
-
- int rcode = (int)wsrep->append_key(
- wsrep,
- wsrep_ws_handle(thd, trx),
- &wkey,
- 1,
- shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
- copy);
+ int rcode = wsrep_thd_append_key(thd, &wkey, 1, key_type);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
WSREP_WARN("Appending row key failed: %s, %d",
@@ -10404,16 +10415,30 @@ int
ha_innobase::wsrep_append_keys(
/*===========================*/
THD *thd,
- bool shared,
+ Wsrep_service_key_type key_type, /*!< in: access type of this row
+ operation:
+ (shared, exclusive, reference...) */
const uchar* record0, /* in: row in MySQL format */
const uchar* record1) /* in: row in MySQL format */
{
+ /* Sanity check: newly inserted records should always be passed with
+ EXCLUSIVE key type, all the rest are expected to carry a pre-image
+ */
+ ut_a(record1 != NULL || key_type == WSREP_SERVICE_KEY_EXCLUSIVE);
+
int rcode;
DBUG_ENTER("wsrep_append_keys");
bool key_appended = false;
trx_t *trx = thd_to_trx(thd);
+#ifdef WSREP_DEBUG_PRINT
+ fprintf(stderr, "%s conn %lu, trx " TRX_ID_FMT ", table %s\nSQL: %s\n",
+ wsrep_key_type_to_str(key_type),
+ thd_get_thread_id(thd), trx->id,
+ table_share->table_name.str, wsrep_thd_query(thd));
+#endif
+
if (table_share && table_share->tmp_table != NO_TMP_TABLE) {
WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s",
thd_get_thread_id(thd),
@@ -10436,7 +10461,7 @@ ha_innobase::wsrep_append_keys(
if (!is_null) {
rcode = wsrep_append_key(
thd, trx, table_share, keyval,
- len, shared);
+ len, key_type);
if (rcode) {
DBUG_RETURN(rcode);
@@ -10454,68 +10479,91 @@ ha_innobase::wsrep_append_keys(
KEY* key_info = table->key_info + i;
if (key_info->flags & HA_NOSAME) {
hasPK = true;
+ break;
}
}
for (i=0; i<table->s->keys; ++i) {
- uint len;
- char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
- char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
- char* key0 = &keyval0[1];
- char* key1 = &keyval1[1];
KEY* key_info = table->key_info + i;
- ibool is_null;
dict_index_t* idx = innobase_get_index(i);
dict_table_t* tab = (idx) ? idx->table : NULL;
+ /* keyval[] shall contain an ordinal number at byte 0
+ and the actual key data shall be written at byte 1.
+ Hence the total data length is the key length + 1 */
+ char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
+ char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
keyval0[0] = (char)i;
keyval1[0] = (char)i;
+ char* key0 = &keyval0[1];
+ char* key1 = &keyval1[1];
if (!tab) {
WSREP_WARN("MariaDB-InnoDB key mismatch %s %s",
table->s->table_name.str,
key_info->name.str);
}
- /* !hasPK == table with no PK, must append all non-unique keys */
+ /* !hasPK == table with no PK,
+ must append all non-unique keys */
if (!hasPK || key_info->flags & HA_NOSAME ||
((tab &&
referenced_by_foreign_key2(tab, idx)) ||
(!tab && referenced_by_foreign_key()))) {
- len = wsrep_store_key_val_for_row(
+ ibool is_null0;
+ uint len0 = wsrep_store_key_val_for_row(
thd, table, i, key0,
WSREP_MAX_SUPPORTED_KEY_LENGTH,
- record0, &is_null);
- if (!is_null) {
- rcode = wsrep_append_key(
- thd, trx, table_share,
- keyval0, len+1, shared);
-
- if (rcode) {
- DBUG_RETURN(rcode);
- }
-
- if (key_info->flags & HA_NOSAME || shared)
- key_appended = true;
- } else {
- WSREP_DEBUG("NULL key skipped: %s",
- wsrep_thd_query(thd));
- }
+ record0, &is_null0);
if (record1) {
- len = wsrep_store_key_val_for_row(
+ ibool is_null1;
+ uint len1 = wsrep_store_key_val_for_row(
thd, table, i, key1,
WSREP_MAX_SUPPORTED_KEY_LENGTH,
- record1, &is_null);
+ record1, &is_null1);
+
+ if (is_null0 != is_null1 ||
+ len0 != len1 ||
+ memcmp(key0, key1, len0)) {
+ /* This key has chaged. If it
+ is unique, this is an exclusive
+ operation -> upgrade key type */
+ if (key_info->flags & HA_NOSAME) {
+ key_type = WSREP_SERVICE_KEY_EXCLUSIVE;
+ }
- if (!is_null && memcmp(key0, key1, len)) {
- rcode = wsrep_append_key(
+ if (!is_null1) {
+ rcode = wsrep_append_key(
thd, trx, table_share,
- keyval1, len+1, shared);
- if (rcode) DBUG_RETURN(rcode);
+ keyval1,
+ /* for len1+1 see keyval1
+ initialization comment */
+ len1+1, key_type);
+ if (rcode)
+ DBUG_RETURN(rcode);
+ }
}
}
+
+ if (!is_null0) {
+ rcode = wsrep_append_key(
+ thd, trx, table_share,
+ /* for len0+1 see keyval0
+ initialization comment */
+ keyval0, len0+1, key_type);
+ if (rcode)
+ DBUG_RETURN(rcode);
+
+ if (key_info->flags & HA_NOSAME ||
+ key_type == WSREP_SERVICE_KEY_SHARED||
+ key_type == WSREP_SERVICE_KEY_REFERENCE)
+ key_appended = true;
+ } else {
+ WSREP_DEBUG("NULL key skipped: %s",
+ wsrep_thd_query(thd));
+ }
}
}
}
@@ -10529,7 +10577,7 @@ ha_innobase::wsrep_append_keys(
if ((rcode = wsrep_append_key(thd, trx, table_share,
(const char*) digest, 16,
- shared))) {
+ key_type))) {
DBUG_RETURN(rcode);
}
@@ -10538,7 +10586,7 @@ ha_innobase::wsrep_append_keys(
digest, record1, table, m_prebuilt);
if ((rcode = wsrep_append_key(thd, trx, table_share,
(const char*) digest,
- 16, shared))) {
+ 16, key_type))) {
DBUG_RETURN(rcode);
}
}
@@ -10603,9 +10651,9 @@ create_table_check_doc_id_col(
ULINT_UNDEFINED if column is of the
wrong type/name/size */
{
- uint n_fields = mysql_fields(form);
+ ut_ad(!omits_virtual_cols(*form->s));
- for (ulint i = 0; i < n_fields; i++) {
+ for (ulint i = 0; i < form->s->fields; i++) {
const Field* field;
ulint col_type;
ulint col_len;
@@ -10798,6 +10846,7 @@ create_table_info_t::create_table_def()
DBUG_PRINT("enter", ("table_name: %s", m_table_name));
DBUG_ASSERT(m_trx->mysql_thd == m_thd);
+ DBUG_ASSERT(!m_drop_before_rollback);
/* MySQL does the name length check. But we do additional check
on the name length here */
@@ -11046,9 +11095,8 @@ err_col:
dict_table_add_system_columns(table, heap);
if (table->is_temporary()) {
- /* Get a new table ID. FIXME: Make this a private
- sequence, not shared with persistent tables! */
- dict_table_assign_new_id(table, m_trx);
+ m_trx->table_id = table->id
+ = dict_sys->get_temporary_table_id();
ut_ad(dict_tf_get_rec_format(table->flags)
!= REC_FORMAT_COMPRESSED);
table->space_id = SRV_TMP_SPACE_ID;
@@ -11060,6 +11108,7 @@ err_col:
table, m_trx,
(fil_encryption_t)options->encryption,
(uint32_t)options->encryption_key_id);
+ m_drop_before_rollback = (err == DB_SUCCESS);
}
DBUG_EXECUTE_IF("ib_crash_during_create_for_encryption",
@@ -11075,9 +11124,6 @@ err_col:
case DB_SUCCESS:
ut_ad(table);
m_table = table;
- if (m_flags2 & DICT_TF2_FTS) {
- fts_optimize_add_table(table);
- }
DBUG_RETURN(0);
default:
break;
@@ -11096,7 +11142,8 @@ err_col:
: ER_TABLESPACE_EXISTS, MYF(0), display_name);
}
- DBUG_RETURN(convert_error_code_to_mysql(err, m_flags, m_thd));}
+ DBUG_RETURN(convert_error_code_to_mysql(err, m_flags, m_thd));
+}
/*****************************************************************//**
Creates an index in an InnoDB database. */
@@ -11301,7 +11348,7 @@ create_table_info_t::create_option_data_directory_is_valid()
}
/* Do not use DATA DIRECTORY with TEMPORARY TABLE. */
- if (m_create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+ if (m_create_info->tmp_table()) {
push_warning(
m_thd, Sql_condition::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
@@ -11330,8 +11377,7 @@ create_table_info_t::create_options_are_invalid()
const char* ret = NULL;
enum row_type row_format = m_create_info->row_type;
- const bool is_temp
- = m_create_info->options & HA_LEX_CREATE_TMP_TABLE;
+ const bool is_temp = m_create_info->tmp_table();
ut_ad(m_thd != NULL);
@@ -11479,7 +11525,7 @@ Check engine specific table options not handled by SQL-parser.
const char*
create_table_info_t::check_table_options()
{
- enum row_type row_format = m_form->s->row_type;
+ enum row_type row_format = m_create_info->row_type;
ha_table_option_struct *options= m_form->s->option_struct;
fil_encryption_t encrypt = (fil_encryption_t)options->encryption;
bool should_encrypt = (encrypt == FIL_ENCRYPTION_ON);
@@ -11526,7 +11572,16 @@ create_table_info_t::check_table_options()
return "PAGE_COMPRESSED";
}
- if (row_format == ROW_TYPE_REDUNDANT) {
+ switch (row_format) {
+ default:
+ break;
+ case ROW_TYPE_DEFAULT:
+ if (m_default_row_format
+ != DEFAULT_ROW_FORMAT_REDUNDANT) {
+ break;
+ }
+ /* fall through */
+ case ROW_TYPE_REDUNDANT:
push_warning(
m_thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
@@ -11688,7 +11743,7 @@ create_table_info_t::parse_table_name(
if (m_innodb_file_per_table
&& !mysqld_embedded
- && !(m_create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
+ && !m_create_info->tmp_table()) {
if ((name[1] == ':')
|| (name[0] == '\\' && name[1] == '\\')) {
@@ -11732,9 +11787,9 @@ create_table_info_t::parse_table_name(
/** Determine InnoDB table flags.
If strict_mode=OFF, this will adjust the flags to what should be assumed.
-@retval true if successful, false if error */
-bool
-create_table_info_t::innobase_table_flags()
+@retval true on success
+@retval false on error */
+bool create_table_info_t::innobase_table_flags()
{
DBUG_ENTER("innobase_table_flags");
@@ -11742,11 +11797,9 @@ create_table_info_t::innobase_table_flags()
ulint zip_ssize = 0;
enum row_type row_type;
rec_format_t innodb_row_format =
- get_row_format(innodb_default_row_format);
- const bool is_temp
- = m_create_info->options & HA_LEX_CREATE_TMP_TABLE;
- bool zip_allowed
- = !is_temp;
+ get_row_format(m_default_row_format);
+ const bool is_temp = m_create_info->tmp_table();
+ bool zip_allowed = !is_temp;
const ulint zip_ssize_max =
ut_min(static_cast<ulint>(UNIV_PAGE_SSIZE_MAX),
@@ -11843,7 +11896,7 @@ index_bad:
}
}
- row_type = m_form->s->row_type;
+ row_type = m_create_info->row_type;
if (zip_ssize && zip_allowed) {
/* if ROW_FORMAT is set to default,
@@ -12146,9 +12199,8 @@ create_table_info_t::set_tablespace_type(
/* Ignore the current innodb-file-per-table setting if we are
creating a temporary table. */
- m_use_file_per_table =
- m_allow_file_per_table
- && !(m_create_info->options & HA_LEX_CREATE_TMP_TABLE);
+ m_use_file_per_table = m_allow_file_per_table
+ && !m_create_info->tmp_table();
/* DATA DIRECTORY must have m_use_file_per_table but cannot be
used with TEMPORARY tables. */
@@ -12179,8 +12231,6 @@ create_table_info_t::initialize()
DBUG_RETURN(HA_ERR_WRONG_INDEX);
}
- ut_ad(m_form->s->row_type == m_create_info->row_type);
-
/* Get the transaction associated with the current thd, or create one
if not yet created */
@@ -12224,8 +12274,6 @@ int create_table_info_t::prepare_create_table(const char* name, bool strict)
ut_ad(m_thd != NULL);
ut_ad(m_create_info != NULL);
- ut_ad(m_form->s->row_type == m_create_info->row_type);
-
set_tablespace_type(false);
normalize_table_name(m_table_name, name);
@@ -12267,8 +12315,6 @@ int create_table_info_t::create_table(bool create_fk)
int error;
int primary_key_no;
uint i;
- const char* stmt;
- size_t stmt_len;
DBUG_ENTER("create_table");
@@ -12286,6 +12332,9 @@ int create_table_info_t::create_table(bool create_fk)
DBUG_RETURN(error);
}
+ DBUG_ASSERT(m_drop_before_rollback
+ == !(m_flags2 & DICT_TF2_TEMPORARY));
+
/* Create the keys */
if (m_form->s->keys == 0 || primary_key_no == -1) {
@@ -12344,8 +12393,7 @@ int create_table_info_t::create_table(bool create_fk)
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
FTS_DOC_ID_INDEX_NAME);
- error = -1;
- DBUG_RETURN(error);
+ DBUG_RETURN(-1);
case FTS_EXIST_DOC_ID_INDEX:
case FTS_NOT_EXIST_DOC_ID_INDEX:
break;
@@ -12358,10 +12406,6 @@ int create_table_info_t::create_table(bool create_fk)
error = convert_error_code_to_mysql(err, 0, NULL);
if (error) {
- row_drop_table_for_mysql(m_table_name, m_trx,
- SQLCOM_DROP_DB);
- trx_rollback_to_savepoint(m_trx, NULL);
- m_trx->error_state = DB_SUCCESS;
DBUG_RETURN(error);
}
}
@@ -12383,15 +12427,28 @@ int create_table_info_t::create_table(bool create_fk)
dict_table_get_all_fts_indexes(m_table, fts->indexes);
}
- stmt = innobase_get_stmt_unsafe(m_thd, &stmt_len);
-
- if (stmt) {
- dberr_t err = row_table_add_foreign_constraints(
- create_fk ? m_trx : NULL, stmt, stmt_len, m_table_name,
- m_create_info->options & HA_LEX_CREATE_TMP_TABLE);
+ size_t stmt_len;
+ if (const char* stmt = innobase_get_stmt_unsafe(m_thd, &stmt_len)) {
+ dberr_t err = create_fk
+ ? dict_create_foreign_constraints(
+ m_trx, stmt, stmt_len, m_table_name,
+ m_flags2 & DICT_TF2_TEMPORARY)
+ : DB_SUCCESS;
+ if (err == DB_SUCCESS) {
+ /* Check that also referencing constraints are ok */
+ dict_names_t fk_tables;
+ err = dict_load_foreigns(m_table_name, NULL,
+ false, true,
+ DICT_ERR_IGNORE_NONE,
+ fk_tables);
+ while (err == DB_SUCCESS && !fk_tables.empty()) {
+ dict_load_table(fk_tables.front(), true,
+ DICT_ERR_IGNORE_NONE);
+ fk_tables.pop_front();
+ }
+ }
switch (err) {
-
case DB_PARENT_NO_INDEX:
push_warning_printf(
m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -12424,10 +12481,9 @@ int create_table_info_t::create_table(bool create_fk)
break;
}
- error = convert_error_code_to_mysql(err, m_flags, NULL);
-
- if (error) {
- DBUG_RETURN(error);
+ if (err != DB_SUCCESS) {
+ DBUG_RETURN(convert_error_code_to_mysql(
+ err, m_flags, NULL));
}
}
@@ -12476,6 +12532,10 @@ create_table_info_t::create_table_update_dict()
trx_free(m_trx);
DBUG_RETURN(-1);
}
+
+ mutex_enter(&dict_sys->mutex);
+ fts_optimize_add_table(innobase_table);
+ mutex_exit(&dict_sys->mutex);
}
if (const Field* ai = m_form->found_next_number_field) {
@@ -12585,14 +12645,21 @@ ha_innobase::create(
}
if ((error = info.create_table(own_trx))) {
- row_drop_table_for_mysql(norm_name, trx, SQLCOM_DROP_TABLE,
- true);
+ /* Drop the being-created table before rollback,
+ so that rollback can possibly rename back a table
+ that could have been renamed before the failed creation. */
+ if (info.drop_before_rollback()) {
+ trx->error_state = DB_SUCCESS;
+ row_drop_table_for_mysql(info.table_name(),
+ trx, SQLCOM_TRUNCATE, true,
+ false);
+ }
trx_rollback_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
if (own_trx) {
trx_free(trx);
- DBUG_RETURN(error);
}
+ DBUG_RETURN(error);
}
innobase_commit_low(trx);
@@ -12937,16 +13004,25 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom)
int ha_innobase::delete_table(const char* name)
{
enum_sql_command sqlcom = enum_sql_command(thd_sql_command(ha_thd()));
-
- if (sqlcom == SQLCOM_TRUNCATE
- && thd_killed(ha_thd())
- && (m_prebuilt == NULL || m_prebuilt->table->is_temporary())) {
- sqlcom = SQLCOM_DROP_TABLE;
- }
-
- /* SQLCOM_TRUNCATE will be passed via ha_innobase::truncate() only. */
- DBUG_ASSERT(sqlcom != SQLCOM_TRUNCATE);
- return delete_table(name, sqlcom);
+ /* SQLCOM_TRUNCATE should be passed via ha_innobase::truncate() only.
+
+ On client disconnect, when dropping temporary tables, the
+ previous sqlcom would not be overwritten. In such a case, we
+ will have thd_kill_level() != NOT_KILLED, !m_prebuilt can
+ hold, and sqlcom could be anything, including TRUNCATE.
+
+ The sqlcom only matters for persistent tables; no persistent
+ metadata or FOREIGN KEY metadata is kept for temporary
+ tables. Therefore, we relax the assertion. If there is a bug
+ that slips through this assertion due to !m_prebuilt, the
+ worst impact should be that on DROP TABLE of a persistent
+ table, FOREIGN KEY constraints will be ignored and their
+ metadata will not be removed. */
+ DBUG_ASSERT(sqlcom != SQLCOM_TRUNCATE
+ || (thd_kill_level(ha_thd()) != THD_IS_NOT_KILLED
+ && (!m_prebuilt
+ || m_prebuilt->table->is_temporary())));
+ return delete_table(name, sqlcom);
}
/** Remove all tables in the named database inside InnoDB.
@@ -13025,6 +13101,7 @@ innobase_drop_database(
@param[in] from old table name
@param[in] to new table name
@param[in] commit whether to commit trx
+@param[in] use_fk whether to parse and enforce FOREIGN KEY constraints
@return DB_SUCCESS or error code */
inline
dberr_t
@@ -13032,7 +13109,8 @@ innobase_rename_table(
trx_t* trx,
const char* from,
const char* to,
- bool commit = true)
+ bool commit,
+ bool use_fk)
{
dberr_t error;
char norm_to[FN_REFLEN];
@@ -13087,7 +13165,8 @@ innobase_rename_table(
goto func_exit;
}
- error = row_rename_table_for_mysql(norm_from, norm_to, trx, commit);
+ error = row_rename_table_for_mysql(norm_from, norm_to, trx, commit,
+ use_fk);
if (error != DB_SUCCESS) {
if (error == DB_TABLE_NOT_FOUND
@@ -13112,7 +13191,8 @@ innobase_rename_table(
#endif /* _WIN32 */
trx_start_if_not_started(trx, true);
error = row_rename_table_for_mysql(
- par_case_name, norm_to, trx, TRUE);
+ par_case_name, norm_to, trx,
+ true, false);
}
}
@@ -13168,7 +13248,7 @@ int ha_innobase::truncate()
dict_table_t* ib_table = m_prebuilt->table;
const time_t update_time = ib_table->update_time;
const ulint stored_lock = m_prebuilt->stored_select_lock_type;
- memset(&info, 0, sizeof info);
+ info.init();
update_create_info_from_table(&info, table);
if (ib_table->is_temporary()) {
@@ -13193,14 +13273,31 @@ int ha_innobase::truncate()
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
row_mysql_lock_data_dictionary(trx);
int err = convert_error_code_to_mysql(
- innobase_rename_table(trx, ib_table->name.m_name, temp_name, false),
+ innobase_rename_table(trx, ib_table->name.m_name, temp_name,
+ false, false),
ib_table->flags, m_user_thd);
if (err) {
trx_rollback_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
} else {
+ switch (dict_tf_get_rec_format(ib_table->flags)) {
+ case REC_FORMAT_REDUNDANT:
+ info.row_type = ROW_TYPE_REDUNDANT;
+ break;
+ case REC_FORMAT_COMPACT:
+ info.row_type = ROW_TYPE_COMPACT;
+ break;
+ case REC_FORMAT_COMPRESSED:
+ info.row_type = ROW_TYPE_COMPRESSED;
+ break;
+ case REC_FORMAT_DYNAMIC:
+ info.row_type = ROW_TYPE_DYNAMIC;
+ break;
+ }
+
err = create(name, table, &info,
- dict_table_is_file_per_table(ib_table), trx);
+ ib_table->is_temporary()
+ || dict_table_is_file_per_table(ib_table), trx);
}
trx_free(trx);
@@ -13246,7 +13343,7 @@ ha_innobase::rename_table(
++trx->will_lock;
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
- dberr_t error = innobase_rename_table(trx, from, to);
+ dberr_t error = innobase_rename_table(trx, from, to, true, true);
DEBUG_SYNC(thd, "after_innobase_rename_table");
@@ -14386,20 +14483,9 @@ ha_innobase::check(
if (!(check_opt->flags & T_QUICK)
&& !index->is_corrupted()) {
- /* Enlarge the fatal lock wait timeout during
- CHECK TABLE. */
- my_atomic_addlong(
- &srv_fatal_semaphore_wait_threshold,
- SRV_SEMAPHORE_WAIT_EXTENSION);
dberr_t err = btr_validate_index(
- index, m_prebuilt->trx, false);
-
- /* Restore the fatal lock wait timeout after
- CHECK TABLE. */
- my_atomic_addlong(
- &srv_fatal_semaphore_wait_threshold,
- -SRV_SEMAPHORE_WAIT_EXTENSION);
+ index, m_prebuilt->trx);
if (err != DB_SUCCESS) {
is_ok = false;
@@ -15381,8 +15467,7 @@ ha_innobase::external_lock(
if (!skip) {
#ifdef WITH_WSREP
- if (!wsrep_on(thd) || wsrep_thd_exec_mode(thd) == LOCAL_STATE)
- {
+ if (!wsrep_on(thd) || wsrep_thd_is_local(m_user_thd)) {
#endif /* WITH_WSREP */
my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0),
" InnoDB is limited to row-logging when"
@@ -16896,6 +16981,14 @@ innobase_rollback_by_xid(
}
if (trx_t* trx = trx_get_trx_by_xid(xid)) {
+#ifdef WITH_WSREP
+ /* If a wsrep transaction is being rolled back during
+ the recovery, we must clear the xid in order to avoid
+ writing serialisation history for rolled back transaction. */
+ if (wsrep_is_wsrep_xid(trx->xid)) {
+ trx->xid->null();
+ }
+#endif /* WITH_WSREP */
int ret = innobase_rollback_trx(trx);
trx_deregister_from_2pc(trx);
ut_ad(!trx->will_lock);
@@ -17102,9 +17195,7 @@ fast_shutdown_validate(
uint new_val = *reinterpret_cast<uint*>(save);
if (srv_fast_shutdown && !new_val
- && !my_atomic_loadptr_explicit(reinterpret_cast<void**>
- (&srv_running),
- MY_MEMORY_ORDER_RELAXED)) {
+ && !srv_running.load(std::memory_order_relaxed)) {
return(1);
}
@@ -18498,123 +18589,32 @@ wsrep_innobase_kill_one_trx(
bf_trx ? bf_trx->id : 0);
DBUG_RETURN(1);
}
-
WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
-
+ wsrep_thd_LOCK(thd);
WSREP_DEBUG("BF kill (" ULINTPF ", seqno: " INT64PF
"), victim: (%lu) trx: " TRX_ID_FMT,
signal, bf_seqno,
thd_get_thread_id(thd),
victim_trx->id);
- WSREP_DEBUG("Aborting query: %s conf %d trx: %" PRId64,
+ WSREP_DEBUG("Aborting query: %s conf %s trx: %lld",
(thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void",
- wsrep_thd_conflict_state(thd, FALSE),
- wsrep_thd_ws_handle(thd)->trx_id);
-
- wsrep_thd_LOCK(thd);
- DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
- {
- const char act[]=
- "now "
- "wait_for signal.wsrep_after_BF_victim_lock";
- DBUG_ASSERT(!debug_sync_set_action(bf_thd,
- STRING_WITH_LEN(act)));
- };);
-
-
- if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
- WSREP_DEBUG("kill trx EXITING for " TRX_ID_FMT,
- victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- DBUG_RETURN(0);
- }
-
- if (wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
- WSREP_DEBUG("withdraw for BF trx: " TRX_ID_FMT ", state: %d",
- victim_trx->id,
- wsrep_thd_get_conflict_state(thd));
- }
-
- switch (wsrep_thd_get_conflict_state(thd)) {
- case NO_CONFLICT:
- wsrep_thd_set_conflict_state(thd, MUST_ABORT);
- break;
- case MUST_ABORT:
- WSREP_DEBUG("victim " TRX_ID_FMT " in MUST ABORT state",
- victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- DBUG_RETURN(0);
- break;
- case ABORTED:
- case ABORTING: // fall through
- default:
- WSREP_DEBUG("victim " TRX_ID_FMT " in state %d",
- victim_trx->id, wsrep_thd_get_conflict_state(thd));
- wsrep_thd_UNLOCK(thd);
- DBUG_RETURN(0);
- break;
- }
-
- switch (wsrep_thd_query_state(thd)) {
- case QUERY_COMMITTING:
- enum wsrep_status rcode;
-
- WSREP_DEBUG("kill query for: %ld",
- thd_get_thread_id(thd));
- WSREP_DEBUG("kill trx QUERY_COMMITTING for " TRX_ID_FMT,
- victim_trx->id);
-
- if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- wsrep_abort_slave_trx(bf_seqno,
- wsrep_thd_trx_seqno(thd));
- } else {
- wsrep_t *wsrep= get_wsrep();
- rcode = wsrep->abort_pre_commit(
- wsrep, bf_seqno,
- (wsrep_trx_id_t)wsrep_thd_ws_handle(thd)->trx_id
- );
-
- switch (rcode) {
- case WSREP_WARNING:
- WSREP_DEBUG("cancel commit warning: "
- TRX_ID_FMT,
- victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- DBUG_RETURN(1);
- break;
- case WSREP_OK:
- break;
- default:
- WSREP_ERROR(
- "cancel commit bad exit: %d "
- TRX_ID_FMT,
- rcode, victim_trx->id);
- /* unable to interrupt, must abort */
- /* note: kill_mysql() will block, if we cannot.
- * kill the lock holder first.
- */
- abort();
- break;
- }
- }
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- break;
- case QUERY_EXEC:
- /* it is possible that victim trx is itself waiting for some
- * other lock. We need to cancel this waiting
- */
- WSREP_DEBUG("kill trx QUERY_EXEC for " TRX_ID_FMT,
- victim_trx->id);
-
- victim_trx->lock.was_chosen_as_deadlock_victim= TRUE;
-
+ wsrep_thd_transaction_state_str(thd),
+ wsrep_thd_transaction_id(thd));
+
+ /*
+ * we mark with was_chosen_as_deadlock_victim transaction,
+ * which is already marked as BF victim
+ * lock_sys is held until this vicitm has aborted
+ */
+ victim_trx->lock.was_chosen_as_wsrep_victim = TRUE;
+
+ wsrep_thd_UNLOCK(thd);
+ if (wsrep_thd_bf_abort(bf_thd, thd, signal))
+ {
if (victim_trx->lock.wait_lock) {
- WSREP_DEBUG("victim has wait flag: %ld",
- thd_get_thread_id(thd));
+ WSREP_DEBUG("victim has wait flag: %lu",
+ thd_get_thread_id(thd));
lock_t* wait_lock = victim_trx->lock.wait_lock;
if (wait_lock) {
@@ -18622,67 +18622,7 @@ wsrep_innobase_kill_one_trx(
victim_trx->lock.was_chosen_as_deadlock_victim= TRUE;
lock_cancel_waiting_and_release(wait_lock);
}
-
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- } else {
- /* abort currently executing query */
- DBUG_PRINT("wsrep",("sending KILL_QUERY to: %lu",
- thd_get_thread_id(thd)));
- WSREP_DEBUG("kill query for: %ld",
- thd_get_thread_id(thd));
- /* Note that innobase_kill_query will take lock_mutex
- and trx_mutex */
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
-
- /* for BF thd, we need to prevent him from committing */
- if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- wsrep_abort_slave_trx(bf_seqno,
- wsrep_thd_trx_seqno(thd));
- }
- }
- break;
- case QUERY_IDLE:
- {
- WSREP_DEBUG("kill IDLE for " TRX_ID_FMT, victim_trx->id);
-
- if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- WSREP_DEBUG("kill BF IDLE, seqno: %lld",
- (long long)wsrep_thd_trx_seqno(thd));
- wsrep_thd_UNLOCK(thd);
- wsrep_abort_slave_trx(bf_seqno,
- wsrep_thd_trx_seqno(thd));
- DBUG_RETURN(0);
- }
- /* This will lock thd from proceeding after net_read() */
- wsrep_thd_set_conflict_state(thd, ABORTING);
-
- wsrep_lock_rollback();
-
- if (wsrep_aborting_thd_contains(thd)) {
- WSREP_WARN("duplicate thd aborter %lu",
- (ulong) thd_get_thread_id(thd));
- } else {
- wsrep_aborting_thd_enqueue(thd);
- DBUG_PRINT("wsrep",("enqueuing trx abort for %lu",
- thd_get_thread_id(thd)));
- WSREP_DEBUG("enqueuing trx abort for (%lu)",
- thd_get_thread_id(thd));
}
-
- DBUG_PRINT("wsrep",("signalling wsrep rollbacker"));
- WSREP_DEBUG("signaling aborter");
- wsrep_unlock_rollback();
- wsrep_thd_UNLOCK(thd);
-
- break;
- }
- default:
- WSREP_WARN("bad wsrep query state: %d",
- wsrep_thd_query_state(thd));
- wsrep_thd_UNLOCK(thd);
- break;
}
DBUG_RETURN(0);
@@ -18702,26 +18642,22 @@ wsrep_abort_transaction(
trx_t* victim_trx = thd_to_trx(victim_thd);
trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
- WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %d",
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
wsrep_thd_query(bf_thd),
wsrep_thd_query(victim_thd),
- wsrep_thd_conflict_state(victim_thd, FALSE));
+ wsrep_thd_transaction_state_str(victim_thd));
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
- int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
- victim_trx, signal);
- lock_mutex_exit();
+ int rcode= wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
+ victim_trx, signal);
trx_mutex_exit(victim_trx);
+ lock_mutex_exit();
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
- WSREP_DEBUG("victim does not have transaction");
- wsrep_thd_LOCK(victim_thd);
- wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT);
- wsrep_thd_UNLOCK(victim_thd);
- wsrep_thd_awake(victim_thd, signal);
+ wsrep_thd_bf_abort(bf_thd, victim_thd, signal);
}
DBUG_RETURN(-1);
@@ -18757,15 +18693,6 @@ innobase_wsrep_get_checkpoint(
trx_rseg_read_wsrep_checkpoint(*xid);
return 0;
}
-
-static void wsrep_fake_trx_id(handlerton *, THD *thd)
-{
- trx_id_t trx_id = trx_sys.get_new_trx_id();
- WSREP_DEBUG("innodb fake trx id: " TRX_ID_FMT " thd: %s",
- trx_id, wsrep_thd_query(thd));
- wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
-}
-
#endif /* WITH_WSREP */
/* plugin options */
@@ -21041,7 +20968,7 @@ const char* BUG_REPORT_MSG =
const char* FORCE_RECOVERY_MSG =
"Please refer to "
- "https://mariadb.com/kb/en/library/xtradbinnodb-recovery-modes/"
+ "https://mariadb.com/kb/en/library/innodb-recovery-modes/"
" for information about forcing recovery.";
const char* ERROR_CREATING_MSG =
@@ -21059,7 +20986,7 @@ const char* SET_TRANSACTION_MSG =
"Please refer to https://mariadb.com/kb/en/library/set-transaction/";
const char* INNODB_PARAMETERS_MSG =
- "Please refer to https://mariadb.com/kb/en/library/xtradbinnodb-server-system-variables/";
+ "Please refer to https://mariadb.com/kb/en/library/innodb-system-variables/";
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset.