[CF] Rethinking ColumnFamilyHandle and fix to dropping column families

Summary:
The change to the public behavior:
* When opening a DB or creating new column family client gets a ColumnFamilyHandle.
* As long as column family handle is alive, client can do whatever he wants with it, even drop it
* Dropped column family can still be read from (using the column family handle)
* Added a new call CloseColumnFamily(). Client has to close all column families that he has opened before deleting the DB
* As soon as column family is closed, any calls to DB using that column family handle will fail (also any outstanding calls)

Internally:
* Ref-counting ColumnFamilyData
* New thread-safety for ColumnFamilySet
* Dropped column families are now completely dropped and their memory cleaned-up

Test Plan: added some tests to column_family_test

Reviewers: dhruba, haobo, kailiu, sdong

CC: leveldb

Differential Revision: https://reviews.facebook.net/D16101
This commit is contained in:
Igor Canadi 2014-02-10 17:04:44 -08:00
parent 8d4db63a2d
commit b06840aa7d
24 changed files with 641 additions and 440 deletions

View File

@ -13,6 +13,7 @@
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include "db/db_impl.h"
#include "db/version_set.h" #include "db/version_set.h"
#include "db/internal_stats.h" #include "db/internal_stats.h"
#include "db/compaction_picker.h" #include "db/compaction_picker.h"
@ -22,6 +23,27 @@
namespace rocksdb { namespace rocksdb {
ColumnFamilyHandleImpl::ColumnFamilyHandleImpl(ColumnFamilyData* cfd,
DBImpl* db, port::Mutex* mutex)
: cfd_(cfd), db_(db), mutex_(mutex) {
if (cfd_ != nullptr) {
cfd_->Ref();
}
}
ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
if (cfd_ != nullptr) {
DBImpl::DeletionState deletion_state;
mutex_->Lock();
if (cfd_->Unref()) {
delete cfd_;
}
db_->FindObsoleteFiles(deletion_state, false, true);
mutex_->Unlock();
db_->PurgeObsoleteFiles(deletion_state);
}
}
namespace { namespace {
// Fix user-supplied options to be reasonable // Fix user-supplied options to be reasonable
template <class T, class V> template <class T, class V>
@ -134,11 +156,14 @@ ColumnFamilyData::ColumnFamilyData(const std::string& dbname, uint32_t id,
Version* dummy_versions, Cache* table_cache, Version* dummy_versions, Cache* table_cache,
const ColumnFamilyOptions& options, const ColumnFamilyOptions& options,
const DBOptions* db_options, const DBOptions* db_options,
const EnvOptions& storage_options) const EnvOptions& storage_options,
ColumnFamilySet* column_family_set)
: id_(id), : id_(id),
name_(name), name_(name),
dummy_versions_(dummy_versions), dummy_versions_(dummy_versions),
current_(nullptr), current_(nullptr),
refs_(0),
dropped_(false),
internal_comparator_(options.comparator), internal_comparator_(options.comparator),
internal_filter_policy_(options.filter_policy), internal_filter_policy_(options.filter_policy),
options_(SanitizeOptions(&internal_comparator_, &internal_filter_policy_, options_(SanitizeOptions(&internal_comparator_, &internal_filter_policy_,
@ -151,7 +176,10 @@ ColumnFamilyData::ColumnFamilyData(const std::string& dbname, uint32_t id,
next_(nullptr), next_(nullptr),
prev_(nullptr), prev_(nullptr),
log_number_(0), log_number_(0),
need_slowdown_for_num_level0_files_(false) { need_slowdown_for_num_level0_files_(false),
column_family_set_(column_family_set) {
Ref();
// if dummy_versions is nullptr, then this is a dummy column family. // if dummy_versions is nullptr, then this is a dummy column family.
if (dummy_versions != nullptr) { if (dummy_versions != nullptr) {
internal_stats_.reset(new InternalStats(options.num_levels, db_options->env, internal_stats_.reset(new InternalStats(options.num_levels, db_options->env,
@ -172,7 +200,15 @@ ColumnFamilyData::ColumnFamilyData(const std::string& dbname, uint32_t id,
} }
} }
// DB mutex held
ColumnFamilyData::~ColumnFamilyData() { ColumnFamilyData::~ColumnFamilyData() {
assert(refs_ == 0);
// remove from linked list
auto prev = prev_;
auto next = next_;
prev->next_ = next;
next->prev_ = prev;
if (super_version_ != nullptr) { if (super_version_ != nullptr) {
bool is_last_reference __attribute__((unused)); bool is_last_reference __attribute__((unused));
is_last_reference = super_version_->Unref(); is_last_reference = super_version_->Unref();
@ -180,6 +216,17 @@ ColumnFamilyData::~ColumnFamilyData() {
super_version_->Cleanup(); super_version_->Cleanup();
delete super_version_; delete super_version_;
} }
// it's nullptr for dummy CFD
if (column_family_set_ != nullptr) {
// remove from column_family_set
column_family_set_->DropColumnFamily(this);
}
if (current_ != nullptr) {
current_->Unref();
}
if (dummy_versions_ != nullptr) { if (dummy_versions_ != nullptr) {
// List must be empty // List must be empty
assert(dummy_versions_->next_ == dummy_versions_); assert(dummy_versions_->next_ == dummy_versions_);
@ -248,24 +295,25 @@ ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
: max_column_family_(0), : max_column_family_(0),
dummy_cfd_(new ColumnFamilyData(dbname, 0, "", nullptr, nullptr, dummy_cfd_(new ColumnFamilyData(dbname, 0, "", nullptr, nullptr,
ColumnFamilyOptions(), db_options, ColumnFamilyOptions(), db_options,
storage_options_)), storage_options_, nullptr)),
db_name_(dbname), db_name_(dbname),
db_options_(db_options), db_options_(db_options),
storage_options_(storage_options), storage_options_(storage_options),
table_cache_(table_cache), table_cache_(table_cache),
spin_lock_(ATOMIC_FLAG_INIT) { spin_lock_(ATOMIC_FLAG_INIT) {
// initialize linked list // initialize linked list
dummy_cfd_->prev_.store(dummy_cfd_); dummy_cfd_->prev_ = dummy_cfd_;
dummy_cfd_->next_.store(dummy_cfd_); dummy_cfd_->next_ = dummy_cfd_;
} }
ColumnFamilySet::~ColumnFamilySet() { ColumnFamilySet::~ColumnFamilySet() {
for (auto& cfd : column_family_data_) { while (column_family_data_.size() > 0) {
delete cfd.second; // cfd destructor will delete itself from column_family_data_
} auto cfd = column_family_data_.begin()->second;
for (auto& cfd : droppped_column_families_) { cfd->Unref();
delete cfd; delete cfd;
} }
dummy_cfd_->Unref();
delete dummy_cfd_; delete dummy_cfd_;
} }
@ -303,39 +351,36 @@ uint32_t ColumnFamilySet::GetNextColumnFamilyID() {
return ++max_column_family_; return ++max_column_family_;
} }
// under a DB mutex
ColumnFamilyData* ColumnFamilySet::CreateColumnFamily( ColumnFamilyData* ColumnFamilySet::CreateColumnFamily(
const std::string& name, uint32_t id, Version* dummy_versions, const std::string& name, uint32_t id, Version* dummy_versions,
const ColumnFamilyOptions& options) { const ColumnFamilyOptions& options) {
assert(column_families_.find(name) == column_families_.end()); assert(column_families_.find(name) == column_families_.end());
column_families_.insert({name, id});
ColumnFamilyData* new_cfd = ColumnFamilyData* new_cfd =
new ColumnFamilyData(db_name_, id, name, dummy_versions, table_cache_, new ColumnFamilyData(db_name_, id, name, dummy_versions, table_cache_,
options, db_options_, storage_options_); options, db_options_, storage_options_, this);
Lock();
column_families_.insert({name, id});
column_family_data_.insert({id, new_cfd}); column_family_data_.insert({id, new_cfd});
Unlock();
max_column_family_ = std::max(max_column_family_, id); max_column_family_ = std::max(max_column_family_, id);
// add to linked list // add to linked list
new_cfd->next_.store(dummy_cfd_); new_cfd->next_ = dummy_cfd_;
auto prev = dummy_cfd_->prev_.load(); auto prev = dummy_cfd_->prev_;
new_cfd->prev_.store(prev); new_cfd->prev_ = prev;
prev->next_.store(new_cfd); prev->next_ = new_cfd;
dummy_cfd_->prev_.store(new_cfd); dummy_cfd_->prev_ = new_cfd;
return new_cfd; return new_cfd;
} }
void ColumnFamilySet::DropColumnFamily(uint32_t id) { // under a DB mutex
assert(id != 0); void ColumnFamilySet::DropColumnFamily(ColumnFamilyData* cfd) {
auto cfd_iter = column_family_data_.find(id); auto cfd_iter = column_family_data_.find(cfd->GetID());
assert(cfd_iter != column_family_data_.end()); assert(cfd_iter != column_family_data_.end());
auto cfd = cfd_iter->second; Lock();
column_families_.erase(cfd->GetName());
cfd->current()->Unref();
droppped_column_families_.push_back(cfd);
column_family_data_.erase(cfd_iter); column_family_data_.erase(cfd_iter);
// remove from linked list column_families_.erase(cfd->GetName());
auto prev = cfd->prev_.load(); Unlock();
auto next = cfd->next_.load();
prev->next_.store(next);
next->prev_.store(prev);
} }
void ColumnFamilySet::Lock() { void ColumnFamilySet::Lock() {
@ -347,8 +392,11 @@ void ColumnFamilySet::Lock() {
void ColumnFamilySet::Unlock() { spin_lock_.clear(std::memory_order_release); } void ColumnFamilySet::Unlock() { spin_lock_.clear(std::memory_order_release); }
bool ColumnFamilyMemTablesImpl::Seek(uint32_t column_family_id) { bool ColumnFamilyMemTablesImpl::Seek(uint32_t column_family_id) {
// maybe outside of db mutex, should lock
column_family_set_->Lock();
current_ = column_family_set_->GetColumnFamily(column_family_id); current_ = column_family_set_->GetColumnFamily(column_family_id);
handle_.id = column_family_id; column_family_set_->Unlock();
handle_.SetCFD(current_);
return current_ != nullptr; return current_ != nullptr;
} }
@ -367,10 +415,9 @@ const Options* ColumnFamilyMemTablesImpl::GetFullOptions() const {
return current_->full_options(); return current_->full_options();
} }
const ColumnFamilyHandle& ColumnFamilyMemTablesImpl::GetColumnFamilyHandle() ColumnFamilyHandle* ColumnFamilyMemTablesImpl::GetColumnFamilyHandle() {
const {
assert(current_ != nullptr); assert(current_ != nullptr);
return handle_; return &handle_;
} }
} // namespace rocksdb } // namespace rocksdb

View File

@ -30,6 +30,35 @@ class CompactionPicker;
class Compaction; class Compaction;
class InternalKey; class InternalKey;
class InternalStats; class InternalStats;
class ColumnFamilyData;
class DBImpl;
class ColumnFamilyHandleImpl : public ColumnFamilyHandle {
public:
// create while holding the mutex
ColumnFamilyHandleImpl(ColumnFamilyData* cfd, DBImpl* db, port::Mutex* mutex);
// destroy without mutex
virtual ~ColumnFamilyHandleImpl();
virtual ColumnFamilyData* cfd() const { return cfd_; }
private:
ColumnFamilyData* cfd_;
DBImpl* db_;
port::Mutex* mutex_;
};
// does not ref-count cfd_
class ColumnFamilyHandleInternal : public ColumnFamilyHandleImpl {
public:
ColumnFamilyHandleInternal()
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr) {}
void SetCFD(ColumnFamilyData* cfd) { internal_cfd_ = cfd; }
virtual ColumnFamilyData* cfd() const override { return internal_cfd_; }
private:
ColumnFamilyData* internal_cfd_;
};
// holds references to memtable, all immutable memtables and version // holds references to memtable, all immutable memtables and version
struct SuperVersion { struct SuperVersion {
@ -63,12 +92,35 @@ extern ColumnFamilyOptions SanitizeOptions(const InternalKeyComparator* icmp,
const InternalFilterPolicy* ipolicy, const InternalFilterPolicy* ipolicy,
const ColumnFamilyOptions& src); const ColumnFamilyOptions& src);
class ColumnFamilySet;
// column family metadata. not thread-safe. should be protected by db_mutex // column family metadata. not thread-safe. should be protected by db_mutex
class ColumnFamilyData { class ColumnFamilyData {
public: public:
~ColumnFamilyData();
uint32_t GetID() const { return id_; } uint32_t GetID() const { return id_; }
const std::string& GetName() { return name_; } const std::string& GetName() { return name_; }
// DB mutex held for all these
void Ref() { ++refs_; }
// will just decrease reference count to 0, but will not delete it. returns
// true if the ref count was decreased to zero and needs to be cleaned up by
// the caller
bool Unref() {
assert(refs_ > 0);
return --refs_ == 0;
}
bool Dead() { return refs_ == 0; }
// SetDropped() and IsDropped() are thread-safe
void SetDropped() {
// can't drop default CF
assert(id_ != 0);
dropped_.store(true);
}
bool IsDropped() const { return dropped_.load(); }
int NumberLevels() const { return options_.num_levels; } int NumberLevels() const { return options_.num_levels; }
void SetLogNumber(uint64_t log_number) { log_number_ = log_number; } void SetLogNumber(uint64_t log_number) { log_number_ = log_number; }
@ -126,16 +178,19 @@ class ColumnFamilyData {
const std::string& name, Version* dummy_versions, const std::string& name, Version* dummy_versions,
Cache* table_cache, const ColumnFamilyOptions& options, Cache* table_cache, const ColumnFamilyOptions& options,
const DBOptions* db_options, const DBOptions* db_options,
const EnvOptions& storage_options); const EnvOptions& storage_options,
~ColumnFamilyData(); ColumnFamilySet* column_family_set);
ColumnFamilyData* next() { return next_.load(); } ColumnFamilyData* next() { return next_; }
uint32_t id_; uint32_t id_;
const std::string name_; const std::string name_;
Version* dummy_versions_; // Head of circular doubly-linked list of versions. Version* dummy_versions_; // Head of circular doubly-linked list of versions.
Version* current_; // == dummy_versions->prev_ Version* current_; // == dummy_versions->prev_
int refs_; // outstanding references to ColumnFamilyData
std::atomic<bool> dropped_; // true if client dropped it
const InternalKeyComparator internal_comparator_; const InternalKeyComparator internal_comparator_;
const InternalFilterPolicy internal_filter_policy_; const InternalFilterPolicy internal_filter_policy_;
@ -157,8 +212,8 @@ class ColumnFamilyData {
// pointers for a circular linked list. we use it to support iterations // pointers for a circular linked list. we use it to support iterations
// that can be concurrent with writes // that can be concurrent with writes
std::atomic<ColumnFamilyData*> next_; ColumnFamilyData* next_;
std::atomic<ColumnFamilyData*> prev_; ColumnFamilyData* prev_;
// This is the earliest log file number that contains data from this // This is the earliest log file number that contains data from this
// Column Family. All earlier log files must be ignored and not // Column Family. All earlier log files must be ignored and not
@ -172,6 +227,8 @@ class ColumnFamilyData {
// An object that keeps all the compaction stats // An object that keeps all the compaction stats
// and picks the next compaction // and picks the next compaction
std::unique_ptr<CompactionPicker> compaction_picker_; std::unique_ptr<CompactionPicker> compaction_picker_;
ColumnFamilySet* column_family_set_;
}; };
// Thread safe only for reading without a writer. All access should be // Thread safe only for reading without a writer. All access should be
@ -183,7 +240,10 @@ class ColumnFamilySet {
explicit iterator(ColumnFamilyData* cfd) explicit iterator(ColumnFamilyData* cfd)
: current_(cfd) {} : current_(cfd) {}
iterator& operator++() { iterator& operator++() {
// dummy is never dead, so this will never be infinite
do {
current_ = current_->next(); current_ = current_->next();
} while (current_->Dead());
return *this; return *this;
} }
bool operator!=(const iterator& other) { bool operator!=(const iterator& other) {
@ -216,26 +276,31 @@ class ColumnFamilySet {
ColumnFamilyData* CreateColumnFamily(const std::string& name, uint32_t id, ColumnFamilyData* CreateColumnFamily(const std::string& name, uint32_t id,
Version* dummy_version, Version* dummy_version,
const ColumnFamilyOptions& options); const ColumnFamilyOptions& options);
void DropColumnFamily(uint32_t id); void DropColumnFamily(ColumnFamilyData* cfd);
iterator begin() { return iterator(dummy_cfd_->next()); } iterator begin() { return iterator(dummy_cfd_->next()); }
iterator end() { return iterator(dummy_cfd_); } iterator end() { return iterator(dummy_cfd_); }
// ColumnFamilySet has interesting thread-safety requirements // ColumnFamilySet has interesting thread-safety requirements
// * CreateColumnFamily() or DropColumnFamily() -- need to Lock() and also // * CreateColumnFamily() or DropColumnFamily() -- need to protect by DB
// execute inside of DB mutex // mutex. Inside, column_family_data_ and column_families_ will be protected
// * Iterate -- without any locks // by Lock() and Unlock()
// * GetDefault(), GetColumnFamily(), Exists(), GetID(), // * Iterate -- hold DB mutex, but you can release it in the body of
// GetNextColumnFamilyID() -- either inside of DB mutex or call Lock() // iteration. If you release DB mutex in body, reference the column
// family before the mutex and unreference after you unlock, since the column
// family might get dropped when you release the DB mutex.
// * GetDefault(), GetColumnFamily(), Exists(), GetID() -- either inside of DB
// mutex or call Lock()
// * GetNextColumnFamilyID() -- inside of DB mutex
void Lock(); void Lock();
void Unlock(); void Unlock();
private: private:
// when mutating: 1. DB mutex locked first, 2. spinlock locked second
// when reading, either: 1. lock DB mutex, or 2. lock spinlock
// (if both, respect the ordering to avoid deadlock!)
std::unordered_map<std::string, uint32_t> column_families_; std::unordered_map<std::string, uint32_t> column_families_;
std::unordered_map<uint32_t, ColumnFamilyData*> column_family_data_; std::unordered_map<uint32_t, ColumnFamilyData*> column_family_data_;
// we need to keep them alive because we still can't control the lifetime of
// all of column family data members (options for example)
std::vector<ColumnFamilyData*> droppped_column_families_;
uint32_t max_column_family_; uint32_t max_column_family_;
ColumnFamilyData* dummy_cfd_; ColumnFamilyData* dummy_cfd_;
@ -266,12 +331,12 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
virtual const Options* GetFullOptions() const override; virtual const Options* GetFullOptions() const override;
// Returns column family handle for the selected column family // Returns column family handle for the selected column family
virtual const ColumnFamilyHandle& GetColumnFamilyHandle() const override; virtual ColumnFamilyHandle* GetColumnFamilyHandle() override;
private: private:
ColumnFamilySet* column_family_set_; ColumnFamilySet* column_family_set_;
ColumnFamilyData* current_; ColumnFamilyData* current_;
ColumnFamilyHandle handle_; ColumnFamilyHandleInternal handle_;
}; };
} // namespace rocksdb } // namespace rocksdb

View File

@ -31,6 +31,10 @@ class ColumnFamilyTest {
} }
void Close() { void Close() {
for (auto h : handles_) {
delete h;
}
handles_.clear();
delete db_; delete db_;
db_ = nullptr; db_ = nullptr;
} }
@ -45,6 +49,10 @@ class ColumnFamilyTest {
} }
void Destroy() { void Destroy() {
for (auto h : handles_) {
delete h;
}
handles_.clear();
delete db_; delete db_;
db_ = nullptr; db_ = nullptr;
ASSERT_OK(DestroyDB(dbname_, Options(db_options_, column_family_options_))); ASSERT_OK(DestroyDB(dbname_, Options(db_options_, column_family_options_)));
@ -59,6 +67,14 @@ class ColumnFamilyTest {
} }
} }
void DropColumnFamilies(const vector<int>& cfs) {
for (auto cf : cfs) {
ASSERT_OK(db_->DropColumnFamily(handles_[cf]));
delete handles_[cf];
handles_[cf] = nullptr;
}
}
Status Put(int cf, const string& key, const string& value) { Status Put(int cf, const string& key, const string& value) {
return db_->Put(WriteOptions(), handles_[cf], Slice(key), Slice(value)); return db_->Put(WriteOptions(), handles_[cf], Slice(key), Slice(value));
} }
@ -111,6 +127,12 @@ class ColumnFamilyTest {
return result; return result;
} }
int CountLiveFiles(int cf) {
std::vector<LiveFileMetaData> metadata;
db_->GetLiveFilesMetaData(&metadata);
return static_cast<int>(metadata.size());
}
// Do n memtable flushes, each of which produces an sstable // Do n memtable flushes, each of which produces an sstable
// covering the range [small,large]. // covering the range [small,large].
void MakeTables(int cf, int n, const string& small, void MakeTables(int cf, int n, const string& small,
@ -146,7 +168,7 @@ class ColumnFamilyTest {
ASSERT_OK(destfile->Close()); ASSERT_OK(destfile->Close());
} }
vector<ColumnFamilyHandle> handles_; vector<ColumnFamilyHandle*> handles_;
ColumnFamilyOptions column_family_options_; ColumnFamilyOptions column_family_options_;
DBOptions db_options_; DBOptions db_options_;
string dbname_; string dbname_;
@ -156,16 +178,9 @@ class ColumnFamilyTest {
TEST(ColumnFamilyTest, AddDrop) { TEST(ColumnFamilyTest, AddDrop) {
ASSERT_OK(Open({"default"})); ASSERT_OK(Open({"default"}));
ColumnFamilyHandle handles[4]; CreateColumnFamilies({"one", "two", "three"});
ASSERT_OK( DropColumnFamilies({2});
db_->CreateColumnFamily(column_family_options_, "one", &handles[0])); CreateColumnFamilies({"four"});
ASSERT_OK(
db_->CreateColumnFamily(column_family_options_, "two", &handles[1]));
ASSERT_OK(
db_->CreateColumnFamily(column_family_options_, "three", &handles[2]));
ASSERT_OK(db_->DropColumnFamily(handles[1]));
ASSERT_OK(
db_->CreateColumnFamily(column_family_options_, "four", &handles[3]));
Close(); Close();
ASSERT_TRUE(Open({"default"}).IsInvalidArgument()); ASSERT_TRUE(Open({"default"}).IsInvalidArgument());
ASSERT_OK(Open({"default", "one", "three", "four"})); ASSERT_OK(Open({"default", "one", "three", "four"}));
@ -177,6 +192,33 @@ TEST(ColumnFamilyTest, AddDrop) {
ASSERT_TRUE(families == vector<string>({"default", "four", "one", "three"})); ASSERT_TRUE(families == vector<string>({"default", "four", "one", "three"}));
} }
TEST(ColumnFamilyTest, DropTest) {
// first iteration - dont reopen DB before dropping
// second iteration - reopen DB before dropping
for (int iter = 0; iter < 2; ++iter) {
ASSERT_OK(Open({"default"}));
CreateColumnFamilies({"pikachu"});
Close();
ASSERT_OK(Open({"default", "pikachu"}));
for (int i = 0; i < 100; ++i) {
ASSERT_OK(Put(1, std::to_string(i), "bar" + std::to_string(i)));
}
ASSERT_OK(Flush(1));
if (iter == 1) {
Close();
ASSERT_OK(Open({"default", "pikachu"}));
}
ASSERT_EQ("bar1", Get(1, "1"));
ASSERT_EQ(CountLiveFiles(1), 1);
DropColumnFamilies({1});
// make sure that all files are deleted when we drop the column family
ASSERT_EQ(CountLiveFiles(1), 0);
Destroy();
}
}
TEST(ColumnFamilyTest, ReadWrite) { TEST(ColumnFamilyTest, ReadWrite) {
ASSERT_OK(Open({"default"})); ASSERT_OK(Open({"default"}));
CreateColumnFamilies({"one", "two"}); CreateColumnFamilies({"one", "two"});

View File

@ -43,6 +43,7 @@ Compaction::Compaction(Version* input_version, int level, int out_level,
is_full_compaction_(false), is_full_compaction_(false),
level_ptrs_(std::vector<size_t>(number_levels_)) { level_ptrs_(std::vector<size_t>(number_levels_)) {
cfd_->Ref();
input_version_->Ref(); input_version_->Ref();
edit_ = new VersionEdit(); edit_ = new VersionEdit();
edit_->SetColumnFamily(cfd_->GetID()); edit_->SetColumnFamily(cfd_->GetID());
@ -56,6 +57,11 @@ Compaction::~Compaction() {
if (input_version_ != nullptr) { if (input_version_ != nullptr) {
input_version_->Unref(); input_version_->Unref();
} }
if (cfd_ != nullptr) {
if (cfd_->Unref()) {
delete cfd_;
}
}
} }
bool Compaction::IsTrivialMove() const { bool Compaction::IsTrivialMove() const {
@ -168,6 +174,12 @@ void Compaction::ReleaseInputs() {
input_version_->Unref(); input_version_->Unref();
input_version_ = nullptr; input_version_ = nullptr;
} }
if (cfd_ != nullptr) {
if (cfd_->Unref()) {
delete cfd_;
}
cfd_ = nullptr;
}
} }
void Compaction::ReleaseCompactionFiles(Status status) { void Compaction::ReleaseCompactionFiles(Status status) {

View File

@ -74,7 +74,7 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
// Make a set of all of the live *.sst files // Make a set of all of the live *.sst files
std::set<uint64_t> live; std::set<uint64_t> live;
default_cfd_->current()->AddLiveFiles(&live); default_cf_handle_->cfd()->current()->AddLiveFiles(&live);
ret.clear(); ret.clear();
ret.reserve(live.size() + 2); //*.sst + CURRENT + MANIFEST ret.reserve(live.size() + 2); //*.sst + CURRENT + MANIFEST

View File

@ -42,7 +42,6 @@
#include "rocksdb/cache.h" #include "rocksdb/cache.h"
#include "rocksdb/compaction_filter.h" #include "rocksdb/compaction_filter.h"
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/column_family.h"
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "rocksdb/merge_operator.h" #include "rocksdb/merge_operator.h"
#include "rocksdb/statistics.h" #include "rocksdb/statistics.h"
@ -218,6 +217,7 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname)
shutting_down_(nullptr), shutting_down_(nullptr),
bg_cv_(&mutex_), bg_cv_(&mutex_),
logfile_number_(0), logfile_number_(0),
default_cf_handle_(nullptr),
tmp_batch_(), tmp_batch_(),
bg_compaction_scheduled_(0), bg_compaction_scheduled_(0),
bg_manual_only_(0), bg_manual_only_(0),
@ -270,14 +270,24 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname)
DBImpl::~DBImpl() { DBImpl::~DBImpl() {
// Wait for background work to finish // Wait for background work to finish
mutex_.Lock();
if (flush_on_destroy_) { if (flush_on_destroy_) {
autovector<ColumnFamilyData*> to_delete;
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
if (cfd->mem()->GetFirstSequenceNumber() != 0) { if (cfd->mem()->GetFirstSequenceNumber() != 0) {
cfd->Ref();
mutex_.Unlock();
FlushMemTable(cfd, FlushOptions()); FlushMemTable(cfd, FlushOptions());
}
}
}
mutex_.Lock(); mutex_.Lock();
if (cfd->Unref()) {
to_delete.push_back(cfd);
}
}
}
for (auto cfd : to_delete) {
delete cfd;
}
}
shutting_down_.Release_Store(this); // Any non-nullptr value is ok shutting_down_.Release_Store(this); // Any non-nullptr value is ok
while (bg_compaction_scheduled_ || while (bg_compaction_scheduled_ ||
bg_flush_scheduled_ || bg_flush_scheduled_ ||
@ -285,6 +295,10 @@ DBImpl::~DBImpl() {
bg_cv_.Wait(); bg_cv_.Wait();
} }
mutex_.Unlock(); mutex_.Unlock();
if (default_cf_handle_ != nullptr) {
// we need to delete handle outside of lock because it does its own locking
delete default_cf_handle_;
}
if (db_lock_ != nullptr) { if (db_lock_ != nullptr) {
env_->UnlockFile(db_lock_); env_->UnlockFile(db_lock_);
@ -816,7 +830,8 @@ Status DBImpl::Recover(
Status s = versions_->Recover(column_families); Status s = versions_->Recover(column_families);
if (s.ok()) { if (s.ok()) {
SequenceNumber max_sequence(0); SequenceNumber max_sequence(0);
default_cfd_ = versions_->GetColumnFamilySet()->GetDefault(); default_cf_handle_ = new ColumnFamilyHandleImpl(
versions_->GetColumnFamilySet()->GetDefault(), this, &mutex_);
// Recover from all newer log files than the ones named in the // Recover from all newer log files than the ones named in the
// descriptor (new log files may have been added by the previous // descriptor (new log files may have been added by the previous
@ -891,6 +906,7 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, SequenceNumber* max_sequence,
mutex_.AssertHeld(); mutex_.AssertHeld();
std::unordered_map<int, VersionEdit> version_edits; std::unordered_map<int, VersionEdit> version_edits;
// no need to refcount because iteration is under mutex
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
VersionEdit edit; VersionEdit edit;
edit.SetColumnFamily(cfd->GetID()); edit.SetColumnFamily(cfd->GetID());
@ -934,7 +950,6 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, SequenceNumber* max_sequence,
} }
WriteBatchInternal::SetContents(&batch, record); WriteBatchInternal::SetContents(&batch, record);
// No need to lock ColumnFamilySet here since its under a DB mutex
status = WriteBatchInternal::InsertInto( status = WriteBatchInternal::InsertInto(
&batch, column_family_memtables_.get(), log_number); &batch, column_family_memtables_.get(), log_number);
@ -950,6 +965,8 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, SequenceNumber* max_sequence,
} }
if (!read_only) { if (!read_only) {
// no need to refcount since client still doesn't have access
// to the DB and can not drop column families while we iterate
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
if (cfd->mem()->ApproximateMemoryUsage() > if (cfd->mem()->ApproximateMemoryUsage() >
cfd->options()->write_buffer_size) { cfd->options()->write_buffer_size) {
@ -973,6 +990,8 @@ Status DBImpl::RecoverLogFile(uint64_t log_number, SequenceNumber* max_sequence,
} }
if (!read_only) { if (!read_only) {
// no need to refcount since client still doesn't have access
// to the DB and can not drop column families while we iterate
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
auto iter = version_edits.find(cfd->GetID()); auto iter = version_edits.find(cfd->GetID());
assert(iter != version_edits.end()); assert(iter != version_edits.end());
@ -1198,10 +1217,8 @@ Status DBImpl::FlushMemTableToOutputFile(ColumnFamilyData* cfd,
// This will release and re-acquire the mutex. // This will release and re-acquire the mutex.
Status s = WriteLevel0Table(cfd, mems, edit, &file_number); Status s = WriteLevel0Table(cfd, mems, edit, &file_number);
if (s.ok() && shutting_down_.Acquire_Load()) { if (s.ok() && (shutting_down_.Acquire_Load() || cfd->IsDropped())) {
s = Status::IOError( s = Status::IOError("Column family closed during memtable flush");
"Database shutdown started during memtable compaction"
);
} }
// Replace immutable memtable with the generated Table // Replace immutable memtable with the generated Table
@ -1229,15 +1246,11 @@ Status DBImpl::FlushMemTableToOutputFile(ColumnFamilyData* cfd,
return s; return s;
} }
Status DBImpl::CompactRange(const ColumnFamilyHandle& column_family, Status DBImpl::CompactRange(ColumnFamilyHandle* column_family,
const Slice* begin, const Slice* end, const Slice* begin, const Slice* end,
bool reduce_level, int target_level) { bool reduce_level, int target_level) {
mutex_.Lock(); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); auto cfd = cfh->cfd();
mutex_.Unlock();
// this is asserting because client calling DB methods with undefined
// ColumnFamilyHandle is undefined behavior.
assert(cfd != nullptr);
Status s = FlushMemTable(cfd, FlushOptions()); Status s = FlushMemTable(cfd, FlushOptions());
if (!s.ok()) { if (!s.ok()) {
@ -1367,38 +1380,25 @@ Status DBImpl::ReFitLevel(ColumnFamilyData* cfd, int level, int target_level) {
return status; return status;
} }
int DBImpl::NumberLevels(const ColumnFamilyHandle& column_family) { int DBImpl::NumberLevels(ColumnFamilyHandle* column_family) {
mutex_.Lock(); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); return cfh->cfd()->NumberLevels();
mutex_.Unlock();
assert(cfd != nullptr);
return cfd->NumberLevels();
} }
int DBImpl::MaxMemCompactionLevel(const ColumnFamilyHandle& column_family) { int DBImpl::MaxMemCompactionLevel(ColumnFamilyHandle* column_family) {
mutex_.Lock(); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); return cfh->cfd()->options()->max_mem_compaction_level;
mutex_.Unlock();
assert(cfd != nullptr);
return cfd->options()->max_mem_compaction_level;
} }
int DBImpl::Level0StopWriteTrigger(const ColumnFamilyHandle& column_family) { int DBImpl::Level0StopWriteTrigger(ColumnFamilyHandle* column_family) {
mutex_.Lock(); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); return cfh->cfd()->options()->level0_stop_writes_trigger;
mutex_.Unlock();
assert(cfd != nullptr);
return cfd->options()->level0_stop_writes_trigger;
} }
Status DBImpl::Flush(const FlushOptions& options, Status DBImpl::Flush(const FlushOptions& options,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
mutex_.Lock(); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); return FlushMemTable(cfh->cfd(), options);
mutex_.Unlock();
assert(cfd != nullptr);
return FlushMemTable(cfd, options);
} }
SequenceNumber DBImpl::GetLatestSequenceNumber() const { SequenceNumber DBImpl::GetLatestSequenceNumber() const {
@ -1666,11 +1666,12 @@ Status DBImpl::RunManualCompaction(ColumnFamilyData* cfd, int input_level,
Status DBImpl::TEST_CompactRange(int level, Status DBImpl::TEST_CompactRange(int level,
const Slice* begin, const Slice* begin,
const Slice* end) { const Slice* end) {
auto default_cfd = default_cf_handle_->cfd();
int output_level = int output_level =
(default_cfd_->options()->compaction_style == kCompactionStyleUniversal) (default_cfd->options()->compaction_style == kCompactionStyleUniversal)
? level ? level
: level + 1; : level + 1;
return RunManualCompaction(default_cfd_, level, output_level, begin, end); return RunManualCompaction(default_cfd, level, output_level, begin, end);
} }
Status DBImpl::FlushMemTable(ColumnFamilyData* cfd, Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
@ -1698,11 +1699,11 @@ Status DBImpl::WaitForFlushMemTable(ColumnFamilyData* cfd) {
} }
Status DBImpl::TEST_FlushMemTable() { Status DBImpl::TEST_FlushMemTable() {
return FlushMemTable(default_cfd_, FlushOptions()); return FlushMemTable(default_cf_handle_->cfd(), FlushOptions());
} }
Status DBImpl::TEST_WaitForFlushMemTable() { Status DBImpl::TEST_WaitForFlushMemTable() {
return WaitForFlushMemTable(default_cfd_); return WaitForFlushMemTable(default_cf_handle_->cfd());
} }
Status DBImpl::TEST_WaitForCompact() { Status DBImpl::TEST_WaitForCompact() {
@ -1728,6 +1729,7 @@ void DBImpl::MaybeScheduleFlushOrCompaction() {
// DB is being deleted; no more background compactions // DB is being deleted; no more background compactions
} else { } else {
bool is_flush_pending = false; bool is_flush_pending = false;
// no need to refcount since we're under a mutex
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
if (cfd->imm()->IsFlushPending()) { if (cfd->imm()->IsFlushPending()) {
is_flush_pending = true; is_flush_pending = true;
@ -1744,6 +1746,7 @@ void DBImpl::MaybeScheduleFlushOrCompaction() {
} }
} }
bool is_compaction_needed = false; bool is_compaction_needed = false;
// no need to refcount since we're under a mutex
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
if (cfd->current()->NeedsCompaction()) { if (cfd->current()->NeedsCompaction()) {
is_compaction_needed = true; is_compaction_needed = true;
@ -1774,17 +1777,38 @@ void DBImpl::BGWorkCompaction(void* db) {
Status DBImpl::BackgroundFlush(bool* madeProgress, Status DBImpl::BackgroundFlush(bool* madeProgress,
DeletionState& deletion_state) { DeletionState& deletion_state) {
Status stat; mutex_.AssertHeld();
// call_status is failure if at least one flush was a failure. even if
// flushing one column family reports a failure, we will continue flushing
// other column families. however, call_status will be a failure in that case.
Status call_status;
autovector<ColumnFamilyData*> to_delete;
// refcounting in iteration
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
while (stat.ok() && cfd->imm()->IsFlushPending()) { if (cfd->IsDropped()) {
continue;
}
cfd->Ref();
Status flush_status;
while (flush_status.ok() && cfd->imm()->IsFlushPending()) {
Log(options_.info_log, Log(options_.info_log,
"BackgroundCallFlush doing FlushMemTableToOutputFile with column " "BackgroundCallFlush doing FlushMemTableToOutputFile with column "
"family %u, flush slots available %d", "family %u, flush slots available %d",
cfd->GetID(), options_.max_background_flushes - bg_flush_scheduled_); cfd->GetID(), options_.max_background_flushes - bg_flush_scheduled_);
stat = FlushMemTableToOutputFile(cfd, madeProgress, deletion_state); flush_status =
FlushMemTableToOutputFile(cfd, madeProgress, deletion_state);
}
if (call_status.ok() && !flush_status.ok()) {
call_status = flush_status;
}
if (cfd->Unref()) {
to_delete.push_back(cfd);
} }
} }
return stat; for (auto cfd : to_delete) {
delete cfd;
}
return call_status;
} }
void DBImpl::BackgroundCallFlush() { void DBImpl::BackgroundCallFlush() {
@ -1835,7 +1859,7 @@ void DBImpl::TEST_PurgeObsoleteteWAL() {
uint64_t DBImpl::TEST_GetLevel0TotalSize() { uint64_t DBImpl::TEST_GetLevel0TotalSize() {
MutexLock l(&mutex_); MutexLock l(&mutex_);
return default_cfd_->current()->NumLevelBytes(0); return default_cf_handle_->cfd()->current()->NumLevelBytes(0);
} }
void DBImpl::BackgroundCallCompaction() { void DBImpl::BackgroundCallCompaction() {
@ -1921,8 +1945,9 @@ Status DBImpl::BackgroundCompaction(bool* madeProgress,
? "(end)" ? "(end)"
: manual_end->DebugString().c_str())); : manual_end->DebugString().c_str()));
} else { } else {
// no need to refcount in iteration since it's always under a mutex
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
if (!cfd->options()->disable_auto_compactions) { if (!cfd->options()->disable_auto_compactions && !cfd->IsDropped()) {
c.reset(cfd->PickCompaction()); c.reset(cfd->PickCompaction());
if (c != nullptr) { if (c != nullptr) {
// update statistics // update statistics
@ -2302,7 +2327,8 @@ Status DBImpl::DoCompactionWork(CompactionState* compact,
compaction_filter = compaction_filter_from_factory.get(); compaction_filter = compaction_filter_from_factory.get();
} }
for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { while (input->Valid() && !shutting_down_.Acquire_Load() &&
!cfd->IsDropped()) {
Slice key = input->key(); Slice key = input->key();
Slice value = input->value(); Slice value = input->value();
@ -2546,8 +2572,8 @@ Status DBImpl::DoCompactionWork(CompactionState* compact,
} }
} }
if (status.ok() && shutting_down_.Acquire_Load()) { if (status.ok() && (shutting_down_.Acquire_Load() || cfd->IsDropped())) {
status = Status::IOError("Database shutdown started during compaction"); status = Status::IOError("Column family closing started during compaction");
} }
if (status.ok() && compact->builder != nullptr) { if (status.ok() && compact->builder != nullptr) {
status = FinishCompactionOutputFile(compact, input.get()); status = FinishCompactionOutputFile(compact, input.get());
@ -2638,8 +2664,7 @@ struct IterState {
static void CleanupIteratorState(void* arg1, void* arg2) { static void CleanupIteratorState(void* arg1, void* arg2) {
IterState* state = reinterpret_cast<IterState*>(arg1); IterState* state = reinterpret_cast<IterState*>(arg1);
DBImpl::DeletionState deletion_state(state->db->GetOptions(). DBImpl::DeletionState deletion_state;
max_write_buffer_number);
bool need_cleanup = state->super_version->Unref(); bool need_cleanup = state->super_version->Unref();
if (need_cleanup) { if (need_cleanup) {
@ -2677,11 +2702,17 @@ Iterator* DBImpl::NewInternalIterator(const ReadOptions& options,
return internal_iter; return internal_iter;
} }
ColumnFamilyHandle* DBImpl::DefaultColumnFamily() const {
return default_cf_handle_;
}
Iterator* DBImpl::TEST_NewInternalIterator() { Iterator* DBImpl::TEST_NewInternalIterator() {
mutex_.Lock(); mutex_.Lock();
SuperVersion* super_version = default_cfd_->GetSuperVersion()->Ref(); SuperVersion* super_version =
default_cf_handle_->cfd()->GetSuperVersion()->Ref();
mutex_.Unlock(); mutex_.Unlock();
return NewInternalIterator(ReadOptions(), default_cfd_, super_version); return NewInternalIterator(ReadOptions(), default_cf_handle_->cfd(),
super_version);
} }
std::pair<Iterator*, Iterator*> DBImpl::GetTailingIteratorPair( std::pair<Iterator*, Iterator*> DBImpl::GetTailingIteratorPair(
@ -2725,11 +2756,11 @@ std::pair<Iterator*, Iterator*> DBImpl::GetTailingIteratorPair(
int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {
MutexLock l(&mutex_); MutexLock l(&mutex_);
return default_cfd_->current()->MaxNextLevelOverlappingBytes(); return default_cf_handle_->cfd()->current()->MaxNextLevelOverlappingBytes();
} }
Status DBImpl::Get(const ReadOptions& options, Status DBImpl::Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value) { std::string* value) {
return GetImpl(options, column_family, key, value); return GetImpl(options, column_family, key, value);
} }
@ -2762,18 +2793,16 @@ void DBImpl::InstallSuperVersion(ColumnFamilyData* cfd,
} }
Status DBImpl::GetImpl(const ReadOptions& options, Status DBImpl::GetImpl(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value, bool* value_found) {
bool* value_found) {
StopWatch sw(env_, options_.statistics.get(), DB_GET, false); StopWatch sw(env_, options_.statistics.get(), DB_GET, false);
StopWatchNano snapshot_timer(env_, false); StopWatchNano snapshot_timer(env_, false);
StartPerfTimer(&snapshot_timer); StartPerfTimer(&snapshot_timer);
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
mutex_.Lock(); mutex_.Lock();
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id);
// this is asserting because client calling DB methods with undefined
// ColumnFamilyHandle is undefined behavior.
assert(cfd != nullptr);
SuperVersion* get_version = cfd->GetSuperVersion()->Ref(); SuperVersion* get_version = cfd->GetSuperVersion()->Ref();
mutex_.Unlock(); mutex_.Unlock();
@ -2851,7 +2880,7 @@ Status DBImpl::GetImpl(const ReadOptions& options,
std::vector<Status> DBImpl::MultiGet( std::vector<Status> DBImpl::MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, std::vector<std::string>* values) { const std::vector<Slice>& keys, std::vector<std::string>* values) {
StopWatch sw(env_, options_.statistics.get(), DB_MULTIGET, false); StopWatch sw(env_, options_.statistics.get(), DB_MULTIGET, false);
@ -2869,8 +2898,12 @@ std::vector<Status> DBImpl::MultiGet(
std::unordered_map<uint32_t, MultiGetColumnFamilyData*> multiget_cf_data; std::unordered_map<uint32_t, MultiGetColumnFamilyData*> multiget_cf_data;
// fill up and allocate outside of mutex // fill up and allocate outside of mutex
for (auto cf : column_family) { for (auto cf : column_family) {
if (multiget_cf_data.find(cf.id) == multiget_cf_data.end()) { auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(cf);
multiget_cf_data.insert({cf.id, new MultiGetColumnFamilyData()}); auto cfd = cfh->cfd();
if (multiget_cf_data.find(cfd->GetID()) == multiget_cf_data.end()) {
auto mgcfd = new MultiGetColumnFamilyData();
mgcfd->cfd = cfd;
multiget_cf_data.insert({cfd->GetID(), mgcfd});
} }
} }
@ -2881,10 +2914,8 @@ std::vector<Status> DBImpl::MultiGet(
snapshot = versions_->LastSequence(); snapshot = versions_->LastSequence();
} }
for (auto mgd_iter : multiget_cf_data) { for (auto mgd_iter : multiget_cf_data) {
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(mgd_iter.first); mgd_iter.second->super_version =
assert(cfd != nullptr); mgd_iter.second->cfd->GetSuperVersion()->Ref();
mgd_iter.second->cfd = cfd;
mgd_iter.second->super_version = cfd->GetSuperVersion()->Ref();
} }
mutex_.Unlock(); mutex_.Unlock();
@ -2910,7 +2941,8 @@ std::vector<Status> DBImpl::MultiGet(
std::string* value = &(*values)[i]; std::string* value = &(*values)[i];
LookupKey lkey(keys[i], snapshot); LookupKey lkey(keys[i], snapshot);
auto mgd_iter = multiget_cf_data.find(column_family[i].id); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family[i]);
auto mgd_iter = multiget_cf_data.find(cfh->cfd()->GetID());
assert(mgd_iter != multiget_cf_data.end()); assert(mgd_iter != multiget_cf_data.end());
auto mgd = mgd_iter->second; auto mgd = mgd_iter->second;
auto super_version = mgd->super_version; auto super_version = mgd->super_version;
@ -2974,64 +3006,61 @@ std::vector<Status> DBImpl::MultiGet(
Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& options, Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& options,
const std::string& column_family_name, const std::string& column_family_name,
ColumnFamilyHandle* handle) { ColumnFamilyHandle** handle) {
// whenever we are writing to column family set, we have to lock mutex_.Lock();
versions_->GetColumnFamilySet()->Lock();
if (versions_->GetColumnFamilySet()->Exists(column_family_name)) { if (versions_->GetColumnFamilySet()->Exists(column_family_name)) {
return Status::InvalidArgument("Column family already exists"); return Status::InvalidArgument("Column family already exists");
} }
VersionEdit edit; VersionEdit edit;
edit.AddColumnFamily(column_family_name); edit.AddColumnFamily(column_family_name);
handle->id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID(); uint32_t new_id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID();
edit.SetColumnFamily(handle->id); edit.SetColumnFamily(new_id);
mutex_.Lock(); Status s = versions_->LogAndApply(default_cf_handle_->cfd(), &edit, &mutex_);
Status s = versions_->LogAndApply(default_cfd_, &edit, &mutex_);
if (s.ok()) { if (s.ok()) {
// add to internal data structures // add to internal data structures
versions_->CreateColumnFamily(options, &edit); auto cfd = versions_->CreateColumnFamily(options, &edit);
*handle = new ColumnFamilyHandleImpl(cfd, this, &mutex_);
} }
mutex_.Unlock(); mutex_.Unlock();
versions_->GetColumnFamilySet()->Unlock();
Log(options_.info_log, "Created column family \"%s\"", Log(options_.info_log, "Created column family \"%s\"",
column_family_name.c_str()); column_family_name.c_str());
return s; return s;
} }
Status DBImpl::DropColumnFamily(const ColumnFamilyHandle& column_family) { Status DBImpl::DropColumnFamily(ColumnFamilyHandle* column_family) {
if (column_family.id == 0) { auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
if (cfd->GetID() == 0) {
return Status::InvalidArgument("Can't drop default column family"); return Status::InvalidArgument("Can't drop default column family");
} }
// whenever we are writing to column family set, we have to lock Log(options_.info_log, "Dropping column family with id %u\n", cfd->GetID());
versions_->GetColumnFamilySet()->Lock();
if (!versions_->GetColumnFamilySet()->Exists(column_family.id)) {
return Status::NotFound("Column family not found");
}
VersionEdit edit; VersionEdit edit;
edit.DropColumnFamily(); edit.DropColumnFamily();
edit.SetColumnFamily(column_family.id); edit.SetColumnFamily(cfd->GetID());
mutex_.Lock();
Status s = versions_->LogAndApply(default_cfd_, &edit, &mutex_); MutexLock l(&mutex_);
if (s.ok()) { if (cfd->IsDropped()) {
// remove from internal data structures return Status::InvalidArgument("Column family already dropped!\n");
versions_->DropColumnFamily(&edit); }
} Status s = versions_->LogAndApply(cfd, &edit, &mutex_);
versions_->GetColumnFamilySet()->Unlock(); if (s.ok()) {
DeletionState deletion_state; cfd->SetDropped();
FindObsoleteFiles(deletion_state, false, true); // DB is holding one reference to each column family when it's alive,
mutex_.Unlock(); // need to drop it now
if (cfd->Unref()) {
delete cfd;
}
}
PurgeObsoleteFiles(deletion_state);
Log(options_.info_log, "Dropped column family with id %u\n",
column_family.id);
return s; return s;
} }
bool DBImpl::KeyMayExist(const ReadOptions& options, bool DBImpl::KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value, bool* value_found) {
bool* value_found) {
if (value_found != nullptr) { if (value_found != nullptr) {
// falsify later if key-may-exist but can't fetch value // falsify later if key-may-exist but can't fetch value
*value_found = true; *value_found = true;
@ -3047,12 +3076,12 @@ bool DBImpl::KeyMayExist(const ReadOptions& options,
} }
Iterator* DBImpl::NewIterator(const ReadOptions& options, Iterator* DBImpl::NewIterator(const ReadOptions& options,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
SequenceNumber latest_snapshot = 0; SequenceNumber latest_snapshot = 0;
SuperVersion* super_version = nullptr; SuperVersion* super_version = nullptr;
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
mutex_.Lock(); mutex_.Lock();
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id);
assert(cfd != nullptr);
if (!options.tailing) { if (!options.tailing) {
super_version = cfd->GetSuperVersion()->Ref(); super_version = cfd->GetSuperVersion()->Ref();
latest_snapshot = versions_->LastSequence(); latest_snapshot = versions_->LastSequence();
@ -3083,7 +3112,7 @@ Iterator* DBImpl::NewIterator(const ReadOptions& options,
Status DBImpl::NewIterators( Status DBImpl::NewIterators(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
std::vector<Iterator*>* iterators) { std::vector<Iterator*>* iterators) {
// TODO // TODO
return Status::NotSupported("Not yet!"); return Status::NotSupported("Not yet!");
@ -3100,20 +3129,15 @@ void DBImpl::ReleaseSnapshot(const Snapshot* s) {
} }
// Convenience methods // Convenience methods
Status DBImpl::Put(const WriteOptions& o, Status DBImpl::Put(const WriteOptions& o, ColumnFamilyHandle* column_family,
const ColumnFamilyHandle& column_family, const Slice& key, const Slice& key, const Slice& val) {
const Slice& val) {
return DB::Put(o, column_family, key, val); return DB::Put(o, column_family, key, val);
} }
Status DBImpl::Merge(const WriteOptions& o, Status DBImpl::Merge(const WriteOptions& o, ColumnFamilyHandle* column_family,
const ColumnFamilyHandle& column_family, const Slice& key, const Slice& key, const Slice& val) {
const Slice& val) { auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
mutex_.Lock(); if (!cfh->cfd()->options()->merge_operator) {
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id);
mutex_.Unlock();
assert(cfd != nullptr);
if (!cfd->options()->merge_operator) {
return Status::NotSupported("Provide a merge_operator when opening DB"); return Status::NotSupported("Provide a merge_operator when opening DB");
} else { } else {
return DB::Merge(o, column_family, key, val); return DB::Merge(o, column_family, key, val);
@ -3121,8 +3145,7 @@ Status DBImpl::Merge(const WriteOptions& o,
} }
Status DBImpl::Delete(const WriteOptions& options, Status DBImpl::Delete(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key) {
const Slice& key) {
return DB::Delete(options, column_family, key); return DB::Delete(options, column_family, key);
} }
@ -3155,13 +3178,22 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) {
} }
Status status; Status status;
autovector<ColumnFamilyData*> to_delete;
// refcounting cfd in iteration
for (auto cfd : *versions_->GetColumnFamilySet()) { for (auto cfd : *versions_->GetColumnFamilySet()) {
cfd->Ref();
// May temporarily unlock and wait. // May temporarily unlock and wait.
status = MakeRoomForWrite(cfd, my_batch == nullptr); status = MakeRoomForWrite(cfd, my_batch == nullptr);
if (cfd->Unref()) {
to_delete.push_back(cfd);
}
if (!status.ok()) { if (!status.ok()) {
break; break;
} }
} }
for (auto cfd : to_delete) {
delete cfd;
}
uint64_t last_sequence = versions_->LastSequence(); uint64_t last_sequence = versions_->LastSequence();
Writer* last_writer = &w; Writer* last_writer = &w;
if (status.ok() && my_batch != nullptr) { // nullptr batch is for compactions if (status.ok() && my_batch != nullptr) { // nullptr batch is for compactions
@ -3221,13 +3253,10 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) {
if (status.ok()) { if (status.ok()) {
StopWatchNano write_memtable_timer(env_, false); StopWatchNano write_memtable_timer(env_, false);
// reading the column family set outside of DB mutex -- should lock
versions_->GetColumnFamilySet()->Lock();
StartPerfTimer(&write_memtable_timer); StartPerfTimer(&write_memtable_timer);
status = WriteBatchInternal::InsertInto( status = WriteBatchInternal::InsertInto(
updates, column_family_memtables_.get(), 0, this, false); updates, column_family_memtables_.get(), 0, this, false);
BumpPerfTime(&perf_context.write_memtable_time, &write_memtable_timer); BumpPerfTime(&perf_context.write_memtable_time, &write_memtable_timer);
versions_->GetColumnFamilySet()->Unlock();
if (!status.ok()) { if (!status.ok()) {
// Panic for in-memory corruptions // Panic for in-memory corruptions
@ -3536,29 +3565,28 @@ Env* DBImpl::GetEnv() const {
return env_; return env_;
} }
const Options& DBImpl::GetOptions(const ColumnFamilyHandle& column_family) const Options& DBImpl::GetOptions(ColumnFamilyHandle* column_family) const {
const { auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
return *default_cfd_->full_options(); return *cfh->cfd()->full_options();
} }
bool DBImpl::GetProperty(const ColumnFamilyHandle& column_family, bool DBImpl::GetProperty(ColumnFamilyHandle* column_family,
const Slice& property, std::string* value) { const Slice& property, std::string* value) {
value->clear(); value->clear();
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
MutexLock l(&mutex_); MutexLock l(&mutex_);
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id);
assert(cfd != nullptr);
return cfd->internal_stats()->GetProperty(property, value, cfd); return cfd->internal_stats()->GetProperty(property, value, cfd);
} }
void DBImpl::GetApproximateSizes(const ColumnFamilyHandle& column_family, void DBImpl::GetApproximateSizes(ColumnFamilyHandle* column_family,
const Range* range, int n, uint64_t* sizes) { const Range* range, int n, uint64_t* sizes) {
// TODO(opt): better implementation // TODO(opt): better implementation
Version* v; Version* v;
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
{ {
MutexLock l(&mutex_); MutexLock l(&mutex_);
auto cfd =
versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id);
assert(cfd != nullptr);
v = cfd->current(); v = cfd->current();
v->Ref(); v->Ref();
} }
@ -3656,7 +3684,7 @@ Status DBImpl::DeleteFile(std::string name) {
void DBImpl::GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata) { void DBImpl::GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata) {
MutexLock l(&mutex_); MutexLock l(&mutex_);
return versions_->GetLiveFilesMetaData(metadata); versions_->GetLiveFilesMetaData(metadata);
} }
Status DBImpl::GetDbIdentity(std::string& identity) { Status DBImpl::GetDbIdentity(std::string& identity) {
@ -3688,38 +3716,40 @@ Status DBImpl::GetDbIdentity(std::string& identity) {
// Default implementations of convenience methods that subclasses of DB // Default implementations of convenience methods that subclasses of DB
// can call if they wish // can call if they wish
Status DB::Put(const WriteOptions& opt, const ColumnFamilyHandle& column_family, Status DB::Put(const WriteOptions& opt, ColumnFamilyHandle* column_family,
const Slice& key, const Slice& value) { const Slice& key, const Slice& value) {
// Pre-allocate size of write batch conservatively. // Pre-allocate size of write batch conservatively.
// 8 bytes are taken by header, 4 bytes for count, 1 byte for type, // 8 bytes are taken by header, 4 bytes for count, 1 byte for type,
// and we allocate 11 extra bytes for key length, as well as value length. // and we allocate 11 extra bytes for key length, as well as value length.
WriteBatch batch(key.size() + value.size() + 24); WriteBatch batch(key.size() + value.size() + 24);
batch.Put(column_family.id, key, value); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
batch.Put(cfh->cfd()->GetID(), key, value);
return Write(opt, &batch); return Write(opt, &batch);
} }
Status DB::Delete(const WriteOptions& opt, Status DB::Delete(const WriteOptions& opt, ColumnFamilyHandle* column_family,
const ColumnFamilyHandle& column_family, const Slice& key) { const Slice& key) {
WriteBatch batch; WriteBatch batch;
batch.Delete(column_family.id, key); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
batch.Delete(cfh->cfd()->GetID(), key);
return Write(opt, &batch); return Write(opt, &batch);
} }
Status DB::Merge(const WriteOptions& opt, Status DB::Merge(const WriteOptions& opt, ColumnFamilyHandle* column_family,
const ColumnFamilyHandle& column_family, const Slice& key, const Slice& key, const Slice& value) {
const Slice& value) {
WriteBatch batch; WriteBatch batch;
batch.Merge(column_family.id, key, value); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
batch.Merge(cfh->cfd()->GetID(), key, value);
return Write(opt, &batch); return Write(opt, &batch);
} }
// Default implementation -- returns not supported status // Default implementation -- returns not supported status
Status DB::CreateColumnFamily(const ColumnFamilyOptions& options, Status DB::CreateColumnFamily(const ColumnFamilyOptions& options,
const std::string& column_family_name, const std::string& column_family_name,
ColumnFamilyHandle* handle) { ColumnFamilyHandle** handle) {
return Status::NotSupported(""); return Status::NotSupported("");
} }
Status DB::DropColumnFamily(const ColumnFamilyHandle& column_family) { Status DB::DropColumnFamily(ColumnFamilyHandle* column_family) {
return Status::NotSupported(""); return Status::NotSupported("");
} }
@ -3731,14 +3761,22 @@ Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {
std::vector<ColumnFamilyDescriptor> column_families; std::vector<ColumnFamilyDescriptor> column_families;
column_families.push_back( column_families.push_back(
ColumnFamilyDescriptor(default_column_family_name, cf_options)); ColumnFamilyDescriptor(default_column_family_name, cf_options));
std::vector<ColumnFamilyHandle> handles; std::vector<ColumnFamilyHandle*> handles;
return DB::Open(db_options, dbname, column_families, &handles, dbptr); Status s = DB::Open(db_options, dbname, column_families, &handles, dbptr);
if (s.ok()) {
assert(handles.size() == 1);
// i can delete the handle since DBImpl is always holding a reference to
// default column family
delete handles[0];
}
return s;
} }
Status DB::Open(const DBOptions& db_options, const std::string& dbname, Status DB::Open(const DBOptions& db_options, const std::string& dbname,
const std::vector<ColumnFamilyDescriptor>& column_families, const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle>* handles, DB** dbptr) { std::vector<ColumnFamilyHandle*>* handles, DB** dbptr) {
*dbptr = nullptr; *dbptr = nullptr;
handles->clear();
EnvOptions soptions; EnvOptions soptions;
size_t max_write_buffer_size = 0; size_t max_write_buffer_size = 0;
@ -3784,20 +3822,22 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
// that we used by calling impl->versions_->NewFileNumber() // that we used by calling impl->versions_->NewFileNumber()
// The used log number are already written to manifest in RecoverLogFile() // The used log number are already written to manifest in RecoverLogFile()
// method // method
s = impl->versions_->LogAndApply(impl->default_cfd_, &edit, &impl->mutex_, s = impl->versions_->LogAndApply(impl->default_cf_handle_->cfd(), &edit,
&impl->mutex_,
impl->db_directory_.get()); impl->db_directory_.get());
} }
if (s.ok()) { if (s.ok()) {
// set column family handles // set column family handles
handles->clear();
for (auto cf : column_families) { for (auto cf : column_families) {
if (!impl->versions_->GetColumnFamilySet()->Exists(cf.name)) { if (!impl->versions_->GetColumnFamilySet()->Exists(cf.name)) {
s = Status::InvalidArgument("Column family not found: ", cf.name); s = Status::InvalidArgument("Column family not found: ", cf.name);
handles->clear();
break; break;
} }
uint32_t id = impl->versions_->GetColumnFamilySet()->GetID(cf.name); uint32_t id = impl->versions_->GetColumnFamilySet()->GetID(cf.name);
handles->push_back(ColumnFamilyHandle(id)); auto cfd = impl->versions_->GetColumnFamilySet()->GetColumnFamily(id);
assert(cfd != nullptr);
handles->push_back(
new ColumnFamilyHandleImpl(cfd, impl, &impl->mutex_));
} }
} }
if (s.ok()) { if (s.ok()) {
@ -3836,6 +3876,9 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
if (s.ok()) { if (s.ok()) {
*dbptr = impl; *dbptr = impl;
} else { } else {
for (auto h : *handles) {
delete h;
}
handles->clear(); handles->clear();
delete impl; delete impl;
} }

View File

@ -45,32 +45,31 @@ class DBImpl : public DB {
// Implementations of the DB interface // Implementations of the DB interface
using DB::Put; using DB::Put;
virtual Status Put(const WriteOptions& options, virtual Status Put(const WriteOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& value); const Slice& value);
using DB::Merge; using DB::Merge;
virtual Status Merge(const WriteOptions& options, virtual Status Merge(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, const Slice& value); const Slice& value);
using DB::Delete; using DB::Delete;
virtual Status Delete(const WriteOptions& options, virtual Status Delete(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key);
const Slice& key);
using DB::Write; using DB::Write;
virtual Status Write(const WriteOptions& options, WriteBatch* updates); virtual Status Write(const WriteOptions& options, WriteBatch* updates);
using DB::Get; using DB::Get;
virtual Status Get(const ReadOptions& options, virtual Status Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value); std::string* value);
using DB::MultiGet; using DB::MultiGet;
virtual std::vector<Status> MultiGet( virtual std::vector<Status> MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, std::vector<std::string>* values); const std::vector<Slice>& keys, std::vector<std::string>* values);
virtual Status CreateColumnFamily(const ColumnFamilyOptions& options, virtual Status CreateColumnFamily(const ColumnFamilyOptions& options,
const std::string& column_family, const std::string& column_family,
ColumnFamilyHandle* handle); ColumnFamilyHandle** handle);
virtual Status DropColumnFamily(const ColumnFamilyHandle& column_family); virtual Status DropColumnFamily(ColumnFamilyHandle* column_family);
// Returns false if key doesn't exist in the database and true if it may. // Returns false if key doesn't exist in the database and true if it may.
// If value_found is not passed in as null, then return the value if found in // If value_found is not passed in as null, then return the value if found in
@ -78,43 +77,41 @@ class DBImpl : public DB {
// , otherwise false. // , otherwise false.
using DB::KeyMayExist; using DB::KeyMayExist;
virtual bool KeyMayExist(const ReadOptions& options, virtual bool KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value, bool* value_found = nullptr);
bool* value_found = nullptr);
using DB::NewIterator; using DB::NewIterator;
virtual Iterator* NewIterator(const ReadOptions& options, virtual Iterator* NewIterator(const ReadOptions& options,
const ColumnFamilyHandle& column_family); ColumnFamilyHandle* column_family);
virtual Status NewIterators( virtual Status NewIterators(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
std::vector<Iterator*>* iterators); std::vector<Iterator*>* iterators);
virtual const Snapshot* GetSnapshot(); virtual const Snapshot* GetSnapshot();
virtual void ReleaseSnapshot(const Snapshot* snapshot); virtual void ReleaseSnapshot(const Snapshot* snapshot);
using DB::GetProperty; using DB::GetProperty;
virtual bool GetProperty(const ColumnFamilyHandle& column_family, virtual bool GetProperty(ColumnFamilyHandle* column_family,
const Slice& property, std::string* value); const Slice& property, std::string* value);
using DB::GetApproximateSizes; using DB::GetApproximateSizes;
virtual void GetApproximateSizes(const ColumnFamilyHandle& column_family, virtual void GetApproximateSizes(ColumnFamilyHandle* column_family,
const Range* range, int n, uint64_t* sizes); const Range* range, int n, uint64_t* sizes);
using DB::CompactRange; using DB::CompactRange;
virtual Status CompactRange(const ColumnFamilyHandle& column_family, virtual Status CompactRange(ColumnFamilyHandle* column_family,
const Slice* begin, const Slice* end, const Slice* begin, const Slice* end,
bool reduce_level = false, int target_level = -1); bool reduce_level = false, int target_level = -1);
using DB::NumberLevels; using DB::NumberLevels;
virtual int NumberLevels(const ColumnFamilyHandle& column_family); virtual int NumberLevels(ColumnFamilyHandle* column_family);
using DB::MaxMemCompactionLevel; using DB::MaxMemCompactionLevel;
virtual int MaxMemCompactionLevel(const ColumnFamilyHandle& column_family); virtual int MaxMemCompactionLevel(ColumnFamilyHandle* column_family);
using DB::Level0StopWriteTrigger; using DB::Level0StopWriteTrigger;
virtual int Level0StopWriteTrigger(const ColumnFamilyHandle& column_family); virtual int Level0StopWriteTrigger(ColumnFamilyHandle* column_family);
virtual const std::string& GetName() const; virtual const std::string& GetName() const;
virtual Env* GetEnv() const; virtual Env* GetEnv() const;
using DB::GetOptions; using DB::GetOptions;
virtual const Options& GetOptions(const ColumnFamilyHandle& column_family) virtual const Options& GetOptions(ColumnFamilyHandle* column_family) const;
const;
using DB::Flush; using DB::Flush;
virtual Status Flush(const FlushOptions& options, virtual Status Flush(const FlushOptions& options,
const ColumnFamilyHandle& column_family); ColumnFamilyHandle* column_family);
virtual Status DisableFileDeletions(); virtual Status DisableFileDeletions();
virtual Status EnableFileDeletions(bool force); virtual Status EnableFileDeletions(bool force);
// All the returned filenames start with "/" // All the returned filenames start with "/"
@ -246,6 +243,8 @@ class DBImpl : public DB {
// It is not necessary to hold the mutex when invoking this method. // It is not necessary to hold the mutex when invoking this method.
void PurgeObsoleteFiles(DeletionState& deletion_state); void PurgeObsoleteFiles(DeletionState& deletion_state);
ColumnFamilyHandle* DefaultColumnFamily() const;
protected: protected:
Env* const env_; Env* const env_;
const std::string dbname_; const std::string dbname_;
@ -381,7 +380,7 @@ class DBImpl : public DB {
port::CondVar bg_cv_; // Signalled when background work finishes port::CondVar bg_cv_; // Signalled when background work finishes
uint64_t logfile_number_; uint64_t logfile_number_;
unique_ptr<log::Writer> log_; unique_ptr<log::Writer> log_;
ColumnFamilyData* default_cfd_; ColumnFamilyHandleImpl* default_cf_handle_;
unique_ptr<ColumnFamilyMemTablesImpl> column_family_memtables_; unique_ptr<ColumnFamilyMemTablesImpl> column_family_memtables_;
std::string host_name_; std::string host_name_;
@ -493,9 +492,9 @@ class DBImpl : public DB {
// Function that Get and KeyMayExist call with no_io true or false // Function that Get and KeyMayExist call with no_io true or false
// Note: 'value_found' from KeyMayExist propagates here // Note: 'value_found' from KeyMayExist propagates here
Status GetImpl(const ReadOptions& options, Status GetImpl(const ReadOptions& options, ColumnFamilyHandle* column_family,
const ColumnFamilyHandle& column_family, const Slice& key, const Slice& key, std::string* value,
std::string* value, bool* value_found = nullptr); bool* value_found = nullptr);
}; };
// Sanitize db options. The caller should delete result.info_log if // Sanitize db options. The caller should delete result.info_log if

View File

@ -29,7 +29,6 @@
#include "db/write_batch_internal.h" #include "db/write_batch_internal.h"
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "rocksdb/column_family.h"
#include "rocksdb/status.h" #include "rocksdb/status.h"
#include "rocksdb/table.h" #include "rocksdb/table.h"
#include "rocksdb/merge_operator.h" #include "rocksdb/merge_operator.h"
@ -54,11 +53,12 @@ DBImplReadOnly::~DBImplReadOnly() {
// Implementations of the DB interface // Implementations of the DB interface
Status DBImplReadOnly::Get(const ReadOptions& options, Status DBImplReadOnly::Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value) { std::string* value) {
Status s; Status s;
SequenceNumber snapshot = versions_->LastSequence(); SequenceNumber snapshot = versions_->LastSequence();
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
SuperVersion* super_version = cfd->GetSuperVersion(); SuperVersion* super_version = cfd->GetSuperVersion();
MergeContext merge_context; MergeContext merge_context;
LookupKey lkey(key, snapshot); LookupKey lkey(key, snapshot);
@ -73,9 +73,9 @@ Status DBImplReadOnly::Get(const ReadOptions& options,
} }
Iterator* DBImplReadOnly::NewIterator(const ReadOptions& options, Iterator* DBImplReadOnly::NewIterator(const ReadOptions& options,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
auto cfd = versions_->GetColumnFamilySet()->GetColumnFamily(column_family.id); auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
assert(cfd != nullptr); auto cfd = cfh->cfd();
SuperVersion* super_version = cfd->GetSuperVersion()->Ref(); SuperVersion* super_version = cfd->GetSuperVersion()->Ref();
SequenceNumber latest_snapshot = versions_->LastSequence(); SequenceNumber latest_snapshot = versions_->LastSequence();
Iterator* internal_iter = NewInternalIterator(options, cfd, super_version); Iterator* internal_iter = NewInternalIterator(options, cfd, super_version);

View File

@ -32,18 +32,18 @@ class DBImplReadOnly : public DBImpl {
// Implementations of the DB interface // Implementations of the DB interface
using DB::Get; using DB::Get;
virtual Status Get(const ReadOptions& options, virtual Status Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value); std::string* value);
// TODO: Implement ReadOnly MultiGet? // TODO: Implement ReadOnly MultiGet?
using DBImpl::NewIterator; using DBImpl::NewIterator;
virtual Iterator* NewIterator(const ReadOptions&, virtual Iterator* NewIterator(const ReadOptions&,
const ColumnFamilyHandle& column_family); ColumnFamilyHandle* column_family);
virtual Status NewIterators( virtual Status NewIterators(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
std::vector<Iterator*>* iterators) { std::vector<Iterator*>* iterators) {
// TODO // TODO
return Status::NotSupported("Not supported yet."); return Status::NotSupported("Not supported yet.");
@ -51,27 +51,26 @@ class DBImplReadOnly : public DBImpl {
using DBImpl::Put; using DBImpl::Put;
virtual Status Put(const WriteOptions& options, virtual Status Put(const WriteOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& value) { const Slice& value) {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }
using DBImpl::Merge; using DBImpl::Merge;
virtual Status Merge(const WriteOptions& options, virtual Status Merge(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, const Slice& value) { const Slice& value) {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }
using DBImpl::Delete; using DBImpl::Delete;
virtual Status Delete(const WriteOptions& options, virtual Status Delete(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key) {
const Slice& key) {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }
virtual Status Write(const WriteOptions& options, WriteBatch* updates) { virtual Status Write(const WriteOptions& options, WriteBatch* updates) {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }
using DBImpl::CompactRange; using DBImpl::CompactRange;
virtual Status CompactRange(const ColumnFamilyHandle& column_family, virtual Status CompactRange(ColumnFamilyHandle* column_family,
const Slice* begin, const Slice* end, const Slice* begin, const Slice* end,
bool reduce_level = false, bool reduce_level = false,
int target_level = -1) { int target_level = -1) {
@ -90,7 +89,7 @@ class DBImplReadOnly : public DBImpl {
} }
using DBImpl::Flush; using DBImpl::Flush;
virtual Status Flush(const FlushOptions& options, virtual Status Flush(const FlushOptions& options,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }

View File

@ -65,7 +65,7 @@ void DBImpl::LogDBDeployStats() {
uint64_t file_total_size = 0; uint64_t file_total_size = 0;
uint32_t file_total_num = 0; uint32_t file_total_num = 0;
Version* current = default_cfd_->current(); Version* current = default_cf_handle_->cfd()->current();
for (int i = 0; i < current->NumberLevels(); i++) { for (int i = 0; i < current->NumberLevels(); i++) {
file_total_num += current->NumLevelFiles(i); file_total_num += current->NumLevelFiles(i);
file_total_size += current->NumLevelBytes(i); file_total_size += current->NumLevelBytes(i);

View File

@ -4743,22 +4743,28 @@ class ModelDB: public DB {
explicit ModelDB(const Options& options) : options_(options) {} explicit ModelDB(const Options& options) : options_(options) {}
using DB::Put; using DB::Put;
virtual Status Put(const WriteOptions& o, const ColumnFamilyHandle& cf, virtual Status Put(const WriteOptions& o, ColumnFamilyHandle* cf,
const Slice& k, const Slice& v) { const Slice& k, const Slice& v) {
return DB::Put(o, cf, k, v); WriteBatch batch;
batch.Put(0, k, v);
return Write(o, &batch);
} }
using DB::Merge; using DB::Merge;
virtual Status Merge(const WriteOptions& o, const ColumnFamilyHandle& cf, virtual Status Merge(const WriteOptions& o, ColumnFamilyHandle* cf,
const Slice& k, const Slice& v) { const Slice& k, const Slice& v) {
return DB::Merge(o, cf, k, v); WriteBatch batch;
batch.Merge(0, k, v);
return Write(o, &batch);
} }
using DB::Delete; using DB::Delete;
virtual Status Delete(const WriteOptions& o, const ColumnFamilyHandle& cf, virtual Status Delete(const WriteOptions& o, ColumnFamilyHandle* cf,
const Slice& key) { const Slice& key) {
return DB::Delete(o, cf, key); WriteBatch batch;
batch.Delete(0, key);
return Write(o, &batch);
} }
using DB::Get; using DB::Get;
virtual Status Get(const ReadOptions& options, const ColumnFamilyHandle& cf, virtual Status Get(const ReadOptions& options, ColumnFamilyHandle* cf,
const Slice& key, std::string* value) { const Slice& key, std::string* value) {
return Status::NotSupported(key); return Status::NotSupported(key);
} }
@ -4766,7 +4772,7 @@ class ModelDB: public DB {
using DB::MultiGet; using DB::MultiGet;
virtual std::vector<Status> MultiGet( virtual std::vector<Status> MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, std::vector<std::string>* values) { const std::vector<Slice>& keys, std::vector<std::string>* values) {
std::vector<Status> s(keys.size(), std::vector<Status> s(keys.size(),
Status::NotSupported("Not implemented.")); Status::NotSupported("Not implemented."));
@ -4774,9 +4780,8 @@ class ModelDB: public DB {
} }
using DB::KeyMayExist; using DB::KeyMayExist;
virtual bool KeyMayExist(const ReadOptions& options, virtual bool KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value, bool* value_found = nullptr) {
bool* value_found = nullptr) {
if (value_found != nullptr) { if (value_found != nullptr) {
*value_found = false; *value_found = false;
} }
@ -4784,7 +4789,7 @@ class ModelDB: public DB {
} }
using DB::NewIterator; using DB::NewIterator;
virtual Iterator* NewIterator(const ReadOptions& options, virtual Iterator* NewIterator(const ReadOptions& options,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
if (options.snapshot == nullptr) { if (options.snapshot == nullptr) {
KVMap* saved = new KVMap; KVMap* saved = new KVMap;
*saved = map_; *saved = map_;
@ -4797,7 +4802,7 @@ class ModelDB: public DB {
} }
virtual Status NewIterators( virtual Status NewIterators(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
std::vector<Iterator*>* iterators) { std::vector<Iterator*>* iterators) {
return Status::NotSupported("Not supported yet"); return Status::NotSupported("Not supported yet");
} }
@ -4831,36 +4836,34 @@ class ModelDB: public DB {
} }
using DB::GetProperty; using DB::GetProperty;
virtual bool GetProperty(const ColumnFamilyHandle& column_family, virtual bool GetProperty(ColumnFamilyHandle* column_family,
const Slice& property, std::string* value) { const Slice& property, std::string* value) {
return false; return false;
} }
using DB::GetApproximateSizes; using DB::GetApproximateSizes;
virtual void GetApproximateSizes(const ColumnFamilyHandle& column_family, virtual void GetApproximateSizes(ColumnFamilyHandle* column_family,
const Range* range, int n, uint64_t* sizes) { const Range* range, int n, uint64_t* sizes) {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
sizes[i] = 0; sizes[i] = 0;
} }
} }
using DB::CompactRange; using DB::CompactRange;
virtual Status CompactRange(const ColumnFamilyHandle& column_family, virtual Status CompactRange(ColumnFamilyHandle* column_family,
const Slice* start, const Slice* end, const Slice* start, const Slice* end,
bool reduce_level, int target_level) { bool reduce_level, int target_level) {
return Status::NotSupported("Not supported operation."); return Status::NotSupported("Not supported operation.");
} }
using DB::NumberLevels; using DB::NumberLevels;
virtual int NumberLevels(const ColumnFamilyHandle& column_family) { virtual int NumberLevels(ColumnFamilyHandle* column_family) { return 1; }
return 1;
}
using DB::MaxMemCompactionLevel; using DB::MaxMemCompactionLevel;
virtual int MaxMemCompactionLevel(const ColumnFamilyHandle& column_family) { virtual int MaxMemCompactionLevel(ColumnFamilyHandle* column_family) {
return 1; return 1;
} }
using DB::Level0StopWriteTrigger; using DB::Level0StopWriteTrigger;
virtual int Level0StopWriteTrigger(const ColumnFamilyHandle& column_family) { virtual int Level0StopWriteTrigger(ColumnFamilyHandle* column_family) {
return -1; return -1;
} }
@ -4873,14 +4876,13 @@ class ModelDB: public DB {
} }
using DB::GetOptions; using DB::GetOptions;
virtual const Options& GetOptions(const ColumnFamilyHandle& column_family) virtual const Options& GetOptions(ColumnFamilyHandle* column_family) const {
const {
return options_; return options_;
} }
using DB::Flush; using DB::Flush;
virtual Status Flush(const rocksdb::FlushOptions& options, virtual Status Flush(const rocksdb::FlushOptions& options,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
Status ret; Status ret;
return ret; return ret;
} }
@ -4916,6 +4918,8 @@ class ModelDB: public DB {
return Status::NotSupported("Not supported in Model DB"); return Status::NotSupported("Not supported in Model DB");
} }
virtual ColumnFamilyHandle* DefaultColumnFamily() const { return nullptr; }
private: private:
class ModelIter: public Iterator { class ModelIter: public Iterator {
public: public:

View File

@ -1396,9 +1396,6 @@ VersionSet::VersionSet(const std::string& dbname, const DBOptions* options,
storage_options_compactions_(storage_options_) {} storage_options_compactions_(storage_options_) {}
VersionSet::~VersionSet() { VersionSet::~VersionSet() {
for (auto cfd : *column_family_set_) {
cfd->current()->Unref();
}
// we need to delete column_family_set_ because its destructor depends on // we need to delete column_family_set_ because its destructor depends on
// VersionSet // VersionSet
column_family_set_.reset(); column_family_set_.reset();
@ -1434,6 +1431,11 @@ Status VersionSet::LogAndApply(ColumnFamilyData* column_family_data,
bool new_descriptor_log) { bool new_descriptor_log) {
mu->AssertHeld(); mu->AssertHeld();
if (column_family_data->IsDropped()) {
// no need to write anything to the manifest
return Status::OK();
}
// queue our request // queue our request
ManifestWriter w(mu, column_family_data, edit); ManifestWriter w(mu, column_family_data, edit);
manifest_writers_.push_back(&w); manifest_writers_.push_back(&w);
@ -1759,7 +1761,13 @@ Status VersionSet::Recover(
assert(builder != builders.end()); assert(builder != builders.end());
delete builder->second; delete builder->second;
builders.erase(builder); builders.erase(builder);
DropColumnFamily(&edit); auto cfd = column_family_set_->GetColumnFamily(edit.column_family_);
if (cfd->Unref()) {
delete cfd;
} else {
// who else can have reference to cfd!?
assert(false);
}
} else if (cf_in_not_found) { } else if (cf_in_not_found) {
column_families_not_found.erase(edit.column_family_); column_families_not_found.erase(edit.column_family_);
} else { } else {
@ -2433,8 +2441,4 @@ ColumnFamilyData* VersionSet::CreateColumnFamily(
return new_cfd; return new_cfd;
} }
void VersionSet::DropColumnFamily(VersionEdit* edit) {
column_family_set_->DropColumnFamily(edit->column_family_);
}
} // namespace rocksdb } // namespace rocksdb

View File

@ -396,8 +396,6 @@ class VersionSet {
ColumnFamilyData* CreateColumnFamily(const ColumnFamilyOptions& options, ColumnFamilyData* CreateColumnFamily(const ColumnFamilyOptions& options,
VersionEdit* edit); VersionEdit* edit);
void DropColumnFamily(VersionEdit* edit);
ColumnFamilySet* GetColumnFamilySet() { return column_family_set_.get(); } ColumnFamilySet* GetColumnFamilySet() { return column_family_set_.get(); }
private: private:

View File

@ -277,7 +277,13 @@ class MemTableInserter : public WriteBatch::Handler {
std::string prev_value; std::string prev_value;
std::string merged_value; std::string merged_value;
Status s = db_->Get(ropts, key, &prev_value);
auto cf_handle = cf_mems_->GetColumnFamilyHandle();
if (cf_handle == nullptr) {
cf_handle = db_->DefaultColumnFamily();
}
Status s = db_->Get(ropts, cf_handle, key, &prev_value);
char* prev_buffer = const_cast<char*>(prev_value.c_str()); char* prev_buffer = const_cast<char*>(prev_value.c_str());
uint32_t prev_size = prev_value.size(); uint32_t prev_size = prev_value.size();
auto status = options->inplace_callback(s.ok() ? prev_buffer : nullptr, auto status = options->inplace_callback(s.ok() ? prev_buffer : nullptr,
@ -333,8 +339,11 @@ class MemTableInserter : public WriteBatch::Handler {
ReadOptions read_options; ReadOptions read_options;
read_options.snapshot = &read_from_snapshot; read_options.snapshot = &read_from_snapshot;
db_->Get(read_options, cf_mems_->GetColumnFamilyHandle(), key, auto cf_handle = cf_mems_->GetColumnFamilyHandle();
&get_value); if (cf_handle == nullptr) {
cf_handle = db_->DefaultColumnFamily();
}
db_->Get(read_options, cf_handle, key, &get_value);
Slice get_value_slice = Slice(get_value); Slice get_value_slice = Slice(get_value);
// 2) Apply this merge // 2) Apply this merge
@ -378,8 +387,11 @@ class MemTableInserter : public WriteBatch::Handler {
ReadOptions ropts; ReadOptions ropts;
ropts.snapshot = &read_from_snapshot; ropts.snapshot = &read_from_snapshot;
std::string value; std::string value;
if (!db_->KeyMayExist(ropts, cf_mems_->GetColumnFamilyHandle(), key, auto cf_handle = cf_mems_->GetColumnFamilyHandle();
&value)) { if (cf_handle == nullptr) {
cf_handle = db_->DefaultColumnFamily();
}
if (!db_->KeyMayExist(ropts, cf_handle, key, &value)) {
RecordTick(options->statistics.get(), NUMBER_FILTERED_DELETES); RecordTick(options->statistics.get(), NUMBER_FILTERED_DELETES);
return; return;
} }

View File

@ -12,7 +12,6 @@
#include "rocksdb/write_batch.h" #include "rocksdb/write_batch.h"
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/options.h" #include "rocksdb/options.h"
#include "rocksdb/column_family.h"
namespace rocksdb { namespace rocksdb {
@ -28,7 +27,7 @@ class ColumnFamilyMemTables {
virtual uint64_t GetLogNumber() const = 0; virtual uint64_t GetLogNumber() const = 0;
virtual MemTable* GetMemTable() const = 0; virtual MemTable* GetMemTable() const = 0;
virtual const Options* GetFullOptions() const = 0; virtual const Options* GetFullOptions() const = 0;
virtual const ColumnFamilyHandle& GetColumnFamilyHandle() const = 0; virtual ColumnFamilyHandle* GetColumnFamilyHandle() = 0;
}; };
class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables { class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables {
@ -53,9 +52,7 @@ class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables {
return options_; return options_;
} }
const ColumnFamilyHandle& GetColumnFamilyHandle() const override { ColumnFamilyHandle* GetColumnFamilyHandle() override { return nullptr; }
return default_column_family;
}
private: private:
bool ok_; bool ok_;

View File

@ -1,31 +0,0 @@
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#pragma once
#include "rocksdb/slice.h"
#include <string>
namespace rocksdb {
// Column family's name is translated to ColumnFamilyHandle at DB open or column
// family open time. Clients use ColumnFamilyHandle to comunicate with the DB
//
// Column family names that start with "." (a dot) are system specific and
// should not be used by the clients
struct ColumnFamilyHandle {
uint32_t id;
// default
ColumnFamilyHandle() : id() {}
explicit ColumnFamilyHandle(uint32_t _id) : id(_id) {}
};
const ColumnFamilyHandle default_column_family = ColumnFamilyHandle();
extern const std::string default_column_family_name;
} // namespace rocksdb

View File

@ -23,8 +23,15 @@ namespace rocksdb {
using std::unique_ptr; using std::unique_ptr;
struct ColumnFamilyHandle; class ColumnFamilyHandle {
extern const ColumnFamilyHandle default_column_family; public:
ColumnFamilyHandle() {}
virtual ~ColumnFamilyHandle() {}
private:
ColumnFamilyHandle(const ColumnFamilyHandle&); // no copying
};
extern const std::string default_column_family_name;
struct ColumnFamilyDescriptor { struct ColumnFamilyDescriptor {
std::string name; std::string name;
@ -106,7 +113,7 @@ class DB {
// will use to operate on column family column_family[i] // will use to operate on column family column_family[i]
static Status Open(const DBOptions& db_options, const std::string& name, static Status Open(const DBOptions& db_options, const std::string& name,
const std::vector<ColumnFamilyDescriptor>& column_families, const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle>* handles, DB** dbptr); std::vector<ColumnFamilyHandle*>* handles, DB** dbptr);
// ListColumnFamilies will open the DB specified by argument name // ListColumnFamilies will open the DB specified by argument name
// and return the list of all column families in that DB // and return the list of all column families in that DB
@ -123,23 +130,22 @@ class DB {
// through the argument handle. // through the argument handle.
virtual Status CreateColumnFamily(const ColumnFamilyOptions& options, virtual Status CreateColumnFamily(const ColumnFamilyOptions& options,
const std::string& column_family_name, const std::string& column_family_name,
ColumnFamilyHandle* handle); ColumnFamilyHandle** handle);
// Drop a column family specified by column_family handle. // Drop a column family specified by column_family handle. This call
// All data related to the column family will be deleted before // only records a drop record in the manifest and prevents the column
// the function returns. // family from flushing and compacting.
// Calls referring to the dropped column family will fail. virtual Status DropColumnFamily(ColumnFamilyHandle* column_family);
virtual Status DropColumnFamily(const ColumnFamilyHandle& column_family);
// Set the database entry for "key" to "value". // Set the database entry for "key" to "value".
// Returns OK on success, and a non-OK status on error. // Returns OK on success, and a non-OK status on error.
// Note: consider setting options.sync = true. // Note: consider setting options.sync = true.
virtual Status Put(const WriteOptions& options, virtual Status Put(const WriteOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& value) = 0; const Slice& value) = 0;
Status Put(const WriteOptions& options, const Slice& key, Status Put(const WriteOptions& options, const Slice& key,
const Slice& value) { const Slice& value) {
return Put(options, default_column_family, key, value); return Put(options, DefaultColumnFamily(), key, value);
} }
// Remove the database entry (if any) for "key". Returns OK on // Remove the database entry (if any) for "key". Returns OK on
@ -147,10 +153,10 @@ class DB {
// did not exist in the database. // did not exist in the database.
// Note: consider setting options.sync = true. // Note: consider setting options.sync = true.
virtual Status Delete(const WriteOptions& options, virtual Status Delete(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family,
const Slice& key) = 0; const Slice& key) = 0;
Status Delete(const WriteOptions& options, const Slice& key) { Status Delete(const WriteOptions& options, const Slice& key) {
return Delete(options, default_column_family, key); return Delete(options, DefaultColumnFamily(), key);
} }
// Merge the database entry for "key" with "value". Returns OK on success, // Merge the database entry for "key" with "value". Returns OK on success,
@ -158,11 +164,11 @@ class DB {
// determined by the user provided merge_operator when opening DB. // determined by the user provided merge_operator when opening DB.
// Note: consider setting options.sync = true. // Note: consider setting options.sync = true.
virtual Status Merge(const WriteOptions& options, virtual Status Merge(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, const Slice& value) = 0; const Slice& value) = 0;
Status Merge(const WriteOptions& options, const Slice& key, Status Merge(const WriteOptions& options, const Slice& key,
const Slice& value) { const Slice& value) {
return Merge(options, default_column_family, key, value); return Merge(options, DefaultColumnFamily(), key, value);
} }
// Apply the specified updates to the database. // Apply the specified updates to the database.
@ -178,10 +184,10 @@ class DB {
// //
// May return some other Status on an error. // May return some other Status on an error.
virtual Status Get(const ReadOptions& options, virtual Status Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value) = 0; std::string* value) = 0;
Status Get(const ReadOptions& options, const Slice& key, std::string* value) { Status Get(const ReadOptions& options, const Slice& key, std::string* value) {
return Get(options, default_column_family, key, value); return Get(options, DefaultColumnFamily(), key, value);
} }
// If keys[i] does not exist in the database, then the i'th returned // If keys[i] does not exist in the database, then the i'th returned
@ -196,13 +202,13 @@ class DB {
// duplicate values in order. // duplicate values in order.
virtual std::vector<Status> MultiGet( virtual std::vector<Status> MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, std::vector<std::string>* values) = 0; const std::vector<Slice>& keys, std::vector<std::string>* values) = 0;
std::vector<Status> MultiGet(const ReadOptions& options, std::vector<Status> MultiGet(const ReadOptions& options,
const std::vector<Slice>& keys, const std::vector<Slice>& keys,
std::vector<std::string>* values) { std::vector<std::string>* values) {
return MultiGet(options, std::vector<ColumnFamilyHandle>( return MultiGet(options, std::vector<ColumnFamilyHandle*>(
keys.size(), default_column_family), keys.size(), DefaultColumnFamily()),
keys, values); keys, values);
} }
@ -214,9 +220,8 @@ class DB {
// to make this lighter weight is to avoid doing any IOs. // to make this lighter weight is to avoid doing any IOs.
// Default implementation here returns true and sets 'value_found' to false // Default implementation here returns true and sets 'value_found' to false
virtual bool KeyMayExist(const ReadOptions& options, virtual bool KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value, bool* value_found = nullptr) {
bool* value_found = nullptr) {
if (value_found != nullptr) { if (value_found != nullptr) {
*value_found = false; *value_found = false;
} }
@ -224,7 +229,7 @@ class DB {
} }
bool KeyMayExist(const ReadOptions& options, const Slice& key, bool KeyMayExist(const ReadOptions& options, const Slice& key,
std::string* value, bool* value_found = nullptr) { std::string* value, bool* value_found = nullptr) {
return KeyMayExist(options, default_column_family, key, value, value_found); return KeyMayExist(options, DefaultColumnFamily(), key, value, value_found);
} }
// Return a heap-allocated iterator over the contents of the database. // Return a heap-allocated iterator over the contents of the database.
@ -234,16 +239,16 @@ class DB {
// Caller should delete the iterator when it is no longer needed. // Caller should delete the iterator when it is no longer needed.
// The returned iterator should be deleted before this db is deleted. // The returned iterator should be deleted before this db is deleted.
virtual Iterator* NewIterator(const ReadOptions& options, virtual Iterator* NewIterator(const ReadOptions& options,
const ColumnFamilyHandle& column_family) = 0; ColumnFamilyHandle* column_family) = 0;
Iterator* NewIterator(const ReadOptions& options) { Iterator* NewIterator(const ReadOptions& options) {
return NewIterator(options, default_column_family); return NewIterator(options, DefaultColumnFamily());
} }
// Returns iterators from a consistent database state across multiple // Returns iterators from a consistent database state across multiple
// column families. Iterators are heap allocated and need to be deleted // column families. Iterators are heap allocated and need to be deleted
// before the db is deleted // before the db is deleted
virtual Status NewIterators( virtual Status NewIterators(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
std::vector<Iterator*>* iterators) = 0; std::vector<Iterator*>* iterators) = 0;
// Return a handle to the current DB state. Iterators created with // Return a handle to the current DB state. Iterators created with
@ -270,10 +275,10 @@ class DB {
// about the internal operation of the DB. // about the internal operation of the DB.
// "rocksdb.sstables" - returns a multi-line string that describes all // "rocksdb.sstables" - returns a multi-line string that describes all
// of the sstables that make up the db contents. // of the sstables that make up the db contents.
virtual bool GetProperty(const ColumnFamilyHandle& column_family, virtual bool GetProperty(ColumnFamilyHandle* column_family,
const Slice& property, std::string* value) = 0; const Slice& property, std::string* value) = 0;
bool GetProperty(const Slice& property, std::string* value) { bool GetProperty(const Slice& property, std::string* value) {
return GetProperty(default_column_family, property, value); return GetProperty(DefaultColumnFamily(), property, value);
} }
// For each i in [0,n-1], store in "sizes[i]", the approximate // For each i in [0,n-1], store in "sizes[i]", the approximate
@ -284,11 +289,11 @@ class DB {
// sizes will be one-tenth the size of the corresponding user data size. // sizes will be one-tenth the size of the corresponding user data size.
// //
// The results may not include the sizes of recently written data. // The results may not include the sizes of recently written data.
virtual void GetApproximateSizes(const ColumnFamilyHandle& column_family, virtual void GetApproximateSizes(ColumnFamilyHandle* column_family,
const Range* range, int n, const Range* range, int n,
uint64_t* sizes) = 0; uint64_t* sizes) = 0;
void GetApproximateSizes(const Range* range, int n, uint64_t* sizes) { void GetApproximateSizes(const Range* range, int n, uint64_t* sizes) {
GetApproximateSizes(default_column_family, range, n, sizes); GetApproximateSizes(DefaultColumnFamily(), range, n, sizes);
} }
// Compact the underlying storage for the key range [*begin,*end]. // Compact the underlying storage for the key range [*begin,*end].
@ -308,35 +313,31 @@ class DB {
// hosting all the files. In this case, client could set reduce_level // hosting all the files. In this case, client could set reduce_level
// to true, to move the files back to the minimum level capable of holding // to true, to move the files back to the minimum level capable of holding
// the data set or a given level (specified by non-negative target_level). // the data set or a given level (specified by non-negative target_level).
virtual Status CompactRange(const ColumnFamilyHandle& column_family, virtual Status CompactRange(ColumnFamilyHandle* column_family,
const Slice* begin, const Slice* end, const Slice* begin, const Slice* end,
bool reduce_level = false, bool reduce_level = false,
int target_level = -1) = 0; int target_level = -1) = 0;
Status CompactRange(const Slice* begin, const Slice* end, Status CompactRange(const Slice* begin, const Slice* end,
bool reduce_level = false, int target_level = -1) { bool reduce_level = false, int target_level = -1) {
return CompactRange(default_column_family, begin, end, reduce_level, return CompactRange(DefaultColumnFamily(), begin, end, reduce_level,
target_level); target_level);
} }
// Number of levels used for this DB. // Number of levels used for this DB.
virtual int NumberLevels(const ColumnFamilyHandle& column_family) = 0; virtual int NumberLevels(ColumnFamilyHandle* column_family) = 0;
int NumberLevels() { int NumberLevels() { return NumberLevels(DefaultColumnFamily()); }
return NumberLevels(default_column_family);
}
// Maximum level to which a new compacted memtable is pushed if it // Maximum level to which a new compacted memtable is pushed if it
// does not create overlap. // does not create overlap.
virtual int MaxMemCompactionLevel( virtual int MaxMemCompactionLevel(ColumnFamilyHandle* column_family) = 0;
const ColumnFamilyHandle& column_family) = 0;
int MaxMemCompactionLevel() { int MaxMemCompactionLevel() {
return MaxMemCompactionLevel(default_column_family); return MaxMemCompactionLevel(DefaultColumnFamily());
} }
// Number of files in level-0 that would stop writes. // Number of files in level-0 that would stop writes.
virtual int Level0StopWriteTrigger( virtual int Level0StopWriteTrigger(ColumnFamilyHandle* column_family) = 0;
const ColumnFamilyHandle& column_family) = 0;
int Level0StopWriteTrigger() { int Level0StopWriteTrigger() {
return Level0StopWriteTrigger(default_column_family); return Level0StopWriteTrigger(DefaultColumnFamily());
} }
// Get DB name -- the exact same name that was provided as an argument to // Get DB name -- the exact same name that was provided as an argument to
@ -347,17 +348,17 @@ class DB {
virtual Env* GetEnv() const = 0; virtual Env* GetEnv() const = 0;
// Get DB Options that we use // Get DB Options that we use
virtual const Options& GetOptions(const ColumnFamilyHandle& column_family) virtual const Options& GetOptions(ColumnFamilyHandle* column_family)
const = 0; const = 0;
const Options& GetOptions() const { const Options& GetOptions() const {
return GetOptions(default_column_family); return GetOptions(DefaultColumnFamily());
} }
// Flush all mem-table data. // Flush all mem-table data.
virtual Status Flush(const FlushOptions& options, virtual Status Flush(const FlushOptions& options,
const ColumnFamilyHandle& column_family) = 0; ColumnFamilyHandle* column_family) = 0;
Status Flush(const FlushOptions& options) { Status Flush(const FlushOptions& options) {
return Flush(options, default_column_family); return Flush(options, DefaultColumnFamily());
} }
// Prevent file deletions. Compactions will continue to occur, // Prevent file deletions. Compactions will continue to occur,
@ -426,6 +427,9 @@ class DB {
// be set properly // be set properly
virtual Status GetDbIdentity(std::string& identity) = 0; virtual Status GetDbIdentity(std::string& identity) = 0;
// Returns default column family handle
virtual ColumnFamilyHandle* DefaultColumnFamily() const = 0;
private: private:
// No copying allowed // No copying allowed
DB(const DB&); DB(const DB&);

View File

@ -27,7 +27,6 @@
#include <string> #include <string>
#include "rocksdb/status.h" #include "rocksdb/status.h"
#include "rocksdb/column_family.h"
namespace rocksdb { namespace rocksdb {

View File

@ -23,14 +23,14 @@ class StackableDB : public DB {
using DB::Put; using DB::Put;
virtual Status Put(const WriteOptions& options, virtual Status Put(const WriteOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& val) override { const Slice& val) override {
return db_->Put(options, column_family, key, val); return db_->Put(options, column_family, key, val);
} }
using DB::Get; using DB::Get;
virtual Status Get(const ReadOptions& options, virtual Status Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value) override { std::string* value) override {
return db_->Get(options, column_family, key, value); return db_->Get(options, column_family, key, value);
} }
@ -38,7 +38,7 @@ class StackableDB : public DB {
using DB::MultiGet; using DB::MultiGet;
virtual std::vector<Status> MultiGet( virtual std::vector<Status> MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, const std::vector<Slice>& keys,
std::vector<std::string>* values) override { std::vector<std::string>* values) override {
return db_->MultiGet(options, column_family, keys, values); return db_->MultiGet(options, column_family, keys, values);
@ -46,23 +46,23 @@ class StackableDB : public DB {
using DB::KeyMayExist; using DB::KeyMayExist;
virtual bool KeyMayExist(const ReadOptions& options, virtual bool KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value,
bool* value_found = nullptr) override { bool* value_found = nullptr) override {
return db_->KeyMayExist(options, column_family, key, value, value_found); return db_->KeyMayExist(options, column_family, key, value, value_found);
} }
using DB::Delete; using DB::Delete;
virtual Status Delete(const WriteOptions& wopts, virtual Status Delete(const WriteOptions& wopts,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family,
const Slice& key) override { const Slice& key) override {
return db_->Delete(wopts, column_family, key); return db_->Delete(wopts, column_family, key);
} }
using DB::Merge; using DB::Merge;
virtual Status Merge(const WriteOptions& options, virtual Status Merge(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, const Slice& value) override { const Slice& value) override {
return db_->Merge(options, column_family, key, value); return db_->Merge(options, column_family, key, value);
} }
@ -74,14 +74,13 @@ class StackableDB : public DB {
using DB::NewIterator; using DB::NewIterator;
virtual Iterator* NewIterator(const ReadOptions& opts, virtual Iterator* NewIterator(const ReadOptions& opts,
const ColumnFamilyHandle& column_family) ColumnFamilyHandle* column_family) override {
override {
return db_->NewIterator(opts, column_family); return db_->NewIterator(opts, column_family);
} }
virtual Status NewIterators( virtual Status NewIterators(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
std::vector<Iterator*>* iterators) { std::vector<Iterator*>* iterators) {
return db_->NewIterators(options, column_family, iterators); return db_->NewIterators(options, column_family, iterators);
} }
@ -96,20 +95,20 @@ class StackableDB : public DB {
} }
using DB::GetProperty; using DB::GetProperty;
virtual bool GetProperty(const ColumnFamilyHandle& column_family, virtual bool GetProperty(ColumnFamilyHandle* column_family,
const Slice& property, std::string* value) override { const Slice& property, std::string* value) override {
return db_->GetProperty(column_family, property, value); return db_->GetProperty(column_family, property, value);
} }
using DB::GetApproximateSizes; using DB::GetApproximateSizes;
virtual void GetApproximateSizes(const ColumnFamilyHandle& column_family, virtual void GetApproximateSizes(ColumnFamilyHandle* column_family,
const Range* r, int n, const Range* r, int n,
uint64_t* sizes) override { uint64_t* sizes) override {
return db_->GetApproximateSizes(column_family, r, n, sizes); return db_->GetApproximateSizes(column_family, r, n, sizes);
} }
using DB::CompactRange; using DB::CompactRange;
virtual Status CompactRange(const ColumnFamilyHandle& column_family, virtual Status CompactRange(ColumnFamilyHandle* column_family,
const Slice* begin, const Slice* end, const Slice* begin, const Slice* end,
bool reduce_level = false, bool reduce_level = false,
int target_level = -1) override { int target_level = -1) override {
@ -118,18 +117,18 @@ class StackableDB : public DB {
} }
using DB::NumberLevels; using DB::NumberLevels;
virtual int NumberLevels(const ColumnFamilyHandle& column_family) override { virtual int NumberLevels(ColumnFamilyHandle* column_family) override {
return db_->NumberLevels(column_family); return db_->NumberLevels(column_family);
} }
using DB::MaxMemCompactionLevel; using DB::MaxMemCompactionLevel;
virtual int MaxMemCompactionLevel(const ColumnFamilyHandle& column_family) virtual int MaxMemCompactionLevel(ColumnFamilyHandle* column_family)
override { override {
return db_->MaxMemCompactionLevel(column_family); return db_->MaxMemCompactionLevel(column_family);
} }
using DB::Level0StopWriteTrigger; using DB::Level0StopWriteTrigger;
virtual int Level0StopWriteTrigger(const ColumnFamilyHandle& column_family) virtual int Level0StopWriteTrigger(ColumnFamilyHandle* column_family)
override { override {
return db_->Level0StopWriteTrigger(column_family); return db_->Level0StopWriteTrigger(column_family);
} }
@ -143,14 +142,14 @@ class StackableDB : public DB {
} }
using DB::GetOptions; using DB::GetOptions;
virtual const Options& GetOptions(const ColumnFamilyHandle& column_family) virtual const Options& GetOptions(ColumnFamilyHandle* column_family) const
const override { override {
return db_->GetOptions(column_family); return db_->GetOptions(column_family);
} }
using DB::Flush; using DB::Flush;
virtual Status Flush(const FlushOptions& fopts, virtual Status Flush(const FlushOptions& fopts,
const ColumnFamilyHandle& column_family) override { ColumnFamilyHandle* column_family) override {
return db_->Flush(fopts, column_family); return db_->Flush(fopts, column_family);
} }
@ -189,6 +188,10 @@ class StackableDB : public DB {
return db_->GetUpdatesSince(seq_number, iter); return db_->GetUpdatesSince(seq_number, iter);
} }
virtual ColumnFamilyHandle* DefaultColumnFamily() const override {
return db_->DefaultColumnFamily();
}
protected: protected:
DB* db_; DB* db_;
}; };

View File

@ -46,6 +46,9 @@ class FilterBlockBuilder {
bool SamePrefix(const Slice &key1, const Slice &key2) const; bool SamePrefix(const Slice &key1, const Slice &key2) const;
void GenerateFilter(); void GenerateFilter();
// important: all of these might point to invalid addresses
// at the time of destruction of this filter block. destructor
// should NOT dereference them.
const FilterPolicy* policy_; const FilterPolicy* policy_;
const SliceTransform* prefix_extractor_; const SliceTransform* prefix_extractor_;
bool whole_key_filtering_; bool whole_key_filtering_;

View File

@ -11,7 +11,6 @@
#include "db/filename.h" #include "db/filename.h"
#include "db/write_batch_internal.h" #include "db/write_batch_internal.h"
#include "rocksdb/write_batch.h" #include "rocksdb/write_batch.h"
#include "rocksdb/column_family.h"
#include "rocksdb/cache.h" #include "rocksdb/cache.h"
#include "util/coding.h" #include "util/coding.h"

View File

@ -45,8 +45,8 @@ class DummyDB : public StackableDB {
} }
using DB::GetOptions; using DB::GetOptions;
virtual const Options& GetOptions(const ColumnFamilyHandle& column_family) virtual const Options& GetOptions(ColumnFamilyHandle* column_family) const
const override { override {
return options_; return options_;
} }
@ -70,6 +70,10 @@ class DummyDB : public StackableDB {
return Status::OK(); return Status::OK();
} }
virtual ColumnFamilyHandle* DefaultColumnFamily() const override {
return nullptr;
}
class DummyLogFile : public LogFile { class DummyLogFile : public LogFile {
public: public:
/* implicit */ /* implicit */

View File

@ -120,7 +120,7 @@ Status DBWithTTL::StripTS(std::string* str) {
} }
Status DBWithTTL::Put(const WriteOptions& options, Status DBWithTTL::Put(const WriteOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& val) { const Slice& val) {
WriteBatch batch; WriteBatch batch;
batch.Put(key, val); batch.Put(key, val);
@ -128,7 +128,7 @@ Status DBWithTTL::Put(const WriteOptions& options,
} }
Status DBWithTTL::Get(const ReadOptions& options, Status DBWithTTL::Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value) { std::string* value) {
Status st = db_->Get(options, key, value); Status st = db_->Get(options, key, value);
if (!st.ok()) { if (!st.ok()) {
@ -143,7 +143,7 @@ Status DBWithTTL::Get(const ReadOptions& options,
std::vector<Status> DBWithTTL::MultiGet( std::vector<Status> DBWithTTL::MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, std::vector<std::string>* values) { const std::vector<Slice>& keys, std::vector<std::string>* values) {
return std::vector<Status>(keys.size(), return std::vector<Status>(keys.size(),
Status::NotSupported("MultiGet not\ Status::NotSupported("MultiGet not\
@ -151,9 +151,8 @@ std::vector<Status> DBWithTTL::MultiGet(
} }
bool DBWithTTL::KeyMayExist(const ReadOptions& options, bool DBWithTTL::KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value, bool* value_found) {
bool* value_found) {
bool ret = db_->KeyMayExist(options, key, value, value_found); bool ret = db_->KeyMayExist(options, key, value, value_found);
if (ret && value != nullptr && value_found != nullptr && *value_found) { if (ret && value != nullptr && value_found != nullptr && *value_found) {
if (!SanityCheckTimestamp(*value).ok() || !StripTS(value).ok()) { if (!SanityCheckTimestamp(*value).ok() || !StripTS(value).ok()) {
@ -164,8 +163,8 @@ bool DBWithTTL::KeyMayExist(const ReadOptions& options,
} }
Status DBWithTTL::Merge(const WriteOptions& options, Status DBWithTTL::Merge(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, const Slice& value) { const Slice& value) {
WriteBatch batch; WriteBatch batch;
batch.Merge(key, value); batch.Merge(key, value);
return Write(options, &batch); return Write(options, &batch);
@ -211,7 +210,7 @@ Status DBWithTTL::Write(const WriteOptions& opts, WriteBatch* updates) {
} }
Iterator* DBWithTTL::NewIterator(const ReadOptions& opts, Iterator* DBWithTTL::NewIterator(const ReadOptions& opts,
const ColumnFamilyHandle& column_family) { ColumnFamilyHandle* column_family) {
return new TtlIterator(db_->NewIterator(opts, column_family)); return new TtlIterator(db_->NewIterator(opts, column_family));
} }

View File

@ -22,38 +22,37 @@ class DBWithTTL : public StackableDB {
using StackableDB::Put; using StackableDB::Put;
virtual Status Put(const WriteOptions& options, virtual Status Put(const WriteOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& val) override; const Slice& val) override;
using StackableDB::Get; using StackableDB::Get;
virtual Status Get(const ReadOptions& options, virtual Status Get(const ReadOptions& options,
const ColumnFamilyHandle& column_family, const Slice& key, ColumnFamilyHandle* column_family, const Slice& key,
std::string* value) override; std::string* value) override;
using StackableDB::MultiGet; using StackableDB::MultiGet;
virtual std::vector<Status> MultiGet( virtual std::vector<Status> MultiGet(
const ReadOptions& options, const ReadOptions& options,
const std::vector<ColumnFamilyHandle>& column_family, const std::vector<ColumnFamilyHandle*>& column_family,
const std::vector<Slice>& keys, const std::vector<Slice>& keys,
std::vector<std::string>* values) override; std::vector<std::string>* values) override;
using StackableDB::KeyMayExist; using StackableDB::KeyMayExist;
virtual bool KeyMayExist(const ReadOptions& options, virtual bool KeyMayExist(const ReadOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, std::string* value, std::string* value,
bool* value_found = nullptr) override; bool* value_found = nullptr) override;
using StackableDB::Merge; using StackableDB::Merge;
virtual Status Merge(const WriteOptions& options, virtual Status Merge(const WriteOptions& options,
const ColumnFamilyHandle& column_family, ColumnFamilyHandle* column_family, const Slice& key,
const Slice& key, const Slice& value) override; const Slice& value) override;
virtual Status Write(const WriteOptions& opts, WriteBatch* updates) override; virtual Status Write(const WriteOptions& opts, WriteBatch* updates) override;
using StackableDB::NewIterator; using StackableDB::NewIterator;
virtual Iterator* NewIterator(const ReadOptions& opts, virtual Iterator* NewIterator(const ReadOptions& opts,
const ColumnFamilyHandle& column_family) ColumnFamilyHandle* column_family) override;
override;
// Simulate a db crash, no elegant closing of database. // Simulate a db crash, no elegant closing of database.
void TEST_Destroy_DBWithTtl(); void TEST_Destroy_DBWithTtl();