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