Skip to content

Commit 7c5e583

Browse files
committed
ColumnFamilySet
Summary: I created a separate class ColumnFamilySet to keep track of column families. Before we did this in VersionSet and I believe this approach is cleaner. Let me know if you have any comments. I will commit tomorrow. Test Plan: make check Reviewers: dhruba, haobo, kailiu, sdong CC: leveldb Differential Revision: https://reviews.facebook.net/D15357
1 parent f9a25dd commit 7c5e583

10 files changed

+410
-192
lines changed

db/column_family.cc

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include "db/column_family.h"
2+
#include "db/version_set.h"
3+
4+
namespace rocksdb {
5+
6+
ColumnFamilyData::ColumnFamilyData(uint32_t id, const std::string& name,
7+
Version* dummy_versions,
8+
const ColumnFamilyOptions& options)
9+
: id(id),
10+
name(name),
11+
dummy_versions(dummy_versions),
12+
current(nullptr),
13+
options(options) {}
14+
15+
ColumnFamilyData::~ColumnFamilyData() {
16+
// List must be empty
17+
assert(dummy_versions->next_ == dummy_versions);
18+
delete dummy_versions;
19+
}
20+
21+
ColumnFamilySet::ColumnFamilySet() : max_column_family_(0) {}
22+
23+
ColumnFamilySet::~ColumnFamilySet() {
24+
for (auto& cfd : column_family_data_) {
25+
delete cfd.second;
26+
}
27+
for (auto& cfd : droppped_column_families_) {
28+
delete cfd;
29+
}
30+
}
31+
32+
ColumnFamilyData* ColumnFamilySet::GetDefault() const {
33+
auto ret = GetColumnFamily(0);
34+
assert(ret != nullptr); // default column family should always exist
35+
return ret;
36+
}
37+
38+
ColumnFamilyData* ColumnFamilySet::GetColumnFamily(uint32_t id) const {
39+
auto cfd_iter = column_family_data_.find(id);
40+
if (cfd_iter != column_family_data_.end()) {
41+
return cfd_iter->second;
42+
} else {
43+
return nullptr;
44+
}
45+
}
46+
47+
bool ColumnFamilySet::Exists(uint32_t id) {
48+
return column_family_data_.find(id) != column_family_data_.end();
49+
}
50+
51+
bool ColumnFamilySet::Exists(const std::string& name) {
52+
return column_families_.find(name) != column_families_.end();
53+
}
54+
55+
uint32_t ColumnFamilySet::GetID(const std::string& name) {
56+
auto cfd_iter = column_families_.find(name);
57+
assert(cfd_iter != column_families_.end());
58+
return cfd_iter->second;
59+
}
60+
61+
uint32_t ColumnFamilySet::GetNextColumnFamilyID() {
62+
return ++max_column_family_;
63+
}
64+
65+
ColumnFamilyData* ColumnFamilySet::CreateColumnFamily(
66+
const std::string& name, uint32_t id, Version* dummy_versions,
67+
const ColumnFamilyOptions& options) {
68+
assert(column_families_.find(name) == column_families_.end());
69+
column_families_.insert({name, id});
70+
ColumnFamilyData* new_cfd =
71+
new ColumnFamilyData(id, name, dummy_versions, options);
72+
column_family_data_.insert({id, new_cfd});
73+
max_column_family_ = std::max(max_column_family_, id);
74+
return new_cfd;
75+
}
76+
77+
void ColumnFamilySet::DropColumnFamily(uint32_t id) {
78+
auto cfd = column_family_data_.find(id);
79+
assert(cfd != column_family_data_.end());
80+
column_families_.erase(cfd->second->name);
81+
cfd->second->current->Unref();
82+
droppped_column_families_.push_back(cfd->second);
83+
column_family_data_.erase(cfd);
84+
}
85+
86+
} // namespace rocksdb

