Skip to content

Commit 6e5f896

Browse files
amitabdahlerlend
authored andcommitted
Bug#26486160 : mysql server upgrade to 8.0.3 with 1 million tables fails
When mysql-5.7 data directory contains a large number of tables, in-place upgrade to 8.0 takes a large amount of memory. The large amount of memory consumption is due to usage of THD::mem_root and THD::main_mem_root for space allocation in - prepare_create_field() for table migration - dd::create_dd_user_table() for table migration - migrate_routine_to_dd() - migrate_event_to_dd() - add_sdi_info() Fix: - Allocate m_query_tables_list in THD::Transaction_state on heap rather than thd->main_mem_root. - Add fetch_global_component_names() and fetch_global_component_ids() APIs to DD Client to replace usage of fetch_global_components() in add_sdi_info(). - Reduce scope of Auto_releaser in add_sdi_info() to each Tablespace and to each Table. - Swap out THD::mem_root while adding SDI information and migrating tables, events and routines. - Add trans_commit_stmt() and trans_commit() after each call of dd::sdi::store(). - Register InnoDB engine in the Transaction context when calling Handler::sdi_set() so that trans_commit_stmt() can release InnoDB locks on the tables. Change-Id: Ib96259a5c991d48c90df6ea0735f6fbce4aabb23
1 parent 685a0a2 commit 6e5f896

File tree

18 files changed

+247
-155
lines changed

18 files changed

+247
-155
lines changed

sql/dd/cache/dictionary_client.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,34 @@ class Dictionary_client {
855855
std::vector<String_type> *names) const
856856
MY_ATTRIBUTE((warn_unused_result));
857857

