Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PS-5874 : Upgrade to 8.0.16-7 breaks on innodb_dynamic_metadata with encrypted #3390

Merged
merged 1 commit into from
Sep 17, 2019

Conversation

robgolebiowski
Copy link
Contributor

tablespace

Upgrade creates tables in mysql tablespaces in two phases:

  • Phase 1 creates tables based on actual DD properties,
    taken from dd_properties table, option SYSTEM_TABLES.
    We add here in-memory encryption flag to CREATE statement
    if the mysql tablespace is encrypted.
  • Phase 2 create target tables. We add here in-memory encryption
    flag to CREATE statement if mysql tablespace is encrypted and update
    SYSTEM_TABLES option in dd_properties with encryption flag.

@satya-bodapati satya-bodapati changed the title Upgrade to 8.0.16-7 breaks on innodb_dynamic_metadata with encrypted PS-5874 - Upgrade to 8.0.16-7 breaks on innodb_dynamic_metadata with encrypted Aug 27, 2019
@satya-bodapati satya-bodapati changed the title PS-5874 - Upgrade to 8.0.16-7 breaks on innodb_dynamic_metadata with encrypted PS-5874 : Upgrade to 8.0.16-7 breaks on innodb_dynamic_metadata with encrypted Aug 27, 2019
@@ -165,6 +165,7 @@ bool update_system_tables(THD *thd) {
std::unique_ptr<Properties> table_def_properties(
Properties::parse_properties(def));
table_def->set_actual_table_definition(*table_def_properties);
table_def->set_actual_encrypted();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this done unconditionally?

Side note: since robert is on vacation, I am debugging this to find the answer

Copy link
Contributor

@satya-bodapati satya-bodapati Aug 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few more questions:

Why is the property change done in-memory only and not registerd in DD properties?

Why do we do the "CREATE TABLE mysql.innodb_dynamic_metadata" (the actual table vs target table) when the table already existed in SE. Does the mysql_execute_command() or mysql_create_table() really try to create table in SE?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answers from debugging

  1. (on the unconditionally question) : No answer yet
  2. property change (adding encryption='y') to DD properties is not just in-memory change. It is written to disk as well ( dd::update_properties()) is called
  3. the CREATE TABLE innodb_dynamic_metadata doesn't result in table creation in SE. (we already have the table in SE). This step is only to create TABLE*/TABLE_SHARE* for core tables.

@@ -1352,7 +1353,9 @@ bool initialize_dd_properties(THD *thd) {
*/
if (!bootstrap::DD_bootstrap_ctx::instance().is_initialize() &&
bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade() &&
update_system_tables(thd)) {
update_system_tables(thd) &&
update_properties(thd, nullptr, nullptr,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using this update_properties() the DD_properties of the dictionary tables are stored on disk? Next restart shouldn't depend on in-memory flag?

Also why do we need this unconditionally?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am guessing that restart would keep using this in-memory flag and add double "encryption=y" again? Have to debug and find out

Copy link
Contributor

@satya-bodapati satya-bodapati Sep 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DD properties after update_properties is like this:
tbl_props->raw_string()
$12 = "col0=table_id\=2\;;col1=table_id\=2\;;col2=table_id\=2\;;col3=table_id\=2\;;col4=table_id\=2\;;data=;def=fields\=elem0\\\=def\\\\\\\=metadata BLOB NOT NULL\\\\\\\;lbl\
\\\\\=metadata\\\\\\\;pos\\\\\\\=2\\\\\\\;\\\;elem1\\\=def\\\\\\\=table_id BIGINT UNSIGNED NOT NULL\\\\\\\;lbl\\\\\\\=table_id\\\\\\\;pos\\\
\\\\=0\\\\\\\;\\\;elem2\\\=def\\\\\\\=version BIGINT UNSIGNED NOT NULL\\\\\\\;lbl\\\\\\\=version\\\\\\\;pos\\\\\\\=1\\\\\\\;\\\;\;foreign_key
s\=\;indexes\=elem0\\\=def\\\\\\\=PRIMARY KEY (table_id)\\\\\\\;lbl\\\\\\\=index_pk\\\\\\\;pos\\\\\\\=0\\\\\\\;\\\;\;name\=innodb_dynamic_metadata\;op
tions\=elem0\\\=def\\\\\\\=DEFAULT CHARSET", '\' <repeats 15 times>, "=utf8\\\\\\\;lbl\\\\\\\=CHARSET\\\\\\\;pos\\\\\\\=1\\\\\\\;\\\;elem1\\\=def\\\
\\\\=COLLATE", '\' <repeats 15 times>, "=utf8_bin\\\\\\\;lbl\\\\\\\=COLLATION\\\\\\\;pos\\\\\\\=2\\\\\\\;\\\;elem2\\\=def\\\\\\\=ENCRYPTION", '\' <rep
eats 15 times>, "='Y'\\\\\\\;lbl\\\\\\\=ENCRYPTION\\\\\\\;pos\\\\\\\=6\\\\\\\;\\\;elem3\\\=def\\\\\\\=ENGINE", '\' <repeats 15 times>, "=INNODB\\\\\\
\;lbl\\\\\\\=ENGINE\\\\\\\;pos\\\\\\\=0\\\\\\\;\\\;elem4\\\=def\\\\\\\=ROW_FORMAT", '\' <repeats 15 times>, "=DYNAMIC\\\\\\\;lbl\\\\\\\=ROW_FORMAT
\\\\\\;pos\\\\\\\=3\\\\\\\;\\\;elem5\\\=def\\\\\\\=STATS_PERSISTENT", '\' <repeats 15 times>, "=0\\\\\\\;lbl\\\\\\\=STATS_PERSISTENT\\\\\\\;pos\\
\\\\=4\\\\\\\;\\\;elem6\\\=def\\\\\\\=TABLESPACE", '\' <repeats 15 times>, "=mysql\\\\\\\;lbl\\\\\\\=TABLESPACE\\\\\\\;pos\\\\\\\=5\\\\\\\;\\
\;\;;id=2;idx0=id\=2\;root\=5\;space_id\=4294967294\;table_id\=2\;trx_id\=0\;;space_id=1;"

We can see that ENCRYPTION="Y". So this goes to disk. Next I have to check if next restart also adds the same

@@ -58,8 +60,19 @@ Object_table_impl::Object_table_impl()
}

void Object_table_impl::set_encrypted() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I observed that this is used only for DD properties table and for the rest the constructor does this.

@@ -35,7 +35,9 @@ Object_table_impl::Object_table_impl()
m_target_def(),
m_actual_present(false),
m_actual_def(),
m_hidden(true) {
m_hidden(true),
was_target_encryption_set{false},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better names are m_target_encryption_set and m_actual_encryption_set

Why do you always use "was_"?

@@ -125,6 +127,8 @@ class Object_table_impl : virtual public Object_table {

virtual void set_encrypted();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be rename this set_target_encrypted() instead of generic set_encrypted(). We have sibling set_actual_encrypted().

@@ -125,6 +127,8 @@ class Object_table_impl : virtual public Object_table {

virtual void set_encrypted();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the person who reviews this code should understand what actual vs target table means, it is better if there is atleast 'some' comment on function (along with description in commit message)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to reproduce the above crash in 8.0.15 and I couldn't. May be specific to patch or specific to 8.0.16. Will check

There is new bug with 8.0.16. default_table_encryption=ON at bootstrap doesn't encrypt mysql.ibd. I fixed this (wrote patch and I have to submit PR)

8.0.16 doesn't have the above issue. So this crash is specific to upgrade of encrypted mysql.ibd from 8.0.15 to 8.0.16

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed as part of PS-5925 and PS-5926 (the blockers for this PR)

@@ -58,8 +60,19 @@ Object_table_impl::Object_table_impl()
}

void Object_table_impl::set_encrypted() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in the constructor the member variable is not set. This is a bug
I would suggest to call this set_encrypted() method from constructor

@satya-bodapati
Copy link
Contributor

After applying patch:

Crash after upgrade and restart

Y-010116] [Server] /home/satya/WORK/PS-8.0/bld/runtime_output_directory/mysqld (mysqld 8.0.16-6-debug) starting as process 15893
2019-08-28T11:31:17.368595Z 1 [ERROR] [MY-013183] [InnoDB] Assertion failure: os0file.cc:8983:strlen(srv_uuid) != 0 thread 140737087076096
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/8.0/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.

Thread 2 "mysqld" received signal SIGABRT, Aborted.
[Switching to Thread 0x7fffe814f700 (LWP 15899)]
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff5d3c801 in __GI_abort () at abort.c:79
#2 0x0000555559e1168b in ut_dbg_assertion_failed (expr=0x55555b75a742 "strlen(srv_uuid) != 0", file=0x55555b758038 "/home/satya/WORK/PS-8.0/storage/innobase/os/os0file.cc", line=8983)
at /home/satya/WORK/PS-8.0/storage/innobase/ut/ut0dbg.cc:92
#3 0x0000555559c4716d in Encryption::get_master_key_from_info (encrypt_info=0x7fffe04ce899 "", version=Encryption::ENCRYPTION_VERSION_3, m_key_id=0x7fffe814d85c, srv_uuid=0x7fffe814da20 "",
master_key=0x7fffe814d868) at /home/satya/WORK/PS-8.0/storage/innobase/os/os0file.cc:8983
#4 0x0000555559c47350 in Encryption::decode_encryption_info (key=0x7fffe04c9588 "", iv=0x7fffe04c95c8 "", encryption_info=0x7fffe04ce896 "lCC")
at /home/satya/WORK/PS-8.0/storage/innobase/os/os0file.cc:9043
#5 0x000055555a00ce70 in fsp_header_get_encryption_key (fsp_flags=26624, key=0x7fffe04c9588 "", iv=0x7fffe04c95c8 "", page=0x7fffe04cc000 "\351%\276\257")
at /home/satya/WORK/PS-8.0/storage/innobase/fsp/fsp0fsp.cc:1193
#6 0x000055555a01e44d in Datafile::validate_first_page (this=0x7fffe814e070, space_id=4294967294, flush_lsn=0x0, for_import=false) at /home/satya/WORK/PS-8.0/storage/innobase/fsp/fsp0file.cc:724
#7 0x000055555a01d284 in Datafile::validate_to_dd (this=0x7fffe814e070, space_id=4294967294, flags=26624, for_import=false) at /home/satya/WORK/PS-8.0/storage/innobase/fsp/fsp0file.cc:405
#8 0x0000555559fc599f in fil_ibd_open (validate=true, purpose=FIL_TYPE_TABLESPACE, space_id=4294967294, flags=26624, space_name=0x55555b82e2e8 "mysql", table_name=0x55555b82e2e8 "mysql",
path_in=0x55555b82e2ee "mysql.ibd", strict=true, old_space=false, keyring_encryption_info=...) at /home/satya/WORK/PS-8.0/storage/innobase/fil/fil0fil.cc:5729
#9 0x0000555559ac55f3 in dd_open_hardcoded (space_id=4294967294, filename=0x55555b82e2ee "mysql.ibd", flags=26624) at /home/satya/WORK/PS-8.0/storage/innobase/handler/ha_innodb.cc:5512
#10 0x0000555559ac5c23 in innobase_init_files (dict_init_mode=DICT_INIT_CHECK_FILES, tablespaces=0x7fffe814e910, is_dd_encrypted=@0x7fffe814e7f5: true)
at /home/satya/WORK/PS-8.0/storage/innobase/handler/ha_innodb.cc:5655
#11 0x0000555559ad6ec5 in innobase_ddse_dict_init (dict_init_mode=DICT_INIT_CHECK_FILES, version=80016, tables=0x7fffe814e8f0, tablespaces=0x7fffe814e910)
at /home/satya/WORK/PS-8.0/storage/innobase/handler/ha_innodb.cc:12728
#12 0x0000555559605430 in dd::bootstrap::DDSE_dict_init (thd=0x55555cd56850, dict_init_mode=DICT_INIT_CHECK_FILES, version=80016) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:748
#13 0x0000555559810486 in dd::upgrade_57::do_pre_checks_and_initialize_dd (thd=0x55555cd56850) at /home/satya/WORK/PS-8.0/sql/dd/upgrade_57/upgrade.cc:912
#14 0x000055555885d4ff in bootstrap::handle_bootstrap (arg=0x55555cd56850) at /home/satya/WORK/PS-8.0/sql/bootstrap.cc:347
#15 0x00005555599cbb74 in pfs_spawn_thread (arg=0x55555cc48d70) at /home/satya/WORK/PS-8.0/storage/perfschema/pfs.cc:2836
#16 0x00007ffff79b66db in start_thread (arg=0x7fffe814f700) at pthread_create.c:463
#17 0x00007ffff5e1d88f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

@satya-bodapati
Copy link
Contributor

I tried to reproduce the above crash in 8.0.15 and I couldn't. May be specific to patch or specific to 8.0.16. Will check

@satya-bodapati
Copy link
Contributor

the above crash is easy to reproduce. Just add restart in the test

--let $assert_cond= "[SELECT ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME=\\'mysql\\']" = 'Y'

--source include/restart_mysqld.inc
SHOW TABLES;

--source include/shutdown_mysqld.inc

@satya-bodapati
Copy link
Contributor

Another thing to find out how the upstream does "ALTER TABLESPACE mysql ENCRYPTION='Y'". Does it add encryption attribute in dd_properties of all tables?

@satya-bodapati
Copy link
Contributor

Found the reason for crash. it is not related to this patch. I could reproduce the same crash in 8.0.15 using same datadir

@satya-bodapati
Copy link
Contributor

Another thing to find out how the upstream does "ALTER TABLESPACE mysql ENCRYPTION='Y'". Does it add encryption attribute in dd_properties of all tables?

The answer is NO. Upstream does kind of "cheating". It doesn't treat mysql tablespace as encrypted during the bootstrap phase.

@satya-bodapati
Copy link
Contributor

Found the reason for crash. it is not related to this patch. I could reproduce the same crash in 8.0.15 using same datadir

Fixed as PS-5925 and PS-5926

@satya-bodapati
Copy link
Contributor

My fear on double encryption is indeed true. I just bumped up DD version to simulate upgrade and it crashed.

#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff5d3c801 in __GI_abort () at abort.c:79
#2 0x00007ffff5d2c39a in __assert_fail_base (fmt=0x7ffff5eb37d8 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n",
assertion=assertion@entry=0x55555afddef8 "element_numbers != nullptr && element_definitions != nullptr && element_numbers->find(element_name) == element_numbers->end() && element_definitions->find(element_number) == element_definitions->end()", file=file@entry=0x55555afddea8 "/home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h", line=line@entry=115,
function=function@entry=0x55555afde960 <dd::Object_table_definition_impl::add_element(int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::map<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, int, std::less<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const, int> > >, std::map<int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, std::less, std::allocator<std::pair<int const, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > > > >)::PRETTY_FUNCTION> "void dd::Object_table_definition_impl::add_element(int, const String_type&, const String_type&, dd::Object_table_definition_impl::Element_numbers*, dd::Object_table_definition_impl::Element_definitions*)") at assert.c:92
#3 0x00007ffff5d2c412 in __GI___assert_fail (
assertion=0x55555afddef8 "element_numbers != nullptr && element_definitions != nullptr && element_numbers->find(element_name) == element_numbers->end() && element_definitions->find(element_number) == element_definitions->end()", file=0x55555afddea8 "/home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h", line=115,
function=0x55555afde960 <dd::Object_table_definition_impl::add_element(int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::map<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, int, std::less<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const, int> > >, std::map<int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, std::less, std::allocator<std::pair<int const, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > > > >)::PRETTY_FUNCTION> "void dd::Object_table_definition_impl::add_element(int, const String_type&, const String_type&, dd::Object_table_definition_impl::Element_numbers*, dd::Object_table_definition_impl::Element_definitions*)") at assert.c:101
#4 0x00005555595f016b in dd::Object_table_definition_impl::add_element (this=0x7fffe04d0ac8, element_number=6, element_name="ENCRYPTION", element_definition="ENCRYPTION='Y'",
element_numbers=0x7fffe04d0c50, element_definitions=0x7fffe04d0c80) at /home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h:112
#5 0x00005555595f0f86 in dd::Object_table_definition_impl::add_option (this=0x7fffe04d0ac8, option_number=6, option_name="ENCRYPTION", option_definition="ENCRYPTION='Y'")
at /home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h:283
#6 0x00005555597bbad0 in dd::Object_table_impl::set_actual_encrypted (this=0x7fffe04d08b0) at /home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_impl.cc:72
#7 0x00005555596027a5 in (anonymous namespace)::update_system_tables (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:168
#8 0x0000555559608f03 in dd::initialize_dd_properties (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:1356
#9 0x0000555559606c56 in dd::bootstrap::restart (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:1061
#10 0x000055555980feb5 in dd::upgrade_57::restart_dictionary (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/upgrade_57/upgrade.cc:795
#11 0x00005555598107f9 in dd::upgrade_57::do_pre_checks_and_initialize_dd (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/upgrade_57/upgrade.cc:951
#12 0x000055555885d5df in bootstrap::handle_bootstrap (arg=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/bootstrap.cc:347
#13 0x00005555599cbc54 in pfs_spawn_thread (arg=0x55555cc48d70) at /home/satya/WORK/PS-8.0/storage/perfschema/pfs.cc:2836
#14 0x00007ffff79b66db in start_thread (arg=0x7fffe814f700) at pthread_create.c:463
#15 0x00007ffff5e1d88f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb)

