mirror of
https://github.com/MariaDB/server.git
synced 2025-01-24 07:44:22 +01:00
Merge branch '10.2' of github.com:MariaDB/server into 10.2
This commit is contained in:
commit
951ca5dd04
121 changed files with 7095 additions and 2514 deletions
|
@ -28,6 +28,7 @@ addons:
|
|||
- libpam0g-dev
|
||||
- libreadline-gplv2-dev
|
||||
- libssl-dev
|
||||
- libnuma-dev
|
||||
- lsb-release
|
||||
- perl
|
||||
- po-debconf
|
||||
|
|
|
@ -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
38
cmake/numa.cmake
Normal 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()
|
||||
|
|
@ -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
1
debian/control
vendored
|
@ -19,6 +19,7 @@ Build-Depends: bison,
|
|||
libreadline-gplv2-dev,
|
||||
libssl-dev,
|
||||
libxml2-dev,
|
||||
libnuma-dev,
|
||||
lsb-release,
|
||||
perl (>= 5.6.0),
|
||||
po-debconf,
|
||||
|
|
|
@ -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
356
include/json_lib.h
Normal 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 */
|
||||
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
55
mysql-test/extra/rpl_tests/delayed_slave_wait_on_query.inc
Normal file
55
mysql-test/extra/rpl_tests/delayed_slave_wait_on_query.inc
Normal 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
|
|
@ -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.
|
||||
|
|
9
mysql-test/include/have_numa.inc
Normal file
9
mysql-test/include/have_numa.inc
Normal 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.
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
118
mysql-test/include/rpl_assert.inc
Normal file
118
mysql-test/include/rpl_assert.inc
Normal 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=
|
28
mysql-test/include/show_delayed_slave_state.inc
Normal file
28
mysql-test/include/show_delayed_slave_state.inc
Normal 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'
|
||||
}
|
26
mysql-test/include/sync_with_master.inc
Normal file
26
mysql-test/include/sync_with_master.inc
Normal 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
|
123
mysql-test/r/func_json.result
Normal file
123
mysql-test/r/func_json.result
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
17
mysql-test/suite/rpl/r/rpl_delayed_slave,parallel.rdiff
Normal file
17
mysql-test/suite/rpl/r/rpl_delayed_slave,parallel.rdiff
Normal 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
|
192
mysql-test/suite/rpl/r/rpl_delayed_slave.result
Normal file
192
mysql-test/suite/rpl/r/rpl_delayed_slave.result
Normal 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
|
58
mysql-test/suite/rpl/r/rpl_delayed_slave2.result
Normal file
58
mysql-test/suite/rpl/r/rpl_delayed_slave2.result
Normal 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
|
5
mysql-test/suite/rpl/t/rpl_delayed_slave.combinations
Normal file
5
mysql-test/suite/rpl/t/rpl_delayed_slave.combinations
Normal file
|
@ -0,0 +1,5 @@
|
|||
[nonparallel]
|
||||
|
||||
[parallel]
|
||||
--slave-parallel-mode=conservative
|
||||
--slave-parallel-threads=10
|
424
mysql-test/suite/rpl/t/rpl_delayed_slave.test
Normal file
424
mysql-test/suite/rpl/t/rpl_delayed_slave.test
Normal 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
|
65
mysql-test/suite/rpl/t/rpl_delayed_slave2.test
Normal file
65
mysql-test/suite/rpl/t/rpl_delayed_slave2.test
Normal 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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
--loose-innodb_numa_interleave=1
|
|
@ -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;
|
||||
|
54
mysql-test/t/func_json.test
Normal file
54
mysql-test/t/func_json.test
Normal 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');
|
||||
|
|
@ -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
|
||||
...
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
16
sql/item.h
16
sql/item.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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
1109
sql/item_jsonfunc.cc
Normal file
File diff suppressed because it is too large
Load diff
304
sql/item_jsonfunc.h
Normal file
304
sql/item_jsonfunc.h
Normal 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 */
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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)},
|
||||
|
|
10
sql/log.cc
10
sql/log.cc
|
@ -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(););
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
258
sql/rpl_rli.cc
258
sql/rpl_rli.cc
|
@ -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
|
||||
|
|
112
sql/rpl_rli.h
112
sql/rpl_rli.h
|
@ -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;
|
||||
|
||||
|
|
388
sql/slave.cc
388
sql/slave.cc
|
@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
26
sql/slave.h
26
sql/slave.h
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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)) { \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue