Merge branch '10.2' of github.com:MariaDB/server into 10.2

This commit is contained in:
Sergei Petrunia 2016-10-27 17:05:00 +03:00
commit 951ca5dd04
121 changed files with 7095 additions and 2514 deletions

View file

@ -28,6 +28,7 @@ addons:
- libpam0g-dev
- libreadline-gplv2-dev
- libssl-dev
- libnuma-dev
- lsb-release
- perl
- po-debconf

View file

@ -162,6 +162,7 @@ INCLUDE(install_macros)
INCLUDE(systemd)
INCLUDE(mysql_add_executable)
INCLUDE(crc32-vpmsum)
INCLUDE(numa)
# Handle options
OPTION(DISABLE_SHARED
@ -356,6 +357,7 @@ IF(WITH_UNIT_TESTS)
ADD_SUBDIRECTORY(unittest/examples)
ADD_SUBDIRECTORY(unittest/mysys)
ADD_SUBDIRECTORY(unittest/my_decimal)
ADD_SUBDIRECTORY(unittest/json_lib)
IF(NOT WITHOUT_SERVER)
ADD_SUBDIRECTORY(unittest/sql)
ENDIF()

38
cmake/numa.cmake Normal file
View file

@ -0,0 +1,38 @@
MACRO (MYSQL_CHECK_NUMA)
CHECK_INCLUDE_FILES(numa.h HAVE_NUMA_H)
CHECK_INCLUDE_FILES(numaif.h HAVE_NUMAIF_H)
IF(HAVE_NUMA_H AND HAVE_NUMAIF_H)
OPTION(WITH_NUMA "Explicitly set NUMA memory allocation policy" ON)
ELSE()
OPTION(WITH_NUMA "Explicitly set NUMA memory allocation policy" OFF)
ENDIF()
IF(WITH_NUMA AND HAVE_NUMA_H AND HAVE_NUMAIF_H)
SET(SAVE_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} numa)
CHECK_C_SOURCE_COMPILES(
"
#include <numa.h>
#include <numaif.h>
int main()
{
struct bitmask *all_nodes= numa_all_nodes_ptr;
set_mempolicy(MPOL_DEFAULT, 0, 0);
return all_nodes != NULL;
}"
HAVE_LIBNUMA)
SET(CMAKE_REQUIRED_LIBRARIES ${SAVE_CMAKE_REQUIRED_LIBRARIES})
ELSE()
SET(HAVE_LIBNUMA 0)
ENDIF()
IF(WITH_NUMA AND NOT HAVE_LIBNUMA)
# Forget it in cache, abort the build.
UNSET(WITH_NUMA CACHE)
MESSAGE(FATAL_ERROR "Could not find numa headers/libraries")
ENDIF()
ENDMACRO()

View file

@ -106,6 +106,7 @@
#cmakedefine HAVE_LIBWRAP 1
#cmakedefine HAVE_SYSTEMD 1
#cmakedefine HAVE_CRC32_VPMSUM 1
#cmakedefine HAVE_LIBNUMA 1
/* Does "struct timespec" have a "sec" and "nsec" field? */
#cmakedefine HAVE_TIMESPEC_TS_SEC 1

1
debian/control vendored
View file

@ -19,6 +19,7 @@ Build-Depends: bison,
libreadline-gplv2-dev,
libssl-dev,
libxml2-dev,
libnuma-dev,
lsb-release,
perl (>= 5.6.0),
po-debconf,

View file

@ -61,6 +61,7 @@ SET(HEADERS
my_compiler.h
handler_state.h
handler_ername.h
json_lib.h
)
INSTALL(FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDEDIR} COMPONENT Development)

356
include/json_lib.h Normal file
View file

@ -0,0 +1,356 @@
#ifndef JSON_LIB_INCLUDED
#define JSON_LIB_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#define JSON_DEPTH_LIMIT 32
/*
When error happens, the c_next of the JSON engine contains the
character that caused the error, and the c_str is the position
in string where the error occurs.
*/
enum json_errors {
JE_BAD_CHR= -1, /* Invalid character, charset handler cannot read it. */
JE_NOT_JSON_CHR= -2, /* Character met not used in JSON. */
/* ASCII 00-08 for instance. */
JE_EOS= -3, /* Unexpected end of string. */
JE_SYN= -4, /* The next character breaks the JSON syntax. */
JE_STRING_CONST= -5, /* Character disallowed in string constant. */
JE_ESCAPING= -6, /* Error in the escaping. */
JE_DEPTH= -7, /* The limit on the JSON depth was overrun. */
};
typedef struct st_json_string_t
{
const uchar *c_str; /* Current position in JSON string */
const uchar *str_end; /* The end on the string. */
my_wc_t c_next; /* UNICODE of the last read character */
int error; /* error code. */
CHARSET_INFO *cs; /* Character set of the JSON string. */
my_charset_conv_mb_wc wc; /* UNICODE conversion function. */
/* It's taken out of the cs just to speed calls. */
} json_string_t;
void json_string_set_cs(json_string_t *s, CHARSET_INFO *i_cs);
void json_string_set_str(json_string_t *s,
const uchar *str, const uchar *end);
#define json_next_char(j) \
(j)->wc((j)->cs, &(j)->c_next, (j)->c_str, (j)->str_end)
#define json_eos(j) ((j)->c_str >= (j)->str_end)
/*
read_string_const_chr() reads the next character of the string constant
and saves it to the js->c_next.
It takes into account possible escapings, so if for instance
the string is '\b', the read_string_const_chr() sets 8.
*/
int json_read_string_const_chr(json_string_t *js);
/*
Various JSON-related operations expect JSON path as a parameter.
The path is a string like this "$.keyA[2].*"
The path itself is a number of steps specifying either a key or a position
in an array. Some of them can be wildcards.
So the representation of the JSON path is the json_path_t class
containing an array of json_path_step_t objects.
*/
enum json_path_step_types
{
JSON_PATH_KEY=0,
JSON_PATH_ARRAY=1
};
typedef struct st_json_path_step_t
{
enum json_path_step_types type; /* The type of the step - KEY or ARRAY */
int wild; /* If the step is a wildcard */
const uchar *key; /* Pointer to the beginning of the key. */
const uchar *key_end; /* Pointer to the end of the key. */
uint n_item; /* Item number in an array. No meaning for the key step. */
} json_path_step_t;
typedef struct st_json_path_t
{
json_string_t s; /* The string to be parsed. */
json_path_step_t steps[JSON_DEPTH_LIMIT]; /* Steps of the path. */
json_path_step_t *last_step; /* Points to the last step. */
int mode_strict; /* TRUE if the path specified as 'strict' */
} json_path_t;
int json_path_setup(json_path_t *p,
CHARSET_INFO *i_cs, const uchar *str, const uchar *end);
/*
The set of functions and structures below provides interface
to the JSON text parser.
Running the parser normally goes like this:
json_engine_t j_eng; // structure keeps parser's data
json_scan_start(j_eng) // begin the parsing
do
{
// The parser has read next piece of JSON
// and set fields of j_eng structure accordingly.
// So let's see what we have:
switch (j_eng.state)
{
case JST_KEY:
// Handle key name. See the json_read_keyname_chr()
// Probably compare it with the keyname we're looking for
case JST_VALUE:
// Handle value. It is either value of the key or an array item.
// see the json_read_value()
case JST_OBJ_START:
// parser found an object (the '{' in JSON)
case JST_OBJ_END:
// parser found the end of the object (the '}' in JSON)
case JST_ARRAY_START:
// parser found an array (the '[' in JSON)
case JST_ARRAY_END:
// parser found the end of the array (the ']' in JSON)
};
} while (json_scan_next() == 0); // parse next structure
if (j_eng.s.error) // we need to check why the loop ended.
// Did we get to the end of JSON, or came upon error.
{
signal_error_in_JSON()
}
Parts of JSON can be quickly skipped. If we are not interested
in a particular key, we can just skip it with json_skip_key() call.
Similarly json_skip_level() goes right to the end of an object
or an array.
*/
/* These are JSON parser states that user can expect and handle. */
enum json_states {
JST_VALUE, /* value found */
JST_KEY, /* key found */
JST_OBJ_START, /* object */
JST_OBJ_END, /* object ended */
JST_ARRAY_START, /* array */
JST_ARRAY_END, /* array ended */
NR_JSON_USER_STATES
};
enum json_value_types
{
JSON_VALUE_OBJECT=0,
JSON_VALUE_ARRAY=1,
JSON_VALUE_STRING,
JSON_VALUE_NUMBER,
JSON_VALUE_TRUE,
JSON_VALUE_FALSE,
JSON_VALUE_NULL
};
typedef struct st_json_engine_t
{
json_string_t s; /* String to parse. */
int sav_c_len; /* Length of the current character.
Can be more than 1 for multibyte charsets */
int state; /* The state of the parser. One of 'enum json_states'.
It tells us what construction of JSON we've just read. */
/* These values are only set after the json_read_value() call. */
enum json_value_types value_type; /* type of the value.*/
const uchar *value; /* Points to the value. */
const uchar *value_begin;/* Points to where the value starts in the JSON. */
/*
In most cases the 'value' and 'value_begin' are equal.
They only differ if the value is a string constants. Then 'value_begin'
points to the starting quotation mark, while the 'value' - to
the first character of the string.
*/
const uchar *value_end; /* Points to the next character after the value. */
int value_len; /* The length of the value. Does not count quotations for */
/* string constants. */
int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */
int *stack_p; /* The 'stack' pointer. */
} json_engine_t;
int json_scan_start(json_engine_t *je,
CHARSET_INFO *i_cs, const uchar *str, const uchar *end);
int json_scan_next(json_engine_t *j);
/*
json_read_keyname_chr() function assists parsing the name of an JSON key.
It only can be called when the json_engine is in JST_KEY.
The json_read_keyname_chr() reads one character of the name of the key,
and puts it in j_eng.s.next_c.
Typical usage is like this:
if (j_eng.state == JST_KEY)
{
while (json_read_keyname_chr(&j) == 0)
{
//handle next character i.e. match it against the pattern
}
}
*/
int json_read_keyname_chr(json_engine_t *j);
/*
json_read_value() function parses the JSON value syntax,
so that we can handle the value of a key or an array item.
It only returns meaningful result when the engine is in
the JST_VALUE state.
Typical usage is like this:
if (j_eng.state == JST_VALUE)
{
json_read_value(&j_eng);
switch(j_eng.value_type)
{
case JSON_VALUE_STRING:
// get the string
str= j_eng.value;
str_length= j_eng.value_len;
case JSON_VALUE_NUMBER:
// get the number
... etc
}
*/
int json_read_value(json_engine_t *j);
/*
json_skip_key() makes parser skip the content of the current
JSON key quickly.
It can be called only when the json_engine state is JST_KEY.
Typical usage is:
if (j_eng.state == JST_KEY)
{
if (key_does_not_match(j_eng))
json_skip_key(j_eng);
}
*/
int json_skip_key(json_engine_t *j);
/*
json_skip_level() makes parser quickly skip the JSON content
to the end of the current object or array.
It is used when we're not interested in the rest of an array
or the rest of the keys of an object.
*/
int json_skip_level(json_engine_t *j);
#define json_skip_array_item json_skip_key
/*
Checks if the current value is of scalar type -
not an OBJECT nor ARRAY.
*/
#define json_value_scalar(je) ((je)->value_type > JSON_VALUE_ARRAY)
/*
Look for the JSON PATH in the json string.
Function can be called several times with same JSON/PATH to
find multiple matches.
On the first call, the json_engine_t parameter should be
initialized with the JSON string, and the json_path_t with the JSON path
appropriately. The 'p_cur_step' should point at the first
step of the path.
The 'array_counters' is the array of JSON_DEPTH_LIMIT size.
It stores the array counters of the parsed JSON.
If function returns 0, it means it found the match. The position of
the match is je->s.c_str. Then we can call the json_find_path()
with same engine/path/p_cur_step to get the next match.
Non-zero return means no matches found.
Check je->s.error to see if there was an error in JSON.
*/
int json_find_path(json_engine_t *je,
json_path_t *p, json_path_step_t **p_cur_step,
uint *array_counters);
typedef struct st_json_find_paths_t
{
uint n_paths;
json_path_t *paths;
uint cur_depth;
uint *path_depths;
uint array_counters[JSON_DEPTH_LIMIT];
} json_find_paths_t;
int json_find_paths_first(json_engine_t *je, json_find_paths_t *state,
uint n_paths, json_path_t *paths, uint *path_depths);
int json_find_paths_next(json_engine_t *je, json_find_paths_t *state);
/*
Converst JSON string constant into ordinary string constant
which can involve unpacking json escapes and changing character set.
Returns negative integer in the case of an error,
the length of the result otherwise.
*/
int json_unescape(CHARSET_INFO *json_cs,
const uchar *json_str, const uchar *json_end,
CHARSET_INFO *res_cs,
uchar *res, uchar *res_end);
/*
Converst ordinary string constant into JSON string constant.
which can involve appropriate escaping and changing character set.
Returns negative integer in the case of an error,
the length of the result otherwise.
*/
int json_escape(CHARSET_INFO *str_cs, const uchar *str, const uchar *str_end,
CHARSET_INFO *json_cs, uchar *json, uchar *json_end);
/*
Appends the ASCII string to the json with the charset conversion.
*/
int json_append_ascii(CHARSET_INFO *json_cs,
uchar *json, uchar *json_end,
const uchar *ascii, const uchar *ascii_end);
#ifdef __cplusplus
}
#endif
#endif /* JSON_LIB_INCLUDED */

View file

@ -282,8 +282,16 @@ make_atomic_store(ptr)
#if SIZEOF_LONG == 4
#define my_atomic_addlong(A,B) my_atomic_add32((int32*) (A), (B))
#define my_atomic_loadlong(A) my_atomic_load32((int32*) (A))
#define my_atomic_storelong(A,B) my_atomic_store32((int32*) (A), (B))
#define my_atomic_faslong(A,B) my_atomic_fas32((int32*) (A), (B))
#define my_atomic_caslong(A,B,C) my_atomic_cas32((int32*) (A), (int32*) (B), (C))
#else
#define my_atomic_addlong(A,B) my_atomic_add64((int64*) (A), (B))
#define my_atomic_loadlong(A) my_atomic_load64((int64*) (A))
#define my_atomic_storelong(A,B) my_atomic_store64((int64*) (A), (B))
#define my_atomic_faslong(A,B) my_atomic_fas64((int64*) (A), (B))
#define my_atomic_caslong(A,B,C) my_atomic_cas64((int64*) (A), (int64*) (B), (C))
#endif
#ifdef _atomic_h_cleanup_

View file

@ -109,6 +109,8 @@ my_bool net_write_command(NET *net,unsigned char command,
const unsigned char *packet, size_t len);
int net_real_write(NET *net,const unsigned char *packet, size_t len);
unsigned long my_net_read_packet(NET *net, my_bool read_from_server);
ulong my_net_read_packet_reallen(NET *net, my_bool read_from_server,
ulong* reallen);
struct sockaddr;
int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen,
unsigned int timeout);

View file

@ -585,6 +585,8 @@ my_bool net_write_command(NET *net,unsigned char command,
const unsigned char *packet, size_t len);
int net_real_write(NET *net,const unsigned char *packet, size_t len);
unsigned long my_net_read_packet(NET *net, my_bool read_from_server);
ulong my_net_read_packet_reallen(NET *net, my_bool read_from_server,
ulong* reallen);
#define my_net_read(A) my_net_read_packet((A), 0)
#ifdef MY_GLOBAL_INCLUDED

View file

@ -104,6 +104,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
const unsigned char *arg, ulong arg_length,
my_bool skip_check, MYSQL_STMT *stmt);
unsigned long cli_safe_read(MYSQL *mysql);
unsigned long cli_safe_read_reallen(MYSQL *mysql, ulong* reallen);
void net_clear_error(NET *net);
void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net);
void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate,

View file

@ -50,7 +50,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc
../sql/item_geofunc.cc ../sql/item_row.cc ../sql/item_strfunc.cc
../sql/item_subselect.cc ../sql/item_sum.cc ../sql/item_timefunc.cc
../sql/item_xmlfunc.cc ../sql/key.cc ../sql/lock.cc ../sql/log.cc
../sql/item_xmlfunc.cc ../sql/item_jsonfunc.cc
../sql/key.cc ../sql/lock.cc ../sql/log.cc
../sql/log_event.cc ../sql/mf_iocache.cc ../sql/my_decimal.cc
../sql/net_serv.cc ../sql/opt_range.cc ../sql/opt_sum.cc
../sql/parse_file.cc ../sql/procedure.cc ../sql/protocol.cc

View file

@ -0,0 +1,55 @@
# ==== Purpose ====
#
# Auxiliary file used by rpl_delayed_slave.test. This assumes that an
# 'INSERT INTO t1...' query has been executed on the master. It does
# this:
#
# - After half the delay, check the status. It should be delaying and
# the query should not have executed.
#
# - After one and a half delay, check the status. It should not be
# delaying and the query should be executed.
#
#
# ==== Usage ====
#
# --let $query_number= 4
# --source extra/rpl_tests/delayed_slave_wait_on_query.inc
#
# Parameters:
# $query_number
# The value of the 'b' column in t1 for the row inserted by the query
# we are waiting for.
connection master;
--echo [on slave]
--let $slave_timeout= $time1
--source include/sync_slave_io_with_master.inc
--echo # sleep 1*T
--sleep $time1
--let $assert_text= Query $query_number should not be executed
--let $assert_cond= MAX(b) < $query_number FROM t1
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Waiting until MASTER_DELAY...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%"
--source include/rpl_assert.inc
--echo # sleep 1*T
--sleep $time1
--echo # sync with master (with timeout 1*T)
--source include/sync_with_master.inc
--let $assert_text= Query $query_number should be executed
--let $assert_cond= MAX(b) = $query_number FROM t1
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Has read all relay log...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%"
--source include/rpl_assert.inc
--source include/check_slave_is_running.inc

View file

@ -67,6 +67,9 @@ if ($tmp)
--echo Replicate_Do_Domain_Ids
--echo Replicate_Ignore_Domain_Ids
--echo Parallel_Mode conservative
--echo SQL_Delay 0
--echo SQL_Remaining_Delay NULL
--echo Slave_SQL_Running_State
}
if (!$tmp) {
# Note: after WL#5177, fields 13-18 shall not be filtered-out.

View file

@ -0,0 +1,9 @@
let $numa_support = `SELECT COUNT(VARIABLE_VALUE) = 1 FROM
INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_numa_interleave'`;
if ( $numa_support == 0 )
{
--skip Test requires: Binary must be built with NUMA support.
}

View file

@ -101,16 +101,16 @@ if ($relocate_index_file)
--eval LOAD DATA INFILE '$relocate_fix_relay_log_info' INTO TABLE tmp (entry)
--let $count= `SELECT count(*) FROM tmp`
--let $_curr_entry= `SELECT entry FROM tmp WHERE id=1`
--let $_curr_entry= `SELECT entry FROM tmp WHERE id=2`
--let $_curr_entry_basename= `SELECT RIGHT(RTRIM("$_curr_entry"), LOCATE("$_path_separator",REVERSE(RTRIM("$_curr_entry"))) -1)`
if ($relocate_is_windows)
{
--eval UPDATE tmp SET entry='$_to\$_curr_entry_basename' WHERE id=1
--eval UPDATE tmp SET entry='$_to\$_curr_entry_basename' WHERE id=2
}
if (!$relocate_is_windows)
{
--eval UPDATE tmp SET entry='$_to/$_curr_entry_basename' WHERE id=1
--eval UPDATE tmp SET entry='$_to/$_curr_entry_basename' WHERE id=2
}
--remove_file $relocate_fix_relay_log_info

View file

@ -0,0 +1,118 @@
# ==== Purpose ====
#
# Check if a condition holds, fail with debug info if not.
#
# The condition is parsed before executed. The following constructs
# are supported:
#
# [SQL STATEMENT, COLUMN, ROW]
# The square bracket is replaced by the result from SQL STATEMENT,
# in the given COLUMN and ROW.
#
# <1>
# This is a shorthand for the result of the first executed square
# bracket. <2> is a shorthand for the second executed square
# bracket, and so on.
#
# ==== Usage ====
#
# --let $assert_text= Relay_Log_Pos must be smaller than pos.
# --let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] >= $min_pos AND <1> <= $max_pos
# [--let $assert_quiet= 1]
# [--let $rpl_debug= 1]
# --source include/rpl_assert.inc
#
# Parameters:
#
# $assert_text
# Text that describes what is being checked. By default, this text
# is written to the query log.
#
# $assert_cond
# Condition to check. See above for details about the format. The
# condition will be executed as `SELECT $assert_cond`. Note: this
# condition is parsed using SQL statements, quoted inside single
# quotes, so it must not contain single quotes itself (use double
# quotes for strings).
#
# $assert_quiet
# Do not print $assert_text to the query log.
#
# $rpl_debug
# Print extra debug info.
if ($rpl_debug)
{
--echo # debug: assert_text='$assert_text' assert_cond='$assert_cond'
}
# Sanity-check input
if (`SELECT "$assert_text" = ""`)
{
--die ERROR IN TEST: the mysqltest variable rpl_test must be set
}
# Evaluate square brackets in cond.
--let $_rpl_assert_substmt_number= 1
--let $_rpl_interpolated_cond= $assert_cond
--let $_rpl_assert_lbracket= `SELECT LOCATE('[', '$_rpl_interpolated_cond')`
while ($_rpl_assert_lbracket)
{
# Get position of right bracket
--let $_rpl_assert_rbracket= `SELECT LOCATE(']', '$_rpl_interpolated_cond')`
if (!$_rpl_assert_rbracket)
{
--echo BUG IN TEST: Mismatching square brackets in assert_cond: '$assert_cond'
--die BUG IN TEST: Mismatching square brackets in $assert_cond
}
# Get sub-statement and result of it
--let $_rpl_assert_substmt= `SELECT SUBSTRING('$_rpl_interpolated_cond', $_rpl_assert_lbracket + 1, $_rpl_assert_rbracket - $_rpl_assert_lbracket - 1)`
--let $_rpl_assert_substmt_result= query_get_value($_rpl_assert_substmt)
if ($rpl_debug)
{
--echo # debug: sub-statement='$_rpl_assert_substmt' result='$rpl_assert_result'
}
# Replace sub-statement by its result
--let $_rpl_interpolated_cond= `SELECT REPLACE('$_rpl_interpolated_cond', '[$_rpl_assert_substmt]', '$_rpl_assert_substmt_result')`
# Replace result references by result
--let $_rpl_interpolated_cond= `SELECT REPLACE('$_rpl_interpolated_cond', '<$_rpl_assert_substmt_number>', '$_rpl_assert_substmt_result')`
--let $_rpl_assert_lbracket= `SELECT LOCATE('[', '$_rpl_interpolated_cond')`
--inc $_rpl_assert_substmt_number
}
if ($rpl_debug)
{
--echo # debug: interpolated_cond='$_rpl_interpolated_cond'
}
# Execute.
--let $_rpl_assert_result= `SELECT $_rpl_interpolated_cond`
if ($rpl_debug)
{
--echo # debug: result='$_rpl_assert_result'
}
# Check.
if (!$_rpl_assert_result)
{
--echo ######## Test assertion failed: $assert_text ########
--echo Dumping debug info:
--source include/show_rpl_debug_info.inc
--echo Assertion text: '$assert_text'
--echo Assertion condition: '$assert_cond'
--echo Assertion condition, interpolated: '$_rpl_interpolated_cond'
--echo Assertion result: '$_rpl_assert_result'
--die Test assertion failed in rpl_assertion.inc
}
if (!$assert_quiet)
{
--echo # Asserted this: $assert_text
}
--let $assert_text=
--let $assert_cond=

View file

@ -0,0 +1,28 @@
# ==== Purpose ====
#
# Display the delay state of the SQL thread.
#
# ==== Usage ====
#
# --let $verbose_delayed_slave_state= [0|1]
# --source extra/rpl_tests/show_delayed_slave_state.inc
#
# By default, the output is normalized so that it does not depend on
# exact timing or exact binlog positions. If
# $verbose_delayed_slave_state is set, then it outputs exact times and
# binlog positions. This can be useful for debugging.
--let $_delayed_slave_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running_State, 1)
--let $_delayed_slave_remaining_delay= query_get_value(SHOW SLAVE STATUS, SQL_Remaining_Delay, 1)
--let $_delayed_slave_qualitative_delay= `SELECT CASE WHEN "$_delayed_slave_remaining_delay" = "NULL" THEN "NULL" WHEN "$_delayed_slave_remaining_delay" = "0" THEN "0" ELSE "greater than zero" END`
--let $_delayed_slave_io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1)
--let $_delayed_slave_sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1)
--let $_delayed_slave_qualitative_log_pos= `SELECT IF($_delayed_slave_io_pos > $_delayed_slave_sql_pos, "behind", "in sync with")`
--echo Slave_SQL_Running_State='$_delayed_slave_status'; SQL_Remaining_Delay is $_delayed_slave_qualitative_delay; SQL thread is $_delayed_slave_qualitative_log_pos IO thread
if ($verbose_delayed_slave_state) {
--echo SQL_Remaining_Delay='$_delayed_slave_remaining_delay'; Read_master_log_pos='$_delayed_slave_io_pos'; Exec_Master_Log_Pos='$_delayed_slave_sql_pos'
}

View file

@ -0,0 +1,26 @@
# ==== Purpose ====
#
# This file does the same as the built-in command sync_with_master,
# but can be configured to use a custom timeout. This has the benefit
# that it accepts the same $slave_timeout and $master_connection
# parameters as wait_for_slave_param.inc
#
#
# ==== Usage ====
#
# --connection master
# --source include/save_master_pos.inc
# --connection slave
# --source include/sync_with_master.inc
#
# Parameters to this macro are $slave_timeout and
# $master_connection. See wait_for_slave_param.inc for
# descriptions.
--let $slave_param= Relay_Master_Log_File
--let $slave_param_value= $_master_file
--source include/wait_for_slave_param.inc
--let $slave_param= Exec_Master_Log_Pos
--let $slave_param_value= $_master_pos
--source include/wait_for_slave_param.inc

View file

@ -0,0 +1,123 @@
select json_valid('[1, 2]');
json_valid('[1, 2]')
1
select json_valid('"string"}');
json_valid('"string"}')
0
select json_valid('{"key1":1, "key2":[2,3]}');
json_valid('{"key1":1, "key2":[2,3]}')
1
select json_valid('[false, true, null]');
json_valid('[false, true, null]')
1
select json_value('{"key1":123}', '$.key2');
json_value('{"key1":123}', '$.key2')
NULL
select json_value('{"key1":123}', '$.key1');
json_value('{"key1":123}', '$.key1')
123
select json_value('{"key1":[1,2,3]}', '$.key1');
json_value('{"key1":[1,2,3]}', '$.key1')
NULL
select json_value('{"key1": [1,2,3], "key1":123}', '$.key1');
json_value('{"key1": [1,2,3], "key1":123}', '$.key1')
123
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2');
json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2')
NULL
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');
json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1')
{"a":1, "b":[1,2]}
select json_query('{"key1": 1}', '$.key1');
json_query('{"key1": 1}', '$.key1')
NULL
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
json_query('{"key1":123, "key1": [1,2,3]}', '$.key1')
[1,2,3]
select json_array(1);
json_array(1)
[1]
select json_array(1, "text", false, null);
json_array(1, "text", false, null)
[1, "text", false, null]
select json_array_append('["a", "b"]', '$', FALSE);
json_array_append('["a", "b"]', '$', FALSE)
["a", "b", false]
select json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2);
json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2)
{"k1":1, "k2":["a", "b", 2]}
select json_contains('{"k1":123, "k2":345}', '123', '$.k1');
json_contains('{"k1":123, "k2":345}', '123', '$.k1')
1
select json_contains('"you"', '"you"');
json_contains('"you"', '"you"')
1
select json_contains('"youth"', '"you"');
json_contains('"youth"', '"you"')
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]")
1
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]")
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.ma");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.ma")
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1");
json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1")
1
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1", "$.ma");
json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1", "$.ma")
1
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.ma");
json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.ma")
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.key2");
json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.key2")
1
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1")
asd
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY")
NULL
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2")
["asd", [2,3]]
select json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2");
json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2")
[5, [2,3]]
select json_extract('{"key0":true, "key1":"qwe"}', "$.key1");
json_extract('{"key0":true, "key1":"qwe"}', "$.key1")
qwe
select json_object("ki", 1, "mi", "ya");
json_object("ki", 1, "mi", "ya")
{"ki": 1, "mi": "ya"}
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2");
json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2")
1
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");
json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]")
1
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]");
json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]")
0
select json_quote('"string"');
json_quote('"string"')
\"string\"
select json_merge('string', 123);
json_merge('string', 123)
["string", 123]
select json_type('{"k1":123, "k2":345}');
json_type('{"k1":123, "k2":345}')
OBJECT
select json_type('[123, "k2", 345]');
json_type('[123, "k2", 345]')
ARRAY
select json_type("true");
json_type("true")
BOOLEAN
select json_type('123');
json_type('123')
NUMBER

View file

@ -774,6 +774,9 @@ The following options may be given as the first argument:
--range-alloc-block-size=#
Allocation block size for storing ranges during
optimization
--read-binlog-speed-limit=#
Maximum speed(KB/s) to read binlog from master (0 = no
limit)
--read-buffer-size=#
Each thread that does a sequential scan allocates a
buffer of this size for each table it scans. If you do
@ -1399,6 +1402,7 @@ query-cache-type OFF
query-cache-wlock-invalidate FALSE
query-prealloc-size 24576
range-alloc-block-size 4096
read-binlog-speed-limit 0
read-buffer-size 131072
read-only FALSE
read-rnd-buffer-size 262144

View file

@ -1584,7 +1584,7 @@ SELECT * FROM t1 WHERE ((c1 IS NOT NULL) >= (NOT TRUE)) IS NOT NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` where (((`test`.`t1`.`c1` is not null) >= <cache>((not(1)))) is not null)
Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` where (((`test`.`t1`.`c1` is not null) >= 0) is not null)
SELECT * FROM t1 WHERE ((c1 IS NOT NULL) >= (NOT TRUE)) IS NOT NULL;
c1
1

View file

@ -89,17 +89,17 @@ MASTER 2.2
# EOF
#
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 1073741824 7 0 60.000
MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No conservative 0 1073741824 7 0 60.000
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 7 0 60.000
MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 7 0 60.000
include/wait_for_slave_to_start.inc
set default_master_connection = 'MASTER 2.2';
include/wait_for_slave_to_start.inc
set default_master_connection = '';
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 1073741824 6 0 60.000
MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No conservative 0 1073741824 6 0 60.000
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 6 0 60.000
MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 6 0 60.000
#
# List of files matching '*info*' pattern
# after slave server restart

View file

@ -13,15 +13,15 @@ insert into t1 values (1),(2);
connection slave;
stop slave 'master1';
show slave 'master1' status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode
127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-master1.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space> None 0 No NULL No 0 0 1 No conservative
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State
127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-master1.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space> None 0 No NULL No 0 0 1 No conservative 0 NULL
mysqld-relay-bin-master1.000001
mysqld-relay-bin-master1.000002
mysqld-relay-bin-master1.index
reset slave 'master1';
show slave 'master1' status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode
127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space> None 0 No NULL No 0 0 1 No conservative
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State
127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space> None 0 No NULL No 0 0 1 No conservative 0 NULL
reset slave 'master1' all;
show slave 'master1' status;
ERROR HY000: There is no master connection 'master1'

View file

@ -18,9 +18,9 @@ connection slave;
connection master2;
connection slave;
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave1.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 1073741824 7 0 60.000
slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 1073741824 7 0 60.000
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave1.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 7 0 60.000
slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 7 0 60.000
start all slaves;
stop slave 'slave1';
show slave 'slave1' status;
@ -71,21 +71,24 @@ Gtid_IO_Pos
Replicate_Do_Domain_Ids
Replicate_Ignore_Domain_Ids
Parallel_Mode conservative
SQL_Delay 0
SQL_Remaining_Delay NULL
Slave_SQL_Running_State
reset slave 'slave1';
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave1 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space1> None 0 No NULL No 0 0 1 No conservative 0 1073741824 7 0 60.000
slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 1073741824 7 0 60.000
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave1 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space1> None 0 No NULL No 0 0 1 No conservative 0 NULL 0 1073741824 7 0 60.000
slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 7 0 60.000
reset slave 'slave1' all;
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 1073741824 7 0 60.000
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 2 No conservative 0 NULL Slave has read all relay log; waiting for the slave I/O thread to update it 0 1073741824 7 0 60.000
stop all slaves;
Warnings:
Note 1938 SLAVE 'slave2' stopped
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space1> None 0 No NULL No 0 0 2 No conservative 0 1073741824 7 0 60.000
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-slave2.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space1> None 0 No NULL No 0 0 2 No conservative 0 NULL 0 1073741824 7 0 60.000
stop all slaves;
include/reset_master_slave.inc
disconnect slave;

View file

