]>
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 | // 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. | |
9 | ||
10 | #include <stdio.h> | |
11 | ||
12 | #ifndef ROCKSDB_LITE | |
13 | #include <algorithm> | |
14 | #include <cmath> | |
15 | #include <vector> | |
16 | ||
20effc67 | 17 | #include "port/stack_trace.h" |
7c673cae FG |
18 | #include "rocksdb/table.h" |
19 | #include "rocksdb/table_properties.h" | |
20 | #include "rocksdb/utilities/table_properties_collectors.h" | |
20effc67 | 21 | #include "test_util/testharness.h" |
7c673cae FG |
22 | #include "util/random.h" |
23 | #include "utilities/table_properties_collectors/compact_on_deletion_collector.h" | |
24 | ||
20effc67 TL |
25 | namespace ROCKSDB_NAMESPACE { |
26 | ||
27 | TEST(CompactOnDeletionCollector, DeletionRatio) { | |
28 | TablePropertiesCollectorFactory::Context context; | |
29 | context.column_family_id = | |
30 | TablePropertiesCollectorFactory::Context::kUnknownColumnFamily; | |
31 | const size_t kTotalEntries = 100; | |
32 | ||
33 | { | |
34 | // Disable deletion ratio. | |
35 | for (double deletion_ratio : {-1.5, -1.0, 0.0, 1.5, 2.0}) { | |
36 | auto factory = NewCompactOnDeletionCollectorFactory(0, 0, deletion_ratio); | |
37 | std::unique_ptr<TablePropertiesCollector> collector( | |
38 | factory->CreateTablePropertiesCollector(context)); | |
39 | for (size_t i = 0; i < kTotalEntries; i++) { | |
40 | // All entries are deletion entries. | |
1e59de90 TL |
41 | ASSERT_OK( |
42 | collector->AddUserKey("hello", "rocksdb", kEntryDelete, 0, 0)); | |
20effc67 TL |
43 | ASSERT_FALSE(collector->NeedCompact()); |
44 | } | |
1e59de90 | 45 | ASSERT_OK(collector->Finish(nullptr)); |
20effc67 TL |
46 | ASSERT_FALSE(collector->NeedCompact()); |
47 | } | |
48 | } | |
49 | ||
50 | { | |
51 | for (double deletion_ratio : {0.3, 0.5, 0.8, 1.0}) { | |
52 | auto factory = NewCompactOnDeletionCollectorFactory(0, 0, deletion_ratio); | |
53 | const size_t deletion_entries_trigger = | |
54 | static_cast<size_t>(deletion_ratio * kTotalEntries); | |
55 | for (int delta : {-1, 0, 1}) { | |
56 | // Actual deletion entry ratio <, =, > deletion_ratio | |
57 | size_t actual_deletion_entries = deletion_entries_trigger + delta; | |
58 | std::unique_ptr<TablePropertiesCollector> collector( | |
59 | factory->CreateTablePropertiesCollector(context)); | |
60 | for (size_t i = 0; i < kTotalEntries; i++) { | |
61 | if (i < actual_deletion_entries) { | |
1e59de90 TL |
62 | ASSERT_OK( |
63 | collector->AddUserKey("hello", "rocksdb", kEntryDelete, 0, 0)); | |
20effc67 | 64 | } else { |
1e59de90 TL |
65 | ASSERT_OK( |
66 | collector->AddUserKey("hello", "rocksdb", kEntryPut, 0, 0)); | |
20effc67 TL |
67 | } |
68 | ASSERT_FALSE(collector->NeedCompact()); | |
69 | } | |
1e59de90 | 70 | ASSERT_OK(collector->Finish(nullptr)); |
20effc67 TL |
71 | if (delta >= 0) { |
72 | // >= deletion_ratio | |
73 | ASSERT_TRUE(collector->NeedCompact()); | |
74 | } else { | |
75 | ASSERT_FALSE(collector->NeedCompact()); | |
76 | } | |
77 | } | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | TEST(CompactOnDeletionCollector, SlidingWindow) { | |
1e59de90 TL |
83 | const int kWindowSizes[] = {1000, 10000, 10000, 127, 128, 129, |
84 | 255, 256, 257, 2, 10000}; | |
85 | const int kDeletionTriggers[] = {500, 9500, 4323, 47, 61, 128, | |
86 | 250, 250, 250, 2, 2}; | |
20effc67 TL |
87 | TablePropertiesCollectorFactory::Context context; |
88 | context.column_family_id = | |
f67539c2 | 89 | TablePropertiesCollectorFactory::Context::kUnknownColumnFamily; |
7c673cae FG |
90 | |
91 | std::vector<int> window_sizes; | |
92 | std::vector<int> deletion_triggers; | |
93 | // deterministic tests | |
94 | for (int test = 0; test < 9; ++test) { | |
95 | window_sizes.emplace_back(kWindowSizes[test]); | |
96 | deletion_triggers.emplace_back(kDeletionTriggers[test]); | |
97 | } | |
98 | ||
99 | // randomize tests | |
20effc67 | 100 | Random rnd(301); |
7c673cae | 101 | const int kMaxTestSize = 100000l; |
f67539c2 | 102 | for (int random_test = 0; random_test < 10; random_test++) { |
7c673cae FG |
103 | int window_size = rnd.Uniform(kMaxTestSize) + 1; |
104 | int deletion_trigger = rnd.Uniform(window_size); | |
105 | window_sizes.emplace_back(window_size); | |
106 | deletion_triggers.emplace_back(deletion_trigger); | |
107 | } | |
108 | ||
109 | assert(window_sizes.size() == deletion_triggers.size()); | |
110 | ||
111 | for (size_t test = 0; test < window_sizes.size(); ++test) { | |
112 | const int kBucketSize = 128; | |
113 | const int kWindowSize = window_sizes[test]; | |
114 | const int kPaddedWindowSize = | |
115 | kBucketSize * ((window_sizes[test] + kBucketSize - 1) / kBucketSize); | |
116 | const int kNumDeletionTrigger = deletion_triggers[test]; | |
117 | const int kBias = (kNumDeletionTrigger + kBucketSize - 1) / kBucketSize; | |
118 | // Simple test | |
119 | { | |
20effc67 TL |
120 | auto factory = NewCompactOnDeletionCollectorFactory(kWindowSize, |
121 | kNumDeletionTrigger); | |
7c673cae FG |
122 | const int kSample = 10; |
123 | for (int delete_rate = 0; delete_rate <= kSample; ++delete_rate) { | |
20effc67 | 124 | std::unique_ptr<TablePropertiesCollector> collector( |
11fdf7f2 | 125 | factory->CreateTablePropertiesCollector(context)); |
7c673cae FG |
126 | int deletions = 0; |
127 | for (int i = 0; i < kPaddedWindowSize; ++i) { | |
128 | if (i % kSample < delete_rate) { | |
1e59de90 TL |
129 | ASSERT_OK( |
130 | collector->AddUserKey("hello", "rocksdb", kEntryDelete, 0, 0)); | |
7c673cae FG |
131 | deletions++; |
132 | } else { | |
1e59de90 TL |
133 | ASSERT_OK( |
134 | collector->AddUserKey("hello", "rocksdb", kEntryPut, 0, 0)); | |
7c673cae FG |
135 | } |
136 | } | |
1e59de90 | 137 | if (collector->NeedCompact() != (deletions >= kNumDeletionTrigger) && |
7c673cae | 138 | std::abs(deletions - kNumDeletionTrigger) > kBias) { |
1e59de90 TL |
139 | fprintf(stderr, |
140 | "[Error] collector->NeedCompact() != (%d >= %d)" | |
7c673cae | 141 | " with kWindowSize = %d and kNumDeletionTrigger = %d\n", |
1e59de90 TL |
142 | deletions, kNumDeletionTrigger, kWindowSize, |
143 | kNumDeletionTrigger); | |
20effc67 | 144 | ASSERT_TRUE(false); |
7c673cae | 145 | } |
1e59de90 | 146 | ASSERT_OK(collector->Finish(nullptr)); |
7c673cae FG |
147 | } |
148 | } | |
149 | ||
150 | // Only one section of a file satisfies the compaction trigger | |
151 | { | |
20effc67 TL |
152 | auto factory = NewCompactOnDeletionCollectorFactory(kWindowSize, |
153 | kNumDeletionTrigger); | |
7c673cae FG |
154 | const int kSample = 10; |
155 | for (int delete_rate = 0; delete_rate <= kSample; ++delete_rate) { | |
20effc67 | 156 | std::unique_ptr<TablePropertiesCollector> collector( |
11fdf7f2 | 157 | factory->CreateTablePropertiesCollector(context)); |
7c673cae FG |
158 | int deletions = 0; |
159 | for (int section = 0; section < 5; ++section) { | |
160 | int initial_entries = rnd.Uniform(kWindowSize) + kWindowSize; | |
161 | for (int i = 0; i < initial_entries; ++i) { | |
1e59de90 TL |
162 | ASSERT_OK( |
163 | collector->AddUserKey("hello", "rocksdb", kEntryPut, 0, 0)); | |
7c673cae FG |
164 | } |
165 | } | |
166 | for (int i = 0; i < kPaddedWindowSize; ++i) { | |
167 | if (i % kSample < delete_rate) { | |
1e59de90 TL |
168 | ASSERT_OK( |
169 | collector->AddUserKey("hello", "rocksdb", kEntryDelete, 0, 0)); | |
7c673cae FG |
170 | deletions++; |
171 | } else { | |
1e59de90 TL |
172 | ASSERT_OK( |
173 | collector->AddUserKey("hello", "rocksdb", kEntryPut, 0, 0)); | |
7c673cae FG |
174 | } |
175 | } | |
176 | for (int section = 0; section < 5; ++section) { | |
177 | int ending_entries = rnd.Uniform(kWindowSize) + kWindowSize; | |
178 | for (int i = 0; i < ending_entries; ++i) { | |
1e59de90 TL |
179 | ASSERT_OK( |
180 | collector->AddUserKey("hello", "rocksdb", kEntryPut, 0, 0)); | |
7c673cae FG |
181 | } |
182 | } | |
183 | if (collector->NeedCompact() != (deletions >= kNumDeletionTrigger) && | |
184 | std::abs(deletions - kNumDeletionTrigger) > kBias) { | |
1e59de90 TL |
185 | fprintf(stderr, |
186 | "[Error] collector->NeedCompact() %d != (%d >= %d)" | |
7c673cae | 187 | " with kWindowSize = %d, kNumDeletionTrigger = %d\n", |
1e59de90 TL |
188 | collector->NeedCompact(), deletions, kNumDeletionTrigger, |
189 | kWindowSize, kNumDeletionTrigger); | |
20effc67 | 190 | ASSERT_TRUE(false); |
7c673cae | 191 | } |
1e59de90 | 192 | ASSERT_OK(collector->Finish(nullptr)); |
7c673cae FG |
193 | } |
194 | } | |
195 | ||
196 | // TEST 3: Issues a lots of deletes, but their density is not | |
197 | // high enough to trigger compaction. | |
198 | { | |
20effc67 TL |
199 | std::unique_ptr<TablePropertiesCollector> collector; |
200 | auto factory = NewCompactOnDeletionCollectorFactory(kWindowSize, | |
201 | kNumDeletionTrigger); | |
7c673cae FG |
202 | collector.reset(factory->CreateTablePropertiesCollector(context)); |
203 | assert(collector->NeedCompact() == false); | |
204 | // Insert "kNumDeletionTrigger * 0.95" deletions for every | |
205 | // "kWindowSize" and verify compaction is not needed. | |
206 | const int kDeletionsPerSection = kNumDeletionTrigger * 95 / 100; | |
207 | if (kDeletionsPerSection >= 0) { | |
208 | for (int section = 0; section < 200; ++section) { | |
209 | for (int i = 0; i < kPaddedWindowSize; ++i) { | |
210 | if (i < kDeletionsPerSection) { | |
1e59de90 TL |
211 | ASSERT_OK(collector->AddUserKey("hello", "rocksdb", kEntryDelete, |
212 | 0, 0)); | |
7c673cae | 213 | } else { |
1e59de90 TL |
214 | ASSERT_OK( |
215 | collector->AddUserKey("hello", "rocksdb", kEntryPut, 0, 0)); | |
7c673cae FG |
216 | } |
217 | } | |
218 | } | |
219 | if (collector->NeedCompact() && | |
220 | std::abs(kDeletionsPerSection - kNumDeletionTrigger) > kBias) { | |
1e59de90 TL |
221 | fprintf(stderr, |
222 | "[Error] collector->NeedCompact() != false" | |
7c673cae FG |
223 | " with kWindowSize = %d and kNumDeletionTrigger = %d\n", |
224 | kWindowSize, kNumDeletionTrigger); | |
20effc67 | 225 | ASSERT_TRUE(false); |
7c673cae | 226 | } |
1e59de90 | 227 | ASSERT_OK(collector->Finish(nullptr)); |
7c673cae FG |
228 | } |
229 | } | |
230 | } | |
20effc67 TL |
231 | } |
232 | ||
233 | } // namespace ROCKSDB_NAMESPACE | |
234 | ||
235 | int main(int argc, char** argv) { | |
236 | ROCKSDB_NAMESPACE::port::InstallStackTraceHandler(); | |
237 | ::testing::InitGoogleTest(&argc, argv); | |
238 | return RUN_ALL_TESTS(); | |
7c673cae FG |
239 | } |
240 | #else | |
11fdf7f2 | 241 | int main(int /*argc*/, char** /*argv*/) { |
7c673cae FG |
242 | fprintf(stderr, "SKIPPED as RocksDBLite does not include utilities.\n"); |
243 | return 0; | |
244 | } | |
245 | #endif // !ROCKSDB_LITE |