
[Commits] 2b76f6f: MDEV-16703: Update AUTO_INCREMENT in the UPDATE statement
by psergeyļ¼ askmonty.org 26 Aug '18
by psergeyļ¼ askmonty.org 26 Aug '18
26 Aug '18
revision-id: 2b76f6f61dba93fd920456a0dd9efd366a6dc6b1
parent(s): 2a361ebe1b9c52eadfe811a219a89df6a0d6e3ea
committer: Sergei Petrunia
branch nick: 10.2-r14
timestamp: 2018-08-26 15:10:32 +0300
message:
MDEV-16703: Update AUTO_INCREMENT in the UPDATE statement
Currently RocksDB engine doesn't update AUTO_INCREMENT in the UPDATE statement.
For example,
CREATE TABLE t1 (pk INT AUTO_INCREMENT, a INT, PRIMARY KEY(pk)) ENGINE=RocksDB;
INSERT INTO t1 (a) VALUES (1);
UPDATE t1 SET pk = 3; ==> AUTO_INCREMENT should be updated to 4.
Without this fix, it hits the Assertion `dd_val >= last_val' failed in
myrocks::ha_rocksdb::load_auto_incr_value_from_index.
(cherry picked from commit f7154242b8807fdaa74ed0b89c3de8c35ee35edb)
---
storage/rocksdb/ha_rocksdb.cc | 2 +-
storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result | 8 ++++++++
storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test | 10 ++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc
index c1c3191..adef71e 100644
--- a/storage/rocksdb/ha_rocksdb.cc
+++ b/storage/rocksdb/ha_rocksdb.cc
@@ -9553,7 +9553,7 @@ int ha_rocksdb::update_pk(const Rdb_key_def &kd,
}
}
- if (table->next_number_field) {
+ if (table->found_next_number_field) {
update_auto_incr_val_from_field();
}
diff --git a/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result b/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result
index 8cc9b07..0c49622 100644
--- a/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result
+++ b/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result
@@ -150,3 +150,11 @@ CREATE TABLE t0(c0 BLOB) ENGINE=ROCKSDB;
INSERT INTO t0 VALUES(0);
ALTER TABLE t0 AUTO_INCREMENT=0;
DROP TABLE t0;
+#---------------------------------------------------------------
+# MDEV-16703 Assertion failed in load_auto_incr_value_from_index
+#---------------------------------------------------------------
+CREATE TABLE t1 (pk INT AUTO_INCREMENT, a INT, PRIMARY KEY(pk)) ENGINE=RocksDB;
+INSERT INTO t1 (a) VALUES (1);
+UPDATE t1 SET pk = 3;
+ALTER TABLE t1 AUTO_INCREMENT 2;
+DROP TABLE t1;
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test b/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test
index 9d7f036..86a0a7f 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test
+++ b/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test
@@ -116,3 +116,13 @@ CREATE TABLE t0(c0 BLOB) ENGINE=ROCKSDB;
INSERT INTO t0 VALUES(0);
ALTER TABLE t0 AUTO_INCREMENT=0;
DROP TABLE t0;
+
+--echo #---------------------------------------------------------------
+--echo # MDEV-16703 Assertion failed in load_auto_incr_value_from_index
+--echo #---------------------------------------------------------------
+
+CREATE TABLE t1 (pk INT AUTO_INCREMENT, a INT, PRIMARY KEY(pk)) ENGINE=RocksDB;
+INSERT INTO t1 (a) VALUES (1);
+UPDATE t1 SET pk = 3;
+ALTER TABLE t1 AUTO_INCREMENT 2;
+DROP TABLE t1;
1
0

[Commits] e25114a: Added a new parameter for the function eq_ranges_exceeds_limit()
by IgorBabaev 24 Aug '18
by IgorBabaev 24 Aug '18
24 Aug '18
revision-id: e25114a2270876cb8ad182162add8bc2038333d1 (mariadb-10.3.7-150-ge25114a)
parent(s): 65a56d96a799441abea93fbd201c4c808953576d
author: Igor Babaev
committer: Igor Babaev
timestamp: 2018-08-24 21:15:08 -0700
message:
Added a new parameter for the function eq_ranges_exceeds_limit()
introduced in the patch fo MDEV-16934.
---
sql/multi_range_read.cc | 8 +++++---
sql/opt_range.cc | 12 ++----------
sql/opt_range.h | 3 ++-
3 files changed, 9 insertions(+), 14 deletions(-)
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index be2cb8b..d6952e7 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -65,13 +65,15 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
ha_rows rows, total_rows= 0;
uint n_ranges=0;
THD *thd= table->in_use;
+ uint limit= thd->variables.eq_range_index_dive_limit;
+ bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq,
+ seq_init_param,
+ limit);
+
/* Default MRR implementation doesn't need buffer */
*bufsz= 0;
- bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq,
- seq_init_param);
-
seq_it= seq->init(seq_init_param, n_ranges, *flags);
while (!seq->next(seq_it, &range))
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 2d941ee..0b29fcd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -14647,20 +14647,12 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names,
/* Check whether the number for equality ranges exceeds the set threshold */
-bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param)
+bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint limit)
{
KEY_MULTI_RANGE range;
range_seq_t seq_it;
uint count = 0;
- PARAM *param= ((SEL_ARG_RANGE_SEQ*) seq_init_param)->param;
-#if 0
- uint limit= param->thd->variables.eq_range_index_dive_limit;
-#else
- /* FIXME: multi_range_read_info_const() is not being called with
- seq_init_param as the 3rd parameter, for example in
- ha_partition::multi_range_read_info_const() */
- uint limit= 0;
-#endif
if (limit == 0)
{
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 1628c79..d541698 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -1724,7 +1724,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond);
-bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param);
+bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint limit);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
1
0

[Commits] c826b6b: Added a new parameter for the function eq_ranges_exceeds_limit()
by IgorBabaev 24 Aug '18
by IgorBabaev 24 Aug '18
24 Aug '18
revision-id: c826b6b8da3c9ee89ab457155bae96310213e5a1 (mariadb-10.2.16-104-gc826b6b)
parent(s): 8b949d961ce46479eb10b6ddb5d91eb7d8bc0f73
author: Igor Babaev
committer: Igor Babaev
timestamp: 2018-08-24 20:53:00 -0700
message:
Added a new parameter for the function eq_ranges_exceeds_limit()
introduced in the patch fo MDEV-16934.
---
sql/multi_range_read.cc | 8 +++++---
sql/opt_range.cc | 5 ++---
sql/opt_range.h | 3 ++-
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index 94a96c2..9b6d0e8 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -64,13 +64,15 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
ha_rows rows, total_rows= 0;
uint n_ranges=0;
THD *thd= table->in_use;
+ uint limit= thd->variables.eq_range_index_dive_limit;
+ bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq,
+ seq_init_param,
+ limit);
+
/* Default MRR implementation doesn't need buffer */
*bufsz= 0;
- bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq,
- seq_init_param);
-
seq_it= seq->init(seq_init_param, n_ranges, *flags);
while (!seq->next(seq_it, &range))
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 47e0701..2c015c1 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -14619,13 +14619,12 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names,
/* Check whether the number for equality ranges exceeds the set threshold */
-bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param)
+bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint limit)
{
KEY_MULTI_RANGE range;
range_seq_t seq_it;
uint count = 0;
- PARAM *param= ((SEL_ARG_RANGE_SEQ*) seq_init_param)->param;
- uint limit= param->thd->variables.eq_range_index_dive_limit;
if (limit == 0)
{
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 6698c98..9e0bd3a 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -1664,7 +1664,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond);
-bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param);
+bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint limit);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
1
0

[Commits] 80a169e2e63: MDEV-16803: Pushdown Item_func_in item that uses vectors in several SELECTs
by Galina 24 Aug '18
by Galina 24 Aug '18
24 Aug '18
revision-id: 80a169e2e63ea709e5232ff2461582cbf02cd29d (mariadb-10.2.16-104-g80a169e2e63)
parent(s): 8b949d961ce46479eb10b6ddb5d91eb7d8bc0f73
author: Galina Shalygina
committer: Galina Shalygina
timestamp: 2018-08-24 15:51:05 +0200
message:
MDEV-16803: Pushdown Item_func_in item that uses vectors in several SELECTs
The bug appears because of the Item_func_in::build_clone() method.
The 'array' field for the Item_func_in item that can be pushed into
the materialized view/derived table was built in the wrong way.
It becomes lame after the pushdown of the condition into the first
SELECT that defines that view/derived table. The server crashes in
the pushdown into the next SELECT while trying to use already lame
'array' field.
To fix it Item_func_in::build_clone() was changed.
---
mysql-test/r/derived_cond_pushdown.result | 21 +++++++++++++++++++++
mysql-test/t/derived_cond_pushdown.test | 20 ++++++++++++++++++++
sql/item_cmpfunc.cc | 3 +--
3 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result
index fd930d13547..9ef3488e06d 100644
--- a/mysql-test/r/derived_cond_pushdown.result
+++ b/mysql-test/r/derived_cond_pushdown.result
@@ -10220,3 +10220,24 @@ EXPLAIN
}
}
DROP TABLE t1;
+#
+# MDEV-16803: pushdown condition with IN predicate in the derived table
+# defined with several SELECT statements
+#
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2),(3,2),(1,1);
+SELECT * FROM
+(
+SELECT a,b,1 as c
+FROM t1
+UNION ALL
+SELECT a,b,2 as c
+FROM t1
+) AS tab
+WHERE ((a,b) IN ((1,2),(3,2)));
+a b c
+1 2 1
+3 2 1
+1 2 2
+3 2 2
+DROP TABLE t1;
diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test
index b8e74a2d5aa..23109662c6d 100644
--- a/mysql-test/t/derived_cond_pushdown.test
+++ b/mysql-test/t/derived_cond_pushdown.test
@@ -2022,3 +2022,23 @@ EVAL $query;
EVAL EXPLAIN FORMAT=JSON $query;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-16803: pushdown condition with IN predicate in the derived table
+--echo # defined with several SELECT statements
+--echo #
+
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2),(3,2),(1,1);
+
+SELECT * FROM
+(
+ SELECT a,b,1 as c
+ FROM t1
+ UNION ALL
+ SELECT a,b,2 as c
+ FROM t1
+) AS tab
+WHERE ((a,b) IN ((1,2),(3,2)));
+
+DROP TABLE t1;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 577a98df0d2..69ebeb2b95c 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4436,9 +4436,8 @@ Item *Item_func_in::build_clone(THD *thd, MEM_ROOT *mem_root)
Item_func_in *clone= (Item_func_in *) Item_func::build_clone(thd, mem_root);
if (clone)
{
- if (array && clone->create_array(thd))
- return NULL;
bzero(&clone->cmp_items, sizeof(cmp_items));
+ clone->fix_length_and_dec();
}
return clone;
}
1
0

[Commits] 700232cdd5f: Renamed the objects created for the system variable 'in_predicate_conversion_threshold'
by Galina 24 Aug '18
by Galina 24 Aug '18
24 Aug '18
revision-id: 700232cdd5f7c7d2254644b33b93fa0c15f1e2f7 (mariadb-10.3.7-147-g700232cdd5f)
parent(s): 9c5a0380019ba16016708b4eb9031818830f8fb9
author: Galina Shalygina
committer: Galina Shalygina
timestamp: 2018-08-24 15:41:02 +0200
message:
Renamed the objects created for the system variable 'in_predicate_conversion_threshold'
---
sql/mysqld.cc | 2 +-
sql/sql_class.h | 2 +-
sql/sql_priv.h | 2 +-
sql/sql_tvc.cc | 2 +-
sql/sys_vars.cc | 6 +++---
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1a3ff53be6f..9e36b919c62 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4751,7 +4751,7 @@ static int init_common_variables()
return 1;
}
- global_system_variables.in_subquery_conversion_threshold= IN_SUBQUERY_CONVERSION_THRESHOLD;
+ global_system_variables.in_predicate_conversion_threshold= IN_PREDICATE_CONVERSION_THRESHOLD;
return 0;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index faae443e7a0..52115124cd9 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -725,7 +725,7 @@ typedef struct system_variables
uint idle_write_transaction_timeout;
uint column_compression_threshold;
uint column_compression_zlib_level;
- uint in_subquery_conversion_threshold;
+ uint in_predicate_conversion_threshold;
vers_asof_timestamp_t vers_asof_timestamp;
ulong vers_alter_history;
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index e48b6195bb7..ba7a68e57ec 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -327,7 +327,7 @@
/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
#define UNDEF_POS (-1)
-#define IN_SUBQUERY_CONVERSION_THRESHOLD 1000
+#define IN_PREDICATE_CONVERSION_THRESHOLD 1000
#endif /* !MYSQL_CLIENT */
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 188ba8c4629..6ec9e7e9238 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -791,7 +791,7 @@ bool Item_func_in::to_be_transformed_into_in_subq(THD *thd)
if (args[1]->type() == Item::ROW_ITEM)
values_count*= ((Item_row *)(args[1]))->cols();
- if (values_count < thd->variables.in_subquery_conversion_threshold)
+ if (values_count < thd->variables.in_predicate_conversion_threshold)
return false;
return true;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 8858259c863..37848f27b90 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -6071,12 +6071,12 @@ static Sys_var_mybool Sys_session_track_state_change(
#endif //EMBEDDED_LIBRARY
#ifndef DBUG_OFF
-static Sys_var_uint Sys_in_subquery_conversion_threshold(
+static Sys_var_uint Sys_in_predicate_conversion_threshold(
"in_predicate_conversion_threshold",
"The minimum number of scalar elements in the value list of "
"IN predicate that triggers its conversion to IN subquery",
- SESSION_VAR(in_subquery_conversion_threshold), CMD_LINE(OPT_ARG),
- VALID_RANGE(0, UINT_MAX), DEFAULT(IN_SUBQUERY_CONVERSION_THRESHOLD), BLOCK_SIZE(1));
+ SESSION_VAR(in_predicate_conversion_threshold), CMD_LINE(OPT_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(IN_PREDICATE_CONVERSION_THRESHOLD), BLOCK_SIZE(1));
#endif
static Sys_var_enum Sys_secure_timestamp(
1
0
revision-id: 6c6ca907ee84e3f129bc33be8202c0fee2f29196 (mariadb-10.3.7-144-g6c6ca90)
parent(s): 2c76653849c1729bedc213b233089bf361c82e12
author: Igor Babaev
committer: Igor Babaev
timestamp: 2018-08-24 00:51:47 -0700
message:
Correction for MDEV-16930.
---
sql/sql_yacc.yy | 4 ++--
sql/sql_yacc_ora.yy | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1ec7317..7ed4498 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -13345,7 +13345,7 @@ values_with_names:
if (unlikely(Lex->insert_list->push_back($4, thd->mem_root)))
MYSQL_YYABORT;
// give some name in case of using in table value constuctor (TVC)
- if (!$4->name.str)
+ if (!$4->name.str || $4->name.str == item_empty_name)
$4->set_name(thd, $3, (uint) ($5 - $3), thd->charset());
}
| remember_name expr_or_default remember_end
@@ -13353,7 +13353,7 @@ values_with_names:
if (unlikely(Lex->insert_list->push_back($2, thd->mem_root)))
MYSQL_YYABORT;
// give some name in case of using in table value constuctor (TVC)
- if (!$2->name.str)
+ if (!$2->name.str || $2->name.str == item_empty_name)
$2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
}
;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index a644618..8f98cfa 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -13500,7 +13500,7 @@ values_with_names:
if (unlikely(Lex->insert_list->push_back($4, thd->mem_root)))
MYSQL_YYABORT;
// give some name in case of using in table value constuctor (TVC)
- if (!$4->name.str)
+ if (!$4->name.str || $4->name.str == item_empty_name)
$4->set_name(thd, $3, (uint) ($5 - $3), thd->charset());
}
| remember_name expr_or_default remember_end
@@ -13508,7 +13508,7 @@ values_with_names:
if (unlikely(Lex->insert_list->push_back($2, thd->mem_root)))
MYSQL_YYABORT;
// give some name in case of using in table value constuctor (TVC)
- if (!$2->name.str)
+ if (!$2->name.str || $2->name.str == item_empty_name)
$2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
}
;
1
0

[Commits] 2c76653: Added test cases for MDEV-17017 and MDEV-16930 into compat/oracle
by IgorBabaev 23 Aug '18
by IgorBabaev 23 Aug '18
23 Aug '18
revision-id: 2c76653849c1729bedc213b233089bf361c82e12 (mariadb-10.3.7-143-g2c76653)
parent(s): b4cf8557e3821ff3220a5ec62ff937a1f96793e9
author: Igor Babaev
committer: Igor Babaev
timestamp: 2018-08-23 17:43:54 -0700
message:
Added test cases for MDEV-17017 and MDEV-16930 into compat/oracle
---
.../compat/oracle/r/table_value_constr.result | 84 ++++++++++++++++++++++
.../suite/compat/oracle/t/table_value_constr.test | 44 ++++++++++++
2 files changed, 128 insertions(+)
diff --git a/mysql-test/suite/compat/oracle/r/table_value_constr.result b/mysql-test/suite/compat/oracle/r/table_value_constr.result
index 31dcecf..18fce08 100644
--- a/mysql-test/suite/compat/oracle/r/table_value_constr.result
+++ b/mysql-test/suite/compat/oracle/r/table_value_constr.result
@@ -2099,3 +2099,87 @@ v
#
with t as (values (),()) select 1 from t;
ERROR HY000: Row with no elements is not allowed in table value constructor in this context
+#
+# MDEV-17017: TVC in derived table
+#
+create table t1 (a int);
+insert into t1 values (9), (3), (2);
+select * from (values (7), (5), (8), (1), (3), (8), (1)) t;
+7
+7
+5
+8
+1
+3
+8
+1
+explain select * from (values (7), (5), (8), (1), (3), (8), (1)) t;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 7
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
+select * from (values (1,11), (7,77), (3,31), (4,42)) t;
+1 11
+1 11
+7 77
+3 31
+4 42
+explain select * from (values (1,11), (7,77), (3,31), (4,42)) t;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
+select * from (values (7), (5), (8), (1) union values (3), (8), (1)) t;
+7
+7
+5
+8
+1
+3
+explain select * from (values (7), (5), (8), (1) union values (3), (8), (1)) t;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 7
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
+3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
+select * from (values (7), (5), (8), (1) union select * from t1) t;
+7
+7
+5
+8
+1
+9
+3
+2
+explain select * from (values (7), (5), (8), (1) union select * from t1) t;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 7
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
+3 UNION t1 ALL NULL NULL NULL NULL 3
+NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
+drop table t1;
+#
+# MDEV-16930: expression in the first row of TVC specifying derived table
+#
+SELECT 1 + 1, 2, 'abc';
+1 + 1 2 abc
+2 2 abc
+SELECT * FROM (SELECT 1 + 1, 2, 'abc') t;
+1 + 1 2 abc
+2 2 abc
+WITH cte AS (SELECT 1 + 1, 2, 'abc') SELECT * FROM cte;
+1 + 1 2 abc
+2 2 abc
+SELECT 1 + 1, 2, 'abc' UNION SELECT 3+4, 3, 'abc';
+1 + 1 2 abc
+2 2 abc
+7 3 abc
+CREATE VIEW v1 AS SELECT 1 + 1, 2, 'abc';
+SELECT * FROM v1;
+1 + 1 2 abc
+2 2 abc
+DROP VIEW v1;
+VALUES(1 + 1,2,'abc');
+1 + 1 2 abc
+2 2 abc
+SELECT * FROM (VALUES(1 + 1,2,'abc')) t;
+1 + 1 2 abc
+2 2 abc
diff --git a/mysql-test/suite/compat/oracle/t/table_value_constr.test b/mysql-test/suite/compat/oracle/t/table_value_constr.test
index 66519e9..37d2521 100644
--- a/mysql-test/suite/compat/oracle/t/table_value_constr.test
+++ b/mysql-test/suite/compat/oracle/t/table_value_constr.test
@@ -1081,3 +1081,47 @@ DELIMITER ;|
--error ER_EMPTY_ROW_IN_TVC
with t as (values (),()) select 1 from t;
+
+--echo #
+--echo # MDEV-17017: TVC in derived table
+--echo #
+
+create table t1 (a int);
+insert into t1 values (9), (3), (2);
+
+let $q1=
+select * from (values (7), (5), (8), (1), (3), (8), (1)) t;
+eval $q1;
+eval explain $q1;
+
+let $q2=
+select * from (values (1,11), (7,77), (3,31), (4,42)) t;
+eval $q2;
+eval explain $q2;
+
+let $q3=
+select * from (values (7), (5), (8), (1) union values (3), (8), (1)) t;
+eval $q3;
+eval explain $q3;
+
+let $q4=
+select * from (values (7), (5), (8), (1) union select * from t1) t;
+eval $q4;
+eval explain $q4;
+
+drop table t1;
+
+--echo #
+--echo # MDEV-16930: expression in the first row of TVC specifying derived table
+--echo #
+
+SELECT 1 + 1, 2, 'abc';
+SELECT * FROM (SELECT 1 + 1, 2, 'abc') t;
+WITH cte AS (SELECT 1 + 1, 2, 'abc') SELECT * FROM cte;
+SELECT 1 + 1, 2, 'abc' UNION SELECT 3+4, 3, 'abc';
+CREATE VIEW v1 AS SELECT 1 + 1, 2, 'abc';
+SELECT * FROM v1;
+DROP VIEW v1;
+
+VALUES(1 + 1,2,'abc');
+SELECT * FROM (VALUES(1 + 1,2,'abc')) t;
1
0

[Commits] b4cf855: Corrected test results after the last change in range.test
by IgorBabaev 23 Aug '18
by IgorBabaev 23 Aug '18
23 Aug '18
revision-id: b4cf8557e3821ff3220a5ec62ff937a1f96793e9 (mariadb-10.3.7-142-gb4cf855)
parent(s): 6b9dd66f0770077b2573de5d16671e7463f8c5d5
author: Igor Babaev
committer: Igor Babaev
timestamp: 2018-08-23 14:39:38 -0700
message:
Corrected test results after the last change in range.test
---
mysql-test/main/range_mrr_icp.result | 24 ------------------------
1 file changed, 24 deletions(-)
diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result
index 483957f..9ce6f8b 100644
--- a/mysql-test/main/range_mrr_icp.result
+++ b/mysql-test/main/range_mrr_icp.result
@@ -1050,30 +1050,6 @@ select a, hex(filler) from t1 where a not between 'b' and 'b';
a hex(filler)
a 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
drop table t1,t2,t3;
-create table t1 (a int);
-insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
-create table t2 (a int, key(a));
-insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C;
-set in_predicate_conversion_threshold= 2000;
-set @a="select * from t2 force index (a) where a NOT IN(0";
-select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z;
-count(*)
-1000
-set @a=concat(@a, ')');
-insert into t2 values (11),(13),(15);
-set @b= concat("explain ", @a);
-prepare stmt1 from @b;
-execute stmt1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 index a a 5 NULL 1003 Using where; Using index
-prepare stmt1 from @a;
-execute stmt1;
-a
-11
-13
-15
-set in_predicate_conversion_threshold= default;
-drop table t1, t2;
CREATE TABLE t1 (
id int NOT NULL DEFAULT '0',
b int NOT NULL DEFAULT '0',
1
0

[Commits] 6b9dd66: Move the testcase for BUG#21282 to a file that includes have_debug.inc
by psergeyļ¼ askmonty.org 23 Aug '18
by psergeyļ¼ askmonty.org 23 Aug '18
23 Aug '18
revision-id: 6b9dd66f0770077b2573de5d16671e7463f8c5d5
parent(s): c43d11b96e27f25d248f4740a2274f1bfb1d5845
committer: Sergei Petrunia
branch nick: 10.3-r3
timestamp: 2018-08-23 19:30:26 +0300
message:
Move the testcase for BUG#21282 to a file that includes have_debug.inc
The testcase needs to set in_predicate_conversion_threshold which
is only available in debug builds (this is subject to further discussion).
---
mysql-test/main/range.result | 24 ------------------------
mysql-test/main/range.test | 28 ----------------------------
mysql-test/main/range_debug.result | 24 ++++++++++++++++++++++++
mysql-test/main/range_debug.test | 30 ++++++++++++++++++++++++++++++
4 files changed, 54 insertions(+), 52 deletions(-)
diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result
index cbf9d5b..052ea09 100644
--- a/mysql-test/main/range.result
+++ b/mysql-test/main/range.result
@@ -1048,30 +1048,6 @@ select a, hex(filler) from t1 where a not between 'b' and 'b';
a hex(filler)
a 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
drop table t1,t2,t3;
-create table t1 (a int);
-insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
-create table t2 (a int, key(a));
-insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C;
-set in_predicate_conversion_threshold= 2000;
-set @a="select * from t2 force index (a) where a NOT IN(0";
-select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z;
-count(*)
-1000
-set @a=concat(@a, ')');
-insert into t2 values (11),(13),(15);
-set @b= concat("explain ", @a);
-prepare stmt1 from @b;
-execute stmt1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 index a a 5 NULL 1003 Using where; Using index
-prepare stmt1 from @a;
-execute stmt1;
-a
-11
-13
-15
-set in_predicate_conversion_threshold= default;
-drop table t1, t2;
CREATE TABLE t1 (
id int NOT NULL DEFAULT '0',
b int NOT NULL DEFAULT '0',
diff --git a/mysql-test/main/range.test b/mysql-test/main/range.test
index 43b5b18..7006f15 100644
--- a/mysql-test/main/range.test
+++ b/mysql-test/main/range.test
@@ -863,34 +863,6 @@ select a, hex(filler) from t1 where a not between 'b' and 'b';
drop table t1,t2,t3;
#
-# BUG#21282
-#
-create table t1 (a int);
-insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
-create table t2 (a int, key(a));
-insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C;
-
-set in_predicate_conversion_threshold= 2000;
-
-set @a="select * from t2 force index (a) where a NOT IN(0";
-select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z;
-set @a=concat(@a, ')');
-
-insert into t2 values (11),(13),(15);
-
-set @b= concat("explain ", @a);
-
-prepare stmt1 from @b;
-execute stmt1;
-
-prepare stmt1 from @a;
-execute stmt1;
-
-set in_predicate_conversion_threshold= default;
-
-drop table t1, t2;
-
-#
# Bug #18165: range access for BETWEEN with a constant for the first argument
#
diff --git a/mysql-test/main/range_debug.result b/mysql-test/main/range_debug.result
new file mode 100644
index 0000000..5597671
--- /dev/null
+++ b/mysql-test/main/range_debug.result
@@ -0,0 +1,24 @@
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, key(a));
+insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C;
+set in_predicate_conversion_threshold= 2000;
+set @a="select * from t2 force index (a) where a NOT IN(0";
+select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z;
+count(*)
+1000
+set @a=concat(@a, ')');
+insert into t2 values (11),(13),(15);
+set @b= concat("explain ", @a);
+prepare stmt1 from @b;
+execute stmt1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index a a 5 NULL 1003 Using where; Using index
+prepare stmt1 from @a;
+execute stmt1;
+a
+11
+13
+15
+set in_predicate_conversion_threshold= default;
+drop table t1, t2;
diff --git a/mysql-test/main/range_debug.test b/mysql-test/main/range_debug.test
new file mode 100644
index 0000000..ef331cd
--- /dev/null
+++ b/mysql-test/main/range_debug.test
@@ -0,0 +1,30 @@
+source include/have_debug.inc;
+#
+# BUG#21282
+#
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, key(a));
+insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C;
+
+set in_predicate_conversion_threshold= 2000;
+
+set @a="select * from t2 force index (a) where a NOT IN(0";
+select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z;
+set @a=concat(@a, ')');
+
+insert into t2 values (11),(13),(15);
+
+set @b= concat("explain ", @a);
+
+prepare stmt1 from @b;
+execute stmt1;
+
+prepare stmt1 from @a;
+execute stmt1;
+
+set in_predicate_conversion_threshold= default;
+
+drop table t1, t2;
+
+
1
0

[Commits] e4ec889c21e: Merge remote-tracking branch 'wsrep/10.3_wsrep_api-26' into 10.4
by jan 23 Aug '18
by jan 23 Aug '18
23 Aug '18
revision-id: e4ec889c21ef24fbdfef3d0a36828807241877da (mariadb-10.3.6-101-ge4ec889c21e)
parent(s): d6d63f4844bf87adb6250d1b1d43e86feab9a5d0 420cfe4efe72674d4291c0d5a46205ab70b6b91c
author: Jan Lindstrƶm
committer: Jan Lindstrƶm
timestamp: 2018-08-23 17:14:13 +0300
message:
Merge remote-tracking branch 'wsrep/10.3_wsrep_api-26' into 10.4
Conflicts:
mysql-test/include/check-testcase.test
mysql-test/include/wait_until_connected_again.inc
mysql-test/suite/galera/disabled.def
mysql-test/suite/galera/r/MW-416.result
mysql-test/suite/galera/r/galera#500.result
mysql-test/suite/galera/r/galera_var_dirty_reads.result
mysql-test/suite/galera/t/MW-416.test
mysql-test/suite/galera/t/galera#500.test
sql/handler.cc
sql/item_strfunc.cc
sql/item_strfunc.h
sql/slave.cc
sql/sql_class.cc
sql/sql_class.h
sql/sql_connect.cc
sql/sql_insert.cc
sql/sql_parse.cc
sql/sql_plugin.cc
sql/sql_prepare.cc
sql/wsrep_applier.cc
sql/wsrep_mysqld.cc
sql/wsrep_mysqld.h
sql/wsrep_sst.cc
sql/wsrep_thd.cc
storage/innobase/handler/ha_innodb.cc
CMakeLists.txt | 9 +-
cmake/wsrep.cmake | 2 +-
include/mysql/service_wsrep.h | 59 +-
include/wsrep.h | 5 +
mysql-test/include/galera_cluster.inc | 6 +
.../galera => }/include/galera_have_debug_sync.inc | 0
mysql-test/include/galera_wait_sync_point.inc | 11 +
mysql-test/include/have_ipv6.inc | 20 +
mysql-test/include/kill_galera.inc | 20 +
mysql-test/include/mtr_warnings.sql | 46 +
mysql-test/include/restart_mysqld.inc | 1 -
mysql-test/include/wait_wsrep_ready.inc | 13 +
mysql-test/include/wsrep_wait_disconnect.inc | 20 +
mysql-test/lib/My/ConfigFactory.pm | 6 +-
mysql-test/main/mysqld--help-notwin.result | 1472 ++++++++++++++
.../main/query_cache_size_functionality.result | 226 +++
.../main/query_cache_type_functionality.result | 250 +++
mysql-test/mysql-test-run.pl | 124 ++
mysql-test/suite/galera/disabled.def | 2 +-
mysql-test/suite/galera/galera_2nodes.cnf | 25 +-
.../suite/galera/galera_2nodes_as_master.cnf | 12 +
mysql-test/suite/galera/galera_2nodes_as_slave.cnf | 47 +-
mysql-test/suite/galera/galera_3nodes_as_slave.cnf | 59 +-
mysql-test/suite/galera/galera_4nodes.cnf | 15 +
.../suite/galera/include/galera_load_provider.inc | 68 +
mysql-test/suite/galera/include/galera_resume.inc | 2 +-
.../suite/galera/include/galera_sst_restore.inc | 2 +-
.../suite/galera/include/galera_st_clean_slave.inc | 1 +
.../galera/include/galera_st_disconnect_slave.inc | 8 +
.../galera/include/galera_unload_provider.inc | 8 +
mysql-test/suite/galera/r/GAL-382.result | 2 +
mysql-test/suite/galera/r/GAL-401.result | 2 +
mysql-test/suite/galera/r/GCF-1081.result | 47 +
mysql-test/suite/galera/r/GCF-939.result | 12 +
mysql-test/suite/galera/r/MDEV-15443.result | 2 +
mysql-test/suite/galera/r/MW-252.result | 2 +
mysql-test/suite/galera/r/MW-258.result | 2 +
mysql-test/suite/galera/r/MW-259.result | 2 +
mysql-test/suite/galera/r/MW-284.result | 4 +
mysql-test/suite/galera/r/MW-285.result | 2 +
mysql-test/suite/galera/r/MW-292.result | 27 +-
mysql-test/suite/galera/r/MW-309.result | 2 +
mysql-test/suite/galera/r/MW-313.result | 2 +
mysql-test/suite/galera/r/MW-328A.result | 18 +-
mysql-test/suite/galera/r/MW-328B.result | 2 +
mysql-test/suite/galera/r/MW-328C.result | 2 +
mysql-test/suite/galera/r/MW-328D.result | 2 +
mysql-test/suite/galera/r/MW-328E.result | 2 +
mysql-test/suite/galera/r/MW-329.result | 9 +-
mysql-test/suite/galera/r/MW-336.result | 2 +
mysql-test/suite/galera/r/MW-357.result | 2 +
mysql-test/suite/galera/r/MW-360.result | 41 +
mysql-test/suite/galera/r/MW-369.result | 65 +-
mysql-test/suite/galera/r/MW-388.result | 4 +-
mysql-test/suite/galera/r/MW-402.result | 76 +-
mysql-test/suite/galera/r/MW-416.result | 20 +-
mysql-test/suite/galera/r/MW-86-wait1.result | 17 +-
mysql-test/suite/galera/r/MW-86-wait8.result | 16 +-
mysql-test/suite/galera/r/MW-86.result | 78 +
mysql-test/suite/galera/r/basic.result | 2 +
mysql-test/suite/galera/r/binlog_checksum.result | 2 +
mysql-test/suite/galera/r/create.result | 2 +
.../suite/galera/r/enforce_storage_engine.result | 2 +
.../suite/galera/r/enforce_storage_engine2.result | 2 +
mysql-test/suite/galera/r/ev51914.result | 2 +
mysql-test/suite/galera/r/fk.result | 2 +
mysql-test/suite/galera/r/galera#414.result | 2 +
mysql-test/suite/galera/r/galera#500.result | 6 +
mysql-test/suite/galera/r/galera_admin.result | 2 +
.../galera/r/galera_alter_engine_innodb.result | 2 +
.../galera/r/galera_alter_engine_myisam.result | 2 +
.../suite/galera/r/galera_alter_table_force.result | 2 +
.../galera/r/galera_applier_ftwrl_table.result | 2 +
.../r/galera_applier_ftwrl_table_alter.result | 2 +
mysql-test/suite/galera/r/galera_as_master.result | 4 +
.../suite/galera/r/galera_as_master_gtid.result | 44 +-
.../suite/galera/r/galera_as_master_large.result | 2 +
.../suite/galera/r/galera_as_slave_autoinc.result | 4 +
.../suite/galera/r/galera_as_slave_gtid.result | 2 +
.../r/galera_as_slave_gtid_replicate_do_db.result | 160 ++
.../galera_as_slave_gtid_replicate_do_db_cc.result | 315 +++
.../suite/galera/r/galera_as_slave_nonprim.result | 18 +
.../galera/r/galera_autoinc_sst_xtrabackup.result | 2 +
mysql-test/suite/galera/r/galera_bf_abort.result | 4 +-
.../r/galera_bf_abort_flush_for_export.result | 2 +
.../galera/r/galera_bf_abort_for_update.result | 6 +-
.../suite/galera/r/galera_bf_abort_ftwrl.result | 2 +
.../suite/galera/r/galera_bf_abort_get_lock.result | 4 +-
.../galera/r/galera_bf_abort_group_commit.result | 685 +++++++
.../galera/r/galera_bf_abort_lock_table.result | 2 +
.../suite/galera/r/galera_bf_abort_shutdown.result | 9 +
.../suite/galera/r/galera_bf_abort_sleep.result | 4 +-
.../suite/galera/r/galera_bf_lock_wait.result | 2 +
.../suite/galera/r/galera_binlog_cache_size.result | 2 +
.../suite/galera/r/galera_binlog_checksum.result | 2 +
.../r/galera_binlog_event_max_size_max.result | 2 +
.../r/galera_binlog_event_max_size_min.result | 2 +
.../suite/galera/r/galera_binlog_row_image.result | 2 +
.../suite/galera/r/galera_create_function.result | 2 +
.../suite/galera/r/galera_create_procedure.result | 2 +
.../galera/r/galera_create_table_as_select.result | 103 +
.../suite/galera/r/galera_create_table_like.result | 2 +
.../suite/galera/r/galera_create_trigger.result | 2 +
.../suite/galera/r/galera_ddl_multiline.result | 2 +
mysql-test/suite/galera/r/galera_defaults.result | 25 +-
.../suite/galera/r/galera_delete_limit.result | 2 +
.../suite/galera/r/galera_desync_overlapped.result | 2 +
mysql-test/suite/galera/r/galera_drop_multi.result | 2 +
mysql-test/suite/galera/r/galera_enum.result | 4 +-
mysql-test/suite/galera/r/galera_events.result | 2 +
.../suite/galera/r/galera_fk_cascade_delete.result | 2 +
.../suite/galera/r/galera_fk_cascade_update.result | 2 +
.../suite/galera/r/galera_fk_conflict.result | 4 +-
.../suite/galera/r/galera_fk_mismatch.result | 2 +
.../suite/galera/r/galera_fk_multicolumn.result | 2 +
.../suite/galera/r/galera_fk_multitable.result | 2 +
mysql-test/suite/galera/r/galera_fk_no_pk.result | 2 +
.../galera/r/galera_fk_selfreferential.result | 2 +
mysql-test/suite/galera/r/galera_fk_setnull.result | 2 +
.../suite/galera/r/galera_flush_local.result | 2 +
.../galera/r/galera_forced_binlog_format.result | 20 +-
mysql-test/suite/galera/r/galera_ftwrl.result | 2 +
.../suite/galera/r/galera_ftwrl_drain.result | 2 +
mysql-test/suite/galera/r/galera_fulltext.result | 2 +
.../r/galera_gcache_recover_full_gcache.result | 2 +-
.../suite/galera/r/galera_gcs_fc_limit.result | 2 +
.../galera/r/galera_gcs_max_packet_size.result | 2 +
mysql-test/suite/galera/r/galera_gra_log.result | 2 +
mysql-test/suite/galera/r/galera_gtid.result | 2 +
mysql-test/suite/galera/r/galera_gtid_slave.result | 11 +-
.../galera/r/galera_gtid_slave_sst_rsync.result | 106 +-
.../suite/galera/r/galera_insert_ignore.result | 2 +
.../suite/galera/r/galera_insert_multi.result | 4 +-
.../galera/r/galera_ist_innodb_flush_logs.result | 24 +-
.../suite/galera/r/galera_ist_progress.result | 5 +
.../suite/galera/r/galera_ist_recv_bind.result | 2 +
.../galera/r/galera_ist_restart_joiner.result | 3 +-
mysql-test/suite/galera/r/galera_ist_rsync.result | 2 +
.../suite/galera/r/galera_ist_xtrabackup-v2.result | 40 +-
mysql-test/suite/galera/r/galera_kill_ddl.result | 2 +
.../suite/galera/r/galera_kill_largechanges.result | 2 +
.../suite/galera/r/galera_kill_smallchanges.result | 2 +
mysql-test/suite/galera/r/galera_lock_table.result | 2 +
mysql-test/suite/galera/r/galera_log_bin.result | 4 +
.../suite/galera/r/galera_log_output_csv.result | 2 +
.../suite/galera/r/galera_many_columns.result | 4 +-
.../suite/galera/r/galera_many_indexes.result | 4 +-
mysql-test/suite/galera/r/galera_many_rows.result | 4 +-
.../suite/galera/r/galera_many_tables_nopk.result | 4 +-
.../suite/galera/r/galera_many_tables_pk.result | 4 +-
mysql-test/suite/galera/r/galera_mdev_10812.result | 2 +
mysql-test/suite/galera/r/galera_mdev_13787.result | 2 +
mysql-test/suite/galera/r/galera_mdl_race.result | 4 +-
.../suite/galera/r/galera_multi_database.result | 2 +
.../suite/galera/r/galera_myisam_autocommit.result | 2 +
.../galera/r/galera_myisam_transactions.result | 2 +
mysql-test/suite/galera/r/galera_nopk_bit.result | 4 +-
mysql-test/suite/galera/r/galera_nopk_blob.result | 4 +-
.../galera/r/galera_nopk_large_varchar.result | 4 +-
.../suite/galera/r/galera_nopk_unicode.result | 4 +-
.../r/galera_parallel_apply_lock_table.result | 6 +-
.../r/galera_parallel_autoinc_largetrx.result | 4 +-
.../r/galera_parallel_autoinc_manytrx.result | 2 +
.../suite/galera/r/galera_parallel_simple.result | 2 +
.../suite/galera/r/galera_pk_bigint_signed.result | 4 +-
.../galera/r/galera_pk_bigint_unsigned.result | 4 +-
.../galera/r/galera_prepared_statement.result | 2 +
.../suite/galera/r/galera_query_cache.result | 2 +
.../galera/r/galera_query_cache_sync_wait.result | 2 +
mysql-test/suite/galera/r/galera_read_only.result | 2 +
.../galera/r/galera_repl_key_format_flat16.result | 2 +
.../suite/galera/r/galera_repl_max_ws_size.result | 4 +-
.../suite/galera/r/galera_restart_nochanges.result | 2 +
.../r/galera_restart_on_unknown_option.result | 2 +
mysql-test/suite/galera/r/galera_rsu_add_pk.result | 2 +
.../suite/galera/r/galera_rsu_drop_pk.result | 2 +
mysql-test/suite/galera/r/galera_rsu_error.result | 2 +
mysql-test/suite/galera/r/galera_rsu_simple.result | 2 +
.../suite/galera/r/galera_rsu_wsrep_desync.result | 2 +
mysql-test/suite/galera/r/galera_sbr.result | 2 +
mysql-test/suite/galera/r/galera_sbr_binlog.result | 2 +
.../galera/r/galera_schema_dirty_reads.result | 2 +
.../suite/galera/r/galera_serializable.result | 8 +-
mysql-test/suite/galera/r/galera_server.result | 2 +
.../suite/galera/r/galera_sql_log_bin_zero.result | 2 +
mysql-test/suite/galera/r/galera_ssl.result | 2 +
.../suite/galera/r/galera_ssl_compression.result | 2 +
.../suite/galera/r/galera_sst_mysqldump.result | 114 ++
mysql-test/suite/galera/r/galera_sst_rsync.result | 2 +-
.../suite/galera/r/galera_sst_xtrabackup-v2.result | 110 ++
...alera_sst_xtrabackup-v2_encrypt_with_key.result | 2 +
.../suite/galera/r/galera_status_cluster.result | 2 +
.../galera/r/galera_status_local_index.result | 2 +
.../galera/r/galera_status_local_state.result | 2 +
.../suite/galera/r/galera_suspend_slave.result | 2 +
.../suite/galera/r/galera_sync_wait_show.result | 2 +
.../r/galera_toi_alter_auto_increment.result | 2 +
.../suite/galera/r/galera_toi_ddl_error.result | 5 +
.../suite/galera/r/galera_toi_ddl_fk_update.result | 2 +
.../suite/galera/r/galera_toi_ddl_locking.result | 32 +-
.../galera/r/galera_toi_ddl_nonconflicting.result | 2 +
.../galera/r/galera_toi_ddl_sequential.result | 2 +
.../suite/galera/r/galera_toi_drop_database.result | 6 +-
mysql-test/suite/galera/r/galera_toi_ftwrl.result | 2 +
.../galera/r/galera_toi_lock_exclusive.result | 4 +-
.../suite/galera/r/galera_toi_lock_shared.result | 2 +
.../suite/galera/r/galera_toi_truncate.result | 4 +-
.../galera/r/galera_transaction_read_only.result | 2 +
.../galera/r/galera_transaction_replay.result | 96 +-
mysql-test/suite/galera/r/galera_truncate.result | 2 +
.../galera/r/galera_truncate_temporary.result | 2 +
.../galera/r/galera_unicode_identifiers.result | 2 +
mysql-test/suite/galera/r/galera_unicode_pk.result | 6 +-
.../suite/galera/r/galera_update_limit.result | 2 +
.../suite/galera/r/galera_v1_row_events.result | 2 +
.../suite/galera/r/galera_var_OSU_method.result | 2 +
.../suite/galera/r/galera_var_OSU_method2.result | 2 +
.../r/galera_var_auto_inc_control_off.result | 4 +-
.../galera/r/galera_var_certify_nonPK_off.result | 2 +
.../galera/r/galera_var_cluster_address.result | 6 +-
.../suite/galera/r/galera_var_desync_on.result | 2 +
.../suite/galera/r/galera_var_dirty_reads.result | 1 -
.../suite/galera/r/galera_var_fkchecks.result | 2 +
.../galera/r/galera_var_gtid_domain_id.result | 2 +
.../galera/r/galera_var_ignore_apply_errors.result | 154 ++
.../r/galera_var_innodb_disallow_writes.result | 2 +
.../galera/r/galera_var_load_data_splitting.result | 2 +
.../suite/galera/r/galera_var_log_bin.result | 2 +
.../suite/galera/r/galera_var_max_ws_rows.result | 2 +
.../suite/galera/r/galera_var_max_ws_size.result | 4 +-
.../r/galera_var_mysql_replication_bundle.result | 2 +
.../suite/galera/r/galera_var_node_address.result | 2 +
.../galera/r/galera_var_reject_queries.result | 2 +
.../r/galera_var_replicate_myisam_off.result | 2 +
.../galera/r/galera_var_replicate_myisam_on.result | 2 +
.../suite/galera/r/galera_var_slave_threads.result | 210 +-
.../suite/galera/r/galera_var_sst_auth.result | 2 +
.../suite/galera/r/galera_var_sync_wait.result | 2 +
.../suite/galera/r/galera_var_wsrep_on_off.result | 2 +
mysql-test/suite/galera/r/galera_wan.result | 2 +
.../suite/galera/r/galera_wan_restart_ist.result | 2 +
.../suite/galera/r/galera_wan_restart_sst.result | 2 +
.../galera/r/galera_wsrep_desync_wsrep_on.result | 2 +
.../galera/r/galera_wsrep_log_conficts.result | 4 +-
.../suite/galera/r/galera_wsrep_new_cluster.result | 2 +
.../r/galera_wsrep_provider_options_syntax.result | 2 +
.../galera/r/galera_zero_length_column.result | 2 +
mysql-test/suite/galera/r/grant.result | 2 +
mysql-test/suite/galera/r/lp1276424.result | 2 +
mysql-test/suite/galera/r/lp1347768.result | 2 +
mysql-test/suite/galera/r/lp1376747-2.result | 2 +
mysql-test/suite/galera/r/lp1376747-3.result | 2 +
mysql-test/suite/galera/r/lp1376747-4.result | 2 +
mysql-test/suite/galera/r/lp1376747.result | 2 +
mysql-test/suite/galera/r/lp1438990.result | 2 +
mysql-test/suite/galera/r/lp959512.result | 2 +
mysql-test/suite/galera/r/mdev_10518.result | 2 +
mysql-test/suite/galera/r/mdev_9290.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#110.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#198.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#201.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#237.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#247.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#31.result | 2 +
mysql-test/suite/galera/r/mysql-wsrep#90.result | 2 +
mysql-test/suite/galera/r/partition.result | 6 +-
mysql-test/suite/galera/r/pxc-421.result | 2 +
mysql-test/suite/galera/r/query_cache.result | 2 +
mysql-test/suite/galera/r/rename.result | 2 +
mysql-test/suite/galera/r/rpl_row_annotate.result | 8 +-
mysql-test/suite/galera/r/sql_log_bin.result | 2 +
mysql-test/suite/galera/r/unique_key.result | 2 +
mysql-test/suite/galera/r/view.result | 2 +
.../galera/r/wsrep_trx_fragment_size_non_sr.result | 25 +
.../galera/r/wsrep_trx_fragment_size_sr.result | 13 +
mysql-test/suite/galera/t/GAL-419.test | 4 +-
mysql-test/suite/galera/t/GCF-1081.test | 72 +
mysql-test/suite/galera/t/GCF-939.test | 25 +
mysql-test/suite/galera/t/MW-284.test | 2 +
mysql-test/suite/galera/t/MW-292.test | 50 +-
mysql-test/suite/galera/t/MW-328A.test | 40 +-
mysql-test/suite/galera/t/MW-329.test | 28 +-
mysql-test/suite/galera/t/MW-336.test | 10 +-
mysql-test/suite/galera/t/MW-360-master.opt | 2 +
mysql-test/suite/galera/t/MW-360.test | 100 +
mysql-test/suite/galera/t/MW-369.inc | 7 +-
mysql-test/suite/galera/t/MW-369.test | 1 -
mysql-test/suite/galera/t/MW-388.test | 1 -
mysql-test/suite/galera/t/MW-402.test | 56 +-
mysql-test/suite/galera/t/MW-416.test | 24 +-
mysql-test/suite/galera/t/MW-86-master.opt | 1 +
mysql-test/suite/galera/t/MW-86-wait1.test | 13 +-
mysql-test/suite/galera/t/MW-86-wait8.test | 11 +-
mysql-test/suite/galera/t/MW-86.test | 193 ++
mysql-test/suite/galera/t/disabled.def | 13 +
.../t/galera_applier_ftwrl_table_alter-master.opt | 2 +-
mysql-test/suite/galera/t/galera_as_master.test | 2 +
.../suite/galera/t/galera_as_master_gtid.test | 24 +-
.../t/galera_as_master_gtid_change_master.test | 2 +
mysql-test/suite/galera/t/galera_as_slave.test | 19 +-
.../suite/galera/t/galera_as_slave_autoinc.test | 20 +-
.../suite/galera/t/galera_as_slave_gtid.test | 21 +-
.../t/galera_as_slave_gtid_replicate_do_db.cnf | 17 +
.../t/galera_as_slave_gtid_replicate_do_db.test | 150 ++
.../t/galera_as_slave_gtid_replicate_do_db_cc.test | 176 ++
.../suite/galera/t/galera_as_slave_nonprim.test | 28 +-
.../suite/galera/t/galera_as_slave_preordered.test | 19 +-
.../t/galera_as_slave_replication_bundle.test | 13 +-
.../galera/t/galera_autoinc_sst_xtrabackup.cnf | 2 +-
.../galera/t/galera_bf_abort_group_commit.cnf | 15 +
.../galera/t/galera_bf_abort_group_commit.test | 76 +
.../suite/galera/t/galera_bf_abort_shutdown.test | 22 +
.../galera/t/galera_create_table_as_select.test | 145 ++
mysql-test/suite/galera/t/galera_defaults.test | 4 +-
.../galera/t/galera_forced_binlog_format.test | 5 +-
mysql-test/suite/galera/t/galera_ftwrl_drain.test | 2 +-
.../t/galera_gcache_recover_full_gcache.test | 4 +-
mysql-test/suite/galera/t/galera_gtid-master.opt | 2 +-
mysql-test/suite/galera/t/galera_gtid_slave.test | 14 +
.../galera/t/galera_gtid_slave_sst_rsync.test | 109 +-
.../galera/t/galera_ist_innodb_flush_logs.cnf | 2 +-
mysql-test/suite/galera/t/galera_ist_progress.test | 4 +-
.../suite/galera/t/galera_ist_restart_joiner.test | 2 +-
.../suite/galera/t/galera_ist_xtrabackup-v2.cnf | 2 +-
mysql-test/suite/galera/t/galera_log_bin.test | 2 +
mysql-test/suite/galera/t/galera_migrate.cnf | 2 +
.../galera/t/galera_parallel_apply_lock_table.test | 4 +-
.../suite/galera/t/galera_parallel_simple.test | 2 +-
mysql-test/suite/galera/t/galera_pc_recovery.test | 93 +
mysql-test/suite/galera/t/galera_split_brain.test | 6 +-
mysql-test/suite/galera/t/galera_ssl_upgrade.test | 4 +
.../suite/galera/t/galera_sst_mysqldump.test | 3 +-
.../galera/t/galera_sst_xtrabackup-v2-options.cnf | 2 +-
.../suite/galera/t/galera_sst_xtrabackup-v2.cnf | 2 +-
.../galera_sst_xtrabackup-v2_encrypt_with_key.cnf | 2 +-
.../suite/galera/t/galera_toi_ddl_error.test | 5 +
.../suite/galera/t/galera_toi_ddl_locking.test | 53 +-
.../suite/galera/t/galera_transaction_replay.test | 201 +-
.../suite/galera/t/galera_var_cluster_address.test | 9 +-
.../suite/galera/t/galera_var_dirty_reads.test | 9 +-
.../galera/t/galera_var_ignore_apply_errors.test | 235 +++
mysql-test/suite/galera/t/galera_var_log_bin.cnf | 5 +
.../suite/galera/t/galera_var_slave_threads.test | 123 +-
.../galera/t/galera_vote_drop_temporary-master.opt | 1 +
.../suite/galera/t/galera_wsrep_new_cluster.test | 1 -
.../suite/galera/t/mysql-wsrep#198-master.opt | 1 +
mysql-test/suite/galera/t/partition.test | 16 +-
mysql-test/suite/galera/t/rpl_row_annotate.test | 6 +-
.../galera/t/wsrep_trx_fragment_size_non_sr.test | 26 +
.../suite/galera/t/wsrep_trx_fragment_size_sr.test | 22 +
mysql-test/suite/galera_3nodes/galera_3nodes.cnf | 1 +
.../suite/galera_3nodes/include/galera_suspend.inc | 2 +-
.../r/galera_certification_ccc.result | 2 +
.../r/galera_certification_double_failure.result | 3 +
.../r/galera_ipv6_xtrabackup-v2.result | 3 -
.../r/galera_ist_gcache_rollover.result | 2 +
.../galera_3nodes/r/galera_pc_bootstrap.result | 13 +
.../suite/galera_3nodes/r/galera_pc_weight.result | 8 +-
.../galera_3nodes/r/galera_wsrep_schema.result | 77 +
mysql-test/suite/galera_3nodes/t/GAL-501.test | 6 +
.../t/galera_certification_double_failure.test | 2 +
.../t/galera_evs_suspect_timeout.test | 6 +-
mysql-test/suite/galera_3nodes/t/galera_garbd.test | 5 +-
.../galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf | 4 +
.../galera_3nodes/t/galera_ipv6_xtrabackup-v2.test | 30 +-
.../t/galera_ist_gcache_rollover.test | 2 +-
.../suite/galera_3nodes/t/galera_pc_weight.cnf | 8 +-
.../suite/galera_3nodes/t/galera_pc_weight.test | 34 +-
.../t/galera_slave_options_ignore.test | 1 +
.../suite/galera_3nodes/t/galera_wsrep_schema.test | 74 +
.../suite/galera_3nodes_ee/galera_3nodes.cnf | 1 +
.../include/galera_check_voting_recovery.inc | 58 +
mysql-test/suite/galera_3nodes_ee/my.cnf | 1 +
mysql-test/suite/galera_3nodes_ee/r/GCF-354.result | 23 +
mysql-test/suite/galera_3nodes_ee/r/GCF-361.result | 16 +
mysql-test/suite/galera_3nodes_ee/r/GCF-363.result | 31 +
mysql-test/suite/galera_3nodes_ee/r/GCF-376.result | 48 +
.../galera_3nodes_ee/r/galera-features#115.result | 21 +
.../galera_3nodes_ee/r/galera-features#119.result | 19 +
.../galera_3nodes_ee/r/galera-features#79.result | 32 +
.../r/galera_nbo_kill_master.result | 27 +
.../r/galera_nbo_kill_slave_ist.result | 35 +
.../r/galera_nbo_kill_slave_sst.result | 33 +
.../r/galera_nbo_master_majority_failure.result | 46 +
.../r/galera_nbo_master_majority_success.result | 50 +
.../r/galera_nbo_master_minority_failure.result | 52 +
.../r/galera_nbo_master_minority_success.result | 52 +
.../r/galera_nbo_master_non_prim_failure.result | 42 +
.../r/galera_nbo_master_non_prim_success.result | 32 +
.../r/galera_nbo_shutdown_slave_ist.result | 28 +
.../r/galera_nbo_slave_non_prim.result | 35 +
.../galera_3nodes_ee/r/galera_toi_vote.result | 19 +
.../r/galera_vote_rejoin_mysqldump.result | 60 +
.../suite/galera_3nodes_ee/r/galera_vote_sr.result | 52 +
.../r/mysql-wsrep-features#131.result | 12 +
mysql-test/suite/galera_3nodes_ee/t/GCF-354.cnf | 4 +
mysql-test/suite/galera_3nodes_ee/t/GCF-354.test | 59 +
mysql-test/suite/galera_3nodes_ee/t/GCF-361.cnf | 4 +
mysql-test/suite/galera_3nodes_ee/t/GCF-361.test | 47 +
mysql-test/suite/galera_3nodes_ee/t/GCF-363.cnf | 8 +
mysql-test/suite/galera_3nodes_ee/t/GCF-363.test | 68 +
mysql-test/suite/galera_3nodes_ee/t/GCF-376.cnf | 4 +
mysql-test/suite/galera_3nodes_ee/t/GCF-376.test | 84 +
.../galera_3nodes_ee/t/galera-features#115.cnf | 4 +
.../galera_3nodes_ee/t/galera-features#115.test | 67 +
.../galera_3nodes_ee/t/galera-features#119.test | 61 +
.../galera_3nodes_ee/t/galera-features#79.test | 75 +
.../galera_3nodes_ee/t/galera_nbo_kill_master.test | 73 +
.../t/galera_nbo_kill_slave_ist.test | 73 +
.../t/galera_nbo_kill_slave_sst.cnf | 11 +
.../t/galera_nbo_kill_slave_sst.test | 70 +
.../t/galera_nbo_master_majority_failure.cnf | 4 +
.../t/galera_nbo_master_majority_failure.test | 38 +
.../t/galera_nbo_master_majority_success.cnf | 4 +
.../t/galera_nbo_master_majority_success.test | 38 +
.../t/galera_nbo_master_minority_failure.cnf | 4 +
.../t/galera_nbo_master_minority_failure.test | 35 +
.../t/galera_nbo_master_minority_success.cnf | 4 +
.../t/galera_nbo_master_minority_success.test | 41 +
.../t/galera_nbo_master_non_prim_failure.test | 92 +
.../t/galera_nbo_master_non_prim_success.test | 80 +
.../t/galera_nbo_shutdown_slave_ist.test | 66 +
.../t/galera_nbo_slave_non_prim.test | 69 +
.../suite/galera_3nodes_ee/t/galera_toi_vote.cnf | 4 +
.../suite/galera_3nodes_ee/t/galera_toi_vote.test | 63 +
.../t/galera_vote_rejoin_mysqldump.cnf | 4 +
.../t/galera_vote_rejoin_mysqldump.test | 80 +
.../galera_3nodes_ee/t/galera_vote_sr-master.opt | 2 +
.../suite/galera_3nodes_ee/t/galera_vote_sr.test | 87 +
.../t/mysql-wsrep-features#131.test | 39 +
.../suite/galera_3nodes_sr/galera_3nodes.cnf | 1 +
mysql-test/suite/galera_3nodes_sr/my.cnf | 1 +
mysql-test/suite/galera_3nodes_sr/r/GCF-336.result | 26 +
mysql-test/suite/galera_3nodes_sr/r/GCF-582.result | 23 +
mysql-test/suite/galera_3nodes_sr/r/GCF-606.result | 23 +
mysql-test/suite/galera_3nodes_sr/r/GCF-609.result | 20 +
.../suite/galera_3nodes_sr/r/GCF-810A.result | 256 +++
.../suite/galera_3nodes_sr/r/GCF-810B.result | 100 +
.../suite/galera_3nodes_sr/r/GCF-810C.result | 177 ++
mysql-test/suite/galera_3nodes_sr/r/GCF-817.result | 33 +
mysql-test/suite/galera_3nodes_sr/r/GCF-832.result | 15 +
.../r/galera_sr_isolate_master.result | 62 +
.../galera_3nodes_sr/r/galera_sr_join_slave.result | 25 +
.../r/galera_sr_kill_master.result | 22 +
.../r/galera_sr_kill_slave_after_apply.result | 38 +
...alera_sr_kill_slave_after_apply_rollback.result | 44 +
...lera_sr_kill_slave_after_apply_rollback2.result | 31 +
.../r/galera_sr_kill_slave_before_apply.result | 27 +
.../r/galera_sr_threeway_split.result | 84 +
mysql-test/suite/galera_3nodes_sr/t/GCF-336.test | 47 +
mysql-test/suite/galera_3nodes_sr/t/GCF-582.test | 39 +
mysql-test/suite/galera_3nodes_sr/t/GCF-606.test | 80 +
mysql-test/suite/galera_3nodes_sr/t/GCF-609.test | 30 +
mysql-test/suite/galera_3nodes_sr/t/GCF-810A.test | 137 ++
mysql-test/suite/galera_3nodes_sr/t/GCF-810B.test | 49 +
mysql-test/suite/galera_3nodes_sr/t/GCF-810C.test | 70 +
mysql-test/suite/galera_3nodes_sr/t/GCF-817.test | 101 +
mysql-test/suite/galera_3nodes_sr/t/GCF-832.test | 36 +
mysql-test/suite/galera_3nodes_sr/t/disabled.def | 0
.../t/galera_sr_isolate_master.test | 127 ++
.../galera_3nodes_sr/t/galera_sr_join_slave.test | 56 +
.../galera_3nodes_sr/t/galera_sr_kill_master.test | 56 +
.../t/galera_sr_kill_slave_after_apply.test | 75 +
.../galera_sr_kill_slave_after_apply_rollback.test | 76 +
...galera_sr_kill_slave_after_apply_rollback2.test | 56 +
.../t/galera_sr_kill_slave_before_apply.test | 71 +
.../t/galera_sr_threeway_split.cnf | 5 +
.../t/galera_sr_threeway_split.test | 169 ++
mysql-test/suite/galera_ee/galera_2nodes.cnf | 1 +
mysql-test/suite/galera_ee/galera_4nodes.cnf | 1 +
mysql-test/suite/galera_ee/my.cnf | 1 +
mysql-test/suite/galera_ee/r/GCF-329A.result | 30 +
mysql-test/suite/galera_ee/r/GCF-329B.result | 16 +
mysql-test/suite/galera_ee/r/GCF-360.result | 416 ++++
mysql-test/suite/galera_ee/r/GCF-421.result | 14 +
mysql-test/suite/galera_ee/r/GCF-546.result | 28 +
mysql-test/suite/galera_ee/r/GCF-563.result | 52 +
mysql-test/suite/galera_ee/r/GCF-849.result | 11 +
mysql-test/suite/galera_ee/r/GCF-854.result | 16 +
.../suite/galera_ee/r/galera-features#117.result | 29 +
.../r/galera_nbo_alter_conflicting.result | 14 +
.../suite/galera_ee/r/galera_nbo_alter_copy.result | 44 +
.../galera_ee/r/galera_nbo_alter_engine.result | 22 +
.../r/galera_nbo_alter_error_duplicate.result | 30 +
.../galera_ee/r/galera_nbo_alter_exclusive.result | 37 +
.../galera_ee/r/galera_nbo_alter_inplace.result | 39 +
.../galera_ee/r/galera_nbo_alter_multi.result | 11 +
.../r/galera_nbo_alter_nonconflicting.result | 29 +
.../galera_ee/r/galera_nbo_alter_parallel.result | 45 +
.../galera_ee/r/galera_nbo_alter_partition.result | 26 +
.../galera_ee/r/galera_nbo_alter_rename.result | 19 +
.../suite/galera_ee/r/galera_nbo_alter_toi.result | 38 +
.../galera_ee/r/galera_nbo_create_index.result | 36 +
.../suite/galera_ee/r/galera_nbo_ddl_error.result | 22 +
.../galera_ee/r/galera_nbo_error_on_all.result | 13 +
.../suite/galera_ee/r/galera_nbo_local_mdl.result | 12 +
.../galera_ee/r/galera_nbo_processlist.result | 35 +
.../suite/galera_ee/r/galera_nbo_sst_slave.result | 23 +
.../galera_ee/r/galera_nbo_temporary_table.result | 14 +
.../galera_ee/r/galera_nbo_unsupported.result | 26 +
.../galera_ee/r/galera_vote_rejoin_ddl.result | 44 +
.../galera_ee/r/galera_vote_rejoin_dml.result | 47 +
.../galera_ee/r/mysql-wsrep-features#127.result | 5 +
.../galera_ee/r/mysql-wsrep-features#128.result | 7 +
.../galera_ee/r/mysql-wsrep-features#131.result | 12 +
.../galera_ee/r/mysql-wsrep-features#132.result | 18 +
mysql-test/suite/galera_ee/t/GCF-329A.test | 42 +
mysql-test/suite/galera_ee/t/GCF-329B.test | 53 +
mysql-test/suite/galera_ee/t/GCF-360.cnf | 17 +
mysql-test/suite/galera_ee/t/GCF-360.test | 64 +
mysql-test/suite/galera_ee/t/GCF-421.test | 46 +
mysql-test/suite/galera_ee/t/GCF-546.test | 47 +
mysql-test/suite/galera_ee/t/GCF-563.test | 63 +
mysql-test/suite/galera_ee/t/GCF-849.test | 39 +
mysql-test/suite/galera_ee/t/GCF-854.test | 42 +
.../suite/galera_ee/t/galera-features#117.cnf | 4 +
.../suite/galera_ee/t/galera-features#117.test | 37 +
.../galera_ee/t/galera_nbo_alter_conflicting.test | 57 +
.../suite/galera_ee/t/galera_nbo_alter_copy.test | 67 +
.../suite/galera_ee/t/galera_nbo_alter_engine.test | 31 +
.../t/galera_nbo_alter_error_duplicate.test | 34 +
.../galera_ee/t/galera_nbo_alter_exclusive.test | 64 +
.../galera_ee/t/galera_nbo_alter_inplace.test | 67 +
.../suite/galera_ee/t/galera_nbo_alter_multi.test | 15 +
.../t/galera_nbo_alter_nonconflicting.test | 57 +
.../galera_ee/t/galera_nbo_alter_parallel.test | 65 +
.../galera_ee/t/galera_nbo_alter_partition.test | 29 +
.../suite/galera_ee/t/galera_nbo_alter_rename.test | 31 +
.../suite/galera_ee/t/galera_nbo_alter_toi.test | 53 +
.../suite/galera_ee/t/galera_nbo_create_index.test | 34 +
.../suite/galera_ee/t/galera_nbo_ddl_error.test | 38 +
.../suite/galera_ee/t/galera_nbo_error_on_all.test | 21 +
.../suite/galera_ee/t/galera_nbo_local_mdl.test | 55 +
.../suite/galera_ee/t/galera_nbo_processlist.test | 81 +
.../suite/galera_ee/t/galera_nbo_sst_slave.test | 89 +
.../t/galera_nbo_temporary_table-master.opt | 2 +
.../galera_ee/t/galera_nbo_temporary_table.test | 37 +
.../suite/galera_ee/t/galera_nbo_unsupported.test | 42 +
.../suite/galera_ee/t/galera_vote_rejoin_ddl.cnf | 5 +
.../suite/galera_ee/t/galera_vote_rejoin_ddl.test | 87 +
.../suite/galera_ee/t/galera_vote_rejoin_dml.cnf | 4 +
.../suite/galera_ee/t/galera_vote_rejoin_dml.test | 91 +
.../galera_ee/t/mysql-wsrep-features#127.test | 16 +
.../t/mysql-wsrep-features#128-master.opt | 1 +
.../galera_ee/t/mysql-wsrep-features#128.test | 11 +
.../galera_ee/t/mysql-wsrep-features#131.test | 38 +
.../galera_ee/t/mysql-wsrep-features#132.test | 39 +
mysql-test/suite/galera_sr/galera_2nodes.cnf | 1 +
mysql-test/suite/galera_sr/my.cnf | 1 +
mysql-test/suite/galera_sr/r/GCF-1008.result | 50 +
mysql-test/suite/galera_sr/r/GCF-1018.result | 15 +
mysql-test/suite/galera_sr/r/GCF-1018B.result | 8 +
mysql-test/suite/galera_sr/r/GCF-1043A.result | 15 +
mysql-test/suite/galera_sr/r/GCF-1043B.result | 15 +
mysql-test/suite/galera_sr/r/GCF-1051.result | 37 +
mysql-test/suite/galera_sr/r/GCF-1060.result | 15 +
mysql-test/suite/galera_sr/r/GCF-437.result | 12 +
mysql-test/suite/galera_sr/r/GCF-561.result | 42 +
mysql-test/suite/galera_sr/r/GCF-571.result | 56 +
mysql-test/suite/galera_sr/r/GCF-572.result | 29 +
mysql-test/suite/galera_sr/r/GCF-574.result | 11 +
mysql-test/suite/galera_sr/r/GCF-580.result | 11 +
mysql-test/suite/galera_sr/r/GCF-585.result | 25 +
mysql-test/suite/galera_sr/r/GCF-597.result | 15 +
mysql-test/suite/galera_sr/r/GCF-620.result | 14 +
mysql-test/suite/galera_sr/r/GCF-623.result | 22 +
mysql-test/suite/galera_sr/r/GCF-627.result | 18 +
mysql-test/suite/galera_sr/r/GCF-845.result | 14 +
mysql-test/suite/galera_sr/r/GCF-851.result | 24 +
mysql-test/suite/galera_sr/r/GCF-867.result | 2 +
mysql-test/suite/galera_sr/r/GCF-889.result | 18 +
mysql-test/suite/galera_sr/r/GCF-900.result | 13 +
.../suite/galera_sr/r/galera-features#56.result | 21 +
.../suite/galera_sr/r/galera_sr_bf_abort.result | 448 +++++
mysql-test/suite/galera_sr/r/galera_sr_blob.result | 15 +
.../suite/galera_sr/r/galera_sr_cc_master.result | 45 +
.../suite/galera_sr/r/galera_sr_cc_slave.result | 46 +
.../suite/galera_sr/r/galera_sr_concurrent.result | 28 +
.../suite/galera_sr/r/galera_sr_conflict.result | 14 +
.../r/galera_sr_conflict_on_commit.result | 22 +
.../r/galera_sr_conflict_on_commit2.result | 19 +
.../galera_sr_conflict_with_rollback_master.result | 22 +
.../suite/galera_sr/r/galera_sr_ddl_master.result | 41 +
.../suite/galera_sr/r/galera_sr_ddl_schema.result | 18 +
.../suite/galera_sr/r/galera_sr_ddl_slave.result | 42 +
.../galera_sr/r/galera_sr_ddl_unrelated.result | 34 +
.../galera_sr/r/galera_sr_dupkey_error.result | 36 +
.../suite/galera_sr/r/galera_sr_fk_conflict.result | 34 +
mysql-test/suite/galera_sr/r/galera_sr_gtid.result | 65 +
.../galera_sr/r/galera_sr_insert_select.result | 11 +
.../r/galera_sr_kill_all_nobootstrap.result | 21 +
.../r/galera_sr_kill_all_norecovery.result | 22 +
.../r/galera_sr_kill_all_pcrecovery.result | 22 +
.../galera_sr/r/galera_sr_kill_connection.result | 25 +
.../suite/galera_sr/r/galera_sr_kill_query.result | 17 +
.../suite/galera_sr/r/galera_sr_kill_slave.result | 39 +
.../galera_sr/r/galera_sr_large_fragment.result | 28 +
.../suite/galera_sr/r/galera_sr_load_data.result | 8 +
.../r/galera_sr_load_data_splitting.result | 9 +
.../suite/galera_sr/r/galera_sr_log_bin.result | 87 +
.../galera_sr/r/galera_sr_many_fragments.result | 28 +
.../suite/galera_sr/r/galera_sr_myisam.result | 11 +
.../galera_sr/r/galera_sr_mysqldump_sst.result | 40 +
.../galera_sr/r/galera_sr_parallel_apply.result | 26 +
.../suite/galera_sr/r/galera_sr_rollback.result | 29 +
.../galera_sr/r/galera_sr_rollback_retry.result | 26 +
.../r/galera_sr_rollback_savepoint.result | 33 +
.../r/galera_sr_rollback_statement.result | 22 +
mysql-test/suite/galera_sr/r/galera_sr_sbr.result | 16 +
.../galera_sr/r/galera_sr_shutdown_master.result | 20 +
.../galera_sr/r/galera_sr_shutdown_slave.result | 29 +
.../galera_sr/r/galera_sr_small_gcache.result | 10 +
.../galera_sr/r/galera_sr_table_contents.result | 198 ++
.../r/galera_sr_transaction_replay.result | 101 +
.../galera_sr/r/galera_sr_unit_statements.result | 18 +
.../galera_sr/r/galera_sr_v1_row_events.result | 15 +
.../suite/galera_sr/r/galera_sr_ws_size.result | 29 +
.../suite/galera_sr/r/galera_sr_ws_size2.result | 28 +
.../r/galera_var_ignore_apply_errors_sr.result | 22 +
.../suite/galera_sr/r/mysql-wsrep#215.result | 88 +
.../galera_sr/r/mysql-wsrep-features#136.result | 41 +
.../galera_sr/r/mysql-wsrep-features#138.result | 17 +
.../galera_sr/r/mysql-wsrep-features#14.result | 8 +
.../galera_sr/r/mysql-wsrep-features#148.result | 27 +
.../galera_sr/r/mysql-wsrep-features#15.result | 8 +
.../galera_sr/r/mysql-wsrep-features#165.result | 752 ++++++++
.../galera_sr/r/mysql-wsrep-features#213.result | 26 +
.../galera_sr/r/mysql-wsrep-features#214.result | 46 +
.../galera_sr/r/mysql-wsrep-features#22.result | 26 +
.../galera_sr/r/mysql-wsrep-features#27.result | 17 +
.../galera_sr/r/mysql-wsrep-features#29.result | 14 +
.../galera_sr/r/mysql-wsrep-features#32.result | 22 +
.../galera_sr/r/mysql-wsrep-features#35.result | 26 +
.../galera_sr/r/mysql-wsrep-features#8.result | 27 +
.../galera_sr/r/mysql-wsrep-features#9.result | 12 +
.../galera_sr/r/mysql-wsrep-features#93.result | 15 +
.../galera_sr/r/mysql-wsrep-features#96.result | 26 +
mysql-test/suite/galera_sr/t/GCF-1008.inc | 36 +
mysql-test/suite/galera_sr/t/GCF-1008.test | 18 +
mysql-test/suite/galera_sr/t/GCF-1018.test | 38 +
mysql-test/suite/galera_sr/t/GCF-1018B.test | 40 +
mysql-test/suite/galera_sr/t/GCF-1043A.test | 13 +
mysql-test/suite/galera_sr/t/GCF-1043B.test | 13 +
mysql-test/suite/galera_sr/t/GCF-1051.test | 52 +
mysql-test/suite/galera_sr/t/GCF-1060.test | 9 +
mysql-test/suite/galera_sr/t/GCF-437.test | 21 +
mysql-test/suite/galera_sr/t/GCF-561.test | 65 +
mysql-test/suite/galera_sr/t/GCF-571.test | 54 +
mysql-test/suite/galera_sr/t/GCF-572.test | 54 +
mysql-test/suite/galera_sr/t/GCF-574.test | 27 +
mysql-test/suite/galera_sr/t/GCF-580.test | 27 +
mysql-test/suite/galera_sr/t/GCF-585.test | 40 +
mysql-test/suite/galera_sr/t/GCF-597.test | 29 +
mysql-test/suite/galera_sr/t/GCF-620.test | 22 +
mysql-test/suite/galera_sr/t/GCF-623.test | 31 +
mysql-test/suite/galera_sr/t/GCF-627.test | 30 +
mysql-test/suite/galera_sr/t/GCF-845.test | 30 +
mysql-test/suite/galera_sr/t/GCF-851.test | 24 +
mysql-test/suite/galera_sr/t/GCF-867.test | 42 +
mysql-test/suite/galera_sr/t/GCF-889.test | 28 +
mysql-test/suite/galera_sr/t/GCF-900.test | 28 +
mysql-test/suite/galera_sr/t/disabled.def | 4 +
.../suite/galera_sr/t/galera-features#56.test | 55 +
.../suite/galera_sr/t/galera_sr_bf_abort.inc | 145 ++
.../suite/galera_sr/t/galera_sr_bf_abort.test | 48 +
mysql-test/suite/galera_sr/t/galera_sr_blob.test | 38 +
.../suite/galera_sr/t/galera_sr_cc_master.test | 87 +
.../suite/galera_sr/t/galera_sr_cc_slave.test | 86 +
.../suite/galera_sr/t/galera_sr_concurrent.test | 45 +
.../suite/galera_sr/t/galera_sr_conflict.test | 45 +
.../galera_sr/t/galera_sr_conflict_on_commit.test | 45 +
.../galera_sr/t/galera_sr_conflict_on_commit2.test | 46 +
.../t/galera_sr_conflict_with_rollback_master.test | 44 +
.../suite/galera_sr/t/galera_sr_ddl_master.test | 63 +
.../suite/galera_sr/t/galera_sr_ddl_schema.test | 43 +
.../suite/galera_sr/t/galera_sr_ddl_slave.test | 65 +
.../suite/galera_sr/t/galera_sr_ddl_unrelated.test | 53 +
.../suite/galera_sr/t/galera_sr_dupkey_error.test | 57 +
.../suite/galera_sr/t/galera_sr_fk_conflict.test | 62 +
.../suite/galera_sr/t/galera_sr_gtid-master.opt | 1 +
mysql-test/suite/galera_sr/t/galera_sr_gtid.test | 46 +
.../suite/galera_sr/t/galera_sr_insert_select.test | 33 +
.../t/galera_sr_kill_all_nobootstrap.test | 52 +
.../galera_sr/t/galera_sr_kill_all_norecovery.cnf | 4 +
.../galera_sr/t/galera_sr_kill_all_norecovery.test | 53 +
.../galera_sr/t/galera_sr_kill_all_pcrecovery.test | 54 +
.../galera_sr/t/galera_sr_kill_connection.test | 59 +
.../suite/galera_sr/t/galera_sr_kill_query.test | 53 +
.../suite/galera_sr/t/galera_sr_kill_slave.cnf | 4 +
.../suite/galera_sr/t/galera_sr_kill_slave.test | 80 +
.../t/galera_sr_large_fragment-master.opt | 1 +
.../galera_sr/t/galera_sr_large_fragment.test | 58 +
.../suite/galera_sr/t/galera_sr_load_data.test | 39 +
.../galera_sr/t/galera_sr_load_data_splitting.test | 50 +
.../suite/galera_sr/t/galera_sr_log_bin-master.opt | 1 +
.../suite/galera_sr/t/galera_sr_log_bin.test | 66 +
.../galera_sr/t/galera_sr_many_fragments.test | 53 +
mysql-test/suite/galera_sr/t/galera_sr_myisam.test | 29 +
.../suite/galera_sr/t/galera_sr_mysqldump_sst.cnf | 11 +
.../suite/galera_sr/t/galera_sr_mysqldump_sst.test | 79 +
.../galera_sr/t/galera_sr_parallel_apply.test | 59 +
.../suite/galera_sr/t/galera_sr_rollback.test | 76 +
.../galera_sr/t/galera_sr_rollback_retry.test | 55 +
.../galera_sr/t/galera_sr_rollback_savepoint.test | 51 +
.../galera_sr/t/galera_sr_rollback_statement.test | 61 +
mysql-test/suite/galera_sr/t/galera_sr_sbr.test | 31 +
.../galera_sr/t/galera_sr_shutdown_master.test | 45 +
.../galera_sr/t/galera_sr_shutdown_slave.test | 63 +
.../suite/galera_sr/t/galera_sr_small_gcache.cnf | 6 +
.../suite/galera_sr/t/galera_sr_small_gcache.test | 21 +
.../galera_sr/t/galera_sr_table_contents.test | 49 +
.../galera_sr/t/galera_sr_transaction_replay.test | 260 +++
.../galera_sr/t/galera_sr_unit_statements.test | 47 +
.../galera_sr/t/galera_sr_v1_row_events-master.opt | 1 +
.../suite/galera_sr/t/galera_sr_v1_row_events.test | 27 +
.../suite/galera_sr/t/galera_sr_ws_size.test | 70 +
.../suite/galera_sr/t/galera_sr_ws_size2.test | 62 +
.../t/galera_var_ignore_apply_errors_sr.test | 37 +
mysql-test/suite/galera_sr/t/mysql-wsrep#215.test | 161 ++
.../t/mysql-wsrep-features#136-master.opt | 1 +
.../galera_sr/t/mysql-wsrep-features#136.test | 37 +
.../galera_sr/t/mysql-wsrep-features#138.test | 25 +
.../suite/galera_sr/t/mysql-wsrep-features#14.test | 21 +
.../galera_sr/t/mysql-wsrep-features#148.test | 60 +
.../suite/galera_sr/t/mysql-wsrep-features#15.test | 17 +
.../suite/galera_sr/t/mysql-wsrep-features#165.inc | 104 +
.../galera_sr/t/mysql-wsrep-features#165.test | 41 +
.../galera_sr/t/mysql-wsrep-features#213.test | 63 +
.../galera_sr/t/mysql-wsrep-features#214.test | 86 +
.../suite/galera_sr/t/mysql-wsrep-features#22.test | 47 +
.../suite/galera_sr/t/mysql-wsrep-features#27.test | 29 +
.../suite/galera_sr/t/mysql-wsrep-features#29.test | 23 +
.../galera_sr/t/mysql-wsrep-features#32-master.opt | 1 +
.../suite/galera_sr/t/mysql-wsrep-features#32.test | 44 +
.../suite/galera_sr/t/mysql-wsrep-features#35.test | 46 +
.../suite/galera_sr/t/mysql-wsrep-features#8.test | 63 +
.../suite/galera_sr/t/mysql-wsrep-features#9.test | 44 +
.../suite/galera_sr/t/mysql-wsrep-features#93.test | 29 +
.../suite/galera_sr/t/mysql-wsrep-features#96.test | 45 +
.../suite/innodb/r/innodb-index-online-fk.result | 10 +-
mysql-test/suite/innodb/t/galera.skip | 53 +
.../suite/innodb/t/innodb-index-online-fk.test | 10 +-
packaging/deb-in/CMakeLists.txt | 357 ++++
plugin/wsrep_info/plugin.cc | 2 +
scripts/mysqld_safe.sh | 11 +-
scripts/wsrep_sst_mysqldump.sh | 1 +
scripts/wsrep_sst_xtrabackup-v2.sh | 2 +-
sql/CMakeLists.txt | 15 +-
sql/events.cc | 1 -
sql/ha_partition.cc | 7 +
sql/ha_partition.h | 3 +
sql/handler.cc | 216 ++-
sql/item_create.cc | 102 +-
sql/item_strfunc.cc | 102 +
sql/item_strfunc.h | 52 +
sql/lock.cc | 25 +-
sql/log.cc | 379 +++-
sql/log.h | 19 +
sql/log_event.cc | 19 +-
sql/mdl.cc | 74 +-
sql/mysqld.cc | 51 +-
sql/protocol.cc | 21 +-
sql/slave.cc | 111 +-
sql/sp_head.cc | 29 +-
sql/sql_alter.cc | 2 +-
sql/sql_base.cc | 23 +-
sql/sql_class.cc | 145 +-
sql/sql_class.h | 373 +++-
sql/sql_connect.cc | 5 +-
sql/sql_insert.cc | 53 +-
sql/sql_load.cc | 9 +-
sql/sql_parse.cc | 604 ++++--
sql/sql_parse.h | 2 +
sql/sql_plugin.cc | 5 +
sql/sql_plugin_services.ic | 9 +-
sql/sql_prepare.cc | 8 +-
sql/sql_repl.cc | 11 +
sql/sql_table.cc | 32 +-
sql/sql_truncate.cc | 18 +-
sql/sys_vars.cc | 38 +-
sql/table.cc | 7 +
sql/transaction.cc | 36 +-
sql/wsrep_applier.cc | 898 ++++++++-
sql/wsrep_applier.h | 67 +-
sql/wsrep_binlog.cc | 201 +-
sql/wsrep_binlog.h | 55 +-
sql/wsrep_dummy.cc | 19 +-
sql/wsrep_hton.cc | 1 +
sql/wsrep_mysqld.cc | 2036 ++++++++++++++++----
sql/wsrep_mysqld.h | 333 +++-
sql/wsrep_plugin.cc | 53 +
sql/wsrep_priv.h | 9 +-
sql/wsrep_schema.cc | 1481 ++++++++++++++
sql/wsrep_schema.h | 141 ++
sql/wsrep_sr.cc | 428 ++++
sql/wsrep_sr.h | 275 +++
sql/wsrep_sr_file.cc | 563 ++++++
sql/wsrep_sr_file.h | 111 ++
sql/wsrep_sr_table.cc | 223 +++
sql/wsrep_sr_table.h | 67 +
sql/wsrep_sst.cc | 169 +-
sql/wsrep_sst.h | 10 +-
sql/wsrep_tc.h | 0
sql/wsrep_thd.cc | 751 +++++++-
sql/wsrep_thd.h | 176 +-
sql/wsrep_thd_pool.cc | 122 ++
sql/wsrep_thd_pool.h | 37 +
sql/wsrep_trans_observer.cc | 1663 ++++++++++++++++
sql/wsrep_trans_observer.h | 117 ++
sql/wsrep_utils.cc | 1 +
sql/wsrep_utils.h | 34 +
sql/wsrep_var.cc | 184 +-
sql/wsrep_var.h | 5 +-
sql/wsrep_xid.cc | 42 +-
sql/wsrep_xid.h | 12 +-
storage/innobase/buf/buf0dump.cc | 6 +-
storage/innobase/handler/ha_innodb.cc | 228 +--
storage/innobase/handler/ha_innodb.h | 9 +-
storage/innobase/include/ha_prototypes.h | 5 +
storage/innobase/include/trx0trx.h | 17 +
storage/innobase/lock/lock0lock.cc | 14 +-
storage/innobase/lock/lock0wait.cc | 8 +-
storage/innobase/row/row0ins.cc | 22 +
storage/innobase/row/row0sel.cc | 16 +
storage/innobase/row/row0upd.cc | 14 +-
storage/innobase/trx/trx0roll.cc | 5 +
storage/innobase/trx/trx0rseg.cc | 3 +-
wsrep/wsrep_api.h | 533 +++--
wsrep/wsrep_dummy.c | 116 +-
wsrep/wsrep_gtid.c | 2 +-
wsrep/wsrep_listener.c | 261 +++
wsrep/wsrep_loader.c | 28 +-
wsrep/wsrep_uuid.c | 11 +
833 files changed, 36460 insertions(+), 2491 deletions(-)
diff --cc CMakeLists.txt
index 58b6cc62e9f,3ff19ae33a2..5477e68a113
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@@ -398,13 -403,8 +403,9 @@@ IF(NOT WITHOUT_SERVER
IF(WITH_EMBEDDED_SERVER)
ADD_SUBDIRECTORY(libmysqld)
ADD_SUBDIRECTORY(libmysqld/examples)
+ ADD_SUBDIRECTORY(unittest/embedded)
ENDIF(WITH_EMBEDDED_SERVER)
- IF(WITH_WSREP)
- ADD_SUBDIRECTORY(wsrep)
- ENDIF()
-
ADD_SUBDIRECTORY(mysql-test)
ADD_SUBDIRECTORY(mysql-test/lib/My/SafeProcess)
ADD_SUBDIRECTORY(sql-bench)
diff --cc include/mysql/service_wsrep.h
index 1540a5e56fe,2459d8776f0..d0d00cf2013
--- a/include/mysql/service_wsrep.h
+++ b/include/mysql/service_wsrep.h
@@@ -1,4 -1,9 +1,5 @@@
-//#ifndef MYSQL_SERVICE_WSREP_INCLUDED
-//#ifdef MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED && MYSQL_SERVICE_WSREP_STATIC_INCLUDED
-#if (defined (MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED)) || (!defined(MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_STATIC_INCLUDED))
-
-#else
+#ifndef MYSQL_SERVICE_WSREP_INCLUDED
+
/* Copyright (c) 2015 MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify
@@@ -55,8 -61,7 +57,8 @@@ enum wsrep_query_state
QUERY_IDLE,
QUERY_EXEC,
QUERY_COMMITTING,
++ QUERY_ORDERED_COMMIT,
QUERY_EXITING,
- QUERY_ROLLINGBACK,
};
enum wsrep_trx_status {
@@@ -65,9 -70,9 +67,9 @@@
WSREP_TRX_SIZE_EXCEEDED, /* trx size exceeded */
WSREP_TRX_ERROR, /* native mysql error */
};
-#endif
+
struct xid_t;
- struct wsrep;
+ struct wsrep_st;
struct wsrep_ws_handle;
struct wsrep_buf;
@@@ -80,17 -85,17 +82,12 @@@ extern struct wsrep_service_st
my_bool (*get_wsrep_load_data_splitting_func)();
my_bool (*get_wsrep_log_conflicts_func)();
long (*get_wsrep_protocol_version_func)();
- my_bool (*wsrep_aborting_thd_contains_func)(THD *thd);
- void (*wsrep_aborting_thd_enqueue_func)(THD *thd);
bool (*wsrep_consistency_check_func)(THD *thd);
- int (*wsrep_is_wsrep_xid_func)(const struct xid_t *xid);
- //int (*wsrep_is_wsrep_xid_func)(const struct xid_t *xid);
+ int (*wsrep_is_wsrep_xid_func)(const void *xid);
long long (*wsrep_xid_seqno_func)(const struct xid_t *xid);
const unsigned char* (*wsrep_xid_uuid_func)(const struct xid_t *xid);
- void (*wsrep_lock_rollback_func)();
- int (*wsrep_on_func)(MYSQL_THD);
- void (*wsrep_post_commit_func)(THD* thd, bool all);
- bool (*wsrep_prepare_key_func)(const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
- enum wsrep_trx_status (*wsrep_run_wsrep_commit_func)(THD *thd, bool all);
- // int (*wsrep_on_func)(MYSQL_THD);
+ int (*wsrep_on_func)(void *);
- // void (*wsrep_post_commit_func)(THD* thd, bool all);
- //bool (*wsrep_prepare_key_func)(const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
+ bool (*wsrep_prepare_key_for_innodb_func)(THD* thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
- //enum wsrep_trx_status (*wsrep_run_wsrep_commit_func)(THD *thd, bool all);
void (*wsrep_thd_LOCK_func)(THD *thd);
void (*wsrep_thd_UNLOCK_func)(THD *thd);
void (*wsrep_thd_awake_func)(THD *thd, my_bool signal);
@@@ -99,7 -105,8 +97,7 @@@
enum wsrep_exec_mode (*wsrep_thd_exec_mode_func)(THD *thd);
const char * (*wsrep_thd_exec_mode_str_func)(THD *thd);
enum wsrep_conflict_state (*wsrep_thd_get_conflict_state_func)(MYSQL_THD);
- my_bool (*wsrep_thd_is_BF_func)(MYSQL_THD , my_bool);
- // my_bool (*wsrep_thd_is_BF_func)(MYSQL_THD , my_bool);
+ my_bool (*wsrep_thd_is_BF_func)(void* , my_bool);
my_bool (*wsrep_thd_is_wsrep_func)(MYSQL_THD thd);
char * (*wsrep_thd_query_func)(THD *thd);
enum wsrep_query_state (*wsrep_thd_query_state_func)(THD *thd);
@@@ -111,10 -118,16 +109,11 @@@
struct wsrep_ws_handle * (*wsrep_thd_ws_handle_func)(THD *thd);
int (*wsrep_trx_is_aborting_func)(MYSQL_THD thd);
int (*wsrep_trx_order_before_func)(MYSQL_THD, MYSQL_THD);
- void (*wsrep_unlock_rollback_func)();
- //void (wsrep_thd_xid_func)(const void *thd_ptr, void *xid, size_t xid_size);
} *wsrep_service;
+
-#define MYSQL_SERVICE_WSREP_INCLUDED
-#endif
-
#ifdef MYSQL_DYNAMIC_PLUGIN
+
-#define MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED
#define get_wsrep() wsrep_service->get_wsrep_func()
#define get_wsrep_certify_nonPK() wsrep_service->get_wsrep_certify_nonPK_func()
#define get_wsrep_debug() wsrep_service->get_wsrep_debug_func()
@@@ -148,7 -156,7 +142,6 @@@
#define wsrep_thd_query_state(T) wsrep_service->wsrep_thd_query_state_func(T)
#define wsrep_thd_query_state_str(T) wsrep_service->wsrep_thd_query_state_str_func(T)
#define wsrep_thd_retry_counter(T) wsrep_service->wsrep_thd_retry_counter_func(T)
- #define wsrep_thd_set_conflict_state(T,S) wsrep_service->wsrep_thd_set_conflict_state_func(T,S)
- //#define wsrep_thd_set_conflict_state(T,S) wsrep_service->wsrep_thd_set_conflict_state_func(T,S)
#define wsrep_thd_ignore_table(T) wsrep_service->wsrep_thd_ignore_table_func(T)
#define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T)
#define wsrep_thd_ws_handle(T) wsrep_service->wsrep_thd_ws_handle_func(T)
@@@ -173,10 -183,11 +167,11 @@@ extern my_bool wsrep_load_data_splittin
extern my_bool wsrep_drupal_282555_workaround;
extern my_bool wsrep_recovery;
extern long wsrep_protocol_version;
+ extern my_thread_id wsrep_thd_thread_id(THD *thd);
-
+
bool wsrep_consistency_check(THD *thd);
- bool wsrep_prepare_key(const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len);
- char *wsrep_thd_query(THD *thd);
+ bool wsrep_prepare_key_for_innodb(THD* thd, const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len);
+ extern "C" char *wsrep_thd_query(THD *thd);
const char *wsrep_thd_conflict_state_str(THD *thd);
const char *wsrep_thd_exec_mode_str(THD *thd);
const char *wsrep_thd_query_state_str(THD *thd);
@@@ -185,10 -196,12 +180,10 @@@ enum wsrep_conflict_state wsrep_thd_get
enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
enum wsrep_query_state wsrep_thd_query_state(THD *thd);
enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, bool all);
- int wsrep_is_wsrep_xid(const struct xid_t* xid);
-//int wsrep_is_wsrep_xid(const struct xid_t* xid);
+ int wsrep_is_wsrep_xid(const void* xid);
long long wsrep_xid_seqno(const struct xid_t* xid);
const unsigned char* wsrep_xid_uuid(const struct xid_t* xid);
- int wsrep_on(MYSQL_THD thd);
-//int wsrep_on(MYSQL_THD thd);
+ int wsrep_on(void *);
int wsrep_thd_retry_counter(THD *thd);
int wsrep_trx_is_aborting(MYSQL_THD thd);
int wsrep_trx_order_before(MYSQL_THD thd1, MYSQL_THD thd2);
@@@ -201,12 -214,12 +196,11 @@@ my_bool get_wsrep_recovery()
my_bool get_wsrep_load_data_splitting();
my_bool get_wsrep_log_conflicts();
my_bool wsrep_aborting_thd_contains(THD *thd);
- my_bool wsrep_thd_is_BF(MYSQL_THD thd, my_bool sync);
-//my_bool wsrep_thd_is_BF(MYSQL_THD thd, my_bool sync);
+ my_bool wsrep_thd_is_BF(void* thd, my_bool sync);
my_bool wsrep_thd_is_wsrep(MYSQL_THD thd);
- struct wsrep *get_wsrep();
+ struct wsrep_st *get_wsrep();
struct wsrep_ws_handle *wsrep_thd_ws_handle(THD *thd);
void wsrep_aborting_thd_enqueue(THD *thd);
- void wsrep_lock_rollback();
void wsrep_post_commit(THD* thd, bool all);
void wsrep_thd_LOCK(THD *thd);
void wsrep_thd_UNLOCK(THD *thd);
diff --cc mysql-test/main/mysqld--help-notwin.result
index 00000000000,b7db372a704..b7db372a704
mode 000000,100644..100644
--- a/mysql-test/main/mysqld--help-notwin.result
+++ b/mysql-test/main/mysqld--help-notwin.result
diff --cc mysql-test/main/query_cache_size_functionality.result
index 00000000000,7563b3e61eb..7563b3e61eb
mode 000000,100644..100644
--- a/mysql-test/main/query_cache_size_functionality.result
+++ b/mysql-test/main/query_cache_size_functionality.result
diff --cc mysql-test/main/query_cache_type_functionality.result
index 00000000000,134d8c3a066..134d8c3a066
mode 000000,100644..100644
--- a/mysql-test/main/query_cache_type_functionality.result
+++ b/mysql-test/main/query_cache_type_functionality.result
diff --cc mysql-test/suite/galera/t/galera_sst_mysqldump.test
index 835fac94a68,527072a53e9..b72fa687411
--- a/mysql-test/suite/galera/t/galera_sst_mysqldump.test
+++ b/mysql-test/suite/galera/t/galera_sst_mysqldump.test
@@@ -1,6 -1,5 +1,6 @@@
+--source include/big_test.inc
--source include/galera_cluster.inc
-
+ --source include/have_innodb.inc
--source suite/galera/include/galera_sst_set_mysqldump.inc
--let $node_1=node_1
diff --cc mysql-test/suite/galera/t/galera_var_dirty_reads.test
index 1f01c4aac07,075fea83d2f..dc1698ef497
--- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test
+++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
@@@ -4,18 -4,7 +4,13 @@@
--source include/galera_cluster.inc
--source include/have_innodb.inc
+--source include/have_perfschema.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
- # Save original auto_increment_offset values.
- --let $node_1=node_1
- --let $node_2=node_2
- --source include/auto_increment_offset_save.inc
-
--connection node_2
--let $wsrep_cluster_address_saved = `SELECT @@global.wsrep_cluster_address`
diff --cc sql/CMakeLists.txt
index 0037ff23153,e7fd2680f54..8d5f0c1ce2d
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@@ -42,13 -48,25 +48,12 @@@ ${PCRE_INCLUDES
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}/sql
- ${WSREP_INCLUDES}
)
-SET(GEN_SOURCES
-${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h
-${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
-${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.h
-${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
-${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
-${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
-)
-SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES}
- PROPERTIES GENERATED 1)
-IF(NOT CMAKE_CROSSCOMPILING)
- ADD_EXECUTABLE(gen_lex_token gen_lex_token.cc
- ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h)
-ENDIF()
+
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
diff --cc sql/handler.cc
index b3481c7e429,256b2a51076..cb3f156be81
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@@ -55,6 -55,10 +55,12 @@@
#include "wsrep_mysqld.h"
#include "wsrep.h"
#include "wsrep_xid.h"
++#ifdef WITH_WSREP
+ #include "wsrep_sr.h"
++#endif
+ #include "wsrep_thd.h"
+ #include "wsrep_trans_observer.h" /* wsrep transaction hooks */
+ #include "log.h"
/*
While we have legacy_db_type, we have this array to
diff --cc sql/item_strfunc.cc
index 12618d68c27,c312b853764..38338174ae7
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@@ -5244,23 -5205,104 +5244,125 @@@ null
return NULL;
}
+Item_temptable_rowid::Item_temptable_rowid(TABLE *table_arg)
+ : Item_str_func(table_arg->in_use), table(table_arg)
+{
+ max_length= table->file->ref_length;
+}
+
+bool Item_temptable_rowid::fix_length_and_dec()
+{
+ used_tables_cache= table->map;
+ const_item_cache= false;
+ return FALSE;
+}
+
+String *Item_temptable_rowid::val_str(String *str)
+{
+ if (!((null_value= table->null_row)))
+ table->file->position(table->record[0]);
+ str_value.set((char*)(table->file->ref), max_length, &my_charset_bin);
+ return &str_value;
+}
++
+ #ifdef WITH_WSREP
+
+ #include "wsrep_mysqld.h"
+
+ String * Item_func_wsrep_last_written_gtid::val_str_ascii(String *str)
+ {
+ wsrep_gtid_t gtid;
+ wsrep_thd_last_written_gtid(current_thd, >id);
+
+ if (gtid_str.alloc(WSREP_GTID_STR_LEN))
+ {
+ my_error(ER_OUTOFMEMORY, WSREP_GTID_STR_LEN);
+ null_value= true;
+ return NULL;
+ }
+ int gtid_len = wsrep_gtid_print(>id,
+ (char*)gtid_str.ptr(),
+ WSREP_GTID_STR_LEN);
+ if (gtid_len < 0)
+ {
+ my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
+ "wsrep_gtid_print failed");
+ null_value= true;
+ return NULL;
+ }
+ gtid_str.length(gtid_len);
+ return >id_str;
+ }
+
+ String * Item_func_wsrep_last_seen_gtid::val_str_ascii(String *str)
+ {
+ wsrep_gtid_t gtid;
+ wsrep_last_committed_id(>id);
+
+ if (gtid_str.alloc(WSREP_GTID_STR_LEN))
+ {
+ my_error(ER_OUTOFMEMORY, WSREP_GTID_STR_LEN);
+ null_value= true;
+ return NULL;
+ }
+ int gtid_len= wsrep_gtid_print(>id,
+ (char*)gtid_str.ptr(),
+ WSREP_GTID_STR_LEN);
+ if (gtid_len < 0)
+ {
+ my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
+ "wsrep_gtid_print failed");
+ null_value= true;
+ return NULL;
+ }
+ gtid_str.length(gtid_len);
+ return >id_str;
+ }
+
+ longlong Item_func_wsrep_sync_wait_upto::val_int()
+ {
+ int timeout = -1;
+ String* gtid_str= args[0]->val_str(&value);
+ if (gtid_str == NULL)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ return 0LL;
+ }
+
+ if (arg_count == 2)
+ {
+ timeout = args[1]->val_int();
+ }
+
+ wsrep_gtid_t gtid;
+ int gtid_len= wsrep_gtid_scan(gtid_str->ptr(), gtid_str->length(), >id);
+ if (gtid_len < 0)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ return 0LL;
+ }
+
+ if (gtid.seqno == WSREP_SEQNO_UNDEFINED &&
+ wsrep_uuid_compare(>id.uuid, &WSREP_UUID_UNDEFINED) == 0)
+ {
+ return 1LL;
+ }
+
+ wsrep_status_t status= wsrep_sync_wait_upto(current_thd, >id, timeout);
+
+ if (status != WSREP_OK)
+ {
+ int err;
+ switch (status) {
+ case WSREP_TRX_MISSING:
+ err= ER_WRONG_ARGUMENTS;
+ break;
+ default:
+ err= ER_LOCK_WAIT_TIMEOUT;
+ }
+ my_error(err, MYF(0), func_name());
+ return 0LL;
+ }
+ return 1LL;
+ }
+ #endif /* WITH_WSREP */
diff --cc sql/item_strfunc.h
index 7c4ab93dc80,20311604742..5fd13725b45
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@@ -1784,25 -1751,54 +1784,77 @@@ public
{ return get_item_copy<Item_func_dyncol_list>(thd, this); }
};
+/*
+ this is used by JOIN_TAB::keep_current_rowid
+ and stores handler::position().
+ It has nothing to do with _rowid pseudo-column, that the parser supports.
+*/
+class Item_temptable_rowid :public Item_str_func
+{
+public:
+ TABLE *table;
+ Item_temptable_rowid(TABLE *table_arg);
+ const Type_handler *type_handler() const { return &type_handler_string; }
+ Field *create_tmp_field(bool group, TABLE *table)
+ { return create_table_field_from_handler(table); }
+ String *val_str(String *str);
+ enum Functype functype() const { return TEMPTABLE_ROWID; }
+ const char *func_name() const { return "<rowid>"; }
+ bool fix_length_and_dec();
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_temptable_rowid>(thd, this); }
+};
+
+ #ifdef WITH_WSREP
+
+ #include "../wsrep/wsrep_api.h"
+
+ class Item_func_wsrep_last_written_gtid: public Item_str_ascii_func
+ {
+ String gtid_str;
+ public:
+ Item_func_wsrep_last_written_gtid(THD *thd): Item_str_ascii_func(thd) {}
+ const char *func_name() const { return "wsrep_last_written_gtid"; }
+ String *val_str_ascii(String *);
- void fix_length_and_dec()
++ bool fix_length_and_dec()
+ {
+ max_length = WSREP_GTID_STR_LEN;
+ maybe_null = true;
++ return false;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_wsrep_last_written_gtid>(thd, this); }
+ };
+
+ class Item_func_wsrep_last_seen_gtid: public Item_str_ascii_func
+ {
+ String gtid_str;
+ public:
+ Item_func_wsrep_last_seen_gtid(THD *thd): Item_str_ascii_func(thd) {}
+ const char *func_name() const { return "wsrep_last_seen_gtid"; }
+ String *val_str_ascii(String *);
- void fix_length_and_dec()
++ bool fix_length_and_dec()
+ {
+ max_length = WSREP_GTID_STR_LEN;
+ maybe_null = true;
++ return false;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_wsrep_last_seen_gtid>(thd, this); }
+ };
+
+ class Item_func_wsrep_sync_wait_upto: public Item_int_func
+ {
+ String value;
+ public:
+ Item_func_wsrep_sync_wait_upto(THD *thd, Item *a): Item_int_func(thd, a) {}
+ Item_func_wsrep_sync_wait_upto(THD *thd, Item *a, Item* b): Item_int_func(thd, a, b) {}
+ const Type_handler *type_handler() const { return &type_handler_string; }
+ const char *func_name() const { return "wsrep_sync_wait_upto_gtid"; }
+ longlong val_int();
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_wsrep_sync_wait_upto>(thd, this); }
+ };
+ #endif /* WITH_WSREP */
-#endif /* ITEM_STRFUNC_INCLUDED */
+
+#endif /* ITEM_STRFUNC_INCLUDED */
diff --cc sql/mysqld.cc
index ce14dc678c6,7795d063d0e..d3b9ab03640
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@@ -5330,6 -5331,30 +5347,15 @@@ static int init_server_components(
}
}
- if (strlen(wsrep_provider)== 0 ||
- !strcmp(wsrep_provider, WSREP_NONE))
++ if (WSREP_NOT_SPECIFIED)
+ {
+ // enable normal operation in case no provider is specified
++#ifndef EMBEDDED_LIBRARY
+ wsrep_ready_set(TRUE);
- global_system_variables.wsrep_on = 0;
-#ifdef OUT
- wsrep_init_args args;
- args.logger_cb = wsrep_log_cb;
- args.options = (wsrep_provider_options) ?
- wsrep_provider_options : "";
- int rcode = wsrep->init(wsrep, &args);
- if (rcode)
- {
- DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode));
- WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode);
- wsrep->free(wsrep);
- free(wsrep);
- wsrep = NULL;
- }
- return rcode;
+ #endif
++ global_system_variables.wsrep_on = 0;
+ }
+
if (opt_bin_log)
{
if (mysql_bin_log.open_index_file(opt_binlog_index_name, opt_bin_logname,
diff --cc sql/protocol.cc
index 29004fe24e4,41895c153f1..d370ff38e4a
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@@ -551,8 -551,23 +551,25 @@@ static uchar *net_store_length_fast(uch
void Protocol::end_statement()
{
- /* sanity check*/
- DBUG_ASSERT_IF_WSREP(!(WSREP(thd) && thd->wsrep_conflict_state == REPLAYING));
+ /*
+ Commented out: This sanity check does not hold in general.
+ Thd->LOCK_wsrep_thd() must be unlocked before sending response
+ to client, so BF abort may sneak in here.
+ DBUG_ASSERT(!WSREP(thd) || thd->wsrep_conflict_state() == NO_CONFLICT);
+ */
+
+ /*
+ sanity check, don't send end statement while replaying
+ */
++#ifdef WITH_WSREP
+ DBUG_ASSERT(thd->wsrep_conflict_state_unsafe() != REPLAYING);
+ if (WSREP(thd) && thd->wsrep_conflict_state_unsafe()== REPLAYING)
+ {
+ WSREP_ERROR("attempting net_end_statement while replaying");
+ return;
+ }
++#endif
+
DBUG_ENTER("Protocol::end_statement");
DBUG_ASSERT(! thd->get_stmt_da()->is_sent());
bool error= FALSE;
diff --cc sql/sql_base.cc
index e46b7675bbe,e711dd004db..0587d401461
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@@ -63,6 -63,7 +63,9 @@@
#endif
#include "wsrep_mysqld.h"
#include "wsrep_thd.h"
++#ifdef WITH_WSREP
+ #include "wsrep_sr.h"
++#endif
bool
No_such_table_error_handler::handle_condition(THD *,
diff --cc sql/sql_class.h
index 25e2d736cdc,a2ae8611f41..8e08864abf7
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@@ -3212,7 -3256,6 +3232,9 @@@ public
query_id_t first_query_id;
} binlog_evt_union;
++ mysql_mutex_t LOCK_wsrep_thd;
+ mysql_cond_t COND_wsrep_thd;
++
/**
Internal parser state.
Note that since the parser is not re-entrant, we keep only one parser
@@@ -3298,8 -3346,9 +3325,9 @@@
mysql_mutex_lock(&LOCK_thd_kill);
awake_no_mutex(state_to_set);
mysql_mutex_unlock(&LOCK_thd_kill);
+ mysql_mutex_unlock(&LOCK_wsrep_thd);
}
--
++
/** Disconnect the associated communication endpoint. */
void disconnect();
@@@ -4738,13 -4666,223 +4773,221 @@@ public
const bool wsrep_applier; /* dedicated slave applier thread */
bool wsrep_applier_closing; /* applier marked to close */
bool wsrep_client_thread; /* to identify client threads*/
- bool wsrep_PA_safe;
- bool wsrep_converted_lock_session;
- bool wsrep_apply_toi; /* applier processing in TOI */
enum wsrep_exec_mode wsrep_exec_mode;
query_id_t wsrep_last_query_id;
- enum wsrep_query_state wsrep_query_state;
- enum wsrep_conflict_state wsrep_conflict_state;
+ XID wsrep_xid;
+
+ /** This flag denotes that record locking should be skipped during INSERT
+ and gap locking during SELECT. Only used by the streaming replication thread
+ that only modifies the wsrep_schema.SR table. */
+ my_bool wsrep_skip_locking;
+
+ /*
+ Delegated rollback:
+
+ Wsrep_query_state, wsrep_conflict_state and wsrep_exec_mode define
+ together the state for rollback process. In most of the cases the
+ client thread will handle the rollback, but if the BF abort happens when
+ the client thread is in QUERY_IDLE state, the rollback process
+ is delegated to rollbacker thread. In this case rollbacker thread
+ will do the rollback on behalf of client thread and will leave
+ the states into the following
+ * wsrep_query_state = QUERY_IDLE
+ * wsrep_conflict_state = ABORTED
+ * wsrep_exec_mode = LOCAL_ROLLBACK
+ */
+
+ /*
+ Set wsrep_query_state
+
+ Asserts LOCK_wsrep_thd ownership.
+ */
+ void set_wsrep_query_state(enum wsrep_query_state state)
+ {
+ mysql_mutex_assert_owner(&LOCK_wsrep_thd);
+ /*
+ State machine:
+
+ QI - QUERY_IDLE
+ QX - QUERY_EXEC
+ QC - QUERY_COMMITTING
+ QOC - QUERY_ORDERED_COMMIT
+ QE - QUERY_EXITING
+
+ |---> QE
+ |
+ o--> QI <-> QX -> QC -> QOC
+ ^ | |
+ |-------------
+ */
+ static const bool allowed[QUERY_EXITING + 1][QUERY_EXITING + 1] =
+ {
+ /* QI QX QC QOC, QE To / From */
+ { false, true, false, false, true }, /* QI */
+ { true , false, true, false, false }, /* QX */
+ { false, true, false, true, false }, /* QC */
+ { false, true, false, false, false }, /* QOC */
+ { false, false, false, false, false } /* QE */
+ };
+ if (allowed[m_wsrep_query_state][state] == false)
+ {
+ WSREP_DEBUG("Unallowed query state change %d -> %d",
+ m_wsrep_query_state, state);
+ }
+ DBUG_ASSERT(allowed[m_wsrep_query_state][state] == true);
+ m_wsrep_query_state= state;
+ }
+
+ /*
+ Return current wsrep_query_state
+
+ Asserts LOCK_wsrep_thd ownership
+ */
+ enum wsrep_query_state wsrep_query_state() const
+ {
+ mysql_mutex_assert_owner(&LOCK_wsrep_thd);
+ return m_wsrep_query_state;
+ }
+
+ /*
+ Return current wsrep_query_state
+
+ Does not assert LOCK_wsrep_thd ownership, useful for
+ debugging and logging where strict access is not
+ absolutely required.
+ */
+ enum wsrep_query_state wsrep_query_state_unsafe() const
+ {
+ return m_wsrep_query_state;
+ }
+
+ void set_wsrep_conflict_state(enum wsrep_conflict_state state)
+ {
+ mysql_mutex_assert_owner(&LOCK_wsrep_thd);
+ /*
+ State machine
+
+ NC - NO_CONFLICT
+ MA - MUST_ABORT
+ AB - ABORTING
+ AD - ABORTED
+ MR - MUST_REPLAY
+ RI - REPLAYING
+ RA - RETRY_AUTOCOMMIT
+ CF - CERT_FAILURE
+
+ 1) BF abort
+ 2) Cert failure or rollback
+ 3) Pre commit returns success, so the transaction must be replayed
+ 4) Pre commit return certification failure, cleanup after certification
+ failure
+ 5) Post rollback phase
+ 6) Is autocommit and wsrep_retry_autocommit is set
+ 7) Simultaneous certification failure and BF abort
+
+ 4 5
+ -> NC <-----------------> CF -------------------
+ | ^^ | 7 |
+ | || 1 2 | |
+ | 6||-----------> MA --------> AB ------> AD <-|
+ | | | ^ |
+ | |-> RA | 3 | |
+ | | | |
+ | -> MR -> RI - |
+ | | |
+ |------------------------------------------
+
+ */
+
+ static const bool allowed[CERT_FAILURE + 1][CERT_FAILURE + 1] =
+ {
+ /* NC MA AB AD MR RI RA CF To / From */
+ { false, true, false, false, false, false, true, true }, /* NC */
+ { true, false, true, false, true, false, false, false }, /* MA */
+ { false, false, false, true, false, false, false, false }, /* AB */
+ { true , false, false, false, false, false, false, false }, /* AD */
+ { false, false, false, false, false, true, false, false }, /* MR */
+ { true, false, true, false, false, false, false, false }, /* RI */
+ { true, false, false, false, false, false, false, false }, /* RA */
+ { true, false, true, true, false, false, false, false } /* CF */
+ };
+ if (allowed[m_wsrep_conflict_state][state] == false)
+ {
+ WSREP_DEBUG("Unallowed conflict state change %d -> %d",
+ m_wsrep_conflict_state, state);
+ }
+ DBUG_ASSERT(allowed[m_wsrep_conflict_state][state] == true);
+
+ /*
+ Sanity checks agains query state and thread context
+ */
+ switch (state)
+ {
+ case MUST_ABORT:
+ break;
+ default:
+ /*
+ Only the current thread context may change the state apart from
+ NC -> MA transition.
+ */
+ DBUG_ASSERT(this == current_thd);
+ break;
+ }
+ #ifndef DBUG_OFF
+ if (state == NO_CONFLICT)
+ {
+ m_wsrep_conflict_state_history.clear();
+ }
+ else
+ {
+ m_wsrep_conflict_state_history.push_back(m_wsrep_conflict_state);
+ }
+ #endif /* DBUG_OFF */
+ m_wsrep_conflict_state= state;
+ }
+
+ /*
+ Return wsrep_conflict_state
+
+ Asserts LOCK_wsrep_thd ownership
+ */
+ enum wsrep_conflict_state wsrep_conflict_state() const
+ {
+ mysql_mutex_assert_owner(&LOCK_wsrep_thd);
+ return m_wsrep_conflict_state;
+ }
+
+ /*
+ Return wsrep_conflict_state
+
+ Does not assert LOCK_wsrep_thd ownership, useful mostly
+ for debugging and logging where strict access is not
+ aboslutely required.
+ */
+ enum wsrep_conflict_state wsrep_conflict_state_unsafe() const
+ {
+ return m_wsrep_conflict_state;
+ }
+
+ /*
+ Check if wsrep rollback process has started
+ */
+ bool wsrep_is_rolling_back() const
+ {
+ return (wsrep_conflict_state() == MUST_ABORT ||
+ wsrep_conflict_state() == ABORTING);
+ }
+
+ private:
+ enum wsrep_query_state m_wsrep_query_state;
+ enum wsrep_conflict_state m_wsrep_conflict_state;
+ #ifndef DBUG_OFF
+ std::vector<enum wsrep_conflict_state> m_wsrep_conflict_state_history;
+ #endif /* DBUG_OFF */
+ public:
+
- mysql_mutex_t LOCK_wsrep_thd;
- mysql_cond_t COND_wsrep_thd;
+ // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75
+ // wsrep_seqno_t wsrep_trx_seqno;
wsrep_trx_meta_t wsrep_trx_meta;
uint32 wsrep_rand;
Relay_log_info *wsrep_rli;
diff --cc sql/sql_connect.cc
index b48070b9c8f,23ff25cdd8c..088dec72313
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@@ -1407,9 -1406,9 +1406,9 @@@ void do_handle_one_connection(CONNECT *
#ifdef WITH_WSREP
if (WSREP(thd))
{
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_EXITING;
+ thd->set_wsrep_query_state(QUERY_EXITING);
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
#endif
end_thread:
diff --cc sql/sql_insert.cc
index 51acf10a98a,ccd566c7d43..a6aa8b999dc
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@@ -3902,10 -3919,12 +3902,14 @@@ bool select_insert::prepare_eof(
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
- error= (IF_WSREP((thd->wsrep_conflict_state == MUST_ABORT ||
- thd->wsrep_conflict_state == CERT_FAILURE) ? -1 :, )
- (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
- table->file->ha_end_bulk_insert() : 0));
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
++
+ error= (IF_WSREP((thd->wsrep_conflict_state() == MUST_ABORT ||
+ thd->wsrep_conflict_state() == CERT_FAILURE) ? -1 :, )
- (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
- table->file->ha_end_bulk_insert() : 0));
++ (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
++ table->file->ha_end_bulk_insert() : 0));
++
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
if (likely(!error) && unlikely(thd->is_error()))
error= thd->get_stmt_da()->sql_errno();
@@@ -4564,10 -4583,17 +4568,19 @@@ bool select_create::send_eof(
if (!table->s->tmp_table)
{
#ifdef WITH_WSREP
+ if (WSREP_ON)
+ {
+ if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ (void) wsrep_ws_handle_for_trx(&thd->wsrep_ws_handle,
+ thd->wsrep_next_trx_id());
+ }
+ DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ WSREP_DEBUG("CTAS key append for trx: %lu thd %llu query %lld ",
+ thd->wsrep_trx_id(), thd->thread_id, thd->query_id);
+
/*
- append table level exclusive key for CTAS
+ append table level exclusive key for CTAS
*/
wsrep_key_arr_t key_arr= {0, 0};
wsrep_prepare_keys_for_isolation(thd,
@@@ -4591,8 -4617,7 +4604,8 @@@
return true;
}
/* If commit fails, we should be able to reset the OK status. */
- thd->get_stmt_da()->set_overwrite_status(TRUE);
+ thd->get_stmt_da()->set_overwrite_status(true);
+ }
#endif /* WITH_WSREP */
trans_commit_stmt(thd);
if (!(thd->variables.option_bits & OPTION_GTID_BEGIN))
@@@ -4600,14 -4625,14 +4613,14 @@@
#ifdef WITH_WSREP
if (WSREP_ON)
{
- thd->get_stmt_da()->set_overwrite_status(FALSE);
- mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state != NO_CONFLICT)
+ thd->get_stmt_da()->set_overwrite_status(false);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state() != NO_CONFLICT)
{
- WSREP_DEBUG("select_create commit failed, thd: %lld err: %d %s",
- (longlong) thd->thread_id, thd->wsrep_conflict_state,
- thd->query());
+ WSREP_DEBUG("select_create commit failed, thd: %lld err: %d %s",
+ thd->thread_id, thd->wsrep_conflict_state(),
+ WSREP_QUERY(thd));
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
abort_result_set();
DBUG_RETURN(true);
}
diff --cc sql/sql_parse.cc
index 1baa26ab465,49629030dcf..18cded52a74
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@@ -1576,38 -1506,77 +1507,77 @@@ bool dispatch_command(enum enum_server_
compile_time_assert(COM_END == 255);
#ifdef WITH_WSREP
- if (WSREP(thd))
+ bool wsrep_on= WSREP_ON;
+ if (wsrep_on)
{
- if (!thd->in_multi_stmt_transaction_mode())
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ DBUG_ASSERT(thd->wsrep_query_state() == QUERY_IDLE);
+ if (thd->wsrep_is_rolling_back())
{
- thd->wsrep_PA_safe= true;
+ /*
+ Rollback thread is rolling back a transaction for this thd,
+ wait until it has finished.
+ */
+ while (thd->wsrep_is_rolling_back())
+ {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ my_sleep(1000);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ }
+ DBUG_ASSERT(thd->wsrep_conflict_state() == ABORTED);
}
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_EXEC;
- if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
- {
- thd->wsrep_conflict_state= NO_CONFLICT;
- }
- if (thd->wsrep_conflict_state== MUST_ABORT)
- {
- wsrep_client_rollback(thd);
- }
- /* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */
- if (thd->wsrep_conflict_state == ABORTED &&
- command != COM_STMT_CLOSE && command != COM_QUIT)
+ /*
+ BF aborter should atomically check thd query state and start
+ background rollback process if the thd query state is QUERY_IDLE.
+ Because the wait for the background rollback is done above we should
+ be here either in NO_CONFLICT or in ABORTED state.
+ */
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT ||
+ thd->wsrep_conflict_state() == ABORTED);
+
+ thd->set_wsrep_query_state(QUERY_EXEC);
+
+ /*
+ Aborted by background rollbacker thread. Jump straight to dispatch_end
+ label where the error handling is performed.
+
+ We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted.
+ (see MDEV-10812).
+ */
+ if (thd->wsrep_conflict_state() == ABORTED)
{
- my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
- MYF(0));
- WSREP_DEBUG("Deadlock error for: %s", thd->query());
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- thd->reset_killed();
- thd->mysys_var->abort = 0;
- thd->wsrep_conflict_state = NO_CONFLICT;
- thd->wsrep_retry_counter = 0;
- goto dispatch_end;
+ thd->store_globals();
+ WSREP_LOG_THD(thd, "enter found BF aborted");
+ DBUG_ASSERT(!thd->get_stmt_da()->is_set());
+
+ if (command == COM_STMT_PREPARE ||
+ command == COM_STMT_FETCH ||
+ command == COM_STMT_SEND_LONG_DATA ||
+ command == COM_STMT_CLOSE ||
+ command == COM_QUIT
+ )
+ {
+ WSREP_DEBUG("Prepared Statement bail out or COM_QUIT");
+ }
+ else
+ {
+ thd->reset_killed();
+ thd->mysys_var->abort = 0;
+ thd->wsrep_retry_counter = 0;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ #ifdef WSREP_TODO
+ /*
+ Increment threads running to compensate dec_thread_running() called
+ after dispatch_end label.
+ */
+ inc_thread_running();
+ #endif /* WSREP_TODO */
+ goto dispatch_end;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
}
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
#endif /* WITH_WSREP */
#if defined(ENABLED_PROFILING)
@@@ -1840,8 -1816,27 +1817,29 @@@
break;
if (WSREP_ON)
- wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
- is_com_multi, is_next_command);
+ {
+ if (wsrep_mysql_parse(thd, thd->query(), thd->query_length(),
+ &parser_state,
+ is_com_multi, is_next_command))
+ {
+ WSREP_DEBUG("Deadlock error for: %s", thd->query());
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->killed = NOT_KILLED;
+ thd->mysys_var->abort = 0;
++#ifdef WITH_WSREP
+ thd->wsrep_retry_counter = 0;
++#endif
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ #ifdef WSREP_TODO
+ /*
+ Increment threads running to compensate dec_thread_running() called
+ after dispatch_end label.
+ */
+ inc_thread_running();
+ #endif /* WSREP_TODO */
+ goto dispatch_end;
+ }
+ }
else
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
is_com_multi, is_next_command);
@@@ -1930,8 -1925,28 +1928,30 @@@
parser_state.reset(beginning_of_next_stmt, length);
if (WSREP_ON)
- wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state,
- is_com_multi, is_next_command);
+ {
+ if (wsrep_mysql_parse(thd, beginning_of_next_stmt,
+ length, &parser_state,
+ is_com_multi, is_next_command))
+ {
+ WSREP_DEBUG("Deadlock error for: %s", thd->query());
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->killed = NOT_KILLED;
+ thd->mysys_var->abort = 0;
++#ifdef WITH_WSREP
+ thd->wsrep_retry_counter = 0;
++#endif
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ #ifdef WSREP_TODO
+ /*
+ Increment threads running to compensate dec_thread_running() called
+ after dispatch_end label.
+ */
+ inc_thread_running();
+ #endif /* WSREP_TODO */
+
+ goto dispatch_end;
+ }
+ }
else
mysql_parse(thd, beginning_of_next_stmt, length, &parser_state,
is_com_multi, is_next_command);
@@@ -2367,10 -2382,10 +2387,10 @@@ com_multi_end
break;
}
--#ifdef WITH_WSREP
dispatch_end:
++#ifdef WITH_WSREP
- if (WSREP(thd))
+ if (wsrep_on)
{
/*
MDEV-10812
@@@ -2378,15 -2393,52 +2398,51 @@@
*/
DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE)
|| thd->get_stmt_da()->is_disabled());
- /* wsrep BF abort in query exec phase */
- mysql_mutex_lock(&thd->LOCK_thd_data);
- do_end_of_statement= thd->wsrep_conflict_state != REPLAYING &&
- thd->wsrep_conflict_state != RETRY_AUTOCOMMIT;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
- else
- do_end_of_statement= true;
+ /*
+ BF aborted before sending response back to client
+ */
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ do_end_of_statement= thd->wsrep_conflict_state() != REPLAYING &&
+ thd->wsrep_conflict_state() != RETRY_AUTOCOMMIT;
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ wsrep_client_rollback(thd);
+ wsrep_post_rollback(thd);
+ DBUG_ASSERT(thd->wsrep_conflict_state() == ABORTED);
+ }
+ if (thd->wsrep_conflict_state() == ABORTED &&
+ !(command == COM_STMT_PREPARE ||
+ command == COM_STMT_FETCH ||
+ command == COM_STMT_SEND_LONG_DATA ||
+ command == COM_STMT_CLOSE ||
+ command == COM_QUIT
+ ))
+ {
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ wsrep_cleanup_transaction(thd);
+ WSREP_LOG_THD(thd, "leave");
+ }
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ /*
+ Final check after sending response back to client. Handle possible
+ BF abort and query state change atomically. Don't call
+ wsrep_cleanup_transaction() to leave thd->wsrep_conflict_state()
+ to ABORTED so that the rollback will be detected when the client
+ returns to action.
+ */
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ wsrep_client_rollback(thd);
+ wsrep_post_rollback(thd);
+ WSREP_LOG_THD(thd, "after return to client found BF aborted");
+ }
+ thd->set_wsrep_query_state(QUERY_IDLE);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ } else { /* if (WSREP(thd))... */
+ do_end_of_statement= true;
+ }
#endif /* WITH_WSREP */
if (do_end_of_statement)
@@@ -4758,12 -4822,10 +4826,10 @@@ end_with_restore_list
case SQLCOM_INSERT_SELECT:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
- select_result *sel_result;
+ select_insert *sel_result;
bool explain= MY_TEST(lex->describe);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (WSREP_CLIENT(thd) &&
- wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE))
- goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
if ((res= insert_precheck(thd, all_tables)))
break;
@@@ -7854,35 -7909,35 +7961,46 @@@ static bool wsrep_mysql_parse(THD *thd
com_statement_info[thd->get_command()].m_key);
MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(),
thd->query_length());
+
+ DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
+ {
+ const char act[]=
+ "now "
+ "SIGNAL wsrep_retry_autocommit_reached "
+ "WAIT_FOR wsrep_retry_autocommit_continue";
+ DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
+ });
}
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
mysql_parse(thd, rawbuf, length, parser_state, is_com_multi,
is_next_command);
+ (void) wsrep_after_command(thd, !thd->in_active_multi_stmt_transaction());
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ /*
+ State after after_command hook must be either NO_CONFLICT
+ or MUST_ABORT if the BF abort happened just after leaving
+ after_command hook.
+ */
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT ||
+ thd->wsrep_conflict_state() == MUST_ABORT ||
+ thd->wsrep_conflict_state() == RETRY_AUTOCOMMIT);
if (WSREP(thd)) {
/* wsrep BF abort in query exec phase */
- mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state == MUST_ABORT) {
+ if (thd->wsrep_conflict_state() == MUST_ABORT) {
wsrep_client_rollback(thd);
WSREP_DEBUG("abort in exec query state, avoiding autocommit");
}
- if (thd->wsrep_conflict_state == MUST_REPLAY)
+ /* note: this is obsolete, comin from 10.3.6 merging */
+ if (thd->wsrep_conflict_state() == MUST_REPLAY)
{
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ WSREP_WARN("EXPLAIN DELETED");
if (thd->lex->explain)
delete_explain_query(thd->lex);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+
wsrep_replay_transaction(thd);
}
@@@ -7957,8 -8061,9 +8124,9 @@@
thd->wsrep_retry_query_len = 0;
thd->wsrep_retry_command = COM_CONNECT;
}
+#endif /* WITH_WSREP */
+ return false;
}
-#endif /* WITH_WSREP */
/*
When you modify mysql_parse(), you may need to modify
diff --cc sql/sql_prepare.cc
index c615356b354,6d77497e68f..c9a36b02fe4
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@@ -4197,8 -4196,8 +4197,8 @@@ reexecute
if (WSREP_ON)
{
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- switch (thd->wsrep_conflict_state)
+ switch (thd->wsrep_conflict_state())
{
case CERT_FAILURE:
WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %lld err: %d",
@@@ -4393,8 -4392,8 +4393,8 @@@ reexecute
if (WSREP_ON)
{
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- switch (thd->wsrep_conflict_state)
+ switch (thd->wsrep_conflict_state())
{
case CERT_FAILURE:
WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %lld err: %d",
diff --cc sql/sql_truncate.cc
index d515aacd1d0,1fcab7e480c..2239afbb13b
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@@ -416,9 -416,20 +416,23 @@@ bool Sql_cmd_truncate_table::truncate_t
if (WSREP(thd) &&
wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, 0))
DBUG_RETURN(TRUE);
- if (lock_table(thd, table_ref, &hton_can_recreate))
- DBUG_RETURN(TRUE);
+
+ /*
+ When using non-blocking operation for TRUNCATE always fall to
+ handler_truncate() in order to avoid calling lock_table_names()
+ twice.
+ */
++#ifdef WITH_WSREP
+ if (WSREP(thd) && thd->wsrep_nbo_ctx) {
+ hton_can_recreate= false;
+ }
+ else
++#endif
+ {
+ if (lock_table(thd, table_ref, &hton_can_recreate))
+ DBUG_RETURN(TRUE);
+ }
+
if (hton_can_recreate)
{
/*
diff --cc sql/wsrep_applier.cc
index f2d90def5ef,32e153b29dd..e3de1e160a4
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@@ -14,6 -14,6 +14,7 @@@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "mariadb.h"
++#include "my_pthread.h"
#include "wsrep_priv.h"
#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
#include "wsrep_xid.h"
@@@ -95,14 -146,20 +147,20 @@@ int wsrep_apply_events(THD* thd
{
WSREP_INFO("applier has been aborted, skipping apply_rbr: %lld",
(long long) wsrep_thd_trx_seqno(thd));
- DBUG_RETURN(WSREP_CB_FAILURE);
+ DBUG_RETURN(WSREP_ERR_ABORTED);
}
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_EXEC;
- if (thd->wsrep_conflict_state!= REPLAYING)
- thd->wsrep_conflict_state= NO_CONFLICT;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ // thd->set_wsrep_query_state(QUERY_EXEC);
+ if (thd->wsrep_conflict_state() != REPLAYING)
+ {
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+ if (thd->wsrep_conflict_state() != NO_CONFLICT)
+ {
+ thd->set_wsrep_conflict_state(NO_CONFLICT);
+ }
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld",
(long long) wsrep_thd_trx_seqno(thd));
@@@ -197,9 -254,8 +255,8 @@@
}
error:
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_IDLE;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
assert(thd->wsrep_exec_mode== REPL_RECV);
diff --cc sql/wsrep_dummy.cc
index 0b6e7e0d5bb,4f099460919..57cc0d51997
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@@ -17,7 -17,7 +17,13 @@@
#include <sql_class.h>
#include <mysql/service_wsrep.h>
- my_bool wsrep_thd_is_BF(THD *, my_bool)
++int64_t wsrep_thd_trx_seqno(const THD *)
++{ return 0;}
++
++my_thread_id wsrep_thd_thread_id(THD *thd)
++{ return (my_thread_id)0; }
++
+ my_bool wsrep_thd_is_BF(void *, my_bool)
{ return 0; }
int wsrep_trx_order_before(THD *, THD *)
@@@ -38,6 -39,10 +45,9 @@@ const unsigned char* wsrep_xid_uuid(con
return uuid;
}
-#ifdef TODO
+ bool wsrep_prepare_key_for_innodb(THD* thd, const uchar*, size_t, const uchar*, size_t, struct wsrep_buf*, size_t*)
-{ return -1; }
-#endif
++{ return 0; }
++
bool wsrep_prepare_key(const uchar*, size_t, const uchar*, size_t, struct wsrep_buf*, size_t*)
{ return 0; }
@@@ -77,6 -82,6 +87,9 @@@ bool wsrep_consistency_check(THD *
void wsrep_lock_rollback()
{ }
++int wsrep_on(void *)
++{ return 0;}
++
int wsrep_on(THD *thd)
{ return 0; }
diff --cc sql/wsrep_mysqld.cc
index 0a2735fe0b7,49f60f5241b..951497e100f
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@@ -33,11 -35,19 +35,18 @@@
#include "wsrep_var.h"
#include "wsrep_binlog.h"
#include "wsrep_applier.h"
+ #include "wsrep_sr.h"
+ #include "wsrep_sr_file.h"
+ #include "wsrep_sr_table.h"
+ #include "wsrep_schema.h"
+ #include "wsrep_thd_pool.h"
#include "wsrep_xid.h"
+ #include "wsrep_trans_observer.h"
#include <cstdio>
#include <cstdlib>
+ #include <string>
#include "log_event.h"
#include <slave.h>
-#include "sql_plugin.h" /* wsrep_plugins_pre_init() */
wsrep_t *wsrep = NULL;
/*
@@@ -145,11 -166,16 +165,15 @@@ PSI_mutex_key key_LOCK_wsrep_thd
key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst,
key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init,
key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync,
- key_LOCK_wsrep_config_state;
+ key_LOCK_wsrep_config_state,
+ key_LOCK_wsrep_SR_pool,
+ key_LOCK_wsrep_SR_store, key_LOCK_wsrep_thd_pool, key_LOCK_wsrep_nbo,
+ key_LOCK_wsrep_thd_queue;
- PSI_cond_key key_COND_wsrep_rollback,
+ PSI_cond_key key_COND_wsrep_thd,
key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst,
- key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread;
+ key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread,
+ key_COND_wsrep_nbo, key_COND_wsrep_thd_queue;
-
PSI_file_key key_file_wsrep_gra_log;
@@@ -212,11 -242,24 +240,25 @@@ long long wsrep_local_bf_aborts =
const char* wsrep_provider_name = provider_name;
const char* wsrep_provider_version = provider_version;
const char* wsrep_provider_vendor = provider_vendor;
+ char* wsrep_provider_capabilities = NULL;
+ char* wsrep_cluster_capabilities = NULL;
/* End wsrep status variables */
- wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED;
- wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED;
- long wsrep_protocol_version = 3;
+ wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED;
+ wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED;
+ wsp::node_status local_status;
+ static wsrep_view_status_t local_view_status = WSREP_VIEW_NON_PRIMARY;
+
+ class SR_storage_file *wsrep_SR_store_file = NULL;
+ class SR_storage_table *wsrep_SR_store_table = NULL;
+ class SR_storage *wsrep_SR_store = NULL;
+
+ /*
+ */
+ #define WSREP_THD_POOL_SIZE 16
+ Wsrep_thd_pool* wsrep_thd_pool= 0;
+ Wsrep_schema *wsrep_schema= 0;
++static bool wsrep_schema_inited= false;
wsp::Config_state *wsrep_config_state;
@@@ -296,19 -344,178 +343,187 @@@ void wsrep_init_sidno(const wsrep_uuid_
}
#endif /* GTID_SUPPORT */
- static wsrep_cb_status_t
- wsrep_view_handler_cb (void* app_ctx,
- void* recv_ctx,
- const wsrep_view_info_t* view,
- const char* state,
- size_t state_len,
- void** sst_req,
- size_t* sst_req_len)
+ void wsrep_init_schema()
{
- *sst_req = NULL;
- *sst_req_len = 0;
- DBUG_ASSERT(!wsrep_schema);
-
+ WSREP_INFO("wsrep_init_schema_and_SR %p %p", wsrep_schema, wsrep_SR_store);
+ if (!wsrep_schema)
+ {
+ if (wsrep_before_SE()) {
+ delete wsrep_thd_pool;
++ wsrep_thd_pool=0;
++ }
++
++ if (!wsrep_thd_pool) {
+ wsrep_thd_pool= new Wsrep_thd_pool(WSREP_THD_POOL_SIZE);
+ }
++
+ wsrep_schema= new Wsrep_schema(wsrep_thd_pool);
- if (wsrep_schema->init())
++
++ if (strcmp (wsrep_provider, WSREP_NONE))
+ {
- WSREP_ERROR("Failed to init wsrep schema");
- unireg_abort(1);
++ if (wsrep_schema->init())
++ {
++ WSREP_ERROR("Failed to init wsrep schema");
++ delete wsrep_schema;
++ delete wsrep_thd_pool;
++ unireg_abort(1);
++ }
+ }
+ }
+ }
+
+ void wsrep_init_SR()
+ {
+ /* initialize SR pools, now that innodb has initialized */
+ if (wsrep_SR_store && wsrep_SR_store->init(wsrep_cluster_state_uuid,
+ wsrep_schema)) {
+ WSREP_ERROR("wsrep SR persistency store initialization failed");
+ unireg_abort(1);
+ }
+ else {
+ if (wsrep_SR_store && wsrep_SR_store->restore(0)) {
+ WSREP_ERROR("wsrep SR persistency restore failed");
+ unireg_abort(1);
+ }
+ }
+ }
+
+ int wsrep_replay_from_SR_store(THD* thd, const wsrep_trx_meta_t& meta)
+ {
+ DBUG_ENTER("wsrep_replay_from_SR_store");
+ if (!wsrep_SR_store) {
+ WSREP_ERROR("no SR persistency store defined, can't replay");
+ DBUG_RETURN(1);
+ }
+
+ int ret= wsrep_SR_store->replay_trx(thd, meta);
+ DBUG_RETURN(ret);
+ }
+
+ static void wsrep_rollback_SR_connections()
+ {
+ THD *tmp;
+ mysql_mutex_lock(&LOCK_thread_count);
+
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++))
+ {
+ mysql_mutex_lock(&tmp->LOCK_wsrep_thd);
+ if (tmp->wsrep_client_thread && tmp->wsrep_is_streaming())
+ {
+ tmp->set_wsrep_conflict_state(MUST_ABORT);
+ if (tmp->wsrep_query_state() == QUERY_IDLE)
+ {
+ wsrep_fire_rollbacker(tmp);
+ }
+ /*
+ No need to send rollback fragment for this trx: slaves rollback
+ all SR transactions whose master goes non-Primary.
+ */
+ tmp->wsrep_SR_rollback_replicated_for_trx= tmp->wsrep_trx_id();
+ }
+ mysql_mutex_unlock(&tmp->LOCK_wsrep_thd);
+ }
+
+ mysql_mutex_unlock(&LOCK_thread_count);
+ }
+
+ /** Export the WSREP provider's capabilities as a human readable string.
+ * The result is saved in a dynamically allocated string of the form:
+ * :cap1:cap2:cap3:
+ */
+ static void wsrep_capabilities_export(wsrep_cap_t const cap, char** str)
+ {
+ static const char* names[] =
+ {
+ /* Keep in sync with wsrep/wsrep_api.h WSREP_CAP_* macros. */
+ "MULTI_MASTER",
+ "CERTIFICATION",
+ "PARALLEL_APPLYING",
+ "TRX_REPLAY",
+ "ISOLATION",
+ "PAUSE",
+ "CAUSAL_READS",
+ "CAUSAL_TRX",
+ "INCREMENTAL_WRITESET",
+ "SESSION_LOCKS",
+ "DISTRIBUTED_LOCKS",
+ "CONSISTENCY_CHECK",
+ "UNORDERED",
+ "ANNOTATION",
+ "PREORDERED",
+ "STREAMING",
+ "SNAPSHOT",
+ "NBO",
+ };
+
+ std::string s;
+ for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i)
+ {
+ if (cap & (1ULL << i))
+ {
+ if (s.empty())
+ {
+ s = ":";
+ }
+ s += names[i];
+ s += ":";
+ }
+ }
+
+ /* A read from the string pointed to by *str may be started at any time,
+ * so it must never point to free(3)d memory or non '\0' terminated string. */
+
+ char* const previous = *str;
+
+ *str = strdup(s.c_str());
+
+ if (previous != NULL)
+ {
+ free(previous);
+ }
+ }
+
+ wsrep_cb_status_t
+ wsrep_connected_handler_cb(void* app_ctx,
+ const wsrep_view_info_t* initial_view)
+ {
+ if (initial_view->my_idx < 0) {
+ WSREP_ERROR("Invalid index %d in initial view", initial_view->my_idx);
+ return WSREP_CB_FAILURE;
+ }
+
+ node_uuid= initial_view->members[initial_view->my_idx].id;
+ cluster_uuid= initial_view->state_id.uuid;
+ wsrep_cluster_status= cluster_status_str[initial_view->status];
+
+ char node_uuid_str[WSREP_UUID_STR_LEN + 1];
+ (void)wsrep_uuid_print(&node_uuid, node_uuid_str, sizeof(node_uuid_str));
+ (void)wsrep_uuid_print(&cluster_uuid, cluster_uuid_str,
+ sizeof(cluster_uuid_str));
+
+ WSREP_INFO("Connected to cluster %s with id: %s",
+ cluster_uuid_str, node_uuid_str);
+ return WSREP_CB_SUCCESS;
+ }
- wsrep_member_status_t memb_status= wsrep_config_state->get_status();
+ static wsrep_cb_status_t
+ wsrep_view_handler_cb(void* app_ctx,
+ void* recv_ctx,
+ const wsrep_view_info_t* view,
+ /* TODO: These are unused, should be removed?*/
+ const char* state,
+ size_t state_len)
+ {
+ /* Allow calling view handler from non-applier threads */
+ struct st_my_thread_var* tmp_thread_var= 0;
+ if (!my_thread_var) {
+ my_thread_init();
+ tmp_thread_var= my_thread_var;
+ }
+
+ wsrep_cb_status_t ret= WSREP_CB_SUCCESS;
+ wsrep_member_status_t new_status= local_status.get();
if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t)))
{
@@@ -853,6 -1233,12 +1240,14 @@@ void wsrep_init_startup (bool first
void wsrep_deinit(bool free_options)
{
DBUG_ASSERT(wsrep_inited == 1);
- delete wsrep_schema;
++ if (wsrep_schema)
++ delete wsrep_schema;
+ wsrep_schema= 0;
+ WSREP_DEBUG("wsrep_deinit, free %d", free_options);
- delete wsrep_thd_pool;
++ if (wsrep_thd_pool)
++ delete wsrep_thd_pool;
+ wsrep_thd_pool= 0;
+
wsrep_unload(wsrep);
wsrep= 0;
provider_name[0]= '\0';
@@@ -1000,13 -1462,15 +1471,17 @@@ bool wsrep_start_replication(
bool wsrep_must_sync_wait (THD* thd, uint mask)
{
- return (thd->variables.wsrep_sync_wait & mask) &&
+ bool ret;
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ ret= (thd->variables.wsrep_sync_wait & mask) &&
thd->variables.wsrep_on &&
+ !(thd->variables.wsrep_dirty_reads &&
+ !is_update_query(thd->lex->sql_command)) &&
!thd->in_active_multi_stmt_transaction() &&
- thd->wsrep_conflict_state != REPLAYING &&
+ thd->wsrep_conflict_state() != REPLAYING &&
thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ return ret;
}
bool wsrep_sync_wait (THD* thd, uint mask)
@@@ -1399,8 -1972,97 +1983,97 @@@ create_view_query(THD *thd, uchar** buf
}
/* Forward declarations. */
- static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
- static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
+ int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
+ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
+ /*
+ Rewrite DROP TABLE for TOI. Temporary tables are eliminated from
+ the query as they are visible only to client connection.
+
+ TODO: See comments for sql_base.cc:drop_temporary_table() and refine
+ the function to deal with transactional locked tables.
+ */
+ static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len)
+ {
+
+ LEX* lex= thd->lex;
- SELECT_LEX* select_lex= &lex->select_lex;
++ SELECT_LEX* select_lex= lex->first_select_lex();
+ TABLE_LIST* first_table= select_lex->table_list.first;
+ String buff;
+
+ bool found_temp_table= false;
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (thd->find_temporary_table(table->db.str, table->table_name.str))
+ {
+ found_temp_table= true;
+ break;
+ }
+ }
+
+ if (found_temp_table)
+ {
+ buff.append("DROP TABLE ");
+ if (lex->create_info.if_exists())
+ buff.append("IF EXISTS ");
+
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (!thd->find_temporary_table(table->db.str, table->table_name.str))
+ {
+ append_identifier(thd, &buff, table->db.str, table->db.length);
+ buff.append(".");
+ append_identifier(thd, &buff, table->table_name.str, table->table_name.length);
+ buff.append(",");
+ }
+ }
+
+ /* Chop the last comma */
+ buff.chop();
+ buff.append(" /* generated by wsrep */");
+
+ WSREP_DEBUG("Rewrote '%s' as '%s'", thd->query(), buff.ptr());
+
+ return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
+ }
+ else
+ {
+ return wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
+ buf, buf_len);
+ }
+ }
+
+ static int wsrep_TOI_event_buf(THD* thd, uchar** buf, size_t* buf_len)
+ {
+ int err;
+ switch (thd->lex->sql_command)
+ {
+ case SQLCOM_CREATE_VIEW:
+ err= create_view_query(thd, buf, buf_len);
+ break;
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_CREATE_SPFUNCTION:
+ err= wsrep_create_sp(thd, buf, buf_len);
+ break;
+ case SQLCOM_CREATE_TRIGGER:
+ err= wsrep_create_trigger_query(thd, buf, buf_len);
+ break;
+ case SQLCOM_CREATE_EVENT:
+ err= wsrep_create_event_query(thd, buf, buf_len);
+ break;
+ case SQLCOM_ALTER_EVENT:
+ err= wsrep_alter_event_query(thd, buf, buf_len);
+ break;
+ case SQLCOM_DROP_TABLE:
+ err= wsrep_drop_table_query(thd, buf, buf_len);
+ break;
+ default:
+ err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), buf,
+ buf_len);
+ break;
+ }
+
+ return err;
+ }
/*
Decide if statement should run in TOI.
@@@ -1831,10 -2773,11 +2784,11 @@@ bool wsrep_grant_mdl_exception(MDL_cont
lock is not granted to the requester THD, thus it has to wait.
@return false
*/
+ mysql_mutex_lock(&request_thd->LOCK_wsrep_thd);
if (request_thd->wsrep_exec_mode == TOTAL_ORDER ||
- request_thd->wsrep_exec_mode == REPL_RECV)
- {
+ request_thd->wsrep_exec_mode == REPL_RECV) {
+
- mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&request_thd->LOCK_thd_data);
WSREP_MDL_LOG(DEBUG, "MDL conflict ", schema, schema_len,
request_thd, granted_thd);
ticket->wsrep_report(wsrep_debug);
@@@ -1854,8 -2809,24 +2820,24 @@@
{
WSREP_DEBUG("BF thread waiting for FLUSH");
ticket->wsrep_report(wsrep_debug);
- mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
- ret= false;
+ ret = FALSE;
+ }
+ else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
+ {
+ WSREP_DEBUG("DROP caused BF abort");
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
+ ret = FALSE;
+ }
+ else if (granted_thd->wsrep_query_state() == QUERY_COMMITTING)
+ {
+ WSREP_DEBUG("mdl granted, but commiting thd abort scheduled");
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
+ ret = FALSE;
}
else
{
@@@ -1886,9 -2872,8 +2883,8 @@@
}
else
{
- mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&request_thd->LOCK_thd_data);
}
-
return ret;
}
@@@ -2043,9 -3133,9 +3144,9 @@@ static inline bool is_replaying_connect
{
bool ret;
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false;
+ ret= (thd->wsrep_conflict_state() == REPLAYING) ? true : false;
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
return ret;
}
@@@ -2055,9 -3145,9 +3156,9 @@@ static inline bool is_committing_connec
{
bool ret;
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
- ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false;
+ ret= (thd->wsrep_query_state() == QUERY_COMMITTING) ? true : false;
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
return ret;
}
diff --cc sql/wsrep_mysqld.h
index 699a4daf27a,82e8ceafc45..5145fe86a19
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@@ -24,36 -26,71 +24,28 @@@
#ifdef WITH_WSREP
typedef struct st_mysql_show_var SHOW_VAR;
-#include "mysqld.h"
-#include "log.h"
++
#include <sql_priv.h>
--//#include "rpl_gtid.h"
#include "../wsrep/wsrep_api.h"
#include "mdl.h"
#include "mysqld.h"
-#include "log.h"
#include "sql_table.h"
+ #include <vector>
+
#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX
class set_var;
class THD;
+ typedef std::vector<wsrep_trx_meta_t> wsrep_fragment_set;
+
-enum wsrep_exec_mode {
- LOCAL_STATE,
- REPL_RECV,
- TOTAL_ORDER,
- LOCAL_COMMIT,
- LOCAL_ROLLBACK
-};
-
-enum wsrep_query_state {
- QUERY_IDLE,
- QUERY_EXEC,
- QUERY_COMMITTING,
- QUERY_ORDERED_COMMIT,
- QUERY_EXITING
-};
-
-enum wsrep_conflict_state {
- NO_CONFLICT,
- MUST_ABORT,
- ABORTING,
- ABORTED,
- MUST_REPLAY,
- REPLAYING,
- RETRY_AUTOCOMMIT,
- CERT_FAILURE
-};
-
enum wsrep_consistency_check_mode {
NO_CONSISTENCY_CHECK,
CONSISTENCY_CHECK_DECLARED,
CONSISTENCY_CHECK_RUNNING,
};
-#ifdef OLD_MARIADB
--struct wsrep_thd_shadow {
-- ulonglong options;
-- uint server_status;
-- enum wsrep_exec_mode wsrep_exec_mode;
-- Vio *vio;
-- ulong tx_isolation;
-- const char *db;
-- size_t db_length;
-- my_hrtime_t user_time;
-- longlong row_count_func;
--};
-
-#endif
// Global wsrep parameters
extern wsrep_t* wsrep;
@@@ -77,7 -116,8 +69,6 @@@ extern const char* wsrep_start_position
extern ulong wsrep_max_ws_size;
extern ulong wsrep_max_ws_rows;
extern const char* wsrep_notify_cmd;
- extern long wsrep_max_protocol_version;
-extern my_bool wsrep_certify_nonPK;
-//extern int wsrep_protocol_version;
extern ulong wsrep_forced_binlog_format;
extern my_bool wsrep_desync;
extern ulong wsrep_reject_queries;
@@@ -114,9 -162,16 +110,17 @@@ enum enum_wsrep_sync_wait
WSREP_SYNC_WAIT_MAX = 0xF
};
+ enum enum_wsrep_ignore_apply_error {
+ WSREP_IGNORE_ERRORS_NONE = 0x0,
+ WSREP_IGNORE_ERRORS_ON_RECONCILING_DDL = 0x1,
+ WSREP_IGNORE_ERRORS_ON_RECONCILING_DML = 0x2,
+ WSREP_IGNORE_ERRORS_ON_DDL = 0x4,
+ WSREP_IGNORE_ERRORS_MAX = 0x7
+ };
+
// MySQL status variables
extern my_bool wsrep_connected;
+extern my_bool wsrep_ready;
extern const char* wsrep_cluster_state_uuid;
extern long long wsrep_cluster_conf_id;
extern const char* wsrep_cluster_status;
@@@ -126,9 -181,14 +130,12 @@@ extern long long wsrep_local_bf_abort
extern const char* wsrep_provider_name;
extern const char* wsrep_provider_version;
extern const char* wsrep_provider_vendor;
+ extern char* wsrep_provider_capabilities;
+ extern char* wsrep_cluster_capabilities;
- int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope);
-//int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff,
-// enum enum_var_type scope);
+ int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
+ int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff);
+ void wsrep_free_status(THD *thd);
int wsrep_init();
void wsrep_deinit(bool free_options);
@@@ -147,20 -207,43 +154,19 @@@ void wsrep_init_startup(bool before)
// Other wsrep global variables
extern my_bool wsrep_inited; // whether wsrep is initialized ?
-extern "C" {
- enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
- enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd, my_bool sync);
- void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
- void wsrep_thd_set_conflict_state(
- THD *thd, enum wsrep_conflict_state state);
-//void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
-//void wsrep_thd_set_conflict_state(
-// THD *thd, enum wsrep_conflict_state state);
--
- extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
- extern "C" void wsrep_thd_set_query_state(
- THD *thd, enum wsrep_query_state state);
-enum wsrep_query_state wsrep_thd_query_state(THD *thd);
-
-const char * wsrep_thd_exec_mode_str(THD *thd);
-const char * wsrep_thd_conflict_state_str(THD *thd);
-const char * wsrep_thd_query_state_str(THD *thd);
-wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd);
-}
--
extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id);
--
+ extern "C" void wsrep_fire_rollbacker(THD *thd);
extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
extern "C" time_t wsrep_thd_query_start(THD *thd);
-extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
-extern "C" int64_t wsrep_thd_trx_seqno(const THD *thd);
extern "C" query_id_t wsrep_thd_query_id(THD *thd);
+ extern "C" wsrep_trx_id_t wsrep_thd_next_trx_id(THD *thd);
+ extern "C" wsrep_trx_id_t wsrep_thd_trx_id(THD *thd);
-extern "C" char * wsrep_thd_query(THD *thd);
-//extern char * wsrep_thd_query(THD *thd);
extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd);
extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id);
- extern void wsrep_close_client_connections(my_bool wait_to_end);
+ extern "C" void wsrep_thd_last_written_gtid(THD *thd, wsrep_gtid_t *t);
+ extern "C" ulong wsrep_thd_trx_fragment_size(THD *thd);
-extern void wsrep_thd_xid(const void *thd_ptr, void *xid, size_t xid_size);
+
extern int wsrep_wait_committing_connections_close(int wait_time);
extern void wsrep_close_applier(THD *thd);
extern void wsrep_wait_appliers_close(THD *thd);
@@@ -186,8 -280,11 +203,15 @@@ extern wsrep_seqno_t wsrep_locked_seqno
wsrep_provider && \
strcmp(wsrep_provider, WSREP_NONE))
++#define WSREP_NOT_SPECIFIED \
++ (strlen(wsrep_provider)== 0 || \
++ !strcmp(wsrep_provider, WSREP_NONE))
++
#define WSREP(thd) \
- (WSREP_ON && thd->variables.wsrep_on)
+ (thd && WSREP_NNULL(thd))
+
+ #define WSREP_CLIENT_NNULL(thd) \
+ (WSREP_NNULL(thd) && thd->wsrep_client_thread)
#define WSREP_CLIENT(thd) \
(WSREP(thd) && thd->wsrep_client_thread)
@@@ -231,6 -344,30 +259,22 @@@ void wsrep_log(void (*fun)(const char *
extern my_bool wsrep_ready_get();
extern void wsrep_ready_wait();
-#ifndef OUT
-enum wsrep_trx_status {
- WSREP_TRX_OK,
- WSREP_TRX_CERT_FAIL, /* certification failure, must abort */
- WSREP_TRX_SIZE_EXCEEDED, /* trx size exceeded */
- WSREP_TRX_ERROR, /* native mysql error */
-};
-#endif
+ static inline
+ wsrep_status_t wsrep_trx_status_to_wsrep_status(wsrep_trx_status status)
+ {
+ switch (status)
+ {
+ case WSREP_TRX_OK:
+ return WSREP_OK;
+ case WSREP_TRX_CERT_FAIL:
+ case WSREP_TRX_ERROR:
+ return WSREP_TRX_FAIL;
+ case WSREP_TRX_SIZE_EXCEEDED:
+ return WSREP_SIZE_EXCEEDED;
+ }
+ return WSREP_NOT_IMPLEMENTED;
+ }
+
class Ha_trx_info;
struct THD_TRANS;
void wsrep_register_hton(THD* thd, bool all);
@@@ -237,12 -376,8 +283,6 @@@ void wsrep_post_rollback(THD* thd)
void wsrep_brute_force_killer(THD *thd);
int wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id);
- /* this is visible for client build so that innodb plugin gets this */
- typedef struct wsrep_aborting_thd {
- struct wsrep_aborting_thd *next;
- THD *aborting_thd;
- } *wsrep_aborting_thd_t;
-//extern "C" bool wsrep_consistency_check(void *thd_ptr);
--
extern mysql_mutex_t LOCK_wsrep_ready;
extern mysql_cond_t COND_wsrep_ready;
extern mysql_mutex_t LOCK_wsrep_sst;
@@@ -267,6 -402,9 +307,9 @@@ extern my_bool wsrep_preordered_o
extern handlerton *wsrep_hton;
#ifdef HAVE_PSI_INTERFACE
++
+ extern PSI_mutex_key key_LOCK_wsrep_thd;
+ extern PSI_cond_key key_COND_wsrep_thd;
-
extern PSI_mutex_key key_LOCK_wsrep_ready;
extern PSI_mutex_key key_COND_wsrep_ready;
extern PSI_mutex_key key_LOCK_wsrep_sst;
@@@ -287,12 -431,142 +336,143 @@@ extern PSI_file_key key_file_wsrep_gra_
struct TABLE_LIST;
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
const TABLE_LIST* table_list);
+
+ void wsrep_begin_nbo_unlock(THD*);
+ void wsrep_end_nbo_lock(THD*, const TABLE_LIST *table_list);
+
void wsrep_to_isolation_end(THD *thd);
+
void wsrep_cleanup_transaction(THD *thd);
+ bool wsrep_append_SR_keys(THD *thd);
int wsrep_to_buf_helper(
THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len);
+ int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
+ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len);
+ bool wsrep_stmt_rollback_is_safe(THD* thd);
+
+ void wsrep_init_sidno(const wsrep_uuid_t&);
+ bool wsrep_node_is_donor();
+ bool wsrep_node_is_synced();
+
+ void wsrep_init_schema();
+ void wsrep_init_SR();
+ void wsrep_verify_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno);
+ int wsrep_replay_from_SR_store(THD*, const wsrep_trx_meta_t&);
+ void wsrep_node_uuid(wsrep_uuid_t&);
+
+ class Log_event;
+ int wsrep_ignored_error_code(Log_event* ev, int error);
+ int wsrep_must_ignore_error(THD* thd);
+
+ bool wsrep_replicate_GTID(THD* thd);
+
+ /*
+ * Helper class for non-blocking operations.
+ */
+ class Wsrep_nbo_ctx
+ {
+ public:
+ Wsrep_nbo_ctx(const void* buf, size_t buf_len,
+ uint32_t flags, const wsrep_trx_meta_t& meta) :
+ buf_ (0),
+ buf_len_(buf_len),
+ flags_ (flags),
+ meta_ (meta),
+ mutex_ (),
+ cond_ (),
+ ready_ (false),
+ executing_(false),
+ toi_released_(false)
+ {
+ mysql_mutex_init(key_LOCK_wsrep_nbo, &mutex_, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_nbo, &cond_, NULL);
+
+ if ((buf_ = malloc(buf_len_)) == 0) {
+ throw std::exception();
+ }
+ memcpy(buf_, buf, buf_len);
+ }
+
+
+ ~Wsrep_nbo_ctx() {
+ free(buf_);
+ }
+
+ const void* buf() { return buf_; }
+ size_t buf_len() { return buf_len_; }
+ uint32_t flags() { return flags_; }
+ const wsrep_trx_meta_t& meta() { return meta_; }
+
+ void wait_sync()
+ {
+ mysql_mutex_lock(&mutex_);
+ while (ready_ == false)
+ {
+ mysql_cond_wait(&cond_, &mutex_);
+ }
+ mysql_mutex_unlock(&mutex_);
+ }
+
+ void signal()
+ {
+ mysql_mutex_lock(&mutex_);
+ ready_ = true;
+ mysql_cond_signal(&cond_);
+ mysql_mutex_unlock(&mutex_);
+ }
+
+ bool ready() const { return ready_; }
+
+ void set_executing(bool val) { executing_ = val; }
+
+ bool executing() const { return executing_; }
+
+ void set_toi_released(bool val) { toi_released_ = true; }
+
+ bool toi_released() const { return toi_released_; }
+
+ private:
+ void* buf_;
+ size_t buf_len_;
+ uint32_t flags_;
+ wsrep_trx_meta_t meta_;
+ mysql_mutex_t mutex_;
+ mysql_cond_t cond_;
+ bool ready_;
+ bool executing_;
+ bool toi_released_;
+ };
+
+ /*
+ Convenience macros for determining NBO start and END
+ */
+ #define WSREP_NBO_START(flags_) \
+ ((flags_ & WSREP_FLAG_ISOLATION) && (flags_ & WSREP_FLAG_TRX_START) && \
+ !(flags_ & WSREP_FLAG_TRX_END))
+
+ #define WSREP_NBO_END(flags_) \
+ ((flags_ & WSREP_FLAG_ISOLATION) && !(flags_ & WSREP_FLAG_TRX_START) && \
+ (flags_ & WSREP_FLAG_TRX_END))
+
+ #define WSREP_TOI(flags_) \
+ ((flags_ & WSREP_FLAG_ISOLATION) && (flags_ & WSREP_FLAG_TRX_START) && \
+ (flags_ & WSREP_FLAG_TRX_END))
+
+ typedef struct wsrep_key_arr
+ {
+ wsrep_key_t* keys;
+ size_t keys_len;
+ } wsrep_key_arr_t;
++
+ bool wsrep_prepare_keys_for_isolation(THD* thd,
+ const char* db,
+ const char* table,
+ const TABLE_LIST* table_list,
+ wsrep_key_arr_t* ka);
+ void wsrep_keys_free(wsrep_key_arr_t* key_arr);
+
extern bool
wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
MDL_ticket *ticket,
@@@ -342,9 -628,9 +534,11 @@@ bool wsrep_node_is_synced()
#define WSREP(T) (0)
#define WSREP_ON (0)
#define WSREP_EMULATE_BINLOG(thd) (0)
++#define WSREP_EMULATE_BINLOG_NNULL(thd) (0)
#define WSREP_CLIENT(thd) (0)
#define WSREP_FORMAT(my_format) ((ulong)my_format)
#define WSREP_PROVIDER_EXISTS (0)
++#define WSREP_NOT_SPECIFIED (1)
#define wsrep_emulate_bin_log (0)
#define wsrep_to_isolation (0)
#define wsrep_init() (1)
@@@ -366,5 -652,36 +560,38 @@@
#define wsrep_thr_deinit() do {} while(0)
#define wsrep_running_threads (0)
#define WSREP_BINLOG_FORMAT(my_format) my_format
-
+ #endif /* WITH_WSREP */
++
++#ifdef WITH_WSREP
+ /**
+ * Check if the wsrep provider (ie the Galera library) is capable of
+ * doing streaming replication.
+ * @return true if SR capable
+ */
+ bool wsrep_provider_is_SR_capable();
+
+ /**
+ * Mark current commit ordered if binlogging is not enabled.
+ *
+ * The purpose of this function is to leave commit order critical
+ * section if binlog is not enabled.
+ *
+ * The function can be called from inside storage engine during commit.
+ * Binlog options are checked inside the function.
+ *
+ * @return Zero in case of success, non-zero in case of failure.
+ */
+
+ int wsrep_ordered_commit_if_no_binlog(THD*);
+
+ /**
+ * Commit the current transaction with the
+ * MySQL "Transaction Coordinator Log" (see `class TC_LOG` in sql/log.h).
+ * Calling this function will generate and assign a new wsrep transaction id
+ * for `thd`.
+ * @return WSREP_OK on success or other WSREP_* error code on failure
+ */
+ wsrep_status_t wsrep_tc_log_commit(THD* thd);
+
+#endif /* WITH_WSREP */
#endif /* WSREP_MYSQLD_H */
diff --cc sql/wsrep_sr_file.cc
index 00000000000,7ea6d480dad..7745b759349
mode 000000,100644..100644
--- a/sql/wsrep_sr_file.cc
+++ b/sql/wsrep_sr_file.cc
@@@ -1,0 -1,562 +1,563 @@@
+ /* Copyright (C) 2013 Codership Oy <info(a)codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+ #include <my_global.h>
++#include "my_pthread.h"
+ #include "wsrep_priv.h"
+ #include "wsrep_api.h"
+ #include "wsrep_sr_file.h"
+ #include "wsrep_applier.h" // wsrep_apply()
+ #include "wsrep_thd.h"
+ #include "wsrep_utils.h"
+ #include <map>
+ #include <string>
+ #include <ostream>
+ #include <iostream>
+ #include <fstream>
+ #include <list>
+ #include <dirent.h>
+ #include <sstream>
+ #include <iomanip>
+
+ /* to prepare wsrep_uuid_t usable in std::map */
+ inline bool operator==(const node_trx_t& lhs, const node_trx_t& rhs) {
+ return(memcmp(lhs.data, rhs.data, 24) == 0);
+ }
+ inline bool operator!=(const node_trx_t& lhs, const node_trx_t& rhs) {
+ return !operator==(lhs,rhs);
+ }
+ inline bool operator< (const node_trx_t& lhs, const node_trx_t& rhs) {
+ return(memcmp(lhs.data, rhs.data, 24) < 0);
+ }
+ inline bool operator> (const node_trx_t& lhs, const node_trx_t& rhs) {
+ return operator< (rhs,lhs);
+ }
+ inline bool operator<=(const node_trx_t& lhs, const node_trx_t& rhs) {
+ return !operator> (lhs,rhs);
+ }
+ inline bool operator>=(const node_trx_t& lhs, const node_trx_t& rhs) {
+ return !operator< (lhs,rhs);
+ }
+
+ typedef std::map<uint64_t, std::vector<unsigned char> > frag_list_t;
+ typedef std::map<node_trx_t, frag_list_t> db_t;
+
+ class SR_file {
+ std::string const name_;
+ std::ofstream outfile_;
+
+ size_t size_;
+ long frags_;
+ int const order_;
+
+ typedef std::map<node_trx_t, bool> trxs_t;
+ trxs_t trxs_;
+
+ /* will go in file header */
+ signed long long min_seqno_;
+ signed long long max_seqno_;
+
+ public:
+ SR_file(std::string name, int order) :
+ name_(name),
+ order_(order)
+ {
+ outfile_.open(name.c_str(), std::ios::out | std::ios::app | std::ios::binary );
+ size_ = 0;
+ min_seqno_ = 0;
+ max_seqno_ = 0;
+ }
+ SR_file() : order_(0)
+ {
+ }
+ int get_order() { return order_; }
+ std::string get_name() { return name_; }
+
+ void write_file_header();
+ void read_file_header();
+ void write_frag_header(
+ wsrep_uuid_t *node_uuid,
+ wsrep_trx_id_t trx,
+ wsrep_seqno_t seqno,
+ uint32_t flags)
+ {
+ char uuid_str[37] = {'\0',};
+ wsrep_uuid_print(node_uuid, uuid_str, 37);
+
+ outfile_ << uuid_str;
+ outfile_ << ' ' << trx << ' ' << seqno;
+
+ if (flags & WSREP_FLAG_TRX_START) {
+ outfile_ << 'B';
+ } else {
+ outfile_ << ' ';
+ }
+ if (flags & WSREP_FLAG_TRX_END) {
+ outfile_ << 'C';
+ } else {
+ outfile_ << ' ';
+ }
+ if (flags & WSREP_FLAG_ROLLBACK) {
+ outfile_ << 'R';
+ } else {
+ outfile_ << ' ';
+ }
+ }
+ void append(wsrep_uuid_t *node_uuid,
+ wsrep_trx_id_t trx,
+ wsrep_seqno_t seqno,
+ uint32_t flags,
+ const uchar *buf,
+ size_t buf_len)
+ {
+ if (seqno < min_seqno_ || min_seqno_ == 0) min_seqno_ = seqno;
+ if (seqno > max_seqno_ || max_seqno_ == 0) max_seqno_ = seqno;
+
+ write_frag_header(node_uuid, trx, seqno, flags);
+ outfile_ << buf_len << '#';
+ outfile_.write((char*)(buf), buf_len);
+ size_ += buf_len;
+ size_ += 35; /* for header */
+
+ node_trx_t trxid = { {'\0',} };
+ memcpy(trxid.data, node_uuid->data, 16);
+ sprintf((char*)&(trxid.data[16]), "%ld", trx);
+ trxs_[trxid] = true;
+ };
+
+ bool remove(const wsrep_uuid_t *node_uuid,
+ const wsrep_seqno_t seqno)
+ {
+ node_trx_t trxid = { {'\0',} };
+ memcpy(trxid.data, node_uuid->data, 16);
+ sprintf((char*)&(trxid.data[16]), "%ld", seqno);
+
+ //std::string trxid = node_uuid + std::to_string(seqno);
+ trxs_[trxid] = false;
+
+ /* check if all transactions are over in this file */
+ bool all_gone(true);
+
+ trxs_t::iterator iterator;
+ for(iterator = trxs_.begin(); iterator != trxs_.end(); iterator++) {
+ if (iterator->second == true)
+ {
+ all_gone = false;
+ continue;
+ }
+ }
+
+ return all_gone;
+ }
+
+ size_t size()
+ {
+ return size_;
+ }
+
+ class File_hdr {
+ };
+
+ class Frag_hdr {
+ };
+
+ void close()
+ {
+ outfile_.close();
+ }
+ };
+
+ int SR_storage_file::max_file_order()
+ {
+ int max = 0;
+ std::list<SR_file*>::iterator iterator;
+ for (iterator = files_.begin(); iterator != files_.end(); ++iterator) {
+ if ((*iterator)->get_order() > max) max = (*iterator)->get_order();
+ }
+ return max;
+ }
+
+ std::string *SR_storage_file::new_name(int order)
+ {
+ std::string *name = new std::string(dir_);
+ *name += "/wsrep_SR_";
+ *name += order;
+ *name += ".dat";
+ return name;
+ }
+
+ SR_file *SR_storage_file::append_file() {
+
+ int order = max_file_order() + 1;
+ std::stringstream ss;
+ ss << dir_ << "/wsrep_SR_store." << order;
+ SR_file *file = new SR_file(ss.str(), order);
+ files_.push_back(file);
+ return file;
+ }
+
+ void SR_storage_file::remove_file(SR_file *file) {
+ remove(file->get_name().c_str());
+ delete file;
+ }
+
+ SR_storage_file::SR_storage_file(
+ const char *dir,
+ size_t limit,
+ const char * cluster_uuid_str)
+ {
+ dir_ = std::string(dir);
+ size_limit_ = limit;
+ wsrep_uuid_scan(cluster_uuid_str, 37, &cluster_uuid_);
+ restored_ = false;
+
+ curr_file_ = NULL;
+
+ WSREP_DEBUG("SR pool initialized, group: %s", cluster_uuid_str);
+ }
+
+ int SR_storage_file::init(const char* cluster_uuid_str, Wsrep_schema* unused)
+ {
+ int rcode = 0;
+
+ WSREP_DEBUG("SR pool initialized,");
+ WSREP_DEBUG("cluster_uuid:str: %s", cluster_uuid_str);
+ wsrep_uuid_scan(cluster_uuid_str, 37, &cluster_uuid_);
+
+ return rcode;
+ }
+
+ THD* SR_storage_file::append_frag(THD* thd,
+ uint32_t flags,
+ const uchar* buf,
+ size_t buf_len)
+ {
+ wsrep_uuid_t *node_uuid = &(thd->wsrep_trx_meta.stid.node);
+ wsrep_trx_id_t trx = thd->wsrep_trx_meta.stid.trx;
+ wsrep_seqno_t seqno = thd->wsrep_trx_meta.gtid.seqno;
+
+ if (!restored_) return NULL;
+
+ wsp::auto_lock lock(&LOCK_wsrep_SR_store);
+
+ if (!curr_file_) curr_file_ = append_file();
+
+ assert(curr_file_);
+
+ curr_file_->append(node_uuid, trx, seqno, flags, buf, buf_len);
+
+ if (curr_file_->size() > size_limit_)
+ {
+ curr_file_->close();
+ curr_file_ = NULL;
+ }
+
+ return NULL;
+ }
+
+ void SR_storage_file::remove_trx( THD *thd )
+ {
+ assert (thd);
+ const wsrep_uuid_t *node_uuid = &(thd->wsrep_trx_meta.stid.node);
+ const wsrep_trx_id_t trxid = thd->wsrep_trx_meta.stid.trx;
+
+ /* remove from all SR files */
+ wsp::auto_lock lock(&LOCK_wsrep_SR_store);
+
+ std::list<SR_file*>::iterator iterator;
+ for (iterator = files_.begin(); iterator != files_.end();) {
+ if ((*iterator)->remove(node_uuid, trxid))
+ {
+ if (curr_file_ == *iterator) curr_file_ = NULL;
+
+ remove_file(*iterator);
+
+ std::list<SR_file*>::iterator prev = iterator++;
+ files_.erase(prev);
+ }
+ else
+ {
+ ++iterator;
+ }
+ }
+ }
+
+ void SR_storage_file::rollback_trx( THD* thd )
+
+ {
+ WSREP_DEBUG("SR_storage_file::commit_trx");
+ remove_trx(thd);
+ }
+
+ int SR_storage_file::replay_trx(THD* thd, const wsrep_trx_meta_t& meta)
+ {
+ WSREP_ERROR("SR_storage_file::replay_trx not implemented");
+ return 1;
+ }
+
+
+ void SR_storage_file::read_trxs_from_file(
+ std::string file, trxs_t *trxs, THD *thd, enum read_mode mode)
+ {
+ std::ifstream infile;
+
+ WSREP_DEBUG("read_trxs_from_file");
+
+ if (!strcmp(file.c_str(), "---"))
+ {
+ WSREP_DEBUG("SR file comment line skipped");
+ return;
+ }
+ infile.open(file.c_str(), std::ios::in | std::ios::binary);
+ infile.exceptions (
+ std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
+
+ try {
+
+ while (infile.good())
+ {
+ char uuid[37] = {'\0',};
+ wsrep_uuid_t node_uuid;
+ wsrep_trx_id_t trxid;
+ wsrep_seqno_t seqno;
+ char begin = '#';
+ char commit = '#';
+ char rollback = '#';
+ int len;
+ char *buf;
+
+ /* 1 source node UUID */
+ if (infile.get(uuid, 37))
+ {
+ wsrep_uuid_scan(uuid, 37, &node_uuid);
+ }
+ else
+ break;
+
+ /* 2 source node trx ID */
+ infile >> trxid;
+
+ /* 3 trx seqno */
+ infile >> seqno;
+
+ /* 4 flags: Begin-Commit-Rollback */
+ begin = (char)infile.get();
+ commit = (char)infile.get();
+ rollback = (char)infile.get();
+
+ /* 5 rbr buffer length */
+ infile >> len;
+
+ /* # after header part */
+ if ( (char)infile.get() != '#')
+ {
+ WSREP_WARN("SR frament file bad line: %s %ld %ld %c %c %c",
+ uuid, trxid, seqno, begin, commit, rollback);
+ return;
+ }
+
+ /* 6 the buffer */
+ buf = new char [len];
+ infile.read(buf, len);
+
+ /* */
+ node_trx_t nodetrx;
+ memcpy(nodetrx.data, node_uuid.data, 16);
+ sprintf((char*)&(nodetrx.data[16]), "%ld", trxid);
+
+ int flags = 0;
+ wsrep_trx_meta_t meta;
+ meta.gtid.uuid = cluster_uuid_;
+ meta.gtid.seqno = seqno;
+ meta.stid.node = node_uuid;
+ meta.stid.trx = trxid;
+
+ if (begin == 'B')
+ {
+ if (mode == FILTER)
+ {
+ WSREP_DEBUG("new trx in SR file: trx %ld seqno %ld", trxid, seqno);
+ (*trxs)[nodetrx] = true;
+ }
+ else
+ {
+ flags |= WSREP_FLAG_TRX_START;
+ }
+ }
+ else if (!(*trxs)[nodetrx])
+ {
+ WSREP_WARN("unfinished trx in SR file: trx %ld seqno %ld",
+ trxid, seqno);
+ }
+
+ if (mode == FILTER && (commit == 'C' || rollback == 'R'))
+ {
+ WSREP_DEBUG("trx commit in SR file: trx %ld seqno %ld", trxid, seqno);
+ (*trxs)[nodetrx] = false;
+ }
+
+ if (mode == POPULATE && (*trxs)[nodetrx])
+ {
+ /* pending transaction to launch in sr_pool */
+ WSREP_DEBUG("launching SR trx: %ld", trxid);
+
+ wsrep_buf_t const ws= { buf, size_t(len) };
+ wsrep_apply_error err;
+ if (wsrep_apply(thd, flags, &ws, &meta, err) !=
+ WSREP_CB_SUCCESS)
+ {
+ WSREP_WARN("Streaming Replication fragment restore failed: %s",
+ err.c_str() ? err.c_str() : "(null)");
+ return;
+ }
+ DBUG_ASSERT(err.is_null());
+ }
+ else if (mode == POPULATE)
+ WSREP_DEBUG("not populating trx %ld seqno %ld", trxid, seqno);
+
+ delete[] buf;
+ }
+ }
+ catch(std::exception e)
+ {
+ if(infile.eof())
+ {
+ WSREP_DEBUG("infile EOF");
+ }
+ else
+ WSREP_DEBUG("infile exception");
+ }
+ }
+
+ int SR_storage_file::restore( THD *thd )
+ {
+ std::ifstream infile;
+ std::string file(dir_ + '/' + "wsrep_SR_info");
+ THD * SRthd = NULL;
+
+ char cluster_uuid_str[37] = {'\0',};
+
+ wsp::auto_lock lock(&LOCK_wsrep_SR_store);
+
+ if (restored_)
+ {
+ return 0;
+ }
+ wsrep_uuid_print(&cluster_uuid_, cluster_uuid_str, 37);
+
+ WSREP_DEBUG("SR pool restore, group %s", cluster_uuid_str);
+
+ /* read SR store info */
+ infile.open(file.c_str(), std::ios::in);
+ if (infile.is_open())
+ {
+ std::string line;
+ getline (infile, line);
+
+ /* this should be cluster uuid */
+ if (line.length() != 36)
+ {
+ WSREP_WARN("Streaming Replication info file is corrupted");
+ restored_ = true;
+ return -1;
+ }
+
+ if (strncmp(cluster_uuid_str, line.c_str(), 36)) {
+ WSREP_WARN("Streaming Replication cluster uuid has changed, \n"
+ "cluster in SR file: %s\n"
+ "current cluster: %s",
+ line.c_str(), cluster_uuid_str);
+ restored_ = true;
+ return -2;
+ }
+
+ trxs_t trxs;
+
+ bool thd_started = false;
+ if (!thd)
+ {
+ SRthd = wsrep_start_SR_THD((char*)&infile);
+ SRthd->wsrep_SR_thd = false;
+ thd_started = true;
+ SRthd->store_globals();
+ }
+ else
+ {
+ SRthd = thd;
+ }
+
+ /* read all fragment files, and filter out committed trxs */
+ while ( getline (infile, line) && strcmp(line.c_str(), "---"))
+ {
+ WSREP_DEBUG("SR file filtering line: %s", line.c_str());
+ read_trxs_from_file(line, &trxs, SRthd, FILTER);
+ }
+ /* read again, and populate pending trxs */
+ infile.seekg(infile.beg);
+ getline (infile, line);
+
+ while ( getline (infile, line) )
+ {
+ WSREP_DEBUG("SR file populating line: %s", line.c_str());
+ read_trxs_from_file(line, &trxs, SRthd, POPULATE);
+ }
+ infile.close();
+ if (thd_started)
+ {
+ wsrep_end_SR_THD(SRthd);
+ }
+ else
+ {
+ thd->store_globals();
+ }
+ }
+
+ restored_ = true;
+ remove(file.c_str());
+ return 0;
+ }
+
+ void SR_storage_file::close()
+ {
+ WSREP_DEBUG("SR_storage_file::close()");
+ wsp::auto_lock lock(&LOCK_wsrep_SR_store);
+
+ /* write store info */
+ std::string file(dir_ + '/' + "wsrep_SR_info");
+ std::ofstream srinfo;
+ char cluster_uuid_str[37] = {'\0',};
+
+ wsrep_uuid_print(&cluster_uuid_, cluster_uuid_str, 37);
+
+ srinfo.open(file.c_str());
+ srinfo << cluster_uuid_str << '\n';
+
+ /* close transactions */
+ std::list<SR_file*>::iterator iterator;
+ for (iterator = files_.begin(); iterator != files_.end();)
+ {
+ std::list<SR_file*>::iterator prev = iterator++;
+ WSREP_DEBUG("Closing streaming replication file: %s",
+ (*prev)->get_name().c_str());
+
+ srinfo << (*prev)->get_name() << '\n';
+ (*prev)->close();
+ }
+ srinfo << "---" << '\n';
+
+ srinfo.close();
+
+ restored_ = false;
+ }
diff --cc sql/wsrep_sr_table.cc
index 00000000000,ebbc7784510..bbde72fc30c
mode 000000,100644..100644
--- a/sql/wsrep_sr_table.cc
+++ b/sql/wsrep_sr_table.cc
@@@ -1,0 -1,222 +1,223 @@@
+ /* Copyright (C) 2013 Codership Oy <info(a)codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
-
++#include <my_global.h>
++#include "my_pthread.h"
+ #include "wsrep_priv.h"
+ #include "wsrep_sr_table.h"
+ #include "wsrep_schema.h"
+
+ #include "sql_class.h"
+
+
+ SR_storage_table::SR_storage_table()
+ :
+ wsrep_schema_(0)
+ {
+ }
+
+ SR_storage_table::~SR_storage_table()
+ {
+ }
+
+ int SR_storage_table::init(const char* cluster_uuid_str,
+ Wsrep_schema* wsrep_schema)
+ {
+ /* Storage tables have been created by Wsrep_schema */
+ wsrep_schema_= wsrep_schema;
+ return 0;
+ }
+
+
+ THD* SR_storage_table::append_frag(THD* thd,
+ uint32_t flags,
+ const uchar* buf,
+ size_t buf_len)
+ {
+ /*
+ During restore phase fragments are read from storage, don't
+ append back.
+ */
+ if (restored_ == false) {
+ return NULL;
+ }
+
+ thd->wsrep_trx_meta.stid.trx = thd->wsrep_ws_handle.trx_id;
+
+ THD* ret = wsrep_schema_->append_frag(thd->wsrep_trx_meta, flags,
+ buf, buf_len);
+ if (!ret) {
+ WSREP_ERROR("Failed to append frag to persistent storage");
+ }
+ else {
+ WSREP_DEBUG("SR_storage_table::append_frag(): thd %lld, seqno %lld, "
+ "trx_id: %ld, thd_ret: %p",
+ thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx, ret);
+ }
+
+ thd->store_globals(); /* Restore original thread context */
+ return ret;
+ }
+
+ void SR_storage_table::update_frag_seqno(THD* thd, THD* orig_THD)
+ {
+ thd->store_globals();
+
+ if (wsrep_schema_->update_frag_seqno(thd, orig_THD->wsrep_trx_meta)) {
+ WSREP_ERROR("Failed to update seqno, must abort");
+ unireg_abort(1);
+ }
+
+ orig_THD->wsrep_SR_fragments.push_back(orig_THD->wsrep_trx_meta);
+ orig_THD->store_globals(); /* Restore original thread context */
+ }
+
+ void SR_storage_table::release_SR_thd(THD* thd)
+ {
+ thd->store_globals();
+ wsrep_schema_->release_SR_thd(thd);
+ }
+
+ void SR_storage_table::append_frag_apply(THD* thd,
+ uint32_t flags,
+ const uchar* buf,
+ size_t buf_len)
+ {
+ /*
+ During restore phase fragments are read from storage, don't
+ append back.
+ */
+ if (restored_ == false) {
+ return;
+ }
+
+ if (wsrep_schema_->append_frag_apply(thd, thd->wsrep_trx_meta, flags,
+ buf, buf_len)) {
+ WSREP_ERROR("Failed to append frag to persistent storage, must abort");
+ unireg_abort(1);
+ }
+
+ thd->store_globals(); /* Restore original thread context */
+ }
+
+ void SR_storage_table::append_frag_commit(THD* thd,
+ uint32_t flags,
+ const uchar* buf,
+ size_t buf_len)
+ {
+ /*
+ During restore phase fragments are read from storage, don't
+ append back.
+ */
+ if (restored_ == false) {
+ return;
+ }
+
+ if (wsrep_schema_->append_frag_commit(thd->wsrep_trx_meta, flags,
+ buf, buf_len)) {
+ WSREP_ERROR("Failed to append frag to persistent storage, must abort");
+ unireg_abort(1);
+ }
+
+ thd->wsrep_SR_fragments.push_back(thd->wsrep_trx_meta);
+ thd->store_globals(); /* Restore original thread context */
+ }
+
+ void SR_storage_table::remove_trx(THD* thd)
+ {
+ WSREP_DEBUG("SR_storage_table::remove_trx(%lld) seqno %lld, trx %ld",
+ thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx);
+ int err= wsrep_schema_->remove_trx(thd, &thd->wsrep_SR_fragments);
+ if (err == -1) {
+ WSREP_DEBUG("SR_storage_table::remove_trx() interrupted");
+ } else if (err) {
+ WSREP_WARN("Failed to delete fragments from persistent storage");
+ }
+ }
+
+ void SR_storage_table::remove_trx(wsrep_SR_trx_info* trx)
+ {
+ remove_trx(trx->get_THD());
+ }
+
+ void SR_storage_table::rollback_trx(THD* thd)
+ {
+ WSREP_DEBUG("SR_storage_table::rollback_trx(%lld) seqno %lld, trx %ld",
+ thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx);
+ int err= wsrep_schema_->rollback_trx(thd);
+ if (err == -1) {
+ WSREP_DEBUG("SR_storage_table::rollback_trx() interrupted");
+ } else if (err) {
+ WSREP_WARN("Failed to delete fragments from persistent storage");
+ }
+ thd->store_globals(); /* Restore original thread context */
+ }
+
+ void SR_storage_table::rollback_trx(wsrep_SR_trx_info* trx)
+ {
+ rollback_trx(trx->get_THD());
+ }
+
+ void SR_storage_table::trx_done(THD* thd)
+ {
+ if (thd->wsrep_conflict_state() != MUST_REPLAY)
+ thd->wsrep_SR_fragments.clear();
+ }
+
+ int SR_storage_table::replay_trx(THD* thd, const wsrep_trx_meta_t& meta)
+ {
+ return wsrep_schema_->replay_trx(thd, meta);
+ }
+
+ int SR_storage_table::restore(THD* thd)
+ {
+ if (restored_ == true) {
+ WSREP_DEBUG("SR_storage_table::restore: Already restored");
+ return 0;
+ }
+
+ WSREP_INFO("SR_storage_table::restore");
+ int ret= wsrep_schema_->restore_frags();
+ if (thd) {
+ thd->store_globals();
+ }
+ else {
+ my_pthread_setspecific_ptr(THR_THD, NULL);
+ }
+ restored_= true;
+ return ret;
+ }
+
+ void SR_storage_table::prepare_for_open_tables(THD *thd, TABLE_LIST **table_list)
+ {
+ wsrep_schema_->init_SR_table(&thd->wsrep_SR_table);
+ TABLE_LIST *ptr= *table_list;
+ if (!ptr)
+ {
+ *table_list= &thd->wsrep_SR_table;
+ }
+ else
+ {
+ while (ptr->next_global) ptr = ptr->next_global;
+ ptr->next_global = &thd->wsrep_SR_table;
+ }
+ }
+
+ void SR_storage_table::close()
+ {
+ }
diff --cc sql/wsrep_sst.cc
index d5b0344c456,7c5963c031f..fff7e747f9b
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@@ -28,9 -28,8 +28,10 @@@
#include "wsrep_xid.h"
#include <cstdio>
#include <cstdlib>
-
+#include <my_service_manager.h>
+ const char wsrep_defaults_group_suffix[256] = {0};
++
static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 +
sizeof(WSREP_SST_OPT_CONF) +
sizeof(WSREP_SST_OPT_CONF_SUFFIX) +
@@@ -1363,25 -1350,14 +1369,26 @@@ void wsrep_SE_init_grab(
if (mysql_mutex_lock (&LOCK_wsrep_sst_init)) abort();
}
- void wsrep_SE_init_wait()
+ int wsrep_SE_init_wait()
{
+ struct timespec wtime = {WSREP_TIMEDWAIT_SECONDS, 0};
+ uint32 total_wtime=0;
+
- while (SE_initialized == false)
+ while (SE_init_status == WSREP_SE_UNINITIALIZED)
{
- mysql_cond_wait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init);
+ mysql_cond_timedwait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init, &wtime);
+
- if (!SE_initialized)
++ if (SE_init_status == WSREP_SE_UNINITIALIZED)
+ {
+ total_wtime += wtime.tv_sec;
+ WSREP_DEBUG("Waiting for SST to complete. waited %u secs.", total_wtime);
+ service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
+ "WSREP SE initialization ongoing.");
+ }
}
+
mysql_mutex_unlock (&LOCK_wsrep_sst_init);
+ return !(SE_init_status == WSREP_SE_INITIALIZED);
}
void wsrep_SE_init_done()
diff --cc sql/wsrep_thd.cc
index ce6d9688cb3,ddfc3ce70d1..489613d0c6c
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@@ -46,18 -53,153 +53,153 @@@ int wsrep_show_bf_aborts (THD *thd, SHO
var->value = (char*)&wsrep_local_bf_aborts;
return 0;
}
+ void wsrep_cleanup_transaction(THD *thd)
+ {
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
+ DBUG_ENTER("wsrep_cleanup_transaction");
+ if (thd->wsrep_exec_mode == REPL_RECV) return;
+
+ DBUG_ASSERT(thd->wsrep_conflict_state() != MUST_REPLAY);
+ DBUG_ASSERT(thd->wsrep_SR_fragments.empty());
+
+ if (wsrep_SR_store) wsrep_SR_store->trx_done(thd);
+ if (wsrep_emulate_bin_log) wsrep_thd_binlog_trx_reset(thd);
+
+ wsrep_reset_SR_trans(thd);
+ thd->wsrep_exec_mode= LOCAL_STATE;
+ if (thd->wsrep_conflict_state() != NO_CONFLICT)
+ {
+ /*
+ Catch half finished rollbacks.
+ */
+ DBUG_ASSERT(thd->wsrep_conflict_state() == ABORTED ||
+ thd->wsrep_conflict_state() == CERT_FAILURE);
+
+ thd->killed= NOT_KILLED;
+ thd->set_wsrep_conflict_state(NO_CONFLICT);
+ }
+
+ if (MUST_REPLAY != thd->wsrep_conflict_state())
+ {
+ thd->wsrep_PA_safe= true;
+ thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
+ thd->set_wsrep_next_trx_id(WSREP_UNDEFINED_TRX_ID);
+
+ if (thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED)
+ {
+ thd->wsrep_last_written_gtid= thd->wsrep_trx_meta.gtid;
+ }
+ thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
+ thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
+ thd->wsrep_affected_rows= 0;
+ thd->wsrep_skip_wsrep_GTID= false;
+ thd->wsrep_xid.null();
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ /*
+ Run post rollback actions.
- /* must have (&thd->LOCK_thd_data) */
- void wsrep_client_rollback(THD *thd)
+ Assert thd->LOCK_wsrep_thd ownership
+ */
+ void wsrep_post_rollback(THD *thd)
{
- WSREP_DEBUG("client rollback due to BF abort for (%lld), query: %s",
- (longlong) thd->thread_id, thd->query());
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
- WSREP_ATOMIC_ADD_LONG(&wsrep_bf_aborts_counter, 1);
+ WSREP_LOG_THD(thd, NULL);
+
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT || /* voluntary */
+ thd->wsrep_conflict_state() == ABORTING); /* BF abort or cert failure */
- thd->wsrep_conflict_state= ABORTING;
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
- trans_rollback(thd);
+
+ if (thd->wsrep_trx_has_seqno())
+ {
+ if (!wsrep_gtid_mode)
+ {
+ void* ptr= NULL;
+ size_t len= 0;
+ wsrep_buf_t err= {ptr, len};
+ if (wsrep->commit_order_enter(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta))
+ {
+ WSREP_WARN("wsrep_post_rollback: failed to enter commit order");
+ }
+ if (wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, &err))
+ {
+ WSREP_WARN("wsrep_post_rollback: failed to leave commit order");
+ }
+ }
+ /*
+ If binlogging is on commit ordering is done when dummy
+ event is written into binlog
+ */
+ else if (wsrep_write_dummy_event(thd, "rollback"))
+ {
+ WSREP_WARN("wsrep_post_rollback: failed to write dummy event");
+ }
+ }
+
+ if (wsrep->release(wsrep, &thd->wsrep_ws_handle))
+ {
+ WSREP_WARN("wsrep::release fail: %llu %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT ||
+ thd->wsrep_conflict_state() == ABORTING);
+
+ if (thd->wsrep_conflict_state() == NO_CONFLICT)
+ {
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ thd->set_wsrep_conflict_state(ABORTING);
+ thd->set_wsrep_conflict_state(ABORTED);
+ }
+ else
+ {
+ thd->set_wsrep_conflict_state(ABORTED);
+ }
+ }
+
+ /*
+ must have (&thd->LOCK_wsrep_thd)
+ thd->wsrep_conflict_state must be MUST_ABORT
+ */
+ void wsrep_client_rollback(THD *thd, bool rollbacker)
+ {
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
+ DBUG_ASSERT(thd->wsrep_conflict_state() == MUST_ABORT ||
+ thd->wsrep_conflict_state() == CERT_FAILURE);
+ WSREP_DEBUG("client rollback due to BF abort for (%lld %lld), query: %s",
+ thd->thread_id, thd->query_id, WSREP_QUERY(thd));
+
+ my_atomic_add64(&wsrep_bf_aborts_counter, 1);
+
+ /*
+ Rollback proccess should be fired only for threads which are not
+ in the process of committing.
+ */
+ DBUG_ASSERT(thd->wsrep_query_state() != QUERY_COMMITTING);
+ if (rollbacker)
+ {
+ DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
+ }
+
+ thd->set_wsrep_conflict_state(ABORTING);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ if (thd->wsrep_is_streaming())
+ {
+ WSREP_DEBUG("wsrep_client_rollback: thd: %lld fragments %zu",
+ thd->thread_id, thd->wsrep_SR_fragments.size());
+ wsrep_SR_store->rollback_trx(thd);
+ thd->wsrep_SR_fragments.clear();
+ }
if (thd->locked_tables_mode && thd->lock)
{
@@@ -82,12 -222,46 +222,45 @@@
if (thd->get_binlog_table_maps())
{
- WSREP_DEBUG("clearing binlog table map for BF abort (%lld)",
- (longlong) thd->thread_id);
+ WSREP_DEBUG("clearing binlog table map for BF abort (%lld)", thd->thread_id);
thd->clear_binlog_table_maps();
}
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_conflict_state= ABORTED;
+
+ /*
+ trans_rolback() must be called after all locks are released since it
+ calls ha_rollback_trans() which acquires TO
+ */
+ if (trans_rollback(thd))
+ {
+ WSREP_WARN("client rollback failed for: %lld %lld, conf: %d",
+ thd->thread_id, thd->query_id,
+ thd->wsrep_conflict_state_unsafe());
+ }
+
+ if (rollbacker && thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED)
+ {
+ /*
+ Thd has been assigned seqno and it needs to release provider
+ resoureces. Do it in separate thread to avoid deadlocks.
+ */
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_ROLLBACK);
+ if (wsrep_post_rollback_queue->push_back(thd))
+ {
+ WSREP_WARN("duplicate thd %llu for post-rollbacker",
+ wsrep_thd_thread_id(thd));
+ }
+ }
+
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ /*
+ If the seqno is not set there is no need for post rollback
+ actions.
+ */
+ if (rollbacker /* && wsrep_thd_trx_seqno(thd) == WSREP_SEQNO_UNDEFINED */)
+ {
+ wsrep_post_rollback(thd);
+ }
+
+ return;
}
#define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1
@@@ -231,8 -410,8 +409,8 @@@ void wsrep_replay_transaction(THD *thd
thd->get_stmt_da()->reset_diagnostics_area();
- thd->wsrep_conflict_state= REPLAYING;
+ thd->set_wsrep_conflict_state(REPLAYING);
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
thd->reset_for_next_command();
thd->reset_killed();
@@@ -269,11 -448,16 +447,16 @@@
(void *)thd);
wsrep_return_from_bf_mode(thd, &shadow);
- if (thd->wsrep_conflict_state!= REPLAYING)
- WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state );
+
+ WSREP_DEBUG("replayed %lld, seqno %lld, rcode %d",
+ thd->thread_id, (long long)wsrep_thd_trx_seqno(thd), rcode);
+ DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
- mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ if (thd->wsrep_conflict_state() != REPLAYING)
+ WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state());
+
switch (rcode)
{
case WSREP_OK:
@@@ -328,8 -527,7 +526,7 @@@
/* we're now in inconsistent state, must abort */
/* http://bazaar.launchpad.net/~codership/codership-mysql/5.6/revision/3962#sq⦠*/
- mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
-
unireg_abort(1);
break;
}
@@@ -495,20 -705,19 +704,19 @@@ static void wsrep_rollback_process(THD
*/
mysql_mutex_unlock(&LOCK_wsrep_rollback);
- mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
+ mysql_mutex_lock(&aborting->LOCK_thd_data);
- if (aborting->wsrep_conflict_state== ABORTED)
+ if (aborting->wsrep_conflict_state()== ABORTED)
{
WSREP_DEBUG("WSREP, thd already aborted: %llu state: %d",
(long long)aborting->real_id,
- aborting->wsrep_conflict_state);
+ aborting->wsrep_conflict_state());
- mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&aborting->LOCK_thd_data);
mysql_mutex_lock(&LOCK_wsrep_rollback);
continue;
}
- aborting->wsrep_conflict_state= ABORTING;
- mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
+ mysql_mutex_unlock(&aborting->LOCK_thd_data);
set_current_thd(aborting);
aborting->store_globals();
@@@ -558,10 -856,10 +855,10 @@@ enum wsrep_conflict_state wsrep_thd_con
enum wsrep_conflict_state state = NO_CONFLICT;
if (thd)
{
- if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (sync) mysql_mutex_lock(&thd->LOCK_thd_data);
- state = thd->wsrep_conflict_state;
+ state = thd->wsrep_conflict_state();
- if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (sync) mysql_mutex_unlock(&thd->LOCK_thd_data);
}
return state;
}
diff --cc sql/wsrep_thd_pool.cc
index 00000000000,842542cab64..d65b5bde185
mode 000000,100644..100644
--- a/sql/wsrep_thd_pool.cc
+++ b/sql/wsrep_thd_pool.cc
@@@ -1,0 -1,120 +1,122 @@@
+ /* Copyright (C) 2015 Codership Oy <info(a)codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+
++#include <my_global.h>
++#include "my_pthread.h"
+ #include "wsrep_mysqld.h"
+ #include "wsrep_thd_pool.h"
+ #include "wsrep_utils.h"
+ #include "sql_class.h"
+ //#include "global_threads.h"
+
+ #include <list>
+
+ static THD* wsrep_thd_pool_new_thd()
+ {
+ THD *thd = new THD(next_thread_id());
+ thd->thread_stack= (char*) &thd;
+ thd->security_ctx->skip_grants();
+ thd->system_thread= SYSTEM_THREAD_GENERIC;
+
+ mysql_mutex_lock(&LOCK_thread_count);
+
+ thd->real_id=pthread_self(); // Keep purify happy
+
+ WSREP_DEBUG("Wsrep_thd_pool: creating system thread: %lld",
+ (long long)thd->thread_id);
+ thd->prior_thr_create_utime= thd->start_utime= thd->thr_create_utime;
+ (void) mysql_mutex_unlock(&LOCK_thread_count);
+
+ thd->variables.wsrep_on = 0;
+ thd->variables.sql_log_bin = 0;
+ thd->variables.option_bits &= ~OPTION_BIN_LOG;
+ thd->variables.tx_isolation = ISO_READ_COMMITTED;
+
+ thd->wsrep_exec_mode = REPL_RECV;
+ // thd->wsrep_exec_mode = LOCAL_STATE;
+
+ return thd;
+ }
+
+ Wsrep_thd_pool::Wsrep_thd_pool(size_t threads)
+ :
+ threads_(threads),
+ pool_()
+ {
+ WSREP_DEBUG("Wsrep_thd_pool constructor");
+ wsp::auto_lock lock(&LOCK_wsrep_thd_pool);
+ pool_.reserve(threads);
+ for (size_t i= 0; i < threads; ++i)
+ {
+ pool_.push_back(wsrep_thd_pool_new_thd());
+ }
+ }
+
+ Wsrep_thd_pool::~Wsrep_thd_pool()
+ {
+ wsp::auto_lock lock(&LOCK_wsrep_thd_pool);
+ while (!pool_.empty())
+ {
+ THD *thd = pool_.back();
+ WSREP_DEBUG("Wsrep_thd_pool: closing thread %lld",
+ (long long)thd->thread_id);
+
+ delete thd;
+
+ pool_.pop_back();
+ }
+ }
+
+ THD* Wsrep_thd_pool::get_thd(THD* thd)
+ {
+ wsp::auto_lock lock(&LOCK_wsrep_thd_pool);
+ THD *ret= NULL;
+ if (pool_.empty())
+ {
+ ret= wsrep_thd_pool_new_thd();
+ }
+ else
+ {
+ ret= pool_.back();
+ pool_.pop_back();
+ }
+ if (thd)
+ {
+ ret->thread_stack = thd->thread_stack;
+ }
+ else
+ {
+ ret->thread_stack= (char*) &ret;
+ }
+ ret->store_globals();
+ return ret;
+ }
+
+ void Wsrep_thd_pool::release_thd(THD* thd)
+ {
+ DBUG_ASSERT(!thd->mdl_context.has_locks());
+ DBUG_ASSERT(!thd->open_tables);
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ wsp::auto_lock lock(&LOCK_wsrep_thd_pool);
+ if (pool_.size() < threads_)
+ {
+ pool_.push_back(thd);
+ }
+ else
+ {
+ delete thd;
+ }
+ }
diff --cc sql/wsrep_trans_observer.cc
index 00000000000,c4bc0218309..9a914ea37b7
mode 000000,100644..100644
--- a/sql/wsrep_trans_observer.cc
+++ b/sql/wsrep_trans_observer.cc
@@@ -1,0 -1,1663 +1,1663 @@@
+ /* Copyright 2016 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+ /*
+ Implementation of wsrep transaction observer hooks.
+
+ * wsrep_after_row(): called after each row write/update/delete, will run
+ SR step
+ * wsrep_before_prepare(): SR table cleanup
+ * wsrep_after_prepare(): will run wsrep_certify() which replicates
+ and certifies transaction for transactions which have registered
+ binlog hton
+ * wsrep_before_commit(): run wsrep_certify() for autocommit
+ DML when binlog_format = STATEMENT and grab commit time
+ critical via section wsrep->commit_order_enter()
+ * wsrep_ordered_commit(): release commit time critical section
+ via wsrep->commit_order_leave()
+ * wsrep_after_commit(): release rest of the trx resources from
+ provider
+ * wsrep_before_rollback(): on SR rollback construct SR_trx_info
+ and send rollback event before actual rollback happens. Set
+ wsrep_exec_mode to LOCAL_ROLLBACK
+ * wsrep_after_rollback(): in case of statement rollback check if
+ it is safe for SR and if not, trigger full transaction rollback
+ * wsrep_after_command():
+ * run wsrep_SR_step()
+ * perform post rollback operations for thds which have
+ wsrep_exec_mode LOCAL_ROLLBACK
+ * perform wsrep_client_rollback() for thds with wsrep_conflict_state
+ MUST_ABORT or CERT_FAILURE
+ * run wsrep_client_rollback() for thd which has seqno assigned
+ * cleanup transaction after rollback
+ * do rollback process for threads which have BF aborted or have
+ failed certification but have not rolled back yet.
+ * replay transactions which need to be replayed
+
+
+ Note: The rollback processing has been postponed to after_command hook
+ because sometimes the rollback process needs to be done for threads
+ which have valid wsrep seqno and rollback for such a threads should
+ be done after all tables are closed in order to avoid deadlocks.
+ Although wsrep rollback steps would be possible to do earlier in
+ after_rollback hook, this approach was chosen for simplicity.
+ */
+
+
+ #include "wsrep_trans_observer.h"
+ #include "wsrep_mysqld.h"
+ #include "wsrep_xid.h"
+ #include "wsrep_sr.h"
+ #include "wsrep_thd.h"
+
+ #include "replication.h"
+ #include "transaction.h"
+ #include "sql_base.h" /* close_thread_tables() */
+ #include "sql_class.h" /* THD */
+ #include "sql_parse.h" /* stmt_causes_implicit_commit() */
+ #include "rpl_filter.h" /* Rpl_filter */
+ #include "log.h"
+ #include "debug_sync.h" /* DEBUG_SYNC */
+
+ #include <map>
+
+ extern class SR_storage *wsrep_SR_store;
+ extern Rpl_filter* binlog_filter;
+
+
+ static void wsrep_wait_for_replayers(THD *thd)
+ {
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ int replay_round= 0;
+ while (wsrep_replaying > 0 &&
+ thd->wsrep_conflict_state() == NO_CONFLICT &&
+ thd->killed == NOT_KILLED &&
+ !shutdown_in_progress)
+ {
+
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ mysql_mutex_lock(&thd->mysys_var->mutex);
+ thd_proc_info(thd, "wsrep waiting on replaying");
+ thd->mysys_var->current_mutex= &LOCK_wsrep_replaying;
+ thd->mysys_var->current_cond= &COND_wsrep_replaying;
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
+
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ // Using timedwait is a hack to avoid deadlock in case if BF victim
+ // misses the signal.
+ struct timespec wtime;
+ clock_gettime(CLOCK_REALTIME, &wtime);
+ long prev_nsec = wtime.tv_nsec;
+ wtime.tv_nsec = (wtime.tv_nsec + 1000000) % 1000000000;
+ // If nsecs rolled over, increment seconds.
+ wtime.tv_sec += (wtime.tv_nsec < prev_nsec ? 1 : 0);
+ mysql_cond_timedwait(&COND_wsrep_replaying, &LOCK_wsrep_replaying,
+ &wtime);
+
+ if (replay_round++ % 100000 == 0)
+ WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: (%lld) "
+ "conflict: %d (round: %d)",
+ wsrep_replaying, thd->thread_id,
+ thd->wsrep_conflict_state_unsafe(), replay_round);
+
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+
+ mysql_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ }
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ }
+
+ static int wsrep_prepare_data_for_replication(THD *thd)
+ {
+ DBUG_ENTER("wsrep_prepare_data_for_replication");
+ size_t data_len= 0;
+ IO_CACHE* cache= wsrep_get_trans_cache(thd);
+
+ if (cache)
+ {
+ thd->binlog_flush_pending_rows_event(true);
+ enum wsrep_trx_status rcode= wsrep_write_cache(wsrep, thd, cache, &data_len);
+ if (rcode != WSREP_TRX_OK)
+ {
+ WSREP_ERROR("rbr write fail, data_len:: %zu",
+ data_len);
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT,
+ wsrep_trx_status_to_wsrep_status(rcode));
+ DBUG_RETURN(1);
+ }
+ }
+
+ if (data_len == 0)
+ {
+ if (thd->get_stmt_da()->is_ok() &&
+ thd->get_stmt_da()->affected_rows() > 0 &&
+ !binlog_filter->is_on())
+ {
+ WSREP_DEBUG("empty rbr buffer, query: %s, "
+ "affected rows: %llu, "
+ "changed tables: %d, "
+ "sql_log_bin: %d, "
+ "wsrep status (%d %d %d)",
+ WSREP_QUERY(thd),
+ thd->get_stmt_da()->affected_rows(),
+ stmt_has_updated_trans_table(thd),
+ thd->variables.sql_log_bin,
+ thd->wsrep_exec_mode, thd->wsrep_query_state_unsafe(),
+ thd->wsrep_conflict_state_unsafe());
+ }
+ else
+ {
+ WSREP_DEBUG("empty rbr buffer, query: %s", WSREP_QUERY(thd));
+ }
+
+ if (!thd->wsrep_is_streaming())
+ {
+ WSREP_ERROR("I/O error reading from thd's binlog iocache: "
+ "errno=%d, io cache code=%d", my_errno, cache->error);
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT);
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+
+ /*
+ Run wsrep pre_commit phase
+
+ Asserts thd->LOCK_wsrep_thd ownership
+ */
+ static wsrep_trx_status wsrep_certify(THD *thd)
+ {
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
+ DBUG_ENTER("wsrep_certify");
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+ DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID);
+
+ /*
+ We must not proceed for certify() if there are threads
+ replaying transactions. This is because replaying thread
+ may have released some locks which this thread then acquired.
+
+ Now if the replaying ends before write set gets replicated,
+ the replayed write set may fall out of this write sets
+ certification range, so the conflict won't be detected.
+ This will lead to applying error later on.
+
+ Conflict state must be checked out once more after waiting
+ for replayers to detect if replaying transaction (or other)
+ has BF aborted this.
+ */
+ wsrep_wait_for_replayers(thd);
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ // Transaction was BF aborted
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ thd->set_wsrep_query_state(QUERY_COMMITTING);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DEBUG_SYNC(thd, "wsrep_before_replication");
+
+ if (wsrep_prepare_data_for_replication(thd))
+ {
+ /* Error will be set in function to prepare data */
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ if (thd->killed != NOT_KILLED)
+ {
+ WSREP_INFO("thd %lld killed with signal %d, skipping replication",
+ thd->thread_id, thd->killed);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_trx_id())
+ {
+ WSREP_WARN("SQL statement was ineffective, THD: %lld\n"
+ "schema: %s \n"
+ "QUERY: %s\n"
+ " => Skipping replication",
+ thd->thread_id,
+ (thd->db.str ? thd->db.str : "(null)"),
+ WSREP_QUERY(thd));
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ uint32_t flags= WSREP_FLAG_TRX_END;
+ if (!thd->wsrep_PA_safe || thd->wsrep_is_streaming())
+ {
+ flags |= WSREP_FLAG_PA_UNSAFE;
+ }
+
+ if (thd->wsrep_is_streaming())
+ {
+ if (!wsrep_append_SR_keys(thd))
+ {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+ }
+
+ wsrep_status_t rcode= wsrep->certify(wsrep,
+ (wsrep_conn_id_t) thd->thread_id,
+ &thd->wsrep_ws_handle,
+ flags,
+ &thd->wsrep_trx_meta);
+
+ WSREP_DEBUG("Trx certify(%lu): rcode %d, seqno %lld, trx %ld, "
+ "flags %u, conf %d, SQL: %s",
+ thd->thread_id, rcode,(long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx, flags, thd->wsrep_conflict_state_unsafe(),
+ thd->query());
+
+ DBUG_ASSERT((thd->wsrep_trx_meta.depends_on >= 0 &&
+ thd->wsrep_trx_meta.depends_on <
+ thd->wsrep_trx_meta.gtid.seqno) ||
+ WSREP_OK != rcode);
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ DEBUG_SYNC(thd, "wsrep_after_replication");
+
+ if (WSREP_OK == rcode)
+ {
+ DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
+
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ rcode= WSREP_BF_ABORT;
+ WSREP_DEBUG("Not calling commit_order_enter() due to conflict state"
+ " == MUST_ABORT thd: %lu, seqno: %lld",
+ thd->thread_id, (long long)wsrep_thd_trx_seqno(thd));
+ }
+ }
+
+ wsrep_trx_status ret= WSREP_TRX_ERROR;
+
+ switch (rcode)
+ {
+ case WSREP_TRX_MISSING:
+ WSREP_WARN("Transaction missing in provider thd: %lld schema: %s SQL: %s",
+ thd->thread_id, (thd->db.str ? thd->db.str : "(null)"),
+ WSREP_QUERY(thd));
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_TRX_MISSING);
+ break;
+ case WSREP_BF_ABORT:
+ DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
+ thd->set_wsrep_conflict_state(MUST_REPLAY);
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ ++wsrep_replaying;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ break;
+ case WSREP_OK:
+ /*
+ Ignore BF abort from storage engine in commit phase.
+ This however requires that the storage engine BF abort
+ respects QUERY_COMMITTING query state.
+
+ TODO: Consider removing this and respecting BF abort.
+ Also adjust allowed state transitions in
+ THD::set_wsrep_conflict_state().
+
+ NOTE: If we have rcode WSREP_OK here it means that transaction
+ entered commit critical section in wsrep->commit_order_enter()
+ call. It is a bug in a provider/BF abort code if it allowed
+ BF abort after that.
+ */
+ DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ thd->killed= NOT_KILLED;
+ WSREP_WARN("Ignoring MUST_ABORT state");
+ thd->set_wsrep_conflict_state(NO_CONFLICT);
+ }
+
+ thd->wsrep_exec_mode= LOCAL_COMMIT;
+ DBUG_PRINT("wsrep", ("replicating commit success"));
+ DBUG_EXECUTE_IF("crash_last_fragment_commit_success",
+ DBUG_SUICIDE(););
+ ret= WSREP_TRX_OK;
+ break;
+ case WSREP_TRX_FAIL:
+ if (thd->wsrep_conflict_state() == NO_CONFLICT)
+ {
+ thd->set_wsrep_conflict_state(CERT_FAILURE);
+ WSREP_LOG_CONFLICT(NULL, thd, FALSE);
+ }
+ else
+ {
+ DBUG_ASSERT(thd->wsrep_conflict_state() == MUST_ABORT);
+ }
+ my_error(ER_LOCK_DEADLOCK, MYF(0), WSREP_TRX_FAIL);
+ ret= WSREP_TRX_CERT_FAIL;
+ break;
+ case WSREP_SIZE_EXCEEDED:
+ WSREP_ERROR("wsrep_certify(%lu): transaction size exceeded",
+ thd->thread_id);
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED);
+ ret= WSREP_TRX_SIZE_EXCEEDED;
+ break;
+ case WSREP_CONN_FAIL:
+ WSREP_DEBUG("wsrep_certify(%lu): replication aborted",
+ thd->thread_id);
+ my_error(ER_LOCK_DEADLOCK, MYF(0), WSREP_CONN_FAIL);
+ break;
+ case WSREP_WARNING:
+ WSREP_WARN("provider returned warning");
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_WARNING);
+ break;
+ case WSREP_NODE_FAIL:
+ WSREP_ERROR("replication aborted");
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_NODE_FAIL);
+ break;
+ case WSREP_NOT_IMPLEMENTED:
+ WSREP_ERROR("certify() or commit_order_enter() not implemented");
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_NOT_IMPLEMENTED);
+ break;
+ default:
+ WSREP_ERROR("wsrep_certify(%lu): unknown provider failure",
+ thd->thread_id);
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), rcode);
+ break;
+ }
+
+ /*
+ In case of success we keep the QUERY_COMMITTING
+ */
+ if (rcode != WSREP_OK)
+ {
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ }
+
+ DBUG_RETURN(ret);
+ }
+
+ static wsrep_trx_status wsrep_replicate_fragment(THD *thd)
+ {
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
+ DBUG_ENTER("wsrep_replicate_fragment");
+ DBUG_ASSERT(thd->wsrep_exec_mode != REPL_RECV &&
+ thd->wsrep_exec_mode != TOTAL_ORDER);
+ DBUG_ASSERT(thd->wsrep_SR_rollback_replicated_for_trx !=
+ thd->wsrep_trx_id());
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+
+ wsrep_wait_for_replayers(thd);
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ // Transaction was BF aborted
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ thd->set_wsrep_query_state(QUERY_COMMITTING);
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ bool reset_trx_meta= false;
+ IO_CACHE *cache= wsrep_get_trans_cache(thd);
+ size_t data_len= 0;
+ uint32_t flags= (thd->wsrep_PA_safe ? 0 : WSREP_FLAG_PA_UNSAFE);
+ if (thd->wsrep_fragments_sent == 0)
+ {
+ flags |= WSREP_FLAG_TRX_START;
+ }
+
+ /*
+ thd->wsrep_fragments_sent must be incremented before wsrep_write_cache
+ to get thd->wsrep_rbr_buf populated. This also needs to be decremented
+ whenever error is returned from this function.
+ */
+ ++thd->wsrep_fragments_sent;
+ if (cache)
+ {
+ enum wsrep_trx_status rcode;
+ if ((rcode = wsrep_write_cache(wsrep, thd, cache, &data_len)) != WSREP_TRX_OK)
+ {
+ WSREP_ERROR("SR rbr write fail, data_len: %zu ret: %d",
+ data_len, rcode);
+ --thd->wsrep_fragments_sent;
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(rcode);
+ }
+ }
+
+ #if 0
+ WSREP_INFO("wsrep_replicate_fragment: base: %lu bytes: %u data_len %zu fragments_sent: %lu",
+ wsrep_get_fragment_base(thd),
+ wsrep_get_trans_cache_position(thd),
+ data_len,
+ thd->wsrep_fragments_sent);
+ #endif
+
+ if (data_len == 0)
+ {
+ if (thd->get_stmt_da()->is_ok() &&
+ thd->get_stmt_da()->affected_rows() > 0 &&
+ !binlog_filter->is_on())
+ {
+ WSREP_WARN("empty rbr buffer, query: %s, "
+ "affected rows: %llu, "
+ "changed tables: %d, "
+ "sql_log_bin: %d, "
+ "wsrep status (%d %d %d)",
+ thd->query(), thd->get_stmt_da()->affected_rows(),
+ stmt_has_updated_trans_table(thd),
+ thd->variables.sql_log_bin,
+ thd->wsrep_exec_mode, thd->wsrep_query_state(),
+ thd->wsrep_conflict_state_unsafe());
+ }
+ else
+ {
+ WSREP_WARN("empty rbr buffer, query: %s", thd->query());
+ }
+ --thd->wsrep_fragments_sent;
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_trx_id())
+ {
+ WSREP_WARN("SQL statement was ineffective, THD: %lld, buf: %zu\n"
+ "QUERY: %s\n"
+ " => Skipping fragment replication",
+ thd->thread_id, data_len, thd->query());
+ --thd->wsrep_fragments_sent;
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ THD *SR_thd= NULL;
+ if (wsrep_SR_store)
+ {
+ SR_thd= wsrep_SR_store->append_frag(thd, flags, thd->wsrep_rbr_buf,
+ data_len);
+ if (!SR_thd)
+ {
+ my_error(ER_BINLOG_ROW_LOGGING_FAILED, MYF(0));
+ --thd->wsrep_fragments_sent;
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+ }
+
+ my_free(thd->wsrep_rbr_buf);
+ thd->wsrep_rbr_buf= NULL;
+
+ DBUG_EXECUTE_IF("crash_replicate_fragment_before_certify",
+ DBUG_SUICIDE(););
+
+ wsrep_status_t rcode= wsrep->certify(wsrep,
+ (wsrep_conn_id_t)thd->thread_id,
+ &thd->wsrep_ws_handle,
+ flags,
+ &thd->wsrep_trx_meta);
+
+ WSREP_DEBUG("Fragment certify(%lu): rcode %d, seqno %lld, trx %ld, "
+ "flags %u, conf %d, SQL: %s",
+ thd->thread_id, rcode,(long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx, flags,
+ thd->wsrep_conflict_state_unsafe(),
+ thd->query());
+ DBUG_EXECUTE_IF("crash_replicate_fragment_after_certify",
+ DBUG_SUICIDE(););
+
+ bool frag_updated= false;
+ if (WSREP_OK == rcode)
+ {
+ DBUG_ASSERT(thd->wsrep_trx_has_seqno());
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ my_bool const must_abort= (thd->wsrep_conflict_state() == MUST_ABORT);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ if (must_abort)
+ {
+ rcode= WSREP_BF_ABORT;
+ }
+ else
+ {
+ rcode= wsrep->commit_order_enter(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta);
+ if (rcode == WSREP_OK)
+ {
+ wsrep_xid_init(&SR_thd->wsrep_xid, thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ wsrep_SR_store->update_frag_seqno(SR_thd, thd);
+ frag_updated= true;
+ rcode= wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, NULL);
+ if (rcode != WSREP_OK && rcode != WSREP_BF_ABORT)
+ {
+ WSREP_ERROR("wsrep_replicate_fragment(%lu): seqno %lld, trx %ld "
+ "Failed to leave commit order %d",
+ thd->thread_id,
+ (long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx,
+ rcode);
+ }
+ if (rcode == WSREP_OK)
+ {
+ rcode= wsrep->release(wsrep, &thd->wsrep_ws_handle);
+ if (rcode != WSREP_OK)
+ {
+ WSREP_ERROR("wsrep_replicate_fragment(%lu): seqno %lld, trx %ld "
+ "Failed to release ws handle %d",
+ thd->thread_id,
+ (long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_trx_meta.stid.trx,
+ rcode);
+ }
+ }
+ reset_trx_meta= true;
+ }
+ else
+ {
+ DBUG_ASSERT(rcode == WSREP_BF_ABORT || rcode == WSREP_TRX_FAIL);
+ }
+ }
+ }
+
+ if (!frag_updated)
+ {
+ wsrep_SR_store->release_SR_thd(SR_thd);
+ SR_thd= NULL;
+ thd->store_globals();
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ /*
+ If the SR transaction was BF aborted at this stage
+ we abort whole transaction.
+ */
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ rcode= WSREP_BF_ABORT;
+ }
+
+ wsrep_trx_status ret;
+
+ switch (rcode)
+ {
+ case WSREP_OK:
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+ DBUG_PRINT("wsrep", ("replicating commit success"));
+ if (thd->killed != NOT_KILLED)
+ {
+ WSREP_DEBUG("thd %lld killed with signal %d, during fragment replication",
+ thd->thread_id, thd->killed);
+ }
+ DBUG_EXECUTE_IF("crash_replicate_fragment_success",
+ DBUG_SUICIDE(););
+ ret= WSREP_TRX_OK;
+ break;
+ case WSREP_BF_ABORT:
+ if (thd->wsrep_conflict_state() != MUST_ABORT)
+ {
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ }
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK, WSREP_TRX_FAIL);
+ ret= WSREP_TRX_ERROR;
+ break;
+ case WSREP_TRX_FAIL:
+ thd->set_wsrep_conflict_state(CERT_FAILURE);
+ WSREP_LOG_CONFLICT(NULL, thd, FALSE);
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK, WSREP_TRX_FAIL);
+ ret= WSREP_TRX_CERT_FAIL;
+ break;
+ case WSREP_SIZE_EXCEEDED:
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ ret= WSREP_TRX_SIZE_EXCEEDED;
+ break;
+ case WSREP_CONN_FAIL:
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ ret= WSREP_TRX_ERROR;
+ break;
+ default:
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ ret= WSREP_TRX_ERROR;
+ break;
+ }
+
+ thd->set_wsrep_query_state(QUERY_EXEC);
+
+ if (SR_thd && wsrep_thd_trx_seqno(thd) == WSREP_SEQNO_UNDEFINED)
+ {
+ --thd->wsrep_fragments_sent;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ wsrep_SR_store->release_SR_thd(SR_thd);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->store_globals();
+ }
+
+ /*
+ Reset trx meta if pre_commit certify() (regardless of conflict state),
+ new seqno will be used for next fragment.
+ In case of failure GTID may be required in rollback process.
+ */
+ if (reset_trx_meta)
+ {
+ WSREP_DEBUG("Reset trx meta for %lu", thd->thread_id);
+ thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
+ thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
+ }
+
+ DBUG_RETURN(ret);
+ }
+
+ static int wsrep_SR_step(THD *thd, uint unit)
+ {
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
+ DBUG_ENTER("wsrep_SR_step");
+ if (!wsrep_may_produce_SR_step(thd) ||
+ unit != thd->variables.wsrep_trx_fragment_unit ||
+ thd->variables.wsrep_trx_fragment_size == 0 ||
+ thd->get_stmt_da()->is_error())
+ {
+ #if 0
+ WSREP_DEBUG("wsrep_SR_step: skip, frag_size: %lu is_error: %d",
+ thd->variables.wsrep_trx_fragment_size,
+ thd->get_stmt_da()->is_error());
+ #endif /* 0 */
+ DBUG_RETURN(0);
+ }
+
+ /*
+ Flush pending rows event into IO cache buffer
+ */
+ thd->binlog_flush_pending_rows_event(true);
+
+ wsrep_trx_status ret= WSREP_TRX_OK;
+ uint written= (wsrep_get_trans_cache_position(thd)
+ - wsrep_get_fragment_base(thd));
+ bool replicate= false;
+
+ switch (thd->variables.wsrep_trx_fragment_unit)
+ {
+ case WSREP_FRAG_BYTES:
+ if (written >= thd->variables.wsrep_trx_fragment_size)
+ replicate= true;
+ break;
+ case WSREP_FRAG_ROWS:
+ case WSREP_FRAG_STATEMENTS:
+ wsrep_append_fill_rate(thd, 1);
+ if (wsrep_get_fragment_fill(thd) >= thd->variables.wsrep_trx_fragment_size)
+ replicate= true;
+ break;
+ default:
+ wsrep_append_fill_rate(thd, 1);
+ replicate= true;
+ DBUG_ASSERT(0);
+ }
+
+ if (replicate)
+ {
+ WSREP_DEBUG("fragment fill: %lu fragment unit: %lu fragment size: %lu written: %u",
+ wsrep_get_fragment_fill(thd),
+ thd->variables.wsrep_trx_fragment_unit,
+ thd->variables.wsrep_trx_fragment_size,
+ written);
+
+ ret= wsrep_replicate_fragment(thd);
+ if (ret == WSREP_TRX_OK)
+ {
+ wsrep_reset_fragment_fill(thd, 0);
+ wsrep_step_fragment_base(thd, written);
+ }
+ }
+
+ if (ret)
+ {
+ if (!thd->get_stmt_da()->is_error())
+ {
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT,
+ wsrep_trx_status_to_wsrep_status(ret));
+ }
+ }
+
+ DBUG_RETURN(ret);
+ }
+
+ bool wsrep_replicate_GTID(THD *thd)
+ {
+ if (thd->slave_thread)
+ {
+ WSREP_DEBUG("GTID replication");
+ DBUG_ASSERT (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id);
+ thd->set_wsrep_next_trx_id(thd->query_id);
+ (void)wsrep_ws_handle_for_trx(&thd->wsrep_ws_handle,
+ thd->wsrep_next_trx_id());
+ DBUG_ASSERT (WSREP_UNDEFINED_TRX_ID != thd->wsrep_ws_handle.trx_id);
+
+ int rcode= wsrep_certify(thd);
+ if (rcode)
+ {
+ WSREP_INFO("GTID replication failed: %d", rcode);
+ if (wsrep->commit_order_enter(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta))
+ {
+ WSREP_ERROR("wsrep::commit_order_enter fail: %llu %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+
+ if (wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, NULL))
+ {
+ WSREP_ERROR("wsrep::commit_order_leave fail: %llu %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+
+ thd->wsrep_replicate_GTID= false;
+ my_message(ER_ERROR_DURING_COMMIT,
+ "WSREP GTID replication was interrupted", MYF(0));
+
+ return true;
+ }
+ }
+ thd->wsrep_replicate_GTID= false;
+ return false;
+ }
+
+
+ /*
+ Utility methods to be called from hooks
+ */
+
+ /*
+ Log some THD info and called context
+ */
+ static void wsrep_log_thd(THD* thd, bool is_real_trans, const char *function)
+ {
+ char message[10];
+ snprintf(message, sizeof(message), "real: %d", is_real_trans);
+ message[sizeof(message) - 1] = '\0';
+ wsrep_log_thd(thd, message, function);
+ }
+
+
+ /*
+ Determine if the hook should be run
+
+ @return 0 Failure
+ @return 1 Success
+ */
+ static int wsrep_run_hook(const THD* thd, bool is_real_trans,
+ bool for_real_trans)
+ {
+ return (WSREP(thd) && /* THD is non NULL, wsrep is enabled for thd
+ and is client thread */
+ thd->wsrep_exec_mode != TOTAL_ORDER && /* not TOI execution */
+ thd->wsrep_exec_mode != REPL_RECV && /* not applier or replayer */
+ (!for_real_trans || is_real_trans) &&
+ !(for_real_trans && /* CTAS SELECT phase */
+ WSREP_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT &&
+ thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
- thd->lex->select_lex.item_list.elements)
++ thd->lex->current_select->item_list.elements)
+ );
+ }
+
+ static inline
+ int wsrep_is_effective_not_to_replay(THD *thd)
+ {
+ mysql_mutex_assert_owner(&thd->LOCK_wsrep_thd);
+ int ret= (
+ /* effective */
+ thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID &&
+ /* not to replay */
+ thd->wsrep_conflict_state() != MUST_REPLAY
+ );
+ return ret;
+ }
+
+
+ int wsrep_after_row(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_after_row");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ /*
+ We want to run this hook for each row, not just ones which
+ end autocommits or transactions.
+ */
+ if (!wsrep_run_hook(thd, is_real_trans, false))
+ {
+ DBUG_RETURN(0);
+ }
+
+
+ #if 0
+ /*
+ Logging this hook is disabled, it gets very verbose.
+ */
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_row enter");
+ #endif /* 0 */
+ int ret= 0;
+
+ /*
+ TODO: Move this before row operation, maybe before_row() hook.
+ */
+ if (!wsrep_certify_nonPK)
+ {
+ for (TABLE* table= thd->open_tables; table != NULL; table= table->next)
+ {
+ if (table->key_info == NULL || table->s->primary_key == MAX_KEY)
+ {
+ WSREP_DEBUG("No primary key found for table %s.%s",
+ table->s->db.str, table->s->table_name.str);
+ ret= 1;
+ break;
+ }
+ }
+ }
+
+ if (!ret)
+ {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state() == NO_CONFLICT)
+ {
+ ret|= wsrep_SR_step(thd, WSREP_FRAG_BYTES);
+ ret|= wsrep_SR_step(thd, WSREP_FRAG_ROWS);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ #if 0
+ /*
+ Logging this hook is disabled, it gets very verbose.
+ */
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_row leave");
+ #endif /* 0 */
+
+
+ DBUG_RETURN(ret);
+ }
+
+ int wsrep_before_prepare(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_before_prepare");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ if (!wsrep_run_hook(thd, is_real_trans, true))
+ {
+ DBUG_RETURN(0);
+ }
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_prepare enter");
+ }
+
+ int ret= 0;
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (wsrep_is_effective_not_to_replay(thd))
+ {
+ if (thd->wsrep_is_streaming())
+ {
+ DBUG_EXECUTE_IF("crash_last_fragment_commit_before_fragment_removal",
+ DBUG_SUICIDE(););
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ /*
+ We don't support implicit commit for SR transactions.
+ */
+ if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_BEGIN))
+ {
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT);
+ ret= 1;
+ }
+ else
+ {
+ /*
+ Disable SR temporarily in order to avoid SR step from
+ after_row() hook when deleting fragments.
+ */
+ ulong frag_size_orig= thd->variables.wsrep_trx_fragment_size;
+ thd->variables.wsrep_trx_fragment_size= 0;
+ wsrep_remove_SR_fragments(thd);
+ thd->variables.wsrep_trx_fragment_size= frag_size_orig;
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ DBUG_EXECUTE_IF("crash_last_fragment_commit_after_fragment_removal",
+ DBUG_SUICIDE(););
+ }
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_prepare leave");
+ }
+ DBUG_RETURN(ret);
+ }
+
+ int wsrep_after_prepare(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_after_prepare");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ if (!wsrep_run_hook(thd, is_real_trans, true))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_prepare enter");
+ }
+
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
+ /*
+ thd->wsrep_exec_mode will be set in wsrep_certify() according
+ to outcome
+ */
+ int ret= 1;
+
+ if (wsrep_is_effective_not_to_replay(thd))
+ {
+ if (thd->wsrep_conflict_state() == NO_CONFLICT)
+ {
+ ret= wsrep_certify(thd);
+ if (ret)
+ {
+ DBUG_ASSERT(thd->wsrep_conflict_state() == MUST_REPLAY ||
+ thd->get_stmt_da()->is_error());
+ }
+ }
+ else
+ {
+ /*
+ BF aborted before pre commit, set state to aborting
+ and return error to trigger rollback.
+ */
+ DBUG_ASSERT(thd->wsrep_conflict_state() == MUST_ABORT);
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ }
+ }
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_prepare leave");
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(ret);
+ }
+
+ int wsrep_before_commit(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_before_commit");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ /*
+ Applier/replayer codepath
+ */
+ if (thd->wsrep_exec_mode == REPL_RECV)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_commit enter");
+ if (is_real_trans)
+ {
+ DBUG_ASSERT(thd->wsrep_trx_must_order_commit());
+ if (wsrep->commit_order_enter(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta) != WSREP_OK)
+ {
+ WSREP_ERROR("Failed to enter applier commit order critical section");
+ DBUG_RETURN(1);
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_COMMITTING);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_commit leave");
+ DBUG_RETURN(0);
+ }
+
+
+ if (!wsrep_run_hook(thd, is_real_trans, true))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_commit enter");
+ }
+
+ int ret= 0;
+ if (thd->wsrep_exec_mode == LOCAL_STATE)
+ {
+ /*
+ We got here without having prepare phase first. This may
+ happen for example via trans_commit_stmt() -> tc_log->commit(thd, false)
+ in case of autocommit DML and binlog_format = STATEMENT.
+ */
+ if (wsrep_is_effective_not_to_replay(thd))
+ {
+ if (thd->wsrep_conflict_state() == NO_CONFLICT)
+ {
+ ret= wsrep_certify(thd);
+ }
+ else
+ {
+ /*
+ BF aborted before pre commit, set state to aborting
+ and return error to trigger rollback.
+ */
+ DBUG_ASSERT(thd->wsrep_conflict_state() == MUST_ABORT);
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ ret= 1;
+ }
+ }
+ }
+
+
+ if (!ret && wsrep_is_effective_not_to_replay(thd))
+ {
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ ret= 1;
+ }
+ else
+ {
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ wsrep_status_t rcode= wsrep->commit_order_enter(wsrep,
+ &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ switch (rcode)
+ {
+ case WSREP_OK:
+ wsrep_xid_init(&thd->wsrep_xid, thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ break;
+ case WSREP_BF_ABORT:
+ DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
+ if (thd->wsrep_conflict_state() != MUST_ABORT)
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ ++wsrep_replaying;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ ret= 1;
+ break;
+ default:
+ WSREP_ERROR("Could not enter commit order critical section");
+ abort();
+ }
+ }
+ }
+
+ DBUG_ASSERT(ret ||
+ thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID ||
+ thd->wsrep_exec_mode == LOCAL_COMMIT);
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_commit leave");
+ }
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(ret);
+ }
+
+ int wsrep_ordered_commit(THD* thd, bool all, const wsrep_apply_error& err)
+ {
+ DBUG_ENTER("wsrep_ordered_commit");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ /*
+ Applier/replayer codepath
+ */
+ if (thd->wsrep_exec_mode == REPL_RECV)
+ {
+ int ret= 0;
+ wsrep_log_thd(thd, is_real_trans, "wsrep_ordered_commit enter");
+ if (is_real_trans)
+ {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ bool run_commit_order_leave=
+ (thd->wsrep_query_state() != QUERY_ORDERED_COMMIT);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (run_commit_order_leave)
+ {
+ wsrep_buf_t const err_buf= err.get_buf();
+ wsrep_status_t const rcode=
+ wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, &err_buf);
+
+ if (rcode != WSREP_OK)
+ {
+ DBUG_ASSERT(rcode == WSREP_NODE_FAIL);
+ if (err.is_null())
+ {
+ WSREP_ERROR("Failed to leave commit order critical section, "
+ "rcode: %d", rcode);
+ }
+ else
+ {
+ WSREP_WARN("Replication can't continue due to the error in a "
+ "writeset apply operation: %s", err.c_str());
+ }
+ ret= 1;
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_ORDERED_COMMIT);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ }
+ DBUG_RETURN(ret);
+ }
+
+ if (!wsrep_run_hook(thd, is_real_trans, true))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_ordered_commit enter");
+ }
+
+ DBUG_ASSERT(thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID ||
+ (thd->wsrep_exec_mode == LOCAL_COMMIT &&
+ thd->wsrep_query_state() == QUERY_COMMITTING));
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+ if (wsrep_is_effective_not_to_replay(thd))
+ {
+ thd->wsrep_SR_fragments.clear();
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (wsrep_thd_trx_seqno(thd) != WSREP_SEQNO_UNDEFINED &&
+ wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, NULL))
+ {
+ WSREP_ERROR("wsrep::commit_order_leave fail: %llu %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_ORDERED_COMMIT);
+ }
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_ordered_commit leave");
+ }
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(0);
+ }
+
+ int wsrep_after_commit(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_after_commit");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ if (!wsrep_run_hook(thd, is_real_trans, true))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_commit enter");
+ }
+
+ DBUG_ASSERT(thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID ||
+ (thd->wsrep_exec_mode == LOCAL_COMMIT &&
+ (thd->wsrep_query_state() == QUERY_COMMITTING ||
+ thd->wsrep_query_state() == QUERY_ORDERED_COMMIT)));
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT ||
+ thd->wsrep_conflict_state() == MUST_ABORT);
+
+ if (wsrep_is_effective_not_to_replay(thd))
+ {
+ if (thd->wsrep_query_state() == QUERY_COMMITTING)
+ {
+ thd->wsrep_SR_fragments.clear();
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (wsrep_thd_trx_seqno(thd) != WSREP_SEQNO_UNDEFINED &&
+ wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, NULL))
+ {
+ WSREP_ERROR("wsrep::commit_order_leave fail: %llu %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_ORDERED_COMMIT);
+ }
+
+ DBUG_ASSERT(thd->wsrep_query_state() == QUERY_ORDERED_COMMIT);
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (wsrep->release(wsrep, &thd->wsrep_ws_handle))
+ {
+ WSREP_WARN("wsrep::release fail: %lld %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ }
+
+ if (thd->wsrep_conflict_state() == MUST_ABORT)
+ {
+ assert(0);
+ WSREP_LOG_THD(thd, "BF aborted at commit phase");
+ thd->killed= NOT_KILLED;
+ thd->set_wsrep_conflict_state(NO_CONFLICT);
+ }
+
+ wsrep_cleanup_transaction(thd);
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_commit leave");
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(0);
+ }
+
+ int wsrep_before_rollback(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_before_rollback");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ if (!wsrep_run_hook(thd, is_real_trans, false))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ (void)wsrep_ws_handle_for_trx(&thd->wsrep_ws_handle,
+ thd->wsrep_next_trx_id());
+
+ if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ WSREP_DEBUG("wsrep_before_rollback: setting trx_id to undefined, thd %llu %s",
+ thd->thread_id, thd->query());
+ }
+ }
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_rollback enter");
+ }
+
+ if (thd->wsrep_query_state() == QUERY_COMMITTING)
+ {
+ DBUG_ASSERT(thd->wsrep_conflict_state() == MUST_ABORT);
+ WSREP_DEBUG("Query aborted while committing");
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ thd->set_wsrep_conflict_state(MUST_REPLAY);
+ thd->wsrep_exec_mode= LOCAL_STATE;
+ }
+
+ if (thd->wsrep_exec_mode != LOCAL_ROLLBACK &&
+ wsrep_is_effective_not_to_replay(thd) &&
+ (is_real_trans ||
+ (thd->wsrep_is_streaming() &&
+ (!wsrep_stmt_rollback_is_safe(thd) ||
+ thd->wsrep_conflict_state() != NO_CONFLICT))))
+ {
+ if (thd->wsrep_is_streaming() &&
+ /*
+ Cert failure will generate implicit rollback event on slaves
+
+ TODO: Need to do SR table cleanup on certification failure here.
+ */
+ thd->wsrep_conflict_state() != CERT_FAILURE &&
+ thd->wsrep_SR_rollback_replicated_for_trx != thd->wsrep_trx_id())
+ {
+ wsrep_prepare_SR_trx_info_for_rollback(thd);
+ thd->wsrep_SR_rollback_replicated_for_trx= thd->wsrep_trx_id();
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ DEBUG_SYNC(thd, "wsrep_before_SR_rollback");
+ WSREP_DEBUG("Replicating rollback for %ld %ld",
+ thd->thread_id, thd->wsrep_trx_id());
+ wsrep_status_t rcode= wsrep->rollback(wsrep,
+ thd->wsrep_trx_id(), NULL);
+ if (rcode != WSREP_OK)
+ {
+ WSREP_WARN("failed to send SR rollback for %lld", thd->thread_id);
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ }
+ thd->wsrep_exec_mode= LOCAL_ROLLBACK;
+ }
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_before_rollback leave");
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(0);
+ }
+
+ int wsrep_after_rollback(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_after_rollback");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ if (!wsrep_run_hook(thd, is_real_trans, false))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_rollback enter");
+ }
+
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT || /* voluntary or stmt rollback */
+ thd->wsrep_conflict_state() == MUST_ABORT || /* BF abort */
+ thd->wsrep_conflict_state() == ABORTING || /* called from wsrep_client_rollback() */
+ thd->wsrep_conflict_state() == CERT_FAILURE || /* cert failure */
+ thd->wsrep_conflict_state() == MUST_REPLAY || /* BF abort with successful repl */
+ (thd->wsrep_conflict_state() == ABORTED) /* trans_rollback_stmt() from mysql_exec_command() */
+ );
+
+ if (!is_real_trans)
+ {
+ /*
+ Statement rollback
+ */
+ if ((thd->wsrep_is_streaming() && !wsrep_stmt_rollback_is_safe(thd)))
+ {
+ /*
+ Statement rollback is not safe, do full rollback and report to client.
+ */
+ if (thd->wsrep_conflict_state() == NO_CONFLICT)
+ {
+ /*
+ If the statement rollback is due to an error, such as ER_DUP_ENTRY,
+ the client may not expect a full transaction rollback.
+ Set the conflict state to must abort here so that after_command()
+ hook will override the error to ER_LOCK_DEADLOCK.
+ */
+ thd->set_wsrep_conflict_state(MUST_ABORT);
+ }
+
+ /*
+ From trans_rollback()
+ */
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ /*
+ Calling ha_rollback_trans() here will call rollback hooks recursively.
+ */
+ ha_rollback_trans(thd, TRUE);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->variables.option_bits&= ~OPTION_BEGIN;
+ //thd->transaction.all.reset_unsafe_rollback_flags();
+ thd->transaction.all.m_unsafe_rollback_flags= 0;
+ thd->lex->start_transaction_opt= 0;
+ }
+ }
+ else
+ {
+ if (thd->wsrep_conflict_state() == ABORTED)
+ {
+ thd->wsrep_exec_mode= LOCAL_ROLLBACK;
+ }
+ if (wsrep_is_effective_not_to_replay(thd))
+ {
+ /*
+ Must have gone through before_rollback() hook at least once.
+ */
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_ROLLBACK);
+ }
+ }
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_rollback leave");
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(0);
+ }
+
+ int wsrep_after_command(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_after_command");
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ /*
+ We want to run this hook for each command, not just ones which
+ end autocommits or transactions.
+ */
+ if (!wsrep_run_hook(thd, is_real_trans, false))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_command enter");
+ }
+
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE ||
+ thd->wsrep_exec_mode == LOCAL_ROLLBACK);
+
+ int ret= 0;
+
+ switch (thd->wsrep_exec_mode)
+ {
+ case LOCAL_STATE:
+ /*
+ Run SR step if
+ - No conflict detected
+ - Trnsaction is active, it has acquired trx_id
+ - Not read-only command
+ */
+ if (thd->wsrep_conflict_state() == NO_CONFLICT &&
+ thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID &&
+ thd->lex->sql_command != SQLCOM_SELECT)
+ {
+ ret|= wsrep_SR_step(thd, WSREP_FRAG_BYTES);
+ ret|= wsrep_SR_step(thd, WSREP_FRAG_STATEMENTS);
+ }
+ break;
+ case LOCAL_ROLLBACK:
+ {
+ bool should_retry= false;
+ const bool forced_rollback(thd->wsrep_conflict_state() == MUST_ABORT ||
+ thd->wsrep_conflict_state() == CERT_FAILURE);
+
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT ||
+ thd->wsrep_conflict_state() == MUST_ABORT ||
+ thd->wsrep_conflict_state() == CERT_FAILURE);
+ /*
+ If conflict state is NO_CONFLICT the transaction was either
+ voluntary or done due to deadlock.
+ */
+ if (forced_rollback)
+ {
+ should_retry= !(
+ thd->wsrep_is_streaming() || // SR transactions do not retry
+ thd->spcont // SP code not patched to handle retry
+ );
+ wsrep_client_rollback(thd, false);
+ }
+ wsrep_post_rollback(thd);
+ if (forced_rollback)
+ {
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ }
+ wsrep_cleanup_transaction(thd);
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
+ DBUG_ASSERT(thd->wsrep_conflict_state() == NO_CONFLICT);
+ /*
+ Retry autocommit in case of deadlock error, usually seen
+ as ER_LOCK_DEADLOCK, sometimes as ER_QUERY_INTERRUPTED.
+ */
+ if (should_retry && thd->get_stmt_da()->is_error() &&
+ (thd->get_stmt_da()->sql_errno() == ER_LOCK_DEADLOCK ||
+ thd->get_stmt_da()->sql_errno() == ER_QUERY_INTERRUPTED))
+ {
+ thd->set_wsrep_conflict_state(RETRY_AUTOCOMMIT);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (thd->wsrep_conflict_state() == MUST_ABORT ||
+ thd->wsrep_conflict_state() == CERT_FAILURE)
+ {
+ wsrep_client_rollback(thd);
+ wsrep_post_rollback(thd);
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ wsrep_cleanup_transaction(thd);
+ }
+
+ if (thd->wsrep_conflict_state() == MUST_REPLAY &&
+ !thd->spcont)
+ {
+ /*
+ BF aborted during commit, must replay
+ */
+ wsrep_replay_transaction(thd);
+ }
+
+ if (thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_log_thd(thd, is_real_trans, "wsrep_after_command leave");
+ }
+
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(ret);
+ }
+
+ int wsrep_before_GTID_binlog(THD* thd, bool all)
+ {
+ DBUG_ENTER("wsrep_before_GTID_binlogt");
+ int ret= 0;
+
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ if (!wsrep_run_hook(thd, is_real_trans, true))
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (wsrep_replicate_GTID(thd))
+ {
+ ret = 1;
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ wsrep_status_t rcode;
+ if (!ret &&
+ (rcode = wsrep->commit_order_enter(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta)))
+ {
+ WSREP_ERROR("wsrep::commit_order_enter fail: %llu %d",
+ (long long)thd->thread_id, rcode);
+ ret= 1;
+ }
+
+ if (!ret &&
+ (rcode = wsrep->commit_order_leave(wsrep, &thd->wsrep_ws_handle,
+ &thd->wsrep_trx_meta, NULL)))
+ {
+ WSREP_ERROR("wsrep::commit_order_leave fail: %llu %d",
+ (long long)thd->thread_id, rcode);
+ ret= 1;
+ }
+
+ if (!ret)
+ {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->set_wsrep_query_state(QUERY_ORDERED_COMMIT);
+ thd->set_wsrep_query_state(QUERY_EXEC);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+
+ if (wsrep->release(wsrep, &thd->wsrep_ws_handle))
+ {
+ WSREP_WARN("wsrep::release fail: %lld %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ wsrep_cleanup_transaction(thd);
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(ret);
+ }
+
+ int wsrep_register_trans_observer(void *p)
+ {
+ return 0;
+ }
+
+ int wsrep_unregister_trans_observer(void *p)
+ {
+ return 0;
+ }
diff --cc sql/wsrep_utils.cc
index 3c341e222b3,3c341e222b3..e9dad5f1912
--- a/sql/wsrep_utils.cc
+++ b/sql/wsrep_utils.cc
@@@ -21,6 -21,6 +21,7 @@@
#endif
#include "mariadb.h"
++#include "my_pthread.h"
#include "wsrep_utils.h"
#include "wsrep_mysqld.h"
diff --cc sql/wsrep_utils.h
index 277cea9dc31,f6520dda86e..bb3203c87e9
--- a/sql/wsrep_utils.h
+++ b/sql/wsrep_utils.h
@@@ -219,6 -240,6 +240,7 @@@ public
return &member_info_;
}
++#ifdef WITH_WSREP
int lock()
{
return mysql_mutex_lock(&LOCK_wsrep_config_state);
@@@ -228,6 -249,6 +250,7 @@@
{
return mysql_mutex_unlock(&LOCK_wsrep_config_state);
}
++#endif
private:
wsrep_view_info_t view_;
diff --cc sql/wsrep_xid.h
index 5b33a904de1,21d0a3f8f41..04dedb1f583
--- a/sql/wsrep_xid.h
+++ b/sql/wsrep_xid.h
@@@ -24,6 -23,7 +23,7 @@@
#include "handler.h" // XID typedef
void wsrep_xid_init(xid_t*, const wsrep_uuid_t&, wsrep_seqno_t);
-int wsrep_is_wsrep_xid(const void* xid);
++extern "C" int wsrep_is_wsrep_xid(const void* xid);
const wsrep_uuid_t* wsrep_xid_uuid(const XID&);
wsrep_seqno_t wsrep_xid_seqno(const XID&);
diff --cc storage/innobase/buf/buf0dump.cc
index a0c4baad64d,95102dcbd87..bc96e91c486
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@@ -43,9 -43,12 +43,9 @@@ Created April 08, 2011 Vasil Dimo
#include "ut0byte.h"
#include <algorithm>
-#ifdef WITH_WSREP_OUT
-extern my_bool wsrep_recovery;
-#endif /* WITH_WSREP */
--#include "mysql/service_wsrep.h" /* wsrep_recovery */
#include <my_service_manager.h>
++#include "mysql/service_wsrep.h" /* wsrep_recovery */
enum status_severity {
STATUS_INFO,
@@@ -858,7 -861,7 +858,7 @@@ DECLARE_THREAD(buf_dump_thread)(void*
"Dumping of buffer pool not started"
" as load was incomplete");
#ifdef WITH_WSREP
-- } else if (wsrep_recovery) {
++ } else if (get_wsrep_recovery()) {
#endif /* WITH_WSREP */
} else {
buf_dump(FALSE/* do complete dump at shutdown */);
diff --cc storage/innobase/handler/ha_innodb.cc
index b0af34814af,62aec753777..56d41bf00b6
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@@ -5137,7 -5087,7 +5152,8 @@@ static void innobase_kill_query(handler
{
DBUG_ENTER("innobase_kill_query");
#ifdef WITH_WSREP
-- if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) {
++ if (wsrep_on(thd) &&
++ wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) {
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
@@@ -16754,7 -16705,7 +16768,10 @@@ ha_innobase::get_auto_increment
thd_get_thread_id(ha_thd()),
current, autoinc);
-- if (!wsrep_on(ha_thd())) {
++#ifdef WITH_WSREP
++ if (!wsrep_on(ha_thd()))
++#endif
++ {
current = autoinc - m_prebuilt->autoinc_increment;
}
@@@ -18992,14 -18814,27 +18880,28 @@@ wsrep_abort_transaction
my_bool signal)
{
DBUG_ENTER("wsrep_innobase_abort_thd");
- trx_t* victim_trx = thd_to_trx(victim_thd);
- trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
+
+ trx_t* victim_trx = thd_to_trx(victim_thd);
+ trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
+ if (wsrep_debug)
+ {
+ wsrep_thd_LOCK(victim_thd);
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s conf: %d",
+ wsrep_thd_query(bf_thd),
+ wsrep_thd_query(victim_thd),
+ wsrep_thd_conflict_state(victim_thd, FALSE));
+ wsrep_thd_UNLOCK(victim_thd);
+ }
- WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %d",
+ if (wsrep_debug)
+ {
+ wsrep_thd_LOCK(victim_thd);
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s conf: %d",
wsrep_thd_query(bf_thd),
wsrep_thd_query(victim_thd),
- wsrep_thd_conflict_state(victim_thd, FALSE));
+ wsrep_thd_get_conflict_state(victim_thd));
+ wsrep_thd_UNLOCK(victim_thd);
+ }
if (victim_trx) {
lock_mutex_enter();
diff --cc storage/innobase/include/ha_prototypes.h
index 1313705f119,5ecbd4ac600..28bc8f9e565
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@@ -240,6 -240,11 +240,11 @@@ wsrep_innobase_kill_one_trx(void * cons
ulint wsrep_innobase_mysql_sort(int mysql_type, uint charset_number,
unsigned char* str, unsigned int str_length,
unsigned int buf_length);
+ my_bool wsrep_thd_is_SR(void *thd_ptr);
+ my_bool wsrep_thd_skip_locking(void *thd_ptr);
+ void wsrep_handle_SR_rollback(void *BF_thd_ptr, void *victim_thd_ptr);
-void wsrep_thd_xid(const void *thd_ptr, void *xid, size_t xid_size);
++extern "C" void wsrep_thd_xid(const void *thd_ptr, void *xid, size_t xid_size);
+ bool wsrep_bf_abort(void *bf_thd_ptr, void *victim_thd_ptr, bool signal);
#endif /* WITH_WSREP */
/**********************************************************************//**
diff --cc storage/innobase/row/row0ins.cc
index 37ae828d09d,fa2274ad1f4..96db940e769
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@@ -50,6 -50,8 +50,11 @@@ Created 4/20/1996 Heikki Tuur
#include "fts0types.h"
#include "m_string.h"
#include "gis0geo.h"
++#include "log.h"
+ #include "wsrep_mysqld.h"
++#ifdef WITH_WSREP
+ #include "wsrep_schema.h"
++#endif
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
@@@ -3240,9 -3229,26 +3245,26 @@@ row_ins_clust_index_entry
n_uniq = dict_index_is_unique(index) ? index->n_uniq : 0;
+ #ifdef WITH_WSREP
+ const bool skip_locking
+ = wsrep_thd_skip_locking(thr_get_trx(thr)->mysql_thd);
- ulint flags = skip_locking | dict_table_is_temporary(index->table)
++ ulint flags = skip_locking | index->table->is_temporary()
+ ? BTR_NO_LOCKING_FLAG
+ : index->table->no_rollback() ? BTR_NO_ROLLBACK : 0;
+ #ifdef UNIV_DEBUG
+ if (skip_locking && sr_table_name_full_str != index->table->name.m_name) {
+ WSREP_ERROR("Record locking is disabled in this thread, "
+ "but the table being modified is not "
+ "`%s`: `%s`.", sr_table_name_full_str.c_str(),
+ index->table->name.m_name);
+ ut_error;
+ }
+ #endif /* UNIV_DEBUG */
+ #else
ulint flags = index->table->no_rollback() ? BTR_NO_ROLLBACK
- : dict_table_is_temporary(index->table)
+ : index->table->is_temporary()
? BTR_NO_LOCKING_FLAG : 0;
+ #endif /* WITH_WSREP */
const ulint orig_n_fields = entry->n_fields;
/* Try first optimistic descent to the B-tree */
diff --cc storage/innobase/row/row0sel.cc
index b68efbfa7be,680fab0c128..fe49d298bbc
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@@ -56,6 -56,14 +56,15 @@@ Created 12/19/1997 Heikki Tuur
#include "ha_prototypes.h"
#include "srv0mon.h"
#include "ut0new.h"
+ #include "m_string.h" /* for my_sys.h */
+ #include "my_sys.h" /* DEBUG_SYNC_C */
++#ifdef WITH_WSREP
+ #include "wsrep_schema.h"
-
++#endif
+ #include "my_compare.h" /* enum icp_result */
+ #include "thr_lock.h"
+ #include "handler.h"
+ #include "ha_innodb.h"
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
#define SEL_MAX_N_PREFETCH 16
1
0