@ -1,11 +1,11 @@
include/master-slave.inc
[connection master]
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State
show slave '' status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State
show all slaves status;
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
#
# Check error handling
#

View file

@ -0,0 +1,17 @@
--- mysql-test/suite/rpl/r/rpl_delayed_slave.result 2016-10-14 21:14:02.338075590 +0200
+++ mysql-test/suite/rpl/r/rpl_delayed_slave,parallel.reject 2016-10-14 21:17:51.296986686 +0200
@@ -45,7 +45,6 @@
# wait for first query to execute
# sleep 1*T
# Asserted this: Second query executed
-# Asserted this: Status should be executing third query (i.e., 'User sleep')
# sleep 2*T
# Asserted this: Third query executed
# Asserted this: Status should be 'Has read all relay log...'
@@ -167,5 +166,5 @@
conservative
SELECT @@GLOBAL.slave_parallel_threads;
@@GLOBAL.slave_parallel_threads
-0
+10
include/rpl_end.inc

View file

@ -0,0 +1,192 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
connection slave;
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
connection master;
[on master]
CREATE TABLE t1 (a VARCHAR(100), b INT);
INSERT INTO t1 VALUES ("zero", 0);
==== Normal setup ====
[on slave]
connection slave;
include/stop_slave.inc
# CHANGE MASTER TO MASTER_DELAY = 2*T
include/start_slave.inc
# Asserted this: SHOW SLAVE STATUS should return the same delay that we set with CHANGE MASTER
[on master]
connection master;
INSERT INTO t1 VALUES ('normal setup', 1);
connection master;
[on slave]
include/sync_slave_io_with_master.inc
# sleep 1*T
# Asserted this: Query 1 should not be executed
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
# sleep 1*T
# sync with master (with timeout 1*T)
include/wait_for_slave_param.inc [Relay_Master_Log_File]
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
# Asserted this: Query 1 should be executed
# Asserted this: Status should be 'Has read all relay log...'
include/check_slave_is_running.inc
==== Slave lags "naturally" after master ====
[on master]
connection master;
# CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * T); ELSE RETURN 0; END IF; END
INSERT INTO t1 SELECT delay_on_slave(3), 2;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
INSERT INTO t1 VALUES ('slave is already lagging: this statement should execute immediately', 3);
INSERT INTO t1 SELECT delay_on_slave(2), 4;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
[on slave]
include/sync_slave_io_with_master.inc
# sleep 1*T
# Asserted this: No query executed
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
# wait for first query to execute
# sleep 1*T
# Asserted this: Second query executed
# Asserted this: Status should be executing third query (i.e., 'User sleep')
# sleep 2*T
# Asserted this: Third query executed
# Asserted this: Status should be 'Has read all relay log...'
==== Seconds_Behind_Master ====
# Bring slave to sync.
include/stop_slave.inc
CHANGE MASTER TO MASTER_DELAY = 0;
include/start_slave.inc
connection master;
INSERT INTO t1 VALUES ('Syncing slave', 5);
connection slave;
include/stop_slave.inc
# CHANGE MASTER TO MASTER_DELAY = 2*T
include/start_slave.inc
connection master;
INSERT INTO t1 VALUES (delay_on_slave(1), 6);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
connection slave;
# sleep 1*T
# Asserted this: Seconds_Behind_Master should be between 0 and the 2*T
# sleep 1*T
# Asserted this: Seconds_Behind_Master should be at least 2*T
==== STOP SLAVE / START SLAVE + DML ====
include/stop_slave.inc
# CHANGE MASTER TO MASTER_DELAY = 3*T
include/start_slave.inc
[on master]
connection master;
INSERT INTO t1 VALUES ('stop slave and start slave: DML', 7);
[on slave]
connection slave;
# sleep 1*T
include/stop_slave.inc
# Asserted this: STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
# Asserted this: SQL thread position should not increase after STOP SLAVE
# Asserted this: Query should not be executed after STOP SLAVE
# Asserted this: Status should be '' after STOP SLAVE
include/start_slave.inc
# Asserted this: START SLAVE should finish quickly
connection master;
[on slave]
include/sync_slave_io_with_master.inc
# sleep 1*T
# Asserted this: Query 7 should not be executed
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
# sleep 1*T
# sync with master (with timeout 1*T)
include/wait_for_slave_param.inc [Relay_Master_Log_File]
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
# Asserted this: Query 7 should be executed
# Asserted this: Status should be 'Has read all relay log...'
include/check_slave_is_running.inc
==== STOP SLAVE / START SLAVE + DDL ====
This verifies BUG#56442
[on master]
connection master;
CREATE TABLE t_check_dml_not_executed_prematurely (a INT);
include/save_master_pos.inc
[on slave]
connection slave;
# sleep 1*T
include/stop_slave.inc
# Asserted this: STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
# Asserted this: SQL thread position should not increase after STOP SLAVE
# Asserted this: Query should not be executed after STOP SLAVE
# Asserted this: Status should be '' after STOP SLAVE
include/start_slave.inc
# Asserted this: START SLAVE should finish quickly
# sleep 1*T
# Asserted this: DDL Query should not be executed after START SLAVE
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
# sleep 1*T
# sync with master (with timeout 1*T)
include/wait_for_slave_param.inc [Relay_Master_Log_File]
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
# Asserted this: DDL Query should be executed
# Asserted this: Status should be 'Has read all relay log...'
include/check_slave_is_running.inc
==== Change back to no delay ====
[on slave]
connection slave;
include/stop_slave.inc
CHANGE MASTER TO MASTER_DELAY = 0;
# Asserted this: Delay should be 0 when we set it to 0
include/start_slave.inc
[on master]
connection master;
INSERT INTO t1 VALUES ('change back to no delay', 8);
[on slave]
include/sync_slave_io_with_master.inc
# sleep 1*T
# Asserted this: Query should be executed
# Asserted this: Status should be 'Slave has read all relay log...'
==== Reset delay with RESET SLAVE ====
include/stop_slave.inc
CHANGE MASTER TO MASTER_DELAY = 71;
include/start_slave.inc
# Asserted this: Delay should be 71 when we set it to 71
include/stop_slave.inc
RESET SLAVE;
[on master]
connection master;
RESET MASTER;
[on slave]
connection slave;
include/start_slave.inc
# Asserted this: Delay should be 0 after RESET SLAVE
==== Set an invalid value for the delay ====
include/stop_slave.inc
# Expect error for setting negative delay
CHANGE MASTER TO MASTER_DELAY = -1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '-1' at line 1
# Expect that it's ok to set delay of 2^31-1
CHANGE MASTER TO MASTER_DELAY = 2147483647;
# Expect error for setting delay between 2^31 and 2^32-1
CHANGE MASTER TO MASTER_DELAY = 2147483648;
ERROR HY000: The requested value 2147483648 for the master delay exceeds the maximum 2147483647
# Expect error for setting delay to nonsense
CHANGE MASTER TO MASTER_DELAY = blah;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'blah' at line 1
CHANGE MASTER TO MASTER_DELAY = 0;
include/start_slave.inc
==== Clean up ====
[on master]
connection master;
DROP TABLE t1, t_check_dml_not_executed_prematurely;
DROP FUNCTION delay_on_slave;
[on slave]
connection slave;
SELECT @@GLOBAL.slave_parallel_mode;
@@GLOBAL.slave_parallel_mode
conservative
SELECT @@GLOBAL.slave_parallel_threads;
@@GLOBAL.slave_parallel_threads
0
include/rpl_end.inc

View file

@ -0,0 +1,58 @@
include/master-slave.inc
[connection master]
connection master;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(100));
INSERT INTO t1 VALUES (1, "a");
connection slave;
include/stop_slave.inc
CHANGE MASTER TO master_use_gtid=slave_pos;
SET @old_mode= @@GLOBAL.slave_parallel_mode;
SET GLOBAL slave_parallel_mode=optimistic;
SET @old_threads= @@GLOBAL.slave_parallel_threads;
SET GLOBAL slave_parallel_threads=10;
connection master;
INSERT INTO t1 VALUES (2, "b");
INSERT INTO t1 VALUES (3, "b");
INSERT INTO t1 VALUES (4, "b");
SET timestamp= @@timestamp + 24*60*60;
INSERT INTO t1 VALUES (5, "c");
INSERT INTO t1 VALUES (6, "c");
SET timestamp= 0;
include/save_master_gtid.inc
connection slave;
CHANGE MASTER TO master_delay=1;
include/start_slave.inc
SELECT MASTER_GTID_WAIT('GTID1');
MASTER_GTID_WAIT('GTID1')
0
SELECT MASTER_GTID_WAIT('GTID2', 2);
MASTER_GTID_WAIT('GTID2', 2)
-1
include/stop_slave.inc
SELECT * FROM t1 ORDER BY a;
a b
1 a
2 b
3 b
4 b
CHANGE MASTER TO master_delay=0;
include/start_slave.inc
include/sync_with_master_gtid.inc
SELECT * FROM t1 ORDER BY a;
a b
1 a
2 b
3 b
4 b
5 c
6 c
connection slave;
include/stop_slave.inc
CHANGE MASTER TO master_use_gtid=no, master_delay=0;
SET GLOBAL slave_parallel_mode=@old_mode;
SET GLOBAL slave_parallel_threads=@old_threads;
include/start_slave.inc
connection master;
DROP TABLE t1;
include/rpl_end.inc

View file

@ -0,0 +1,5 @@
[nonparallel]
[parallel]
--slave-parallel-mode=conservative
--slave-parallel-threads=10

View file

@ -0,0 +1,424 @@
# ==== Purpose ====
#
# Test the time-delayed replication feature, i.e.,
# CHANGE MASTER TO MASTER_DELAY=X:
#
# - Verify that slave has executed the events after but not before the
# delay timeout.
#
# - Verify that delay is correct when slave is already lagging
# due to slow queries.
#
# - Verify that Seconds_Behind_Master is greater than or equal to the
# delay if the slave still has unprocessed events in the relay log
# and more time than the delay has elapsed since the last event was
# executed on the master.
#
# - Verify that STOP SLAVE works instantly even during a delay, and
# that it does not cause the waited-for event to be executed too
# early on slave.
#
# - Verify that changing back to no delay works.
#
# - Verify that RESET SLAVE sets the delay to 0.
#
# - Verify that setting a bad value for the delay gives an error.
#
# ==== Implementation ====
#
# We run the slave with 10 seconds lag.
#
# In general, to test that a query has not been executed by the slave
# before this time, we wait until the slave IO thread has received the
# event, and then 5 seconds more, and check that the table has not
# been updated. To test that a query has been executed after this
# time, we wait 10 seconds more.
#
# To simulate that the slave lags due to slow queries, we invoke a
# stored function that executes SLEEP if @@gloval.server_id==2. This
# requires that we run with binlog_format=STATEMENT.
#
# ==== Related Bugs and Worklogs ====
#
# WL#344: Time-delayed replication
# BUG#28760: Simulating a replication lag
# [duplicate] BUG#22072: configurable delayed replication
# [duplicate] BUG#21639: Add Replication Delay parameter
# BUG#56442: Slave executes delayed statements when STOP SLAVE is issued
#
# ==== Issues with this Test Case ====
#
# The test is inherently timing-sensitive (i.e., contains races) and
# is likely to fail sporadically on a loaded host.
#
# The test takes a long time; it sleeps for around 20*10 seconds.
--source include/big_test.inc
--source include/not_valgrind.inc
--source include/master-slave.inc
# Needed so that sleeps get executed in the slave SQL thread.
--source include/have_binlog_format_statement.inc
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
--connection slave
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
--connection master
# We assume that any simple operation takes zero time, with an error
# margin of $time1 seconds. Hence, if we run with a delay of $time2
# seconds, we expect that:
# - If we execute a query on master and wait $time1 seconds, then the
# query has been copied to slave but not yet executed.
# - If we execute a query on master and wait $time3 seconds, then the
# query has been executed.
--let $time1= 10
if (`SELECT '$max_query_execution_time' > 0`) {
--let $time1= $max_query_execution_time
}
--let $time2= `SELECT 2 * $time1`
--let $time3= `SELECT 3 * $time1`
--echo [on master]
CREATE TABLE t1 (a VARCHAR(100), b INT);
INSERT INTO t1 VALUES ("zero", 0);
--echo ==== Normal setup ====
--echo [on slave]
--sync_slave_with_master
--source include/stop_slave.inc
--echo # CHANGE MASTER TO MASTER_DELAY = 2*T
--disable_query_log
eval CHANGE MASTER TO MASTER_DELAY = $time2;
--enable_query_log
--source include/start_slave.inc
--let $assert_text= SHOW SLAVE STATUS should return the same delay that we set with CHANGE MASTER
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = $time2
--source include/rpl_assert.inc
--echo [on master]
--connection master
INSERT INTO t1 VALUES ('normal setup', 1);
--let $query_number= 1
--source extra/rpl_tests/delayed_slave_wait_on_query.inc
--echo ==== Slave lags "naturally" after master ====
--echo [on master]
--connection master
--disable_query_log
--echo # CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * T); ELSE RETURN 0; END IF; END
--eval CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * $time1); ELSE RETURN 0; END IF; END
--enable_query_log
INSERT INTO t1 SELECT delay_on_slave(3), 2;
--save_master_pos
INSERT INTO t1 VALUES ('slave is already lagging: this statement should execute immediately', 3);
INSERT INTO t1 SELECT delay_on_slave(2), 4;
--echo [on slave]
--source include/sync_slave_io_with_master.inc
--echo # sleep 1*T
--sleep $time1
--let $assert_text= No query executed
--let $assert_cond= MAX(b) = 1 FROM t1
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Waiting until MASTER_DELAY...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%"
--source include/rpl_assert.inc
--echo # wait for first query to execute
--sync_with_master
--echo # sleep 1*T
--sleep $time1
--let $assert_text= Second query executed
--let $assert_cond= MAX(b) = 3 FROM t1
--source include/rpl_assert.inc
let $parallel= `SELECT @@GLOBAL.slave_parallel_threads`;
if (!$parallel)
{
let $assert_text= Status should be executing third query (i.e., 'User sleep');
let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = "User sleep";
source include/rpl_assert.inc;
}
--echo # sleep 2*T
--sleep $time2
--let $assert_text= Third query executed
--let $assert_cond= MAX(b) = 4 FROM t1
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Has read all relay log...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%"
--source include/rpl_assert.inc
--echo ==== Seconds_Behind_Master ====
--echo # Bring slave to sync.
--source include/stop_slave.inc
CHANGE MASTER TO MASTER_DELAY = 0;
--source include/start_slave.inc
--connection master
INSERT INTO t1 VALUES ('Syncing slave', 5);
--sync_slave_with_master
--source include/stop_slave.inc
--echo # CHANGE MASTER TO MASTER_DELAY = 2*T
--disable_query_log
eval CHANGE MASTER TO MASTER_DELAY = $time2;
--enable_query_log
--source include/start_slave.inc
--connection master
INSERT INTO t1 VALUES (delay_on_slave(1), 6);
--save_master_pos
--connection slave
--echo # sleep 1*T
--sleep $time1
--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] >= 0 AND <1> < $time2
--let $assert_text= Seconds_Behind_Master should be between 0 and the 2*T
--source include/rpl_assert.inc
--echo # sleep 1*T
--sleep $time1
--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] >= $time2
--let $assert_text= Seconds_Behind_Master should be at least 2*T
--source include/rpl_assert.inc
--sync_with_master
--echo ==== STOP SLAVE / START SLAVE + DML ====
# Set up a longer delay.
--source include/stop_slave.inc
--echo # CHANGE MASTER TO MASTER_DELAY = 3*T
--disable_query_log
eval CHANGE MASTER TO MASTER_DELAY = $time3;
--enable_query_log
--source include/start_slave.inc
--echo [on master]
--connection master
INSERT INTO t1 VALUES ('stop slave and start slave: DML', 7);
--echo [on slave]
--connection slave
--echo # sleep 1*T
--sleep $time1
--let $timestamp_before_stop= `SELECT UNIX_TIMESTAMP()`
--let $relay_log_pos_before_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1)
--source include/stop_slave.inc
--let $assert_text= STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
--source include/rpl_assert.inc
--let $assert_text= SQL thread position should not increase after STOP SLAVE
--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = $relay_log_pos_before_stop
--source include/rpl_assert.inc
--let $assert_text= Query should not be executed after STOP SLAVE
--let $assert_cond= MAX(b) = 6 FROM t1
--source include/rpl_assert.inc
--let $assert_text= Status should be '' after STOP SLAVE
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = ""
--source include/rpl_assert.inc
--source include/start_slave.inc
--let $assert_text= START SLAVE should finish quickly
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
--source include/rpl_assert.inc
--let $query_number= 7
--source extra/rpl_tests/delayed_slave_wait_on_query.inc
--echo ==== STOP SLAVE / START SLAVE + DDL ====
--echo This verifies BUG#56442
--echo [on master]
--connection master
CREATE TABLE t_check_dml_not_executed_prematurely (a INT);
--source include/save_master_pos.inc
--echo [on slave]
--connection slave
--echo # sleep 1*T
--sleep $time1
--let $timestamp_before_stop= `SELECT UNIX_TIMESTAMP()`
--let $relay_log_pos_before_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1)
--source include/stop_slave.inc
--let $assert_text= STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
--source include/rpl_assert.inc
--let $assert_text= SQL thread position should not increase after STOP SLAVE
--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = $relay_log_pos_before_stop
--source include/rpl_assert.inc
--let $assert_text= Query should not be executed after STOP SLAVE
--let $assert_cond= COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely"
--source include/rpl_assert.inc
--let $assert_text= Status should be '' after STOP SLAVE
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = ""
--source include/rpl_assert.inc
--source include/start_slave.inc
--let $assert_text= START SLAVE should finish quickly
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
--source include/rpl_assert.inc
--echo # sleep 1*T
--sleep $time1
--let $assert_text= DDL Query should not be executed after START SLAVE
--let $assert_cond= COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely"
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Waiting until MASTER_DELAY...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%"
--source include/rpl_assert.inc
--echo # sleep 1*T
--sleep $time1
--echo # sync with master (with timeout 1*T)
--source include/sync_with_master.inc
--let $assert_text= DDL Query should be executed
--let $assert_cond= COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely"
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Has read all relay log...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%"
--source include/rpl_assert.inc
--source include/check_slave_is_running.inc
--echo ==== Change back to no delay ====
--echo [on slave]
--connection slave
--source include/stop_slave.inc
CHANGE MASTER TO MASTER_DELAY = 0;
--let $assert_text= Delay should be 0 when we set it to 0
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 0
--source include/rpl_assert.inc
--source include/start_slave.inc
--echo [on master]
--connection master
INSERT INTO t1 VALUES ('change back to no delay', 8);
--echo [on slave]
--source include/sync_slave_io_with_master.inc
--echo # sleep 1*T
--sleep $time1
--let $assert_text= Query should be executed
--let $assert_cond= MAX(b) = 8 FROM t1
--source include/rpl_assert.inc
--let $assert_text= Status should be 'Slave has read all relay log...'
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" Like "Slave has read all relay log%"
--source include/rpl_assert.inc
--echo ==== Reset delay with RESET SLAVE ====
--source include/stop_slave.inc
CHANGE MASTER TO MASTER_DELAY = 71;
--source include/start_slave.inc
--let $assert_text= Delay should be 71 when we set it to 71
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 71
--source include/rpl_assert.inc
--source include/stop_slave.inc
RESET SLAVE;
--echo [on master]
--connection master
RESET MASTER;
--echo [on slave]
--connection slave
--source include/start_slave.inc
--let $assert_text= Delay should be 0 after RESET SLAVE
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 0
--source include/rpl_assert.inc
--echo ==== Set an invalid value for the delay ====
--source include/stop_slave.inc
--echo # Expect error for setting negative delay
--error ER_PARSE_ERROR
CHANGE MASTER TO MASTER_DELAY = -1;
--echo # Expect that it's ok to set delay of 2^31-1
CHANGE MASTER TO MASTER_DELAY = 2147483647;
--echo # Expect error for setting delay between 2^31 and 2^32-1
--error ER_MASTER_DELAY_VALUE_OUT_OF_RANGE
CHANGE MASTER TO MASTER_DELAY = 2147483648;
--echo # Expect error for setting delay to nonsense
--error ER_PARSE_ERROR
CHANGE MASTER TO MASTER_DELAY = blah;
# todo: CHANGE MASTER TO MASTER_DELAY = 999999999999999999999999999
# should give error
CHANGE MASTER TO MASTER_DELAY = 0;
--source include/start_slave.inc
--echo ==== Clean up ====
--echo [on master]
--connection master
DROP TABLE t1, t_check_dml_not_executed_prematurely;
DROP FUNCTION delay_on_slave;
--echo [on slave]
--sync_slave_with_master
SELECT @@GLOBAL.slave_parallel_mode;
SELECT @@GLOBAL.slave_parallel_threads;
--source include/rpl_end.inc

View file

@ -0,0 +1,65 @@
--source include/have_innodb.inc
--source include/master-slave.inc
# This test file tests delayed slave for parallel replication (and GTID).
# Uses a different approach from rpl_delayed_slave.test, setting @@timestamp
# to simulate events logged on master at different times.
--connection master
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(100));
INSERT INTO t1 VALUES (1, "a");
--save_master_pos
--connection slave
--sync_with_master
--source include/stop_slave.inc
CHANGE MASTER TO master_use_gtid=slave_pos;
SET @old_mode= @@GLOBAL.slave_parallel_mode;
SET GLOBAL slave_parallel_mode=optimistic;
SET @old_threads= @@GLOBAL.slave_parallel_threads;
SET GLOBAL slave_parallel_threads=10;
--connection master
INSERT INTO t1 VALUES (2, "b");
INSERT INTO t1 VALUES (3, "b");
INSERT INTO t1 VALUES (4, "b");
--let $gtid1= `SELECT @@gtid_binlog_pos`
# Simulate an event a days in the future, for delayed slave to wait on.
SET timestamp= @@timestamp + 24*60*60;
INSERT INTO t1 VALUES (5, "c");
INSERT INTO t1 VALUES (6, "c");
SET timestamp= 0;
--let $gtid2= `SELECT @@gtid_binlog_pos`
--source include/save_master_gtid.inc
--connection slave
CHANGE MASTER TO master_delay=1;
--source include/start_slave.inc
--replace_result $gtid1 GTID1
# First sync halfways, to avoid timing-dependent test failures.
eval SELECT MASTER_GTID_WAIT('$gtid1');
# Try to sync up, should timeout because slave is waiting for one day.
--replace_result $gtid2 GTID2
eval SELECT MASTER_GTID_WAIT('$gtid2', 2);
# Check that we can stop slave while delaying.
--source include/stop_slave.inc
SELECT * FROM t1 ORDER BY a;
CHANGE MASTER TO master_delay=0;
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
SELECT * FROM t1 ORDER BY a;
--connection slave
--source include/stop_slave.inc
CHANGE MASTER TO master_use_gtid=no, master_delay=0;
SET GLOBAL slave_parallel_mode=@old_mode;
SET GLOBAL slave_parallel_threads=@old_threads;
--source include/start_slave.inc
--connection master
DROP TABLE t1;
--source include/rpl_end.inc

View file

@ -0,0 +1,10 @@
SELECT @@GLOBAL.innodb_numa_interleave;
@@GLOBAL.innodb_numa_interleave
1
SET @@GLOBAL.innodb_numa_interleave=off;
ERROR HY000: Variable 'innodb_numa_interleave' is a read only variable
SELECT @@GLOBAL.innodb_numa_interleave;
@@GLOBAL.innodb_numa_interleave
1
SELECT @@SESSION.innodb_numa_interleave;
ERROR HY000: Variable 'innodb_numa_interleave' is a GLOBAL variable

View file

@ -1447,6 +1447,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY YES
COMMAND_LINE_ARGUMENT NONE
VARIABLE_NAME INNODB_LOCK_SCHEDULE_ALGORITHM
SESSION_VALUE NULL
GLOBAL_VALUE vats
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE vats
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE ENUM
VARIABLE_COMMENT The algorithm Innodb uses for deciding which locks to grant next when a lock is released. Possible values are FCFS grant the locks in First-Come-First-Served order; VATS use the Variance-Aware-Transaction-Scheduling algorithm, which uses an Eldest-Transaction-First heuristic.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST fcfs,vats
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_LOCK_WAIT_TIMEOUT
SESSION_VALUE 50
GLOBAL_VALUE 50

View file

@ -894,7 +894,7 @@
NUMERIC_MAX_VALUE 256
@@ -2829,7 +2829,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 184
DEFAULT_VALUE 185
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED

View file

@ -2825,9 +2825,9 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES
SESSION_VALUE NULL
GLOBAL_VALUE 184
GLOBAL_VALUE 185
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 184
DEFAULT_VALUE 185
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum number of statement instruments.

View file

