Skip to content

Commit

Permalink
Merge pull request #1586 from satya-bodapati/dev-reducedlock
Browse files Browse the repository at this point in the history
PXB-3295 : Undo tablespaces are not tracked properly with lock-ddl=RE…
  • Loading branch information
satya-bodapati authored Jul 18, 2024
2 parents 1ad8fd9 + 49c8a34 commit 2fe6a4d
Show file tree
Hide file tree
Showing 10 changed files with 329 additions and 39 deletions.
63 changes: 44 additions & 19 deletions storage/innobase/fil/fil0fil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,15 @@ class Tablespace_dirs {
void set_scan_dirs(const std::string &directories);

/** Discover tablespaces by reading the header from .ibd files.
@param[in] populate_fil_cache if true, tabelspace are loaded to cache
@param[in] is_prep_handled_ddls if true, xtrabackup uses
ibd_open_for_recovery instead of
fil_open_for_xtrabackup()
@param[in] only_undo if true, only the undo tablespaces are
discovered
@return DB_SUCCESS if all goes well */
[[nodiscard]] dberr_t scan(bool populate_fil_cache, bool is_prep_handle_ddls);
[[nodiscard]] dberr_t scan(bool populate_fil_cache, bool is_prep_handle_ddls,
bool only_undo);

/** Clear all the tablespace file data but leave the list of
scanned directories in place. */
Expand Down Expand Up @@ -1700,9 +1707,17 @@ class Fil_system {
}

/** Scan the directories to build the tablespace ID to file name
mapping table. */
dberr_t scan(bool populate_fil_cache, bool is_prep_handle_ddls) {
return (m_dirs.scan(populate_fil_cache, is_prep_handle_ddls));
mapping table
@param[in] populate_fil_cache if true, tabelspace are loaded to cache
@param[in] is_prep_handled_ddls if true, xtrabackup uses
ibd_open_for_recovery instead of
fil_open_for_xtrabackup()
@param[in] only_undo if true, only the undo tablespaces are
discovered
@return DB_SUCCESS on success, other codes on errors */
dberr_t scan(bool populate_fil_cache, bool is_prep_handle_ddls,
bool only_undo) {
return (m_dirs.scan(populate_fil_cache, is_prep_handle_ddls, only_undo));
}

/** Open all known tablespaces. */
Expand Down Expand Up @@ -11964,10 +11979,14 @@ void Tablespace_dirs::set_scan_dirs(const std::string &in_directories) {
}

/** Discover tablespaces by reading the header from .ibd files.
@param[in] in_directories Directories to scan
@param[in] populate_fil_cache if true, tabelspace are loaded to cache
@param[in] is_prep_handled_ddls if true, xtrabackup uses ibd_open_for_recovery
instead of fil_open_for_xtrabackup()
@param[in] only_undo if true, only the undo tablespaces are
discovered
@return DB_SUCCESS if all goes well */
dberr_t Tablespace_dirs::scan(bool populate_fil_cache,
bool is_prep_handle_ddls) {
dberr_t Tablespace_dirs::scan(bool populate_fil_cache, bool is_prep_handle_ddls,
bool only_undo) {
Scanned_files ibd_files;
Scanned_files undo_files;
uint16_t count = 0;
Expand All @@ -11982,9 +12001,10 @@ dberr_t Tablespace_dirs::scan(bool populate_fil_cache,

ib::info(ER_IB_MSG_379) << "Scanning '" << dir.path() << "'";

/* Walk the sub-tree of dir. */

Dir_Walker::walk(real_path_dir, true, [&](const std::string &path) {
/* Walk the sub-tree of dir. If it is undo tablespaces only discovery,
used by xtrabackup, we dont do look into sub directories */
bool walk_subtree = only_undo ? false : true;
Dir_Walker::walk(real_path_dir, walk_subtree, [&](const std::string &path) {
/* If it is a file and the suffix matches ".ibd"
or the undo file name format then store it for
determining the space ID. */
Expand All @@ -12001,11 +12021,12 @@ dberr_t Tablespace_dirs::scan(bool populate_fil_cache,

using Value = Scanned_files::value_type;

if (Fil_path::has_suffix(IBD, file.c_str())) {
ibd_files.push_back(Value{count, file});

} else if (Fil_path::is_undo_tablespace_name(file)) {
if (Fil_path::is_undo_tablespace_name(file)) {
undo_files.push_back(Value{count, file});
} else if (only_undo) {
return;
} else if (Fil_path::has_suffix(IBD, file.c_str())) {
ibd_files.push_back(Value{count, file});
}

if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
Expand Down Expand Up @@ -12055,7 +12076,7 @@ dberr_t Tablespace_dirs::scan(bool populate_fil_cache,
check = std::bind(&Tablespace_dirs::duplicate_check, this, _1, _2, _3, _4,
_5, _6);

if (!populate_fil_cache) {
if (!populate_fil_cache && ibd_files.size() > 0) {
par_for(PFS_NOT_INSTRUMENTED, ibd_files, n_threads, check, &m, &unique,
&duplicates);
}
Expand All @@ -12081,7 +12102,7 @@ dberr_t Tablespace_dirs::scan(bool populate_fil_cache,

debug_sync_point("xtrabackup_suspend_between_file_discovery_and_open");

if (err == DB_SUCCESS && populate_fil_cache) {
if (err == DB_SUCCESS && populate_fil_cache && !only_undo) {
bool result = true;
std::function<void(const Const_iter &, const Const_iter &, size_t, bool &,
bool)>
Expand All @@ -12105,11 +12126,15 @@ void fil_set_scan_dirs(const std::string &directories) {
}

/** Discover tablespaces by reading the header from .ibd files.
@param[in] populate_fil_cache Whether to load tablespaces into fil cache
@param[in] populate_fil_cache Whether to load tablespaces into fil cache
@param[in] is_prep_handled_ddls if true, xtrabackup uses ibd_open_for_recovery
instead of fil_open_for_xtrabackup()
@param[in] only_undo if true, only the undo tablespaces are
discovered
@return DB_SUCCESS if all goes well */
dberr_t fil_scan_for_tablespaces(bool populate_fil_cache,
bool is_prep_handle_ddls) {
return (fil_system->scan(populate_fil_cache, is_prep_handle_ddls));
bool is_prep_handle_ddls, bool only_undo) {
return (fil_system->scan(populate_fil_cache, is_prep_handle_ddls, only_undo));
}

/** Open all known tablespaces. */
Expand Down
9 changes: 5 additions & 4 deletions storage/innobase/include/fil0fil.h
Original file line number Diff line number Diff line change
Expand Up @@ -2240,12 +2240,13 @@ void fil_set_scan_dir(const std::string &directory, bool is_undo_dir = false);
void fil_set_scan_dirs(const std::string &directories);

/** Discover tablespaces by reading the header from .ibd files.
@param[in] populate_fil_cache Whether to load tablespaces into fil cache
@param[in] is_prep_handle_ddls Whether loading tablespaces on prepare phase
to handle the ddls
@param[in] populate_fil_cache Whether to load tablespaces into fil cache
@param[in] is_prep_handle_ddls Whether loading tablespaces on prepare phase
to handle the ddls
@param[in] only_undo if true, only the undo tablespaces are discovered
@return DB_SUCCESS if all goes well */
dberr_t fil_scan_for_tablespaces(bool populate_fil_cache,
bool is_prep_handle_ddls);
bool is_prep_handle_ddls, bool only_undo);

/** Open the tablespace and also get the tablespace filenames, space_id must
already be known.
Expand Down
4 changes: 2 additions & 2 deletions storage/innobase/os/os0file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3708,8 +3708,8 @@ void Dir_Walker::walk_posix(const Path &basedir, bool recursive, Function &&f) {
continue;
}

if (file_type == OS_FILE_TYPE_DIR && recursive) {
directories.push(Entry(path, current.m_depth + 1));
if (file_type == OS_FILE_TYPE_DIR) {
if (recursive) directories.push(Entry(path, current.m_depth + 1));
} else {
f(path, current.m_depth + 1);
}
Expand Down
19 changes: 14 additions & 5 deletions storage/innobase/srv/srv0start.cc
Original file line number Diff line number Diff line change
Expand Up @@ -657,10 +657,12 @@ dberr_t srv_undo_tablespace_open(undo::Tablespace &undo_space) {
}

DBUG_EXECUTE_IF(
"undo_space_open",
if (strncmp(file_name, "./undo_1.ibu", strlen("./undo_1.ibu")) == 0) {
*const_cast<const char **>(&xtrabackup_debug_sync) = "undo_space_open";
debug_sync_point("undo_space_open");
"undo_space_open", if (!is_server_locked()) {
if (strncmp(file_name, "./undo_1.ibu", strlen("./undo_1.ibu")) == 0) {
*const_cast<const char **>(&xtrabackup_debug_sync) =
"undo_space_open";
debug_sync_point("undo_space_open");
}
});

/* Now that space and node exist, make sure this undo tablespace
Expand All @@ -675,6 +677,13 @@ dberr_t srv_undo_tablespace_open(undo::Tablespace &undo_space) {
}
}

// Track undo tablespaces that are found after server is locked
// if lock_ddl is REDUCED, we will do one more undo scan via
// srv_undo_tablespaces_init()/open()
if (ddl_tracker && is_server_locked()) {
ddl_tracker->add_undo_tablespace(space_id, file_name);
}

if (undo::is_reserved(space_id)) {
undo::spaces->add(undo_space);
}
Expand Down Expand Up @@ -1782,7 +1791,7 @@ dberr_t srv_start(bool create_new_db IF_XB(, lsn_t to_lsn)) {
return (srv_init_abort(err));
}

err = fil_scan_for_tablespaces(false, false);
err = fil_scan_for_tablespaces(false, false, false);

if (err != DB_SUCCESS) {
return (srv_init_abort(err));
Expand Down
130 changes: 126 additions & 4 deletions storage/innobase/xtrabackup/src/ddl_tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include <univ.i>
#include "backup_copy.h"
#include "file_utils.h"
#include "fsp0fsp.h" // fsp_is_undo_tablespace
#include "sql_thd_internal_api.h" // create_thd, destroy_thd
#include "xb0xb.h" // check_if_skip_table
#include "xtrabackup.h" // datafiles_iter_t
#include "srv0start.h"
#include "xb0xb.h" // check_if_skip_table
#include "xtrabackup.h" // datafiles_iter_t

void ddl_tracker_t::backup_file_op(uint32_t space_id, mlog_id_t type,
const byte *buf, ulint len,
Expand Down Expand Up @@ -78,6 +80,17 @@ void ddl_tracker_t::add_table_from_ibd_scan(const space_id_t space_id,
tables_in_backup[space_id] = name;
}

void ddl_tracker_t::add_undo_tablespace(const space_id_t space_id,
std::string name) {
Fil_path::normalize(name);
std::lock_guard<std::mutex> lock(m_ddl_tracker_mutex);
if (is_server_locked()) {
after_lock_undo[name] = space_id;
} else {
before_lock_undo[name] = space_id;
}
}

void ddl_tracker_t::add_corrupted_tablespace(const space_id_t space_id,
const std::string &path) {
std::lock_guard<std::mutex> lock(m_ddl_tracker_mutex);
Expand All @@ -87,6 +100,13 @@ void ddl_tracker_t::add_corrupted_tablespace(const space_id_t space_id,

void ddl_tracker_t::add_to_recopy_tables(space_id_t space_id, lsn_t start_lsn,
const std::string operation) {
// There should never be MLOG_INDEX_LOAD. However MLOG_WRITE_STRING on
// new undo tabelsapce creation is possible. But we ignore this as the UNDOs
// are tracked separately
if (fsp_is_undo_tablespace(space_id)) {
return;
}

std::lock_guard<std::mutex> lock(m_ddl_tracker_mutex);
recopy_tables.insert(space_id);
xb::info() << "DDL tracking : LSN: " << start_lsn << " " << operation
Expand All @@ -105,6 +125,11 @@ void ddl_tracker_t::add_missing_table(std::string path) {
void ddl_tracker_t::add_create_table_from_redo(const space_id_t space_id,
lsn_t start_lsn,
const char *name) {
// undo tablespaces are tracked separately.
if (fsp_is_undo_tablespace(space_id)) {
return;
}

std::string new_space_name = name;
Fil_path::normalize(new_space_name);
if (Fil_path::has_prefix(new_space_name, Fil_path::DOT_SLASH)) {
Expand Down Expand Up @@ -147,6 +172,11 @@ void ddl_tracker_t::add_rename_table_from_redo(const space_id_t space_id,
void ddl_tracker_t::add_drop_table_from_redo(const space_id_t space_id,
lsn_t start_lsn,
const char *name) {
// undo tablespaces are tracked separately.
if (fsp_is_undo_tablespace(space_id)) {
return;
}

std::string new_space_name{name};
Fil_path::normalize(new_space_name);
if (Fil_path::has_prefix(new_space_name, Fil_path::DOT_SLASH)) {
Expand All @@ -169,6 +199,13 @@ bool ddl_tracker_t::is_missing_table(const std::string &name) {

void ddl_tracker_t::add_renamed_table(const space_id_t &space_id,
std::string new_name) {
// undo tablespaces are tracked separately.
if (fsp_is_undo_tablespace(space_id)) {
// MLOG_FILE_RENAME is never done for undo tablespace
ut_ad(0);
return;
}

Fil_path::normalize(new_name);
if (Fil_path::has_prefix(new_name, Fil_path::DOT_SLASH)) {
new_name.erase(0, 2);
Expand Down Expand Up @@ -233,15 +270,89 @@ std::string ddl_tracker_t::convert_file_name(space_id_t space_id,
return file_name.substr(0, sep_pos + 1) + std::to_string(space_id) + ext;
}

// Helper function to print the contents of a vector of pairs
void printVector(const std::string &operation, const filevec &vec) {
for (const auto &element : vec) {
xb::info() << operation << element.first << " : " << element.second << " ";
}
}

// Function to find new, deleted, and changed files between two unordered_maps
std::tuple<filevec, filevec> findChanges(const name_to_space_id_t &before,
const name_to_space_id_t &after) {
filevec newFiles;
filevec deletedOrChangedFiles;

// Iterate through the after map to find new, changed, and unchanged files
for (const auto &pair : after) {
auto itBefore = before.find(pair.first);
if (itBefore == before.end()) {
// Element is new
newFiles.emplace_back(pair.first, pair.second);
} else {
// Element exists in before map
if (itBefore->second != pair.second) {
// Element value has changed
deletedOrChangedFiles.emplace_back(
pair.first, itBefore->second); // Use old value from before map
newFiles.emplace_back(pair.first, pair.second);
}
}
}

// Look for deleted
for (const auto &pair : before) {
auto itAfter = after.find(pair.first);

if (itAfter == after.end()) {
// Element is not present in the after map. This is deleted
deletedOrChangedFiles.emplace_back(pair.first, pair.second);
}
}

return {newFiles, deletedOrChangedFiles};
}

std::tuple<filevec, filevec> ddl_tracker_t::handle_undo_ddls() {
xb::info() << "DDL tracking: handling undo DDLs";

undo_spaces_deinit();
undo_spaces_init();
xb_scan_for_tablespaces(false, true);

// Generates the after_lock_undo list
srv_undo_tablespaces_init(false, true);

auto [newfiles, deletedOrChangedFiles] =
findChanges(before_lock_undo, after_lock_undo);

// Print the results
xb::info() << "New UNDO files: ";
printVector("New undo file: ", newfiles);

xb::info() << "Deleted or truncated UNDO files: ";
printVector("Deleted undo file: ", deletedOrChangedFiles);

return {newfiles, deletedOrChangedFiles};
}

void ddl_tracker_t::handle_ddl_operations() {
fil_close_all_files();
fil_close();
fil_init(LONG_MAX);

auto [new_undo_files, deleted_undo_files] = handle_undo_ddls();

xb::info() << "DDL tracking : handling DDL operations";

if (new_tables.empty() && renames.empty() && drops.empty() &&
recopy_tables.empty() && corrupted_tablespaces.empty()) {
recopy_tables.empty() && corrupted_tablespaces.empty() &&
new_undo_files.empty() && deleted_undo_files.empty()) {
xb::info()
<< "DDL tracking : Finished handling DDL operations - No changes";
return;
}

dberr_t err;

for (auto &tablespace : corrupted_tablespaces) {
Expand Down Expand Up @@ -333,7 +444,6 @@ void ddl_tracker_t::handle_ddl_operations() {
"%s", table.second.second.c_str());
}

fil_close_all_files();
for (auto table = new_tables.begin(); table != new_tables.end();) {
if (check_if_skip_table(table->second.c_str())) {
table = new_tables.erase(table);
Expand All @@ -344,6 +454,18 @@ void ddl_tracker_t::handle_ddl_operations() {
table++;
}

// Create .del files for deleted undo tablespaces
for (auto &elem : deleted_undo_files) {
backup_file_printf(
convert_file_name(elem.second, elem.first, ".ibu.del").c_str(), "%s",
"");
}

// Add new undo files to be recopied
for (auto &elem : new_undo_files) {
new_tables[elem.second] = elem.first;
}

if (new_tables.empty()) return;

/* Create data copying threads */
Expand Down
Loading

0 comments on commit 2fe6a4d

Please sign in to comment.