|
|
@ -20,14 +20,12 @@ |
|
|
|
#include "db/wal_manager.h" |
|
|
|
#include "db/wal_manager.h" |
|
|
|
#include "file/file_util.h" |
|
|
|
#include "file/file_util.h" |
|
|
|
#include "file/filename.h" |
|
|
|
#include "file/filename.h" |
|
|
|
#include "options/options_parser.h" |
|
|
|
|
|
|
|
#include "port/port.h" |
|
|
|
#include "port/port.h" |
|
|
|
#include "rocksdb/db.h" |
|
|
|
#include "rocksdb/db.h" |
|
|
|
#include "rocksdb/env.h" |
|
|
|
#include "rocksdb/env.h" |
|
|
|
#include "rocksdb/metadata.h" |
|
|
|
#include "rocksdb/metadata.h" |
|
|
|
#include "rocksdb/transaction_log.h" |
|
|
|
#include "rocksdb/transaction_log.h" |
|
|
|
#include "rocksdb/utilities/checkpoint.h" |
|
|
|
#include "rocksdb/utilities/checkpoint.h" |
|
|
|
#include "rocksdb/utilities/options_util.h" |
|
|
|
|
|
|
|
#include "test_util/sync_point.h" |
|
|
|
#include "test_util/sync_point.h" |
|
|
|
#include "util/cast_util.h" |
|
|
|
#include "util/cast_util.h" |
|
|
|
#include "util/file_checksum_helper.h" |
|
|
|
#include "util/file_checksum_helper.h" |
|
|
@ -41,21 +39,19 @@ Status Checkpoint::Create(DB* db, Checkpoint** checkpoint_ptr) { |
|
|
|
|
|
|
|
|
|
|
|
Status Checkpoint::CreateCheckpoint(const std::string& /*checkpoint_dir*/, |
|
|
|
Status Checkpoint::CreateCheckpoint(const std::string& /*checkpoint_dir*/, |
|
|
|
uint64_t /*log_size_for_flush*/, |
|
|
|
uint64_t /*log_size_for_flush*/, |
|
|
|
uint64_t* /*sequence_number_ptr*/, |
|
|
|
uint64_t* /*sequence_number_ptr*/) { |
|
|
|
const std::string& /*db_log_dir*/, |
|
|
|
|
|
|
|
const std::string& /*wal_dir*/) { |
|
|
|
|
|
|
|
return Status::NotSupported(""); |
|
|
|
return Status::NotSupported(""); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CheckpointImpl::CleanStagingDirectory( |
|
|
|
void CheckpointImpl::CleanStagingDirectory(const std::string& full_private_path, |
|
|
|
const std::string& full_private_path, Logger* info_log) { |
|
|
|
Logger* info_log) { |
|
|
|
std::vector<std::string> subchildren; |
|
|
|
std::vector<std::string> subchildren; |
|
|
|
Status s = db_->GetEnv()->FileExists(full_private_path); |
|
|
|
Status s = db_->GetEnv()->FileExists(full_private_path); |
|
|
|
if (s.IsNotFound()) { |
|
|
|
if (s.IsNotFound()) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
ROCKS_LOG_INFO(info_log, "File exists %s -- %s", |
|
|
|
ROCKS_LOG_INFO(info_log, "File exists %s -- %s", full_private_path.c_str(), |
|
|
|
full_private_path.c_str(), s.ToString().c_str()); |
|
|
|
s.ToString().c_str()); |
|
|
|
s = db_->GetEnv()->GetChildren(full_private_path, &subchildren); |
|
|
|
s = db_->GetEnv()->GetChildren(full_private_path, &subchildren); |
|
|
|
if (s.ok()) { |
|
|
|
if (s.ok()) { |
|
|
|
for (auto& subchild : subchildren) { |
|
|
|
for (auto& subchild : subchildren) { |
|
|
@ -67,8 +63,8 @@ void CheckpointImpl::CleanStagingDirectory( |
|
|
|
} |
|
|
|
} |
|
|
|
// finally delete the private dir
|
|
|
|
// finally delete the private dir
|
|
|
|
s = db_->GetEnv()->DeleteDir(full_private_path); |
|
|
|
s = db_->GetEnv()->DeleteDir(full_private_path); |
|
|
|
ROCKS_LOG_INFO(info_log, "Delete dir %s -- %s", |
|
|
|
ROCKS_LOG_INFO(info_log, "Delete dir %s -- %s", full_private_path.c_str(), |
|
|
|
full_private_path.c_str(), s.ToString().c_str()); |
|
|
|
s.ToString().c_str()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status Checkpoint::ExportColumnFamily( |
|
|
|
Status Checkpoint::ExportColumnFamily( |
|
|
@ -80,9 +76,7 @@ Status Checkpoint::ExportColumnFamily( |
|
|
|
// Builds an openable snapshot of RocksDB
|
|
|
|
// Builds an openable snapshot of RocksDB
|
|
|
|
Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir, |
|
|
|
Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir, |
|
|
|
uint64_t log_size_for_flush, |
|
|
|
uint64_t log_size_for_flush, |
|
|
|
uint64_t* sequence_number_ptr, |
|
|
|
uint64_t* sequence_number_ptr) { |
|
|
|
const std::string& db_log_dir, |
|
|
|
|
|
|
|
const std::string& wal_dir) { |
|
|
|
|
|
|
|
DBOptions db_options = db_->GetDBOptions(); |
|
|
|
DBOptions db_options = db_->GetDBOptions(); |
|
|
|
|
|
|
|
|
|
|
|
Status s = db_->GetEnv()->FileExists(checkpoint_dir); |
|
|
|
Status s = db_->GetEnv()->FileExists(checkpoint_dir); |
|
|
@ -107,54 +101,14 @@ Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir, |
|
|
|
return Status::InvalidArgument("invalid checkpoint directory name"); |
|
|
|
return Status::InvalidArgument("invalid checkpoint directory name"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::string parsed_checkpoint_dir = |
|
|
|
std::string full_private_path = |
|
|
|
checkpoint_dir.substr(0, final_nonslash_idx + 1); |
|
|
|
checkpoint_dir.substr(0, final_nonslash_idx + 1) + ".tmp"; |
|
|
|
std::string full_private_path = parsed_checkpoint_dir + ".tmp"; |
|
|
|
|
|
|
|
ROCKS_LOG_INFO(db_options.info_log, |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, |
|
|
|
"Snapshot process -- using temporary directory %s", |
|
|
|
"Snapshot process -- using temporary directory %s", |
|
|
|
full_private_path.c_str()); |
|
|
|
full_private_path.c_str()); |
|
|
|
CleanStagingDirectory(full_private_path, db_options.info_log.get()); |
|
|
|
CleanStagingDirectory(full_private_path, db_options.info_log.get()); |
|
|
|
// create snapshot directory
|
|
|
|
// create snapshot directory
|
|
|
|
s = db_->GetEnv()->CreateDir(full_private_path); |
|
|
|
s = db_->GetEnv()->CreateDir(full_private_path); |
|
|
|
|
|
|
|
|
|
|
|
// Remove the last `/`s if needed
|
|
|
|
|
|
|
|
std::string parsed_log_dir = |
|
|
|
|
|
|
|
db_log_dir.empty() |
|
|
|
|
|
|
|
? "" |
|
|
|
|
|
|
|
: db_log_dir.substr(0, db_log_dir.find_last_not_of('/') + 1); |
|
|
|
|
|
|
|
std::string parsed_wal_dir = |
|
|
|
|
|
|
|
wal_dir.empty() ? "" |
|
|
|
|
|
|
|
: wal_dir.substr(0, wal_dir.find_last_not_of('/') + 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Info log files are not copied or linked, just update the option value.
|
|
|
|
|
|
|
|
std::string value_log_dir = parsed_log_dir == db_->GetName() || |
|
|
|
|
|
|
|
parsed_log_dir == parsed_checkpoint_dir |
|
|
|
|
|
|
|
? "" |
|
|
|
|
|
|
|
: parsed_log_dir; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the wal_dir is empty, or the same as the source db dir, update the
|
|
|
|
|
|
|
|
// option value to the checkpoint dir.
|
|
|
|
|
|
|
|
std::string value_wal_dir; // Option value to override
|
|
|
|
|
|
|
|
std::string new_wal_dir; // The target location to copy/link WAL files
|
|
|
|
|
|
|
|
if (parsed_wal_dir.empty() || parsed_wal_dir == db_->GetName() || |
|
|
|
|
|
|
|
parsed_wal_dir == parsed_checkpoint_dir) { |
|
|
|
|
|
|
|
value_wal_dir = parsed_checkpoint_dir; |
|
|
|
|
|
|
|
new_wal_dir = full_private_path; // Copy to the temp dir
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
value_wal_dir = parsed_wal_dir; |
|
|
|
|
|
|
|
std::string prefix = parsed_checkpoint_dir + "/"; |
|
|
|
|
|
|
|
// If checkpoint_dir is parent of wal_dir, create the wal dir inside the tmp
|
|
|
|
|
|
|
|
// dir; otherwise, create it directly.
|
|
|
|
|
|
|
|
new_wal_dir = |
|
|
|
|
|
|
|
parsed_wal_dir.rfind(prefix, 0) == 0 |
|
|
|
|
|
|
|
? full_private_path + "/" + parsed_wal_dir.substr(prefix.size()) |
|
|
|
|
|
|
|
: parsed_wal_dir; |
|
|
|
|
|
|
|
s = db_->GetEnv()->FileExists(new_wal_dir); |
|
|
|
|
|
|
|
if (s.IsNotFound()) { |
|
|
|
|
|
|
|
s = db_->GetEnv()->CreateDir(new_wal_dir); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t sequence_number = 0; |
|
|
|
uint64_t sequence_number = 0; |
|
|
|
if (s.ok()) { |
|
|
|
if (s.ok()) { |
|
|
|
// enable file deletions
|
|
|
|
// enable file deletions
|
|
|
@ -165,32 +119,21 @@ Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir, |
|
|
|
s = CreateCustomCheckpoint( |
|
|
|
s = CreateCustomCheckpoint( |
|
|
|
db_options, |
|
|
|
db_options, |
|
|
|
[&](const std::string& src_dirname, const std::string& fname, |
|
|
|
[&](const std::string& src_dirname, const std::string& fname, |
|
|
|
FileType type) { |
|
|
|
FileType) { |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, "Hard Linking %s", |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, "Hard Linking %s", |
|
|
|
fname.c_str()); |
|
|
|
fname.c_str()); |
|
|
|
// WAL file links may be created in another location.
|
|
|
|
return db_->GetFileSystem()->LinkFile(src_dirname + fname, |
|
|
|
return db_->GetFileSystem()->LinkFile( |
|
|
|
full_private_path + fname, |
|
|
|
src_dirname + fname, |
|
|
|
|
|
|
|
(type == kWalFile ? new_wal_dir : full_private_path) + fname, |
|
|
|
|
|
|
|
IOOptions(), nullptr); |
|
|
|
IOOptions(), nullptr); |
|
|
|
} /* link_file_cb */, |
|
|
|
} /* link_file_cb */, |
|
|
|
[&](const std::string& src_dirname, const std::string& fname, |
|
|
|
[&](const std::string& src_dirname, const std::string& fname, |
|
|
|
uint64_t size_limit_bytes, FileType type, |
|
|
|
uint64_t size_limit_bytes, FileType, |
|
|
|
const std::string& /* checksum_func_name */, |
|
|
|
const std::string& /* checksum_func_name */, |
|
|
|
const std::string& /* checksum_val */) { |
|
|
|
const std::string& /* checksum_val */) { |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, "Copying %s", fname.c_str()); |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, "Copying %s", fname.c_str()); |
|
|
|
if (type == kOptionsFile) { |
|
|
|
return CopyFile(db_->GetFileSystem(), src_dirname + fname, |
|
|
|
// Modify and rewrite option files
|
|
|
|
full_private_path + fname, size_limit_bytes, |
|
|
|
return CopyOptionsFile(src_dirname + fname, |
|
|
|
db_options.use_fsync); |
|
|
|
full_private_path + fname, value_log_dir, |
|
|
|
|
|
|
|
value_wal_dir); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Copy other files. WAL files may be copied to another location.
|
|
|
|
|
|
|
|
return Status(CopyFile( |
|
|
|
|
|
|
|
db_->GetFileSystem(), src_dirname + fname, |
|
|
|
|
|
|
|
(type == kWalFile ? new_wal_dir : full_private_path) + fname, |
|
|
|
|
|
|
|
size_limit_bytes, db_options.use_fsync)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} /* copy_file_cb */, |
|
|
|
} /* copy_file_cb */, |
|
|
|
[&](const std::string& fname, const std::string& contents, FileType) { |
|
|
|
[&](const std::string& fname, const std::string& contents, FileType) { |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, "Creating %s", fname.c_str()); |
|
|
|
ROCKS_LOG_INFO(db_options.info_log, "Creating %s", fname.c_str()); |
|
|
@ -210,12 +153,11 @@ Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir, |
|
|
|
|
|
|
|
|
|
|
|
if (s.ok()) { |
|
|
|
if (s.ok()) { |
|
|
|
// move tmp private backup to real snapshot directory
|
|
|
|
// move tmp private backup to real snapshot directory
|
|
|
|
s = db_->GetEnv()->RenameFile(full_private_path, parsed_checkpoint_dir); |
|
|
|
s = db_->GetEnv()->RenameFile(full_private_path, checkpoint_dir); |
|
|
|
} |
|
|
|
} |
|
|
|
if (s.ok()) { |
|
|
|
if (s.ok()) { |
|
|
|
std::unique_ptr<Directory> checkpoint_directory; |
|
|
|
std::unique_ptr<Directory> checkpoint_directory; |
|
|
|
s = db_->GetEnv()->NewDirectory(parsed_checkpoint_dir, |
|
|
|
s = db_->GetEnv()->NewDirectory(checkpoint_dir, &checkpoint_directory); |
|
|
|
&checkpoint_directory); |
|
|
|
|
|
|
|
if (s.ok() && checkpoint_directory != nullptr) { |
|
|
|
if (s.ok() && checkpoint_directory != nullptr) { |
|
|
|
s = checkpoint_directory->Fsync(); |
|
|
|
s = checkpoint_directory->Fsync(); |
|
|
|
} |
|
|
|
} |
|
|
@ -438,8 +380,7 @@ Status CheckpointImpl::CreateCustomCheckpoint( |
|
|
|
auto wal_dir = ioptions.GetWalDir(); |
|
|
|
auto wal_dir = ioptions.GetWalDir(); |
|
|
|
for (size_t i = 0; s.ok() && i < wal_size; ++i) { |
|
|
|
for (size_t i = 0; s.ok() && i < wal_size; ++i) { |
|
|
|
if ((live_wal_files[i]->Type() == kAliveLogFile) && |
|
|
|
if ((live_wal_files[i]->Type() == kAliveLogFile) && |
|
|
|
(!flush_memtable || |
|
|
|
(!flush_memtable || live_wal_files[i]->LogNumber() >= min_log_num)) { |
|
|
|
live_wal_files[i]->LogNumber() >= min_log_num)) { |
|
|
|
|
|
|
|
if (i + 1 == wal_size) { |
|
|
|
if (i + 1 == wal_size) { |
|
|
|
s = copy_file_cb(wal_dir, live_wal_files[i]->PathName(), |
|
|
|
s = copy_file_cb(wal_dir, live_wal_files[i]->PathName(), |
|
|
|
live_wal_files[i]->SizeFileBytes(), kWalFile, |
|
|
|
live_wal_files[i]->SizeFileBytes(), kWalFile, |
|
|
@ -645,37 +586,6 @@ Status CheckpointImpl::ExportFilesInMetaData( |
|
|
|
|
|
|
|
|
|
|
|
return s; |
|
|
|
return s; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status CheckpointImpl::CopyOptionsFile(const std::string& src_file, |
|
|
|
|
|
|
|
const std::string& target_file, |
|
|
|
|
|
|
|
const std::string& db_log_dir, |
|
|
|
|
|
|
|
const std::string& wal_dir) { |
|
|
|
|
|
|
|
Status s; |
|
|
|
|
|
|
|
DBOptions src_db_options; |
|
|
|
|
|
|
|
std::vector<ColumnFamilyDescriptor> src_cf_descs; |
|
|
|
|
|
|
|
s = LoadOptionsFromFile(ConfigOptions(), src_file, &src_db_options, |
|
|
|
|
|
|
|
&src_cf_descs); |
|
|
|
|
|
|
|
if (!s.ok()) { |
|
|
|
|
|
|
|
return s; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Override these 2 options
|
|
|
|
|
|
|
|
src_db_options.db_log_dir = db_log_dir; |
|
|
|
|
|
|
|
src_db_options.wal_dir = wal_dir; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> src_cf_names; |
|
|
|
|
|
|
|
std::vector<ColumnFamilyOptions> src_cf_opts; |
|
|
|
|
|
|
|
src_cf_names.reserve(src_cf_descs.size()); |
|
|
|
|
|
|
|
src_cf_opts.reserve(src_cf_descs.size()); |
|
|
|
|
|
|
|
for (ColumnFamilyDescriptor desc : src_cf_descs) { |
|
|
|
|
|
|
|
src_cf_names.push_back(desc.name); |
|
|
|
|
|
|
|
src_cf_opts.push_back(desc.options); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return PersistRocksDBOptions(src_db_options, src_cf_names, src_cf_opts, |
|
|
|
|
|
|
|
target_file, db_->GetFileSystem()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|
|
|
|
|
|
|
|
|
|
#endif // ROCKSDB_LITE
|
|
|
|
#endif // ROCKSDB_LITE
|
|
|
|