From d0603fc5ba4dc17a155a575edd79ae0fb9de3679 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 2 Jan 2023 18:34:19 +0200 Subject: [PATCH 1/7] MDEV-30240 Wrong result upon aggregate function with SQL_BUFFER_RESULT The problem was that when storing rows into a temporary table, MIN/MAX items that where marked as constants (as theire value had been computed at start of query) would be reset. Fixed by not reseting MIN/MAX items that are marked as const in Item_sum_min_max::clear(). --- mysql-test/main/group_min_max.result | 20 ++++++++++++++++++++ mysql-test/main/group_min_max.test | 17 +++++++++++++++++ sql/item_sum.cc | 14 ++++++++++++-- sql/opt_sum.cc | 2 +- sql/sql_select.cc | 1 - 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result index 214f64df874..d1bd4d8cedb 100644 --- a/mysql-test/main/group_min_max.result +++ b/mysql-test/main/group_min_max.result @@ -4065,3 +4065,23 @@ SELECT DISTINCT owner_id FROM t1 WHERE foo = true GROUP BY owner_id HAVING (COUN owner_id 1 DROP TABLE t1; +# +# MDEV-30240 Wrong result upon aggregate function with SQL_BUFFER_RESULT +# +drop table if exists t1,t2; +Warnings: +Note 1051 Unknown table 'test.t1,test.t2' +CREATE TABLE t1 (pk INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (1),(2); +SELECT SQL_BUFFER_RESULT MIN(pk) FROM t1, t2; +MIN(pk) +1 +SELECT MIN(pk) FROM t1, t2; +MIN(pk) +1 +DROP TABLE t1, t2; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/group_min_max.test b/mysql-test/main/group_min_max.test index 3b043fc0842..7de57d75d36 100644 --- a/mysql-test/main/group_min_max.test +++ b/mysql-test/main/group_min_max.test @@ -1723,3 +1723,20 @@ EXPLAIN SELECT DISTINCT owner_id FROM t1 WHERE foo = true GROUP BY owner_id HAVING (COUNT(*) = 1); SELECT DISTINCT owner_id FROM t1 WHERE foo = true GROUP BY owner_id HAVING (COUNT(*) = 1); DROP TABLE t1; + +--echo # +--echo # MDEV-30240 Wrong result upon aggregate function with SQL_BUFFER_RESULT +--echo # + +drop table if exists t1,t2; +CREATE TABLE t1 (pk INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (1),(2); +SELECT SQL_BUFFER_RESULT MIN(pk) FROM t1, t2; +SELECT MIN(pk) FROM t1, t2; +DROP TABLE t1, t2; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 1c17b5c6409..9baf945644e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2361,8 +2361,15 @@ Item *Item_sum_variance::result_item(THD *thd, Field *field) void Item_sum_min_max::clear() { DBUG_ENTER("Item_sum_min_max::clear"); - value->clear(); - null_value= 1; + /* + We should not clear const items (from SELECT MIN(key) from t1) as then we would loose the + value cached in opt_sum_query() where we replace MIN/MAX/COUNT with constants. + */ + if (!const_item()) + { + value->clear(); + null_value= 1; + } DBUG_VOID_RETURN; } @@ -2475,9 +2482,12 @@ void Item_sum_min_max::no_rows_in_result() /* We may be called here twice in case of ref field in function */ if (was_values) { + bool org_const_item_cache= const_item_cache; was_values= FALSE; was_null_value= value->null_value; + const_item_cache= 0; // Ensure that clear works on const items clear(); + const_item_cache= org_const_item_cache; } DBUG_VOID_RETURN; } diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 27360d4a10c..8664ccae53c 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -438,7 +438,7 @@ int opt_sum_query(THD *thd, The optimization is not applicable in both cases: (a) 'expr' is a non-constant expression. Then we can't replace 'expr' by a constant. - (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + (b) 'expr' is a constant. According to ANSI, MIN/MAX must return NULL if the query does not return any rows. Thus, if we are not able to determine if the query returns any rows, we can't apply the optimization and replace MIN/MAX with a constant. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8de9a3e8b58..1ce7439e06e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -25871,7 +25871,6 @@ bool JOIN::alloc_func_list() @param field_list All items @param send_result_set_metadata Items in select list @param before_group_by Set to 1 if this is called before GROUP BY handling - @param recompute Set to TRUE if sum_funcs must be recomputed @retval 0 ok From f8f747547a64ca82a5784fa394d99d38827c67ae Mon Sep 17 00:00:00 2001 From: Robin Newhouse Date: Thu, 5 Jan 2023 00:20:44 +0000 Subject: [PATCH 2/7] MDEV-30344 MTR tests fail when built without WSREP When building with -DWITH_WSREP=OFF, files required for MTR tests are excluded and several tests fail. This is cause by a recent commit 7b44d0ba which attempted to resolve MDEV-23230. Even when building without WSREP/Galera support some of the MTR include files named *wsrep* are required by other tests. Removing the following from the CMake install macros will avoid excluding the MTR test .inc files: `|include/((w.*)?wsrep.*|.*galera.*)\\.inc` All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. --- cmake/install_macros.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake index 7814f1dbeac..fba0bd03dac 100644 --- a/cmake/install_macros.cmake +++ b/cmake/install_macros.cmake @@ -266,7 +266,7 @@ SET(DEBUGBUILDDIR "${BINARY_PARENTDIR}/debug" CACHE INTERNAL "Directory of debug FUNCTION(INSTALL_MYSQL_TEST from to) IF(INSTALL_MYSQLTESTDIR) IF(NOT WITH_WSREP) - SET(EXCL_GALERA "(suite/(galera|wsrep|sys_vars/[rt]/(sysvars_)?wsrep).*|include/((w.*)?wsrep.*|.*galera.*)\\.inc|std_data/(galera|wsrep).*)") + SET(EXCL_GALERA "(suite/(galera|wsrep|sys_vars/[rt]/(sysvars_)?wsrep).*|std_data/(galera|wsrep).*)") ELSE() SET(EXCL_GALERA "^DOES_NOT_EXIST$") ENDIF() From 12a85c6caf595c685336455e416099b6a8020534 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 5 Jan 2023 11:06:35 +0530 Subject: [PATCH 3/7] MDEV-30346 Avoid block device required error in innodb_fts.misc_debug - Returns DB_LOCK_WAIT_TIMEOUT for the stats_lock_fail debug sync point --- mysql-test/suite/innodb_fts/r/misc_debug.result | 2 +- mysql-test/suite/innodb_fts/t/misc_debug.test | 2 +- storage/innobase/handler/handler0alter.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/innodb_fts/r/misc_debug.result b/mysql-test/suite/innodb_fts/r/misc_debug.result index 11df7d89f0b..cdfc4ff489a 100644 --- a/mysql-test/suite/innodb_fts/r/misc_debug.result +++ b/mysql-test/suite/innodb_fts/r/misc_debug.result @@ -68,7 +68,7 @@ DROP TABLE t1; CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100))ENGINE=InnoDB; SET DEBUG_DBUG="+d,stats_lock_fail"; ALTER TABLE t1 ADD FULLTEXT(f2); -ERROR HY000: Got error 15 "Block device required" from storage engine InnoDB +ERROR HY000: Lock wait timeout exceeded; try restarting transaction SET debug_dbug=@saved_debug_dbug; ALTER TABLE t1 DISCARD TABLESPACE; ALTER TABLE t1 ADD FULLTEXT(f2); diff --git a/mysql-test/suite/innodb_fts/t/misc_debug.test b/mysql-test/suite/innodb_fts/t/misc_debug.test index 229d468201e..08581768eec 100644 --- a/mysql-test/suite/innodb_fts/t/misc_debug.test +++ b/mysql-test/suite/innodb_fts/t/misc_debug.test @@ -108,7 +108,7 @@ DROP TABLE t1; CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100))ENGINE=InnoDB; SET DEBUG_DBUG="+d,stats_lock_fail"; ---error ER_GET_ERRNO +--error ER_LOCK_WAIT_TIMEOUT ALTER TABLE t1 ADD FULLTEXT(f2); SET debug_dbug=@saved_debug_dbug; ALTER TABLE t1 DISCARD TABLESPACE; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 2acf888e625..7c162b9af6a 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -11273,7 +11273,7 @@ err_index: } DBUG_EXECUTE_IF("stats_lock_fail", - error = DB_LOCK_WAIT;); + error = DB_LOCK_WAIT_TIMEOUT;); if (error == DB_SUCCESS) { error = lock_sys_tables(trx); From 494acc19388c7d7f744ebc036cae1329e46101bb Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 4 Jan 2023 19:16:45 +0200 Subject: [PATCH 4/7] MDEV-30325 Wrong result upon range query using index condition wrong result upon range query using index condition This was caused by a bug in key_or() when SEL_ARG* key1 has been cloned and is overlapping with SEL_ARG *key2 Cloning of SEL_ARG's happens only in very special cases, which is why this bug has remained undetected for years. It happend in the following query: SELECT COUNT(*) FROM lineitem force index (i_l_orderkey_quantity,i_l_shipdate) WHERE l_shipdate < '1994-01-01' AND l_orderkey < 800 OR l_quantity > 3 AND l_orderkey NOT IN ( 157, 1444 ); Because there are two different indexes that can be used and the code for IN causes a 'tree_or', which causes all SEL_ARG's to be cloned. Other things: - While checking the code, I found a bug in SEL_ARG::SEL_ARG(SEL_ARG &arg) - This was incrementing next_key_part->use_count as part of creating a copy of an existing SEL_ARG. This is however not enough as the 'reverse operation' when the copy is not needed is 'key2_cpy.increment_use_count(-1)', which does something completely different. Fixed by calling increment_use_count(1) in SEL_ARG::SEL_ARG. --- mysql-test/main/range_aria_dbt3.result | 13 +++++++++++++ mysql-test/main/range_aria_dbt3.test | 24 ++++++++++++++++++++++++ sql/opt_range.cc | 8 ++++---- 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 mysql-test/main/range_aria_dbt3.result create mode 100644 mysql-test/main/range_aria_dbt3.test diff --git a/mysql-test/main/range_aria_dbt3.result b/mysql-test/main/range_aria_dbt3.result new file mode 100644 index 00000000000..ae5a2e1329f --- /dev/null +++ b/mysql-test/main/range_aria_dbt3.result @@ -0,0 +1,13 @@ +set default_storage_engine=Aria; +CREATE DATABASE dbt3_s001; +use dbt3_s001; +# +# MDEV-30325 Wrong result upon range query using index condition +# +SELECT COUNT(*) FROM lineitem force index (i_l_orderkey_quantity,i_l_shipdate) WHERE l_shipdate < '1994-01-01' AND l_orderkey < 800 OR l_quantity > 3 AND l_orderkey NOT IN ( 157, 1444 ); +COUNT(*) +5056 +# +# End of 10.5 tests +# +DROP DATABASE dbt3_s001; diff --git a/mysql-test/main/range_aria_dbt3.test b/mysql-test/main/range_aria_dbt3.test new file mode 100644 index 00000000000..89328280987 --- /dev/null +++ b/mysql-test/main/range_aria_dbt3.test @@ -0,0 +1,24 @@ +# +# This is generic tests using dbt3_s001 tables +# This file uses the Aria storage engine +# + +set default_storage_engine=Aria; + +CREATE DATABASE dbt3_s001; +use dbt3_s001; +--disable_query_log +--source include/dbt3_s001.inc +--enable_query_log + +--echo # +--echo # MDEV-30325 Wrong result upon range query using index condition +--echo # + +SELECT COUNT(*) FROM lineitem force index (i_l_orderkey_quantity,i_l_shipdate) WHERE l_shipdate < '1994-01-01' AND l_orderkey < 800 OR l_quantity > 3 AND l_orderkey NOT IN ( 157, 1444 ); + +--echo # +--echo # End of 10.5 tests +--echo # + +DROP DATABASE dbt3_s001; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ee2ac81abeb..3999d75eb20 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1890,7 +1890,7 @@ SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc() next= 0; if (next_key_part) { - ++next_key_part->use_count; + next_key_part->increment_use_count(1); weight += next_key_part->weight; } } @@ -10607,8 +10607,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) Move on to next range in key2 */ key2->increment_use_count(-1); // Free not used tree - key2=key2_next; - continue; + key2= key2_next; } else { @@ -10622,8 +10621,9 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) tmp: [---------] */ key2->copy_max_to_min(tmp); - continue; + key2= key2_next; } + continue; } /* From d0a534d293edbb1d5345616e3052c0f9b94260a8 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Thu, 5 Jan 2023 14:06:01 +0600 Subject: [PATCH 5/7] Fix synopses in mysys APIs Since 7c58e97 the PSI_memory_key was added to some routines in the mysys/. This commit fixes synopses of functions that were updated with the PSI_memory_key parameter. --- mysys/array.c | 1 + mysys/hash.c | 3 ++- mysys/my_alloc.c | 2 +- mysys/my_malloc.c | 4 +++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/mysys/array.c b/mysys/array.c index 59698a4cc7c..29527ab5145 100644 --- a/mysys/array.c +++ b/mysys/array.c @@ -23,6 +23,7 @@ SYNOPSIS init_dynamic_array2() + ps_key Key to register instrumented memory array Pointer to an array element_size Size of element init_buffer Initial buffer pointer diff --git a/mysys/hash.c b/mysys/hash.c index abc11b42500..c86b0d92cb6 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -60,8 +60,9 @@ my_hash_value_type my_hash_sort(CHARSET_INFO *cs, const uchar *key, dynamic array that is part of the hash will allocate memory as required during insertion. + @param[in] psi_key The key to register instrumented memory @param[in,out] hash The hash that is initialized - @param[in[ growth_size size incrememnt for the underlying dynarray + @param[in] growth_size size incrememnt for the underlying dynarray @param[in] charset The character set information @param[in] size The hash size @param[in] key_offest The key offset for the hash diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 3e0b774b0c7..c3205eac6f0 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -34,8 +34,8 @@ SYNOPSIS init_alloc_root() + key - key to register instrumented memory mem_root - memory root to initialize - name - name of memroot (for debugging) block_size - size of chunks (blocks) used for memory allocation (It is external size of chunk i.e. it should include memory required for internal structures, thus it diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c index befdcb0e5c3..c32831ed20d 100644 --- a/mysys/my_malloc.c +++ b/mysys/my_malloc.c @@ -59,6 +59,7 @@ void set_malloc_size_cb(MALLOC_SIZE_CB func) /** Allocate a sized block of memory. + @param key Key to register instrumented memory @param size The size of the memory block in bytes. @param flags Failure action modifiers (bitmasks). @@ -120,7 +121,8 @@ void *my_malloc(PSI_memory_key key, size_t size, myf my_flags) /** @brief wrapper around realloc() - @param old_point pointer to currently allocated area + @param key key to register instrumented memory + @param old_point pointer to currently allocated area @param size new size requested, must be >0 @param my_flags flags From cad33ded19e45a0187754b2ad03c4c634405aa46 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 6 Jan 2023 09:08:43 +1100 Subject: [PATCH 6/7] MDEV-30344: Without wsrep needs wsrep{,_on}.h headers In the Develop package because of their use from sql_class.h which is the main file for THD needed by server plugins. --- include/CMakeLists.txt | 2 -- sql/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index e094a7b7a0c..1024821e569 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -77,7 +77,6 @@ FOREACH(f ${HEADERS_GEN_CONFIGURE}) ENDFOREACH(f) IF(NOT WITH_WSREP) SET(EXCL_SERVICE_WSREP "service_wsrep.h") - SET(EXCL_WSREP "wsrep.h") ENDIF() INSTALL(DIRECTORY mysql/ DESTINATION ${INSTALL_INCLUDEDIR}/server/mysql COMPONENT Development @@ -94,7 +93,6 @@ MACRO(INSTALL_PRIVATE DIR) FILES_MATCHING PATTERN "*.h" PATTERN CMakeFiles EXCLUDE PATTERN mysql EXCLUDE - PATTERN "${EXCL_WSREP}" EXCLUDE REGEX "\\./(${EXCL_RE}$)" EXCLUDE) ENDMACRO() diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 583fe11b38b..18054252584 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -496,7 +496,7 @@ IF(WIN32) ENDIF(WIN32) IF(NOT WITH_WSREP) - SET(EXCL_WSREP "wsrep*.h") + SET(EXCL_WSREP "wsrep_[a-np-z]*.h") ENDIF() INSTALL(DIRECTORY . DESTINATION ${INSTALL_INCLUDEDIR}/server/private COMPONENT Development FILES_MATCHING PATTERN "*.h" From 17858e03a7bfe7f154a7f8097d2473dbd1cb20f2 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 2 Jan 2023 13:13:59 +0530 Subject: [PATCH 7/7] MDEV-30179 mariabackup --backup fails with FATAL ERROR: ... failed to copy datafile - Mariabackup fails to copy the undo log tablespace when it undergoes truncation. So Mariabackup should detect the redo log which does undo tablespace truncation and also backup should read the minimum file size of the tablespace and ignore the error while reading. - Throw error when innodb undo tablespace read failed, but backup doesn't find the redo log for undo tablespace truncation --- extra/mariabackup/fil_cur.cc | 27 +++++++++++++-- extra/mariabackup/fil_cur.h | 1 + extra/mariabackup/xtrabackup.cc | 54 ++++++++++++++++++++++++++--- storage/innobase/include/log0recv.h | 5 +++ storage/innobase/log/log0recv.cc | 4 +++ 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index 8fe6af06b76..8d7fb3c7492 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -130,6 +130,7 @@ xb_fil_cur_open( in case of error */ cursor->buf = NULL; cursor->node = NULL; + cursor->n_process_batch = 0; cursor->space_id = node->space->id; @@ -374,6 +375,8 @@ xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t* cursor, return(XB_FIL_CUR_EOF); } +reinit_buf: + cursor->n_process_batch++; if (to_read > (ib_int64_t) cursor->buf_size) { to_read = (ib_int64_t) cursor->buf_size; } @@ -415,9 +418,27 @@ read_retry: cursor->buf_page_no = static_cast(offset / page_size); if (os_file_read(IORequestRead, cursor->file, cursor->buf, offset, - (ulint) to_read) != DB_SUCCESS) { - ret = XB_FIL_CUR_ERROR; - goto func_exit; + (ulint) to_read) != DB_SUCCESS) { + if (!srv_is_undo_tablespace(cursor->space_id)) { + ret = XB_FIL_CUR_ERROR; + goto func_exit; + } + + if (cursor->buf_page_no + >= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES) { + ret = XB_FIL_CUR_SKIP; + goto func_exit; + } + + to_read = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES * page_size; + + if (cursor->n_process_batch > 1) { + ret = XB_FIL_CUR_ERROR; + goto func_exit; + } + + space->release(); + goto reinit_buf; } /* check pages for corruption and re-read if necessary. i.e. in case of partially written pages */ diff --git a/extra/mariabackup/fil_cur.h b/extra/mariabackup/fil_cur.h index 0027b7768e9..ac561f71060 100644 --- a/extra/mariabackup/fil_cur.h +++ b/extra/mariabackup/fil_cur.h @@ -58,6 +58,7 @@ struct xb_fil_cur_t { uint thread_n; /*!< thread number for diagnostics */ ulint space_id; /*!< ID of tablespace */ ulint space_size; /*!< space size in pages */ + uint32_t n_process_batch;/*!< Number of batch processed */ /** @return whether this is not a file-per-table tablespace */ bool is_system() const diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 1c64e0a8f2a..2c8b83d3a67 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -247,6 +247,10 @@ long innobase_file_io_threads = 4; ulong innobase_read_io_threads = 4; ulong innobase_write_io_threads = 4; +/** Store the failed read of undo tablespace ids. Protected by +backup mutex */ +static std::set fail_undo_ids; + longlong innobase_page_size = (1LL << 14); /* 16KB */ char* innobase_buffer_pool_filename = NULL; @@ -366,6 +370,10 @@ struct ddl_tracker_t { static ddl_tracker_t ddl_tracker; +/** Store the space ids of truncated undo log tablespaces. Protected +by recv_sys.mutex */ +static std::set undo_trunc_ids; + // Convert non-null terminated filename to space name std::string filename_to_spacename(const byte *filename, size_t len); @@ -874,6 +882,10 @@ static void backup_file_op_fail(ulint space_id, bool create, } } +static void backup_undo_trunc(uint32_t space_id) +{ + undo_trunc_ids.insert(space_id); +} /* Retrieve default data directory, to be used with --copy-back. @@ -2780,15 +2792,27 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n, } /* The main copy loop */ - while ((res = xb_fil_cur_read(&cursor, corrupted_pages)) == - XB_FIL_CUR_SUCCESS) { + while (1) { + res = xb_fil_cur_read(&cursor, corrupted_pages); + if (res == XB_FIL_CUR_ERROR) { + goto error; + } + + if (res == XB_FIL_CUR_EOF) { + break; + } + if (!write_filter.process(&write_filt_ctxt, dstfile)) { goto error; } - } - if (res == XB_FIL_CUR_ERROR) { - goto error; + if (res == XB_FIL_CUR_SKIP) { + pthread_mutex_lock(&backup_mutex); + fail_undo_ids.insert( + static_cast(cursor.space_id)); + pthread_mutex_unlock(&backup_mutex); + break; + } } if (write_filter.finalize @@ -4368,6 +4392,23 @@ static bool xtrabackup_backup_low() dst_log_file = NULL; + std::vector failed_ids; + std::set_difference( + fail_undo_ids.begin(), fail_undo_ids.end(), + undo_trunc_ids.begin(), undo_trunc_ids.end(), + std::inserter(failed_ids, failed_ids.begin())); + + for (uint32_t id : failed_ids) { + msg("mariabackup: Failed to read undo log " + "tablespace space id %d and there is no undo " + "tablespace truncation redo record.", + id); + } + + if (failed_ids.size() > 0) { + return false; + } + if(!xtrabackup_incremental) { strcpy(metadata_type, "full-backuped"); metadata_from_lsn = 0; @@ -4442,6 +4483,7 @@ static bool xtrabackup_backup_func() srv_operation = SRV_OPERATION_BACKUP; log_file_op = backup_file_op; + undo_space_trunc = backup_undo_trunc; metadata_to_lsn = 0; /* initialize components */ @@ -4450,6 +4492,7 @@ fail: metadata_to_lsn = log_copying_running; stop_backup_threads(); log_file_op = NULL; + undo_space_trunc = NULL; if (dst_log_file) { ds_close(dst_log_file); dst_log_file = NULL; @@ -4741,6 +4784,7 @@ fail_before_log_copying_thread_start: innodb_shutdown(); log_file_op = NULL; + undo_space_trunc = NULL; pthread_mutex_destroy(&backup_mutex); pthread_cond_destroy(&scanned_lsn_cond); if (!corrupted_pages.empty()) { diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index 9159ba00859..e4a8f0d25a2 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -90,6 +90,11 @@ extern void (*log_file_op)(ulint space_id, bool create, const byte* name, ulint len, const byte* new_name, ulint new_len); +/** Report an operation which does undo log tablespace truncation +during backup +@param space_id undo tablespace identifier */ +extern void (*undo_space_trunc)(uint32_t space_id); + /** Stored redo log record */ struct log_rec_t { diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 511ccc5afe6..d21251dd2d9 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -596,6 +596,8 @@ void (*log_file_op)(ulint space_id, bool create, const byte* name, ulint len, const byte* new_name, ulint new_len); +void (*undo_space_trunc)(uint32_t space_id); + /** Information about initializing page contents during redo log processing. FIXME: Rely on recv_sys.pages! */ class mlog_init_t @@ -1949,6 +1951,8 @@ same_page: TRX_SYS_MAX_UNDO_SPACES, "compatibility"); truncated_undo_spaces[space_id - srv_undo_space_id_start]= { recovered_lsn, page_no }; + if (undo_space_trunc) + undo_space_trunc(space_id); #endif last_offset= 1; /* the next record must not be same_page */ continue;