1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge 10.1 into 10.2

This commit is contained in:
Marko Mäkelä
2017-12-13 23:14:15 +02:00
36 changed files with 623 additions and 251 deletions

View File

@@ -166,8 +166,8 @@ static struct my_option my_long_options[]=
"server with which it was built/distributed.",
&opt_version_check, &opt_version_check, 0,
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"write-binlog", OPT_WRITE_BINLOG, "All commands including those, "
"issued by mysqlcheck, are written to the binary log.",
{"write-binlog", OPT_WRITE_BINLOG, "All commands including those "
"issued by mysqlcheck are written to the binary log.",
&opt_write_binlog, &opt_write_binlog, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}

View File

@@ -63,6 +63,12 @@ typedef struct st_mysql_lex_string LEX_STRING;
/* NO and OK is the same used just to show semantics */
#define ER_DYNCOL_NO ER_DYNCOL_OK
#ifdef HAVE_CHARSET_utf8mb4
#define DYNCOL_UTF (&my_charset_utf8mb4_general_ci)
#else
#define DYNCOL_UTF (&my_charset_utf8_general_ci)
#endif
enum enum_dyncol_func_result
{
ER_DYNCOL_OK= 0,

View File

@@ -691,8 +691,7 @@ it was built/distributed. Defaults to on; use \fB\-\-skip\-version\-check\fR to
.sp
Cause binary logging to be enabled while
\fBmysql_upgrade\fR
runs\&. This is the default behavior; to disable binary logging during the upgrade, use the inverse of this option (that is, start the program with
\fB\-\-skip\-write\-binlog\fR)\&.
runs\&.
.RE
.SH "COPYRIGHT"
.br

View File

@@ -10272,6 +10272,21 @@ DROP TABLE allbytes;
SET sql_mode = DEFAULT;
# End of ctype_backslash.inc
#
# MDEV-12681 Wrong VIEW results for CHAR(0xDF USING latin1)
#
SET NAMES utf8;
SELECT CHAR(0xDF USING latin1);
CHAR(0xDF USING latin1)
ß
CREATE OR REPLACE VIEW v1 AS SELECT CHAR(0xDF USING latin1) AS c;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select char(0xdf using latin1) AS `c` utf8 utf8_general_ci
SELECT * FROM v1;
c
ß
DROP VIEW v1;
#
# End of 10.0 tests
#
#

View File

@@ -3430,6 +3430,32 @@ a b
a 😁 b a ? b
DROP TABLE t1;
#
# MDEV-8949: COLUMN_CREATE unicode name breakage
#
SET NAMES utf8mb4;
SELECT COLUMN_JSON(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1));
COLUMN_JSON(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1))
{"😎":1}
SELECT COLUMN_LIST(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1));
COLUMN_LIST(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1))
`😎`
SELECT COLUMN_GET(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1), _utf8mb4 0xF09F988E
as int);
COLUMN_GET(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1), _utf8mb4 0xF09F988E
as int)
1
CREATE TABLE t1 AS SELECT
COLUMN_LIST(COLUMN_CREATE('a',1)),
COLUMN_JSON(COLUMN_CREATE('b',1));
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`COLUMN_LIST(COLUMN_CREATE('a',1))` longtext CHARACTER SET utf8mb4 DEFAULT NULL,
`COLUMN_JSON(COLUMN_CREATE('b',1))` longtext CHARACTER SET utf8mb4 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
SET NAMES default;
#
# End of 10.0 tests
#
#

View File