db/column_family.h

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
2+
// This source code is licensed under the BSD-style license found in the
3+
// LICENSE file in the root directory of this source tree. An additional grant
4+
// of patent rights can be found in the PATENTS file in the same directory.
5+
//
6+
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7+
// Use of this source code is governed by a BSD-style license that can be
8+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9+
10+
#pragma once
11+
12+
#include "rocksdb/options.h"
13+
14+
#include <map>
15+
#include <string>
16+
#include <vector>
17+
18+
namespace rocksdb {
19+
20+
class Version;
21+
class VersionSet;
22+
23+
// column family metadata
24+
struct ColumnFamilyData {
25+
uint32_t id;
26+
std::string name;
27+
Version* dummy_versions; // Head of circular doubly-linked list of versions.
28+
Version* current; // == dummy_versions->prev_
29+
ColumnFamilyOptions options;
30+
31+
ColumnFamilyData(uint32_t id, const std::string& name,
32+
Version* dummy_versions, const ColumnFamilyOptions& options);
33+
~ColumnFamilyData();
34+
};
35+
36+
class ColumnFamilySet {
37+
public:
38+
class iterator {
39+
public:
40+
explicit iterator(
41+
std::unordered_map<uint32_t, ColumnFamilyData*>::iterator itr)
42+
: itr_(itr) {}
43+
iterator& operator++() {
44+
++itr_;
45+
return *this;
46+
}
47+
bool operator!=(const iterator& other) { return this->itr_ != other.itr_; }
48+
ColumnFamilyData* operator*() { return itr_->second; }
49+
private:
50+
std::unordered_map<uint32_t, ColumnFamilyData*>::iterator itr_;
51+
};
52+
53+
ColumnFamilySet();
54+
~ColumnFamilySet();
55+
56+
ColumnFamilyData* GetDefault() const;
57+
// GetColumnFamily() calls return nullptr if column family is not found
58+
ColumnFamilyData* GetColumnFamily(uint32_t id) const;
59+
bool Exists(uint32_t id);
60+
bool Exists(const std::string& name);
61+
uint32_t GetID(const std::string& name);
62+
// this call will return the next available column family ID. it guarantees
63+
// that there is no column family with id greater than or equal to the
64+
// returned value in the current running instance. It does not, however,
65+
// guarantee that the returned ID is unique accross RocksDB restarts.
66+
// For example, if a client adds a column family 6 and then drops it,
67+
// after a restart, we might reuse column family 6 ID.
68+
uint32_t GetNextColumnFamilyID();
69+
70+
ColumnFamilyData* CreateColumnFamily(const std::string& name, uint32_t id,
71+
Version* dummy_version,
72+
const ColumnFamilyOptions& options);
73+
void DropColumnFamily(uint32_t id);
74+
75+
iterator begin() { return iterator(column_family_data_.begin()); }
76+
iterator end() { return iterator(column_family_data_.end()); }
77+
78+
private:
79+
std::unordered_map<std::string, uint32_t> column_families_;
80+
std::unordered_map<uint32_t, ColumnFamilyData*> column_family_data_;
81+
// we need to keep them alive because we still can't control the lifetime of
82+
// all of column family data members (options for example)
83+
std::vector<ColumnFamilyData*> droppped_column_families_;
84+
uint32_t max_column_family_;
85+
};
86+
87+
} // namespace rocksdb

db/column_family_test.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ TEST(ColumnFamilyTest, AddDrop) {
6969
Close();
7070

7171
vector<string> families;
72-
DB::ListColumnFamilies(db_options_, dbname_, &families);
72+
ASSERT_OK(DB::ListColumnFamilies(db_options_, dbname_, &families));
7373
sort(families.begin(), families.end());
7474
ASSERT_TRUE(families == vector<string>({"default", "four", "one", "three"}));
7575
}

db/db_impl.cc

+19-45
Original file line numberDiff line numberDiff line change
@@ -913,21 +913,8 @@ Status DBImpl::Recover(
913913
}
914914
}
915915