@satya-bodapati
Copy link
Contributor

So on restart, dd::Object_table_impl::Object_table_impl() sets encryption property..

My fear on double encryption is indeed true. I just bumped up DD version to simulate upgrade and it crashed.

#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff5d3c801 in __GI_abort () at abort.c:79
#2 0x00007ffff5d2c39a in __assert_fail_base (fmt=0x7ffff5eb37d8 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n",
assertion=assertion@entry=0x55555afddef8 "element_numbers != nullptr && element_definitions != nullptr && element_numbers->find(element_name) == element_numbers->end() && element_definitions->find(element_number) == element_definitions->end()", file=file@entry=0x55555afddea8 "/home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h", line=line@entry=115,
function=function@entry=0x55555afde960 <dd::Object_table_definition_impl::add_element(int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::map<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, int, std::less<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const, int> > >, std::map<int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, std::less, std::allocator<std::pair<int const, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > > > >)::PRETTY_FUNCTION> "void dd::Object_table_definition_impl::add_element(int, const String_type&, const String_type&, dd::Object_table_definition_impl::Element_numbers*, dd::Object_table_definition_impl::Element_definitions*)") at assert.c:92
#3 0x00007ffff5d2c412 in __GI___assert_fail (
assertion=0x55555afddef8 "element_numbers != nullptr && element_definitions != nullptr && element_numbers->find(element_name) == element_numbers->end() && element_definitions->find(element_number) == element_definitions->end()", file=0x55555afddea8 "/home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h", line=115,
function=0x55555afde960 <dd::Object_table_definition_impl::add_element(int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&, std::map<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, int, std::less<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const, int> > >, std::map<int, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >, std::less, std::allocator<std::pair<int const, std::__cxx11::basic_string<char, std::char_traits, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > > > >)::PRETTY_FUNCTION> "void dd::Object_table_definition_impl::add_element(int, const String_type&, const String_type&, dd::Object_table_definition_impl::Element_numbers*, dd::Object_table_definition_impl::Element_definitions*)") at assert.c:101
#4 0x00005555595f016b in dd::Object_table_definition_impl::add_element (this=0x7fffe04d0ac8, element_number=6, element_name="ENCRYPTION", element_definition="ENCRYPTION='Y'",
element_numbers=0x7fffe04d0c50, element_definitions=0x7fffe04d0c80) at /home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h:112
#5 0x00005555595f0f86 in dd::Object_table_definition_impl::add_option (this=0x7fffe04d0ac8, option_number=6, option_name="ENCRYPTION", option_definition="ENCRYPTION='Y'")
at /home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_definition_impl.h:283
#6 0x00005555597bbad0 in dd::Object_table_impl::set_actual_encrypted (this=0x7fffe04d08b0) at /home/satya/WORK/PS-8.0/sql/dd/impl/types/object_table_impl.cc:72
#7 0x00005555596027a5 in (anonymous namespace)::update_system_tables (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:168
#8 0x0000555559608f03 in dd::initialize_dd_properties (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:1356
#9 0x0000555559606c56 in dd::bootstrap::restart (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/impl/bootstrap/bootstrapper.cc:1061
#10 0x000055555980feb5 in dd::upgrade_57::restart_dictionary (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/upgrade_57/upgrade.cc:795
#11 0x00005555598107f9 in dd::upgrade_57::do_pre_checks_and_initialize_dd (thd=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/dd/upgrade_57/upgrade.cc:951
#12 0x000055555885d5df in bootstrap::handle_bootstrap (arg=0x55555cd58d50) at /home/satya/WORK/PS-8.0/sql/bootstrap.cc:347
#13 0x00005555599cbc54 in pfs_spawn_thread (arg=0x55555cc48d70) at /home/satya/WORK/PS-8.0/storage/perfschema/pfs.cc:2836
#14 0x00007ffff79b66db in start_thread (arg=0x7fffe814f700) at pthread_create.c:463
#15 0x00007ffff5e1d88f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb)

