Skip to content

Commit f342b48

Browse files
Merge pull request #1687 from satya-bodapati/PXB-trunk-3571
[trunk] PXB-3571 : --transition-key does not save keys with --lock-ddl=reduced
2 parents 3a15b13 + 5c23df3 commit f342b48

11 files changed

Lines changed: 370 additions & 153 deletions

File tree

storage/innobase/xtrabackup/src/backup_copy.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,17 @@ bool backup_start(Backup_context &context) {
14061406
/* LTFB/LIFB has to be executed before copying MyISAM */
14071407
if (ddl_tracker != nullptr) {
14081408
debug_sync_point("ddl_tracker_before_lock_ddl");
1409+
1410+
/* The tablespaces will be closed on handle_ddl_operations. Hence
1411+
dump the tablespace keys now. For tablespace that are tracked as
1412+
dropped, dont dump the tablespace encryption keys. Note that we
1413+
still need to save tablespace keys found from redo. We cannot do it
1414+
now as the redo log thread is still in progress. It is done after
1415+
the redo thread is stopped. See TablespaceKeyDumper::dump_from_redo() */
1416+
if (context.ts_key_dumper != nullptr) {
1417+
context.ts_key_dumper->dump_from_spaces(true);
1418+
}
1419+
14091420
if (!lock_tables_for_backup(mysql_connection, opt_backup_lock_timeout,
14101421
opt_backup_lock_retry_count)) {
14111422
return (false);

storage/innobase/xtrabackup/src/backup_mysql.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,13 @@ class Myrocks_checkpoint {
145145
file_list data_files() const;
146146
};
147147

148+
class TablespaceKeyDumper;
149+
148150
struct Backup_context {
149151
Myrocks_checkpoint myrocks_checkpoint;
150152
std::unordered_set<std::string> rocksdb_files;
151153
Redo_Log_Data_Manager *redo_mgr;
154+
TablespaceKeyDumper *ts_key_dumper;
152155
};
153156

154157
/* server capabilities */

storage/innobase/xtrabackup/src/ddl_tracker.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ void ddl_tracker_t::add_drop_table_from_redo(const space_id_t space_id,
255255
<< " delete space ID: " << space_id << " Name: " << new_space_name;
256256
}
257257

258+
bool ddl_tracker_t::is_tablespace_dropped(const space_id_t space_id) {
259+
std::lock_guard<std::mutex> lock(m_ddl_tracker_mutex);
260+
return (drops.find(space_id) != drops.end());
261+
}
262+
258263
void ddl_tracker_t::add_rename_ibd_scan(const space_id_t &space_id,
259264
std::string new_name) {
260265
// undo tablespaces are tracked separately.

storage/innobase/xtrabackup/src/ddl_tracker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ class ddl_tracker_t {
155155
@param[in] space_id tablespace identifier
156156
@param[in] new_name tablespace new name */
157157
void add_rename_ibd_scan(const space_id_t &space_id, std::string new_name);
158+
159+
/** @return true if tablespace is dropped
160+
@param[in] space_id tablespace id */
161+
bool is_tablespace_dropped(const space_id_t space_id);
158162
};
159163

160164
/** Insert into meta files map. This map is later used to delete the right

storage/innobase/xtrabackup/src/keyring_plugins.cc

Lines changed: 162 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3838
#include "keyring_operations_helper.h"
3939

4040
#include "backup_mysql.h"
41+
#include "ddl_tracker.h"
4142
#include "keyring_plugins.h"
4243
#include "rpl_log_encryption.h"
4344
#include "utils.h"
@@ -186,17 +187,6 @@ dberr_t xb_set_encryption(fil_space_t *space) {
186187
return (fil_set_encryption(space->id, Encryption::AES, key, iv));
187188
}
188189

189-
#define TRANSITION_KEY_PREFIX_STR "XBKey"
190-
191-
const char *TRANSITION_KEY_PREFIX = TRANSITION_KEY_PREFIX_STR;
192-
const size_t TRANSITION_KEY_PREFIX_LEN = sizeof(TRANSITION_KEY_PREFIX_STR) - 1;
193-
const size_t TRANSITION_KEY_RANDOM_DATA_LEN = 32;
194-
const size_t TRANSITION_KEY_NAME_MAX_LEN_V1 =
195-
Encryption::SERVER_UUID_LEN + 2 + 45;
196-
const size_t TRANSITION_KEY_NAME_MAX_LEN_V2 =
197-
TRANSITION_KEY_PREFIX_LEN + Encryption::SERVER_UUID_LEN +
198-
TRANSITION_KEY_RANDOM_DATA_LEN + 1;
199-
200190
/** Fetch the key from keyring.
201191
@param[in] key_name key name
202192
@param[out] key key
@@ -250,9 +240,14 @@ static bool xb_create_transition_key(char *key_name, char *key) {
250240

251241
base64_encode(rand32, 20, rand64);
252242

243+
std::ostringstream oss;
244+
253245
/* Trasnsition key name is composed of server uuid and random suffix. */
254-
snprintf(key_name, TRANSITION_KEY_NAME_MAX_LEN_V2, "%s-%s-%s",
255-
TRANSITION_KEY_PREFIX, server_uuid, rand64);
246+
oss << TRANSITION_KEY_PREFIX << '-' << server_uuid << '-' << rand64;
247+
std::string s = oss.str();
248+
memset(key_name, 0, TRANSITION_KEY_NAME_MAX_LEN_V2);
249+
std::memcpy(key_name, s.data(),
250+
std::min(s.size(), TRANSITION_KEY_NAME_MAX_LEN_V2));
256251

257252
/* Let keyring generate key for us. */
258253
ret = srv_keyring_generator->generate(key_name, nullptr, "AES",
@@ -661,120 +656,6 @@ static bool xb_tablespace_keys_write_single(ds_file_t *stream,
661656
return (true);
662657
}
663658

664-
/** Dump tablespace keys into encrypted "xtrabackup_keys" file.
665-
@param[in] ds_ctxt datasink context to output file into
666-
@param[in] transition_key transition key used to encrypt
667-
tablespace keys
668-
@param[in] transition_key_len transition key length
669-
@return true if success */
670-
bool xb_tablespace_keys_dump(ds_ctxt_t *ds_ctxt, const char *transition_key,
671-
size_t transition_key_len) {
672-
byte derived_key[Encryption::KEY_LEN];
673-
byte salt[XB_KDF_SALT_SIZE];
674-
char transition_key_name[TRANSITION_KEY_NAME_MAX_LEN_V2];
675-
char transition_key_buf[Encryption::KEY_LEN];
676-
677-
xb::info() << "Saving " << XTRABACKUP_KEYS_FILE;
678-
679-
if (my_rand_buffer(salt, sizeof(salt)) != 0) {
680-
return (false);
681-
}
682-
683-
memset(transition_key_name, 0, sizeof(transition_key_name));
684-
685-
if (transition_key == NULL) {
686-
if (!xb_create_transition_key(transition_key_name, transition_key_buf)) {
687-
return (false);
688-
}
689-
transition_key = transition_key_buf;
690-
transition_key_len = Encryption::KEY_LEN;
691-
}
692-
693-
xb_libgcrypt_init();
694-
bool ret = xb_derive_key(transition_key, transition_key_len, salt,
695-
sizeof(salt), sizeof(derived_key), derived_key);
696-
697-
if (!ret) {
698-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
699-
<< ": failed to derive encryption key.";
700-
return (false);
701-
}
702-
703-
dberr_t err;
704-
MY_STAT stat_info;
705-
memset(&stat_info, 0, sizeof(MY_STAT));
706-
707-
ds_file_t *stream = ds_open(ds_ctxt, XTRABACKUP_KEYS_FILE, &stat_info);
708-
if (stream == NULL) {
709-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
710-
<< ": failed to create file.";
711-
return (false);
712-
}
713-
714-
if (ds_write(stream, XTRABACKUP_KEYS_MAGIC_V2, XTRABACKUP_KEYS_MAGIC_SIZE)) {
715-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
716-
<< ": failed to write magic.";
717-
goto error;
718-
}
719-
720-
if (ds_write(stream, salt, sizeof(salt))) {
721-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
722-
<< ": failed to write salt.";
723-
goto error;
724-
}
725-
726-
if (ds_write(stream, transition_key_name, sizeof(transition_key_name))) {
727-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
728-
<< ": failed to write transition key name.";
729-
goto error;
730-
}
731-
732-
err = Fil_space_iterator::for_each_space([&](fil_space_t *space) {
733-
if (space->m_encryption_metadata.m_type == Encryption::NONE) {
734-
return (DB_SUCCESS);
735-
}
736-
if (!xb_tablespace_keys_write_single(stream, derived_key, space->id,
737-
space->m_encryption_metadata.m_key,
738-
space->m_encryption_metadata.m_iv)) {
739-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
740-
<< ": failed to save tablespace key.";
741-
return (DB_ERROR);
742-
}
743-
return (DB_SUCCESS);
744-
});
745-
746-
if (err != DB_SUCCESS) {
747-
goto error;
748-
}
749-
750-
if (recv_sys->keys != nullptr) {
751-
for (auto &key : *recv_sys->keys) {
752-
if (!xb_tablespace_keys_write_single(stream, derived_key, key.space_id,
753-
key.ptr, key.iv)) {
754-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
755-
<< ": failed to save tablespace key.";
756-
goto error;
757-
}
758-
}
759-
}
760-
761-
for (const auto &entry : encryption_info) {
762-
if (!xb_tablespace_keys_write_single(stream, derived_key, entry.first,
763-
entry.second.key, entry.second.iv)) {
764-
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
765-
<< ": failed to save tablespace key.";
766-
goto error;
767-
}
768-
}
769-
770-
ds_close(stream);
771-
return (true);
772-
773-
error:
774-
ds_close(stream);
775-
return (false);
776-
}
777-
778659
/**
779660
Read encrypted binlog file header
780661
@@ -896,3 +777,157 @@ void xb_keyring_shutdown() {
896777
free_list(opt_plugin_load_list_ptr);
897778
xtrabackup::components::deinitialize_service_handles();
898779
}
780+
781+
TablespaceKeyDumper::TablespaceKeyDumper(ds_ctxt_t *ds_ctxt,
782+
const char *transition_key,
783+
size_t transition_key_len)
784+
: m_ds_ctxt(ds_ctxt),
785+
m_transition_key(transition_key),
786+
m_transition_key_len(transition_key_len),
787+
m_stream(nullptr),
788+
m_state(State::Init),
789+
m_finalized(false) {
790+
memset(m_salt, 0, sizeof(m_salt));
791+
memset(m_derived_key, 0, sizeof(m_derived_key));
792+
memset(m_transition_key_name, 0, sizeof(m_transition_key_name));
793+
}
794+
795+
bool TablespaceKeyDumper::is_initialized() const {
796+
return m_state != State::Init;
797+
}
798+
799+
bool TablespaceKeyDumper::initialize() {
800+
xb::info() << "Saving " << XTRABACKUP_KEYS_FILE;
801+
802+
if (my_rand_buffer(m_salt, sizeof(m_salt)) != 0) return false;
803+
804+
if (m_transition_key == nullptr) {
805+
if (!xb_create_transition_key(m_transition_key_name,
806+
m_transition_key_buf)) {
807+
return false;
808+
}
809+
m_transition_key = m_transition_key_buf;
810+
m_transition_key_len = Encryption::KEY_LEN;
811+
}
812+
813+
xb_libgcrypt_init();
814+
if (!xb_derive_key(m_transition_key, m_transition_key_len, m_salt,
815+
sizeof(m_salt), sizeof(m_derived_key), m_derived_key)) {
816+
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
817+
<< ": failed to derive encryption key.";
818+
return false;
819+
}
820+
821+
MY_STAT stat_info;
822+
memset(&stat_info, 0, sizeof(MY_STAT));
823+
824+
m_stream = ds_open(m_ds_ctxt, XTRABACKUP_KEYS_FILE, &stat_info);
825+
if (!m_stream) {
826+
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
827+
<< ": failed to create file.";
828+
return false;
829+
}
830+
831+
if (ds_write(m_stream, XTRABACKUP_KEYS_MAGIC_V2,
832+
XTRABACKUP_KEYS_MAGIC_SIZE) ||
833+
ds_write(m_stream, m_salt, sizeof(m_salt)) ||
834+
ds_write(m_stream, m_transition_key_name,
835+
sizeof(m_transition_key_name))) {
836+
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
837+
<< ": failed to write header.";
838+
ds_close(m_stream);
839+
m_stream = nullptr;
840+
return false;
841+
}
842+
843+
m_state = State::Initialized;
844+
return true;
845+
}
846+
847+
bool TablespaceKeyDumper::dump_from_spaces(bool use_ddl_tracker) {
848+
if (use_ddl_tracker) {
849+
ut_a(ddl_tracker != nullptr);
850+
}
851+
852+
if (m_state != State::Initialized && m_state != State::SpacesDumpedOnce)
853+
return fail_state("dump_from_spaces");
854+
855+
m_state = State::SpacesDumpedOnce;
856+
857+
dberr_t err = Fil_space_iterator::for_each_space([&](fil_space_t *space) {
858+
if (space->m_encryption_metadata.m_type == Encryption::NONE) {
859+
return DB_SUCCESS;
860+
}
861+
862+
if (use_ddl_tracker && ddl_tracker != nullptr) {
863+
if (ddl_tracker->is_tablespace_dropped(space->id)) {
864+
return DB_SUCCESS;
865+
}
866+
}
867+
868+
if (!xb_tablespace_keys_write_single(m_stream, m_derived_key, space->id,
869+
space->m_encryption_metadata.m_key,
870+
space->m_encryption_metadata.m_iv)) {
871+
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
872+
<< ": failed to save tablespace key.";
873+
return DB_ERROR;
874+
}
875+
876+
return DB_SUCCESS;
877+
});
878+
879+
return err == DB_SUCCESS;
880+
}
881+
882+
bool TablespaceKeyDumper::dump_from_redo() {
883+
if (m_state != State::SpacesDumpedOnce) return fail_state("dump_from_redo");
884+
m_state = State::RecoveryDumped;
885+
886+
if (!recv_sys || !recv_sys->keys) return true;
887+
888+
for (auto &key : *recv_sys->keys) {
889+
if (!xb_tablespace_keys_write_single(m_stream, m_derived_key, key.space_id,
890+
key.ptr, key.iv)) {
891+
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
892+
<< ": failed to save tablespace key.";
893+
return false;
894+
}
895+
}
896+
897+
return true;
898+
}
899+
900+
bool TablespaceKeyDumper::dump_from_encryption_infos() {
901+
if (m_state != State::RecoveryDumped)
902+
return fail_state("dump_from_encryption_infos");
903+
m_state = State::EncryptionInfosDumped;
904+
905+
for (const auto &entry : encryption_info) {
906+
if (!xb_tablespace_keys_write_single(m_stream, m_derived_key, entry.first,
907+
entry.second.key, entry.second.iv)) {
908+
xb::error() << "Error writing " << XTRABACKUP_KEYS_FILE
909+
<< ": failed to save tablespace key.";
910+
return false;
911+
}
912+
}
913+
914+
return true;
915+
}
916+
917+
void TablespaceKeyDumper::finalize() {
918+
if (m_stream) {
919+
ds_close(m_stream);
920+
m_stream = nullptr;
921+
}
922+
m_finalized = true;
923+
}
924+
925+
TablespaceKeyDumper::~TablespaceKeyDumper() {
926+
assert(m_finalized && "finalize() must be called before destruction");
927+
}
928+
929+
bool TablespaceKeyDumper::fail_state(const char *func) {
930+
xb::error() << "Invalid call to " << func
931+
<< ": incorrect stage or already called.";
932+
return false;
933+
}

0 commit comments

Comments
 (0)