Skip to content

Commit d0de413

Browse files
committed
WriteBatchWithIndex to allow different Comparators for different column families
Summary: Previously, one single column family is given to WriteBatchWithIndex to index keys for all column families. An extra map from column family ID to comparator is maintained which can override the default comparator given in the constructor. A WriteBatchWithIndex::SetComparatorForCF() is added for user to add comparators per column family. Also move more codes into anonymous namespace. Test Plan: Add a unit test Reviewers: ljin, igor Reviewed By: igor Subscribers: dhruba, leveldb, yhchiang Differential Revision: https://reviews.facebook.net/D23355
1 parent 57a32f1 commit d0de413

File tree

6 files changed

+189
-41
lines changed

6 files changed

+189
-41
lines changed

db/column_family.cc

+13
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
8686

8787
uint32_t ColumnFamilyHandleImpl::GetID() const { return cfd()->GetID(); }
8888

89+
const Comparator* ColumnFamilyHandleImpl::user_comparator() const {
90+
return cfd()->user_comparator();
91+
}
92+
8993
ColumnFamilyOptions SanitizeOptions(const InternalKeyComparator* icmp,
9094
const ColumnFamilyOptions& src) {
9195
ColumnFamilyOptions result = src;
@@ -726,4 +730,13 @@ uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family) {
726730
return column_family_id;
727731
}
728732

733+
const Comparator* GetColumnFamilyUserComparator(
734+
ColumnFamilyHandle* column_family) {
735+
if (column_family != nullptr) {
736+
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
737+
return cfh->user_comparator();
738+
}
739+
return nullptr;
740+
}
741+
729742
} // namespace rocksdb

db/column_family.h

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class ColumnFamilyHandleImpl : public ColumnFamilyHandle {
4949
// destroy without mutex
5050
virtual ~ColumnFamilyHandleImpl();
5151
virtual ColumnFamilyData* cfd() const { return cfd_; }
52+
virtual const Comparator* user_comparator() const;
5253

5354
virtual uint32_t GetID() const;
5455

@@ -448,4 +449,7 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
448449

449450
extern uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family);
450451

452+
extern const Comparator* GetColumnFamilyUserComparator(
453+
ColumnFamilyHandle* column_family);
454+
451455
} // namespace rocksdb

db/write_batch_test.cc

+4-1
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
289289
explicit ColumnFamilyHandleImplDummy(int id)
290290
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
291291
uint32_t GetID() const override { return id_; }
292+
const Comparator* user_comparator() const override {
293+
return BytewiseComparator();
294+
}
292295

293296
private:
294297
uint32_t id_;
@@ -320,7 +323,7 @@ TEST(WriteBatchTest, ColumnFamiliesBatchTest) {
320323
}
321324

