diff --git a/db/db_properties_test.cc b/db/db_properties_test.cc index ad1afc661..bae1963d4 100644 --- a/db/db_properties_test.cc +++ b/db/db_properties_test.cc @@ -224,7 +224,7 @@ void GetExpectedTableProperties(TableProperties* expected_tp, const int kBloomBitsPerKey, const size_t kBlockSize) { const int kKeyCount = kTableCount * kKeysPerTable; - const int kAvgSuccessorSize = kKeySize / 2; + const int kAvgSuccessorSize = kKeySize / 5; const int kEncodingSavePerKey = kKeySize / 4; expected_tp->raw_key_size = kKeyCount * (kKeySize + 8); expected_tp->raw_value_size = kKeyCount * kValueSize; diff --git a/db/dbformat_test.cc b/db/dbformat_test.cc index e79dbc683..b431690cc 100644 --- a/db/dbformat_test.cc +++ b/db/dbformat_test.cc @@ -92,6 +92,30 @@ TEST_F(FormatTest, InternalKeyShortSeparator) { Shorten(IKey("foo", 100, kTypeValue), IKey("hello", 200, kTypeValue))); + ASSERT_EQ(IKey("ABC2", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("ABC1AAAAA", 100, kTypeValue), + IKey("ABC2ABB", 200, kTypeValue))); + + ASSERT_EQ(IKey("AAA2", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("AAA1AAA", 100, kTypeValue), + IKey("AAA2AA", 200, kTypeValue))); + + ASSERT_EQ( + IKey("AAA2", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("AAA1AAA", 100, kTypeValue), IKey("AAA4", 200, kTypeValue))); + + ASSERT_EQ( + IKey("AAA1B", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("AAA1AAA", 100, kTypeValue), IKey("AAA2", 200, kTypeValue))); + + ASSERT_EQ(IKey("AAA2", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("AAA1AAA", 100, kTypeValue), + IKey("AAA2A", 200, kTypeValue))); + + ASSERT_EQ( + IKey("AAA1", 100, kTypeValue), + Shorten(IKey("AAA1", 100, kTypeValue), IKey("AAA2", 200, kTypeValue))); + // When start user key is prefix of limit user key ASSERT_EQ(IKey("foo", 100, kTypeValue), Shorten(IKey("foo", 100, kTypeValue), diff --git a/util/comparator.cc b/util/comparator.cc index cb802d55b..4a5d3641a 100644 --- a/util/comparator.cc +++ b/util/comparator.cc @@ -49,13 +49,41 @@ class BytewiseComparatorImpl : public Comparator { if (diff_index >= min_length) { // Do not shorten if one string is a prefix of the other } else { - uint8_t diff_byte = static_cast((*start)[diff_index]); - if (diff_byte < static_cast(0xff) && - diff_byte + 1 < static_cast(limit[diff_index])) { + uint8_t start_byte = static_cast((*start)[diff_index]); + uint8_t limit_byte = static_cast(limit[diff_index]); + if (start_byte >= limit_byte || (diff_index == start->size() - 1)) { + // Cannot shorten since limit is smaller than start or start is + // already the shortest possible. + return; + } + assert(start_byte < limit_byte); + + if (diff_index < limit.size() - 1 || start_byte + 1 < limit_byte) { (*start)[diff_index]++; start->resize(diff_index + 1); - assert(Compare(*start, limit) < 0); + } else { + // v + // A A 1 A A A + // A A 2 + // + // Incrementing the current byte will make start bigger than limit, we + // will skip this byte, and find the first non 0xFF byte in start and + // increment it. + diff_index++; + + while (diff_index < start->size()) { + // Keep moving until we find the first non 0xFF byte to + // increment it + if (static_cast((*start)[diff_index]) < + static_cast(0xff)) { + (*start)[diff_index]++; + start->resize(diff_index + 1); + break; + } + diff_index++; + } } + assert(Compare(*start, limit) < 0); } }