Skip to content

Commit f3c109b

Browse files
author
Kapil Agrawal
committed
Problem
------- The transaction dependency writeset history map doesn't have protection from concurrent access. Analysis -------- This is because we are not locking m_writeset_history by LOCK_slave_trans_dep_tracker at all places wherever it is accessed whereas the same object is getting locked while clearing the history map. Fix --- The Writeset_history::m_writeset_history is now guarded by LOCK_slave_trans_dep_tracker where ever it is accessed and this protects concurrent update on Writeset_history:: m_writeset_history. Note : This bug fix also protects m_opt_tracking_mode variable explicitly using atomics. RB#24250
1 parent 69e2de8 commit f3c109b

8 files changed

+140
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CREATE TABLE t1 (i INT PRIMARY KEY);
2+
SET GLOBAL TRANSACTION_WRITE_SET_EXTRACTION = 'XXHASH64';
3+
SET GLOBAL BINLOG_TRANSACTION_DEPENDENCY_TRACKING = WRITESET;
4+
BEGIN;
5+
INSERT INTO t1 VALUES(1);
6+
SET DEBUG_SYNC="wait_in_get_dependency SIGNAL dep_tracker WAIT_FOR go_ahead_dml";
7+
commit;
8+
SET DEBUG_SYNC= "now WAIT_FOR dep_tracker";
9+
SET GLOBAL BINLOG_TRANSACTION_DEPENDENCY_TRACKING=WRITESET_SESSION;
10+
include/assert.inc [con2 is waiting for LOCK_slave_trans_dep_tracker.]
11+
SET DEBUG_SYNC="now SIGNAL go_ahead_dml";
12+
SET GLOBAL BINLOG_TRANSACTION_DEPENDENCY_TRACKING= TRACKING_MODE;
13+
SET GLOBAL TRANSACTION_WRITE_SET_EXTRACTION= EXTRACTION_ALG;
14+
SET DEBUG_SYNC="RESET";
15+
DROP TABLE t1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#=== Purpose ===
2+
#
3+
# This test verifies that the transaction dependency writeset
4+
# history map has protection from concurrent access.
5+
#
6+
# === Implementation ===
7+
#
8+
# 1. Do a DML on server such that it writes the GTID in the binlog and then halt
9+
# the thread in get_dependency function using debug sync utility.
10+
# 2. Execute 'set global binlog_transaction_dependency_tracking=WRITESET or
11+
# WRITESET_SESSION'.
12+
# 3. Verify that the thread in step 2 waits until LOCK_slave_trans_dep_tracker
13+
# lock is released by the thread in step 1.
14+
#
15+
# === References ===
16+
#
17+
# Bug#29719364 THE BUGFIX FOR BUG#28511326 SEEMS INCORRECT
18+
#
19+
# This test case is binlog_format agnostic
20+
--source include/have_binlog_format_row.inc
21+
# This test case uses debug_sync
22+
--source include/have_debug.inc
23+
--source include/have_debug_sync.inc
24+
CREATE TABLE t1 (i INT PRIMARY KEY);
25+
26+
# Save the current tracking mode and extraction algorithm.
27+
--let $old_trx_tracker = `SELECT @@GLOBAL.BINLOG_TRANSACTION_DEPENDENCY_TRACKING`
28+
--let $old_trx_write_set_extraction = `SELECT @@GLOBAL.TRANSACTION_WRITE_SET_EXTRACTION`
29+
30+
# Set the global transaction extraction algorithm and tracking mode.
31+
SET GLOBAL TRANSACTION_WRITE_SET_EXTRACTION = 'XXHASH64';
32+
SET GLOBAL BINLOG_TRANSACTION_DEPENDENCY_TRACKING = WRITESET;
33+
34+
--connect(con1,localhost,root,,)
35+
--connect(con2,localhost,root,,)
36+
37+
# Do a DML such that it writes GTID and calls
38+
# get_dependency to update writeset history map.
39+
--connection con1
40+
BEGIN;
41+
INSERT INTO t1 VALUES(1);
42+
SET DEBUG_SYNC="wait_in_get_dependency SIGNAL dep_tracker WAIT_FOR go_ahead_dml";
43+
--send commit
44+
45+
# Set transaction dependency tracking mode to writeset
46+
# so that it clears the writeset history.
47+
--connection con2
48+
--let $thread_id = `SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID =CONNECTION_ID()`
49+
SET DEBUG_SYNC= "now WAIT_FOR dep_tracker";
50+
--send SET GLOBAL BINLOG_TRANSACTION_DEPENDENCY_TRACKING=WRITESET_SESSION
51+
52+
--connection default
53+
# wait until it tries to take LOCK_slave_trans_dep_tracker.
54+
--let $wait_condition= SELECT EVENT_NAME= 'wait/synch/mutex/sql/LOCK_slave_trans_dep_tracker' FROM performance_schema.events_waits_current WHERE THREAD_ID=$thread_id
55+
--source include/wait_condition.inc
56+
57+
# since one thread has taken the LOCK_slave_trans_dep_tracker,
58+
# the other thread has to wait in order to aquire this lock.
59+
--connection default
60+
--let $assert_text= con2 is waiting for LOCK_slave_trans_dep_tracker.
61+
--let $assert_cond= "[SELECT EVENT_NAME FROM performance_schema.events_waits_current WHERE THREAD_ID=$thread_id]" = "wait/synch/mutex/sql/LOCK_slave_trans_dep_tracker"
62+
--source include/assert.inc
63+
64+
#Signal the thread waiting in get_dependency.
65+
SET DEBUG_SYNC="now SIGNAL go_ahead_dml";
66+
67+
--connection con1
68+
--reap
69+
--connection con2
70+
--reap
71+
72+
#Cleanup
73+
--disconnect con1
74+
--disconnect con2
75+
--connection default
76+
--replace_result $old_trx_tracker TRACKING_MODE
77+
--eval SET GLOBAL BINLOG_TRANSACTION_DEPENDENCY_TRACKING= $old_trx_tracker
78+
--replace_result $old_trx_write_set_extraction EXTRACTION_ALG
79+
--eval SET GLOBAL TRANSACTION_WRITE_SET_EXTRACTION= $old_trx_write_set_extraction
80+
SET DEBUG_SYNC="RESET";
81+
DROP TABLE t1;