@ -1,5 +1,5 @@
--- suite/sys_vars/r/sysvars_server_notembedded.result
+++ suite/sys_vars/r/sysvars_server_notembedded.reject
--- suite/sys_vars/r/sysvars_server_notembedded.result 2016-10-21 18:47:47.000000000 +0300
+++ suite/sys_vars/r/sysvars_server_notembedded.reject 2016-10-24 02:02:03.000000000 +0300
@@ -57,7 +57,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE 1
@ -449,7 +449,7 @@
VARIABLE_COMMENT Maximum number of prepared statements in the server
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
@@ -2171,7 +2171,7 @@
@@ -2185,7 +2185,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4294967295
VARIABLE_SCOPE SESSION
@ -458,7 +458,7 @@
VARIABLE_COMMENT Maximum number of iterations when executing recursive queries
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -2199,7 +2199,7 @@
@@ -2213,7 +2213,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4294967295
VARIABLE_SCOPE SESSION
@ -467,7 +467,7 @@
VARIABLE_COMMENT Limit assumed max number of seeks when looking up rows based on a key
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
@@ -2213,7 +2213,7 @@
@@ -2227,7 +2227,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE SESSION
@ -476,7 +476,7 @@
VARIABLE_COMMENT The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored)
NUMERIC_MIN_VALUE 4
NUMERIC_MAX_VALUE 8388608
@@ -2227,7 +2227,7 @@
@@ -2241,7 +2241,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
@ -485,7 +485,7 @@
VARIABLE_COMMENT Maximum stored procedure recursion depth
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 255
@@ -2255,7 +2255,7 @@
@@ -2269,7 +2269,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32
VARIABLE_SCOPE SESSION
@ -494,7 +494,7 @@
VARIABLE_COMMENT Unused, will be removed.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
@@ -2283,7 +2283,7 @@
@@ -2297,7 +2297,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4294967295
VARIABLE_SCOPE GLOBAL
@ -503,7 +503,7 @@
VARIABLE_COMMENT After this many write locks, allow some read locks to run in between
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
@@ -2297,7 +2297,7 @@
@@ -2311,7 +2311,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
@ -512,7 +512,7 @@
VARIABLE_COMMENT Unused
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1048576
@@ -2311,7 +2311,7 @@
@@ -2325,7 +2325,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8
VARIABLE_SCOPE GLOBAL
@ -521,7 +521,7 @@
VARIABLE_COMMENT Unused
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1024
@@ -2325,7 +2325,7 @@
@@ -2339,7 +2339,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
@ -530,7 +530,7 @@
VARIABLE_COMMENT Don't write queries to slow log that examine fewer rows than that
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -2339,7 +2339,7 @@
@@ -2353,7 +2353,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 262144
VARIABLE_SCOPE SESSION
@ -539,7 +539,7 @@
VARIABLE_COMMENT Size of buffer to use when using MRR with range access
NUMERIC_MIN_VALUE 8192
NUMERIC_MAX_VALUE 2147483647
@@ -2353,10 +2353,10 @@
@@ -2367,10 +2367,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 256
VARIABLE_SCOPE SESSION
@ -552,7 +552,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -2367,7 +2367,7 @@
@@ -2381,7 +2381,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
@ -561,7 +561,7 @@
VARIABLE_COMMENT Block size to be used for MyISAM index pages
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 16384
@@ -2381,7 +2381,7 @@
@@ -2395,7 +2395,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 6
VARIABLE_SCOPE GLOBAL
@ -570,7 +570,7 @@
VARIABLE_COMMENT Default pointer size to be used for MyISAM tables
NUMERIC_MIN_VALUE 2
NUMERIC_MAX_VALUE 7
@@ -2391,9 +2391,9 @@
@@ -2405,9 +2405,9 @@
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME MYISAM_MAX_SORT_FILE_SIZE
SESSION_VALUE NULL
@ -582,7 +582,7 @@
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Don't use the fast sort index method to created index if the temporary file would get bigger than this
@@ -2405,14 +2405,14 @@
@@ -2419,14 +2419,14 @@
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME MYISAM_MMAP_SIZE
SESSION_VALUE NULL
@ -600,7 +600,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY YES
@@ -2437,10 +2437,10 @@
@@ -2451,10 +2451,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1
VARIABLE_SCOPE SESSION
@ -613,7 +613,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -2454,7 +2454,7 @@
@@ -2468,7 +2468,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE
NUMERIC_MIN_VALUE 4096
@ -622,7 +622,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -2507,7 +2507,7 @@
@@ -2521,7 +2521,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 16384
VARIABLE_SCOPE SESSION
@ -631,7 +631,7 @@
VARIABLE_COMMENT Buffer length for TCP/IP and socket communication
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1048576
@@ -2521,7 +2521,7 @@
@@ -2535,7 +2535,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 30
VARIABLE_SCOPE SESSION
@ -640,7 +640,7 @@
VARIABLE_COMMENT Number of seconds to wait for more data from a connection before aborting the read
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 31536000
@@ -2535,7 +2535,7 @@
@@ -2549,7 +2549,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE SESSION
@ -649,7 +649,7 @@
VARIABLE_COMMENT If a read on a communication port is interrupted, retry this many times before giving up
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
@@ -2549,7 +2549,7 @@
@@ -2563,7 +2563,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 60
VARIABLE_SCOPE SESSION
@ -658,7 +658,7 @@
VARIABLE_COMMENT Number of seconds to wait for a block to be written to a connection before aborting the write
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 31536000
@@ -2619,7 +2619,7 @@
@@ -2633,7 +2633,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1
VARIABLE_SCOPE SESSION
@ -667,7 +667,7 @@
VARIABLE_COMMENT Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search; 1 - prune plans based on number of retrieved rows
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1
@@ -2633,7 +2633,7 @@
@@ -2647,7 +2647,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 62
VARIABLE_SCOPE SESSION
@ -676,7 +676,7 @@
VARIABLE_COMMENT Maximum depth of search performed by the query optimizer. Values larger than the number of relations in a query result in better query plans, but take longer to compile a query. Values smaller than the number of tables in a relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 62
@@ -2647,7 +2647,7 @@
@@ -2661,7 +2661,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE SESSION
@ -685,7 +685,7 @@
VARIABLE_COMMENT Controls number of record samples to check condition selectivity
NUMERIC_MIN_VALUE 10
NUMERIC_MAX_VALUE 4294967295
@@ -2675,7 +2675,7 @@
@@ -2689,7 +2689,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1
VARIABLE_SCOPE SESSION
@ -694,7 +694,7 @@
VARIABLE_COMMENT Controls selectivity of which conditions the optimizer takes into account to calculate cardinality of a partial join when it searches for the best execution plan Meaning: 1 - use selectivity of index backed range conditions to calculate the cardinality of a partial join if the last joined table is accessed by full table scan or an index scan, 2 - use selectivity of index backed range conditions to calculate the cardinality of a partial join in any case, 3 - additionally always use selectivity of range conditions that are not backed by any index to calculate the cardinality of a partial join, 4 - use histograms to calculate selectivity of range conditions that are not backed by any index to calculate the cardinality of a partial join.5 - additionally use selectivity of certain non-range predicates calculated on record samples
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 5
@@ -2703,7 +2703,7 @@
@@ -2717,7 +2717,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -703,7 +703,7 @@
VARIABLE_COMMENT Maximum number of instrumented user@host accounts. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2717,7 +2717,7 @@
@@ -2731,7 +2731,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -712,7 +712,7 @@
VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 200
@@ -2731,7 +2731,7 @@
@@ -2745,7 +2745,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -721,7 +721,7 @@
VARIABLE_COMMENT Number of rows in EVENTS_STAGES_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2745,7 +2745,7 @@
@@ -2759,7 +2759,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -730,7 +730,7 @@
VARIABLE_COMMENT Number of rows per thread in EVENTS_STAGES_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
@@ -2759,7 +2759,7 @@
@@ -2773,7 +2773,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -739,7 +739,7 @@
VARIABLE_COMMENT Number of rows in EVENTS_STATEMENTS_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2773,7 +2773,7 @@
@@ -2787,7 +2787,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -748,7 +748,7 @@
VARIABLE_COMMENT Number of rows per thread in EVENTS_STATEMENTS_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
@@ -2787,7 +2787,7 @@
@@ -2801,7 +2801,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -757,7 +757,7 @@
VARIABLE_COMMENT Number of rows in EVENTS_WAITS_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2801,7 +2801,7 @@
@@ -2815,7 +2815,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -766,7 +766,7 @@
VARIABLE_COMMENT Number of rows per thread in EVENTS_WAITS_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
@@ -2815,7 +2815,7 @@
@@ -2829,7 +2829,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -775,7 +775,7 @@
VARIABLE_COMMENT Maximum number of instrumented hosts. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2829,7 +2829,7 @@
@@ -2843,7 +2843,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 80
VARIABLE_SCOPE GLOBAL
@ -784,7 +784,7 @@
VARIABLE_COMMENT Maximum number of condition instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -2843,7 +2843,7 @@
@@ -2857,7 +2857,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -793,7 +793,7 @@
VARIABLE_COMMENT Maximum number of instrumented condition objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2857,7 +2857,7 @@
@@ -2871,7 +2871,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
@ -802,7 +802,7 @@
VARIABLE_COMMENT Maximum length considered for digest text, when stored in performance_schema tables.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
@@ -2871,7 +2871,7 @@
@@ -2885,7 +2885,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@ -811,7 +811,7 @@
VARIABLE_COMMENT Maximum number of file instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -2885,7 +2885,7 @@
@@ -2899,7 +2899,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32768
VARIABLE_SCOPE GLOBAL
@ -820,7 +820,7 @@
VARIABLE_COMMENT Maximum number of opened instrumented files.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
@@ -2899,7 +2899,7 @@
@@ -2913,7 +2913,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -829,7 +829,7 @@
VARIABLE_COMMENT Maximum number of instrumented files. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2913,7 +2913,7 @@
@@ -2927,7 +2927,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 200
VARIABLE_SCOPE GLOBAL
@ -838,7 +838,7 @@
VARIABLE_COMMENT Maximum number of mutex instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -2927,7 +2927,7 @@
@@ -2941,7 +2941,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -847,7 +847,7 @@
VARIABLE_COMMENT Maximum number of instrumented MUTEX objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 104857600
@@ -2941,7 +2941,7 @@
@@ -2955,7 +2955,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 40
VARIABLE_SCOPE GLOBAL
@ -856,7 +856,7 @@
VARIABLE_COMMENT Maximum number of rwlock instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -2955,7 +2955,7 @@
@@ -2969,7 +2969,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -865,7 +865,7 @@
VARIABLE_COMMENT Maximum number of instrumented RWLOCK objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 104857600
@@ -2969,7 +2969,7 @@
@@ -2983,7 +2983,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@ -874,7 +874,7 @@
VARIABLE_COMMENT Maximum number of socket instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -2983,7 +2983,7 @@
@@ -2997,7 +2997,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -883,7 +883,7 @@
VARIABLE_COMMENT Maximum number of opened instrumented sockets. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -2997,7 +2997,7 @@
@@ -3011,7 +3011,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 150
VARIABLE_SCOPE GLOBAL
@ -892,16 +892,16 @@
VARIABLE_COMMENT Maximum number of stage instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -3011,7 +3011,7 @@
@@ -3025,7 +3025,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 181
DEFAULT_VALUE 185
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Maximum number of statement instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -3025,7 +3025,7 @@
@@ -3039,7 +3039,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -910,7 +910,7 @@
VARIABLE_COMMENT Maximum number of opened instrumented tables. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -3039,7 +3039,7 @@
@@ -3053,7 +3053,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -919,7 +919,7 @@
VARIABLE_COMMENT Maximum number of instrumented tables. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -3053,7 +3053,7 @@
@@ -3067,7 +3067,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@ -928,7 +928,7 @@
VARIABLE_COMMENT Maximum number of thread instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
@@ -3067,7 +3067,7 @@
@@ -3081,7 +3081,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -937,7 +937,7 @@
VARIABLE_COMMENT Maximum number of instrumented threads. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -3081,7 +3081,7 @@
@@ -3095,7 +3095,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -946,7 +946,7 @@
VARIABLE_COMMENT Size of session attribute string buffer per thread. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -3095,7 +3095,7 @@
@@ -3109,7 +3109,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE GLOBAL
@ -955,7 +955,7 @@
VARIABLE_COMMENT Maximum number of rows in SETUP_ACTORS.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1024
@@ -3109,7 +3109,7 @@
@@ -3123,7 +3123,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE GLOBAL
@ -964,7 +964,7 @@
VARIABLE_COMMENT Maximum number of rows in SETUP_OBJECTS.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
@@ -3123,7 +3123,7 @@
@@ -3137,7 +3137,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@ -973,7 +973,7 @@
VARIABLE_COMMENT Maximum number of instrumented users. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
@@ -3193,7 +3193,7 @@
@@ -3207,7 +3207,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32768
VARIABLE_SCOPE SESSION
@ -982,7 +982,7 @@
VARIABLE_COMMENT The size of the buffer that is allocated when preloading indexes
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1073741824
@@ -3221,7 +3221,7 @@
@@ -3235,7 +3235,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 15
VARIABLE_SCOPE SESSION
@ -991,7 +991,7 @@
VARIABLE_COMMENT Limit of query profiling memory
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 100
@@ -3235,7 +3235,7 @@
@@ -3249,7 +3249,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 5
VARIABLE_SCOPE SESSION
@ -1000,7 +1000,7 @@
VARIABLE_COMMENT Seconds between sending progress reports to the client for time-consuming statements. Set to 0 to disable progress reporting.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -3305,7 +3305,7 @@
@@ -3319,7 +3319,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 16384
VARIABLE_SCOPE SESSION
@ -1009,7 +1009,7 @@
VARIABLE_COMMENT Allocation block size for query parsing and execution
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 4294967295
@@ -3319,7 +3319,7 @@
@@ -3333,7 +3333,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1048576
VARIABLE_SCOPE GLOBAL
@ -1018,7 +1018,7 @@
VARIABLE_COMMENT Don't cache results that are bigger than this
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -3333,7 +3333,7 @@
@@ -3347,7 +3347,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE GLOBAL
@ -1027,7 +1027,7 @@
VARIABLE_COMMENT The minimum size for blocks allocated by the query cache
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -3350,7 +3350,7 @@
@@ -3364,7 +3364,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The memory allocated to store results from old queries
NUMERIC_MIN_VALUE 0
@ -1036,7 +1036,7 @@
NUMERIC_BLOCK_SIZE 1024
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -3403,7 +3403,7 @@
@@ -3417,7 +3417,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 24576
VARIABLE_SCOPE SESSION
@ -1045,7 +1045,7 @@
VARIABLE_COMMENT Persistent buffer for query parsing and execution
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 4294967295
@@ -3417,7 +3417,7 @@
@@ -3431,7 +3431,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE SESSION
@ -1054,7 +1054,16 @@
VARIABLE_COMMENT Allocation block size for storing ranges during optimization
NUMERIC_MIN_VALUE 4096
NUMERIC_MAX_VALUE 4294967295
@@ -3431,7 +3431,7 @@
@@ -3448,7 +3448,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum speed(KB/s) to read binlog from master (0 = no limit)
NUMERIC_MIN_VALUE 0
-NUMERIC_MAX_VALUE 18446744073709551615
+NUMERIC_MAX_VALUE 4294967295
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -3459,7 +3459,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 131072
VARIABLE_SCOPE SESSION
@ -1063,7 +1072,7 @@
VARIABLE_COMMENT Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value
NUMERIC_MIN_VALUE 8192
NUMERIC_MAX_VALUE 2147483647
@@ -3459,7 +3459,7 @@
@@ -3487,7 +3487,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 262144
VARIABLE_SCOPE SESSION
@ -1072,7 +1081,7 @@
VARIABLE_COMMENT When reading rows in sorted order after a sort, the rows are read through this buffer to avoid a disk seeks
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 2147483647
@@ -3739,10 +3739,10 @@
@@ -3767,10 +3767,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8388608
VARIABLE_SCOPE SESSION
@ -1085,16 +1094,16 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -3781,7 +3781,7 @@
@@ -3809,7 +3809,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE 0
DEFAULT_VALUE 1
VARIABLE_SCOPE SESSION
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Uniquely identifies the server instance in the community of replication partners
NUMERIC_MIN_VALUE 0
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
@@ -3907,7 +3907,7 @@
@@ -3991,7 +3991,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -1103,7 +1112,7 @@
VARIABLE_COMMENT Maximum number of parallel threads to use on slave for events in a single replication domain. When using multiple domains, this can be used to limit a single domain from grabbing all threads and thus stalling other domains. The default of 0 means to allow a domain to grab as many threads as it wants, up to the value of slave_parallel_threads.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16383
@@ -3949,7 +3949,7 @@
@@ -4033,7 +4033,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1073741824
VARIABLE_SCOPE GLOBAL
@ -1112,7 +1121,7 @@
VARIABLE_COMMENT The maximum packet length to sent successfully from the master to slave.
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1073741824
@@ -3977,7 +3977,7 @@
@@ -4061,7 +4061,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 131072
VARIABLE_SCOPE GLOBAL
@ -1121,7 +1130,7 @@
VARIABLE_COMMENT Limit on how much memory SQL threads should use per parallel replication thread when reading ahead in the relay log looking for opportunities for parallel replication. Only used when --slave-parallel-threads > 0.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 2147483647
@@ -4005,7 +4005,7 @@
@@ -4089,7 +4089,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -1130,7 +1139,7 @@
VARIABLE_COMMENT If non-zero, number of threads to spawn to apply in parallel events on the slave that were group-committed on the master or were logged with GTID in different replication domains. Note that these threads are in addition to the IO and SQL threads, which are always created by a replication slave
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16383
@@ -4019,7 +4019,7 @@
@@ -4103,7 +4103,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -1139,7 +1148,7 @@
VARIABLE_COMMENT Alias for slave_parallel_threads
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16383
@@ -4075,7 +4075,7 @@
@@ -4159,7 +4159,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@ -1148,7 +1157,7 @@
VARIABLE_COMMENT Number of times the slave SQL thread will retry a transaction in case it failed with a deadlock or elapsed lock wait timeout, before giving up and stopping
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -4103,7 +4103,7 @@
@@ -4187,7 +4187,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 2
VARIABLE_SCOPE GLOBAL
@ -1157,7 +1166,7 @@
VARIABLE_COMMENT If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
@@ -4162,7 +4162,7 @@
@@ -4246,7 +4246,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Each thread that needs to do a sort allocates a buffer of this size
NUMERIC_MIN_VALUE 1024
@ -1166,7 +1175,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -4453,7 +4453,7 @@
@@ -4551,7 +4551,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 256
VARIABLE_SCOPE GLOBAL
@ -1175,7 +1184,7 @@
VARIABLE_COMMENT The soft upper limit for number of cached stored routines for one connection.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 524288
@@ -4551,7 +4551,7 @@
@@ -4649,7 +4649,7 @@
GLOBAL_VALUE_ORIGIN AUTO
DEFAULT_VALUE 400
VARIABLE_SCOPE GLOBAL
@ -1184,7 +1193,7 @@
VARIABLE_COMMENT The number of cached table definitions
NUMERIC_MIN_VALUE 400
NUMERIC_MAX_VALUE 524288
@@ -4565,7 +4565,7 @@
@@ -4663,7 +4663,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 2000
VARIABLE_SCOPE GLOBAL
@ -1193,7 +1202,7 @@
VARIABLE_COMMENT The number of cached open tables
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 524288
@@ -4579,7 +4579,7 @@
@@ -4691,7 +4691,7 @@
GLOBAL_VALUE_ORIGIN AUTO
DEFAULT_VALUE 256
VARIABLE_SCOPE GLOBAL
@ -1202,7 +1211,7 @@
VARIABLE_COMMENT How many threads we should keep in a cache for reuse. These are freed after 5 minutes of idle time
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16384
@@ -4593,7 +4593,7 @@
@@ -4705,7 +4705,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@ -1211,7 +1220,7 @@
VARIABLE_COMMENT Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.This variable has no effect, and is deprecated. It will be removed in a future release.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 512
@@ -4778,7 +4778,7 @@
@@ -4918,7 +4918,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT If an internal in-memory temporary table exceeds this size, MySQL will automatically convert it to an on-disk MyISAM or Aria table
NUMERIC_MIN_VALUE 1024
@ -1220,7 +1229,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -4789,7 +4789,7 @@
@@ -4929,7 +4929,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8192
VARIABLE_SCOPE SESSION
@ -1229,7 +1238,7 @@
VARIABLE_COMMENT Allocation block size for transactions to be stored in binary log
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 134217728
@@ -4803,7 +4803,7 @@
@@ -4943,7 +4943,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE SESSION
@ -1238,7 +1247,7 @@
VARIABLE_COMMENT Persistent buffer for transactions to be stored in binary log
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 134217728
@@ -4901,7 +4901,7 @@
@@ -5041,7 +5041,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 28800
VARIABLE_SCOPE SESSION
@ -1247,7 +1256,7 @@
VARIABLE_COMMENT The number of seconds the server waits for activity on a connection before closing it
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 31536000
@@ -5089,7 +5089,7 @@
@@ -5145,7 +5145,7 @@
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME OPEN_FILES_LIMIT
VARIABLE_SCOPE GLOBAL
@ -1256,7 +1265,7 @@
VARIABLE_COMMENT If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of file descriptors
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
@@ -5102,7 +5102,7 @@
@@ -5158,7 +5158,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Sets the internal state of the RAND() generator for replication purposes
NUMERIC_MIN_VALUE 0
@ -1265,7 +1274,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -5112,7 +5112,7 @@
@@ -5168,7 +5168,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Sets the internal state of the RAND() generator for replication purposes
NUMERIC_MIN_VALUE 0
@ -1274,7 +1283,7 @@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -5197,7 +5197,7 @@
@@ -5253,7 +5253,7 @@
VARIABLE_NAME LOG_TC_SIZE
GLOBAL_VALUE_ORIGIN AUTO
VARIABLE_SCOPE GLOBAL

View file

@ -3439,6 +3439,20 @@ NUMERIC_BLOCK_SIZE 1024
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME READ_BINLOG_SPEED_LIMIT
SESSION_VALUE NULL
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum speed(KB/s) to read binlog from master (0 = no limit)
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 18446744073709551615
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME READ_BUFFER_SIZE
SESSION_VALUE 131072
GLOBAL_VALUE 131072

View file

@ -0,0 +1 @@
--loose-innodb_numa_interleave=1

View file

@ -0,0 +1,14 @@
--source include/have_innodb.inc
--source include/have_numa.inc
--source include/have_64bit.inc
SELECT @@GLOBAL.innodb_numa_interleave;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SET @@GLOBAL.innodb_numa_interleave=off;
SELECT @@GLOBAL.innodb_numa_interleave;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT @@SESSION.innodb_numa_interleave;

View file

@ -0,0 +1,54 @@
select json_valid('[1, 2]');
select json_valid('"string"}');
select json_valid('{"key1":1, "key2":[2,3]}');
select json_valid('[false, true, null]');
select json_value('{"key1":123}', '$.key2');
select json_value('{"key1":123}', '$.key1');
select json_value('{"key1":[1,2,3]}', '$.key1');
select json_value('{"key1": [1,2,3], "key1":123}', '$.key1');
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2');
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');
select json_query('{"key1": 1}', '$.key1');
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
select json_array(1);
select json_array(1, "text", false, null);
select json_array_append('["a", "b"]', '$', FALSE);
select json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2);
select json_contains('{"k1":123, "k2":345}', '123', '$.k1');
select json_contains('"you"', '"you"');
select json_contains('"youth"', '"you"');
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]");
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.ma");
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1");
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1", "$.ma");
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.ma");
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.key2");
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1");
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY");
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2");
select json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2");
select json_extract('{"key0":true, "key1":"qwe"}', "$.key1");
select json_object("ki", 1, "mi", "ya");
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2");
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]");
select json_quote('"string"');
select json_merge('string', 123);
select json_type('{"k1":123, "k2":345}');
select json_type('[123, "k2", 345]');
select json_type("true");
select json_type('123');

View file

@ -1451,3 +1451,123 @@ g codership/mysql-wsrep/issues#176
fun:start_thread
fun:clone
}
#
# MDEV-11061: OpenSSL 0.9.8 problems
#
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Cond
obj:*/libz.so*
...
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Value8
obj:*/libz.so*
...
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Cond
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Value8
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Cond
obj:*/libssl.so.0.9.8
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Value8
obj:*/libssl.so.0.9.8
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Cond
fun:memcpy
obj:*/libcrypto.so.0.9.8
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Value8
fun:memcpy
obj:*/libcrypto.so.0.9.8
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Cond
fun:is_overlap
fun:memcpy
obj:*/libcrypto.so.0.9.8
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Cond
fun:memset
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Value8
fun:memset
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}
{
MDEV-11061: OpenSSL 0.9.8
Memcheck:Param
write(buf)
obj:*/libpthread-2.9.so*
obj:*/libcrypto.so.0.9.8
...
obj:*/libssl.so.0.9.8
...
}

View file

@ -38,13 +38,13 @@
static char *heap_start;
#ifdef HAVE_BSS_START
#if(defined HAVE_BSS_START) && !(defined __linux__)
extern char *__bss_start;
#endif
void my_init_stacktrace()
{
#ifdef HAVE_BSS_START
#if(defined HAVE_BSS_START) && !(defined __linux__)
heap_start = (char*) &__bss_start;
#endif
}

View file

@ -569,16 +569,22 @@ err:
Error message is set.
@retval
*/
ulong
cli_safe_read(MYSQL *mysql)
{
ulong reallen = 0;
return cli_safe_read_reallen(mysql, &reallen);
}
ulong
cli_safe_read_reallen(MYSQL *mysql, ulong* reallen)
{
NET *net= &mysql->net;
ulong len=0;
restart:
if (net->vio != 0)
len= my_net_read_packet(net, 0);
len= my_net_read_packet_reallen(net, 0, reallen);
if (len == packet_error || len == 0)
{

View file

@ -136,7 +136,7 @@ SET (SQL_SOURCE
opt_table_elimination.cc sql_expression_cache.cc
gcalc_slicescan.cc gcalc_tools.cc
threadpool_common.cc ../sql-common/mysql_async.c
my_apc.cc my_apc.h mf_iocache_encr.cc
my_apc.cc my_apc.h mf_iocache_encr.cc item_jsonfunc.cc
my_json_writer.cc my_json_writer.h
rpl_gtid.cc rpl_parallel.cc
sql_type.cc sql_type.h

View file

@ -2900,6 +2900,14 @@ void Item_int::print(String *str, enum_query_type query_type)
}
Item *Item_bool::neg_transformer(THD *thd)
{
value= !value;
name= 0;
return this;
}
Item_uint::Item_uint(THD *thd, const char *str_arg, uint length):
Item_int(thd, str_arg, length)
{

View file

@ -2997,6 +2997,21 @@ public:
};
/*
We sometimes need to distinguish a number from a boolean:
a[1] and a[true] are different things in XPath.
Also in JSON boolean values should be treated differently.
*/
class Item_bool :public Item_int
{
public:
Item_bool(THD *thd, const char *str_arg, longlong i):
Item_int(thd, str_arg, i, 1) {}
bool is_bool_type() { return true; }
Item *neg_transformer(THD *thd);
};
class Item_uint :public Item_int
{
public:
@ -4750,6 +4765,7 @@ public:
#include "item_timefunc.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
#include "item_jsonfunc.h"
#include "item_create.h"
#endif

View file

@ -1708,6 +1708,201 @@ protected:
#endif
class Create_func_json_exists : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_json_exists s_singleton;
protected:
Create_func_json_exists() {}
virtual ~Create_func_json_exists() {}
};
class Create_func_json_valid : public Create_func_arg1
{
public:
virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_json_valid s_singleton;
protected:
Create_func_json_valid() {}
virtual ~Create_func_json_valid() {}
};
class Create_func_json_type : public Create_func_arg1
{
public:
virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_json_type s_singleton;
protected:
Create_func_json_type() {}
virtual ~Create_func_json_type() {}
};
class Create_func_json_depth : public Create_func_arg1
{
public:
virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_json_depth s_singleton;
protected:
Create_func_json_depth() {}
virtual ~Create_func_json_depth() {}
};
class Create_func_json_value : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_json_value s_singleton;
protected:
Create_func_json_value() {}
virtual ~Create_func_json_value() {}
};
class Create_func_json_query : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_json_query s_singleton;
protected:
Create_func_json_query() {}
virtual ~Create_func_json_query() {}
};
class Create_func_json_contains: public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_contains s_singleton;
protected:
Create_func_json_contains() {}
virtual ~Create_func_json_contains() {}
};
class Create_func_json_contains_path : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_contains_path s_singleton;
protected:
Create_func_json_contains_path() {}
virtual ~Create_func_json_contains_path() {}
};
class Create_func_json_extract : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_extract s_singleton;
protected:
Create_func_json_extract() {}
virtual ~Create_func_json_extract() {}
};
class Create_func_json_array : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_array s_singleton;
protected:
Create_func_json_array() {}
virtual ~Create_func_json_array() {}
};
class Create_func_json_array_append : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_array_append s_singleton;
protected:
Create_func_json_array_append() {}
virtual ~Create_func_json_array_append() {}
};
class Create_func_json_object : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_object s_singleton;
protected:
Create_func_json_object() {}
virtual ~Create_func_json_object() {}
};
class Create_func_json_length : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_length s_singleton;
protected:
Create_func_json_length() {}
virtual ~Create_func_json_length() {}
};
class Create_func_json_merge : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_json_merge s_singleton;
protected:
Create_func_json_merge() {}
virtual ~Create_func_json_merge() {}
};
class Create_func_json_quote : public Create_func_arg1
{
public:
virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_json_quote s_singleton;
protected:
Create_func_json_quote() {}
virtual ~Create_func_json_quote() {}
};
class Create_func_last_day : public Create_func_arg1
{
public:
@ -4572,6 +4767,69 @@ Create_func_issimple::create_1_arg(THD *thd, Item *arg1)
#endif
Create_func_json_exists Create_func_json_exists::s_singleton;
Item*
Create_func_json_exists::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_json_exists(thd, arg1, arg2);
}
Create_func_json_valid Create_func_json_valid::s_singleton;
Item*
Create_func_json_valid::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_json_valid(thd, arg1);
}
Create_func_json_type Create_func_json_type::s_singleton;
Item*
Create_func_json_type::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_json_type(thd, arg1);
}
Create_func_json_depth Create_func_json_depth::s_singleton;
Item*
Create_func_json_depth::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_json_depth(thd, arg1);
}
Create_func_json_value Create_func_json_value::s_singleton;
Item*
Create_func_json_value::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_json_value(thd, arg1, arg2);
}
Create_func_json_query Create_func_json_query::s_singleton;
Item*
Create_func_json_query::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_json_query(thd, arg1, arg2);
}
Create_func_json_quote Create_func_json_quote::s_singleton;
Item*
Create_func_json_quote::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_json_quote(thd, arg1);
}
Create_func_last_day Create_func_last_day::s_singleton;
Item*
@ -4581,6 +4839,207 @@ Create_func_last_day::create_1_arg(THD *thd, Item *arg1)
}
Create_func_json_array Create_func_json_array::s_singleton;
Item*
Create_func_json_array::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func;
if (item_list != NULL)
{
func= new (thd->mem_root) Item_func_json_array(thd, *item_list);
}
else
{
func= new (thd->mem_root) Item_func_json_array(thd);
}
return func;
}
Create_func_json_array_append Create_func_json_array_append::s_singleton;
Item*
Create_func_json_array_append::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0;
if (item_list != NULL)
arg_count= item_list->elements;
if (arg_count < 3 || (arg_count & 1) == 0 /*is even*/)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
}
else
{
func= new (thd->mem_root) Item_func_json_array_append(thd, *item_list);
}
return func;
}
Create_func_json_object Create_func_json_object::s_singleton;
Item*
Create_func_json_object::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func;
int arg_count;
if (item_list != NULL)
{
arg_count= item_list->elements;
if ((arg_count & 1) != 0 /*is odd*/)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
func= NULL;
}
else
{
func= new (thd->mem_root) Item_func_json_object(thd, *item_list);
}
}
else
{
arg_count= 0;
func= new (thd->mem_root) Item_func_json_object(thd);
}
return func;
}
Create_func_json_length Create_func_json_length::s_singleton;
Item*
Create_func_json_length::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func;
int arg_count;
if (item_list == NULL ||
(arg_count= item_list->elements) == 0)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
func= NULL;
}
else
{
func= new (thd->mem_root) Item_func_json_length(thd, *item_list);
}
return func;
}
Create_func_json_merge Create_func_json_merge::s_singleton;
Item*
Create_func_json_merge::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func;
int arg_count;
if (item_list == NULL ||
(arg_count= item_list->elements) == 0)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
func= NULL;
}
else
{
func= new (thd->mem_root) Item_func_json_merge(thd, *item_list);
}
return func;
}
Create_func_json_contains Create_func_json_contains::s_singleton;
Item*
Create_func_json_contains::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0;
if (item_list != NULL)
arg_count= item_list->elements;
if (arg_count < 2 /* json_doc, val, [path]...*/)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
}
else
{
func= new (thd->mem_root) Item_func_json_contains(thd, *item_list);
}
return func;
}
Create_func_json_contains_path Create_func_json_contains_path::s_singleton;
Item*
Create_func_json_contains_path::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0;
if (item_list != NULL)
arg_count= item_list->elements;
if (arg_count < 3 /* json_doc, one_or_all, path, [path]...*/)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
}
else
{
func= new (thd->mem_root) Item_func_json_contains_path(thd, *item_list);
}
return func;
}
Create_func_json_extract Create_func_json_extract::s_singleton;
Item*
Create_func_json_extract::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0;
if (item_list != NULL)
arg_count= item_list->elements;
if (arg_count < 2 /* json_doc, path, [path]...*/)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
}
else
{
func= new (thd->mem_root) Item_func_json_extract(thd, *item_list);
}
return func;
}
Create_func_last_insert_id Create_func_last_insert_id::s_singleton;
Item*
@ -5852,6 +6311,21 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { C_STRING_WITH_LEN("IS_FREE_LOCK") }, BUILDER(Create_func_is_free_lock)},
{ { C_STRING_WITH_LEN("IS_USED_LOCK") }, BUILDER(Create_func_is_used_lock)},
{ { C_STRING_WITH_LEN("JSON_ARRAY") }, BUILDER(Create_func_json_array)},
{ { C_STRING_WITH_LEN("JSON_ARRAY_APPEND") }, BUILDER(Create_func_json_array_append)},
{ { C_STRING_WITH_LEN("JSON_CONTAINS") }, BUILDER(Create_func_json_contains)},
{ { C_STRING_WITH_LEN("JSON_CONTAINS_PATH") }, BUILDER(Create_func_json_contains_path)},
{ { C_STRING_WITH_LEN("JSON_DEPTH") }, BUILDER(Create_func_json_depth)},
{ { C_STRING_WITH_LEN("JSON_EXISTS") }, BUILDER(Create_func_json_exists)},
{ { C_STRING_WITH_LEN("JSON_EXTRACT") }, BUILDER(Create_func_json_extract)},
{ { C_STRING_WITH_LEN("JSON_LENGTH") }, BUILDER(Create_func_json_length)},
{ { C_STRING_WITH_LEN("JSON_MERGE") }, BUILDER(Create_func_json_merge)},
{ { C_STRING_WITH_LEN("JSON_QUERY") }, BUILDER(Create_func_json_query)},
{ { C_STRING_WITH_LEN("JSON_QUOTE") }, BUILDER(Create_func_json_quote)},
{ { C_STRING_WITH_LEN("JSON_OBJECT") }, BUILDER(Create_func_json_object)},
{ { C_STRING_WITH_LEN("JSON_TYPE") }, BUILDER(Create_func_json_type)},
{ { C_STRING_WITH_LEN("JSON_VALID") }, BUILDER(Create_func_json_valid)},
{ { C_STRING_WITH_LEN("JSON_VALUE") }, BUILDER(Create_func_json_value)},
{ { C_STRING_WITH_LEN("LAST_DAY") }, BUILDER(Create_func_last_day)},
{ { C_STRING_WITH_LEN("LAST_INSERT_ID") }, BUILDER(Create_func_last_insert_id)},
{ { C_STRING_WITH_LEN("LCASE") }, BUILDER(Create_func_lcase)},

1109
sql/item_jsonfunc.cc Normal file

File diff suppressed because it is too large Load diff

304
sql/item_jsonfunc.h Normal file
View file

@ -0,0 +1,304 @@
#ifndef ITEM_JSONFUNC_INCLUDED
#define ITEM_JSONFUNC_INCLUDED
/* Copyright (c) 2016, MariaDB
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 St, Fifth Floor, Boston, MA 02110-1301 USA */
/* This file defines all JSON functions */
#include <json_lib.h>
#include "item_cmpfunc.h" // Item_bool_func
#include "item_strfunc.h" // Item_str_func
class json_path_with_flags
{
public:
json_path_t p;
bool constant;
bool parsed;
json_path_step_t *cur_step;
void set_constant_flag(bool s_constant)
{
constant= s_constant;
parsed= FALSE;
}
};
class Item_func_json_valid: public Item_int_func
{
protected:
String tmp_value;
public:
Item_func_json_valid(THD *thd, Item *json) : Item_int_func(thd, json) {}
longlong val_int();
const char *func_name() const { return "json_valid"; }
void fix_length_and_dec()
{
Item_int_func::fix_length_and_dec();
maybe_null= 1;
}
bool is_bool_type() { return true; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_valid>(thd, mem_root, this); }
};
class Item_func_json_exists: public Item_int_func
{
protected:
json_path_with_flags path;
String tmp_js, tmp_path;
public:
Item_func_json_exists(THD *thd, Item *js, Item *path):
Item_int_func(thd, js, path) {}
const char *func_name() const { return "json_exists"; }
bool is_bool_type() { return true; }
void fix_length_and_dec();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_exists>(thd, mem_root, this); }
longlong val_int();
};
class Item_func_json_value: public Item_str_func
{
protected:
json_path_with_flags path;
String tmp_js, tmp_path;
public:
Item_func_json_value(THD *thd, Item *js, Item *path):
Item_str_func(thd, js, path) {}
const char *func_name() const { return "json_value"; }
void fix_length_and_dec();
String *val_str(String *);
virtual bool check_and_get_value(json_engine_t *je, String *res, int *error);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_value>(thd, mem_root, this); }
};
class Item_func_json_query: public Item_func_json_value
{
public:
Item_func_json_query(THD *thd, Item *js, Item *path):
Item_func_json_value(thd, js, path) {}
const char *func_name() const { return "json_query"; }
bool check_and_get_value(json_engine_t *je, String *res, int *error);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_query>(thd, mem_root, this); }
};
class Item_func_json_quote: public Item_str_func
{
protected:
String tmp_s;
public:
Item_func_json_quote(THD *thd, Item *s): Item_str_func(thd, s) {}
const char *func_name() const { return "json_quote"; }
void fix_length_and_dec();
String *val_str(String *);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_quote>(thd, mem_root, this); }
};
class Item_json_str_multipath: public Item_str_func
{
protected:
json_path_with_flags *paths;
String *tmp_paths;
public:
Item_json_str_multipath(THD *thd, List<Item> &list):
Item_str_func(thd, list), tmp_paths(0) {}
bool fix_fields(THD *thd, Item **ref);
void cleanup();
virtual uint get_n_paths() const = 0;
};
class Item_func_json_extract: public Item_json_str_multipath
{
protected:
String tmp_js;
public:
Item_func_json_extract(THD *thd, List<Item> &list):
Item_json_str_multipath(thd, list) {}
const char *func_name() const { return "json_extract"; }
void fix_length_and_dec();
String *val_str(String *);
longlong val_int();
uint get_n_paths() const { return arg_count - 1; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_extract>(thd, mem_root, this); }
};
class Item_func_json_contains: public Item_int_func
{
protected:
String tmp_js;
json_path_with_flags *paths;
String *tmp_paths;
bool a2_constant, a2_parsed;
String tmp_val, *val;
public:
Item_func_json_contains(THD *thd, List<Item> &list):
Item_int_func(thd, list), tmp_paths(0) {}
const char *func_name() const { return "json_contains"; }
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
void cleanup();
longlong val_int();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_contains>(thd, mem_root, this); }
};
class Item_func_json_contains_path: public Item_int_func
{
protected:
String tmp_js;
json_path_with_flags *paths;
String *tmp_paths;
bool mode_one;
bool ooa_constant, ooa_parsed;
public:
Item_func_json_contains_path(THD *thd, List<Item> &list):
Item_int_func(thd, list), tmp_paths(0) {}
const char *func_name() const { return "json_contains_path"; }
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
void cleanup();
longlong val_int();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_contains_path>(thd, mem_root, this); }
};
class Item_func_json_array: public Item_str_func
{
protected:
String tmp_val;
public:
Item_func_json_array(THD *thd):
Item_str_func(thd) {}
Item_func_json_array(THD *thd, List<Item> &list):
Item_str_func(thd, list) {}
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "json_array"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_array>(thd, mem_root, this); }
};
class Item_func_json_array_append: public Item_json_str_multipath
{
protected:
String tmp_js;
String tmp_val;
public:
Item_func_json_array_append(THD *thd, List<Item> &list):
Item_json_str_multipath(thd, list) {}
void fix_length_and_dec();
String *val_str(String *);
uint get_n_paths() const { return arg_count/2; }
const char *func_name() const { return "json_array_append"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_array_append>(thd, mem_root, this); }
};
class Item_func_json_object: public Item_func_json_array
{
public:
Item_func_json_object(THD *thd):
Item_func_json_array(thd) {}
Item_func_json_object(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {}
String *val_str(String *);
const char *func_name() const { return "json_object"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_object>(thd, mem_root, this); }
};
class Item_func_json_merge: public Item_func_json_array
{
protected:
String tmp_val;
public:
Item_func_json_merge(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {}
String *val_str(String *);
const char *func_name() const { return "json_merge"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_merge>(thd, mem_root, this); }
};
class Item_func_json_length: public Item_int_func
{
protected:
String tmp_js;
String tmp_path;
public:
Item_func_json_length(THD *thd, List<Item> &list):
Item_int_func(thd, list) {}
const char *func_name() const { return "json_length"; }
longlong val_int();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_length>(thd, mem_root, this); }
};
class Item_func_json_depth: public Item_int_func
{
protected:
String tmp_js;
public:
Item_func_json_depth(THD *thd, Item *js): Item_int_func(thd, js) {}
const char *func_name() const { return "json_depth"; }
longlong val_int();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_depth>(thd, mem_root, this); }
};
class Item_func_json_type: public Item_str_func
{
protected:
String tmp_js;
public:
Item_func_json_type(THD *thd, Item *js): Item_str_func(thd, js) {}
const char *func_name() const { return "json_type"; }
void fix_length_and_dec();
String *val_str(String *);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_type>(thd, mem_root, this); }
};
#endif /* ITEM_JSONFUNC_INCLUDED */