To get this crash: Apply this PR, get datadir, and then apply this patch

diff --git a/sql/dd/dd_version.h b/sql/dd/dd_version.h
index ee1dd0e1d96..216225b958f 100644
--- a/sql/dd/dd_version.h
+++ b/sql/dd/dd_version.h
@@ -176,7 +176,7 @@
 */
 namespace dd {
 
-static const uint DD_VERSION = 80016;
+static const uint DD_VERSION = 80017;

Startup on this datadir by 8017 (upcoming merge too may be) will cause failure

@satya-bodapati
Copy link
Contributor

Very happy to find a problem that will occur in future 😊

@satya-bodapati
Copy link
Contributor

Next onto fixing this issue

@satya-bodapati
Copy link
Contributor

Next onto fixing this issue

A temporary patch that solves the double encryption issue.

diff --git a/sql/dd/impl/bootstrap/bootstrapper.cc b/sql/dd/impl/bootstrap/bootstrapper.cc
index 9b564821dc9..1a1cadab5ae 100644
--- a/sql/dd/impl/bootstrap/bootstrapper.cc
+++ b/sql/dd/impl/bootstrap/bootstrapper.cc
@@ -72,6 +72,7 @@
 #include "sql/mysqld.h"
 #include "sql/sql_zip_dict.h"
 #include "sql/thd_raii.h"
+#include "sql/dd/impl/types/object_table_definition_impl.h"
 
 using namespace dd;
 
@@ -162,9 +163,39 @@ bool update_system_tables(THD *thd) {
         my_error(ER_DD_METADATA_NOT_FOUND, MYF(0), it->first.c_str());
         return true;
       }
+
       std::unique_ptr<Properties> table_def_properties(
           Properties::parse_properties(def));
+
+      String_type options_str;
+      table_def_properties->get("options", &options_str);
+      std::unique_ptr<Properties> opts(
+          Properties::parse_properties(options_str));
+      bool encryption_exists = false;
+      for (Properties::const_iterator it = opts->begin(); it != opts->end();
+           ++it) {
+        String_type label;
+        int pos = 0;
+        String_type def;
+
+        std::unique_ptr<Properties> element(
+            Properties::parse_properties(it->second));
+        if (element->get("lbl", &label) || element->get("pos", &pos) ||
+            element->get("def", &def)) {
+        }
+        fprintf(stderr, "Label is %s\n", label.c_str());
+        fprintf(stderr, "pos is %d\n", pos);
+        fprintf(stderr, "definition is %s\n", def.c_str());
+
+        if (my_strcasecmp(system_charset_info, label.c_str(), "ENCRYPTION") ==
+            0) {
+          encryption_exists = true;
+          break;
+        }
+      }
+
       table_def->set_actual_table_definition(*table_def_properties);
+      if (!encryption_exists) table_def->set_actual_encrypted();
     }
   }