sql/binlog.cc

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2009, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -5249,7 +5249,10 @@ bool MYSQL_BIN_LOG::open_binlog(const char *log_name,
52495249
At every rotate memorize the last transaction counter state to use it as
52505250
offset at logging the transaction logical timestamps.
52515251
*/
5252+
mysql_mutex_lock(&LOCK_slave_trans_dep_tracker);
52525253
m_dependency_tracker.rotate();
5254+
mysql_mutex_unlock(&LOCK_slave_trans_dep_tracker);
5255+
52535256
#ifdef HAVE_REPLICATION
52545257
close_purge_index_file();
52555258
#endif

sql/mysqld.cc

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
22

33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -724,7 +724,6 @@ char *opt_general_logname, *opt_slow_logname, *opt_bin_logname;
724724

725725
static volatile sig_atomic_t kill_in_progress;
726726

727-
728727
static my_bool opt_myisam_log;
729728
static int cleanup_done;
730729
static ulong opt_specialflag;
@@ -3092,6 +3091,12 @@ int init_common_variables()
30923091
return 1;
30933092
}
30943093

3094+
/*
3095+
We set the atomic field m_opt_tracking_mode to the value of the sysvar
3096+
variable m_opt_tracking_mode_value here, as it now has the user given
3097+
value.
3098+
*/
3099+
set_mysqld_opt_tracking_mode();
30953100
if (global_system_variables.transaction_write_set_extraction == HASH_ALGORITHM_OFF
30963101
&& mysql_bin_log.m_dependency_tracker.m_opt_tracking_mode != DEPENDENCY_TRACKING_COMMIT_ORDER)
30973102
{
@@ -9587,4 +9592,9 @@ bool update_named_pipe_full_access_group(const char *new_group_name)
95879592

95889593
#endif /* _WIN32 && !EMBEDDED_LIBRARY */
95899594

9595+
void set_mysqld_opt_tracking_mode()
9596+
{
9597+
my_atomic_store64(&mysql_bin_log.m_dependency_tracker.m_opt_tracking_mode,
9598+
mysql_bin_log.m_dependency_tracker.m_opt_tracking_mode_value);
9599+
}
95909600

sql/mysqld.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2010, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -401,6 +401,11 @@ static inline int my_thread_set_THR_THD(THD *thd)
401401
return my_set_thread_local(THR_THD, thd);
402402
}
403403

404+
/**
405+
Set m_opt_tracking_mode with a user given value associated with sysvar.
406+
*/
407+
void set_mysqld_opt_tracking_mode();
408+
404409
#ifdef HAVE_PSI_INTERFACE
405410

406411
C_MODE_START

