mirror of
https://github.com/MariaDB/server.git
synced 2025-11-03 14:33:32 +03:00
Merge 10.10 into 10.11
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,2 +0,0 @@
|
|||||||
/debian @ottok
|
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ variables:
|
|||||||
CMAKE_FLAGS: "-DWITH_SSL=system -DPLUGIN_COLUMNSTORE=NO -DPLUGIN_ROCKSDB=NO -DPLUGIN_S3=NO -DPLUGIN_MROONGA=NO -DPLUGIN_CONNECT=NO -DPLUGIN_MROONGA=NO -DPLUGIN_TOKUDB=NO -DPLUGIN_PERFSCHEMA=NO -DWITH_WSREP=OFF"
|
CMAKE_FLAGS: "-DWITH_SSL=system -DPLUGIN_COLUMNSTORE=NO -DPLUGIN_ROCKSDB=NO -DPLUGIN_S3=NO -DPLUGIN_MROONGA=NO -DPLUGIN_CONNECT=NO -DPLUGIN_MROONGA=NO -DPLUGIN_TOKUDB=NO -DPLUGIN_PERFSCHEMA=NO -DWITH_WSREP=OFF"
|
||||||
# Major version dictates which branches share the same ccache. E.g. 10.6-abc
|
# Major version dictates which branches share the same ccache. E.g. 10.6-abc
|
||||||
# and 10.6-xyz will have the same cache.
|
# and 10.6-xyz will have the same cache.
|
||||||
MARIADB_MAJOR_VERSION: "10.8"
|
MARIADB_MAJOR_VERSION: "10.9"
|
||||||
# NOTE! Currently ccache is only used on the Centos8 build. As each job has
|
# NOTE! Currently ccache is only used on the Centos8 build. As each job has
|
||||||
# sufficiently different environments they are unable to benefit from each
|
# sufficiently different environments they are unable to benefit from each
|
||||||
# other's ccaches. As each build generates about 1 GB of ccache, having
|
# other's ccaches. As each build generates about 1 GB of ccache, having
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ ELSEIF(RPM MATCHES "sles")
|
|||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
# MDEV-24629, we need it outside of ELSIFs
|
# MDEV-24629, we need it outside of ELSIFs
|
||||||
IF(RPM MATCHES "fedora3[234]")
|
IF(RPM MATCHES "fedora")
|
||||||
ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1)
|
ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
|||||||
35
debian/additions/innotop/innotop
vendored
Normal file → Executable file
35
debian/additions/innotop/innotop
vendored
Normal file → Executable file
@@ -20,6 +20,9 @@
|
|||||||
# Street, Fifth Floor, Boston, MA 02110-1335 USA
|
# Street, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
use feature ':5.16';
|
||||||
use warnings FATAL => 'all';
|
use warnings FATAL => 'all';
|
||||||
|
|
||||||
our $VERSION = '1.11.4';
|
our $VERSION = '1.11.4';
|
||||||
@@ -265,7 +268,7 @@ sub get_dbh {
|
|||||||
$dbh->do($sql);
|
$dbh->do($sql);
|
||||||
MKDEBUG && _d('Enabling charset for STDOUT');
|
MKDEBUG && _d('Enabling charset for STDOUT');
|
||||||
if ( $charset eq 'utf8' ) {
|
if ( $charset eq 'utf8' ) {
|
||||||
binmode(STDOUT, ':utf8')
|
binmode(STDOUT, ':encoding(UTF-8)')
|
||||||
or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
|
or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -612,6 +615,9 @@ sub ts_to_string {
|
|||||||
|
|
||||||
sub parse_innodb_timestamp {
|
sub parse_innodb_timestamp {
|
||||||
my $text = shift;
|
my $text = shift;
|
||||||
|
if ( ! defined $text ) {
|
||||||
|
return (0, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
my ( $y, $m, $d, $h, $i, $s )
|
my ( $y, $m, $d, $h, $i, $s )
|
||||||
= $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
|
= $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
|
||||||
die("Can't get timestamp from $text\n") unless $y;
|
die("Can't get timestamp from $text\n") unless $y;
|
||||||
@@ -803,7 +809,8 @@ sub parse_fk_transaction_error {
|
|||||||
# TODO: write some tests for this
|
# TODO: write some tests for this
|
||||||
sub parse_innodb_record_dump {
|
sub parse_innodb_record_dump {
|
||||||
my ( $dump, $complete, $debug ) = @_;
|
my ( $dump, $complete, $debug ) = @_;
|
||||||
return undef unless $dump;
|
# Use bare return as recommend in page 199 of PBP
|
||||||
|
return unless $dump;
|
||||||
|
|
||||||
my $result = {};
|
my $result = {};
|
||||||
|
|
||||||
@@ -6769,6 +6776,9 @@ sub set_precision {
|
|||||||
my ( $num, $precision ) = @_;
|
my ( $num, $precision ) = @_;
|
||||||
$num = 0 unless defined $num;
|
$num = 0 unless defined $num;
|
||||||
$precision = $config{num_digits}->{val} if !defined $precision;
|
$precision = $config{num_digits}->{val} if !defined $precision;
|
||||||
|
if ( $num eq "" ) {
|
||||||
|
$num = int(0);
|
||||||
|
}
|
||||||
sprintf("%.${precision}f", $num);
|
sprintf("%.${precision}f", $num);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6777,6 +6787,9 @@ sub set_precision {
|
|||||||
sub percent {
|
sub percent {
|
||||||
my ( $num ) = @_;
|
my ( $num ) = @_;
|
||||||
$num = 0 unless defined $num;
|
$num = 0 unless defined $num;
|
||||||
|
if ( $num eq "" ) {
|
||||||
|
$num = int(0);
|
||||||
|
}
|
||||||
my $digits = $config{num_digits}->{val};
|
my $digits = $config{num_digits}->{val};
|
||||||
return sprintf("%.${digits}f", $num * 100)
|
return sprintf("%.${digits}f", $num * 100)
|
||||||
. ($config{show_percent}->{val} ? '%' : '');
|
. ($config{show_percent}->{val} ? '%' : '');
|
||||||
@@ -6841,7 +6854,7 @@ sub make_color_func {
|
|||||||
push @criteria,
|
push @criteria,
|
||||||
"( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }";
|
"( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }";
|
||||||
}
|
}
|
||||||
return undef unless @criteria;
|
return unless @criteria;
|
||||||
my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}';
|
my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}';
|
||||||
die if $EVAL_ERROR;
|
die if $EVAL_ERROR;
|
||||||
return $sub;
|
return $sub;
|
||||||
@@ -7521,10 +7534,10 @@ sub choose_connections {
|
|||||||
sub do_stmt {
|
sub do_stmt {
|
||||||
my ( $cxn, $stmt_name, @args ) = @_;
|
my ( $cxn, $stmt_name, @args ) = @_;
|
||||||
|
|
||||||
return undef if $file;
|
return if $file;
|
||||||
|
|
||||||
# Test if the cxn should not even be tried
|
# Test if the cxn should not even be tried
|
||||||
return undef if $dbhs{$cxn}
|
return if $dbhs{$cxn}
|
||||||
&& $dbhs{$cxn}->{failed}
|
&& $dbhs{$cxn}->{failed}
|
||||||
&& ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
|
&& ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
|
||||||
|
|
||||||
@@ -7596,10 +7609,10 @@ sub handle_cxn_error {
|
|||||||
sub do_query {
|
sub do_query {
|
||||||
my ( $cxn, $query ) = @_;
|
my ( $cxn, $query ) = @_;
|
||||||
|
|
||||||
return undef if $file;
|
return if $file;
|
||||||
|
|
||||||
# Test if the cxn should not even be tried
|
# Test if the cxn should not even be tried
|
||||||
return undef if $dbhs{$cxn}
|
return if $dbhs{$cxn}
|
||||||
&& $dbhs{$cxn}->{failed}
|
&& $dbhs{$cxn}->{failed}
|
||||||
&& ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
|
&& ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
|
||||||
|
|
||||||
@@ -7781,7 +7794,7 @@ sub compile_select_stmt {
|
|||||||
sub compile_filter {
|
sub compile_filter {
|
||||||
my ( $text ) = @_;
|
my ( $text ) = @_;
|
||||||
my ( $sub, $err );
|
my ( $sub, $err );
|
||||||
eval "\$sub = sub { my \$set = shift; $text }";
|
eval { $sub = sub { my $set = shift; $text } };
|
||||||
if ( $EVAL_ERROR ) {
|
if ( $EVAL_ERROR ) {
|
||||||
$EVAL_ERROR =~ s/at \(eval.*$//;
|
$EVAL_ERROR =~ s/at \(eval.*$//;
|
||||||
$sub = sub { return $EVAL_ERROR };
|
$sub = sub { return $EVAL_ERROR };
|
||||||
@@ -8013,7 +8026,7 @@ sub load_config_plugins {
|
|||||||
|
|
||||||
# First, find a list of all plugins that exist on disk, and get information about them.
|
# First, find a list of all plugins that exist on disk, and get information about them.
|
||||||
my $dir = $config{plugin_dir}->{val};
|
my $dir = $config{plugin_dir}->{val};
|
||||||
foreach my $p_file ( <$dir/*.pm> ) {
|
foreach my $p_file (glob($dir."/*.pm")) {
|
||||||
my ($package, $desc);
|
my ($package, $desc);
|
||||||
eval {
|
eval {
|
||||||
open my $p_in, "<", $p_file or die $OS_ERROR;
|
open my $p_in, "<", $p_file or die $OS_ERROR;
|
||||||
@@ -9192,7 +9205,7 @@ sub switch_var_set {
|
|||||||
# edit_stmt_sleep_times {{{3
|
# edit_stmt_sleep_times {{{3
|
||||||
sub edit_stmt_sleep_times {
|
sub edit_stmt_sleep_times {
|
||||||
$clear_screen_sub->();
|
$clear_screen_sub->();
|
||||||
my $stmt = prompt_list('Specify a statement', '', sub { return sort keys %stmt_maker_for });
|
my $stmt = prompt_list('Specify a statement', '', sub { my @tmparray = sort keys %stmt_maker_for; return @tmparray });
|
||||||
return unless $stmt && exists $stmt_maker_for{$stmt};
|
return unless $stmt && exists $stmt_maker_for{$stmt};
|
||||||
$clear_screen_sub->();
|
$clear_screen_sub->();
|
||||||
my $curr_val = $stmt_sleep_time_for{$stmt} || 0;
|
my $curr_val = $stmt_sleep_time_for{$stmt} || 0;
|
||||||
@@ -9843,7 +9856,7 @@ sub get_slave_status {
|
|||||||
sub is_func {
|
sub is_func {
|
||||||
my ( $word ) = @_;
|
my ( $word ) = @_;
|
||||||
return defined(&$word)
|
return defined(&$word)
|
||||||
|| eval "my \$x= sub { $word }; 1"
|
|| eval { my $x = sub { $word }; 1 }
|
||||||
|| $EVAL_ERROR !~ m/^Bareword/;
|
|| $EVAL_ERROR !~ m/^Bareword/;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
debian/mariadb-server.mariadb.init
vendored
2
debian/mariadb-server.mariadb.init
vendored
@@ -86,7 +86,7 @@ sanity_checks() {
|
|||||||
datadir=`mariadbd_get_param datadir`
|
datadir=`mariadbd_get_param datadir`
|
||||||
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
||||||
# 4096 blocks is then lower than 4 MB
|
# 4096 blocks is then lower than 4 MB
|
||||||
df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1`
|
df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$datadir" | tail -n 1)"
|
||||||
if [ "$df_available_blocks" -lt "4096" ]; then
|
if [ "$df_available_blocks" -lt "4096" ]; then
|
||||||
log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
|
log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
|
||||||
echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
|
echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
|
||||||
|
|||||||
23
debian/mariadb-server.preinst
vendored
23
debian/mariadb-server.preinst
vendored
@@ -223,14 +223,23 @@ then
|
|||||||
mkdir -Z $mysql_datadir
|
mkdir -Z $mysql_datadir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
# Check if MariaDB datadir is available if not fails.
|
||||||
# 4096 blocks is then lower than 4 MB
|
# There should be symlink or directory available or something will fail.
|
||||||
df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1`
|
if [ -d "$mysql_datadir" ] || [ -L "$mysql_datadir" ]
|
||||||
if [ "$df_available_blocks" -lt "4096" ]
|
|
||||||
then
|
then
|
||||||
echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2
|
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
||||||
db_stop
|
# 4096 blocks is then lower than 4 MB
|
||||||
exit 1
|
df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$mysql_datadir" | tail -n 1)"
|
||||||
|
if [ "$df_available_blocks" -lt "4096" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2
|
||||||
|
db_stop
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ERROR: There's no directory or symlink available: $mysql_datadir/" 1>&2
|
||||||
|
db_stop
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Since the home directory was created before putting the user into
|
# Since the home directory was created before putting the user into
|
||||||
|
|||||||
@@ -847,27 +847,49 @@ void mdl_lock_all()
|
|||||||
|
|
||||||
|
|
||||||
// Convert non-null terminated filename to space name
|
// Convert non-null terminated filename to space name
|
||||||
|
// Note that in 10.6 the filename may be an undo file name
|
||||||
static std::string filename_to_spacename(const void *filename, size_t len)
|
static std::string filename_to_spacename(const void *filename, size_t len)
|
||||||
{
|
{
|
||||||
// null- terminate filename
|
char f[FN_REFLEN];
|
||||||
char *f = (char *)malloc(len + 1);
|
char *p= 0, *table, *db;
|
||||||
ut_a(f);
|
DBUG_ASSERT(len < FN_REFLEN);
|
||||||
memcpy(f, filename, len);
|
|
||||||
f[len] = 0;
|
strmake(f, (const char*) filename, len);
|
||||||
for (size_t i = 0; i < len; i++)
|
|
||||||
if (f[i] == '\\')
|
#ifdef _WIN32
|
||||||
f[i] = '/';
|
for (size_t i = 0; i < len; i++)
|
||||||
char *p = strrchr(f, '.');
|
{
|
||||||
ut_a(p);
|
if (f[i] == '\\')
|
||||||
*p = 0;
|
f[i] = '/';
|
||||||
char *table = strrchr(f, '/');
|
}
|
||||||
ut_a(table);
|
#endif
|
||||||
*table = 0;
|
|
||||||
char *db = strrchr(f, '/');
|
/* Remove extension, if exists */
|
||||||
*table = '/';
|
if (!(p= strrchr(f, '.')))
|
||||||
std::string s(db ? db+1 : f);
|
goto err;
|
||||||
free(f);
|
*p= 0;
|
||||||
return s;
|
|
||||||
|
/* Find table name */
|
||||||
|
if (!(table= strrchr(f, '/')))
|
||||||
|
goto err;
|
||||||
|
*table = 0;
|
||||||
|
|
||||||
|
/* Find database name */
|
||||||
|
db= strrchr(f, '/');
|
||||||
|
*table = '/';
|
||||||
|
if (!db)
|
||||||
|
goto err;
|
||||||
|
{
|
||||||
|
std::string s(db+1);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
/* Not a database/table. Return original (converted) name */
|
||||||
|
if (p)
|
||||||
|
*p= '.'; // Restore removed extension
|
||||||
|
std::string s(f);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Report an operation to create, delete, or rename a file during backup.
|
/** Report an operation to create, delete, or rename a file during backup.
|
||||||
@@ -3146,7 +3168,7 @@ static bool xtrabackup_copy_logfile()
|
|||||||
if (log_sys.buf[recv_sys.offset] <= 1)
|
if (log_sys.buf[recv_sys.offset] <= 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (recv_sys.parse_mtr(STORE_NO) == recv_sys_t::OK)
|
if (recv_sys.parse_mtr<false>(false) == recv_sys_t::OK)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -3156,7 +3178,7 @@ static bool xtrabackup_copy_logfile()
|
|||||||
sequence_offset));
|
sequence_offset));
|
||||||
*seq= 1;
|
*seq= 1;
|
||||||
}
|
}
|
||||||
while ((r= recv_sys.parse_mtr(STORE_NO)) == recv_sys_t::OK);
|
while ((r= recv_sys.parse_mtr<false>(false)) == recv_sys_t::OK);
|
||||||
|
|
||||||
if (ds_write(dst_log_file, log_sys.buf + start_offset,
|
if (ds_write(dst_log_file, log_sys.buf + start_offset,
|
||||||
recv_sys.offset - start_offset))
|
recv_sys.offset - start_offset))
|
||||||
|
|||||||
@@ -249,14 +249,15 @@ static inline void lex_string_set3(LEX_CSTRING *lex_str, const char *c_str,
|
|||||||
*/
|
*/
|
||||||
static inline int safe_strcpy(char *dst, size_t dst_size, const char *src)
|
static inline int safe_strcpy(char *dst, size_t dst_size, const char *src)
|
||||||
{
|
{
|
||||||
memset(dst, '\0', dst_size);
|
DBUG_ASSERT(dst_size > 0);
|
||||||
strncpy(dst, src, dst_size - 1);
|
/* Note, strncpy will zerofill end of dst if src shorter than dst_size */
|
||||||
/*
|
strncpy(dst, src, dst_size);
|
||||||
If the first condition is true, we are guaranteed to have src length
|
if (dst[dst_size-1])
|
||||||
>= (dst_size - 1), hence safe to access src[dst_size - 1].
|
{
|
||||||
*/
|
/* Ensure string is zero terminated */
|
||||||
if (dst[dst_size - 2] != '\0' && src[dst_size - 1] != '\0')
|
dst[dst_size-1]= 0;
|
||||||
return 1; /* Truncation of src. */
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ typedef struct st_myrg_info
|
|||||||
ulong cache_size;
|
ulong cache_size;
|
||||||
uint merge_insert_method;
|
uint merge_insert_method;
|
||||||
uint tables,options,reclength,keys;
|
uint tables,options,reclength,keys;
|
||||||
|
uint key_parts;
|
||||||
my_bool cache_in_use;
|
my_bool cache_in_use;
|
||||||
/* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
|
/* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
|
||||||
my_bool children_attached;
|
my_bool children_attached;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ extern struct wsrep_service_st {
|
|||||||
my_bool (*wsrep_on_func)(const MYSQL_THD thd);
|
my_bool (*wsrep_on_func)(const MYSQL_THD thd);
|
||||||
bool (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
|
bool (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
|
||||||
void (*wsrep_thd_LOCK_func)(const MYSQL_THD thd);
|
void (*wsrep_thd_LOCK_func)(const MYSQL_THD thd);
|
||||||
|
int (*wsrep_thd_TRYLOCK_func)(const MYSQL_THD thd);
|
||||||
void (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd);
|
void (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd);
|
||||||
const char * (*wsrep_thd_query_func)(const MYSQL_THD thd);
|
const char * (*wsrep_thd_query_func)(const MYSQL_THD thd);
|
||||||
int (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd);
|
int (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd);
|
||||||
@@ -89,7 +90,6 @@ extern struct wsrep_service_st {
|
|||||||
ulong (*wsrep_OSU_method_get_func)(const MYSQL_THD thd);
|
ulong (*wsrep_OSU_method_get_func)(const MYSQL_THD thd);
|
||||||
my_bool (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd);
|
my_bool (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd);
|
||||||
void (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val);
|
void (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val);
|
||||||
bool (*wsrep_thd_set_wsrep_aborter_func)(MYSQL_THD bf_thd, MYSQL_THD thd);
|
|
||||||
void (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd,
|
void (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd,
|
||||||
unsigned long long trx_id);
|
unsigned long long trx_id);
|
||||||
void (*wsrep_thd_kill_LOCK_func)(const MYSQL_THD thd);
|
void (*wsrep_thd_kill_LOCK_func)(const MYSQL_THD thd);
|
||||||
@@ -111,6 +111,7 @@ extern struct wsrep_service_st {
|
|||||||
#define wsrep_on(thd) (thd) && WSREP_ON && wsrep_service->wsrep_on_func(thd)
|
#define wsrep_on(thd) (thd) && WSREP_ON && wsrep_service->wsrep_on_func(thd)
|
||||||
#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G)
|
#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G)
|
||||||
#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T)
|
#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T)
|
||||||
|
#define wsrep_thd_TRYLOCK(T) wsrep_service->wsrep_thd_TRYLOCK_func(T)
|
||||||
#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T)
|
#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T)
|
||||||
#define wsrep_thd_kill_LOCK(T) wsrep_service->wsrep_thd_kill_LOCK_func(T)
|
#define wsrep_thd_kill_LOCK(T) wsrep_service->wsrep_thd_kill_LOCK_func(T)
|
||||||
#define wsrep_thd_kill_UNLOCK(T) wsrep_service->wsrep_thd_kill_UNLOCK_func(T)
|
#define wsrep_thd_kill_UNLOCK(T) wsrep_service->wsrep_thd_kill_UNLOCK_func(T)
|
||||||
@@ -141,7 +142,6 @@ extern struct wsrep_service_st {
|
|||||||
#define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T)
|
#define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T)
|
||||||
#define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T)
|
#define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T)
|
||||||
#define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V)
|
#define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V)
|
||||||
#define wsrep_thd_set_wsrep_aborter(T) wsrep_service->wsrep_thd_set_wsrep_aborter_func(T1, T2)
|
|
||||||
#define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I)
|
#define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I)
|
||||||
#define wsrep_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T)
|
#define wsrep_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T)
|
||||||
#else
|
#else
|
||||||
@@ -175,6 +175,8 @@ void wsrep_set_data_home_dir(const char *data_dir);
|
|||||||
extern "C" my_bool wsrep_on(const MYSQL_THD thd);
|
extern "C" my_bool wsrep_on(const MYSQL_THD thd);
|
||||||
/* Lock thd wsrep lock */
|
/* Lock thd wsrep lock */
|
||||||
extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd);
|
extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd);
|
||||||
|
/* Try thd wsrep lock. Return non-zero if lock could not be taken. */
|
||||||
|
extern "C" int wsrep_thd_TRYLOCK(const MYSQL_THD thd);
|
||||||
/* Unlock thd wsrep lock */
|
/* Unlock thd wsrep lock */
|
||||||
extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd);
|
extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd);
|
||||||
|
|
||||||
@@ -197,8 +199,6 @@ extern "C" my_bool wsrep_thd_is_local(const MYSQL_THD thd);
|
|||||||
/* Return true if thd is in high priority mode */
|
/* Return true if thd is in high priority mode */
|
||||||
/* todo: rename to is_high_priority() */
|
/* todo: rename to is_high_priority() */
|
||||||
extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
|
extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
|
||||||
/* set wsrep_aborter for the target THD */
|
|
||||||
extern "C" bool wsrep_thd_set_wsrep_aborter(MYSQL_THD bf_thd, MYSQL_THD victim_thd);
|
|
||||||
/* Return true if thd is in TOI mode */
|
/* Return true if thd is in TOI mode */
|
||||||
extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd);
|
extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd);
|
||||||
/* Return true if thd is in replicating TOI mode */
|
/* Return true if thd is in replicating TOI mode */
|
||||||
@@ -249,7 +249,6 @@ extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
|
|||||||
extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd);
|
extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd);
|
||||||
extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd);
|
extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd);
|
||||||
extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val);
|
extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val);
|
||||||
extern "C" bool wsrep_thd_set_wsrep_aborter(MYSQL_THD bf_thd, MYSQL_THD victim_thd);
|
|
||||||
extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
|
extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
|
||||||
unsigned long long trx_id);
|
unsigned long long trx_id);
|
||||||
/* declare parallel applying unsafety for the THD */
|
/* declare parallel applying unsafety for the THD */
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use strict;
|
|||||||
|
|
||||||
use Exporter;
|
use Exporter;
|
||||||
use base "Exporter";
|
use base "Exporter";
|
||||||
our @EXPORT= qw /rmtree mkpath copytree/;
|
our @EXPORT= qw /rmtree mkpath copytree make_readonly/;
|
||||||
|
|
||||||
use File::Find;
|
use File::Find;
|
||||||
use File::Copy;
|
use File::Copy;
|
||||||
@@ -184,6 +184,10 @@ sub copytree {
|
|||||||
# Only copy plain files
|
# Only copy plain files
|
||||||
next unless -f "$from_dir/$_";
|
next unless -f "$from_dir/$_";
|
||||||
copy("$from_dir/$_", "$to_dir/$_");
|
copy("$from_dir/$_", "$to_dir/$_");
|
||||||
|
if (!$use_umask)
|
||||||
|
{
|
||||||
|
chmod(0666, "$to_dir/$_");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closedir(DIR);
|
closedir(DIR);
|
||||||
|
|
||||||
@@ -193,4 +197,29 @@ sub copytree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub make_readonly {
|
||||||
|
my ($dir) = @_;
|
||||||
|
|
||||||
|
die "Usage: make_readonly(<dir>])"
|
||||||
|
unless @_ == 1;
|
||||||
|
|
||||||
|
opendir(DIR, "$dir")
|
||||||
|
or croak("Can't find $dir$!");
|
||||||
|
for(readdir(DIR)) {
|
||||||
|
|
||||||
|
next if "$_" eq "." or "$_" eq "..";
|
||||||
|
|
||||||
|
if ( -d "$dir/$_" )
|
||||||
|
{
|
||||||
|
make_readonly("$dir/$_");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only copy plain files
|
||||||
|
next unless -f "$dir/$_";
|
||||||
|
chmod 0444, "$dir/$_";
|
||||||
|
}
|
||||||
|
closedir(DIR);
|
||||||
|
}
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ our @EXPORT= qw(create_process);
|
|||||||
# Retry a couple of times if fork returns EAGAIN
|
# Retry a couple of times if fork returns EAGAIN
|
||||||
#
|
#
|
||||||
sub _safe_fork {
|
sub _safe_fork {
|
||||||
my $retries= 5;
|
my $retries= 100;
|
||||||
my $pid;
|
my $pid;
|
||||||
|
|
||||||
FORK:
|
FORK:
|
||||||
|
|||||||
@@ -1157,3 +1157,28 @@ explain select * from t1 limit 0 offset 10;
|
|||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
#
|
||||||
|
# MDEV-28285 Unexpected result when combining DISTINCT, subselect
|
||||||
|
# and LIMIT
|
||||||
|
#
|
||||||
|
create table t1 (a int primary key);
|
||||||
|
create table t2 (a int primary key, b int not null);
|
||||||
|
insert into t1 select seq from seq_1_to_10;
|
||||||
|
insert into t2 select seq,seq from seq_1_to_10;
|
||||||
|
select distinct a from t1 where t1.a=1 and t1.a in (select a from t2 where t2.b in (1,2));
|
||||||
|
a
|
||||||
|
1
|
||||||
|
explain select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using index; Using temporary
|
||||||
|
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func 1
|
||||||
|
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 10 Using where
|
||||||
|
select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
|
||||||
|
a
|
||||||
|
select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 0,1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# end of 10.5 tests
|
||||||
|
#
|
||||||
|
|||||||
@@ -892,3 +892,24 @@ explain select * from t1 limit 0;
|
|||||||
explain select * from t1 limit 0 offset 10;
|
explain select * from t1 limit 0 offset 10;
|
||||||
|
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-28285 Unexpected result when combining DISTINCT, subselect
|
||||||
|
--echo # and LIMIT
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int primary key);
|
||||||
|
create table t2 (a int primary key, b int not null);
|
||||||
|
|
||||||
|
insert into t1 select seq from seq_1_to_10;
|
||||||
|
insert into t2 select seq,seq from seq_1_to_10;
|
||||||
|
|
||||||
|
select distinct a from t1 where t1.a=1 and t1.a in (select a from t2 where t2.b in (1,2));
|
||||||
|
explain select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
|
||||||
|
select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
|
||||||
|
select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 0,1;
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # end of 10.5 tests
|
||||||
|
--echo #
|
||||||
|
|||||||
@@ -2578,5 +2578,29 @@ SELECT JSON_EXTRACT('{ "my-key": 1 }', '$.my-key');
|
|||||||
JSON_EXTRACT('{ "my-key": 1 }', '$.my-key')
|
JSON_EXTRACT('{ "my-key": 1 }', '$.my-key')
|
||||||
1
|
1
|
||||||
#
|
#
|
||||||
|
# MDEV-23187: Assorted assertion failures in json_find_path with certain collations
|
||||||
|
#
|
||||||
|
SET @save_collation_connection= @@collation_connection;
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
JSON_VALUE(@json,'$.A[last-1][last-1].key1')
|
||||||
|
NULL
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
|
||||||
|
SET collation_connection='ucs2_bin';
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
JSON_VALUE(@json,'$.A[last-1][last-1].key1')
|
||||||
|
NULL
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
|
||||||
|
SET sql_mode=0,character_set_connection=utf32;
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
JSON_VALUE(@json,'$.A[last-1][last-1].key1')
|
||||||
|
NULL
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
|
||||||
|
SET sql_mode=0,character_set_connection=utf32;
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
JSON_VALUE(@json,'$.A[last-1][last-1].key1')
|
||||||
|
NULL
|
||||||
|
SET @@collation_connection= @save_collation_connection;
|
||||||
|
#
|
||||||
# End of 10.9 Test
|
# End of 10.9 Test
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1772,6 +1772,32 @@ DROP TABLE t1;
|
|||||||
SELECT JSON_EXTRACT('{ "my-key": 1 }', '$."my-key"');
|
SELECT JSON_EXTRACT('{ "my-key": 1 }', '$."my-key"');
|
||||||
SELECT JSON_EXTRACT('{ "my-key": 1 }', '$.my-key');
|
SELECT JSON_EXTRACT('{ "my-key": 1 }', '$.my-key');
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-23187: Assorted assertion failures in json_find_path with certain collations
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
|
||||||
|
SET @save_collation_connection= @@collation_connection;
|
||||||
|
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
|
||||||
|
SET collation_connection='ucs2_bin';
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
|
||||||
|
SET sql_mode=0,character_set_connection=utf32;
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
|
||||||
|
|
||||||
|
SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
|
||||||
|
SET sql_mode=0,character_set_connection=utf32;
|
||||||
|
SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
|
||||||
|
|
||||||
|
SET @@collation_connection= @save_collation_connection;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.9 Test
|
--echo # End of 10.9 Test
|
||||||
--echo #
|
--echo #
|
||||||
|
|||||||
@@ -4095,6 +4095,116 @@ MIN(pk) a
|
|||||||
5 10
|
5 10
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
|
# MDEV-6768 Wrong result with agregate with join with no resultset
|
||||||
|
#
|
||||||
|
create table t1
|
||||||
|
(
|
||||||
|
PARENT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
PARENT_FIELD VARCHAR(10),
|
||||||
|
PRIMARY KEY (PARENT_ID)
|
||||||
|
) engine=innodb;
|
||||||
|
create table t2
|
||||||
|
(
|
||||||
|
CHILD_ID INT NOT NULL AUTO_INCREMENT,
|
||||||
|
PARENT_ID INT NOT NULL,
|
||||||
|
CHILD_FIELD varchar(10),
|
||||||
|
PRIMARY KEY (CHILD_ID)
|
||||||
|
)engine=innodb;
|
||||||
|
INSERT INTO t1 (PARENT_FIELD)
|
||||||
|
SELECT 'AAAA';
|
||||||
|
INSERT INTO t2 (PARENT_ID, CHILD_FIELD)
|
||||||
|
SELECT 1, 'BBBB';
|
||||||
|
explain select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 1 Using where
|
||||||
|
select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
PARENT_ID min(CHILD_FIELD)
|
||||||
|
NULL NULL
|
||||||
|
select
|
||||||
|
1,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
1 min(CHILD_FIELD)
|
||||||
|
1 NULL
|
||||||
|
select
|
||||||
|
IFNULL(t1.PARENT_ID,1),
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
IFNULL(t1.PARENT_ID,1) min(CHILD_FIELD)
|
||||||
|
1 NULL
|
||||||
|
# Check that things works with MyISAM (which has different explain)
|
||||||
|
alter table t1 engine=myisam;
|
||||||
|
alter table t2 engine=myisam;
|
||||||
|
explain select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
PARENT_ID min(CHILD_FIELD)
|
||||||
|
NULL NULL
|
||||||
|
drop table t1,t2;
|
||||||
|
# Check that things works if sub queries are re-executed
|
||||||
|
create table t1 (a int primary key, b int);
|
||||||
|
create table t2 (a int primary key, b int);
|
||||||
|
create table t3 (a int primary key, b int);
|
||||||
|
insert into t1 values (1,1),(2,2),(3,3);
|
||||||
|
insert into t2 values (1,1),(2,2),(3,3);
|
||||||
|
insert into t3 values (1,1),(3,3);
|
||||||
|
explain
|
||||||
|
select *,
|
||||||
|
(select
|
||||||
|
CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
|
||||||
|
'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
|
||||||
|
from t2,t3
|
||||||
|
where t2.a=1 and t1.b = t3.a) as s1
|
||||||
|
from t1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
|
||||||
|
2 DEPENDENT SUBQUERY t2 const PRIMARY PRIMARY 4 const 1 Using index
|
||||||
|
2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1
|
||||||
|
select *,
|
||||||
|
(select
|
||||||
|
CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
|
||||||
|
'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
|
||||||
|
from t2,t3
|
||||||
|
where t2.a=1 and t1.b = t3.a) as s1
|
||||||
|
from t1;
|
||||||
|
a b s1
|
||||||
|
1 1 t2:1;min_t3_b:1
|
||||||
|
2 2 t2:t2a-null;min_t3_b:t3b-null
|
||||||
|
3 3 t2:1;min_t3_b:3
|
||||||
|
drop table t1,t2,t3;
|
||||||
|
#
|
||||||
# End of 10.5 tests
|
# End of 10.5 tests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1749,6 +1749,116 @@ SELECT MIN(pk), a FROM t1 WHERE pk <> 1 GROUP BY a;
|
|||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-6768 Wrong result with agregate with join with no resultset
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1
|
||||||
|
(
|
||||||
|
PARENT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
PARENT_FIELD VARCHAR(10),
|
||||||
|
PRIMARY KEY (PARENT_ID)
|
||||||
|
) engine=innodb;
|
||||||
|
|
||||||
|
create table t2
|
||||||
|
(
|
||||||
|
CHILD_ID INT NOT NULL AUTO_INCREMENT,
|
||||||
|
PARENT_ID INT NOT NULL,
|
||||||
|
CHILD_FIELD varchar(10),
|
||||||
|
PRIMARY KEY (CHILD_ID)
|
||||||
|
)engine=innodb;
|
||||||
|
|
||||||
|
INSERT INTO t1 (PARENT_FIELD)
|
||||||
|
SELECT 'AAAA';
|
||||||
|
|
||||||
|
INSERT INTO t2 (PARENT_ID, CHILD_FIELD)
|
||||||
|
SELECT 1, 'BBBB';
|
||||||
|
|
||||||
|
explain select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
|
||||||
|
select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
|
||||||
|
select
|
||||||
|
1,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
|
||||||
|
select
|
||||||
|
IFNULL(t1.PARENT_ID,1),
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
|
||||||
|
|
||||||
|
--echo # Check that things works with MyISAM (which has different explain)
|
||||||
|
|
||||||
|
alter table t1 engine=myisam;
|
||||||
|
alter table t2 engine=myisam;
|
||||||
|
|
||||||
|
explain select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
|
||||||
|
select
|
||||||
|
t1.PARENT_ID,
|
||||||
|
min(CHILD_FIELD)
|
||||||
|
from t1 straight_join t2
|
||||||
|
where t1.PARENT_ID = 1
|
||||||
|
and t1.PARENT_ID = t2.PARENT_ID
|
||||||
|
and t2.CHILD_FIELD = "ZZZZ";
|
||||||
|
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo # Check that things works if sub queries are re-executed
|
||||||
|
|
||||||
|
create table t1 (a int primary key, b int);
|
||||||
|
create table t2 (a int primary key, b int);
|
||||||
|
create table t3 (a int primary key, b int);
|
||||||
|
|
||||||
|
insert into t1 values (1,1),(2,2),(3,3);
|
||||||
|
insert into t2 values (1,1),(2,2),(3,3);
|
||||||
|
insert into t3 values (1,1),(3,3);
|
||||||
|
|
||||||
|
explain
|
||||||
|
select *,
|
||||||
|
(select
|
||||||
|
CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
|
||||||
|
'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
|
||||||
|
from t2,t3
|
||||||
|
where t2.a=1 and t1.b = t3.a) as s1
|
||||||
|
from t1;
|
||||||
|
|
||||||
|
select *,
|
||||||
|
(select
|
||||||
|
CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
|
||||||
|
'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
|
||||||
|
from t2,t3
|
||||||
|
where t2.a=1 and t1.b = t3.a) as s1
|
||||||
|
from t1;
|
||||||
|
|
||||||
|
drop table t1,t2,t3;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.5 tests
|
--echo # End of 10.5 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|||||||
@@ -3902,6 +3902,18 @@ DROP TABLE t1;
|
|||||||
DROP TABLE m1;
|
DROP TABLE m1;
|
||||||
set global default_storage_engine=@save_default_storage_engine;
|
set global default_storage_engine=@save_default_storage_engine;
|
||||||
#
|
#
|
||||||
|
# MDEV-31083 ASAN use-after-poison in myrg_attach_children
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (f TEXT, FULLTEXT (f)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES ('foo'),('bar');
|
||||||
|
CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1);
|
||||||
|
SELECT * FROM mrg;
|
||||||
|
f
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
DROP TABLE mrg, t1;
|
||||||
|
End of 10.5 tests
|
||||||
|
#
|
||||||
# End of 10.0 tests
|
# End of 10.0 tests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -2859,6 +2859,18 @@ set global default_storage_engine=@save_default_storage_engine;
|
|||||||
# gone so execution of other tests won't be affected by their presence.
|
# gone so execution of other tests won't be affected by their presence.
|
||||||
--source include/wait_until_count_sessions.inc
|
--source include/wait_until_count_sessions.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-31083 ASAN use-after-poison in myrg_attach_children
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (f TEXT, FULLTEXT (f)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES ('foo'),('bar');
|
||||||
|
CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1);
|
||||||
|
SELECT * FROM mrg;
|
||||||
|
DROP TABLE mrg, t1;
|
||||||
|
|
||||||
|
--echo End of 10.5 tests
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.0 tests
|
--echo # End of 10.0 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|||||||
@@ -1824,7 +1824,6 @@ test.t1 analyze status Table is already up to date
|
|||||||
test.t2 analyze status Engine-independent statistics collected
|
test.t2 analyze status Engine-independent statistics collected
|
||||||
test.t2 analyze status Table is already up to date
|
test.t2 analyze status Table is already up to date
|
||||||
set optimizer_switch='exists_to_in=off';
|
set optimizer_switch='exists_to_in=off';
|
||||||
set optimizer_use_condition_selectivity=2;
|
|
||||||
SELECT * FROM t1
|
SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
@@ -1849,18 +1848,39 @@ id a
|
|||||||
17 17
|
17 17
|
||||||
18 18
|
18 18
|
||||||
19 19
|
19 19
|
||||||
explain SELECT * FROM t1
|
set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
WHERE A.a=t1.a AND t2.b < 20);
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
|
||||||
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
||||||
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
||||||
EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
|
set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
|
||||||
|
WHERE
|
||||||
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE A const PRIMARY,a PRIMARY 4 const 1
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
|
||||||
1 SIMPLE B ref a a 5 const 1
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
||||||
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
||||||
|
set @query="EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
|
||||||
|
set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
|
||||||
|
WHERE
|
||||||
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
|
||||||
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
||||||
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
||||||
|
set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
|
||||||
|
WHERE
|
||||||
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
|
||||||
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
||||||
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
||||||
explain SELECT * FROM t1
|
explain SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
@@ -1870,7 +1890,6 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||||||
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
|
||||||
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
|
||||||
set optimizer_switch= @save_optimizer_switch;
|
set optimizer_switch= @save_optimizer_switch;
|
||||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
#
|
#
|
||||||
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
|
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
|
||||||
|
|||||||
@@ -1236,13 +1236,10 @@ set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
|
|||||||
|
|
||||||
drop table t1,t2,t3;
|
drop table t1,t2,t3;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4
|
--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
create table t1 (id int, a int, PRIMARY KEY(id), key(a));
|
create table t1 (id int, a int, PRIMARY KEY(id), key(a));
|
||||||
insert into t1 select seq,seq from seq_1_to_100;
|
insert into t1 select seq,seq from seq_1_to_100;
|
||||||
|
|
||||||
@@ -1252,7 +1249,6 @@ insert into t2 select seq,seq,seq from seq_1_to_100;
|
|||||||
analyze table t1,t2 persistent for all;
|
analyze table t1,t2 persistent for all;
|
||||||
|
|
||||||
set optimizer_switch='exists_to_in=off';
|
set optimizer_switch='exists_to_in=off';
|
||||||
set optimizer_use_condition_selectivity=2;
|
|
||||||
|
|
||||||
let $query= SELECT * FROM t1
|
let $query= SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
@@ -1260,14 +1256,16 @@ let $query= SELECT * FROM t1
|
|||||||
WHERE A.a=t1.a AND t2.b < 20);
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
|
|
||||||
eval $query;
|
eval $query;
|
||||||
eval explain $query;
|
eval set statement optimizer_use_condition_selectivity=2 for explain $query;
|
||||||
|
eval set statement optimizer_use_condition_selectivity=4 for explain $query;
|
||||||
|
|
||||||
EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
|
set @query="EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
|
||||||
|
eval set statement optimizer_use_condition_selectivity=2 for explain $query;
|
||||||
|
eval set statement optimizer_use_condition_selectivity=4 for explain $query;
|
||||||
|
|
||||||
eval explain $query;
|
eval explain $query;
|
||||||
|
|
||||||
set optimizer_switch= @save_optimizer_switch;
|
set optimizer_switch= @save_optimizer_switch;
|
||||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
|
|||||||
@@ -1836,7 +1836,6 @@ test.t1 analyze status OK
|
|||||||
test.t2 analyze status Engine-independent statistics collected
|
test.t2 analyze status Engine-independent statistics collected
|
||||||
test.t2 analyze status OK
|
test.t2 analyze status OK
|
||||||
set optimizer_switch='exists_to_in=off';
|
set optimizer_switch='exists_to_in=off';
|
||||||
set optimizer_use_condition_selectivity=2;
|
|
||||||
SELECT * FROM t1
|
SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
@@ -1861,18 +1860,39 @@ id a
|
|||||||
17 17
|
17 17
|
||||||
18 18
|
18 18
|
||||||
19 19
|
19 19
|
||||||
explain SELECT * FROM t1
|
set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
WHERE A.a=t1.a AND t2.b < 20);
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
|
1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
|
||||||
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
||||||
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
||||||
EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
|
set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
|
||||||
|
WHERE
|
||||||
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE A const PRIMARY,a PRIMARY 4 const 1
|
1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
|
||||||
1 SIMPLE B ref a a 5 const 1 Using index
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
||||||
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
||||||
|
set @query="EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
|
||||||
|
set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
|
||||||
|
WHERE
|
||||||
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
|
||||||
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
||||||
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
||||||
|
set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
|
||||||
|
WHERE
|
||||||
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
|
WHERE A.a=t1.a AND t2.b < 20);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
|
||||||
|
3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
||||||
|
3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
||||||
explain SELECT * FROM t1
|
explain SELECT * FROM t1
|
||||||
WHERE
|
WHERE
|
||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||||
@@ -1882,7 +1902,6 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||||||
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
|
||||||
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
|
||||||
set optimizer_switch= @save_optimizer_switch;
|
set optimizer_switch= @save_optimizer_switch;
|
||||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
#
|
#
|
||||||
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
|
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
|
||||||
|
|||||||
@@ -1230,6 +1230,8 @@ SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
|
|||||||
c1
|
c1
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1292 Truncated incorrect datetime value: 'r'
|
Warning 1292 Truncated incorrect datetime value: 'r'
|
||||||
|
SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
|
||||||
|
c1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1 (c1 timestamp);
|
CREATE TABLE t1 (c1 timestamp);
|
||||||
INSERT INTO t1 VALUES ('2010-01-01 00:00:00');
|
INSERT INTO t1 VALUES ('2010-01-01 00:00:00');
|
||||||
|
|||||||
@@ -810,6 +810,7 @@ DROP TABLE t1;
|
|||||||
CREATE TABLE t1 (c1 timestamp);
|
CREATE TABLE t1 (c1 timestamp);
|
||||||
SELECT MIN(t1.c1) AS k1 FROM t1 HAVING (k1 >= ALL(SELECT 'a' UNION SELECT 'r'));
|
SELECT MIN(t1.c1) AS k1 FROM t1 HAVING (k1 >= ALL(SELECT 'a' UNION SELECT 'r'));
|
||||||
SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
|
SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
|
||||||
|
SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
CREATE TABLE t1 (c1 timestamp);
|
CREATE TABLE t1 (c1 timestamp);
|
||||||
|
|||||||
@@ -408,8 +408,11 @@ sub main {
|
|||||||
|
|
||||||
mark_time_used('collect');
|
mark_time_used('collect');
|
||||||
|
|
||||||
mysql_install_db(default_mysqld(), "$opt_vardir/install.db") unless using_extern();
|
if (!using_extern())
|
||||||
|
{
|
||||||
|
mysql_install_db(default_mysqld(), "$opt_vardir/install.db");
|
||||||
|
make_readonly("$opt_vardir/install.db");
|
||||||
|
}
|
||||||
if ($opt_dry_run)
|
if ($opt_dry_run)
|
||||||
{
|
{
|
||||||
for (@$tests) {
|
for (@$tests) {
|
||||||
|
|||||||
@@ -27,3 +27,5 @@ galera_bf_kill_debug : timeout after 900 seconds
|
|||||||
galera_ssl_upgrade : [Warning] Failed to load slave replication state from table mysql.gtid_slave_pos: 130: Incorrect file format 'gtid_slave_pos'
|
galera_ssl_upgrade : [Warning] Failed to load slave replication state from table mysql.gtid_slave_pos: 130: Incorrect file format 'gtid_slave_pos'
|
||||||
galera_parallel_simple : timeout related to wsrep_sync_wait
|
galera_parallel_simple : timeout related to wsrep_sync_wait
|
||||||
galera_insert_bulk : MDEV-30536 no expected deadlock in galera_insert_bulk test
|
galera_insert_bulk : MDEV-30536 no expected deadlock in galera_insert_bulk test
|
||||||
|
MDEV-27713 : test is using get_lock(), which is now rejected in cluster
|
||||||
|
galera_bf_abort_group_commit : MDEV-30855 PR to remove the test exists
|
||||||
|
|||||||
21
mysql-test/suite/galera/r/MDEV-29293.result
Normal file
21
mysql-test/suite/galera/r/MDEV-29293.result
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
connection node_2;
|
||||||
|
connection node_1;
|
||||||
|
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
|
connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
|
set wsrep_sync_wait = 0;
|
||||||
|
CREATE TABLE t1(a int not null primary key auto_increment, b int) engine=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (1,2);
|
||||||
|
connection node_1a;
|
||||||
|
BEGIN;
|
||||||
|
UPDATE t1 SET b=3 WHERE a=1;
|
||||||
|
connection node_1;
|
||||||
|
set debug_sync='wsrep_kill_before_awake_no_mutex SIGNAL before_kill WAIT_FOR continue';
|
||||||
|
connection node_1b;
|
||||||
|
set debug_sync= 'now WAIT_FOR before_kill';
|
||||||
|
connection node_2;
|
||||||
|
UPDATE t1 SET b=7 WHERE a=1;
|
||||||
|
connection node_1b;
|
||||||
|
set debug_sync= 'now SIGNAL continue';
|
||||||
|
connection node_1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC= 'RESET';
|
||||||
@@ -82,6 +82,7 @@ connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
|||||||
LOCK TABLE t2 WRITE;
|
LOCK TABLE t2 WRITE;
|
||||||
connection node_1;
|
connection node_1;
|
||||||
CREATE TABLE t1 AS SELECT * FROM t2;;
|
CREATE TABLE t1 AS SELECT * FROM t2;;
|
||||||
|
connection node_1a;
|
||||||
connection node_2;
|
connection node_2;
|
||||||
SELECT COUNT(*) = 5 FROM t2;
|
SELECT COUNT(*) = 5 FROM t2;
|
||||||
COUNT(*) = 5
|
COUNT(*) = 5
|
||||||
|
|||||||
@@ -134,6 +134,3 @@ connection node_1;
|
|||||||
call mtr.add_suppression("Error in Log_event::read_log_event():.*");
|
call mtr.add_suppression("Error in Log_event::read_log_event():.*");
|
||||||
CALL mtr.add_suppression("conflict state 7 after post commit");
|
CALL mtr.add_suppression("conflict state 7 after post commit");
|
||||||
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
|
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
|
||||||
connection node_2;
|
|
||||||
call mtr.add_suppression("Error in Log_event::read_log_event():.*");
|
|
||||||
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
|
|
||||||
|
|||||||
27
mysql-test/suite/galera/r/galera_kill_group_commit.result
Normal file
27
mysql-test/suite/galera/r/galera_kill_group_commit.result
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
connection node_2;
|
||||||
|
connection node_1;
|
||||||
|
connect node_1_kill, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
|
connect node_1_ctrl, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
connect node_1_follower, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
connection node_1;
|
||||||
|
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
SET SESSION DEBUG_SYNC = "commit_before_enqueue SIGNAL leader_before_enqueue_reached WAIT_FOR leader_before_enqueue_continue";
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
connection node_1_ctrl;
|
||||||
|
SET DEBUG_SYNC = "now WAIT_FOR leader_before_enqueue_reached";
|
||||||
|
connection node_1_follower;
|
||||||
|
INSERT INTO t1 VALUES (2);;
|
||||||
|
connection node_1_ctrl;
|
||||||
|
connection node_1_kill;
|
||||||
|
# Execute KILL QUERY for group commit follower
|
||||||
|
SET DEBUG_SYNC = "now SIGNAL leader_before_enqueue_continue";
|
||||||
|
connection node_1_follower;
|
||||||
|
connection node_1;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
f1
|
||||||
|
1
|
||||||
|
2
|
||||||
|
SET DEBUG_SYNC = "RESET";
|
||||||
|
DROP TABLE t1;
|
||||||
@@ -36,7 +36,10 @@ SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
|
|||||||
connection node_1;
|
connection node_1;
|
||||||
SELECT COUNT(*) FROM t1;
|
SELECT COUNT(*) FROM t1;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
1
|
connection node_1;
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
COUNT(*)
|
||||||
|
0
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
SET GLOBAL debug_dbug = NULL;
|
SET GLOBAL debug_dbug = NULL;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|||||||
41
mysql-test/suite/galera/t/MDEV-29293.test
Normal file
41
mysql-test/suite/galera/t/MDEV-29293.test
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
--source include/galera_cluster.inc
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
--source include/galera_have_debug_sync.inc
|
||||||
|
|
||||||
|
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
|
--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
|
set wsrep_sync_wait = 0;
|
||||||
|
|
||||||
|
CREATE TABLE t1(a int not null primary key auto_increment, b int) engine=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (1,2);
|
||||||
|
|
||||||
|
--connection node_1a
|
||||||
|
--let $victim_id = `SELECT CONNECTION_ID()`
|
||||||
|
BEGIN;
|
||||||
|
UPDATE t1 SET b=3 WHERE a=1;
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
set debug_sync='wsrep_kill_before_awake_no_mutex SIGNAL before_kill WAIT_FOR continue';
|
||||||
|
--disable_query_log
|
||||||
|
--disable_result_log
|
||||||
|
--send_eval KILL CONNECTION $victim_id
|
||||||
|
--enable_result_log
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
--connection node_1b
|
||||||
|
set debug_sync= 'now WAIT_FOR before_kill';
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
UPDATE t1 SET b=7 WHERE a=1;
|
||||||
|
|
||||||
|
--connection node_1b
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE User = 'system user' AND State LIKE 'Update_rows_log_event%';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
set debug_sync= 'now SIGNAL continue';
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
--reap
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC= 'RESET';
|
||||||
|
|
||||||
@@ -113,6 +113,10 @@ LOCK TABLE t2 WRITE;
|
|||||||
--connection node_1
|
--connection node_1
|
||||||
--send CREATE TABLE t1 AS SELECT * FROM t2;
|
--send CREATE TABLE t1 AS SELECT * FROM t2;
|
||||||
|
|
||||||
|
--connection node_1a
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE STATE LIKE 'Waiting for table metadata lock%'
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
--connection node_2
|
--connection node_2
|
||||||
SELECT COUNT(*) = 5 FROM t2;
|
SELECT COUNT(*) = 5 FROM t2;
|
||||||
CREATE TABLE t1 AS SELECT * FROM t2;
|
CREATE TABLE t1 AS SELECT * FROM t2;
|
||||||
@@ -121,7 +125,7 @@ CREATE TABLE t1 AS SELECT * FROM t2;
|
|||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--connection node_1
|
--connection node_1
|
||||||
--error ER_TABLE_EXISTS_ERROR,ER_LOCK_DEADLOCK
|
--error ER_TABLE_EXISTS_ERROR,ER_QUERY_INTERRUPTED
|
||||||
--reap
|
--reap
|
||||||
|
|
||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
|
|||||||
5
mysql-test/suite/galera/t/galera_kill_group_commit.cnf
Normal file
5
mysql-test/suite/galera/t/galera_kill_group_commit.cnf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
!include ../galera_2nodes.cnf
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
log-bin
|
||||||
|
log-slave-updates
|
||||||
69
mysql-test/suite/galera/t/galera_kill_group_commit.test
Normal file
69
mysql-test/suite/galera/t/galera_kill_group_commit.test
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#
|
||||||
|
# Verify that transaction which has reached group commit queue
|
||||||
|
# cannot be killed. If the kill succeeds, assertion for
|
||||||
|
# wsrep transaction state will fail.
|
||||||
|
#
|
||||||
|
# If the bug is present, i.e. wsrep transaction gets killed during
|
||||||
|
# group commit wait, this test is enough to reproduce the crash
|
||||||
|
# most of the time.
|
||||||
|
#
|
||||||
|
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
--source include/galera_cluster.inc
|
||||||
|
|
||||||
|
# Connection for KILL commands
|
||||||
|
--connect node_1_kill, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
|
# Connection for sync point control
|
||||||
|
--connect node_1_ctrl, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
# Connection for group commit follower
|
||||||
|
--connect node_1_follower, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
|
# Need to disable sync wait to reach commit queue when leader
|
||||||
|
# is blocked.
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
--let $follower_id = `SELECT CONNECTION_ID()`
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
SET SESSION DEBUG_SYNC = "commit_before_enqueue SIGNAL leader_before_enqueue_reached WAIT_FOR leader_before_enqueue_continue";
|
||||||
|
--send INSERT INTO t1 VALUES (1)
|
||||||
|
|
||||||
|
--connection node_1_ctrl
|
||||||
|
SET DEBUG_SYNC = "now WAIT_FOR leader_before_enqueue_reached";
|
||||||
|
|
||||||
|
--connection node_1_follower
|
||||||
|
# SET SESSION DEBUG_SYNC = "group_commit_waiting_for_prior SIGNAL follower_waiting_for_prior_reached WAIT_FOR follower_waiting_for_prior_continue";
|
||||||
|
--send INSERT INTO t1 VALUES (2);
|
||||||
|
|
||||||
|
--connection node_1_ctrl
|
||||||
|
# TODO: Is it possible to use sync points to enforce group commit to happen?
|
||||||
|
# The leader will hold commit monitor in commit_before_enqueue sync point,
|
||||||
|
# which prevents the follower to reach the group commit wait state.
|
||||||
|
# We now sleep and expect the follower to reach group commit, but this
|
||||||
|
# may cause false negatives.
|
||||||
|
--sleep 1
|
||||||
|
|
||||||
|
--connection node_1_kill
|
||||||
|
--echo # Execute KILL QUERY for group commit follower
|
||||||
|
--disable_query_log
|
||||||
|
--disable_result_log
|
||||||
|
# Because it is currently impossible to verify that the
|
||||||
|
# follower has reached group commit queue, the KILL may
|
||||||
|
# sometimes return success.
|
||||||
|
--error 0,ER_KILL_DENIED_ERROR
|
||||||
|
--eval KILL QUERY $follower_id
|
||||||
|
--enable_result_log
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
SET DEBUG_SYNC = "now SIGNAL leader_before_enqueue_continue";
|
||||||
|
--connection node_1_follower
|
||||||
|
--reap
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
--reap
|
||||||
|
SELECT * FROM t1;
|
||||||
|
|
||||||
|
SET DEBUG_SYNC = "RESET";
|
||||||
|
DROP TABLE t1;
|
||||||
@@ -64,6 +64,7 @@ SELECT COUNT(*) FROM t1;
|
|||||||
SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
|
SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
|
||||||
|
|
||||||
--connection node_1
|
--connection node_1
|
||||||
|
--error 0,ER_LOCK_DEADLOCK
|
||||||
--reap
|
--reap
|
||||||
SELECT COUNT(*) FROM t1;
|
SELECT COUNT(*) FROM t1;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
set global innodb_monitor_disable = All;
|
|
||||||
select name, if(enabled,'enabled','disabled') status
|
select name, if(enabled,'enabled','disabled') status
|
||||||
from information_schema.innodb_metrics;
|
from information_schema.innodb_metrics;
|
||||||
name status
|
name status
|
||||||
metadata_table_handles_opened disabled
|
metadata_table_handles_opened disabled
|
||||||
lock_deadlocks disabled
|
lock_deadlocks enabled
|
||||||
lock_timeouts disabled
|
lock_timeouts enabled
|
||||||
lock_rec_lock_waits disabled
|
lock_rec_lock_waits disabled
|
||||||
lock_table_lock_waits disabled
|
lock_table_lock_waits disabled
|
||||||
lock_rec_lock_requests disabled
|
lock_rec_lock_requests disabled
|
||||||
@@ -14,30 +13,30 @@ lock_rec_locks disabled
|
|||||||
lock_table_lock_created disabled
|
lock_table_lock_created disabled
|
||||||
lock_table_lock_removed disabled
|
lock_table_lock_removed disabled
|
||||||
lock_table_locks disabled
|
lock_table_locks disabled
|
||||||
lock_row_lock_current_waits disabled
|
lock_row_lock_current_waits enabled
|
||||||
lock_row_lock_time disabled
|
lock_row_lock_time enabled
|
||||||
lock_row_lock_time_max disabled
|
lock_row_lock_time_max enabled
|
||||||
lock_row_lock_waits disabled
|
lock_row_lock_waits enabled
|
||||||
lock_row_lock_time_avg disabled
|
lock_row_lock_time_avg enabled
|
||||||
buffer_pool_size disabled
|
buffer_pool_size enabled
|
||||||
buffer_pool_reads disabled
|
buffer_pool_reads enabled
|
||||||
buffer_pool_read_requests disabled
|
buffer_pool_read_requests enabled
|
||||||
buffer_pool_write_requests disabled
|
buffer_pool_write_requests enabled
|
||||||
buffer_pool_wait_free disabled
|
buffer_pool_wait_free enabled
|
||||||
buffer_pool_read_ahead disabled
|
buffer_pool_read_ahead enabled
|
||||||
buffer_pool_read_ahead_evicted disabled
|
buffer_pool_read_ahead_evicted enabled
|
||||||
buffer_pool_pages_total disabled
|
buffer_pool_pages_total enabled
|
||||||
buffer_pool_pages_misc disabled
|
buffer_pool_pages_misc enabled
|
||||||
buffer_pool_pages_data disabled
|
buffer_pool_pages_data enabled
|
||||||
buffer_pool_bytes_data disabled
|
buffer_pool_bytes_data enabled
|
||||||
buffer_pool_pages_dirty disabled
|
buffer_pool_pages_dirty enabled
|
||||||
buffer_pool_bytes_dirty disabled
|
buffer_pool_bytes_dirty enabled
|
||||||
buffer_pool_pages_free disabled
|
buffer_pool_pages_free enabled
|
||||||
buffer_pages_created disabled
|
buffer_pages_created enabled
|
||||||
buffer_pages_written disabled
|
buffer_pages_written enabled
|
||||||
buffer_pages_read disabled
|
buffer_pages_read enabled
|
||||||
buffer_data_reads disabled
|
buffer_data_reads enabled
|
||||||
buffer_data_written disabled
|
buffer_data_written enabled
|
||||||
buffer_flush_batch_scanned disabled
|
buffer_flush_batch_scanned disabled
|
||||||
buffer_flush_batch_num_scan disabled
|
buffer_flush_batch_num_scan disabled
|
||||||
buffer_flush_batch_scanned_per_call disabled
|
buffer_flush_batch_scanned_per_call disabled
|
||||||
@@ -70,8 +69,8 @@ buffer_flush_background_pages disabled
|
|||||||
buffer_LRU_batch_scanned disabled
|
buffer_LRU_batch_scanned disabled
|
||||||
buffer_LRU_batch_num_scan disabled
|
buffer_LRU_batch_num_scan disabled
|
||||||
buffer_LRU_batch_scanned_per_call disabled
|
buffer_LRU_batch_scanned_per_call disabled
|
||||||
buffer_LRU_batch_flush_total_pages disabled
|
buffer_LRU_batch_flush_total_pages enabled
|
||||||
buffer_LRU_batch_evict_total_pages disabled
|
buffer_LRU_batch_evict_total_pages enabled
|
||||||
buffer_LRU_single_flush_failure_count disabled
|
buffer_LRU_single_flush_failure_count disabled
|
||||||
buffer_LRU_get_free_search disabled
|
buffer_LRU_get_free_search disabled
|
||||||
buffer_LRU_search_scanned disabled
|
buffer_LRU_search_scanned disabled
|
||||||
@@ -112,21 +111,21 @@ buffer_page_written_blob disabled
|
|||||||
buffer_page_written_zblob disabled
|
buffer_page_written_zblob disabled
|
||||||
buffer_page_written_zblob2 disabled
|
buffer_page_written_zblob2 disabled
|
||||||
buffer_page_written_other disabled
|
buffer_page_written_other disabled
|
||||||
os_data_reads disabled
|
os_data_reads enabled
|
||||||
os_data_writes disabled
|
os_data_writes enabled
|
||||||
os_data_fsyncs disabled
|
os_data_fsyncs enabled
|
||||||
os_pending_reads disabled
|
os_pending_reads enabled
|
||||||
os_pending_writes disabled
|
os_pending_writes enabled
|
||||||
os_log_bytes_written disabled
|
os_log_bytes_written enabled
|
||||||
trx_rw_commits disabled
|
trx_rw_commits disabled
|
||||||
trx_ro_commits disabled
|
trx_ro_commits disabled
|
||||||
trx_nl_ro_commits disabled
|
trx_nl_ro_commits disabled
|
||||||
trx_commits_insert_update disabled
|
trx_commits_insert_update disabled
|
||||||
trx_rollbacks disabled
|
trx_rollbacks disabled
|
||||||
trx_rollbacks_savepoint disabled
|
trx_rollbacks_savepoint disabled
|
||||||
trx_rseg_history_len disabled
|
trx_rseg_history_len enabled
|
||||||
trx_undo_slots_used disabled
|
trx_undo_slots_used disabled
|
||||||
trx_undo_slots_cached disabled
|
trx_undo_slots_cached enabled
|
||||||
trx_rseg_current_size disabled
|
trx_rseg_current_size disabled
|
||||||
purge_del_mark_records disabled
|
purge_del_mark_records disabled
|
||||||
purge_upd_exist_or_extern_records disabled
|
purge_upd_exist_or_extern_records disabled
|
||||||
@@ -142,9 +141,9 @@ log_lsn_current disabled
|
|||||||
log_lsn_checkpoint_age disabled
|
log_lsn_checkpoint_age disabled
|
||||||
log_lsn_buf_pool_oldest disabled
|
log_lsn_buf_pool_oldest disabled
|
||||||
log_max_modified_age_async disabled
|
log_max_modified_age_async disabled
|
||||||
log_waits disabled
|
log_waits enabled
|
||||||
log_write_requests disabled
|
log_write_requests enabled
|
||||||
log_writes disabled
|
log_writes enabled
|
||||||
compress_pages_compressed disabled
|
compress_pages_compressed disabled
|
||||||
compress_pages_decompressed disabled
|
compress_pages_decompressed disabled
|
||||||
compression_pad_increments disabled
|
compression_pad_increments disabled
|
||||||
@@ -162,34 +161,34 @@ index_page_merge_successful disabled
|
|||||||
index_page_reorg_attempts disabled
|
index_page_reorg_attempts disabled
|
||||||
index_page_reorg_successful disabled
|
index_page_reorg_successful disabled
|
||||||
index_page_discards disabled
|
index_page_discards disabled
|
||||||
adaptive_hash_searches disabled
|
adaptive_hash_searches enabled
|
||||||
adaptive_hash_searches_btree disabled
|
adaptive_hash_searches_btree enabled
|
||||||
adaptive_hash_pages_added disabled
|
adaptive_hash_pages_added disabled
|
||||||
adaptive_hash_pages_removed disabled
|
adaptive_hash_pages_removed disabled
|
||||||
adaptive_hash_rows_added disabled
|
adaptive_hash_rows_added disabled
|
||||||
adaptive_hash_rows_removed disabled
|
adaptive_hash_rows_removed disabled
|
||||||
adaptive_hash_rows_deleted_no_hash_entry disabled
|
adaptive_hash_rows_deleted_no_hash_entry disabled
|
||||||
adaptive_hash_rows_updated disabled
|
adaptive_hash_rows_updated disabled
|
||||||
file_num_open_files disabled
|
file_num_open_files enabled
|
||||||
ibuf_merges_insert disabled
|
ibuf_merges_insert enabled
|
||||||
ibuf_merges_delete_mark disabled
|
ibuf_merges_delete_mark enabled
|
||||||
ibuf_merges_delete disabled
|
ibuf_merges_delete enabled
|
||||||
ibuf_merges_discard_insert disabled
|
ibuf_merges_discard_insert enabled
|
||||||
ibuf_merges_discard_delete_mark disabled
|
ibuf_merges_discard_delete_mark enabled
|
||||||
ibuf_merges_discard_delete disabled
|
ibuf_merges_discard_delete enabled
|
||||||
ibuf_merges disabled
|
ibuf_merges enabled
|
||||||
ibuf_size disabled
|
ibuf_size enabled
|
||||||
innodb_master_thread_sleeps disabled
|
innodb_master_thread_sleeps disabled
|
||||||
innodb_activity_count disabled
|
innodb_activity_count enabled
|
||||||
innodb_master_active_loops disabled
|
innodb_master_active_loops disabled
|
||||||
innodb_master_idle_loops disabled
|
innodb_master_idle_loops disabled
|
||||||
innodb_log_flush_usec disabled
|
innodb_log_flush_usec disabled
|
||||||
innodb_dict_lru_usec disabled
|
innodb_dict_lru_usec disabled
|
||||||
innodb_dict_lru_count_active disabled
|
innodb_dict_lru_count_active disabled
|
||||||
innodb_dict_lru_count_idle disabled
|
innodb_dict_lru_count_idle disabled
|
||||||
innodb_dblwr_writes disabled
|
innodb_dblwr_writes enabled
|
||||||
innodb_dblwr_pages_written disabled
|
innodb_dblwr_pages_written enabled
|
||||||
innodb_page_size disabled
|
innodb_page_size enabled
|
||||||
ddl_background_drop_indexes disabled
|
ddl_background_drop_indexes disabled
|
||||||
ddl_online_create_index disabled
|
ddl_online_create_index disabled
|
||||||
ddl_pending_alter_table disabled
|
ddl_pending_alter_table disabled
|
||||||
@@ -199,6 +198,9 @@ icp_attempts disabled
|
|||||||
icp_no_match disabled
|
icp_no_match disabled
|
||||||
icp_out_of_range disabled
|
icp_out_of_range disabled
|
||||||
icp_match disabled
|
icp_match disabled
|
||||||
|
set global innodb_monitor_disable = All;
|
||||||
|
select name from information_schema.innodb_metrics where enabled;
|
||||||
|
name
|
||||||
set global innodb_monitor_enable = all;
|
set global innodb_monitor_enable = all;
|
||||||
select name from information_schema.innodb_metrics where not enabled;
|
select name from information_schema.innodb_metrics where not enabled;
|
||||||
name
|
name
|
||||||
|
|||||||
@@ -26,4 +26,60 @@ UPDATE mysql.innodb_table_stats SET last_update=NULL WHERE table_name='t1';
|
|||||||
XA END 'test';
|
XA END 'test';
|
||||||
XA ROLLBACK 'test';
|
XA ROLLBACK 'test';
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Testing a non-default format: Field_timestamp0 - UINT4 based
|
||||||
|
#
|
||||||
|
SET @@global.mysql56_temporal_format=0;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
last_update timestamp /* mariadb-5.3 */ NO current_timestamp() on update current_timestamp()
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
last_update timestamp /* mariadb-5.3 */ NO current_timestamp() on update current_timestamp()
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
TIMESTAMPDIFF(DAY,last_update,now())<=1
|
||||||
|
1
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
TIMESTAMPDIFF(DAY,last_update,now())<=1
|
||||||
|
1
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Now as the table t1 is dropped, expect no statistics
|
||||||
|
#
|
||||||
|
SELECT * FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
database_name table_name last_update n_rows clustered_index_size sum_of_other_index_sizes
|
||||||
|
SELECT * FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
database_name table_name index_name last_update stat_name stat_value sample_size stat_description
|
||||||
|
#
|
||||||
|
# Testing with the default format: Field_timestampf - BINARY(4) based with the UNSIGNED_FLAG
|
||||||
|
#
|
||||||
|
SET @@global.mysql56_temporal_format=1;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
last_update timestamp NO current_timestamp() on update current_timestamp()
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
last_update timestamp NO current_timestamp() on update current_timestamp()
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
TIMESTAMPDIFF(DAY,last_update,now())<=1
|
||||||
|
1
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
TIMESTAMPDIFF(DAY,last_update,now())<=1
|
||||||
|
1
|
||||||
|
DROP TABLE t1;
|
||||||
# End of 10.6 tests
|
# End of 10.6 tests
|
||||||
|
|||||||
@@ -5,12 +5,14 @@
|
|||||||
# sys_vars.innodb_monitor_enable_basic
|
# sys_vars.innodb_monitor_enable_basic
|
||||||
|
|
||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
set global innodb_monitor_disable = All;
|
|
||||||
# Test turn on/off the monitor counter with "all" option
|
# Test turn on/off the monitor counter with "all" option
|
||||||
# By default, they will be off.
|
# By default, they will be off.
|
||||||
select name, if(enabled,'enabled','disabled') status
|
select name, if(enabled,'enabled','disabled') status
|
||||||
from information_schema.innodb_metrics;
|
from information_schema.innodb_metrics;
|
||||||
|
|
||||||
|
set global innodb_monitor_disable = All;
|
||||||
|
select name from information_schema.innodb_metrics where enabled;
|
||||||
|
|
||||||
# Turn on all monitor counters
|
# Turn on all monitor counters
|
||||||
set global innodb_monitor_enable = all;
|
set global innodb_monitor_enable = all;
|
||||||
|
|
||||||
|
|||||||
@@ -28,4 +28,57 @@ XA END 'test';
|
|||||||
XA ROLLBACK 'test';
|
XA ROLLBACK 'test';
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
# The following tests demonstrate that these columns:
|
||||||
|
# - innodb_table_stats.last_update
|
||||||
|
# - innodb_index_stats.last_update
|
||||||
|
# have sane values close to NOW(), rather than any garbage,
|
||||||
|
# with all TIMESTAMP formats.
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing a non-default format: Field_timestamp0 - UINT4 based
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@global.mysql56_temporal_format=0;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||||
|
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Now as the table t1 is dropped, expect no statistics
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SELECT * FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
SELECT * FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing with the default format: Field_timestampf - BINARY(4) based with the UNSIGNED_FLAG
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@global.mysql56_temporal_format=1;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
--echo # End of 10.6 tests
|
--echo # End of 10.6 tests
|
||||||
|
|||||||
26
mysql-test/suite/parts/r/partition_purge.result
Normal file
26
mysql-test/suite/parts/r/partition_purge.result
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
CREATE TABLE t1(f1 INT, f2 INT, INDEX(f1))ENGINE=InnoDB
|
||||||
|
PARTITION BY LIST(f1) (
|
||||||
|
PARTITION p1 VALUES in (1, 2, 3),
|
||||||
|
PARTITION p2 VALUES in (4, 5, 6));
|
||||||
|
INSERT INTO t1 VALUES(1, 1), (1, 1), (6, 1);
|
||||||
|
connect con1,localhost,root,,,;
|
||||||
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
|
connect con2,localhost,root,,,;
|
||||||
|
SET DEBUG_SYNC="innodb_rollback_inplace_alter_table SIGNAL default_resume WAIT_FOR alter_resume";
|
||||||
|
ALTER TABLE t1 ADD UNIQUE INDEX(f1);
|
||||||
|
connection default;
|
||||||
|
set DEBUG_SYNC="now WAIT_FOR default_resume";
|
||||||
|
SET DEBUG_SYNC="innodb_row_update_for_mysql_begin SIGNAL alter_resume WAIT_FOR alter_finish";
|
||||||
|
DELETE FROM t1;
|
||||||
|
connection con2;
|
||||||
|
ERROR 23000: Duplicate entry '1' for key 'f1_2'
|
||||||
|
SET DEBUG_SYNC="now SIGNAL alter_finish";
|
||||||
|
connection default;
|
||||||
|
connection con1;
|
||||||
|
commit;
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
disconnect con2;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
|
drop table t1;
|
||||||
|
SET DEBUG_SYNC=reset;
|
||||||
1
mysql-test/suite/parts/t/partition_purge.opt
Normal file
1
mysql-test/suite/parts/t/partition_purge.opt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
--innodb_purge_threads=1
|
||||||
37
mysql-test/suite/parts/t/partition_purge.test
Normal file
37
mysql-test/suite/parts/t/partition_purge.test
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_partition.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
|
||||||
|
CREATE TABLE t1(f1 INT, f2 INT, INDEX(f1))ENGINE=InnoDB
|
||||||
|
PARTITION BY LIST(f1) (
|
||||||
|
PARTITION p1 VALUES in (1, 2, 3),
|
||||||
|
PARTITION p2 VALUES in (4, 5, 6));
|
||||||
|
INSERT INTO t1 VALUES(1, 1), (1, 1), (6, 1);
|
||||||
|
connect(con1,localhost,root,,,);
|
||||||
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
|
|
||||||
|
connect(con2,localhost,root,,,);
|
||||||
|
SET DEBUG_SYNC="innodb_rollback_inplace_alter_table SIGNAL default_resume WAIT_FOR alter_resume";
|
||||||
|
send ALTER TABLE t1 ADD UNIQUE INDEX(f1);
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
set DEBUG_SYNC="now WAIT_FOR default_resume";
|
||||||
|
SET DEBUG_SYNC="innodb_row_update_for_mysql_begin SIGNAL alter_resume WAIT_FOR alter_finish";
|
||||||
|
send DELETE FROM t1;
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
--error ER_DUP_ENTRY
|
||||||
|
reap;
|
||||||
|
SET DEBUG_SYNC="now SIGNAL alter_finish";
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
reap;
|
||||||
|
connection con1;
|
||||||
|
commit;
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
disconnect con2;
|
||||||
|
--source ../../innodb/include/wait_all_purged.inc
|
||||||
|
drop table t1;
|
||||||
|
SET DEBUG_SYNC=reset;
|
||||||
17
plugin/type_mysql_timestamp/CMakeLists.txt
Normal file
17
plugin/type_mysql_timestamp/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright (c) 2019, MariaDB corporation
|
||||||
|
#
|
||||||
|
# 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, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
|
MYSQL_ADD_PLUGIN(type_mysql_timestamp plugin.cc RECOMPILE_FOR_EMBEDDED
|
||||||
|
MODULE_ONLY COMPONENT Test)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
--plugin-load-add=$TYPE_MYSQL_TIMESTAMP_SO
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package My::Suite::Type_test;
|
||||||
|
|
||||||
|
@ISA = qw(My::Suite);
|
||||||
|
|
||||||
|
return "No TYPE_TEST plugin" unless $ENV{TYPE_MYSQL_TIMESTAMP_SO};
|
||||||
|
|
||||||
|
sub is_default { 1 }
|
||||||
|
|
||||||
|
bless { };
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#
|
||||||
|
# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
|
||||||
|
#
|
||||||
|
SELECT
|
||||||
|
PLUGIN_NAME,
|
||||||
|
PLUGIN_VERSION,
|
||||||
|
PLUGIN_STATUS,
|
||||||
|
PLUGIN_TYPE,
|
||||||
|
PLUGIN_AUTHOR,
|
||||||
|
PLUGIN_DESCRIPTION,
|
||||||
|
PLUGIN_LICENSE,
|
||||||
|
PLUGIN_MATURITY,
|
||||||
|
PLUGIN_AUTH_VERSION
|
||||||
|
FROM INFORMATION_SCHEMA.PLUGINS
|
||||||
|
WHERE PLUGIN_TYPE='DATA TYPE'
|
||||||
|
AND PLUGIN_NAME LIKE 'type_mysql_timestamp';
|
||||||
|
PLUGIN_NAME type_mysql_timestamp
|
||||||
|
PLUGIN_VERSION 1.0
|
||||||
|
PLUGIN_STATUS ACTIVE
|
||||||
|
PLUGIN_TYPE DATA TYPE
|
||||||
|
PLUGIN_AUTHOR MariaDB Corporation
|
||||||
|
PLUGIN_DESCRIPTION Data type TYPE_MYSQL_TIMESTAMP
|
||||||
|
PLUGIN_LICENSE GPL
|
||||||
|
PLUGIN_MATURITY Experimental
|
||||||
|
PLUGIN_AUTH_VERSION 1.0
|
||||||
|
CREATE TABLE t1 (a TYPE_MYSQL_TIMESTAMP);
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` type_mysql_timestamp NULL DEFAULT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1 (a TIMESTAMP);
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` timestamp NULL DEFAULT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
|
||||||
|
ALTER TABLE t1 MODIFY a TYPE_MYSQL_TIMESTAMP;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` type_mysql_timestamp NULL DEFAULT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
|
||||||
|
DROP TABLE t1;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--vertical_results
|
||||||
|
SELECT
|
||||||
|
PLUGIN_NAME,
|
||||||
|
PLUGIN_VERSION,
|
||||||
|
PLUGIN_STATUS,
|
||||||
|
PLUGIN_TYPE,
|
||||||
|
PLUGIN_AUTHOR,
|
||||||
|
PLUGIN_DESCRIPTION,
|
||||||
|
PLUGIN_LICENSE,
|
||||||
|
PLUGIN_MATURITY,
|
||||||
|
PLUGIN_AUTH_VERSION
|
||||||
|
FROM INFORMATION_SCHEMA.PLUGINS
|
||||||
|
WHERE PLUGIN_TYPE='DATA TYPE'
|
||||||
|
AND PLUGIN_NAME LIKE 'type_mysql_timestamp';
|
||||||
|
--horizontal_results
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a TYPE_MYSQL_TIMESTAMP);
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a TIMESTAMP);
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
ALTER TABLE t1 MODIFY a TYPE_MYSQL_TIMESTAMP;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#
|
||||||
|
# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
|
||||||
|
#
|
||||||
|
SET @@global.innodb_stats_persistent=0;
|
||||||
|
SHOW CREATE TABLE mysql.innodb_table_stats;
|
||||||
|
Table Create Table
|
||||||
|
innodb_table_stats CREATE TABLE `innodb_table_stats` (
|
||||||
|
`database_name` varchar(64) NOT NULL,
|
||||||
|
`table_name` varchar(199) NOT NULL,
|
||||||
|
`last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`n_rows` bigint(20) unsigned NOT NULL,
|
||||||
|
`clustered_index_size` bigint(20) unsigned NOT NULL,
|
||||||
|
`sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`database_name`,`table_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_table_stats;
|
||||||
|
Table Create Table
|
||||||
|
innodb_table_stats CREATE TABLE `innodb_table_stats` (
|
||||||
|
`database_name` varchar(64) NOT NULL,
|
||||||
|
`table_name` varchar(199) NOT NULL,
|
||||||
|
`last_update` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`n_rows` bigint(20) unsigned NOT NULL,
|
||||||
|
`clustered_index_size` bigint(20) unsigned NOT NULL,
|
||||||
|
`sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`database_name`,`table_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_index_stats;
|
||||||
|
Table Create Table
|
||||||
|
innodb_index_stats CREATE TABLE `innodb_index_stats` (
|
||||||
|
`database_name` varchar(64) NOT NULL,
|
||||||
|
`table_name` varchar(199) NOT NULL,
|
||||||
|
`index_name` varchar(64) NOT NULL,
|
||||||
|
`last_update` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`stat_name` varchar(64) NOT NULL,
|
||||||
|
`stat_value` bigint(20) unsigned NOT NULL,
|
||||||
|
`sample_size` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`stat_description` varchar(1024) NOT NULL,
|
||||||
|
PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
|
||||||
|
SET @@global.innodb_stats_persistent=1;
|
||||||
|
CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (10);
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @@global.innodb_stats_persistent=0;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_table_stats;
|
||||||
|
Table Create Table
|
||||||
|
innodb_table_stats CREATE TABLE `innodb_table_stats` (
|
||||||
|
`database_name` varchar(64) NOT NULL,
|
||||||
|
`table_name` varchar(199) NOT NULL,
|
||||||
|
`last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`n_rows` bigint(20) unsigned NOT NULL,
|
||||||
|
`clustered_index_size` bigint(20) unsigned NOT NULL,
|
||||||
|
`sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`database_name`,`table_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_index_stats;
|
||||||
|
Table Create Table
|
||||||
|
innodb_index_stats CREATE TABLE `innodb_index_stats` (
|
||||||
|
`database_name` varchar(64) NOT NULL,
|
||||||
|
`table_name` varchar(199) NOT NULL,
|
||||||
|
`index_name` varchar(64) NOT NULL,
|
||||||
|
`last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`stat_name` varchar(64) NOT NULL,
|
||||||
|
`stat_value` bigint(20) unsigned NOT NULL,
|
||||||
|
`sample_size` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`stat_description` varchar(1024) NOT NULL,
|
||||||
|
PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
|
||||||
|
SET @@global.innodb_stats_persistent=1;
|
||||||
|
#
|
||||||
|
# Testing MySQL-5.6-alike Field_timestampf: BINARY(4) based, without UNSIGNED_FLAG
|
||||||
|
#
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
last_update type_mysql_timestamp NO current_timestamp() on update current_timestamp()
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
last_update type_mysql_timestamp NO current_timestamp() on update current_timestamp()
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
TIMESTAMPDIFF(DAY,last_update,now())<=1
|
||||||
|
1
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
TIMESTAMPDIFF(DAY,last_update,now())<=1
|
||||||
|
1
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Now as the table t1 is dropped, expect no statistics
|
||||||
|
#
|
||||||
|
SELECT * FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
database_name table_name last_update n_rows clustered_index_size sum_of_other_index_sizes
|
||||||
|
SELECT * FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
database_name table_name index_name last_update stat_name stat_value sample_size stat_description
|
||||||
|
#
|
||||||
|
# Restore the structure of the tables
|
||||||
|
#
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@global.innodb_stats_persistent=0;
|
||||||
|
SHOW CREATE TABLE mysql.innodb_table_stats;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_table_stats;
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_index_stats;
|
||||||
|
SET @@global.innodb_stats_persistent=1;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (10);
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
SET @@global.innodb_stats_persistent=0;
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_table_stats;
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW CREATE TABLE mysql.innodb_index_stats;
|
||||||
|
SET @@global.innodb_stats_persistent=1;
|
||||||
|
|
||||||
|
|
||||||
|
# The following test demonstrate that these columns:
|
||||||
|
# - innodb_table_stats.last_update
|
||||||
|
# - innodb_index_stats.last_update
|
||||||
|
# have sane values close to NOW(), rather than any garbage,
|
||||||
|
# with MySQL-alike Field_timestampf
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing MySQL-5.6-alike Field_timestampf: BINARY(4) based, without UNSIGNED_FLAG
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
|
||||||
|
SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
|
||||||
|
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Now as the table t1 is dropped, expect no statistics
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SELECT * FROM mysql.innodb_table_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1';
|
||||||
|
SELECT * FROM mysql.innodb_index_stats
|
||||||
|
WHERE database_name='test' AND table_name='t1' AND stat_name='size';
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Restore the structure of the tables
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
|
ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
|
||||||
177
plugin/type_mysql_timestamp/plugin.cc
Normal file
177
plugin/type_mysql_timestamp/plugin.cc
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2023, MariaDB Corporation
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#include <my_global.h>
|
||||||
|
#include <sql_class.h>
|
||||||
|
#include <mysql/plugin_data_type.h>
|
||||||
|
#include "sql_type.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Type_collection_local: public Type_collection
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const Type_handler *aggregate_common(const Type_handler *h1,
|
||||||
|
const Type_handler *h2) const;
|
||||||
|
public:
|
||||||
|
const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type_handler *aggregate_for_result(const Type_handler *h1,
|
||||||
|
const Type_handler *h2)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return aggregate_common(h1, h2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type_handler *aggregate_for_comparison(const Type_handler *h1,
|
||||||
|
const Type_handler *h2)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return aggregate_common(h1, h2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type_handler *aggregate_for_min_max(const Type_handler *h1,
|
||||||
|
const Type_handler *h2)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return aggregate_common(h1, h2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type_handler *aggregate_for_num_op(const Type_handler *h1,
|
||||||
|
const Type_handler *h2)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return aggregate_common(h1, h2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Type_collection_local type_collection_local;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
A more MySQL compatible Field:
|
||||||
|
it does not set the UNSIGNED_FLAG.
|
||||||
|
This is how MySQL's Field_timestampf works.
|
||||||
|
*/
|
||||||
|
class Field_mysql_timestampf :public Field_timestampf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Field_mysql_timestampf(const LEX_CSTRING &name,
|
||||||
|
const Record_addr &addr,
|
||||||
|
enum utype unireg_check_arg,
|
||||||
|
TABLE_SHARE *share, decimal_digits_t dec_arg)
|
||||||
|
:Field_timestampf(addr.ptr(), addr.null_ptr(), addr.null_bit(),
|
||||||
|
unireg_check_arg, &name, share, dec_arg)
|
||||||
|
{
|
||||||
|
flags&= ~UNSIGNED_FLAG; // MySQL compatibility
|
||||||
|
}
|
||||||
|
void sql_type(String &str) const override
|
||||||
|
{
|
||||||
|
sql_type_opt_dec_comment(str,
|
||||||
|
Field_mysql_timestampf::type_handler()->name(),
|
||||||
|
dec, type_version_mysql56());
|
||||||
|
}
|
||||||
|
const Type_handler *type_handler() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Type_handler_mysql_timestamp2: public Type_handler_timestamp2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const Type_collection *type_collection() const override
|
||||||
|
{
|
||||||
|
return &type_collection_local;
|
||||||
|
}
|
||||||
|
Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
|
||||||
|
const LEX_CSTRING *name,
|
||||||
|
const Record_addr &rec, const Bit_addr &bit,
|
||||||
|
const Column_definition_attributes *attr,
|
||||||
|
uint32 flags) const override
|
||||||
|
{
|
||||||
|
return new (root)
|
||||||
|
Field_mysql_timestampf(*name, rec, attr->unireg_check, share,
|
||||||
|
attr->temporal_dec(MAX_DATETIME_WIDTH));
|
||||||
|
}
|
||||||
|
void Column_definition_implicit_upgrade(Column_definition *c) const override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Suppress the automatic upgrade depending on opt_mysql56_temporal_format,
|
||||||
|
derived from Type_handler_timestamp_common.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Type_handler_mysql_timestamp2 type_handler_mysql_timestamp2;
|
||||||
|
|
||||||
|
|
||||||
|
const Type_handler *Field_mysql_timestampf::type_handler() const
|
||||||
|
{
|
||||||
|
return &type_handler_mysql_timestamp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Type_handler *
|
||||||
|
Type_collection_local::aggregate_common(const Type_handler *h1,
|
||||||
|
const Type_handler *h2) const
|
||||||
|
{
|
||||||
|
if (h1 == h2)
|
||||||
|
return h1;
|
||||||
|
|
||||||
|
static const Type_aggregator::Pair agg[]=
|
||||||
|
{
|
||||||
|
{
|
||||||
|
&type_handler_timestamp2,
|
||||||
|
&type_handler_mysql_timestamp2,
|
||||||
|
&type_handler_mysql_timestamp2
|
||||||
|
},
|
||||||
|
{NULL,NULL,NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Type_aggregator::find_handler_in_array(agg, h1, h2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct st_mariadb_data_type plugin_descriptor_type_mysql_timestamp=
|
||||||
|
{
|
||||||
|
MariaDB_DATA_TYPE_INTERFACE_VERSION,
|
||||||
|
&type_handler_mysql_timestamp2
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
maria_declare_plugin(type_mysql_timestamp)
|
||||||
|
{
|
||||||
|
MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
|
||||||
|
&plugin_descriptor_type_mysql_timestamp, // pointer to type-specific plugin descriptor
|
||||||
|
"type_mysql_timestamp", // plugin name
|
||||||
|
"MariaDB Corporation", // plugin author
|
||||||
|
"Data type TYPE_MYSQL_TIMESTAMP", // the plugin description
|
||||||
|
PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
|
||||||
|
0, // Pointer to plugin initialization function
|
||||||
|
0, // Pointer to plugin deinitialization function
|
||||||
|
0x0100, // Numeric version 0xAABB means AA.BB version
|
||||||
|
NULL, // Status variables
|
||||||
|
NULL, // System variables
|
||||||
|
"1.0", // String version representation
|
||||||
|
MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/
|
||||||
|
}
|
||||||
|
maria_declare_plugin_end;
|
||||||
@@ -3354,7 +3354,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
TIMESTAMP(0..6) - MySQL56 version
|
TIMESTAMP(0..6) - MySQL56 version
|
||||||
*/
|
*/
|
||||||
class Field_timestampf final :public Field_timestamp_with_dec {
|
class Field_timestampf :public Field_timestamp_with_dec {
|
||||||
void store_TIMEVAL(const timeval &tv) override;
|
void store_TIMEVAL(const timeval &tv) override;
|
||||||
public:
|
public:
|
||||||
Field_timestampf(uchar *ptr_arg,
|
Field_timestampf(uchar *ptr_arg,
|
||||||
|
|||||||
@@ -7972,6 +7972,9 @@ Compare_keys handler::compare_key_parts(const Field &old_field,
|
|||||||
concurrent accesses. And it's an overkill to take LOCK_plugin and
|
concurrent accesses. And it's an overkill to take LOCK_plugin and
|
||||||
iterate the whole installed_htons[] array every time.
|
iterate the whole installed_htons[] array every time.
|
||||||
|
|
||||||
|
@note Object victim_thd is not guaranteed to exist after this
|
||||||
|
function returns.
|
||||||
|
|
||||||
@param bf_thd brute force THD asking for the abort
|
@param bf_thd brute force THD asking for the abort
|
||||||
@param victim_thd victim THD to be aborted
|
@param victim_thd victim THD to be aborted
|
||||||
|
|
||||||
@@ -7985,6 +7988,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
|
|||||||
if (!WSREP(bf_thd) &&
|
if (!WSREP(bf_thd) &&
|
||||||
!(bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU &&
|
!(bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU &&
|
||||||
wsrep_thd_is_toi(bf_thd))) {
|
wsrep_thd_is_toi(bf_thd))) {
|
||||||
|
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||||
|
mysql_mutex_unlock(&victim_thd->LOCK_thd_kill);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7996,6 +8001,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
WSREP_WARN("Cannot abort InnoDB transaction");
|
WSREP_WARN("Cannot abort InnoDB transaction");
|
||||||
|
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||||
|
mysql_mutex_unlock(&victim_thd->LOCK_thd_kill);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include "sql_sequence.h"
|
#include "sql_sequence.h"
|
||||||
#include "mem_root_array.h"
|
#include "mem_root_array.h"
|
||||||
#include <utility> // pair
|
#include <utility> // pair
|
||||||
|
#include <my_attribute.h> /* __attribute__ */
|
||||||
|
|
||||||
class Alter_info;
|
class Alter_info;
|
||||||
class Virtual_column_info;
|
class Virtual_column_info;
|
||||||
@@ -1460,9 +1461,9 @@ struct handlerton
|
|||||||
const char *query, uint query_length,
|
const char *query, uint query_length,
|
||||||
const char *db, const char *table_name);
|
const char *db, const char *table_name);
|
||||||
|
|
||||||
void (*abort_transaction)(handlerton *hton, THD *bf_thd,
|
void (*abort_transaction)(handlerton *hton, THD *bf_thd, THD *victim_thd,
|
||||||
THD *victim_thd, my_bool signal);
|
my_bool signal) __attribute__((nonnull));
|
||||||
int (*set_checkpoint)(handlerton *hton, const XID* xid);
|
int (*set_checkpoint)(handlerton *hton, const XID *xid);
|
||||||
int (*get_checkpoint)(handlerton *hton, XID* xid);
|
int (*get_checkpoint)(handlerton *hton, XID* xid);
|
||||||
/**
|
/**
|
||||||
Check if the version of the table matches the version in the .frm
|
Check if the version of the table matches the version in the .frm
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ public:
|
|||||||
{
|
{
|
||||||
for (uint i= 0; i < arg_count; i++)
|
for (uint i= 0; i < arg_count; i++)
|
||||||
{
|
{
|
||||||
args[i]->no_rows_in_result();
|
args[i]->restore_to_before_no_rows_in_result();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void convert_const_compared_to_int_field(THD *thd);
|
void convert_const_compared_to_int_field(THD *thd);
|
||||||
|
|||||||
@@ -1747,6 +1747,11 @@ static void close_connections(void)
|
|||||||
(void) unlink(mysqld_unix_port);
|
(void) unlink(mysqld_unix_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
The following is needed to the threads stuck in
|
||||||
|
setup_connection_thread_globals()
|
||||||
|
to continue.
|
||||||
|
*/
|
||||||
listen_sockets.free_memory();
|
listen_sockets.free_memory();
|
||||||
mysql_mutex_unlock(&LOCK_start_thread);
|
mysql_mutex_unlock(&LOCK_start_thread);
|
||||||
|
|
||||||
@@ -2032,6 +2037,7 @@ static void clean_up(bool print_message)
|
|||||||
end_ssl();
|
end_ssl();
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
vio_end();
|
vio_end();
|
||||||
|
listen_sockets.free_memory();
|
||||||
#endif /*!EMBEDDED_LIBRARY*/
|
#endif /*!EMBEDDED_LIBRARY*/
|
||||||
#if defined(ENABLED_DEBUG_SYNC)
|
#if defined(ENABLED_DEBUG_SYNC)
|
||||||
/* End the debug sync facility. See debug_sync.cc. */
|
/* End the debug sync facility. See debug_sync.cc. */
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ extern "C" void wsrep_thd_LOCK(const THD *thd)
|
|||||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int wsrep_thd_TRYLOCK(const THD *thd)
|
||||||
|
{
|
||||||
|
return mysql_mutex_trylock(&thd->LOCK_thd_data);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void wsrep_thd_UNLOCK(const THD *thd)
|
extern "C" void wsrep_thd_UNLOCK(const THD *thd)
|
||||||
{
|
{
|
||||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||||
@@ -196,6 +201,7 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
|
|||||||
|
|
||||||
/* Note: do not store/reset globals before wsrep_bf_abort() call
|
/* Note: do not store/reset globals before wsrep_bf_abort() call
|
||||||
to avoid losing BF thd context. */
|
to avoid losing BF thd context. */
|
||||||
|
mysql_mutex_lock(&victim_thd->LOCK_thd_data);
|
||||||
if (!(bf_thd && bf_thd != victim_thd))
|
if (!(bf_thd && bf_thd != victim_thd))
|
||||||
{
|
{
|
||||||
DEBUG_SYNC(victim_thd, "wsrep_before_SR_rollback");
|
DEBUG_SYNC(victim_thd, "wsrep_before_SR_rollback");
|
||||||
@@ -208,6 +214,7 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
|
|||||||
{
|
{
|
||||||
wsrep_thd_self_abort(victim_thd);
|
wsrep_thd_self_abort(victim_thd);
|
||||||
}
|
}
|
||||||
|
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||||
if (bf_thd)
|
if (bf_thd)
|
||||||
{
|
{
|
||||||
wsrep_store_threadvars(bf_thd);
|
wsrep_store_threadvars(bf_thd);
|
||||||
@@ -218,7 +225,7 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd,
|
|||||||
my_bool signal)
|
my_bool signal)
|
||||||
{
|
{
|
||||||
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
|
||||||
mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_data);
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||||
my_bool ret= wsrep_bf_abort(bf_thd, victim_thd);
|
my_bool ret= wsrep_bf_abort(bf_thd, victim_thd);
|
||||||
/*
|
/*
|
||||||
Send awake signal if victim was BF aborted or does not
|
Send awake signal if victim was BF aborted or does not
|
||||||
@@ -227,19 +234,8 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd,
|
|||||||
*/
|
*/
|
||||||
if ((ret || !wsrep_on(victim_thd)) && signal)
|
if ((ret || !wsrep_on(victim_thd)) && signal)
|
||||||
{
|
{
|
||||||
mysql_mutex_lock(&victim_thd->LOCK_thd_data);
|
|
||||||
|
|
||||||
if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id)
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("victim is killed already by %llu, skipping awake",
|
|
||||||
victim_thd->wsrep_aborter);
|
|
||||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
victim_thd->wsrep_aborter= bf_thd->thread_id;
|
victim_thd->wsrep_aborter= bf_thd->thread_id;
|
||||||
victim_thd->awake_no_mutex(KILL_QUERY_HARD);
|
victim_thd->awake_no_mutex(KILL_QUERY_HARD);
|
||||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
|
||||||
} else {
|
} else {
|
||||||
WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal);
|
WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal);
|
||||||
}
|
}
|
||||||
@@ -368,25 +364,6 @@ extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd)
|
|||||||
return(global_system_variables.wsrep_OSU_method);
|
return(global_system_variables.wsrep_OSU_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd)
|
|
||||||
{
|
|
||||||
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
|
||||||
if (!bf_thd)
|
|
||||||
{
|
|
||||||
victim_thd->wsrep_aborter= 0;
|
|
||||||
WSREP_DEBUG("wsrep_thd_set_wsrep_aborter resetting wsrep_aborter");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
victim_thd->wsrep_aborter= bf_thd->thread_id;
|
|
||||||
WSREP_DEBUG("wsrep_thd_set_wsrep_aborter setting wsrep_aborter %u",
|
|
||||||
victim_thd->wsrep_aborter);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
|
extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
|
||||||
unsigned long long trx_id)
|
unsigned long long trx_id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1293,6 +1293,11 @@ void THD::init()
|
|||||||
wsrep_affected_rows = 0;
|
wsrep_affected_rows = 0;
|
||||||
m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
|
m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
|
||||||
wsrep_aborter = 0;
|
wsrep_aborter = 0;
|
||||||
|
wsrep_abort_by_kill = NOT_KILLED;
|
||||||
|
wsrep_abort_by_kill_err = 0;
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
wsrep_killed_state = 0;
|
||||||
|
#endif /* DBUG_OFF */
|
||||||
wsrep_desynced_backup_stage= false;
|
wsrep_desynced_backup_stage= false;
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
@@ -1641,6 +1646,13 @@ void THD::reset_for_reuse()
|
|||||||
#endif
|
#endif
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
wsrep_free_status(this);
|
wsrep_free_status(this);
|
||||||
|
wsrep_cs().reset_error();
|
||||||
|
wsrep_aborter= 0;
|
||||||
|
wsrep_abort_by_kill= NOT_KILLED;
|
||||||
|
wsrep_abort_by_kill_err= 0;
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
wsrep_killed_state= 0;
|
||||||
|
#endif /* DBUG_OFF */
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1897,7 +1909,9 @@ void THD::awake_no_mutex(killed_state state_to_set)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Interrupt target waiting inside a storage engine. */
|
/* Interrupt target waiting inside a storage engine. */
|
||||||
if (state_to_set != NOT_KILLED && !wsrep_is_bf_aborted(this))
|
if (state_to_set != NOT_KILLED &&
|
||||||
|
IF_WSREP(!wsrep_is_bf_aborted(this) && wsrep_abort_by_kill == NOT_KILLED,
|
||||||
|
true))
|
||||||
ha_kill_query(this, thd_kill_level(this));
|
ha_kill_query(this, thd_kill_level(this));
|
||||||
|
|
||||||
abort_current_cond_wait(false);
|
abort_current_cond_wait(false);
|
||||||
@@ -2125,6 +2139,17 @@ void THD::reset_killed()
|
|||||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||||
}
|
}
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
|
if (WSREP_NNULL(this))
|
||||||
|
{
|
||||||
|
if (wsrep_abort_by_kill != NOT_KILLED)
|
||||||
|
{
|
||||||
|
mysql_mutex_assert_not_owner(&LOCK_thd_kill);
|
||||||
|
mysql_mutex_lock(&LOCK_thd_kill);
|
||||||
|
wsrep_abort_by_kill= NOT_KILLED;
|
||||||
|
wsrep_abort_by_kill_err= 0;
|
||||||
|
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||||
|
}
|
||||||
|
}
|
||||||
mysql_mutex_assert_not_owner(&LOCK_thd_data);
|
mysql_mutex_assert_not_owner(&LOCK_thd_data);
|
||||||
mysql_mutex_lock(&LOCK_thd_data);
|
mysql_mutex_lock(&LOCK_thd_data);
|
||||||
wsrep_aborter= 0;
|
wsrep_aborter= 0;
|
||||||
|
|||||||
@@ -5382,7 +5382,14 @@ public:
|
|||||||
bool wsrep_ignore_table;
|
bool wsrep_ignore_table;
|
||||||
/* thread who has started kill for this THD protected by LOCK_thd_data*/
|
/* thread who has started kill for this THD protected by LOCK_thd_data*/
|
||||||
my_thread_id wsrep_aborter;
|
my_thread_id wsrep_aborter;
|
||||||
|
/* Kill signal used, if thread was killed by manual KILL. Protected by
|
||||||
|
LOCK_thd_kill. */
|
||||||
|
std::atomic<killed_state> wsrep_abort_by_kill;
|
||||||
|
/* */
|
||||||
|
struct err_info* wsrep_abort_by_kill_err;
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
int wsrep_killed_state;
|
||||||
|
#endif /* DBUG_OFF */
|
||||||
/* true if BF abort is observed in do_command() right after reading
|
/* true if BF abort is observed in do_command() right after reading
|
||||||
client's packet, and if the client has sent PS execute command. */
|
client's packet, and if the client has sent PS execute command. */
|
||||||
bool wsrep_delayed_BF_abort;
|
bool wsrep_delayed_BF_abort;
|
||||||
|
|||||||
@@ -61,6 +61,15 @@ class Select_limit_counters
|
|||||||
with_ties= false;
|
with_ties= false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send the first row, still honoring offset_limit_cnt */
|
||||||
|
void send_first_row()
|
||||||
|
{
|
||||||
|
/* Guard against overflow */
|
||||||
|
if ((select_limit_cnt= offset_limit_cnt +1 ) == 0)
|
||||||
|
select_limit_cnt= offset_limit_cnt;
|
||||||
|
// with_ties= false; Remove // on merge to 10.6
|
||||||
|
}
|
||||||
|
|
||||||
bool is_unlimited() const
|
bool is_unlimited() const
|
||||||
{ return select_limit_cnt == HA_POS_ERROR; }
|
{ return select_limit_cnt == HA_POS_ERROR; }
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -7866,7 +7866,7 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
|
|||||||
thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)
|
thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)
|
||||||
{
|
{
|
||||||
#ifdef ENABLED_DEBUG_SYNC
|
#ifdef ENABLED_DEBUG_SYNC
|
||||||
DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
|
DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
|
||||||
{
|
{
|
||||||
const char act[]=
|
const char act[]=
|
||||||
"now "
|
"now "
|
||||||
@@ -9229,23 +9229,20 @@ kill_one_thread(THD *thd, my_thread_id id, killed_state kill_signal, killed_type
|
|||||||
thd->security_ctx->user_matches(tmp->security_ctx))
|
thd->security_ctx->user_matches(tmp->security_ctx))
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
{
|
{
|
||||||
|
{
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
DEBUG_SYNC(thd, "before_awake_no_mutex");
|
if (WSREP(tmp))
|
||||||
if (tmp->wsrep_aborter && tmp->wsrep_aborter != thd->thread_id)
|
{
|
||||||
{
|
error = wsrep_kill_thd(thd, tmp, kill_signal);
|
||||||
/* victim is in hit list already, bail out */
|
}
|
||||||
WSREP_DEBUG("victim %lld has wsrep aborter: %lu, skipping awake()",
|
else
|
||||||
id, tmp->wsrep_aborter);
|
{
|
||||||
error= 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
{
|
|
||||||
WSREP_DEBUG("kill_one_thread victim: %lld wsrep_aborter %lu"
|
|
||||||
" by signal %d",
|
|
||||||
id, tmp->wsrep_aborter, kill_signal);
|
|
||||||
tmp->awake_no_mutex(kill_signal);
|
tmp->awake_no_mutex(kill_signal);
|
||||||
error= 0;
|
error= 0;
|
||||||
|
#ifdef WITH_WSREP
|
||||||
|
}
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -9368,18 +9365,6 @@ static
|
|||||||
void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
|
void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
|
||||||
{
|
{
|
||||||
uint error;
|
uint error;
|
||||||
#ifdef WITH_WSREP
|
|
||||||
if (WSREP(thd))
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("sql_kill called");
|
|
||||||
if (thd->wsrep_applier)
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("KILL in applying, bailing out here");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
|
||||||
}
|
|
||||||
#endif /* WITH_WSREP */
|
|
||||||
if (likely(!(error= kill_one_thread(thd, id, state, type))))
|
if (likely(!(error= kill_one_thread(thd, id, state, type))))
|
||||||
{
|
{
|
||||||
if (!thd->killed)
|
if (!thd->killed)
|
||||||
@@ -9389,11 +9374,6 @@ void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
my_error(error, MYF(0), id);
|
my_error(error, MYF(0), id);
|
||||||
#ifdef WITH_WSREP
|
|
||||||
return;
|
|
||||||
wsrep_error_label:
|
|
||||||
my_error(ER_KILL_DENIED_ERROR, MYF(0), (long long) thd->thread_id);
|
|
||||||
#endif /* WITH_WSREP */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -9402,18 +9382,6 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
|
|||||||
{
|
{
|
||||||
uint error;
|
uint error;
|
||||||
ha_rows rows;
|
ha_rows rows;
|
||||||
#ifdef WITH_WSREP
|
|
||||||
if (WSREP(thd))
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("sql_kill_user called");
|
|
||||||
if (thd->wsrep_applier)
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("KILL in applying, bailing out here");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
|
|
||||||
}
|
|
||||||
#endif /* WITH_WSREP */
|
|
||||||
switch (error= kill_threads_for_user(thd, user, state, &rows))
|
switch (error= kill_threads_for_user(thd, user, state, &rows))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -9429,11 +9397,6 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
|
|||||||
default:
|
default:
|
||||||
my_error(error, MYF(0));
|
my_error(error, MYF(0));
|
||||||
}
|
}
|
||||||
#ifdef WITH_WSREP
|
|
||||||
return;
|
|
||||||
wsrep_error_label:
|
|
||||||
my_error(ER_KILL_DENIED_ERROR, MYF(0), (long long) thd->thread_id);
|
|
||||||
#endif /* WITH_WSREP */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ static struct wsrep_service_st wsrep_handler = {
|
|||||||
wsrep_on,
|
wsrep_on,
|
||||||
wsrep_prepare_key_for_innodb,
|
wsrep_prepare_key_for_innodb,
|
||||||
wsrep_thd_LOCK,
|
wsrep_thd_LOCK,
|
||||||
|
wsrep_thd_TRYLOCK,
|
||||||
wsrep_thd_UNLOCK,
|
wsrep_thd_UNLOCK,
|
||||||
wsrep_thd_query,
|
wsrep_thd_query,
|
||||||
wsrep_thd_retry_counter,
|
wsrep_thd_retry_counter,
|
||||||
@@ -179,7 +180,6 @@ static struct wsrep_service_st wsrep_handler = {
|
|||||||
wsrep_OSU_method_get,
|
wsrep_OSU_method_get,
|
||||||
wsrep_thd_has_ignored_error,
|
wsrep_thd_has_ignored_error,
|
||||||
wsrep_thd_set_ignored_error,
|
wsrep_thd_set_ignored_error,
|
||||||
wsrep_thd_set_wsrep_aborter,
|
|
||||||
wsrep_report_bf_lock_wait,
|
wsrep_report_bf_lock_wait,
|
||||||
wsrep_thd_kill_LOCK,
|
wsrep_thd_kill_LOCK,
|
||||||
wsrep_thd_kill_UNLOCK,
|
wsrep_thd_kill_UNLOCK,
|
||||||
|
|||||||
@@ -150,10 +150,10 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order);
|
|||||||
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
|
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
|
||||||
bool change_list, bool *simple_order);
|
bool change_list, bool *simple_order);
|
||||||
static int return_zero_rows(JOIN *join, select_result *res,
|
static int return_zero_rows(JOIN *join, select_result *res,
|
||||||
List<TABLE_LIST> &tables,
|
List<TABLE_LIST> *tables,
|
||||||
List<Item> &fields, bool send_row,
|
List<Item> *fields, bool send_row,
|
||||||
ulonglong select_options, const char *info,
|
ulonglong select_options, const char *info,
|
||||||
Item *having, List<Item> &all_fields);
|
Item *having, List<Item> *all_fields);
|
||||||
static COND *build_equal_items(JOIN *join, COND *cond,
|
static COND *build_equal_items(JOIN *join, COND *cond,
|
||||||
COND_EQUAL *inherited,
|
COND_EQUAL *inherited,
|
||||||
List<TABLE_LIST> *join_list,
|
List<TABLE_LIST> *join_list,
|
||||||
@@ -1301,11 +1301,40 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
Check fields, find best join, do the select and output fields.
|
Check fields, find best join, do the select and output fields.
|
||||||
mysql_select assumes that all tables are already opened
|
mysql_select assumes that all tables are already opened
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if we have a field reference. If yes, we have to use
|
||||||
|
mixed_implicit_grouping.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool check_list_for_field(List<Item> *items)
|
||||||
|
{
|
||||||
|
List_iterator_fast <Item> select_it(*items);
|
||||||
|
Item *select_el;
|
||||||
|
|
||||||
|
while ((select_el= select_it++))
|
||||||
|
{
|
||||||
|
if (select_el->with_field())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_list_for_field(ORDER *order)
|
||||||
|
{
|
||||||
|
for (; order; order= order->next)
|
||||||
|
{
|
||||||
|
if (order->item[0]->with_field())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Prepare of whole select (including sub queries in future).
|
Prepare of whole select (including sub queries in future).
|
||||||
@@ -1387,53 +1416,44 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
|
|||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TRUE if the SELECT list mixes elements with and without grouping,
|
mixed_implicit_grouping will be set to TRUE if the SELECT list
|
||||||
and there is no GROUP BY clause. Mixing non-aggregated fields with
|
mixes elements with and without grouping, and there is no GROUP BY
|
||||||
aggregate functions in the SELECT list is a MySQL extenstion that
|
clause.
|
||||||
is allowed only if the ONLY_FULL_GROUP_BY sql mode is not set.
|
Mixing non-aggregated fields with aggregate functions in the
|
||||||
|
SELECT list or HAVING is a MySQL extension that is allowed only if
|
||||||
|
the ONLY_FULL_GROUP_BY sql mode is not set.
|
||||||
*/
|
*/
|
||||||
mixed_implicit_grouping= false;
|
mixed_implicit_grouping= false;
|
||||||
if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
|
if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
|
||||||
select_lex->with_sum_func && !group_list)
|
select_lex->with_sum_func && !group_list)
|
||||||
{
|
{
|
||||||
List_iterator_fast <Item> select_it(fields_list);
|
if (check_list_for_field(&fields_list) ||
|
||||||
Item *select_el; /* Element of the SELECT clause, can be an expression. */
|
check_list_for_field(order))
|
||||||
bool found_field_elem= false;
|
|
||||||
bool found_sum_func_elem= false;
|
|
||||||
|
|
||||||
while ((select_el= select_it++))
|
|
||||||
{
|
{
|
||||||
if (select_el->with_sum_func())
|
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
|
||||||
found_sum_func_elem= true;
|
|
||||||
if (select_el->with_field())
|
mixed_implicit_grouping= true; // mark for future
|
||||||
found_field_elem= true;
|
|
||||||
if (found_sum_func_elem && found_field_elem)
|
while (TABLE_LIST *tbl= li++)
|
||||||
{
|
{
|
||||||
mixed_implicit_grouping= true;
|
/*
|
||||||
break;
|
If the query uses implicit grouping where the select list
|
||||||
|
contains both aggregate functions and non-aggregate fields,
|
||||||
|
any non-aggregated field may produce a NULL value. Set all
|
||||||
|
fields of each table as nullable before semantic analysis to
|
||||||
|
take into account this change of nullability.
|
||||||
|
|
||||||
|
Note: this loop doesn't touch tables inside merged
|
||||||
|
semi-joins, because subquery-to-semijoin conversion has not
|
||||||
|
been done yet. This is intended.
|
||||||
|
*/
|
||||||
|
if (tbl->table)
|
||||||
|
tbl->table->maybe_null= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table_count= select_lex->leaf_tables.elements;
|
table_count= select_lex->leaf_tables.elements;
|
||||||
|
|
||||||
TABLE_LIST *tbl;
|
|
||||||
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
|
|
||||||
while ((tbl= li++))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
If the query uses implicit grouping where the select list contains both
|
|
||||||
aggregate functions and non-aggregate fields, any non-aggregated field
|
|
||||||
may produce a NULL value. Set all fields of each table as nullable before
|
|
||||||
semantic analysis to take into account this change of nullability.
|
|
||||||
|
|
||||||
Note: this loop doesn't touch tables inside merged semi-joins, because
|
|
||||||
subquery-to-semijoin conversion has not been done yet. This is intended.
|
|
||||||
*/
|
|
||||||
if (mixed_implicit_grouping && tbl->table)
|
|
||||||
tbl->table->maybe_null= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint real_og_num= og_num;
|
uint real_og_num= og_num;
|
||||||
if (skip_order_by &&
|
if (skip_order_by &&
|
||||||
select_lex != select_lex->master_unit()->global_parameters())
|
select_lex != select_lex->master_unit()->global_parameters())
|
||||||
@@ -1453,7 +1473,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
|
|||||||
|
|
||||||
{
|
{
|
||||||
List_iterator_fast<TABLE_LIST> it(select_lex->leaf_tables);
|
List_iterator_fast<TABLE_LIST> it(select_lex->leaf_tables);
|
||||||
while ((tbl= it++))
|
while (TABLE_LIST *tbl= it++)
|
||||||
{
|
{
|
||||||
if (tbl->table_function &&
|
if (tbl->table_function &&
|
||||||
tbl->table_function->setup(thd, tbl, select_lex_arg))
|
tbl->table_function->setup(thd, tbl, select_lex_arg))
|
||||||
@@ -4074,7 +4094,7 @@ bool JOIN::make_aggr_tables_info()
|
|||||||
set_items_ref_array(items0);
|
set_items_ref_array(items0);
|
||||||
if (join_tab)
|
if (join_tab)
|
||||||
join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
|
join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
|
||||||
setup_end_select_func(this, NULL);
|
setup_end_select_func(this);
|
||||||
group= has_group_by;
|
group= has_group_by;
|
||||||
|
|
||||||
DBUG_RETURN(false);
|
DBUG_RETURN(false);
|
||||||
@@ -4469,13 +4489,7 @@ JOIN::reinit()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset of sum functions */
|
clear_sum_funcs();
|
||||||
if (sum_funcs)
|
|
||||||
{
|
|
||||||
Item_sum *func, **func_ptr= sum_funcs;
|
|
||||||
while ((func= *(func_ptr++)))
|
|
||||||
func->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (no_rows_in_result_called)
|
if (no_rows_in_result_called)
|
||||||
{
|
{
|
||||||
@@ -4758,12 +4772,12 @@ void JOIN::exec_inner()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(void) return_zero_rows(this, result, select_lex->leaf_tables,
|
(void) return_zero_rows(this, result, &select_lex->leaf_tables,
|
||||||
*columns_list,
|
columns_list,
|
||||||
send_row_on_empty_set(),
|
send_row_on_empty_set(),
|
||||||
select_options,
|
select_options,
|
||||||
zero_result_cause,
|
zero_result_cause,
|
||||||
having ? having : tmp_having, all_fields);
|
having ? having : tmp_having, &all_fields);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15641,10 +15655,36 @@ ORDER *simple_remove_const(ORDER *order, COND *where)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set all fields in the table to have a null value
|
||||||
|
|
||||||
|
@param tables Table list
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void make_tables_null_complemented(List<TABLE_LIST> *tables)
|
||||||
|
{
|
||||||
|
List_iterator<TABLE_LIST> ti(*tables);
|
||||||
|
TABLE_LIST *table;
|
||||||
|
while ((table= ti++))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Don't touch semi-join materialization tables, as the a join_free()
|
||||||
|
call may have freed them (and HAVING clause can't have references to
|
||||||
|
them anyway).
|
||||||
|
*/
|
||||||
|
if (!table->is_jtbm())
|
||||||
|
{
|
||||||
|
TABLE *tbl= table->table;
|
||||||
|
mark_as_null_row(tbl); // Set fields to NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> *tables,
|
||||||
List<Item> &fields, bool send_row, ulonglong select_options,
|
List<Item> *fields, bool send_row, ulonglong select_options,
|
||||||
const char *info, Item *having, List<Item> &all_fields)
|
const char *info, Item *having, List<Item> *all_fields)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("return_zero_rows");
|
DBUG_ENTER("return_zero_rows");
|
||||||
|
|
||||||
@@ -15660,24 +15700,15 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
|||||||
Set all tables to have NULL row. This is needed as we will be evaluating
|
Set all tables to have NULL row. This is needed as we will be evaluating
|
||||||
HAVING condition.
|
HAVING condition.
|
||||||
*/
|
*/
|
||||||
List_iterator<TABLE_LIST> ti(tables);
|
make_tables_null_complemented(tables);
|
||||||
TABLE_LIST *table;
|
|
||||||
while ((table= ti++))
|
List_iterator_fast<Item> it(*all_fields);
|
||||||
{
|
|
||||||
/*
|
|
||||||
Don't touch semi-join materialization tables, as the above join_free()
|
|
||||||
call has freed them (and HAVING clause can't have references to them
|
|
||||||
anyway).
|
|
||||||
*/
|
|
||||||
if (!table->is_jtbm())
|
|
||||||
mark_as_null_row(table->table); // All fields are NULL
|
|
||||||
}
|
|
||||||
List_iterator_fast<Item> it(all_fields);
|
|
||||||
Item *item;
|
Item *item;
|
||||||
/*
|
/*
|
||||||
Inform all items (especially aggregating) to calculate HAVING correctly,
|
Inform all items (especially aggregating) to calculate HAVING correctly,
|
||||||
also we will need it for sending results.
|
also we will need it for sending results.
|
||||||
*/
|
*/
|
||||||
|
join->no_rows_in_result_called= 1;
|
||||||
while ((item= it++))
|
while ((item= it++))
|
||||||
item->no_rows_in_result();
|
item->no_rows_in_result();
|
||||||
if (having && having->val_int() == 0)
|
if (having && having->val_int() == 0)
|
||||||
@@ -15691,12 +15722,12 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
|||||||
join->thd->limit_found_rows= 0;
|
join->thd->limit_found_rows= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(result->send_result_set_metadata(fields,
|
if (!(result->send_result_set_metadata(*fields,
|
||||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
|
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
|
||||||
{
|
{
|
||||||
bool send_error= FALSE;
|
bool send_error= FALSE;
|
||||||
if (send_row)
|
if (send_row)
|
||||||
send_error= result->send_data_with_check(fields, join->unit, 0) > 0;
|
send_error= result->send_data_with_check(*fields, join->unit, 0) > 0;
|
||||||
if (likely(!send_error))
|
if (likely(!send_error))
|
||||||
result->send_eof(); // Should be safe
|
result->send_eof(); // Should be safe
|
||||||
}
|
}
|
||||||
@@ -15712,49 +15743,42 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
used only in JOIN::clear (always) and in do_select()
|
Reset table rows to contain a null-complement row (all fields are null)
|
||||||
(if there where no matching rows)
|
|
||||||
|
Used only in JOIN::clear() and in do_select() if there where no matching rows.
|
||||||
|
|
||||||
@param join JOIN
|
@param join JOIN
|
||||||
@param cleared_tables If not null, clear also const tables and mark all
|
@param cleared_tables Used to mark all cleared tables in the map. Needed for
|
||||||
cleared tables in the map. cleared_tables is only
|
unclear_tables() to know which tables to restore to
|
||||||
set when called from do_select() when there is a
|
their original state.
|
||||||
group function and there where no matching rows.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void clear_tables(JOIN *join, table_map *cleared_tables)
|
static void clear_tables(JOIN *join, table_map *cleared_tables)
|
||||||
{
|
{
|
||||||
/*
|
DBUG_ASSERT(cleared_tables);
|
||||||
must clear only the non-const tables as const tables are not re-calculated.
|
|
||||||
*/
|
|
||||||
for (uint i= 0 ; i < join->table_count ; i++)
|
for (uint i= 0 ; i < join->table_count ; i++)
|
||||||
{
|
{
|
||||||
TABLE *table= join->table[i];
|
TABLE *table= join->table[i];
|
||||||
|
|
||||||
if (table->null_row)
|
if (table->null_row)
|
||||||
continue; // Nothing more to do
|
continue; // Nothing more to do
|
||||||
if (!(table->map & join->const_table_map) || cleared_tables)
|
(*cleared_tables)|= (((table_map) 1) << i);
|
||||||
|
if (table->s->null_bytes)
|
||||||
{
|
{
|
||||||
if (cleared_tables)
|
/*
|
||||||
{
|
Remember null bits for the record so that we can restore the
|
||||||
(*cleared_tables)|= (((table_map) 1) << i);
|
original const record in unclear_tables()
|
||||||
if (table->s->null_bytes)
|
*/
|
||||||
{
|
memcpy(table->record[1], table->null_flags, table->s->null_bytes);
|
||||||
/*
|
|
||||||
Remember null bits for the record so that we can restore the
|
|
||||||
original const record in unclear_tables()
|
|
||||||
*/
|
|
||||||
memcpy(table->record[1], table->null_flags, table->s->null_bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mark_as_null_row(table); // All fields are NULL
|
|
||||||
}
|
}
|
||||||
|
mark_as_null_row(table); // All fields are NULL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reverse null marking for tables and restore null bits.
|
Reverse null marking for tables and restore null bits.
|
||||||
|
This return the tables to the state of before clear_tables().
|
||||||
|
|
||||||
We have to do this because the tables may be re-used in a sub query
|
We have to do this because the tables may be re-used in a sub query
|
||||||
and the subquery will assume that the const tables contains the original
|
and the subquery will assume that the const tables contains the original
|
||||||
@@ -21493,9 +21517,9 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab)
|
|||||||
end_select function to use. This function can't fail.
|
end_select function to use. This function can't fail.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab)
|
Next_select_func setup_end_select_func(JOIN *join)
|
||||||
{
|
{
|
||||||
TMP_TABLE_PARAM *tmp_tbl= tab ? tab->tmp_table_param : &join->tmp_table_param;
|
TMP_TABLE_PARAM *tmp_tbl= &join->tmp_table_param;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Choose method for presenting result to user. Use end_send_group
|
Choose method for presenting result to user. Use end_send_group
|
||||||
@@ -21565,7 +21589,7 @@ do_select(JOIN *join, Procedure *procedure)
|
|||||||
join->duplicate_rows= join->send_records=0;
|
join->duplicate_rows= join->send_records=0;
|
||||||
if (join->only_const_tables() && !join->need_tmp)
|
if (join->only_const_tables() && !join->need_tmp)
|
||||||
{
|
{
|
||||||
Next_select_func end_select= setup_end_select_func(join, NULL);
|
Next_select_func end_select= setup_end_select_func(join);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HAVING will be checked after processing aggregate functions,
|
HAVING will be checked after processing aggregate functions,
|
||||||
@@ -22040,6 +22064,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Restore state if mark_as_null_row() have been called */
|
||||||
if (join_tab->last_inner)
|
if (join_tab->last_inner)
|
||||||
{
|
{
|
||||||
JOIN_TAB *last_inner_tab= join_tab->last_inner;
|
JOIN_TAB *last_inner_tab= join_tab->last_inner;
|
||||||
@@ -23452,11 +23477,18 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||||||
{
|
{
|
||||||
int idx= -1;
|
int idx= -1;
|
||||||
enum_nested_loop_state ok_code= NESTED_LOOP_OK;
|
enum_nested_loop_state ok_code= NESTED_LOOP_OK;
|
||||||
|
/*
|
||||||
|
join_tab can be 0 in the case all tables are const tables and we did not
|
||||||
|
need a temporary table to store the result.
|
||||||
|
In this case we use the original given fields, which is stored in
|
||||||
|
join->fields.
|
||||||
|
*/
|
||||||
List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;
|
List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;
|
||||||
DBUG_ENTER("end_send_group");
|
DBUG_ENTER("end_send_group");
|
||||||
|
|
||||||
if (!join->items3.is_null() && !join->set_group_rpa)
|
if (!join->items3.is_null() && !join->set_group_rpa)
|
||||||
{
|
{
|
||||||
|
/* Move ref_pointer_array to points to items3 */
|
||||||
join->set_group_rpa= true;
|
join->set_group_rpa= true;
|
||||||
join->set_items_ref_array(join->items3);
|
join->set_items_ref_array(join->items3);
|
||||||
}
|
}
|
||||||
@@ -23464,10 +23496,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||||||
if (!join->first_record || end_of_records ||
|
if (!join->first_record || end_of_records ||
|
||||||
(idx=test_if_group_changed(join->group_fields)) >= 0)
|
(idx=test_if_group_changed(join->group_fields)) >= 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!join->group_sent &&
|
if (!join->group_sent &&
|
||||||
(join->first_record ||
|
(join->first_record ||
|
||||||
(end_of_records && !join->group && !join->group_optimized_away)))
|
(end_of_records && !join->group && !join->group_optimized_away)))
|
||||||
{
|
{
|
||||||
|
table_map cleared_tables= (table_map) 0;
|
||||||
if (join->procedure)
|
if (join->procedure)
|
||||||
join->procedure->end_group();
|
join->procedure->end_group();
|
||||||
/* Test if there was a group change. */
|
/* Test if there was a group change. */
|
||||||
@@ -23492,11 +23526,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||||||
/* Reset all sum functions on group change. */
|
/* Reset all sum functions on group change. */
|
||||||
if (!join->first_record)
|
if (!join->first_record)
|
||||||
{
|
{
|
||||||
List_iterator_fast<Item> it(*join->fields);
|
|
||||||
Item *item;
|
|
||||||
/* No matching rows for group function */
|
/* No matching rows for group function */
|
||||||
join->clear();
|
|
||||||
|
|
||||||
|
List_iterator_fast<Item> it(*fields);
|
||||||
|
Item *item;
|
||||||
|
join->no_rows_in_result_called= 1;
|
||||||
|
|
||||||
|
join->clear(&cleared_tables);
|
||||||
while ((item= it++))
|
while ((item= it++))
|
||||||
item->no_rows_in_result();
|
item->no_rows_in_result();
|
||||||
}
|
}
|
||||||
@@ -23524,7 +23560,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||||||
if (join->rollup_send_data((uint) (idx+1)))
|
if (join->rollup_send_data((uint) (idx+1)))
|
||||||
error= 1;
|
error= 1;
|
||||||
}
|
}
|
||||||
}
|
if (join->no_rows_in_result_called)
|
||||||
|
{
|
||||||
|
/* Restore null tables to original state */
|
||||||
|
join->no_rows_in_result_called= 0;
|
||||||
|
if (cleared_tables)
|
||||||
|
unclear_tables(join, &cleared_tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (unlikely(error > 0))
|
if (unlikely(error > 0))
|
||||||
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
|
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
|
||||||
if (end_of_records)
|
if (end_of_records)
|
||||||
@@ -23841,6 +23884,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
|||||||
{
|
{
|
||||||
if (join->first_record || (end_of_records && !join->group))
|
if (join->first_record || (end_of_records && !join->group))
|
||||||
{
|
{
|
||||||
|
table_map cleared_tables= (table_map) 0;
|
||||||
if (join->procedure)
|
if (join->procedure)
|
||||||
join->procedure->end_group();
|
join->procedure->end_group();
|
||||||
int send_group_parts= join->send_group_parts;
|
int send_group_parts= join->send_group_parts;
|
||||||
@@ -23849,7 +23893,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
|||||||
if (!join->first_record)
|
if (!join->first_record)
|
||||||
{
|
{
|
||||||
/* No matching rows for group function */
|
/* No matching rows for group function */
|
||||||
join->clear();
|
join->clear(&cleared_tables);
|
||||||
}
|
}
|
||||||
copy_sum_funcs(join->sum_funcs,
|
copy_sum_funcs(join->sum_funcs,
|
||||||
join->sum_funcs_end[send_group_parts]);
|
join->sum_funcs_end[send_group_parts]);
|
||||||
@@ -23872,6 +23916,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
|||||||
DBUG_RETURN(NESTED_LOOP_ERROR);
|
DBUG_RETURN(NESTED_LOOP_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cleared_tables)
|
||||||
|
unclear_tables(join, &cleared_tables);
|
||||||
if (end_of_records)
|
if (end_of_records)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -25603,7 +25649,7 @@ JOIN_TAB::remove_duplicates()
|
|||||||
!(join->select_options & OPTION_FOUND_ROWS))
|
!(join->select_options & OPTION_FOUND_ROWS))
|
||||||
{
|
{
|
||||||
// only const items with no OPTION_FOUND_ROWS
|
// only const items with no OPTION_FOUND_ROWS
|
||||||
join->unit->lim.set_single_row(); // Only send first row
|
join->unit->lim.send_first_row(); // Only send first row
|
||||||
my_free(sortorder);
|
my_free(sortorder);
|
||||||
DBUG_RETURN(false);
|
DBUG_RETURN(false);
|
||||||
}
|
}
|
||||||
@@ -28007,11 +28053,8 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg,
|
|||||||
(end_send_group/end_write_group)
|
(end_send_group/end_write_group)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void JOIN::clear()
|
void inline JOIN::clear_sum_funcs()
|
||||||
{
|
{
|
||||||
clear_tables(this, 0);
|
|
||||||
copy_fields(&tmp_table_param);
|
|
||||||
|
|
||||||
if (sum_funcs)
|
if (sum_funcs)
|
||||||
{
|
{
|
||||||
Item_sum *func, **func_ptr= sum_funcs;
|
Item_sum *func, **func_ptr= sum_funcs;
|
||||||
@@ -28021,6 +28064,22 @@ void JOIN::clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prepare for returning 'empty row' when there is no matching row.
|
||||||
|
|
||||||
|
- Mark all tables with mark_as_null_row()
|
||||||
|
- Make a copy of of all simple SELECT items
|
||||||
|
- Reset all sum functions to NULL or 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void JOIN::clear(table_map *cleared_tables)
|
||||||
|
{
|
||||||
|
clear_tables(this, cleared_tables);
|
||||||
|
copy_fields(&tmp_table_param);
|
||||||
|
clear_sum_funcs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
|
Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
|
||||||
|
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ enum sj_strategy_enum
|
|||||||
|
|
||||||
typedef enum_nested_loop_state
|
typedef enum_nested_loop_state
|
||||||
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
|
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
|
||||||
Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab);
|
Next_select_func setup_end_select_func(JOIN *join);
|
||||||
int rr_sequential(READ_RECORD *info);
|
int rr_sequential(READ_RECORD *info);
|
||||||
int read_record_func_for_rr_and_unpack(READ_RECORD *info);
|
int read_record_func_for_rr_and_unpack(READ_RECORD *info);
|
||||||
Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
|
Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
|
||||||
@@ -1722,7 +1722,8 @@ public:
|
|||||||
void join_free();
|
void join_free();
|
||||||
/** Cleanup this JOIN, possibly for reuse */
|
/** Cleanup this JOIN, possibly for reuse */
|
||||||
void cleanup(bool full);
|
void cleanup(bool full);
|
||||||
void clear();
|
void clear(table_map *cleared_tables);
|
||||||
|
void inline clear_sum_funcs();
|
||||||
bool send_row_on_empty_set()
|
bool send_row_on_empty_set()
|
||||||
{
|
{
|
||||||
return (do_send_rows && implicit_grouping && !group_optimized_away &&
|
return (do_send_rows && implicit_grouping && !group_optimized_away &&
|
||||||
|
|||||||
@@ -7574,8 +7574,9 @@ extern Named_type_handler<Type_handler_time> type_handler_time;
|
|||||||
extern Named_type_handler<Type_handler_time2> type_handler_time2;
|
extern Named_type_handler<Type_handler_time2> type_handler_time2;
|
||||||
extern Named_type_handler<Type_handler_datetime> type_handler_datetime;
|
extern Named_type_handler<Type_handler_datetime> type_handler_datetime;
|
||||||
extern Named_type_handler<Type_handler_datetime2> type_handler_datetime2;
|
extern Named_type_handler<Type_handler_datetime2> type_handler_datetime2;
|
||||||
extern Named_type_handler<Type_handler_timestamp> type_handler_timestamp;
|
|
||||||
extern Named_type_handler<Type_handler_timestamp2> type_handler_timestamp2;
|
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_timestamp> type_handler_timestamp;
|
||||||
|
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_timestamp2> type_handler_timestamp2;
|
||||||
|
|
||||||
extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
|
extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
|
||||||
|
|
||||||
|
|||||||
10
sql/table.h
10
sql/table.h
@@ -3376,10 +3376,16 @@ inline void mark_as_null_row(TABLE *table)
|
|||||||
bfill(table->null_flags,table->s->null_bytes,255);
|
bfill(table->null_flags,table->s->null_bytes,255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Restore table to state before mark_as_null_row() call.
|
||||||
|
This assumes that the caller has restored table->null_flags,
|
||||||
|
as is done in unclear_tables().
|
||||||
|
*/
|
||||||
|
|
||||||
inline void unmark_as_null_row(TABLE *table)
|
inline void unmark_as_null_row(TABLE *table)
|
||||||
{
|
{
|
||||||
table->null_row=0;
|
table->null_row= 0;
|
||||||
table->status= STATUS_NO_RECORD;
|
table->status&= ~STATUS_NULL_ROW;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_simple_order(ORDER *order);
|
bool is_simple_order(ORDER *order);
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ my_bool wsrep_on(const THD *)
|
|||||||
void wsrep_thd_LOCK(const THD *)
|
void wsrep_thd_LOCK(const THD *)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
int wsrep_thd_TRYLOCK(const THD *)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void wsrep_thd_UNLOCK(const THD *)
|
void wsrep_thd_UNLOCK(const THD *)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@@ -154,8 +159,6 @@ void wsrep_thd_set_ignored_error(THD*, my_bool)
|
|||||||
{ }
|
{ }
|
||||||
ulong wsrep_OSU_method_get(const THD*)
|
ulong wsrep_OSU_method_get(const THD*)
|
||||||
{ return 0;}
|
{ return 0;}
|
||||||
bool wsrep_thd_set_wsrep_aborter(THD*, THD*)
|
|
||||||
{ return 0;}
|
|
||||||
|
|
||||||
void wsrep_report_bf_lock_wait(const THD*,
|
void wsrep_report_bf_lock_wait(const THD*,
|
||||||
unsigned long long)
|
unsigned long long)
|
||||||
|
|||||||
@@ -510,6 +510,7 @@ int Wsrep_high_priority_service::log_dummy_write_set(const wsrep::ws_handle& ws_
|
|||||||
m_thd->wait_for_prior_commit();
|
m_thd->wait_for_prior_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WSREP_DEBUG("checkpointing dummy write set %lld", ws_meta.seqno().get());
|
||||||
wsrep_set_SE_checkpoint(ws_meta.gtid(), wsrep_gtid_server.gtid());
|
wsrep_set_SE_checkpoint(ws_meta.gtid(), wsrep_gtid_server.gtid());
|
||||||
|
|
||||||
if (!WSREP_EMULATE_BINLOG(m_thd))
|
if (!WSREP_EMULATE_BINLOG(m_thd))
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
#include "log_event.h"
|
#include "log_event.h"
|
||||||
#include "sql_connect.h"
|
#include "sql_connect.h"
|
||||||
#include "thread_cache.h"
|
#include "thread_cache.h"
|
||||||
|
#include "debug_sync.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -3107,6 +3108,20 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
request_thd, granted_thd);
|
request_thd, granted_thd);
|
||||||
ticket->wsrep_report(wsrep_debug);
|
ticket->wsrep_report(wsrep_debug);
|
||||||
|
|
||||||
|
DEBUG_SYNC(request_thd, "before_wsrep_thd_abort");
|
||||||
|
DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort", {
|
||||||
|
const char act[]= "now "
|
||||||
|
"SIGNAL sync.before_wsrep_thd_abort_reached "
|
||||||
|
"WAIT_FOR signal.before_wsrep_thd_abort";
|
||||||
|
DBUG_ASSERT(!debug_sync_set_action(request_thd, STRING_WITH_LEN(act)));
|
||||||
|
};);
|
||||||
|
|
||||||
|
/* Here we will call wsrep_abort_transaction so we should hold
|
||||||
|
THD::LOCK_thd_data to protect victim from concurrent usage
|
||||||
|
and THD::LOCK_thd_kill to protect from disconnect or delete.
|
||||||
|
|
||||||
|
*/
|
||||||
|
mysql_mutex_lock(&granted_thd->LOCK_thd_kill);
|
||||||
mysql_mutex_lock(&granted_thd->LOCK_thd_data);
|
mysql_mutex_lock(&granted_thd->LOCK_thd_data);
|
||||||
|
|
||||||
if (wsrep_thd_is_toi(granted_thd) ||
|
if (wsrep_thd_is_toi(granted_thd) ||
|
||||||
@@ -3118,13 +3133,11 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
wsrep_thd_query(request_thd));
|
wsrep_thd_query(request_thd));
|
||||||
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
||||||
ticket->wsrep_report(wsrep_debug);
|
ticket->wsrep_report(wsrep_debug);
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
|
||||||
}
|
}
|
||||||
else if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd))
|
else if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd))
|
||||||
{
|
{
|
||||||
WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
|
WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
|
||||||
schema, schema_len, request_thd, granted_thd);
|
schema, schema_len, request_thd, granted_thd);
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
|
||||||
WSREP_DEBUG("wsrep_handle_mdl_conflict DDL vs SR for %s",
|
WSREP_DEBUG("wsrep_handle_mdl_conflict DDL vs SR for %s",
|
||||||
wsrep_thd_query(request_thd));
|
wsrep_thd_query(request_thd));
|
||||||
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
||||||
@@ -3136,6 +3149,7 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
request_thd, granted_thd);
|
request_thd, granted_thd);
|
||||||
ticket->wsrep_report(true);
|
ticket->wsrep_report(true);
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||||
|
mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
|
||||||
unireg_abort(1);
|
unireg_abort(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3146,7 +3160,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
wsrep_thd_query(request_thd));
|
wsrep_thd_query(request_thd));
|
||||||
THD_STAGE_INFO(request_thd, stage_waiting_ddl);
|
THD_STAGE_INFO(request_thd, stage_waiting_ddl);
|
||||||
ticket->wsrep_report(wsrep_debug);
|
ticket->wsrep_report(wsrep_debug);
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
|
||||||
if (granted_thd->current_backup_stage != BACKUP_FINISHED &&
|
if (granted_thd->current_backup_stage != BACKUP_FINISHED &&
|
||||||
wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
|
wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
|
||||||
{
|
{
|
||||||
@@ -3160,7 +3173,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
wsrep_thd_query(request_thd));
|
wsrep_thd_query(request_thd));
|
||||||
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
||||||
ticket->wsrep_report(wsrep_debug);
|
ticket->wsrep_report(wsrep_debug);
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
|
||||||
wsrep_abort_thd(request_thd, granted_thd, 1);
|
wsrep_abort_thd(request_thd, granted_thd, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -3174,7 +3186,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
|
|
||||||
if (granted_thd->wsrep_trx().active())
|
if (granted_thd->wsrep_trx().active())
|
||||||
{
|
{
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
|
||||||
wsrep_abort_thd(request_thd, granted_thd, 1);
|
wsrep_abort_thd(request_thd, granted_thd, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -3183,10 +3194,9 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
Granted_thd is likely executing with wsrep_on=0. If the requesting
|
Granted_thd is likely executing with wsrep_on=0. If the requesting
|
||||||
thd is BF, BF abort and wait.
|
thd is BF, BF abort and wait.
|
||||||
*/
|
*/
|
||||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
|
||||||
|
|
||||||
if (wsrep_thd_is_BF(request_thd, FALSE))
|
if (wsrep_thd_is_BF(request_thd, FALSE))
|
||||||
{
|
{
|
||||||
|
granted_thd->awake_no_mutex(KILL_QUERY_HARD);
|
||||||
ha_abort_transaction(request_thd, granted_thd, TRUE);
|
ha_abort_transaction(request_thd, granted_thd, TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -3195,10 +3205,14 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
schema, schema_len,
|
schema, schema_len,
|
||||||
request_thd, granted_thd);
|
request_thd, granted_thd);
|
||||||
ticket->wsrep_report(true);
|
ticket->wsrep_report(true);
|
||||||
|
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||||
|
mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
|
||||||
unireg_abort(1);
|
unireg_abort(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||||
|
mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3210,13 +3224,17 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
|||||||
static bool abort_replicated(THD *thd)
|
static bool abort_replicated(THD *thd)
|
||||||
{
|
{
|
||||||
bool ret_code= false;
|
bool ret_code= false;
|
||||||
|
mysql_mutex_lock(&thd->LOCK_thd_kill);
|
||||||
|
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||||
if (thd->wsrep_trx().state() == wsrep::transaction::s_committing)
|
if (thd->wsrep_trx().state() == wsrep::transaction::s_committing)
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
|
WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
|
||||||
|
|
||||||
(void)wsrep_abort_thd(thd, thd, TRUE);
|
wsrep_abort_thd(thd, thd, TRUE);
|
||||||
ret_code= true;
|
ret_code= true;
|
||||||
}
|
}
|
||||||
|
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||||
|
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,9 +148,13 @@ void Wsrep_server_service::release_high_priority_service(wsrep::high_priority_se
|
|||||||
wsrep_delete_threadvars();
|
wsrep_delete_threadvars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wsrep_server_service::background_rollback(wsrep::client_state& client_state)
|
void Wsrep_server_service::background_rollback(
|
||||||
|
wsrep::unique_lock<wsrep::mutex> &lock WSREP_UNUSED,
|
||||||
|
wsrep::client_state &client_state)
|
||||||
{
|
{
|
||||||
Wsrep_client_state& cs= static_cast<Wsrep_client_state&>(client_state);
|
DBUG_ASSERT(lock.owns_lock());
|
||||||
|
Wsrep_client_state &cs= static_cast<Wsrep_client_state &>(client_state);
|
||||||
|
mysql_mutex_assert_owner(&cs.thd()->LOCK_thd_data);
|
||||||
wsrep_fire_rollbacker(cs.thd());
|
wsrep_fire_rollbacker(cs.thd());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ public:
|
|||||||
|
|
||||||
void release_high_priority_service(wsrep::high_priority_service*);
|
void release_high_priority_service(wsrep::high_priority_service*);
|
||||||
|
|
||||||
void background_rollback(wsrep::client_state&);
|
void background_rollback(wsrep::unique_lock<wsrep::mutex> &,
|
||||||
|
wsrep::client_state &);
|
||||||
|
|
||||||
void bootstrap();
|
void bootstrap();
|
||||||
void log_message(enum wsrep::log::level, const char*);
|
void log_message(enum wsrep::log::level, const char*);
|
||||||
|
|||||||
204
sql/wsrep_thd.cc
204
sql/wsrep_thd.cc
@@ -307,48 +307,9 @@ void wsrep_fire_rollbacker(THD *thd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool wsrep_bf_abort_low(THD *bf_thd, THD *victim_thd)
|
||||||
int wsrep_abort_thd(THD *bf_thd,
|
|
||||||
THD *victim_thd,
|
|
||||||
my_bool signal)
|
|
||||||
{
|
{
|
||||||
DBUG_ENTER("wsrep_abort_thd");
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||||
|
|
||||||
mysql_mutex_lock(&victim_thd->LOCK_thd_data);
|
|
||||||
|
|
||||||
/* Note that when you use RSU node is desynced from cluster, thus WSREP(thd)
|
|
||||||
might not be true.
|
|
||||||
*/
|
|
||||||
if ((WSREP_NNULL(bf_thd) ||
|
|
||||||
((WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) &&
|
|
||||||
wsrep_thd_is_toi(bf_thd))) &&
|
|
||||||
!wsrep_thd_is_aborting(victim_thd))
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu",
|
|
||||||
(long long)bf_thd->real_id, (long long)victim_thd->real_id);
|
|
||||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
|
||||||
ha_abort_transaction(bf_thd, victim_thd, signal);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WSREP_DEBUG("wsrep_abort_thd not effective: bf %llu victim %llu "
|
|
||||||
"wsrep %d wsrep_on %d RSU %d TOI %d aborting %d",
|
|
||||||
(long long)bf_thd->real_id, (long long)victim_thd->real_id,
|
|
||||||
WSREP_NNULL(bf_thd), WSREP_ON,
|
|
||||||
bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU,
|
|
||||||
wsrep_thd_is_toi(bf_thd),
|
|
||||||
wsrep_thd_is_aborting(victim_thd));
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
|
|
||||||
{
|
|
||||||
WSREP_LOG_THD(bf_thd, "BF aborter before");
|
|
||||||
WSREP_LOG_THD(victim_thd, "victim before");
|
|
||||||
|
|
||||||
#ifdef ENABLED_DEBUG_SYNC
|
#ifdef ENABLED_DEBUG_SYNC
|
||||||
DBUG_EXECUTE_IF("sync.wsrep_bf_abort",
|
DBUG_EXECUTE_IF("sync.wsrep_bf_abort",
|
||||||
@@ -362,6 +323,85 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
|
|||||||
};);
|
};);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno());
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Adopt the lock, it is being held by the caller. */
|
||||||
|
Wsrep_mutex wsm{&victim_thd->LOCK_thd_data};
|
||||||
|
wsrep::unique_lock<wsrep::mutex> lock{wsm, std::adopt_lock};
|
||||||
|
|
||||||
|
if (wsrep_thd_is_toi(bf_thd))
|
||||||
|
{
|
||||||
|
ret= victim_thd->wsrep_cs().total_order_bf_abort(lock, bf_seqno);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(WSREP(victim_thd) ? victim_thd->wsrep_trx().active() : 1);
|
||||||
|
ret= victim_thd->wsrep_cs().bf_abort(lock, bf_seqno);
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
/* BF abort should be allowed only once by wsrep-lib.*/
|
||||||
|
DBUG_ASSERT(victim_thd->wsrep_aborter == 0);
|
||||||
|
victim_thd->wsrep_aborter= bf_thd->thread_id;
|
||||||
|
wsrep_bf_aborts_counter++;
|
||||||
|
}
|
||||||
|
lock.release(); /* No unlock at the end of the scope. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check for wsrep-lib calls to return with LOCK_thd_data held. */
|
||||||
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wsrep_abort_thd(THD *bf_thd,
|
||||||
|
THD *victim_thd,
|
||||||
|
my_bool signal)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("wsrep_abort_thd");
|
||||||
|
|
||||||
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
|
||||||
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||||
|
|
||||||
|
/* Note that when you use RSU node is desynced from cluster, thus WSREP(thd)
|
||||||
|
might not be true.
|
||||||
|
*/
|
||||||
|
if ((WSREP(bf_thd)
|
||||||
|
|| ((WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU)
|
||||||
|
&& wsrep_thd_is_toi(bf_thd))
|
||||||
|
|| bf_thd->lex->sql_command == SQLCOM_KILL)
|
||||||
|
&& !wsrep_thd_is_aborting(victim_thd) &&
|
||||||
|
wsrep_bf_abort_low(bf_thd, victim_thd) &&
|
||||||
|
!victim_thd->wsrep_cs().is_rollbacker_active())
|
||||||
|
{
|
||||||
|
WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu",
|
||||||
|
(long long)bf_thd->real_id, (long long)victim_thd->real_id);
|
||||||
|
victim_thd->awake_no_mutex(KILL_QUERY_HARD);
|
||||||
|
ha_abort_transaction(bf_thd, victim_thd, signal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WSREP_DEBUG("wsrep_abort_thd not effective: bf %llu victim %llu "
|
||||||
|
"wsrep %d wsrep_on %d RSU %d TOI %d aborting %d",
|
||||||
|
(long long)bf_thd->real_id, (long long)victim_thd->real_id,
|
||||||
|
WSREP_NNULL(bf_thd), WSREP_ON,
|
||||||
|
bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU,
|
||||||
|
wsrep_thd_is_toi(bf_thd),
|
||||||
|
wsrep_thd_is_aborting(victim_thd));
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
|
||||||
|
{
|
||||||
|
WSREP_LOG_THD(bf_thd, "BF aborter before");
|
||||||
|
WSREP_LOG_THD(victim_thd, "victim before");
|
||||||
|
|
||||||
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||||
|
|
||||||
if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
|
if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("wsrep_bf_abort, BF abort for non active transaction."
|
WSREP_DEBUG("wsrep_bf_abort, BF abort for non active transaction."
|
||||||
@@ -384,30 +424,84 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
|
|||||||
wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
|
wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
|
||||||
{
|
{
|
||||||
WSREP_DEBUG("killing connection for non wsrep session");
|
WSREP_DEBUG("killing connection for non wsrep session");
|
||||||
mysql_mutex_lock(&victim_thd->LOCK_thd_data);
|
|
||||||
victim_thd->awake_no_mutex(KILL_CONNECTION);
|
victim_thd->awake_no_mutex(KILL_CONNECTION);
|
||||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret;
|
return wsrep_bf_abort_low(bf_thd, victim_thd);
|
||||||
wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno());
|
}
|
||||||
|
|
||||||
if (wsrep_thd_is_toi(bf_thd))
|
uint wsrep_kill_thd(THD *thd, THD *victim_thd, killed_state kill_signal)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("wsrep_kill_thd");
|
||||||
|
DBUG_ASSERT(WSREP(victim_thd));
|
||||||
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
|
||||||
|
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||||
|
using trans= wsrep::transaction;
|
||||||
|
auto trx_state= victim_thd->wsrep_trx().state();
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
victim_thd->wsrep_killed_state= trx_state;
|
||||||
|
#endif /* DBUG_OFF */
|
||||||
|
/*
|
||||||
|
Already killed or in commit codepath. Mark the victim as killed,
|
||||||
|
the killed status will be restored in wsrep_after_commit() and
|
||||||
|
will be processed after the commit is over. In case of multiple
|
||||||
|
KILLs happened on commit codepath, the last one will be effective.
|
||||||
|
*/
|
||||||
|
if (victim_thd->wsrep_abort_by_kill ||
|
||||||
|
trx_state == trans::s_preparing ||
|
||||||
|
trx_state == trans::s_committing ||
|
||||||
|
trx_state == trans::s_ordered_commit)
|
||||||
{
|
{
|
||||||
ret= victim_thd->wsrep_cs().total_order_bf_abort(bf_seqno);
|
victim_thd->wsrep_abort_by_kill= kill_signal;
|
||||||
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
else
|
/*
|
||||||
|
Mark killed victim_thd with kill_signal so that awake_no_mutex does
|
||||||
|
not dive into storage engine. We use ha_abort_transaction()
|
||||||
|
to do the storage engine part for wsrep THDs.
|
||||||
|
*/
|
||||||
|
DEBUG_SYNC(thd, "wsrep_kill_before_awake_no_mutex");
|
||||||
|
victim_thd->wsrep_abort_by_kill= kill_signal;
|
||||||
|
victim_thd->awake_no_mutex(kill_signal);
|
||||||
|
/* ha_abort_transaction() releases tmp->LOCK_thd_kill, so tmp
|
||||||
|
is not safe to access anymore. */
|
||||||
|
ha_abort_transaction(thd, victim_thd, 1);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wsrep_backup_kill_for_commit(THD *thd)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(WSREP(thd));
|
||||||
|
mysql_mutex_assert_owner(&thd->LOCK_thd_kill);
|
||||||
|
DBUG_ASSERT(thd->killed != NOT_KILLED);
|
||||||
|
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||||
|
/* If the transaction will roll back, keep the killed state.
|
||||||
|
For must replay, the replay will happen in different THD context
|
||||||
|
which is high priority and cannot be killed. The owning thread will
|
||||||
|
pick the killed state in after statement processing. */
|
||||||
|
if (thd->wsrep_trx().state() != wsrep::transaction::s_cert_failed &&
|
||||||
|
thd->wsrep_trx().state() != wsrep::transaction::s_must_abort &&
|
||||||
|
thd->wsrep_trx().state() != wsrep::transaction::s_aborting &&
|
||||||
|
thd->wsrep_trx().state() != wsrep::transaction::s_must_replay)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(WSREP(victim_thd) ? victim_thd->wsrep_trx().active() : 1);
|
thd->wsrep_abort_by_kill= thd->killed;
|
||||||
ret= victim_thd->wsrep_cs().bf_abort(bf_seqno);
|
thd->wsrep_abort_by_kill_err= thd->killed_err;
|
||||||
|
thd->killed= NOT_KILLED;
|
||||||
|
thd->killed_err= 0;
|
||||||
}
|
}
|
||||||
if (ret)
|
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||||
{
|
}
|
||||||
wsrep_bf_aborts_counter++;
|
|
||||||
}
|
void wsrep_restore_kill_after_commit(THD *thd)
|
||||||
return ret;
|
{
|
||||||
|
DBUG_ASSERT(WSREP(thd));
|
||||||
|
mysql_mutex_assert_owner(&thd->LOCK_thd_kill);
|
||||||
|
thd->killed= thd->wsrep_abort_by_kill;
|
||||||
|
thd->killed_err= thd->wsrep_abort_by_kill_err;
|
||||||
|
thd->wsrep_abort_by_kill= NOT_KILLED;
|
||||||
|
thd->wsrep_abort_by_kill_err= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wsrep_create_threadvars()
|
int wsrep_create_threadvars()
|
||||||
|
|||||||
@@ -88,10 +88,39 @@ bool wsrep_create_appliers(long threads, bool mutex_protected=false);
|
|||||||
void wsrep_create_rollbacker();
|
void wsrep_create_rollbacker();
|
||||||
|
|
||||||
bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd);
|
bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd);
|
||||||
int wsrep_abort_thd(THD *bf_thd,
|
/*
|
||||||
|
Abort transaction for victim_thd. This function is called from
|
||||||
|
MDL BF abort codepath.
|
||||||
|
*/
|
||||||
|
void wsrep_abort_thd(THD *bf_thd,
|
||||||
THD *victim_thd,
|
THD *victim_thd,
|
||||||
my_bool signal) __attribute__((nonnull(1,2)));
|
my_bool signal) __attribute__((nonnull(1,2)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
Kill wsrep connection with kill_signal. Object thd is not
|
||||||
|
guaranteed to exist anymore when this function returns.
|
||||||
|
|
||||||
|
Asserts that the caller holds victim_thd->LOCK_thd_kill,
|
||||||
|
victim_thd->LOCK_thd_data.
|
||||||
|
|
||||||
|
@param thd THD object for connection that executes the KILL.
|
||||||
|
@param victim_thd THD object for connection to be killed.
|
||||||
|
@param kill_signal Kill signal.
|
||||||
|
|
||||||
|
@return Zero if the kill was successful, otherwise non-zero error code.
|
||||||
|
*/
|
||||||
|
uint wsrep_kill_thd(THD *thd, THD *victim_thd, killed_state kill_signal);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Backup kill status for commit.
|
||||||
|
*/
|
||||||
|
void wsrep_backup_kill_for_commit(THD *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Restore KILL status after commit.
|
||||||
|
*/
|
||||||
|
void wsrep_restore_kill_after_commit(THD *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Helper methods to deal with thread local storage.
|
Helper methods to deal with thread local storage.
|
||||||
The purpose of these methods is to hide the details of thread
|
The purpose of these methods is to hide the details of thread
|
||||||
|
|||||||
@@ -256,6 +256,11 @@ static inline int wsrep_before_prepare(THD* thd, bool all)
|
|||||||
thd->wsrep_trx().ws_meta().gtid(),
|
thd->wsrep_trx().ws_meta().gtid(),
|
||||||
wsrep_gtid_server.gtid());
|
wsrep_gtid_server.gtid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mysql_mutex_lock(&thd->LOCK_thd_kill);
|
||||||
|
if (thd->killed) wsrep_backup_kill_for_commit(thd);
|
||||||
|
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,6 +330,11 @@ static inline int wsrep_before_commit(THD* thd, bool all)
|
|||||||
wsrep_gtid_server.gtid());
|
wsrep_gtid_server.gtid());
|
||||||
wsrep_register_for_group_commit(thd);
|
wsrep_register_for_group_commit(thd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mysql_mutex_lock(&thd->LOCK_thd_kill);
|
||||||
|
if (thd->killed) wsrep_backup_kill_for_commit(thd);
|
||||||
|
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +353,8 @@ static inline int wsrep_before_commit(THD* thd, bool all)
|
|||||||
static inline int wsrep_ordered_commit(THD* thd, bool all)
|
static inline int wsrep_ordered_commit(THD* thd, bool all)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("wsrep_ordered_commit");
|
DBUG_ENTER("wsrep_ordered_commit");
|
||||||
WSREP_DEBUG("wsrep_ordered_commit: %d", wsrep_is_real(thd, all));
|
WSREP_DEBUG("wsrep_ordered_commit: %d %lld", wsrep_is_real(thd, all),
|
||||||
|
(long long) wsrep_thd_trx_seqno(thd));
|
||||||
DBUG_ASSERT(wsrep_run_commit_hook(thd, all));
|
DBUG_ASSERT(wsrep_run_commit_hook(thd, all));
|
||||||
DBUG_RETURN(thd->wsrep_cs().ordered_commit());
|
DBUG_RETURN(thd->wsrep_cs().ordered_commit());
|
||||||
}
|
}
|
||||||
@@ -451,10 +462,18 @@ int wsrep_after_statement(THD* thd)
|
|||||||
wsrep::to_c_string(thd->wsrep_cs().state()),
|
wsrep::to_c_string(thd->wsrep_cs().state()),
|
||||||
wsrep::to_c_string(thd->wsrep_cs().mode()),
|
wsrep::to_c_string(thd->wsrep_cs().mode()),
|
||||||
wsrep::to_c_string(thd->wsrep_cs().transaction().state()));
|
wsrep::to_c_string(thd->wsrep_cs().transaction().state()));
|
||||||
DBUG_RETURN((thd->wsrep_cs().state() != wsrep::client_state::s_none &&
|
int ret= ((thd->wsrep_cs().state() != wsrep::client_state::s_none &&
|
||||||
thd->wsrep_cs().mode() == Wsrep_client_state::m_local) &&
|
thd->wsrep_cs().mode() == Wsrep_client_state::m_local) &&
|
||||||
!thd->internal_transaction() ?
|
!thd->internal_transaction() ?
|
||||||
thd->wsrep_cs().after_statement() : 0);
|
thd->wsrep_cs().after_statement() : 0);
|
||||||
|
|
||||||
|
if (wsrep_is_active(thd))
|
||||||
|
{
|
||||||
|
mysql_mutex_lock(&thd->LOCK_thd_kill);
|
||||||
|
wsrep_restore_kill_after_commit(thd);
|
||||||
|
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wsrep_after_apply(THD* thd)
|
static inline void wsrep_after_apply(THD* thd)
|
||||||
|
|||||||
@@ -2140,6 +2140,8 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
block->page.lock.x_lock();
|
block->page.lock.x_lock();
|
||||||
|
if (block->page.is_ibuf_exist())
|
||||||
|
ibuf_merge_or_delete_for_page(nullptr, page_id, block->page.zip_size());
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
if (block->index)
|
if (block->index)
|
||||||
btr_search_drop_page_hash_index(block, false);
|
btr_search_drop_page_hash_index(block, false);
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ void buf_dblwr_t::recover()
|
|||||||
const uint32_t space_id= page_get_space_id(page);
|
const uint32_t space_id= page_get_space_id(page);
|
||||||
const page_id_t page_id(space_id, page_no);
|
const page_id_t page_id(space_id, page_no);
|
||||||
|
|
||||||
if (recv_sys.lsn < lsn)
|
if (recv_sys.scanned_lsn < lsn)
|
||||||
{
|
{
|
||||||
ib::info() << "Ignoring a doublewrite copy of page " << page_id
|
ib::info() << "Ignoring a doublewrite copy of page " << page_id
|
||||||
<< " with future log sequence number " << lsn;
|
<< " with future log sequence number " << lsn;
|
||||||
|
|||||||
@@ -966,11 +966,19 @@ uint32_t fil_space_t::flush_freed(bool writable)
|
|||||||
mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
|
mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
|
||||||
mysql_mutex_assert_not_owner(&buf_pool.mutex);
|
mysql_mutex_assert_not_owner(&buf_pool.mutex);
|
||||||
|
|
||||||
freed_range_mutex.lock();
|
for (;;)
|
||||||
if (freed_ranges.empty() || log_sys.get_flushed_lsn() < get_last_freed_lsn())
|
|
||||||
{
|
{
|
||||||
|
freed_range_mutex.lock();
|
||||||
|
if (freed_ranges.empty())
|
||||||
|
{
|
||||||
|
freed_range_mutex.unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const lsn_t flush_lsn= last_freed_lsn;
|
||||||
|
if (log_sys.get_flushed_lsn() >= flush_lsn)
|
||||||
|
break;
|
||||||
freed_range_mutex.unlock();
|
freed_range_mutex.unlock();
|
||||||
return 0;
|
log_write_up_to(flush_lsn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned physical{physical_size()};
|
const unsigned physical{physical_size()};
|
||||||
@@ -2430,6 +2438,7 @@ static void buf_flush_page_cleaner()
|
|||||||
else if (buf_pool.ran_out())
|
else if (buf_pool.ran_out())
|
||||||
{
|
{
|
||||||
buf_pool.page_cleaner_set_idle(false);
|
buf_pool.page_cleaner_set_idle(false);
|
||||||
|
buf_pool.get_oldest_modification(0);
|
||||||
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
|
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
|
||||||
n= srv_max_io_capacity;
|
n= srv_max_io_capacity;
|
||||||
mysql_mutex_lock(&buf_pool.mutex);
|
mysql_mutex_lock(&buf_pool.mutex);
|
||||||
@@ -2583,6 +2592,7 @@ ATTRIBUTE_COLD void buf_flush_page_cleaner_init()
|
|||||||
/** Flush the buffer pool on shutdown. */
|
/** Flush the buffer pool on shutdown. */
|
||||||
ATTRIBUTE_COLD void buf_flush_buffer_pool()
|
ATTRIBUTE_COLD void buf_flush_buffer_pool()
|
||||||
{
|
{
|
||||||
|
ut_ad(!os_aio_pending_reads());
|
||||||
ut_ad(!buf_page_cleaner_is_active);
|
ut_ad(!buf_page_cleaner_is_active);
|
||||||
ut_ad(!buf_flush_sync_lsn);
|
ut_ad(!buf_flush_sync_lsn);
|
||||||
|
|
||||||
|
|||||||
@@ -1086,7 +1086,11 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
|
|||||||
|
|
||||||
ut_a(!zip || !bpage->oldest_modification());
|
ut_a(!zip || !bpage->oldest_modification());
|
||||||
ut_ad(bpage->zip_size());
|
ut_ad(bpage->zip_size());
|
||||||
|
/* Skip consistency checks if the page was freed.
|
||||||
|
In recovery, we could get a sole FREE_PAGE record
|
||||||
|
and nothing else, for a ROW_FORMAT=COMPRESSED page.
|
||||||
|
Its contents would be garbage. */
|
||||||
|
if (!bpage->is_freed())
|
||||||
switch (fil_page_get_type(page)) {
|
switch (fil_page_get_type(page)) {
|
||||||
case FIL_PAGE_TYPE_ALLOCATED:
|
case FIL_PAGE_TYPE_ALLOCATED:
|
||||||
case FIL_PAGE_INODE:
|
case FIL_PAGE_INODE:
|
||||||
@@ -1217,6 +1221,7 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage, uint32_t state)
|
|||||||
buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold());
|
buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold());
|
||||||
page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
|
page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
|
||||||
|
|
||||||
|
recv_sys.free_corrupted_page(id);
|
||||||
mysql_mutex_lock(&mutex);
|
mysql_mutex_lock(&mutex);
|
||||||
hash_lock.lock();
|
hash_lock.lock();
|
||||||
|
|
||||||
@@ -1241,8 +1246,6 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage, uint32_t state)
|
|||||||
buf_LRU_block_free_hashed_page(reinterpret_cast<buf_block_t*>(bpage));
|
buf_LRU_block_free_hashed_page(reinterpret_cast<buf_block_t*>(bpage));
|
||||||
|
|
||||||
mysql_mutex_unlock(&mutex);
|
mysql_mutex_unlock(&mutex);
|
||||||
|
|
||||||
recv_sys.free_corrupted_page(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update buf_pool.LRU_old_ratio.
|
/** Update buf_pool.LRU_old_ratio.
|
||||||
|
|||||||
@@ -265,9 +265,6 @@ buf_read_page_low(
|
|||||||
buf_page_t* bpage;
|
buf_page_t* bpage;
|
||||||
|
|
||||||
if (buf_dblwr.is_inside(page_id)) {
|
if (buf_dblwr.is_inside(page_id)) {
|
||||||
ib::error() << "Trying to read doublewrite buffer page "
|
|
||||||
<< page_id;
|
|
||||||
ut_ad(0);
|
|
||||||
space->release();
|
space->release();
|
||||||
return DB_PAGE_CORRUPTED;
|
return DB_PAGE_CORRUPTED;
|
||||||
}
|
}
|
||||||
@@ -525,7 +522,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
|
|||||||
|
|
||||||
/* We will check that almost all pages in the area have been accessed
|
/* We will check that almost all pages in the area have been accessed
|
||||||
in the desired order. */
|
in the desired order. */
|
||||||
const bool descending= page_id == low;
|
const bool descending= page_id != low;
|
||||||
|
|
||||||
if (!descending && page_id != high_1)
|
if (!descending && page_id != high_1)
|
||||||
/* This is not a border page of the area */
|
/* This is not a border page of the area */
|
||||||
@@ -555,7 +552,7 @@ fail:
|
|||||||
uint32_t{buf_pool.read_ahead_area});
|
uint32_t{buf_pool.read_ahead_area});
|
||||||
page_id_t new_low= low, new_high_1= high_1;
|
page_id_t new_low= low, new_high_1= high_1;
|
||||||
unsigned prev_accessed= 0;
|
unsigned prev_accessed= 0;
|
||||||
for (page_id_t i= low; i != high_1; ++i)
|
for (page_id_t i= low; i <= high_1; ++i)
|
||||||
{
|
{
|
||||||
buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(i.fold());
|
buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(i.fold());
|
||||||
transactional_shared_lock_guard<page_hash_latch> g
|
transactional_shared_lock_guard<page_hash_latch> g
|
||||||
@@ -583,12 +580,21 @@ failed:
|
|||||||
if (prev == FIL_NULL || next == FIL_NULL)
|
if (prev == FIL_NULL || next == FIL_NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
page_id_t id= page_id;
|
page_id_t id= page_id;
|
||||||
if (descending && next - 1 == page_id.page_no())
|
if (descending)
|
||||||
id.set_page_no(prev);
|
{
|
||||||
else if (!descending && prev + 1 == page_id.page_no())
|
if (id == high_1)
|
||||||
id.set_page_no(next);
|
++id;
|
||||||
|
else if (next - 1 != page_id.page_no())
|
||||||
|
goto fail;
|
||||||
|
else
|
||||||
|
id.set_page_no(prev);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
goto fail; /* Successor or predecessor not in the right order */
|
{
|
||||||
|
if (prev + 1 != page_id.page_no())
|
||||||
|
goto fail;
|
||||||
|
id.set_page_no(next);
|
||||||
|
}
|
||||||
|
|
||||||
new_low= id - (id.page_no() % buf_read_ahead_area);
|
new_low= id - (id.page_no() % buf_read_ahead_area);
|
||||||
new_high_1= new_low + (buf_read_ahead_area - 1);
|
new_high_1= new_low + (buf_read_ahead_area - 1);
|
||||||
@@ -620,7 +626,7 @@ failed:
|
|||||||
/* If we got this far, read-ahead can be sensible: do it */
|
/* If we got this far, read-ahead can be sensible: do it */
|
||||||
count= 0;
|
count= 0;
|
||||||
for (ulint ibuf_mode= ibuf ? BUF_READ_IBUF_PAGES_ONLY : BUF_READ_ANY_PAGE;
|
for (ulint ibuf_mode= ibuf ? BUF_READ_IBUF_PAGES_ONLY : BUF_READ_ANY_PAGE;
|
||||||
new_low != new_high_1; ++new_low)
|
new_low <= new_high_1; ++new_low)
|
||||||
{
|
{
|
||||||
if (ibuf_bitmap_page(new_low, zip_size))
|
if (ibuf_bitmap_page(new_low, zip_size))
|
||||||
continue;
|
continue;
|
||||||
@@ -649,60 +655,35 @@ failed:
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return whether a page has been freed */
|
/** Schedule a page for recovery.
|
||||||
inline bool fil_space_t::is_freed(uint32_t page)
|
@param space tablespace
|
||||||
|
@param page_id page identifier
|
||||||
|
@param recs log records
|
||||||
|
@param init page initialization, or nullptr if the page needs to be read */
|
||||||
|
void buf_read_recover(fil_space_t *space, const page_id_t page_id,
|
||||||
|
page_recv_t &recs, recv_init *init)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
|
ut_ad(space->id == page_id.space());
|
||||||
return freed_ranges.contains(page);
|
space->reacquire();
|
||||||
}
|
const ulint zip_size= space->zip_size();
|
||||||
|
|
||||||
/** Issues read requests for pages which recovery wants to read in.
|
if (init)
|
||||||
@param space_id tablespace identifier
|
{
|
||||||
@param page_nos page numbers to read, in ascending order */
|
if (buf_page_t *bpage= buf_page_init_for_read(BUF_READ_ANY_PAGE, page_id,
|
||||||
void buf_read_recv_pages(uint32_t space_id, st_::span<uint32_t> page_nos)
|
zip_size, true))
|
||||||
{
|
{
|
||||||
fil_space_t* space = fil_space_t::get(space_id);
|
ut_ad(bpage->in_file());
|
||||||
|
os_fake_read(IORequest{bpage, (buf_tmp_buffer_t*) &recs,
|
||||||
if (!space) {
|
UT_LIST_GET_FIRST(space->chain),
|
||||||
/* The tablespace is missing or unreadable: do nothing */
|
IORequest::READ_ASYNC}, ptrdiff_t(init));
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
else if (dberr_t err= buf_read_page_low(space, false, BUF_READ_ANY_PAGE,
|
||||||
const ulint zip_size = space->zip_size();
|
page_id, zip_size, true))
|
||||||
|
{
|
||||||
for (ulint i = 0; i < page_nos.size(); i++) {
|
if (err != DB_SUCCESS_LOCKED_REC)
|
||||||
|
sql_print_error("InnoDB: Recovery failed to read page "
|
||||||
/* Ignore if the page already present in freed ranges. */
|
UINT32PF " from %s",
|
||||||
if (space->is_freed(page_nos[i])) {
|
page_id.page_no(), space->chain.start->name);
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const page_id_t cur_page_id(space_id, page_nos[i]);
|
|
||||||
|
|
||||||
ulint limit = 0;
|
|
||||||
for (ulint j = 0; j < buf_pool.n_chunks; j++) {
|
|
||||||
limit += buf_pool.chunks[j].size / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os_aio_pending_reads() >= limit) {
|
|
||||||
os_aio_wait_until_no_pending_reads(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
space->reacquire();
|
|
||||||
switch (buf_read_page_low(space, false, BUF_READ_ANY_PAGE,
|
|
||||||
cur_page_id, zip_size, true)) {
|
|
||||||
case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sql_print_error("InnoDB: Recovery failed to read page "
|
|
||||||
UINT32PF " from %s",
|
|
||||||
cur_page_id.page_no(),
|
|
||||||
space->chain.start->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DBUG_PRINT("ib_buf", ("recovery read (%zu pages) for %s",
|
|
||||||
page_nos.size(), space->chain.start->name));
|
|
||||||
space->release();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,17 @@ static const dict_table_schema_t table_stats_schema =
|
|||||||
{
|
{
|
||||||
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
||||||
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
|
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
|
||||||
{"last_update", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 4},
|
/*
|
||||||
|
Don't check the DATA_UNSIGNED flag in last_update.
|
||||||
|
It presents if the server is running in a pure MariaDB installation,
|
||||||
|
because MariaDB's Field_timestampf::flags has UNSIGNED_FLAG.
|
||||||
|
But DATA_UNSIGNED misses when the server starts on a MySQL-5.7 directory
|
||||||
|
(during a migration), because MySQL's Field_timestampf::flags does not
|
||||||
|
have UNSIGNED_FLAG.
|
||||||
|
This is fine not to check DATA_UNSIGNED, because Field_timestampf
|
||||||
|
in both MariaDB and MySQL support only non-negative time_t values.
|
||||||
|
*/
|
||||||
|
{"last_update", DATA_INT, DATA_NOT_NULL, 4},
|
||||||
{"n_rows", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
{"n_rows", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
||||||
{"clustered_index_size", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
{"clustered_index_size", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
||||||
{"sum_of_other_index_sizes", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
{"sum_of_other_index_sizes", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
||||||
@@ -218,7 +228,11 @@ static const dict_table_schema_t index_stats_schema =
|
|||||||
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
||||||
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
|
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
|
||||||
{"index_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
{"index_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
||||||
{"last_update", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 4},
|
/*
|
||||||
|
Don't check the DATA_UNSIGNED flag in last_update.
|
||||||
|
See comments about last_update in table_stats_schema above.
|
||||||
|
*/
|
||||||
|
{"last_update", DATA_INT, DATA_NOT_NULL, 4},
|
||||||
{"stat_name", DATA_VARMYSQL, DATA_NOT_NULL, 64*3},
|
{"stat_name", DATA_VARMYSQL, DATA_NOT_NULL, 64*3},
|
||||||
{"stat_value", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
{"stat_value", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
|
||||||
{"sample_size", DATA_INT, DATA_UNSIGNED, 8},
|
{"sample_size", DATA_INT, DATA_UNSIGNED, 8},
|
||||||
|
|||||||
@@ -447,7 +447,9 @@ static bool fil_node_open_file(fil_node_t *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fil_node_open_file_low(node);
|
/* The node can be opened beween releasing and acquiring fil_system.mutex
|
||||||
|
in the above code */
|
||||||
|
return node->is_open() || fil_node_open_file_low(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Close the file handle. */
|
/** Close the file handle. */
|
||||||
@@ -1953,8 +1955,8 @@ err_exit:
|
|||||||
FIL_TYPE_TABLESPACE,
|
FIL_TYPE_TABLESPACE,
|
||||||
crypt_data, mode, true)) {
|
crypt_data, mode, true)) {
|
||||||
fil_node_t* node = space->add(path, file, size, false, true);
|
fil_node_t* node = space->add(path, file, size, false, true);
|
||||||
mysql_mutex_unlock(&fil_system.mutex);
|
|
||||||
IF_WIN(node->find_metadata(), node->find_metadata(file, true));
|
IF_WIN(node->find_metadata(), node->find_metadata(file, true));
|
||||||
|
mysql_mutex_unlock(&fil_system.mutex);
|
||||||
mtr.start();
|
mtr.start();
|
||||||
mtr.set_named_space(space);
|
mtr.set_named_space(space);
|
||||||
ut_a(fsp_header_init(space, size, &mtr) == DB_SUCCESS);
|
ut_a(fsp_header_init(space, size, &mtr) == DB_SUCCESS);
|
||||||
@@ -2775,53 +2777,55 @@ func_exit:
|
|||||||
|
|
||||||
#include <tpool.h>
|
#include <tpool.h>
|
||||||
|
|
||||||
/** Callback for AIO completion */
|
void IORequest::write_complete() const
|
||||||
void fil_aio_callback(const IORequest &request)
|
|
||||||
{
|
{
|
||||||
ut_ad(fil_validate_skip());
|
ut_ad(fil_validate_skip());
|
||||||
ut_ad(request.node);
|
ut_ad(node);
|
||||||
|
ut_ad(is_write());
|
||||||
|
|
||||||
if (!request.bpage)
|
if (!bpage)
|
||||||
{
|
{
|
||||||
ut_ad(!srv_read_only_mode);
|
ut_ad(!srv_read_only_mode);
|
||||||
if (request.type == IORequest::DBLWR_BATCH)
|
if (type == IORequest::DBLWR_BATCH)
|
||||||
buf_dblwr.flush_buffered_writes_completed(request);
|
buf_dblwr.flush_buffered_writes_completed(*this);
|
||||||
else
|
else
|
||||||
ut_ad(request.type == IORequest::WRITE_ASYNC);
|
ut_ad(type == IORequest::WRITE_ASYNC);
|
||||||
write_completed:
|
|
||||||
request.node->complete_write();
|
|
||||||
}
|
|
||||||
else if (request.is_write())
|
|
||||||
{
|
|
||||||
buf_page_write_complete(request);
|
|
||||||
goto write_completed;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
buf_page_write_complete(*this);
|
||||||
|
|
||||||
|
node->complete_write();
|
||||||
|
node->space->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IORequest::read_complete() const
|
||||||
|
{
|
||||||
|
ut_ad(fil_validate_skip());
|
||||||
|
ut_ad(node);
|
||||||
|
ut_ad(is_read());
|
||||||
|
ut_ad(bpage);
|
||||||
|
|
||||||
|
/* IMPORTANT: since i/o handling for reads will read also the insert
|
||||||
|
buffer in fil_system.sys_space, we have to be very careful not to
|
||||||
|
introduce deadlocks. We never close fil_system.sys_space data files
|
||||||
|
and never issue asynchronous reads of change buffer pages. */
|
||||||
|
const page_id_t id(bpage->id());
|
||||||
|
|
||||||
|
if (dberr_t err= bpage->read_complete(*node))
|
||||||
{
|
{
|
||||||
ut_ad(request.is_read());
|
if (recv_recovery_is_on() && !srv_force_recovery)
|
||||||
|
|
||||||
/* IMPORTANT: since i/o handling for reads will read also the insert
|
|
||||||
buffer in fil_system.sys_space, we have to be very careful not to
|
|
||||||
introduce deadlocks. We never close fil_system.sys_space data
|
|
||||||
files and never issue asynchronous reads of change buffer pages. */
|
|
||||||
const page_id_t id(request.bpage->id());
|
|
||||||
|
|
||||||
if (dberr_t err= request.bpage->read_complete(*request.node))
|
|
||||||
{
|
{
|
||||||
if (recv_recovery_is_on() && !srv_force_recovery)
|
mysql_mutex_lock(&recv_sys.mutex);
|
||||||
{
|
recv_sys.set_corrupt_fs();
|
||||||
mysql_mutex_lock(&recv_sys.mutex);
|
mysql_mutex_unlock(&recv_sys.mutex);
|
||||||
recv_sys.set_corrupt_fs();
|
|
||||||
mysql_mutex_unlock(&recv_sys.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != DB_FAIL)
|
|
||||||
ib::error() << "Failed to read page " << id.page_no()
|
|
||||||
<< " from file '" << request.node->name << "': " << err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (err != DB_FAIL)
|
||||||
|
ib::error() << "Failed to read page " << id.page_no()
|
||||||
|
<< " from file '" << node->name << "': " << err;
|
||||||
}
|
}
|
||||||
|
|
||||||
request.node->space->release();
|
node->space->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Flush to disk the writes in file spaces of the given type
|
/** Flush to disk the writes in file spaces of the given type
|
||||||
|
|||||||
@@ -1284,23 +1284,20 @@ static dberr_t fsp_free_page(fil_space_t *space, page_no_t offset, mtr_t *mtr)
|
|||||||
+ header->page.frame, frag_n_used - 1);
|
+ header->page.frame, frag_n_used - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtr->free(*space, static_cast<uint32_t>(offset));
|
||||||
|
xdes_set_free<true>(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
|
||||||
|
ut_ad(err == DB_SUCCESS);
|
||||||
|
|
||||||
if (!xdes_get_n_used(descr)) {
|
if (!xdes_get_n_used(descr)) {
|
||||||
/* The extent has become free: move it to another list */
|
/* The extent has become free: move it to another list */
|
||||||
err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG,
|
err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG,
|
||||||
xdes, xoffset, mtr);
|
xdes, xoffset, mtr);
|
||||||
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
|
if (err == DB_SUCCESS) {
|
||||||
return err;
|
err = fsp_free_extent(space, offset, mtr);
|
||||||
}
|
|
||||||
err = fsp_free_extent(space, offset, mtr);
|
|
||||||
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mtr->free(*space, static_cast<uint32_t>(offset));
|
return err;
|
||||||
xdes_set_free<true>(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
|
|
||||||
|
|
||||||
return DB_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Number of segment inodes which fit on a single page */
|
/** @return Number of segment inodes which fit on a single page */
|
||||||
|
|||||||
@@ -945,7 +945,8 @@ static SHOW_VAR innodb_status_variables[]= {
|
|||||||
{"buffer_pool_read_ahead", &buf_pool.stat.n_ra_pages_read, SHOW_SIZE_T},
|
{"buffer_pool_read_ahead", &buf_pool.stat.n_ra_pages_read, SHOW_SIZE_T},
|
||||||
{"buffer_pool_read_ahead_evicted",
|
{"buffer_pool_read_ahead_evicted",
|
||||||
&buf_pool.stat.n_ra_pages_evicted, SHOW_SIZE_T},
|
&buf_pool.stat.n_ra_pages_evicted, SHOW_SIZE_T},
|
||||||
{"buffer_pool_read_requests", &buf_pool.stat.n_page_gets, SHOW_SIZE_T},
|
{"buffer_pool_read_requests",
|
||||||
|
&export_vars.innodb_buffer_pool_read_requests, SHOW_SIZE_T},
|
||||||
{"buffer_pool_reads", &buf_pool.stat.n_pages_read, SHOW_SIZE_T},
|
{"buffer_pool_reads", &buf_pool.stat.n_pages_read, SHOW_SIZE_T},
|
||||||
{"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T},
|
{"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T},
|
||||||
{"buffer_pool_write_requests", &buf_pool.flush_list_requests, SHOW_SIZE_T},
|
{"buffer_pool_write_requests", &buf_pool.flush_list_requests, SHOW_SIZE_T},
|
||||||
@@ -1917,8 +1918,9 @@ static void innodb_disable_internal_writes(bool disable)
|
|||||||
sst_enable_innodb_writes();
|
sst_enable_innodb_writes();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wsrep_abort_transaction(handlerton*, THD *, THD *, my_bool);
|
static void wsrep_abort_transaction(handlerton *, THD *, THD *, my_bool)
|
||||||
static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
|
__attribute__((nonnull));
|
||||||
|
static int innobase_wsrep_set_checkpoint(handlerton *hton, const XID *xid);
|
||||||
static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
|
static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
@@ -18622,36 +18624,45 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id)
|
|||||||
wsrep_thd_client_mode_str(vthd),
|
wsrep_thd_client_mode_str(vthd),
|
||||||
wsrep_thd_transaction_state_str(vthd),
|
wsrep_thd_transaction_state_str(vthd),
|
||||||
wsrep_thd_query(vthd));
|
wsrep_thd_query(vthd));
|
||||||
/* Mark transaction as a victim for Galera abort */
|
aborting= true;
|
||||||
vtrx->lock.set_wsrep_victim();
|
|
||||||
if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd))
|
|
||||||
aborting= true;
|
|
||||||
else
|
|
||||||
WSREP_DEBUG("kill transaction skipped due to wsrep_aborter set");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||||
vtrx->mutex_unlock();
|
vtrx->mutex_unlock();
|
||||||
}
|
}
|
||||||
wsrep_thd_UNLOCK(vthd);
|
|
||||||
if (aborting)
|
DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
|
||||||
|
if (aborting && wsrep_thd_bf_abort(bf_thd, vthd, true))
|
||||||
{
|
{
|
||||||
|
/* Need to grab mutexes again to ensure that the trx is still in
|
||||||
|
right state. */
|
||||||
|
lock_sys.wr_lock(SRW_LOCK_CALL);
|
||||||
|
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||||
|
vtrx->mutex_lock();
|
||||||
|
|
||||||
/* if victim is waiting for some other lock, we have to cancel
|
/* if victim is waiting for some other lock, we have to cancel
|
||||||
that waiting
|
that waiting
|
||||||
*/
|
*/
|
||||||
lock_sys.cancel_lock_wait_for_trx(vtrx);
|
if (vtrx->id == trx_id)
|
||||||
|
|
||||||
DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
|
|
||||||
if (!wsrep_thd_bf_abort(bf_thd, vthd, true))
|
|
||||||
{
|
{
|
||||||
wsrep_thd_LOCK(vthd);
|
switch (vtrx->state) {
|
||||||
wsrep_thd_set_wsrep_aborter(NULL, vthd);
|
default:
|
||||||
wsrep_thd_UNLOCK(vthd);
|
break;
|
||||||
|
case TRX_STATE_ACTIVE:
|
||||||
WSREP_DEBUG("wsrep_thd_bf_abort has failed, victim %lu will survive",
|
case TRX_STATE_PREPARED:
|
||||||
thd_get_thread_id(vthd));
|
lock_sys.cancel_lock_wait_for_wsrep_bf_abort(vtrx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
lock_sys.wr_unlock();
|
||||||
|
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||||
|
vtrx->mutex_unlock();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WSREP_DEBUG("wsrep_thd_bf_abort has failed, victim %lu will survive",
|
||||||
|
thd_get_thread_id(vthd));
|
||||||
|
}
|
||||||
|
wsrep_thd_UNLOCK(vthd);
|
||||||
wsrep_thd_kill_UNLOCK(vthd);
|
wsrep_thd_kill_UNLOCK(vthd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18659,68 +18670,50 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id)
|
|||||||
/** This function forces the victim transaction to abort. Aborting the
|
/** This function forces the victim transaction to abort. Aborting the
|
||||||
transaction does NOT end it, it still has to be rolled back.
|
transaction does NOT end it, it still has to be rolled back.
|
||||||
|
|
||||||
|
The caller must lock LOCK_thd_kill and LOCK_thd_data.
|
||||||
|
|
||||||
@param bf_thd brute force THD asking for the abort
|
@param bf_thd brute force THD asking for the abort
|
||||||
@param victim_thd victim THD to be aborted
|
@param victim_thd victim THD to be aborted
|
||||||
|
|
||||||
@return 0 victim was aborted
|
|
||||||
@return -1 victim thread was aborted (no transaction)
|
|
||||||
*/
|
*/
|
||||||
static
|
static void wsrep_abort_transaction(handlerton *, THD *bf_thd, THD *victim_thd,
|
||||||
void
|
my_bool signal)
|
||||||
wsrep_abort_transaction(
|
|
||||||
handlerton*,
|
|
||||||
THD *bf_thd,
|
|
||||||
THD *victim_thd,
|
|
||||||
my_bool signal)
|
|
||||||
{
|
{
|
||||||
DBUG_ENTER("wsrep_abort_transaction");
|
DBUG_ENTER("wsrep_abort_transaction");
|
||||||
ut_ad(bf_thd);
|
ut_ad(bf_thd);
|
||||||
ut_ad(victim_thd);
|
ut_ad(victim_thd);
|
||||||
|
|
||||||
wsrep_thd_kill_LOCK(victim_thd);
|
trx_t *victim_trx= thd_to_trx(victim_thd);
|
||||||
wsrep_thd_LOCK(victim_thd);
|
|
||||||
trx_t* victim_trx= thd_to_trx(victim_thd);
|
|
||||||
wsrep_thd_UNLOCK(victim_thd);
|
|
||||||
|
|
||||||
WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
|
WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
|
||||||
wsrep_thd_query(bf_thd),
|
wsrep_thd_query(bf_thd), wsrep_thd_query(victim_thd),
|
||||||
wsrep_thd_query(victim_thd),
|
wsrep_thd_transaction_state_str(victim_thd));
|
||||||
wsrep_thd_transaction_state_str(victim_thd));
|
|
||||||
|
|
||||||
if (victim_trx) {
|
if (!victim_trx)
|
||||||
victim_trx->lock.set_wsrep_victim();
|
{
|
||||||
|
WSREP_DEBUG("abort transaction: victim did not exist");
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
wsrep_thd_LOCK(victim_thd);
|
lock_sys.wr_lock(SRW_LOCK_CALL);
|
||||||
bool aborting= !wsrep_thd_set_wsrep_aborter(bf_thd, victim_thd);
|
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||||
wsrep_thd_UNLOCK(victim_thd);
|
victim_trx->mutex_lock();
|
||||||
if (aborting) {
|
|
||||||
DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
|
|
||||||
DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort",
|
|
||||||
{
|
|
||||||
const char act[]=
|
|
||||||
"now "
|
|
||||||
"SIGNAL sync.before_wsrep_thd_abort_reached "
|
|
||||||
"WAIT_FOR signal.before_wsrep_thd_abort";
|
|
||||||
DBUG_ASSERT(!debug_sync_set_action(bf_thd,
|
|
||||||
STRING_WITH_LEN(act)));
|
|
||||||
};);
|
|
||||||
wsrep_thd_bf_abort(bf_thd, victim_thd, signal);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort",
|
|
||||||
{
|
|
||||||
const char act[]=
|
|
||||||
"now "
|
|
||||||
"SIGNAL sync.before_wsrep_thd_abort_reached "
|
|
||||||
"WAIT_FOR signal.before_wsrep_thd_abort";
|
|
||||||
DBUG_ASSERT(!debug_sync_set_action(bf_thd,
|
|
||||||
STRING_WITH_LEN(act)));
|
|
||||||
};);
|
|
||||||
wsrep_thd_bf_abort(bf_thd, victim_thd, signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
wsrep_thd_kill_UNLOCK(victim_thd);
|
switch (victim_trx->state) {
|
||||||
DBUG_VOID_RETURN;
|
default:
|
||||||
|
break;
|
||||||
|
case TRX_STATE_ACTIVE:
|
||||||
|
case TRX_STATE_PREPARED:
|
||||||
|
/* Cancel lock wait if the victim is waiting for a lock in InnoDB.
|
||||||
|
The transaction which is blocked somewhere else (e.g. waiting
|
||||||
|
for next command or MDL) has been interrupted by THD::awake_no_mutex()
|
||||||
|
on server level before calling this function. */
|
||||||
|
lock_sys.cancel_lock_wait_for_wsrep_bf_abort(victim_trx);
|
||||||
|
}
|
||||||
|
lock_sys.wr_unlock();
|
||||||
|
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||||
|
victim_trx->mutex_unlock();
|
||||||
|
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -2365,6 +2365,7 @@ tablespace_deleted:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ulint zip_size = s->zip_size(), size = s->size;
|
const ulint zip_size = s->zip_size(), size = s->size;
|
||||||
|
s->x_lock();
|
||||||
s->release();
|
s->release();
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
@@ -2382,13 +2383,17 @@ tablespace_deleted:
|
|||||||
|| !page_is_leaf(block->page.frame);
|
|| !page_is_leaf(block->page.frame);
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
if (err == DB_TABLESPACE_DELETED) {
|
if (err == DB_TABLESPACE_DELETED) {
|
||||||
|
s->x_unlock();
|
||||||
goto tablespace_deleted;
|
goto tablespace_deleted;
|
||||||
}
|
}
|
||||||
if (!remove) {
|
if (!remove) {
|
||||||
|
s->x_unlock();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->x_unlock();
|
||||||
|
|
||||||
if (srv_shutdown_state == SRV_SHUTDOWN_NONE
|
if (srv_shutdown_state == SRV_SHUTDOWN_NONE
|
||||||
|| srv_fast_shutdown) {
|
|| srv_fast_shutdown) {
|
||||||
continue;
|
continue;
|
||||||
@@ -2417,7 +2422,7 @@ tablespace_deleted:
|
|||||||
/* Prevent an infinite loop, by removing entries from
|
/* Prevent an infinite loop, by removing entries from
|
||||||
the change buffer in the case the bitmap bits were
|
the change buffer in the case the bitmap bits were
|
||||||
wrongly clear even though buffered changes exist. */
|
wrongly clear even though buffered changes exist. */
|
||||||
ibuf_delete_recs(page_id_t(space_ids[i], page_nos[i]));
|
ibuf_delete_recs(page_id_t(space_id, page_nos[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4195,25 +4200,26 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block,
|
|||||||
|
|
||||||
ibuf_mtr_commit(&mtr);
|
ibuf_mtr_commit(&mtr);
|
||||||
|
|
||||||
if (bitmap_bits
|
if (!bitmap_bits) {
|
||||||
&& DB_SUCCESS
|
done:
|
||||||
|
/* No changes are buffered for this page. */
|
||||||
|
space->release();
|
||||||
|
return DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!block
|
||||||
|
|| DB_SUCCESS
|
||||||
== fseg_page_is_allocated(space, page_id.page_no())) {
|
== fseg_page_is_allocated(space, page_id.page_no())) {
|
||||||
ibuf_mtr_start(&mtr);
|
ibuf_mtr_start(&mtr);
|
||||||
mtr.set_named_space(space);
|
mtr.set_named_space(space);
|
||||||
ibuf_reset_bitmap(block, page_id, zip_size, &mtr);
|
ibuf_reset_bitmap(block, page_id, zip_size, &mtr);
|
||||||
ibuf_mtr_commit(&mtr);
|
ibuf_mtr_commit(&mtr);
|
||||||
bitmap_bits = 0;
|
|
||||||
if (!block
|
if (!block
|
||||||
|| btr_page_get_index_id(block->page.frame)
|
|| btr_page_get_index_id(block->page.frame)
|
||||||
!= DICT_IBUF_ID_MIN + IBUF_SPACE_ID) {
|
!= DICT_IBUF_ID_MIN + IBUF_SPACE_ID) {
|
||||||
ibuf_delete_recs(page_id);
|
ibuf_delete_recs(page_id);
|
||||||
}
|
}
|
||||||
}
|
goto done;
|
||||||
|
|
||||||
if (!bitmap_bits) {
|
|
||||||
/* No changes are buffered for this page. */
|
|
||||||
space->release();
|
|
||||||
return DB_SUCCESS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,7 @@ struct buf_pool_info_t
|
|||||||
ulint flush_list_len; /*!< Length of buf_pool.flush_list */
|
ulint flush_list_len; /*!< Length of buf_pool.flush_list */
|
||||||
ulint n_pend_unzip; /*!< buf_pool.n_pend_unzip, pages
|
ulint n_pend_unzip; /*!< buf_pool.n_pend_unzip, pages
|
||||||
pending decompress */
|
pending decompress */
|
||||||
ulint n_pend_reads; /*!< buf_pool.n_pend_reads, pages
|
ulint n_pend_reads; /*!< os_aio_pending_reads() */
|
||||||
pending read */
|
|
||||||
ulint n_pending_flush_lru; /*!< Pages pending flush in LRU */
|
ulint n_pending_flush_lru; /*!< Pages pending flush in LRU */
|
||||||
ulint n_pending_flush_list; /*!< Pages pending flush in FLUSH
|
ulint n_pending_flush_list; /*!< Pages pending flush in FLUSH
|
||||||
LIST */
|
LIST */
|
||||||
|
|||||||
@@ -102,10 +102,13 @@ which could result in a deadlock if the OS does not support asynchronous io.
|
|||||||
ulint
|
ulint
|
||||||
buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf);
|
buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf);
|
||||||
|
|
||||||
/** Issue read requests for pages that need to be recovered.
|
/** Schedule a page for recovery.
|
||||||
@param space_id tablespace identifier
|
@param space tablespace
|
||||||
@param page_nos page numbers to read, in ascending order */
|
@param page_id page identifier
|
||||||
void buf_read_recv_pages(uint32_t space_id, st_::span<uint32_t> page_nos);
|
@param recs log records
|
||||||
|
@param init page initialization, or nullptr if the page needs to be read */
|
||||||
|
void buf_read_recover(fil_space_t *space, const page_id_t page_id,
|
||||||
|
page_recv_t &recs, recv_init *init);
|
||||||
|
|
||||||
/** @name Modes used in read-ahead @{ */
|
/** @name Modes used in read-ahead @{ */
|
||||||
/** read only pages belonging to the insert buffer tree */
|
/** read only pages belonging to the insert buffer tree */
|
||||||
|
|||||||
@@ -638,8 +638,6 @@ public:
|
|||||||
/** Close all tablespace files at shutdown */
|
/** Close all tablespace files at shutdown */
|
||||||
static void close_all();
|
static void close_all();
|
||||||
|
|
||||||
/** @return last_freed_lsn */
|
|
||||||
lsn_t get_last_freed_lsn() { return last_freed_lsn; }
|
|
||||||
/** Update last_freed_lsn */
|
/** Update last_freed_lsn */
|
||||||
void update_last_freed_lsn(lsn_t lsn) { last_freed_lsn= lsn; }
|
void update_last_freed_lsn(lsn_t lsn) { last_freed_lsn= lsn; }
|
||||||
|
|
||||||
|
|||||||
@@ -955,6 +955,10 @@ public:
|
|||||||
|
|
||||||
/** Cancel possible lock waiting for a transaction */
|
/** Cancel possible lock waiting for a transaction */
|
||||||
static void cancel_lock_wait_for_trx(trx_t *trx);
|
static void cancel_lock_wait_for_trx(trx_t *trx);
|
||||||
|
#ifdef WITH_WSREP
|
||||||
|
/** Cancel lock waiting for a wsrep BF abort. */
|
||||||
|
static void cancel_lock_wait_for_wsrep_bf_abort(trx_t *trx);
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The lock system */
|
/** The lock system */
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ Created 9/20/1997 Heikki Tuuri
|
|||||||
#define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on)
|
#define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on)
|
||||||
|
|
||||||
ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result))
|
ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||||
/** Apply any buffered redo log to a page that was just read from a data file.
|
/** Apply any buffered redo log to a page.
|
||||||
@param[in,out] space tablespace
|
@param space tablespace
|
||||||
@param[in,out] bpage buffer pool page
|
@param bpage buffer pool page
|
||||||
@return whether the page was recovered correctly */
|
@return whether the page was recovered correctly */
|
||||||
bool recv_recover_page(fil_space_t* space, buf_page_t* bpage);
|
bool recv_recover_page(fil_space_t* space, buf_page_t* bpage);
|
||||||
|
|
||||||
@@ -49,17 +49,6 @@ of first system tablespace page
|
|||||||
@return error code or DB_SUCCESS */
|
@return error code or DB_SUCCESS */
|
||||||
dberr_t recv_recovery_from_checkpoint_start();
|
dberr_t recv_recovery_from_checkpoint_start();
|
||||||
|
|
||||||
/** Whether to store redo log records in recv_sys.pages */
|
|
||||||
enum store_t {
|
|
||||||
/** Do not store redo log records. */
|
|
||||||
STORE_NO,
|
|
||||||
/** Store redo log records. */
|
|
||||||
STORE_YES,
|
|
||||||
/** Store redo log records if the tablespace exists. */
|
|
||||||
STORE_IF_EXISTS
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Report an operation to create, delete, or rename a file during backup.
|
/** Report an operation to create, delete, or rename a file during backup.
|
||||||
@param[in] space_id tablespace identifier
|
@param[in] space_id tablespace identifier
|
||||||
@param[in] type file operation redo log type
|
@param[in] type file operation redo log type
|
||||||
@@ -125,21 +114,15 @@ struct recv_dblwr_t
|
|||||||
list pages;
|
list pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** the recovery state and buffered records for a page */
|
/** recv_sys.pages entry; protected by recv_sys.mutex */
|
||||||
struct page_recv_t
|
struct page_recv_t
|
||||||
{
|
{
|
||||||
/** Recovery state; protected by recv_sys.mutex */
|
/** Recovery status: 0=not in progress, 1=log is being applied,
|
||||||
enum
|
-1=log has been applied and the entry may be erased.
|
||||||
{
|
Transitions from 1 to -1 are NOT protected by recv_sys.mutex. */
|
||||||
/** not yet processed */
|
Atomic_relaxed<int8_t> being_processed{0};
|
||||||
RECV_NOT_PROCESSED,
|
/** Whether reading the page will be skipped */
|
||||||
/** not processed; the page will be reinitialized */
|
bool skip_read= false;
|
||||||
RECV_WILL_NOT_READ,
|
|
||||||
/** page is being read */
|
|
||||||
RECV_BEING_READ,
|
|
||||||
/** log records are being applied on the page */
|
|
||||||
RECV_BEING_PROCESSED
|
|
||||||
} state= RECV_NOT_PROCESSED;
|
|
||||||
/** Latest written byte offset when applying the log records.
|
/** Latest written byte offset when applying the log records.
|
||||||
@see mtr_t::m_last_offset */
|
@see mtr_t::m_last_offset */
|
||||||
uint16_t last_offset= 1;
|
uint16_t last_offset= 1;
|
||||||
@@ -162,6 +145,9 @@ struct page_recv_t
|
|||||||
head= recs;
|
head= recs;
|
||||||
tail= recs;
|
tail= recs;
|
||||||
}
|
}
|
||||||
|
/** Remove the last records for the page
|
||||||
|
@param start_lsn start of the removed log */
|
||||||
|
ATTRIBUTE_COLD void rewind(lsn_t start_lsn);
|
||||||
|
|
||||||
/** @return the last log snippet */
|
/** @return the last log snippet */
|
||||||
const log_rec_t* last() const { return tail; }
|
const log_rec_t* last() const { return tail; }
|
||||||
@@ -180,8 +166,8 @@ struct page_recv_t
|
|||||||
iterator begin() { return head; }
|
iterator begin() { return head; }
|
||||||
iterator end() { return NULL; }
|
iterator end() { return NULL; }
|
||||||
bool empty() const { ut_ad(!head == !tail); return !head; }
|
bool empty() const { ut_ad(!head == !tail); return !head; }
|
||||||
/** Clear and free the records; @see recv_sys_t::alloc() */
|
/** Clear and free the records; @see recv_sys_t::add() */
|
||||||
inline void clear();
|
void clear();
|
||||||
} log;
|
} log;
|
||||||
|
|
||||||
/** Trim old log records for a page.
|
/** Trim old log records for a page.
|
||||||
@@ -190,21 +176,27 @@ struct page_recv_t
|
|||||||
inline bool trim(lsn_t start_lsn);
|
inline bool trim(lsn_t start_lsn);
|
||||||
/** Ignore any earlier redo log records for this page. */
|
/** Ignore any earlier redo log records for this page. */
|
||||||
inline void will_not_read();
|
inline void will_not_read();
|
||||||
/** @return whether the log records for the page are being processed */
|
};
|
||||||
bool is_being_processed() const { return state == RECV_BEING_PROCESSED; }
|
|
||||||
|
/** A page initialization operation that was parsed from the redo log */
|
||||||
|
struct recv_init
|
||||||
|
{
|
||||||
|
/** log sequence number of the page initialization */
|
||||||
|
lsn_t lsn;
|
||||||
|
/** Whether btr_page_create() avoided a read of the page.
|
||||||
|
At the end of the last recovery batch, mark_ibuf_exist()
|
||||||
|
will mark pages for which this flag is set. */
|
||||||
|
bool created;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Recovery system data structure */
|
/** Recovery system data structure */
|
||||||
struct recv_sys_t
|
struct recv_sys_t
|
||||||
{
|
{
|
||||||
/** mutex protecting apply_log_recs and page_recv_t::state */
|
using init= recv_init;
|
||||||
mysql_mutex_t mutex;
|
|
||||||
|
/** mutex protecting this as well as some of page_recv_t */
|
||||||
|
alignas(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex;
|
||||||
private:
|
private:
|
||||||
/** condition variable for
|
|
||||||
!apply_batch_on || pages.empty() || found_corrupt_log || found_corrupt_fs */
|
|
||||||
pthread_cond_t cond;
|
|
||||||
/** whether recv_apply_hashed_log_recs() is running */
|
|
||||||
bool apply_batch_on;
|
|
||||||
/** set when finding a corrupt log block or record, or there is a
|
/** set when finding a corrupt log block or record, or there is a
|
||||||
log parsing buffer overflow */
|
log parsing buffer overflow */
|
||||||
bool found_corrupt_log;
|
bool found_corrupt_log;
|
||||||
@@ -226,6 +218,8 @@ public:
|
|||||||
size_t offset;
|
size_t offset;
|
||||||
/** log sequence number of the first non-parsed record */
|
/** log sequence number of the first non-parsed record */
|
||||||
lsn_t lsn;
|
lsn_t lsn;
|
||||||
|
/** log sequence number of the last parsed mini-transaction */
|
||||||
|
lsn_t scanned_lsn;
|
||||||
/** log sequence number at the end of the FILE_CHECKPOINT record, or 0 */
|
/** log sequence number at the end of the FILE_CHECKPOINT record, or 0 */
|
||||||
lsn_t file_checkpoint;
|
lsn_t file_checkpoint;
|
||||||
/** the time when progress was last reported */
|
/** the time when progress was last reported */
|
||||||
@@ -238,6 +232,9 @@ public:
|
|||||||
map pages;
|
map pages;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** iterator to pages, used by parse() */
|
||||||
|
map::iterator pages_it;
|
||||||
|
|
||||||
/** Process a record that indicates that a tablespace size is being shrunk.
|
/** Process a record that indicates that a tablespace size is being shrunk.
|
||||||
@param page_id first page that is not in the file
|
@param page_id first page that is not in the file
|
||||||
@param lsn log sequence number of the shrink operation */
|
@param lsn log sequence number of the shrink operation */
|
||||||
@@ -257,30 +254,42 @@ public:
|
|||||||
/** The contents of the doublewrite buffer */
|
/** The contents of the doublewrite buffer */
|
||||||
recv_dblwr_t dblwr;
|
recv_dblwr_t dblwr;
|
||||||
|
|
||||||
/** Last added LSN to pages, before switching to STORE_NO */
|
|
||||||
lsn_t last_stored_lsn= 0;
|
|
||||||
|
|
||||||
inline void read(os_offset_t offset, span<byte> buf);
|
inline void read(os_offset_t offset, span<byte> buf);
|
||||||
inline size_t files_size();
|
inline size_t files_size();
|
||||||
void close_files() { files.clear(); files.shrink_to_fit(); }
|
void close_files() { files.clear(); files.shrink_to_fit(); }
|
||||||
|
|
||||||
|
/** Advance pages_it if it matches the iterator */
|
||||||
|
void pages_it_invalidate(const map::iterator &p)
|
||||||
|
{
|
||||||
|
mysql_mutex_assert_owner(&mutex);
|
||||||
|
if (pages_it == p)
|
||||||
|
pages_it++;
|
||||||
|
}
|
||||||
|
/** Invalidate pages_it if it points to the given tablespace */
|
||||||
|
void pages_it_invalidate(uint32_t space_id)
|
||||||
|
{
|
||||||
|
mysql_mutex_assert_owner(&mutex);
|
||||||
|
if (pages_it != pages.end() && pages_it->first.space() == space_id)
|
||||||
|
pages_it= pages.end();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Attempt to initialize a page based on redo log records.
|
/** Attempt to initialize a page based on redo log records.
|
||||||
@param page_id page identifier
|
@param p iterator
|
||||||
@param p iterator pointing to page_id
|
|
||||||
@param mtr mini-transaction
|
@param mtr mini-transaction
|
||||||
@param b pre-allocated buffer pool block
|
@param b pre-allocated buffer pool block
|
||||||
|
@param init page initialization
|
||||||
@return the recovered block
|
@return the recovered block
|
||||||
@retval nullptr if the page cannot be initialized based on log records
|
@retval nullptr if the page cannot be initialized based on log records
|
||||||
@retval -1 if the page cannot be recovered due to corruption */
|
@retval -1 if the page cannot be recovered due to corruption */
|
||||||
inline buf_block_t *recover_low(const page_id_t page_id, map::iterator &p,
|
inline buf_block_t *recover_low(const map::iterator &p, mtr_t &mtr,
|
||||||
mtr_t &mtr, buf_block_t *b);
|
buf_block_t *b, init &init);
|
||||||
/** Attempt to initialize a page based on redo log records.
|
/** Attempt to initialize a page based on redo log records.
|
||||||
@param page_id page identifier
|
@param page_id page identifier
|
||||||
@return the recovered block
|
@return the recovered block
|
||||||
@retval nullptr if the page cannot be initialized based on log records
|
@retval nullptr if the page cannot be initialized based on log records
|
||||||
@retval -1 if the page cannot be recovered due to corruption */
|
@retval -1 if the page cannot be recovered due to corruption */
|
||||||
buf_block_t *recover_low(const page_id_t page_id);
|
ATTRIBUTE_COLD buf_block_t *recover_low(const page_id_t page_id);
|
||||||
|
|
||||||
/** All found log files (multiple ones are possible if we are upgrading
|
/** All found log files (multiple ones are possible if we are upgrading
|
||||||
from before MariaDB Server 10.5.1) */
|
from before MariaDB Server 10.5.1) */
|
||||||
@@ -289,10 +298,27 @@ private:
|
|||||||
/** Base node of the redo block list.
|
/** Base node of the redo block list.
|
||||||
List elements are linked via buf_block_t::unzip_LRU. */
|
List elements are linked via buf_block_t::unzip_LRU. */
|
||||||
UT_LIST_BASE_NODE_T(buf_block_t) blocks;
|
UT_LIST_BASE_NODE_T(buf_block_t) blocks;
|
||||||
|
|
||||||
|
/** Allocate a block from the buffer pool for recv_sys.pages */
|
||||||
|
ATTRIBUTE_COLD buf_block_t *add_block();
|
||||||
|
|
||||||
|
/** Wait for buffer pool to become available.
|
||||||
|
@param pages number of buffer pool pages needed */
|
||||||
|
ATTRIBUTE_COLD void wait_for_pool(size_t pages);
|
||||||
|
|
||||||
|
/** Free log for processed pages. */
|
||||||
|
void garbage_collect();
|
||||||
|
|
||||||
|
/** Apply a recovery batch.
|
||||||
|
@param space_id current tablespace identifier
|
||||||
|
@param space current tablespace
|
||||||
|
@param free_block spare buffer block
|
||||||
|
@param last_batch whether it is possible to write more redo log
|
||||||
|
@return whether the caller must provide a new free_block */
|
||||||
|
bool apply_batch(uint32_t space_id, fil_space_t *&space,
|
||||||
|
buf_block_t *&free_block, bool last_batch);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Check whether the number of read redo log blocks exceeds the maximum.
|
|
||||||
@return whether the memory is exhausted */
|
|
||||||
inline bool is_memory_exhausted();
|
|
||||||
/** Apply buffered log to persistent data pages.
|
/** Apply buffered log to persistent data pages.
|
||||||
@param last_batch whether it is possible to write more redo log */
|
@param last_batch whether it is possible to write more redo log */
|
||||||
void apply(bool last_batch);
|
void apply(bool last_batch);
|
||||||
@@ -310,7 +336,7 @@ public:
|
|||||||
/** Clean up after create() */
|
/** Clean up after create() */
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
bool is_initialised() const { return last_stored_lsn != 0; }
|
bool is_initialised() const { return scanned_lsn != 0; }
|
||||||
|
|
||||||
/** Find the latest checkpoint.
|
/** Find the latest checkpoint.
|
||||||
@return error code or DB_SUCCESS */
|
@return error code or DB_SUCCESS */
|
||||||
@@ -321,60 +347,76 @@ public:
|
|||||||
@param start_lsn start LSN of the mini-transaction
|
@param start_lsn start LSN of the mini-transaction
|
||||||
@param lsn @see mtr_t::commit_lsn()
|
@param lsn @see mtr_t::commit_lsn()
|
||||||
@param l redo log snippet
|
@param l redo log snippet
|
||||||
@param len length of l, in bytes */
|
@param len length of l, in bytes
|
||||||
inline void add(map::iterator it, lsn_t start_lsn, lsn_t lsn,
|
@return whether we ran out of memory */
|
||||||
const byte *l, size_t len);
|
bool add(map::iterator it, lsn_t start_lsn, lsn_t lsn,
|
||||||
|
const byte *l, size_t len);
|
||||||
|
|
||||||
enum parse_mtr_result { OK, PREMATURE_EOF, GOT_EOF };
|
/** Parsing result */
|
||||||
|
enum parse_mtr_result {
|
||||||
|
/** a record was successfully parsed */
|
||||||
|
OK,
|
||||||
|
/** the log ended prematurely (need to read more) */
|
||||||
|
PREMATURE_EOF,
|
||||||
|
/** the end of the log was reached */
|
||||||
|
GOT_EOF,
|
||||||
|
/** parse<true>(l, false) ran out of memory */
|
||||||
|
GOT_OOM
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Parse and register one log_t::FORMAT_10_8 mini-transaction.
|
/** Parse and register one log_t::FORMAT_10_8 mini-transaction.
|
||||||
@param store whether to store the records
|
@tparam store whether to store the records
|
||||||
@param l log data source */
|
@param l log data source
|
||||||
|
@param if_exists if store: whether to check if the tablespace exists */
|
||||||
|
template<typename source,bool store>
|
||||||
|
inline parse_mtr_result parse(source &l, bool if_exists) noexcept;
|
||||||
|
|
||||||
|
/** Rewind a mini-transaction when parse() runs out of memory.
|
||||||
|
@param l log data source
|
||||||
|
@param begin start of the mini-transaction */
|
||||||
template<typename source>
|
template<typename source>
|
||||||
inline parse_mtr_result parse(store_t store, source& l) noexcept;
|
ATTRIBUTE_COLD void rewind(source &l, source &begin) noexcept;
|
||||||
|
|
||||||
|
/** Report progress in terms of LSN or pages remaining */
|
||||||
|
ATTRIBUTE_COLD void report_progress() const;
|
||||||
public:
|
public:
|
||||||
/** Parse and register one log_t::FORMAT_10_8 mini-transaction,
|
/** Parse and register one log_t::FORMAT_10_8 mini-transaction,
|
||||||
handling log_sys.is_pmem() buffer wrap-around.
|
handling log_sys.is_pmem() buffer wrap-around.
|
||||||
@param store whether to store the records */
|
@tparam store whether to store the records
|
||||||
static parse_mtr_result parse_mtr(store_t store) noexcept;
|
@param if_exists if store: whether to check if the tablespace exists */
|
||||||
|
template<bool store>
|
||||||
|
static parse_mtr_result parse_mtr(bool if_exists) noexcept;
|
||||||
|
|
||||||
/** Parse and register one log_t::FORMAT_10_8 mini-transaction,
|
/** Parse and register one log_t::FORMAT_10_8 mini-transaction,
|
||||||
handling log_sys.is_pmem() buffer wrap-around.
|
handling log_sys.is_pmem() buffer wrap-around.
|
||||||
@param store whether to store the records */
|
@tparam store whether to store the records
|
||||||
static parse_mtr_result parse_pmem(store_t store) noexcept
|
@param if_exists if store: whether to check if the tablespace exists */
|
||||||
|
template<bool store>
|
||||||
|
static parse_mtr_result parse_pmem(bool if_exists) noexcept
|
||||||
#ifdef HAVE_PMEM
|
#ifdef HAVE_PMEM
|
||||||
;
|
;
|
||||||
#else
|
#else
|
||||||
{ return parse_mtr(store); }
|
{ return parse_mtr<store>(if_exists); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Erase log records for a page. */
|
||||||
|
void erase(map::iterator p);
|
||||||
|
|
||||||
/** Clear a fully processed set of stored redo log records. */
|
/** Clear a fully processed set of stored redo log records. */
|
||||||
inline void clear();
|
void clear();
|
||||||
|
|
||||||
/** Determine whether redo log recovery progress should be reported.
|
/** Determine whether redo log recovery progress should be reported.
|
||||||
@param time the current time
|
@param time the current time
|
||||||
@return whether progress should be reported
|
@return whether progress should be reported
|
||||||
(the last report was at least 15 seconds ago) */
|
(the last report was at least 15 seconds ago) */
|
||||||
bool report(time_t time)
|
bool report(time_t time);
|
||||||
{
|
|
||||||
if (time - progress_time < 15)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
progress_time= time;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The alloc() memory alignment, in bytes */
|
/** The alloc() memory alignment, in bytes */
|
||||||
static constexpr size_t ALIGNMENT= sizeof(size_t);
|
static constexpr size_t ALIGNMENT= sizeof(size_t);
|
||||||
|
|
||||||
/** Allocate memory for log_rec_t
|
|
||||||
@param len allocation size, in bytes
|
|
||||||
@return pointer to len bytes of memory (never NULL) */
|
|
||||||
inline void *alloc(size_t len);
|
|
||||||
|
|
||||||
/** Free a redo log snippet.
|
/** Free a redo log snippet.
|
||||||
@param data buffer returned by alloc() */
|
@param data buffer allocated in add() */
|
||||||
inline void free(const void *data);
|
inline void free(const void *data);
|
||||||
|
|
||||||
/** Remove records for a corrupted page.
|
/** Remove records for a corrupted page.
|
||||||
@@ -386,8 +428,6 @@ public:
|
|||||||
ATTRIBUTE_COLD void set_corrupt_fs();
|
ATTRIBUTE_COLD void set_corrupt_fs();
|
||||||
/** Flag log file corruption during recovery. */
|
/** Flag log file corruption during recovery. */
|
||||||
ATTRIBUTE_COLD void set_corrupt_log();
|
ATTRIBUTE_COLD void set_corrupt_log();
|
||||||
/** Possibly finish a recovery batch. */
|
|
||||||
inline void maybe_finish_batch();
|
|
||||||
|
|
||||||
/** @return whether data file corruption was found */
|
/** @return whether data file corruption was found */
|
||||||
bool is_corrupt_fs() const { return UNIV_UNLIKELY(found_corrupt_fs); }
|
bool is_corrupt_fs() const { return UNIV_UNLIKELY(found_corrupt_fs); }
|
||||||
@@ -405,13 +445,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Try to recover a tablespace that was not readable earlier
|
/** Try to recover a tablespace that was not readable earlier
|
||||||
@param p iterator, initially pointing to page_id_t{space_id,0};
|
@param p iterator
|
||||||
the records will be freed and the iterator advanced
|
|
||||||
@param name tablespace file name
|
@param name tablespace file name
|
||||||
@param free_block spare buffer block
|
@param free_block spare buffer block
|
||||||
@return whether recovery failed */
|
@return recovered tablespace
|
||||||
bool recover_deferred(map::iterator &p, const std::string &name,
|
@retval nullptr if recovery failed */
|
||||||
buf_block_t *&free_block);
|
fil_space_t *recover_deferred(const map::iterator &p,
|
||||||
|
const std::string &name,
|
||||||
|
buf_block_t *&free_block);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The recovery system */
|
/** The recovery system */
|
||||||
|
|||||||
@@ -212,6 +212,10 @@ public:
|
|||||||
bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_ASYNC)) != 0; }
|
bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_ASYNC)) != 0; }
|
||||||
bool is_async() const { return (type & (READ_SYNC ^ READ_ASYNC)) != 0; }
|
bool is_async() const { return (type & (READ_SYNC ^ READ_ASYNC)) != 0; }
|
||||||
|
|
||||||
|
void write_complete() const;
|
||||||
|
void read_complete() const;
|
||||||
|
void fake_read_complete(os_offset_t offset) const;
|
||||||
|
|
||||||
/** If requested, free storage space associated with a section of the file.
|
/** If requested, free storage space associated with a section of the file.
|
||||||
@param off byte offset from the start (SEEK_SET)
|
@param off byte offset from the start (SEEK_SET)
|
||||||
@param len size of the hole in bytes
|
@param len size of the hole in bytes
|
||||||
@@ -1040,6 +1044,11 @@ int os_aio_init();
|
|||||||
Frees the asynchronous io system. */
|
Frees the asynchronous io system. */
|
||||||
void os_aio_free();
|
void os_aio_free();
|
||||||
|
|
||||||
|
/** Submit a fake read request during crash recovery.
|
||||||
|
@param type fake read request
|
||||||
|
@param offset additional context */
|
||||||
|
void os_fake_read(const IORequest &type, os_offset_t offset);
|
||||||
|
|
||||||
/** Request a read or write.
|
/** Request a read or write.
|
||||||
@param type I/O request
|
@param type I/O request
|
||||||
@param buf buffer
|
@param buf buffer
|
||||||
|
|||||||
@@ -617,6 +617,8 @@ struct export_var_t{
|
|||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */
|
ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
/** buf_pool.stat.n_page_gets (a sharded counter) */
|
||||||
|
ulint innodb_buffer_pool_read_requests;
|
||||||
ulint innodb_checkpoint_age;
|
ulint innodb_checkpoint_age;
|
||||||
ulint innodb_checkpoint_max_age;
|
ulint innodb_checkpoint_max_age;
|
||||||
ulint innodb_data_pending_reads; /*!< Pending reads */
|
ulint innodb_data_pending_reads; /*!< Pending reads */
|
||||||
|
|||||||
@@ -1055,7 +1055,7 @@ public:
|
|||||||
void close();
|
void close();
|
||||||
|
|
||||||
/** @return total number of active (non-prepared) transactions */
|
/** @return total number of active (non-prepared) transactions */
|
||||||
ulint any_active_transactions();
|
size_t any_active_transactions(size_t *prepared= nullptr);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -216,14 +216,6 @@ buf_block_t*
|
|||||||
trx_undo_assign_low(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
|
trx_undo_assign_low(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
|
||||||
mtr_t *mtr, dberr_t *err)
|
mtr_t *mtr, dberr_t *err)
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
/******************************************************************//**
|
|
||||||
Sets the state of the undo log segment at a transaction finish.
|
|
||||||
@return undo log segment header page, x-latched */
|
|
||||||
buf_block_t*
|
|
||||||
trx_undo_set_state_at_finish(
|
|
||||||
/*=========================*/
|
|
||||||
trx_undo_t* undo, /*!< in: undo log memory copy */
|
|
||||||
mtr_t* mtr); /*!< in: mtr */
|
|
||||||
|
|
||||||
/** Set the state of the undo log segment at a XA PREPARE or XA ROLLBACK.
|
/** Set the state of the undo log segment at a XA PREPARE or XA ROLLBACK.
|
||||||
@param[in,out] trx transaction
|
@param[in,out] trx transaction
|
||||||
|
|||||||
@@ -5732,13 +5732,14 @@ static void lock_release_autoinc_locks(trx_t *trx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Cancel a waiting lock request and release possibly waiting transactions */
|
/** Cancel a waiting lock request and release possibly waiting transactions */
|
||||||
template <bool from_deadlock= false>
|
template <bool from_deadlock= false, bool inner_trx_lock= true>
|
||||||
void lock_cancel_waiting_and_release(lock_t *lock)
|
void lock_cancel_waiting_and_release(lock_t *lock)
|
||||||
{
|
{
|
||||||
lock_sys.assert_locked(*lock);
|
lock_sys.assert_locked(*lock);
|
||||||
mysql_mutex_assert_owner(&lock_sys.wait_mutex);
|
mysql_mutex_assert_owner(&lock_sys.wait_mutex);
|
||||||
trx_t *trx= lock->trx;
|
trx_t *trx= lock->trx;
|
||||||
trx->mutex_lock();
|
if (inner_trx_lock)
|
||||||
|
trx->mutex_lock();
|
||||||
ut_d(const auto trx_state= trx->state);
|
ut_d(const auto trx_state= trx->state);
|
||||||
ut_ad(trx_state == TRX_STATE_COMMITTED_IN_MEMORY ||
|
ut_ad(trx_state == TRX_STATE_COMMITTED_IN_MEMORY ||
|
||||||
trx_state == TRX_STATE_ACTIVE);
|
trx_state == TRX_STATE_ACTIVE);
|
||||||
@@ -5762,7 +5763,8 @@ void lock_cancel_waiting_and_release(lock_t *lock)
|
|||||||
|
|
||||||
lock_wait_end<from_deadlock>(trx);
|
lock_wait_end<from_deadlock>(trx);
|
||||||
|
|
||||||
trx->mutex_unlock();
|
if (inner_trx_lock)
|
||||||
|
trx->mutex_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
|
void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
|
||||||
@@ -5779,6 +5781,19 @@ void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
|
|||||||
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_WSREP
|
||||||
|
void lock_sys_t::cancel_lock_wait_for_wsrep_bf_abort(trx_t *trx)
|
||||||
|
{
|
||||||
|
lock_sys.assert_locked();
|
||||||
|
mysql_mutex_assert_owner(&lock_sys.wait_mutex);
|
||||||
|
ut_ad(trx->mutex_is_owner());
|
||||||
|
ut_ad(trx->state == TRX_STATE_ACTIVE || trx->state == TRX_STATE_PREPARED);
|
||||||
|
trx->lock.set_wsrep_victim();
|
||||||
|
if (lock_t *lock= trx->lock.wait_lock)
|
||||||
|
lock_cancel_waiting_and_release<false, false>(lock);
|
||||||
|
}
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
/** Cancel a waiting lock request.
|
/** Cancel a waiting lock request.
|
||||||
@tparam check_victim whether to check for DB_DEADLOCK
|
@tparam check_victim whether to check for DB_DEADLOCK
|
||||||
@param trx active transaction
|
@param trx active transaction
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3427,15 +3427,12 @@ os_file_get_status(
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void io_callback_errorcheck(const tpool::aiocb *cb)
|
||||||
extern void fil_aio_callback(const IORequest &request);
|
|
||||||
|
|
||||||
static void io_callback(tpool::aiocb *cb)
|
|
||||||
{
|
{
|
||||||
const IORequest &request= *static_cast<const IORequest*>
|
|
||||||
(static_cast<const void*>(cb->m_userdata));
|
|
||||||
if (cb->m_err != DB_SUCCESS)
|
if (cb->m_err != DB_SUCCESS)
|
||||||
{
|
{
|
||||||
|
const IORequest &request= *static_cast<const IORequest*>
|
||||||
|
(static_cast<const void*>(cb->m_userdata));
|
||||||
ib::fatal() << "IO Error: " << cb->m_err << " during " <<
|
ib::fatal() << "IO Error: " << cb->m_err << " during " <<
|
||||||
(request.is_async() ? "async " : "sync ") <<
|
(request.is_async() ? "async " : "sync ") <<
|
||||||
(request.is_LRU() ? "lru " : "") <<
|
(request.is_LRU() ? "lru " : "") <<
|
||||||
@@ -3443,19 +3440,36 @@ static void io_callback(tpool::aiocb *cb)
|
|||||||
" of " << cb->m_len << " bytes, for file " << cb->m_fh << ", returned " <<
|
" of " << cb->m_len << " bytes, for file " << cb->m_fh << ", returned " <<
|
||||||
cb->m_ret_len;
|
cb->m_ret_len;
|
||||||
}
|
}
|
||||||
/* Return cb back to cache*/
|
}
|
||||||
if (cb->m_opcode == tpool::aio_opcode::AIO_PREAD)
|
|
||||||
{
|
static void fake_io_callback(void *c)
|
||||||
ut_ad(read_slots->contains(cb));
|
{
|
||||||
fil_aio_callback(request);
|
tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
|
||||||
read_slots->release(cb);
|
ut_ad(read_slots->contains(cb));
|
||||||
}
|
static_cast<const IORequest*>(static_cast<const void*>(cb->m_userdata))->
|
||||||
else
|
fake_read_complete(cb->m_offset);
|
||||||
{
|
read_slots->release(cb);
|
||||||
ut_ad(write_slots->contains(cb));
|
}
|
||||||
fil_aio_callback(request);
|
|
||||||
write_slots->release(cb);
|
static void read_io_callback(void *c)
|
||||||
}
|
{
|
||||||
|
tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
|
||||||
|
ut_ad(cb->m_opcode == tpool::aio_opcode::AIO_PREAD);
|
||||||
|
io_callback_errorcheck(cb);
|
||||||
|
ut_ad(read_slots->contains(cb));
|
||||||
|
static_cast<const IORequest*>
|
||||||
|
(static_cast<const void*>(cb->m_userdata))->read_complete();
|
||||||
|
read_slots->release(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_io_callback(void *c)
|
||||||
|
{
|
||||||
|
tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
|
||||||
|
ut_ad(cb->m_opcode == tpool::aio_opcode::AIO_PWRITE);
|
||||||
|
ut_ad(write_slots->contains(cb));
|
||||||
|
static_cast<const IORequest*>
|
||||||
|
(static_cast<const void*>(cb->m_userdata))->write_complete();
|
||||||
|
write_slots->release(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LINUX_NATIVE_AIO
|
#ifdef LINUX_NATIVE_AIO
|
||||||
@@ -3758,6 +3772,28 @@ void os_aio_wait_until_no_pending_reads(bool declare)
|
|||||||
tpool::tpool_wait_end();
|
tpool::tpool_wait_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Submit a fake read request during crash recovery.
|
||||||
|
@param type fake read request
|
||||||
|
@param offset additional context */
|
||||||
|
void os_fake_read(const IORequest &type, os_offset_t offset)
|
||||||
|
{
|
||||||
|
tpool::aiocb *cb= read_slots->acquire();
|
||||||
|
|
||||||
|
cb->m_group= read_slots->get_task_group();
|
||||||
|
cb->m_fh= type.node->handle.m_file;
|
||||||
|
cb->m_buffer= nullptr;
|
||||||
|
cb->m_len= 0;
|
||||||
|
cb->m_offset= offset;
|
||||||
|
cb->m_opcode= tpool::aio_opcode::AIO_PREAD;
|
||||||
|
new (cb->m_userdata) IORequest{type};
|
||||||
|
cb->m_internal_task.m_func= fake_io_callback;
|
||||||
|
cb->m_internal_task.m_arg= cb;
|
||||||
|
cb->m_internal_task.m_group= cb->m_group;
|
||||||
|
|
||||||
|
srv_thread_pool->submit_task(&cb->m_internal_task);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Request a read or write.
|
/** Request a read or write.
|
||||||
@param type I/O request
|
@param type I/O request
|
||||||
@param buf buffer
|
@param buf buffer
|
||||||
@@ -3803,23 +3839,32 @@ func_exit:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io_slots* slots;
|
||||||
|
tpool::callback_func callback;
|
||||||
|
tpool::aio_opcode opcode;
|
||||||
|
|
||||||
if (type.is_read()) {
|
if (type.is_read()) {
|
||||||
++os_n_file_reads;
|
++os_n_file_reads;
|
||||||
|
slots = read_slots;
|
||||||
|
callback = read_io_callback;
|
||||||
|
opcode = tpool::aio_opcode::AIO_PREAD;
|
||||||
} else {
|
} else {
|
||||||
++os_n_file_writes;
|
++os_n_file_writes;
|
||||||
|
slots = write_slots;
|
||||||
|
callback = write_io_callback;
|
||||||
|
opcode = tpool::aio_opcode::AIO_PWRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
compile_time_assert(sizeof(IORequest) <= tpool::MAX_AIO_USERDATA_LEN);
|
compile_time_assert(sizeof(IORequest) <= tpool::MAX_AIO_USERDATA_LEN);
|
||||||
io_slots* slots= type.is_read() ? read_slots : write_slots;
|
|
||||||
tpool::aiocb* cb = slots->acquire();
|
tpool::aiocb* cb = slots->acquire();
|
||||||
|
|
||||||
cb->m_buffer = buf;
|
cb->m_buffer = buf;
|
||||||
cb->m_callback = (tpool::callback_func)io_callback;
|
cb->m_callback = callback;
|
||||||
cb->m_group = slots->get_task_group();
|
cb->m_group = slots->get_task_group();
|
||||||
cb->m_fh = type.node->handle.m_file;
|
cb->m_fh = type.node->handle.m_file;
|
||||||
cb->m_len = (int)n;
|
cb->m_len = (int)n;
|
||||||
cb->m_offset = offset;
|
cb->m_offset = offset;
|
||||||
cb->m_opcode = type.is_read() ? tpool::aio_opcode::AIO_PREAD : tpool::aio_opcode::AIO_PWRITE;
|
cb->m_opcode = opcode;
|
||||||
new (cb->m_userdata) IORequest{type};
|
new (cb->m_userdata) IORequest{type};
|
||||||
|
|
||||||
if (srv_thread_pool->submit_io(cb)) {
|
if (srv_thread_pool->submit_io(cb)) {
|
||||||
@@ -3827,6 +3872,7 @@ func_exit:
|
|||||||
os_file_handle_error(type.node->name, type.is_read()
|
os_file_handle_error(type.node->name, type.is_read()
|
||||||
? "aio read" : "aio write");
|
? "aio read" : "aio write");
|
||||||
err = DB_IO_ERROR;
|
err = DB_IO_ERROR;
|
||||||
|
type.node->space->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
|
|||||||
@@ -214,14 +214,14 @@ row_ins_sec_index_entry_by_modify(
|
|||||||
made to the clustered index, and completed the
|
made to the clustered index, and completed the
|
||||||
secondary index creation before we got here. In this
|
secondary index creation before we got here. In this
|
||||||
case, the change would already be there. The CREATE
|
case, the change would already be there. The CREATE
|
||||||
INDEX should be waiting for a MySQL meta-data lock
|
INDEX should be in wait_while_table_is_used() at least
|
||||||
upgrade at least until this INSERT or UPDATE
|
until this INSERT or UPDATE returns. After that point,
|
||||||
returns. After that point, set_committed(true)
|
set_committed(true) would be invoked in
|
||||||
would be invoked in commit_inplace_alter_table(). */
|
commit_inplace_alter_table(). */
|
||||||
ut_a(update->n_fields == 0);
|
ut_a(update->n_fields == 0);
|
||||||
ut_a(!cursor->index()->is_committed());
|
|
||||||
ut_ad(!dict_index_is_online_ddl(cursor->index()));
|
ut_ad(!dict_index_is_online_ddl(cursor->index()));
|
||||||
return(DB_SUCCESS);
|
return cursor->index()->is_committed()
|
||||||
|
? DB_CORRUPTION : DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == BTR_MODIFY_LEAF) {
|
if (mode == BTR_MODIFY_LEAF) {
|
||||||
|
|||||||
@@ -615,6 +615,8 @@ row_purge_del_mark(
|
|||||||
const auto type= node->index->type;
|
const auto type= node->index->type;
|
||||||
if (type & (DICT_FTS | DICT_CORRUPT))
|
if (type & (DICT_FTS | DICT_CORRUPT))
|
||||||
continue;
|
continue;
|
||||||
|
if (node->index->online_status > ONLINE_INDEX_CREATION)
|
||||||
|
continue;
|
||||||
if (UNIV_UNLIKELY(DICT_VIRTUAL & type) && !node->index->is_committed() &&
|
if (UNIV_UNLIKELY(DICT_VIRTUAL & type) && !node->index->is_committed() &&
|
||||||
node->index->has_new_v_col())
|
node->index->has_new_v_col())
|
||||||
continue;
|
continue;
|
||||||
@@ -767,6 +769,11 @@ row_purge_upd_exist_or_extern_func(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->index->online_status
|
||||||
|
> ONLINE_INDEX_CREATION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (row_upd_changes_ord_field_binary(node->index, node->update,
|
if (row_upd_changes_ord_field_binary(node->index, node->update,
|
||||||
thr, NULL, NULL)) {
|
thr, NULL, NULL)) {
|
||||||
/* Build the older version of the index entry */
|
/* Build the older version of the index entry */
|
||||||
|
|||||||
@@ -674,7 +674,7 @@ static monitor_info_t innodb_counter_info[] =
|
|||||||
{"trx_rseg_history_len", "transaction",
|
{"trx_rseg_history_len", "transaction",
|
||||||
"Length of the TRX_RSEG_HISTORY list",
|
"Length of the TRX_RSEG_HISTORY list",
|
||||||
static_cast<monitor_type_t>(
|
static_cast<monitor_type_t>(
|
||||||
MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT),
|
MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT | MONITOR_DEFAULT_ON),
|
||||||
MONITOR_DEFAULT_START, MONITOR_RSEG_HISTORY_LEN},
|
MONITOR_DEFAULT_START, MONITOR_RSEG_HISTORY_LEN},
|
||||||
|
|
||||||
{"trx_undo_slots_used", "transaction", "Number of undo slots used",
|
{"trx_undo_slots_used", "transaction", "Number of undo slots used",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user