1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
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.
10 #include "db/dbformat.h"
12 #include "table/block_based/index_builder.h"
13 #include "test_util/testharness.h"
14 #include "test_util/testutil.h"
16 namespace ROCKSDB_NAMESPACE
{
18 static std::string
IKey(const std::string
& user_key
, uint64_t seq
,
21 AppendInternalKey(&encoded
, ParsedInternalKey(user_key
, seq
, vt
));
25 static std::string
Shorten(const std::string
& s
, const std::string
& l
) {
26 std::string result
= s
;
27 ShortenedIndexBuilder::FindShortestInternalKeySeparator(*BytewiseComparator(),
32 static std::string
ShortSuccessor(const std::string
& s
) {
33 std::string result
= s
;
34 ShortenedIndexBuilder::FindShortInternalKeySuccessor(*BytewiseComparator(),
39 static void TestKey(const std::string
& key
, uint64_t seq
, ValueType vt
) {
40 std::string encoded
= IKey(key
, seq
, vt
);
43 ParsedInternalKey
decoded("", 0, kTypeValue
);
45 ASSERT_OK(ParseInternalKey(in
, &decoded
, true /* log_err_key */));
46 ASSERT_EQ(key
, decoded
.user_key
.ToString());
47 ASSERT_EQ(seq
, decoded
.sequence
);
48 ASSERT_EQ(vt
, decoded
.type
);
50 ASSERT_NOK(ParseInternalKey(Slice("bar"), &decoded
, true /* log_err_key */));
53 class FormatTest
: public testing::Test
{};
55 TEST_F(FormatTest
, InternalKey_EncodeDecode
) {
56 const char* keys
[] = {"", "k", "hello", "longggggggggggggggggggggg"};
57 const uint64_t seq
[] = {1,
69 for (unsigned int k
= 0; k
< sizeof(keys
) / sizeof(keys
[0]); k
++) {
70 for (unsigned int s
= 0; s
< sizeof(seq
) / sizeof(seq
[0]); s
++) {
71 TestKey(keys
[k
], seq
[s
], kTypeValue
);
72 TestKey("hello", 1, kTypeDeletion
);
77 TEST_F(FormatTest
, InternalKeyShortSeparator
) {
78 // When user keys are same
79 ASSERT_EQ(IKey("foo", 100, kTypeValue
),
80 Shorten(IKey("foo", 100, kTypeValue
), IKey("foo", 99, kTypeValue
)));
82 IKey("foo", 100, kTypeValue
),
83 Shorten(IKey("foo", 100, kTypeValue
), IKey("foo", 101, kTypeValue
)));
85 IKey("foo", 100, kTypeValue
),
86 Shorten(IKey("foo", 100, kTypeValue
), IKey("foo", 100, kTypeValue
)));
88 IKey("foo", 100, kTypeValue
),
89 Shorten(IKey("foo", 100, kTypeValue
), IKey("foo", 100, kTypeDeletion
)));
91 // When user keys are misordered
92 ASSERT_EQ(IKey("foo", 100, kTypeValue
),
93 Shorten(IKey("foo", 100, kTypeValue
), IKey("bar", 99, kTypeValue
)));
95 // When user keys are different, but correctly ordered
97 IKey("g", kMaxSequenceNumber
, kValueTypeForSeek
),
98 Shorten(IKey("foo", 100, kTypeValue
), IKey("hello", 200, kTypeValue
)));
100 ASSERT_EQ(IKey("ABC2", kMaxSequenceNumber
, kValueTypeForSeek
),
101 Shorten(IKey("ABC1AAAAA", 100, kTypeValue
),
102 IKey("ABC2ABB", 200, kTypeValue
)));
104 ASSERT_EQ(IKey("AAA2", kMaxSequenceNumber
, kValueTypeForSeek
),
105 Shorten(IKey("AAA1AAA", 100, kTypeValue
),
106 IKey("AAA2AA", 200, kTypeValue
)));
109 IKey("AAA2", kMaxSequenceNumber
, kValueTypeForSeek
),
110 Shorten(IKey("AAA1AAA", 100, kTypeValue
), IKey("AAA4", 200, kTypeValue
)));
113 IKey("AAA1B", kMaxSequenceNumber
, kValueTypeForSeek
),
114 Shorten(IKey("AAA1AAA", 100, kTypeValue
), IKey("AAA2", 200, kTypeValue
)));
116 ASSERT_EQ(IKey("AAA2", kMaxSequenceNumber
, kValueTypeForSeek
),
117 Shorten(IKey("AAA1AAA", 100, kTypeValue
),
118 IKey("AAA2A", 200, kTypeValue
)));
121 IKey("AAA1", 100, kTypeValue
),
122 Shorten(IKey("AAA1", 100, kTypeValue
), IKey("AAA2", 200, kTypeValue
)));
124 // When start user key is prefix of limit user key
126 IKey("foo", 100, kTypeValue
),
127 Shorten(IKey("foo", 100, kTypeValue
), IKey("foobar", 200, kTypeValue
)));
129 // When limit user key is prefix of start user key
131 IKey("foobar", 100, kTypeValue
),
132 Shorten(IKey("foobar", 100, kTypeValue
), IKey("foo", 200, kTypeValue
)));
135 TEST_F(FormatTest
, InternalKeyShortestSuccessor
) {
136 ASSERT_EQ(IKey("g", kMaxSequenceNumber
, kValueTypeForSeek
),
137 ShortSuccessor(IKey("foo", 100, kTypeValue
)));
138 ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue
),
139 ShortSuccessor(IKey("\xff\xff", 100, kTypeValue
)));
142 TEST_F(FormatTest
, IterKeyOperation
) {
144 const char p
[] = "abcdefghijklmnopqrstuvwxyz";
145 const char q
[] = "0123456789";
147 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
150 k
.TrimAppend(0, p
, 3);
151 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
154 k
.TrimAppend(1, p
, 3);
155 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
156 std::string("aabc"));
158 k
.TrimAppend(0, p
, 26);
159 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
160 std::string("abcdefghijklmnopqrstuvwxyz"));
162 k
.TrimAppend(26, q
, 10);
163 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
164 std::string("abcdefghijklmnopqrstuvwxyz0123456789"));
166 k
.TrimAppend(36, q
, 1);
167 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
168 std::string("abcdefghijklmnopqrstuvwxyz01234567890"));
170 k
.TrimAppend(26, q
, 1);
171 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
172 std::string("abcdefghijklmnopqrstuvwxyz0"));
174 // Size going up, memory allocation is triggered
175 k
.TrimAppend(27, p
, 26);
176 ASSERT_EQ(std::string(k
.GetUserKey().data(), k
.GetUserKey().size()),
177 std::string("abcdefghijklmnopqrstuvwxyz0"
178 "abcdefghijklmnopqrstuvwxyz"));
181 TEST_F(FormatTest
, UpdateInternalKey
) {
182 std::string
user_key("abcdefghijklmnopqrstuvwxyz");
183 uint64_t new_seq
= 0x123456;
184 ValueType new_val_type
= kTypeDeletion
;
187 AppendInternalKey(&ikey
, ParsedInternalKey(user_key
, 100U, kTypeValue
));
188 size_t ikey_size
= ikey
.size();
189 UpdateInternalKey(&ikey
, new_seq
, new_val_type
);
190 ASSERT_EQ(ikey_size
, ikey
.size());
193 ParsedInternalKey decoded
;
194 ASSERT_OK(ParseInternalKey(in
, &decoded
, true /* log_err_key */));
195 ASSERT_EQ(user_key
, decoded
.user_key
.ToString());
196 ASSERT_EQ(new_seq
, decoded
.sequence
);
197 ASSERT_EQ(new_val_type
, decoded
.type
);
200 TEST_F(FormatTest
, RangeTombstoneSerializeEndKey
) {
201 RangeTombstone
t("a", "b", 2);
202 InternalKey
k("b", 3, kTypeValue
);
203 const InternalKeyComparator
cmp(BytewiseComparator());
204 ASSERT_LT(cmp
.Compare(t
.SerializeEndKey(), k
), 0);
207 } // namespace ROCKSDB_NAMESPACE
209 int main(int argc
, char** argv
) {
210 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
211 ::testing::InitGoogleTest(&argc
, argv
);
212 RegisterCustomObjects(argc
, argv
);
213 return RUN_ALL_TESTS();