]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
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). | |
7c673cae FG |
5 | // |
6 | // Test for issue 178: a manual compaction causes deleted data to reappear. | |
7 | #include <iostream> | |
8 | #include <sstream> | |
9 | #include <cstdlib> | |
10 | ||
f67539c2 | 11 | #include "port/port.h" |
7c673cae | 12 | #include "rocksdb/compaction_filter.h" |
f67539c2 | 13 | #include "rocksdb/db.h" |
7c673cae FG |
14 | #include "rocksdb/slice.h" |
15 | #include "rocksdb/write_batch.h" | |
f67539c2 | 16 | #include "test_util/testharness.h" |
7c673cae | 17 | |
f67539c2 | 18 | using namespace ROCKSDB_NAMESPACE; |
7c673cae FG |
19 | |
20 | namespace { | |
21 | ||
11fdf7f2 TL |
22 | // Reasoning: previously the number was 1100000. Since the keys are written to |
23 | // the batch in one write each write will result into one SST file. each write | |
24 | // will result into one SST file. We reduced the write_buffer_size to 1K to | |
25 | // basically have the same effect with however less number of keys, which | |
26 | // results into less test runtime. | |
27 | const int kNumKeys = 1100; | |
7c673cae FG |
28 | |
29 | std::string Key1(int i) { | |
30 | char buf[100]; | |
31 | snprintf(buf, sizeof(buf), "my_key_%d", i); | |
32 | return buf; | |
33 | } | |
34 | ||
35 | std::string Key2(int i) { | |
36 | return Key1(i) + "_xxx"; | |
37 | } | |
38 | ||
39 | class ManualCompactionTest : public testing::Test { | |
40 | public: | |
41 | ManualCompactionTest() { | |
42 | // Get rid of any state from an old run. | |
f67539c2 TL |
43 | dbname_ = ROCKSDB_NAMESPACE::test::PerThreadDBPath("rocksdb_cbug_test"); |
44 | DestroyDB(dbname_, ROCKSDB_NAMESPACE::Options()); | |
7c673cae FG |
45 | } |
46 | ||
47 | std::string dbname_; | |
48 | }; | |
49 | ||
50 | class DestroyAllCompactionFilter : public CompactionFilter { | |
51 | public: | |
52 | DestroyAllCompactionFilter() {} | |
53 | ||
494da23a TL |
54 | bool Filter(int /*level*/, const Slice& /*key*/, const Slice& existing_value, |
55 | std::string* /*new_value*/, | |
56 | bool* /*value_changed*/) const override { | |
7c673cae FG |
57 | return existing_value.ToString() == "destroy"; |
58 | } | |
59 | ||
494da23a | 60 | const char* Name() const override { return "DestroyAllCompactionFilter"; } |
7c673cae FG |
61 | }; |
62 | ||
63 | TEST_F(ManualCompactionTest, CompactTouchesAllKeys) { | |
64 | for (int iter = 0; iter < 2; ++iter) { | |
65 | DB* db; | |
66 | Options options; | |
67 | if (iter == 0) { // level compaction | |
68 | options.num_levels = 3; | |
69 | options.compaction_style = kCompactionStyleLevel; | |
70 | } else { // universal compaction | |
71 | options.compaction_style = kCompactionStyleUniversal; | |
72 | } | |
73 | options.create_if_missing = true; | |
f67539c2 | 74 | options.compression = ROCKSDB_NAMESPACE::kNoCompression; |
7c673cae FG |
75 | options.compaction_filter = new DestroyAllCompactionFilter(); |
76 | ASSERT_OK(DB::Open(options, dbname_, &db)); | |
77 | ||
78 | db->Put(WriteOptions(), Slice("key1"), Slice("destroy")); | |
79 | db->Put(WriteOptions(), Slice("key2"), Slice("destroy")); | |
80 | db->Put(WriteOptions(), Slice("key3"), Slice("value3")); | |
81 | db->Put(WriteOptions(), Slice("key4"), Slice("destroy")); | |
82 | ||
83 | Slice key4("key4"); | |
84 | db->CompactRange(CompactRangeOptions(), nullptr, &key4); | |
85 | Iterator* itr = db->NewIterator(ReadOptions()); | |
86 | itr->SeekToFirst(); | |
87 | ASSERT_TRUE(itr->Valid()); | |
88 | ASSERT_EQ("key3", itr->key().ToString()); | |
89 | itr->Next(); | |
90 | ASSERT_TRUE(!itr->Valid()); | |
91 | delete itr; | |
92 | ||
93 | delete options.compaction_filter; | |
94 | delete db; | |
95 | DestroyDB(dbname_, options); | |
96 | } | |
97 | } | |
98 | ||
99 | TEST_F(ManualCompactionTest, Test) { | |
100 | // Open database. Disable compression since it affects the creation | |
101 | // of layers and the code below is trying to test against a very | |
102 | // specific scenario. | |
f67539c2 TL |
103 | ROCKSDB_NAMESPACE::DB* db; |
104 | ROCKSDB_NAMESPACE::Options db_options; | |
11fdf7f2 | 105 | db_options.write_buffer_size = 1024; |
7c673cae | 106 | db_options.create_if_missing = true; |
f67539c2 TL |
107 | db_options.compression = ROCKSDB_NAMESPACE::kNoCompression; |
108 | ASSERT_OK(ROCKSDB_NAMESPACE::DB::Open(db_options, dbname_, &db)); | |
7c673cae FG |
109 | |
110 | // create first key range | |
f67539c2 | 111 | ROCKSDB_NAMESPACE::WriteBatch batch; |
7c673cae FG |
112 | for (int i = 0; i < kNumKeys; i++) { |
113 | batch.Put(Key1(i), "value for range 1 key"); | |
114 | } | |
f67539c2 | 115 | ASSERT_OK(db->Write(ROCKSDB_NAMESPACE::WriteOptions(), &batch)); |
7c673cae FG |
116 | |
117 | // create second key range | |
118 | batch.Clear(); | |
119 | for (int i = 0; i < kNumKeys; i++) { | |
120 | batch.Put(Key2(i), "value for range 2 key"); | |
121 | } | |
f67539c2 | 122 | ASSERT_OK(db->Write(ROCKSDB_NAMESPACE::WriteOptions(), &batch)); |
7c673cae FG |
123 | |
124 | // delete second key range | |
125 | batch.Clear(); | |
126 | for (int i = 0; i < kNumKeys; i++) { | |
127 | batch.Delete(Key2(i)); | |
128 | } | |
f67539c2 | 129 | ASSERT_OK(db->Write(ROCKSDB_NAMESPACE::WriteOptions(), &batch)); |
7c673cae FG |
130 | |
131 | // compact database | |
132 | std::string start_key = Key1(0); | |
133 | std::string end_key = Key1(kNumKeys - 1); | |
f67539c2 TL |
134 | ROCKSDB_NAMESPACE::Slice least(start_key.data(), start_key.size()); |
135 | ROCKSDB_NAMESPACE::Slice greatest(end_key.data(), end_key.size()); | |
7c673cae FG |
136 | |
137 | // commenting out the line below causes the example to work correctly | |
138 | db->CompactRange(CompactRangeOptions(), &least, &greatest); | |
139 | ||
140 | // count the keys | |
f67539c2 TL |
141 | ROCKSDB_NAMESPACE::Iterator* iter = |
142 | db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions()); | |
7c673cae FG |
143 | int num_keys = 0; |
144 | for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { | |
145 | num_keys++; | |
146 | } | |
147 | delete iter; | |
148 | ASSERT_EQ(kNumKeys, num_keys) << "Bad number of keys"; | |
149 | ||
150 | // close database | |
151 | delete db; | |
f67539c2 | 152 | DestroyDB(dbname_, ROCKSDB_NAMESPACE::Options()); |
7c673cae FG |
153 | } |
154 | ||
155 | } // anonymous namespace | |
156 | ||
157 | int main(int argc, char** argv) { | |
158 | ::testing::InitGoogleTest(&argc, argv); | |
159 | return RUN_ALL_TESTS(); | |
160 | } |