322325
TEST(WriteBatchTest, ColumnFamiliesBatchWithIndexTest) {
323-
WriteBatchWithIndex batch(BytewiseComparator(), 20);
326+
WriteBatchWithIndex batch;
324327
ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
325328
batch.Put(&zero, Slice("foo"), Slice("bar"));
326329
batch.Put(&two, Slice("twofoo"), Slice("bar2"));

include/rocksdb/utilities/write_batch_with_index.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111

1212
#pragma once
1313

14-
#include "rocksdb/status.h"
14+
#include "rocksdb/comparator.h"
1515
#include "rocksdb/slice.h"
16+
#include "rocksdb/status.h"
1617
#include "rocksdb/write_batch.h"
1718

1819
namespace rocksdb {
@@ -56,12 +57,14 @@ class WBWIIterator {
5657
// A user can call NewIterator() to create an iterator.
5758
class WriteBatchWithIndex {
5859
public:
59-
// index_comparator indicates the order when iterating data in the write
60-
// batch. Technically, it doesn't have to be the same as the one used in
61-
// the DB.
60+
// backup_index_comparator: the backup comparator used to compare keys
61+
// within the same column family, if column family is not given in the
62+
// interface, or we can't find a column family from the column family handle
63+
// passed in, backup_index_comparator will be used for the column family.
6264
// reserved_bytes: reserved bytes in underlying WriteBatch
63-
explicit WriteBatchWithIndex(const Comparator* index_comparator,
64-
size_t reserved_bytes = 0);
65+
explicit WriteBatchWithIndex(
66+
const Comparator* backup_index_comparator = BytewiseComparator(),
67+
size_t reserved_bytes = 0);
6568
virtual ~WriteBatchWithIndex();
6669

6770
WriteBatch* GetWriteBatch();

utilities/write_batch_with_index/write_batch_with_index.cc

+49-30
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class ReadableWriteBatch : public WriteBatch {
2020
Status GetEntryFromDataOffset(size_t data_offset, WriteType* type, Slice* Key,
2121
Slice* value, Slice* blob) const;
2222
};
23-
} // namespace
2423

2524
// Key used by skip list, as the binary searchable index of WriteBatchWithIndex.
2625
struct WriteBatchIndexEntry {
@@ -38,44 +37,28 @@ struct WriteBatchIndexEntry {
3837

3938
class WriteBatchEntryComparator {
4039
public:
41-
WriteBatchEntryComparator(const Comparator* comparator,
40+
WriteBatchEntryComparator(const Comparator* default_comparator,
4241
const ReadableWriteBatch* write_batch)
43-
: comparator_(comparator), write_batch_(write_batch) {}
42+
: default_comparator_(default_comparator), write_batch_(write_batch) {}
4443
// Compare a and b. Return a negative value if a is less than b, 0 if they
4544
// are equal, and a positive value if a is greater than b
4645
int operator()(const WriteBatchIndexEntry* entry1,
4746
const WriteBatchIndexEntry* entry2) const;
4847

48+
void SetComparatorForCF(uint32_t column_family_id,
49+
const Comparator* comparator) {
50+
cf_comparator_map_[column_family_id] = comparator;
51+
}
52+
4953
private:
50-
const Comparator* comparator_;
54+
const Comparator* default_comparator_;
55+
std::unordered_map<uint32_t, const Comparator*> cf_comparator_map_;
5156
const ReadableWriteBatch* write_batch_;
5257
};
5358

5459
typedef SkipList<WriteBatchIndexEntry*, const WriteBatchEntryComparator&>
5560
WriteBatchEntrySkipList;
5661

57-
struct WriteBatchWithIndex::Rep {
58-
Rep(const Comparator* index_comparator, size_t reserved_bytes = 0)
59-
: write_batch(reserved_bytes),
60-
comparator(index_comparator, &write_batch),
61-
skip_list(comparator, &arena) {}
62-
ReadableWriteBatch write_batch;
63-
WriteBatchEntryComparator comparator;
64-
Arena arena;
65-
WriteBatchEntrySkipList skip_list;
66-
67-
WriteBatchIndexEntry* GetEntry(ColumnFamilyHandle* column_family) {
68-
return GetEntryWithCfId(GetColumnFamilyID(column_family));
69-
}
70-
71-
WriteBatchIndexEntry* GetEntryWithCfId(uint32_t column_family_id) {
72-
auto* mem = arena.Allocate(sizeof(WriteBatchIndexEntry));
73-
auto* index_entry = new (mem)
74-
WriteBatchIndexEntry(write_batch.GetDataSize(), column_family_id);
75-
return index_entry;
76-
}
77-
};
78-
7962
class WBWIIteratorImpl : public WBWIIterator {
8063
public:
8164
WBWIIteratorImpl(uint32_t column_family_id,
@@ -138,6 +121,35 @@ class WBWIIteratorImpl : public WBWIIterator {
138121
}
139122
}
140123
};
124+
} // namespace
125+
126+
struct WriteBatchWithIndex::Rep {
127+
Rep(const Comparator* index_comparator, size_t reserved_bytes = 0)
128+
: write_batch(reserved_bytes),
129+
comparator(index_comparator, &write_batch),
130+
skip_list(comparator, &arena) {}
131+
ReadableWriteBatch write_batch;
132+
WriteBatchEntryComparator comparator;
133+
Arena arena;
134+
WriteBatchEntrySkipList skip_list;
135+
136+
WriteBatchIndexEntry* GetEntry(ColumnFamilyHandle* column_family) {
137+
uint32_t cf_id = GetColumnFamilyID(column_family);
138+
const auto* cf_cmp = GetColumnFamilyUserComparator(column_family);
139+
if (cf_cmp != nullptr) {
140+
comparator.SetComparatorForCF(cf_id, cf_cmp);
141+
}
142+
143+
return GetEntryWithCfId(cf_id);
144+
}
145+
146+
WriteBatchIndexEntry* GetEntryWithCfId(uint32_t column_family_id) {
147+
auto* mem = arena.Allocate(sizeof(WriteBatchIndexEntry));
148+
auto* index_entry = new (mem)
149+
WriteBatchIndexEntry(write_batch.GetDataSize(), column_family_id);
150+
return index_entry;
151+
}
152+
};
141153

142154
Status ReadableWriteBatch::GetEntryFromDataOffset(size_t data_offset,
143155
WriteType* type, Slice* Key,
@@ -179,9 +191,9 @@ Status ReadableWriteBatch::GetEntryFromDataOffset(size_t data_offset,
179191
return Status::OK();
180192
}
181193

182-
WriteBatchWithIndex::WriteBatchWithIndex(const Comparator* index_comparator,
183-
size_t reserved_bytes)
184-
: rep(new Rep(index_comparator, reserved_bytes)) {}
194+
WriteBatchWithIndex::WriteBatchWithIndex(
195+
const Comparator* default_index_comparator, size_t reserved_bytes)
196+
: rep(new Rep(default_index_comparator, reserved_bytes)) {}
185197

186198
WriteBatchWithIndex::~WriteBatchWithIndex() { delete rep; }
187199

@@ -287,7 +299,14 @@ int WriteBatchEntryComparator::operator()(
287299
key2 = *(entry2->search_key);
288300
}
289301

290-
int cmp = comparator_->Compare(key1, key2);
302+
int cmp;
303+
auto comparator_for_cf = cf_comparator_map_.find(entry1->column_family);
304+
if (comparator_for_cf != cf_comparator_map_.end()) {
305+
cmp = comparator_for_cf->second->Compare(key1, key2);
306+
} else {
307+
cmp = default_comparator_->Compare(key1, key2);
308+
}
309+
291310
if (cmp != 0) {
292311
return cmp;
293312
} else if (entry1->offset > entry2->offset) {

utilities/write_batch_with_index/write_batch_with_index_test.cc

+110-4
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ namespace rocksdb {
1919
namespace {
2020
class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
2121
public:
22-
explicit ColumnFamilyHandleImplDummy(int id)
23-
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
22+
explicit ColumnFamilyHandleImplDummy(int id, const Comparator* comparator)
23+
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr),
24+
id_(id),
25+
comparator_(comparator) {}
2426
uint32_t GetID() const override { return id_; }
27+
const Comparator* user_comparator() const override { return comparator_; }
2528

2629
private:
2730
uint32_t id_;
31+
const Comparator* comparator_;
2832
};
2933

3034
struct Entry {
@@ -90,8 +94,9 @@ TEST(WriteBatchWithIndexTest, TestValueAsSecondaryIndex) {
9094
index_map[e.value].push_back(&e);
9195
}
9296

93-
WriteBatchWithIndex batch(BytewiseComparator(), 20);
94-
ColumnFamilyHandleImplDummy data(6), index(8);
97+
WriteBatchWithIndex batch(nullptr, 20);
98+
ColumnFamilyHandleImplDummy data(6, BytewiseComparator());
99+
ColumnFamilyHandleImplDummy index(8, BytewiseComparator());
95100
for (auto& e : entries) {
96101
if (e.type == kPutRecord) {
97102
batch.Put(&data, e.key, e.value);
@@ -230,6 +235,107 @@ TEST(WriteBatchWithIndexTest, TestValueAsSecondaryIndex) {
230235
}
231236
}
232237

238+
class ReverseComparator : public Comparator {
239+
public:
240+
ReverseComparator() {}
241+
242+
virtual const char* Name() const override {
243+
return "rocksdb.ReverseComparator";
244+
}
245+
246+
virtual int Compare(const Slice& a, const Slice& b) const override {
247+
return 0 - BytewiseComparator()->Compare(a, b);
248+
}
249+
250+
virtual void FindShortestSeparator(std::string* start,
251+
const Slice& limit) const {}
252+
virtual void FindShortSuccessor(std::string* key) const {}
253+
};
254+
255+
TEST(WriteBatchWithIndexTest, TestComparatorForCF) {
256+
ReverseComparator reverse_cmp;
257+
ColumnFamilyHandleImplDummy cf1(6, nullptr);
258+
ColumnFamilyHandleImplDummy reverse_cf(66, &reverse_cmp);
259+
ColumnFamilyHandleImplDummy cf2(88, BytewiseComparator());
260+
WriteBatchWithIndex batch(BytewiseComparator(), 20);
261+
262+
batch.Put(&cf1, "ddd", "");
263+
batch.Put(&cf2, "aaa", "");
264+
batch.Put(&cf2, "eee", "");
265+
batch.Put(&cf1, "ccc", "");
266+
batch.Put(&reverse_cf, "a11", "");
267+
batch.Put(&cf1, "bbb", "");
268+
batch.Put(&reverse_cf, "a33", "");
269+
batch.Put(&reverse_cf, "a22", "");
270+
271+
{
272+
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf1));
273+
iter->Seek("");
274+
ASSERT_OK(iter->status());
275+
ASSERT_TRUE(iter->Valid());
276+
ASSERT_EQ("bbb", iter->Entry().key.ToString());
277+
iter->Next();
278+
ASSERT_OK(iter->status());
279+
ASSERT_TRUE(iter->Valid());
280+
ASSERT_EQ("ccc", iter->Entry().key.ToString());
281+
iter->Next();
282+
ASSERT_OK(iter->status());
283+
ASSERT_TRUE(iter->Valid());
284+
ASSERT_EQ("ddd", iter->Entry().key.ToString());
285+
iter->Next();
286+
ASSERT_OK(iter->status());
287+
ASSERT_TRUE(!iter->Valid());
288+
}
289+
290+
{
291+
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf2));
292+
iter->Seek("");
293+
ASSERT_OK(iter->status());
294+
ASSERT_TRUE(iter->Valid());
295+
ASSERT_EQ("aaa", iter->Entry().key.ToString());
296+
iter->Next();
297+
ASSERT_OK(iter->status());
298+
ASSERT_TRUE(iter->Valid());
299+
ASSERT_EQ("eee", iter->Entry().key.ToString());
300+
iter->Next();
301+
ASSERT_OK(iter->status());
302+
ASSERT_TRUE(!iter->Valid());
303+
}
304+
305+
{
306+
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&reverse_cf));
307+
iter->Seek("");
308+
ASSERT_OK(iter->status());
309+
ASSERT_TRUE(!iter->Valid());
310+
311+
iter->Seek("z");
312+
ASSERT_OK(iter->status());
313+
ASSERT_TRUE(iter->Valid());
314+
ASSERT_EQ("a33", iter->Entry().key.ToString());
315+
iter->Next();
316+
ASSERT_OK(iter->status());
317+
ASSERT_TRUE(iter->Valid());
318+
ASSERT_EQ("a22", iter->Entry().key.ToString());
319+
iter->Next();
320+
ASSERT_OK(iter->status());
321+
ASSERT_TRUE(iter->Valid());
322+
ASSERT_EQ("a11", iter->Entry().key.ToString());
323+
iter->Next();
324+
ASSERT_OK(iter->status());
325+
ASSERT_TRUE(!iter->Valid());
326+
327+
iter->Seek("a22");
328+
ASSERT_OK(iter->status());
329+
ASSERT_TRUE(iter->Valid());
330+
ASSERT_EQ("a22", iter->Entry().key.ToString());
331+
332+
iter->Seek("a13");
333+
ASSERT_OK(iter->status());
334+
ASSERT_TRUE(iter->Valid());
335+
ASSERT_EQ("a11", iter->Entry().key.ToString());
336+
}
337+
}
338+
233339
} // namespace
234340

235341
int main(int argc, char** argv) { return rocksdb::test::RunAllTests(); }

0 commit comments

Comments
 (0)