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/db_test_util.h"
11 #include "file/sst_file_manager_impl.h"
12 #include "port/port.h"
13 #include "port/stack_trace.h"
14 #include "rocksdb/sst_file_manager.h"
15 #include "util/random.h"
17 namespace ROCKSDB_NAMESPACE
{
19 class DBSSTTest
: public DBTestBase
{
21 DBSSTTest() : DBTestBase("/db_sst_test", /*env_do_fsync=*/true) {}
25 // A class which remembers the name of each flushed file.
26 class FlushedFileCollector
: public EventListener
{
28 FlushedFileCollector() {}
29 ~FlushedFileCollector() override
{}
31 void OnFlushCompleted(DB
* /*db*/, const FlushJobInfo
& info
) override
{
32 std::lock_guard
<std::mutex
> lock(mutex_
);
33 flushed_files_
.push_back(info
.file_path
);
36 std::vector
<std::string
> GetFlushedFiles() {
37 std::lock_guard
<std::mutex
> lock(mutex_
);
38 std::vector
<std::string
> result
;
39 for (auto fname
: flushed_files_
) {
40 result
.push_back(fname
);
44 void ClearFlushedFiles() {
45 std::lock_guard
<std::mutex
> lock(mutex_
);
46 flushed_files_
.clear();
50 std::vector
<std::string
> flushed_files_
;
53 #endif // ROCKSDB_LITE
55 TEST_F(DBSSTTest
, DontDeletePendingOutputs
) {
58 options
.create_if_missing
= true;
59 DestroyAndReopen(options
);
61 // Every time we write to a table file, call FOF/POF with full DB scan. This
62 // will make sure our pending_outputs_ protection work correctly
63 std::function
<void()> purge_obsolete_files_function
= [&]() {
64 JobContext
job_context(0);
65 dbfull()->TEST_LockMutex();
66 dbfull()->FindObsoleteFiles(&job_context
, true /*force*/);
67 dbfull()->TEST_UnlockMutex();
68 dbfull()->PurgeObsoleteFiles(job_context
);
72 env_
->table_write_callback_
= &purge_obsolete_files_function
;
74 for (int i
= 0; i
< 2; ++i
) {
75 ASSERT_OK(Put("a", "begin"));
76 ASSERT_OK(Put("z", "end"));
80 // If pending output guard does not work correctly, PurgeObsoleteFiles() will
81 // delete the file that Compaction is trying to create, causing this: error
82 // db/db_test.cc:975: IO error:
83 // /tmp/rocksdbtest-1552237650/db_test/000009.sst: No such file or directory
87 // 1 Create some SST files by inserting K-V pairs into DB
88 // 2 Close DB and change suffix from ".sst" to ".ldb" for every other SST file
89 // 3 Open DB and check if all key can be read
90 TEST_F(DBSSTTest
, SSTsWithLdbSuffixHandling
) {
91 Options options
= CurrentOptions();
92 options
.write_buffer_size
= 110 << 10; // 110KB
93 options
.num_levels
= 4;
94 DestroyAndReopen(options
);
98 for (int i
= 0; i
< 10; ++i
) {
99 GenerateNewFile(&rnd
, &key_id
, false);
103 int const num_files
= GetSstFileCount(dbname_
);
104 ASSERT_GT(num_files
, 0);
107 std::vector
<std::string
> values
;
108 values
.reserve(key_id
);
109 for (int k
= 0; k
< key_id
; ++k
) {
110 values
.push_back(Get(Key(k
)));
114 std::vector
<std::string
> filenames
;
115 GetSstFiles(env_
, dbname_
, &filenames
);
116 int num_ldb_files
= 0;
117 for (size_t i
= 0; i
< filenames
.size(); ++i
) {
121 std::string
const rdb_name
= dbname_
+ "/" + filenames
[i
];
122 std::string
const ldb_name
= Rocks2LevelTableFileName(rdb_name
);
123 ASSERT_TRUE(env_
->RenameFile(rdb_name
, ldb_name
).ok());
126 ASSERT_GT(num_ldb_files
, 0);
127 ASSERT_EQ(num_files
, GetSstFileCount(dbname_
));
130 for (int k
= 0; k
< key_id
; ++k
) {
131 ASSERT_EQ(values
[k
], Get(Key(k
)));
136 // Check that we don't crash when opening DB with
137 // DBOptions::skip_checking_sst_file_sizes_on_db_open = true.
138 TEST_F(DBSSTTest
, SkipCheckingSSTFileSizesOnDBOpen
) {
139 ASSERT_OK(Put("pika", "choo"));
142 // Just open the DB with the option set to true and check that we don't crash.
145 options
.skip_checking_sst_file_sizes_on_db_open
= true;
148 ASSERT_EQ("choo", Get("pika"));
152 TEST_F(DBSSTTest
, DontDeleteMovedFile
) {
153 // This test triggers move compaction and verifies that the file is not
154 // deleted when it's part of move compaction
155 Options options
= CurrentOptions();
157 options
.create_if_missing
= true;
158 options
.max_bytes_for_level_base
= 1024 * 1024; // 1 MB
159 options
.level0_file_num_compaction_trigger
=
160 2; // trigger compaction when we have 2 files
161 DestroyAndReopen(options
);
164 // Create two 1MB sst files
165 for (int i
= 0; i
< 2; ++i
) {
166 // Create 1MB sst file
167 for (int j
= 0; j
< 100; ++j
) {
168 ASSERT_OK(Put(Key(i
* 50 + j
), rnd
.RandomString(10 * 1024)));
172 // this should execute both L0->L1 and L1->(move)->L2 compactions
173 dbfull()->TEST_WaitForCompact();
174 ASSERT_EQ("0,0,1", FilesPerLevel(0));
176 // If the moved file is actually deleted (the move-safeguard in
177 // ~Version::Version() is not there), we get this failure:
178 // Corruption: Can't access /000009.sst
182 // This reproduces a bug where we don't delete a file because when it was
183 // supposed to be deleted, it was blocked by pending_outputs
185 // 1. current file_number is 13
186 // 2. compaction (1) starts, blocks deletion of all files starting with 13
188 // 3. file 13 is created by compaction (2)
189 // 4. file 13 is consumed by compaction (3) and file 15 was created. Since file
190 // 13 has no references, it is put into VersionSet::obsolete_files_
191 // 5. FindObsoleteFiles() gets file 13 from VersionSet::obsolete_files_. File 13
192 // is deleted from obsolete_files_ set.
193 // 6. PurgeObsoleteFiles() tries to delete file 13, but this file is blocked by
194 // pending outputs since compaction (1) is still running. It is not deleted and
195 // it is not present in obsolete_files_ anymore. Therefore, we never delete it.
196 TEST_F(DBSSTTest
, DeleteObsoleteFilesPendingOutputs
) {
197 Options options
= CurrentOptions();
199 options
.write_buffer_size
= 2 * 1024 * 1024; // 2 MB
200 options
.max_bytes_for_level_base
= 1024 * 1024; // 1 MB
201 options
.level0_file_num_compaction_trigger
=
202 2; // trigger compaction when we have 2 files
203 options
.max_background_flushes
= 2;
204 options
.max_background_compactions
= 2;
206 OnFileDeletionListener
* listener
= new OnFileDeletionListener();
207 options
.listeners
.emplace_back(listener
);
212 // Create two 1MB sst files
213 for (int i
= 0; i
< 2; ++i
) {
214 // Create 1MB sst file
215 for (int j
= 0; j
< 100; ++j
) {
216 ASSERT_OK(Put(Key(i
* 50 + j
), rnd
.RandomString(10 * 1024)));
220 // this should execute both L0->L1 and L1->(move)->L2 compactions
221 dbfull()->TEST_WaitForCompact();
222 ASSERT_EQ("0,0,1", FilesPerLevel(0));
224 test::SleepingBackgroundTask blocking_thread
;
226 bool already_blocked(false);
229 std::function
<void()> block_first_time
= [&]() {
230 bool blocking
= false;
232 MutexLock
l(&mutex_
);
233 if (!already_blocked
) {
235 already_blocked
= true;
239 blocking_thread
.DoSleep();
242 env_
->table_write_callback_
= &block_first_time
;
243 // Insert 2.5MB data, which should trigger a flush because we exceed
244 // write_buffer_size. The flush will be blocked with block_first_time
245 // pending_file is protecting all the files created after
246 for (int j
= 0; j
< 256; ++j
) {
247 ASSERT_OK(Put(Key(j
), rnd
.RandomString(10 * 1024)));
249 blocking_thread
.WaitUntilSleeping();
251 ASSERT_OK(dbfull()->TEST_CompactRange(2, nullptr, nullptr));
253 ASSERT_EQ("0,0,0,1", FilesPerLevel(0));
254 std::vector
<LiveFileMetaData
> metadata
;
255 db_
->GetLiveFilesMetaData(&metadata
);
256 ASSERT_EQ(metadata
.size(), 1U);
257 auto file_on_L2
= metadata
[0].name
;
258 listener
->SetExpectedFileName(dbname_
+ file_on_L2
);
260 ASSERT_OK(dbfull()->TEST_CompactRange(3, nullptr, nullptr, nullptr,
261 true /* disallow trivial move */));
262 ASSERT_EQ("0,0,0,0,1", FilesPerLevel(0));
265 blocking_thread
.WakeUp();
266 blocking_thread
.WaitUntilDone();
267 dbfull()->TEST_WaitForFlushMemTable();
268 // File just flushed is too big for L0 and L1 so gets moved to L2.
269 dbfull()->TEST_WaitForCompact();
270 ASSERT_EQ("0,0,1,0,1", FilesPerLevel(0));
273 db_
->GetLiveFilesMetaData(&metadata
);
274 ASSERT_EQ(metadata
.size(), 2U);
276 // This file should have been deleted during last compaction
277 ASSERT_EQ(Status::NotFound(), env_
->FileExists(dbname_
+ file_on_L2
));
278 listener
->VerifyMatchedCount(1);
281 TEST_F(DBSSTTest
, DBWithSstFileManager
) {
282 std::shared_ptr
<SstFileManager
> sst_file_manager(NewSstFileManager(env_
));
283 auto sfm
= static_cast<SstFileManagerImpl
*>(sst_file_manager
.get());
286 int files_deleted
= 0;
288 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
289 "SstFileManagerImpl::OnAddFile", [&](void* /*arg*/) { files_added
++; });
290 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
291 "SstFileManagerImpl::OnDeleteFile",
292 [&](void* /*arg*/) { files_deleted
++; });
293 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
294 "SstFileManagerImpl::OnMoveFile", [&](void* /*arg*/) { files_moved
++; });
295 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
297 Options options
= CurrentOptions();
298 options
.sst_file_manager
= sst_file_manager
;
299 DestroyAndReopen(options
);
302 for (int i
= 0; i
< 25; i
++) {
303 GenerateNewRandomFile(&rnd
);
305 dbfull()->TEST_WaitForFlushMemTable();
306 dbfull()->TEST_WaitForCompact();
307 // Verify that we are tracking all sst files in dbname_
308 std::unordered_map
<std::string
, uint64_t> files_in_db
;
309 ASSERT_OK(GetAllSSTFiles(&files_in_db
));
310 ASSERT_EQ(sfm
->GetTrackedFiles(), files_in_db
);
312 ASSERT_OK(db_
->CompactRange(CompactRangeOptions(), nullptr, nullptr));
314 std::unordered_map
<std::string
, uint64_t> files_in_db
;
315 ASSERT_OK(GetAllSSTFiles(&files_in_db
));
316 // Verify that we are tracking all sst files in dbname_
317 ASSERT_EQ(sfm
->GetTrackedFiles(), files_in_db
);
318 // Verify the total files size
319 uint64_t total_files_size
= 0;
320 for (auto& file_to_size
: files_in_db
) {
321 total_files_size
+= file_to_size
.second
;
323 ASSERT_EQ(sfm
->GetTotalSize(), total_files_size
);
324 // We flushed at least 25 files
325 ASSERT_GE(files_added
, 25);
326 // Compaction must have deleted some files
327 ASSERT_GT(files_deleted
, 0);
328 // No files were moved
329 ASSERT_EQ(files_moved
, 0);
333 ASSERT_EQ(sfm
->GetTrackedFiles(), files_in_db
);
334 ASSERT_EQ(sfm
->GetTotalSize(), total_files_size
);
336 // Verify that we track all the files again after the DB is closed and opened
338 sst_file_manager
.reset(NewSstFileManager(env_
));
339 options
.sst_file_manager
= sst_file_manager
;
340 sfm
= static_cast<SstFileManagerImpl
*>(sst_file_manager
.get());
343 ASSERT_EQ(sfm
->GetTrackedFiles(), files_in_db
);
344 ASSERT_EQ(sfm
->GetTotalSize(), total_files_size
);
346 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
349 TEST_F(DBSSTTest
, RateLimitedDelete
) {
350 Destroy(last_options_
);
351 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
352 {"DBSSTTest::RateLimitedDelete:1",
353 "DeleteScheduler::BackgroundEmptyTrash"},
356 std::vector
<uint64_t> penalties
;
357 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
358 "DeleteScheduler::BackgroundEmptyTrash:Wait",
359 [&](void* arg
) { penalties
.push_back(*(static_cast<uint64_t*>(arg
))); });
360 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
361 "InstrumentedCondVar::TimedWaitInternal", [&](void* arg
) {
362 // Turn timed wait into a simulated sleep
363 uint64_t* abs_time_us
= static_cast<uint64_t*>(arg
);
364 uint64_t cur_time
= env_
->NowMicros();
365 if (*abs_time_us
> cur_time
) {
366 env_
->MockSleepForMicroseconds(*abs_time_us
- cur_time
);
369 // Plus an additional short, random amount
370 env_
->MockSleepForMicroseconds(Random::GetTLSInstance()->Uniform(10));
372 // Set wait until time to before (actual) current time to force not
374 *abs_time_us
= Env::Default()->NowMicros();
377 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
379 Options options
= CurrentOptions();
380 SetTimeElapseOnlySleepOnReopen(&options
);
381 options
.disable_auto_compactions
= true;
383 options
.statistics
= CreateDBStatistics();
385 int64_t rate_bytes_per_sec
= 1024 * 10; // 10 Kbs / Sec
387 options
.sst_file_manager
.reset(
388 NewSstFileManager(env_
, nullptr, "", 0, false, &s
, 0));
390 options
.sst_file_manager
->SetDeleteRateBytesPerSecond(rate_bytes_per_sec
);
391 auto sfm
= static_cast<SstFileManagerImpl
*>(options
.sst_file_manager
.get());
392 sfm
->delete_scheduler()->SetMaxTrashDBRatio(1.1);
395 wo
.disableWAL
= true;
396 ASSERT_OK(TryReopen(options
));
397 // Create 4 files in L0
398 for (char v
= 'a'; v
<= 'd'; v
++) {
399 ASSERT_OK(Put("Key2", DummyString(1024, v
), wo
));
400 ASSERT_OK(Put("Key3", DummyString(1024, v
), wo
));
401 ASSERT_OK(Put("Key4", DummyString(1024, v
), wo
));
402 ASSERT_OK(Put("Key1", DummyString(1024, v
), wo
));
403 ASSERT_OK(Put("Key4", DummyString(1024, v
), wo
));
406 // We created 4 sst files in L0
407 ASSERT_EQ("4", FilesPerLevel(0));
409 std::vector
<LiveFileMetaData
> metadata
;
410 db_
->GetLiveFilesMetaData(&metadata
);
412 // Compaction will move the 4 files in L0 to trash and create 1 L1 file
413 ASSERT_OK(db_
->CompactRange(CompactRangeOptions(), nullptr, nullptr));
414 ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
415 ASSERT_EQ("0,1", FilesPerLevel(0));
417 uint64_t delete_start_time
= env_
->NowMicros();
418 // Hold BackgroundEmptyTrash
419 TEST_SYNC_POINT("DBSSTTest::RateLimitedDelete:1");
420 sfm
->WaitForEmptyTrash();
421 uint64_t time_spent_deleting
= env_
->NowMicros() - delete_start_time
;
423 uint64_t total_files_size
= 0;
424 uint64_t expected_penlty
= 0;
425 ASSERT_EQ(penalties
.size(), metadata
.size());
426 for (size_t i
= 0; i
< metadata
.size(); i
++) {
427 total_files_size
+= metadata
[i
].size
;
428 expected_penlty
= ((total_files_size
* 1000000) / rate_bytes_per_sec
);
429 ASSERT_EQ(expected_penlty
, penalties
[i
]);
431 ASSERT_GT(time_spent_deleting
, expected_penlty
* 0.9);
432 ASSERT_LT(time_spent_deleting
, expected_penlty
* 1.1);
433 ASSERT_EQ(4, options
.statistics
->getAndResetTickerCount(FILES_MARKED_TRASH
));
435 0, options
.statistics
->getAndResetTickerCount(FILES_DELETED_IMMEDIATELY
));
437 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
440 TEST_F(DBSSTTest
, RateLimitedWALDelete
) {
441 Destroy(last_options_
);
443 std::vector
<uint64_t> penalties
;
444 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
445 "DeleteScheduler::BackgroundEmptyTrash:Wait",
446 [&](void* arg
) { penalties
.push_back(*(static_cast<uint64_t*>(arg
))); });
448 Options options
= CurrentOptions();
449 options
.disable_auto_compactions
= true;
450 options
.compression
= kNoCompression
;
453 int64_t rate_bytes_per_sec
= 1024 * 10; // 10 Kbs / Sec
455 options
.sst_file_manager
.reset(
456 NewSstFileManager(env_
, nullptr, "", 0, false, &s
, 0));
458 options
.sst_file_manager
->SetDeleteRateBytesPerSecond(rate_bytes_per_sec
);
459 auto sfm
= static_cast<SstFileManagerImpl
*>(options
.sst_file_manager
.get());
460 sfm
->delete_scheduler()->SetMaxTrashDBRatio(3.1);
461 SetTimeElapseOnlySleepOnReopen(&options
);
463 ASSERT_OK(TryReopen(options
));
464 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
466 // Create 4 files in L0
467 for (char v
= 'a'; v
<= 'd'; v
++) {
468 ASSERT_OK(Put("Key2", DummyString(1024, v
)));
469 ASSERT_OK(Put("Key3", DummyString(1024, v
)));
470 ASSERT_OK(Put("Key4", DummyString(1024, v
)));
471 ASSERT_OK(Put("Key1", DummyString(1024, v
)));
472 ASSERT_OK(Put("Key4", DummyString(1024, v
)));
475 // We created 4 sst files in L0
476 ASSERT_EQ("4", FilesPerLevel(0));
478 // Compaction will move the 4 files in L0 to trash and create 1 L1 file
479 CompactRangeOptions cro
;
480 cro
.bottommost_level_compaction
= BottommostLevelCompaction::kForce
;
481 ASSERT_OK(db_
->CompactRange(cro
, nullptr, nullptr));
482 ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
483 ASSERT_EQ("0,1", FilesPerLevel(0));
485 sfm
->WaitForEmptyTrash();
486 ASSERT_EQ(penalties
.size(), 8);
488 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
491 class DBWALTestWithParam
493 public testing::WithParamInterface
<std::tuple
<std::string
, bool>> {
495 DBWALTestWithParam() {
496 wal_dir_
= std::get
<0>(GetParam());
497 wal_dir_same_as_dbname_
= std::get
<1>(GetParam());
500 std::string wal_dir_
;
501 bool wal_dir_same_as_dbname_
;
504 TEST_P(DBWALTestWithParam
, WALTrashCleanupOnOpen
) {
505 class MyEnv
: public EnvWrapper
{
507 MyEnv(Env
* t
) : EnvWrapper(t
), fake_log_delete(false) {}
509 Status
DeleteFile(const std::string
& fname
) {
510 if (fname
.find(".log.trash") != std::string::npos
&& fake_log_delete
) {
514 return target()->DeleteFile(fname
);
517 void set_fake_log_delete(bool fake
) { fake_log_delete
= fake
; }
520 bool fake_log_delete
;
523 std::unique_ptr
<MyEnv
> env(new MyEnv(env_
));
524 Destroy(last_options_
);
526 env
->set_fake_log_delete(true);
528 Options options
= CurrentOptions();
529 options
.disable_auto_compactions
= true;
530 options
.compression
= kNoCompression
;
531 options
.env
= env
.get();
532 options
.wal_dir
= dbname_
+ wal_dir_
;
534 int64_t rate_bytes_per_sec
= 1024 * 10; // 10 Kbs / Sec
536 options
.sst_file_manager
.reset(
537 NewSstFileManager(env_
, nullptr, "", 0, false, &s
, 0));
539 options
.sst_file_manager
->SetDeleteRateBytesPerSecond(rate_bytes_per_sec
);
540 auto sfm
= static_cast<SstFileManagerImpl
*>(options
.sst_file_manager
.get());
541 sfm
->delete_scheduler()->SetMaxTrashDBRatio(3.1);
543 ASSERT_OK(TryReopen(options
));
545 // Create 4 files in L0
546 for (char v
= 'a'; v
<= 'd'; v
++) {
547 ASSERT_OK(Put("Key2", DummyString(1024, v
)));
548 ASSERT_OK(Put("Key3", DummyString(1024, v
)));
549 ASSERT_OK(Put("Key4", DummyString(1024, v
)));
550 ASSERT_OK(Put("Key1", DummyString(1024, v
)));
551 ASSERT_OK(Put("Key4", DummyString(1024, v
)));
554 // We created 4 sst files in L0
555 ASSERT_EQ("4", FilesPerLevel(0));
559 options
.sst_file_manager
.reset();
560 std::vector
<std::string
> filenames
;
561 int trash_log_count
= 0;
562 if (!wal_dir_same_as_dbname_
) {
563 // Forcibly create some trash log files
564 std::unique_ptr
<WritableFile
> result
;
565 env
->NewWritableFile(options
.wal_dir
+ "/1000.log.trash", &result
,
569 env
->GetChildren(options
.wal_dir
, &filenames
);
570 for (const std::string
& fname
: filenames
) {
571 if (fname
.find(".log.trash") != std::string::npos
) {
575 ASSERT_GE(trash_log_count
, 1);
577 env
->set_fake_log_delete(false);
578 ASSERT_OK(TryReopen(options
));
582 env
->GetChildren(options
.wal_dir
, &filenames
);
583 for (const std::string
& fname
: filenames
) {
584 if (fname
.find(".log.trash") != std::string::npos
) {
588 ASSERT_EQ(trash_log_count
, 0);
592 INSTANTIATE_TEST_CASE_P(DBWALTestWithParam
, DBWALTestWithParam
,
593 ::testing::Values(std::make_tuple("", true),
594 std::make_tuple("_wal_dir", false)));
596 TEST_F(DBSSTTest
, OpenDBWithExistingTrash
) {
597 Options options
= CurrentOptions();
599 options
.sst_file_manager
.reset(
600 NewSstFileManager(env_
, nullptr, "", 1024 * 1024 /* 1 MB/sec */));
601 auto sfm
= static_cast<SstFileManagerImpl
*>(options
.sst_file_manager
.get());
603 Destroy(last_options_
);
605 // Add some trash files to the db directory so the DB can clean them up
606 env_
->CreateDirIfMissing(dbname_
);
607 ASSERT_OK(WriteStringToFile(env_
, "abc", dbname_
+ "/" + "001.sst.trash"));
608 ASSERT_OK(WriteStringToFile(env_
, "abc", dbname_
+ "/" + "002.sst.trash"));
609 ASSERT_OK(WriteStringToFile(env_
, "abc", dbname_
+ "/" + "003.sst.trash"));
611 // Reopen the DB and verify that it deletes existing trash files
612 ASSERT_OK(TryReopen(options
));
613 sfm
->WaitForEmptyTrash();
614 ASSERT_NOK(env_
->FileExists(dbname_
+ "/" + "001.sst.trash"));
615 ASSERT_NOK(env_
->FileExists(dbname_
+ "/" + "002.sst.trash"));
616 ASSERT_NOK(env_
->FileExists(dbname_
+ "/" + "003.sst.trash"));
620 // Create a DB with 2 db_paths, and generate multiple files in the 2
621 // db_paths using CompactRangeOptions, make sure that files that were
622 // deleted from first db_path were deleted using DeleteScheduler and
623 // files in the second path were not.
624 TEST_F(DBSSTTest
, DeleteSchedulerMultipleDBPaths
) {
625 std::atomic
<int> bg_delete_file(0);
626 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
627 "DeleteScheduler::DeleteTrashFile:DeleteFile",
628 [&](void* /*arg*/) { bg_delete_file
++; });
629 // The deletion scheduler sometimes skips marking file as trash according to
630 // a heuristic. In that case the deletion will go through the below SyncPoint.
631 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
632 "DeleteScheduler::DeleteFile", [&](void* /*arg*/) { bg_delete_file
++; });
634 Options options
= CurrentOptions();
635 options
.disable_auto_compactions
= true;
636 options
.db_paths
.emplace_back(dbname_
, 1024 * 100);
637 options
.db_paths
.emplace_back(dbname_
+ "_2", 1024 * 100);
640 int64_t rate_bytes_per_sec
= 1024 * 1024; // 1 Mb / Sec
642 options
.sst_file_manager
.reset(
643 NewSstFileManager(env_
, nullptr, "", rate_bytes_per_sec
, false, &s
,
644 /* max_trash_db_ratio= */ 1.1));
647 auto sfm
= static_cast<SstFileManagerImpl
*>(options
.sst_file_manager
.get());
649 DestroyAndReopen(options
);
650 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
653 wo
.disableWAL
= true;
655 // Create 4 files in L0
656 for (int i
= 0; i
< 4; i
++) {
657 ASSERT_OK(Put("Key" + ToString(i
), DummyString(1024, 'A'), wo
));
660 // We created 4 sst files in L0
661 ASSERT_EQ("4", FilesPerLevel(0));
662 // Compaction will delete files from L0 in first db path and generate a new
663 // file in L1 in second db path
664 CompactRangeOptions compact_options
;
665 compact_options
.target_path_id
= 1;
668 ASSERT_OK(db_
->CompactRange(compact_options
, &begin
, &end
));
669 ASSERT_EQ("0,1", FilesPerLevel(0));
671 // Create 4 files in L0
672 for (int i
= 4; i
< 8; i
++) {
673 ASSERT_OK(Put("Key" + ToString(i
), DummyString(1024, 'B'), wo
));
676 ASSERT_EQ("4,1", FilesPerLevel(0));
678 // Compaction will delete files from L0 in first db path and generate a new
679 // file in L1 in second db path
682 ASSERT_OK(db_
->CompactRange(compact_options
, &begin
, &end
));
683 ASSERT_EQ("0,2", FilesPerLevel(0));
685 sfm
->WaitForEmptyTrash();
686 ASSERT_EQ(bg_delete_file
, 8);
688 // Compaction will delete both files and regenerate a file in L1 in second
689 // db path. The deleted files should still be cleaned up via delete scheduler.
690 compact_options
.bottommost_level_compaction
=
691 BottommostLevelCompaction::kForceOptimized
;
692 ASSERT_OK(db_
->CompactRange(compact_options
, nullptr, nullptr));
693 ASSERT_EQ("0,1", FilesPerLevel(0));
695 sfm
->WaitForEmptyTrash();
696 ASSERT_EQ(bg_delete_file
, 10);
698 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
701 TEST_F(DBSSTTest
, DestroyDBWithRateLimitedDelete
) {
702 int bg_delete_file
= 0;
703 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
704 "DeleteScheduler::DeleteTrashFile:DeleteFile",
705 [&](void* /*arg*/) { bg_delete_file
++; });
706 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
709 Options options
= CurrentOptions();
710 options
.disable_auto_compactions
= true;
712 options
.sst_file_manager
.reset(
713 NewSstFileManager(env_
, nullptr, "", 0, false, &s
, 0));
715 DestroyAndReopen(options
);
717 // Create 4 files in L0
718 for (int i
= 0; i
< 4; i
++) {
719 ASSERT_OK(Put("Key" + ToString(i
), DummyString(1024, 'A')));
722 // We created 4 sst files in L0
723 ASSERT_EQ("4", FilesPerLevel(0));
725 // Close DB and destroy it using DeleteScheduler
728 int num_sst_files
= 0;
729 int num_wal_files
= 0;
730 std::vector
<std::string
> db_files
;
731 env_
->GetChildren(dbname_
, &db_files
);
732 for (std::string f
: db_files
) {
733 if (f
.substr(f
.find_last_of(".") + 1) == "sst") {
735 } else if (f
.substr(f
.find_last_of(".") + 1) == "log") {
739 ASSERT_GT(num_sst_files
, 0);
740 ASSERT_GT(num_wal_files
, 0);
742 auto sfm
= static_cast<SstFileManagerImpl
*>(options
.sst_file_manager
.get());
744 sfm
->SetDeleteRateBytesPerSecond(1024 * 1024);
745 sfm
->delete_scheduler()->SetMaxTrashDBRatio(1.1);
746 ASSERT_OK(DestroyDB(dbname_
, options
));
747 sfm
->WaitForEmptyTrash();
748 ASSERT_EQ(bg_delete_file
, num_sst_files
+ num_wal_files
);
751 TEST_F(DBSSTTest
, DBWithMaxSpaceAllowed
) {
752 std::shared_ptr
<SstFileManager
> sst_file_manager(NewSstFileManager(env_
));
753 auto sfm
= static_cast<SstFileManagerImpl
*>(sst_file_manager
.get());
755 Options options
= CurrentOptions();
756 options
.sst_file_manager
= sst_file_manager
;
757 options
.disable_auto_compactions
= true;
758 DestroyAndReopen(options
);
762 // Generate a file containing 100 keys.
763 for (int i
= 0; i
< 100; i
++) {
764 ASSERT_OK(Put(Key(i
), rnd
.RandomString(50)));
768 uint64_t first_file_size
= 0;
769 std::unordered_map
<std::string
, uint64_t> files_in_db
;
770 ASSERT_OK(GetAllSSTFiles(&files_in_db
, &first_file_size
));
771 ASSERT_EQ(sfm
->GetTotalSize(), first_file_size
);
773 // Set the maximum allowed space usage to the current total size
774 sfm
->SetMaxAllowedSpaceUsage(first_file_size
+ 1);
776 ASSERT_OK(Put("key1", "val1"));
777 // This flush will cause bg_error_ and will fail
781 TEST_F(DBSSTTest
, CancellingCompactionsWorks
) {
782 std::shared_ptr
<SstFileManager
> sst_file_manager(NewSstFileManager(env_
));
783 auto sfm
= static_cast<SstFileManagerImpl
*>(sst_file_manager
.get());
785 Options options
= CurrentOptions();
786 options
.sst_file_manager
= sst_file_manager
;
787 options
.level0_file_num_compaction_trigger
= 2;
788 options
.statistics
= CreateDBStatistics();
789 DestroyAndReopen(options
);
791 int completed_compactions
= 0;
792 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
793 "DBImpl::BackgroundCompaction():CancelledCompaction", [&](void* /*arg*/) {
794 sfm
->SetMaxAllowedSpaceUsage(0);
795 ASSERT_EQ(sfm
->GetCompactionsReservedSize(), 0);
797 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
798 "DBImpl::BackgroundCompaction:NonTrivial:AfterRun",
799 [&](void* /*arg*/) { completed_compactions
++; });
800 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
804 // Generate a file containing 10 keys.
805 for (int i
= 0; i
< 10; i
++) {
806 ASSERT_OK(Put(Key(i
), rnd
.RandomString(50)));
809 uint64_t total_file_size
= 0;
810 std::unordered_map
<std::string
, uint64_t> files_in_db
;
811 ASSERT_OK(GetAllSSTFiles(&files_in_db
, &total_file_size
));
812 // Set the maximum allowed space usage to the current total size
813 sfm
->SetMaxAllowedSpaceUsage(2 * total_file_size
+ 1);
815 // Generate another file to trigger compaction.
816 for (int i
= 0; i
< 10; i
++) {
817 ASSERT_OK(Put(Key(i
), rnd
.RandomString(50)));
820 dbfull()->TEST_WaitForCompact(true);
822 // Because we set a callback in CancelledCompaction, we actually
823 // let the compaction run
824 ASSERT_GT(completed_compactions
, 0);
825 ASSERT_EQ(sfm
->GetCompactionsReservedSize(), 0);
826 // Make sure the stat is bumped
827 ASSERT_GT(dbfull()->immutable_db_options().statistics
.get()->getTickerCount(COMPACTION_CANCELLED
), 0);
829 dbfull()->immutable_db_options().statistics
.get()->getTickerCount(
830 FILES_MARKED_TRASH
));
832 dbfull()->immutable_db_options().statistics
.get()->getTickerCount(
833 FILES_DELETED_IMMEDIATELY
));
834 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
837 TEST_F(DBSSTTest
, CancellingManualCompactionsWorks
) {
838 std::shared_ptr
<SstFileManager
> sst_file_manager(NewSstFileManager(env_
));
839 auto sfm
= static_cast<SstFileManagerImpl
*>(sst_file_manager
.get());
841 Options options
= CurrentOptions();
842 options
.sst_file_manager
= sst_file_manager
;
843 options
.statistics
= CreateDBStatistics();
845 FlushedFileCollector
* collector
= new FlushedFileCollector();
846 options
.listeners
.emplace_back(collector
);
848 DestroyAndReopen(options
);
852 // Generate a file containing 10 keys.
853 for (int i
= 0; i
< 10; i
++) {
854 ASSERT_OK(Put(Key(i
), rnd
.RandomString(50)));
857 uint64_t total_file_size
= 0;
858 std::unordered_map
<std::string
, uint64_t> files_in_db
;
859 ASSERT_OK(GetAllSSTFiles(&files_in_db
, &total_file_size
));
860 // Set the maximum allowed space usage to the current total size
861 sfm
->SetMaxAllowedSpaceUsage(2 * total_file_size
+ 1);
863 // Generate another file to trigger compaction.
864 for (int i
= 0; i
< 10; i
++) {
865 ASSERT_OK(Put(Key(i
), rnd
.RandomString(50)));
869 // OK, now trigger a manual compaction
870 dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
872 // Wait for manual compaction to get scheduled and finish
873 dbfull()->TEST_WaitForCompact(true);
875 ASSERT_EQ(sfm
->GetCompactionsReservedSize(), 0);
876 // Make sure the stat is bumped
877 ASSERT_EQ(dbfull()->immutable_db_options().statistics
.get()->getTickerCount(
878 COMPACTION_CANCELLED
),
881 // Now make sure CompactFiles also gets cancelled
882 auto l0_files
= collector
->GetFlushedFiles();
883 dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files
, 0);
885 // Wait for manual compaction to get scheduled and finish
886 dbfull()->TEST_WaitForCompact(true);
888 ASSERT_EQ(dbfull()->immutable_db_options().statistics
.get()->getTickerCount(
889 COMPACTION_CANCELLED
),
891 ASSERT_EQ(sfm
->GetCompactionsReservedSize(), 0);
893 // Now let the flush through and make sure GetCompactionsReservedSize
895 sfm
->SetMaxAllowedSpaceUsage(0);
896 int completed_compactions
= 0;
897 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
898 "CompactFilesImpl:End", [&](void* /*arg*/) { completed_compactions
++; });
900 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
901 dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files
, 0);
902 dbfull()->TEST_WaitForCompact(true);
904 ASSERT_EQ(sfm
->GetCompactionsReservedSize(), 0);
905 ASSERT_GT(completed_compactions
, 0);
907 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
910 TEST_F(DBSSTTest
, DBWithMaxSpaceAllowedRandomized
) {
911 // This test will set a maximum allowed space for the DB, then it will
912 // keep filling the DB until the limit is reached and bg_error_ is set.
913 // When bg_error_ is set we will verify that the DB size is greater
916 std::vector
<int> max_space_limits_mbs
= {1, 10};
917 std::atomic
<bool> bg_error_set(false);
919 std::atomic
<int> reached_max_space_on_flush(0);
920 std::atomic
<int> reached_max_space_on_compaction(0);
921 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
922 "DBImpl::FlushMemTableToOutputFile:MaxAllowedSpaceReached",
924 Status
* bg_error
= static_cast<Status
*>(arg
);
926 reached_max_space_on_flush
++;
927 // clear error to ensure compaction callback is called
928 *bg_error
= Status::OK();
931 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
932 "DBImpl::BackgroundCompaction():CancelledCompaction", [&](void* arg
) {
933 bool* enough_room
= static_cast<bool*>(arg
);
937 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
938 "CompactionJob::FinishCompactionOutputFile:MaxAllowedSpaceReached",
941 reached_max_space_on_compaction
++;
944 for (auto limit_mb
: max_space_limits_mbs
) {
945 bg_error_set
= false;
946 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearTrace();
947 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
948 std::shared_ptr
<SstFileManager
> sst_file_manager(NewSstFileManager(env_
));
949 auto sfm
= static_cast<SstFileManagerImpl
*>(sst_file_manager
.get());
951 Options options
= CurrentOptions();
952 options
.sst_file_manager
= sst_file_manager
;
953 options
.write_buffer_size
= 1024 * 512; // 512 Kb
954 DestroyAndReopen(options
);
957 sfm
->SetMaxAllowedSpaceUsage(limit_mb
* 1024 * 1024);
959 // It is easy to detect if the test is stuck in a loop. No need for
960 // complex termination logic.
962 auto s
= Put(rnd
.RandomString(10), rnd
.RandomString(50));
967 ASSERT_TRUE(bg_error_set
);
968 uint64_t total_sst_files_size
= 0;
969 std::unordered_map
<std::string
, uint64_t> files_in_db
;
970 ASSERT_OK(GetAllSSTFiles(&files_in_db
, &total_sst_files_size
));
971 ASSERT_GE(total_sst_files_size
, limit_mb
* 1024 * 1024);
972 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
975 ASSERT_GT(reached_max_space_on_flush
, 0);
976 ASSERT_GT(reached_max_space_on_compaction
, 0);
979 TEST_F(DBSSTTest
, OpenDBWithInfiniteMaxOpenFiles
) {
980 // Open DB with infinite max open files
981 // - First iteration use 1 thread to open files
982 // - Second iteration use 5 threads to open files
983 for (int iter
= 0; iter
< 2; iter
++) {
985 options
.create_if_missing
= true;
986 options
.write_buffer_size
= 100000;
987 options
.disable_auto_compactions
= true;
988 options
.max_open_files
= -1;
990 options
.max_file_opening_threads
= 1;
992 options
.max_file_opening_threads
= 5;
994 options
= CurrentOptions(options
);
995 DestroyAndReopen(options
);
997 // Create 12 Files in L0 (then move then to L2)
998 for (int i
= 0; i
< 12; i
++) {
999 std::string k
= "L2_" + Key(i
);
1000 ASSERT_OK(Put(k
, k
+ std::string(1000, 'a')));
1003 CompactRangeOptions compact_options
;
1004 compact_options
.change_level
= true;
1005 compact_options
.target_level
= 2;
1006 db_
->CompactRange(compact_options
, nullptr, nullptr);
1008 // Create 12 Files in L0
1009 for (int i
= 0; i
< 12; i
++) {
1010 std::string k
= "L0_" + Key(i
);
1011 ASSERT_OK(Put(k
, k
+ std::string(1000, 'a')));
1016 // Reopening the DB will load all existing files
1018 ASSERT_EQ("12,0,12", FilesPerLevel(0));
1019 std::vector
<std::vector
<FileMetaData
>> files
;
1020 dbfull()->TEST_GetFilesMetaData(db_
->DefaultColumnFamily(), &files
);
1022 for (const auto& level
: files
) {
1023 for (const auto& file
: level
) {
1024 ASSERT_TRUE(file
.table_reader_handle
!= nullptr);
1028 for (int i
= 0; i
< 12; i
++) {
1029 ASSERT_EQ(Get("L0_" + Key(i
)), "L0_" + Key(i
) + std::string(1000, 'a'));
1030 ASSERT_EQ(Get("L2_" + Key(i
)), "L2_" + Key(i
) + std::string(1000, 'a'));
1035 TEST_F(DBSSTTest
, GetTotalSstFilesSize
) {
1036 // We don't propagate oldest-key-time table property on compaction and
1037 // just write 0 as default value. This affect the exact table size, since
1038 // we encode table properties as varint64. Force time to be 0 to work around
1039 // it. Should remove the workaround after we propagate the property on
1041 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
1042 "FlushJob::WriteLevel0Table:oldest_ancester_time", [&](void* arg
) {
1043 uint64_t* current_time
= static_cast<uint64_t*>(arg
);
1046 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
1048 Options options
= CurrentOptions();
1049 options
.disable_auto_compactions
= true;
1050 options
.compression
= kNoCompression
;
1051 DestroyAndReopen(options
);
1052 // Generate 5 files in L0
1053 for (int i
= 0; i
< 5; i
++) {
1054 for (int j
= 0; j
< 10; j
++) {
1055 std::string val
= "val_file_" + ToString(i
);
1056 ASSERT_OK(Put(Key(j
), val
));
1060 ASSERT_EQ("5", FilesPerLevel(0));
1062 std::vector
<LiveFileMetaData
> live_files_meta
;
1063 dbfull()->GetLiveFilesMetaData(&live_files_meta
);
1064 ASSERT_EQ(live_files_meta
.size(), 5);
1065 uint64_t single_file_size
= live_files_meta
[0].size
;
1067 uint64_t live_sst_files_size
= 0;
1068 uint64_t total_sst_files_size
= 0;
1069 for (const auto& file_meta
: live_files_meta
) {
1070 live_sst_files_size
+= file_meta
.size
;
1073 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1074 &total_sst_files_size
));
1075 // Live SST files = 5
1076 // Total SST files = 5
1077 ASSERT_EQ(live_sst_files_size
, 5 * single_file_size
);
1078 ASSERT_EQ(total_sst_files_size
, 5 * single_file_size
);
1080 // hold current version
1081 std::unique_ptr
<Iterator
> iter1(dbfull()->NewIterator(ReadOptions()));
1083 // Compact 5 files into 1 file in L0
1084 ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
1085 ASSERT_EQ("0,1", FilesPerLevel(0));
1087 live_files_meta
.clear();
1088 dbfull()->GetLiveFilesMetaData(&live_files_meta
);
1089 ASSERT_EQ(live_files_meta
.size(), 1);
1091 live_sst_files_size
= 0;
1092 total_sst_files_size
= 0;
1093 for (const auto& file_meta
: live_files_meta
) {
1094 live_sst_files_size
+= file_meta
.size
;
1096 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1097 &total_sst_files_size
));
1098 // Live SST files = 1 (compacted file)
1099 // Total SST files = 6 (5 original files + compacted file)
1100 ASSERT_EQ(live_sst_files_size
, 1 * single_file_size
);
1101 ASSERT_EQ(total_sst_files_size
, 6 * single_file_size
);
1103 // hold current version
1104 std::unique_ptr
<Iterator
> iter2(dbfull()->NewIterator(ReadOptions()));
1106 // Delete all keys and compact, this will delete all live files
1107 for (int i
= 0; i
< 10; i
++) {
1108 ASSERT_OK(Delete(Key(i
)));
1111 ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
1112 ASSERT_EQ("", FilesPerLevel(0));
1114 live_files_meta
.clear();
1115 dbfull()->GetLiveFilesMetaData(&live_files_meta
);
1116 ASSERT_EQ(live_files_meta
.size(), 0);
1118 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1119 &total_sst_files_size
));
1120 // Live SST files = 0
1121 // Total SST files = 6 (5 original files + compacted file)
1122 ASSERT_EQ(total_sst_files_size
, 6 * single_file_size
);
1125 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1126 &total_sst_files_size
));
1127 // Live SST files = 0
1128 // Total SST files = 1 (compacted file)
1129 ASSERT_EQ(total_sst_files_size
, 1 * single_file_size
);
1132 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1133 &total_sst_files_size
));
1134 // Live SST files = 0
1135 // Total SST files = 0
1136 ASSERT_EQ(total_sst_files_size
, 0);
1138 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
1141 TEST_F(DBSSTTest
, GetTotalSstFilesSizeVersionsFilesShared
) {
1142 Options options
= CurrentOptions();
1143 options
.disable_auto_compactions
= true;
1144 options
.compression
= kNoCompression
;
1145 DestroyAndReopen(options
);
1146 // Generate 5 files in L0
1147 for (int i
= 0; i
< 5; i
++) {
1148 ASSERT_OK(Put(Key(i
), "val"));
1151 ASSERT_EQ("5", FilesPerLevel(0));
1153 std::vector
<LiveFileMetaData
> live_files_meta
;
1154 dbfull()->GetLiveFilesMetaData(&live_files_meta
);
1155 ASSERT_EQ(live_files_meta
.size(), 5);
1156 uint64_t single_file_size
= live_files_meta
[0].size
;
1158 uint64_t live_sst_files_size
= 0;
1159 uint64_t total_sst_files_size
= 0;
1160 for (const auto& file_meta
: live_files_meta
) {
1161 live_sst_files_size
+= file_meta
.size
;
1164 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1165 &total_sst_files_size
));
1167 // Live SST files = 5
1168 // Total SST files = 5
1169 ASSERT_EQ(live_sst_files_size
, 5 * single_file_size
);
1170 ASSERT_EQ(total_sst_files_size
, 5 * single_file_size
);
1172 // hold current version
1173 std::unique_ptr
<Iterator
> iter1(dbfull()->NewIterator(ReadOptions()));
1175 // Compaction will do trivial move from L0 to L1
1176 ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
1177 ASSERT_EQ("0,5", FilesPerLevel(0));
1179 live_files_meta
.clear();
1180 dbfull()->GetLiveFilesMetaData(&live_files_meta
);
1181 ASSERT_EQ(live_files_meta
.size(), 5);
1183 live_sst_files_size
= 0;
1184 total_sst_files_size
= 0;
1185 for (const auto& file_meta
: live_files_meta
) {
1186 live_sst_files_size
+= file_meta
.size
;
1188 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1189 &total_sst_files_size
));
1190 // Live SST files = 5
1191 // Total SST files = 5 (used in 2 version)
1192 ASSERT_EQ(live_sst_files_size
, 5 * single_file_size
);
1193 ASSERT_EQ(total_sst_files_size
, 5 * single_file_size
);
1195 // hold current version
1196 std::unique_ptr
<Iterator
> iter2(dbfull()->NewIterator(ReadOptions()));
1198 // Delete all keys and compact, this will delete all live files
1199 for (int i
= 0; i
< 5; i
++) {
1200 ASSERT_OK(Delete(Key(i
)));
1203 ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
1204 ASSERT_EQ("", FilesPerLevel(0));
1206 live_files_meta
.clear();
1207 dbfull()->GetLiveFilesMetaData(&live_files_meta
);
1208 ASSERT_EQ(live_files_meta
.size(), 0);
1210 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1211 &total_sst_files_size
));
1212 // Live SST files = 0
1213 // Total SST files = 5 (used in 2 version)
1214 ASSERT_EQ(total_sst_files_size
, 5 * single_file_size
);
1219 ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
1220 &total_sst_files_size
));
1221 // Live SST files = 0
1222 // Total SST files = 0
1223 ASSERT_EQ(total_sst_files_size
, 0);
1226 #endif // ROCKSDB_LITE
1228 } // namespace ROCKSDB_NAMESPACE
1230 int main(int argc
, char** argv
) {
1231 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
1232 ::testing::InitGoogleTest(&argc
, argv
);
1233 return RUN_ALL_TESTS();