Skip to content

Commit

Permalink
Fix user comparator receiving internal key (facebook#4575)
Browse files Browse the repository at this point in the history
Summary:
There was a bug that the user comparator would receive the internal key instead of the user key. The bug was due to RangeMightExistAfterSortedRun expecting user key but receiving internal key when called in GenerateBottommostFiles. The patch augment an existing unit test to reproduce the bug and fixes it.
Pull Request resolved: facebook#4575

Differential Revision: D10500434

Pulled By: maysamyabandeh

fbshipit-source-id: 858346d2fd102cce9e20516d77338c112bdfe366
  • Loading branch information
ajkr committed Feb 28, 2019
1 parent b238986 commit 2ebfe52
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 11 deletions.
32 changes: 28 additions & 4 deletions db/db_compaction_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2953,6 +2953,12 @@ TEST_F(DBCompactionTest, SuggestCompactRangeNoTwoLevel0Compactions) {
dbfull()->TEST_WaitForCompact();
}

static std::string ShortKey(int i) {
assert(i < 10000);
char buf[100];
snprintf(buf, sizeof(buf), "key%04d", i);
return std::string(buf);
}

TEST_P(DBCompactionTestWithParam, ForceBottommostLevelCompaction) {
int32_t trivial_move = 0;
Expand All @@ -2965,10 +2971,28 @@ TEST_P(DBCompactionTestWithParam, ForceBottommostLevelCompaction) {
[&](void* /*arg*/) { non_trivial_move++; });
rocksdb::SyncPoint::GetInstance()->EnableProcessing();

// The key size is guaranteed to be <= 8
class ShortKeyComparator : public Comparator {
int Compare(const rocksdb::Slice& a,
const rocksdb::Slice& b) const override {
assert(a.size() <= 8);
assert(b.size() <= 8);
return BytewiseComparator()->Compare(a, b);
}
const char* Name() const override { return "ShortKeyComparator"; }
void FindShortestSeparator(std::string* start,
const rocksdb::Slice& limit) const override {
return BytewiseComparator()->FindShortestSeparator(start, limit);
}
void FindShortSuccessor(std::string* key) const override {
return BytewiseComparator()->FindShortSuccessor(key);
}
} short_key_cmp;
Options options = CurrentOptions();
options.target_file_size_base = 100000000;
options.write_buffer_size = 100000000;
options.max_subcompactions = max_subcompactions_;
options.comparator = &short_key_cmp;
DestroyAndReopen(options);

int32_t value_size = 10 * 1024; // 10 KB
Expand All @@ -2978,7 +3002,7 @@ TEST_P(DBCompactionTestWithParam, ForceBottommostLevelCompaction) {
// File with keys [ 0 => 99 ]
for (int i = 0; i < 100; i++) {
values.push_back(RandomString(&rnd, value_size));
ASSERT_OK(Put(Key(i), values[i]));
ASSERT_OK(Put(ShortKey(i), values[i]));
}
ASSERT_OK(Flush());

Expand All @@ -2995,7 +3019,7 @@ TEST_P(DBCompactionTestWithParam, ForceBottommostLevelCompaction) {
// File with keys [ 100 => 199 ]
for (int i = 100; i < 200; i++) {
values.push_back(RandomString(&rnd, value_size));
ASSERT_OK(Put(Key(i), values[i]));
ASSERT_OK(Put(ShortKey(i), values[i]));
}
ASSERT_OK(Flush());

Expand All @@ -3013,7 +3037,7 @@ TEST_P(DBCompactionTestWithParam, ForceBottommostLevelCompaction) {
// File with keys [ 200 => 299 ]
for (int i = 200; i < 300; i++) {
values.push_back(RandomString(&rnd, value_size));
ASSERT_OK(Put(Key(i), values[i]));
ASSERT_OK(Put(ShortKey(i), values[i]));
}
ASSERT_OK(Flush());

Expand All @@ -3031,7 +3055,7 @@ TEST_P(DBCompactionTestWithParam, ForceBottommostLevelCompaction) {
ASSERT_EQ(non_trivial_move, 0);

for (int i = 0; i < 300; i++) {
ASSERT_EQ(Get(Key(i)), values[i]);
ASSERT_EQ(Get(ShortKey(i)), values[i]);
}

rocksdb::SyncPoint::GetInstance()->DisableProcessing();
Expand Down
10 changes: 6 additions & 4 deletions db/version_set.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1996,7 +1996,9 @@ void VersionStorageInfo::GenerateBottommostFiles() {
} else {
l0_file_idx = -1;
}
if (!RangeMightExistAfterSortedRun(f.smallest_key, f.largest_key,
Slice smallest_user_key = ExtractUserKey(f.smallest_key);
Slice largest_user_key = ExtractUserKey(f.largest_key);
if (!RangeMightExistAfterSortedRun(smallest_user_key, largest_user_key,
static_cast<int>(level),
l0_file_idx)) {
bottommost_files_.emplace_back(static_cast<int>(level),
Expand Down Expand Up @@ -2630,8 +2632,8 @@ uint64_t VersionStorageInfo::EstimateLiveDataSize() const {
}

bool VersionStorageInfo::RangeMightExistAfterSortedRun(
const Slice& smallest_key, const Slice& largest_key, int last_level,
int last_l0_idx) {
const Slice& smallest_user_key, const Slice& largest_user_key,
int last_level, int last_l0_idx) {
assert((last_l0_idx != -1) == (last_level == 0));
// TODO(ajkr): this preserves earlier behavior where we considered an L0 file
// bottommost only if it's the oldest L0 file and there are no files on older
Expand All @@ -2653,7 +2655,7 @@ bool VersionStorageInfo::RangeMightExistAfterSortedRun(
// which overlap with [`smallest_key`, `largest_key`].
if (files_[level].size() > 0 &&
(last_level == 0 ||
OverlapInLevel(level, &smallest_key, &largest_key))) {
OverlapInLevel(level, &smallest_user_key, &largest_user_key))) {
return true;
}
}
Expand Down
6 changes: 3 additions & 3 deletions db/version_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,9 @@ class VersionStorageInfo {
// @param last_level Level after which we check for overlap
// @param last_l0_idx If `last_level == 0`, index of L0 file after which we
// check for overlap; otherwise, must be -1
bool RangeMightExistAfterSortedRun(const Slice& smallest_key,
const Slice& largest_key, int last_level,
int last_l0_idx);
bool RangeMightExistAfterSortedRun(const Slice& smallest_user_key,
const Slice& largest_user_key,
int last_level, int last_l0_idx);

private:
const InternalKeyComparator* internal_comparator_;
Expand Down

0 comments on commit 2ebfe52

Please sign in to comment.