@satya-bodapati
Copy link
Contributor

I have to check if we can survive without the on-disk change

@satya-bodapati
Copy link
Contributor

I have to check if we can survive without the on-disk change

No, even if I remove dd::update_properties line from this PR, there is another place where dd::update_properties is called.

So it goes to disk by default on upgrades.

So two options infront of us

  1. Accept on-disk changes. DD properties of core DD tables will deviate from Upstream (My major concern) :( We will need some kind of special handling for future versions too (to avoid double encryption attribute additions)

  2. Since table creation in mysql is hardcoded (all done by server), we can exempt the encryption flag check for tables to be created in mysql tablespace. This is not as bad as it looks :) because it is restricted to tablespace that is used only server and not users. Also upstream is also doing some kind of cheating here.

@satya-bodapati
Copy link
Contributor

satya-bodapati commented Sep 4, 2019

I have to check if we can survive without the on-disk change

No, even if I remove dd::update_properties line from this PR, there is another place where dd::update_properties is called.

So it goes to disk by default on upgrades.

So two options infront of us

1. Accept on-disk changes. DD properties of core DD tables will deviate from Upstream (My major concern) :( We will need some kind of special handling for future versions too (to avoid double encryption attribute additions)

2. Since table creation in mysql is hardcoded (all done by server), we can exempt the encryption flag check for tables to be created in mysql tablespace. This is not as bad as it looks :) because it is restricted to tablespace that is used only server and not users. Also upstream is also doing some kind of cheating here.