916-
Status s = versions_->Recover();
916+
Status s = versions_->Recover(column_families);
917917
if (s.ok()) {
918-
if (column_families.size() != versions_->column_families_.size()) {
919-
return Status::InvalidArgument("Column family specifications mismatch");
920-
}
921-
for (auto cf : column_families) {
922-
auto cf_iter = versions_->column_families_.find(cf.name);
923-
if (cf_iter == versions_->column_families_.end()) {
924-
return Status::InvalidArgument("Column family specifications mismatch");
925-
}
926-
auto cf_data_iter = versions_->column_family_data_.find(cf_iter->second);
927-
assert(cf_data_iter != versions_->column_family_data_.end());
928-
cf_data_iter->second->options = cf.options;
929-
}
930-
931918
SequenceNumber max_sequence(0);
932919

933920
// Recover from all newer log files than the ones named in the
@@ -2933,11 +2920,13 @@ std::vector<Status> DBImpl::MultiGet(
29332920
Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& options,
29342921
const std::string& column_family_name,
29352922
ColumnFamilyHandle* handle) {
2923+
if (!versions_->GetColumnFamilySet()->Exists(column_family_name)) {
2924+
return Status::InvalidArgument("Column family already exists");
2925+
}
29362926
VersionEdit edit;
29372927
edit.AddColumnFamily(column_family_name);
29382928
MutexLock l(&mutex_);
2939-
++versions_->max_column_family_;
2940-
handle->id = versions_->max_column_family_;
2929+
handle->id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID();
29412930
edit.SetColumnFamily(handle->id);
29422931
Status s = versions_->LogAndApply(&edit, &mutex_);
29432932
if (s.ok()) {
@@ -2948,21 +2937,16 @@ Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& options,
29482937
}
29492938

29502939
Status DBImpl::DropColumnFamily(const ColumnFamilyHandle& column_family) {
2951-
// TODO this is not good. implement some sort of refcounting
2952-
// column family data and only delete when refcount goes to 0
2953-
// We don't want to delete column family if there is a compaction going on,
2954-
// or if there are some outstanding iterators
29552940
if (column_family.id == 0) {
29562941
return Status::InvalidArgument("Can't drop default column family");
29572942
}
2958-
VersionEdit edit;
2959-
edit.DropColumnFamily();
2960-
edit.SetColumnFamily(column_family.id);
29612943
MutexLock l(&mutex_);
2962-
auto data_iter = versions_->column_family_data_.find(column_family.id);
2963-
if (data_iter == versions_->column_family_data_.end()) {
2944+
if (!versions_->GetColumnFamilySet()->Exists(column_family.id)) {
29642945
return Status::NotFound("Column family not found");
29652946
}
2947+
VersionEdit edit;
2948+
edit.DropColumnFamily();
2949+
edit.SetColumnFamily(column_family.id);
29662950
Status s = versions_->LogAndApply(&edit, &mutex_);
29672951
if (s.ok()) {
29682952
// remove from internal data structures
@@ -3968,10 +3952,16 @@ Status DB::OpenWithColumnFamilies(
39683952
// set column family handles
39693953
handles->clear();
39703954
for (auto cf : column_families) {
3971-
auto cf_iter = impl->versions_->column_families_.find(cf.name);
3972-
assert(cf_iter != impl->versions_->column_families_.end());
3973-
handles->push_back(ColumnFamilyHandle(cf_iter->second));
3955+
if (!impl->versions_->GetColumnFamilySet()->Exists(cf.name)) {
3956+
s = Status::InvalidArgument("Column family not found: ", cf.name);
3957+
handles->clear();
3958+
break;
3959+
}
3960+
uint32_t id = impl->versions_->GetColumnFamilySet()->GetID(cf.name);
3961+
handles->push_back(ColumnFamilyHandle(id));
39743962
}
3963+
}
3964+
if (s.ok()) {
39753965
delete impl->InstallSuperVersion(new DBImpl::SuperVersion());
39763966
impl->mem_->SetLogNumber(impl->logfile_number_);
39773967
impl->DeleteObsoleteFiles();
@@ -4006,23 +3996,7 @@ Status DB::OpenWithColumnFamilies(
40063996
Status DB::ListColumnFamilies(const DBOptions& db_options,
40073997
const std::string& name,
40083998
std::vector<std::string>* column_families) {
4009-
Options options(db_options, ColumnFamilyOptions());
4010-
InternalKeyComparator* icmp = new InternalKeyComparator(options.comparator);
4011-
TableCache* table_cache = new TableCache(name, &options, EnvOptions(options),
4012-
db_options.max_open_files - 10);
4013-
VersionSet* version_set =
4014-
new VersionSet(name, &options, EnvOptions(options), table_cache, icmp);
4015-
4016-
version_set->Recover();
4017-
column_families->clear();
4018-
for (auto cf : version_set->column_families_) {
4019-
column_families->push_back(cf.first);
4020-
}
4021-
4022-
delete version_set;
4023-
delete table_cache;
4024-
delete icmp;
4025-
return Status::NotSupported("Working on it");
3999+
return VersionSet::ListColumnFamilies(column_families, name, db_options.env);
40264000
}
40274001

40284002
Snapshot::~Snapshot() {

db/db_test.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -5035,7 +5035,9 @@ void BM_LogAndApply(int iters, int num_base_files) {
50355035
Options options;
50365036
EnvOptions sopt;
50375037
VersionSet vset(dbname, &options, sopt, nullptr, &cmp);
5038-
ASSERT_OK(vset.Recover());
5038+
std::vector<ColumnFamilyDescriptor> dummy;
5039+
dummy.push_back(ColumnFamilyDescriptor());
5040+
ASSERT_OK(vset.Recover(dummy));
50395041
VersionEdit vbase;
50405042
uint64_t fnum = 1;
50415043
for (int i = 0; i < num_base_files; i++) {

0 commit comments

Comments
 (0)