1 | // Copyright (c) 2013 The LevelDB Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
4 | |
5 | #include "gtest/gtest.h" |
6 | #include "db/db_impl.h" |
7 | #include "leveldb/cache.h" |
8 | #include "leveldb/db.h" |
9 | #include "util/testutil.h" |
10 | |
11 | namespace leveldb { |
12 | |
13 | class AutoCompactTest : public testing::Test { |
14 | public: |
15 | AutoCompactTest() { |
16 | dbname_ = testing::TempDir() + "autocompact_test" ; |
17 | tiny_cache_ = NewLRUCache(100); |
18 | options_.block_cache = tiny_cache_; |
19 | DestroyDB(dbname_, options_); |
20 | options_.create_if_missing = true; |
21 | options_.compression = kNoCompression; |
22 | EXPECT_LEVELDB_OK(DB::Open(options_, dbname_, &db_)); |
23 | } |
24 | |
25 | ~AutoCompactTest() { |
26 | delete db_; |
27 | DestroyDB(dbname_, Options()); |
28 | delete tiny_cache_; |
29 | } |
30 | |
31 | std::string Key(int i) { |
32 | char buf[100]; |
33 | std::snprintf(buf, sizeof(buf), "key%06d" , i); |
34 | return std::string(buf); |
35 | } |
36 | |
37 | uint64_t Size(const Slice& start, const Slice& limit) { |
38 | Range r(start, limit); |
39 | uint64_t size; |
40 | db_->GetApproximateSizes(&r, 1, &size); |
41 | return size; |
42 | } |
43 | |
44 | void DoReads(int n); |
45 | |
46 | private: |
47 | std::string dbname_; |
48 | Cache* tiny_cache_; |
49 | Options options_; |
50 | DB* db_; |
51 | }; |
52 | |
53 | static const int kValueSize = 200 * 1024; |
54 | static const int kTotalSize = 100 * 1024 * 1024; |
55 | static const int kCount = kTotalSize / kValueSize; |
56 | |
57 | // Read through the first n keys repeatedly and check that they get |
58 | // compacted (verified by checking the size of the key space). |
59 | void AutoCompactTest::DoReads(int n) { |
60 | std::string value(kValueSize, 'x'); |
61 | DBImpl* dbi = reinterpret_cast<DBImpl*>(db_); |
62 | |
63 | // Fill database |
64 | for (int i = 0; i < kCount; i++) { |
65 | ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), Key(i), value)); |
66 | } |
67 | ASSERT_LEVELDB_OK(dbi->TEST_CompactMemTable()); |
68 | |
69 | // Delete everything |
70 | for (int i = 0; i < kCount; i++) { |
71 | ASSERT_LEVELDB_OK(db_->Delete(WriteOptions(), Key(i))); |
72 | } |
73 | ASSERT_LEVELDB_OK(dbi->TEST_CompactMemTable()); |
74 | |
75 | // Get initial measurement of the space we will be reading. |
76 | const int64_t initial_size = Size(Key(0), Key(n)); |
77 | const int64_t initial_other_size = Size(Key(n), Key(kCount)); |
78 | |
79 | // Read until size drops significantly. |
80 | std::string limit_key = Key(n); |
81 | for (int read = 0; true; read++) { |
82 | ASSERT_LT(read, 100) << "Taking too long to compact" ; |
83 | Iterator* iter = db_->NewIterator(ReadOptions()); |
84 | for (iter->SeekToFirst(); |
85 | iter->Valid() && iter->key().ToString() < limit_key; iter->Next()) { |
86 | // Drop data |
87 | } |
88 | delete iter; |
89 | // Wait a little bit to allow any triggered compactions to complete. |
90 | Env::Default()->SleepForMicroseconds(1000000); |
91 | uint64_t size = Size(Key(0), Key(n)); |
92 | std::fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n" , read + 1, |
93 | size / 1048576.0, Size(Key(n), Key(kCount)) / 1048576.0); |
94 | if (size <= initial_size / 10) { |
95 | break; |
96 | } |
97 | } |
98 | |
99 | // Verify that the size of the key space not touched by the reads |
100 | // is pretty much unchanged. |
101 | const int64_t final_other_size = Size(Key(n), Key(kCount)); |
102 | ASSERT_LE(final_other_size, initial_other_size + 1048576); |
103 | ASSERT_GE(final_other_size, initial_other_size / 5 - 1048576); |
104 | } |
105 | |
106 | TEST_F(AutoCompactTest, ReadAll) { DoReads(kCount); } |
107 | |
108 | TEST_F(AutoCompactTest, ReadHalf) { DoReads(kCount / 2); } |
109 | |
110 | } // namespace leveldb |
111 | |