From 2151aed44d15d7055d7608af94b9a01093ec77c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 18 Mar 2019 13:10:28 +0200 Subject: [PATCH] Follow-up fix to MDEV-12026: FIL_SPACE_FLAGS trump fil_space_t::flags Whenever we are reading the first page of a data file, we may have to adjust the provisionally created fil_space_t::flags to match what is actually inside the data files. In this way, we will never accidentally change the format of a data file. fil_node_t::read_page0(): After validating the FIL_SPACE_FLAGS, always assign them to space->flags. btr_root_adjust_on_import(), Datafile::validate_to_dd(), fil_space_for_table_exists_in_mem(): Adapt to the fix in fil_node_t::read_page0(). fsp_flags_try_adjust(): Skip the adjustment if full_crc32 is being used. This adjustment was introduced in MDEV-11623 for upgrading from MariaDB 10.1.0 to 10.1.20, which used an accidentally changed format of FIL_SPACE_FLAGS. MariaDB before 10.4.3 never set the flag that now indicates the full_crc32 format. --- storage/innobase/btr/btr0btr.cc | 18 +++++++++++++++--- storage/innobase/fil/fil0fil.cc | 30 +++++++++++++++++++++--------- storage/innobase/fsp/fsp0file.cc | 5 +++-- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 56a1fb8d231..223814a12be 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -392,9 +392,21 @@ btr_root_adjust_on_import( } else { /* Check that the table flags and the tablespace flags match. */ - err = (dict_tf_to_fsp_flags(table->flags) - == table->space->flags) - ? DB_SUCCESS : DB_CORRUPTION; + ulint tf = dict_tf_to_fsp_flags(table->flags); + ulint sf = table->space->flags; + sf &= ~FSP_FLAGS_MEM_MASK; + tf &= ~FSP_FLAGS_MEM_MASK; + if (fil_space_t::is_flags_equal(tf, sf) + || fil_space_t::is_flags_equal(sf, tf)) { + mutex_enter(&fil_system.mutex); + table->space->flags = (table->space->flags + & ~FSP_FLAGS_MEM_MASK) + | (tf & FSP_FLAGS_MEM_MASK); + mutex_exit(&fil_system.mutex); + err = DB_SUCCESS; + } else { + err = DB_CORRUPTION; + } } } else { err = DB_SUCCESS; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 596621ae069..eed123d865e 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -507,8 +507,8 @@ bool fil_node_t::read_page0(bool first) + page); if (!fil_space_t::is_valid_flags(flags, space->id)) { ulint cflags = fsp_flags_convert_from_101(flags); - if (cflags == ULINT_UNDEFINED - || (cflags ^ space->flags) & ~FSP_FLAGS_MEM_MASK) { + if (cflags == ULINT_UNDEFINED) { +invalid: ib::error() << "Expected tablespace flags " << ib::hex(space->flags) @@ -518,9 +518,19 @@ bool fil_node_t::read_page0(bool first) return false; } + ulint cf = cflags & ~FSP_FLAGS_MEM_MASK; + ulint sf = space->flags & ~FSP_FLAGS_MEM_MASK; + + if (!fil_space_t::is_flags_equal(cf, sf) + && !fil_space_t::is_flags_equal(sf, cf)) { + goto invalid; + } + flags = cflags; } + ut_ad(!(flags & FSP_FLAGS_MEM_MASK)); + /* Try to read crypt_data from page 0 if it is not yet read. */ if (!space->crypt_data) { space->crypt_data = fil_space_read_crypt_data( @@ -552,10 +562,7 @@ bool fil_node_t::read_page0(bool first) size_bytes &= ~os_offset_t(mask); } - if (space->flags != flags - && fil_space_t::is_flags_equal(flags, space->flags)) { - space->flags = flags; - } + space->flags = (space->flags & FSP_FLAGS_MEM_MASK) | flags; this->size = ulint(size_bytes / psize); space->size += this->size; @@ -3887,7 +3894,7 @@ void fsp_flags_try_adjust(fil_space_t* space, ulint flags) { ut_ad(!srv_read_only_mode); ut_ad(fil_space_t::is_valid_flags(flags, space->id)); - if (space->full_crc32()) { + if (space->full_crc32() || fil_space_t::full_crc32(flags)) { return; } if (!space->size && (space->purpose != FIL_TYPE_TABLESPACE @@ -3947,7 +3954,11 @@ fil_space_for_table_exists_in_mem( mutex_enter(&fil_system.mutex); if (fil_space_t* space = fil_space_get_by_id(id)) { - if ((space->flags ^ expected_flags) & ~FSP_FLAGS_MEM_MASK) { + ulint tf = expected_flags & ~FSP_FLAGS_MEM_MASK; + ulint sf = space->flags & ~FSP_FLAGS_MEM_MASK; + + if (!fil_space_t::is_flags_equal(tf, sf) + && !fil_space_t::is_flags_equal(sf, tf)) { goto func_exit; } @@ -3963,7 +3974,8 @@ fil_space_for_table_exists_in_mem( /* Adjust the flags that are in FSP_FLAGS_MEM_MASK. FSP_SPACE_FLAGS will not be written back here. */ - space->flags = expected_flags; + space->flags = (space->flags & ~FSP_FLAGS_MEM_MASK) + | (expected_flags & FSP_FLAGS_MEM_MASK); mutex_exit(&fil_system.mutex); if (!srv_read_only_mode) { fsp_flags_try_adjust(space, expected_flags diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index 3c9e1685492..a4f83def85b 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, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 @@ -409,7 +409,8 @@ Datafile::validate_to_dd(ulint space_id, ulint flags) If the datafile is a file-per-table tablespace then also match the row format and zip page size. */ if (m_space_id == space_id - && fil_space_t::is_flags_equal(m_flags, flags)) { + && (fil_space_t::is_flags_equal(flags, m_flags) + || fil_space_t::is_flags_equal(m_flags, flags))) { /* Datafile matches the tablespace expected. */ return(DB_SUCCESS); }