@@ -4556,6 +4556,27 @@ set global max_allowed_packet=default;
# End of 5.6 tests
#
#
# Start of 10.0 tests
#
#
# MDEV-12681 Wrong VIEW results for CHAR(0xDF USING latin1)
#
EXPLAIN EXTENDED SELECT CHAR(0xDF USING latin1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select char(0xdf using latin1) AS `CHAR(0xDF USING latin1)`
EXPLAIN EXTENDED SELECT CHAR(0xDF USING `binary`);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select char(0xdf) AS `CHAR(0xDF USING ``binary``)`
EXPLAIN EXTENDED SELECT CHAR(0xDF);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select char(0xdf) AS `CHAR(0xDF)`
#
# Start of 10.1 tests
#
#

View File

@@ -0,0 +1,64 @@
#
# MDEV-13797 InnoDB may hang if shutdown is initiated soon after startup
# while rolling back recovered incomplete transactions
#
CREATE TABLE t (a INT) ENGINE=InnoDB;
BEGIN;
COMMIT;
connect con$c,localhost,root,,;
CREATE TABLE t8 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t8 (a) SELECT NULL FROM t;
UPDATE t8 SET a=a+100, b=a;
DELETE FROM t8;
connect con$c,localhost,root,,;
CREATE TABLE t7 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t7 (a) SELECT NULL FROM t;
UPDATE t7 SET a=a+100, b=a;
DELETE FROM t7;
connect con$c,localhost,root,,;
CREATE TABLE t6 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t6 (a) SELECT NULL FROM t;
UPDATE t6 SET a=a+100, b=a;
DELETE FROM t6;
connect con$c,localhost,root,,;
CREATE TABLE t5 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t5 (a) SELECT NULL FROM t;
UPDATE t5 SET a=a+100, b=a;
DELETE FROM t5;
connect con$c,localhost,root,,;
CREATE TABLE t4 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t4 (a) SELECT NULL FROM t;
UPDATE t4 SET a=a+100, b=a;
DELETE FROM t4;
connect con$c,localhost,root,,;
CREATE TABLE t3 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t3 (a) SELECT NULL FROM t;
UPDATE t3 SET a=a+100, b=a;
DELETE FROM t3;
connect con$c,localhost,root,,;
CREATE TABLE t2 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t2 (a) SELECT NULL FROM t;
UPDATE t2 SET a=a+100, b=a;
DELETE FROM t2;
connect con$c,localhost,root,,;
CREATE TABLE t1 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 (a) SELECT NULL FROM t;
UPDATE t1 SET a=a+100, b=a;
DELETE FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t;
INSERT INTO t1(a) SELECT NULL FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t1;
connection default;
SET GLOBAL innodb_flush_log_at_trx_commit=1;
CREATE TABLE u(a SERIAL) ENGINE=INNODB;
DROP TABLE t,u;

View File

@@ -0,0 +1,59 @@
--source include/have_innodb.inc
--source include/not_embedded.inc
--echo #
--echo # MDEV-13797 InnoDB may hang if shutdown is initiated soon after startup
--echo # while rolling back recovered incomplete transactions
--echo #
CREATE TABLE t (a INT) ENGINE=InnoDB;
let $size = 100;
let $trx = 8;
let $c = $size;
BEGIN;
--disable_query_log
while ($c) {
INSERT INTO t VALUES();
dec $c;
}
--enable_query_log
COMMIT;
let $c = $trx;
while ($c)
{
connect (con$c,localhost,root,,);
eval CREATE TABLE t$c (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
BEGIN;
eval INSERT INTO t$c (a) SELECT NULL FROM t;
eval UPDATE t$c SET a=a+$size, b=a;
eval DELETE FROM t$c;
dec $c;
}
INSERT INTO t1(a) SELECT NULL FROM t;
INSERT INTO t1(a) SELECT NULL FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t1;
INSERT INTO t1(a) SELECT NULL FROM t1;
--connection default
SET GLOBAL innodb_flush_log_at_trx_commit=1;
CREATE TABLE u(a SERIAL) ENGINE=INNODB;
--let $shutdown_timeout=0
--source include/restart_mysqld.inc
--let $shutdown_timeout=60
--source include/restart_mysqld.inc
--disable_query_log
let $c = $trx;
while ($c)
{
disconnect con$c;
eval DROP TABLE t$c;
dec $c;
}
--enable_query_log
DROP TABLE t,u;

View File

@@ -1 +1 @@
--innodb-open-files=13
--innodb-open-files=20

View File

@@ -1878,6 +1878,18 @@ SELECT _utf8 0x7E, _utf8 X'7E', _utf8 B'01111110';
let $ctype_unescape_combinations=selected;
--source include/ctype_unescape.inc
--echo #
--echo # MDEV-12681 Wrong VIEW results for CHAR(0xDF USING latin1)
--echo #
SET NAMES utf8;
SELECT CHAR(0xDF USING latin1);
CREATE OR REPLACE VIEW v1 AS SELECT CHAR(0xDF USING latin1) AS c;
SHOW CREATE VIEW v1;
SELECT * FROM v1;
DROP VIEW v1;
--echo #
--echo # End of 10.0 tests
--echo #

View File

@@ -1922,6 +1922,24 @@ INSERT IGNORE INTO t1 SELECT 'a 😁 b', 'a 😁 b';
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # MDEV-8949: COLUMN_CREATE unicode name breakage
--echo #
SET NAMES utf8mb4;
SELECT COLUMN_JSON(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1));
SELECT COLUMN_LIST(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1));
SELECT COLUMN_GET(COLUMN_CREATE(_utf8mb4 0xF09F988E, 1), _utf8mb4 0xF09F988E
as int);
CREATE TABLE t1 AS SELECT
COLUMN_LIST(COLUMN_CREATE('a',1)),
COLUMN_JSON(COLUMN_CREATE('b',1));
SHOW CREATE TABLE t1;
DROP TABLE t1;
SET NAMES default;
--echo #
--echo # End of 10.0 tests
--echo #

View File

@@ -1756,6 +1756,18 @@ set global max_allowed_packet=default;
--echo # End of 5.6 tests
--echo #
--echo #
--echo # Start of 10.0 tests
--echo #
--echo #
--echo # MDEV-12681 Wrong VIEW results for CHAR(0xDF USING latin1)
--echo #
EXPLAIN EXTENDED SELECT CHAR(0xDF USING latin1);
EXPLAIN EXTENDED SELECT CHAR(0xDF USING `binary`);
EXPLAIN EXTENDED SELECT CHAR(0xDF);
--echo #
--echo # Start of 10.1 tests
--echo #
@@ -1800,7 +1812,6 @@ SELECT f1,HEX(f2) FROM t1 WHERE f1='YQ==' AND (f2= from_base64(
SELECT f1,HEX(f2) FROM t1 WHERE f1='YQ==' AND (f2= from_base64("Yq==") OR f2= from_base64("YQ=="));
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #

View File

@@ -4183,8 +4183,7 @@ mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json,
}
else
{
if ((rc= mariadb_dyncol_val_str(json, &val,
&my_charset_utf8_general_ci, '"')) < 0)
if ((rc= mariadb_dyncol_val_str(json, &val, DYNCOL_UTF, '"')) < 0)
goto err;
}
}

View File

