mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
This is patch for the https://jira.mariadb.org/browse/MDEV-9519 issue:
If we have a 2+ node cluster which is replicating from an async master and the binlog_format is set to STATEMENT and multi-row inserts are executed on a table with an auto_increment column such that values are automatically generated by MySQL, then the server node generates wrong auto_increment values, which are different from what was generated on the async master. The causes and fixes: 1. We need to improve processing of changing the auto-increment values after changing the cluster size. 2. If wsrep auto_increment_control switched on during operation of the node, then we should immediately update the auto_increment_increment and auto_increment_offset global variables, without waiting of the next invocation of the wsrep_view_handler_cb() callback. In the current version these variables retain its initial values if wsrep_auto_increment_control is switched on during operation of the node, which leads to inconsistent results on the different nodes in some scenarios. 3. If wsrep auto_increment_control switched off during operation of the node, then we must return the original values of the auto_increment_increment and auto_increment_offset global variables, as the user has set. To make this possible, we need to add a "shadow copies" of these variables (which stores the latest values set by the user).
This commit is contained in:
parent
5960815630
commit
75dfd4acb9
11 changed files with 677 additions and 30 deletions
147
mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result
Normal file
147
mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result
Normal file
|
@ -0,0 +1,147 @@
|
|||
SET GLOBAL wsrep_forced_binlog_format='STATEMENT';
|
||||
SET GLOBAL wsrep_forced_binlog_format='STATEMENT';
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
insert into t1(i) values(null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
3 dummy_text
|
||||
5 dummy_text
|
||||
7 dummy_text
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
3 dummy_text
|
||||
5 dummy_text
|
||||
7 dummy_text
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
drop table t1;
|
||||
SET SESSION binlog_format='STATEMENT';
|
||||
show variables like 'binlog_format';
|
||||
Variable_name Value
|
||||
binlog_format STATEMENT
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
SET SESSION auto_increment_increment = 3;
|
||||
SET SESSION auto_increment_offset = 1;
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
insert into t1(i) values(null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
4 dummy_text
|
||||
7 dummy_text
|
||||
10 dummy_text
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
4 dummy_text
|
||||
7 dummy_text
|
||||
10 dummy_text
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
SET SESSION binlog_format='ROW';
|
||||
show variables like 'binlog_format';
|
||||
Variable_name Value
|
||||
binlog_format ROW
|
||||
show variables like '%auto_increment%';
|
||||
Variable_name Value
|
||||
auto_increment_increment 2
|
||||
auto_increment_offset 1
|
||||
wsrep_auto_increment_control ON
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
show variables like '%auto_increment%';
|
||||
Variable_name Value
|
||||
auto_increment_increment 3
|
||||
auto_increment_offset 1
|
||||
wsrep_auto_increment_control OFF
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
drop table t1;
|
||||
SET GLOBAL wsrep_forced_binlog_format='ROW';
|
||||
SET GLOBAL wsrep_forced_binlog_format='ROW';
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
insert into t1(i) values(null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
3 dummy_text
|
||||
5 dummy_text
|
||||
7 dummy_text
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
3 dummy_text
|
||||
5 dummy_text
|
||||
7 dummy_text
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
drop table t1;
|
||||
SET SESSION binlog_format='ROW';
|
||||
show variables like 'binlog_format';
|
||||
Variable_name Value
|
||||
binlog_format ROW
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
SET SESSION auto_increment_increment = 3;
|
||||
SET SESSION auto_increment_offset = 1;
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
insert into t1(i) values(null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
4 dummy_text
|
||||
7 dummy_text
|
||||
10 dummy_text
|
||||
select * from t1;
|
||||
i c
|
||||
1 dummy_text
|
||||
4 dummy_text
|
||||
7 dummy_text
|
||||
10 dummy_text
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
show variables like 'binlog_format';
|
||||
Variable_name Value
|
||||
binlog_format ROW
|
||||
show variables like '%auto_increment%';
|
||||
Variable_name Value
|
||||
auto_increment_increment 2
|
||||
auto_increment_offset 1
|
||||
wsrep_auto_increment_control ON
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
show variables like '%auto_increment%';
|
||||
Variable_name Value
|
||||
auto_increment_increment 3
|
||||
auto_increment_offset 1
|
||||
wsrep_auto_increment_control OFF
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
drop table t1;
|
223
mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test
Normal file
223
mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test
Normal file
|
@ -0,0 +1,223 @@
|
|||
##
|
||||
## Tests the auto-increment with binlog in STATEMENT mode.
|
||||
##
|
||||
|
||||
--source include/galera_cluster.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
--let $node_1=node_1
|
||||
--let $node_2=node_2
|
||||
--source include/auto_increment_offset_save.inc
|
||||
|
||||
##
|
||||
## Verify the correct operation of the auto-increment when the binlog
|
||||
## format artificially set to the 'STATEMENT' (although this mode is
|
||||
## not recommended in the current version):
|
||||
##
|
||||
|
||||
--connection node_2
|
||||
SET GLOBAL wsrep_forced_binlog_format='STATEMENT';
|
||||
|
||||
--connection node_1
|
||||
SET GLOBAL wsrep_forced_binlog_format='STATEMENT';
|
||||
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
insert into t1(i) values(null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
--connection node_2
|
||||
|
||||
select * from t1;
|
||||
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
|
||||
--connection node_1
|
||||
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
|
||||
drop table t1;
|
||||
|
||||
##
|
||||
## Check the operation when the automatic control over the auto-increment
|
||||
## settings is switched off, that is, when we use the increment step and
|
||||
## the offset specified by the user. In the current session, the binlog
|
||||
## format is set to 'STATEMENT'. It is important that the values of the
|
||||
## auto-increment options does not changed on other node - it allows us
|
||||
## to check the correct transmission of the auto-increment options to
|
||||
## other nodes:
|
||||
##
|
||||
|
||||
--disable_warnings
|
||||
SET SESSION binlog_format='STATEMENT';
|
||||
--enable_warnings
|
||||
|
||||
show variables like 'binlog_format';
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
|
||||
SET SESSION auto_increment_increment = 3;
|
||||
SET SESSION auto_increment_offset = 1;
|
||||
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
insert into t1(i) values(null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
--connection node_2
|
||||
|
||||
select * from t1;
|
||||
|
||||
--connection node_1
|
||||
|
||||
##
|
||||
## Verify the return to automatic calculation of the step
|
||||
## and offset of the auto-increment:
|
||||
##
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
|
||||
SET SESSION binlog_format='ROW';
|
||||
|
||||
show variables like 'binlog_format';
|
||||
show variables like '%auto_increment%';
|
||||
|
||||
##
|
||||
## Verify the recovery of original user-defined values after
|
||||
## stopping the automatic control over auto-increment:
|
||||
##
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
|
||||
show variables like '%auto_increment%';
|
||||
|
||||
##
|
||||
## Restore original options and drop test table:
|
||||
##
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
|
||||
drop table t1;
|
||||
|
||||
##
|
||||
## Verify the correct operation of the auto-increment when the binlog
|
||||
## format set to the 'ROW':
|
||||
##
|
||||
|
||||
--connection node_2
|
||||
SET GLOBAL wsrep_forced_binlog_format='ROW';
|
||||
|
||||
--connection node_1
|
||||
SET GLOBAL wsrep_forced_binlog_format='ROW';
|
||||
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
insert into t1(i) values(null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
--connection node_2
|
||||
|
||||
select * from t1;
|
||||
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
|
||||
--connection node_1
|
||||
|
||||
SET GLOBAL wsrep_forced_binlog_format='none';
|
||||
|
||||
drop table t1;
|
||||
|
||||
##
|
||||
## Check the operation when the automatic control over the auto-increment
|
||||
## settings is switched off, that is, when we use the increment step and
|
||||
## the offset specified by the user. In the current session, the binlog
|
||||
## format is set to 'ROW'. It is important that the values of the
|
||||
## auto-increment options does not changed on other node - it allows us
|
||||
## to check the correct transmission of the auto-increment options to
|
||||
## other nodes:
|
||||
##
|
||||
|
||||
SET SESSION binlog_format='ROW';
|
||||
|
||||
show variables like 'binlog_format';
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
|
||||
SET SESSION auto_increment_increment = 3;
|
||||
SET SESSION auto_increment_offset = 1;
|
||||
|
||||
CREATE TABLE t1 (
|
||||
i int(11) NOT NULL AUTO_INCREMENT,
|
||||
c char(32) DEFAULT 'dummy_text',
|
||||
PRIMARY KEY (i)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
insert into t1(i) values(null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
insert into t1(i) values(null), (null), (null);
|
||||
|
||||
select * from t1;
|
||||
|
||||
--connection node_2
|
||||
|
||||
select * from t1;
|
||||
|
||||
--connection node_1
|
||||
|
||||
##
|
||||
## Verify the return to automatic calculation of the step
|
||||
## and offset of the auto-increment:
|
||||
##
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
|
||||
show variables like 'binlog_format';
|
||||
show variables like '%auto_increment%';
|
||||
|
||||
##
|
||||
## Verify the recovery of original user-defined values after
|
||||
## stopping the automatic control over auto-increment:
|
||||
##
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='OFF';
|
||||
|
||||
show variables like '%auto_increment%';
|
||||
|
||||
##
|
||||
## Restore original options and drop test table:
|
||||
##
|
||||
|
||||
SET GLOBAL wsrep_auto_increment_control='ON';
|
||||
|
||||
drop table t1;
|
||||
|
||||
--source include/auto_increment_offset_restore.inc
|
46
sql/field.h
46
sql/field.h
|
@ -1329,6 +1329,17 @@ public:
|
|||
/* Hash value */
|
||||
virtual void hash(ulong *nr, ulong *nr2);
|
||||
|
||||
/**
|
||||
Get the upper limit of the MySQL integral and floating-point type.
|
||||
|
||||
@return maximum allowed value for the field
|
||||
*/
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
DBUG_ASSERT(false);
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks whether a string field is part of write_set.
|
||||
|
||||
|
@ -1796,6 +1807,11 @@ public:
|
|||
*to= *from;
|
||||
return from + 1;
|
||||
}
|
||||
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
return unsigned_flag ? 0xFFULL : 0x7FULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1837,6 +1853,10 @@ public:
|
|||
virtual const uchar *unpack(uchar* to, const uchar *from,
|
||||
const uchar *from_end, uint param_data)
|
||||
{ return unpack_int16(to, from, from_end); }
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
return unsigned_flag ? 0xFFFFULL : 0x7FFFULL;
|
||||
}
|
||||
};
|
||||
|
||||
class Field_medium :public Field_num {
|
||||
|
@ -1870,6 +1890,10 @@ public:
|
|||
{
|
||||
return Field::pack(to, from, max_length);
|
||||
}
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
return unsigned_flag ? 0xFFFFFFULL : 0x7FFFFFULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1915,6 +1939,10 @@ public:
|
|||
{
|
||||
return unpack_int32(to, from, from_end);
|
||||
}
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
return unsigned_flag ? 0xFFFFFFFFULL : 0x7FFFFFFFULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1964,6 +1992,10 @@ public:
|
|||
{
|
||||
return unpack_int64(to, from, from_end);
|
||||
}
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
return unsigned_flag ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1997,6 +2029,13 @@ public:
|
|||
uint32 pack_length() const { return sizeof(float); }
|
||||
uint row_pack_length() const { return pack_length(); }
|
||||
void sql_type(String &str) const;
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
/*
|
||||
We use the maximum as per IEEE754-2008 standard, 2^24
|
||||
*/
|
||||
return 0x1000000ULL;
|
||||
}
|
||||
private:
|
||||
int do_save_field_metadata(uchar *first_byte);
|
||||
};
|
||||
|
@ -2039,6 +2078,13 @@ public:
|
|||
uint32 pack_length() const { return sizeof(double); }
|
||||
uint row_pack_length() const { return pack_length(); }
|
||||
void sql_type(String &str) const;
|
||||
virtual ulonglong get_max_int_value() const
|
||||
{
|
||||
/*
|
||||
We use the maximum as per IEEE754-2008 standard, 2^53
|
||||
*/
|
||||
return 0x20000000000000ULL;
|
||||
}
|
||||
private:
|
||||
int do_save_field_metadata(uchar *first_byte);
|
||||
};
|
||||
|
|
|
@ -2853,9 +2853,15 @@ compute_next_insert_id(ulonglong nr,struct system_variables *variables)
|
|||
nr= nr + 1; // optimization of the formula below
|
||||
else
|
||||
{
|
||||
/*
|
||||
Calculating the number of complete auto_increment_increment extents:
|
||||
*/
|
||||
nr= (((nr+ variables->auto_increment_increment -
|
||||
variables->auto_increment_offset)) /
|
||||
(ulonglong) variables->auto_increment_increment);
|
||||
/*
|
||||
Adding an offset to the auto_increment_increment extent boundary:
|
||||
*/
|
||||
nr= (nr* (ulonglong) variables->auto_increment_increment +
|
||||
variables->auto_increment_offset);
|
||||
}
|
||||
|
@ -2911,8 +2917,14 @@ prev_insert_id(ulonglong nr, struct system_variables *variables)
|
|||
}
|
||||
if (variables->auto_increment_increment == 1)
|
||||
return nr; // optimization of the formula below
|
||||
/*
|
||||
Calculating the number of complete auto_increment_increment extents:
|
||||
*/
|
||||
nr= (((nr - variables->auto_increment_offset)) /
|
||||
(ulonglong) variables->auto_increment_increment);
|
||||
/*
|
||||
Adding an offset to the auto_increment_increment extent boundary:
|
||||
*/
|
||||
return (nr * (ulonglong) variables->auto_increment_increment +
|
||||
variables->auto_increment_offset);
|
||||
}
|
||||
|
@ -3134,10 +3146,23 @@ int handler::update_auto_increment()
|
|||
if (unlikely(tmp)) // Out of range value in store
|
||||
{
|
||||
/*
|
||||
It's better to return an error here than getting a confusing
|
||||
'duplicate key error' later.
|
||||
first test if the query was aborted due to strict mode constraints
|
||||
*/
|
||||
result= HA_ERR_AUTOINC_ERANGE;
|
||||
if (thd->killed == KILL_BAD_DATA ||
|
||||
nr > table->next_number_field->get_max_int_value())
|
||||
DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
|
||||
|
||||
/*
|
||||
field refused this value (overflow) and truncated it, use the result of
|
||||
the truncation (which is going to be inserted); however we try to
|
||||
decrease it to honour auto_increment_* variables.
|
||||
That will shift the left bound of the reserved interval, we don't
|
||||
bother shifting the right bound (anyway any other value from this
|
||||
interval will cause a duplicate key).
|
||||
*/
|
||||
nr= prev_insert_id(table->next_number_field->val_int(), variables);
|
||||
if (unlikely(table->next_number_field->store((longlong) nr, TRUE)))
|
||||
nr= table->next_number_field->val_int();
|
||||
}
|
||||
if (append)
|
||||
{
|
||||
|
|
|
@ -4193,6 +4193,20 @@ static int init_common_variables()
|
|||
DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
|
||||
server_version, SYSTEM_TYPE,MACHINE_TYPE));
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
/*
|
||||
We need to initialize auxiliary variables, that will be
|
||||
further keep the original values of auto-increment options
|
||||
as they set by the user. These variables used to restore
|
||||
user-defined values of the auto-increment options after
|
||||
setting of the wsrep_auto_increment_control to 'OFF'.
|
||||
*/
|
||||
global_system_variables.saved_auto_increment_increment=
|
||||
global_system_variables.auto_increment_increment;
|
||||
global_system_variables.saved_auto_increment_offset=
|
||||
global_system_variables.auto_increment_offset;
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
#ifdef HAVE_LARGE_PAGES
|
||||
/* Initialize large page size */
|
||||
if (opt_large_pages)
|
||||
|
|
|
@ -552,6 +552,17 @@ typedef struct system_variables
|
|||
ha_rows max_join_size;
|
||||
ha_rows expensive_subquery_limit;
|
||||
ulong auto_increment_increment, auto_increment_offset;
|
||||
#ifdef WITH_WSREP
|
||||
/*
|
||||
Variables with stored values of the auto_increment_increment
|
||||
and auto_increment_offset options that are will be needed when
|
||||
wsrep_auto_increment_control will be set to 'OFF', because the
|
||||
setting it to 'ON' leads to overwriting of the original values
|
||||
(which are set by the user) by calculated values (which are
|
||||
based on the cluster's size):
|
||||
*/
|
||||
ulong saved_auto_increment_increment, saved_auto_increment_offset;
|
||||
#endif /* WITH_WSREP */
|
||||
ulong lock_wait_timeout;
|
||||
ulong join_cache_level;
|
||||
ulong max_allowed_packet;
|
||||
|
|
|
@ -345,13 +345,56 @@ static Sys_var_long Sys_pfs_connect_attrs_size(
|
|||
|
||||
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
|
||||
/*
|
||||
We need to keep the original values set by the user, as they will
|
||||
be lost if wsrep_auto_increment_control set to 'ON':
|
||||
*/
|
||||
static bool update_auto_increment_increment (sys_var *self, THD *thd, enum_var_type type)
|
||||
{
|
||||
if (type == OPT_GLOBAL)
|
||||
global_system_variables.saved_auto_increment_increment=
|
||||
global_system_variables.auto_increment_increment;
|
||||
else
|
||||
thd->variables.saved_auto_increment_increment=
|
||||
thd->variables.auto_increment_increment;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
static Sys_var_ulong Sys_auto_increment_increment(
|
||||
"auto_increment_increment",
|
||||
"Auto-increment columns are incremented by this",
|
||||
SESSION_VAR(auto_increment_increment),
|
||||
CMD_LINE(OPT_ARG),
|
||||
VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1),
|
||||
#ifdef WITH_WSREP
|
||||
NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0),
|
||||
ON_UPDATE(update_auto_increment_increment));
|
||||
#else
|
||||
NO_MUTEX_GUARD, IN_BINLOG);
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
|
||||
/*
|
||||
We need to keep the original values set by the user, as they will
|
||||
be lost if wsrep_auto_increment_control set to 'ON':
|
||||
*/
|
||||
static bool update_auto_increment_offset (sys_var *self, THD *thd, enum_var_type type)
|
||||
{
|
||||
if (type == OPT_GLOBAL)
|
||||
global_system_variables.saved_auto_increment_offset=
|
||||
global_system_variables.auto_increment_offset;
|
||||
else
|
||||
thd->variables.saved_auto_increment_offset=
|
||||
thd->variables.auto_increment_offset;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
static Sys_var_ulong Sys_auto_increment_offset(
|
||||
"auto_increment_offset",
|
||||
|
@ -360,7 +403,12 @@ static Sys_var_ulong Sys_auto_increment_offset(
|
|||
SESSION_VAR(auto_increment_offset),
|
||||
CMD_LINE(OPT_ARG),
|
||||
VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1),
|
||||
#ifdef WITH_WSREP
|
||||
NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0),
|
||||
ON_UPDATE(update_auto_increment_offset));
|
||||
#else
|
||||
NO_MUTEX_GUARD, IN_BINLOG);
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
static Sys_var_mybool Sys_automatic_sp_privileges(
|
||||
"automatic_sp_privileges",
|
||||
|
@ -4847,11 +4895,54 @@ static Sys_var_ulong Sys_wsrep_retry_autocommit(
|
|||
SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1));
|
||||
|
||||
static bool update_wsrep_auto_increment_control (sys_var *self, THD *thd, enum_var_type type)
|
||||
{
|
||||
if (wsrep_auto_increment_control)
|
||||
{
|
||||
/*
|
||||
The variables that control auto increment shall be calculated
|
||||
automaticaly based on the size of the cluster. This usually done
|
||||
within the wsrep_view_handler_cb callback. However, if the user
|
||||
manually sets the value of wsrep_auto_increment_control to 'ON',
|
||||
then we should to re-calculate these variables again (because
|
||||
these values may be required before wsrep_view_handler_cb will
|
||||
be re-invoked, which is rarely invoked if the cluster stays in
|
||||
the stable state):
|
||||
*/
|
||||
global_system_variables.auto_increment_increment=
|
||||
wsrep_cluster_size ? wsrep_cluster_size : 1;
|
||||
global_system_variables.auto_increment_offset=
|
||||
wsrep_local_index >= 0 ? wsrep_local_index + 1 : 1;
|
||||
thd->variables.auto_increment_increment=
|
||||
global_system_variables.auto_increment_increment;
|
||||
thd->variables.auto_increment_offset=
|
||||
global_system_variables.auto_increment_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
We must restore the last values of the variables that
|
||||
are explicitly specified by the user:
|
||||
*/
|
||||
global_system_variables.auto_increment_increment=
|
||||
global_system_variables.saved_auto_increment_increment;
|
||||
global_system_variables.auto_increment_offset=
|
||||
global_system_variables.saved_auto_increment_offset;
|
||||
thd->variables.auto_increment_increment=
|
||||
thd->variables.saved_auto_increment_increment;
|
||||
thd->variables.auto_increment_offset=
|
||||
thd->variables.saved_auto_increment_offset;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Sys_var_mybool Sys_wsrep_auto_increment_control(
|
||||
"wsrep_auto_increment_control", "To automatically control the "
|
||||
"assignment of autoincrement variables",
|
||||
GLOBAL_VAR(wsrep_auto_increment_control),
|
||||
CMD_LINE(OPT_ARG), DEFAULT(TRUE));
|
||||
CMD_LINE(OPT_ARG), DEFAULT(TRUE),
|
||||
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
|
||||
ON_UPDATE(update_wsrep_auto_increment_control));
|
||||
|
||||
static Sys_var_mybool Sys_wsrep_drupal_282555_workaround(
|
||||
"wsrep_drupal_282555_workaround", "Enable a workaround to handle the "
|
||||
|
|
|
@ -161,6 +161,10 @@ extern "C" query_id_t wsrep_thd_query_id(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 "C" void wsrep_thd_auto_increment_variables(THD*,
|
||||
unsigned long long *offset,
|
||||
unsigned long long *increment);
|
||||
|
||||
extern void wsrep_close_client_connections(my_bool wait_to_end);
|
||||
extern int wsrep_wait_committing_connections_close(int wait_time);
|
||||
extern void wsrep_close_applier(THD *thd);
|
||||
|
|
|
@ -676,3 +676,25 @@ bool wsrep_thd_has_explicit_locks(THD *thd)
|
|||
assert(thd);
|
||||
return thd->mdl_context.has_explicit_locks();
|
||||
}
|
||||
|
||||
/*
|
||||
Get auto increment variables for THD. Use global settings for
|
||||
applier threads.
|
||||
*/
|
||||
extern "C"
|
||||
void wsrep_thd_auto_increment_variables(THD* thd,
|
||||
unsigned long long* offset,
|
||||
unsigned long long* increment)
|
||||
{
|
||||
if (thd->wsrep_exec_mode == REPL_RECV &&
|
||||
thd->wsrep_conflict_state != REPLAYING)
|
||||
{
|
||||
*offset= global_system_variables.auto_increment_offset;
|
||||
*increment= global_system_variables.auto_increment_increment;
|
||||
}
|
||||
else
|
||||
{
|
||||
*offset= thd->variables.auto_increment_offset;
|
||||
*increment= thd->variables.auto_increment_increment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8396,14 +8396,29 @@ set_max_autoinc:
|
|||
/* This should filter out the negative
|
||||
values set explicitly by the user. */
|
||||
if (auto_inc <= col_max_value) {
|
||||
ut_a(prebuilt->autoinc_increment > 0);
|
||||
|
||||
ulonglong offset;
|
||||
ulonglong increment;
|
||||
dberr_t err;
|
||||
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
/* Applier threads which are
|
||||
processing ROW events and don't go
|
||||
through server level autoinc
|
||||
processing, therefore m_prebuilt
|
||||
autoinc values don't get
|
||||
properly assigned. Fetch values from
|
||||
server side. */
|
||||
if (wsrep_on(current_thd) &&
|
||||
wsrep_thd_exec_mode(current_thd) == REPL_RECV) {
|
||||
wsrep_thd_auto_increment_variables(current_thd, &offset, &increment);
|
||||
} else {
|
||||
#endif /* WITH_WSREP */
|
||||
ut_a(prebuilt->autoinc_increment > 0);
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
auto_inc = innobase_next_autoinc(
|
||||
auto_inc,
|
||||
|
@ -8918,16 +8933,32 @@ ha_innobase::update_row(
|
|||
|
||||
/* We need the upper limit of the col type to check for
|
||||
whether we update the table autoinc counter or not. */
|
||||
col_max_value = innobase_get_int_col_max_value(
|
||||
table->next_number_field);
|
||||
col_max_value =
|
||||
table->next_number_field->get_max_int_value();
|
||||
|
||||
if (auto_inc <= col_max_value && auto_inc != 0) {
|
||||
|
||||
ulonglong offset;
|
||||
ulonglong increment;
|
||||
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
/* Applier threads which are processing
|
||||
ROW events and don't go through server
|
||||
level autoinc processing, therefore
|
||||
m_prebuilt autoinc values don't get
|
||||
properly assigned. Fetch values from
|
||||
server side. */
|
||||
if (wsrep_on(current_thd) &&
|
||||
wsrep_thd_exec_mode(current_thd) == REPL_RECV) {
|
||||
wsrep_thd_auto_increment_variables(
|
||||
current_thd, &offset, &increment);
|
||||
} else {
|
||||
#endif /* WITH_WSREP */
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
auto_inc = innobase_next_autoinc(
|
||||
auto_inc, 1, increment, offset, col_max_value);
|
||||
|
@ -16038,13 +16069,13 @@ ha_innobase::get_auto_increment(
|
|||
increment,
|
||||
thd_get_thread_id(ha_thd()),
|
||||
current, autoinc);
|
||||
if (!wsrep_on(ha_thd()))
|
||||
{
|
||||
current = autoinc - prebuilt->autoinc_increment;
|
||||
}
|
||||
|
||||
current = innobase_next_autoinc(
|
||||
current, 1, increment, offset, col_max_value);
|
||||
if (!wsrep_on(ha_thd())) {
|
||||
current = autoinc - prebuilt->autoinc_increment;
|
||||
|
||||
current = innobase_next_autoinc(
|
||||
current, 1, increment, offset, col_max_value);
|
||||
}
|
||||
|
||||
dict_table_autoinc_initialize(prebuilt->table, current);
|
||||
|
||||
|
|
|
@ -8988,8 +8988,25 @@ set_max_autoinc:
|
|||
ulonglong increment;
|
||||
dberr_t err;
|
||||
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
/* Applier threads which are
|
||||
processing ROW events and don't go
|
||||
through server level autoinc
|
||||
processing, therefore m_prebuilt
|
||||
autoinc values don't get
|
||||
properly assigned. Fetch values from
|
||||
server side. */
|
||||
if (wsrep_on(current_thd) &&
|
||||
wsrep_thd_exec_mode(current_thd) == REPL_RECV) {
|
||||
wsrep_thd_auto_increment_variables(current_thd, &offset, &increment);
|
||||
} else {
|
||||
#endif /* WITH_WSREP */
|
||||
ut_a(prebuilt->autoinc_increment > 0);
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
auto_inc = innobase_next_autoinc(
|
||||
auto_inc,
|
||||
|
@ -9502,16 +9519,32 @@ ha_innobase::update_row(
|
|||
|
||||
/* We need the upper limit of the col type to check for
|
||||
whether we update the table autoinc counter or not. */
|
||||
col_max_value = innobase_get_int_col_max_value(
|
||||
table->next_number_field);
|
||||
col_max_value =
|
||||
table->next_number_field->get_max_int_value();
|
||||
|
||||
if (auto_inc <= col_max_value && auto_inc != 0) {
|
||||
|
||||
ulonglong offset;
|
||||
ulonglong increment;
|
||||
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
/* Applier threads which are processing
|
||||
ROW events and don't go through server
|
||||
level autoinc processing, therefore
|
||||
m_prebuilt autoinc values don't get
|
||||
properly assigned. Fetch values from
|
||||
server side. */
|
||||
if (wsrep_on(current_thd) &&
|
||||
wsrep_thd_exec_mode(current_thd) == REPL_RECV) {
|
||||
wsrep_thd_auto_increment_variables(
|
||||
current_thd, &offset, &increment);
|
||||
} else {
|
||||
#endif /* WITH_WSREP */
|
||||
offset = prebuilt->autoinc_offset;
|
||||
increment = prebuilt->autoinc_increment;
|
||||
#ifdef WITH_WSREP
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
auto_inc = innobase_next_autoinc(
|
||||
auto_inc, 1, increment, offset, col_max_value);
|
||||
|
@ -16742,13 +16775,13 @@ ha_innobase::get_auto_increment(
|
|||
increment,
|
||||
thd_get_thread_id(ha_thd()),
|
||||
current, autoinc);
|
||||
if (!wsrep_on(ha_thd()))
|
||||
{
|
||||
current = autoinc - prebuilt->autoinc_increment;
|
||||
}
|
||||
|
||||
current = innobase_next_autoinc(
|
||||
current, 1, increment, offset, col_max_value);
|
||||
if (!wsrep_on(ha_thd())) {
|
||||
current = autoinc - prebuilt->autoinc_increment;
|
||||
|
||||
current = innobase_next_autoinc(
|
||||
current, 1, increment, offset, col_max_value);
|
||||
}
|
||||
|
||||
dict_table_autoinc_initialize(prebuilt->table, current);
|
||||
|
||||
|
|
Loading…
Reference in a new issue