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
|
# Rocksdb Change Log
|
||||||
## Unreleased
|
## Unreleased
|
||||||
### New Features
|
### New Features
|
||||||
|
* Enabled checkpoint on readonly db (DBImplReadOnly).
|
||||||
|
|
||||||
### Public API Change
|
### 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.
|
* 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 {
|
virtual Status EnableFileDeletions(bool /*force*/) override {
|
||||||
return Status::NotSupported("Not supported in compacted db mode.");
|
return Status::NotSupported("Not supported in compacted db mode.");
|
||||||
}
|
}
|
||||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
virtual Status GetLiveFiles(std::vector<std::string>& ret,
|
||||||
uint64_t* /*manifest_file_size*/,
|
uint64_t* manifest_file_size,
|
||||||
bool /*flush_memtable*/ = true) override {
|
bool /*flush_memtable*/) override {
|
||||||
return Status::NotSupported("Not supported in compacted db mode.");
|
return DBImpl::GetLiveFiles(ret, manifest_file_size,
|
||||||
|
false /* flush_memtable */);
|
||||||
}
|
}
|
||||||
using DBImpl::Flush;
|
using DBImpl::Flush;
|
||||||
virtual Status Flush(const FlushOptions& /*options*/,
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +89,11 @@ class DBImplReadOnly : public DBImpl {
|
|||||||
virtual Status EnableFileDeletions(bool /*force*/) override {
|
virtual Status EnableFileDeletions(bool /*force*/) override {
|
||||||
return Status::NotSupported("Not supported operation in read only mode.");
|
return Status::NotSupported("Not supported operation in read only mode.");
|
||||||
}
|
}
|
||||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
virtual Status GetLiveFiles(std::vector<std::string>& ret,
|
||||||
uint64_t* /*manifest_file_size*/,
|
uint64_t* manifest_file_size,
|
||||||
bool /*flush_memtable*/ = true) override {
|
bool /*flush_memtable*/) override {
|
||||||
return Status::NotSupported("Not supported operation in read only mode.");
|
return DBImpl::GetLiveFiles(ret, manifest_file_size,
|
||||||
|
false /* flush_memtable */);
|
||||||
}
|
}
|
||||||
|
|
||||||
using DBImpl::Flush;
|
using DBImpl::Flush;
|
||||||
|
@ -164,6 +164,16 @@ class CheckpointTest : public testing::Test {
|
|||||||
return DB::OpenForReadOnly(options, dbname_, &db_);
|
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) {
|
Status TryReopen(const Options& options) {
|
||||||
Close();
|
Close();
|
||||||
last_options_ = options;
|
last_options_ = options;
|
||||||
@ -612,6 +622,69 @@ TEST_F(CheckpointTest, CheckpointWithUnsyncedDataDropped) {
|
|||||||
db_ = nullptr;
|
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
|
} // namespace rocksdb
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
Loading…
Reference in New Issue
Block a user