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/version_set.h"
11 #include "db/log_writer.h"
12 #include "table/mock_table.h"
13 #include "util/logging.h"
14 #include "util/string_util.h"
15 #include "util/testharness.h"
16 #include "util/testutil.h"
20 class GenerateLevelFilesBriefTest
: public testing::Test
{
22 std::vector
<FileMetaData
*> files_
;
23 LevelFilesBrief file_level_
;
26 GenerateLevelFilesBriefTest() { }
28 ~GenerateLevelFilesBriefTest() override
{
29 for (size_t i
= 0; i
< files_
.size(); i
++) {
34 void Add(const char* smallest
, const char* largest
,
35 SequenceNumber smallest_seq
= 100,
36 SequenceNumber largest_seq
= 100) {
37 FileMetaData
* f
= new FileMetaData
;
38 f
->fd
= FileDescriptor(files_
.size() + 1, 0, 0);
39 f
->smallest
= InternalKey(smallest
, smallest_seq
, kTypeValue
);
40 f
->largest
= InternalKey(largest
, largest_seq
, kTypeValue
);
46 for (size_t i
= 0; i
< files_
.size(); i
++) {
47 if (file_level_
.files
[i
].fd
.GetNumber() != files_
[i
]->fd
.GetNumber()) {
55 TEST_F(GenerateLevelFilesBriefTest
, Empty
) {
56 DoGenerateLevelFilesBrief(&file_level_
, files_
, &arena_
);
57 ASSERT_EQ(0u, file_level_
.num_files
);
58 ASSERT_EQ(0, Compare());
61 TEST_F(GenerateLevelFilesBriefTest
, Single
) {
63 DoGenerateLevelFilesBrief(&file_level_
, files_
, &arena_
);
64 ASSERT_EQ(1u, file_level_
.num_files
);
65 ASSERT_EQ(0, Compare());
68 TEST_F(GenerateLevelFilesBriefTest
, Multiple
) {
73 DoGenerateLevelFilesBrief(&file_level_
, files_
, &arena_
);
74 ASSERT_EQ(4u, file_level_
.num_files
);
75 ASSERT_EQ(0, Compare());
78 class CountingLogger
: public Logger
{
80 CountingLogger() : log_count(0) {}
82 void Logv(const char* /*format*/, va_list /*ap*/) override
{ log_count
++; }
86 Options
GetOptionsWithNumLevels(int num_levels
,
87 std::shared_ptr
<CountingLogger
> logger
) {
89 opt
.num_levels
= num_levels
;
90 opt
.info_log
= logger
;
94 class VersionStorageInfoTest
: public testing::Test
{
96 const Comparator
* ucmp_
;
97 InternalKeyComparator icmp_
;
98 std::shared_ptr
<CountingLogger
> logger_
;
100 ImmutableCFOptions ioptions_
;
101 MutableCFOptions mutable_cf_options_
;
102 VersionStorageInfo vstorage_
;
104 InternalKey
GetInternalKey(const char* ukey
,
105 SequenceNumber smallest_seq
= 100) {
106 return InternalKey(ukey
, smallest_seq
, kTypeValue
);
109 VersionStorageInfoTest()
110 : ucmp_(BytewiseComparator()),
112 logger_(new CountingLogger()),
113 options_(GetOptionsWithNumLevels(6, logger_
)),
115 mutable_cf_options_(options_
),
116 vstorage_(&icmp_
, ucmp_
, 6, kCompactionStyleLevel
, nullptr, false) {}
118 ~VersionStorageInfoTest() override
{
119 for (int i
= 0; i
< vstorage_
.num_levels(); i
++) {
120 for (auto* f
: vstorage_
.LevelFiles(i
)) {
121 if (--f
->refs
== 0) {
128 void Add(int level
, uint32_t file_number
, const char* smallest
,
129 const char* largest
, uint64_t file_size
= 0) {
130 assert(level
< vstorage_
.num_levels());
131 FileMetaData
* f
= new FileMetaData
;
132 f
->fd
= FileDescriptor(file_number
, 0, file_size
);
133 f
->smallest
= GetInternalKey(smallest
, 0);
134 f
->largest
= GetInternalKey(largest
, 0);
135 f
->compensated_file_size
= file_size
;
138 f
->num_deletions
= 0;
139 vstorage_
.AddFile(level
, f
);
142 void Add(int level
, uint32_t file_number
, const InternalKey
& smallest
,
143 const InternalKey
& largest
, uint64_t file_size
= 0) {
144 assert(level
< vstorage_
.num_levels());
145 FileMetaData
* f
= new FileMetaData
;
146 f
->fd
= FileDescriptor(file_number
, 0, file_size
);
147 f
->smallest
= smallest
;
148 f
->largest
= largest
;
149 f
->compensated_file_size
= file_size
;
152 f
->num_deletions
= 0;
153 vstorage_
.AddFile(level
, f
);
156 std::string
GetOverlappingFiles(int level
, const InternalKey
& begin
,
157 const InternalKey
& end
) {
158 std::vector
<FileMetaData
*> inputs
;
159 vstorage_
.GetOverlappingInputs(level
, &begin
, &end
, &inputs
);
162 for (size_t i
= 0; i
< inputs
.size(); ++i
) {
166 AppendNumberTo(&result
, inputs
[i
]->fd
.GetNumber());
172 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelStatic
) {
173 ioptions_
.level_compaction_dynamic_level_bytes
= false;
174 mutable_cf_options_
.max_bytes_for_level_base
= 10;
175 mutable_cf_options_
.max_bytes_for_level_multiplier
= 5;
176 Add(4, 100U, "1", "2");
177 Add(5, 101U, "1", "2");
179 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
180 ASSERT_EQ(vstorage_
.MaxBytesForLevel(1), 10U);
181 ASSERT_EQ(vstorage_
.MaxBytesForLevel(2), 50U);
182 ASSERT_EQ(vstorage_
.MaxBytesForLevel(3), 250U);
183 ASSERT_EQ(vstorage_
.MaxBytesForLevel(4), 1250U);
185 ASSERT_EQ(0, logger_
->log_count
);
188 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelDynamic
) {
189 ioptions_
.level_compaction_dynamic_level_bytes
= true;
190 mutable_cf_options_
.max_bytes_for_level_base
= 1000;
191 mutable_cf_options_
.max_bytes_for_level_multiplier
= 5;
192 Add(5, 1U, "1", "2", 500U);
194 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
195 ASSERT_EQ(0, logger_
->log_count
);
196 ASSERT_EQ(vstorage_
.base_level(), 5);
198 Add(5, 2U, "3", "4", 550U);
199 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
200 ASSERT_EQ(0, logger_
->log_count
);
201 ASSERT_EQ(vstorage_
.MaxBytesForLevel(4), 1000U);
202 ASSERT_EQ(vstorage_
.base_level(), 4);
204 Add(4, 3U, "3", "4", 550U);
205 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
206 ASSERT_EQ(0, logger_
->log_count
);
207 ASSERT_EQ(vstorage_
.MaxBytesForLevel(4), 1000U);
208 ASSERT_EQ(vstorage_
.base_level(), 4);
210 Add(3, 4U, "3", "4", 250U);
211 Add(3, 5U, "5", "7", 300U);
212 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
213 ASSERT_EQ(1, logger_
->log_count
);
214 ASSERT_EQ(vstorage_
.MaxBytesForLevel(4), 1005U);
215 ASSERT_EQ(vstorage_
.MaxBytesForLevel(3), 1000U);
216 ASSERT_EQ(vstorage_
.base_level(), 3);
218 Add(1, 6U, "3", "4", 5U);
219 Add(1, 7U, "8", "9", 5U);
220 logger_
->log_count
= 0;
221 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
222 ASSERT_EQ(1, logger_
->log_count
);
223 ASSERT_GT(vstorage_
.MaxBytesForLevel(4), 1005U);
224 ASSERT_GT(vstorage_
.MaxBytesForLevel(3), 1005U);
225 ASSERT_EQ(vstorage_
.MaxBytesForLevel(2), 1005U);
226 ASSERT_EQ(vstorage_
.MaxBytesForLevel(1), 1000U);
227 ASSERT_EQ(vstorage_
.base_level(), 1);
230 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelDynamicLotsOfData
) {
231 ioptions_
.level_compaction_dynamic_level_bytes
= true;
232 mutable_cf_options_
.max_bytes_for_level_base
= 100;
233 mutable_cf_options_
.max_bytes_for_level_multiplier
= 2;
234 Add(0, 1U, "1", "2", 50U);
235 Add(1, 2U, "1", "2", 50U);
236 Add(2, 3U, "1", "2", 500U);
237 Add(3, 4U, "1", "2", 500U);
238 Add(4, 5U, "1", "2", 1700U);
239 Add(5, 6U, "1", "2", 500U);
241 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
242 ASSERT_EQ(vstorage_
.MaxBytesForLevel(4), 800U);
243 ASSERT_EQ(vstorage_
.MaxBytesForLevel(3), 400U);
244 ASSERT_EQ(vstorage_
.MaxBytesForLevel(2), 200U);
245 ASSERT_EQ(vstorage_
.MaxBytesForLevel(1), 100U);
246 ASSERT_EQ(vstorage_
.base_level(), 1);
247 ASSERT_EQ(0, logger_
->log_count
);
250 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelDynamicLargeLevel
) {
251 uint64_t kOneGB
= 1000U * 1000U * 1000U;
252 ioptions_
.level_compaction_dynamic_level_bytes
= true;
253 mutable_cf_options_
.max_bytes_for_level_base
= 10U * kOneGB
;
254 mutable_cf_options_
.max_bytes_for_level_multiplier
= 10;
255 Add(0, 1U, "1", "2", 50U);
256 Add(3, 4U, "1", "2", 32U * kOneGB
);
257 Add(4, 5U, "1", "2", 500U * kOneGB
);
258 Add(5, 6U, "1", "2", 3000U * kOneGB
);
260 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
261 ASSERT_EQ(vstorage_
.MaxBytesForLevel(5), 3000U * kOneGB
);
262 ASSERT_EQ(vstorage_
.MaxBytesForLevel(4), 300U * kOneGB
);
263 ASSERT_EQ(vstorage_
.MaxBytesForLevel(3), 30U * kOneGB
);
264 ASSERT_EQ(vstorage_
.MaxBytesForLevel(2), 10U * kOneGB
);
265 ASSERT_EQ(vstorage_
.base_level(), 2);
266 ASSERT_EQ(0, logger_
->log_count
);
269 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelDynamicWithLargeL0_1
) {
270 ioptions_
.level_compaction_dynamic_level_bytes
= true;
271 mutable_cf_options_
.max_bytes_for_level_base
= 40000;
272 mutable_cf_options_
.max_bytes_for_level_multiplier
= 5;
273 mutable_cf_options_
.level0_file_num_compaction_trigger
= 2;
275 Add(0, 1U, "1", "2", 10000U);
276 Add(0, 2U, "1", "2", 10000U);
277 Add(0, 3U, "1", "2", 10000U);
279 Add(5, 4U, "1", "2", 1286250U);
280 Add(4, 5U, "1", "2", 200000U);
281 Add(3, 6U, "1", "2", 40000U);
282 Add(2, 7U, "1", "2", 8000U);
284 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
285 ASSERT_EQ(0, logger_
->log_count
);
286 ASSERT_EQ(2, vstorage_
.base_level());
287 // level multiplier should be 3.5
288 ASSERT_EQ(vstorage_
.level_multiplier(), 5.0);
289 // Level size should be around 30,000, 105,000, 367,500
290 ASSERT_EQ(40000U, vstorage_
.MaxBytesForLevel(2));
291 ASSERT_EQ(51450U, vstorage_
.MaxBytesForLevel(3));
292 ASSERT_EQ(257250U, vstorage_
.MaxBytesForLevel(4));
295 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelDynamicWithLargeL0_2
) {
296 ioptions_
.level_compaction_dynamic_level_bytes
= true;
297 mutable_cf_options_
.max_bytes_for_level_base
= 10000;
298 mutable_cf_options_
.max_bytes_for_level_multiplier
= 5;
299 mutable_cf_options_
.level0_file_num_compaction_trigger
= 2;
301 Add(0, 11U, "1", "2", 10000U);
302 Add(0, 12U, "1", "2", 10000U);
303 Add(0, 13U, "1", "2", 10000U);
305 Add(5, 4U, "1", "2", 1286250U);
306 Add(4, 5U, "1", "2", 200000U);
307 Add(3, 6U, "1", "2", 40000U);
308 Add(2, 7U, "1", "2", 8000U);
310 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
311 ASSERT_EQ(0, logger_
->log_count
);
312 ASSERT_EQ(2, vstorage_
.base_level());
313 // level multiplier should be 3.5
314 ASSERT_LT(vstorage_
.level_multiplier(), 3.6);
315 ASSERT_GT(vstorage_
.level_multiplier(), 3.4);
316 // Level size should be around 30,000, 105,000, 367,500
317 ASSERT_EQ(30000U, vstorage_
.MaxBytesForLevel(2));
318 ASSERT_LT(vstorage_
.MaxBytesForLevel(3), 110000U);
319 ASSERT_GT(vstorage_
.MaxBytesForLevel(3), 100000U);
320 ASSERT_LT(vstorage_
.MaxBytesForLevel(4), 370000U);
321 ASSERT_GT(vstorage_
.MaxBytesForLevel(4), 360000U);
324 TEST_F(VersionStorageInfoTest
, MaxBytesForLevelDynamicWithLargeL0_3
) {
325 ioptions_
.level_compaction_dynamic_level_bytes
= true;
326 mutable_cf_options_
.max_bytes_for_level_base
= 10000;
327 mutable_cf_options_
.max_bytes_for_level_multiplier
= 5;
328 mutable_cf_options_
.level0_file_num_compaction_trigger
= 2;
330 Add(0, 11U, "1", "2", 5000U);
331 Add(0, 12U, "1", "2", 5000U);
332 Add(0, 13U, "1", "2", 5000U);
333 Add(0, 14U, "1", "2", 5000U);
334 Add(0, 15U, "1", "2", 5000U);
335 Add(0, 16U, "1", "2", 5000U);
337 Add(5, 4U, "1", "2", 1286250U);
338 Add(4, 5U, "1", "2", 200000U);
339 Add(3, 6U, "1", "2", 40000U);
340 Add(2, 7U, "1", "2", 8000U);
342 vstorage_
.CalculateBaseBytes(ioptions_
, mutable_cf_options_
);
343 ASSERT_EQ(0, logger_
->log_count
);
344 ASSERT_EQ(2, vstorage_
.base_level());
345 // level multiplier should be 3.5
346 ASSERT_LT(vstorage_
.level_multiplier(), 3.6);
347 ASSERT_GT(vstorage_
.level_multiplier(), 3.4);
348 // Level size should be around 30,000, 105,000, 367,500
349 ASSERT_EQ(30000U, vstorage_
.MaxBytesForLevel(2));
350 ASSERT_LT(vstorage_
.MaxBytesForLevel(3), 110000U);
351 ASSERT_GT(vstorage_
.MaxBytesForLevel(3), 100000U);
352 ASSERT_LT(vstorage_
.MaxBytesForLevel(4), 370000U);
353 ASSERT_GT(vstorage_
.MaxBytesForLevel(4), 360000U);
356 TEST_F(VersionStorageInfoTest
, EstimateLiveDataSize
) {
357 // Test whether the overlaps are detected as expected
358 Add(1, 1U, "4", "7", 1U); // Perfect overlap with last level
359 Add(2, 2U, "3", "5", 1U); // Partial overlap with last level
360 Add(2, 3U, "6", "8", 1U); // Partial overlap with last level
361 Add(3, 4U, "1", "9", 1U); // Contains range of last level
362 Add(4, 5U, "4", "5", 1U); // Inside range of last level
363 Add(4, 5U, "6", "7", 1U); // Inside range of last level
364 Add(5, 6U, "4", "7", 10U);
365 ASSERT_EQ(10U, vstorage_
.EstimateLiveDataSize());
368 TEST_F(VersionStorageInfoTest
, EstimateLiveDataSize2
) {
369 Add(0, 1U, "9", "9", 1U); // Level 0 is not ordered
370 Add(0, 1U, "5", "6", 1U); // Ignored because of [5,6] in l1
371 Add(1, 1U, "1", "2", 1U); // Ignored because of [2,3] in l2
372 Add(1, 2U, "3", "4", 1U); // Ignored because of [2,3] in l2
373 Add(1, 3U, "5", "6", 1U);
374 Add(2, 4U, "2", "3", 1U);
375 Add(3, 5U, "7", "8", 1U);
376 ASSERT_EQ(4U, vstorage_
.EstimateLiveDataSize());
379 TEST_F(VersionStorageInfoTest
, GetOverlappingInputs
) {
380 // Two files that overlap at the range deletion tombstone sentinel.
381 Add(1, 1U, {"a", 0, kTypeValue
}, {"b", kMaxSequenceNumber
, kTypeRangeDeletion
}, 1);
382 Add(1, 2U, {"b", 0, kTypeValue
}, {"c", 0, kTypeValue
}, 1);
383 // Two files that overlap at the same user key.
384 Add(1, 3U, {"d", 0, kTypeValue
}, {"e", kMaxSequenceNumber
, kTypeValue
}, 1);
385 Add(1, 4U, {"e", 0, kTypeValue
}, {"f", 0, kTypeValue
}, 1);
386 // Two files that do not overlap.
387 Add(1, 5U, {"g", 0, kTypeValue
}, {"h", 0, kTypeValue
}, 1);
388 Add(1, 6U, {"i", 0, kTypeValue
}, {"j", 0, kTypeValue
}, 1);
389 vstorage_
.UpdateNumNonEmptyLevels();
390 vstorage_
.GenerateLevelFilesBrief();
392 ASSERT_EQ("1,2", GetOverlappingFiles(
393 1, {"a", 0, kTypeValue
}, {"b", 0, kTypeValue
}));
394 ASSERT_EQ("1", GetOverlappingFiles(
395 1, {"a", 0, kTypeValue
}, {"b", kMaxSequenceNumber
, kTypeRangeDeletion
}));
396 ASSERT_EQ("2", GetOverlappingFiles(
397 1, {"b", kMaxSequenceNumber
, kTypeValue
}, {"c", 0, kTypeValue
}));
398 ASSERT_EQ("3,4", GetOverlappingFiles(
399 1, {"d", 0, kTypeValue
}, {"e", 0, kTypeValue
}));
400 ASSERT_EQ("3", GetOverlappingFiles(
401 1, {"d", 0, kTypeValue
}, {"e", kMaxSequenceNumber
, kTypeRangeDeletion
}));
402 ASSERT_EQ("3,4", GetOverlappingFiles(
403 1, {"e", kMaxSequenceNumber
, kTypeValue
}, {"f", 0, kTypeValue
}));
404 ASSERT_EQ("3,4", GetOverlappingFiles(
405 1, {"e", 0, kTypeValue
}, {"f", 0, kTypeValue
}));
406 ASSERT_EQ("5", GetOverlappingFiles(
407 1, {"g", 0, kTypeValue
}, {"h", 0, kTypeValue
}));
408 ASSERT_EQ("6", GetOverlappingFiles(
409 1, {"i", 0, kTypeValue
}, {"j", 0, kTypeValue
}));
413 class FindLevelFileTest
: public testing::Test
{
415 LevelFilesBrief file_level_
;
416 bool disjoint_sorted_files_
;
419 FindLevelFileTest() : disjoint_sorted_files_(true) { }
421 ~FindLevelFileTest() override
{}
423 void LevelFileInit(size_t num
= 0) {
424 char* mem
= arena_
.AllocateAligned(num
* sizeof(FdWithKeyRange
));
425 file_level_
.files
= new (mem
)FdWithKeyRange
[num
];
426 file_level_
.num_files
= 0;
429 void Add(const char* smallest
, const char* largest
,
430 SequenceNumber smallest_seq
= 100,
431 SequenceNumber largest_seq
= 100) {
432 InternalKey smallest_key
= InternalKey(smallest
, smallest_seq
, kTypeValue
);
433 InternalKey largest_key
= InternalKey(largest
, largest_seq
, kTypeValue
);
435 Slice smallest_slice
= smallest_key
.Encode();
436 Slice largest_slice
= largest_key
.Encode();
438 char* mem
= arena_
.AllocateAligned(
439 smallest_slice
.size() + largest_slice
.size());
440 memcpy(mem
, smallest_slice
.data(), smallest_slice
.size());
441 memcpy(mem
+ smallest_slice
.size(), largest_slice
.data(),
442 largest_slice
.size());
444 // add to file_level_
445 size_t num
= file_level_
.num_files
;
446 auto& file
= file_level_
.files
[num
];
447 file
.fd
= FileDescriptor(num
+ 1, 0, 0);
448 file
.smallest_key
= Slice(mem
, smallest_slice
.size());
449 file
.largest_key
= Slice(mem
+ smallest_slice
.size(),
450 largest_slice
.size());
451 file_level_
.num_files
++;
454 int Find(const char* key
) {
455 InternalKey
target(key
, 100, kTypeValue
);
456 InternalKeyComparator
cmp(BytewiseComparator());
457 return FindFile(cmp
, file_level_
, target
.Encode());
460 bool Overlaps(const char* smallest
, const char* largest
) {
461 InternalKeyComparator
cmp(BytewiseComparator());
462 Slice
s(smallest
!= nullptr ? smallest
: "");
463 Slice
l(largest
!= nullptr ? largest
: "");
464 return SomeFileOverlapsRange(cmp
, disjoint_sorted_files_
, file_level_
,
465 (smallest
!= nullptr ? &s
: nullptr),
466 (largest
!= nullptr ? &l
: nullptr));
470 TEST_F(FindLevelFileTest
, LevelEmpty
) {
473 ASSERT_EQ(0, Find("foo"));
474 ASSERT_TRUE(! Overlaps("a", "z"));
475 ASSERT_TRUE(! Overlaps(nullptr, "z"));
476 ASSERT_TRUE(! Overlaps("a", nullptr));
477 ASSERT_TRUE(! Overlaps(nullptr, nullptr));
480 TEST_F(FindLevelFileTest
, LevelSingle
) {
484 ASSERT_EQ(0, Find("a"));
485 ASSERT_EQ(0, Find("p"));
486 ASSERT_EQ(0, Find("p1"));
487 ASSERT_EQ(0, Find("q"));
488 ASSERT_EQ(1, Find("q1"));
489 ASSERT_EQ(1, Find("z"));
491 ASSERT_TRUE(! Overlaps("a", "b"));
492 ASSERT_TRUE(! Overlaps("z1", "z2"));
493 ASSERT_TRUE(Overlaps("a", "p"));
494 ASSERT_TRUE(Overlaps("a", "q"));
495 ASSERT_TRUE(Overlaps("a", "z"));
496 ASSERT_TRUE(Overlaps("p", "p1"));
497 ASSERT_TRUE(Overlaps("p", "q"));
498 ASSERT_TRUE(Overlaps("p", "z"));
499 ASSERT_TRUE(Overlaps("p1", "p2"));
500 ASSERT_TRUE(Overlaps("p1", "z"));
501 ASSERT_TRUE(Overlaps("q", "q"));
502 ASSERT_TRUE(Overlaps("q", "q1"));
504 ASSERT_TRUE(! Overlaps(nullptr, "j"));
505 ASSERT_TRUE(! Overlaps("r", nullptr));
506 ASSERT_TRUE(Overlaps(nullptr, "p"));
507 ASSERT_TRUE(Overlaps(nullptr, "p1"));
508 ASSERT_TRUE(Overlaps("q", nullptr));
509 ASSERT_TRUE(Overlaps(nullptr, nullptr));
512 TEST_F(FindLevelFileTest
, LevelMultiple
) {
519 ASSERT_EQ(0, Find("100"));
520 ASSERT_EQ(0, Find("150"));
521 ASSERT_EQ(0, Find("151"));
522 ASSERT_EQ(0, Find("199"));
523 ASSERT_EQ(0, Find("200"));
524 ASSERT_EQ(1, Find("201"));
525 ASSERT_EQ(1, Find("249"));
526 ASSERT_EQ(1, Find("250"));
527 ASSERT_EQ(2, Find("251"));
528 ASSERT_EQ(2, Find("299"));
529 ASSERT_EQ(2, Find("300"));
530 ASSERT_EQ(2, Find("349"));
531 ASSERT_EQ(2, Find("350"));
532 ASSERT_EQ(3, Find("351"));
533 ASSERT_EQ(3, Find("400"));
534 ASSERT_EQ(3, Find("450"));
535 ASSERT_EQ(4, Find("451"));
537 ASSERT_TRUE(! Overlaps("100", "149"));
538 ASSERT_TRUE(! Overlaps("251", "299"));
539 ASSERT_TRUE(! Overlaps("451", "500"));
540 ASSERT_TRUE(! Overlaps("351", "399"));
542 ASSERT_TRUE(Overlaps("100", "150"));
543 ASSERT_TRUE(Overlaps("100", "200"));
544 ASSERT_TRUE(Overlaps("100", "300"));
545 ASSERT_TRUE(Overlaps("100", "400"));
546 ASSERT_TRUE(Overlaps("100", "500"));
547 ASSERT_TRUE(Overlaps("375", "400"));
548 ASSERT_TRUE(Overlaps("450", "450"));
549 ASSERT_TRUE(Overlaps("450", "500"));
552 TEST_F(FindLevelFileTest
, LevelMultipleNullBoundaries
) {
559 ASSERT_TRUE(! Overlaps(nullptr, "149"));
560 ASSERT_TRUE(! Overlaps("451", nullptr));
561 ASSERT_TRUE(Overlaps(nullptr, nullptr));
562 ASSERT_TRUE(Overlaps(nullptr, "150"));
563 ASSERT_TRUE(Overlaps(nullptr, "199"));
564 ASSERT_TRUE(Overlaps(nullptr, "200"));
565 ASSERT_TRUE(Overlaps(nullptr, "201"));
566 ASSERT_TRUE(Overlaps(nullptr, "400"));
567 ASSERT_TRUE(Overlaps(nullptr, "800"));
568 ASSERT_TRUE(Overlaps("100", nullptr));
569 ASSERT_TRUE(Overlaps("200", nullptr));
570 ASSERT_TRUE(Overlaps("449", nullptr));
571 ASSERT_TRUE(Overlaps("450", nullptr));
574 TEST_F(FindLevelFileTest
, LevelOverlapSequenceChecks
) {
577 Add("200", "200", 5000, 3000);
578 ASSERT_TRUE(! Overlaps("199", "199"));
579 ASSERT_TRUE(! Overlaps("201", "300"));
580 ASSERT_TRUE(Overlaps("200", "200"));
581 ASSERT_TRUE(Overlaps("190", "200"));
582 ASSERT_TRUE(Overlaps("200", "210"));
585 TEST_F(FindLevelFileTest
, LevelOverlappingFiles
) {
590 disjoint_sorted_files_
= false;
591 ASSERT_TRUE(! Overlaps("100", "149"));
592 ASSERT_TRUE(! Overlaps("601", "700"));
593 ASSERT_TRUE(Overlaps("100", "150"));
594 ASSERT_TRUE(Overlaps("100", "200"));
595 ASSERT_TRUE(Overlaps("100", "300"));
596 ASSERT_TRUE(Overlaps("100", "400"));
597 ASSERT_TRUE(Overlaps("100", "500"));
598 ASSERT_TRUE(Overlaps("375", "400"));
599 ASSERT_TRUE(Overlaps("450", "450"));
600 ASSERT_TRUE(Overlaps("450", "500"));
601 ASSERT_TRUE(Overlaps("450", "700"));
602 ASSERT_TRUE(Overlaps("600", "700"));
605 class VersionSetTestBase
{
607 const static std::string kColumnFamilyName1
;
608 const static std::string kColumnFamilyName2
;
609 const static std::string kColumnFamilyName3
;
612 : env_(Env::Default()),
613 dbname_(test::PerThreadDBPath("version_set_test")),
615 mutable_cf_options_(cf_options_
),
616 table_cache_(NewLRUCache(50000, 16)),
617 write_buffer_manager_(db_options_
.db_write_buffer_size
),
618 versions_(new VersionSet(dbname_
, &db_options_
, env_options_
,
619 table_cache_
.get(), &write_buffer_manager_
,
620 &write_controller_
)),
621 shutting_down_(false),
622 mock_table_factory_(std::make_shared
<mock::MockTableFactory
>()) {
623 EXPECT_OK(env_
->CreateDirIfMissing(dbname_
));
624 db_options_
.db_paths
.emplace_back(dbname_
,
625 std::numeric_limits
<uint64_t>::max());
628 void PrepareManifest(std::vector
<ColumnFamilyDescriptor
>* column_families
,
629 SequenceNumber
* last_seqno
,
630 std::unique_ptr
<log::Writer
>* log_writer
) {
631 assert(column_families
!= nullptr);
632 assert(last_seqno
!= nullptr);
633 assert(log_writer
!= nullptr);
635 new_db
.SetLogNumber(0);
636 new_db
.SetNextFile(2);
637 new_db
.SetLastSequence(0);
639 const std::vector
<std::string
> cf_names
= {
640 kDefaultColumnFamilyName
, kColumnFamilyName1
, kColumnFamilyName2
,
642 const int kInitialNumOfCfs
= static_cast<int>(cf_names
.size());
643 autovector
<VersionEdit
> new_cfs
;
644 uint64_t last_seq
= 1;
646 for (int i
= 1; i
!= kInitialNumOfCfs
; ++i
) {
648 new_cf
.AddColumnFamily(cf_names
[i
]);
649 new_cf
.SetColumnFamily(cf_id
++);
650 new_cf
.SetLogNumber(0);
651 new_cf
.SetNextFile(2);
652 new_cf
.SetLastSequence(last_seq
++);
653 new_cfs
.emplace_back(new_cf
);
655 *last_seqno
= last_seq
;
657 const std::string manifest
= DescriptorFileName(dbname_
, 1);
658 std::unique_ptr
<WritableFile
> file
;
659 Status s
= env_
->NewWritableFile(
660 manifest
, &file
, env_
->OptimizeForManifestWrite(env_options_
));
662 std::unique_ptr
<WritableFileWriter
> file_writer(
663 new WritableFileWriter(std::move(file
), manifest
, env_options_
));
665 log_writer
->reset(new log::Writer(std::move(file_writer
), 0, false));
667 new_db
.EncodeTo(&record
);
668 s
= (*log_writer
)->AddRecord(record
);
669 for (const auto& e
: new_cfs
) {
672 s
= (*log_writer
)->AddRecord(record
);
678 cf_options_
.table_factory
= mock_table_factory_
;
679 for (const auto& cf_name
: cf_names
) {
680 column_families
->emplace_back(cf_name
, cf_options_
);
684 // Create DB with 3 column families.
686 std::vector
<ColumnFamilyDescriptor
> column_families
;
687 SequenceNumber last_seqno
;
688 std::unique_ptr
<log::Writer
> log_writer
;
690 PrepareManifest(&column_families
, &last_seqno
, &log_writer
);
692 // Make "CURRENT" file point to the new manifest file.
693 Status s
= SetCurrentFile(env_
, dbname_
, 1, nullptr);
696 EXPECT_OK(versions_
->Recover(column_families
, false));
697 EXPECT_EQ(column_families
.size(),
698 versions_
->GetColumnFamilySet()->NumberOfColumnFamilies());
702 const std::string dbname_
;
703 EnvOptions env_options_
;
704 ImmutableDBOptions db_options_
;
705 ColumnFamilyOptions cf_options_
;
706 MutableCFOptions mutable_cf_options_
;
707 std::shared_ptr
<Cache
> table_cache_
;
708 WriteController write_controller_
;
709 WriteBufferManager write_buffer_manager_
;
710 std::shared_ptr
<VersionSet
> versions_
;
711 InstrumentedMutex mutex_
;
712 std::atomic
<bool> shutting_down_
;
713 std::shared_ptr
<mock::MockTableFactory
> mock_table_factory_
;
716 const std::string
VersionSetTestBase::kColumnFamilyName1
= "alice";
717 const std::string
VersionSetTestBase::kColumnFamilyName2
= "bob";
718 const std::string
VersionSetTestBase::kColumnFamilyName3
= "charles";
720 class VersionSetTest
: public VersionSetTestBase
, public testing::Test
{
722 VersionSetTest() : VersionSetTestBase() {}
725 TEST_F(VersionSetTest
, SameColumnFamilyGroupCommit
) {
727 const int kGroupSize
= 5;
728 autovector
<VersionEdit
> edits
;
729 for (int i
= 0; i
!= kGroupSize
; ++i
) {
730 edits
.emplace_back(VersionEdit());
732 autovector
<ColumnFamilyData
*> cfds
;
733 autovector
<const MutableCFOptions
*> all_mutable_cf_options
;
734 autovector
<autovector
<VersionEdit
*>> edit_lists
;
735 for (int i
= 0; i
!= kGroupSize
; ++i
) {
736 cfds
.emplace_back(versions_
->GetColumnFamilySet()->GetDefault());
737 all_mutable_cf_options
.emplace_back(&mutable_cf_options_
);
738 autovector
<VersionEdit
*> edit_list
;
739 edit_list
.emplace_back(&edits
[i
]);
740 edit_lists
.emplace_back(edit_list
);
743 SyncPoint::GetInstance()->DisableProcessing();
744 SyncPoint::GetInstance()->ClearAllCallBacks();
746 SyncPoint::GetInstance()->SetCallBack(
747 "VersionSet::ProcessManifestWrites:SameColumnFamily", [&](void* arg
) {
748 uint32_t* cf_id
= reinterpret_cast<uint32_t*>(arg
);
749 EXPECT_EQ(0, *cf_id
);
752 SyncPoint::GetInstance()->EnableProcessing();
755 versions_
->LogAndApply(cfds
, all_mutable_cf_options
, edit_lists
, &mutex_
);
758 EXPECT_EQ(kGroupSize
- 1, count
);
761 TEST_F(VersionSetTest
, HandleValidAtomicGroup
) {
762 std::vector
<ColumnFamilyDescriptor
> column_families
;
763 SequenceNumber last_seqno
;
764 std::unique_ptr
<log::Writer
> log_writer
;
765 PrepareManifest(&column_families
, &last_seqno
, &log_writer
);
767 // Append multiple version edits that form an atomic group
768 const int kAtomicGroupSize
= 3;
769 std::vector
<VersionEdit
> edits(kAtomicGroupSize
);
770 int remaining
= kAtomicGroupSize
;
771 for (size_t i
= 0; i
!= edits
.size(); ++i
) {
772 edits
[i
].SetLogNumber(0);
773 edits
[i
].SetNextFile(2);
774 edits
[i
].MarkAtomicGroup(--remaining
);
775 edits
[i
].SetLastSequence(last_seqno
++);
778 for (const auto& edit
: edits
) {
780 edit
.EncodeTo(&record
);
781 s
= log_writer
->AddRecord(record
);
786 s
= SetCurrentFile(env_
, dbname_
, 1, nullptr);
789 SyncPoint::GetInstance()->DisableProcessing();
790 SyncPoint::GetInstance()->ClearAllCallBacks();
792 bool first_in_atomic_group
= false;
793 bool last_in_atomic_group
= false;
795 SyncPoint::GetInstance()->SetCallBack(
796 "VersionSet::Recover:FirstInAtomicGroup", [&](void* arg
) {
797 VersionEdit
* e
= reinterpret_cast<VersionEdit
*>(arg
);
798 EXPECT_EQ(edits
.front().DebugString(),
799 e
->DebugString()); // compare based on value
800 first_in_atomic_group
= true;
802 SyncPoint::GetInstance()->SetCallBack(
803 "VersionSet::Recover:LastInAtomicGroup", [&](void* arg
) {
804 VersionEdit
* e
= reinterpret_cast<VersionEdit
*>(arg
);
805 EXPECT_EQ(edits
.back().DebugString(),
806 e
->DebugString()); // compare based on value
807 EXPECT_TRUE(first_in_atomic_group
);
808 last_in_atomic_group
= true;
810 SyncPoint::GetInstance()->EnableProcessing();
812 EXPECT_OK(versions_
->Recover(column_families
, false));
813 EXPECT_EQ(column_families
.size(),
814 versions_
->GetColumnFamilySet()->NumberOfColumnFamilies());
815 EXPECT_TRUE(first_in_atomic_group
);
816 EXPECT_TRUE(last_in_atomic_group
);
819 TEST_F(VersionSetTest
, HandleIncompleteTrailingAtomicGroup
) {
820 std::vector
<ColumnFamilyDescriptor
> column_families
;
821 SequenceNumber last_seqno
;
822 std::unique_ptr
<log::Writer
> log_writer
;
823 PrepareManifest(&column_families
, &last_seqno
, &log_writer
);
825 // Append multiple version edits that form an atomic group
826 const int kAtomicGroupSize
= 4;
827 const int kNumberOfPersistedVersionEdits
= kAtomicGroupSize
- 1;
828 std::vector
<VersionEdit
> edits(kNumberOfPersistedVersionEdits
);
829 int remaining
= kAtomicGroupSize
;
830 for (size_t i
= 0; i
!= edits
.size(); ++i
) {
831 edits
[i
].SetLogNumber(0);
832 edits
[i
].SetNextFile(2);
833 edits
[i
].MarkAtomicGroup(--remaining
);
834 edits
[i
].SetLastSequence(last_seqno
++);
837 for (const auto& edit
: edits
) {
839 edit
.EncodeTo(&record
);
840 s
= log_writer
->AddRecord(record
);
845 s
= SetCurrentFile(env_
, dbname_
, 1, nullptr);
848 SyncPoint::GetInstance()->DisableProcessing();
849 SyncPoint::GetInstance()->ClearAllCallBacks();
851 bool first_in_atomic_group
= false;
852 bool last_in_atomic_group
= false;
855 SyncPoint::GetInstance()->SetCallBack(
856 "VersionSet::Recover:FirstInAtomicGroup", [&](void* arg
) {
857 VersionEdit
* e
= reinterpret_cast<VersionEdit
*>(arg
);
858 EXPECT_EQ(edits
.front().DebugString(),
859 e
->DebugString()); // compare based on value
860 first_in_atomic_group
= true;
862 SyncPoint::GetInstance()->SetCallBack(
863 "VersionSet::Recover:LastInAtomicGroup",
864 [&](void* /* arg */) { last_in_atomic_group
= true; });
865 SyncPoint::GetInstance()->SetCallBack("VersionSet::Recover:AtomicGroup",
866 [&](void* /* arg */) { ++num
; });
867 SyncPoint::GetInstance()->EnableProcessing();
869 EXPECT_OK(versions_
->Recover(column_families
, false));
870 EXPECT_EQ(column_families
.size(),
871 versions_
->GetColumnFamilySet()->NumberOfColumnFamilies());
872 EXPECT_TRUE(first_in_atomic_group
);
873 EXPECT_FALSE(last_in_atomic_group
);
874 EXPECT_EQ(kNumberOfPersistedVersionEdits
, num
);
877 TEST_F(VersionSetTest
, HandleCorruptedAtomicGroup
) {
878 std::vector
<ColumnFamilyDescriptor
> column_families
;
879 SequenceNumber last_seqno
;
880 std::unique_ptr
<log::Writer
> log_writer
;
881 PrepareManifest(&column_families
, &last_seqno
, &log_writer
);
883 // Append multiple version edits that form an atomic group
884 const int kAtomicGroupSize
= 4;
885 std::vector
<VersionEdit
> edits(kAtomicGroupSize
);
886 int remaining
= kAtomicGroupSize
;
887 for (size_t i
= 0; i
!= edits
.size(); ++i
) {
888 edits
[i
].SetLogNumber(0);
889 edits
[i
].SetNextFile(2);
890 if (i
!= (kAtomicGroupSize
/ 2)) {
891 edits
[i
].MarkAtomicGroup(--remaining
);
893 edits
[i
].SetLastSequence(last_seqno
++);
896 for (const auto& edit
: edits
) {
898 edit
.EncodeTo(&record
);
899 s
= log_writer
->AddRecord(record
);
904 s
= SetCurrentFile(env_
, dbname_
, 1, nullptr);
907 SyncPoint::GetInstance()->DisableProcessing();
908 SyncPoint::GetInstance()->ClearAllCallBacks();
911 SyncPoint::GetInstance()->SetCallBack(
912 "VersionSet::Recover:AtomicGroupMixedWithNormalEdits", [&](void* arg
) {
913 VersionEdit
* e
= reinterpret_cast<VersionEdit
*>(arg
);
914 EXPECT_EQ(edits
[kAtomicGroupSize
/ 2].DebugString(), e
->DebugString());
917 SyncPoint::GetInstance()->EnableProcessing();
918 EXPECT_NOK(versions_
->Recover(column_families
, false));
919 EXPECT_EQ(column_families
.size(),
920 versions_
->GetColumnFamilySet()->NumberOfColumnFamilies());
924 TEST_F(VersionSetTest
, HandleIncorrectAtomicGroupSize
) {
925 std::vector
<ColumnFamilyDescriptor
> column_families
;
926 SequenceNumber last_seqno
;
927 std::unique_ptr
<log::Writer
> log_writer
;
928 PrepareManifest(&column_families
, &last_seqno
, &log_writer
);
930 // Append multiple version edits that form an atomic group
931 const int kAtomicGroupSize
= 4;
932 std::vector
<VersionEdit
> edits(kAtomicGroupSize
);
933 int remaining
= kAtomicGroupSize
;
934 for (size_t i
= 0; i
!= edits
.size(); ++i
) {
935 edits
[i
].SetLogNumber(0);
936 edits
[i
].SetNextFile(2);
938 edits
[i
].MarkAtomicGroup(--remaining
);
940 edits
[i
].MarkAtomicGroup(remaining
--);
942 edits
[i
].SetLastSequence(last_seqno
++);
945 for (const auto& edit
: edits
) {
947 edit
.EncodeTo(&record
);
948 s
= log_writer
->AddRecord(record
);
953 s
= SetCurrentFile(env_
, dbname_
, 1, nullptr);
956 SyncPoint::GetInstance()->DisableProcessing();
957 SyncPoint::GetInstance()->ClearAllCallBacks();
959 bool incorrect_group_size
= false;
960 SyncPoint::GetInstance()->SetCallBack(
961 "VersionSet::Recover:IncorrectAtomicGroupSize", [&](void* arg
) {
962 VersionEdit
* e
= reinterpret_cast<VersionEdit
*>(arg
);
963 EXPECT_EQ(edits
[1].DebugString(), e
->DebugString());
964 incorrect_group_size
= true;
966 SyncPoint::GetInstance()->EnableProcessing();
967 EXPECT_NOK(versions_
->Recover(column_families
, false));
968 EXPECT_EQ(column_families
.size(),
969 versions_
->GetColumnFamilySet()->NumberOfColumnFamilies());
970 EXPECT_TRUE(incorrect_group_size
);
973 class VersionSetTestDropOneCF
: public VersionSetTestBase
,
974 public testing::TestWithParam
<std::string
> {
976 VersionSetTestDropOneCF() : VersionSetTestBase() {}
979 // This test simulates the following execution sequence
980 // Time thread1 bg_flush_thr
981 // | Prepare version edits (e1,e2,e3) for atomic
982 // | flush cf1, cf2, cf3
983 // | Enqueue e to drop cfi
984 // | to manifest_writers_
985 // | Enqueue (e1,e2,e3) to manifest_writers_
988 // | cfi.IsDropped() is true
989 // | Apply (e1,e2,e3),
990 // | since cfi.IsDropped() == true, we need to
991 // | drop ei and write the rest to MANIFEST.
994 // Repeat the test for i = 1, 2, 3 to simulate dropping the first, middle and
995 // last column family in an atomic group.
996 TEST_P(VersionSetTestDropOneCF
, HandleDroppedColumnFamilyInAtomicGroup
) {
997 std::vector
<ColumnFamilyDescriptor
> column_families
;
998 SequenceNumber last_seqno
;
999 std::unique_ptr
<log::Writer
> log_writer
;
1000 PrepareManifest(&column_families
, &last_seqno
, &log_writer
);
1001 Status s
= SetCurrentFile(env_
, dbname_
, 1, nullptr);
1004 EXPECT_OK(versions_
->Recover(column_families
, false /* read_only */));
1005 EXPECT_EQ(column_families
.size(),
1006 versions_
->GetColumnFamilySet()->NumberOfColumnFamilies());
1008 const int kAtomicGroupSize
= 3;
1009 const std::vector
<std::string
> non_default_cf_names
= {
1010 kColumnFamilyName1
, kColumnFamilyName2
, kColumnFamilyName3
};
1012 // Drop one column family
1013 VersionEdit drop_cf_edit
;
1014 drop_cf_edit
.DropColumnFamily();
1015 const std::string
cf_to_drop_name(GetParam());
1017 versions_
->GetColumnFamilySet()->GetColumnFamily(cf_to_drop_name
);
1018 ASSERT_NE(nullptr, cfd_to_drop
);
1019 // Increase its refcount because cfd_to_drop is used later, and we need to
1020 // prevent it from being deleted.
1022 drop_cf_edit
.SetColumnFamily(cfd_to_drop
->GetID());
1024 s
= versions_
->LogAndApply(cfd_to_drop
,
1025 *cfd_to_drop
->GetLatestMutableCFOptions(),
1026 &drop_cf_edit
, &mutex_
);
1030 std::vector
<VersionEdit
> edits(kAtomicGroupSize
);
1031 uint32_t remaining
= kAtomicGroupSize
;
1033 autovector
<ColumnFamilyData
*> cfds
;
1034 autovector
<const MutableCFOptions
*> mutable_cf_options_list
;
1035 autovector
<autovector
<VersionEdit
*>> edit_lists
;
1036 for (const auto& cf_name
: non_default_cf_names
) {
1037 auto cfd
= (cf_name
!= cf_to_drop_name
)
1038 ? versions_
->GetColumnFamilySet()->GetColumnFamily(cf_name
)
1040 ASSERT_NE(nullptr, cfd
);
1041 cfds
.push_back(cfd
);
1042 mutable_cf_options_list
.emplace_back(cfd
->GetLatestMutableCFOptions());
1043 edits
[i
].SetColumnFamily(cfd
->GetID());
1044 edits
[i
].SetLogNumber(0);
1045 edits
[i
].SetNextFile(2);
1046 edits
[i
].MarkAtomicGroup(--remaining
);
1047 edits
[i
].SetLastSequence(last_seqno
++);
1048 autovector
<VersionEdit
*> tmp_edits
;
1049 tmp_edits
.push_back(&edits
[i
]);
1050 edit_lists
.emplace_back(tmp_edits
);
1054 SyncPoint::GetInstance()->DisableProcessing();
1055 SyncPoint::GetInstance()->ClearAllCallBacks();
1056 SyncPoint::GetInstance()->SetCallBack(
1057 "VersionSet::ProcessManifestWrites:CheckOneAtomicGroup", [&](void* arg
) {
1058 std::vector
<VersionEdit
*>* tmp_edits
=
1059 reinterpret_cast<std::vector
<VersionEdit
*>*>(arg
);
1060 EXPECT_EQ(kAtomicGroupSize
- 1, tmp_edits
->size());
1061 for (const auto e
: *tmp_edits
) {
1063 for (const auto& e2
: edits
) {
1073 SyncPoint::GetInstance()->EnableProcessing();
1075 s
= versions_
->LogAndApply(cfds
, mutable_cf_options_list
, edit_lists
,
1079 ASSERT_EQ(1, called
);
1080 if (cfd_to_drop
->Unref()) {
1082 cfd_to_drop
= nullptr;
1086 INSTANTIATE_TEST_CASE_P(
1087 AtomicGroup
, VersionSetTestDropOneCF
,
1088 testing::Values(VersionSetTestBase::kColumnFamilyName1
,
1089 VersionSetTestBase::kColumnFamilyName2
,
1090 VersionSetTestBase::kColumnFamilyName3
));
1092 } // namespace rocksdb
1094 int main(int argc
, char** argv
) {
1095 ::testing::InitGoogleTest(&argc
, argv
);
1096 return RUN_ALL_TESTS();