Its kind of pick the poison scenario

  1. Clean but deviate from upstream disk format, do extra handling for future version
  2. Not clean (somewhat hackish, same as upstream) but compatible to upstream disk format

@satya-bodapati
Copy link
Contributor

Other issues with deviating from upgrade on-disk format is that 8.0 provides ability to downgrade until as specific version (like two minor versions?). So such on-disk deviation will prevent downgrades

@satya-bodapati
Copy link
Contributor

Another thing to find out how the upstream does "ALTER TABLESPACE mysql ENCRYPTION='Y'". Does it add encryption attribute in dd_properties of all tables?

The answer is NO. Upstream does kind of "cheating". It doesn't treat mysql tablespace as encrypted during the bootstrap phase.

DD properties are not updated but the table options of DD tables in mysql.tables.options are updated.

@satya-bodapati
Copy link
Contributor

Another thing to find out how the upstream does "ALTER TABLESPACE mysql ENCRYPTION='Y'". Does it add encryption attribute in dd_properties of all tables?

The answer is NO. Upstream does kind of "cheating". It doesn't treat mysql tablespace as encrypted during the bootstrap phase.

DD properties are not updated but the table options of DD tables in mysql.tables.options are updated.

Not sure if this is useful or not .. Because when DD is booted, the tables are created from DD properties? This is because mysql.tables is not available during bootstrap

