Skip to content

Commit 76fb444

Browse files
pedrolgomesPiotr Obrzut
authored andcommitted
BUG#32019842: WRITE_SET VECTOR HAS NO UPPER MEMORY LIMIT
When the option is active, each server transaction will collect write sets for each row, allowing to identify what changes the transaction made, important for replication parallelization in general and Group Replication conflict detection. This patch improves the handling of write set collection for each transaction in 2 ways. First is that write sets are discarded if their size grow above binlog_transaction_dependency_history_size. As a consequence the transaction will no longer be marked as concurrent with previous ones even if they touch different data. The second one is that components like Group Replication can set memory limits for the collection of write sets. Components like GR are dependent on write sets being present, so they will never be discarded, but breaking this memory limit will cause transactions to abort. ReviewBoard: 25520 ReviewBoard: 25592
1 parent 372b037 commit 76fb444

29 files changed

+511
-72
lines changed

include/mysql/service_rpl_transaction_write_set.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
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,
@@ -66,17 +66,32 @@ typedef struct st_trans_write_set Transaction_write_set;
6666

6767
extern struct transaction_write_set_service_st {
6868
Transaction_write_set* (*get_transaction_write_set)(unsigned long m_thread_id);
69+
void (*require_full_write_set)(int requires_ws);
70+
void (*set_write_set_memory_size_limit)(long long size_limit);
71+
void (*update_write_set_memory_size_limit)(long long size_limit);
6972
} *transaction_write_set_service;
7073

7174
#ifdef MYSQL_DYNAMIC_PLUGIN
7275

7376
#define get_transaction_write_set(m_thread_id) \
7477
(transaction_write_set_service->get_transaction_write_set((m_thread_id)))
78+
#define require_full_write_set(requires_ws) \
79+
transaction_write_set_service->require_full_write_set(requires_ws)
80+
#define set_write_set_memory_size_limit(size_limit) \
81+
transaction_write_set_service->set_write_set_memory_size_limit(size_limit)
82+
#define update_write_set_memory_size_limit(size_limit) \
83+
transaction_write_set_service->update_write_set_memory_size_limit(size_limit)
7584

7685
#else
7786

7887
Transaction_write_set* get_transaction_write_set(unsigned long m_thread_id);
7988

89+
void require_full_write_set(int requires_ws);
90+
91+
void set_write_set_memory_size_limit(long long size_limit);
92+
93+
void update_write_set_memory_size_limit(long long size_limit);
94+
8095
#endif
8196

8297
#ifdef __cplusplus

include/mysql/services.h.pp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,14 @@
444444
typedef struct st_trans_write_set Transaction_write_set;
445445
extern struct transaction_write_set_service_st {
446446
Transaction_write_set* (*get_transaction_write_set)(unsigned long m_thread_id);
447+
void (*require_full_write_set)(int requires_ws);
448+
void (*set_write_set_memory_size_limit)(long long size_limit);
449+
void (*update_write_set_memory_size_limit)(long long size_limit);
447450
} *transaction_write_set_service;
448451
Transaction_write_set* get_transaction_write_set(unsigned long m_thread_id);
452+
void require_full_write_set(int requires_ws);
453+
void set_write_set_memory_size_limit(long long size_limit);
454+
void update_write_set_memory_size_limit(long long size_limit);
449455
#include <mysql/service_security_context.h>
450456
typedef char my_svc_bool;
451457
extern struct security_context_service_st {

mysql-test/suite/rpl/r/rpl_binlog_transaction_dependency_history_size.result

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Warnings:
33
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
44
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
55
[connection master]
6+
SET @binlog_transaction_dependency_tracking_save = @@GLOBAL.binlog_transaction_dependency_tracking;
67

78
SET GLOBAL binlog_transaction_dependency_tracking = WRITESET;
89
######## 1. WRITESET ########
@@ -105,4 +106,5 @@ FLUSH LOGS;
105106
include/include/assert_logical_timestamps.inc [0 1;1 2;2 3;3 4;4 5;5 6;6 7;7 8;8 9;9 10;10 11;11 12;9 13;13 14]
106107
# Verify that replication is correct
107108
include/sync_slave_sql_with_master.inc
109+
SET GLOBAL binlog_transaction_dependency_tracking = @binlog_transaction_dependency_tracking_save;
108110
include/rpl_end.inc

mysql-test/suite/rpl/t/rpl_binlog_transaction_dependency_history_size.test

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@
2525
# ==== References ====
2626
# WL#9556: Writeset-based MTS dependency tracking on master
2727
################################################################################
28+
29+
--source include/have_binlog_format_row.inc
2830
--let $rpl_extra_connections_per_server= 7
2931
--source include/master-slave.inc
30-
--source include/have_binlog_format_row.inc
3132

3233
--connection master
34+
35+
SET @binlog_transaction_dependency_tracking_save = @@GLOBAL.binlog_transaction_dependency_tracking;
36+
3337
# Loop between binlog_transaction_dependency_tracking modes
3438
--let $type= 0
3539
while ($type < 3)
@@ -132,4 +136,7 @@ while ($type < 3)
132136
}
133137

