mirror of
https://github.com/MariaDB/server.git
synced 2025-11-02 02:53:04 +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"
|
||||
# Major version dictates which branches share the same ccache. E.g. 10.6-abc
|
||||
# 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
|
||||
# sufficiently different environments they are unable to benefit from each
|
||||
# other's ccaches. As each build generates about 1 GB of ccache, having
|
||||
|
||||
@@ -297,7 +297,7 @@ ELSEIF(RPM MATCHES "sles")
|
||||
ENDIF()
|
||||
|
||||
# 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)
|
||||
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
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use feature ':5.16';
|
||||
use warnings FATAL => 'all';
|
||||
|
||||
our $VERSION = '1.11.4';
|
||||
@@ -265,7 +268,7 @@ sub get_dbh {
|
||||
$dbh->do($sql);
|
||||
MKDEBUG && _d('Enabling charset for STDOUT');
|
||||
if ( $charset eq 'utf8' ) {
|
||||
binmode(STDOUT, ':utf8')
|
||||
binmode(STDOUT, ':encoding(UTF-8)')
|
||||
or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
|
||||
}
|
||||
else {
|
||||
@@ -612,6 +615,9 @@ sub ts_to_string {
|
||||
|
||||
sub parse_innodb_timestamp {
|
||||
my $text = shift;
|
||||
if ( ! defined $text ) {
|
||||
return (0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
my ( $y, $m, $d, $h, $i, $s )
|
||||
= $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
|
||||
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
|
||||
sub parse_innodb_record_dump {
|
||||
my ( $dump, $complete, $debug ) = @_;
|
||||
return undef unless $dump;
|
||||
# Use bare return as recommend in page 199 of PBP
|
||||
return unless $dump;
|
||||
|
||||
my $result = {};
|
||||
|
||||
@@ -6769,6 +6776,9 @@ sub set_precision {
|
||||
my ( $num, $precision ) = @_;
|
||||
$num = 0 unless defined $num;
|
||||
$precision = $config{num_digits}->{val} if !defined $precision;
|
||||
if ( $num eq "" ) {
|
||||
$num = int(0);
|
||||
}
|
||||
sprintf("%.${precision}f", $num);
|
||||
}
|
||||
|
||||
@@ -6777,6 +6787,9 @@ sub set_precision {
|
||||
sub percent {
|
||||
my ( $num ) = @_;
|
||||
$num = 0 unless defined $num;
|
||||
if ( $num eq "" ) {
|
||||
$num = int(0);
|
||||
}
|
||||
my $digits = $config{num_digits}->{val};
|
||||
return sprintf("%.${digits}f", $num * 100)
|
||||
. ($config{show_percent}->{val} ? '%' : '');
|
||||
@@ -6841,7 +6854,7 @@ sub make_color_func {
|
||||
push @criteria,
|
||||
"( 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) . '}';
|
||||
die if $EVAL_ERROR;
|
||||
return $sub;
|
||||
@@ -7521,10 +7534,10 @@ sub choose_connections {
|
||||
sub do_stmt {
|
||||
my ( $cxn, $stmt_name, @args ) = @_;
|
||||
|
||||
return undef if $file;
|
||||
return if $file;
|
||||
|
||||
# Test if the cxn should not even be tried
|
||||
return undef if $dbhs{$cxn}
|
||||
return if $dbhs{$cxn}
|
||||
&& $dbhs{$cxn}->{failed}
|
||||
&& ( !$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 {
|
||||
my ( $cxn, $query ) = @_;
|
||||
|
||||
return undef if $file;
|
||||
return if $file;
|
||||
|
||||
# Test if the cxn should not even be tried
|
||||
return undef if $dbhs{$cxn}
|
||||
return if $dbhs{$cxn}
|
||||
&& $dbhs{$cxn}->{failed}
|
||||
&& ( !$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 {
|
||||
my ( $text ) = @_;
|
||||
my ( $sub, $err );
|
||||
eval "\$sub = sub { my \$set = shift; $text }";
|
||||
eval { $sub = sub { my $set = shift; $text } };
|
||||
if ( $EVAL_ERROR ) {
|
||||
$EVAL_ERROR =~ s/at \(eval.*$//;
|
||||
$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.
|
||||
my $dir = $config{plugin_dir}->{val};
|
||||
foreach my $p_file ( <$dir/*.pm> ) {
|
||||
foreach my $p_file (glob($dir."/*.pm")) {
|
||||
my ($package, $desc);
|
||||
eval {
|
||||
open my $p_in, "<", $p_file or die $OS_ERROR;
|
||||
@@ -9192,7 +9205,7 @@ sub switch_var_set {
|
||||
# edit_stmt_sleep_times {{{3
|
||||
sub edit_stmt_sleep_times {
|
||||
$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};
|
||||
$clear_screen_sub->();
|
||||
my $curr_val = $stmt_sleep_time_for{$stmt} || 0;
|
||||
@@ -9843,7 +9856,7 @@ sub get_slave_status {
|
||||
sub is_func {
|
||||
my ( $word ) = @_;
|
||||
return defined(&$word)
|
||||
|| eval "my \$x= sub { $word }; 1"
|
||||
|| eval { my $x = sub { $word }; 1 }
|
||||
|| $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`
|
||||
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
||||
# 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
|
||||
log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
|
||||
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
|
||||
fi
|
||||
|
||||
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
||||
# 4096 blocks is then lower than 4 MB
|
||||
df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1`
|
||||
if [ "$df_available_blocks" -lt "4096" ]
|
||||
# Check if MariaDB datadir is available if not fails.
|
||||
# There should be symlink or directory available or something will fail.
|
||||
if [ -d "$mysql_datadir" ] || [ -L "$mysql_datadir" ]
|
||||
then
|
||||
echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2
|
||||
db_stop
|
||||
exit 1
|
||||
# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
|
||||
# 4096 blocks is then lower than 4 MB
|
||||
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
|
||||
|
||||
# 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
|
||||
// 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)
|
||||
{
|
||||
// null- terminate filename
|
||||
char *f = (char *)malloc(len + 1);
|
||||
ut_a(f);
|
||||
memcpy(f, filename, len);
|
||||
f[len] = 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (f[i] == '\\')
|
||||
f[i] = '/';
|
||||
char *p = strrchr(f, '.');
|
||||
ut_a(p);
|
||||
*p = 0;
|
||||
char *table = strrchr(f, '/');
|
||||
ut_a(table);
|
||||
*table = 0;
|
||||
char *db = strrchr(f, '/');
|
||||
*table = '/';
|
||||
std::string s(db ? db+1 : f);
|
||||
free(f);
|
||||
return s;
|
||||
char f[FN_REFLEN];
|
||||
char *p= 0, *table, *db;
|
||||
DBUG_ASSERT(len < FN_REFLEN);
|
||||
|
||||
strmake(f, (const char*) filename, len);
|
||||
|
||||
#ifdef _WIN32
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (f[i] == '\\')
|
||||
f[i] = '/';
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remove extension, if exists */
|
||||
if (!(p= strrchr(f, '.')))
|
||||
goto err;
|
||||
*p= 0;
|
||||
|
||||
/* 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.
|
||||
@@ -3146,7 +3168,7 @@ static bool xtrabackup_copy_logfile()
|
||||
if (log_sys.buf[recv_sys.offset] <= 1)
|
||||
break;
|
||||
|
||||
if (recv_sys.parse_mtr(STORE_NO) == recv_sys_t::OK)
|
||||
if (recv_sys.parse_mtr<false>(false) == recv_sys_t::OK)
|
||||
{
|
||||
do
|
||||
{
|
||||
@@ -3156,7 +3178,7 @@ static bool xtrabackup_copy_logfile()
|
||||
sequence_offset));
|
||||
*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,
|
||||
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)
|
||||
{
|
||||
memset(dst, '\0', dst_size);
|
||||
strncpy(dst, src, dst_size - 1);
|
||||
/*
|
||||
If the first condition is true, we are guaranteed to have src length
|
||||
>= (dst_size - 1), hence safe to access src[dst_size - 1].
|
||||
*/
|
||||
if (dst[dst_size - 2] != '\0' && src[dst_size - 1] != '\0')
|
||||
return 1; /* Truncation of src. */
|
||||
DBUG_ASSERT(dst_size > 0);
|
||||
/* Note, strncpy will zerofill end of dst if src shorter than dst_size */
|
||||
strncpy(dst, src, dst_size);
|
||||
if (dst[dst_size-1])
|
||||
{
|
||||
/* Ensure string is zero terminated */
|
||||
dst[dst_size-1]= 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ typedef struct st_myrg_info
|
||||
ulong cache_size;
|
||||
uint merge_insert_method;
|
||||
uint tables,options,reclength,keys;
|
||||
uint key_parts;
|
||||
my_bool cache_in_use;
|
||||
/* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
|
||||
my_bool children_attached;
|
||||
|
||||
@@ -57,6 +57,7 @@ extern struct wsrep_service_st {
|
||||
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*);
|
||||
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);
|
||||
const char * (*wsrep_thd_query_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);
|
||||
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);
|
||||
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,
|
||||
unsigned long long trx_id);
|
||||
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_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_TRYLOCK(T) wsrep_service->wsrep_thd_TRYLOCK_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_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_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_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_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T)
|
||||
#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);
|
||||
/* Lock thd wsrep lock */
|
||||
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 */
|
||||
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 */
|
||||
/* todo: rename to is_high_priority() */
|
||||
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 */
|
||||
extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd);
|
||||
/* 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" 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" 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,
|
||||
unsigned long long trx_id);
|
||||
/* declare parallel applying unsafety for the THD */
|
||||
|
||||
@@ -34,7 +34,7 @@ use strict;
|
||||
|
||||
use Exporter;
|
||||
use base "Exporter";
|
||||
our @EXPORT= qw /rmtree mkpath copytree/;
|
||||
our @EXPORT= qw /rmtree mkpath copytree make_readonly/;
|
||||
|
||||
use File::Find;
|
||||
use File::Copy;
|
||||
@@ -184,6 +184,10 @@ sub copytree {
|
||||
# Only copy plain files
|
||||
next unless -f "$from_dir/$_";
|
||||
copy("$from_dir/$_", "$to_dir/$_");
|
||||
if (!$use_umask)
|
||||
{
|
||||
chmod(0666, "$to_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;
|
||||
|
||||
@@ -40,7 +40,7 @@ our @EXPORT= qw(create_process);
|
||||
# Retry a couple of times if fork returns EAGAIN
|
||||
#
|
||||
sub _safe_fork {
|
||||
my $retries= 5;
|
||||
my $retries= 100;
|
||||
my $pid;
|
||||
|
||||
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
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit
|
||||
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;
|
||||
|
||||
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')
|
||||
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
|
||||
#
|
||||
|
||||
@@ -1772,6 +1772,32 @@ DROP TABLE t1;
|
||||
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 # End of 10.9 Test
|
||||
--echo #
|
||||
|
||||
@@ -4095,6 +4095,116 @@ MIN(pk) a
|
||||
5 10
|
||||
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
|
||||
#
|
||||
#
|
||||
|
||||
@@ -1749,6 +1749,116 @@ SELECT MIN(pk), a FROM t1 WHERE pk <> 1 GROUP BY a;
|
||||
|
||||
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 # End of 10.5 tests
|
||||
--echo #
|
||||
|
||||
@@ -3902,6 +3902,18 @@ DROP TABLE t1;
|
||||
DROP TABLE m1;
|
||||
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
|
||||
#
|
||||
#
|
||||
|
||||
@@ -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.
|
||||
--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 # End of 10.0 tests
|
||||
--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 Table is already up to date
|
||||
set optimizer_switch='exists_to_in=off';
|
||||
set optimizer_use_condition_selectivity=2;
|
||||
SELECT * FROM t1
|
||||
WHERE
|
||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||
@@ -1849,18 +1848,39 @@ id a
|
||||
17 17
|
||||
18 18
|
||||
19 19
|
||||
explain SELECT * FROM t1
|
||||
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
|
||||
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
|
||||
EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
|
||||
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 SIMPLE A const PRIMARY,a PRIMARY 4 const 1
|
||||
1 SIMPLE B ref a a 5 const 1
|
||||
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 @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
|
||||
WHERE
|
||||
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 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_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
|
||||
drop table t1,t2;
|
||||
#
|
||||
# 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;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4
|
||||
--echo #
|
||||
|
||||
|
||||
|
||||
create table t1 (id int, a int, PRIMARY KEY(id), key(a));
|
||||
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;
|
||||
|
||||
set optimizer_switch='exists_to_in=off';
|
||||
set optimizer_use_condition_selectivity=2;
|
||||
|
||||
let $query= SELECT * FROM t1
|
||||
WHERE
|
||||
@@ -1260,14 +1256,16 @@ let $query= SELECT * FROM t1
|
||||
WHERE A.a=t1.a AND t2.b < 20);
|
||||
|
||||
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;
|
||||
|
||||
set optimizer_switch= @save_optimizer_switch;
|
||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
|
||||
drop table t1,t2;
|
||||
|
||||
--echo #
|
||||
|
||||
@@ -1836,7 +1836,6 @@ test.t1 analyze status OK
|
||||
test.t2 analyze status Engine-independent statistics collected
|
||||
test.t2 analyze status OK
|
||||
set optimizer_switch='exists_to_in=off';
|
||||
set optimizer_use_condition_selectivity=2;
|
||||
SELECT * FROM t1
|
||||
WHERE
|
||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
|
||||
@@ -1861,18 +1860,39 @@ id a
|
||||
17 17
|
||||
18 18
|
||||
19 19
|
||||
explain SELECT * FROM t1
|
||||
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
|
||||
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
|
||||
EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
|
||||
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 SIMPLE A const PRIMARY,a PRIMARY 4 const 1
|
||||
1 SIMPLE B ref a a 5 const 1 Using index
|
||||
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 @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
|
||||
WHERE
|
||||
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 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_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
|
||||
drop table t1,t2;
|
||||
#
|
||||
# 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
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect datetime value: 'r'
|
||||
SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
|
||||
c1
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (c1 timestamp);
|
||||
INSERT INTO t1 VALUES ('2010-01-01 00:00:00');
|
||||
|
||||
@@ -810,6 +810,7 @@ DROP TABLE t1;
|
||||
CREATE TABLE t1 (c1 timestamp);
|
||||
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) > 0;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (c1 timestamp);
|
||||
|
||||
@@ -408,8 +408,11 @@ sub main {
|
||||
|
||||
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)
|
||||
{
|
||||
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_parallel_simple : timeout related to wsrep_sync_wait
|
||||
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;
|
||||
connection node_1;
|
||||
CREATE TABLE t1 AS SELECT * FROM t2;;
|
||||
connection node_1a;
|
||||
connection node_2;
|
||||
SELECT COUNT(*) = 5 FROM t2;
|
||||
COUNT(*) = 5
|
||||
|
||||
@@ -134,6 +134,3 @@ connection node_1;
|
||||
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("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;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
1
|
||||
connection node_1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
0
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
SET GLOBAL debug_dbug = NULL;
|
||||
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
|
||||
--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
|
||||
SELECT COUNT(*) = 5 FROM t2;
|
||||
CREATE TABLE t1 AS SELECT * FROM t2;
|
||||
@@ -121,7 +125,7 @@ CREATE TABLE t1 AS SELECT * FROM t2;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--connection node_1
|
||||
--error ER_TABLE_EXISTS_ERROR,ER_LOCK_DEADLOCK
|
||||
--error ER_TABLE_EXISTS_ERROR,ER_QUERY_INTERRUPTED
|
||||
--reap
|
||||
|
||||
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';
|
||||
|
||||
--connection node_1
|
||||
--error 0,ER_LOCK_DEADLOCK
|
||||
--reap
|
||||
SELECT COUNT(*) FROM t1;
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
set global innodb_monitor_disable = All;
|
||||
select name, if(enabled,'enabled','disabled') status
|
||||
from information_schema.innodb_metrics;
|
||||
name status
|
||||
metadata_table_handles_opened disabled
|
||||
lock_deadlocks disabled
|
||||
lock_timeouts disabled
|
||||
lock_deadlocks enabled
|
||||
lock_timeouts enabled
|
||||
lock_rec_lock_waits disabled
|
||||
lock_table_lock_waits disabled
|
||||
lock_rec_lock_requests disabled
|
||||
@@ -14,30 +13,30 @@ lock_rec_locks disabled
|
||||
lock_table_lock_created disabled
|
||||
lock_table_lock_removed disabled
|
||||
lock_table_locks disabled
|
||||
lock_row_lock_current_waits disabled
|
||||
lock_row_lock_time disabled
|
||||
lock_row_lock_time_max disabled
|
||||
lock_row_lock_waits disabled
|
||||
lock_row_lock_time_avg disabled
|
||||
buffer_pool_size disabled
|
||||
buffer_pool_reads disabled
|
||||
buffer_pool_read_requests disabled
|
||||
buffer_pool_write_requests disabled
|
||||
buffer_pool_wait_free disabled
|
||||
buffer_pool_read_ahead disabled
|
||||
buffer_pool_read_ahead_evicted disabled
|
||||
buffer_pool_pages_total disabled
|
||||
buffer_pool_pages_misc disabled
|
||||
buffer_pool_pages_data disabled
|
||||
buffer_pool_bytes_data disabled
|
||||
buffer_pool_pages_dirty disabled
|
||||
buffer_pool_bytes_dirty disabled
|
||||
buffer_pool_pages_free disabled
|
||||
buffer_pages_created disabled
|
||||
buffer_pages_written disabled
|
||||
buffer_pages_read disabled
|
||||
buffer_data_reads disabled
|
||||
buffer_data_written disabled
|
||||
lock_row_lock_current_waits enabled
|
||||
lock_row_lock_time enabled
|
||||
lock_row_lock_time_max enabled
|
||||
lock_row_lock_waits enabled
|
||||
lock_row_lock_time_avg enabled
|
||||
buffer_pool_size enabled
|
||||
buffer_pool_reads enabled
|
||||
buffer_pool_read_requests enabled
|
||||
buffer_pool_write_requests enabled
|
||||
buffer_pool_wait_free enabled
|
||||
buffer_pool_read_ahead enabled
|
||||
buffer_pool_read_ahead_evicted enabled
|
||||
buffer_pool_pages_total enabled
|
||||
buffer_pool_pages_misc enabled
|
||||
buffer_pool_pages_data enabled
|
||||
buffer_pool_bytes_data enabled
|
||||
buffer_pool_pages_dirty enabled
|
||||
buffer_pool_bytes_dirty enabled
|
||||
buffer_pool_pages_free enabled
|
||||
buffer_pages_created enabled
|
||||
buffer_pages_written enabled
|
||||
buffer_pages_read enabled
|
||||
buffer_data_reads enabled
|
||||
buffer_data_written enabled
|
||||
buffer_flush_batch_scanned disabled
|
||||
buffer_flush_batch_num_scan 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_num_scan disabled
|
||||
buffer_LRU_batch_scanned_per_call disabled
|
||||
buffer_LRU_batch_flush_total_pages disabled
|
||||
buffer_LRU_batch_evict_total_pages disabled
|
||||
buffer_LRU_batch_flush_total_pages enabled
|
||||
buffer_LRU_batch_evict_total_pages enabled
|
||||
buffer_LRU_single_flush_failure_count disabled
|
||||
buffer_LRU_get_free_search disabled
|
||||
buffer_LRU_search_scanned disabled
|
||||
@@ -112,21 +111,21 @@ buffer_page_written_blob disabled
|
||||
buffer_page_written_zblob disabled
|
||||
buffer_page_written_zblob2 disabled
|
||||
buffer_page_written_other disabled
|
||||
os_data_reads disabled
|
||||
os_data_writes disabled
|
||||
os_data_fsyncs disabled
|
||||
os_pending_reads disabled
|
||||
os_pending_writes disabled
|
||||
os_log_bytes_written disabled
|
||||
os_data_reads enabled
|
||||
os_data_writes enabled
|
||||
os_data_fsyncs enabled
|
||||
os_pending_reads enabled
|
||||
os_pending_writes enabled
|
||||
os_log_bytes_written enabled
|
||||
trx_rw_commits disabled
|
||||
trx_ro_commits disabled
|
||||
trx_nl_ro_commits disabled
|
||||
trx_commits_insert_update disabled
|
||||
trx_rollbacks disabled
|
||||
trx_rollbacks_savepoint disabled
|
||||
trx_rseg_history_len disabled
|
||||
trx_rseg_history_len enabled
|
||||
trx_undo_slots_used disabled
|
||||
trx_undo_slots_cached disabled
|
||||
trx_undo_slots_cached enabled
|
||||
trx_rseg_current_size disabled
|
||||
purge_del_mark_records disabled
|
||||
purge_upd_exist_or_extern_records disabled
|
||||
@@ -142,9 +141,9 @@ log_lsn_current disabled
|
||||
log_lsn_checkpoint_age disabled
|
||||
log_lsn_buf_pool_oldest disabled
|
||||
log_max_modified_age_async disabled
|
||||
log_waits disabled
|
||||
log_write_requests disabled
|
||||
log_writes disabled
|
||||
log_waits enabled
|
||||
log_write_requests enabled
|
||||
log_writes enabled
|
||||
compress_pages_compressed disabled
|
||||
compress_pages_decompressed disabled
|
||||
compression_pad_increments disabled
|
||||
@@ -162,34 +161,34 @@ index_page_merge_successful disabled
|
||||
index_page_reorg_attempts disabled
|
||||
index_page_reorg_successful disabled
|
||||
index_page_discards disabled
|
||||
adaptive_hash_searches disabled
|
||||
adaptive_hash_searches_btree disabled
|
||||
adaptive_hash_searches enabled
|
||||
adaptive_hash_searches_btree enabled
|
||||
adaptive_hash_pages_added disabled
|
||||
adaptive_hash_pages_removed disabled
|
||||
adaptive_hash_rows_added disabled
|
||||
adaptive_hash_rows_removed disabled
|
||||
adaptive_hash_rows_deleted_no_hash_entry disabled
|
||||
adaptive_hash_rows_updated disabled
|
||||
file_num_open_files disabled
|
||||
ibuf_merges_insert disabled
|
||||
ibuf_merges_delete_mark disabled
|
||||
ibuf_merges_delete disabled
|
||||
ibuf_merges_discard_insert disabled
|
||||
ibuf_merges_discard_delete_mark disabled
|
||||
ibuf_merges_discard_delete disabled
|
||||
ibuf_merges disabled
|
||||
ibuf_size disabled
|
||||
file_num_open_files enabled
|
||||
ibuf_merges_insert enabled
|
||||
ibuf_merges_delete_mark enabled
|
||||
ibuf_merges_delete enabled
|
||||
ibuf_merges_discard_insert enabled
|
||||
ibuf_merges_discard_delete_mark enabled
|
||||
ibuf_merges_discard_delete enabled
|
||||
ibuf_merges enabled
|
||||
ibuf_size enabled
|
||||
innodb_master_thread_sleeps disabled
|
||||
innodb_activity_count disabled
|
||||
innodb_activity_count enabled
|
||||
innodb_master_active_loops disabled
|
||||
innodb_master_idle_loops disabled
|
||||
innodb_log_flush_usec disabled
|
||||
innodb_dict_lru_usec disabled
|
||||
innodb_dict_lru_count_active disabled
|
||||
innodb_dict_lru_count_idle disabled
|
||||
innodb_dblwr_writes disabled
|
||||
innodb_dblwr_pages_written disabled
|
||||
innodb_page_size disabled
|
||||
innodb_dblwr_writes enabled
|
||||
innodb_dblwr_pages_written enabled
|
||||
innodb_page_size enabled
|
||||
ddl_background_drop_indexes disabled
|
||||
ddl_online_create_index disabled
|
||||
ddl_pending_alter_table disabled
|
||||
@@ -199,6 +198,9 @@ icp_attempts disabled
|
||||
icp_no_match disabled
|
||||
icp_out_of_range 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;
|
||||
select name from information_schema.innodb_metrics where not enabled;
|
||||
name
|
||||
|
||||
@@ -26,4 +26,60 @@ UPDATE mysql.innodb_table_stats SET last_update=NULL WHERE table_name='t1';
|
||||
XA END 'test';
|
||||
XA ROLLBACK 'test';
|
||||
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
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
# sys_vars.innodb_monitor_enable_basic
|
||||
|
||||
--source include/have_innodb.inc
|
||||
set global innodb_monitor_disable = All;
|
||||
# Test turn on/off the monitor counter with "all" option
|
||||
# By default, they will be off.
|
||||
select name, if(enabled,'enabled','disabled') status
|
||||
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
|
||||
set global innodb_monitor_enable = all;
|
||||
|
||||
|
||||
@@ -28,4 +28,57 @@ XA END 'test';
|
||||
XA ROLLBACK 'test';
|
||||
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
|
||||
|
||||
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
|
||||
*/
|
||||
class Field_timestampf final :public Field_timestamp_with_dec {
|
||||
class Field_timestampf :public Field_timestamp_with_dec {
|
||||
void store_TIMEVAL(const timeval &tv) override;
|
||||
public:
|
||||
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
|
||||
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 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) &&
|
||||
!(bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU &&
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -7996,6 +8001,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "sql_sequence.h"
|
||||
#include "mem_root_array.h"
|
||||
#include <utility> // pair
|
||||
#include <my_attribute.h> /* __attribute__ */
|
||||
|
||||
class Alter_info;
|
||||
class Virtual_column_info;
|
||||
@@ -1460,9 +1461,9 @@ struct handlerton
|
||||
const char *query, uint query_length,
|
||||
const char *db, const char *table_name);
|
||||
|
||||
void (*abort_transaction)(handlerton *hton, THD *bf_thd,
|
||||
THD *victim_thd, my_bool signal);
|
||||
int (*set_checkpoint)(handlerton *hton, const XID* xid);
|
||||
void (*abort_transaction)(handlerton *hton, THD *bf_thd, THD *victim_thd,
|
||||
my_bool signal) __attribute__((nonnull));
|
||||
int (*set_checkpoint)(handlerton *hton, const XID *xid);
|
||||
int (*get_checkpoint)(handlerton *hton, XID* xid);
|
||||
/**
|
||||
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++)
|
||||
{
|
||||
args[i]->no_rows_in_result();
|
||||
args[i]->restore_to_before_no_rows_in_result();
|
||||
}
|
||||
}
|
||||
void convert_const_compared_to_int_field(THD *thd);
|
||||
|
||||
@@ -1747,6 +1747,11 @@ static void close_connections(void)
|
||||
(void) unlink(mysqld_unix_port);
|
||||
}
|
||||
}
|
||||
/*
|
||||
The following is needed to the threads stuck in
|
||||
setup_connection_thread_globals()
|
||||
to continue.
|
||||
*/
|
||||
listen_sockets.free_memory();
|
||||
mysql_mutex_unlock(&LOCK_start_thread);
|
||||
|
||||
@@ -2032,6 +2037,7 @@ static void clean_up(bool print_message)
|
||||
end_ssl();
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
vio_end();
|
||||
listen_sockets.free_memory();
|
||||
#endif /*!EMBEDDED_LIBRARY*/
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
to avoid losing BF thd context. */
|
||||
mysql_mutex_lock(&victim_thd->LOCK_thd_data);
|
||||
if (!(bf_thd && bf_thd != victim_thd))
|
||||
{
|
||||
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);
|
||||
}
|
||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||
if (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)
|
||||
{
|
||||
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);
|
||||
/*
|
||||
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)
|
||||
{
|
||||
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->awake_no_mutex(KILL_QUERY_HARD);
|
||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
unsigned long long trx_id)
|
||||
{
|
||||
|
||||
@@ -1293,6 +1293,11 @@ void THD::init()
|
||||
wsrep_affected_rows = 0;
|
||||
m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
|
||||
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;
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
@@ -1641,6 +1646,13 @@ void THD::reset_for_reuse()
|
||||
#endif
|
||||
#ifdef WITH_WSREP
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -1897,7 +1909,9 @@ void THD::awake_no_mutex(killed_state state_to_set)
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
abort_current_cond_wait(false);
|
||||
@@ -2125,6 +2139,17 @@ void THD::reset_killed()
|
||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||
}
|
||||
#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_lock(&LOCK_thd_data);
|
||||
wsrep_aborter= 0;
|
||||
|
||||
@@ -5382,7 +5382,14 @@ public:
|
||||
bool wsrep_ignore_table;
|
||||
/* thread who has started kill for this THD protected by LOCK_thd_data*/
|
||||
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
|
||||
client's packet, and if the client has sent PS execute command. */
|
||||
bool wsrep_delayed_BF_abort;
|
||||
|
||||
@@ -61,6 +61,15 @@ class Select_limit_counters
|
||||
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
|
||||
{ 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)
|
||||
{
|
||||
#ifdef ENABLED_DEBUG_SYNC
|
||||
DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
|
||||
DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
|
||||
{
|
||||
const char act[]=
|
||||
"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))
|
||||
#endif /* WITH_WSREP */
|
||||
{
|
||||
{
|
||||
#ifdef WITH_WSREP
|
||||
DEBUG_SYNC(thd, "before_awake_no_mutex");
|
||||
if (tmp->wsrep_aborter && tmp->wsrep_aborter != thd->thread_id)
|
||||
{
|
||||
/* victim is in hit list already, bail out */
|
||||
WSREP_DEBUG("victim %lld has wsrep aborter: %lu, skipping awake()",
|
||||
id, tmp->wsrep_aborter);
|
||||
error= 0;
|
||||
}
|
||||
else
|
||||
if (WSREP(tmp))
|
||||
{
|
||||
error = wsrep_kill_thd(thd, tmp, kill_signal);
|
||||
}
|
||||
else
|
||||
{
|
||||
#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);
|
||||
error= 0;
|
||||
#ifdef WITH_WSREP
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -9368,18 +9365,6 @@ static
|
||||
void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
|
||||
{
|
||||
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 (!thd->killed)
|
||||
@@ -9389,11 +9374,6 @@ void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
|
||||
}
|
||||
else
|
||||
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;
|
||||
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))
|
||||
{
|
||||
case 0:
|
||||
@@ -9429,11 +9397,6 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
|
||||
default:
|
||||
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_prepare_key_for_innodb,
|
||||
wsrep_thd_LOCK,
|
||||
wsrep_thd_TRYLOCK,
|
||||
wsrep_thd_UNLOCK,
|
||||
wsrep_thd_query,
|
||||
wsrep_thd_retry_counter,
|
||||
@@ -179,7 +180,6 @@ static struct wsrep_service_st wsrep_handler = {
|
||||
wsrep_OSU_method_get,
|
||||
wsrep_thd_has_ignored_error,
|
||||
wsrep_thd_set_ignored_error,
|
||||
wsrep_thd_set_wsrep_aborter,
|
||||
wsrep_report_bf_lock_wait,
|
||||
wsrep_thd_kill_LOCK,
|
||||
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,
|
||||
bool change_list, bool *simple_order);
|
||||
static int return_zero_rows(JOIN *join, select_result *res,
|
||||
List<TABLE_LIST> &tables,
|
||||
List<Item> &fields, bool send_row,
|
||||
List<TABLE_LIST> *tables,
|
||||
List<Item> *fields, bool send_row,
|
||||
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,
|
||||
COND_EQUAL *inherited,
|
||||
List<TABLE_LIST> *join_list,
|
||||
@@ -1301,11 +1301,40 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Check fields, find best join, do the select and output fields.
|
||||
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).
|
||||
@@ -1387,53 +1416,44 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/*
|
||||
TRUE if the SELECT list mixes elements with and without grouping,
|
||||
and there is no GROUP BY clause. Mixing non-aggregated fields with
|
||||
aggregate functions in the SELECT list is a MySQL extenstion that
|
||||
is allowed only if the ONLY_FULL_GROUP_BY sql mode is not set.
|
||||
mixed_implicit_grouping will be set to TRUE if the SELECT list
|
||||
mixes elements with and without grouping, and there is no GROUP BY
|
||||
clause.
|
||||
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;
|
||||
if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
|
||||
select_lex->with_sum_func && !group_list)
|
||||
{
|
||||
List_iterator_fast <Item> select_it(fields_list);
|
||||
Item *select_el; /* Element of the SELECT clause, can be an expression. */
|
||||
bool found_field_elem= false;
|
||||
bool found_sum_func_elem= false;
|
||||
|
||||
while ((select_el= select_it++))
|
||||
if (check_list_for_field(&fields_list) ||
|
||||
check_list_for_field(order))
|
||||
{
|
||||
if (select_el->with_sum_func())
|
||||
found_sum_func_elem= true;
|
||||
if (select_el->with_field())
|
||||
found_field_elem= true;
|
||||
if (found_sum_func_elem && found_field_elem)
|
||||
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
|
||||
|
||||
mixed_implicit_grouping= true; // mark for future
|
||||
|
||||
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_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;
|
||||
if (skip_order_by &&
|
||||
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);
|
||||
while ((tbl= it++))
|
||||
while (TABLE_LIST *tbl= it++)
|
||||
{
|
||||
if (tbl->table_function &&
|
||||
tbl->table_function->setup(thd, tbl, select_lex_arg))
|
||||
@@ -4074,7 +4094,7 @@ bool JOIN::make_aggr_tables_info()
|
||||
set_items_ref_array(items0);
|
||||
if (join_tab)
|
||||
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;
|
||||
|
||||
DBUG_RETURN(false);
|
||||
@@ -4469,13 +4489,7 @@ JOIN::reinit()
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset of sum functions */
|
||||
if (sum_funcs)
|
||||
{
|
||||
Item_sum *func, **func_ptr= sum_funcs;
|
||||
while ((func= *(func_ptr++)))
|
||||
func->clear();
|
||||
}
|
||||
clear_sum_funcs();
|
||||
|
||||
if (no_rows_in_result_called)
|
||||
{
|
||||
@@ -4758,12 +4772,12 @@ void JOIN::exec_inner()
|
||||
}
|
||||
else
|
||||
{
|
||||
(void) return_zero_rows(this, result, select_lex->leaf_tables,
|
||||
*columns_list,
|
||||
(void) return_zero_rows(this, result, &select_lex->leaf_tables,
|
||||
columns_list,
|
||||
send_row_on_empty_set(),
|
||||
select_options,
|
||||
zero_result_cause,
|
||||
having ? having : tmp_having, all_fields);
|
||||
having ? having : tmp_having, &all_fields);
|
||||
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
|
||||
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
||||
List<Item> &fields, bool send_row, ulonglong select_options,
|
||||
const char *info, Item *having, List<Item> &all_fields)
|
||||
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> *tables,
|
||||
List<Item> *fields, bool send_row, ulonglong select_options,
|
||||
const char *info, Item *having, List<Item> *all_fields)
|
||||
{
|
||||
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
|
||||
HAVING condition.
|
||||
*/
|
||||
List_iterator<TABLE_LIST> ti(tables);
|
||||
TABLE_LIST *table;
|
||||
while ((table= ti++))
|
||||
{
|
||||
/*
|
||||
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);
|
||||
make_tables_null_complemented(tables);
|
||||
|
||||
List_iterator_fast<Item> it(*all_fields);
|
||||
Item *item;
|
||||
/*
|
||||
Inform all items (especially aggregating) to calculate HAVING correctly,
|
||||
also we will need it for sending results.
|
||||
*/
|
||||
join->no_rows_in_result_called= 1;
|
||||
while ((item= it++))
|
||||
item->no_rows_in_result();
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(result->send_result_set_metadata(fields,
|
||||
if (!(result->send_result_set_metadata(*fields,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
|
||||
{
|
||||
bool send_error= FALSE;
|
||||
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))
|
||||
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()
|
||||
(if there where no matching rows)
|
||||
Reset table rows to contain a null-complement row (all fields are null)
|
||||
|
||||
Used only in JOIN::clear() and in do_select() if there where no matching rows.
|
||||
|
||||
@param join JOIN
|
||||
@param cleared_tables If not null, clear also const tables and mark all
|
||||
cleared tables in the map. cleared_tables is only
|
||||
set when called from do_select() when there is a
|
||||
group function and there where no matching rows.
|
||||
@param cleared_tables Used to mark all cleared tables in the map. Needed for
|
||||
unclear_tables() to know which tables to restore to
|
||||
their original state.
|
||||
*/
|
||||
|
||||
static void clear_tables(JOIN *join, table_map *cleared_tables)
|
||||
{
|
||||
/*
|
||||
must clear only the non-const tables as const tables are not re-calculated.
|
||||
*/
|
||||
DBUG_ASSERT(cleared_tables);
|
||||
for (uint i= 0 ; i < join->table_count ; i++)
|
||||
{
|
||||
TABLE *table= join->table[i];
|
||||
|
||||
if (table->null_row)
|
||||
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)
|
||||
{
|
||||
(*cleared_tables)|= (((table_map) 1) << i);
|
||||
if (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
|
||||
/*
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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
|
||||
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.
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -21565,7 +21589,7 @@ do_select(JOIN *join, Procedure *procedure)
|
||||
join->duplicate_rows= join->send_records=0;
|
||||
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,
|
||||
@@ -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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
DBUG_ENTER("end_send_group");
|
||||
|
||||
if (!join->items3.is_null() && !join->set_group_rpa)
|
||||
{
|
||||
/* Move ref_pointer_array to points to items3 */
|
||||
join->set_group_rpa= true;
|
||||
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 ||
|
||||
(idx=test_if_group_changed(join->group_fields)) >= 0)
|
||||
{
|
||||
|
||||
if (!join->group_sent &&
|
||||
(join->first_record ||
|
||||
(end_of_records && !join->group && !join->group_optimized_away)))
|
||||
{
|
||||
table_map cleared_tables= (table_map) 0;
|
||||
if (join->procedure)
|
||||
join->procedure->end_group();
|
||||
/* 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. */
|
||||
if (!join->first_record)
|
||||
{
|
||||
List_iterator_fast<Item> it(*join->fields);
|
||||
Item *item;
|
||||
/* 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++))
|
||||
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)))
|
||||
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))
|
||||
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
|
||||
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))
|
||||
{
|
||||
table_map cleared_tables= (table_map) 0;
|
||||
if (join->procedure)
|
||||
join->procedure->end_group();
|
||||
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)
|
||||
{
|
||||
/* No matching rows for group function */
|
||||
join->clear();
|
||||
join->clear(&cleared_tables);
|
||||
}
|
||||
copy_sum_funcs(join->sum_funcs,
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (cleared_tables)
|
||||
unclear_tables(join, &cleared_tables);
|
||||
if (end_of_records)
|
||||
goto end;
|
||||
}
|
||||
@@ -25603,7 +25649,7 @@ JOIN_TAB::remove_duplicates()
|
||||
!(join->select_options & 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);
|
||||
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)
|
||||
*/
|
||||
|
||||
void JOIN::clear()
|
||||
void inline JOIN::clear_sum_funcs()
|
||||
{
|
||||
clear_tables(this, 0);
|
||||
copy_fields(&tmp_table_param);
|
||||
|
||||
if (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
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ enum sj_strategy_enum
|
||||
|
||||
typedef enum_nested_loop_state
|
||||
(*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 read_record_func_for_rr_and_unpack(READ_RECORD *info);
|
||||
Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
|
||||
@@ -1722,7 +1722,8 @@ public:
|
||||
void join_free();
|
||||
/** Cleanup this JOIN, possibly for reuse */
|
||||
void cleanup(bool full);
|
||||
void clear();
|
||||
void clear(table_map *cleared_tables);
|
||||
void inline clear_sum_funcs();
|
||||
bool send_row_on_empty_set()
|
||||
{
|
||||
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_datetime> type_handler_datetime;
|
||||
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;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
table->null_row=0;
|
||||
table->status= STATUS_NO_RECORD;
|
||||
table->null_row= 0;
|
||||
table->status&= ~STATUS_NULL_ROW;
|
||||
}
|
||||
|
||||
bool is_simple_order(ORDER *order);
|
||||
|
||||
@@ -56,6 +56,11 @@ my_bool wsrep_on(const THD *)
|
||||
void wsrep_thd_LOCK(const THD *)
|
||||
{ }
|
||||
|
||||
int wsrep_thd_TRYLOCK(const THD *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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*)
|
||||
{ return 0;}
|
||||
bool wsrep_thd_set_wsrep_aborter(THD*, THD*)
|
||||
{ return 0;}
|
||||
|
||||
void wsrep_report_bf_lock_wait(const THD*,
|
||||
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();
|
||||
}
|
||||
|
||||
WSREP_DEBUG("checkpointing dummy write set %lld", ws_meta.seqno().get());
|
||||
wsrep_set_SE_checkpoint(ws_meta.gtid(), wsrep_gtid_server.gtid());
|
||||
|
||||
if (!WSREP_EMULATE_BINLOG(m_thd))
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "log_event.h"
|
||||
#include "sql_connect.h"
|
||||
#include "thread_cache.h"
|
||||
#include "debug_sync.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -3107,6 +3108,20 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
||||
request_thd, granted_thd);
|
||||
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);
|
||||
|
||||
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));
|
||||
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
||||
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))
|
||||
{
|
||||
WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
|
||||
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_thd_query(request_thd));
|
||||
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);
|
||||
ticket->wsrep_report(true);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
|
||||
unireg_abort(1);
|
||||
}
|
||||
}
|
||||
@@ -3146,7 +3160,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
||||
wsrep_thd_query(request_thd));
|
||||
THD_STAGE_INFO(request_thd, stage_waiting_ddl);
|
||||
ticket->wsrep_report(wsrep_debug);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
if (granted_thd->current_backup_stage != BACKUP_FINISHED &&
|
||||
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));
|
||||
THD_STAGE_INFO(request_thd, stage_waiting_isolation);
|
||||
ticket->wsrep_report(wsrep_debug);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
wsrep_abort_thd(request_thd, granted_thd, 1);
|
||||
}
|
||||
else
|
||||
@@ -3174,7 +3186,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
||||
|
||||
if (granted_thd->wsrep_trx().active())
|
||||
{
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
wsrep_abort_thd(request_thd, granted_thd, 1);
|
||||
}
|
||||
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
|
||||
thd is BF, BF abort and wait.
|
||||
*/
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
|
||||
if (wsrep_thd_is_BF(request_thd, FALSE))
|
||||
{
|
||||
granted_thd->awake_no_mutex(KILL_QUERY_HARD);
|
||||
ha_abort_transaction(request_thd, granted_thd, TRUE);
|
||||
}
|
||||
else
|
||||
@@ -3195,10 +3205,14 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
||||
schema, schema_len,
|
||||
request_thd, granted_thd);
|
||||
ticket->wsrep_report(true);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
|
||||
unireg_abort(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3210,13 +3224,17 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
|
||||
static bool abort_replicated(THD *thd)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,9 +148,13 @@ void Wsrep_server_service::release_high_priority_service(wsrep::high_priority_se
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wsrep_abort_thd(THD *bf_thd,
|
||||
THD *victim_thd,
|
||||
my_bool signal)
|
||||
static bool wsrep_bf_abort_low(THD *bf_thd, THD *victim_thd)
|
||||
{
|
||||
DBUG_ENTER("wsrep_abort_thd");
|
||||
|
||||
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");
|
||||
mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
|
||||
|
||||
#ifdef ENABLED_DEBUG_SYNC
|
||||
DBUG_EXECUTE_IF("sync.wsrep_bf_abort",
|
||||
@@ -362,6 +323,85 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
|
||||
};);
|
||||
#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())
|
||||
{
|
||||
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_DEBUG("killing connection for non wsrep session");
|
||||
mysql_mutex_lock(&victim_thd->LOCK_thd_data);
|
||||
victim_thd->awake_no_mutex(KILL_CONNECTION);
|
||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret;
|
||||
wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno());
|
||||
return wsrep_bf_abort_low(bf_thd, victim_thd);
|
||||
}
|
||||
|
||||
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);
|
||||
ret= victim_thd->wsrep_cs().bf_abort(bf_seqno);
|
||||
thd->wsrep_abort_by_kill= thd->killed;
|
||||
thd->wsrep_abort_by_kill_err= thd->killed_err;
|
||||
thd->killed= NOT_KILLED;
|
||||
thd->killed_err= 0;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
wsrep_bf_aborts_counter++;
|
||||
}
|
||||
return ret;
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
}
|
||||
|
||||
void wsrep_restore_kill_after_commit(THD *thd)
|
||||
{
|
||||
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()
|
||||
|
||||
@@ -88,10 +88,39 @@ bool wsrep_create_appliers(long threads, bool mutex_protected=false);
|
||||
void wsrep_create_rollbacker();
|
||||
|
||||
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,
|
||||
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.
|
||||
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(),
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -325,6 +330,11 @@ static inline int wsrep_before_commit(THD* thd, bool all)
|
||||
wsrep_gtid_server.gtid());
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -343,7 +353,8 @@ static inline int wsrep_before_commit(THD* thd, bool all)
|
||||
static inline int wsrep_ordered_commit(THD* thd, bool all)
|
||||
{
|
||||
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_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().mode()),
|
||||
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->internal_transaction() ?
|
||||
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)
|
||||
|
||||
@@ -2140,6 +2140,8 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr)
|
||||
}
|
||||
|
||||
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
|
||||
if (block->index)
|
||||
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 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
|
||||
<< " 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.mutex);
|
||||
|
||||
freed_range_mutex.lock();
|
||||
if (freed_ranges.empty() || log_sys.get_flushed_lsn() < get_last_freed_lsn())
|
||||
for (;;)
|
||||
{
|
||||
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();
|
||||
return 0;
|
||||
log_write_up_to(flush_lsn, true);
|
||||
}
|
||||
|
||||
const unsigned physical{physical_size()};
|
||||
@@ -2430,6 +2438,7 @@ static void buf_flush_page_cleaner()
|
||||
else if (buf_pool.ran_out())
|
||||
{
|
||||
buf_pool.page_cleaner_set_idle(false);
|
||||
buf_pool.get_oldest_modification(0);
|
||||
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
|
||||
n= srv_max_io_capacity;
|
||||
mysql_mutex_lock(&buf_pool.mutex);
|
||||
@@ -2583,6 +2592,7 @@ ATTRIBUTE_COLD void buf_flush_page_cleaner_init()
|
||||
/** Flush the buffer pool on shutdown. */
|
||||
ATTRIBUTE_COLD void buf_flush_buffer_pool()
|
||||
{
|
||||
ut_ad(!os_aio_pending_reads());
|
||||
ut_ad(!buf_page_cleaner_is_active);
|
||||
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_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)) {
|
||||
case FIL_PAGE_TYPE_ALLOCATED:
|
||||
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());
|
||||
page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
|
||||
|
||||
recv_sys.free_corrupted_page(id);
|
||||
mysql_mutex_lock(&mutex);
|
||||
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));
|
||||
|
||||
mysql_mutex_unlock(&mutex);
|
||||
|
||||
recv_sys.free_corrupted_page(id);
|
||||
}
|
||||
|
||||
/** Update buf_pool.LRU_old_ratio.
|
||||
|
||||
@@ -265,9 +265,6 @@ buf_read_page_low(
|
||||
buf_page_t* bpage;
|
||||
|
||||
if (buf_dblwr.is_inside(page_id)) {
|
||||
ib::error() << "Trying to read doublewrite buffer page "
|
||||
<< page_id;
|
||||
ut_ad(0);
|
||||
space->release();
|
||||
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
|
||||
in the desired order. */
|
||||
const bool descending= page_id == low;
|
||||
const bool descending= page_id != low;
|
||||
|
||||
if (!descending && page_id != high_1)
|
||||
/* This is not a border page of the area */
|
||||
@@ -555,7 +552,7 @@ fail:
|
||||
uint32_t{buf_pool.read_ahead_area});
|
||||
page_id_t new_low= low, new_high_1= high_1;
|
||||
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());
|
||||
transactional_shared_lock_guard<page_hash_latch> g
|
||||
@@ -583,12 +580,21 @@ failed:
|
||||
if (prev == FIL_NULL || next == FIL_NULL)
|
||||
goto fail;
|
||||
page_id_t id= page_id;
|
||||
if (descending && next - 1 == page_id.page_no())
|
||||
id.set_page_no(prev);
|
||||
else if (!descending && prev + 1 == page_id.page_no())
|
||||
id.set_page_no(next);
|
||||
if (descending)
|
||||
{
|
||||
if (id == high_1)
|
||||
++id;
|
||||
else if (next - 1 != page_id.page_no())
|
||||
goto fail;
|
||||
else
|
||||
id.set_page_no(prev);
|
||||
}
|
||||
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_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 */
|
||||
count= 0;
|
||||
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))
|
||||
continue;
|
||||
@@ -649,60 +655,35 @@ failed:
|
||||
return count;
|
||||
}
|
||||
|
||||
/** @return whether a page has been freed */
|
||||
inline bool fil_space_t::is_freed(uint32_t page)
|
||||
/** Schedule a page for recovery.
|
||||
@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);
|
||||
return freed_ranges.contains(page);
|
||||
}
|
||||
|
||||
/** Issues read requests for pages which recovery wants to read in.
|
||||
@param space_id tablespace identifier
|
||||
@param page_nos page numbers to read, in ascending order */
|
||||
void buf_read_recv_pages(uint32_t space_id, st_::span<uint32_t> page_nos)
|
||||
{
|
||||
fil_space_t* space = fil_space_t::get(space_id);
|
||||
|
||||
if (!space) {
|
||||
/* The tablespace is missing or unreadable: do nothing */
|
||||
return;
|
||||
}
|
||||
|
||||
const ulint zip_size = space->zip_size();
|
||||
|
||||
for (ulint i = 0; i < page_nos.size(); i++) {
|
||||
|
||||
/* Ignore if the page already present in freed ranges. */
|
||||
if (space->is_freed(page_nos[i])) {
|
||||
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();
|
||||
ut_ad(space->id == page_id.space());
|
||||
space->reacquire();
|
||||
const ulint zip_size= space->zip_size();
|
||||
|
||||
if (init)
|
||||
{
|
||||
if (buf_page_t *bpage= buf_page_init_for_read(BUF_READ_ANY_PAGE, page_id,
|
||||
zip_size, true))
|
||||
{
|
||||
ut_ad(bpage->in_file());
|
||||
os_fake_read(IORequest{bpage, (buf_tmp_buffer_t*) &recs,
|
||||
UT_LIST_GET_FIRST(space->chain),
|
||||
IORequest::READ_ASYNC}, ptrdiff_t(init));
|
||||
}
|
||||
}
|
||||
else if (dberr_t err= buf_read_page_low(space, false, BUF_READ_ANY_PAGE,
|
||||
page_id, zip_size, true))
|
||||
{
|
||||
if (err != DB_SUCCESS_LOCKED_REC)
|
||||
sql_print_error("InnoDB: Recovery failed to read page "
|
||||
UINT32PF " from %s",
|
||||
page_id.page_no(), space->chain.start->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,17 @@ static const dict_table_schema_t table_stats_schema =
|
||||
{
|
||||
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
|
||||
{"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},
|
||||
{"clustered_index_size", 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},
|
||||
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
|
||||
{"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_value", DATA_INT, DATA_NOT_NULL | 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. */
|
||||
@@ -1953,8 +1955,8 @@ err_exit:
|
||||
FIL_TYPE_TABLESPACE,
|
||||
crypt_data, mode, 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));
|
||||
mysql_mutex_unlock(&fil_system.mutex);
|
||||
mtr.start();
|
||||
mtr.set_named_space(space);
|
||||
ut_a(fsp_header_init(space, size, &mtr) == DB_SUCCESS);
|
||||
@@ -2775,53 +2777,55 @@ func_exit:
|
||||
|
||||
#include <tpool.h>
|
||||
|
||||
/** Callback for AIO completion */
|
||||
void fil_aio_callback(const IORequest &request)
|
||||
void IORequest::write_complete() const
|
||||
{
|
||||
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);
|
||||
if (request.type == IORequest::DBLWR_BATCH)
|
||||
buf_dblwr.flush_buffered_writes_completed(request);
|
||||
if (type == IORequest::DBLWR_BATCH)
|
||||
buf_dblwr.flush_buffered_writes_completed(*this);
|
||||
else
|
||||
ut_ad(request.type == IORequest::WRITE_ASYNC);
|
||||
write_completed:
|
||||
request.node->complete_write();
|
||||
}
|
||||
else if (request.is_write())
|
||||
{
|
||||
buf_page_write_complete(request);
|
||||
goto write_completed;
|
||||
ut_ad(type == IORequest::WRITE_ASYNC);
|
||||
}
|
||||
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());
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (recv_recovery_is_on() && !srv_force_recovery)
|
||||
{
|
||||
mysql_mutex_lock(&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;
|
||||
mysql_mutex_lock(&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 '" << node->name << "': " << err;
|
||||
}
|
||||
|
||||
request.node->space->release();
|
||||
node->space->release();
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
/* The extent has become free: move it to another list */
|
||||
err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG,
|
||||
xdes, xoffset, mtr);
|
||||
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
|
||||
return err;
|
||||
}
|
||||
err = fsp_free_extent(space, offset, mtr);
|
||||
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
|
||||
return err;
|
||||
if (err == DB_SUCCESS) {
|
||||
err = fsp_free_extent(space, offset, mtr);
|
||||
}
|
||||
}
|
||||
|
||||
mtr->free(*space, static_cast<uint32_t>(offset));
|
||||
xdes_set_free<true>(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
|
||||
|
||||
return DB_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @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_evicted",
|
||||
&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_wait_free", &buf_pool.stat.LRU_waits, 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();
|
||||
}
|
||||
|
||||
static void wsrep_abort_transaction(handlerton*, THD *, THD *, my_bool);
|
||||
static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
|
||||
static void wsrep_abort_transaction(handlerton *, THD *, THD *, my_bool)
|
||||
__attribute__((nonnull));
|
||||
static int innobase_wsrep_set_checkpoint(handlerton *hton, const XID *xid);
|
||||
static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
|
||||
#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_transaction_state_str(vthd),
|
||||
wsrep_thd_query(vthd));
|
||||
/* Mark transaction as a victim for Galera abort */
|
||||
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");
|
||||
aborting= true;
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||
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
|
||||
that waiting
|
||||
*/
|
||||
lock_sys.cancel_lock_wait_for_trx(vtrx);
|
||||
|
||||
DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
|
||||
if (!wsrep_thd_bf_abort(bf_thd, vthd, true))
|
||||
if (vtrx->id == trx_id)
|
||||
{
|
||||
wsrep_thd_LOCK(vthd);
|
||||
wsrep_thd_set_wsrep_aborter(NULL, vthd);
|
||||
wsrep_thd_UNLOCK(vthd);
|
||||
|
||||
WSREP_DEBUG("wsrep_thd_bf_abort has failed, victim %lu will survive",
|
||||
thd_get_thread_id(vthd));
|
||||
switch (vtrx->state) {
|
||||
default:
|
||||
break;
|
||||
case TRX_STATE_ACTIVE:
|
||||
case TRX_STATE_PREPARED:
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
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 victim_thd victim THD to be aborted
|
||||
|
||||
@return 0 victim was aborted
|
||||
@return -1 victim thread was aborted (no transaction)
|
||||
*/
|
||||
static
|
||||
void
|
||||
wsrep_abort_transaction(
|
||||
handlerton*,
|
||||
THD *bf_thd,
|
||||
THD *victim_thd,
|
||||
my_bool signal)
|
||||
static void wsrep_abort_transaction(handlerton *, THD *bf_thd, THD *victim_thd,
|
||||
my_bool signal)
|
||||
{
|
||||
DBUG_ENTER("wsrep_abort_transaction");
|
||||
ut_ad(bf_thd);
|
||||
ut_ad(victim_thd);
|
||||
DBUG_ENTER("wsrep_abort_transaction");
|
||||
ut_ad(bf_thd);
|
||||
ut_ad(victim_thd);
|
||||
|
||||
wsrep_thd_kill_LOCK(victim_thd);
|
||||
wsrep_thd_LOCK(victim_thd);
|
||||
trx_t* victim_trx= thd_to_trx(victim_thd);
|
||||
wsrep_thd_UNLOCK(victim_thd);
|
||||
trx_t *victim_trx= thd_to_trx(victim_thd);
|
||||
|
||||
WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
|
||||
wsrep_thd_query(bf_thd),
|
||||
wsrep_thd_query(victim_thd),
|
||||
wsrep_thd_transaction_state_str(victim_thd));
|
||||
WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
|
||||
wsrep_thd_query(bf_thd), wsrep_thd_query(victim_thd),
|
||||
wsrep_thd_transaction_state_str(victim_thd));
|
||||
|
||||
if (victim_trx) {
|
||||
victim_trx->lock.set_wsrep_victim();
|
||||
if (!victim_trx)
|
||||
{
|
||||
WSREP_DEBUG("abort transaction: victim did not exist");
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
wsrep_thd_LOCK(victim_thd);
|
||||
bool aborting= !wsrep_thd_set_wsrep_aborter(bf_thd, victim_thd);
|
||||
wsrep_thd_UNLOCK(victim_thd);
|
||||
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);
|
||||
}
|
||||
lock_sys.wr_lock(SRW_LOCK_CALL);
|
||||
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||
victim_trx->mutex_lock();
|
||||
|
||||
wsrep_thd_kill_UNLOCK(victim_thd);
|
||||
DBUG_VOID_RETURN;
|
||||
switch (victim_trx->state) {
|
||||
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
|
||||
|
||||
@@ -2365,6 +2365,7 @@ tablespace_deleted:
|
||||
}
|
||||
|
||||
const ulint zip_size = s->zip_size(), size = s->size;
|
||||
s->x_lock();
|
||||
s->release();
|
||||
mtr_t mtr;
|
||||
|
||||
@@ -2382,13 +2383,17 @@ tablespace_deleted:
|
||||
|| !page_is_leaf(block->page.frame);
|
||||
mtr.commit();
|
||||
if (err == DB_TABLESPACE_DELETED) {
|
||||
s->x_unlock();
|
||||
goto tablespace_deleted;
|
||||
}
|
||||
if (!remove) {
|
||||
s->x_unlock();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
s->x_unlock();
|
||||
|
||||
if (srv_shutdown_state == SRV_SHUTDOWN_NONE
|
||||
|| srv_fast_shutdown) {
|
||||
continue;
|
||||
@@ -2417,7 +2422,7 @@ tablespace_deleted:
|
||||
/* Prevent an infinite loop, by removing entries from
|
||||
the change buffer in the case the bitmap bits were
|
||||
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);
|
||||
|
||||
if (bitmap_bits
|
||||
&& DB_SUCCESS
|
||||
if (!bitmap_bits) {
|
||||
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())) {
|
||||
ibuf_mtr_start(&mtr);
|
||||
mtr.set_named_space(space);
|
||||
ibuf_reset_bitmap(block, page_id, zip_size, &mtr);
|
||||
ibuf_mtr_commit(&mtr);
|
||||
bitmap_bits = 0;
|
||||
if (!block
|
||||
|| btr_page_get_index_id(block->page.frame)
|
||||
!= DICT_IBUF_ID_MIN + IBUF_SPACE_ID) {
|
||||
ibuf_delete_recs(page_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitmap_bits) {
|
||||
/* No changes are buffered for this page. */
|
||||
space->release();
|
||||
return DB_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,8 +75,7 @@ struct buf_pool_info_t
|
||||
ulint flush_list_len; /*!< Length of buf_pool.flush_list */
|
||||
ulint n_pend_unzip; /*!< buf_pool.n_pend_unzip, pages
|
||||
pending decompress */
|
||||
ulint n_pend_reads; /*!< buf_pool.n_pend_reads, pages
|
||||
pending read */
|
||||
ulint n_pend_reads; /*!< os_aio_pending_reads() */
|
||||
ulint n_pending_flush_lru; /*!< Pages pending flush in LRU */
|
||||
ulint n_pending_flush_list; /*!< Pages pending flush in FLUSH
|
||||
LIST */
|
||||
|
||||
@@ -102,10 +102,13 @@ which could result in a deadlock if the OS does not support asynchronous io.
|
||||
ulint
|
||||
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.
|
||||
@param space_id tablespace identifier
|
||||
@param page_nos page numbers to read, in ascending order */
|
||||
void buf_read_recv_pages(uint32_t space_id, st_::span<uint32_t> page_nos);
|
||||
/** Schedule a page for recovery.
|
||||
@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);
|
||||
|
||||
/** @name Modes used in read-ahead @{ */
|
||||
/** read only pages belonging to the insert buffer tree */
|
||||
|
||||
@@ -638,8 +638,6 @@ public:
|
||||
/** Close all tablespace files at shutdown */
|
||||
static void close_all();
|
||||
|
||||
/** @return last_freed_lsn */
|
||||
lsn_t get_last_freed_lsn() { return last_freed_lsn; }
|
||||
/** Update last_freed_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 */
|
||||
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 */
|
||||
|
||||
@@ -38,9 +38,9 @@ Created 9/20/1997 Heikki Tuuri
|
||||
#define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on)
|
||||
|
||||
ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||
/** Apply any buffered redo log to a page that was just read from a data file.
|
||||
@param[in,out] space tablespace
|
||||
@param[in,out] bpage buffer pool page
|
||||
/** Apply any buffered redo log to a page.
|
||||
@param space tablespace
|
||||
@param bpage buffer pool page
|
||||
@return whether the page was recovered correctly */
|
||||
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 */
|
||||
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.
|
||||
@param[in] space_id tablespace identifier
|
||||
@param[in] type file operation redo log type
|
||||
@@ -125,21 +114,15 @@ struct recv_dblwr_t
|
||||
list pages;
|
||||
};
|
||||
|
||||
/** the recovery state and buffered records for a page */
|
||||
/** recv_sys.pages entry; protected by recv_sys.mutex */
|
||||
struct page_recv_t
|
||||
{
|
||||
/** Recovery state; protected by recv_sys.mutex */
|
||||
enum
|
||||
{
|
||||
/** not yet processed */
|
||||
RECV_NOT_PROCESSED,
|
||||
/** not processed; the page will be reinitialized */
|
||||
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;
|
||||
/** Recovery status: 0=not in progress, 1=log is being applied,
|
||||
-1=log has been applied and the entry may be erased.
|
||||
Transitions from 1 to -1 are NOT protected by recv_sys.mutex. */
|
||||
Atomic_relaxed<int8_t> being_processed{0};
|
||||
/** Whether reading the page will be skipped */
|
||||
bool skip_read= false;
|
||||
/** Latest written byte offset when applying the log records.
|
||||
@see mtr_t::m_last_offset */
|
||||
uint16_t last_offset= 1;
|
||||
@@ -162,6 +145,9 @@ struct page_recv_t
|
||||
head= 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 */
|
||||
const log_rec_t* last() const { return tail; }
|
||||
@@ -180,8 +166,8 @@ struct page_recv_t
|
||||
iterator begin() { return head; }
|
||||
iterator end() { return NULL; }
|
||||
bool empty() const { ut_ad(!head == !tail); return !head; }
|
||||
/** Clear and free the records; @see recv_sys_t::alloc() */
|
||||
inline void clear();
|
||||
/** Clear and free the records; @see recv_sys_t::add() */
|
||||
void clear();
|
||||
} log;
|
||||
|
||||
/** Trim old log records for a page.
|
||||
@@ -190,21 +176,27 @@ struct page_recv_t
|
||||
inline bool trim(lsn_t start_lsn);
|
||||
/** Ignore any earlier redo log records for this page. */
|
||||
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 */
|
||||
struct recv_sys_t
|
||||
{
|
||||
/** mutex protecting apply_log_recs and page_recv_t::state */
|
||||
mysql_mutex_t mutex;
|
||||
using init= recv_init;
|
||||
|
||||
/** mutex protecting this as well as some of page_recv_t */
|
||||
alignas(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex;
|
||||
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
|
||||
log parsing buffer overflow */
|
||||
bool found_corrupt_log;
|
||||
@@ -226,6 +218,8 @@ public:
|
||||
size_t offset;
|
||||
/** log sequence number of the first non-parsed record */
|
||||
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 */
|
||||
lsn_t file_checkpoint;
|
||||
/** the time when progress was last reported */
|
||||
@@ -238,6 +232,9 @@ public:
|
||||
map pages;
|
||||
|
||||
private:
|
||||
/** iterator to pages, used by parse() */
|
||||
map::iterator pages_it;
|
||||
|
||||
/** Process a record that indicates that a tablespace size is being shrunk.
|
||||
@param page_id first page that is not in the file
|
||||
@param lsn log sequence number of the shrink operation */
|
||||
@@ -257,30 +254,42 @@ public:
|
||||
/** The contents of the doublewrite buffer */
|
||||
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 size_t files_size();
|
||||
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:
|
||||
/** Attempt to initialize a page based on redo log records.
|
||||
@param page_id page identifier
|
||||
@param p iterator pointing to page_id
|
||||
@param p iterator
|
||||
@param mtr mini-transaction
|
||||
@param b pre-allocated buffer pool block
|
||||
@param init page initialization
|
||||
@return the recovered block
|
||||
@retval nullptr if the page cannot be initialized based on log records
|
||||
@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,
|
||||
mtr_t &mtr, buf_block_t *b);
|
||||
inline buf_block_t *recover_low(const map::iterator &p, mtr_t &mtr,
|
||||
buf_block_t *b, init &init);
|
||||
/** Attempt to initialize a page based on redo log records.
|
||||
@param page_id page identifier
|
||||
@return the recovered block
|
||||
@retval nullptr if the page cannot be initialized based on log records
|
||||
@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
|
||||
from before MariaDB Server 10.5.1) */
|
||||
@@ -289,10 +298,27 @@ private:
|
||||
/** Base node of the redo block list.
|
||||
List elements are linked via buf_block_t::unzip_LRU. */
|
||||
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:
|
||||
/** 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.
|
||||
@param last_batch whether it is possible to write more redo log */
|
||||
void apply(bool last_batch);
|
||||
@@ -310,7 +336,7 @@ public:
|
||||
/** Clean up after create() */
|
||||
void close();
|
||||
|
||||
bool is_initialised() const { return last_stored_lsn != 0; }
|
||||
bool is_initialised() const { return scanned_lsn != 0; }
|
||||
|
||||
/** Find the latest checkpoint.
|
||||
@return error code or DB_SUCCESS */
|
||||
@@ -321,60 +347,76 @@ public:
|
||||
@param start_lsn start LSN of the mini-transaction
|
||||
@param lsn @see mtr_t::commit_lsn()
|
||||
@param l redo log snippet
|
||||
@param len length of l, in bytes */
|
||||
inline void add(map::iterator it, lsn_t start_lsn, lsn_t lsn,
|
||||
const byte *l, size_t len);
|
||||
@param len length of l, in bytes
|
||||
@return whether we ran out of memory */
|
||||
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:
|
||||
/** Parse and register one log_t::FORMAT_10_8 mini-transaction.
|
||||
@param store whether to store the records
|
||||
@param l log data source */
|
||||
@tparam store whether to store the records
|
||||
@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>
|
||||
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:
|
||||
/** Parse and register one log_t::FORMAT_10_8 mini-transaction,
|
||||
handling log_sys.is_pmem() buffer wrap-around.
|
||||
@param store whether to store the records */
|
||||
static parse_mtr_result parse_mtr(store_t store) noexcept;
|
||||
@tparam store whether to store the records
|
||||
@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,
|
||||
handling log_sys.is_pmem() buffer wrap-around.
|
||||
@param store whether to store the records */
|
||||
static parse_mtr_result parse_pmem(store_t store) noexcept
|
||||
@tparam store whether to store the records
|
||||
@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
|
||||
;
|
||||
#else
|
||||
{ return parse_mtr(store); }
|
||||
{ return parse_mtr<store>(if_exists); }
|
||||
#endif
|
||||
|
||||
/** Erase log records for a page. */
|
||||
void erase(map::iterator p);
|
||||
|
||||
/** Clear a fully processed set of stored redo log records. */
|
||||
inline void clear();
|
||||
void clear();
|
||||
|
||||
/** Determine whether redo log recovery progress should be reported.
|
||||
@param time the current time
|
||||
@return whether progress should be reported
|
||||
(the last report was at least 15 seconds ago) */
|
||||
bool report(time_t time)
|
||||
{
|
||||
if (time - progress_time < 15)
|
||||
return false;
|
||||
|
||||
progress_time= time;
|
||||
return true;
|
||||
}
|
||||
bool report(time_t time);
|
||||
|
||||
/** The alloc() memory alignment, in bytes */
|
||||
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.
|
||||
@param data buffer returned by alloc() */
|
||||
@param data buffer allocated in add() */
|
||||
inline void free(const void *data);
|
||||
|
||||
/** Remove records for a corrupted page.
|
||||
@@ -386,8 +428,6 @@ public:
|
||||
ATTRIBUTE_COLD void set_corrupt_fs();
|
||||
/** Flag log file corruption during recovery. */
|
||||
ATTRIBUTE_COLD void set_corrupt_log();
|
||||
/** Possibly finish a recovery batch. */
|
||||
inline void maybe_finish_batch();
|
||||
|
||||
/** @return whether data file corruption was found */
|
||||
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
|
||||
@param p iterator, initially pointing to page_id_t{space_id,0};
|
||||
the records will be freed and the iterator advanced
|
||||
@param p iterator
|
||||
@param name tablespace file name
|
||||
@param free_block spare buffer block
|
||||
@return whether recovery failed */
|
||||
bool recover_deferred(map::iterator &p, const std::string &name,
|
||||
buf_block_t *&free_block);
|
||||
@return recovered tablespace
|
||||
@retval nullptr if recovery failed */
|
||||
fil_space_t *recover_deferred(const map::iterator &p,
|
||||
const std::string &name,
|
||||
buf_block_t *&free_block);
|
||||
};
|
||||
|
||||
/** The recovery system */
|
||||
|
||||
@@ -212,6 +212,10 @@ public:
|
||||
bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_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.
|
||||
@param off byte offset from the start (SEEK_SET)
|
||||
@param len size of the hole in bytes
|
||||
@@ -1040,6 +1044,11 @@ int os_aio_init();
|
||||
Frees the asynchronous io system. */
|
||||
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.
|
||||
@param type I/O request
|
||||
@param buf buffer
|
||||
|
||||
@@ -617,6 +617,8 @@ struct export_var_t{
|
||||
#ifdef UNIV_DEBUG
|
||||
ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */
|
||||
#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_max_age;
|
||||
ulint innodb_data_pending_reads; /*!< Pending reads */
|
||||
|
||||
@@ -1055,7 +1055,7 @@ public:
|
||||
void close();
|
||||
|
||||
/** @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,
|
||||
mtr_t *mtr, dberr_t *err)
|
||||
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.
|
||||
@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 */
|
||||
template <bool from_deadlock= false>
|
||||
template <bool from_deadlock= false, bool inner_trx_lock= true>
|
||||
void lock_cancel_waiting_and_release(lock_t *lock)
|
||||
{
|
||||
lock_sys.assert_locked(*lock);
|
||||
mysql_mutex_assert_owner(&lock_sys.wait_mutex);
|
||||
trx_t *trx= lock->trx;
|
||||
trx->mutex_lock();
|
||||
if (inner_trx_lock)
|
||||
trx->mutex_lock();
|
||||
ut_d(const auto trx_state= trx->state);
|
||||
ut_ad(trx_state == TRX_STATE_COMMITTED_IN_MEMORY ||
|
||||
trx_state == TRX_STATE_ACTIVE);
|
||||
@@ -5762,7 +5763,8 @@ void lock_cancel_waiting_and_release(lock_t *lock)
|
||||
|
||||
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)
|
||||
@@ -5779,6 +5781,19 @@ void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
|
||||
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.
|
||||
@tparam check_victim whether to check for DB_DEADLOCK
|
||||
@param trx active transaction
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3427,15 +3427,12 @@ os_file_get_status(
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
extern void fil_aio_callback(const IORequest &request);
|
||||
|
||||
static void io_callback(tpool::aiocb *cb)
|
||||
static void io_callback_errorcheck(const tpool::aiocb *cb)
|
||||
{
|
||||
const IORequest &request= *static_cast<const IORequest*>
|
||||
(static_cast<const void*>(cb->m_userdata));
|
||||
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 " <<
|
||||
(request.is_async() ? "async " : "sync ") <<
|
||||
(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 " <<
|
||||
cb->m_ret_len;
|
||||
}
|
||||
/* Return cb back to cache*/
|
||||
if (cb->m_opcode == tpool::aio_opcode::AIO_PREAD)
|
||||
{
|
||||
ut_ad(read_slots->contains(cb));
|
||||
fil_aio_callback(request);
|
||||
read_slots->release(cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
ut_ad(write_slots->contains(cb));
|
||||
fil_aio_callback(request);
|
||||
write_slots->release(cb);
|
||||
}
|
||||
}
|
||||
|
||||
static void fake_io_callback(void *c)
|
||||
{
|
||||
tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
|
||||
ut_ad(read_slots->contains(cb));
|
||||
static_cast<const IORequest*>(static_cast<const void*>(cb->m_userdata))->
|
||||
fake_read_complete(cb->m_offset);
|
||||
read_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
|
||||
@@ -3758,6 +3772,28 @@ void os_aio_wait_until_no_pending_reads(bool declare)
|
||||
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.
|
||||
@param type I/O request
|
||||
@param buf buffer
|
||||
@@ -3803,23 +3839,32 @@ func_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
io_slots* slots;
|
||||
tpool::callback_func callback;
|
||||
tpool::aio_opcode opcode;
|
||||
|
||||
if (type.is_read()) {
|
||||
++os_n_file_reads;
|
||||
slots = read_slots;
|
||||
callback = read_io_callback;
|
||||
opcode = tpool::aio_opcode::AIO_PREAD;
|
||||
} else {
|
||||
++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);
|
||||
io_slots* slots= type.is_read() ? read_slots : write_slots;
|
||||
tpool::aiocb* cb = slots->acquire();
|
||||
|
||||
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_fh = type.node->handle.m_file;
|
||||
cb->m_len = (int)n;
|
||||
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};
|
||||
|
||||
if (srv_thread_pool->submit_io(cb)) {
|
||||
@@ -3827,6 +3872,7 @@ func_exit:
|
||||
os_file_handle_error(type.node->name, type.is_read()
|
||||
? "aio read" : "aio write");
|
||||
err = DB_IO_ERROR;
|
||||
type.node->space->release();
|
||||
}
|
||||
|
||||
goto func_exit;
|
||||
|
||||
@@ -214,14 +214,14 @@ row_ins_sec_index_entry_by_modify(
|
||||
made to the clustered index, and completed the
|
||||
secondary index creation before we got here. In this
|
||||
case, the change would already be there. The CREATE
|
||||
INDEX should be waiting for a MySQL meta-data lock
|
||||
upgrade at least until this INSERT or UPDATE
|
||||
returns. After that point, set_committed(true)
|
||||
would be invoked in commit_inplace_alter_table(). */
|
||||
INDEX should be in wait_while_table_is_used() at least
|
||||
until this INSERT or UPDATE returns. After that point,
|
||||
set_committed(true) would be invoked in
|
||||
commit_inplace_alter_table(). */
|
||||
ut_a(update->n_fields == 0);
|
||||
ut_a(!cursor->index()->is_committed());
|
||||
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) {
|
||||
|
||||
@@ -615,6 +615,8 @@ row_purge_del_mark(
|
||||
const auto type= node->index->type;
|
||||
if (type & (DICT_FTS | DICT_CORRUPT))
|
||||
continue;
|
||||
if (node->index->online_status > ONLINE_INDEX_CREATION)
|
||||
continue;
|
||||
if (UNIV_UNLIKELY(DICT_VIRTUAL & type) && !node->index->is_committed() &&
|
||||
node->index->has_new_v_col())
|
||||
continue;
|
||||
@@ -767,6 +769,11 @@ row_purge_upd_exist_or_extern_func(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->index->online_status
|
||||
> ONLINE_INDEX_CREATION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (row_upd_changes_ord_field_binary(node->index, node->update,
|
||||
thr, NULL, NULL)) {
|
||||
/* Build the older version of the index entry */
|
||||
|
||||
@@ -674,7 +674,7 @@ static monitor_info_t innodb_counter_info[] =
|
||||
{"trx_rseg_history_len", "transaction",
|
||||
"Length of the TRX_RSEG_HISTORY list",
|
||||
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},
|
||||
|
||||
{"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