mysql-test/t/percona_8_0_15_dd_upgrade_encrypted.test Outdated Show resolved Hide resolved
mysql-test/t/percona_8_0_15_dd_upgrade_encrypted.test Outdated Show resolved Hide resolved
sql/dd/impl/bootstrap/bootstrapper.cc Outdated Show resolved Hide resolved
sql/dd/impl/bootstrap/bootstrapper.cc Outdated Show resolved Hide resolved
sql/dd/impl/bootstrap/bootstrapper.cc Show resolved Hide resolved
sql/dd/impl/bootstrap/bootstrapper.cc Show resolved Hide resolved
sql/dd/impl/bootstrap/bootstrapper.cc Outdated Show resolved Hide resolved
sql/dd/impl/types/object_table_impl.h Show resolved Hide resolved
@satya-bodapati
Copy link
Contributor

tablespace

Upgrade creates tables in mysql tablespaces in two phases:

* Phase 1 creates tables based on actual DD properties,
  taken from dd_properties table, option SYSTEM_TABLES.
  We add here in-memory encryption flag to CREATE statement
  if the mysql tablespace is encrypted.

* Phase 2 create target tables. We add here in-memory encryption
  flag to CREATE statement if mysql tablespace is encrypted and update
  SYSTEM_TABLES option in dd_properties with encryption flag.

Please elaborate the problem clearly and the document the fix

tablespace

During upgrade both actual and target table definitions need to
have ENCRYPTION='Y' set when we upgrading from encrypted mysql.ibd.
When upgrading from version previous to 8.0.16 where mysql.ibd
can be encrypted in PS we need to add ENCRYPTION='Y' to all the system
target tables to be created in mysql tablespace. We also need to add
ENCRYPTION='Y' to actual tables definitions, although those tables already
exist. This step is only to create TABLE*/TABLE_SHARE* for core tables.

Upstream does mysql.ibd encryption after bootstrap with ALTER statement.
Thus encryption of mysql.ibd does not update SYSTEM_TABLES properties in
dd_properties table. To be compliant we do not update dd_properties
SYSTEM_TABLES with ENCRYPTION='Y' (per every SYSTEM TABLE) also.
@robgolebiowski robgolebiowski merged commit 3af21f4 into percona:8.0 Sep 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants