From 7b44d0ba573c3a07d5fe8b43251c705ec1d63597 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 29 Nov 2022 05:21:03 +1100 Subject: [PATCH 1/9] MDEV-23230 wsrep files installed when built without WSREP (#2334) Prevent wsrep files from being installed if WITH_WSREP=OFF. Reviewed by Daniel Black Additionally excluded #include wsrep files and galera* files along with galera/wsrep tests. mysql-test/include/have_wsrep.inc remainds as its used by a few isolated tests. Co-authored-by: Chris Ross --- CMakeLists.txt | 5 ++++- cmake/install_macros.cmake | 6 ++++++ cmake/systemd.cmake | 5 ++++- include/CMakeLists.txt | 11 ++++++++++- man/CMakeLists.txt | 12 +++++++----- sql/CMakeLists.txt | 4 ++++ support-files/CMakeLists.txt | 12 ++++++++++-- 7 files changed, 45 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8a420afed4..f530d2abdc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -550,7 +550,10 @@ INSTALL_DOCUMENTATION(README.md CREDITS COPYING THIRDPARTY COMPONENT Readme) # ${CMAKE_BINARY_DIR}/Docs/INFO_BIN) IF(UNIX) - INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY Docs/README-wsrep COMPONENT Readme) + INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY COMPONENT Readme) + IF(WITH_WSREP) + INSTALL_DOCUMENTATION(Docs/README-wsrep COMPONENT Readme) + ENDIF() ENDIF() INCLUDE(build_depends) diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake index 765f3be23e0..7814f1dbeac 100644 --- a/cmake/install_macros.cmake +++ b/cmake/install_macros.cmake @@ -265,6 +265,11 @@ 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).*)") + ELSE() + SET(EXCL_GALERA "^DOES_NOT_EXIST$") + ENDIF() INSTALL( DIRECTORY ${from} DESTINATION "${INSTALL_MYSQLTESTDIR}/${to}" @@ -286,6 +291,7 @@ FUNCTION(INSTALL_MYSQL_TEST from to) PATTERN "*.vcxproj.user" EXCLUDE PATTERN "CTest*" EXCLUDE PATTERN "*~" EXCLUDE + REGEX "${EXCL_GALERA}" EXCLUDE ) ENDIF() ENDFUNCTION() diff --git a/cmake/systemd.cmake b/cmake/systemd.cmake index 255abe62351..a093b89f3c8 100644 --- a/cmake/systemd.cmake +++ b/cmake/systemd.cmake @@ -44,7 +44,10 @@ MACRO(CHECK_SYSTEMD) IF(HAVE_SYSTEMD_SD_DAEMON_H AND HAVE_SYSTEMD_SD_LISTEN_FDS AND HAVE_SYSTEMD_SD_NOTIFY AND HAVE_SYSTEMD_SD_NOTIFYF) SET(HAVE_SYSTEMD TRUE) - SET(SYSTEMD_SCRIPTS mariadb-service-convert galera_new_cluster galera_recovery) + SET(SYSTEMD_SCRIPTS mariadb-service-convert) + IF(WITH_WSREP) + SET(SYSTEMD_SCRIPTS ${SYSTEMD_SCRIPTS} galera_new_cluster galera_recovery) + ENDIF() IF(DEB) SET(SYSTEMD_EXECSTARTPRE "ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld") SET(SYSTEMD_EXECSTARTPOST "ExecStartPost=/etc/mysql/debian-start") diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index a7b98a11050..7076d2d88d2 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -74,7 +74,15 @@ FOREACH(f ${HEADERS_GEN_CONFIGURE}) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${f} DESTINATION ${INSTALL_INCLUDEDIR}/server COMPONENT Development) ENDFOREACH(f) -INSTALL(DIRECTORY mysql/ DESTINATION ${INSTALL_INCLUDEDIR}/server/mysql COMPONENT Development FILES_MATCHING PATTERN "*.h") +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 + FILES_MATCHING PATTERN "*.h" + PATTERN "${EXCL_SERVICE_WSREP}" EXCLUDE +) STRING(REPLACE "." "\\." EXCL_RE "${HEADERS};${HEADERS_GEN_CONFIGURE}") STRING(REPLACE ";" "|" EXCL_RE "${EXCL_RE}") @@ -85,6 +93,7 @@ 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/man/CMakeLists.txt b/man/CMakeLists.txt index f5ae0a0fb38..975bfd5e887 100644 --- a/man/CMakeLists.txt +++ b/man/CMakeLists.txt @@ -13,6 +13,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA +SET(MAN1_WSREP wsrep_sst_rsync.1 wsrep_sst_common.1 wsrep_sst_mariabackup.1 + wsrep_sst_mysqldump.1 wsrep_sst_rsync_wan.1 galera_recovery.1 galera_new_cluster.1) SET(MAN1_SERVER innochecksum.1 myisam_ftdump.1 myisamchk.1 aria_chk.1 aria_dump_log.1 aria_ftdump.1 aria_pack.1 aria_read_log.1 aria_s3_copy.1 @@ -24,12 +26,12 @@ SET(MAN1_SERVER innochecksum.1 myisam_ftdump.1 myisamchk.1 mysqld_multi.1 mysqld_safe.1 mysqldumpslow.1 mysqlhotcopy.1 perror.1 replace.1 resolve_stack_dump.1 resolveip.1 mariadb-service-convert.1 - mysqld_safe_helper.1 wsrep_sst_common.1 - wsrep_sst_mysqldump.1 wsrep_sst_rsync.1 - galera_recovery.1 galera_new_cluster.1 + mysqld_safe_helper.1 mysql_ldb.1 myrocks_hotbackup.1 - wsrep_sst_mariabackup.1 mbstream.1 mariabackup.1 - wsrep_sst_rsync_wan.1) + mbstream.1 mariabackup.1) +IF(WITH_WSREP) + SET(MAN1_SERVER ${MAN1_SERVER} ${MAN1_WSREP}) +ENDIF() SET(MAN8_SERVER mysqld.8) SET(MAN1_CLIENT msql2mysql.1 mysql.1 mysql_find_rows.1 mysql_waitpid.1 mysqlaccess.1 mysqladmin.1 mysqlbinlog.1 mysqlcheck.1 diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8143136b13b..583fe11b38b 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -495,7 +495,11 @@ IF(WIN32) TARGET_LINK_LIBRARIES(mariadb-upgrade-service mysys winservice) ENDIF(WIN32) +IF(NOT WITH_WSREP) + SET(EXCL_WSREP "wsrep*.h") +ENDIF() INSTALL(DIRECTORY . DESTINATION ${INSTALL_INCLUDEDIR}/server/private COMPONENT Development FILES_MATCHING PATTERN "*.h" PATTERN share EXCLUDE + PATTERN "${EXCL_WSREP}" EXCLUDE PATTERN CMakeFiles EXCLUDE) diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index ff468dcbe9c..d65408fc4dd 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -51,7 +51,11 @@ ENDIF() IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) - FOREACH(script mysqld_multi.server mysql-log-rotate binary-configure wsrep_notify) + SET(SCRIPTS mysqld_multi.server mysql-log-rotate binary-configure) + IF(WITH_WSREP) + SET(SCRIPTS ${SCRIPTS} wsrep_notify) + ENDIF() + FOREACH(script ${SCRIPTS}) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${script}.sh ${CMAKE_CURRENT_BINARY_DIR}/${script} @ONLY ) INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${script} @@ -126,7 +130,11 @@ IF(UNIX) COMMAND ${CMAKE_COMMAND} -E create_symlink ./mariadb.service mysqld.service WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - INSTALL(FILES use_galera_new_cluster.conf + IF(WITH_WSREP) + INSTALL(FILES use_galera_new_cluster.conf + DESTINATION ${inst_location}/systemd COMPONENT SupportFiles) + ENDIF() + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mariadb.service ${CMAKE_CURRENT_BINARY_DIR}/mysql.service ${CMAKE_CURRENT_BINARY_DIR}/mysqld.service From c1de3776a6c6e7bbb170d336cdbc6023cdd28645 Mon Sep 17 00:00:00 2001 From: anson1014 <56494179+anson1014@users.noreply.github.com> Date: Tue, 29 Nov 2022 05:08:14 -0800 Subject: [PATCH 2/9] Extend GitLab CI with build and test jobs for sanitizers (#2174) Add a build and test job for each of ASAN, MSAN, TSAN, and UBSAN to the GitLab pipeline such that current vulnerabilities will be more easily visible and on each new commit, we can ensure that there are no additional errors introduced. Furthermore, sanitizer test runs are run separate from the existing mysql-test-run to isolate sanitizer error from functional errors. 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. --- .gitlab-ci.yml | 108 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2254164da4b..06a6feef8c3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -172,6 +172,39 @@ fedora-clang: - dependencies.dot - dependencies.png +fedora-sanitizer: + stage: build + variables: + GIT_STRATEGY: fetch + GIT_SUBMODULE_STRATEGY: normal + script: + - yum install -y yum-utils rpm-build openssl-devel clang + - yum install -y /usr/lib64/libasan.so.6.0.0 /usr/lib64/libtsan.so.0.0.0 /usr/lib64/libubsan.so.1.0.0 + # This repository does not have any .spec files, so install dependencies based on Fedora spec file + - yum-builddep -y mariadb-server + - mkdir builddir; cd builddir + - export CXX=${CXX:-clang++} + - export CC=${CC:-clang} + - export CXX_FOR_BUILD=${CXX_FOR_BUILD:-clang++} + - export CC_FOR_BUILD=${CC_FOR_BUILD:-clang} + - export CFLAGS='-Wno-unused-command-line-argument' + - export CXXFLAGS='-Wno-unused-command-line-argument' + - cmake -DRPM=$CI_JOB_NAME $CMAKE_FLAGS $SANITIZER .. 2>&1 | tee -a ../build-$CI_JOB_NAME-$CI_COMMIT_REF_SLUG.log + # @TODO: the build will fail consistently at 24% when trying to make using eatmydata + - make package -j 2 2>&1 | tee -a ../build-$CI_JOB_NAME-$CI_COMMIT_REF_SLUG.log + - *rpm_listfiles + - mkdir ../rpm; mv *.rpm ../rpm + artifacts: + when: always # Must be able to see logs + paths: + - build-$CI_JOB_NAME-$CI_COMMIT_REF_SLUG.log + - rpmlist-$CI_JOB_NAME-$CI_COMMIT_REF_SLUG.log + - rpm + - builddir/_CPack_Packages/Linux/RPM/SPECS/ + parallel: + matrix: + - SANITIZER: [-DWITH_ASAN=YES, -DWITH_TSAN=YES, -DWITH_UBSAN=YES, -DWITH_MSAN=YES] + centos8: stage: build image: quay.io/centos/centos:stream8 # CentOS 8 is deprecated, use this Stream8 instead @@ -246,10 +279,8 @@ centos7: - rpm - builddir/_CPack_Packages/Linux/RPM/SPECS/ -mysql-test-run: +.mysql-test-run: &mysql-test-run-def stage: test - dependencies: - - fedora script: # Install packages so tests and the dependencies install # @TODO: RPM missing 'patch' and 'diff' as dependency, so installing it manually for now @@ -265,7 +296,76 @@ mysql-test-run: main.flush_logs_not_windows : query 'flush logs' succeeded - should have failed with error ER_CANT_CREATE_FILE (1004) main.mysql_upgrade_noengine : upgrade output order does not match the expected " > skiplist - - ./mtr --suite=main --force --parallel=auto --xml-report=$CI_PROJECT_DIR/junit.xml --skip-test-list=skiplist + - ./mtr --suite=main --force --parallel=auto --xml-report=$CI_PROJECT_DIR/junit.xml --skip-test-list=skiplist $RESTART_POLICY + +mysql-test-run: + stage: test + dependencies: + - fedora + <<: *mysql-test-run-def + artifacts: + when: always # Also show results when tests fail + reports: + junit: + - junit.xml + +# Duplicate of the above jobs, except we use sanitizer build jobs as a dependency. This is so we can keep +# sanitizer errors separate from functional test failures. Currently, there is no way to run the same +# job for different dependencies. +# +# Additionally, for each sanitizer MTR job, we enable --force-restart so that +# sanitizer errors can be traced to individual tests. The difference in test +# suite runtime as a result of this flag is negligable (~30s for the entire test suite). +# (see https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_MYSQL_TEST_RUN_PL.html) +mysql-test-run-asan: + stage: test + variables: + RESTART_POLICY: "--force-restart" + dependencies: + - "fedora-sanitizer: [-DWITH_ASAN=YES]" + <<: *mysql-test-run-def + artifacts: + when: always # Also show results when tests fail + reports: + junit: + - junit.xml + +mysql-test-run-tsan: + stage: test + variables: + RESTART_POLICY: "--force-restart" + dependencies: + - "fedora-sanitizer: [-DWITH_TSAN=YES]" + <<: *mysql-test-run-def + allow_failure: true + artifacts: + when: always # Also show results when tests fail + reports: + junit: + - junit.xml + +mysql-test-run-ubsan: + stage: test + variables: + RESTART_POLICY: "--force-restart" + dependencies: + - "fedora-sanitizer: [-DWITH_UBSAN=YES]" + <<: *mysql-test-run-def + allow_failure: true + artifacts: + when: always # Also show results when tests fail + reports: + junit: + - junit.xml + +mysql-test-run-msan: + stage: test + variables: + RESTART_POLICY: "--force-restart" + dependencies: + - "fedora-sanitizer: [-DWITH_MSAN=YES]" + <<: *mysql-test-run-def + allow_failure: true artifacts: when: always # Also show results when tests fail reports: From bb29712b450525ba9e956033387361830361932f Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 29 Nov 2022 17:19:30 +0530 Subject: [PATCH 3/9] MDEV-30119 INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION.NAME is NULL for undo tablespaces - Information_schema.innodb_tablespaces_encryption should print undo tablespace name as innodb_undo001, innodb_undo002 and soon. - Encryption test should include undo tablespaces count when the tests are waiting for the condition to check whether all tables are encrypted or decrypted. --- .../encryption/r/encrypt_and_grep,undo3.rdiff | 32 ++++++++++ .../r/innodb-remove-encryption,undo3.rdiff | 32 ++++++++++ .../r/innodb_encrypt_freed,undo3.rdiff | 62 +++++++++++++++++++ ...nnodb_encrypt_key_rotation_age,undo3.rdiff | 52 ++++++++++++++++ .../encryption/t/debug_key_management.test | 3 +- .../suite/encryption/t/encrypt_and_grep.test | 4 +- .../t/innodb-remove-encryption.test | 3 +- .../encryption/t/innodb_encrypt_freed.test | 11 ++-- .../t/innodb_encrypt_key_rotation_age.test | 9 +-- .../suite/encryption/t/innodb_first_page.test | 2 + storage/innobase/handler/i_s.cc | 9 ++- 11 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 mysql-test/suite/encryption/r/encrypt_and_grep,undo3.rdiff create mode 100644 mysql-test/suite/encryption/r/innodb-remove-encryption,undo3.rdiff create mode 100644 mysql-test/suite/encryption/r/innodb_encrypt_freed,undo3.rdiff create mode 100644 mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age,undo3.rdiff diff --git a/mysql-test/suite/encryption/r/encrypt_and_grep,undo3.rdiff b/mysql-test/suite/encryption/r/encrypt_and_grep,undo3.rdiff new file mode 100644 index 00000000000..210c2a61a17 --- /dev/null +++ b/mysql-test/suite/encryption/r/encrypt_and_grep,undo3.rdiff @@ -0,0 +1,32 @@ +--- encrypt_and_grep.result 2022-09-02 22:36:21.669650278 +0530 ++++ encrypt_and_grep.reject 2022-11-29 19:01:22.080027528 +0530 +@@ -14,6 +14,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -35,6 +38,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -62,6 +68,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry diff --git a/mysql-test/suite/encryption/r/innodb-remove-encryption,undo3.rdiff b/mysql-test/suite/encryption/r/innodb-remove-encryption,undo3.rdiff new file mode 100644 index 00000000000..421c962bd2e --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb-remove-encryption,undo3.rdiff @@ -0,0 +1,32 @@ +--- innodb-remove-encryption.result 2022-09-02 20:44:59.960430396 +0530 ++++ innodb-remove-encryption,undo3.reject 2022-11-29 19:02:24.813094277 +0530 +@@ -13,6 +13,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -24,6 +27,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -36,6 +42,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_freed,undo3.rdiff b/mysql-test/suite/encryption/r/innodb_encrypt_freed,undo3.rdiff new file mode 100644 index 00000000000..36eea901a6e --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb_encrypt_freed,undo3.rdiff @@ -0,0 +1,62 @@ +--- innodb_encrypt_freed.result 2021-03-23 15:44:14.466377983 +0530 ++++ innodb_encrypt_freed,undo3.reject 2022-11-29 19:04:24.987010571 +0530 +@@ -14,6 +14,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -29,6 +32,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -40,6 +46,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -55,6 +64,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -70,6 +82,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -87,6 +102,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age,undo3.rdiff b/mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age,undo3.rdiff new file mode 100644 index 00000000000..476b0b3f213 --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age,undo3.rdiff @@ -0,0 +1,52 @@ +--- innodb_encrypt_key_rotation_age.result 2022-06-02 16:15:08.395122720 +0530 ++++ innodb_encrypt_key_rotation_age,undo3.reject 2022-11-29 19:06:07.964542115 +0530 +@@ -12,6 +12,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -27,6 +30,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -39,6 +45,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -59,6 +68,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry +@@ -71,6 +83,9 @@ + SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + NAME + innodb_system ++innodb_undo001 ++innodb_undo002 ++innodb_undo003 + mysql/innodb_index_stats + mysql/innodb_table_stats + mysql/transaction_registry diff --git a/mysql-test/suite/encryption/t/debug_key_management.test b/mysql-test/suite/encryption/t/debug_key_management.test index 15a560d4c42..45a93040d73 100644 --- a/mysql-test/suite/encryption/t/debug_key_management.test +++ b/mysql-test/suite/encryption/t/debug_key_management.test @@ -1,5 +1,6 @@ -- source include/have_innodb.inc -- source include/have_debug.inc +-- source include/innodb_undo_tablespaces.inc -- source include/not_embedded.inc if (`select count(*) = 0 from information_schema.plugins @@ -13,7 +14,7 @@ create table t1(a serial) engine=innoDB; set global innodb_encrypt_tables=ON; show variables like 'innodb_encrypt%'; ---let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + 1 + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` let $wait_condition= select count(*) = $tables_count from information_schema.innodb_tablespaces_encryption where current_key_version=1; --source include/wait_condition.inc diff --git a/mysql-test/suite/encryption/t/encrypt_and_grep.test b/mysql-test/suite/encryption/t/encrypt_and_grep.test index 03f67db83f9..687f14e8a55 100644 --- a/mysql-test/suite/encryption/t/encrypt_and_grep.test +++ b/mysql-test/suite/encryption/t/encrypt_and_grep.test @@ -1,4 +1,5 @@ -- source include/have_innodb.inc +-- source include/innodb_undo_tablespaces.inc -- source include/have_file_key_management_plugin.inc # @@ -59,7 +60,8 @@ SET GLOBAL innodb_encrypt_tables = off; --echo # Wait max 10 min for key encryption threads to decrypt all spaces --let $wait_timeout= 600 ---let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` + --let $wait_condition=SELECT COUNT(*) = $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND CURRENT_KEY_VERSION = 0; --source include/wait_condition.inc diff --git a/mysql-test/suite/encryption/t/innodb-remove-encryption.test b/mysql-test/suite/encryption/t/innodb-remove-encryption.test index 1982616aec2..8ff5fd632fd 100644 --- a/mysql-test/suite/encryption/t/innodb-remove-encryption.test +++ b/mysql-test/suite/encryption/t/innodb-remove-encryption.test @@ -2,6 +2,7 @@ # Test uses restart --source include/not_embedded.inc --source filekeys_plugin.inc +--source include/innodb_undo_tablespaces.inc # # MDEV-15566: System tablespace does not easily key rotate to unencrypted @@ -23,7 +24,7 @@ create table t1(a int not null primary key, b char(200)) engine=innodb; --echo # Wait until encryption threads have encrypted all tablespaces ---let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) = $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND ROTATING_OR_FLUSHING = 0; --source include/wait_condition.inc diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_freed.test b/mysql-test/suite/encryption/t/innodb_encrypt_freed.test index 785b4e9e498..7ba0b5a2d1a 100644 --- a/mysql-test/suite/encryption/t/innodb_encrypt_freed.test +++ b/mysql-test/suite/encryption/t/innodb_encrypt_freed.test @@ -2,6 +2,7 @@ --source include/have_example_key_management_plugin.inc --source include/have_debug.inc --source include/not_embedded.inc +--source include/innodb_undo_tablespaces.inc SHOW VARIABLES LIKE 'innodb_encrypt%'; @@ -10,7 +11,7 @@ SET GLOBAL innodb_encrypt_tables = ON; CREATE TABLE t1(f1 BIGINT PRIMARY KEY, f2 int not null, f3 int not null, index(f1), index idx_1(f2), index(f2, f3)) ENGINE=InnoDB; ---let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + 1 + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --echo # Wait max 10 min for key encryption threads to encrypt all spaces --let $wait_timeout= 600 @@ -30,12 +31,12 @@ insert into t2 values(1); connection default; ---let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + 1 + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` set global innodb_encrypt_tables = OFF; --echo # Wait max 10 min for key encryption threads to decrypt all spaces --let $wait_timeout= 600 ---let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 --source include/wait_condition.inc --sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; @@ -63,7 +64,7 @@ drop table t1, t2; CREATE TABLE t1(f1 BIGINT PRIMARY KEY, f2 int not null, f3 int not null, index(f1), index idx_1(f2), index(f2, f3)) ENGINE=InnoDB; ---let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + 1 + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --echo # Wait max 10 min for key encryption threads to encrypt all spaces --let $wait_timeout= 600 @@ -82,7 +83,7 @@ insert into t2 values(1); connection default; ---let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + 1 + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` set global innodb_encrypt_tables = OFF; --echo # Wait max 10 min for key encryption threads to decrypt all spaces diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test index ef38560c469..c96d33aa1af 100644 --- a/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test +++ b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test @@ -1,6 +1,7 @@ -- source include/have_innodb.inc -- source include/not_embedded.inc -- source include/have_example_key_management_plugin.inc +-- source include/innodb_undo_tablespaces.inc CREATE TABLE t1 (f1 INT, f2 VARCHAR(256))engine=innodb; INSERT INTO t1 VALUES(1, 'MariaDB'), (2, 'Robot'), (3, 'Science'); @@ -20,7 +21,7 @@ let $restart_parameters= --innodb_encryption_threads=5 --innodb_encryption_rotat --echo # Wait until encryption threads have encrypted all tablespaces ---let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + 1 + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc @@ -39,7 +40,7 @@ create table t4 (f1 int not null)engine=innodb encrypted=NO; --echo # Wait until encryption threads have encrypted all tablespaces ---let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc @@ -54,7 +55,7 @@ set global innodb_encrypt_tables = OFF; --echo # Wait until encryption threads to decrypt all unencrypted tablespaces ---let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND ROTATING_OR_FLUSHING = 0; --source include/wait_condition.inc @@ -69,7 +70,7 @@ set global innodb_encrypt_tables = ON; --echo # Wait until encryption threads to encrypt all unencrypted tablespaces ---let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc diff --git a/mysql-test/suite/encryption/t/innodb_first_page.test b/mysql-test/suite/encryption/t/innodb_first_page.test index 7f2f915d010..db4d8eb3b16 100644 --- a/mysql-test/suite/encryption/t/innodb_first_page.test +++ b/mysql-test/suite/encryption/t/innodb_first_page.test @@ -4,12 +4,14 @@ --source include/have_innodb.inc --source include/have_file_key_management_plugin.inc +--source include/innodb_undo_tablespaces.inc let $datadir=`select @@datadir`; --source include/shutdown_mysqld.inc --remove_file $datadir/ib_logfile0 --remove_file $datadir/ibdata1 +--remove_files_wildcard $datadir undo* --source include/start_mysqld.inc diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index bb2f1b6beda..063462a12b9 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6632,7 +6632,6 @@ i_s_dict_fill_tablespaces_encryption( { Field** fields; struct fil_space_crypt_status_t status; - DBUG_ENTER("i_s_dict_fill_tablespaces_encryption"); fields = table_to_fill->field; @@ -6654,6 +6653,14 @@ i_s_dict_fill_tablespaces_encryption( name.data(), name.size(), system_charset_info)); fields[TABLESPACES_ENCRYPTION_NAME]->set_notnull(); + } else if (srv_is_undo_tablespace(space->id)) { + char undo_name[sizeof "innodb_undo000"]; + snprintf(undo_name, sizeof(undo_name), + "innodb_undo%03zu",space->id); + OK(fields[TABLESPACES_ENCRYPTION_NAME]->store( + undo_name, strlen(undo_name), + system_charset_info)); + fields[TABLESPACES_ENCRYPTION_NAME]->set_notnull(); } else { fields[TABLESPACES_ENCRYPTION_NAME]->set_null(); } From 846112ce36844903284be3f2536c184a0bc226ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Nov 2022 06:57:32 +0200 Subject: [PATCH 4/9] MDEV-24412: Create a separate test Some builders in our CI, most notably FreeBSD and IBM AIX, do not support sparse files. Also, Microsoft Windows requires special means for creating sparse files. Since these platforms do not run ./mtr --big-test, we will for now simply move the test to a separate file that requires that option. --- .../r/innodb_encrypt_log_corruption.result | 10 +- .../suite/innodb/r/log_corruption.result | 10 +- mysql-test/suite/innodb/r/log_upgrade.result | 16 +++ mysql-test/suite/innodb/t/log_corruption.test | 36 ------ mysql-test/suite/innodb/t/log_upgrade.test | 118 ++++++++++++++++++ 5 files changed, 136 insertions(+), 54 deletions(-) create mode 100644 mysql-test/suite/innodb/r/log_upgrade.result create mode 100644 mysql-test/suite/innodb/t/log_upgrade.test diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_log_corruption.result b/mysql-test/suite/encryption/r/innodb_encrypt_log_corruption.result index 7563100babb..8d1eb447b03 100644 --- a/mysql-test/suite/encryption/r/innodb_encrypt_log_corruption.result +++ b/mysql-test/suite/encryption/r/innodb_encrypt_log_corruption.result @@ -69,14 +69,6 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED'); COUNT(*) 1 FOUND 3 /InnoDB: Upgrading redo log:/ in mysqld.1.err -# Empty large multi-file redo log from after MariaDB 10.2.2 -# restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-force-recovery=5 --innodb-log-file-size=2m -SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES -WHERE engine = 'innodb' -AND support IN ('YES', 'DEFAULT', 'ENABLED'); -COUNT(*) -1 -FOUND 4 /InnoDB: Upgrading redo log:/ in mysqld.1.err # redo log from "after" MariaDB 10.2.2, but with invalid header checksum # restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption SELECT * FROM INFORMATION_SCHEMA.ENGINES @@ -187,7 +179,7 @@ WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); COUNT(*) 1 -FOUND 6 /InnoDB: Upgrading redo log:/ in mysqld.1.err +FOUND 5 /InnoDB: Upgrading redo log:/ in mysqld.1.err # Minimal MariaDB 10.1.21 encrypted redo log # restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-force-recovery=5 SELECT COUNT(*) `1` FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb' diff --git a/mysql-test/suite/innodb/r/log_corruption.result b/mysql-test/suite/innodb/r/log_corruption.result index 890e3296164..bf92f77d30c 100644 --- a/mysql-test/suite/innodb/r/log_corruption.result +++ b/mysql-test/suite/innodb/r/log_corruption.result @@ -69,14 +69,6 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED'); COUNT(*) 1 FOUND 3 /InnoDB: Upgrading redo log:/ in mysqld.1.err -# Empty large multi-file redo log from after MariaDB 10.2.2 -# restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-force-recovery=5 --innodb-log-file-size=2m -SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES -WHERE engine = 'innodb' -AND support IN ('YES', 'DEFAULT', 'ENABLED'); -COUNT(*) -1 -FOUND 4 /InnoDB: Upgrading redo log:/ in mysqld.1.err # redo log from "after" MariaDB 10.2.2, but with invalid header checksum # restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption SELECT * FROM INFORMATION_SCHEMA.ENGINES @@ -187,7 +179,7 @@ WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); COUNT(*) 1 -FOUND 6 /InnoDB: Upgrading redo log:/ in mysqld.1.err +FOUND 5 /InnoDB: Upgrading redo log:/ in mysqld.1.err # Minimal MariaDB 10.1.21 encrypted redo log # restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_corruption --innodb-force-recovery=5 SELECT * FROM INFORMATION_SCHEMA.ENGINES diff --git a/mysql-test/suite/innodb/r/log_upgrade.result b/mysql-test/suite/innodb/r/log_upgrade.result new file mode 100644 index 00000000000..4da83460f93 --- /dev/null +++ b/mysql-test/suite/innodb/r/log_upgrade.result @@ -0,0 +1,16 @@ +call mtr.add_suppression("InnoDB: The change buffer is corrupted"); +# +# MDEV-24412 InnoDB: Upgrade after a crash is not supported +# +# restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_upgrade --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_upgrade --innodb-force-recovery=5 --innodb-log-file-size=4m +SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +COUNT(*) +1 +FOUND 1 /InnoDB: Upgrading redo log:/ in mysqld.1.err +ib_buffer_pool +ib_logfile0 +ibdata1 +# restart +# End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/log_corruption.test b/mysql-test/suite/innodb/t/log_corruption.test index 27fae80a135..a3ab4510743 100644 --- a/mysql-test/suite/innodb/t/log_corruption.test +++ b/mysql-test/suite/innodb/t/log_corruption.test @@ -291,42 +291,6 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED'); --source include/search_pattern_in_file.inc --let $restart_parameters= $dirs ---echo # Empty large multi-file redo log from after MariaDB 10.2.2 -perl; -do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl"; -my $polynomial = 0x82f63b78; # CRC-32C - -die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0"; -binmode OUT; -$_= pack("Nx[5]nx[5]", 1, 0x1286) . "BogoDB 4.3.2.1" . chr(0) x 478; -print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); -# checkpoint page 1 and all-zero checkpoint 2 -$_= pack("x[13]nCNNx[484]", 0x1286, 12, 2, 0x80c); -print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); -print OUT chr(0) x 1024; -die unless seek(OUT, 0x1FFFFFFFF, 0); -print OUT chr(0); -close OUT or die; -die unless open OUT, ">", "$ENV{bugdir}/ib_logfile1"; -binmode OUT; -die unless seek(OUT, 0x800, 0); # the first 2048 bytes are unused! -$_= pack("Nnnx[500]", 0x80000944, 12, 12); -print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); -die unless seek(OUT, 0x1FFFFFFFF, 0); -print OUT chr(0); -close OUT or die; -EOF - ---let $restart_parameters= $dirs --innodb-force-recovery=5 --innodb-log-file-size=2m ---source include/start_mysqld.inc -SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES -WHERE engine = 'innodb' -AND support IN ('YES', 'DEFAULT', 'ENABLED'); ---source include/shutdown_mysqld.inc ---let SEARCH_PATTERN= InnoDB: Upgrading redo log: ---source include/search_pattern_in_file.inc ---let $restart_parameters= $dirs - --remove_file $bugdir/ib_logfile0 --move_file $bugdir/ib_logfile $bugdir/ib_logfile0 diff --git a/mysql-test/suite/innodb/t/log_upgrade.test b/mysql-test/suite/innodb/t/log_upgrade.test new file mode 100644 index 00000000000..6f548d93b3e --- /dev/null +++ b/mysql-test/suite/innodb/t/log_upgrade.test @@ -0,0 +1,118 @@ +--source include/have_innodb.inc +--source include/have_innodb_16k.inc +# Some operating systems or file systems do not support sparse files. +# For example, tmpfs on FreeBSD does not support them. +# On Microsoft Windows, sparse files have to be created in a special way. +--source include/big_test.inc + +call mtr.add_suppression("InnoDB: The change buffer is corrupted"); + +--source include/shutdown_mysqld.inc + +let bugdir= $MYSQLTEST_VARDIR/tmp/log_upgrade; +--mkdir $bugdir +--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err + +--let $dirs= --innodb-data-home-dir=$bugdir --innodb-log-group-home-dir=$bugdir + +--echo # +--echo # MDEV-24412 InnoDB: Upgrade after a crash is not supported +--echo # + +perl; +do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl"; +my $polynomial = 0x82f63b78; # CRC-32C + +# Create a dummy system tablespace file using the default innodb_page_size=16k +die unless open OUT, ">", "$ENV{bugdir}/ibdata1"; +binmode OUT; + +# We calculate innodb_checksum_algorithm=crc32 for the pages. +# The following bytes are excluded: +# bytes 0..3 (the checksum is stored there) +# bytes 26..37 (encryption key version, post-encryption checksum, tablespace id) +# bytes $page_size-8..$page_size-1 (checksum, LSB of FIL_PAGE_LSN) + +# Tablespace header page with valid FSP_SIZE=768 pages. +# Also, write a dummy FSEG_MAGIC_N at offset 60 to keep fseg_inode_try_get() +# happy when fseg_n_reserved_pages() is following an invalid pointer +# from the all-zero change buffer header page (page 3). +## FIL_PAGE_OFFSET +my $head = pack("Nx[18]", 0); +## FSP_PAGE_SIZE, # FSEG_MAGIC_N +my $body = pack("x[8]Nx[10]Nx[16312]", 768, 97937874); +my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); +# Dummy pages 1..6. +print OUT chr(0) x (6 * 16384); +# Dictionary header page (page 7). +## FIL_PAGE_OFFSET +$head = pack("Nx[18]", 7); +## DICT_HDR_TABLES,DICT_HDR_INDEXES +$body = pack("x[32]Nx[8]Nx[16290]", 8, 9); +$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); + +# Empty SYS_TABLES page (page 8). +## FIL_PAGE_OFFSET, FIL_PAGE_PREV, FIL_PAGE_NEXT, FIL_PAGE_TYPE +$head = pack("NNNx[8]n", 8, ~0, ~0, 17855); +## PAGE_N_DIR_SLOTS, PAGE_HEAP_TOP, PAGE_INDEX_ID == DICT_TABLES_ID +$body = pack("nnx[31]Cx[20]", 2, 124, 1); +$body .= pack("nxnn", 0x801, 3, 116) . "infimum"; +$body .= pack("xnxnxx", 0x901, 0x803) . "supremum"; +$body .= pack("x[16248]nn", 116, 101); +$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); + +# Empty SYS_INDEXES page (page 9). +## FIL_PAGE_OFFSET, FIL_PAGE_PREV, FIL_PAGE_NEXT, FIL_PAGE_TYPE +$head = pack("NNNx[8]n", 9, ~0, ~0, 17855); +## PAGE_N_DIR_SLOTS, PAGE_HEAP_TOP, PAGE_INDEX_ID == DICT_INDEXES_ID +$body = pack("nnx[31]Cx[20]", 2, 124, 3); +$body .= pack("nxnn", 0x801, 3, 116) . "infimum"; +$body .= pack("xnxnxx", 0x901, 0x803) . "supremum"; +$body .= pack("x[16248]nn", 116, 101); +$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); + +die unless seek(OUT, 768 * 16384 - 1, 0); +print OUT chr(0); +close OUT or die; + +die unless open OUT, ">", "$ENV{bugdir}/ib_logfile0"; +binmode OUT; +$_= pack("Nx[5]nx[5]", 1, 0x1286) . "BogoDB 4.3.2.1" . chr(0) x 478; +print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); +# checkpoint page 1 and all-zero checkpoint 2 +$_= pack("x[13]nCNNx[484]", 0x1286, 12, 2, 0x80c); +print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); +die unless seek(OUT, 0x1FFFFFFFF, 0); +print OUT chr(0); +close OUT or die; +die unless open OUT, ">", "$ENV{bugdir}/ib_logfile1"; +binmode OUT; +die unless seek(OUT, 0x800, 0); # the first 2048 bytes are unused! +$_= pack("Nnnx[500]", 0x80000944, 12, 12); +print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); +die unless seek(OUT, 0x1FFFFFFFF, 0); +print OUT chr(0); +close OUT or die; +EOF + +--let $restart_parameters= $dirs --innodb-force-recovery=5 --innodb-log-file-size=4m +--source include/start_mysqld.inc +SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +--source include/shutdown_mysqld.inc +--let SEARCH_PATTERN= InnoDB: Upgrading redo log: +--source include/search_pattern_in_file.inc +--let $restart_parameters= $dirs + +--list_files $bugdir +--remove_files_wildcard $bugdir +--rmdir $bugdir +--let $restart_parameters= +--source include/start_mysqld.inc + +--echo # End of 10.5 tests From 11815641312fdbcab26e47e4b6655c155bc39bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Nov 2022 08:32:05 +0200 Subject: [PATCH 5/9] MDEV-24412: Disable the test on ./mtr --embedded --- mysql-test/suite/innodb/t/log_upgrade.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/suite/innodb/t/log_upgrade.test b/mysql-test/suite/innodb/t/log_upgrade.test index 6f548d93b3e..faf88c41bef 100644 --- a/mysql-test/suite/innodb/t/log_upgrade.test +++ b/mysql-test/suite/innodb/t/log_upgrade.test @@ -4,6 +4,8 @@ # For example, tmpfs on FreeBSD does not support them. # On Microsoft Windows, sparse files have to be created in a special way. --source include/big_test.inc +# include/shutdown_mysqld.inc does not work in ./mtr --embedded +--source include/not_embedded.inc call mtr.add_suppression("InnoDB: The change buffer is corrupted"); From 1188ef4ade88dd42eb9cd05daa9a627aca1a4935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Nov 2022 10:35:40 +0200 Subject: [PATCH 6/9] MDEV-30132 Crash after recovery, with InnoDB: Tried to read ... bytes at offset fil_space_t::prepare_acquired(): Do not attempt to extend (or shrink) files that will be processed by recv_sys_t::recover_deferred(). --- storage/innobase/fil/fil0fil.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 2cbc16b7b6e..a81600f03ae 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -660,6 +660,7 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_acquired() if (!is_open) release(); + else if (node->deferred); else if (auto desired_size= recv_size) { bool success; From fc1403d3a9ef3230324396f621f72f02097c8a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Nov 2022 10:41:11 +0200 Subject: [PATCH 7/9] Cleanup: Remove fil_space_t::is_deferred() The public data member can be checked directly by the only caller. --- extra/mariabackup/fil_cur.cc | 2 +- storage/innobase/include/fil0fil.h | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index 824fb4f4232..31afd39faf1 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -420,7 +420,7 @@ read_retry: goto func_exit; } - defer = space->is_deferred(); + defer = UT_LIST_GET_FIRST(space->chain)->deferred; /* check pages for corruption and re-read if necessary. i.e. in case of partially written pages */ for (page = cursor->buf, i = 0; i < npages; diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 551768c3a22..7837020fec4 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -510,10 +510,6 @@ public: /** @return whether the storage device is rotational (HDD, not SSD) */ inline bool is_rotational() const; - /** whether the tablespace discovery is being deferred during crash - recovery due to incompletely written page 0 */ - inline bool is_deferred() const; - /** Open each file. Never invoked on .ibd files. @param create_new_db whether to skip the call to fil_node_t::read_page0() @return whether all files were opened */ @@ -1191,11 +1187,6 @@ inline bool fil_space_t::is_rotational() const return false; } -inline bool fil_space_t::is_deferred() const -{ - return UT_LIST_GET_FIRST(chain)->deferred; -} - /** Common InnoDB file extensions */ enum ib_extention { NO_EXT = 0, From 15ab2e122da0ce17853a8f9fd0ac720701c8672a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Nov 2022 10:54:03 +0200 Subject: [PATCH 8/9] MDEV-30132 Crash after recovery, with InnoDB: Tried to read ... os_file_read(): Merged with os_file_read_no_error_handling(). Crashing on a partial page read is as unhelpful as crashing on a corrupted page read (commit 0b47c126e31cddda1e94588799599e138400bcf8). Report the file name if it is available via IORequest. --- extra/mariabackup/backup_copy.cc | 4 +- extra/mariabackup/changed_page_bitmap.cc | 11 +-- extra/mariabackup/fil_cur.cc | 4 +- extra/mariabackup/xtrabackup.cc | 9 +- storage/innobase/buf/buf0dblwr.cc | 8 +- storage/innobase/fil/fil0fil.cc | 4 - storage/innobase/fsp/fsp0file.cc | 7 +- storage/innobase/include/os0file.h | 65 ++---------- storage/innobase/include/os0file.inl | 48 +-------- storage/innobase/log/log0log.cc | 3 +- storage/innobase/os/os0file.cc | 121 ++++++----------------- storage/innobase/row/row0import.cc | 37 +++---- storage/innobase/row/row0log.cc | 12 +-- storage/innobase/row/row0merge.cc | 12 +-- storage/innobase/srv/srv0start.cc | 3 +- 15 files changed, 93 insertions(+), 255 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 9f322061ed3..a8959861926 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -561,8 +561,8 @@ datafile_read(datafile_cur_t *cursor) } if (os_file_read(IORequestRead, - cursor->file, cursor->buf, cursor->buf_offset, - to_read) != DB_SUCCESS) { + cursor->file, cursor->buf, cursor->buf_offset, + to_read, nullptr) != DB_SUCCESS) { return(XB_FIL_CUR_ERROR); } diff --git a/extra/mariabackup/changed_page_bitmap.cc b/extra/mariabackup/changed_page_bitmap.cc index 793d7378b0f..a6cc0e01492 100644 --- a/extra/mariabackup/changed_page_bitmap.cc +++ b/extra/mariabackup/changed_page_bitmap.cc @@ -188,18 +188,15 @@ log_online_read_bitmap_page( { ulint checksum; ulint actual_checksum; - ibool success; ut_a(bitmap_file->size >= MODIFIED_PAGE_BLOCK_SIZE); ut_a(bitmap_file->offset <= bitmap_file->size - MODIFIED_PAGE_BLOCK_SIZE); ut_a(bitmap_file->offset % MODIFIED_PAGE_BLOCK_SIZE == 0); - success = os_file_read(IORequestRead, - bitmap_file->file, page, bitmap_file->offset, - MODIFIED_PAGE_BLOCK_SIZE) == DB_SUCCESS; - - if (UNIV_UNLIKELY(!success)) { - + if (DB_SUCCESS != + os_file_read(IORequestRead, bitmap_file->file, page, + bitmap_file->offset, MODIFIED_PAGE_BLOCK_SIZE, + nullptr)) { /* The following call prints an error message */ os_file_get_last_error(TRUE); msg("InnoDB: Warning: failed reading changed page bitmap " diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index 31afd39faf1..d7aca1362ed 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -223,7 +223,7 @@ xb_fil_cur_open( if (!node->space->crypt_data && os_file_read(IORequestRead, node->handle, cursor->buf, 0, - cursor->page_size) == DB_SUCCESS) { + cursor->page_size, nullptr) == DB_SUCCESS) { mysql_mutex_lock(&fil_system.mutex); if (!node->space->crypt_data) { node->space->crypt_data = fil_space_read_crypt_data( @@ -415,7 +415,7 @@ 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) { + (ulint) to_read, nullptr) != DB_SUCCESS) { ret = XB_FIL_CUR_ERROR; goto func_exit; } diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index cd1d21cdf75..56973888457 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3827,7 +3827,7 @@ static dberr_t xb_assign_undo_space_start() byte* page = static_cast (aligned_malloc(srv_page_size, srv_page_size)); - if (os_file_read(IORequestRead, file, page, 0, srv_page_size) + if (os_file_read(IORequestRead, file, page, 0, srv_page_size, nullptr) != DB_SUCCESS) { msg("Reading first page failed.\n"); error = DB_ERROR; @@ -3839,7 +3839,7 @@ static dberr_t xb_assign_undo_space_start() retry: if (os_file_read(IORequestRead, file, page, TRX_SYS_PAGE_NO << srv_page_size_shift, - srv_page_size) != DB_SUCCESS) { + srv_page_size, nullptr) != DB_SUCCESS) { msg("Reading TRX_SYS page failed."); error = DB_ERROR; goto func_exit; @@ -5347,7 +5347,8 @@ xtrabackup_apply_delta( offset = ((incremental_buffers * (page_size / 4)) << page_size_shift); if (os_file_read(IORequestRead, src_file, - incremental_buffer, offset, page_size) + incremental_buffer, offset, page_size, + nullptr) != DB_SUCCESS) { goto error; } @@ -5380,7 +5381,7 @@ xtrabackup_apply_delta( /* read whole of the cluster */ if (os_file_read(IORequestRead, src_file, incremental_buffer, - offset, page_in_buffer * page_size) + offset, page_in_buffer * page_size, nullptr) != DB_SUCCESS) { goto error; } diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index b9f505db56e..c71fd8df068 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2021, MariaDB Corporation. +Copyright (c) 2013, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -253,7 +253,7 @@ dberr_t buf_dblwr_t::init_or_load_pages(pfs_os_file_t file, const char *path) /* Read the TRX_SYS header to check if we are using the doublewrite buffer */ dberr_t err= os_file_read(IORequestRead, file, read_buf, TRX_SYS_PAGE_NO << srv_page_size_shift, - srv_page_size); + srv_page_size, nullptr); if (err != DB_SUCCESS) { @@ -285,7 +285,7 @@ func_exit: /* Read the pages from the doublewrite buffer to memory */ err= os_file_read(IORequestRead, file, write_buf, block1.page_no() << srv_page_size_shift, - size << srv_page_size_shift); + size << srv_page_size_shift, nullptr); if (err != DB_SUCCESS) { @@ -296,7 +296,7 @@ func_exit: err= os_file_read(IORequestRead, file, write_buf + (size << srv_page_size_shift), block2.page_no() << srv_page_size_shift, - size << srv_page_size_shift); + size << srv_page_size_shift, nullptr); if (err != DB_SUCCESS) { ib::error() << "Failed to read the second double write buffer extent"; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index a81600f03ae..89af4e2420f 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2750,10 +2750,6 @@ io_error: buf, offset, len); } - /* We an try to recover the page from the double write buffer if - the decompression fails or the page is corrupt. */ - - ut_a(type.type == IORequest::DBLWR_RECOVER || err == DB_SUCCESS); if (!type.is_async()) { if (type.is_write()) { release_sync_write: diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index d775fd9c657..bc709516b41 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -263,12 +263,11 @@ Datafile::read_first_page(bool read_only_mode) ulint n_read = 0; - err = os_file_read_no_error_handling( + err = os_file_read( IORequestReadPartial, m_handle, m_first_page, 0, page_size, &n_read); if (err == DB_SUCCESS) { - ut_a(n_read == page_size); break; } @@ -664,7 +663,7 @@ Datafile::find_space_id() for (ulint j = 0; j < page_count; ++j) { if (os_file_read(IORequestRead, m_handle, page, - j * page_size, page_size)) { + j * page_size, page_size, nullptr)) { ib::info() << "READ FAIL: page_no:" << j; continue; diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 40ffc4297ec..d64ad9feb87 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -582,12 +582,8 @@ The wrapper functions have the prefix of "innodb_". */ # define os_file_close(file) \ pfs_os_file_close_func(file, __FILE__, __LINE__) -# define os_file_read(type, file, buf, offset, n) \ - pfs_os_file_read_func(type, file, buf, offset, n, __FILE__, __LINE__) - -# define os_file_read_no_error_handling(type, file, buf, offset, n, o) \ - pfs_os_file_read_no_error_handling_func( \ - type, file, buf, offset, n, o, __FILE__, __LINE__) +# define os_file_read(type, file, buf, offset, n, o) \ + pfs_os_file_read_func(type, file, buf, offset, n,o, __FILE__, __LINE__) # define os_file_write(type, name, file, buf, offset, n) \ pfs_os_file_write_func(type, name, file, buf, offset, \ @@ -727,31 +723,6 @@ os_file_read() which requests a synchronous read operation. UNIV_INLINE dberr_t pfs_os_file_read_func( - const IORequest& type, - pfs_os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - const char* src_file, - uint src_line); - -/** NOTE! Please use the corresponding macro os_file_read_no_error_handling(), -not directly this function! -This is the performance schema instrumented wrapper function for -os_file_read_no_error_handling_func() which requests a synchronous -read operation. -@param[in] type IO request context -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read -@param[out] o number of bytes actually read -@param[in] src_file file name where func invoked -@param[in] src_line line where the func invoked -@return DB_SUCCESS if request was successful */ -UNIV_INLINE -dberr_t -pfs_os_file_read_no_error_handling_func( const IORequest& type, pfs_os_file_t file, void* buf, @@ -882,11 +853,8 @@ to original un-instrumented file I/O APIs */ # define os_file_close(file) os_file_close_func(file) -# define os_file_read(type, file, buf, offset, n) \ - os_file_read_func(type, file, buf, offset, n) - -# define os_file_read_no_error_handling(type, file, buf, offset, n, o) \ - os_file_read_no_error_handling_func(type, file, buf, offset, n, o) +# define os_file_read(type, file, buf, offset, n, o) \ + os_file_read_func(type, file, buf, offset, n, o) # define os_file_write(type, name, file, buf, offset, n) \ os_file_write_func(type, name, file, buf, offset, n) @@ -991,6 +959,7 @@ Requests a synchronous read operation. @param[out] buf buffer where to read @param[in] offset file offset where to read @param[in] n number of bytes to read +@param[out] o number of bytes actually read @return DB_SUCCESS if request was successful */ dberr_t os_file_read_func( @@ -998,7 +967,8 @@ os_file_read_func( os_file_t file, void* buf, os_offset_t offset, - ulint n) + ulint n, + ulint* o) MY_ATTRIBUTE((warn_unused_result)); /** Rewind file to its start, read at most size - 1 bytes from it to str, and @@ -1013,27 +983,6 @@ os_file_read_string( char* str, ulint size); -/** NOTE! Use the corresponding macro os_file_read_no_error_handling(), -not directly this function! -Requests a synchronous positioned read operation. This function does not do -any error handling. In case of error it returns FALSE. -@param[in] type IO request context -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read -@param[out] o number of bytes actually read -@return DB_SUCCESS or error code */ -dberr_t -os_file_read_no_error_handling_func( - const IORequest& type, - os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - ulint* o) - MY_ATTRIBUTE((warn_unused_result)); - /** NOTE! Use the corresponding macro os_file_write(), not directly this function! Requests a synchronous write operation. diff --git a/storage/innobase/include/os0file.inl b/storage/innobase/include/os0file.inl index e88f94b8ff3..7de3150540d 100644 --- a/storage/innobase/include/os0file.inl +++ b/storage/innobase/include/os0file.inl @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2010, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -210,52 +210,13 @@ os_file_read() which requests a synchronous read operation. @param[out] buf buffer where to read @param[in] offset file offset where to read @param[in] n number of bytes to read -@param[in] src_file file name where func invoked -@param[in] src_line line where the func invoked -@return DB_SUCCESS if request was successful */ -UNIV_INLINE -dberr_t -pfs_os_file_read_func( - const IORequest& type, - pfs_os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - const char* src_file, - uint src_line) -{ - PSI_file_locker_state state; - struct PSI_file_locker* locker = NULL; - - register_pfs_file_io_begin( - &state, locker, file, n, PSI_FILE_READ, src_file, src_line); - - dberr_t result; - - result = os_file_read_func(type, file, buf, offset, n); - - register_pfs_file_io_end(locker, n); - - return(result); -} - -/** NOTE! Please use the corresponding macro os_file_read_no_error_handling(), -not directly this function! -This is the performance schema instrumented wrapper function for -os_file_read_no_error_handling_func() which requests a synchronous -read operation. -@param[in] type IO request context -@param[in] file Open file handle -@param[out] buf buffer where to read -@param[in] offset file offset where to read -@param[in] n number of bytes to read @param[out] o number of bytes actually read @param[in] src_file file name where func invoked @param[in] src_line line where the func invoked @return DB_SUCCESS if request was successful */ UNIV_INLINE dberr_t -pfs_os_file_read_no_error_handling_func( +pfs_os_file_read_func( const IORequest& type, pfs_os_file_t file, void* buf, @@ -271,8 +232,9 @@ pfs_os_file_read_no_error_handling_func( register_pfs_file_io_begin( &state, locker, file, n, PSI_FILE_READ, src_file, src_line); - dberr_t result = os_file_read_no_error_handling_func( - type, file, buf, offset, n, o); + dberr_t result; + + result = os_file_read_func(type, file, buf, offset, n, o); register_pfs_file_io_end(locker, n); diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 6c888f9f58b..70f561280d9 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -275,7 +275,8 @@ dberr_t file_os_io::close() noexcept dberr_t file_os_io::read(os_offset_t offset, span buf) noexcept { - return os_file_read(IORequestRead, m_fd, buf.data(), offset, buf.size()); + return os_file_read(IORequestRead, m_fd, buf.data(), offset, buf.size(), + nullptr); } dberr_t file_os_io::write(const char *path, os_offset_t offset, diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index dd8c4b0e171..c67d0b50217 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -36,6 +36,7 @@ Created 10/21/1995 Heikki Tuuri #ifndef UNIV_INNOCHECKSUM #include "os0file.h" #include "sql_const.h" +#include "log.h" #ifdef __linux__ # include @@ -177,7 +178,7 @@ mysql_pfs_key_t innodb_temp_file_key; @param[in] should_abort whether to abort on an unknown error @param[in] on_error_silent whether to suppress reports of non-fatal errors @return true if we should retry the operation */ -static MY_ATTRIBUTE((warn_unused_result)) +static bool os_file_handle_error_cond_exit( const char* name, @@ -2768,15 +2769,14 @@ os_file_io( bytes_returned += n_bytes; if (type.type != IORequest::READ_MAYBE_PARTIAL) { - const char* op = type.is_read() - ? "read" : "written"; - - ib::warn() - << n - << " bytes should have been " << op << ". Only " - << bytes_returned - << " bytes " << op << ". Retrying" - << " for the remaining bytes."; + sql_print_warning("InnoDB: %zu bytes should have been" + " %s from %s, but got only %zd." + " Retrying.", + n, type.is_read() + ? "read" : "written", + type.node + ? type.node->name + : "(unknown file)", bytes_returned); } /* Advance the offset and buffer by n_bytes */ @@ -2917,52 +2917,38 @@ os_file_pread( @param[in] offset file offset from the start where to read @param[in] n number of bytes to read, starting from offset @param[out] o number of bytes actually read -@param[in] exit_on_err if true then exit on error @return DB_SUCCESS or error code */ -static MY_ATTRIBUTE((warn_unused_result)) dberr_t -os_file_read_page( +os_file_read_func( const IORequest& type, os_file_t file, void* buf, os_offset_t offset, ulint n, - ulint* o, - bool exit_on_err) + ulint* o) { - dberr_t err; + ut_ad(!type.node || type.node->handle == file); + ut_ad(n); - os_bytes_read_since_printout += n; + os_bytes_read_since_printout+= n; - ut_ad(n > 0); + dberr_t err; + ssize_t n_bytes= os_file_pread(type, file, buf, n, offset, &err); - ssize_t n_bytes = os_file_pread(type, file, buf, n, offset, &err); + if (o) + *o= ulint(n_bytes); - if (o) { - *o = n_bytes; - } + if (ulint(n_bytes) == n || err != DB_SUCCESS) + return err; - if (ulint(n_bytes) == n || (err != DB_SUCCESS && !exit_on_err)) { - return err; - } - int os_err = IF_WIN((int)GetLastError(), errno); + os_file_handle_error_cond_exit(type.node ? type.node->name : nullptr, "read", + false, false); + sql_print_error("InnoDB: Tried to read %zu bytes at offset %llu" + " of file %s, but was only able to read %zd", + n, offset, type.node ? type.node->name : "(unknown)", + n_bytes); - if (!os_file_handle_error_cond_exit( - NULL, "read", exit_on_err, false)) { - ib::fatal() - << "Tried to read " << n << " bytes at offset " - << offset << ", but was only able to read " << n_bytes - << ".Cannot read from file. OS error number " - << os_err << "."; - } else { - ib::error() << "Tried to read " << n << " bytes at offset " - << offset << ", but was only able to read " << n_bytes; - } - if (err == DB_SUCCESS) { - err = DB_IO_ERROR; - } - - return err; + return err ? err : DB_IO_ERROR; } /** Retrieves the last error number if an error occurs in a file io function. @@ -3322,51 +3308,6 @@ os_file_truncate( #endif /* _WIN32 */ } -/** NOTE! Use the corresponding macro os_file_read(), not directly this -function! -Requests a synchronous positioned read operation. -@return DB_SUCCESS if request was successful, DB_IO_ERROR on failure -@param[in] type IO flags -@param[in] file handle to an open file -@param[out] buf buffer where to read -@param[in] offset file offset from the start where to read -@param[in] n number of bytes to read, starting from offset -@return error code -@retval DB_SUCCESS if the operation succeeded */ -dberr_t -os_file_read_func( - const IORequest& type, - os_file_t file, - void* buf, - os_offset_t offset, - ulint n) -{ - return(os_file_read_page(type, file, buf, offset, n, NULL, true)); -} - -/** NOTE! Use the corresponding macro os_file_read_no_error_handling(), -not directly this function! -Requests a synchronous positioned read operation. -@return DB_SUCCESS if request was successful, DB_IO_ERROR on failure -@param[in] type IO flags -@param[in] file handle to an open file -@param[out] buf buffer where to read -@param[in] offset file offset from the start where to read -@param[in] n number of bytes to read, starting from offset -@param[out] o number of bytes actually read -@return DB_SUCCESS or error code */ -dberr_t -os_file_read_no_error_handling_func( - const IORequest& type, - os_file_t file, - void* buf, - os_offset_t offset, - ulint n, - ulint* o) -{ - return(os_file_read_page(type, file, buf, offset, n, o, false)); -} - /** Check the existence and type of the given file. @param[in] path path name of file @param[out] exists true if the file exists @@ -3788,7 +3729,7 @@ dberr_t os_aio(const IORequest &type, void *buf, os_offset_t offset, size_t n) if (!type.is_async()) { err = type.is_read() ? os_file_read_func(type, type.node->handle, - buf, offset, n) + buf, offset, n, nullptr) : os_file_write_func(type, type.node->name, type.node->handle, buf, offset, n); @@ -4149,10 +4090,10 @@ bool fil_node_t::read_page0() if (!deferred) { page_t *page= static_cast(aligned_malloc(psize, psize)); - if (os_file_read(IORequestRead, handle, page, 0, psize) + if (os_file_read(IORequestRead, handle, page, 0, psize, nullptr) != DB_SUCCESS) { - ib::error() << "Unable to read first page of file " << name; + sql_print_error("InnoDB: Unable to read first page of file %s", name); corrupted: aligned_free(page); return false; diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 9e336f267a3..590f9d73990 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3101,9 +3101,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table, static_cast(aligned_malloc(srv_page_size, srv_page_size)), &aligned_free); - if (dberr_t err= os_file_read_no_error_handling(IORequestReadPartial, - file, first_page.get(), 0, - srv_page_size, nullptr)) + if (dberr_t err= os_file_read(IORequestReadPartial, file, first_page.get(), + 0, srv_page_size, nullptr)) return err; auto space_flags= fsp_header_get_flags(first_page.get()); @@ -3141,7 +3140,7 @@ static dberr_t handle_instant_metadata(dict_table_t *table, aligned_malloc(UNIV_PAGE_SIZE_MAX, UNIV_PAGE_SIZE_MAX)), &aligned_free); - if (dberr_t err= os_file_read_no_error_handling( + if (dberr_t err= os_file_read( IORequestReadPartial, file, page.get(), 3 * physical_size, physical_size, nullptr)) return err; @@ -3198,10 +3197,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table, uint64_t child_page_no= btr_node_ptr_get_child_page_no(rec, offsets); if (dberr_t err= - os_file_read_no_error_handling(IORequestReadPartial, file, - page.get(), - child_page_no * physical_size, - physical_size, nullptr)) + os_file_read(IORequestReadPartial, file, page.get(), + child_page_no * physical_size, physical_size, nullptr)) return err; if (dberr_t err= decrypt_decompress(space_crypt, space_flags, @@ -3280,11 +3277,10 @@ static dberr_t handle_instant_metadata(dict_table_t *table, &aligned_free); if (dberr_t err= - os_file_read_no_error_handling(IORequestReadPartial, file, - second_page.get(), physical_size * - mach_read_from_4(ptr + - BTR_EXTERN_PAGE_NO), - srv_page_size, nullptr)) + os_file_read(IORequestReadPartial, file, second_page.get(), + physical_size * + mach_read_from_4(ptr + BTR_EXTERN_PAGE_NO), + physical_size, nullptr)) return err; if (dberr_t err= decrypt_decompress(space_crypt, space_flags, @@ -3696,8 +3692,8 @@ dberr_t FetchIndexRootPages::run(const fil_iterator_t& iter, bool page_compressed= false; - dberr_t err= os_file_read_no_error_handling( - IORequestReadPartial, iter.file, readptr, 3 * size, size, 0); + dberr_t err= os_file_read(IORequestReadPartial, iter.file, readptr, + 3 * size, size, nullptr); if (err != DB_SUCCESS) { ib::error() << iter.filepath << ": os_file_read() failed"; @@ -3821,9 +3817,8 @@ static dberr_t fil_iterate( ? iter.crypt_io_buffer : io_buffer; byte* const writeptr = readptr; - err = os_file_read_no_error_handling( - IORequestReadPartial, - iter.file, readptr, offset, n_bytes, 0); + err = os_file_read(IORequestReadPartial, iter.file, readptr, + offset, n_bytes, nullptr); if (err != DB_SUCCESS) { ib::error() << iter.filepath << ": os_file_read() failed"; @@ -4156,10 +4151,10 @@ fil_tablespace_iterate( block->page.frame = page; block->page.init(buf_page_t::UNFIXED + 1, page_id_t{~0ULL}); - /* Read the first page and determine the page and zip size. */ + /* Read the first page and determine the page size. */ - err = os_file_read_no_error_handling(IORequestReadPartial, - file, page, 0, srv_page_size, 0); + err = os_file_read(IORequestReadPartial, file, page, 0, srv_page_size, + nullptr); if (err == DB_SUCCESS) { err = callback.init(file_size, block); diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 0689f9ca029..42e09ffd180 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -2600,9 +2600,9 @@ all_done: byte* buf = index->online_log->head.block; - if (os_file_read_no_error_handling( - IORequestRead, index->online_log->fd, - buf, ofs, srv_sort_buf_size, 0) != DB_SUCCESS) { + if (DB_SUCCESS + != os_file_read(IORequestRead, index->online_log->fd, + buf, ofs, srv_sort_buf_size, nullptr)) { ib::error() << "Unable to read temporary file" " for table " << index->table->name; @@ -3520,9 +3520,9 @@ all_done: byte* buf = index->online_log->head.block; - if (os_file_read_no_error_handling( - IORequestRead, index->online_log->fd, - buf, ofs, srv_sort_buf_size, 0) != DB_SUCCESS) { + if (DB_SUCCESS + != os_file_read(IORequestRead, index->online_log->fd, + buf, ofs, srv_sort_buf_size, nullptr)) { ib::error() << "Unable to read temporary file" " for index " << index->name; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index dba3c0a144a..8914021d09d 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1087,11 +1087,11 @@ row_merge_read( DBUG_LOG("ib_merge_sort", "fd=" << fd << " ofs=" << ofs); DBUG_EXECUTE_IF("row_merge_read_failure", DBUG_RETURN(FALSE);); - const bool success = DB_SUCCESS == os_file_read_no_error_handling( - IORequestRead, fd, buf, ofs, srv_sort_buf_size, 0); + const dberr_t err = os_file_read( + IORequestRead, fd, buf, ofs, srv_sort_buf_size, nullptr); /* If encryption is enabled decrypt buffer */ - if (success && log_tmp_is_encrypted()) { + if (err == DB_SUCCESS && srv_encrypt_log) { if (!log_tmp_block_decrypt(buf, srv_sort_buf_size, crypt_buf, ofs)) { DBUG_RETURN(false); @@ -1106,11 +1106,7 @@ row_merge_read( posix_fadvise(fd, ofs, srv_sort_buf_size, POSIX_FADV_DONTNEED); #endif /* POSIX_FADV_DONTNEED */ - if (!success) { - ib::error() << "Failed to read merge block at " << ofs; - } - - DBUG_RETURN(success); + DBUG_RETURN(err == DB_SUCCESS); } /********************************************************************//** diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 859492bc957..8b29af5c083 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -518,7 +518,8 @@ static ulint srv_undo_tablespace_open(bool create, const char* name, ulint i) { page_t *page= static_cast(aligned_malloc(srv_page_size, srv_page_size)); - dberr_t err= os_file_read(IORequestRead, fh, page, 0, srv_page_size); + dberr_t err= os_file_read(IORequestRead, fh, page, 0, srv_page_size, + nullptr); if (err != DB_SUCCESS) { err_exit: From 4783f37cf79150db55a7258683e50a04d987af1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Nov 2022 12:06:52 +0200 Subject: [PATCH 9/9] MDEV-30069 fixup: Do not truncate files on recovery recv_sys_t::recover_deferred(): If the file has been determined to be large enough, skip the call to os_file_set_size(), which would use the current value of FSP_SIZE, which during a multi-batch recovery can be smaller than the actual file size. os_file_io(): Also display the file offset in the warning message about partial I/O. --- storage/innobase/log/log0recv.cc | 2 ++ storage/innobase/os/os0file.cc | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 3dcc7e54ab0..b0651d8b8da 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -998,6 +998,7 @@ bool recv_sys_t::recover_deferred(recv_sys_t::map::iterator &p, { space->size= node->size= n_pages; space->set_committed_size(); + goto size_set; } } if (!os_file_set_size(node->name, node->handle, @@ -1007,6 +1008,7 @@ bool recv_sys_t::recover_deferred(recv_sys_t::map::iterator &p, space->release(); goto release_and_fail; } + size_set: node->deferred= false; space->release(); it->second.space= space; diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index c67d0b50217..44783f72972 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -2770,10 +2770,11 @@ os_file_io( if (type.type != IORequest::READ_MAYBE_PARTIAL) { sql_print_warning("InnoDB: %zu bytes should have been" - " %s from %s, but got only %zd." + " %s at %llu from %s," + " but got only %zd." " Retrying.", n, type.is_read() - ? "read" : "written", + ? "read" : "written", offset, type.node ? type.node->name : "(unknown file)", bytes_returned);