1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge 10.7 into 10.8

This commit is contained in:
Marko Mäkelä
2022-06-23 13:46:23 +03:00
17 changed files with 142 additions and 158 deletions

View File

@ -3697,6 +3697,25 @@ SELECT * FROM t1 LEFT JOIN t2 ON a = pk WHERE b >= 0 AND pk IS NULL;
a pk b a pk b
DROP TABLE t1, t2; DROP TABLE t1, t2;
SET @@optimizer_switch= @save_optimizer_switch; SET @@optimizer_switch= @save_optimizer_switch;
# MDEV-28858 Wrong result with table elimination combined with
# not_null_range_scan
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (10,1),(null,2);
CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2);
SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'not_null_range_scan=on';
SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b;
b
2
SET optimizer_switch= 'not_null_range_scan=off';
SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b;
b
2
SET @@optimizer_switch=@save_optimizer_switch;
drop table t1,t2;
# #
# End of 10.5 tests # End of 10.5 tests
# #

View File

@ -2492,6 +2492,24 @@ DROP TABLE t1, t2;
SET @@optimizer_switch= @save_optimizer_switch; SET @@optimizer_switch= @save_optimizer_switch;
--echo
--echo # MDEV-28858 Wrong result with table elimination combined with
--echo # not_null_range_scan
--echo #
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (10,1),(null,2);
CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2);
SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'not_null_range_scan=on';
SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b;
SET optimizer_switch= 'not_null_range_scan=off';
SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b;
SET @@optimizer_switch=@save_optimizer_switch;
drop table t1,t2;
--echo # --echo #
--echo # End of 10.5 tests --echo # End of 10.5 tests
--echo # --echo #

View File

@ -3686,6 +3686,25 @@ SELECT * FROM t1 LEFT JOIN t2 ON a = pk WHERE b >= 0 AND pk IS NULL;
a pk b a pk b
DROP TABLE t1, t2; DROP TABLE t1, t2;
SET @@optimizer_switch= @save_optimizer_switch; SET @@optimizer_switch= @save_optimizer_switch;
# MDEV-28858 Wrong result with table elimination combined with
# not_null_range_scan
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (10,1),(null,2);
CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2);
SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'not_null_range_scan=on';
SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b;
b
2
SET optimizer_switch= 'not_null_range_scan=off';
SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b;
b
2
SET @@optimizer_switch=@save_optimizer_switch;
drop table t1,t2;
# #
# End of 10.5 tests # End of 10.5 tests
# #

View File

@ -6,6 +6,8 @@ call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]
call mtr.add_suppression("InnoDB: Unable to decompress .*.test.t[12]\\.ibd\\[page id: space=[1-9][0-9]*, page number=[0-9]+\\]"); call mtr.add_suppression("InnoDB: Unable to decompress .*.test.t[12]\\.ibd\\[page id: space=[1-9][0-9]*, page number=[0-9]+\\]");
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed read of file '.*test.t[12]\\.ibd'"); call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed read of file '.*test.t[12]\\.ibd'");
call mtr.add_suppression("InnoDB: Failed to read page .* from file '.*'"); call mtr.add_suppression("InnoDB: Failed to read page .* from file '.*'");
call mtr.add_suppression("InnoDB: OPT_PAGE_CHECKSUM mismatch");
call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore corruption");
call mtr.add_suppression("InnoDB: Plugin initialization aborted"); call mtr.add_suppression("InnoDB: Plugin initialization aborted");
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed"); call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Cannot decrypt \\[page id: space="); call mtr.add_suppression("\\[ERROR\\] InnoDB: Cannot decrypt \\[page id: space=");

View File