View file

@ -13,10 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include <my_global.h>
#include "sql_priv.h"
/*
@ -406,19 +402,6 @@ public:
};
/*
We need to distinguish a number from a boolean:
a[1] and a[true] are different things in XPath.
*/
class Item_bool :public Item_int
{
public:
Item_bool(THD *thd, int32 i): Item_int(thd, i) {}
const char *func_name() const { return "xpath_bool"; }
bool is_bool_type() { return true; }
};
/*
Converts its argument into a boolean value.
* a number is true if it is non-zero
@ -1214,13 +1197,13 @@ my_xpath_keyword(MY_XPATH *x,
static Item *create_func_true(MY_XPATH *xpath, Item **args, uint nargs)
{
return new (xpath->thd->mem_root) Item_bool(xpath->thd, 1);
return new (xpath->thd->mem_root) Item_bool(xpath->thd, "xpath_bool", 1);
}
static Item *create_func_false(MY_XPATH *xpath, Item **args, uint nargs)
{
return new (xpath->thd->mem_root) Item_bool(xpath->thd, 0);
return new (xpath->thd->mem_root) Item_bool(xpath->thd, "xpath_bool", 0);
}

View file

@ -21,11 +21,6 @@
/* This file defines all XML functions */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
typedef struct my_xml_node_st MY_XML_NODE;

View file

@ -343,6 +343,7 @@ static SYMBOL symbols[] = {
{ "LOW_PRIORITY", SYM(LOW_PRIORITY)},
{ "MASTER", SYM(MASTER_SYM)},
{ "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM)},
{ "MASTER_DELAY", SYM(MASTER_DELAY_SYM)},
{ "MASTER_GTID_POS", SYM(MASTER_GTID_POS_SYM)},
{ "MASTER_HOST", SYM(MASTER_HOST_SYM)},
{ "MASTER_LOG_FILE", SYM(MASTER_LOG_FILE_SYM)},

View file

@ -4304,6 +4304,10 @@ void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
relay log.
IMPLEMENTATION
- You must hold rli->data_lock before calling this function, since
it writes group_relay_log_pos and similar fields of
Relay_log_info.
- Protects index file with LOCK_index
- Delete relevant relay log files
- Copy all file names after these ones to the front of the index file
@ -4317,7 +4321,7 @@ void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
read by the SQL slave thread are deleted).
@note
- This is only called from the slave-execute thread when it has read
- This is only called from the slave SQL thread when it has read
all commands from a relay log and want to switch to a new relay log.
- When this happens, we can be in an active transaction as
a transaction can span over two relay logs
@ -4348,6 +4352,8 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
DBUG_ASSERT(rli->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT);
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
mysql_mutex_assert_owner(&rli->data_lock);
mysql_mutex_lock(&LOCK_index);
ir= rli->inuse_relaylog_list;
@ -4406,7 +4412,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
}
/* Store where we are in the new file for the execution thread */
flush_relay_log_info(rli);
rli->flush();
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););

View file

@ -966,6 +966,7 @@ int Log_event::do_update_pos(rpl_group_info *rgi)
Relay_log_info *rli= rgi->rli;
DBUG_ENTER("Log_event::do_update_pos");
DBUG_ASSERT(!rli->belongs_to_client());
/*
rli is null when (as far as I (Guilhem) know) the caller is
Load_log_event::do_apply_event *and* that one is called from
@ -6403,6 +6404,9 @@ bool Rotate_log_event::write()
in a A -> B -> A setup.
The NOTES below is a wrong comment which will disappear when 4.1 is merged.
This must only be called from the Slave SQL thread, since it calls
Relay_log_info::flush().
@retval
0 ok
*/
@ -6456,7 +6460,7 @@ int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
(ulong) rli->group_master_log_pos));
mysql_mutex_unlock(&rli->data_lock);
rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
flush_relay_log_info(rli);
rli->flush();
/*
Reset thd->variables.option_bits and sql_mode etc, because this could
@ -8225,6 +8229,9 @@ void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
were we must do this cleaning is in
Start_log_event_v3::do_apply_event(), not here. Because if we come
here, the master was sane.
This must only be called from the Slave SQL thread, since it calls
Relay_log_info::flush().
*/
int Stop_log_event::do_update_pos(rpl_group_info *rgi)
@ -8244,7 +8251,7 @@ int Stop_log_event::do_update_pos(rpl_group_info *rgi)
{
rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
rli->inc_group_relay_log_pos(0, rgi);
flush_relay_log_info(rli);
rli->flush();
}
DBUG_RETURN(0);
}

View file

@ -1133,15 +1133,22 @@ ulong my_net_read(NET *net)
The function returns the length of the found packet or packet_error.
net->read_pos points to the read data.
*/
ulong
my_net_read_packet(NET *net, my_bool read_from_server)
{
ulong reallen = 0;
return my_net_read_packet_reallen(net, read_from_server, &reallen);
}
ulong
my_net_read_packet(NET *net, my_bool read_from_server)
my_net_read_packet_reallen(NET *net, my_bool read_from_server, ulong* reallen)
{
size_t len, complen;
MYSQL_NET_READ_START();
*reallen = 0;
#ifdef HAVE_COMPRESS
if (!net->compress)
{
@ -1164,7 +1171,10 @@ my_net_read_packet(NET *net, my_bool read_from_server)
}
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
{
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
*reallen = len;
}
MYSQL_NET_READ_DONE(0, len);
return len;
#ifdef HAVE_COMPRESS
@ -1265,6 +1275,7 @@ my_net_read_packet(NET *net, my_bool read_from_server)
return packet_error;
}
buf_length+= complen;
*reallen += packet_len;
}
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;

View file

@ -18,7 +18,7 @@
#include "sql_priv.h"
#include <my_dir.h>
#include "rpl_mi.h"
#include "slave.h" // SLAVE_MAX_HEARTBEAT_PERIOD
#include "slave.h"
#include "strfunc.h"
#include "sql_repl.h"
@ -647,7 +647,7 @@ file '%s')", fname);
(ulong) mi->master_log_pos));
mi->rli.mi= mi;
if (init_relay_log_info(&mi->rli, slave_info_fname))
if (mi->rli.init(slave_info_fname))
goto err;
mi->inited = 1;

View file

