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