134138
--connection master
139+
140+
SET GLOBAL binlog_transaction_dependency_tracking = @binlog_transaction_dependency_tracking_save;
141+
135142
--source include/rpl_end.inc

rapid/plugin/group_replication/include/replication_threads_api.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
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,
@@ -75,6 +75,8 @@ class Replication_thread_api
7575
@param priority The channel priority on event application
7676
@param retry_count The number of retries when connecting
7777
@param preserve_logs If logs should be always preserved
78+
@param ignore_ws_mem_limit Shall ignore write set mem limits
79+
@param allow_drop_write_set Shall not require write set to be preserved
7880
7981
@return the operation status
8082
@retval 0 OK
@@ -93,7 +95,9 @@ class Replication_thread_api
9395
bool ssl_verify_server_cert,
9496
int priority,
9597
int retry_count,
96-
bool preserve_logs);
98+
bool preserve_logs,
99+
bool ignore_ws_mem_limit,
100+
bool allow_drop_write_set);
97101

98102
/**
99103
Start the Applier/Receiver threads according to the given options.

rapid/plugin/group_replication/src/handlers/applier_handler.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
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,
@@ -77,7 +77,7 @@ Applier_handler::initialize_repositories(bool reset_logs,
7777
NULL,
7878
false,
7979
GROUP_REPLICATION_APPLIER_THREAD_PRIORITY,
80-
0, true);
80+
0, true, true, true);
8181

8282
if (error)
8383
{

rapid/plugin/group_replication/src/plugin.cc

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
2222

2323
#include <sstream>
24+
#include <mysql/service_rpl_transaction_write_set.h>
2425

2526
#include "observer_server_actions.h"
2627
#include "observer_server_state.h"
@@ -207,7 +208,8 @@ int flow_control_applier_threshold_var= DEFAULT_FLOW_CONTROL_THRESHOLD;
207208
#define DEFAULT_TRANSACTION_SIZE_LIMIT 0
208209
#define MAX_TRANSACTION_SIZE_LIMIT 2147483647
209210
#define MIN_TRANSACTION_SIZE_LIMIT 0
210-
ulong transaction_size_limit_var= DEFAULT_TRANSACTION_SIZE_LIMIT;
211+
ulong transaction_size_limit_base_var= DEFAULT_TRANSACTION_SIZE_LIMIT;
212+
int64 transaction_size_limit_var;
211213

212214
/* Member Weight limits */
213215
#define DEFAULT_MEMBER_WEIGHT 50
@@ -459,6 +461,7 @@ int initialize_plugin_and_join(enum_plugin_con_isolation sql_api_isolation,
459461
//Avoid unnecessary operations
460462
bool enabled_super_read_only= false;
461463
bool read_only_mode= false, super_read_only_mode=false;
464+
bool write_set_limits_set = false;
462465

463466
st_server_ssl_variables server_ssl_variables=
464467
{false,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
@@ -512,6 +515,10 @@ int initialize_plugin_and_join(enum_plugin_con_isolation sql_api_isolation,
512515
if (delayed_init_thd)
513516
delayed_init_thd->signal_read_mode_ready();
514517

518+
require_full_write_set(1);
519+
set_write_set_memory_size_limit(get_transaction_size_limit());
520+
write_set_limits_set = true;
521+
515522
get_server_parameters(&hostname, &port, &uuid, &server_version,
516523
&server_ssl_variables);
517524

@@ -623,6 +630,12 @@ int initialize_plugin_and_join(enum_plugin_con_isolation sql_api_isolation,
623630
leave_group();
624631
terminate_plugin_modules();
625632

633+
if (write_set_limits_set) {
634+
// Remove server constraints on write set collection
635+
update_write_set_memory_size_limit(0);
636+
require_full_write_set(0);
637+
}
638+
626639
if (!server_shutdown_status && server_engine_initialized()
627640
&& enabled_super_read_only)
628641
{
@@ -913,6 +926,10 @@ int plugin_group_replication_stop()
913926
plugin_is_waiting_to_set_server_read_mode= false;
914927
}
915928

929+
// Remove server constraints on write set collection
930+
update_write_set_memory_size_limit(0);
931+
require_full_write_set(0);
932+
916933
DBUG_RETURN(error);
917934
}
918935

@@ -1075,6 +1092,9 @@ int plugin_group_replication_init(MYSQL_PLUGIN plugin_info)
10751092
//Initialize the compatibility module before starting
10761093
init_compatibility_manager();
10771094

1095+
// Set the atomic var to the value of the base plugin variable
1096+
transaction_size_limit_var = transaction_size_limit_base_var;
1097+
10781098
plugin_is_auto_starting= start_group_replication_at_boot_var;
10791099
if (start_group_replication_at_boot_var && plugin_group_replication_start())
10801100
{
@@ -1573,7 +1593,9 @@ bool get_allow_local_disjoint_gtids_join()
15731593
ulong get_transaction_size_limit()
15741594
{
15751595
DBUG_ENTER("get_transaction_size_limit");
1576-
DBUG_RETURN(transaction_size_limit_var);
1596+
DBUG_ASSERT(my_atomic_load64(&transaction_size_limit_var)>=0);
1597+
ulong limit = static_cast<ulong>(my_atomic_load64(&transaction_size_limit_var));
1598+
DBUG_RETURN(limit);
15771599
}
15781600

15791601
bool is_plugin_waiting_to_set_server_read_mode()
@@ -2364,6 +2386,20 @@ update_member_weight(MYSQL_THD, SYS_VAR*,
23642386
DBUG_VOID_RETURN;
23652387
}
23662388

2389+
static void update_transaction_size_limit(MYSQL_THD, SYS_VAR *, void *var_ptr,
2390+
const void *save) {
2391+
2392+
ulong in_val = *static_cast<const ulong *>(save);
2393+
*static_cast<ulong *>(var_ptr) = in_val;
2394+
my_atomic_store64(&transaction_size_limit_var, in_val);
2395+
2396+
transaction_size_limit_var = in_val;
2397+
2398+
if (plugin_is_group_replication_running()) {
2399+
update_write_set_memory_size_limit(transaction_size_limit_var);
2400+
}
2401+
}
2402+
23672403
//Base plugin variables
23682404

23692405
static MYSQL_SYSVAR_STR(
@@ -2791,11 +2827,11 @@ static MYSQL_SYSVAR_INT(
27912827

27922828
static MYSQL_SYSVAR_ULONG(
27932829
transaction_size_limit, /* name */
2794-
transaction_size_limit_var, /* var */
2830+
transaction_size_limit_base_var, /* var */
27952831
PLUGIN_VAR_OPCMDARG, /* optional var */
27962832
"Specifies the limit of transaction size that can be transferred over network.",
27972833
NULL, /* check func. */
2798-
NULL, /* update func. */
2834+
update_transaction_size_limit, /* update func. */
27992835
DEFAULT_TRANSACTION_SIZE_LIMIT, /* default */
28002836
MIN_TRANSACTION_SIZE_LIMIT, /* min */
28012837
MAX_TRANSACTION_SIZE_LIMIT, /* max */

rapid/plugin/group_replication/src/recovery_state_transfer.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
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,
@@ -529,7 +529,7 @@ int Recovery_state_transfer::initialize_donor_connection()
529529
recovery_ssl_crlpath,
530530
recovery_ssl_verify_server_cert,
531531
DEFAULT_THREAD_PRIORITY,
532-
1, false);
532+
1, false, true, true);
533533

534534
if (!error)
535535
{
@@ -721,7 +721,7 @@ int Recovery_state_transfer::purge_recovery_slave_threads_repos()
721721
NULL,
722722
NULL,
723723
DEFAULT_THREAD_PRIORITY,
724-
1, false);
724+
1, false, true, true);
725725

726726
DBUG_RETURN(error);
727727
}

rapid/plugin/group_replication/src/replication_threads_api.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
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,
@@ -40,7 +40,9 @@ Replication_thread_api::initialize_channel(char* hostname,
4040
bool ssl_verify_server_cert,
4141
int priority,
4242
int retry_count,
43-
bool preserve_logs)
43+
bool preserve_logs,
44+
bool ignore_ws_mem_limit,
45+
bool allow_drop_write_set)
4446
{
4547
DBUG_ENTER("Replication_thread_api::initialize");
4648
int error= 0;
@@ -67,6 +69,9 @@ Replication_thread_api::initialize_channel(char* hostname,
6769

6870
info.preserve_relay_logs= preserve_logs;
6971

72+
info.m_ignore_write_set_memory_limit = ignore_ws_mem_limit;
73+
info.m_allow_drop_write_set = allow_drop_write_set;
74+
7075
if( use_ssl || ssl_ca != NULL || ssl_capath != NULL || ssl_cert != NULL ||
7176
ssl_cipher!= NULL || ssl_key != NULL || ssl_crl != NULL ||
7277
ssl_crlpath != NULL || ssl_verify_server_cert)

rapid/plugin/group_replication/tests/mtr/r/gr_transaction_limit.result

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ Note #### Storing MySQL user name or password information in the master info rep
99
[connection server2]
1010
set session sql_log_bin=0;
1111
call mtr.add_suppression("Run function 'before_commit' in plugin 'group_replication' failed");
12-
call mtr.add_suppression("Error on session .*. Transaction of size .* exceeds specified limit 1. To increase the limit please adjust group_replication_transaction_size_limit option.");
12+
call mtr.add_suppression("Error on session .*. Transaction of size .* exceeds specified limit 16. To increase the limit please adjust group_replication_transaction_size_limit option.");
13+
call mtr.add_suppression("Error on session .*. Transaction of size .* exceeds specified limit 1600. To increase the limit please adjust group_replication_transaction_size_limit option.");
1314
set session sql_log_bin=1;
1415

1516
[connection server3]
1617
set session sql_log_bin=0;
1718
call mtr.add_suppression("Run function 'before_commit' in plugin 'group_replication' failed");
18-
call mtr.add_suppression("Error on session .*. Transaction of size .* exceeds specified limit 1024. To increase the limit please adjust group_replication_transaction_size_limit option.");
19+
call mtr.add_suppression("Error on session .*. Transaction of size .* exceeds specified limit 1600. To increase the limit please adjust group_replication_transaction_size_limit option.");
1920
set session sql_log_bin=1;
2021

2122
include/rpl_gr_wait_for_number_of_members.inc
@@ -169,9 +170,12 @@ include/assert.inc ['Checking the number of records in table t1']
169170
## 3.6 Delete all data from table t1 on server 2,
170171
## transaction should be rolledback
171172
[connection server2]
173+
SET @group_replication_transaction_size_limit_save= @@GLOBAL.group_replication_transaction_size_limit;
174+
SET GLOBAL group_replication_transaction_size_limit= 1600;
172175
DELETE FROM t1;
173176
ERROR HY000: Error on observer while running replication hook 'before_commit'.
174177
include/rpl_sync.inc
178+
SET GLOBAL group_replication_transaction_size_limit= @group_replication_transaction_size_limit_save;
175179

176180
[connection server1]
177181
include/assert.inc ['Checking the number of records in table t1']
@@ -185,9 +189,12 @@ include/assert.inc ['Checking the number of records in table t1']
185189
## 3.7 Delete all data from table t1 on server 3,
186190
## transaction should be rolledback
187191
[connection server3]
192+
SET @group_replication_transaction_size_limit_save= @@GLOBAL.group_replication_transaction_size_limit;
193+
SET GLOBAL group_replication_transaction_size_limit= 1600;
188194
DELETE FROM t1;
189195
ERROR HY000: Error on observer while running replication hook 'before_commit'.
190196
include/rpl_sync.inc
197+
SET GLOBAL group_replication_transaction_size_limit= @group_replication_transaction_size_limit_save;
191198

192199
[connection server1]
193200
include/assert.inc ['Checking the number of records in table t1']

0 commit comments

Comments
 (0)