sql/rpl_trx_tracking.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2018, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -25,6 +25,7 @@
2525
#include "mysqld.h"
2626
#include "binlog.h"
2727

28+
#include "debug_sync.h"
2829

2930
Logical_clock::Logical_clock()
3031
: state(SEQ_UNINIT), offset(0)
@@ -217,6 +218,7 @@ Writeset_trx_dependency_tracker::get_dependency(THD *thd,
217218
!write_set_ctx->get_has_related_foreign_keys();
218219
bool exceeds_capacity= false;
219220

221+
mysql_mutex_lock(&LOCK_slave_trans_dep_tracker);
220222
if (can_use_writesets)
221223
{
222224
/*
@@ -231,6 +233,7 @@ Writeset_trx_dependency_tracker::get_dependency(THD *thd,
231233
Compute the greatest sequence_number among all conflicts and add the
232234
transaction's row hashes to the history.
233235
*/
236+
DEBUG_SYNC(thd, "wait_in_get_dependency");
234237
int64 last_parent= m_writeset_history_start;
235238
for (std::set<uint64>::iterator it= writeset->begin();
236239
it != writeset->end(); ++it)
@@ -271,6 +274,7 @@ Writeset_trx_dependency_tracker::get_dependency(THD *thd,
271274
m_writeset_history_start= sequence_number;
272275
m_writeset_history.clear();
273276
}
277+
mysql_mutex_unlock(&LOCK_slave_trans_dep_tracker);
274278
}
275279

276280
void
@@ -316,7 +320,7 @@ Transaction_dependency_tracker::get_dependency(THD *thd,
316320
{
317321
sequence_number= commit_parent= 0;
318322

319-
switch(m_opt_tracking_mode)
323+
switch(my_atomic_load64(&m_opt_tracking_mode))
320324
{
321325
case DEPENDENCY_TRACKING_COMMIT_ORDER:
322326
m_commit_order.get_dependency(thd, sequence_number, commit_parent);

sql/rpl_trx_tracking.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#ifndef RPL_TRX_TRACKING_INCLUDED
2-
/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
/* Copyright (c) 2018, 2020, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -223,7 +223,10 @@ class Transaction_dependency_tracker
223223

224224
public:
225225
/* option opt_binlog_transaction_dependency_tracking */
226-
long m_opt_tracking_mode;
226+
int64 m_opt_tracking_mode;
227+
228+
/* option opt_binlog_transaction_dependency_tracking associated with sysvar */
229+
int64 m_opt_tracking_mode_value;
227230

228231
Writeset_trx_dependency_tracker *get_writeset()
229232
{

sql/sys_vars.cc

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2009, 2020, Oracle and/or its affiliates.
22

33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -3620,13 +3620,20 @@ static bool check_binlog_transaction_dependency_tracking(sys_var *self, THD *thd
36203620

36213621
static bool update_binlog_transaction_dependency_tracking(sys_var* var, THD* thd, enum_var_type v)
36223622
{
3623+
/*
3624+
m_opt_tracking_mode is read and written in an atomic way based
3625+
on the value of m_opt_tracking_mode_value that is associated
3626+
with the sys_var variable.
3627+
*/
3628+
set_mysqld_opt_tracking_mode();
3629+
36233630
/*
36243631
the writeset_history_start needs to be set to 0 whenever there is a
36253632
change in the transaction dependency source so that WS and COMMIT
36263633
transition smoothly.
36273634
*/
3628-
mysql_bin_log.m_dependency_tracker.tracking_mode_changed();
3629-
return false;
3635+
mysql_bin_log.m_dependency_tracker.tracking_mode_changed();
3636+
return false;
36303637
}
36313638

36323639
static PolyLock_mutex
@@ -3639,7 +3646,7 @@ static Sys_var_enum Binlog_transaction_dependency_tracking(
36393646
"assess which transactions can be executed in parallel by the "
36403647
"slave's multi-threaded applier. "
36413648
"Possible values are COMMIT_ORDER, WRITESET and WRITESET_SESSION.",
3642-
GLOBAL_VAR(mysql_bin_log.m_dependency_tracker.m_opt_tracking_mode),
3649+
GLOBAL_VAR(mysql_bin_log.m_dependency_tracker.m_opt_tracking_mode_value),
36433650
CMD_LINE(REQUIRED_ARG), opt_binlog_transaction_dependency_tracking_names,
36443651
DEFAULT(DEPENDENCY_TRACKING_COMMIT_ORDER),
36453652
&PLock_slave_trans_dep_tracker,

0 commit comments

Comments
 (0)