@ -47,9 +47,7 @@ rpt_handle_event(rpl_parallel_thread::queued_event *qev,
if (!(ev->is_artificial_event() || ev->is_relay_log_event() ||
(ev->when == 0)))
rgi->last_master_timestamp= ev->when + (time_t)ev->exec_time;
mysql_mutex_lock(&rli->data_lock);
/* Mutex will be released in apply_event_and_update_pos(). */
err= apply_event_and_update_pos(ev, thd, rgi, rpt);
err= apply_event_and_update_pos_for_parallel(ev, thd, rgi);
thread_safe_increment64(&rli->executed_entries);
/* ToDo: error handling. */
@ -2426,8 +2424,17 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
!(unlikely(rli->gtid_skip_flag != GTID_SKIP_NOT) && is_group_event))
return -1;
/* ToDo: what to do with this lock?!? */
mysql_mutex_unlock(&rli->data_lock);
/* Note: rli->data_lock is released by sql_delay_event(). */
if (sql_delay_event(ev, rli->sql_driver_thd, serial_rgi))
{
/*
If sql_delay_event() returns non-zero, it means that the wait timed out
due to slave stop. We should not queue the event in this case, it must
not be applied yet.
*/
delete ev;
return 1;
}
if (unlikely(typ == FORMAT_DESCRIPTION_EVENT))
{

View file

@ -29,6 +29,7 @@
#include "rpl_utility.h"
#include "transaction.h"
#include "sql_parse.h" // end_trans, ROLLBACK
#include "slave.h"
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
@ -42,30 +43,24 @@ rpl_slave_state *rpl_global_gtid_slave_state;
/* Object used for MASTER_GTID_WAIT(). */
gtid_waiting rpl_global_gtid_waiting;
// Defined in slave.cc
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
const char *const Relay_log_info::state_delaying_string = "Waiting until MASTER_DELAY seconds after master executed event";
Relay_log_info::Relay_log_info(bool is_slave_recovery)
:Slave_reporting_capability("SQL"),
no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
replicate_same_server_id(::replicate_same_server_id),
info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period),
sync_counter(0), is_relay_log_recovery(is_slave_recovery),
save_temporary_tables(0),
mi(0), inuse_relaylog_list(0), last_inuse_relaylog(0),
cur_log_old_open_count(0), group_relay_log_pos(0),
event_relay_log_pos(0),
#if HAVE_valgrind
is_fake(FALSE),
#endif
group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0),
last_master_timestamp(0), sql_thread_caught_up(true), slave_skip_counter(0),
abort_pos_wait(0), slave_run_id(0), sql_driver_thd(),
gtid_skip_flag(GTID_SKIP_NOT), inited(0), abort_slave(0), stop_for_until(0),
slave_running(MYSQL_SLAVE_NOT_RUN), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0), executed_entries(0),
sql_delay(0), sql_delay_end(0),
m_flags(0)
{
DBUG_ENTER("Relay_log_info::Relay_log_info");
@ -117,39 +112,42 @@ Relay_log_info::~Relay_log_info()
}
int init_relay_log_info(Relay_log_info* rli,
const char* info_fname)
/**
Read the relay_log.info file.
@param info_fname The name of the file to read from.
@retval 0 success
@retval 1 failure
*/
int Relay_log_info::init(const char* info_fname)
{
char fname[FN_REFLEN+128];
int info_fd;
const char* msg = 0;
int error = 0;
DBUG_ENTER("init_relay_log_info");
DBUG_ASSERT(!rli->no_storage); // Don't init if there is no storage
DBUG_ENTER("Relay_log_info::init");
if (rli->inited) // Set if this function called
if (inited) // Set if this function called
DBUG_RETURN(0);
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
mysql_mutex_lock(&rli->data_lock);
info_fd = rli->info_fd;
rli->cur_log_fd = -1;
rli->slave_skip_counter=0;
rli->abort_pos_wait=0;
rli->log_space_limit= relay_log_space_limit;
rli->log_space_total= 0;
mysql_mutex_lock(&data_lock);
cur_log_fd = -1;
slave_skip_counter=0;
abort_pos_wait=0;
log_space_limit= relay_log_space_limit;
log_space_total= 0;
char pattern[FN_REFLEN];
(void) my_realpath(pattern, slave_load_tmpdir, 0);
if (fn_format(pattern, PREFIX_SQL_LOAD, pattern, "",
MY_SAFE_PATH | MY_RETURN_REAL_PATH) == NullS)
{
mysql_mutex_unlock(&rli->data_lock);
mysql_mutex_unlock(&data_lock);
sql_print_error("Unable to use slave's temporary directory %s",
slave_load_tmpdir);
DBUG_RETURN(1);
}
unpack_filename(rli->slave_patternload_file, pattern);
rli->slave_patternload_file_size= strlen(rli->slave_patternload_file);
unpack_filename(slave_patternload_file, pattern);
slave_patternload_file_size= strlen(slave_patternload_file);
/*
The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
@ -163,7 +161,7 @@ int init_relay_log_info(Relay_log_info* rli,
if (opt_relay_logname &&
opt_relay_logname[strlen(opt_relay_logname) - 1] == FN_LIBCHAR)
{
mysql_mutex_unlock(&rli->data_lock);
mysql_mutex_unlock(&data_lock);
sql_print_error("Path '%s' is a directory name, please specify \
a file name for --relay-log option", opt_relay_logname);
DBUG_RETURN(1);
@ -175,7 +173,7 @@ a file name for --relay-log option", opt_relay_logname);
opt_relaylog_index_name[strlen(opt_relaylog_index_name) - 1]
== FN_LIBCHAR)
{
mysql_mutex_unlock(&rli->data_lock);
mysql_mutex_unlock(&data_lock);
sql_print_error("Path '%s' is a directory name, please specify \
a file name for --relay-log-index option", opt_relaylog_index_name);
DBUG_RETURN(1);
@ -184,7 +182,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
char buf[FN_REFLEN];
const char *ln;
static bool name_warning_sent= 0;
ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
ln= relay_log.generate_name(opt_relay_logname, "-relay-bin",
1, buf);
/* We send the warning only at startup, not after every RESET SLAVE */
if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent &&
@ -207,7 +205,6 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
}
/* For multimaster, add connection name to relay log filenames */
Master_info* mi= rli->mi;
char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN];
char *buf_relaylog_index_name= opt_relaylog_index_name;
@ -229,12 +226,12 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
*/
if (rli->relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) ||
rli->relay_log.open(ln, LOG_BIN, 0, 0, SEQ_READ_APPEND,
mi->rli.max_relay_log_size, 1, TRUE))
if (relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) ||
relay_log.open(ln, LOG_BIN, 0, 0, SEQ_READ_APPEND,
max_relay_log_size, 1, TRUE))
{
mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Failed when trying to open logs for '%s' in init_relay_log_info(). Error: %M", ln, my_errno);
mysql_mutex_unlock(&data_lock);
sql_print_error("Failed when trying to open logs for '%s' in Relay_log_info::init(). Error: %M", ln, my_errno);
DBUG_RETURN(1);
}
}
@ -256,7 +253,7 @@ file '%s', errno %d)", fname, my_errno);
msg= current_thd->get_stmt_da()->message();
goto err;
}
if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
MYF(MY_WME)))
{
sql_print_error("Failed to create a cache on relay log info file '%s'",
@ -266,20 +263,19 @@ file '%s', errno %d)", fname, my_errno);
}
/* Init relay log with first entry in the relay index file */
if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
if (init_relay_log_pos(this,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
&msg, 0))
{
sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
goto err;
}
rli->group_master_log_name[0]= 0;
rli->group_master_log_pos= 0;
rli->info_fd= info_fd;
group_master_log_name[0]= 0;
group_master_log_pos= 0;
}
else // file exists
{
if (info_fd >= 0)
reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
reinit_io_cache(&info_file, READ_CACHE, 0L,0,0);
else
{
int error=0;
@ -291,7 +287,7 @@ Failed to open the existing relay log info file '%s' (errno %d)",
fname, my_errno);
error= 1;
}
else if (init_io_cache(&rli->info_file, info_fd,
else if (init_io_cache(&info_file, info_fd,
IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
{
sql_print_error("Failed to create a cache on relay log info file '%s'",
@ -302,24 +298,15 @@ Failed to open the existing relay log info file '%s' (errno %d)",
{
if (info_fd >= 0)
mysql_file_close(info_fd, MYF(0));
rli->info_fd= -1;
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
mysql_mutex_unlock(&rli->data_lock);
info_fd= -1;
relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
mysql_mutex_unlock(&data_lock);
DBUG_RETURN(1);
}
}
rli->info_fd = info_fd;
int relay_log_pos, master_log_pos, lines;
char *first_non_digit;
/*
In MySQL 5.6, there is a MASTER_DELAY option to CHANGE MASTER. This is
not yet merged into MariaDB (as of 10.0.13). However, we detect the
presense of the new option in relay-log.info, as a placeholder for
possible later merge of the feature, and to maintain file format
compatibility with MySQL 5.6+.
*/
int dummy_sql_delay;
/*
Starting from MySQL 5.6.x, relay-log.info has a new format.
@ -344,25 +331,25 @@ Failed to open the existing relay log info file '%s' (errno %d)",
it is line count and not binlog name (new format) it will be
overwritten by the second row later.
*/
if (init_strvar_from_file(rli->group_relay_log_name,
sizeof(rli->group_relay_log_name),
&rli->info_file, ""))
if (init_strvar_from_file(group_relay_log_name,
sizeof(group_relay_log_name),
&info_file, ""))
{
msg="Error reading slave log configuration";
goto err;
}
lines= strtoul(rli->group_relay_log_name, &first_non_digit, 10);
lines= strtoul(group_relay_log_name, &first_non_digit, 10);
if (rli->group_relay_log_name[0] != '\0' &&
if (group_relay_log_name[0] != '\0' &&
*first_non_digit == '\0' &&
lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY)
{
DBUG_PRINT("info", ("relay_log_info file is in new format."));
/* Seems to be new format => read relay log name from next line */
if (init_strvar_from_file(rli->group_relay_log_name,
sizeof(rli->group_relay_log_name),
&rli->info_file, ""))
if (init_strvar_from_file(group_relay_log_name,
sizeof(group_relay_log_name),
&info_file, ""))
{
msg="Error reading slave log configuration";
goto err;
@ -372,70 +359,70 @@ Failed to open the existing relay log info file '%s' (errno %d)",
DBUG_PRINT("info", ("relay_log_info file is in old format."));
if (init_intvar_from_file(&relay_log_pos,
&rli->info_file, BIN_LOG_HEADER_SIZE) ||
init_strvar_from_file(rli->group_master_log_name,
sizeof(rli->group_master_log_name),
&rli->info_file, "") ||
init_intvar_from_file(&master_log_pos, &rli->info_file, 0) ||
&info_file, BIN_LOG_HEADER_SIZE) ||
init_strvar_from_file(group_master_log_name,
sizeof(group_master_log_name),
&info_file, "") ||
init_intvar_from_file(&master_log_pos, &info_file, 0) ||
(lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY &&
init_intvar_from_file(&dummy_sql_delay, &rli->info_file, 0)))
init_intvar_from_file(&sql_delay, &info_file, 0)))
{
msg="Error reading slave log configuration";
goto err;
}
strmake_buf(rli->event_relay_log_name,rli->group_relay_log_name);
rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
rli->group_master_log_pos= master_log_pos;
strmake_buf(event_relay_log_name,group_relay_log_name);
group_relay_log_pos= event_relay_log_pos= relay_log_pos;
group_master_log_pos= master_log_pos;
if (rli->is_relay_log_recovery && init_recovery(rli->mi, &msg))
if (is_relay_log_recovery && init_recovery(mi, &msg))
goto err;
rli->relay_log_state.load(rpl_global_gtid_slave_state);
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
relay_log_state.load(rpl_global_gtid_slave_state);
if (init_relay_log_pos(this,
group_relay_log_name,
group_relay_log_pos,
0 /* no data lock*/,
&msg, 0))
{
sql_print_error("Failed to open the relay log '%s' (relay_log_pos %llu)",
rli->group_relay_log_name, rli->group_relay_log_pos);
group_relay_log_name, group_relay_log_pos);
goto err;
}
}
DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%llu rli->event_relay_log_pos=%llu",
my_b_tell(rli->cur_log), rli->event_relay_log_pos));
DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
DBUG_PRINT("info", ("my_b_tell(cur_log)=%llu event_relay_log_pos=%llu",
my_b_tell(cur_log), event_relay_log_pos));
DBUG_ASSERT(event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(cur_log) == event_relay_log_pos);
/*
Now change the cache from READ to WRITE - must do this
before flush_relay_log_info
before Relay_log_info::flush()
*/
reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
if ((error= flush_relay_log_info(rli)))
reinit_io_cache(&info_file, WRITE_CACHE,0L,0,1);
if ((error= flush()))
{
msg= "Failed to flush relay log info file";
goto err;
}
if (count_relay_log_space(rli))
if (count_relay_log_space(this))
{
msg="Error counting relay log space";
goto err;
}
rli->inited= 1;
mysql_mutex_unlock(&rli->data_lock);
inited= 1;
mysql_mutex_unlock(&data_lock);
DBUG_RETURN(error);
err:
sql_print_error("%s", msg);
end_io_cache(&rli->info_file);
end_io_cache(&info_file);
if (info_fd >= 0)
mysql_file_close(info_fd, MYF(0));
rli->info_fd= -1;
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
mysql_mutex_unlock(&rli->data_lock);
info_fd= -1;
relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
mysql_mutex_unlock(&data_lock);
DBUG_RETURN(1);
}
@ -752,6 +739,8 @@ err:
if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg)
*errmsg= "Invalid Format_description log event; could be out of memory";
DBUG_PRINT("info", ("Returning %d from init_relay_log_pos", (*errmsg)?1:0));
DBUG_RETURN ((*errmsg) ? 1 : 0);
}
@ -969,8 +958,11 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
{
DBUG_ENTER("Relay_log_info::inc_group_relay_log_pos");
if (!skip_lock)
if (skip_lock)
mysql_mutex_assert_owner(&data_lock);
else
mysql_mutex_lock(&data_lock);
rgi->inc_event_relay_log_pos();
DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu",
(long) log_pos, (long) group_master_log_pos));
@ -1134,10 +1126,10 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
Indeed, rli->inited==0 does not imply that they already are empty.
It could be that slave's info initialization partly succeeded :
for example if relay-log.info existed but *relay-bin*.*
have been manually removed, init_relay_log_info reads the old
relay-log.info and fills rli->master_log_*, then init_relay_log_info
have been manually removed, Relay_log_info::init() reads the old
relay-log.info and fills rli->master_log_*, then Relay_log_info::init()
checks for the existence of the relay log, this fails and
init_relay_log_info leaves rli->inited to 0.
Relay_log_info::init() leaves rli->inited to 0.
In that pathological case, rli->master_log_pos* will be properly reinited
at the next START SLAVE (as RESET SLAVE or CHANGE
MASTER, the callers of purge_relay_logs, will delete bogus *.info files
@ -1325,6 +1317,7 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
{
DBUG_ENTER("Relay_log_info::stmt_done");
DBUG_ASSERT(!belongs_to_client());
DBUG_ASSERT(rgi->rli == this);
/*
If in a transaction, and if the slave supports transactions, just
@ -1374,7 +1367,7 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
}
DBUG_EXECUTE_IF("inject_crash_before_flush_rli", DBUG_SUICIDE(););
if (mi->using_gtid == Master_info::USE_GTID_NO)
flush_relay_log_info(this);
flush();
DBUG_EXECUTE_IF("inject_crash_after_flush_rli", DBUG_SUICIDE(););
}
DBUG_VOID_RETURN;
@ -2037,4 +2030,79 @@ bool rpl_sql_thread_info::cached_charset_compare(char *charset) const
DBUG_RETURN(0);
}
/**
Store the file and position where the slave's SQL thread are in the
relay log.
Notes:
- This function should be called either from the slave SQL thread,
or when the slave thread is not running. (It reads the
group_{relay|master}_log_{pos|name} and delay fields in the rli
object. These may only be modified by the slave SQL thread or by
a client thread when the slave SQL thread is not running.)
- If there is an active transaction, then we do not update the
position in the relay log. This is to ensure that we re-execute
statements if we die in the middle of an transaction that was
rolled back.
- As a transaction never spans binary logs, we don't have to handle
the case where we do a relay-log-rotation in the middle of the
transaction. If transactions could span several binlogs, we would
have to ensure that we do not delete the relay log file where the
transaction started before switching to a new relay log file.
- Error can happen if writing to file fails or if flushing the file
fails.
@param rli The object representing the Relay_log_info.
@todo Change the log file information to a binary format to avoid
calling longlong2str.
@return 0 on success, 1 on error.
*/
bool Relay_log_info::flush()
{
bool error=0;
DBUG_ENTER("Relay_log_info::flush()");
IO_CACHE *file = &info_file;
// 2*file name, 2*long long, 2*unsigned long, 6*'\n'
char buff[FN_REFLEN * 2 + 22 * 2 + 10 * 2 + 6], *pos;
my_b_seek(file, 0L);
pos= longlong10_to_str(LINES_IN_RELAY_LOG_INFO_WITH_DELAY, buff, 10);
*pos++='\n';
pos=strmov(pos, group_relay_log_name);
*pos++='\n';
pos=longlong10_to_str(group_relay_log_pos, pos, 10);
*pos++='\n';
pos=strmov(pos, group_master_log_name);
*pos++='\n';
pos=longlong10_to_str(group_master_log_pos, pos, 10);
*pos++='\n';
pos= longlong10_to_str(sql_delay, pos, 10);
*pos++= '\n';
if (my_b_write(file, (uchar*) buff, (size_t) (pos-buff)))
error=1;
if (flush_io_cache(file))
error=1;
if (sync_relayloginfo_period &&
!error &&
++sync_counter >= sync_relayloginfo_period)
{
if (my_sync(info_fd, MYF(MY_WME)))
error=1;
sync_counter= 0;
}
/*
Flushing the relay log is done by the slave I/O thread
or by the user on STOP SLAVE.
*/
DBUG_RETURN(error);
}
#endif

View file

@ -29,11 +29,6 @@ class Master_info;
class Rpl_filter;
enum {
LINES_IN_RELAY_LOG_INFO_WITH_DELAY= 5
};
/****************************************************************************
Replication SQL Thread
@ -47,7 +42,7 @@ enum {
Relay_log_info is initialized from the slave.info file if such
exists. Otherwise, data members are intialized with defaults. The
initialization is done with init_relay_log_info() call.
initialization is done with Relay_log_info::init() call.
The format of slave.info file:
@ -78,11 +73,17 @@ public:
};
/*
If flag set, then rli does not store its state in any info file.
This is the case only when we execute BINLOG SQL commands inside
a client, non-replication thread.
The SQL thread owns one Relay_log_info, and each client that has
executed a BINLOG statement owns one Relay_log_info. This function
returns zero for the Relay_log_info object that belongs to the SQL
thread and nonzero for Relay_log_info objects that belong to
clients.
*/
bool no_storage;
inline bool belongs_to_client()
{
DBUG_ASSERT(sql_driver_thd);
return !sql_driver_thd->slave_thread;
}
/*
If true, events with the same server id should be replicated. This
@ -194,6 +195,11 @@ public:
relay log and finishing (commiting) on another relay log. Case which can
happen when, for example, the relay log gets rotated because of
max_binlog_size.
Note: group_relay_log_name, group_relay_log_pos must only be
written from the thread owning the Relay_log_info (SQL thread if
!belongs_to_client(); client thread executing BINLOG statement if
belongs_to_client()).
*/
char group_relay_log_name[FN_REFLEN];
ulonglong group_relay_log_pos;
@ -205,16 +211,17 @@ public:
*/
char future_event_master_log_name[FN_REFLEN];
#ifdef HAVE_valgrind
bool is_fake; /* Mark that this is a fake relay log info structure */
#endif
/*
Original log name and position of the group we're currently executing
(whose coordinates are group_relay_log_name/pos in the relay log)
in the master's binlog. These concern the *group*, because in the master's
binlog the log_pos that comes with each event is the position of the
beginning of the group.
Note: group_master_log_name, group_master_log_pos must only be
written from the thread owning the Relay_log_info (SQL thread if
!belongs_to_client(); client thread executing BINLOG statement if
belongs_to_client()).
*/
char group_master_log_name[FN_REFLEN];
volatile my_off_t group_master_log_pos;
@ -244,6 +251,15 @@ public:
bool sql_thread_caught_up;
void clear_until_condition();
/**
Reset the delay.
This is used by RESET SLAVE to clear the delay.
*/
void clear_sql_delay()
{
sql_delay= 0;
}
/*
Needed for problems when slave stops and we want to restart it
@ -475,8 +491,72 @@ public:
m_flags&= ~flag;
}
/**
Text used in THD::proc_info when the slave SQL thread is delaying.
*/
static const char *const state_delaying_string;
bool flush();
/**
Reads the relay_log.info file.
*/
int init(const char* info_filename);
/**
Indicate that a delay starts.
This does not actually sleep; it only sets the state of this
Relay_log_info object to delaying so that the correct state can be
reported by SHOW SLAVE STATUS and SHOW PROCESSLIST.
Requires rli->data_lock.
@param delay_end The time when the delay shall end.
*/
void start_sql_delay(time_t delay_end)
{
mysql_mutex_assert_owner(&data_lock);
sql_delay_end= delay_end;
thd_proc_info(sql_driver_thd, state_delaying_string);
}
int32 get_sql_delay() { return sql_delay; }
void set_sql_delay(time_t _sql_delay) { sql_delay= _sql_delay; }
time_t get_sql_delay_end() { return sql_delay_end; }
private:
/**
Delay slave SQL thread by this amount, compared to master (in
seconds). This is set with CHANGE MASTER TO MASTER_DELAY=X.
Guarded by data_lock. Initialized by the client thread executing
START SLAVE. Written by client threads executing CHANGE MASTER TO
MASTER_DELAY=X. Read by SQL thread and by client threads
executing SHOW SLAVE STATUS. Note: must not be written while the
slave SQL thread is running, since the SQL thread reads it without
a lock when executing Relay_log_info::flush().
*/
int sql_delay;
/**
During a delay, specifies the point in time when the delay ends.
This is used for the SQL_Remaining_Delay column in SHOW SLAVE STATUS.
Guarded by data_lock. Written by the sql thread. Read by client
threads executing SHOW SLAVE STATUS.
*/
time_t sql_delay_end;
/*
Before the MASTER_DELAY parameter was added (WL#344),
relay_log.info had 4 lines. Now it has 5 lines.
*/
static const int LINES_IN_RELAY_LOG_INFO_WITH_DELAY= 5;
/*
Holds the state of the data in the relay log.
We need this to ensure that we are not in the middle of a
@ -875,10 +955,6 @@ public:
};
// Defined in rpl_rli.cc
int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
extern struct rpl_slave_state *rpl_global_gtid_slave_state;
extern gtid_waiting rpl_global_gtid_waiting;

View file

@ -77,6 +77,7 @@ Master_info *active_mi= 0;
Master_info_index *master_info_index;
my_bool replicate_same_server_id;
ulonglong relay_log_space_limit = 0;
ulonglong opt_read_binlog_speed_limit = 0;
const char *relay_log_index= 0;
const char *relay_log_basename= 0;
@ -735,7 +736,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
DBUG_PRINT("info",("Flushing relay-log info file."));
if (current_thd)
THD_STAGE_INFO(current_thd, stage_flushing_relay_log_info_file);
if (flush_relay_log_info(&mi->rli))
if (mi->rli.flush())
DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
if (my_sync(mi->rli.info_fd, MYF(MY_WME)))
@ -1631,8 +1632,10 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
(master_res= mysql_store_result(mysql)) &&
(master_row= mysql_fetch_row(master_res)))
{
mysql_mutex_lock(&mi->data_lock);
mi->clock_diff_with_master=
(long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
mysql_mutex_unlock(&mi->data_lock);
}
else if (check_io_slave_killed(mi, NULL))
goto slave_killed_err;
@ -1644,7 +1647,9 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
}
else
{
mysql_mutex_lock(&mi->data_lock);
mi->clock_diff_with_master= 0; /* The "most sensible" value */
mysql_mutex_unlock(&mi->data_lock);
sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, "
"do not trust column Seconds_Behind_Master of SHOW "
"SLAVE STATUS. Error: %s (%d)",
@ -2794,6 +2799,15 @@ void show_master_info_get_fields(THD *thd, List<Item> *field_list,
Item_empty_string(thd, "Parallel_Mode",
sizeof("conservative")-1),
mem_root);
field_list->push_back(new (mem_root)
Item_return_int(thd, "SQL_Delay", 10,
MYSQL_TYPE_LONG));
field_list->push_back(new (mem_root)
Item_return_int(thd, "SQL_Remaining_Delay", 8,
MYSQL_TYPE_LONG));
field_list->push_back(new (mem_root)
Item_empty_string(thd, "Slave_SQL_Running_State",
20));
if (full)
{
field_list->push_back(new (mem_root)
@ -2983,6 +2997,7 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
prot_store_ids(thd, &mi->ignore_server_ids);
// Master_Server_id
protocol->store((uint32) mi->master_id);
// SQL_Delay
// Master_Ssl_Crl
protocol->store(mi->ssl_ca, &my_charset_bin);
// Master_Ssl_Crlpath
@ -3005,6 +3020,22 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
protocol->store(mode_name, strlen(mode_name), &my_charset_bin);
}
protocol->store((uint32) mi->rli.get_sql_delay());
// SQL_Remaining_Delay
// THD::proc_info is not protected by any lock, so we read it once
// to ensure that we use the same value throughout this function.
const char *slave_sql_running_state=
mi->rli.sql_driver_thd ? mi->rli.sql_driver_thd->proc_info : "";
if (slave_sql_running_state == Relay_log_info::state_delaying_string)
{
time_t t= my_time(0), sql_delay_end= mi->rli.get_sql_delay_end();
protocol->store((uint32)(t < sql_delay_end ? sql_delay_end - t : 0));
}
else
protocol->store_null();
// Slave_SQL_Running_State
protocol->store(slave_sql_running_state, &my_charset_bin);
if (full)
{
protocol->store((uint32) mi->rli.retried_trans);
@ -3277,13 +3308,15 @@ static int request_dump(THD *thd, MYSQL* mysql, Master_info* mi,
try a reconnect. We do not want to print anything to
the error log in this case because this a anormal
event in an idle server.
network_read_len get the real network read length in VIO, especially using compressed protocol
RETURN VALUES
'packet_error' Error
number Length of packet
*/
static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings)
static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings,
ulong* network_read_len)
{
ulong len;
DBUG_ENTER("read_event");
@ -3298,7 +3331,7 @@ static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings)
DBUG_RETURN(packet_error);
#endif
len = cli_safe_read(mysql);
len = cli_safe_read_reallen(mysql, network_read_len);
if (len == packet_error || (long) len < 1)
{
if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
@ -3369,38 +3402,83 @@ has_temporary_error(THD *thd)
/**
Applies the given event and advances the relay log position.
If this is a lagging slave (specified with CHANGE MASTER TO MASTER_DELAY = X), delays accordingly. Also unlocks rli->data_lock.
In essence, this function does:
Design note: this is the place to unlock rli->data_lock. The lock
must be held when reading delay info from rli, but it should not be
held while sleeping.
@code
ev->apply_event(rli);
ev->update_pos(rli);
@endcode
@param ev Event that is about to be executed.
But it also does some maintainance, such as skipping events if
needed and reporting errors.
@param thd The sql thread's THD object.
If the @c skip flag is set, then it is tested whether the event
should be skipped, by looking at the slave_skip_counter and the
server id. The skip flag should be set when calling this from a
replication thread but not set when executing an explicit BINLOG
statement.
@param rli The sql thread's Relay_log_info structure.
@retval 0 OK.
@retval 0 If the delay timed out and the event shall be executed.
@retval 1 Error calling ev->apply_event().
@retval 2 No error calling ev->apply_event(), but error calling
ev->update_pos().
@retval nonzero If the delay was interrupted and the event shall be skipped.
*/
int apply_event_and_update_pos(Log_event* ev, THD* thd,
rpl_group_info *rgi,
rpl_parallel_thread *rpt)
int
sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi)
{
int exec_res= 0;
Relay_log_info* rli= rgi->rli;
DBUG_ENTER("apply_event_and_update_pos");
long sql_delay= rli->get_sql_delay();
DBUG_ENTER("sql_delay_event");
mysql_mutex_assert_owner(&rli->data_lock);
DBUG_ASSERT(!rli->belongs_to_client());
int type= ev->get_type_code();
if (sql_delay && type != ROTATE_EVENT &&
type != FORMAT_DESCRIPTION_EVENT && type != START_EVENT_V3)
{
// The time when we should execute the event.
time_t sql_delay_end=
ev->when + rli->mi->clock_diff_with_master + sql_delay;
// The current time.
time_t now= my_time(0);
// The time we will have to sleep before executing the event.
unsigned long nap_time= 0;
if (sql_delay_end > now)
nap_time= sql_delay_end - now;
DBUG_PRINT("info", ("sql_delay= %lu "
"ev->when= %lu "
"rli->mi->clock_diff_with_master= %lu "
"now= %ld "
"sql_delay_end= %lu "
"nap_time= %ld",
sql_delay, (long)ev->when,
rli->mi->clock_diff_with_master,
(long)now, sql_delay_end, (long)nap_time));
if (sql_delay_end > now)
{
DBUG_PRINT("info", ("delaying replication event %lu secs",
nap_time));
rli->start_sql_delay(sql_delay_end);
mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(slave_sleep(thd, nap_time, sql_slave_killed, rgi));
}
}
mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(0);
}
/*
First half of apply_event_and_update_pos(), see below.
Setup some THD variables for applying the event.
Split out so that it can run with rli->data_lock held in non-parallel
replication, but without the mutex held in the parallel case.
*/
static int
apply_event_and_update_pos_setup(Log_event* ev, THD* thd, rpl_group_info *rgi)
{
DBUG_ENTER("apply_event_and_update_pos_setup");
DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
ev->get_type_str(), ev->get_type_code(),
@ -3450,13 +3528,23 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd,
(ev->flags & LOG_EVENT_SKIP_REPLICATION_F ? OPTION_SKIP_REPLICATION : 0);
ev->thd = thd; // because up to this point, ev->thd == 0
int reason= ev->shall_skip(rgi);
if (reason == Log_event::EVENT_SKIP_COUNT)
{
DBUG_ASSERT(rli->slave_skip_counter > 0);
rli->slave_skip_counter--;
}
mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(ev->shall_skip(rgi));
}
/*
Second half of apply_event_and_update_pos(), see below.
Do the actual event apply (or skip), and position update.
*/
static int
apply_event_and_update_pos_apply(Log_event* ev, THD* thd, rpl_group_info *rgi,
int reason)
{
int exec_res= 0;
Relay_log_info* rli= rgi->rli;
DBUG_ENTER("apply_event_and_update_pos_apply");
DBUG_EXECUTE_IF("inject_slave_sql_before_apply_event",
{
DBUG_ASSERT(!debug_sync_set_action
@ -3503,16 +3591,16 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd,
if (exec_res == 0)
{
int error= ev->update_pos(rgi);
#ifdef HAVE_valgrind
if (!rli->is_fake)
#endif
#ifndef DBUG_OFF
DBUG_PRINT("info", ("update_pos error = %d", error));
if (!rli->belongs_to_client())
{
DBUG_PRINT("info", ("update_pos error = %d", error));
DBUG_PRINT("info", ("group %llu %s", rli->group_relay_log_pos,
rli->group_relay_log_name));
DBUG_PRINT("info", ("event %llu %s", rli->event_relay_log_pos,
rli->event_relay_log_name));
}
#endif
/*
The update should not fail, so print an error message and
return an error code.
@ -3544,6 +3632,103 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd,
}
/**
Applies the given event and advances the relay log position.
This is needed by the sql thread to execute events from the binlog,
and by clients executing BINLOG statements. Conceptually, this
function does:
@code
ev->apply_event(rli);
ev->update_pos(rli);
@endcode
It also does the following maintainance:
- Initializes the thread's server_id and time; and the event's
thread.
- If !rli->belongs_to_client() (i.e., if it belongs to the slave
sql thread instead of being used for executing BINLOG
statements), it does the following things: (1) skips events if it
is needed according to the server id or slave_skip_counter; (2)
unlocks rli->data_lock; (3) sleeps if required by 'CHANGE MASTER
TO MASTER_DELAY=X'; (4) maintains the running state of the sql
thread (rli->thread_state).
- Reports errors as needed.
@param ev The event to apply.
@param thd The client thread that executes the event (i.e., the
slave sql thread if called from a replication slave, or the client
thread if called to execute a BINLOG statement).
@param rli The relay log info (i.e., the slave's rli if called from
a replication slave, or the client's thd->rli_fake if called to
execute a BINLOG statement).
@retval 0 OK.
@retval 1 Error calling ev->apply_event().
@retval 2 No error calling ev->apply_event(), but error calling
ev->update_pos().
This function is only used in non-parallel replication, where it is called
with rli->data_lock held; this lock is released during this function.
*/
int
apply_event_and_update_pos(Log_event* ev, THD* thd, rpl_group_info *rgi)
{
Relay_log_info* rli= rgi->rli;
mysql_mutex_assert_owner(&rli->data_lock);
int reason= apply_event_and_update_pos_setup(ev, thd, rgi);
if (reason == Log_event::EVENT_SKIP_COUNT)
{
DBUG_ASSERT(rli->slave_skip_counter > 0);
rli->slave_skip_counter--;
}
if (reason == Log_event::EVENT_SKIP_NOT)
{
// Sleeps if needed, and unlocks rli->data_lock.
if (sql_delay_event(ev, thd, rgi))
return 0;
}
else
mysql_mutex_unlock(&rli->data_lock);
return apply_event_and_update_pos_apply(ev, thd, rgi, reason);
}
/*
The version of above apply_event_and_update_pos() used in parallel
replication. Unlike the non-parallel case, this function is called without
rli->data_lock held.
*/
int
apply_event_and_update_pos_for_parallel(Log_event* ev, THD* thd,
rpl_group_info *rgi)
{
Relay_log_info* rli= rgi->rli;
mysql_mutex_assert_not_owner(&rli->data_lock);
int reason= apply_event_and_update_pos_setup(ev, thd, rgi);
/*
In parallel replication, sql_slave_skip_counter is handled in the SQL
driver thread, so 23 should never see EVENT_SKIP_COUNT here.
*/
DBUG_ASSERT(reason != Log_event::EVENT_SKIP_COUNT);
/*
Calling sql_delay_event() was handled in the SQL driver thread when
doing parallel replication.
*/
return apply_event_and_update_pos_apply(ev, thd, rgi, reason);
}
/**
Keep the relay log transaction state up to date.
@ -3619,7 +3804,8 @@ inline void update_state_of_relay_log(Relay_log_info *rli, Log_event *ev)
/**
Top-level function for executing the next event from the relay log.
Top-level function for executing the next event in the relay log.
This is called from the SQL thread.
This function reads the event from the relay log, executes it, and
advances the relay log position. It also handles errors, etc.
@ -3794,7 +3980,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
serial_rgi->future_event_relay_log_pos= rli->future_event_relay_log_pos;
serial_rgi->event_relay_log_name= rli->event_relay_log_name;
serial_rgi->event_relay_log_pos= rli->event_relay_log_pos;
exec_res= apply_event_and_update_pos(ev, thd, serial_rgi, NULL);
exec_res= apply_event_and_update_pos(ev, thd, serial_rgi);
#ifdef WITH_WSREP
WSREP_DEBUG("apply_event_and_update_pos() result: %d", exec_res);
@ -4164,8 +4350,10 @@ connected:
};);
#endif
// TODO: the assignment below should be under mutex (5.0)
mysql_mutex_lock(&mi->run_lock);
mi->slave_running= MYSQL_SLAVE_RUN_CONNECT;
mysql_mutex_unlock(&mi->run_lock);
thd->slave_net = &mysql->net;
THD_STAGE_INFO(thd, stage_checking_master_version);
ret= get_master_version_and_clock(mysql, mi);
@ -4230,9 +4418,11 @@ connected:
mi->slave_running= MYSQL_SLAVE_RUN_READING;
DBUG_ASSERT(mi->last_error().number == 0);
ulonglong lastchecktime = my_hrtime().val;
ulonglong tokenamount = opt_read_binlog_speed_limit*1024;
while (!io_slave_killed(mi))
{
ulong event_len;
ulong event_len, network_read_len = 0;
/*
We say "waiting" because read_event() will wait if there's nothing to
read. But if there's something to read, it will not wait. The
@ -4240,7 +4430,7 @@ connected:
we're in fact receiving nothing.
*/
THD_STAGE_INFO(thd, stage_waiting_for_master_to_send_event);
event_len= read_event(mysql, mi, &suppress_warnings);
event_len= read_event(mysql, mi, &suppress_warnings, &network_read_len);
if (check_io_slave_killed(mi, NullS))
goto err;
@ -4288,6 +4478,47 @@ Stopping slave I/O thread due to out-of-memory error from master");
goto err;
}
/* Control the binlog read speed of master
when read_binlog_speed_limit is non-zero
*/
ulonglong speed_limit_in_bytes = opt_read_binlog_speed_limit * 1024;
if (speed_limit_in_bytes)
{
/* Prevent the tokenamount become a large value,
for example, the IO thread doesn't work for a long time
*/
if (tokenamount > speed_limit_in_bytes * 2)
{
lastchecktime = my_hrtime().val;
tokenamount = speed_limit_in_bytes * 2;
}
do
{
ulonglong currenttime = my_hrtime().val;
tokenamount += (currenttime - lastchecktime) * speed_limit_in_bytes / (1000*1000);
lastchecktime = currenttime;
if(tokenamount < network_read_len)
{
ulonglong micro_time = 1000*1000 * (network_read_len - tokenamount) / speed_limit_in_bytes ;
ulonglong second_time = micro_time / (1000 * 1000);
micro_time = micro_time % (1000 * 1000);
// at least sleep 1000 micro second
my_sleep(micro_time > 1000 ? micro_time : 1000);
/*
If it sleep more than one second,
it should use slave_sleep() to avoid the STOP SLAVE hang.
*/
if (second_time)
slave_sleep(thd, second_time, io_slave_killed, mi);
}
}while(tokenamount < network_read_len);
tokenamount -= network_read_len;
}
/* XXX: 'synced' should be updated by queue_event to indicate
whether event has been synced to disk */
bool synced= 0;
@ -4928,7 +5159,7 @@ pthread_handler_t handle_slave_sql(void *arg)
{
ulong domain_count;
flush_relay_log_info(rli);
rli->flush();
if (mi->using_parallel())
{
/*
@ -6516,75 +6747,6 @@ MYSQL *rpl_connect_master(MYSQL *mysql)
}
#endif
/*
Store the file and position where the execute-slave thread are in the
relay log.
SYNOPSIS
flush_relay_log_info()
rli Relay log information
NOTES
- As this is only called by the slave thread or on STOP SLAVE, with the
log_lock grabbed and the slave thread stopped, we don't need to have
a lock here.
- If there is an active transaction, then we don't update the position
in the relay log. This is to ensure that we re-execute statements
if we die in the middle of an transaction that was rolled back.
- As a transaction never spans binary logs, we don't have to handle the
case where we do a relay-log-rotation in the middle of the transaction.
If this would not be the case, we would have to ensure that we
don't delete the relay log file where the transaction started when
we switch to a new relay log file.
TODO
- Change the log file information to a binary format to avoid calling
longlong2str.
RETURN VALUES
0 ok
1 write error
*/
bool flush_relay_log_info(Relay_log_info* rli)
{
bool error=0;
DBUG_ENTER("flush_relay_log_info");
if (unlikely(rli->no_storage))
DBUG_RETURN(0);
IO_CACHE *file = &rli->info_file;
char buff[FN_REFLEN*2+22*2+4], *pos;
my_b_seek(file, 0L);
pos=strmov(buff, rli->group_relay_log_name);
*pos++='\n';
pos= longlong10_to_str(rli->group_relay_log_pos, pos, 10);
*pos++='\n';
pos=strmov(pos, rli->group_master_log_name);
*pos++='\n';
pos=longlong10_to_str(rli->group_master_log_pos, pos, 10);
*pos='\n';
if (my_b_write(file, (uchar*) buff, (size_t) (pos-buff)+1))
error=1;
if (flush_io_cache(file))
error=1;
if (sync_relayloginfo_period &&
!error &&
++(rli->sync_counter) >= sync_relayloginfo_period)
{
if (my_sync(rli->info_fd, MYF(MY_WME)))
error=1;
rli->sync_counter= 0;
}
/*
Flushing the relay log is done by the slave I/O thread
or by the user on STOP SLAVE.
*/
DBUG_RETURN(error);
}
/*
Called when we notice that the current "hot" log got rotated under our feet.
@ -6941,7 +7103,7 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
}
rli->event_relay_log_pos = BIN_LOG_HEADER_SIZE;
strmake_buf(rli->event_relay_log_name,rli->linfo.log_file_name);
flush_relay_log_info(rli);
rli->flush();
}
/*

View file

@ -17,6 +17,14 @@
#ifndef SLAVE_H
#define SLAVE_H
/**
MASTER_DELAY can be at most (1 << 31) - 1.
*/
#define MASTER_DELAY_MAX (0x7FFFFFFF)
#if INT_MAX < 0x7FFFFFFF
#error "don't support platforms where INT_MAX < 0x7FFFFFFF"
#endif
/**
@defgroup Replication Replication
@{
@ -102,12 +110,14 @@ int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
In Master_info: run_lock, data_lock
run_lock protects all information about the run state: slave_running, thd
and the existence of the I/O thread to stop/start it, you need this mutex).
and the existence of the I/O thread (to stop/start it, you need this mutex).
data_lock protects some moving members of the struct: counters (log name,
position) and relay log (MYSQL_BIN_LOG object).
In Relay_log_info: run_lock, data_lock
see Master_info
However, note that run_lock does not protect
Relay_log_info.run_state; that is protected by data_lock.
Order of acquisition: if you want to have LOCK_active_mi and a run_lock, you
must acquire LOCK_active_mi first.
@ -130,6 +140,7 @@ extern my_bool opt_log_slave_updates;
extern char *opt_slave_skip_errors;
extern my_bool opt_replicate_annotate_row_events;
extern ulonglong relay_log_space_limit;
extern ulonglong opt_read_binlog_speed_limit;
extern ulonglong slave_skipped_errors;
extern const char *relay_log_index;
extern const char *relay_log_basename;
@ -173,7 +184,6 @@ extern const char *relay_log_basename;
int init_slave();
int init_recovery(Master_info* mi, const char** errmsg);
void init_slave_skip_errors(const char* arg);
bool flush_relay_log_info(Relay_log_info* rli);
int register_slave_on_master(MYSQL* mysql);
int terminate_slave_threads(Master_info* mi, int thread_mask,
bool skip_lock = 0);
@ -242,9 +252,17 @@ void set_slave_thread_options(THD* thd);
void set_slave_thread_default_charset(THD *thd, rpl_group_info *rgi);
int rotate_relay_log(Master_info* mi);
int has_temporary_error(THD *thd);
int sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi);
int apply_event_and_update_pos(Log_event* ev, THD* thd,
struct rpl_group_info *rgi,
rpl_parallel_thread *rpt);
struct rpl_group_info *rgi);
int apply_event_and_update_pos_for_parallel(Log_event* ev, THD* thd,
struct rpl_group_info *rgi);
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
pthread_handler_t handle_slave_io(void *arg);
void slave_output_error_info(rpl_group_info *rgi, THD *thd);

View file

@ -17,18 +17,99 @@
#include <my_global.h>
#include "sql_priv.h"
#include "sql_binlog.h"
#include "sql_parse.h" // check_global_access
#include "sql_acl.h" // *_ACL
#include "sql_parse.h"
#include "sql_acl.h"
#include "rpl_rli.h"
#include "base64.h"
#include "slave.h" // apply_event_and_update_pos
#include "log_event.h" // Format_description_log_event,
// EVENT_LEN_OFFSET,
// EVENT_TYPE_OFFSET,
// FORMAT_DESCRIPTION_LOG_EVENT,
// START_EVENT_V3,
// Log_event_type,
// Log_event
#include "slave.h"
#include "log_event.h"
/**
Check if the event type is allowed in a BINLOG statement.
@retval 0 if the event type is ok.
@retval 1 if the event type is not ok.
*/
static int check_event_type(int type, Relay_log_info *rli)
{
Format_description_log_event *fd_event=
rli->relay_log.description_event_for_exec;
/*
Convert event type id of certain old versions (see comment in
Format_description_log_event::Format_description_log_event(char*,...)).
*/
if (fd_event && fd_event->event_type_permutation)
{
IF_DBUG({
int new_type= fd_event->event_type_permutation[type];
DBUG_PRINT("info",
("converting event type %d to %d (%s)",
type, new_type,
Log_event::get_type_str((Log_event_type)new_type)));
},
(void)0);
type= fd_event->event_type_permutation[type];
}
switch (type)
{
case START_EVENT_V3:
case FORMAT_DESCRIPTION_EVENT:
/*
We need a preliminary FD event in order to parse the FD event,
if we don't already have one.
*/
if (!fd_event)
if (!(rli->relay_log.description_event_for_exec=
new Format_description_log_event(4)))
{
my_error(ER_OUTOFMEMORY, MYF(0), 1);
return 1;
}
/* It is always allowed to execute FD events. */
return 0;
case TABLE_MAP_EVENT:
case WRITE_ROWS_EVENT_V1:
case UPDATE_ROWS_EVENT_V1:
case DELETE_ROWS_EVENT_V1:
case WRITE_ROWS_EVENT:
case UPDATE_ROWS_EVENT:
case DELETE_ROWS_EVENT:
case PRE_GA_WRITE_ROWS_EVENT:
case PRE_GA_UPDATE_ROWS_EVENT:
case PRE_GA_DELETE_ROWS_EVENT:
/*
Row events are only allowed if a Format_description_event has
already been seen.
*/
if (fd_event)
return 0;
else
{
my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
MYF(0), Log_event::get_type_str((Log_event_type)type));
return 1;
}
break;
default:
/*
It is not meaningful to execute other events than row-events and
FD events. It would even be dangerous to execute Stop_log_event
and Rotate_log_event since they call Relay_log_info::flush(), which
is not allowed to call by other threads than the slave SQL
thread when the slave SQL thread is running.
*/
my_error(ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT,
MYF(0), Log_event::get_type_str((Log_event_type)type));
return 1;
}
}
/**
Execute a BINLOG statement.
@ -73,31 +154,13 @@ void mysql_client_binlog_statement(THD* thd)
Allocation
*/
/*
If we do not have a Format_description_event, we create a dummy
one here. In this case, the first event we read must be a
Format_description_event.
*/
my_bool have_fd_event= TRUE;
int err;
Relay_log_info *rli;
rpl_group_info *rgi;
rli= thd->rli_fake;
if (!rli)
{
rli= thd->rli_fake= new Relay_log_info(FALSE);
#ifdef HAVE_valgrind
rli->is_fake= TRUE;
#endif
have_fd_event= FALSE;
}
if (rli && !rli->relay_log.description_event_for_exec)
{
rli->relay_log.description_event_for_exec=
new Format_description_log_event(4);
have_fd_event= FALSE;
}
if (!rli && (rli= thd->rli_fake= new Relay_log_info(FALSE)))
rli->sql_driver_thd= thd;
if (!(rgi= thd->rgi_fake))
rgi= thd->rgi_fake= new rpl_group_info(rli);
rgi->thd= thd;
@ -109,16 +172,13 @@ void mysql_client_binlog_statement(THD* thd)
/*
Out of memory check
*/
if (!(rli &&
rli->relay_log.description_event_for_exec &&
buf))
if (!(rli && buf))
{
my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 1); /* needed 1 bytes */
goto end;
}
rli->sql_driver_thd= thd;
rli->no_storage= TRUE;
DBUG_ASSERT(rli->belongs_to_client());
for (char const *strptr= thd->lex->comment.str ;
strptr < thd->lex->comment.str + thd->lex->comment.length ; )
@ -185,23 +245,8 @@ void mysql_client_binlog_statement(THD* thd)
DBUG_PRINT("info", ("event_len=%lu, bytes_decoded=%d",
event_len, bytes_decoded));
/*
If we have not seen any Format_description_event, then we must
see one; it is the only statement that can be read in base64
without a prior Format_description_event.
*/
if (!have_fd_event)
{
int type = (uchar)bufptr[EVENT_TYPE_OFFSET];
if (type == FORMAT_DESCRIPTION_EVENT || type == START_EVENT_V3)
have_fd_event= TRUE;
else
{
my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
MYF(0), Log_event::get_type_str((Log_event_type)type));
goto end;
}
}
if (check_event_type(bufptr[EVENT_TYPE_OFFSET], rli))
goto end;
ev= Log_event::read_log_event(bufptr, event_len, &error,
rli->relay_log.description_event_for_exec,
@ -212,7 +257,7 @@ void mysql_client_binlog_statement(THD* thd)
{
/*
This could actually be an out-of-memory, but it is more likely
causes by a bad statement
caused by a bad statement
*/
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;

View file

@ -4598,19 +4598,20 @@ extern "C" int thd_rpl_is_parallel(const MYSQL_THD thd)
}
/*
This function can optionally be called to check if thd_report_wait_for()
This function can optionally be called to check if thd_rpl_deadlock_check()
needs to be called for waits done by a given transaction.
If this function returns false for a given thd, there is no need to do any
calls to thd_report_wait_for() on that thd.
If this function returns false for a given thd, there is no need to do
any calls to thd_rpl_deadlock_check() on that thd.
This call is optional; it is safe to call thd_report_wait_for() in any case.
This call can be used to save some redundant calls to thd_report_wait_for()
if desired. (This is unlikely to matter much unless there are _lots_ of
waits to report, as the overhead of thd_report_wait_for() is small).
This call is optional; it is safe to call thd_rpl_deadlock_check() in
any case. This call can be used to save some redundant calls to
thd_rpl_deadlock_check() if desired. (This is unlikely to matter much
unless there are _lots_ of waits to report, as the overhead of
thd_rpl_deadlock_check() is small).
*/
extern "C" int
thd_need_wait_for(const MYSQL_THD thd)
thd_need_wait_reports(const MYSQL_THD thd)
{
rpl_group_info *rgi;
@ -4625,75 +4626,9 @@ thd_need_wait_for(const MYSQL_THD thd)
}
/*
Used by InnoDB/XtraDB to report that one transaction THD is about to go to
wait for a transactional lock held by another transactions OTHER_THD.
This is used for parallel replication, where transactions are required to
commit in the same order on the slave as they did on the master. If the
transactions on the slave encounters lock conflicts on the slave that did
not exist on the master, this can cause deadlocks.
Normally, such conflicts will not occur, because the same conflict would
have prevented the two transactions from committing in parallel on the
master, thus preventing them from running in parallel on the slave in the
first place. However, it is possible in case when the optimizer chooses a
different plan on the slave than on the master (eg. table scan instead of
index scan).
InnoDB/XtraDB reports lock waits using this call. If a lock wait causes a
deadlock with the pre-determined commit order, we kill the later transaction,
and later re-try it, to resolve the deadlock.
This call need only receive reports about waits for locks that will remain
until the holding transaction commits. InnoDB/XtraDB auto-increment locks
are released earlier, and so need not be reported. (Such false positives are
not harmful, but could lead to unnecessary kill and retry, so best avoided).
*/
extern "C" void
thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd)
{
rpl_group_info *rgi;
rpl_group_info *other_rgi;
if (!thd)
return;
DEBUG_SYNC(thd, "thd_report_wait_for");
thd->transaction.stmt.mark_trans_did_wait();
if (!other_thd)
return;
binlog_report_wait_for(thd, other_thd);
rgi= thd->rgi_slave;
other_rgi= other_thd->rgi_slave;
if (!rgi || !other_rgi)
return;
if (!rgi->is_parallel_exec)
return;
if (rgi->rli != other_rgi->rli)
return;
if (!rgi->gtid_sub_id || !other_rgi->gtid_sub_id)
return;
if (rgi->current_gtid.domain_id != other_rgi->current_gtid.domain_id)
return;
if (rgi->gtid_sub_id > other_rgi->gtid_sub_id)
return;
/*
This transaction is about to wait for another transaction that is required
by replication binlog order to commit after. This would cause a deadlock.
So send a kill to the other transaction, with a temporary error; this will
cause replication to rollback (and later re-try) the other transaction,
releasing the lock for this transaction so replication can proceed.
*/
other_rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
mysql_mutex_lock(&other_thd->LOCK_thd_data);
other_thd->awake(KILL_CONNECTION);
mysql_mutex_unlock(&other_thd->LOCK_thd_data);
}
/*
Used by storage engines (currently TokuDB) to report that one transaction
THD is about to go to wait for a transactional lock held by another
transactions OTHER_THD.
Used by storage engines (currently TokuDB and InnoDB/XtraDB) to report that
one transaction THD is about to go to wait for a transactional lock held by
another transactions OTHER_THD.
This is used for parallel replication, where transactions are required to
commit in the same order on the slave as they did on the master. If the
@ -4708,9 +4643,9 @@ thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd)
chooses a different plan on the slave than on the master (eg. table scan
instead of index scan).
InnoDB/XtraDB reports lock waits using this call. If a lock wait causes a
deadlock with the pre-determined commit order, we kill the later transaction,
and later re-try it, to resolve the deadlock.
Storage engines report lock waits using this call. If a lock wait causes a
deadlock with the pre-determined commit order, we kill the later
transaction, and later re-try it, to resolve the deadlock.
This call need only receive reports about waits for locks that will remain
until the holding transaction commits. InnoDB/XtraDB auto-increment locks,
@ -4801,8 +4736,8 @@ thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd)
Calling this function is just an optimisation to avoid unnecessary
deadlocks. If it was not used, a gap lock would be set that could eventually
cause a deadlock; the deadlock would be caught by thd_report_wait_for() and
the transaction T2 killed and rolled back (and later re-tried).
cause a deadlock; the deadlock would be caught by thd_rpl_deadlock_check()
and the transaction T2 killed and rolled back (and later re-tried).
*/
extern "C" int
thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd)

View file

@ -2151,7 +2151,6 @@ void st_select_lex::init_select()
in_sum_expr= with_wild= 0;
options= 0;
sql_cache= SQL_CACHE_UNSPECIFIED;
interval_list.empty();
ftfunc_list_alloc.empty();
inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc;

View file

@ -246,11 +246,12 @@ struct LEX_MASTER_INFO
ulong server_id;
uint port, connect_retry;
float heartbeat_period;
int sql_delay;
/*
Enum is used for making it possible to detect if the user
changed variable or if it should be left at old value
*/
enum {LEX_MI_UNCHANGED, LEX_MI_DISABLE, LEX_MI_ENABLE}
enum {LEX_MI_UNCHANGED= 0, LEX_MI_DISABLE, LEX_MI_ENABLE}
ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt,
repl_do_domain_ids_opt, repl_ignore_domain_ids_opt;
enum {
@ -266,6 +267,7 @@ struct LEX_MASTER_INFO
sizeof(ulong), 0, 16, MYF(0));
my_init_dynamic_array(&repl_ignore_domain_ids,
sizeof(ulong), 0, 16, MYF(0));
sql_delay= -1;
}
void reset(bool is_change_master)
{
@ -286,6 +288,7 @@ struct LEX_MASTER_INFO
repl_ignore_domain_ids_opt= LEX_MI_UNCHANGED;
gtid_pos_str= null_lex_str;
use_gtid_opt= LEX_GTID_UNCHANGED;
sql_delay= -1;
}
};
@ -785,7 +788,6 @@ public:
Group_list_ptrs *group_list_ptrs;
List<Item> item_list; /* list of fields & expressions */
List<String> interval_list;
bool is_item_list_lookup;
/*
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake

View file

@ -495,7 +495,7 @@ static enum enum_binlog_checksum_alg get_binlog_checksum_value_at_connect(THD *
TODO
- Inform the slave threads that they should sync the position
in the binary log file with flush_relay_log_info.
in the binary log file with Relay_log_info::flush().
Now they sync is done for next read.
*/
@ -3304,6 +3304,7 @@ int reset_slave(THD *thd, Master_info* mi)
mi->clear_error();
mi->rli.clear_error();
mi->rli.clear_until_condition();
mi->rli.clear_sql_delay();
mi->rli.slave_skip_counter= 0;
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
@ -3613,6 +3614,9 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
if (lex_mi->sql_delay != -1)
mi->rli.set_sql_delay(lex_mi->sql_delay);
if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
mi->ssl_verify_server_cert=
(lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE);
@ -3797,7 +3801,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
in-memory value at restart (thus causing errors, as the old relay log does
not exist anymore).
*/
flush_relay_log_info(&mi->rli);
mi->rli.flush();
mysql_cond_broadcast(&mi->data_cond);
mysql_mutex_unlock(&mi->rli.data_lock);

View file

@ -1359,6 +1359,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token LOOP_SYM
%token LOW_PRIORITY
%token MASTER_CONNECT_RETRY_SYM
%token MASTER_DELAY_SYM
%token MASTER_GTID_POS_SYM
%token MASTER_HOST_SYM
%token MASTER_LOG_FILE_SYM
@ -2338,6 +2339,16 @@ master_def:
{
Lex->mi.connect_retry = $3;
}
| MASTER_DELAY_SYM '=' ulong_num
{
if ($3 > MASTER_DELAY_MAX)
{
my_error(ER_MASTER_DELAY_VALUE_OUT_OF_RANGE, MYF(0),
$3, MASTER_DELAY_MAX);
}
else
Lex->mi.sql_delay = $3;
}
| MASTER_SSL_SYM '=' ulong_num
{
Lex->mi.ssl= $3 ?
@ -7850,6 +7861,7 @@ slave:
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_ALL_START;
lex->type = 0;
/* If you change this code don't forget to update STOP SLAVE too */
}
{}
| STOP_SYM SLAVE optional_connection_name slave_thread_opts
@ -13857,13 +13869,13 @@ literal:
}
| FALSE_SYM
{
$$= new (thd->mem_root) Item_int(thd, (char*) "FALSE",0,1);
$$= new (thd->mem_root) Item_bool(thd, (char*) "FALSE",0);
if ($$ == NULL)
MYSQL_YYABORT;
}
| TRUE_SYM
{
$$= new (thd->mem_root) Item_int(thd, (char*) "TRUE",1,1);
$$= new (thd->mem_root) Item_bool(thd, (char*) "TRUE",1);
if ($$ == NULL)
MYSQL_YYABORT;
}
@ -14744,6 +14756,7 @@ keyword_sp:
| MASTER_PASSWORD_SYM {}
| MASTER_SERVER_ID_SYM {}
| MASTER_CONNECT_RETRY_SYM {}
| MASTER_DELAY_SYM {}
| MASTER_SSL_SYM {}
| MASTER_SSL_CA_SYM {}
| MASTER_SSL_CAPATH_SYM {}

View file

@ -4630,6 +4630,12 @@ static Sys_var_charptr Sys_slave_skip_errors(
READ_ONLY GLOBAL_VAR(opt_slave_skip_errors), CMD_LINE(REQUIRED_ARG),
IN_SYSTEM_CHARSET, DEFAULT(0));
static Sys_var_ulonglong Sys_read_binlog_speed_limit(
"read_binlog_speed_limit", "Maximum speed(KB/s) to read binlog from"
" master (0 = no limit)",
GLOBAL_VAR(opt_read_binlog_speed_limit), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1));
static Sys_var_ulonglong Sys_relay_log_space_limit(
"relay_log_space_limit", "Maximum space to use for all relay logs",
READ_ONLY GLOBAL_VAR(relay_log_space_limit), CMD_LINE(REQUIRED_ARG),

View file

@ -97,7 +97,6 @@ static rpl_group_info* wsrep_relay_group_init(const char* log_fname)
{
Relay_log_info* rli= new Relay_log_info(false);
rli->no_storage= true;
if (!rli->relay_log.description_event_for_exec)
{
rli->relay_log.description_event_for_exec=

View file

@ -13,3 +13,5 @@ jdbc : Variable settings depend on machine configuration
jdbc_new : Variable settings depend on machine configuration
jdbc_oracle : Variable settings depend on machine configuration
jdbc_postgresql : Variable settings depend on machine configuration
json_udf : conflicts with the server JSON functions
json_udf_bin : conflicts with the server JSON functions

View file

@ -30,6 +30,7 @@ MYSQL_CHECK_LZO()
MYSQL_CHECK_LZMA()
MYSQL_CHECK_BZIP2()
MYSQL_CHECK_SNAPPY()
MYSQL_CHECK_NUMA()
INCLUDE(innodb.cmake)
@ -173,11 +174,20 @@ IF(WITH_INNODB)
SET(WITH_INNOBASE_STORAGE_ENGINE TRUE)
ENDIF()
UNSET(NUMA_LIBRARY)
IF(HAVE_LIBNUMA)
SET(NUMA_LIBRARY "numa")
ENDIF()
MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE
# MODULE_ONLY
# MODULE_OUTPUT_NAME ha_innodb
DEFAULT RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${CRC32_VPMSUM_LIBRARY} ${LINKER_SCRIPT})
LINK_LIBRARIES
${ZLIB_LIBRARY}
${CRC32_VPMSUM_LIBRARY}
${NUMA_LIBRARY}
${LINKER_SCRIPT})
IF(WITH_INNOBASE_STORAGE_ENGINE)
ADD_DEPENDENCIES(innobase GenError)

View file

@ -3425,9 +3425,9 @@ ib_cursor_set_memcached_sync(
}
if (flag) {
os_atomic_increment_lint(&table->memcached_sync_count, 1);
my_atomic_addlint(&table->memcached_sync_count, 1);
} else {
os_atomic_decrement_lint(&table->memcached_sync_count, 1);
my_atomic_addlint(&table->memcached_sync_count, -1);
ut_a(table->memcached_sync_count >= 0);
}
} else {

View file

@ -499,7 +499,7 @@ btr_defragment_merge_pages(
// n_recs_to_move number of records to to_page. We try to reduce
// the targeted data size on the to_page by
// BTR_DEFRAGMENT_PAGE_REDUCTION_STEP_SIZE and try again.
os_atomic_increment_ulint(
my_atomic_addlint(
&btr_defragment_compression_failures, 1);
max_ins_size_to_use =
move_size > BTR_DEFRAGMENT_PAGE_REDUCTION_STEP_SIZE
@ -722,10 +722,10 @@ btr_defragment_n_pages(
}
mem_heap_free(heap);
n_defragmented ++;
os_atomic_increment_ulint(
my_atomic_addlint(
&btr_defragment_count, 1);
if (n_pages == n_defragmented) {
os_atomic_increment_ulint(
my_atomic_addlint(
&btr_defragment_failures, 1);
} else {
index->stat_defrag_n_pages_freed += (n_pages - n_defragmented);

View file

@ -96,11 +96,12 @@ struct set_numa_interleave_t
{
if (srv_numa_interleave) {
struct bitmask *numa_mems_allowed = numa_get_mems_allowed();
ib::info() << "Setting NUMA memory policy to"
" MPOL_INTERLEAVE";
if (set_mempolicy(MPOL_INTERLEAVE,
numa_all_nodes_ptr->maskp,
numa_all_nodes_ptr->size) != 0) {
numa_mems_allowed->maskp,
numa_mems_allowed->size) != 0) {
ib::warn() << "Failed to set NUMA memory"
" policy to MPOL_INTERLEAVE: "
@ -1555,10 +1556,11 @@ buf_chunk_init(
#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
if (srv_numa_interleave) {
struct bitmask *numa_mems_allowed = numa_get_mems_allowed();
int st = mbind(chunk->mem, chunk->mem_size(),
MPOL_INTERLEAVE,
numa_all_nodes_ptr->maskp,
numa_all_nodes_ptr->size,
numa_mems_allowed->maskp,
numa_mems_allowed->size,
MPOL_MF_MOVE);
if (st != 0) {
ib::warn() << "Failed to set NUMA memory policy of"
@ -2504,7 +2506,6 @@ buf_pool_withdraw_blocks(
/* retry is not needed */
++buf_withdraw_clock;
os_wmb;
return(false);
}
@ -4292,7 +4293,7 @@ loop:
mutex_enter(pmutex);
ut_ad(buf_pool->n_pend_reads > 0);
os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
my_atomic_addlint(&buf_pool->n_pend_reads, -1);
buf_page_set_io_fix(bpage, BUF_IO_NONE);
mutex_exit(pmutex);
buf_LRU_free_page(bpage, true);
@ -4339,7 +4340,7 @@ loop:
mutex_enter(pmutex);
ut_ad(buf_pool->n_pend_reads > 0);
os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
my_atomic_addlint(&buf_pool->n_pend_reads, -1);
buf_page_set_io_fix(bpage, BUF_IO_NONE);
mutex_exit(pmutex);
buf_LRU_free_page(bpage, true);
@ -5199,8 +5200,7 @@ buf_page_init(
ut_a(buf_fix_count > 0);
os_atomic_increment_uint32(&block->page.buf_fix_count,
buf_fix_count);
my_atomic_add32((int32*) &block->page.buf_fix_count, buf_fix_count);
buf_pool_watch_remove(buf_pool, hash_page);
} else {
@ -5439,8 +5439,7 @@ buf_page_init_for_read(
ut_a(buf_fix_count > 0);
os_atomic_increment_uint32(
&bpage->buf_fix_count, buf_fix_count);
my_atomic_add32((int32*) &bpage->buf_fix_count, buf_fix_count);
ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page));
buf_pool_watch_remove(buf_pool, watch_page);

View file

@ -7334,7 +7334,7 @@ dict_index_zip_pad_update(
/* Use atomics even though we have the mutex.
This is to ensure that we are able to read
info->pad atomically. */
os_atomic_increment_ulint(&info->pad, ZIP_PAD_INCR);
my_atomic_addlint(&info->pad, ZIP_PAD_INCR);
MONITOR_INC(MONITOR_PAD_INCREMENTS);
}
@ -7356,7 +7356,7 @@ dict_index_zip_pad_update(
/* Use atomics even though we have the mutex.
This is to ensure that we are able to read
info->pad atomically. */
os_atomic_decrement_ulint(&info->pad, ZIP_PAD_INCR);
my_atomic_addlint(&info->pad, -ZIP_PAD_INCR);
info->n_rounds = 0;
@ -7430,10 +7430,7 @@ dict_index_zip_pad_optimal_page_size(
return(UNIV_PAGE_SIZE);
}
/* We use atomics to read index->zip_pad.pad. Here we use zero
as increment as are not changing the value of the 'pad'. */
pad = os_atomic_increment_ulint(&index->zip_pad.pad, 0);
pad = my_atomic_loadlint(&index->zip_pad.pad);
ut_ad(pad < UNIV_PAGE_SIZE);
sz = UNIV_PAGE_SIZE - pad;

View file

@ -1045,7 +1045,7 @@ dict_mem_create_temporary_tablename(
size_t dblen = dbend - dbtab + 1;
/* Increment a randomly initialized number for each temp file. */
os_atomic_increment_uint32(&dict_temp_file_num, 1);
my_atomic_add32((int32*) &dict_temp_file_num, 1);
size = dblen + (sizeof(TEMP_FILE_PREFIX) + 3 + 20 + 1 + 10);
name = static_cast<char*>(mem_heap_alloc(heap, size));

View file

@ -379,6 +379,22 @@ static TYPELIB innodb_default_row_format_typelib = {
NULL
};
/** Possible values of the parameter innodb_lock_schedule_algorithm */
static const char* innodb_lock_schedule_algorithm_names[] = {
"fcfs",
"vats",
NullS
};
/** Used to define an enumerate type of the system variable
innodb_lock_schedule_algorithm. */
static TYPELIB innodb_lock_schedule_algorithm_typelib = {
array_elements(innodb_lock_schedule_algorithm_names) - 1,
"innodb_lock_schedule_algorithm_typelib",
innodb_lock_schedule_algorithm_names,
NULL
};
/* The following counter is used to convey information to InnoDB
about server activity: in case of normal DML ops it is not
sensible to call srv_active_wake_master_thread after each
@ -1671,7 +1687,7 @@ thd_is_replication_slave_thread(
/*============================*/
THD* thd) /*!< in: thread handle */
{
return((ibool) thd_slave_thread(thd));
return thd && ((ibool) thd_slave_thread(thd));
}
/******************************************************************//**
@ -5685,8 +5701,7 @@ innobase_kill_query(
wsrep_thd_is_BF(current_thd, FALSE));
}
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
trx->abort_type == TRX_SERVER_ABORT) {
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
ut_ad(!lock_mutex_own());
lock_mutex_enter();
lock_mutex_taken = true;
@ -17080,7 +17095,7 @@ ha_innobase::check(
&& !dict_index_is_corrupted(index)) {
/* Enlarge the fatal lock wait timeout during
CHECK TABLE. */
os_atomic_increment_ulint(
my_atomic_addlint(
&srv_fatal_semaphore_wait_threshold,
SRV_SEMAPHORE_WAIT_EXTENSION);
@ -17089,9 +17104,9 @@ ha_innobase::check(
/* Restore the fatal lock wait timeout after
CHECK TABLE. */
os_atomic_decrement_ulint(
my_atomic_addlint(
&srv_fatal_semaphore_wait_threshold,
SRV_SEMAPHORE_WAIT_EXTENSION);
-SRV_SEMAPHORE_WAIT_EXTENSION);
if (err != DB_SUCCESS) {
is_ok = false;
@ -22784,6 +22799,18 @@ static MYSQL_SYSVAR_ULONG(doublewrite_batch_size, srv_doublewrite_batch_size,
NULL, NULL, 120, 1, 127, 0);
#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
static MYSQL_SYSVAR_ENUM(lock_schedule_algorithm, innodb_lock_schedule_algorithm,
PLUGIN_VAR_RQCMDARG,
"The algorithm Innodb uses for deciding which locks to grant next when"
" a lock is released. Possible values are"
" FCFS"
" grant the locks in First-Come-First-Served order;"
" VATS"
" use the Variance-Aware-Transaction-Scheduling algorithm, which"
" uses an Eldest-Transaction-First heuristic.",
NULL, NULL, INNODB_LOCK_SCHEDULE_ALGORITHM_VATS,
&innodb_lock_schedule_algorithm_typelib);
static MYSQL_SYSVAR_ULONG(buffer_pool_instances, srv_buf_pool_instances,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Number of buffer pool instances, set to higher value on high-end machines to increase scalability",
@ -23657,6 +23684,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(ft_sort_pll_degree),
MYSQL_SYSVAR(large_prefix),
MYSQL_SYSVAR(force_load_corrupted),
MYSQL_SYSVAR(lock_schedule_algorithm),
MYSQL_SYSVAR(locks_unsafe_for_binlog),
MYSQL_SYSVAR(lock_wait_timeout),
MYSQL_SYSVAR(page_size),

View file

@ -1447,7 +1447,7 @@ ibuf_add_ops(
ulint i;
for (i = 0; i < IBUF_OP_COUNT; i++) {
os_atomic_increment_ulint(&arr[i], ops[i]);
my_atomic_addlint(&arr[i], ops[i]);
}
}
@ -4788,7 +4788,7 @@ reset_bit:
btr_pcur_close(&pcur);
mem_heap_free(heap);
os_atomic_increment_ulint(&ibuf->n_merges, 1);
my_atomic_addlint(&ibuf->n_merges, 1);
ibuf_add_ops(ibuf->n_merged_ops, mops);
ibuf_add_ops(ibuf->n_discarded_ops, dops);
if (space != NULL) {

View file

@ -968,7 +968,7 @@ ulint
buf_block_fix(
buf_page_t* bpage)
{
return(os_atomic_increment_uint32(&bpage->buf_fix_count, 1));
return(my_atomic_add32((int32*) &bpage->buf_fix_count, 1) + 1);
}
/** Increments the bufferfix count.
@ -1016,7 +1016,7 @@ ulint
buf_block_unfix(
buf_page_t* bpage)
{
ulint count = os_atomic_decrement_uint32(&bpage->buf_fix_count, 1);
ulint count = my_atomic_add32((int32*) &bpage->buf_fix_count, -1) - 1;
ut_ad(count + 1 != 0);
return(count);
}

View file

@ -31,6 +31,7 @@ Created 2013-03-26 Sunny Bains.
#include "ut0ut.h"
#include "ut0rnd.h"
#include "os0event.h"
#include "sync0arr.h"
/** OS mutex for tracking lock/unlock for debugging */
template <template <typename> class Policy = NoPolicy>
@ -67,8 +68,6 @@ struct OSTrackMutex {
m_mutex.init();
ut_d(m_freed = false);
m_policy.init(*this, id, filename, line);
}
/** Destroy the mutex */
@ -80,8 +79,6 @@ struct OSTrackMutex {
m_mutex.destroy();
ut_d(m_freed = true);
m_policy.destroy();
}
/** Release the mutex. */
@ -129,15 +126,6 @@ struct OSTrackMutex {
return(locked);
}
#ifdef UNIV_DEBUG
/** @return true if the thread owns the mutex. */
bool is_owned() const
UNIV_NOTHROW
{
return(m_locked && m_policy.is_owned());
}
#endif /* UNIV_DEBUG */
/** @return non-const version of the policy */
MutexPolicy& policy()
UNIV_NOTHROW
@ -208,7 +196,6 @@ struct TTASFutexMutex {
UNIV_NOTHROW
{
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
m_policy.init(*this, id, filename, line);
}
/** Destroy the mutex. */
@ -216,7 +203,6 @@ struct TTASFutexMutex {
{
/* The destructor can be called at shutdown. */
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
m_policy.destroy();
}
/** Acquire the mutex.
@ -230,29 +216,28 @@ struct TTASFutexMutex {
const char* filename,
uint32_t line) UNIV_NOTHROW
{
uint32_t n_spins;
lock_word_t lock = ttas(max_spins, max_delay, n_spins);
uint32_t n_spins, n_waits;
/* If there were no waiters when this thread tried
to acquire the mutex then set the waiters flag now.
Additionally, when this thread set the waiters flag it is
possible that the mutex had already been released
by then. In this case the thread can assume it
was granted the mutex. */
uint32_t n_waits;
if (lock != MUTEX_STATE_UNLOCKED) {
if (lock != MUTEX_STATE_LOCKED || !set_waiters()) {
n_waits = wait();
} else {
n_waits = 0;
for (n_spins= 0; n_spins < max_spins; n_spins++) {
if (try_lock()) {
m_policy.add(n_spins, 0);
return;
}
} else {
n_waits = 0;
ut_delay(ut_rnd_interval(0, max_delay));
}
for (n_waits= 0;; n_waits++) {
if (my_atomic_fas32_explicit(&m_lock_word,
MUTEX_STATE_WAITERS,
MY_MEMORY_ORDER_ACQUIRE)
== MUTEX_STATE_UNLOCKED) {
break;
}
syscall(SYS_futex, &m_lock_word,
FUTEX_WAIT_PRIVATE, MUTEX_STATE_WAITERS,
0, 0, 0);
}
m_policy.add(n_spins, n_waits);
@ -261,53 +246,26 @@ struct TTASFutexMutex {
/** Release the mutex. */
void exit() UNIV_NOTHROW
{
/* If there are threads waiting then we have to wake
them up. Reset the lock state to unlocked so that waiting
threads can test for success. */
os_rmb;
if (state() == MUTEX_STATE_WAITERS) {
m_lock_word = MUTEX_STATE_UNLOCKED;
} else if (unlock() == MUTEX_STATE_LOCKED) {
/* No threads waiting, no need to signal a wakeup. */
return;
if (my_atomic_fas32_explicit(&m_lock_word,
MUTEX_STATE_UNLOCKED,
MY_MEMORY_ORDER_RELEASE)
== MUTEX_STATE_WAITERS) {
syscall(SYS_futex, &m_lock_word, FUTEX_WAKE_PRIVATE,
1, 0, 0, 0);
}
signal();
}
/** Try and lock the mutex.
@return the old state of the mutex */
lock_word_t trylock() UNIV_NOTHROW
{
return(CAS(&m_lock_word,
MUTEX_STATE_UNLOCKED, MUTEX_STATE_LOCKED));
}
/** Try and lock the mutex.
@return true if successful */
bool try_lock() UNIV_NOTHROW
{
return(trylock() == MUTEX_STATE_UNLOCKED);
int32 oldval = MUTEX_STATE_UNLOCKED;
return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_LOCKED,
MY_MEMORY_ORDER_ACQUIRE,
MY_MEMORY_ORDER_RELAXED));
}
/** @return true if mutex is unlocked */
bool is_locked() const UNIV_NOTHROW
{
return(state() != MUTEX_STATE_UNLOCKED);
}
#ifdef UNIV_DEBUG
/** @return true if the thread owns the mutex. */
bool is_owned() const UNIV_NOTHROW
{
return(is_locked() && m_policy.is_owned());
}
#endif /* UNIV_DEBUG */
/** @return non-const version of the policy */
MutexPolicy& policy() UNIV_NOTHROW
{
@ -320,105 +278,12 @@ struct TTASFutexMutex {
return(m_policy);
}
private:
/** @return the lock state. */
lock_word_t state() const UNIV_NOTHROW
{
return(m_lock_word);
}
/** Release the mutex.
@return the new state of the mutex */
lock_word_t unlock() UNIV_NOTHROW
{
return(TAS(&m_lock_word, MUTEX_STATE_UNLOCKED));
}
/** Note that there are threads waiting and need to be woken up.
@return true if state was MUTEX_STATE_UNLOCKED (ie. granted) */
bool set_waiters() UNIV_NOTHROW
{
return(TAS(&m_lock_word, MUTEX_STATE_WAITERS)
== MUTEX_STATE_UNLOCKED);
}
/** Set the waiters flag, only if the mutex is locked
@return true if succesful. */
bool try_set_waiters() UNIV_NOTHROW
{
return(CAS(&m_lock_word,
MUTEX_STATE_LOCKED, MUTEX_STATE_WAITERS)
!= MUTEX_STATE_UNLOCKED);
}
/** Wait if the lock is contended.
@return the number of waits */
uint32_t wait() UNIV_NOTHROW
{
uint32_t n_waits = 0;
/* Use FUTEX_WAIT_PRIVATE because our mutexes are
not shared between processes. */
do {
++n_waits;
syscall(SYS_futex, &m_lock_word,
FUTEX_WAIT_PRIVATE, MUTEX_STATE_WAITERS,
0, 0, 0);
// Since we are retrying the operation the return
// value doesn't matter.
} while (!set_waiters());
return(n_waits);
}
/** Wakeup a waiting thread */
void signal() UNIV_NOTHROW
{
syscall(SYS_futex, &m_lock_word, FUTEX_WAKE_PRIVATE,
MUTEX_STATE_LOCKED, 0, 0, 0);
}
/** Poll waiting for mutex to be unlocked.
@param[in] max_spins max spins
@param[in] max_delay max delay per spin
@param[out] n_spins retries before acquire
@return value of lock word before locking. */
lock_word_t ttas(
uint32_t max_spins,
uint32_t max_delay,
uint32_t& n_spins) UNIV_NOTHROW
{
os_rmb;
for (n_spins = 0; n_spins < max_spins; ++n_spins) {
if (!is_locked()) {
lock_word_t lock = trylock();
if (lock == MUTEX_STATE_UNLOCKED) {
/* Lock successful */
return(lock);
}
}
ut_delay(ut_rnd_interval(0, max_delay));
}
return(trylock());
}
private:
/** Policy data */
MutexPolicy m_policy;
/** lock_word is the target of the atomic test-and-set instruction
when atomic operations are enabled. */
lock_word_t m_lock_word MY_ALIGNED(MY_ALIGNOF(ulint));
int32 m_lock_word;
};
#endif /* HAVE_IB_LINUX_FUTEX */
@ -453,7 +318,6 @@ struct TTASMutex {
UNIV_NOTHROW
{
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
m_policy.init(*this, id, filename, line);
}
/** Destroy the mutex. */
@ -461,45 +325,25 @@ struct TTASMutex {
{
/* The destructor can be called at shutdown. */
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
m_policy.destroy();
}
/**
Try and acquire the lock using TestAndSet.
@return true if lock succeeded */
bool tas_lock() UNIV_NOTHROW
{
return(TAS(&m_lock_word, MUTEX_STATE_LOCKED)
== MUTEX_STATE_UNLOCKED);
}
/** In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead. */
void tas_unlock() UNIV_NOTHROW
{
#ifdef UNIV_DEBUG
ut_ad(state() == MUTEX_STATE_LOCKED);
lock_word_t lock =
#endif /* UNIV_DEBUG */
TAS(&m_lock_word, MUTEX_STATE_UNLOCKED);
ut_ad(lock == MUTEX_STATE_LOCKED);
}
/** Try and lock the mutex.
@return true on success */
bool try_lock() UNIV_NOTHROW
{
return(tas_lock());
int32 oldval = MUTEX_STATE_UNLOCKED;
return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_LOCKED,
MY_MEMORY_ORDER_ACQUIRE,
MY_MEMORY_ORDER_RELAXED));
}
/** Release the mutex. */
void exit() UNIV_NOTHROW
{
tas_unlock();
ut_ad(m_lock_word == MUTEX_STATE_LOCKED);
my_atomic_store32_explicit(&m_lock_word, MUTEX_STATE_UNLOCKED,
MY_MEMORY_ORDER_RELEASE);
}
/** Acquire the mutex.
@ -513,35 +357,20 @@ struct TTASMutex {
const char* filename,
uint32_t line) UNIV_NOTHROW
{
if (!try_lock()) {
const uint32_t step = max_spins;
uint32_t n_spins = 0;
uint32_t n_spins = ttas(max_spins, max_delay);
/* No OS waits for spin mutexes */
m_policy.add(n_spins, 0);
while (!try_lock()) {
ut_delay(ut_rnd_interval(0, max_delay));
if (++n_spins == max_spins) {
os_thread_yield();
max_spins+= step;
}
}
}
/** @return the lock state. */
lock_word_t state() const UNIV_NOTHROW
{
return(m_lock_word);
m_policy.add(n_spins, 0);
}
/** @return true if locked by some thread */
bool is_locked() const UNIV_NOTHROW
{
return(m_lock_word != MUTEX_STATE_UNLOCKED);
}
#ifdef UNIV_DEBUG
/** @return true if the calling thread owns the mutex. */
bool is_owned() const UNIV_NOTHROW
{
return(is_locked() && m_policy.is_owned());
}
#endif /* UNIV_DEBUG */
/** @return non-const version of the policy */
MutexPolicy& policy() UNIV_NOTHROW
{
@ -554,43 +383,6 @@ struct TTASMutex {
return(m_policy);
}
private:
/** Spin and try to acquire the lock.
@param[in] max_spins max spins
@param[in] max_delay max delay per spin
@return number spins before acquire */
uint32_t ttas(
uint32_t max_spins,
uint32_t max_delay)
UNIV_NOTHROW
{
uint32_t i = 0;
const uint32_t step = max_spins;
os_rmb;
do {
while (is_locked()) {
ut_delay(ut_rnd_interval(0, max_delay));
++i;
if (i >= max_spins) {
max_spins += step;
os_thread_yield();
break;
}
}
} while (!try_lock());
return(i);
}
private:
// Disable copying
TTASMutex(const TTASMutex&);
@ -601,7 +393,7 @@ private:
/** lock_word is the target of the atomic test-and-set instruction
when atomic operations are enabled. */
lock_word_t m_lock_word;
int32 m_lock_word;
};
template <template <typename> class Policy = NoPolicy>
@ -613,7 +405,6 @@ struct TTASEventMutex {
UNIV_NOTHROW
:
m_lock_word(MUTEX_STATE_UNLOCKED),
m_waiters(),
m_event()
{
/* Check that lock_word is aligned. */
@ -641,8 +432,6 @@ struct TTASEventMutex {
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
m_event = os_event_create(sync_latch_get_name(id));
m_policy.init(*this, id, filename, line);
}
/** This is the real desctructor. This mutex can be created in BSS and
@ -656,8 +445,6 @@ struct TTASEventMutex {
/* We have to free the event before InnoDB shuts down. */
os_event_destroy(m_event);
m_event = 0;
m_policy.destroy();
}
/** Try and lock the mutex. Note: POSIX returns 0 on success.
@ -665,29 +452,23 @@ struct TTASEventMutex {
bool try_lock()
UNIV_NOTHROW
{
return(tas_lock());
int32 oldval = MUTEX_STATE_UNLOCKED;
return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_LOCKED,
MY_MEMORY_ORDER_ACQUIRE,
MY_MEMORY_ORDER_RELAXED));
}
/** Release the mutex. */
void exit()
UNIV_NOTHROW
{
/* A problem: we assume that mutex_reset_lock word
is a memory barrier, that is when we read the waiters
field next, the read must be serialized in memory
after the reset. A speculative processor might
perform the read first, which could leave a waiting
thread hanging indefinitely.
Our current solution call every second
sync_arr_wake_threads_if_sema_free()
to wake up possible hanging threads if they are missed
in mutex_signal_object. */
tas_unlock();
if (m_waiters != 0) {
signal();
if (my_atomic_fas32_explicit(&m_lock_word,
MUTEX_STATE_UNLOCKED,
MY_MEMORY_ORDER_RELEASE)
== MUTEX_STATE_WAITERS) {
os_event_set(m_event);
sync_array_object_signalled();
}
}
@ -703,13 +484,46 @@ struct TTASEventMutex {
uint32_t line)
UNIV_NOTHROW
{
if (!try_lock()) {
spin_and_try_lock(max_spins, max_delay, filename, line);
uint32_t n_spins = 0;
uint32_t n_waits = 0;
const uint32_t step = max_spins;
while (!try_lock()) {
if (n_spins++ == max_spins) {
max_spins += step;
n_waits++;
os_thread_yield();
sync_cell_t* cell;
sync_array_t *sync_arr = sync_array_get_and_reserve_cell(
this,
(m_policy.get_id() == LATCH_ID_BUF_BLOCK_MUTEX
|| m_policy.get_id() == LATCH_ID_BUF_POOL_ZIP)
? SYNC_BUF_BLOCK
: SYNC_MUTEX,
filename, line, &cell);
int32 oldval = MUTEX_STATE_LOCKED;
my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_WAITERS,
MY_MEMORY_ORDER_RELAXED,
MY_MEMORY_ORDER_RELAXED);
if (oldval == MUTEX_STATE_UNLOCKED) {
sync_array_free_cell(sync_arr, cell);
} else {
sync_array_wait_event(sync_arr, cell);
}
} else {
ut_delay(ut_rnd_interval(0, max_delay));
}
}
m_policy.add(n_spins, n_waits);
}
/** @return the lock state. */
lock_word_t state() const
int32 state() const
UNIV_NOTHROW
{
return(m_lock_word);
@ -723,22 +537,6 @@ struct TTASEventMutex {
return(m_event);
}
/** @return true if locked by some thread */
bool is_locked() const
UNIV_NOTHROW
{
return(m_lock_word != MUTEX_STATE_UNLOCKED);
}
#ifdef UNIV_DEBUG
/** @return true if the calling thread owns the mutex. */
bool is_owned() const
UNIV_NOTHROW
{
return(is_locked() && m_policy.is_owned());
}
#endif /* UNIV_DEBUG */
/** @return non-const version of the policy */
MutexPolicy& policy()
UNIV_NOTHROW
@ -753,153 +551,6 @@ struct TTASEventMutex {
return(m_policy);
}
private:
/** Wait in the sync array.
@param[in] filename from where it was called
@param[in] line line number in file
@param[in] spin retry this many times again
@return true if the mutex acquisition was successful. */
bool wait(
const char* filename,
uint32_t line,
uint32_t spin)
UNIV_NOTHROW;
/** Spin and wait for the mutex to become free.
@param[in] max_spins max spins
@param[in] max_delay max delay per spin
@param[in,out] n_spins spin start index
@return true if unlocked */
bool is_free(
uint32_t max_spins,
uint32_t max_delay,
uint32_t& n_spins) const
UNIV_NOTHROW
{
ut_ad(n_spins <= max_spins);
/* Spin waiting for the lock word to become zero. Note
that we do not have to assume that the read access to
the lock word is atomic, as the actual locking is always
committed with atomic test-and-set. In reality, however,
all processors probably have an atomic read of a memory word. */
do {
if (!is_locked()) {
return(true);
}
ut_delay(ut_rnd_interval(0, max_delay));
++n_spins;
} while (n_spins < max_spins);
return(false);
}
/** Spin while trying to acquire the mutex
@param[in] max_spins max number of spins
@param[in] max_delay max delay per spin
@param[in] filename from where called
@param[in] line within filename */
void spin_and_try_lock(
uint32_t max_spins,
uint32_t max_delay,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
uint32_t n_spins = 0;
uint32_t n_waits = 0;
const uint32_t step = max_spins;
os_rmb;
for (;;) {
/* If the lock was free then try and acquire it. */
if (is_free(max_spins, max_delay, n_spins)) {
if (try_lock()) {
break;
} else {
continue;
}
} else {
max_spins = n_spins + step;
}
++n_waits;
os_thread_yield();
/* The 4 below is a heuristic that has existed for a
very long time now. It is unclear if changing this
value will make a difference.
NOTE: There is a delay that happens before the retry,
finding a free slot in the sync arary and the yield
above. Otherwise we could have simply done the extra
spin above. */
if (wait(filename, line, 4)) {
n_spins += 4;
break;
}
}
/* Waits and yields will be the same number in our
mutex design */
m_policy.add(n_spins, n_waits);
}
/** @return the value of the m_waiters flag */
lock_word_t waiters() UNIV_NOTHROW
{
return(m_waiters);
}
/** Note that there are threads waiting on the mutex */
void set_waiters() UNIV_NOTHROW
{
m_waiters = 1;
os_wmb;
}
/** Note that there are no threads waiting on the mutex */
void clear_waiters() UNIV_NOTHROW
{
m_waiters = 0;
os_wmb;
}
/** Try and acquire the lock using TestAndSet.
@return true if lock succeeded */
bool tas_lock() UNIV_NOTHROW
{
return(TAS(&m_lock_word, MUTEX_STATE_LOCKED)
== MUTEX_STATE_UNLOCKED);
}
/** In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead. */
void tas_unlock() UNIV_NOTHROW
{
TAS(&m_lock_word, MUTEX_STATE_UNLOCKED);
}
/** Wakeup any waiting thread(s). */
void signal() UNIV_NOTHROW;
private:
/** Disable copying */
TTASEventMutex(const TTASEventMutex&);
@ -907,11 +558,7 @@ private:
/** lock_word is the target of the atomic test-and-set instruction
when atomic operations are enabled. */
lock_word_t m_lock_word;
/** Set to 0 or 1. 1 if there are (or may be) threads waiting
in the global wait array for this mutex to be released. */
lock_word_t m_waiters;
int32 m_lock_word;
/** Used by sync0arr.cc for the wait queue */
os_event_t m_event;
@ -1031,7 +678,7 @@ struct PolicyMutex
/** @return true if the thread owns the mutex. */
bool is_owned() const UNIV_NOTHROW
{
return(m_impl.is_owned());
return(policy().is_owned());
}
#endif /* UNIV_DEBUG */
@ -1052,6 +699,7 @@ struct PolicyMutex
#endif /* UNIV_PFS_MUTEX */
m_impl.init(id, filename, line);
policy().init(m_impl, id, filename, line);
}
/** Free resources (if any) */
@ -1061,6 +709,7 @@ struct PolicyMutex
pfs_del();
#endif /* UNIV_PFS_MUTEX */
m_impl.destroy();
policy().destroy();
}
/** Required for os_event_t */

View file

@ -40,6 +40,17 @@ Created 5/7/1996 Heikki Tuuri
#include "gis0rtree.h"
#include "lock0prdt.h"
/** Alternatives for innodb_lock_schedule_algorithm, which can be changed by
setting innodb_lock_schedule_algorithm. */
enum innodb_lock_schedule_algorithm_t {
/*!< First Come First Served */
INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS,
/*!< Variance-Aware-Transaction-Scheduling */
INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
};
extern ulong innodb_lock_schedule_algorithm;
// Forward declaration
class ReadView;

View file

@ -1,397 +0,0 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
briefly in the InnoDB documentation. The contributions by Google are
incorporated with their permission, and subject to the conditions contained in
the file COPYING.Google.
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, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/os0atomic.h
Macros for using atomics
Created 2012-09-23 Sunny Bains (Split from os0sync.h)
*******************************************************/
#ifndef os0atomic_h
#define os0atomic_h
#include "univ.i"
#ifdef _WIN32
/** On Windows, InterlockedExchange operates on LONG variable */
typedef LONG lock_word_t;
#elif defined(MUTEX_FUTEX)
typedef int lock_word_t;
# else
typedef ulint lock_word_t;
#endif /* _WIN32 */
#if defined __i386__ || defined __x86_64__ || defined _M_IX86 \
|| defined _M_X64 || defined __WIN__
#define IB_STRONG_MEMORY_MODEL
#endif /* __i386__ || __x86_64__ || _M_IX86 || _M_X64 || __WIN__ */
/**********************************************************//**
Atomic compare-and-swap and increment for InnoDB. */
/** Do an atomic test and set.
@param[in/out] ptr Memory location to set
@param[in] new_val new value
@return old value of memory location. */
UNIV_INLINE
lock_word_t
os_atomic_test_and_set(
volatile lock_word_t* ptr,
lock_word_t new_val);
/** Do an atomic compare and set
@param[in/out] ptr Memory location to set
@param[in] old_val old value to compare
@param[in] new_val new value to set
@return the value of ptr before the operation. */
UNIV_INLINE
lock_word_t
os_atomic_val_compare_and_swap(
volatile lock_word_t* ptr,
lock_word_t old_val,
lock_word_t new_val);
#ifdef _WIN32
/**********************************************************//**
Atomic compare and exchange of signed integers (both 32 and 64 bit).
@return value found before the exchange.
If it is not equal to old_value the exchange did not happen. */
UNIV_INLINE
lint
win_cmp_and_xchg_lint(
/*==================*/
volatile lint* ptr, /*!< in/out: source/destination */
lint new_val, /*!< in: exchange value */
lint old_val); /*!< in: value to compare to */
/**********************************************************//**
Atomic addition of signed integers.
@return Initial value of the variable pointed to by ptr */
UNIV_INLINE
lint
win_xchg_and_add(
/*=============*/
volatile lint* ptr, /*!< in/out: address of destination */
lint val); /*!< in: number to be added */
/**********************************************************//**
Atomic compare and exchange of unsigned integers.
@return value found before the exchange.
If it is not equal to old_value the exchange did not happen. */
UNIV_INLINE
ulint
win_cmp_and_xchg_ulint(
/*===================*/
volatile ulint* ptr, /*!< in/out: source/destination */
ulint new_val, /*!< in: exchange value */
ulint old_val); /*!< in: value to compare to */
/**********************************************************//**
Atomic compare and exchange of 32 bit unsigned integers.
@return value found before the exchange.
If it is not equal to old_value the exchange did not happen. */
UNIV_INLINE
DWORD
win_cmp_and_xchg_dword(
/*===================*/
volatile DWORD* ptr, /*!< in/out: source/destination */
DWORD new_val, /*!< in: exchange value */
DWORD old_val); /*!< in: value to compare to */
/**********************************************************//**
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
# define os_compare_and_swap_lint(ptr, old_val, new_val) \
(win_cmp_and_xchg_lint(ptr, new_val, old_val) == old_val)
# define os_compare_and_swap_ulint(ptr, old_val, new_val) \
(win_cmp_and_xchg_ulint(ptr, new_val, old_val) == old_val)
# define os_compare_and_swap_uint32(ptr, old_val, new_val) \
(InterlockedCompareExchange(ptr, new_val, old_val) == old_val)
/* windows thread objects can always be passed to windows atomic functions */
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
(win_cmp_and_xchg_dword(ptr, new_val, old_val) == old_val)
# define INNODB_RW_LOCKS_USE_ATOMICS
# define IB_ATOMICS_STARTUP_MSG \
"Mutexes and rw_locks use Windows interlocked functions"
/**********************************************************//**
Returns the resulting value, ptr is pointer to target, amount is the
amount of increment. */
# define os_atomic_increment_lint(ptr, amount) \
(win_xchg_and_add(ptr, amount) + amount)
# define os_atomic_increment_ulint(ptr, amount) \
(static_cast<ulint>(win_xchg_and_add( \
reinterpret_cast<volatile lint*>(ptr), \
static_cast<lint>(amount))) \
+ static_cast<ulint>(amount))
# define os_atomic_increment_uint32(ptr, amount) \
(static_cast<ulint>(InterlockedExchangeAdd( \
reinterpret_cast<long*>(ptr), \
static_cast<long>(amount))) \
+ static_cast<ulint>(amount))
# define os_atomic_increment_uint64(ptr, amount) \
(static_cast<ib_uint64_t>(InterlockedExchangeAdd64( \
reinterpret_cast<LONGLONG*>(ptr), \
static_cast<LONGLONG>(amount))) \
+ static_cast<ib_uint64_t>(amount))
/**********************************************************//**
Returns the resulting value, ptr is pointer to target, amount is the
amount to decrement. There is no atomic substract function on Windows */
# define os_atomic_decrement_lint(ptr, amount) \
(win_xchg_and_add(ptr, -(static_cast<lint>(amount))) - amount)
# define os_atomic_decrement_ulint(ptr, amount) \
(static_cast<ulint>(win_xchg_and_add( \
reinterpret_cast<volatile lint*>(ptr), \
-(static_cast<lint>(amount)))) \
- static_cast<ulint>(amount))
# define os_atomic_decrement_uint32(ptr, amount) \
(static_cast<ib_uint32_t>(InterlockedExchangeAdd( \
reinterpret_cast<long*>(ptr), \
-(static_cast<long>(amount)))) \
- static_cast<ib_uint32_t>(amount))
# define os_atomic_decrement_uint64(ptr, amount) \
(static_cast<ib_uint64_t>(InterlockedExchangeAdd64( \
reinterpret_cast<LONGLONG*>(ptr), \
-(static_cast<LONGLONG>(amount)))) \
- static_cast<ib_uint64_t>(amount))
#else
/* Fall back to GCC-style atomic builtins. */
/**********************************************************//**
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
#if defined(HAVE_GCC_SYNC_BUILTINS)
# define os_compare_and_swap(ptr, old_val, new_val) \
__sync_bool_compare_and_swap(ptr, old_val, new_val)
# define os_compare_and_swap_ulint(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
# define os_compare_and_swap_lint(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
# define os_compare_and_swap_uint32(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
#else
UNIV_INLINE
bool
os_compare_and_swap_ulint(volatile ulint* ptr, ulint old_val, ulint new_val)
{
#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#else
return __sync_bool_compare_and_swap(ptr, old_val, new_val);
#endif
}
UNIV_INLINE
bool
os_compare_and_swap_lint(volatile lint* ptr, lint old_val, lint new_val)
{
#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#else
return __sync_bool_compare_and_swap(ptr, old_val, new_val);
#endif
}
UNIV_INLINE
bool
os_compare_and_swap_uint32(volatile ib_uint32_t* ptr, ib_uint32_t old_val, ib_uint32_t new_val)
{
#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#else
return __sync_bool_compare_and_swap(ptr, old_val, new_val);
#endif
}
#endif /* HAVE_GCC_SYNC_BUILTINS */
# ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC
#if defined(HAVE_GCC_SYNC_BUILTINS)
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
#else
UNIV_INLINE
bool
os_compare_and_swap_thread_id(volatile os_thread_id_t* ptr, os_thread_id_t old_val, os_thread_id_t new_val)
{
#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#else
return __sync_bool_compare_and_swap(ptr, old_val, new_val);
#endif
}
#endif /* HAVE_GCC_SYNC_BUILTINS */
# define INNODB_RW_LOCKS_USE_ATOMICS
# define IB_ATOMICS_STARTUP_MSG \
"Mutexes and rw_locks use GCC atomic builtins"
# else /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */
# define IB_ATOMICS_STARTUP_MSG \
"Mutexes use GCC atomic builtins, rw_locks do not"
# endif /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */
/**********************************************************//**
Returns the resulting value, ptr is pointer to target, amount is the
amount of increment. */
#if defined(HAVE_GCC_SYNC_BUILTINS)
# define os_atomic_increment(ptr, amount) \
__sync_add_and_fetch(ptr, amount)
#else
#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
# define os_atomic_increment(ptr, amount) \
__atomic_add_fetch(ptr, amount, __ATOMIC_SEQ_CST)
#else
# define os_atomic_increment(ptr, amount) \
__sync_add_and_fetch(ptr, amount)
#endif
#endif /* HAVE_GCC_SYNC_BUILTINS */
# define os_atomic_increment_lint(ptr, amount) \
os_atomic_increment(ptr, amount)
# define os_atomic_increment_ulint(ptr, amount) \
os_atomic_increment(ptr, amount)
# define os_atomic_increment_uint32(ptr, amount ) \
os_atomic_increment(ptr, amount)
# define os_atomic_increment_uint64(ptr, amount) \
os_atomic_increment(ptr, amount)
/* Returns the resulting value, ptr is pointer to target, amount is the
amount to decrement. */
#if defined(HAVE_GCC_SYNC_BUILTINS)
# define os_atomic_decrement(ptr, amount) \
__sync_sub_and_fetch(ptr, amount)
#else
#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
# define os_atomic_decrement(ptr, amount) \
__atomic_sub_fetch(ptr, amount, __ATOMIC_SEQ_CST)
#else
# define os_atomic_decrement(ptr, amount) \
__sync_sub_and_fetch(ptr, amount)
#endif
#endif /* HAVE_GCC_SYNC_BUILTINS */
# define os_atomic_decrement_lint(ptr, amount) \
os_atomic_decrement(ptr, amount)
# define os_atomic_decrement_ulint(ptr, amount) \
os_atomic_decrement(ptr, amount)
# define os_atomic_decrement_uint32(ptr, amount) \
os_atomic_decrement(ptr, amount)
# define os_atomic_decrement_uint64(ptr, amount) \
os_atomic_decrement(ptr, amount)
#endif
#define os_atomic_inc_ulint(m,v,d) os_atomic_increment_ulint(v, d)
#define os_atomic_dec_ulint(m,v,d) os_atomic_decrement_ulint(v, d)
#define TAS(l, n) os_atomic_test_and_set((l), (n))
#define CAS(l, o, n) os_atomic_val_compare_and_swap((l), (o), (n))
/** barrier definitions for memory ordering */
#ifdef HAVE_IB_GCC_ATOMIC_THREAD_FENCE
# define HAVE_MEMORY_BARRIER
# define os_rmb __atomic_thread_fence(__ATOMIC_ACQUIRE)
# define os_wmb __atomic_thread_fence(__ATOMIC_RELEASE)
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"GCC builtin __atomic_thread_fence() is used for memory barrier"
#elif defined(HAVE_IB_GCC_SYNC_SYNCHRONISE)
# define HAVE_MEMORY_BARRIER
# define os_rmb __sync_synchronize()
# define os_wmb __sync_synchronize()
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"GCC builtin __sync_synchronize() is used for memory barrier"
#elif defined(HAVE_IB_MACHINE_BARRIER_SOLARIS)
# define HAVE_MEMORY_BARRIER
# include <mbarrier.h>
# define os_rmb __machine_r_barrier()
# define os_wmb __machine_w_barrier()
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"Solaris memory ordering functions are used for memory barrier"
#elif defined(HAVE_WINDOWS_MM_FENCE) && defined(_WIN64)
# define HAVE_MEMORY_BARRIER
# include <mmintrin.h>
# define os_rmb _mm_lfence()
# define os_wmb _mm_sfence()
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"_mm_lfence() and _mm_sfence() are used for memory barrier"
#else
# define os_rmb
# define os_wmb
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"Memory barrier is not used"
#endif
#ifndef UNIV_NONINL
#include "os0atomic.ic"
#endif /* UNIV_NOINL */
#endif /* !os0atomic_h */

View file

@ -1,224 +0,0 @@
/*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
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, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/os0atomics.ic
The interface to the operating system synchronization primitives.
Created 2012-09-23 Sunny Bains (Split from include/os0sync.ic)
*******************************************************/
#ifdef _WIN32
#include <winbase.h>
/* Use inline functions to make 64 and 32 bit versions of windows atomic
functions so that typecasts are evaluated at compile time. Take advantage
that lint is either __int64 or long int and windows atomic functions work
on __int64 and LONG */
/**********************************************************//**
Atomic compare and exchange of unsigned integers.
@return value found before the exchange.
If it is not equal to old_value the exchange did not happen. */
UNIV_INLINE
lint
win_cmp_and_xchg_lint(
/*==================*/
volatile lint* ptr, /*!< in/out: source/destination */
lint new_val, /*!< in: exchange value */
lint old_val) /*!< in: value to compare to */
{
# ifdef _WIN64
return(InterlockedCompareExchange64(ptr, new_val, old_val));
# else
return(InterlockedCompareExchange(ptr, new_val, old_val));
# endif /* _WIN64 */
}
/**********************************************************//**
Atomic addition of signed integers.
@return Initial value of the variable pointed to by ptr */
UNIV_INLINE
lint
win_xchg_and_add(
/*=============*/
volatile lint* ptr, /*!< in/out: address of destination */
lint val) /*!< in: number to be added */
{
#ifdef _WIN64
return(InterlockedExchangeAdd64(ptr, val));
#else
return(InterlockedExchangeAdd(ptr, val));
#endif /* _WIN64 */
}
/**********************************************************//**
Atomic compare and exchange of unsigned integers.
@return value found before the exchange.
If it is not equal to old_value the exchange did not happen. */
UNIV_INLINE
ulint
win_cmp_and_xchg_ulint(
/*===================*/
volatile ulint* ptr, /*!< in/out: source/destination */
ulint new_val, /*!< in: exchange value */
ulint old_val) /*!< in: value to compare to */
{
return((ulint) win_cmp_and_xchg_lint(
(volatile lint*) ptr,
(lint) new_val,
(lint) old_val));
}
/**********************************************************//**
Atomic compare and exchange of 32-bit unsigned integers.
@return value found before the exchange.
If it is not equal to old_value the exchange did not happen. */
UNIV_INLINE
DWORD
win_cmp_and_xchg_dword(
/*===================*/
volatile DWORD* ptr, /*!< in/out: source/destination */
DWORD new_val, /*!< in: exchange value */
DWORD old_val) /*!< in: value to compare to */
{
ut_ad(sizeof(DWORD) == sizeof(LONG)); /* We assume this. */
return(InterlockedCompareExchange(
(volatile LONG*) ptr,
(LONG) new_val,
(LONG) old_val));
}
/** Do an atomic test and set.
@param[in,out] ptr Memory location to set
@param[in] new_val new value
@return old value of memory location. */
UNIV_INLINE
lock_word_t
os_atomic_test_and_set(
volatile lock_word_t* ptr,
lock_word_t new_val)
{
return(InterlockedExchange(ptr, new_val));
}
/** Do an atomic compare and set
@param[in,out] ptr Memory location to set
@param[in] old_val old value to compare
@param[in] new_val new value to set
@return the value of ptr before the operation. */
UNIV_INLINE
lock_word_t
os_atomic_val_compare_and_swap(
volatile lock_word_t* ptr,
lock_word_t old_val,
lock_word_t new_val)
{
return(static_cast<lock_word_t>(win_cmp_and_xchg_lint(
reinterpret_cast<volatile lint*>(ptr),
static_cast<lint>(new_val),
static_cast<lint>(old_val))));
}
#elif defined(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE)
/** Do an atomic test and set.
@param[in,out] ptr Memory location to set
@param[in] new_val new value
@return old value of memory location. */
UNIV_INLINE
lock_word_t
os_atomic_test_and_set(
volatile lock_word_t* ptr,
lock_word_t new_val)
{
lock_word_t ret;
/* Silence a compiler warning about unused ptr. */
(void) ptr;
#if defined(__powerpc__) || defined(__aarch64__)
__atomic_exchange(ptr, &new_val, &ret, __ATOMIC_SEQ_CST);
#else
__atomic_exchange(ptr, &new_val, &ret, __ATOMIC_RELEASE);
#endif
return(ret);
}
/** Do an atomic compare and set
@param[in,out] ptr Memory location to set
@param[in] old_val old value to compare
@param[in] new_val new value to set
@return the value of ptr before the operation. */
UNIV_INLINE
lock_word_t
os_atomic_val_compare_and_swap(
volatile lock_word_t* ptr,
lock_word_t old_val,
lock_word_t new_val)
{
/* Silence a compiler warning about unused ptr. */
(void) ptr;
#if defined(__powerpc__) || defined(__aarch64__)
__atomic_compare_exchange(ptr, &old_val, &new_val, false,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#else
__atomic_compare_exchange(ptr, &old_val, &new_val, false,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
#endif
return(old_val);
}
#elif defined(IB_STRONG_MEMORY_MODEL)
/** Do an atomic test and set.
@param[in,out] ptr Memory location to set
@param[in] new_val new value
@return old value of memory location. */
UNIV_INLINE
lock_word_t
os_atomic_test_and_set(
volatile lock_word_t* ptr,
lock_word_t new_val)
{
return(__sync_lock_test_and_set(ptr, new_val));
}
/** Do an atomic compare and set
@param[in,out] ptr Memory location to set
@param[in] old_val old value to compare
@param[in] new_val new value to set
@return the value of ptr before the operation. */
UNIV_INLINE
lock_word_t
os_atomic_val_compare_and_swap(
volatile lock_word_t* ptr,
lock_word_t old_val,
lock_word_t new_val)
{
return(__sync_val_compare_and_swap(ptr, old_val, new_val));
}
#else
#error "Unsupported platform"
#endif /* _WIN32 */

View file

@ -29,7 +29,6 @@ Created Feb 20, 2014 Vasil Dimov
#include "univ.i"
#include "os0atomic.h"
#include "ut0ut.h"
/** Execute a given function exactly once in a multi-threaded environment
@ -79,22 +78,19 @@ public:
void (*do_func)(void*),
void* do_func_arg)
{
/* Avoid calling os_compare_and_swap_uint32() in the most
common case. */
int32 oldval = NEVER_DONE;
/* Avoid calling my_atomic_cas32() in the most common case. */
if (*state == DONE) {
return;
}
if (os_compare_and_swap_uint32(state,
NEVER_DONE, IN_PROGRESS)) {
if (my_atomic_cas32((int32*) state, &oldval, IN_PROGRESS)) {
/* We are the first. Call the function. */
do_func(do_func_arg);
const bool swapped = os_compare_and_swap_uint32(
state, IN_PROGRESS, DONE);
ut_a(swapped);
my_atomic_store32((int32*) state, DONE);
} else {
/* The state is not NEVER_DONE, so either it is
IN_PROGRESS (somebody is calling the function right

View file

@ -613,8 +613,8 @@ Use MONITOR_INC if appropriate mutex protection exists.
# define MONITOR_ATOMIC_INC(monitor) \
if (MONITOR_IS_ON(monitor)) { \
ib_uint64_t value; \
value = os_atomic_increment_uint64( \
(ib_uint64_t*) &MONITOR_VALUE(monitor), 1); \
value = my_atomic_add64( \
(int64*) &MONITOR_VALUE(monitor), 1) + 1; \
/* Note: This is not 100% accurate because of the \
inherent race, we ignore it due to performance. */ \
if (value > (ib_uint64_t) MONITOR_MAX_VALUE(monitor)) { \
@ -628,8 +628,8 @@ Use MONITOR_DEC if appropriate mutex protection exists.
# define MONITOR_ATOMIC_DEC(monitor) \
if (MONITOR_IS_ON(monitor)) { \
ib_uint64_t value; \
value = os_atomic_decrement_uint64( \
(ib_uint64_t*) &MONITOR_VALUE(monitor), 1); \
value = my_atomic_add64( \
(int64*) &MONITOR_VALUE(monitor), -1) - 1; \
/* Note: This is not 100% accurate because of the \
inherent race, we ignore it due to performance. */ \
if (value < (ib_uint64_t) MONITOR_MIN_VALUE(monitor)) { \

View file

@ -85,13 +85,6 @@ Note that one of the wait objects was signalled. */
void
sync_array_object_signalled();
/**********************************************************************//**
If the wakeup algorithm does not work perfectly at semaphore relases,
this function will do the waking (see the comment in mutex_exit). This
function should be called about every 1 second in the server. */
void
sync_arr_wake_threads_if_sema_free();
/**********************************************************************//**
Prints warnings of long semaphore waits to stderr.
@return TRUE if fatal semaphore wait threshold was exceeded */

View file

@ -44,6 +44,8 @@ extern my_bool srv_instrument_semaphores;
#endif /* !UNIV_HOTBACKUP */
# define INNODB_RW_LOCKS_USE_ATOMICS
/** Counters for RW locks. */
struct rw_lock_stats_t {
typedef ib_counter_t<int64_t, IB_N_SLOTS> int64_counter_t;

View file

@ -89,10 +89,9 @@ rw_lock_set_waiter_flag(
rw_lock_t* lock) /*!< in/out: rw-lock */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
(void) os_compare_and_swap_ulint(&lock->waiters, 0, 1);
my_atomic_storelint(&lock->waiters, 1);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 1;
os_wmb;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
@ -107,10 +106,9 @@ rw_lock_reset_waiter_flag(
rw_lock_t* lock) /*!< in/out: rw-lock */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
(void) os_compare_and_swap_ulint(&lock->waiters, 1, 0);
my_atomic_storelint(&lock->waiters, 0);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 0;
os_wmb;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
@ -272,15 +270,13 @@ rw_lock_lock_word_decr(
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
lint local_lock_word;
os_rmb;
local_lock_word = lock->lock_word;
while (local_lock_word > threshold) {
if (os_compare_and_swap_lint(&lock->lock_word,
local_lock_word,
local_lock_word - amount)) {
if (my_atomic_caslint(&lock->lock_word,
&local_lock_word,
local_lock_word - amount)) {
return(true);
}
local_lock_word = lock->lock_word;
}
return(false);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
@ -306,7 +302,7 @@ rw_lock_lock_word_incr(
ulint amount) /*!< in: amount of increment */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
return(os_atomic_increment_lint(&lock->lock_word, amount));
return(my_atomic_addlint(&lock->lock_word, amount) + amount);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lint local_lock_word;
@ -341,19 +337,8 @@ rw_lock_set_writer_id_and_recursion_flag(
os_thread_id_t curr_thread = os_thread_get_curr_id();
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
os_thread_id_t local_thread;
ibool success;
/* Prevent Valgrind warnings about writer_thread being
uninitialized. It does not matter if writer_thread is
uninitialized, because we are comparing writer_thread against
itself, and the operation should always succeed. */
UNIV_MEM_VALID(&lock->writer_thread, sizeof lock->writer_thread);
local_thread = lock->writer_thread;
success = os_compare_and_swap_thread_id(
&lock->writer_thread, local_thread, curr_thread);
ut_a(success);
my_atomic_storelong(&lock->writer_thread, (long) curr_thread);
lock->recursive = recursive;
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
@ -459,7 +444,8 @@ rw_lock_x_lock_func_nowait(
ibool local_recursive= lock->recursive;
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
success = os_compare_and_swap_lint(&lock->lock_word, X_LOCK_DECR, 0);
lint oldval = X_LOCK_DECR;
success = my_atomic_caslint(&lock->lock_word, &oldval, 0);
#else
success = FALSE;
@ -473,7 +459,7 @@ rw_lock_x_lock_func_nowait(
#endif
/* Note: recursive must be loaded before writer_thread see
comment for rw_lock_set_writer_id_and_recursion_flag().
To achieve this we load it before os_compare_and_swap_lint(),
To achieve this we load it before my_atomic_caslint(),
which implies full memory barrier in current implementation. */
if (success) {
rw_lock_set_writer_id_and_recursion_flag(lock, true);

View file

@ -28,6 +28,7 @@ Created 9/5/1995 Heikki Tuuri
#include <vector>
#include <iostream>
#include <my_atomic.h>
#include "ut0new.h"
#include "ut0counter.h"
@ -45,12 +46,6 @@ typedef CRITICAL_SECTION sys_mutex_t;
typedef pthread_mutex_t sys_mutex_t;
#endif /* _WIN32 */
/** The new (C++11) syntax allows the following and we should use it when it
is available on platforms that we support.
enum class mutex_state_t : lock_word_t { ... };
*/
/** Mutex states. */
enum mutex_state_t {
/** Mutex is free */
@ -1261,4 +1256,16 @@ enum rw_lock_flag_t {
#endif /* UNIV_INNOCHECKSUM */
#ifdef _WIN64
#define my_atomic_addlint(A,B) my_atomic_add64((int64*) (A), (B))
#define my_atomic_storelint(A,B) my_atomic_store64((int64*) (A), (B))
#define my_atomic_loadlint(A) my_atomic_load64((int64*) (A))
#define my_atomic_caslint(A,B,C) my_atomic_cas64((int64*) (A), (int64*) (B), (C))
#else
#define my_atomic_addlint my_atomic_addlong
#define my_atomic_storelint my_atomic_storelong
#define my_atomic_loadlint my_atomic_loadlong
#define my_atomic_caslint my_atomic_caslong
#endif
#endif /* sync0types_h */

View file

@ -842,8 +842,7 @@ lock_sys->mutex and sometimes by trx->mutex. */
typedef enum {
TRX_SERVER_ABORT = 0,
TRX_WSREP_ABORT = 1,
TRX_REPLICATION_ABORT = 2
TRX_WSREP_ABORT = 1
} trx_abort_t;
@ -1097,6 +1096,8 @@ struct trx_t {
time_t start_time; /*!< time the state last time became
TRX_STATE_ACTIVE */
clock_t start_time_micro; /*!< start time of the transaction
in microseconds. */
lsn_t commit_lsn; /*!< lsn at the time of the commit */
table_id_t table_id; /*!< Table to drop iff dict_operation
== TRX_DICT_OP_TABLE, or 0. */

View file

@ -32,7 +32,6 @@ extern ulong srv_spin_wait_delay;
extern ulong srv_n_spin_wait_rounds;
extern ulong srv_force_recovery_crash;
#include "os0atomic.h"
#include "sync0policy.h"
#include "ib0mutex.h"
#include <set>
@ -45,25 +44,6 @@ extern ulong srv_force_recovery_crash;
typedef OSMutex EventMutex;
#ifndef UNIV_DEBUG
# ifdef HAVE_IB_LINUX_FUTEX
UT_MUTEX_TYPE(TTASFutexMutex, GenericPolicy, FutexMutex);
UT_MUTEX_TYPE(TTASFutexMutex, BlockMutexPolicy, BlockFutexMutex);
# endif /* HAVE_IB_LINUX_FUTEX */
UT_MUTEX_TYPE(TTASMutex, GenericPolicy, SpinMutex);
UT_MUTEX_TYPE(TTASMutex, BlockMutexPolicy, BlockSpinMutex);
UT_MUTEX_TYPE(OSTrackMutex, GenericPolicy, SysMutex);
UT_MUTEX_TYPE(OSTrackMutex, BlockMutexPolicy, BlockSysMutex);
UT_MUTEX_TYPE(TTASEventMutex, GenericPolicy, SyncArrayMutex);
UT_MUTEX_TYPE(TTASEventMutex, BlockMutexPolicy, BlockSyncArrayMutex);
#else /* !UNIV_DEBUG */
# ifdef HAVE_IB_LINUX_FUTEX
UT_MUTEX_TYPE(TTASFutexMutex, GenericPolicy, FutexMutex);
UT_MUTEX_TYPE(TTASFutexMutex, BlockMutexPolicy, BlockFutexMutex);
@ -78,8 +58,6 @@ UT_MUTEX_TYPE(OSTrackMutex, BlockMutexPolicy, BlockSysMutex);
UT_MUTEX_TYPE(TTASEventMutex, GenericPolicy, SyncArrayMutex);
UT_MUTEX_TYPE(TTASEventMutex, BlockMutexPolicy, BlockSyncArrayMutex);
#endif /* !UNIV_DEBUG */
#ifdef MUTEX_FUTEX
/** The default mutex type. */
typedef FutexMutex ib_mutex_t;
@ -97,8 +75,6 @@ typedef BlockSyncArrayMutex ib_bpmutex_t;
#error "ib_mutex_t type is unknown"
#endif /* MUTEX_FUTEX */
#include "ut0mutex.ic"
extern ulong srv_spin_wait_delay;
extern ulong srv_n_spin_wait_rounds;

View file

@ -1,108 +0,0 @@
/*****************************************************************************
Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
briefly in the InnoDB documentation. The contributions by Google are
incorporated with their permission, and subject to the conditions contained in
the file COPYING.Google.
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, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/ut0mutex.ic
Mutex implementation include file
Created 2012/08/21 Sunny Bains
*******************************************************/
#include "sync0arr.h"
#include "sync0debug.h"
/**
Wait in the sync array.
@return true if the mutex acquisition was successful. */
template <template <typename> class Policy>
bool
TTASEventMutex<Policy>::wait(
const char* filename,
uint32_t line,
uint32_t spin)
UNIV_NOTHROW
{
sync_cell_t* cell;
sync_array_t* sync_arr;
sync_arr = sync_array_get_and_reserve_cell(
this,
(m_policy.get_id() == LATCH_ID_BUF_BLOCK_MUTEX
|| m_policy.get_id() == LATCH_ID_BUF_POOL_ZIP)
? SYNC_BUF_BLOCK
: SYNC_MUTEX,
filename, line, &cell);
/* The memory order of the array reservation and
the change in the waiters field is important: when
we suspend a thread, we first reserve the cell and
then set waiters field to 1. When threads are released
in mutex_exit, the waiters field is first set to zero
and then the event is set to the signaled state. */
set_waiters();
/* Try to reserve still a few times. */
for (uint32_t i = 0; i < spin; ++i) {
if (try_lock()) {
sync_array_free_cell(sync_arr, cell);
/* Note that in this case we leave
the waiters field set to 1. We cannot
reset it to zero, as we do not know if
there are other waiters. */
return(true);
}
}
/* Now we know that there has been some thread
holding the mutex after the change in the wait
array and the waiters field was made. Now there
is no risk of infinite wait on the event. */
sync_array_wait_event(sync_arr, cell);
return(false);
}
/** Wakeup any waiting thread(s). */
template <template <typename> class Policy>
void
TTASEventMutex<Policy>::signal() UNIV_NOTHROW
{
clear_waiters();
/* The memory order of resetting the waiters field and
signaling the object is important. See LEMMA 1 above. */
os_event_set(m_event);
sync_array_object_signalled();
}

View file

@ -35,10 +35,6 @@ Created 1/20/1994 Heikki Tuuri
#include "db0err.h"
#ifndef UNIV_HOTBACKUP
# include "os0atomic.h"
#endif /* UNIV_HOTBACKUP */
#include <time.h>
#ifndef MYSQL_SERVER
@ -81,8 +77,9 @@ typedef time_t ib_time_t;
} while (0)
# else
# define UT_RELAX_CPU() do { \
volatile lint volatile_var; \
os_compare_and_swap_lint(&volatile_var, 0, 1); \
volatile int32 volatile_var; \
int32 oldval= 0;
my_atomic_cas32(&volatile_var, &oldval, 1); \
} while (0)
# endif

View file

@ -158,200 +158,12 @@ IF(HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE)
ENDIF()
IF(NOT MSVC)
# either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
# either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
# workaround for gcc 4.1.2 RHEL5/x86, gcc atomic ops only work under -march=i686
IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" AND CMAKE_COMPILER_IS_GNUCC AND
CMAKE_C_COMPILER_VERSION VERSION_LESS "4.1.3")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
ENDIF()
CHECK_C_SOURCE(
"
int main()
{
long x;
long y;
long res;
x = 10;
y = 123;
res = __sync_bool_compare_and_swap(&x, x, y);
if (!res || x != y) {
return(1);
}
x = 10;
y = 123;
res = __sync_bool_compare_and_swap(&x, x + 1, y);
if (res || x != 10) {
return(1);
}
x = 10;
y = 123;
res = __sync_add_and_fetch(&x, y);
if (res != 123 + 10 || x != 123 + 10) {
return(1);
}
return(0);
}"
HAVE_IB_GCC_ATOMIC_BUILTINS
)
CHECK_C_SOURCE(
"
int main()
{
long res;
char c;
c = 10;
res = __sync_lock_test_and_set(&c, 123);
if (res != 10 || c != 123) {
return(1);
}
return(0);
}"
HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE
)
CHECK_C_SOURCE(
"#include<stdint.h>
int main()
{
int64_t x,y,res;
x = 10;
y = 123;
res = __sync_sub_and_fetch(&y, x);
if (res != y || y != 113) {
return(1);
}
res = __sync_add_and_fetch(&y, x);
if (res != y || y != 123) {
return(1);
}
return(0);
}"
HAVE_IB_GCC_ATOMIC_BUILTINS_64
)
CHECK_C_SOURCE(
"#include<stdint.h>
int main()
{
__sync_synchronize();
return(0);
}"
HAVE_IB_GCC_SYNC_SYNCHRONISE
)
CHECK_C_SOURCE(
"#include<stdint.h>
int main()
{
__atomic_thread_fence(__ATOMIC_ACQUIRE);
__atomic_thread_fence(__ATOMIC_RELEASE);
return(0);
}"
HAVE_IB_GCC_ATOMIC_THREAD_FENCE
)
CHECK_C_SOURCE(
"#include<stdint.h>
int main()
{
unsigned char c;
__atomic_test_and_set(&c, __ATOMIC_ACQUIRE);
__atomic_clear(&c, __ATOMIC_RELEASE);
return(0);
}"
HAVE_IB_GCC_ATOMIC_TEST_AND_SET
)
CHECK_C_SOURCE_RUNS(
"#include<stdint.h>
int main()
{
unsigned char a = 0;
unsigned char b = 0;
unsigned char c = 1;
__atomic_exchange(&a, &b, &c, __ATOMIC_RELEASE);
__atomic_compare_exchange(&a, &b, &c, 0,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
return(0);
}"
HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE
)
CHECK_C_SOURCE_RUNS(
"#include<stdint.h>
int main()
{
unsigned char a = 0;
unsigned char b = 0;
unsigned char c = 1;
__atomic_compare_exchange_n(&a, &b, &c, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return (0);
}"
HAVE_IB_GCC_ATOMIC_SEQ_CST
)
IF (HAVE_IB_GCC_ATOMIC_SEQ_CST)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_CST=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_BUILTINS)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_BYTE=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_BUILTINS_64)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_64=1)
ENDIF()
IF(HAVE_IB_GCC_SYNC_SYNCHRONISE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_SYNC_SYNCHRONISE=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_THREAD_FENCE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_THREAD_FENCE=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_TEST_AND_SET=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE=1)
ENDIF()
# either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not
IF(NOT CMAKE_CROSSCOMPILING)
CHECK_C_SOURCE_RUNS(
"
#include <pthread.h>
#include <string.h>
int main() {
pthread_t x1;
pthread_t x2;
pthread_t x3;
memset(&x1, 0x0, sizeof(x1));
memset(&x2, 0x0, sizeof(x2));
memset(&x3, 0x0, sizeof(x3));
__sync_bool_compare_and_swap(&x1, x2, x3);
return(0);
}"
HAVE_IB_ATOMIC_PTHREAD_T_GCC)
ENDIF()
IF(HAVE_IB_ATOMIC_PTHREAD_T_GCC)
ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_GCC=1)
ENDIF()
# Only use futexes on Linux if GCC atomics are available
IF(NOT MSVC AND NOT CMAKE_CROSSCOMPILING)
@ -402,73 +214,6 @@ IF(HAVE_C99_INITIALIZERS)
ADD_DEFINITIONS(-DHAVE_C99_INITIALIZERS)
ENDIF()
# Solaris atomics
IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
CHECK_FUNCTION_EXISTS(atomic_cas_ulong HAVE_ATOMIC_CAS_ULONG)
CHECK_FUNCTION_EXISTS(atomic_cas_32 HAVE_ATOMIC_CAS_32)
CHECK_FUNCTION_EXISTS(atomic_cas_64 HAVE_ATOMIC_CAS_64)
CHECK_FUNCTION_EXISTS(atomic_add_long_nv HAVE_ATOMIC_ADD_LONG_NV)
CHECK_FUNCTION_EXISTS(atomic_swap_uchar HAVE_ATOMIC_SWAP_UCHAR)
IF(HAVE_ATOMIC_CAS_ULONG AND
HAVE_ATOMIC_CAS_32 AND
HAVE_ATOMIC_CAS_64 AND
HAVE_ATOMIC_ADD_LONG_NV AND
HAVE_ATOMIC_SWAP_UCHAR)
SET(HAVE_IB_SOLARIS_ATOMICS 1)
ENDIF()
IF(HAVE_IB_SOLARIS_ATOMICS)
ADD_DEFINITIONS(-DHAVE_IB_SOLARIS_ATOMICS=1)
ENDIF()
# either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not
CHECK_C_SOURCE_COMPILES(
" #include <pthread.h>
#include <string.h>
int main(int argc, char** argv) {
pthread_t x1;
pthread_t x2;
pthread_t x3;
memset(&x1, 0x0, sizeof(x1));
memset(&x2, 0x0, sizeof(x2));
memset(&x3, 0x0, sizeof(x3));
if (sizeof(pthread_t) == 4) {
atomic_cas_32(&x1, x2, x3);
} else if (sizeof(pthread_t) == 8) {
atomic_cas_64(&x1, x2, x3);
} else {
return(1);
}
return(0);
}
" HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
CHECK_C_SOURCE_COMPILES(
"#include <mbarrier.h>
int main() {
__machine_r_barrier();
__machine_w_barrier();
return(0);
}"
HAVE_IB_MACHINE_BARRIER_SOLARIS)
IF(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_SOLARIS=1)
ENDIF()
IF(HAVE_IB_MACHINE_BARRIER_SOLARIS)
ADD_DEFINITIONS(-DHAVE_IB_MACHINE_BARRIER_SOLARIS=1)
ENDIF()
ENDIF()
IF(UNIX)
# this is needed to know which one of atomic_cas_32() or atomic_cas_64()
# to use in the source
@ -481,11 +226,6 @@ IF(SIZEOF_PTHREAD_T)
ADD_DEFINITIONS(-DSIZEOF_PTHREAD_T=${SIZEOF_PTHREAD_T})
ENDIF()
IF(MSVC)
ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS)
ADD_DEFINITIONS(-DHAVE_WINDOWS_MM_FENCE)
ENDIF()
SET(MUTEXTYPE "event" CACHE STRING "Mutex type: event, sys or futex")
IF(MUTEXTYPE MATCHES "event")

View file

@ -30,6 +30,7 @@ Created 5/7/1996 Heikki Tuuri
#include "ha_prototypes.h"
#include <mysql/service_thd_error_context.h>
#include <sql_class.h>
#include "lock0lock.h"
#include "lock0priv.h"
@ -58,6 +59,9 @@ Created 5/7/1996 Heikki Tuuri
#include <mysql/service_wsrep.h>
#endif /* WITH_WSREP */
/** Lock scheduling algorithm */
ulong innodb_lock_schedule_algorithm = INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS;
/** Total number of cached record locks */
static const ulint REC_LOCK_CACHE = 8;
@ -70,17 +74,32 @@ static const ulint TABLE_LOCK_CACHE = 8;
/** Size in bytes, of the table lock instance */
static const ulint TABLE_LOCK_SIZE = sizeof(ib_lock_t);
/* Buffer to collect THDs to report waits for. */
struct thd_wait_reports {
struct thd_wait_reports *next; /*!< List link */
ulint used; /*!< How many elements in waitees[] */
trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */
};
/*********************************************************************//**
Checks if a waiting record lock request still has to wait in a queue.
@return lock that is causing the wait */
static
const lock_t*
lock_rec_has_to_wait_in_queue(
/*==========================*/
const lock_t* wait_lock); /*!< in: waiting record lock */
extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd);
extern "C" int thd_need_wait_for(const MYSQL_THD thd);
/*************************************************************//**
Grants a lock to a waiting lock request and releases the waiting transaction.
The caller must hold lock_sys->mutex. */
static
void
lock_grant(
/*=======*/
lock_t* lock, /*!< in/out: waiting lock request */
bool owns_trx_mutex); /*!< in: whether lock->trx->mutex is owned */
extern "C" void thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd);
extern "C" int thd_need_wait_reports(const MYSQL_THD thd);
extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd);
extern "C" int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2);
/** Deadlock checker. */
class DeadlockChecker {
public:
@ -109,7 +128,7 @@ private:
const trx_t* trx,
const lock_t* wait_lock,
ib_uint64_t mark_start,
struct thd_wait_reports* waitee_buf_ptr)
bool report_waiters)
:
m_cost(),
m_start(trx),
@ -117,7 +136,7 @@ private:
m_wait_lock(wait_lock),
m_mark_start(mark_start),
m_n_elems(),
m_waitee_ptr(waitee_buf_ptr)
m_report_waiters(report_waiters)
{
}
@ -276,8 +295,8 @@ private:
/** This is to avoid malloc/free calls. */
static state_t s_states[MAX_STACK_SIZE];
/** Buffer to collect THDs to report waits for. */
struct thd_wait_reports* m_waitee_ptr;
/** Set if thd_rpl_deadlock_check() should be called for waits. */
bool m_report_waiters;
};
/** Counter to mark visited nodes during deadlock search. */
@ -286,11 +305,6 @@ ib_uint64_t DeadlockChecker::s_lock_mark_counter = 0;
/** The stack used for deadlock searches. */
DeadlockChecker::state_t DeadlockChecker::s_states[MAX_STACK_SIZE];
extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd);
extern "C" int thd_need_wait_for(const MYSQL_THD thd);
extern "C"
int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd);
#ifdef UNIV_DEBUG
/*********************************************************************//**
Validates the lock system.
@ -1713,6 +1727,167 @@ RecLock::lock_alloc(
return(lock);
}
/*********************************************************************//**
Check if lock1 has higher priority than lock2.
NULL has lowest priority.
If either is a high priority transaction, the lock has higher priority.
If neither of them is wait lock, the first one has higher priority.
If only one of them is a wait lock, it has lower priority.
Otherwise, the one with an older transaction has higher priority.
@returns true if lock1 has higher priority, false otherwise. */
bool
has_higher_priority(
lock_t *lock1,
lock_t *lock2)
{
if (lock1 == NULL) {
return false;
} else if (lock2 == NULL) {
return true;
}
// Ask the upper server layer if any of the two trx should be prefered.
int preference = thd_deadlock_victim_preference(lock1->trx->mysql_thd, lock2->trx->mysql_thd);
if (preference == -1) {
// lock1 is preferred as a victim, so lock2 has higher priority
return false;
} else if (preference == 1) {
// lock2 is preferred as a victim, so lock1 has higher priority
return true;
}
if (trx_is_high_priority(lock1->trx)) {
return true;
}
if (trx_is_high_priority(lock2->trx)) {
return false;
}
// No preference. Compre them by wait mode and trx age.
if (!lock_get_wait(lock1)) {
return true;
} else if (!lock_get_wait(lock2)) {
return false;
}
return lock1->trx->start_time_micro <= lock2->trx->start_time_micro;
}
/*********************************************************************//**
Insert a lock to the hash list according to the mode (whether it is a wait
lock) and the age of the transaction the it is associated with.
If the lock is not a wait lock, insert it to the head of the hash list.
Otherwise, insert it to the middle of the wait locks according to the age of
the transaciton. */
static
dberr_t
lock_rec_insert_by_trx_age(
lock_t *in_lock) /*!< in: lock to be insert */{
ulint space;
ulint page_no;
ulint rec_fold;
lock_t* node;
lock_t* next;
hash_table_t* hash;
hash_cell_t* cell;
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
hash = lock_hash_get(in_lock->type_mode);
cell = hash_get_nth_cell(hash,
hash_calc_hash(rec_fold, hash));
node = (lock_t *) cell->node;
// If in_lock is not a wait lock, we insert it to the head of the list.
if (node == NULL || !lock_get_wait(in_lock) || has_higher_priority(in_lock, node)) {
cell->node = in_lock;
in_lock->hash = node;
if (lock_get_wait(in_lock)) {
lock_grant(in_lock, true);
return DB_SUCCESS_LOCKED_REC;
}
return DB_SUCCESS;
}
while (node != NULL && has_higher_priority((lock_t *) node->hash,
in_lock)) {
node = (lock_t *) node->hash;
}
next = (lock_t *) node->hash;
node->hash = in_lock;
in_lock->hash = next;
if (lock_get_wait(in_lock) && !lock_rec_has_to_wait_in_queue(in_lock)) {
lock_grant(in_lock, true);
if (cell->node != in_lock) {
// Move it to the front of the queue
node->hash = in_lock->hash;
next = (lock_t *) cell->node;
cell->node = in_lock;
in_lock->hash = next;
}
return DB_SUCCESS_LOCKED_REC;
}
return DB_SUCCESS;
}
static
bool
lock_queue_validate(
const lock_t *in_lock) /*!< in: lock whose hash list is to be validated */
{
ulint space;
ulint page_no;
ulint rec_fold;
hash_table_t* hash;
hash_cell_t* cell;
lock_t* next;
bool wait_lock = false;
if (in_lock == NULL) {
return true;
}
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
hash = lock_hash_get(in_lock->type_mode);
cell = hash_get_nth_cell(hash,
hash_calc_hash(rec_fold, hash));
next = (lock_t *) cell->node;
while (next != NULL) {
// If this is a granted lock, check that there's no wait lock before it.
if (!lock_get_wait(next)) {
ut_ad(!wait_lock);
} else {
wait_lock = true;
}
next = next->hash;
}
return true;
}
static
void
lock_rec_insert_to_head(
lock_t *in_lock, /*!< in: lock to be insert */
ulint rec_fold) /*!< in: rec_fold of the page */
{
hash_table_t* hash;
hash_cell_t* cell;
lock_t* node;
if (in_lock == NULL) {
return;
}
hash = lock_hash_get(in_lock->type_mode);
cell = hash_get_nth_cell(hash,
hash_calc_hash(rec_fold, hash));
node = (lock_t *) cell->node;
if (node != in_lock) {
cell->node = in_lock;
in_lock->hash = node;
}
}
/**
Add the lock to the record lock hash and the transaction's lock list
@param[in,out] lock Newly created record lock to add to the rec hash
@ -1723,15 +1898,27 @@ RecLock::lock_add(lock_t* lock, bool add_to_hash)
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(lock->trx));
bool wait_lock = m_mode & LOCK_WAIT;
if (add_to_hash) {
ulint key = m_rec_id.fold();
hash_table_t *lock_hash = lock_hash_get(m_mode);
++lock->index->table->n_rec_locks;
HASH_INSERT(lock_t, hash, lock_hash_get(m_mode), key, lock);
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
if (wait_lock) {
HASH_INSERT(lock_t, hash, lock_hash, key, lock);
} else {
lock_rec_insert_to_head(lock, m_rec_id.fold());
}
} else {
HASH_INSERT(lock_t, hash, lock_hash, key, lock);
}
}
if (m_mode & LOCK_WAIT) {
if (wait_lock) {
lock_set_lock_and_trx_wait(lock, lock->trx);
}
@ -1986,12 +2173,8 @@ RecLock::mark_trx_for_rollback(trx_t* trx)
trx->in_innodb |= TRX_FORCE_ROLLBACK | TRX_FORCE_ROLLBACK_ASYNC;
bool cas;
os_thread_id_t thread_id = os_thread_get_curr_id();
cas = os_compare_and_swap_thread_id(&trx->killed_by, 0, thread_id);
ut_a(cas);
ut_a(!trx->killed_by);
my_atomic_storelong(&trx->killed_by, (long) os_thread_get_curr_id());
m_trx->hit_list.push_back(hit_list_t::value_type(trx));
@ -2075,13 +2258,21 @@ RecLock::add_to_waitq(const lock_t* wait_for, const lock_prdt_t* prdt)
ut_ad(trx_mutex_own(m_trx));
/* m_trx->mysql_thd is NULL if it's an internal trx. So current_thd is used */
if (err == DB_LOCK_WAIT) {
ut_ad(wait_for && wait_for->trx);
wait_for->trx->abort_type = TRX_REPLICATION_ABORT;
thd_report_wait_for(current_thd, wait_for->trx->mysql_thd);
wait_for->trx->abort_type = TRX_SERVER_ABORT;
// Move it only when it does not cause a deadlock.
if (err != DB_DEADLOCK
&& innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)
&& !trx_is_high_priority(lock->trx)) {
HASH_DELETE(lock_t, hash, lock_hash_get(lock->type_mode),
m_rec_id.fold(), lock);
dberr_t res = lock_rec_insert_by_trx_age(lock);
if (res != DB_SUCCESS) {
return res;
}
}
return(err);
}
@ -2496,13 +2687,17 @@ static
void
lock_grant(
/*=======*/
lock_t* lock) /*!< in/out: waiting lock request */
lock_t* lock, /*!< in/out: waiting lock request */
bool owns_trx_mutex) /*!< in: whether lock->trx->mutex is owned */
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(lock->trx) == owns_trx_mutex);
lock_reset_lock_and_trx_wait(lock);
trx_mutex_enter(lock->trx);
if (!owns_trx_mutex) {
trx_mutex_enter(lock->trx);
}
if (lock_get_mode(lock) == LOCK_AUTO_INC) {
dict_table_t* table = lock->un_member.tab_lock.table;
@ -2535,7 +2730,9 @@ lock_grant(
}
}
trx_mutex_exit(lock->trx);
if (!owns_trx_mutex) {
trx_mutex_exit(lock->trx);
}
}
/**
@ -2799,6 +2996,78 @@ lock_rec_cancel(
trx_mutex_exit(lock->trx);
}
static
void
lock_grant_and_move_on_page(
hash_table_t* lock_hash,
ulint space,
ulint page_no)
{
lock_t* lock;
lock_t* previous;
ulint rec_fold = lock_rec_fold(space, page_no);
previous = (lock_t *) hash_get_nth_cell(lock_hash,
hash_calc_hash(rec_fold, lock_hash))->node;
if (previous == NULL) {
return;
}
if (previous->un_member.rec_lock.space == space &&
previous->un_member.rec_lock.page_no == page_no) {
lock = previous;
}
else {
while (previous->hash &&
(previous->hash->un_member.rec_lock.space != space ||
previous->hash->un_member.rec_lock.page_no != page_no)) {
previous = previous->hash;
}
lock = previous->hash;
}
ut_ad(previous->hash == lock || previous == lock);
/* Grant locks if there are no conflicting locks ahead.
Move granted locks to the head of the list. */
for (;lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if ((lock->un_member.rec_lock.space == space)
&& (lock->un_member.rec_lock.page_no == page_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
bool exit_trx_mutex = false;
if (lock->trx->abort_type != TRX_SERVER_ABORT) {
ut_ad(trx_mutex_own(lock->trx));
trx_mutex_exit(lock->trx);
exit_trx_mutex = true;
}
lock_grant(lock, false);
if (exit_trx_mutex) {
ut_ad(!trx_mutex_own(lock->trx));
trx_mutex_enter(lock->trx);
}
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_insert_to_head(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
}
}
}
/*************************************************************//**
Removes a record lock request, waiting or granted, from the queue and
grants locks to other transactions in the queue if they now are entitled
@ -2841,36 +3110,44 @@ lock_rec_dequeue_from_page(
MONITOR_INC(MONITOR_RECLOCK_REMOVED);
MONITOR_DEC(MONITOR_NUM_RECLOCK);
/* Check if waiting locks in the queue can now be granted: grant
locks if there are no conflicting locks ahead. Stop at the first
X lock that is waiting or has been granted. */
if (innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
thd_is_replication_slave_thread(in_lock->trx->mysql_thd)) {
for (lock = lock_rec_get_first_on_page_addr(lock_hash, space, page_no);
lock != NULL;
lock = lock_rec_get_next_on_page(lock)) {
/* Check if waiting locks in the queue can now be granted:
grant locks if there are no conflicting locks ahead. Stop at
the first X lock that is waiting or has been granted. */
if (lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
for (lock = lock_rec_get_first_on_page_addr(lock_hash, space,
page_no);
lock != NULL;
lock = lock_rec_get_next_on_page(lock)) {
/* Grant the lock */
ut_ad(lock->trx != in_lock->trx);
if (lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
bool exit_trx_mutex = false;
/* Grant the lock */
ut_ad(lock->trx != in_lock->trx);
if (lock->trx->abort_type != TRX_SERVER_ABORT) {
ut_ad(trx_mutex_own(lock->trx));
trx_mutex_exit(lock->trx);
exit_trx_mutex = true;
}
bool exit_trx_mutex = false;
lock_grant(lock);
if (lock->trx->abort_type != TRX_SERVER_ABORT) {
ut_ad(trx_mutex_own(lock->trx));
trx_mutex_exit(lock->trx);
exit_trx_mutex = true;
}
if (exit_trx_mutex) {
ut_ad(!trx_mutex_own(lock->trx));
trx_mutex_enter(lock->trx);
lock_grant(lock, false);
if (exit_trx_mutex) {
ut_ad(!trx_mutex_own(lock->trx));
trx_mutex_enter(lock->trx);
}
}
}
}
} else {
lock_grant_and_move_on_page(lock_hash, space, page_no);
}
}
/*************************************************************//**
@ -4620,7 +4897,7 @@ lock_table_dequeue(
/* Grant the lock */
ut_ad(in_lock->trx != lock->trx);
lock_grant(lock);
lock_grant(lock, false);
}
}
}
@ -4704,6 +4981,66 @@ run_again:
}
/*=========================== LOCK RELEASE ==============================*/
static
void
lock_grant_and_move_on_rec(
hash_table_t* lock_hash,
lock_t* first_lock,
ulint heap_no)
{
lock_t* lock;
lock_t* previous;
ulint space;
ulint page_no;
ulint rec_fold;
space = first_lock->un_member.rec_lock.space;
page_no = first_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
previous = (lock_t *) hash_get_nth_cell(lock_hash,
hash_calc_hash(rec_fold, lock_hash))->node;
if (previous == NULL) {
return;
}
if (previous == first_lock) {
lock = previous;
} else {
while (previous->hash &&
previous->hash != first_lock) {
previous = previous->hash;
}
lock = previous->hash;
}
/* Grant locks if there are no conflicting locks ahead.
Move granted locks to the head of the list. */
for (;lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if (lock->un_member.rec_lock.space == space
&& lock->un_member.rec_lock.page_no == page_no
&& lock_rec_get_nth_bit(lock, heap_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock, false);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_insert_to_head(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
}
}
}
/*************************************************************//**
Removes a granted record lock of a transaction from the queue and grants
@ -4765,17 +5102,24 @@ released:
ut_a(!lock_get_wait(lock));
lock_rec_reset_nth_bit(lock, heap_no);
/* Check if we can now grant waiting lock requests */
if (innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
for (lock = first_lock; lock != NULL;
lock = lock_rec_get_next(heap_no, lock)) {
if (lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
/* Check if we can now grant waiting lock requests */
/* Grant the lock */
ut_ad(trx != lock->trx);
lock_grant(lock);
for (lock = first_lock; lock != NULL;
lock = lock_rec_get_next(heap_no, lock)) {
if (lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
/* Grant the lock */
ut_ad(trx != lock->trx);
lock_grant(lock, false);
}
}
} else {
lock_grant_and_move_on_rec(lock_sys->rec_hash, first_lock, heap_no);
}
lock_mutex_exit();
@ -6010,6 +6354,9 @@ lock_rec_queue_validate(
}
}
ut_ad(innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
lock_queue_validate(lock));
func_exit:
if (!locked_lock_trx_sys) {
lock_mutex_exit();
@ -7799,7 +8146,10 @@ DeadlockChecker::get_first_lock(ulint* heap_no) const
/* Must find at least two locks, otherwise there cannot be a
waiting lock, secondly the first lock cannot be the wait_lock. */
ut_a(lock != NULL);
ut_a(lock != m_wait_lock);
ut_a(lock != m_wait_lock ||
(innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)));
/* Check that the lock type doesn't change. */
ut_ad(lock_get_type_low(lock) == lock_get_type_low(m_wait_lock));
@ -7968,27 +8318,11 @@ DeadlockChecker::search()
layer. These locks are released before commit, so they
can not cause deadlocks with binlog-fixed commit
order. */
if (m_waitee_ptr &&
if (m_report_waiters &&
(lock_get_type_low(lock) != LOCK_TABLE ||
lock_get_mode(lock) != LOCK_AUTO_INC)) {
if (m_waitee_ptr->used ==
sizeof(m_waitee_ptr->waitees) /
sizeof(m_waitee_ptr->waitees[0])) {
m_waitee_ptr->next =
(struct thd_wait_reports *)
ut_malloc_nokey(sizeof(*m_waitee_ptr));
m_waitee_ptr = m_waitee_ptr->next;
if (!m_waitee_ptr) {
m_too_deep = true;
return (m_start);
}
m_waitee_ptr->next = NULL;
m_waitee_ptr->used = 0;
}
m_waitee_ptr->waitees[m_waitee_ptr->used++] = lock->trx;
thd_rpl_deadlock_check(m_start->mysql_thd,
lock->trx->mysql_thd);
}
if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
@ -8068,47 +8402,6 @@ DeadlockChecker::trx_rollback()
trx_mutex_exit(trx);
}
static
void
lock_report_waiters_to_mysql(
/*=======================*/
struct thd_wait_reports* waitee_buf_ptr, /*!< in: set of trxs */
THD* mysql_thd, /*!< in: THD */
const trx_t* victim_trx) /*!< in: Trx selected
as deadlock victim, if
any */
{
struct thd_wait_reports* p;
struct thd_wait_reports* q;
ulint i;
p = waitee_buf_ptr;
while (p) {
i = 0;
while (i < p->used) {
trx_t *w_trx = p->waitees[i];
/* There is no need to report waits to a trx already
selected as a victim. */
if (w_trx != victim_trx) {
/* If thd_report_wait_for() decides to kill the
transaction, then we will get a call back into
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
w_trx->abort_type = TRX_REPLICATION_ABORT;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
w_trx->abort_type = TRX_SERVER_ABORT;
}
++i;
}
q = p->next;
if (p != waitee_buf_ptr) {
ut_free(p);
}
p = q;
}
}
/** Checks if a joining lock request results in a deadlock. If a deadlock is
found this function will resolve the deadlock by choosing a victim transaction
and rolling it back. It will attempt to resolve all deadlocks. The returned
@ -8127,36 +8420,20 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, const trx_t* trx)
ut_ad(!srv_read_only_mode);
const trx_t* victim_trx;
struct thd_wait_reports waitee_buf;
struct thd_wait_reports*waitee_buf_ptr;
THD* start_mysql_thd;
THD* start_mysql_thd;
bool report_waits = false;
start_mysql_thd = trx->mysql_thd;
if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) {
waitee_buf_ptr = &waitee_buf;
} else {
waitee_buf_ptr = NULL;
}
if (start_mysql_thd && thd_need_wait_reports(start_mysql_thd))
report_waits = true;
/* Try and resolve as many deadlocks as possible. */
do {
if (waitee_buf_ptr) {
waitee_buf_ptr->next = NULL;
waitee_buf_ptr->used = 0;
}
DeadlockChecker checker(trx, lock, s_lock_mark_counter, waitee_buf_ptr);
DeadlockChecker checker(trx, lock, s_lock_mark_counter, report_waits);
victim_trx = checker.search();
/* Report waits to upper layer, as needed. */
if (waitee_buf_ptr) {
lock_report_waiters_to_mysql(waitee_buf_ptr,
start_mysql_thd,
victim_trx);
}
/* Search too deep, we rollback the joining transaction only
if it is possible to rollback. Otherwise we rollback the
transaction that is holding the lock that the joining

View file

@ -1247,7 +1247,6 @@ loop:
(flush_to_disk == true) case, because the log_mutex
contention also works as the arbitrator for write-IO
(fsync) bandwidth between log files and data files. */
os_rmb;
if (!flush_to_disk && log_sys->write_lsn >= lsn) {
return;
}

View file

@ -134,7 +134,7 @@ struct Block {
byte* m_ptr;
byte pad[CACHE_LINE_SIZE - sizeof(ulint)];
lock_word_t m_in_use;
int32 m_in_use;
};
/** For storing the allocated blocks */
@ -915,7 +915,8 @@ os_alloc_block()
pos = i++ % size;
if (TAS(&blocks[pos].m_in_use, 1) == 0) {
if (my_atomic_fas32_explicit(&blocks[pos].m_in_use, 1,
MY_MEMORY_ORDER_ACQUIRE) == 0) {
block = &blocks[pos];
break;
}
@ -938,7 +939,7 @@ os_free_block(Block* block)
{
ut_ad(block->m_in_use == 1);
TAS(&block->m_in_use, 0);
my_atomic_store32_explicit(&block->m_in_use, 0, MY_MEMORY_ORDER_RELEASE);
/* When this block is not in the block cache, and it's
a temporary block, we need to free it directly. */
@ -5709,12 +5710,12 @@ os_file_pwrite(
++os_n_file_writes;
(void) os_atomic_increment_ulint(&os_n_pending_writes, 1);
(void) my_atomic_addlint(&os_n_pending_writes, 1);
MONITOR_ATOMIC_INC(MONITOR_OS_PENDING_WRITES);
ssize_t n_bytes = os_file_io(type, file, (void*) buf, n, offset, err);
(void) os_atomic_decrement_ulint(&os_n_pending_writes, 1);
(void) my_atomic_addlint(&os_n_pending_writes, -1);
MONITOR_ATOMIC_DEC(MONITOR_OS_PENDING_WRITES);
return(n_bytes);
@ -5792,12 +5793,12 @@ os_file_pread(
{
++os_n_file_reads;
(void) os_atomic_increment_ulint(&os_n_pending_reads, 1);
(void) my_atomic_addlint(&os_n_pending_reads, 1);
MONITOR_ATOMIC_INC(MONITOR_OS_PENDING_READS);
ssize_t n_bytes = os_file_io(type, file, buf, n, offset, err);
(void) os_atomic_decrement_ulint(&os_n_pending_reads, 1);
(void) my_atomic_addlint(&os_n_pending_reads, -1);
MONITOR_ATOMIC_DEC(MONITOR_OS_PENDING_READS);
return(n_bytes);

View file

@ -109,7 +109,7 @@ os_mem_alloc_large(
if (ptr) {
*n = size;
os_atomic_increment_ulint(
my_atomic_addlint(
&os_total_large_mem_allocated, size);
UNIV_MEM_ALLOC(ptr, size);
@ -136,7 +136,7 @@ skip:
ib::info() << "VirtualAlloc(" << size << " bytes) failed;"
" Windows error " << GetLastError();
} else {
os_atomic_increment_ulint(
my_atomic_addlint(
&os_total_large_mem_allocated, size);
UNIV_MEM_ALLOC(ptr, size);
}
@ -152,7 +152,7 @@ skip:
" errno " << errno;
ptr = NULL;
} else {
os_atomic_increment_ulint(
my_atomic_addlint(
&os_total_large_mem_allocated, size);
UNIV_MEM_ALLOC(ptr, size);
}
@ -172,8 +172,8 @@ os_mem_free_large(
#if defined HAVE_LINUX_LARGE_PAGES && defined UNIV_LINUX
if (os_use_large_pages && os_large_page_size && !shmdt(ptr)) {
os_atomic_decrement_ulint(
&os_total_large_mem_allocated, size);
my_atomic_addlint(
&os_total_large_mem_allocated, -size);
UNIV_MEM_FREE(ptr, size);
return;
}
@ -185,8 +185,8 @@ os_mem_free_large(
ib::error() << "VirtualFree(" << ptr << ", " << size
<< ") failed; Windows error " << GetLastError();
} else {
os_atomic_decrement_ulint(
&os_total_large_mem_allocated, size);
my_atomic_addlint(
&os_total_large_mem_allocated, -size);
UNIV_MEM_FREE(ptr, size);
}
#elif !defined OS_MAP_ANON
@ -200,8 +200,8 @@ os_mem_free_large(
ib::error() << "munmap(" << ptr << ", " << size << ") failed;"
" errno " << errno;
} else {
os_atomic_decrement_ulint(
&os_total_large_mem_allocated, size);
my_atomic_addlint(
&os_total_large_mem_allocated, -size);
UNIV_MEM_FREE(ptr, size);
}
#endif

View file

@ -117,9 +117,6 @@ os_thread_create_func(
{
os_thread_id_t new_thread_id;
/* the new thread should look recent changes up here so far. */
os_wmb;
#ifdef _WIN32
HANDLE handle;

Some files were not shown because too many files have changed in this diff Show more