Merge 10.5 into 10.6
This commit is contained in:
commit
3e2ad0e918
@ -1,7 +1,11 @@
|
|||||||
|
SET @save_frequency=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET @save_dbug=@@GLOBAL.debug_dbug;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
||||||
f3 int generated always as (f2 * 2) VIRTUAL,
|
f3 int generated always as (f2 * 2) VIRTUAL,
|
||||||
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
||||||
connect con1,localhost,root,,,;
|
connect con1,localhost,root,,,;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
INSERT INTO t1(f1, f2) VALUES(1,2);
|
INSERT INTO t1(f1, f2) VALUES(1,2);
|
||||||
@ -18,5 +22,6 @@ commit;
|
|||||||
disconnect con1;
|
disconnect con1;
|
||||||
disconnect con2;
|
disconnect con2;
|
||||||
connection default;
|
connection default;
|
||||||
set global debug_dbug=default;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
|
||||||
|
SET GLOBAL debug_dbug=@save_dbug;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
--source include/have_debug.inc
|
--source include/have_debug.inc
|
||||||
|
|
||||||
|
SET @save_frequency=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET @save_dbug=@@GLOBAL.debug_dbug;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
||||||
f3 int generated always as (f2 * 2) VIRTUAL,
|
f3 int generated always as (f2 * 2) VIRTUAL,
|
||||||
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
||||||
connect(con1,localhost,root,,,);
|
connect(con1,localhost,root,,,);
|
||||||
|
--source ../innodb/include/wait_all_purged.inc
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
@ -26,5 +31,6 @@ commit;
|
|||||||
disconnect con1;
|
disconnect con1;
|
||||||
disconnect con2;
|
disconnect con2;
|
||||||
connection default;
|
connection default;
|
||||||
set global debug_dbug=default;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
|
||||||
|
SET GLOBAL debug_dbug=@save_dbug;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
connect prevent_purge,localhost,root,,;
|
connect prevent_purge,localhost,root,,;
|
||||||
start transaction with consistent snapshot;
|
start transaction with consistent snapshot;
|
||||||
connect con_del_1,localhost,root,,;
|
connect con_del_1,localhost,root,,;
|
||||||
@ -34,3 +37,4 @@ disconnect con_del_2;
|
|||||||
connection default;
|
connection default;
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_freq;
|
||||||
|
@ -7,6 +7,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
|||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
||||||
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
||||||
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
connect prevent_purge,localhost,root;
|
connect prevent_purge,localhost,root;
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
@ -19,7 +20,11 @@ UPDATE t1 SET b=4 WHERE a=3;
|
|||||||
disconnect prevent_purge;
|
disconnect prevent_purge;
|
||||||
connection default;
|
connection default;
|
||||||
InnoDB 0 transactions not purged
|
InnoDB 0 transactions not purged
|
||||||
|
connection con1;
|
||||||
|
ROLLBACK;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
FLUSH TABLE t1 FOR EXPORT;
|
FLUSH TABLE t1 FOR EXPORT;
|
||||||
Clustered index root page contents:
|
Clustered index root page contents:
|
||||||
N_RECS=3; LEVEL=0
|
N_RECS=3; LEVEL=0
|
||||||
|
@ -3,6 +3,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
|||||||
CREATE TABLE t1(id INT PRIMARY key, val VARCHAR(16000)) ENGINE=InnoDB;
|
CREATE TABLE t1(id INT PRIMARY key, val VARCHAR(16000)) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
||||||
connect con1,localhost,root,,;
|
connect con1,localhost,root,,;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
DELETE FROM t1 WHERE id=1788;
|
DELETE FROM t1 WHERE id=1788;
|
||||||
|
@ -9,12 +9,10 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency= 1;
|
|||||||
CREATE PROCEDURE insert_n(start int, end int)
|
CREATE PROCEDURE insert_n(start int, end int)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE i INT DEFAULT start;
|
DECLARE i INT DEFAULT start;
|
||||||
START TRANSACTION;
|
|
||||||
WHILE i <= end do
|
WHILE i <= end do
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
||||||
SET i = i + 1;
|
SET i = i + 1;
|
||||||
END WHILE;
|
END WHILE;
|
||||||
COMMIT;
|
|
||||||
END~~
|
END~~
|
||||||
CREATE FUNCTION num_pages_get()
|
CREATE FUNCTION num_pages_get()
|
||||||
RETURNS INT
|
RETURNS INT
|
||||||
@ -30,6 +28,7 @@ END~~
|
|||||||
#
|
#
|
||||||
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
||||||
ENGINE=InnoDB STATS_PERSISTENT=0;
|
ENGINE=InnoDB STATS_PERSISTENT=0;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a b c
|
a b c
|
||||||
@ -38,20 +37,24 @@ a b c
|
|||||||
#
|
#
|
||||||
connect con2, localhost, root,,;
|
connect con2, localhost, root,,;
|
||||||
connection con2;
|
connection con2;
|
||||||
|
BEGIN;
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
CALL insert_n(1, 50);;
|
CALL insert_n(1, 50);;
|
||||||
connect con3, localhost, root,,;
|
connect con3, localhost, root,,;
|
||||||
connection con3;
|
connection con3;
|
||||||
|
BEGIN;
|
||||||
CALL insert_n(51, 100);;
|
CALL insert_n(51, 100);;
|
||||||
connection con2;
|
connection con2;
|
||||||
|
COMMIT;
|
||||||
connection con3;
|
connection con3;
|
||||||
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
|
COMMIT;
|
||||||
connection default;
|
connection default;
|
||||||
#
|
#
|
||||||
# Connect to default and record how many pages were accessed
|
# Connect to default and record how many pages were accessed
|
||||||
# when selecting the record using the secondary key.
|
# when selecting the record using the secondary key.
|
||||||
#
|
#
|
||||||
InnoDB 4 transactions not purged
|
InnoDB 2 transactions not purged
|
||||||
SET @num_pages_1 = num_pages_get();
|
SET @num_pages_1 = num_pages_get();
|
||||||
SELECT * FROM t1 force index (b);
|
SELECT * FROM t1 force index (b);
|
||||||
a b c
|
a b c
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
source include/have_debug.inc;
|
source include/have_debug.inc;
|
||||||
source include/have_debug_sync.inc;
|
source include/have_debug_sync.inc;
|
||||||
|
|
||||||
|
SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
||||||
|
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
--connect(prevent_purge,localhost,root,,)
|
--connect(prevent_purge,localhost,root,,)
|
||||||
start transaction with consistent snapshot;
|
start transaction with consistent snapshot;
|
||||||
|
|
||||||
@ -80,4 +83,5 @@ INSERT INTO t VALUES(30, 20);
|
|||||||
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_freq;
|
||||||
--source include/wait_until_count_sessions.inc
|
--source include/wait_until_count_sessions.inc
|
||||||
|
@ -14,6 +14,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
|||||||
|
|
||||||
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
||||||
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
|
|
||||||
--connect (prevent_purge,localhost,root)
|
--connect (prevent_purge,localhost,root)
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
@ -33,7 +34,12 @@ UPDATE t1 SET b=4 WHERE a=3;
|
|||||||
# Initiate a full purge, which should reset the DB_TRX_ID except for a=3.
|
# Initiate a full purge, which should reset the DB_TRX_ID except for a=3.
|
||||||
--source include/wait_all_purged.inc
|
--source include/wait_all_purged.inc
|
||||||
# Initiate a ROLLBACK of the update, which should reset the DB_TRX_ID for a=3.
|
# Initiate a ROLLBACK of the update, which should reset the DB_TRX_ID for a=3.
|
||||||
|
--connection con1
|
||||||
|
ROLLBACK;
|
||||||
--disconnect con1
|
--disconnect con1
|
||||||
|
--connection default
|
||||||
|
# Reset the DB_TRX_ID for the hidden ADD COLUMN metadata record.
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
|
|
||||||
FLUSH TABLE t1 FOR EXPORT;
|
FLUSH TABLE t1 FOR EXPORT;
|
||||||
# The following is based on innodb.table_flags:
|
# The following is based on innodb.table_flags:
|
||||||
|
@ -9,6 +9,7 @@ CREATE TABLE t1(id INT PRIMARY key, val VARCHAR(16000)) ENGINE=InnoDB;
|
|||||||
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
||||||
|
|
||||||
connect(con1,localhost,root,,);
|
connect(con1,localhost,root,,);
|
||||||
|
source include/wait_all_purged.inc;
|
||||||
# Prevent purge.
|
# Prevent purge.
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
|
@ -13,12 +13,10 @@ DELIMITER ~~;
|
|||||||
CREATE PROCEDURE insert_n(start int, end int)
|
CREATE PROCEDURE insert_n(start int, end int)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE i INT DEFAULT start;
|
DECLARE i INT DEFAULT start;
|
||||||
START TRANSACTION;
|
|
||||||
WHILE i <= end do
|
WHILE i <= end do
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
||||||
SET i = i + 1;
|
SET i = i + 1;
|
||||||
END WHILE;
|
END WHILE;
|
||||||
COMMIT;
|
|
||||||
END~~
|
END~~
|
||||||
|
|
||||||
CREATE FUNCTION num_pages_get()
|
CREATE FUNCTION num_pages_get()
|
||||||
@ -37,6 +35,7 @@ DELIMITER ;~~
|
|||||||
--echo #
|
--echo #
|
||||||
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
||||||
ENGINE=InnoDB STATS_PERSISTENT=0;
|
ENGINE=InnoDB STATS_PERSISTENT=0;
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
|
|
||||||
@ -45,18 +44,22 @@ SELECT * FROM t1;
|
|||||||
--echo #
|
--echo #
|
||||||
connect (con2, localhost, root,,);
|
connect (con2, localhost, root,,);
|
||||||
connection con2;
|
connection con2;
|
||||||
|
BEGIN;
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
--send CALL insert_n(1, 50);
|
--send CALL insert_n(1, 50);
|
||||||
|
|
||||||
connect (con3, localhost, root,,);
|
connect (con3, localhost, root,,);
|
||||||
connection con3;
|
connection con3;
|
||||||
|
BEGIN;
|
||||||
--send CALL insert_n(51, 100);
|
--send CALL insert_n(51, 100);
|
||||||
|
|
||||||
connection con2;
|
connection con2;
|
||||||
reap;
|
reap;
|
||||||
|
COMMIT;
|
||||||
connection con3;
|
connection con3;
|
||||||
reap;
|
reap;
|
||||||
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
|
|
||||||
@ -64,7 +67,7 @@ connection default;
|
|||||||
--echo # Connect to default and record how many pages were accessed
|
--echo # Connect to default and record how many pages were accessed
|
||||||
--echo # when selecting the record using the secondary key.
|
--echo # when selecting the record using the secondary key.
|
||||||
--echo #
|
--echo #
|
||||||
--let $wait_all_purged=4
|
--let $wait_all_purged=2
|
||||||
--source include/wait_all_purged.inc
|
--source include/wait_all_purged.inc
|
||||||
SET @num_pages_1 = num_pages_get();
|
SET @num_pages_1 = num_pages_get();
|
||||||
SELECT * FROM t1 force index (b);
|
SELECT * FROM t1 force index (b);
|
||||||
|
@ -65,53 +65,44 @@ struct alignas(CPU_LEVEL1_DCACHE_LINESIZE) trx_rseg_t
|
|||||||
/** length of the TRX_RSEG_HISTORY list (number of transactions) */
|
/** length of the TRX_RSEG_HISTORY list (number of transactions) */
|
||||||
uint32_t history_size;
|
uint32_t history_size;
|
||||||
|
|
||||||
|
/** Last known transaction that has not been purged yet,
|
||||||
|
or 0 if everything has been purged. */
|
||||||
|
trx_id_t needs_purge;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Reference counter to track rseg allocated transactions,
|
/** Reference counter to track is_persistent() transactions,
|
||||||
with SKIP and NEEDS_PURGE flags. */
|
with SKIP flag. */
|
||||||
std::atomic<uint32_t> ref;
|
std::atomic<uint32_t> ref;
|
||||||
|
|
||||||
/** Whether undo tablespace truncation is pending */
|
/** Whether undo tablespace truncation is pending */
|
||||||
static constexpr uint32_t SKIP= 1;
|
static constexpr uint32_t SKIP= 1;
|
||||||
/** Whether the log segment needs purge */
|
|
||||||
static constexpr uint32_t NEEDS_PURGE= 2;
|
|
||||||
/** Transaction reference count multiplier */
|
/** Transaction reference count multiplier */
|
||||||
static constexpr uint32_t REF= 4;
|
static constexpr uint32_t REF= 2;
|
||||||
|
|
||||||
uint32_t ref_load() const { return ref.load(std::memory_order_relaxed); }
|
uint32_t ref_load() const { return ref.load(std::memory_order_relaxed); }
|
||||||
|
|
||||||
/** Set a bit in ref */
|
/** Set the SKIP bit */
|
||||||
template<bool needs_purge> void ref_set()
|
void ref_set_skip()
|
||||||
{
|
{
|
||||||
static_assert(SKIP == 1U << 0, "compatibility");
|
static_assert(SKIP == 1U, "compatibility");
|
||||||
static_assert(NEEDS_PURGE == 1U << 1, "compatibility");
|
|
||||||
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
||||||
if (needs_purge)
|
__asm__ __volatile__("lock btsl $0, %0" : "+m" (ref));
|
||||||
__asm__ __volatile__("lock btsl $1, %0" : "+m" (ref));
|
|
||||||
else
|
|
||||||
__asm__ __volatile__("lock btsl $0, %0" : "+m" (ref));
|
|
||||||
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
||||||
_interlockedbittestandset(reinterpret_cast<volatile long*>(&ref),
|
_interlockedbittestandset(reinterpret_cast<volatile long*>(&ref), 0);
|
||||||
needs_purge);
|
|
||||||
#else
|
#else
|
||||||
ref.fetch_or(needs_purge ? NEEDS_PURGE : SKIP, std::memory_order_relaxed);
|
ref.fetch_or(SKIP, std::memory_order_relaxed);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/** Clear a bit in ref */
|
/** Clear a bit in ref */
|
||||||
template<bool needs_purge> void ref_reset()
|
void ref_reset_skip()
|
||||||
{
|
{
|
||||||
static_assert(SKIP == 1U << 0, "compatibility");
|
static_assert(SKIP == 1U, "compatibility");
|
||||||
static_assert(NEEDS_PURGE == 1U << 1, "compatibility");
|
|
||||||
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
||||||
if (needs_purge)
|
__asm__ __volatile__("lock btrl $0, %0" : "+m" (ref));
|
||||||
__asm__ __volatile__("lock btrl $1, %0" : "+m" (ref));
|
|
||||||
else
|
|
||||||
__asm__ __volatile__("lock btrl $0, %0" : "+m" (ref));
|
|
||||||
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
||||||
_interlockedbittestandreset(reinterpret_cast<volatile long*>(&ref),
|
_interlockedbittestandreset(reinterpret_cast<volatile long*>(&ref), 0);
|
||||||
needs_purge);
|
|
||||||
#else
|
#else
|
||||||
ref.fetch_and(needs_purge ? ~NEEDS_PURGE : ~SKIP,
|
ref.fetch_and(~SKIP, std::memory_order_relaxed);
|
||||||
std::memory_order_relaxed);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,26 +116,20 @@ public:
|
|||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
/** Note that undo tablespace truncation was started. */
|
/** Note that undo tablespace truncation was started. */
|
||||||
void set_skip_allocation() { ut_ad(is_persistent()); ref_set<false>(); }
|
void set_skip_allocation() { ut_ad(is_persistent()); ref_set_skip(); }
|
||||||
/** Note that undo tablespace truncation was completed. */
|
/** Note that undo tablespace truncation was completed. */
|
||||||
void clear_skip_allocation()
|
void clear_skip_allocation()
|
||||||
{
|
{
|
||||||
ut_ad(is_persistent());
|
ut_ad(is_persistent());
|
||||||
#if defined DBUG_OFF
|
#if defined DBUG_OFF
|
||||||
ref_reset<false>();
|
ref_reset_skip();
|
||||||
#else
|
#else
|
||||||
ut_d(auto r=) ref.fetch_and(~SKIP, std::memory_order_relaxed);
|
ut_d(auto r=) ref.fetch_and(~SKIP, std::memory_order_relaxed);
|
||||||
ut_ad(r == SKIP);
|
ut_ad(r == SKIP);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/** Note that the rollback segment requires purge. */
|
|
||||||
void set_needs_purge() { ref_set<true>(); }
|
|
||||||
/** Note that the rollback segment will not require purge. */
|
|
||||||
void clear_needs_purge() { ref_reset<true>(); }
|
|
||||||
/** @return whether the segment is marked for undo truncation */
|
/** @return whether the segment is marked for undo truncation */
|
||||||
bool skip_allocation() const { return ref_load() & SKIP; }
|
bool skip_allocation() const { return ref_load() & SKIP; }
|
||||||
/** @return whether the segment needs purge */
|
|
||||||
bool needs_purge() const { return ref_load() & NEEDS_PURGE; }
|
|
||||||
/** Increment the reference count */
|
/** Increment the reference count */
|
||||||
void acquire()
|
void acquire()
|
||||||
{ ut_d(auto r=) ref.fetch_add(REF); ut_ad(!(r & SKIP)); }
|
{ ut_d(auto r=) ref.fetch_add(REF); ut_ad(!(r & SKIP)); }
|
||||||
|
@ -246,12 +246,10 @@ trx_undo_free_at_shutdown(trx_t *trx);
|
|||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in] id rollback segment slot
|
@param[in] id rollback segment slot
|
||||||
@param[in] page_no undo log segment page number
|
@param[in] page_no undo log segment page number
|
||||||
@param[in,out] max_trx_id the largest observed transaction ID
|
|
||||||
@return the undo log
|
@return the undo log
|
||||||
@retval nullptr on error */
|
@retval nullptr on error */
|
||||||
trx_undo_t *
|
trx_undo_t *
|
||||||
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no,
|
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no);
|
||||||
trx_id_t &max_trx_id);
|
|
||||||
|
|
||||||
#endif /* !UNIV_INNOCHECKSUM */
|
#endif /* !UNIV_INNOCHECKSUM */
|
||||||
|
|
||||||
@ -493,6 +491,8 @@ or 0 if the transaction has not been committed */
|
|||||||
/** Before MariaDB 10.3.1, when purge did not reset DB_TRX_ID of
|
/** Before MariaDB 10.3.1, when purge did not reset DB_TRX_ID of
|
||||||
surviving user records, this used to be called TRX_UNDO_DEL_MARKS.
|
surviving user records, this used to be called TRX_UNDO_DEL_MARKS.
|
||||||
|
|
||||||
|
This field is redundant; it is only being read by some debug assertions.
|
||||||
|
|
||||||
The value 1 indicates that purge needs to process the undo log segment.
|
The value 1 indicates that purge needs to process the undo log segment.
|
||||||
The value 0 indicates that all of it has been processed, and
|
The value 0 indicates that all of it has been processed, and
|
||||||
trx_purge_free_segment() has been invoked, so the log is not safe to access.
|
trx_purge_free_segment() has been invoked, so the log is not safe to access.
|
||||||
|
@ -263,6 +263,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
|
|||||||
+ undo->hdr_offset;
|
+ undo->hdr_offset;
|
||||||
|
|
||||||
ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1);
|
ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1);
|
||||||
|
ut_ad(rseg->needs_purge > trx->id);
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT
|
if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT
|
||||||
+ rseg_header->page.frame))) {
|
+ rseg_header->page.frame))) {
|
||||||
@ -356,7 +357,6 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
|
|||||||
rseg->last_page_no = undo->hdr_page_no;
|
rseg->last_page_no = undo->hdr_page_no;
|
||||||
rseg->set_last_commit(undo->hdr_offset,
|
rseg->set_last_commit(undo->hdr_offset,
|
||||||
trx->rw_trx_hash_element->no);
|
trx->rw_trx_hash_element->no);
|
||||||
rseg->set_needs_purge();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rseg->history_size++;
|
rseg->history_size++;
|
||||||
@ -387,24 +387,21 @@ static dberr_t trx_purge_remove_log_hdr(buf_block_t *rseg, buf_block_t* log,
|
|||||||
|
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||||
/** Free an undo log segment, and remove the header from the history list.
|
/** Free an undo log segment, and remove the header from the history list.
|
||||||
|
@param[in,out] mtr mini-transaction
|
||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in] hdr_addr file address of log_hdr
|
@param[in] hdr_addr file address of log_hdr
|
||||||
@return error code */
|
@return error code */
|
||||||
static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
static dberr_t
|
||||||
|
trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr)
|
||||||
{
|
{
|
||||||
const page_id_t hdr_page_id{rseg->space->id, hdr_addr.page};
|
mtr.commit();
|
||||||
mtr_t mtr;
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
|
|
||||||
/* We only need the latch to maintain rseg->curr_size. To follow the
|
const page_id_t hdr_page_id{rseg->space->id, hdr_addr.page};
|
||||||
latching order, we must acquire it before acquiring any related
|
|
||||||
page latch. */
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
buf_block_t *rseg_hdr= rseg->get(&mtr, &err);
|
buf_block_t *rseg_hdr= rseg->get(&mtr, &err);
|
||||||
if (!rseg_hdr)
|
if (!rseg_hdr)
|
||||||
goto func_exit;
|
return err;
|
||||||
if (buf_block_t *block= buf_page_get_gen(hdr_page_id, 0, RW_X_LATCH,
|
if (buf_block_t *block= buf_page_get_gen(hdr_page_id, 0, RW_X_LATCH,
|
||||||
nullptr, BUF_GET_POSSIBLY_FREED,
|
nullptr, BUF_GET_POSSIBLY_FREED,
|
||||||
&mtr, &err))
|
&mtr, &err))
|
||||||
@ -419,12 +416,10 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
|
while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
|
||||||
block->page.frame, &mtr))
|
block->page.frame, &mtr))
|
||||||
{
|
{
|
||||||
rseg->latch.wr_unlock();
|
|
||||||
rseg_hdr->fix();
|
rseg_hdr->fix();
|
||||||
block->fix();
|
block->fix();
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
mtr.start();
|
mtr.start();
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
rseg_hdr->page.lock.x_lock();
|
rseg_hdr->page.lock.x_lock();
|
||||||
block->page.lock.x_lock();
|
block->page.lock.x_lock();
|
||||||
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
|
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
|
||||||
@ -443,13 +438,10 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
could become inaccessible garbage in the file space. */
|
could become inaccessible garbage in the file space. */
|
||||||
err= trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr);
|
err= trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr);
|
||||||
if (UNIV_UNLIKELY(err != DB_SUCCESS))
|
if (UNIV_UNLIKELY(err != DB_SUCCESS))
|
||||||
goto func_exit;
|
return err;
|
||||||
byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame;
|
byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame;
|
||||||
if (UNIV_UNLIKELY(mach_read_from_4(hist) < seg_size))
|
if (UNIV_UNLIKELY(mach_read_from_4(hist) < seg_size))
|
||||||
{
|
return DB_CORRUPTION;
|
||||||
err= DB_CORRUPTION;
|
|
||||||
goto func_exit;
|
|
||||||
}
|
|
||||||
mtr.write<4>(*rseg_hdr, hist, mach_read_from_4(hist) - seg_size);
|
mtr.write<4>(*rseg_hdr, hist, mach_read_from_4(hist) - seg_size);
|
||||||
|
|
||||||
/* Here we assume that a file segment with just the header page
|
/* Here we assume that a file segment with just the header page
|
||||||
@ -464,9 +456,6 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
rseg->curr_size -= seg_size;
|
rseg->curr_size -= seg_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
func_exit:
|
|
||||||
rseg->latch.wr_unlock();
|
|
||||||
mtr.commit();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,8 +473,6 @@ trx_purge_truncate_rseg_history(
|
|||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
ut_ad(rseg.is_persistent());
|
|
||||||
rseg.latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
buf_block_t* rseg_hdr = rseg.get(&mtr, &err);
|
buf_block_t* rseg_hdr = rseg.get(&mtr, &err);
|
||||||
@ -501,7 +488,6 @@ trx_purge_truncate_rseg_history(
|
|||||||
loop:
|
loop:
|
||||||
if (hdr_addr.page == FIL_NULL) {
|
if (hdr_addr.page == FIL_NULL) {
|
||||||
func_exit:
|
func_exit:
|
||||||
rseg.latch.wr_unlock();
|
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -533,38 +519,30 @@ func_exit:
|
|||||||
prev_hdr_addr.boffset = static_cast<uint16_t>(prev_hdr_addr.boffset
|
prev_hdr_addr.boffset = static_cast<uint16_t>(prev_hdr_addr.boffset
|
||||||
- TRX_UNDO_HISTORY_NODE);
|
- TRX_UNDO_HISTORY_NODE);
|
||||||
|
|
||||||
if (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
if (!rseg.is_referenced()
|
||||||
+ block->page.frame)
|
&& rseg.needs_purge <= (purge_sys.head.trx_no
|
||||||
|
? purge_sys.head.trx_no
|
||||||
|
: purge_sys.tail.trx_no)
|
||||||
|
&& mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
||||||
|
+ block->page.frame)
|
||||||
== TRX_UNDO_TO_PURGE
|
== TRX_UNDO_TO_PURGE
|
||||||
&& !mach_read_from_2(block->page.frame + hdr_addr.boffset
|
&& !mach_read_from_2(block->page.frame + hdr_addr.boffset
|
||||||
+ TRX_UNDO_NEXT_LOG)) {
|
+ TRX_UNDO_NEXT_LOG)) {
|
||||||
|
/* We can free the whole log segment.
|
||||||
/* We can free the whole log segment */
|
This will call trx_purge_remove_log_hdr(). */
|
||||||
|
err = trx_purge_free_segment(mtr, &rseg, hdr_addr);
|
||||||
rseg.latch.wr_unlock();
|
|
||||||
mtr.commit();
|
|
||||||
|
|
||||||
/* calls the trx_purge_remove_log_hdr()
|
|
||||||
inside trx_purge_free_segment(). */
|
|
||||||
err = trx_purge_free_segment(&rseg, hdr_addr);
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* Remove the log hdr from the rseg history. */
|
/* Remove the log hdr from the rseg history. */
|
||||||
|
rseg.history_size--;
|
||||||
err = trx_purge_remove_log_hdr(rseg_hdr, block,
|
err = trx_purge_remove_log_hdr(rseg_hdr, block,
|
||||||
hdr_addr.boffset, &mtr);
|
hdr_addr.boffset, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
goto func_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rseg.history_size--;
|
|
||||||
rseg.latch.wr_unlock();
|
|
||||||
mtr.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtr.commit();
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
mtr.start();
|
mtr.start();
|
||||||
rseg.latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
hdr_addr = prev_hdr_addr;
|
hdr_addr = prev_hdr_addr;
|
||||||
|
|
||||||
@ -640,8 +618,13 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
|
|||||||
dberr_t err= DB_SUCCESS;
|
dberr_t err= DB_SUCCESS;
|
||||||
for (auto &rseg : trx_sys.rseg_array)
|
for (auto &rseg : trx_sys.rseg_array)
|
||||||
if (rseg.space)
|
if (rseg.space)
|
||||||
|
{
|
||||||
|
ut_ad(rseg.is_persistent());
|
||||||
|
rseg.latch.wr_lock(SRW_LOCK_CALL);
|
||||||
if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head))
|
if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head))
|
||||||
err= e;
|
err= e;
|
||||||
|
rseg.latch.wr_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS || srv_undo_tablespaces_active < 2)
|
if (err != DB_SUCCESS || srv_undo_tablespaces_active < 2)
|
||||||
return;
|
return;
|
||||||
@ -693,43 +676,34 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
|
|||||||
{
|
{
|
||||||
if (rseg.space != &space)
|
if (rseg.space != &space)
|
||||||
continue;
|
continue;
|
||||||
#ifdef SUX_LOCK_GENERIC
|
|
||||||
rseg.latch.rd_lock(SRW_LOCK_CALL);
|
rseg.latch.rd_lock(SRW_LOCK_CALL);
|
||||||
#else
|
|
||||||
transactional_shared_lock_guard<srw_spin_lock> g{rseg.latch};
|
|
||||||
#endif
|
|
||||||
ut_ad(rseg.skip_allocation());
|
ut_ad(rseg.skip_allocation());
|
||||||
if (rseg.is_referenced())
|
if (rseg.is_referenced() || rseg.needs_purge > head.trx_no)
|
||||||
{
|
{
|
||||||
not_free:
|
not_free:
|
||||||
#ifdef SUX_LOCK_GENERIC
|
|
||||||
rseg.latch.rd_unlock();
|
rseg.latch.rd_unlock();
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rseg.curr_size != 1)
|
ut_ad(UT_LIST_GET_LEN(rseg.undo_list) == 0);
|
||||||
|
/* Check if all segments are cached and safe to remove. */
|
||||||
|
ulint cached= 0;
|
||||||
|
|
||||||
|
for (const trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo;
|
||||||
|
undo= UT_LIST_GET_NEXT(undo_list, undo))
|
||||||
{
|
{
|
||||||
/* Check if all segments are cached and safe to remove. */
|
if (head.trx_no < undo->trx_id)
|
||||||
ulint cached= 0;
|
|
||||||
for (trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo;
|
|
||||||
undo= UT_LIST_GET_NEXT(undo_list, undo))
|
|
||||||
{
|
|
||||||
if (head.trx_no < undo->trx_id)
|
|
||||||
goto not_free;
|
|
||||||
else
|
|
||||||
cached+= undo->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(rseg.curr_size > cached);
|
|
||||||
|
|
||||||
if (rseg.curr_size > cached + 1)
|
|
||||||
goto not_free;
|
goto not_free;
|
||||||
|
else
|
||||||
|
cached+= undo->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SUX_LOCK_GENERIC
|
ut_ad(rseg.curr_size > cached);
|
||||||
|
if (rseg.curr_size > cached + 1)
|
||||||
|
goto not_free;
|
||||||
|
|
||||||
rseg.latch.rd_unlock();
|
rseg.latch.rd_unlock();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ib::info() << "Truncating " << file->name;
|
ib::info() << "Truncating " << file->name;
|
||||||
@ -848,7 +822,9 @@ not_free:
|
|||||||
if (rseg.space != &space)
|
if (rseg.space != &space)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dberr_t err;
|
ut_ad(!rseg.is_referenced());
|
||||||
|
ut_ad(rseg.needs_purge <= head.trx_no);
|
||||||
|
|
||||||
buf_block_t *rblock= trx_rseg_header_create(&space,
|
buf_block_t *rblock= trx_rseg_header_create(&space,
|
||||||
&rseg - trx_sys.rseg_array,
|
&rseg - trx_sys.rseg_array,
|
||||||
trx_sys.get_max_trx_id(),
|
trx_sys.get_max_trx_id(),
|
||||||
@ -883,10 +859,6 @@ not_free:
|
|||||||
log_buffer_flush_to_disk();
|
log_buffer_flush_to_disk();
|
||||||
DBUG_SUICIDE(););
|
DBUG_SUICIDE(););
|
||||||
|
|
||||||
for (auto &rseg : trx_sys.rseg_array)
|
|
||||||
if (rseg.space == &space)
|
|
||||||
rseg.clear_skip_allocation();
|
|
||||||
|
|
||||||
ib::info() << "Truncated " << file->name;
|
ib::info() << "Truncated " << file->name;
|
||||||
purge_sys.truncate.last= purge_sys.truncate.current;
|
purge_sys.truncate.last= purge_sys.truncate.current;
|
||||||
ut_ad(&space == purge_sys.truncate.current);
|
ut_ad(&space == purge_sys.truncate.current);
|
||||||
@ -946,7 +918,6 @@ static void trx_purge_rseg_get_next_history_log(
|
|||||||
/* Read the previous log header. */
|
/* Read the previous log header. */
|
||||||
mtr.start();
|
mtr.start();
|
||||||
|
|
||||||
byte needs_purge= 0;
|
|
||||||
trx_id_t trx_no= 0;
|
trx_id_t trx_no= 0;
|
||||||
|
|
||||||
if (const buf_block_t* undo_page=
|
if (const buf_block_t* undo_page=
|
||||||
@ -957,7 +928,6 @@ static void trx_purge_rseg_get_next_history_log(
|
|||||||
|
|
||||||
trx_no= mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
|
trx_no= mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
|
||||||
ut_ad(mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1);
|
ut_ad(mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1);
|
||||||
needs_purge= log_hdr[TRX_UNDO_NEEDS_PURGE + 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
@ -969,11 +939,6 @@ static void trx_purge_rseg_get_next_history_log(
|
|||||||
purge_sys.rseg->last_page_no= prev_log_addr.page;
|
purge_sys.rseg->last_page_no= prev_log_addr.page;
|
||||||
purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no);
|
purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no);
|
||||||
|
|
||||||
if (needs_purge)
|
|
||||||
purge_sys.rseg->set_needs_purge();
|
|
||||||
else
|
|
||||||
purge_sys.rseg->clear_needs_purge();
|
|
||||||
|
|
||||||
/* Purge can also produce events, however these are already ordered
|
/* Purge can also produce events, however these are already ordered
|
||||||
in the rollback segment and any user generated event will be greater
|
in the rollback segment and any user generated event will be greater
|
||||||
than the events that Purge produces. ie. Purge can never produce
|
than the events that Purge produces. ie. Purge can never produce
|
||||||
@ -995,7 +960,7 @@ static void trx_purge_read_undo_rec()
|
|||||||
purge_sys.hdr_offset = purge_sys.rseg->last_offset();
|
purge_sys.hdr_offset = purge_sys.rseg->last_offset();
|
||||||
page_no = purge_sys.hdr_page_no = purge_sys.rseg->last_page_no;
|
page_no = purge_sys.hdr_page_no = purge_sys.rseg->last_page_no;
|
||||||
|
|
||||||
if (purge_sys.rseg->needs_purge()) {
|
if (purge_sys.rseg->needs_purge) {
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
mtr.start();
|
mtr.start();
|
||||||
const buf_block_t* undo_page;
|
const buf_block_t* undo_page;
|
||||||
|
@ -399,7 +399,7 @@ void trx_rseg_t::reinit(uint32_t page)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(!is_referenced());
|
ut_ad(!is_referenced());
|
||||||
clear_needs_purge();
|
needs_purge= 0;
|
||||||
last_commit_and_offset= 0;
|
last_commit_and_offset= 0;
|
||||||
last_page_no= FIL_NULL;
|
last_page_no= FIL_NULL;
|
||||||
curr_size= 1;
|
curr_size= 1;
|
||||||
@ -407,10 +407,9 @@ void trx_rseg_t::reinit(uint32_t page)
|
|||||||
|
|
||||||
/** Read the undo log lists.
|
/** Read the undo log lists.
|
||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in,out] max_trx_id maximum observed transaction identifier
|
|
||||||
@param[in] rseg_header rollback segment header
|
@param[in] rseg_header rollback segment header
|
||||||
@return error code */
|
@return error code */
|
||||||
static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
static dberr_t trx_undo_lists_init(trx_rseg_t *rseg,
|
||||||
const buf_block_t *rseg_header)
|
const buf_block_t *rseg_header)
|
||||||
{
|
{
|
||||||
ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
|
ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
|
||||||
@ -420,8 +419,8 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
uint32_t page_no= trx_rsegf_get_nth_undo(rseg_header, i);
|
uint32_t page_no= trx_rsegf_get_nth_undo(rseg_header, i);
|
||||||
if (page_no != FIL_NULL)
|
if (page_no != FIL_NULL)
|
||||||
{
|
{
|
||||||
const trx_undo_t *undo= trx_undo_mem_create_at_db_start(rseg, i, page_no,
|
const trx_undo_t *undo=
|
||||||
max_trx_id);
|
trx_undo_mem_create_at_db_start(rseg, i, page_no);
|
||||||
if (!undo)
|
if (!undo)
|
||||||
return DB_CORRUPTION;
|
return DB_CORRUPTION;
|
||||||
rseg->curr_size+= undo->size;
|
rseg->curr_size+= undo->size;
|
||||||
@ -434,11 +433,9 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
|
|
||||||
/** Restore the state of a persistent rollback segment.
|
/** Restore the state of a persistent rollback segment.
|
||||||
@param[in,out] rseg persistent rollback segment
|
@param[in,out] rseg persistent rollback segment
|
||||||
@param[in,out] max_trx_id maximum observed transaction identifier
|
|
||||||
@param[in,out] mtr mini-transaction
|
@param[in,out] mtr mini-transaction
|
||||||
@return error code */
|
@return error code */
|
||||||
static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr)
|
||||||
mtr_t *mtr)
|
|
||||||
{
|
{
|
||||||
if (!rseg->space)
|
if (!rseg->space)
|
||||||
return DB_TABLESPACE_NOT_FOUND;
|
return DB_TABLESPACE_NOT_FOUND;
|
||||||
@ -454,8 +451,8 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
trx_id_t id= mach_read_from_8(TRX_RSEG + TRX_RSEG_MAX_TRX_ID +
|
trx_id_t id= mach_read_from_8(TRX_RSEG + TRX_RSEG_MAX_TRX_ID +
|
||||||
rseg_hdr->page.frame);
|
rseg_hdr->page.frame);
|
||||||
|
|
||||||
if (id > max_trx_id)
|
if (id > rseg->needs_purge)
|
||||||
max_trx_id= id;
|
rseg->needs_purge= id;
|
||||||
|
|
||||||
const byte *binlog_name=
|
const byte *binlog_name=
|
||||||
TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr->page.frame;
|
TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr->page.frame;
|
||||||
@ -491,7 +488,7 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
|
|
||||||
rseg->curr_size = mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE +
|
rseg->curr_size = mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE +
|
||||||
rseg_hdr->page.frame) + 1;
|
rseg_hdr->page.frame) + 1;
|
||||||
err= trx_undo_lists_init(rseg, max_trx_id, rseg_hdr);
|
err= trx_undo_lists_init(rseg, rseg_hdr);
|
||||||
if (err != DB_SUCCESS);
|
if (err != DB_SUCCESS);
|
||||||
else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY +
|
else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY +
|
||||||
rseg_hdr->page.frame))
|
rseg_hdr->page.frame))
|
||||||
@ -512,19 +509,16 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
|
|
||||||
trx_id_t id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
trx_id_t id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
||||||
TRX_UNDO_TRX_ID);
|
TRX_UNDO_TRX_ID);
|
||||||
if (id > max_trx_id)
|
if (id > rseg->needs_purge)
|
||||||
max_trx_id= id;
|
rseg->needs_purge= id;
|
||||||
id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
||||||
TRX_UNDO_TRX_NO);
|
TRX_UNDO_TRX_NO);
|
||||||
if (id > max_trx_id)
|
if (id > rseg->needs_purge)
|
||||||
max_trx_id= id;
|
rseg->needs_purge= id;
|
||||||
|
|
||||||
rseg->set_last_commit(node_addr.boffset, id);
|
rseg->set_last_commit(node_addr.boffset, id);
|
||||||
unsigned purge= mach_read_from_2(block->page.frame + node_addr.boffset +
|
ut_ad(mach_read_from_2(block->page.frame + node_addr.boffset +
|
||||||
TRX_UNDO_NEEDS_PURGE);
|
TRX_UNDO_NEEDS_PURGE) <= 1);
|
||||||
ut_ad(purge <= 1);
|
|
||||||
if (purge != 0)
|
|
||||||
rseg->set_needs_purge();
|
|
||||||
|
|
||||||
if (rseg->last_page_no != FIL_NULL)
|
if (rseg->last_page_no != FIL_NULL)
|
||||||
/* There is no need to cover this operation by the purge
|
/* There is no need to cover this operation by the purge
|
||||||
@ -597,9 +591,11 @@ dberr_t trx_rseg_array_init()
|
|||||||
sys, rseg_id)),
|
sys, rseg_id)),
|
||||||
page_no);
|
page_no);
|
||||||
ut_ad(rseg.is_persistent());
|
ut_ad(rseg.is_persistent());
|
||||||
if ((err = trx_rseg_mem_restore(
|
err = trx_rseg_mem_restore(&rseg, &mtr);
|
||||||
&rseg, max_trx_id, &mtr))
|
if (rseg.needs_purge > max_trx_id) {
|
||||||
!= DB_SUCCESS) {
|
max_trx_id = rseg.needs_purge;
|
||||||
|
}
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -651,6 +651,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
|||||||
uint64_t *rows_to_undo)
|
uint64_t *rows_to_undo)
|
||||||
{
|
{
|
||||||
trx_state_t state;
|
trx_state_t state;
|
||||||
|
ut_ad(rseg->needs_purge >= undo->trx_id);
|
||||||
/*
|
/*
|
||||||
This is single-threaded startup code, we do not need the
|
This is single-threaded startup code, we do not need the
|
||||||
protection of trx->mutex here.
|
protection of trx->mutex here.
|
||||||
@ -673,6 +674,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
|||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rseg->acquire();
|
||||||
trx_t *trx= trx_create();
|
trx_t *trx= trx_create();
|
||||||
trx->state= state;
|
trx->state= state;
|
||||||
ut_d(trx->start_file= __FILE__);
|
ut_d(trx->start_file= __FILE__);
|
||||||
@ -681,12 +683,6 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
|||||||
trx->rsegs.m_redo.undo= undo;
|
trx->rsegs.m_redo.undo= undo;
|
||||||
trx->undo_no= undo->top_undo_no + 1;
|
trx->undo_no= undo->top_undo_no + 1;
|
||||||
trx->rsegs.m_redo.rseg= rseg;
|
trx->rsegs.m_redo.rseg= rseg;
|
||||||
/*
|
|
||||||
For transactions with active data will not have rseg size = 1
|
|
||||||
or will not qualify for purge limit criteria. So it is safe to increment
|
|
||||||
this trx_ref_count w/o mutex protection.
|
|
||||||
*/
|
|
||||||
trx->rsegs.m_redo.rseg->acquire();
|
|
||||||
trx->xid= undo->xid;
|
trx->xid= undo->xid;
|
||||||
trx->id= undo->trx_id;
|
trx->id= undo->trx_id;
|
||||||
trx->is_recovered= true;
|
trx->is_recovered= true;
|
||||||
@ -759,6 +755,7 @@ corrupted:
|
|||||||
ut_ad(trx->is_recovered);
|
ut_ad(trx->is_recovered);
|
||||||
ut_ad(trx->rsegs.m_redo.rseg == &rseg);
|
ut_ad(trx->rsegs.m_redo.rseg == &rseg);
|
||||||
ut_ad(rseg.is_referenced());
|
ut_ad(rseg.is_referenced());
|
||||||
|
ut_ad(rseg.needs_purge);
|
||||||
|
|
||||||
trx->rsegs.m_redo.undo = undo;
|
trx->rsegs.m_redo.undo = undo;
|
||||||
if (undo->top_undo_no >= trx->undo_no) {
|
if (undo->top_undo_no >= trx->undo_no) {
|
||||||
@ -794,20 +791,18 @@ corrupted:
|
|||||||
|
|
||||||
/** Assign a persistent rollback segment in a round-robin fashion,
|
/** Assign a persistent rollback segment in a round-robin fashion,
|
||||||
evenly distributed between 0 and innodb_undo_logs-1
|
evenly distributed between 0 and innodb_undo_logs-1
|
||||||
@return persistent rollback segment
|
@param trx transaction */
|
||||||
@retval NULL if innodb_read_only */
|
static void trx_assign_rseg_low(trx_t *trx)
|
||||||
static trx_rseg_t* trx_assign_rseg_low()
|
|
||||||
{
|
{
|
||||||
if (high_level_read_only) {
|
ut_ad(!trx->rsegs.m_redo.rseg);
|
||||||
ut_ad(!srv_available_undo_logs);
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(srv_available_undo_logs == TRX_SYS_N_RSEGS);
|
ut_ad(srv_available_undo_logs == TRX_SYS_N_RSEGS);
|
||||||
|
|
||||||
/* The first slot is always assigned to the system tablespace. */
|
/* The first slot is always assigned to the system tablespace. */
|
||||||
ut_ad(trx_sys.rseg_array[0].space == fil_system.sys_space);
|
ut_ad(trx_sys.rseg_array[0].space == fil_system.sys_space);
|
||||||
|
|
||||||
|
trx_sys.register_rw(trx);
|
||||||
|
ut_ad(trx->id);
|
||||||
|
|
||||||
/* Choose a rollback segment evenly distributed between 0 and
|
/* Choose a rollback segment evenly distributed between 0 and
|
||||||
innodb_undo_logs-1 in a round-robin fashion, skipping those
|
innodb_undo_logs-1 in a round-robin fashion, skipping those
|
||||||
undo tablespaces that are scheduled for truncation. */
|
undo tablespaces that are scheduled for truncation. */
|
||||||
@ -821,7 +816,7 @@ static trx_rseg_t* trx_assign_rseg_low()
|
|||||||
bool look_for_rollover = false;
|
bool look_for_rollover = false;
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
bool allocated = false;
|
bool allocated;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -871,9 +866,7 @@ static trx_rseg_t* trx_assign_rseg_low()
|
|||||||
allocated = rseg->acquire_if_available();
|
allocated = rseg->acquire_if_available();
|
||||||
} while (!allocated);
|
} while (!allocated);
|
||||||
|
|
||||||
ut_ad(rseg->is_referenced());
|
trx->rsegs.m_redo.rseg = rseg;
|
||||||
ut_ad(rseg->is_persistent());
|
|
||||||
return(rseg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Assign a rollback segment for modifying temporary tables.
|
/** Assign a rollback segment for modifying temporary tables.
|
||||||
@ -956,15 +949,11 @@ trx_start_low(
|
|||||||
|
|
||||||
if (!trx->read_only
|
if (!trx->read_only
|
||||||
&& (!trx->mysql_thd || read_write || trx->dict_operation)) {
|
&& (!trx->mysql_thd || read_write || trx->dict_operation)) {
|
||||||
|
|
||||||
/* Temporary rseg is assigned only if the transaction
|
/* Temporary rseg is assigned only if the transaction
|
||||||
updates a temporary table */
|
updates a temporary table */
|
||||||
trx->rsegs.m_redo.rseg = trx_assign_rseg_low();
|
if (!high_level_read_only) {
|
||||||
ut_ad(trx->rsegs.m_redo.rseg != 0
|
trx_assign_rseg_low(trx);
|
||||||
|| srv_read_only_mode
|
}
|
||||||
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|
|
||||||
|
|
||||||
trx_sys.register_rw(trx);
|
|
||||||
} else {
|
} else {
|
||||||
if (!trx->is_autocommit_non_locking()) {
|
if (!trx->is_autocommit_non_locking()) {
|
||||||
|
|
||||||
@ -1055,25 +1044,21 @@ trx_write_serialisation_history(
|
|||||||
|
|
||||||
trx_undo_t*& undo = trx->rsegs.m_redo.undo;
|
trx_undo_t*& undo = trx->rsegs.m_redo.undo;
|
||||||
|
|
||||||
if (!undo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(!trx->read_only);
|
ut_ad(!trx->read_only);
|
||||||
ut_ad(!undo || undo->rseg == rseg);
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
/* Assign the transaction serialisation number and add any
|
/* Assign the transaction serialisation number and add any
|
||||||
undo log to the purge queue. */
|
undo log to the purge queue. */
|
||||||
trx_serialise(trx);
|
|
||||||
if (undo) {
|
if (undo) {
|
||||||
|
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
||||||
|
ut_ad(undo->rseg == rseg);
|
||||||
|
trx_serialise(trx);
|
||||||
UT_LIST_REMOVE(rseg->undo_list, undo);
|
UT_LIST_REMOVE(rseg->undo_list, undo);
|
||||||
trx_purge_add_undo_to_history(trx, undo, mtr);
|
trx_purge_add_undo_to_history(trx, undo, mtr);
|
||||||
|
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
|
||||||
|
rseg->latch.wr_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
rseg->latch.wr_unlock();
|
rseg->release();
|
||||||
|
|
||||||
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
@ -1318,10 +1303,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
|
|||||||
release_locks();
|
release_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trx_rseg_t *rseg= rsegs.m_redo.rseg)
|
|
||||||
/* This is safe due to us having detached the persistent undo log. */
|
|
||||||
rseg->release();
|
|
||||||
|
|
||||||
if (mtr)
|
if (mtr)
|
||||||
{
|
{
|
||||||
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
|
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
|
||||||
@ -1455,6 +1436,13 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr)
|
|||||||
|
|
||||||
mtr->commit();
|
mtr->commit();
|
||||||
}
|
}
|
||||||
|
else if (trx_rseg_t *rseg= rsegs.m_redo.rseg)
|
||||||
|
{
|
||||||
|
ut_ad(id);
|
||||||
|
ut_ad(!rsegs.m_redo.undo);
|
||||||
|
rseg->release();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLED_DEBUG_SYNC
|
#ifdef ENABLED_DEBUG_SYNC
|
||||||
if (debug_sync)
|
if (debug_sync)
|
||||||
DEBUG_SYNC_C("before_trx_state_committed_in_memory");
|
DEBUG_SYNC_C("before_trx_state_committed_in_memory");
|
||||||
@ -2167,11 +2155,7 @@ trx_set_rw_mode(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
trx->rsegs.m_redo.rseg = trx_assign_rseg_low();
|
trx_assign_rseg_low(trx);
|
||||||
ut_ad(trx->rsegs.m_redo.rseg != 0);
|
|
||||||
|
|
||||||
trx_sys.register_rw(trx);
|
|
||||||
ut_ad(trx->id);
|
|
||||||
|
|
||||||
/* So that we can see our own changes. */
|
/* So that we can see our own changes. */
|
||||||
if (trx->read_view.is_open()) {
|
if (trx->read_view.is_open()) {
|
||||||
|
@ -1011,12 +1011,10 @@ static void trx_undo_seg_free(const trx_undo_t *undo)
|
|||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in] id rollback segment slot
|
@param[in] id rollback segment slot
|
||||||
@param[in] page_no undo log segment page number
|
@param[in] page_no undo log segment page number
|
||||||
@param[in,out] max_trx_id the largest observed transaction ID
|
|
||||||
@return the undo log
|
@return the undo log
|
||||||
@retval nullptr on error */
|
@retval nullptr on error */
|
||||||
trx_undo_t *
|
trx_undo_t *
|
||||||
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no,
|
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no)
|
||||||
trx_id_t &max_trx_id)
|
|
||||||
{
|
{
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
XID xid;
|
XID xid;
|
||||||
@ -1054,10 +1052,21 @@ corrupted_type:
|
|||||||
const trx_ulogf_t* const undo_header = block->page.frame + offset;
|
const trx_ulogf_t* const undo_header = block->page.frame + offset;
|
||||||
uint16_t state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
uint16_t state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
||||||
+ block->page.frame);
|
+ block->page.frame);
|
||||||
|
|
||||||
|
const trx_id_t trx_id= mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
|
||||||
|
if (trx_id >> 48) {
|
||||||
|
sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id);
|
||||||
|
goto corrupted;
|
||||||
|
}
|
||||||
|
/* We will increment rseg->needs_purge, like trx_undo_reuse_cached()
|
||||||
|
would do it, to avoid trouble on rollback or XA COMMIT. */
|
||||||
|
trx_id_t trx_no = trx_id + 1;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case TRX_UNDO_ACTIVE:
|
case TRX_UNDO_ACTIVE:
|
||||||
case TRX_UNDO_PREPARED:
|
case TRX_UNDO_PREPARED:
|
||||||
if (UNIV_LIKELY(type != 1)) {
|
if (UNIV_LIKELY(type != 1)) {
|
||||||
|
trx_no = trx_id + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sql_print_error("InnoDB: upgrade from older version than"
|
sql_print_error("InnoDB: upgrade from older version than"
|
||||||
@ -1080,13 +1089,14 @@ corrupted_type:
|
|||||||
goto corrupted_type;
|
goto corrupted_type;
|
||||||
}
|
}
|
||||||
read_trx_no:
|
read_trx_no:
|
||||||
trx_id_t id = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header);
|
trx_no = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header);
|
||||||
if (id >> 48) {
|
if (trx_no >> 48) {
|
||||||
sql_print_error("InnoDB: corrupted TRX_NO %llx", id);
|
sql_print_error("InnoDB: corrupted TRX_NO %llx",
|
||||||
|
trx_no);
|
||||||
goto corrupted;
|
goto corrupted;
|
||||||
}
|
}
|
||||||
if (id > max_trx_id) {
|
if (trx_no < trx_id) {
|
||||||
max_trx_id = id;
|
trx_no = trx_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,13 +1109,8 @@ corrupted_type:
|
|||||||
xid.null();
|
xid.null();
|
||||||
}
|
}
|
||||||
|
|
||||||
trx_id_t trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
|
if (trx_no > rseg->needs_purge) {
|
||||||
if (trx_id >> 48) {
|
rseg->needs_purge = trx_no;
|
||||||
sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id);
|
|
||||||
goto corrupted;
|
|
||||||
}
|
|
||||||
if (trx_id > max_trx_id) {
|
|
||||||
max_trx_id = trx_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trx_undo_t* undo = trx_undo_mem_create(
|
trx_undo_t* undo = trx_undo_mem_create(
|
||||||
@ -1296,6 +1301,22 @@ buf_block_t*
|
|||||||
trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
|
trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
|
||||||
mtr_t* mtr)
|
mtr_t* mtr)
|
||||||
{
|
{
|
||||||
|
if (rseg->is_persistent()) {
|
||||||
|
ut_ad(rseg->is_referenced());
|
||||||
|
if (rseg->needs_purge <= trx->id) {
|
||||||
|
/* trx_purge_truncate_history() compares
|
||||||
|
rseg->needs_purge <= head.trx_no
|
||||||
|
so we need to compensate for that.
|
||||||
|
The rseg->needs_purge after crash
|
||||||
|
recovery would be at least trx->id + 1,
|
||||||
|
because that is the minimum possible value
|
||||||
|
assigned by trx_serialise() on commit. */
|
||||||
|
rseg->needs_purge = trx->id + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ut_ad(!rseg->is_referenced());
|
||||||
|
}
|
||||||
|
|
||||||
trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
|
trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
|
||||||
if (!undo) {
|
if (!undo) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1395,9 +1416,8 @@ buf_block_t*
|
|||||||
trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
|
trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
|
||||||
dberr_t* err, mtr_t* mtr)
|
dberr_t* err, mtr_t* mtr)
|
||||||
{
|
{
|
||||||
ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg);
|
ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg);
|
||||||
ut_ad(rseg == trx->rsegs.m_redo.rseg
|
ut_ad(is_temp || rseg == trx->rsegs.m_redo.rseg);
|
||||||
|| rseg == trx->rsegs.m_noredo.rseg);
|
|
||||||
ut_ad(undo == (is_temp
|
ut_ad(undo == (is_temp
|
||||||
? &trx->rsegs.m_noredo.undo
|
? &trx->rsegs.m_noredo.undo
|
||||||
: &trx->rsegs.m_redo.undo));
|
: &trx->rsegs.m_redo.undo));
|
||||||
@ -1417,7 +1437,6 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
|
|||||||
);
|
);
|
||||||
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
||||||
|
|
||||||
buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr);
|
buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr);
|
||||||
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user