Enable checkpoint of read-only db (#4681)
Summary: 1. DBImplReadOnly::GetLiveFiles should not return NotSupported. Instead, it should call DBImpl::GetLiveFiles(flush_memtable=false). 2. In DBImp::Recover, we should also recover the OPTIONS file name and/or number so that an immediate subsequent GetLiveFiles will get the correct OPTIONS name. Pull Request resolved: https://github.com/facebook/rocksdb/pull/4681 Differential Revision: D13069205 Pulled By: riversand963 fbshipit-source-id: 3e6a0174307d06db5a01feb099b306cea1f7f88a
This commit is contained in:
parent
1b01d23be2
commit
f307479ba6
@ -1,6 +1,7 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
### New Features
|
||||
* Enabled checkpoint on readonly db (DBImplReadOnly).
|
||||
|
||||
### Public API Change
|
||||
* Transaction::GetForUpdate is extended with a do_validate parameter with default value of true. If false it skips validating the snapshot before doing the read. Similarly ::Merge, ::Put, ::Delete, and ::SingleDelete are extended with assume_tracked with default value of false. If true it indicates that call is assumed to be after a ::GetForUpdate.
|
||||
|
@ -67,10 +67,11 @@ class CompactedDBImpl : public DBImpl {
|
||||
virtual Status EnableFileDeletions(bool /*force*/) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
||||
uint64_t* /*manifest_file_size*/,
|
||||
bool /*flush_memtable*/ = true) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
virtual Status GetLiveFiles(std::vector<std::string>& ret,
|
||||
uint64_t* manifest_file_size,
|
||||
bool /*flush_memtable*/) override {
|
||||
return DBImpl::GetLiveFiles(ret, manifest_file_size,
|
||||
false /* flush_memtable */);
|
||||
}
|
||||
using DBImpl::Flush;
|
||||
virtual Status Flush(const FlushOptions& /*options*/,
|
||||
|
@ -479,6 +479,28 @@ Status DBImpl::Recover(
|
||||
}
|
||||
}
|
||||
|
||||
if (read_only) {
|
||||
// If we are opening as read-only, we need to update options_file_number_
|
||||
// to reflect the most recent OPTIONS file. It does not matter for regular
|
||||
// read-write db instance because options_file_number_ will later be
|
||||
// updated to versions_->NewFileNumber() in RenameTempFileToOptionsFile.
|
||||
std::vector<std::string> file_names;
|
||||
if (s.ok()) {
|
||||
s = env_->GetChildren(GetName(), &file_names);
|
||||
}
|
||||
if (s.ok()) {
|
||||
uint64_t number = 0;
|
||||
uint64_t options_file_number = 0;
|
||||
FileType type;
|
||||
for (const auto& fname : file_names) {
|
||||
if (ParseFileName(fname, &number, &type) && type == kOptionsFile) {
|
||||
options_file_number = std::max(number, options_file_number);
|
||||
}
|
||||
}
|
||||
versions_->options_file_number_ = options_file_number;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -89,10 +89,11 @@ class DBImplReadOnly : public DBImpl {
|
||||
virtual Status EnableFileDeletions(bool /*force*/) override {
|
||||
return Status::NotSupported("Not supported operation in read only mode.");
|
||||
}
|
||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
||||
uint64_t* /*manifest_file_size*/,
|
||||
bool /*flush_memtable*/ = true) override {
|
||||
return Status::NotSupported("Not supported operation in read only mode.");
|
||||
virtual Status GetLiveFiles(std::vector<std::string>& ret,
|
||||
uint64_t* manifest_file_size,
|
||||
bool /*flush_memtable*/) override {
|
||||
return DBImpl::GetLiveFiles(ret, manifest_file_size,
|
||||
false /* flush_memtable */);
|
||||
}
|
||||
|
||||
using DBImpl::Flush;
|
||||
|
@ -164,6 +164,16 @@ class CheckpointTest : public testing::Test {
|
||||
return DB::OpenForReadOnly(options, dbname_, &db_);
|
||||
}
|
||||
|
||||
Status ReadOnlyReopenWithColumnFamilies(const std::vector<std::string>& cfs,
|
||||
const Options& options) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (const auto& cf : cfs) {
|
||||
column_families.emplace_back(cf, options);
|
||||
}
|
||||
return DB::OpenForReadOnly(options, dbname_, column_families, &handles_,
|
||||
&db_);
|
||||
}
|
||||
|
||||
Status TryReopen(const Options& options) {
|
||||
Close();
|
||||
last_options_ = options;
|
||||
@ -612,6 +622,69 @@ TEST_F(CheckpointTest, CheckpointWithUnsyncedDataDropped) {
|
||||
db_ = nullptr;
|
||||
}
|
||||
|
||||
TEST_F(CheckpointTest, CheckpointReadOnlyDB) {
|
||||
ASSERT_OK(Put("foo", "foo_value"));
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
Options options = CurrentOptions();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
Checkpoint* checkpoint = nullptr;
|
||||
ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
|
||||
ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
|
||||
delete checkpoint;
|
||||
checkpoint = nullptr;
|
||||
Close();
|
||||
DB* snapshot_db = nullptr;
|
||||
ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
|
||||
ReadOptions read_opts;
|
||||
std::string get_result;
|
||||
ASSERT_OK(snapshot_db->Get(read_opts, "foo", &get_result));
|
||||
ASSERT_EQ("foo_value", get_result);
|
||||
delete snapshot_db;
|
||||
}
|
||||
|
||||
TEST_F(CheckpointTest, CheckpointReadOnlyDBWithMultipleColumnFamilies) {
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "eevee"}, options);
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
ASSERT_OK(Put(i, "foo", "foo_value"));
|
||||
ASSERT_OK(Flush(i));
|
||||
}
|
||||
Close();
|
||||
Status s = ReadOnlyReopenWithColumnFamilies(
|
||||
{kDefaultColumnFamilyName, "pikachu", "eevee"}, options);
|
||||
ASSERT_OK(s);
|
||||
Checkpoint* checkpoint = nullptr;
|
||||
ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
|
||||
ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
|
||||
delete checkpoint;
|
||||
checkpoint = nullptr;
|
||||
Close();
|
||||
|
||||
std::vector<ColumnFamilyDescriptor> column_families{
|
||||
{kDefaultColumnFamilyName, options},
|
||||
{"pikachu", options},
|
||||
{"eevee", options}};
|
||||
DB* snapshot_db = nullptr;
|
||||
std::vector<ColumnFamilyHandle*> snapshot_handles;
|
||||
s = DB::Open(options, snapshot_name_, column_families, &snapshot_handles,
|
||||
&snapshot_db);
|
||||
ASSERT_OK(s);
|
||||
ReadOptions read_opts;
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
std::string get_result;
|
||||
s = snapshot_db->Get(read_opts, snapshot_handles[i], "foo", &get_result);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("foo_value", get_result);
|
||||
}
|
||||
|
||||
for (auto snapshot_h : snapshot_handles) {
|
||||
delete snapshot_h;
|
||||
}
|
||||
snapshot_handles.clear();
|
||||
delete snapshot_db;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
Loading…
Reference in New Issue
Block a user