@@ -273,7 +273,7 @@ void thr_end_alarm(thr_alarm_t *alarmed)
/*
Come here when some alarm in queue is due.
Mark all alarms with are finnished in list.
Shedule alarms to be sent again after 1-10 sec (many alarms at once)
Schedule alarms to be sent again after 1-10 sec (many alarms at once)
If alarm_aborted is set then all alarms are given and resent
every second.
*/
@@ -425,7 +425,7 @@ void end_thr_alarm(my_bool free_structures)
if (alarm_aborted != 1) /* If memory not freed */
{
mysql_mutex_lock(&LOCK_alarm);
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
DBUG_PRINT("info",("Rescheduling %d waiting alarms",alarm_queue.elements));
alarm_aborted= -1; /* mark aborted */
if (alarm_queue.elements || (alarm_thread_running && free_structures))
{

View File

@@ -6976,20 +6976,20 @@ longlong Item_func_dyncol_exists::val_int()
null_value= 1;
return 1;
}
if (my_charset_same(nm->charset(), &my_charset_utf8_general_ci))
if (my_charset_same(nm->charset(), DYNCOL_UTF))
{
buf.str= (char *) nm->ptr();
buf.length= nm->length();
}
else
{
uint strlen= nm->length() * my_charset_utf8_general_ci.mbmaxlen + 1;
uint strlen= nm->length() * DYNCOL_UTF->mbmaxlen + 1;
uint dummy_errors;
buf.str= (char *) current_thd->alloc(strlen);
if (buf.str)
{
buf.length=
copy_and_convert(buf.str, strlen, &my_charset_utf8_general_ci,
copy_and_convert(buf.str, strlen, DYNCOL_UTF,
nm->ptr(), nm->length(), nm->charset(),
&dummy_errors);
}

View File

@@ -2834,6 +2834,20 @@ String *Item_func_make_set::val_str(String *str)
}
void Item_func_char::print(String *str, enum_query_type query_type)
{
str->append(Item_func_char::func_name());
str->append('(');
print_args(str, 0, query_type);
if (collation.collation != &my_charset_bin)
{
str->append(C_STRING_WITH_LEN(" using "));
str->append(collation.collation->csname);
}
str->append(')');
}
String *Item_func_char::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -4412,20 +4426,19 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
if (res)
{
// guaranty UTF-8 string for names
if (my_charset_same(res->charset(), &my_charset_utf8_general_ci))
if (my_charset_same(res->charset(), DYNCOL_UTF))
{
keys_str[i].length= res->length();
keys_str[i].str= thd->strmake(res->ptr(), res->length());
}
else
{
uint strlen= res->length() * my_charset_utf8_general_ci.mbmaxlen + 1;
uint strlen= res->length() * DYNCOL_UTF->mbmaxlen + 1;
uint dummy_errors;
char *str= (char *) thd->alloc(strlen);
if (str)
if (char *str= (char *) thd->alloc(strlen))
{
keys_str[i].length=
copy_and_convert(str, strlen, &my_charset_utf8_general_ci,
copy_and_convert(str, strlen, DYNCOL_UTF,
res->ptr(), res->length(), res->charset(),
&dummy_errors);
keys_str[i].str= str;
@@ -4645,9 +4658,10 @@ String *Item_func_dyncol_json::val_str(String *str)
char *ptr;
size_t length, alloc_length;
dynstr_reassociate(&json, &ptr, &length, &alloc_length);
str->reset(ptr, length, alloc_length, &my_charset_utf8_general_ci);
str->reset(ptr, length, alloc_length, DYNCOL_UTF);
null_value= FALSE;
}
str->set_charset(DYNCOL_UTF);
return str;
null:
@@ -4747,20 +4761,20 @@ bool Item_dyncol_get::get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val,
return 1;
}
if (my_charset_same(nm->charset(), &my_charset_utf8_general_ci))
if (my_charset_same(nm->charset(), DYNCOL_UTF))
{
buf.str= (char *) nm->ptr();
buf.length= nm->length();
}
else
{
uint strlen= nm->length() * my_charset_utf8_general_ci.mbmaxlen + 1;
uint strlen= nm->length() * DYNCOL_UTF->mbmaxlen + 1;
uint dummy_errors;
buf.str= (char *) thd->alloc(strlen);
if (buf.str)
{
buf.length=
copy_and_convert(buf.str, strlen, &my_charset_utf8_general_ci,
copy_and_convert(buf.str, strlen, DYNCOL_UTF,
nm->ptr(), nm->length(), nm->charset(),
&dummy_errors);
}
@@ -5184,7 +5198,6 @@ String *Item_func_dyncol_list::val_str(String *str)
goto null;
str->length(0);
str->set_charset(&my_charset_utf8_general_ci);
for (i= 0; i < count; i++)
{
append_identifier(current_thd, str, names[i].str, names[i].length);
@@ -5194,6 +5207,7 @@ String *Item_func_dyncol_list::val_str(String *str)
null_value= FALSE;
if (names)
my_free(names);
str->set_charset(DYNCOL_UTF);
return str;
null:

View File

@@ -870,6 +870,7 @@ public:
max_length= arg_count * 4;
}
const char *func_name() const { return "char"; }
void print(String *str, enum_query_type query_type);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_char>(thd, mem_root, this); }
};
@@ -1431,14 +1432,14 @@ public:
class Item_func_dyncol_json: public Item_str_func
{
public:
Item_func_dyncol_json(THD *thd, Item *str): Item_str_func(thd, str) {}
Item_func_dyncol_json(THD *thd, Item *str): Item_str_func(thd, str)
{collation.set(DYNCOL_UTF);}
const char *func_name() const{ return "column_json"; }
String *val_str(String *);
void fix_length_and_dec()
{
max_length= MAX_BLOB_WIDTH;
maybe_null= 1;
collation.set(&my_charset_bin);
decimals= 0;
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
@@ -1491,7 +1492,8 @@ public:
class Item_func_dyncol_list: public Item_str_func
{
public:
Item_func_dyncol_list(THD *thd, Item *str): Item_str_func(thd, str) {};
Item_func_dyncol_list(THD *thd, Item *str): Item_str_func(thd, str)
{collation.set(DYNCOL_UTF);}
void fix_length_and_dec() { maybe_null= 1; max_length= MAX_BLOB_WIDTH; };
const char *func_name() const{ return "column_list"; }
String *val_str(String *);

View File

@@ -3866,8 +3866,7 @@ innobase_init(
/* Currently, Galera does not support VATS lock schedule algorithm. */
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& global_system_variables.wsrep_on) {
ib::info() << "In Galera environment Variance-Aware-Transaction-Sheduling Algorithm"
" is not supported. Falling back to First-Come-First-Served order. ";
ib::info() << "For Galera, using innodb_lock_schedule_algorithm=fcfs";
innodb_lock_schedule_algorithm = INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS;
}
#endif /* WITH_WSREP */

View File

@@ -380,9 +380,6 @@ struct que_thr_t{
UT_LIST_NODE_T(que_thr_t)
thrs; /*!< list of thread nodes of the fork
node */
UT_LIST_NODE_T(que_thr_t)
trx_thrs; /*!< lists of threads in wait list of
the trx */
UT_LIST_NODE_T(que_thr_t)
queue; /*!< list of runnable thread nodes in
the server task queue */

View File

@@ -34,6 +34,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0sys.h"
extern bool trx_rollback_or_clean_is_active;
extern const trx_t* trx_roll_crash_recv_trx;
/*******************************************************************//**
Determines if this transaction is rolling back an incomplete transaction
@@ -62,6 +63,10 @@ trx_undo_rec_t*
trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Report progress when rolling back a row of a recovered transaction.
@return whether the rollback should be aborted due to pending shutdown */
bool
trx_roll_must_shutdown();
/*******************************************************************//**
Rollback or clean up any incomplete transactions which were
encountered in crash recovery. If the transaction already was

View File

@@ -1178,7 +1178,16 @@ close_table:
if (!row_undo_search_clust_to_pcur(node)) {
/* As long as this rolling-back transaction exists,
the PRIMARY KEY value pointed to by the undo log
record must exist. But, it is possible that the record
record should exist.
However, if InnoDB is killed during a rollback, or
shut down during the rollback of recovered
transactions, then after restart we may try to roll
back some of the same undo log records again, because
trx_roll_try_truncate() is not being invoked after
every undo log record.
It is also possible that the record
was not modified yet (the DB_ROLL_PTR does not match
node->roll_ptr) and thus there is nothing to roll back.
@@ -1186,8 +1195,11 @@ close_table:
record after successfully acquiring an exclusive lock
on the the clustered index record. That lock will not
be released before the transaction is committed or
fully rolled back. */
ut_ad(node->pcur.btr_cur.low_match == node->ref->n_fields);
fully rolled back. (Exception: if the server was
killed, restarted, and shut down again before the
rollback of the recovered transaction was completed,
it is possible that the transaction was partially
rolled back and locks released.) */
goto close_table;
}

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 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
@@ -339,6 +340,13 @@ row_undo_step(
ut_ad(que_node_get_type(node) == QUE_NODE_UNDO);
if (UNIV_UNLIKELY(trx == trx_roll_crash_recv_trx)
&& trx_roll_must_shutdown()) {
/* Shutdown has been initiated. */
trx->error_state = DB_INTERRUPTED;
return(NULL);
}
err = row_undo(node, thr);
trx->error_state = err;

View File

@@ -2633,8 +2633,6 @@ files_checked:
trx_temp_rseg_create();
}
srv_is_being_started = false;
ut_a(trx_purge_state() == PURGE_STATE_INIT);
/* Create the master thread which does purge and other utility
@@ -2683,6 +2681,8 @@ files_checked:
purge_sys->state = PURGE_STATE_DISABLED;
}
srv_is_being_started = false;
if (!srv_read_only_mode) {
/* wake main loop of page cleaner up */
os_event_set(buf_flush_event);

View File

@@ -24,8 +24,10 @@ Transaction rollback
Created 3/26/1996 Heikki Tuuri
*******************************************************/
#include "ha_prototypes.h"
#include "my_config.h"
#include <my_systemd.h>
#include "ha_prototypes.h"
#include "trx0roll.h"
#include <mysql/service_wsrep.h>
@@ -56,14 +58,7 @@ static const ulint TRX_ROLL_TRUNC_THRESHOLD = 1;
bool trx_rollback_or_clean_is_active;
/** In crash recovery, the current trx to be rolled back; NULL otherwise */
static const trx_t* trx_roll_crash_recv_trx = NULL;
/** In crash recovery we set this to the undo n:o of the current trx to be
rolled back. Then we can print how many % the rollback has progressed. */
static undo_no_t trx_roll_max_undo_no;
/** Auxiliary variable which tells the previous progress % we printed */
static ulint trx_roll_progress_printed_pct;
const trx_t* trx_roll_crash_recv_trx;
/****************************************************************//**
Finishes a transaction rollback. */
@@ -631,8 +626,6 @@ trx_rollback_active(
que_thr_t* thr;
roll_node_t* roll_node;
dict_table_t* table;
int64_t rows_to_undo;
const char* unit = "";
ibool dictionary_locked = FALSE;
heap = mem_heap_create(512);
@@ -651,28 +644,8 @@ trx_rollback_active(
ut_a(thr == que_fork_start_command(fork));
trx_sys_mutex_enter();
trx_roll_crash_recv_trx = trx;
trx_roll_max_undo_no = trx->undo_no;
trx_roll_progress_printed_pct = 0;
rows_to_undo = trx_roll_max_undo_no;
trx_sys_mutex_exit();
if (rows_to_undo > 1000000000) {
rows_to_undo = rows_to_undo / 1000000;
unit = "M";
}
const trx_id_t trx_id = trx_get_id_for_print(trx);
ib::info() << "Rolling back trx with id " << trx_id << ", "
<< rows_to_undo << unit << " rows to undo";
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
row_mysql_lock_data_dictionary(trx);
dictionary_locked = TRUE;
@@ -683,6 +656,17 @@ trx_rollback_active(
que_run_threads(roll_node->undo_thr);
if (trx->error_state != DB_SUCCESS) {
ut_ad(trx->error_state == DB_INTERRUPTED);
ut_ad(!srv_is_being_started);
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
ut_ad(!dictionary_locked);
que_graph_free(static_cast<que_t*>(
roll_node->undo_thr->common.parent));
goto func_exit;
}
trx_rollback_finish(thr_get_trx(roll_node->undo_thr));
/* Free the memory reserved by the undo graph */
@@ -714,11 +698,13 @@ trx_rollback_active(
}
}
func_exit:
if (dictionary_locked) {
row_mysql_unlock_data_dictionary(trx);
}
ib::info() << "Rollback of trx with id " << trx_id << " completed";
ib::info() << "Rollback of trx with id " << ib::hex(trx->id)
<< " completed";
mem_heap_free(heap);
@@ -736,7 +722,7 @@ ibool
trx_rollback_resurrected(
/*=====================*/
trx_t* trx, /*!< in: transaction to rollback or clean */
ibool all) /*!< in: FALSE=roll back dictionary transactions;
ibool* all) /*!< in/out: FALSE=roll back dictionary transactions;
TRUE=roll back all non-PREPARED transactions */
{
ut_ad(trx_sys_mutex_own());
@@ -747,40 +733,102 @@ trx_rollback_resurrected(
to accidentally clean up a non-recovered transaction here. */
trx_mutex_enter(trx);
bool is_recovered = trx->is_recovered;
trx_state_t state = trx->state;
if (!trx->is_recovered) {
func_exit:
trx_mutex_exit(trx);
if (!is_recovered) {
return(FALSE);
}
switch (state) {
switch (trx->state) {
case TRX_STATE_COMMITTED_IN_MEMORY:
trx_mutex_exit(trx);
trx_sys_mutex_exit();
ib::info() << "Cleaning up trx with id "
<< trx_get_id_for_print(trx);
ib::info() << "Cleaning up trx with id " << ib::hex(trx->id);
trx_cleanup_at_db_startup(trx);
trx_free_resurrected(trx);
return(TRUE);
case TRX_STATE_ACTIVE:
if (all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
if (!srv_is_being_started
&& !srv_undo_sources && srv_fast_shutdown) {
fake_prepared:
trx->state = TRX_STATE_PREPARED;
trx_sys->n_prepared_trx++;
trx_sys->n_prepared_recovered_trx++;
*all = FALSE;
goto func_exit;
}
trx_mutex_exit(trx);
if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
trx_sys_mutex_exit();
trx_rollback_active(trx);
if (trx->error_state != DB_SUCCESS) {
ut_ad(trx->error_state == DB_INTERRUPTED);
trx->error_state = DB_SUCCESS;
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
mutex_enter(&trx_sys->mutex);
trx_mutex_enter(trx);
goto fake_prepared;
}
trx_free_for_background(trx);
return(TRUE);
}
return(FALSE);
case TRX_STATE_PREPARED:
return(FALSE);
goto func_exit;
case TRX_STATE_NOT_STARTED:
case TRX_STATE_FORCED_ROLLBACK:
break;
}
ut_error;
return(FALSE);
goto func_exit;
}
/** Report progress when rolling back a row of a recovered transaction.
@return whether the rollback should be aborted due to pending shutdown */
bool
trx_roll_must_shutdown()
{
const trx_t* trx = trx_roll_crash_recv_trx;
ut_ad(trx);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
ut_ad(trx->in_rollback);
if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE
&& !srv_is_being_started
&& !srv_undo_sources && srv_fast_shutdown) {
return true;
}
ib_time_t time = ut_time();
mutex_enter(&trx_sys->mutex);
mutex_enter(&recv_sys->mutex);
if (recv_sys->report(time)) {
ulint n_trx = 0, n_rows = 0;
for (const trx_t* t = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
t != NULL;
t = UT_LIST_GET_NEXT(trx_list, t)) {
assert_trx_in_rw_list(t);
if (t->is_recovered
&& trx_state_eq(t, TRX_STATE_ACTIVE)) {
n_trx++;
n_rows += t->undo_no;
}
}
ib::info() << "To roll back: " << n_trx << " transactions, "
<< n_rows << " rows";
sd_notifyf(0, "STATUS=To roll back: " ULINTPF " transactions, "
ULINTPF " rows", n_trx, n_rows);
}
mutex_exit(&recv_sys->mutex);
mutex_exit(&trx_sys->mutex);
return false;
}
/*******************************************************************//**
@@ -825,17 +873,11 @@ trx_rollback_or_clean_recovered(
assert_trx_in_rw_list(trx);
if (srv_shutdown_state != SRV_SHUTDOWN_NONE
&& srv_fast_shutdown != 0) {
all = FALSE;
break;
}
/* If this function does a cleanup or rollback
then it will release the trx_sys->mutex, therefore
we need to reacquire it before retrying the loop. */
if (trx_rollback_resurrected(trx, all)) {
if (trx_rollback_resurrected(trx, &all)) {
trx_sys_mutex_enter();
@@ -1042,27 +1084,6 @@ trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
ut_ad(trx_roll_check_undo_rec_ordering(
undo_no, undo->rseg->space, trx));
/* We print rollback progress info if we are in a crash recovery
and the transaction has at least 1000 row operations to undo. */
if (trx == trx_roll_crash_recv_trx && trx_roll_max_undo_no > 1000) {
ulint progress_pct = 100 - (ulint)
((undo_no * 100) / trx_roll_max_undo_no);
if (progress_pct != trx_roll_progress_printed_pct) {
if (trx_roll_progress_printed_pct == 0) {
fprintf(stderr,
"\nInnoDB: Progress in percents:"
" %lu", (ulong) progress_pct);
} else {
fprintf(stderr,
" %lu", (ulong) progress_pct);
}
fflush(stderr);
trx_roll_progress_printed_pct = progress_pct;
}
}
trx->undo_no = undo_no;
trx->undo_rseg_space = undo->rseg->space;
mutex_exit(&trx->undo_mutex);

View File

@@ -1826,10 +1826,14 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
trx->is_recovered=false */
trx->is_recovered=false and
trx->state = TRX_STATE_COMMITTED_IN_MEMORY,
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
ut_a(!srv_was_started
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|| srv_fast_shutdown);
break;
default:
ut_error;
@@ -1854,10 +1858,14 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
trx->is_recovered=false */
trx->is_recovered=false and
trx->state = TRX_STATE_COMMITTED_IN_MEMORY,
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
ut_a(!srv_was_started
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|| srv_fast_shutdown);
break;
default:
ut_error;

View File

@@ -6342,7 +6342,6 @@ my_bool translog_write_record(LSN *lsn,
short_trid, &parts, trn, hook_arg);
break;
case LOGRECTYPE_NOT_ALLOWED:
DBUG_ASSERT(0);
default:
DBUG_ASSERT(0);
rc= 1;

View File

@@ -226,7 +226,6 @@ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Rotate # # master-bin.000002;pos=POS
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000002 # Binlog_checkpoint # # master-bin.000002
master-bin.000002 # Gtid # # GTID #-#-#
master-bin.000002 # Query # # use `test`; create table t3 (a int)ENGINE=TokuDB
master-bin.000002 # Gtid # # GTID #-#-#
@@ -268,7 +267,6 @@ slave-bin.000001 # Query # # use `test`; create table t3 (a int)ENGINE=TokuDB
slave-bin.000001 # Rotate # # slave-bin.000002;pos=POS
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002
slave-bin.000002 # Gtid # # GTID #-#-#
slave-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=TokuDB
slave-bin.000002 # Gtid # # BEGIN GTID #-#-#

View File

@@ -222,7 +222,6 @@ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Rotate # # master-bin.000002;pos=POS
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000002 # Binlog_checkpoint # # master-bin.000002
master-bin.000002 # Gtid # # GTID #-#-#
master-bin.000002 # Query # # use `test`; create table t3 (a int)ENGINE=TokuDB
master-bin.000002 # Gtid # # GTID #-#-#
@@ -260,7 +259,6 @@ slave-bin.000001 # Query # # use `test`; create table t3 (a int)ENGINE=TokuDB
slave-bin.000001 # Rotate # # slave-bin.000002;pos=POS
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002
slave-bin.000002 # Gtid # # GTID #-#-#
slave-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=TokuDB
slave-bin.000002 # Gtid # # BEGIN GTID #-#-#

View File

@@ -3903,6 +3903,17 @@ innobase_init(
}
}
#ifdef WITH_WSREP
/* Currently, Galera does not support VATS lock schedule algorithm. */
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& global_system_variables.wsrep_on) {
/* Do not allow InnoDB startup with VATS and Galera */
sql_print_error("In Galera, innodb_lock_schedule_algorithm=vats"
" is not supported.");
goto error;
}
#endif /* WITH_WSREP */
#ifndef HAVE_LZ4
if (innodb_compression_algorithm == PAGE_LZ4_ALGORITHM) {
sql_print_error("InnoDB: innodb_compression_algorithm = %lu unsupported.\n"
@@ -5454,8 +5465,8 @@ innobase_kill_connection(
wsrep_thd_is_BF(current_thd, FALSE),
lock_get_info(trx->lock.wait_lock).c_str());
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
trx->abort_type == TRX_SERVER_ABORT) {
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)
&& trx->abort_type == TRX_SERVER_ABORT) {
ut_ad(!lock_mutex_own());
lock_mutex_enter();
}
@@ -20463,7 +20474,7 @@ static MYSQL_SYSVAR_ENUM(empty_free_list_algorithm,
&innodb_empty_free_list_algorithm_typelib);
static MYSQL_SYSVAR_ENUM(lock_schedule_algorithm, innodb_lock_schedule_algorithm,
PLUGIN_VAR_RQCMDARG,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The algorithm Innodb uses for deciding which locks to grant next when"
" a lock is released. Possible values are"
" FCFS"

View File

@@ -384,9 +384,6 @@ struct que_thr_t{
UT_LIST_NODE_T(que_thr_t)
thrs; /*!< list of thread nodes of the fork
node */
UT_LIST_NODE_T(que_thr_t)
trx_thrs; /*!< lists of threads in wait list of
the trx */
UT_LIST_NODE_T(que_thr_t)
queue; /*!< list of runnable thread nodes in
the server task queue */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 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
@@ -34,6 +35,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0sys.h"
extern bool trx_rollback_or_clean_is_active;
extern const trx_t* trx_roll_crash_recv_trx;
/*******************************************************************//**
Determines if this transaction is rolling back an incomplete transaction
@@ -104,6 +106,11 @@ trx_undo_rec_release(
/*=================*/
trx_t* trx, /*!< in/out: transaction */
undo_no_t undo_no);/*!< in: undo number */
/** Report progress when rolling back a row of a recovered transaction.
@return whether the rollback should be aborted due to pending shutdown */
UNIV_INTERN
bool
trx_roll_must_shutdown();
/*******************************************************************//**
Rollback or clean up any incomplete transactions which were
encountered in crash recovery. If the transaction already was

View File

@@ -937,14 +937,21 @@ lock_reset_lock_and_trx_wait(
ib_logf(IB_LOG_LEVEL_INFO,
"Trx id " TRX_ID_FMT
" is waiting a lock in statement %s"
" is waiting a lock "
" for this trx id " TRX_ID_FMT
" and statement %s wait_lock %p",
" wait_lock %p",
lock->trx->id,
stmt ? stmt : "NULL",
trx_id,
stmt2 ? stmt2 : "NULL",
lock->trx->lock.wait_lock);
if (stmt) {
ib_logf(IB_LOG_LEVEL_INFO, " SQL1: %s\n", stmt);
}
if (stmt2) {
ib_logf(IB_LOG_LEVEL_INFO, " SQL2: %s\n", stmt2);
}
ut_ad(lock->trx->lock.wait_lock == lock);
}
@@ -1714,7 +1721,7 @@ lock_rec_other_has_expl_req(
ulint heap_no,/*!< in: heap number of the record */
trx_id_t trx_id) /*!< in: transaction */
{
const lock_t* lock;
lock_t* lock;
ut_ad(lock_mutex_own());
ut_ad(mode == LOCK_X || mode == LOCK_S);
@@ -1723,7 +1730,7 @@ lock_rec_other_has_expl_req(
for (lock = lock_rec_get_first(block, heap_no);
lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) {
lock = lock_rec_get_next(heap_no, lock)) {
if (lock->trx->id != trx_id
&& (gap
@@ -1810,7 +1817,7 @@ Checks if some other transaction has a conflicting explicit lock request
in the queue, so that we have to wait.
@return lock or NULL */
static
const lock_t*
lock_t*
lock_rec_other_has_conflicting(
/*===========================*/
enum lock_mode mode, /*!< in: LOCK_S or LOCK_X,
@@ -1822,7 +1829,7 @@ lock_rec_other_has_conflicting(
ulint heap_no,/*!< in: heap number of the record */
const trx_t* trx) /*!< in: our transaction */
{
const lock_t* lock;
lock_t* lock;
ibool is_supremum;
ut_ad(lock_mutex_own());
@@ -1831,13 +1838,16 @@ lock_rec_other_has_conflicting(
for (lock = lock_rec_get_first(block, heap_no);
lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) {
lock = lock_rec_get_next(heap_no, lock)) {
#ifdef WITH_WSREP
if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) {
if (wsrep_on_trx(trx)) {
trx_mutex_enter(lock->trx);
wsrep_kill_victim(trx, lock);
/* Below function will roll back either trx
or lock->trx depending on priority of the
transaction. */
wsrep_kill_victim(const_cast<trx_t*>(trx), lock);
trx_mutex_exit(lock->trx);
}
#else
@@ -2045,17 +2055,19 @@ wsrep_print_wait_locks(
{
if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) {
fprintf(stderr, "WSREP: c_lock != wait lock\n");
if (lock_get_type_low(c_lock) & LOCK_TABLE)
if (lock_get_type_low(c_lock) & LOCK_TABLE) {
lock_table_print(stderr, c_lock);
else
} else {
lock_rec_print(stderr, c_lock);
}
if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE)
if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) {
lock_table_print(stderr, c_lock->trx->lock.wait_lock);
else
} else {
lock_rec_print(stderr, c_lock->trx->lock.wait_lock);
}
}
}
#endif /* WITH_WSREP */
/*********************************************************************//**
@@ -2358,8 +2370,8 @@ lock_rec_create(
if (wsrep_debug) {
fprintf(
stderr,
"WSREP: c_lock canceled %llu\n",
(ulonglong) c_lock->trx->id);
"WSREP: c_lock canceled " TRX_ID_FMT "\n",
c_lock->trx->id);
}
/* have to bail out here to avoid lock_set_lock... */
@@ -2551,6 +2563,16 @@ lock_rec_enqueue_waiting(
err = DB_LOCK_WAIT;
}
#ifdef WITH_WSREP
if (!lock_get_wait(lock) && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
if (wsrep_debug) {
fprintf(stderr, "WSREP: BF thread got lock granted early, ID " TRX_ID_FMT
"\n",
lock->trx->id);
}
return(DB_SUCCESS);
}
#endif /* WITH_WSREP */
// Move it only when it does not cause a deadlock.
if (err != DB_DEADLOCK
&& innodb_lock_schedule_algorithm
@@ -2981,6 +3003,15 @@ lock_rec_has_to_wait_in_queue(
#ifdef WITH_WSREP
if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) &&
wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) {
if (wsrep_debug) {
fprintf(stderr,
"BF-BF lock conflict " TRX_ID_FMT
" : " TRX_ID_FMT "\n",
wait_lock->trx->id,
lock->trx->id);
lock_rec_print(stderr, wait_lock);
lock_rec_print(stderr, lock);
}
/* don't wait for another BF lock */
continue;
}
@@ -5017,8 +5048,8 @@ lock_table_create(
}
if (wsrep_debug) {
fprintf(stderr, "WSREP: c_lock canceled %llu\n",
(ulonglong) c_lock->trx->id);
fprintf(stderr, "WSREP: c_lock canceled " TRX_ID_FMT "\n",
c_lock->trx->id);
}
}
if (c_lock) {
@@ -5297,7 +5328,7 @@ Checks if other transactions have an incompatible mode lock request in
the lock queue.
@return lock or NULL */
UNIV_INLINE
const lock_t*
lock_t*
lock_table_other_has_incompatible(
/*==============================*/
const trx_t* trx, /*!< in: transaction, or NULL if all
@@ -5308,7 +5339,7 @@ lock_table_other_has_incompatible(
const dict_table_t* table, /*!< in: table */
enum lock_mode mode) /*!< in: lock mode */
{
const lock_t* lock;
lock_t* lock;
ut_ad(lock_mutex_own());
@@ -5361,7 +5392,7 @@ lock_table(
#endif
trx_t* trx;
dberr_t err;
const lock_t* wait_for;
lock_t* wait_for;
ut_ad(table != NULL);
ut_ad(thr != NULL);
@@ -5412,7 +5443,7 @@ lock_table(
if (wait_for != NULL) {
#ifdef WITH_WSREP
err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr);
err = lock_table_enqueue_waiting(wait_for, mode | flags, table, thr);
#else
err = lock_table_enqueue_waiting(mode | flags, table, thr);
#endif
@@ -7101,7 +7132,7 @@ lock_rec_insert_check_and_lock(
on the successor, which produced an unnecessary deadlock. */
#ifdef WITH_WSREP
if ((c_lock = (ib_lock_t*)lock_rec_other_has_conflicting(
if ((c_lock = lock_rec_other_has_conflicting(
static_cast<enum lock_mode>(
LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION),
block, next_rec_heap_no, trx))) {

View File

@@ -191,21 +191,24 @@ lock_wait_table_reserve_slot(
/*********************************************************************//**
check if lock timeout was for priority thread,
as a side effect trigger lock monitor
@param[in] trx transaction owning the lock
@param[in] locked true if trx and lock_sys_mutex is ownd
@return false for regular lock timeout */
static ibool
static
bool
wsrep_is_BF_lock_timeout(
/*====================*/
trx_t* trx) /* in: trx to check for lock priority */
const trx_t* trx,
bool locked = true)
{
if (wsrep_on_trx(trx) &&
wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
fprintf(stderr, "WSREP: BF lock wait long\n");
if (wsrep_on_trx(trx)
&& wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
fprintf(stderr, "WSREP: BF lock wait long for trx " TRX_ID_FMT "\n", trx->id);
srv_print_innodb_monitor = TRUE;
srv_print_innodb_lock_monitor = TRUE;
os_event_set(srv_monitor_event);
return TRUE;
return true;
}
return FALSE;
return false;
}
#endif /* WITH_WSREP */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 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
@@ -348,6 +349,13 @@ row_undo_step(
ut_ad(que_node_get_type(node) == QUE_NODE_UNDO);
if (UNIV_UNLIKELY(trx == trx_roll_crash_recv_trx)
&& trx_roll_must_shutdown()) {
/* Shutdown has been initiated. */
trx->error_state = DB_INTERRUPTED;
return(NULL);
}
err = row_undo(node, thr);
trx->error_state = err;

View File

@@ -24,6 +24,9 @@ Transaction rollback
Created 3/26/1996 Heikki Tuuri
*******************************************************/
#include "my_config.h"
#include <my_systemd.h>
#include "trx0roll.h"
#ifdef UNIV_NONINL
@@ -60,14 +63,7 @@ rollback */
bool trx_rollback_or_clean_is_active;
/** In crash recovery, the current trx to be rolled back; NULL otherwise */
static const trx_t* trx_roll_crash_recv_trx = NULL;
/** In crash recovery we set this to the undo n:o of the current trx to be
rolled back. Then we can print how many % the rollback has progressed. */
static undo_no_t trx_roll_max_undo_no;
/** Auxiliary variable which tells the previous progress % we printed */
static ulint trx_roll_progress_printed_pct;
const trx_t* trx_roll_crash_recv_trx;
/****************************************************************//**
Finishes a transaction rollback. */
@@ -564,8 +560,6 @@ trx_rollback_active(
que_thr_t* thr;
roll_node_t* roll_node;
dict_table_t* table;
ib_int64_t rows_to_undo;
const char* unit = "";
ibool dictionary_locked = FALSE;
heap = mem_heap_create(512);
@@ -584,30 +578,8 @@ trx_rollback_active(
ut_a(thr == que_fork_start_command(fork));
mutex_enter(&trx_sys->mutex);
trx_roll_crash_recv_trx = trx;
trx_roll_max_undo_no = trx->undo_no;
trx_roll_progress_printed_pct = 0;
rows_to_undo = trx_roll_max_undo_no;
mutex_exit(&trx_sys->mutex);
if (rows_to_undo > 1000000000) {
rows_to_undo = rows_to_undo / 1000000;
unit = "M";
}
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Rolling back trx with id " TRX_ID_FMT ", %lu%s"
" rows to undo\n",
trx->id,
(ulong) rows_to_undo, unit);
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
row_mysql_lock_data_dictionary(trx);
dictionary_locked = TRUE;
@@ -618,6 +590,16 @@ trx_rollback_active(
que_run_threads(roll_node->undo_thr);
if (trx->error_state != DB_SUCCESS) {
ut_ad(trx->error_state == DB_INTERRUPTED);
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
ut_ad(!dictionary_locked);
que_graph_free(static_cast<que_t*>(
roll_node->undo_thr->common.parent));
goto func_exit;
}
trx_rollback_finish(thr_get_trx(roll_node->undo_thr));
/* Free the memory reserved by the undo graph */
@@ -662,13 +644,14 @@ trx_rollback_active(
}
}
ib_logf(IB_LOG_LEVEL_INFO,
"Rollback of trx with id " TRX_ID_FMT " completed", trx->id);
func_exit:
if (dictionary_locked) {
row_mysql_unlock_data_dictionary(trx);
}
ib_logf(IB_LOG_LEVEL_INFO,
"Rollback of trx with id " TRX_ID_FMT " completed", trx->id);
mem_heap_free(heap);
trx_roll_crash_recv_trx = NULL;
@@ -685,7 +668,7 @@ ibool
trx_rollback_resurrected(
/*=====================*/
trx_t* trx, /*!< in: transaction to rollback or clean */
ibool all) /*!< in: FALSE=roll back dictionary transactions;
ibool* all) /*!< in/out: FALSE=roll back dictionary transactions;
TRUE=roll back all non-PREPARED transactions */
{
ut_ad(mutex_own(&trx_sys->mutex));
@@ -696,16 +679,15 @@ trx_rollback_resurrected(
to accidentally clean up a non-recovered transaction here. */
trx_mutex_enter(trx);
bool is_recovered = trx->is_recovered;
trx_state_t state = trx->state;
if (!trx->is_recovered) {
func_exit:
trx_mutex_exit(trx);
if (!is_recovered) {
return(FALSE);
}
switch (state) {
switch (trx->state) {
case TRX_STATE_COMMITTED_IN_MEMORY:
trx_mutex_exit(trx);
mutex_exit(&trx_sys->mutex);
fprintf(stderr,
"InnoDB: Cleaning up trx with id " TRX_ID_FMT "\n",
@@ -714,21 +696,83 @@ trx_rollback_resurrected(
trx_free_for_background(trx);
return(TRUE);
case TRX_STATE_ACTIVE:
if (all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
if (!srv_undo_sources && srv_fast_shutdown) {
fake_prepared:
trx->state = TRX_STATE_PREPARED;
trx_sys->n_prepared_trx++;
trx_sys->n_prepared_recovered_trx++;
*all = FALSE;
goto func_exit;
}
trx_mutex_exit(trx);
if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
mutex_exit(&trx_sys->mutex);
trx_rollback_active(trx);
if (trx->error_state != DB_SUCCESS) {
ut_ad(trx->error_state == DB_INTERRUPTED);
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
mutex_enter(&trx_sys->mutex);
trx_mutex_enter(trx);
goto fake_prepared;
}
trx_free_for_background(trx);
return(TRUE);
}
return(FALSE);
case TRX_STATE_PREPARED:
return(FALSE);
goto func_exit;
case TRX_STATE_NOT_STARTED:
break;
}
ut_error;
return(FALSE);
goto func_exit;
}
/** Report progress when rolling back a row of a recovered transaction.
@return whether the rollback should be aborted due to pending shutdown */
UNIV_INTERN
bool
trx_roll_must_shutdown()
{
const trx_t* trx = trx_roll_crash_recv_trx;
ut_ad(trx);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE
&& !srv_undo_sources && srv_fast_shutdown) {
return true;
}
ib_time_t time = ut_time();
mutex_enter(&trx_sys->mutex);
mutex_enter(&recv_sys->mutex);
if (recv_sys->report(time)) {
ulint n_trx = 0, n_rows = 0;
for (const trx_t* t = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
t != NULL;
t = UT_LIST_GET_NEXT(trx_list, t)) {
assert_trx_in_rw_list(t);
if (t->is_recovered
&& trx_state_eq(t, TRX_STATE_ACTIVE)) {
n_trx++;
n_rows += t->undo_no;
}
}
ib_logf(IB_LOG_LEVEL_INFO,
"To roll back: " ULINTPF " transactions, "
ULINTPF " rows", n_trx, n_rows);
sd_notifyf(0, "STATUS=To roll back: " ULINTPF " transactions, "
ULINTPF " rows", n_trx, n_rows);
}
mutex_exit(&recv_sys->mutex);
mutex_exit(&trx_sys->mutex);
return false;
}
/*******************************************************************//**
@@ -775,17 +819,11 @@ trx_rollback_or_clean_recovered(
assert_trx_in_rw_list(trx);
if (srv_shutdown_state != SRV_SHUTDOWN_NONE
&& srv_fast_shutdown != 0) {
all = FALSE;
break;
}
/* If this function does a cleanup or rollback
then it will release the trx_sys->mutex, therefore
we need to reacquire it before retrying the loop. */
if (trx_rollback_resurrected(trx, all)) {
if (trx_rollback_resurrected(trx, &all)) {
mutex_enter(&trx_sys->mutex);
@@ -1118,7 +1156,6 @@ trx_roll_pop_top_rec_of_trx(
undo_no_t undo_no;
ibool is_insert;
trx_rseg_t* rseg;
ulint progress_pct;
mtr_t mtr;
rseg = trx->rseg;
@@ -1176,27 +1213,6 @@ try_again:
ut_ad(undo_no + 1 == trx->undo_no);
/* We print rollback progress info if we are in a crash recovery
and the transaction has at least 1000 row operations to undo. */
if (trx == trx_roll_crash_recv_trx && trx_roll_max_undo_no > 1000) {
progress_pct = 100 - (ulint)
((undo_no * 100) / trx_roll_max_undo_no);
if (progress_pct != trx_roll_progress_printed_pct) {
if (trx_roll_progress_printed_pct == 0) {
fprintf(stderr,
"\nInnoDB: Progress in percents:"
" %lu", (ulong) progress_pct);
} else {
fprintf(stderr,
" %lu", (ulong) progress_pct);
}
fflush(stderr);
trx_roll_progress_printed_pct = progress_pct;
}
}
trx->undo_no = undo_no;
if (!trx_undo_arr_store_info(trx, undo_no)) {

View File

@@ -2023,10 +2023,14 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
trx->is_recovered=false */
trx->is_recovered=false and
trx->state = TRX_STATE_COMMITTED_IN_MEMORY,
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
ut_a(srv_read_only_mode
|| srv_apply_log_only
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|| srv_fast_shutdown);
break;
default:
ut_error;
@@ -2048,10 +2052,14 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
trx->is_recovered=false */
trx->is_recovered=false and
trx->state = TRX_STATE_COMMITTED_IN_MEMORY,
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
ut_a(srv_read_only_mode
|| srv_apply_log_only
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|| srv_fast_shutdown);
break;
default:
ut_error;