@ -15,6 +15,8 @@ call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]
call mtr.add_suppression("InnoDB: Unable to decompress .*.test.t[12]\\.ibd\\[page id: space=[1-9][0-9]*, page number=[0-9]+\\]"); call mtr.add_suppression("InnoDB: Unable to decompress .*.test.t[12]\\.ibd\\[page id: space=[1-9][0-9]*, page number=[0-9]+\\]");
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed read of file '.*test.t[12]\\.ibd'"); call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed read of file '.*test.t[12]\\.ibd'");
call mtr.add_suppression("InnoDB: Failed to read page .* from file '.*'"); call mtr.add_suppression("InnoDB: Failed to read page .* from file '.*'");
call mtr.add_suppression("InnoDB: OPT_PAGE_CHECKSUM mismatch");
call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore corruption");
call mtr.add_suppression("InnoDB: Plugin initialization aborted"); call mtr.add_suppression("InnoDB: Plugin initialization aborted");
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed"); call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
# for innodb_checksum_algorithm=full_crc32 only # for innodb_checksum_algorithm=full_crc32 only

View File

@ -29971,11 +29971,12 @@ bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond,
DBUG_ENTER("build_notnull_conds_for_range_scans"); DBUG_ENTER("build_notnull_conds_for_range_scans");
for (JOIN_TAB *s= join->join_tab + join->const_tables ; for (JOIN_TAB *s= join->join_tab;
s < join->join_tab + join->table_count ; s++) s < join->join_tab + join->table_count ; s++)
{ {
/* Clear all needed bitmaps to mark found fields */ /* Clear all needed bitmaps to mark found fields */
if (allowed & s->table->map) if ((allowed & s->table->map) &&
!(s->table->map && join->const_table_map))
bitmap_clear_all(&s->table->tmp_set); bitmap_clear_all(&s->table->tmp_set);
} }
@ -29990,17 +29991,18 @@ bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond,
For each table t from 'allowed' build a conjunction of NOT NULL predicates For each table t from 'allowed' build a conjunction of NOT NULL predicates
constructed for all found fields if they are included in some indexes. constructed for all found fields if they are included in some indexes.
If the construction of the conjunction succeeds attach the formula to If the construction of the conjunction succeeds attach the formula to
t->table->notnull_cond. The condition will be used to look for complementary t->table->notnull_cond. The condition will be used to look for
range scans. complementary range scans.
*/ */
for (JOIN_TAB *s= join->join_tab + join->const_tables ; for (JOIN_TAB *s= join->join_tab ;
s < join->join_tab + join->table_count ; s++) s < join->join_tab + join->table_count ; s++)
{ {
TABLE *tab= s->table; TABLE *tab= s->table;
List<Item> notnull_list; List<Item> notnull_list;
Item *notnull_cond= 0; Item *notnull_cond= 0;
if (!(allowed & tab->map)) if (!(allowed & tab->map) ||
(s->table->map && join->const_table_map))
continue; continue;
for (Field** field_ptr= tab->field; *field_ptr; field_ptr++) for (Field** field_ptr= tab->field; *field_ptr; field_ptr++)

View File

@ -234,7 +234,6 @@ SET(INNOBASE_SOURCES
include/trx0i_s.h include/trx0i_s.h
include/trx0purge.h include/trx0purge.h
include/trx0rec.h include/trx0rec.h
include/trx0rec.inl
include/trx0roll.h include/trx0roll.h
include/trx0rseg.h include/trx0rseg.h
include/trx0sys.h include/trx0sys.h

View File

@ -33,10 +33,6 @@ Created 3/26/1996 Heikki Tuuri
#include <queue> #include <queue>
/** A dummy undo record used as a return value when we have a whole undo log
which needs no purge */
extern trx_undo_rec_t trx_purge_dummy_rec;
/** Prepend the history list with an undo log. /** Prepend the history list with an undo log.
Remove the undo log segment from the rseg slot if it is too big for reuse. Remove the undo log segment from the rseg slot if it is too big for reuse.
@param[in] trx transaction @param[in] trx transaction

View File

@ -24,8 +24,7 @@ Transaction undo log record
Created 3/26/1996 Heikki Tuuri Created 3/26/1996 Heikki Tuuri
*******************************************************/ *******************************************************/
#ifndef trx0rec_h #pragma once
#define trx0rec_h
#include "trx0types.h" #include "trx0types.h"
#include "row0types.h" #include "row0types.h"
@ -37,29 +36,31 @@ Created 3/26/1996 Heikki Tuuri
/***********************************************************************//** /***********************************************************************//**
Copies the undo record to the heap. Copies the undo record to the heap.
@return own: copy of undo log record */ @param undo_rec record in an undo log page
UNIV_INLINE @param heap memory heap
trx_undo_rec_t* @return copy of undo_rec
trx_undo_rec_copy( @retval nullptr if the undo log record is corrupted */
/*==============*/ inline trx_undo_rec_t* trx_undo_rec_copy(const trx_undo_rec_t *undo_rec,
const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ mem_heap_t *heap)
mem_heap_t* heap); /*!< in: heap where copied */ {
/**********************************************************************//** const size_t offset= ut_align_offset(undo_rec, srv_page_size);
Reads the undo log record type. const size_t end= mach_read_from_2(undo_rec);
@return record type */ if (end <= offset || end >= srv_page_size - FIL_PAGE_DATA_END)
UNIV_INLINE return nullptr;
ulint const size_t len= end - offset;
trx_undo_rec_get_type( trx_undo_rec_t *rec= static_cast<trx_undo_rec_t*>
/*==================*/ (mem_heap_dup(heap, undo_rec, len));
const trx_undo_rec_t* undo_rec); /*!< in: undo log record */ mach_write_to_2(rec, len);
return rec;
}
/**********************************************************************//** /**********************************************************************//**
Reads the undo log record number. Reads the undo log record number.
@return undo no */ @return undo no */
UNIV_INLINE inline undo_no_t trx_undo_rec_get_undo_no(const trx_undo_rec_t *undo_rec)
undo_no_t {
trx_undo_rec_get_undo_no( return mach_u64_read_much_compressed(undo_rec + 3);
/*=====================*/ }
const trx_undo_rec_t* undo_rec); /*!< in: undo log record */
/**********************************************************************//** /**********************************************************************//**
Returns the start of the undo record data area. */ Returns the start of the undo record data area. */
@ -345,7 +346,3 @@ inline table_id_t trx_undo_rec_get_table_id(const trx_undo_rec_t *rec)
mach_read_next_much_compressed(&rec); mach_read_next_much_compressed(&rec);
return mach_read_next_much_compressed(&rec); return mach_read_next_much_compressed(&rec);
} }
#include "trx0rec.inl"
#endif /* trx0rec_h */

View File

@ -1,73 +0,0 @@
/*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/trx0rec.ic
Transaction undo log record
Created 3/26/1996 Heikki Tuuri
*******************************************************/
/**********************************************************************//**
Reads from an undo log record the record type.
@return record type */
UNIV_INLINE
ulint
trx_undo_rec_get_type(
/*==================*/
const trx_undo_rec_t* undo_rec) /*!< in: undo log record */
{
return(mach_read_from_1(undo_rec + 2) & (TRX_UNDO_CMPL_INFO_MULT - 1));
}
/**********************************************************************//**
Reads the undo log record number.
@return undo no */
UNIV_INLINE
undo_no_t
trx_undo_rec_get_undo_no(
/*=====================*/
const trx_undo_rec_t* undo_rec) /*!< in: undo log record */
{
const byte* ptr;
ptr = undo_rec + 3;
return(mach_u64_read_much_compressed(ptr));
}
/***********************************************************************//**
Copies the undo record to the heap.
@return own: copy of undo log record */
UNIV_INLINE
trx_undo_rec_t*
trx_undo_rec_copy(
/*==============*/
const trx_undo_rec_t* undo_rec, /*!< in: undo log record */
mem_heap_t* heap) /*!< in: heap where copied */
{
ulint len;
len = mach_read_from_2(undo_rec)
- ut_align_offset(undo_rec, srv_page_size);
ut_ad(len < srv_page_size);
trx_undo_rec_t* rec = static_cast<trx_undo_rec_t*>(
mem_heap_dup(heap, undo_rec, len));
mach_write_to_2(rec, len);
return rec;
}

View File

@ -360,7 +360,7 @@ public:
page_id_t get_page_id() const { return page_id; } page_id_t get_page_id() const { return page_id; }
/** Handle the DML undo log and apply it on online indexes */ /** Handle the DML undo log and apply it on online indexes */
void apply_undo_rec(); inline void apply_undo_rec();
~UndorecApplier() ~UndorecApplier()
{ {

View File

@ -1185,12 +1185,9 @@ inline size_t recv_sys_t::files_size()
@param[in] space_id the tablespace ID @param[in] space_id the tablespace ID
@param[in] deleted whether this is a FILE_DELETE record @param[in] deleted whether this is a FILE_DELETE record
@param[in] lsn lsn of the redo log @param[in] lsn lsn of the redo log
@param[in] store whether the redo log has to @param[in] store whether the redo log has to be stored */
stored */ static void fil_name_process(const char *name, ulint len, uint32_t space_id,
static bool deleted, lsn_t lsn, store_t store)
void
fil_name_process(const char* name, ulint len, uint32_t space_id,
bool deleted, lsn_t lsn, store_t store)
{ {
if (srv_operation == SRV_OPERATION_BACKUP if (srv_operation == SRV_OPERATION_BACKUP
|| srv_operation == SRV_OPERATION_BACKUP_NO_DEFER) { || srv_operation == SRV_OPERATION_BACKUP_NO_DEFER) {
@ -1212,13 +1209,17 @@ fil_name_process(const char* name, ulint len, uint32_t space_id,
file_name_t& f = p.first->second; file_name_t& f = p.first->second;
if (deleted) { if (auto d = deferred_spaces.find(space_id)) {
/* Got FILE_DELETE */ if (deleted) {
if (auto d = deferred_spaces.find(static_cast<uint32_t>(
space_id))) {
d->deleted = true; d->deleted = true;
goto got_deleted;
} }
goto reload;
}
if (deleted) {
got_deleted:
/* Got FILE_DELETE */
if (!p.second && f.status != file_name_t::DELETED) { if (!p.second && f.status != file_name_t::DELETED) {
f.status = file_name_t::DELETED; f.status = file_name_t::DELETED;
if (f.space != NULL) { if (f.space != NULL) {
@ -1230,6 +1231,7 @@ fil_name_process(const char* name, ulint len, uint32_t space_id,
ut_ad(f.space == NULL); ut_ad(f.space == NULL);
} else if (p.second // the first FILE_MODIFY or FILE_RENAME } else if (p.second // the first FILE_MODIFY or FILE_RENAME
|| f.name != fname.name) { || f.name != fname.name) {
reload:
fil_space_t* space; fil_space_t* space;
/* Check if the tablespace file exists and contains /* Check if the tablespace file exists and contains
@ -1240,8 +1242,7 @@ fil_name_process(const char* name, ulint len, uint32_t space_id,
case FIL_LOAD_OK: case FIL_LOAD_OK:
ut_ad(space != NULL); ut_ad(space != NULL);
deferred_spaces.remove( deferred_spaces.remove(space_id);
static_cast<uint32_t>(space_id));
if (!f.space) { if (!f.space) {
if (f.size if (f.size
|| f.flags != f.initial_flags) { || f.flags != f.initial_flags) {
@ -1304,8 +1305,7 @@ same_space:
when lsn is already processed */ when lsn is already processed */
if (store != store_t::STORE_IF_EXISTS) { if (store != store_t::STORE_IF_EXISTS) {
deferred_spaces.add( deferred_spaces.add(
static_cast<uint32_t>(space_id), space_id, fname.name.c_str(), lsn);
fname.name.c_str(), lsn);
} }
break; break;
case FIL_LOAD_INVALID: case FIL_LOAD_INVALID:

View File

@ -1114,7 +1114,7 @@ row_purge(
trx_undo_rec_t* undo_rec, /*!< in: record to purge */ trx_undo_rec_t* undo_rec, /*!< in: record to purge */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
if (undo_rec != &trx_purge_dummy_rec) { if (undo_rec != reinterpret_cast<trx_undo_rec_t*>(-1)) {
bool updated_extern; bool updated_extern;
while (row_purge_parse_undo_rec( while (row_purge_parse_undo_rec(

View File

@ -342,7 +342,11 @@ static bool row_undo_rec_get(undo_node_t* node)
node->heap); node->heap);
mtr.commit(); mtr.commit();
switch (trx_undo_rec_get_type(node->undo_rec)) { if (UNIV_UNLIKELY(!node->undo_rec)) {
return false;
}
switch (node->undo_rec[2] & (TRX_UNDO_CMPL_INFO_MULT - 1)) {
case TRX_UNDO_INSERT_METADATA: case TRX_UNDO_INSERT_METADATA:
/* This record type was introduced in MDEV-11369 /* This record type was introduced in MDEV-11369
instant ADD COLUMN, which was implemented after instant ADD COLUMN, which was implemented after
@ -356,13 +360,12 @@ static bool row_undo_rec_get(undo_node_t* node)
case TRX_UNDO_INSERT_REC: case TRX_UNDO_INSERT_REC:
case TRX_UNDO_EMPTY: case TRX_UNDO_EMPTY:
node->roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS; node->roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS;
node->state = undo == temp node->state = is_temp
? UNDO_INSERT_TEMPORARY : UNDO_INSERT_PERSISTENT; ? UNDO_INSERT_TEMPORARY : UNDO_INSERT_PERSISTENT;
break; break;
default: default:
node->state = undo == temp node->state = is_temp
? UNDO_UPDATE_TEMPORARY : UNDO_UPDATE_PERSISTENT; ? UNDO_UPDATE_TEMPORARY : UNDO_UPDATE_PERSISTENT;
break;
} }
trx->undo_no = node->undo_no = trx_undo_rec_get_undo_no( trx->undo_no = node->undo_no = trx_undo_rec_get_undo_no(

View File

@ -55,10 +55,6 @@ ulong srv_max_purge_lag_delay = 0;
/** The global data structure coordinating a purge */ /** The global data structure coordinating a purge */
purge_sys_t purge_sys; purge_sys_t purge_sys;
/** A dummy undo record used as a return value when we have a whole undo log
which needs no purge */
trx_undo_rec_t trx_purge_dummy_rec;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
my_bool srv_purge_view_update_only_debug; my_bool srv_purge_view_update_only_debug;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
@ -1022,7 +1018,9 @@ TRANSACTIONAL_TARGET static void trx_purge_choose_next_log()
/***********************************************************************//** /***********************************************************************//**
Gets the next record to purge and updates the info in the purge system. Gets the next record to purge and updates the info in the purge system.
@return copy of an undo log record or pointer to the dummy undo log record */ @return copy of an undo log record
@retval -1 if there is nothing to purge
@retval nullptr on corruption */
static static
trx_undo_rec_t* trx_undo_rec_t*
trx_purge_get_next_rec( trx_purge_get_next_rec(
@ -1048,11 +1046,10 @@ trx_purge_get_next_rec(
/* Look for the next undo log and record to purge */ /* Look for the next undo log and record to purge */
trx_purge_choose_next_log(); trx_purge_choose_next_log();
return reinterpret_cast<trx_undo_rec_t*>(-1);
return(&trx_purge_dummy_rec);
} }
mtr_start(&mtr); mtr.start();
const buf_block_t* undo_page const buf_block_t* undo_page
= buf_page_get_gen(page_id, 0, RW_S_LATCH, nullptr, = buf_page_get_gen(page_id, 0, RW_S_LATCH, nullptr,
@ -1060,7 +1057,7 @@ trx_purge_get_next_rec(
if (UNIV_UNLIKELY(!undo_page)) { if (UNIV_UNLIKELY(!undo_page)) {
corrupted: corrupted:
mtr.commit(); mtr.commit();
return &trx_purge_dummy_rec; return nullptr;
} }
const buf_block_t* rec2_page = undo_page; const buf_block_t* rec2_page = undo_page;
@ -1105,16 +1102,16 @@ corrupted:
trx_undo_rec_t* rec_copy = trx_undo_rec_copy(undo_page->page.frame trx_undo_rec_t* rec_copy = trx_undo_rec_copy(undo_page->page.frame
+ offset, heap); + offset, heap);
mtr_commit(&mtr); mtr.commit();
return rec_copy;
return(rec_copy);
} }
/********************************************************************//** /********************************************************************//**
Fetches the next undo log record from the history list to purge. It must be Fetches the next undo log record from the history list to purge. It must be
released with the corresponding release function. released with the corresponding release function.
@return copy of an undo log record or pointer to trx_purge_dummy_rec, @return copy of an undo log record
if the whole undo log can skipped in purge; NULL if none left */ @retval -1 if the whole undo log can skipped in purge
@retval nullptr if nothing is left, or on corruption */
static MY_ATTRIBUTE((warn_unused_result)) static MY_ATTRIBUTE((warn_unused_result))
trx_undo_rec_t* trx_undo_rec_t*
trx_purge_fetch_next_rec( trx_purge_fetch_next_rec(
@ -1130,13 +1127,12 @@ trx_purge_fetch_next_rec(
if (!purge_sys.next_stored) { if (!purge_sys.next_stored) {
DBUG_PRINT("ib_purge", DBUG_PRINT("ib_purge",
("no logs left in the history list")); ("no logs left in the history list"));
return(NULL); return nullptr;
} }
} }
if (purge_sys.tail.trx_no >= purge_sys.low_limit_no()) { if (purge_sys.tail.trx_no >= purge_sys.low_limit_no()) {
return nullptr;
return(NULL);
} }
/* fprintf(stderr, "Thread %lu purging trx %llu undo record %llu\n", /* fprintf(stderr, "Thread %lu purging trx %llu undo record %llu\n",
@ -1152,7 +1148,7 @@ trx_purge_fetch_next_rec(
/* The following call will advance the stored values of the /* The following call will advance the stored values of the
purge iterator. */ purge iterator. */
return(trx_purge_get_next_rec(n_pages_handled, heap)); return trx_purge_get_next_rec(n_pages_handled, heap);
} }
/** Run a purge batch. /** Run a purge batch.
@ -1229,7 +1225,8 @@ trx_purge_attach_undo_recs(ulint n_purge_threads)
if (purge_rec.undo_rec == NULL) { if (purge_rec.undo_rec == NULL) {
break; break;
} else if (purge_rec.undo_rec == &trx_purge_dummy_rec) { } else if (purge_rec.undo_rec
== reinterpret_cast<trx_undo_rec_t*>(-1)) {
continue; continue;
} }

View File

@ -307,8 +307,10 @@ inline void UndorecApplier::assign_rec(const buf_block_t &block,
this->undo_rec= trx_undo_rec_copy(block.page.frame + offset, heap); this->undo_rec= trx_undo_rec_copy(block.page.frame + offset, heap);
} }
void UndorecApplier::apply_undo_rec() inline void UndorecApplier::apply_undo_rec()
{ {
if (!undo_rec)
return;
bool updated_extern= false; bool updated_extern= false;
undo_no_t undo_no= 0; undo_no_t undo_no= 0;
table_id_t table_id= 0; table_id_t table_id= 0;

View File

@ -327,21 +327,22 @@ public:
int m_period; int m_period;
std::mutex m_mtx; std::mutex m_mtx;
bool m_on; bool m_on;
std::atomic<bool> m_running; std::atomic<int> m_running;
void run() void run()
{ {
/* /*
In rare cases, multiple callbacks can be scheduled, In rare cases, multiple callbacks can be scheduled,
e.g with set_time(0,0) in a loop. at the same time,. e.g with set_time(0,0) in a loop.
We do not allow parallel execution, as user is not prepared. We do not allow parallel execution, since it is against the expectations.
*/ */
bool expected = false; if (m_running.fetch_add(1, std::memory_order_acquire) > 0)
if (!m_running.compare_exchange_strong(expected, true))
return; return;
do
m_callback(m_data); {
m_running = false; m_callback(m_data);
}
while (m_running.fetch_sub(1, std::memory_order_release) != 1);
if (m_pool && m_period) if (m_pool && m_period)
{ {