858+
/**
859+
Fetch all global component ids of the given type.
860+
861+
@tparam T Type of components to get.
862+
@param [out] ids An std::vector containing all component ids.
863+
864+
@return true Failure (error is reported).
865+
@return false Success.
866+
*/
867+
868+
template <typename T>
869+
bool fetch_global_component_ids(std::vector<Object_id> *ids) const
870+
MY_ATTRIBUTE((warn_unused_result));
871+
872+
/**
873+
Fetch all global component names of the given type.
874+
875+
@tparam T Type of components to get.
876+
@param [out] names An std::vector containing all component names.
877+
878+
@return true Failure (error is reported).
879+
@return false Success.
880+
*/
881+
882+
template <typename T>
883+
bool fetch_global_component_names(std::vector<String_type> *names) const
884+
MY_ATTRIBUTE((warn_unused_result));
885+
858886
/**
859887
Fetch all components in the schema.
860888

sql/dd/impl/cache/dictionary_client.cc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,80 @@ bool Dictionary_client::check_foreign_key_exists(
18771877
return false;
18781878
}
18791879

1880+
template <typename T>
1881+
bool fetch_raw_record(THD *thd,
1882+
std::function<bool(Raw_record *)> const &processor) {
1883+
Transaction_ro trx(thd, ISO_READ_COMMITTED);
1884+
1885+
trx.otx.register_tables<T>();
1886+
Raw_table *table = trx.otx.get_table<T>();
1887+
DBUG_ASSERT(table);
1888+
1889+
if (trx.otx.open_tables()) {
1890+
DBUG_ASSERT(thd->is_system_thread() || thd->killed || thd->is_error());
1891+
return true;
1892+
}
1893+
1894+
std::unique_ptr<Raw_record_set> rs;
1895+
if (table->open_record_set(nullptr, rs)) {
1896+
DBUG_ASSERT(thd->is_system_thread() || thd->killed || thd->is_error());
1897+
return true;
1898+
}
1899+
1900+
Raw_record *r = rs->current_record();
1901+
String_type s;
1902+
while (r) {
1903+
if (processor(r) || rs->next(r)) {
1904+
DBUG_ASSERT(thd->is_system_thread() || thd->killed || thd->is_error());
1905+
return true;
1906+
}
1907+
}
1908+
1909+
return false;
1910+
}
1911+
1912+
// Fetch the ids of all the components.
1913+
template <typename T>
1914+
bool Dictionary_client::fetch_global_component_ids(
1915+
std::vector<Object_id> *ids) const {
1916+
DBUG_ASSERT(ids);
1917+
1918+
auto processor = [&](Raw_record *r) -> bool {
1919+
ids->push_back(r->read_int(0));
1920+
return false;
1921+
};
1922+
1923+
if (fetch_raw_record<T>(m_thd, processor)) {
1924+
ids->clear();
1925+
DBUG_ASSERT(m_thd->is_system_thread() || m_thd->killed ||
1926+
m_thd->is_error());
1927+
return true;
1928+
}
1929+
1930+
return false;
1931+
}
1932+
1933+
// Fetch the names of all the components.
1934+
template <typename T>
1935+
bool Dictionary_client::fetch_global_component_names(
1936+
std::vector<String_type> *names) const {
1937+
DBUG_ASSERT(names);
1938+
1939+
auto processor = [&](Raw_record *r) -> bool {
1940+
names->push_back(r->read_str(T::DD_table::FIELD_NAME));
1941+
return false;
1942+
};
1943+
1944+
if (fetch_raw_record<T>(m_thd, processor)) {
1945+
names->clear();
1946+
DBUG_ASSERT(m_thd->is_system_thread() || m_thd->killed ||
1947+
m_thd->is_error());
1948+
return true;
1949+
}
1950+
1951+
return false;
1952+
}
1953+
18801954
// Fetch the names of all the components in the schema.
18811955
template <typename T>
18821956
bool Dictionary_client::fetch_schema_component_names(
@@ -2757,6 +2831,12 @@ template bool Dictionary_client::fetch_schema_component_names<Abstract_table>(
27572831
template bool Dictionary_client::fetch_schema_component_names<Event>(
27582832
const Schema *, std::vector<String_type> *) const;
27592833

2834+
template bool Dictionary_client::fetch_global_component_ids<Table>(
2835+
std::vector<Object_id> *) const;
2836+
2837+
template bool Dictionary_client::fetch_global_component_names<Tablespace>(
2838+
std::vector<String_type> *) const;
2839+
27602840
template bool Dictionary_client::fetch_referencing_views_object_id<View_table>(
27612841
const char *schema, const char *tbl_or_sf_name,
27622842
std::vector<Object_id> *view_ids) const;

sql/dd/impl/sdi.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ namespace sdi {
545545

546546
bool store(THD *thd, const Table *tp) {
547547
const Table &t = ptr_as_cref(tp);
548-
const handlerton &hton = ptr_as_cref(resolve_hton(thd, t));
548+
handlerton *hton = resolve_hton(thd, t);
549549

550550
return with_schema(thd, t.schema_id(), [&](const Schema &s) {
551551
dd::Sdi_type sdi = serialize(thd, t, s.name());
@@ -558,8 +558,8 @@ bool store(THD *thd, const Table *tp) {
558558
return true;
559559
});
560560
return checked_return(
561-
hton.sdi_set ? sdi_tablespace::store_tbl_sdi(thd, hton, sdi, t, s)
562-
: sdi_file::store_tbl_sdi(sdi, t, s));
561+
hton->sdi_set ? sdi_tablespace::store_tbl_sdi(thd, hton, sdi, t, s)
562+
: sdi_file::store_tbl_sdi(sdi, t, s));
563563
});
564564
}
565565

@@ -572,7 +572,7 @@ bool store(THD *thd, const Tablespace *ts) {
572572
if (sdi.empty()) {
573573
return checked_return(true);
574574
}
575-
return checked_return(sdi_tablespace::store_tsp_sdi(*hton, sdi, *ts));
575+
return checked_return(sdi_tablespace::store_tsp_sdi(hton, sdi, *ts));
576576
}
577577

578578
bool drop(THD *thd, const Table *tp) {

sql/dd/impl/sdi_tablespace.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -163,7 +163,7 @@ dd::sdi_key_t get_sdi_key(const dd::Tablespace &tablespace) {
163163

164164
namespace dd {
165165
namespace sdi_tablespace {
166-
bool store_tbl_sdi(THD *thd, const handlerton &hton, const dd::Sdi_type &sdi,
166+
bool store_tbl_sdi(THD *thd, handlerton *hton, const dd::Sdi_type &sdi,
167167
const dd::Table &table,
168168
const dd::Schema &schema MY_ATTRIBUTE((unused))) {
169169
const dd::sdi_key_t key = get_sdi_key(table);
@@ -172,7 +172,7 @@ bool store_tbl_sdi(THD *thd, const handlerton &hton, const dd::Sdi_type &sdi,
172172
DBUG_PRINT("ddsdi", ("store_sdi_with_schema[](Schema" ENTITY_FMT
173173
", Table" ENTITY_FMT ")",
174174
ENTITY_VAL(schema), ENTITY_VAL(table)));
175-
if (hton.sdi_set(tblspc, &table, &key, sdi.c_str(), sdi.size())) {
175+
if (hton->sdi_set(hton, tblspc, &table, &key, sdi.c_str(), sdi.size())) {
176176
return checked_return(true);
177177
}
178178

@@ -182,12 +182,12 @@ bool store_tbl_sdi(THD *thd, const handlerton &hton, const dd::Sdi_type &sdi,
182182
return apply_to_tablespaces(thd, table, store_sdi);
183183
}
184184

185-
bool store_tsp_sdi(const handlerton &hton, const Sdi_type &sdi,
185+
bool store_tsp_sdi(handlerton *hton, const Sdi_type &sdi,
186186
const Tablespace &tblspc) {
187187
dd::sdi_key_t key = get_sdi_key(tblspc);
188188

189189
DBUG_PRINT("ddsdi", ("store_tsp_sdi(" ENTITY_FMT ")", ENTITY_VAL(tblspc)));
190-
if (hton.sdi_set(tblspc, nullptr, &key, sdi.c_str(), sdi.size())) {
190+
if (hton->sdi_set(hton, tblspc, nullptr, &key, sdi.c_str(), sdi.size())) {
191191
return checked_return(true);
192192
}
193193
return false;

sql/dd/impl/sdi_tablespace.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -61,7 +61,7 @@ namespace sdi_tablespace {
6161
@param table
6262
@param schema
6363
*/
64-
bool store_tbl_sdi(THD *thd, const handlerton &hton, const Sdi_type &sdi,
64+
bool store_tbl_sdi(THD *thd, handlerton *hton, const Sdi_type &sdi,
6565
const Table &table, const dd::Schema &schema);
6666

6767
/**
@@ -71,7 +71,7 @@ bool store_tbl_sdi(THD *thd, const handlerton &hton, const Sdi_type &sdi,
7171
@param sdi
7272
@param tablespace
7373
*/
74-
bool store_tsp_sdi(const handlerton &hton, const Sdi_type &sdi,
74+
bool store_tsp_sdi(handlerton *hton, const Sdi_type &sdi,
7575
const Tablespace &tablespace);
7676

7777
/**

sql/dd/upgrade/event.cc

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -551,12 +551,12 @@ bool migrate_events_to_dd(THD *thd) {
551551
uint flags = MYSQL_LOCK_IGNORE_TIMEOUT;
552552
DML_prelocking_strategy prelocking_strategy;
553553
MEM_ROOT records_mem_root;
554+
Thd_mem_root_guard root_guard(thd, &records_mem_root);
554555

555556
tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
556557

557558
table_list = &tables;
558559
if (open_and_lock_tables(thd, table_list, flags, &prelocking_strategy)) {
559-
close_thread_tables(thd);
560560
LogErr(ERROR_LEVEL, ER_EVENT_CANT_OPEN_TABLE_MYSQL_EVENT);
561561
return true;
562562
}
@@ -593,10 +593,6 @@ bool migrate_events_to_dd(THD *thd) {
593593
goto err;
594594
}
595595

596-
init_sql_alloc(PSI_NOT_INSTRUMENTED, &records_mem_root, MEM_ROOT_BLOCK_SIZE,
597-
0);
598-
thd->mem_root = &records_mem_root;
599-
600596
if (migrate_event_to_dd(thd, event_table)) goto err;
601597

602598
// Read the next row in 'event' table via index.
@@ -610,12 +606,10 @@ bool migrate_events_to_dd(THD *thd) {
610606
}
611607

612608
my_tz_free();
613-
free_root(&records_mem_root, MYF(0));
614609
return false;
615610

616611
err:
617612
my_tz_free();
618-
free_root(&records_mem_root, MYF(0));
619613
return true;
620614
}
621615

sql/dd/upgrade/global.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -40,14 +40,20 @@ namespace upgrade_57 {
4040
const char *TRN_EXT = ".TRN";
4141
const char *TRG_EXT = ".TRG";
4242

43-
System_table_close_guard::System_table_close_guard(THD *thd, TABLE *table) {
43+
Thd_mem_root_guard::Thd_mem_root_guard(THD *thd, MEM_ROOT *mem_root) {
4444
m_thd = thd;
45-
m_table = table;
46-
m_mem_root = m_thd->mem_root;
45+
m_thd_prev_mem_root = m_thd->mem_root;
46+
m_thd->mem_root = mem_root;
4747
}
4848

49+
Thd_mem_root_guard::~Thd_mem_root_guard() {
50+
m_thd->mem_root = m_thd_prev_mem_root;
51+
}
52+
53+
System_table_close_guard::System_table_close_guard(THD *thd, TABLE *table)
54+
: m_thd(thd), m_table(table) {}
55+
4956
System_table_close_guard::~System_table_close_guard() {
50-
m_thd->mem_root = m_mem_root;
5157
if (m_table->file->inited) (void)m_table->file->ha_index_end();
5258
close_thread_tables(m_thd);
5359
}

sql/dd/upgrade/global.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,26 @@ const String_type index_stats_backup = "innodb_index_stats_backup57";
5454
const String_type table_stats = "innodb_table_stats";
5555
const String_type table_stats_backup = "innodb_table_stats_backup57";
5656

57+
/**
58+
THD::mem_root is only switched with the given mem_root and switched back
59+
on destruction. This does not free any mem_root.
60+
*/
61+
class Thd_mem_root_guard {
62+
THD *m_thd;
63+
MEM_ROOT *m_thd_prev_mem_root;
64+
65+
public:
66+
Thd_mem_root_guard(THD *thd, MEM_ROOT *mem_root);
67+
~Thd_mem_root_guard();
68+
};
69+
5770
/**
5871
RAII for handling open and close of event and proc tables.
5972
*/
6073

6174
class System_table_close_guard {
6275
THD *m_thd;
6376
TABLE *m_table;
64-
MEM_ROOT *m_mem_root;
6577

6678
public:
6779
System_table_close_guard(THD *thd, TABLE *table);

sql/dd/upgrade/routine.cc

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,12 @@ bool migrate_routines_to_dd(THD *thd) {
442442
uint flags = MYSQL_LOCK_IGNORE_TIMEOUT;
443443
DML_prelocking_strategy prelocking_strategy;
444444
MEM_ROOT records_mem_root;
445+
Thd_mem_root_guard root_guard(thd, &records_mem_root);
445446

446447
tables.init_one_table("mysql", 5, "proc", 4, "proc", TL_READ);
447448

448449
table_list = &tables;
449450
if (open_and_lock_tables(thd, table_list, flags, &prelocking_strategy)) {
450-
close_thread_tables(thd);
451451
LogErr(ERROR_LEVEL, ER_CANT_OPEN_TABLE_MYSQL_PROC);
452452
return true;
453453
}
@@ -473,35 +473,25 @@ bool migrate_routines_to_dd(THD *thd) {
473473
// Read first record from mysql.proc table. Return if table is empty.
474474
if ((error = proc_table->file->ha_index_first(proc_table->record[0]))) {
475475
if (error == HA_ERR_END_OF_FILE) return false;
476-
477476
LogErr(ERROR_LEVEL, ER_CANT_READ_TABLE_MYSQL_PROC);
478477
return true;
479478
}
480479

481-
init_sql_alloc(PSI_NOT_INSTRUMENTED, &records_mem_root, MEM_ROOT_BLOCK_SIZE,
482-
0);
483-
thd->mem_root = &records_mem_root;
484-
485480
// Migrate first record read to dd routines table.
486-
if (migrate_routine_to_dd(thd, proc_table)) goto err;
481+
if (migrate_routine_to_dd(thd, proc_table)) return true;
487482

488483
// Read one record from mysql.proc table and
489484
// migrate it until all records are finished
490485
while (!(error = proc_table->file->ha_index_next(proc_table->record[0]))) {
491-
if (migrate_routine_to_dd(thd, proc_table)) goto err;
486+
if (migrate_routine_to_dd(thd, proc_table)) return true;
492487
}
493488

494489
if (error != HA_ERR_END_OF_FILE) {
495490
LogErr(ERROR_LEVEL, ER_CANT_READ_TABLE_MYSQL_PROC);
496-
goto err;
491+
return true;
497492
}
498493

499-
free_root(&records_mem_root, MYF(0));
500494
return false;
501-
502-
err:
503-
free_root(&records_mem_root, MYF(0));
504-
return true;
505495
}
506496

507497
} // namespace upgrade_57

0 commit comments

Comments
 (0)