1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same directory.
6 // Test for issue 178: a manual compaction causes deleted data to reappear.
11 #include "rocksdb/db.h"
12 #include "rocksdb/compaction_filter.h"
13 #include "rocksdb/slice.h"
14 #include "rocksdb/write_batch.h"
15 #include "util/testharness.h"
16 #include "port/port.h"
18 using namespace rocksdb
;
22 const int kNumKeys
= 1100000;
24 std::string
Key1(int i
) {
26 snprintf(buf
, sizeof(buf
), "my_key_%d", i
);
30 std::string
Key2(int i
) {
31 return Key1(i
) + "_xxx";
34 class ManualCompactionTest
: public testing::Test
{
36 ManualCompactionTest() {
37 // Get rid of any state from an old run.
38 dbname_
= rocksdb::test::TmpDir() + "/rocksdb_cbug_test";
39 DestroyDB(dbname_
, rocksdb::Options());
45 class DestroyAllCompactionFilter
: public CompactionFilter
{
47 DestroyAllCompactionFilter() {}
49 virtual bool Filter(int level
, const Slice
& key
, const Slice
& existing_value
,
50 std::string
* new_value
,
51 bool* value_changed
) const override
{
52 return existing_value
.ToString() == "destroy";
55 virtual const char* Name() const override
{
56 return "DestroyAllCompactionFilter";
60 TEST_F(ManualCompactionTest
, CompactTouchesAllKeys
) {
61 for (int iter
= 0; iter
< 2; ++iter
) {
64 if (iter
== 0) { // level compaction
65 options
.num_levels
= 3;
66 options
.compaction_style
= kCompactionStyleLevel
;
67 } else { // universal compaction
68 options
.compaction_style
= kCompactionStyleUniversal
;
70 options
.create_if_missing
= true;
71 options
.compression
= rocksdb::kNoCompression
;
72 options
.compaction_filter
= new DestroyAllCompactionFilter();
73 ASSERT_OK(DB::Open(options
, dbname_
, &db
));
75 db
->Put(WriteOptions(), Slice("key1"), Slice("destroy"));
76 db
->Put(WriteOptions(), Slice("key2"), Slice("destroy"));
77 db
->Put(WriteOptions(), Slice("key3"), Slice("value3"));
78 db
->Put(WriteOptions(), Slice("key4"), Slice("destroy"));
81 db
->CompactRange(CompactRangeOptions(), nullptr, &key4
);
82 Iterator
* itr
= db
->NewIterator(ReadOptions());
84 ASSERT_TRUE(itr
->Valid());
85 ASSERT_EQ("key3", itr
->key().ToString());
87 ASSERT_TRUE(!itr
->Valid());
90 delete options
.compaction_filter
;
92 DestroyDB(dbname_
, options
);
96 TEST_F(ManualCompactionTest
, Test
) {
97 // Open database. Disable compression since it affects the creation
98 // of layers and the code below is trying to test against a very
101 rocksdb::Options db_options
;
102 db_options
.create_if_missing
= true;
103 db_options
.compression
= rocksdb::kNoCompression
;
104 ASSERT_OK(rocksdb::DB::Open(db_options
, dbname_
, &db
));
106 // create first key range
107 rocksdb::WriteBatch batch
;
108 for (int i
= 0; i
< kNumKeys
; i
++) {
109 batch
.Put(Key1(i
), "value for range 1 key");
111 ASSERT_OK(db
->Write(rocksdb::WriteOptions(), &batch
));
113 // create second key range
115 for (int i
= 0; i
< kNumKeys
; i
++) {
116 batch
.Put(Key2(i
), "value for range 2 key");
118 ASSERT_OK(db
->Write(rocksdb::WriteOptions(), &batch
));
120 // delete second key range
122 for (int i
= 0; i
< kNumKeys
; i
++) {
123 batch
.Delete(Key2(i
));
125 ASSERT_OK(db
->Write(rocksdb::WriteOptions(), &batch
));
128 std::string start_key
= Key1(0);
129 std::string end_key
= Key1(kNumKeys
- 1);
130 rocksdb::Slice
least(start_key
.data(), start_key
.size());
131 rocksdb::Slice
greatest(end_key
.data(), end_key
.size());
133 // commenting out the line below causes the example to work correctly
134 db
->CompactRange(CompactRangeOptions(), &least
, &greatest
);
137 rocksdb::Iterator
* iter
= db
->NewIterator(rocksdb::ReadOptions());
139 for (iter
->SeekToFirst(); iter
->Valid(); iter
->Next()) {
143 ASSERT_EQ(kNumKeys
, num_keys
) << "Bad number of keys";
147 DestroyDB(dbname_
, rocksdb::Options());
150 } // anonymous namespace
152 int main(int argc
, char** argv
) {
153 ::testing::InitGoogleTest(&argc
, argv
);
154 return RUN_ALL_TESTS();