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).
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 #include "db/version_edit.h"
11 #include "test_util/sync_point.h"
12 #include "test_util/testharness.h"
13 #include "util/coding.h"
14
15 namespace ROCKSDB_NAMESPACE {
16
TestEncodeDecode(const VersionEdit & edit)17 static void TestEncodeDecode(const VersionEdit& edit) {
18 std::string encoded, encoded2;
19 edit.EncodeTo(&encoded);
20 VersionEdit parsed;
21 Status s = parsed.DecodeFrom(encoded);
22 ASSERT_TRUE(s.ok()) << s.ToString();
23 parsed.EncodeTo(&encoded2);
24 ASSERT_EQ(encoded, encoded2);
25 }
26
27 class VersionEditTest : public testing::Test {};
28
TEST_F(VersionEditTest,EncodeDecode)29 TEST_F(VersionEditTest, EncodeDecode) {
30 static const uint64_t kBig = 1ull << 50;
31 static const uint32_t kBig32Bit = 1ull << 30;
32
33 VersionEdit edit;
34 for (int i = 0; i < 4; i++) {
35 TestEncodeDecode(edit);
36 edit.AddFile(3, kBig + 300 + i, kBig32Bit + 400 + i, 0,
37 InternalKey("foo", kBig + 500 + i, kTypeValue),
38 InternalKey("zoo", kBig + 600 + i, kTypeDeletion),
39 kBig + 500 + i, kBig + 600 + i, false, kInvalidBlobFileNumber,
40 888, 678, "234", "crc32c");
41 edit.DeleteFile(4, kBig + 700 + i);
42 }
43
44 edit.SetComparatorName("foo");
45 edit.SetLogNumber(kBig + 100);
46 edit.SetNextFile(kBig + 200);
47 edit.SetLastSequence(kBig + 1000);
48 TestEncodeDecode(edit);
49 }
50
TEST_F(VersionEditTest,EncodeDecodeNewFile4)51 TEST_F(VersionEditTest, EncodeDecodeNewFile4) {
52 static const uint64_t kBig = 1ull << 50;
53
54 VersionEdit edit;
55 edit.AddFile(3, 300, 3, 100, InternalKey("foo", kBig + 500, kTypeValue),
56 InternalKey("zoo", kBig + 600, kTypeDeletion), kBig + 500,
57 kBig + 600, true, kInvalidBlobFileNumber,
58 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
59 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
60 edit.AddFile(4, 301, 3, 100, InternalKey("foo", kBig + 501, kTypeValue),
61 InternalKey("zoo", kBig + 601, kTypeDeletion), kBig + 501,
62 kBig + 601, false, kInvalidBlobFileNumber,
63 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
64 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
65 edit.AddFile(5, 302, 0, 100, InternalKey("foo", kBig + 502, kTypeValue),
66 InternalKey("zoo", kBig + 602, kTypeDeletion), kBig + 502,
67 kBig + 602, true, kInvalidBlobFileNumber, 666, 888,
68 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
69 edit.AddFile(5, 303, 0, 100, InternalKey("foo", kBig + 503, kTypeBlobIndex),
70 InternalKey("zoo", kBig + 603, kTypeBlobIndex), kBig + 503,
71 kBig + 603, true, 1001, kUnknownOldestAncesterTime,
72 kUnknownFileCreationTime, kUnknownFileChecksum,
73 kUnknownFileChecksumFuncName);
74 ;
75
76 edit.DeleteFile(4, 700);
77
78 edit.SetComparatorName("foo");
79 edit.SetLogNumber(kBig + 100);
80 edit.SetNextFile(kBig + 200);
81 edit.SetLastSequence(kBig + 1000);
82 TestEncodeDecode(edit);
83
84 std::string encoded, encoded2;
85 edit.EncodeTo(&encoded);
86 VersionEdit parsed;
87 Status s = parsed.DecodeFrom(encoded);
88 ASSERT_TRUE(s.ok()) << s.ToString();
89 auto& new_files = parsed.GetNewFiles();
90 ASSERT_TRUE(new_files[0].second.marked_for_compaction);
91 ASSERT_TRUE(!new_files[1].second.marked_for_compaction);
92 ASSERT_TRUE(new_files[2].second.marked_for_compaction);
93 ASSERT_TRUE(new_files[3].second.marked_for_compaction);
94 ASSERT_EQ(3u, new_files[0].second.fd.GetPathId());
95 ASSERT_EQ(3u, new_files[1].second.fd.GetPathId());
96 ASSERT_EQ(0u, new_files[2].second.fd.GetPathId());
97 ASSERT_EQ(0u, new_files[3].second.fd.GetPathId());
98 ASSERT_EQ(kInvalidBlobFileNumber,
99 new_files[0].second.oldest_blob_file_number);
100 ASSERT_EQ(kInvalidBlobFileNumber,
101 new_files[1].second.oldest_blob_file_number);
102 ASSERT_EQ(kInvalidBlobFileNumber,
103 new_files[2].second.oldest_blob_file_number);
104 ASSERT_EQ(1001, new_files[3].second.oldest_blob_file_number);
105 }
106
TEST_F(VersionEditTest,ForwardCompatibleNewFile4)107 TEST_F(VersionEditTest, ForwardCompatibleNewFile4) {
108 static const uint64_t kBig = 1ull << 50;
109 VersionEdit edit;
110 edit.AddFile(3, 300, 3, 100, InternalKey("foo", kBig + 500, kTypeValue),
111 InternalKey("zoo", kBig + 600, kTypeDeletion), kBig + 500,
112 kBig + 600, true, kInvalidBlobFileNumber,
113 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
114 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
115 edit.AddFile(4, 301, 3, 100, InternalKey("foo", kBig + 501, kTypeValue),
116 InternalKey("zoo", kBig + 601, kTypeDeletion), kBig + 501,
117 kBig + 601, false, kInvalidBlobFileNumber, 686, 868, "234",
118 "crc32c");
119 edit.DeleteFile(4, 700);
120
121 edit.SetComparatorName("foo");
122 edit.SetLogNumber(kBig + 100);
123 edit.SetNextFile(kBig + 200);
124 edit.SetLastSequence(kBig + 1000);
125
126 std::string encoded;
127
128 // Call back function to add extra customized builds.
129 bool first = true;
130 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
131 "VersionEdit::EncodeTo:NewFile4:CustomizeFields", [&](void* arg) {
132 std::string* str = reinterpret_cast<std::string*>(arg);
133 PutVarint32(str, 33);
134 const std::string str1 = "random_string";
135 PutLengthPrefixedSlice(str, str1);
136 if (first) {
137 first = false;
138 PutVarint32(str, 22);
139 const std::string str2 = "s";
140 PutLengthPrefixedSlice(str, str2);
141 }
142 });
143 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
144 edit.EncodeTo(&encoded);
145 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
146
147 VersionEdit parsed;
148 Status s = parsed.DecodeFrom(encoded);
149 ASSERT_TRUE(s.ok()) << s.ToString();
150 ASSERT_TRUE(!first);
151 auto& new_files = parsed.GetNewFiles();
152 ASSERT_TRUE(new_files[0].second.marked_for_compaction);
153 ASSERT_TRUE(!new_files[1].second.marked_for_compaction);
154 ASSERT_EQ(3u, new_files[0].second.fd.GetPathId());
155 ASSERT_EQ(3u, new_files[1].second.fd.GetPathId());
156 ASSERT_EQ(1u, parsed.GetDeletedFiles().size());
157 }
158
TEST_F(VersionEditTest,NewFile4NotSupportedField)159 TEST_F(VersionEditTest, NewFile4NotSupportedField) {
160 static const uint64_t kBig = 1ull << 50;
161 VersionEdit edit;
162 edit.AddFile(3, 300, 3, 100, InternalKey("foo", kBig + 500, kTypeValue),
163 InternalKey("zoo", kBig + 600, kTypeDeletion), kBig + 500,
164 kBig + 600, true, kInvalidBlobFileNumber,
165 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
166 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
167
168 edit.SetComparatorName("foo");
169 edit.SetLogNumber(kBig + 100);
170 edit.SetNextFile(kBig + 200);
171 edit.SetLastSequence(kBig + 1000);
172
173 std::string encoded;
174
175 // Call back function to add extra customized builds.
176 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
177 "VersionEdit::EncodeTo:NewFile4:CustomizeFields", [&](void* arg) {
178 std::string* str = reinterpret_cast<std::string*>(arg);
179 const std::string str1 = "s";
180 PutLengthPrefixedSlice(str, str1);
181 });
182 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
183 edit.EncodeTo(&encoded);
184 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
185
186 VersionEdit parsed;
187 Status s = parsed.DecodeFrom(encoded);
188 ASSERT_NOK(s);
189 }
190
TEST_F(VersionEditTest,EncodeEmptyFile)191 TEST_F(VersionEditTest, EncodeEmptyFile) {
192 VersionEdit edit;
193 edit.AddFile(0, 0, 0, 0, InternalKey(), InternalKey(), 0, 0, false,
194 kInvalidBlobFileNumber, kUnknownOldestAncesterTime,
195 kUnknownFileCreationTime, kUnknownFileChecksum,
196 kUnknownFileChecksumFuncName);
197 std::string buffer;
198 ASSERT_TRUE(!edit.EncodeTo(&buffer));
199 }
200
TEST_F(VersionEditTest,ColumnFamilyTest)201 TEST_F(VersionEditTest, ColumnFamilyTest) {
202 VersionEdit edit;
203 edit.SetColumnFamily(2);
204 edit.AddColumnFamily("column_family");
205 edit.SetMaxColumnFamily(5);
206 TestEncodeDecode(edit);
207
208 edit.Clear();
209 edit.SetColumnFamily(3);
210 edit.DropColumnFamily();
211 TestEncodeDecode(edit);
212 }
213
TEST_F(VersionEditTest,MinLogNumberToKeep)214 TEST_F(VersionEditTest, MinLogNumberToKeep) {
215 VersionEdit edit;
216 edit.SetMinLogNumberToKeep(13);
217 TestEncodeDecode(edit);
218
219 edit.Clear();
220 edit.SetMinLogNumberToKeep(23);
221 TestEncodeDecode(edit);
222 }
223
TEST_F(VersionEditTest,AtomicGroupTest)224 TEST_F(VersionEditTest, AtomicGroupTest) {
225 VersionEdit edit;
226 edit.MarkAtomicGroup(1);
227 TestEncodeDecode(edit);
228 }
229
TEST_F(VersionEditTest,IgnorableField)230 TEST_F(VersionEditTest, IgnorableField) {
231 VersionEdit ve;
232 std::string encoded;
233
234 // Size of ignorable field is too large
235 PutVarint32Varint64(&encoded, 2 /* kLogNumber */, 66);
236 // This is a customized ignorable tag
237 PutVarint32Varint64(&encoded,
238 0x2710 /* A field with kTagSafeIgnoreMask set */,
239 5 /* fieldlength 5 */);
240 encoded += "abc"; // Only fills 3 bytes,
241 ASSERT_NOK(ve.DecodeFrom(encoded));
242
243 encoded.clear();
244 // Error when seeing unidentified tag that is not ignorable
245 PutVarint32Varint64(&encoded, 2 /* kLogNumber */, 66);
246 // This is a customized ignorable tag
247 PutVarint32Varint64(&encoded, 666 /* A field with kTagSafeIgnoreMask unset */,
248 3 /* fieldlength 3 */);
249 encoded += "abc"; // Fill 3 bytes
250 PutVarint32Varint64(&encoded, 3 /* next file number */, 88);
251 ASSERT_NOK(ve.DecodeFrom(encoded));
252
253 // Safely ignore an identified but safely ignorable entry
254 encoded.clear();
255 PutVarint32Varint64(&encoded, 2 /* kLogNumber */, 66);
256 // This is a customized ignorable tag
257 PutVarint32Varint64(&encoded,
258 0x2710 /* A field with kTagSafeIgnoreMask set */,
259 3 /* fieldlength 3 */);
260 encoded += "abc"; // Fill 3 bytes
261 PutVarint32Varint64(&encoded, 3 /* kNextFileNumber */, 88);
262
263 ASSERT_OK(ve.DecodeFrom(encoded));
264
265 ASSERT_TRUE(ve.HasLogNumber());
266 ASSERT_TRUE(ve.HasNextFile());
267 ASSERT_EQ(66, ve.GetLogNumber());
268 ASSERT_EQ(88, ve.GetNextFile());
269 }
270
TEST_F(VersionEditTest,DbId)271 TEST_F(VersionEditTest, DbId) {
272 VersionEdit edit;
273 edit.SetDBId("ab34-cd12-435f-er00");
274 TestEncodeDecode(edit);
275
276 edit.Clear();
277 edit.SetDBId("34ba-cd12-435f-er01");
278 TestEncodeDecode(edit);
279 }
280
281 } // namespace ROCKSDB_NAMESPACE
282
main(int argc,char ** argv)283 int main(int argc, char** argv) {
284 ::testing::InitGoogleTest(&argc, argv);
285 return RUN_ALL_TESTS();
286 }
287