summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-03-19 16:04:59 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2019-03-19 16:04:59 +0200
commit117291db8b35ddb4cd8c89ee4d8de888160b7163 (patch)
tree05041fcbc5a4c5c14531d148505216cb88add73c /sql
parent26e5bff00318272c717561e7b980036df3332d7b (diff)
parenta77e2668667e46d96c445a4a9a8325b7fe9461b3 (diff)
downloadmariadb-git-117291db8b35ddb4cd8c89ee4d8de888160b7163.tar.gz
Merge 10.2 into 10.3
Diffstat (limited to 'sql')
-rw-r--r--sql/log.cc51
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_load.cc48
-rw-r--r--sql/sql_plugin_services.ic2
-rw-r--r--sql/sql_select.cc3
-rw-r--r--sql/wsrep_dummy.cc6
-rw-r--r--sql/wsrep_hton.cc1
-rw-r--r--sql/wsrep_thd.cc10
9 files changed, 111 insertions, 20 deletions
diff --git a/sql/log.cc b/sql/log.cc
index 0018ce2cdc6..23ef3152843 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -6474,8 +6474,25 @@ err:
it's list before dump-thread tries to send it
*/
update_binlog_end_pos(offset);
+ /*
+ If a transaction with the LOAD DATA statement is divided
+ into logical mini-transactions (of the 10K rows) and binlog
+ is rotated, then the last portion of data may be lost due to
+ wsrep handler re-registration at the boundary of the split.
+ Since splitting of the LOAD DATA into mini-transactions is
+ logical, we should not allow these mini-transactions to fall
+ into separate binlogs. Therefore, it is necessary to prohibit
+ the rotation of binlog in the middle of processing LOAD DATA:
+ */
+#ifdef WITH_WSREP
+ if (!thd->wsrep_split_flag)
+ {
+#endif /* WITH_WSREP */
if (unlikely((error= rotate(false, &check_purge))))
check_purge= false;
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
}
}
}
@@ -7201,8 +7218,25 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd)
likely(!(error= flush_and_sync(0))))
{
update_binlog_end_pos();
+ /*
+ If a transaction with the LOAD DATA statement is divided
+ into logical mini-transactions (of the 10K rows) and binlog
+ is rotated, then the last portion of data may be lost due to
+ wsrep handler re-registration at the boundary of the split.
+ Since splitting of the LOAD DATA into mini-transactions is
+ logical, we should not allow these mini-transactions to fall
+ into separate binlogs. Therefore, it is necessary to prohibit
+ the rotation of binlog in the middle of processing LOAD DATA:
+ */
+#ifdef WITH_WSREP
+ if (!thd->wsrep_split_flag)
+ {
+#endif /* WITH_WSREP */
if (unlikely((error= rotate(false, &check_purge))))
check_purge= false;
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
}
offset= my_b_tell(&log_file);
@@ -7969,6 +8003,20 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
mark_xids_active(binlog_id, xid_count);
}
+ /*
+ If a transaction with the LOAD DATA statement is divided
+ into logical mini-transactions (of the 10K rows) and binlog
+ is rotated, then the last portion of data may be lost due to
+ wsrep handler re-registration at the boundary of the split.
+ Since splitting of the LOAD DATA into mini-transactions is
+ logical, we should not allow these mini-transactions to fall
+ into separate binlogs. Therefore, it is necessary to prohibit
+ the rotation of binlog in the middle of processing LOAD DATA:
+ */
+#ifdef WITH_WSREP
+ if (!leader->thd->wsrep_split_flag)
+ {
+#endif /* WITH_WSREP */
if (rotate(false, &check_purge))
{
/*
@@ -7988,6 +8036,9 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, errno);
check_purge= false;
}
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
/* In case of binlog rotate, update the correct current binlog offset. */
commit_offset= my_b_write_tell(&log_file);
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 4ff57856cd9..051abb66c0c 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -787,6 +787,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
wsrep_affected_rows = 0;
wsrep_replicate_GTID = false;
wsrep_skip_wsrep_GTID = false;
+ wsrep_split_flag = false;
#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -1239,6 +1240,7 @@ void THD::init(bool skip_lock)
wsrep_affected_rows = 0;
wsrep_replicate_GTID = false;
wsrep_skip_wsrep_GTID = false;
+ wsrep_split_flag = false;
#endif /* WITH_WSREP */
if (variables.sql_log_bin)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e8083c5981b..1ac422f40b3 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4727,6 +4727,14 @@ public:
ulong wsrep_affected_rows;
bool wsrep_replicate_GTID;
bool wsrep_skip_wsrep_GTID;
+ /* This flag is set when innodb do an intermediate commit to
+ processing the LOAD DATA INFILE statement by splitting it into 10K
+ rows chunks. If flag is set, then binlog rotation is not performed
+ while intermediate transaction try to commit, because in this case
+ rotation causes unregistration of innodb handler. Later innodb handler
+ registered again, but replication of last chunk of rows is skipped
+ by the innodb engine: */
+ bool wsrep_split_flag;
#endif /* WITH_WSREP */
/* Handling of timeouts for commands */
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index b7e110e4b95..92ef222c8b7 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -41,6 +41,7 @@
#include "sql_trigger.h"
#include "sql_derived.h"
#include "sql_show.h"
+#include "debug_sync.h"
extern "C" int _my_b_net_read(IO_CACHE *info, uchar *Buffer, size_t Count);
@@ -119,16 +120,26 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table,
if (hton->db_type != DB_TYPE_INNODB)
DBUG_RETURN(false);
WSREP_DEBUG("intermediate transaction commit in LOAD DATA");
+ wsrep_set_load_multi_commit(thd, true);
if (wsrep_run_wsrep_commit(thd, true) != WSREP_TRX_OK) DBUG_RETURN(true);
if (binlog_hton->commit(binlog_hton, thd, true)) DBUG_RETURN(true);
wsrep_post_commit(thd, true);
hton->commit(hton, thd, true);
+ wsrep_set_load_multi_commit(thd, false);
+ DEBUG_SYNC(thd, "intermediate_transaction_commit");
table->file->extra(HA_EXTRA_FAKE_START_STMT);
}
DBUG_RETURN(false);
}
-# define WSREP_LOAD_DATA_SPLIT(thd,table,info) \
+/*
+ If the commit fails, then an early return from
+ the function occurs there and therefore we need
+ to reset the table->auto_increment_field_not_null
+ flag, which is usually reset after calling
+ the write_record():
+*/
+#define WSREP_LOAD_DATA_SPLIT(thd,table,info) \
if (wsrep_load_data_split(thd,table,info)) \
{ \
table->auto_increment_field_not_null= FALSE; \
@@ -138,6 +149,14 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table,
#define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */
#endif /* WITH_WSREP */
+#define WRITE_RECORD(thd,table,info) \
+ do { \
+ int err_= write_record(thd, table, &info); \
+ table->auto_increment_field_not_null= FALSE; \
+ if (err_) \
+ DBUG_RETURN(1); \
+ } while (0)
+
class READ_INFO: public Load_data_param
{
File file;
@@ -918,7 +937,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
List_iterator_fast<Item> it(fields_vars);
Item *item;
TABLE *table= table_list->table;
- bool err, progress_reports;
+ bool progress_reports;
ulonglong counter, time_to_report_progress;
DBUG_ENTER("read_fixed_length");
@@ -1010,11 +1029,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
}
WSREP_LOAD_DATA_SPLIT(thd, table, info);
- err= write_record(thd, table, &info);
- table->auto_increment_field_not_null= FALSE;
- if (err)
- DBUG_RETURN(1);
-
+ WRITE_RECORD(thd, table, info);
+
/*
We don't need to reset auto-increment field since we are restoring
its default value at the beginning of each loop iteration.
@@ -1047,7 +1063,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
Item *item;
TABLE *table= table_list->table;
uint enclosed_length;
- bool err, progress_reports;
+ bool progress_reports;
ulonglong counter, time_to_report_progress;
DBUG_ENTER("read_sep_field");
@@ -1153,10 +1169,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
}
WSREP_LOAD_DATA_SPLIT(thd, table, info);
- err= write_record(thd, table, &info);
- table->auto_increment_field_not_null= FALSE;
- if (err)
- DBUG_RETURN(1);
+ WRITE_RECORD(thd, table, info);
+
/*
We don't need to reset auto-increment field since we are restoring
its default value at the beginning of each loop iteration.
@@ -1200,7 +1214,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
for ( ; ; it.rewind())
{
- bool err;
if (thd->killed)
{
thd->send_kill_message();
@@ -1274,13 +1287,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
case VIEW_CHECK_ERROR:
DBUG_RETURN(-1);
}
-
+
WSREP_LOAD_DATA_SPLIT(thd, table, info);
- err= write_record(thd, table, &info);
- table->auto_increment_field_not_null= false;
- if (err)
- DBUG_RETURN(1);
-
+ WRITE_RECORD(thd, table, info);
+
/*
We don't need to reset auto-increment field since we are restoring
its default value at the beginning of each loop iteration.
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index db73dbb6913..57600e1b4eb 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -180,6 +180,8 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_thd_trx_seqno,
wsrep_thd_ws_handle,
wsrep_thd_auto_increment_variables,
+ wsrep_set_load_multi_commit,
+ wsrep_is_load_multi_commit,
wsrep_trx_is_aborting,
wsrep_trx_order_before,
wsrep_unlock_rollback,
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7ce4ea49c73..6915d4d23ca 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -21264,7 +21264,8 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
the new parent Item. This should not be expensive because all
children of Item_cond_and should be fixed by now.
*/
- new_cond->fix_fields(thd, 0);
+ if (new_cond->fix_fields(thd, 0))
+ return (COND*) 0;
new_cond->used_tables_cache=
((Item_cond_and*) cond)->used_tables_cache &
tables;
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 9afdb36a643..97ec85f7566 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -142,6 +142,12 @@ void wsrep_thd_auto_increment_variables(THD *thd,
*increment= thd->variables.auto_increment_increment;
}
+void wsrep_set_load_multi_commit(THD *thd, bool split)
+{ }
+
+bool wsrep_is_load_multi_commit(THD *thd)
+{ return false; }
+
int wsrep_trx_is_aborting(THD *)
{ return 0; }
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
index 8110faf7d11..aa8dff8d188 100644
--- a/sql/wsrep_hton.cc
+++ b/sql/wsrep_hton.cc
@@ -46,6 +46,7 @@ void wsrep_cleanup_transaction(THD *thd)
thd->wsrep_exec_mode= LOCAL_STATE;
thd->wsrep_affected_rows= 0;
thd->wsrep_skip_wsrep_GTID= false;
+ thd->wsrep_split_flag= false;
return;
}
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index f28063849ea..df09610b66b 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -707,3 +707,13 @@ my_bool wsrep_thd_is_applier(MYSQL_THD thd)
return (is_applier);
}
+
+void wsrep_set_load_multi_commit(THD *thd, bool split)
+{
+ thd->wsrep_split_flag= split;
+}
+
+bool wsrep_is_load_multi_commit(THD *thd)
+{
+ return thd->wsrep_split_flag;
+}