/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/db_properties_test.cc
Line | Count | Source (jump to first uncovered line) |
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. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | |
24 | | #include <string> |
25 | | |
26 | | #include "yb/rocksdb/db/db_test_util.h" |
27 | | #include "yb/rocksdb/perf_context.h" |
28 | | #include "yb/rocksdb/perf_level.h" |
29 | | #include "yb/rocksdb/port/stack_trace.h" |
30 | | |
31 | | namespace rocksdb { |
32 | | |
33 | | class DBPropertiesTest : public DBTestBase { |
34 | | public: |
35 | 15 | DBPropertiesTest() : DBTestBase("/db_properties_test") {} |
36 | | }; |
37 | | |
38 | | #ifndef ROCKSDB_LITE |
39 | 1 | TEST_F(DBPropertiesTest, Empty) { |
40 | 30 | do { |
41 | 30 | Options options; |
42 | 30 | options.env = env_; |
43 | 30 | options.write_buffer_size = 100000; // Small write buffer |
44 | 30 | options = CurrentOptions(options); |
45 | 30 | CreateAndReopenWithCF({"pikachu"}, options); |
46 | | |
47 | 30 | std::string num; |
48 | 30 | ASSERT_TRUE(dbfull()->GetProperty( |
49 | 30 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
50 | 30 | ASSERT_EQ("0", num); |
51 | | |
52 | 30 | ASSERT_OK(Put(1, "foo", "v1")); |
53 | 30 | ASSERT_EQ("v1", Get(1, "foo")); |
54 | 30 | ASSERT_TRUE(dbfull()->GetProperty( |
55 | 30 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
56 | 30 | ASSERT_EQ("1", num); |
57 | | |
58 | | // Block sync calls |
59 | 30 | env_->delay_sstable_sync_.store(true, std::memory_order_release); |
60 | 30 | ASSERT_OK(Put(1, "k1", std::string(100000, 'x'))); // Fill memtable |
61 | 30 | ASSERT_TRUE(dbfull()->GetProperty( |
62 | 30 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
63 | 30 | ASSERT_EQ("2", num); |
64 | | |
65 | 30 | ASSERT_OK(Put(1, "k2", std::string(100000, 'y'))); // Trigger compaction |
66 | 30 | ASSERT_TRUE(dbfull()->GetProperty( |
67 | 30 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
68 | 30 | ASSERT_EQ("1", num); |
69 | | |
70 | 30 | ASSERT_EQ("v1", Get(1, "foo")); |
71 | | // Release sync calls |
72 | 30 | env_->delay_sstable_sync_.store(false, std::memory_order_release); |
73 | | |
74 | 30 | ASSERT_OK(db_->DisableFileDeletions()); |
75 | 30 | ASSERT_TRUE( |
76 | 30 | dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); |
77 | 30 | ASSERT_EQ("1", num); |
78 | | |
79 | 30 | ASSERT_OK(db_->DisableFileDeletions()); |
80 | 30 | ASSERT_TRUE( |
81 | 30 | dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); |
82 | 30 | ASSERT_EQ("2", num); |
83 | | |
84 | 30 | ASSERT_OK(db_->DisableFileDeletions()); |
85 | 30 | ASSERT_TRUE( |
86 | 30 | dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); |
87 | 30 | ASSERT_EQ("3", num); |
88 | | |
89 | 30 | ASSERT_OK(db_->EnableFileDeletions(false)); |
90 | 30 | ASSERT_TRUE( |
91 | 30 | dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); |
92 | 30 | ASSERT_EQ("2", num); |
93 | | |
94 | 30 | ASSERT_OK(db_->EnableFileDeletions()); |
95 | 30 | ASSERT_TRUE( |
96 | 30 | dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); |
97 | 30 | ASSERT_EQ("0", num); |
98 | 30 | } while (ChangeOptions()); |
99 | 1 | } |
100 | | |
101 | 1 | TEST_F(DBPropertiesTest, CurrentVersionNumber) { |
102 | 1 | uint64_t v1, v2, v3; |
103 | 1 | ASSERT_TRUE( |
104 | 1 | dbfull()->GetIntProperty("rocksdb.current-super-version-number", &v1)); |
105 | 1 | ASSERT_OK(Put("12345678", "")); |
106 | 1 | ASSERT_TRUE( |
107 | 1 | dbfull()->GetIntProperty("rocksdb.current-super-version-number", &v2)); |
108 | 1 | ASSERT_OK(Flush());; |
109 | 1 | ASSERT_TRUE( |
110 | 1 | dbfull()->GetIntProperty("rocksdb.current-super-version-number", &v3)); |
111 | | |
112 | 1 | ASSERT_EQ(v1, v2); |
113 | 1 | ASSERT_GT(v3, v2); |
114 | 1 | } |
115 | | |
116 | 1 | TEST_F(DBPropertiesTest, GetAggregatedIntPropertyTest) { |
117 | 1 | const int kKeySize = 100; |
118 | 1 | const int kValueSize = 500; |
119 | 1 | const int kKeyNum = 100; |
120 | | |
121 | 1 | Options options; |
122 | 1 | options.env = env_; |
123 | 1 | options.create_if_missing = true; |
124 | 1 | options.write_buffer_size = (kKeySize + kValueSize) * kKeyNum / 10; |
125 | | // Make them never flush |
126 | 1 | options.min_write_buffer_number_to_merge = 1000; |
127 | 1 | options.max_write_buffer_number = 1000; |
128 | 1 | options = CurrentOptions(options); |
129 | 1 | CreateAndReopenWithCF({"one", "two", "three", "four"}, options); |
130 | | |
131 | 1 | Random rnd(301); |
132 | 5 | for (auto* handle : handles_) { |
133 | 505 | for (int i = 0; i < kKeyNum; ++i) { |
134 | 500 | ASSERT_OK(db_->Put( |
135 | 500 | WriteOptions(), handle, RandomString(&rnd, kKeySize), RandomString(&rnd, kValueSize))); |
136 | 500 | } |
137 | 5 | } |
138 | | |
139 | 1 | uint64_t manual_sum = 0; |
140 | 1 | uint64_t api_sum = 0; |
141 | 1 | uint64_t value = 0; |
142 | 5 | for (auto* handle : handles_) { |
143 | 5 | ASSERT_TRUE( |
144 | 5 | db_->GetIntProperty(handle, DB::Properties::kSizeAllMemTables, &value)); |
145 | 5 | manual_sum += value; |
146 | 5 | } |
147 | 1 | ASSERT_TRUE(db_->GetAggregatedIntProperty(DB::Properties::kSizeAllMemTables, |
148 | 1 | &api_sum)); |
149 | 1 | ASSERT_GT(manual_sum, 0); |
150 | 1 | ASSERT_EQ(manual_sum, api_sum); |
151 | | |
152 | 1 | ASSERT_FALSE(db_->GetAggregatedIntProperty(DB::Properties::kDBStats, &value)); |
153 | | |
154 | 1 | uint64_t before_flush_trm; |
155 | 1 | uint64_t after_flush_trm; |
156 | 5 | for (auto* handle : handles_) { |
157 | 5 | ASSERT_TRUE(db_->GetAggregatedIntProperty( |
158 | 5 | DB::Properties::kEstimateTableReadersMem, &before_flush_trm)); |
159 | | |
160 | | // Issue flush and expect larger memory usage of table readers. |
161 | 5 | ASSERT_OK(db_->Flush(FlushOptions(), handle)); |
162 | | |
163 | 5 | ASSERT_TRUE(db_->GetAggregatedIntProperty( |
164 | 5 | DB::Properties::kEstimateTableReadersMem, &after_flush_trm)); |
165 | 5 | ASSERT_GT(after_flush_trm, before_flush_trm); |
166 | 5 | } |
167 | 1 | } |
168 | | |
169 | | namespace { |
170 | 903 | void ResetTableProperties(TableProperties* tp) { |
171 | 903 | tp->data_size = 0; |
172 | 903 | tp->data_index_size = 0; |
173 | 903 | tp->filter_size = 0; |
174 | 903 | tp->filter_index_size = 0; |
175 | 903 | tp->raw_key_size = 0; |
176 | 903 | tp->raw_value_size = 0; |
177 | 903 | tp->num_data_blocks = 0; |
178 | 903 | tp->num_entries = 0; |
179 | 903 | tp->num_filter_blocks = 0; |
180 | 903 | tp->num_data_index_blocks = 0; |
181 | 903 | } |
182 | | |
183 | 803 | void ParseTablePropertiesString(std::string tp_string, TableProperties* tp) { |
184 | 803 | double dummy_double; |
185 | 803 | std::replace(tp_string.begin(), tp_string.end(), ';', ' '); |
186 | 803 | std::replace(tp_string.begin(), tp_string.end(), '=', ' '); |
187 | 803 | ResetTableProperties(tp); |
188 | | |
189 | 803 | sscanf(tp_string.c_str(), |
190 | 803 | "# data blocks %" SCNu64 |
191 | 803 | " # data index blocks %" SCNu64 |
192 | 803 | " # filter blocks %" SCNu64 |
193 | 803 | " # entries %" SCNu64 |
194 | 803 | " raw key size %" SCNu64 |
195 | 803 | " raw average key size %lf " |
196 | 803 | " raw value size %" SCNu64 |
197 | 803 | " raw average value size %lf " |
198 | 803 | " data blocks total size %" SCNu64 |
199 | 803 | " data index size %" SCNu64 |
200 | 803 | " filter blocks total size %" SCNu64 |
201 | 803 | " filter index block size %" SCNu64, |
202 | 803 | &tp->num_data_blocks, &tp->num_data_index_blocks, &tp->num_filter_blocks, &tp->num_entries, |
203 | 803 | &tp->raw_key_size, &dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size, |
204 | 803 | &tp->data_index_size, &tp->filter_size, &tp->filter_index_size); |
205 | 803 | } |
206 | | |
207 | 500 | void VerifySimilar(uint64_t a, uint64_t b, double bias, const std::string& label) { |
208 | 1.00k | ASSERT_EQ(a == 0U, b == 0U) << " " << label << ": " << a << " vs " << b; |
209 | 500 | if (a == 0) { |
210 | 100 | return; |
211 | 100 | } |
212 | 400 | const double dbl_a = static_cast<double>(a); |
213 | 400 | const double dbl_b = static_cast<double>(b); |
214 | 800 | ASSERT_LT(fabs(dbl_a - dbl_b) / (dbl_a + dbl_b), bias) |
215 | 800 | << " " << label << ": " << a << " vs " << b; |
216 | 400 | } |
217 | | |
218 | | void VerifyTableProperties(const TableProperties& base_tp, |
219 | | const TableProperties& new_tp, |
220 | | double filter_size_bias = 0.1, |
221 | | double index_size_bias = 0.1, |
222 | | double data_size_bias = 0.1, |
223 | 100 | double num_data_blocks_bias = 0.05) { |
224 | 100 | VerifySimilar(base_tp.data_size, new_tp.data_size, data_size_bias, "data_size"); |
225 | 100 | VerifySimilar( |
226 | 100 | base_tp.data_index_size, new_tp.data_index_size, index_size_bias, "data_index_size"); |
227 | 100 | VerifySimilar(base_tp.filter_size, new_tp.filter_size, filter_size_bias, "filter_size"); |
228 | 100 | VerifySimilar( |
229 | 100 | base_tp.filter_index_size, new_tp.filter_index_size, index_size_bias, "filter_index_size"); |
230 | 100 | VerifySimilar( |
231 | 100 | base_tp.num_data_blocks, new_tp.num_data_blocks, num_data_blocks_bias, "num_data_blocks"); |
232 | 100 | ASSERT_EQ(base_tp.raw_key_size, new_tp.raw_key_size); |
233 | 100 | ASSERT_EQ(base_tp.raw_value_size, new_tp.raw_value_size); |
234 | 100 | ASSERT_EQ(base_tp.num_entries, new_tp.num_entries); |
235 | 100 | } |
236 | | |
237 | | void GetExpectedTableProperties(TableProperties* expected_tp, |
238 | | const int kKeySize, const int kValueSize, |
239 | | const int kKeysPerTable, const int kTableCount, |
240 | | const int kBloomBitsPerKey, |
241 | 100 | const size_t kBlockSize) { |
242 | 100 | const int kKeyCount = kTableCount * kKeysPerTable; |
243 | 100 | const int kAvgSuccessorSize = kKeySize / 6; |
244 | 100 | const int kEncodingSavePerKey = kKeySize / 4; |
245 | 100 | expected_tp->raw_key_size = kKeyCount * (kKeySize + 8); |
246 | 100 | expected_tp->raw_value_size = kKeyCount * kValueSize; |
247 | 100 | expected_tp->num_entries = kKeyCount; |
248 | 100 | expected_tp->num_data_blocks = |
249 | 100 | kTableCount * |
250 | 100 | (kKeysPerTable * (kKeySize - kEncodingSavePerKey + kValueSize)) / |
251 | 100 | kBlockSize; |
252 | 100 | expected_tp->data_size = |
253 | 100 | kTableCount * (kKeysPerTable * (kKeySize + 8 + kValueSize)); |
254 | 100 | expected_tp->data_index_size = |
255 | 100 | expected_tp->num_data_blocks * (kAvgSuccessorSize + 12); |
256 | 100 | expected_tp->filter_index_size = 0; // Only applicable to fixed-size filter. |
257 | 100 | expected_tp->filter_size = |
258 | 100 | kTableCount * (kKeysPerTable * kBloomBitsPerKey / 8); |
259 | | // For block-based filter number of data and filter blocks is the same. |
260 | 100 | expected_tp->num_filter_blocks = expected_tp->num_data_blocks; |
261 | 100 | } |
262 | | } // anonymous namespace |
263 | | |
264 | 1 | TEST_F(DBPropertiesTest, ValidatePropertyInfo) { |
265 | 33 | for (const auto& ppt_name_and_info : InternalStats::ppt_name_to_info) { |
266 | | // If C++ gets a std::string_literal, this would be better to check at |
267 | | // compile-time using static_assert. |
268 | 33 | ASSERT_TRUE(ppt_name_and_info.first.empty() || |
269 | 33 | !isdigit(ppt_name_and_info.first.back())); |
270 | | |
271 | 33 | ASSERT_TRUE((ppt_name_and_info.second.handle_string == nullptr) != |
272 | 33 | (ppt_name_and_info.second.handle_int == nullptr)); |
273 | 33 | } |
274 | 1 | } |
275 | | |
276 | 1 | TEST_F(DBPropertiesTest, AggregatedTableProperties) { |
277 | 4 | for (int kTableCount = 40; kTableCount <= 100; kTableCount += 30) { |
278 | 3 | const int kKeysPerTable = 100; |
279 | 3 | const int kKeySize = 80; |
280 | 3 | const int kValueSize = 200; |
281 | 3 | const int kBloomBitsPerKey = 20; |
282 | | |
283 | 3 | Options options = CurrentOptions(); |
284 | 3 | options.level0_file_num_compaction_trigger = 8; |
285 | 3 | options.compression = kNoCompression; |
286 | 3 | options.create_if_missing = true; |
287 | | |
288 | 3 | BlockBasedTableOptions table_options; |
289 | 3 | table_options.filter_policy.reset( |
290 | 3 | NewBloomFilterPolicy(kBloomBitsPerKey, false)); |
291 | 3 | table_options.block_size = 1024; |
292 | 3 | options.table_factory.reset(new BlockBasedTableFactory(table_options)); |
293 | | |
294 | 3 | DestroyAndReopen(options); |
295 | | |
296 | 3 | Random rnd(5632); |
297 | 213 | for (int table = 1; table <= kTableCount; ++table) { |
298 | 21.2k | for (int i = 0; i < kKeysPerTable; ++i) { |
299 | 21.0k | ASSERT_OK(db_->Put( |
300 | 21.0k | WriteOptions(), RandomString(&rnd, kKeySize), RandomString(&rnd, kValueSize))); |
301 | 21.0k | } |
302 | 210 | ASSERT_OK(db_->Flush(FlushOptions())); |
303 | 210 | } |
304 | 3 | std::string property; |
305 | 3 | db_->GetProperty(DB::Properties::kAggregatedTableProperties, &property); |
306 | | |
307 | 3 | TableProperties expected_tp; |
308 | 3 | GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize, |
309 | 3 | kKeysPerTable, kTableCount, kBloomBitsPerKey, |
310 | 3 | table_options.block_size); |
311 | | |
312 | 3 | TableProperties output_tp; |
313 | 3 | ParseTablePropertiesString(property, &output_tp); |
314 | | |
315 | 3 | VerifyTableProperties(expected_tp, output_tp); |
316 | 3 | } |
317 | 1 | } |
318 | | |
319 | 1 | TEST_F(DBPropertiesTest, ReadLatencyHistogramByLevel) { |
320 | 1 | Options options = CurrentOptions(); |
321 | 1 | options.write_buffer_size = 110 << 10; |
322 | 1 | options.level0_file_num_compaction_trigger = 6; |
323 | 1 | options.num_levels = 4; |
324 | 1 | options.compression = kNoCompression; |
325 | 1 | options.max_bytes_for_level_base = 4500 << 10; |
326 | 1 | options.target_file_size_base = 98 << 10; |
327 | 1 | options.max_write_buffer_number = 2; |
328 | 1 | options.statistics = rocksdb::CreateDBStatisticsForTests(); |
329 | 1 | options.max_open_files = 100; |
330 | | |
331 | 1 | BlockBasedTableOptions table_options; |
332 | 1 | table_options.no_block_cache = true; |
333 | | |
334 | 1 | DestroyAndReopen(options); |
335 | 1 | int key_index = 0; |
336 | 1 | Random rnd(301); |
337 | 9 | for (int num = 0; num < 8; num++) { |
338 | 8 | ASSERT_OK(Put("foo", "bar")); |
339 | 8 | GenerateNewFile(&rnd, &key_index); |
340 | 8 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
341 | 8 | } |
342 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
343 | | |
344 | 1 | std::string prop; |
345 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
346 | | |
347 | | // Get() after flushes, See latency histogram tracked. |
348 | 801 | for (int key = 0; key < key_index; key++) { |
349 | 800 | Get(Key(key)); |
350 | 800 | } |
351 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
352 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram")); |
353 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram")); |
354 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram")); |
355 | | |
356 | | // Reopen and issue Get(). See thee latency tracked |
357 | 1 | Reopen(options); |
358 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
359 | 801 | for (int key = 0; key < key_index; key++) { |
360 | 800 | Get(Key(key)); |
361 | 800 | } |
362 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
363 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram")); |
364 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram")); |
365 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram")); |
366 | | |
367 | | // Reopen and issue iterating. See thee latency tracked |
368 | 1 | Reopen(options); |
369 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
370 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 0 read latency histogram")); |
371 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 1 read latency histogram")); |
372 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram")); |
373 | 1 | { |
374 | 1 | unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions())); |
375 | 801 | for (iter->Seek(Key(0)); iter->Valid(); iter->Next()) { |
376 | 800 | } |
377 | 1 | } |
378 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
379 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram")); |
380 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram")); |
381 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram")); |
382 | | |
383 | | // options.max_open_files preloads table readers. |
384 | 1 | options.max_open_files = -1; |
385 | 1 | Reopen(options); |
386 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
387 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram")); |
388 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram")); |
389 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram")); |
390 | 801 | for (int key = 0; key < key_index; key++) { |
391 | 800 | Get(Key(key)); |
392 | 800 | } |
393 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop)); |
394 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram")); |
395 | 1 | ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram")); |
396 | 1 | ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram")); |
397 | 1 | } |
398 | | |
399 | 1 | TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) { |
400 | 1 | const int kTableCount = 100; |
401 | 1 | const int kKeysPerTable = 10; |
402 | 1 | const int kKeySize = 50; |
403 | 1 | const int kValueSize = 400; |
404 | 1 | const int kMaxLevel = 7; |
405 | 1 | const int kBloomBitsPerKey = 20; |
406 | 1 | Random rnd(301); |
407 | 1 | Options options = CurrentOptions(); |
408 | 1 | options.level0_file_num_compaction_trigger = 8; |
409 | 1 | options.compression = kNoCompression; |
410 | 1 | options.create_if_missing = true; |
411 | 1 | options.level0_file_num_compaction_trigger = 2; |
412 | 1 | options.target_file_size_base = 8192; |
413 | 1 | options.max_bytes_for_level_base = 10000; |
414 | 1 | options.max_bytes_for_level_multiplier = 2; |
415 | | // This ensures there no compaction happening when we call GetProperty(). |
416 | 1 | options.disable_auto_compactions = true; |
417 | | |
418 | 1 | BlockBasedTableOptions table_options; |
419 | 1 | table_options.filter_policy.reset( |
420 | 1 | NewBloomFilterPolicy(kBloomBitsPerKey, false)); |
421 | 1 | table_options.block_size = 1024; |
422 | 1 | options.table_factory.reset(new BlockBasedTableFactory(table_options)); |
423 | | |
424 | 1 | DestroyAndReopen(options); |
425 | | |
426 | 1 | std::string level_tp_strings[kMaxLevel]; |
427 | 1 | std::string tp_string; |
428 | 1 | TableProperties level_tps[kMaxLevel]; |
429 | 1 | TableProperties tp, sum_tp, expected_tp; |
430 | 101 | for (int table = 1; table <= kTableCount; ++table) { |
431 | 1.10k | for (int i = 0; i < kKeysPerTable; ++i) { |
432 | 1.00k | ASSERT_OK(db_->Put(WriteOptions(), RandomString(&rnd, kKeySize), |
433 | 1.00k | RandomString(&rnd, kValueSize))); |
434 | 1.00k | } |
435 | 100 | ASSERT_OK(db_->Flush(FlushOptions())); |
436 | 100 | ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr)); |
437 | 100 | ResetTableProperties(&sum_tp); |
438 | 800 | for (int level = 0; level < kMaxLevel; ++level) { |
439 | 700 | db_->GetProperty( |
440 | 700 | DB::Properties::kAggregatedTablePropertiesAtLevel + ToString(level), |
441 | 700 | &level_tp_strings[level]); |
442 | 700 | ParseTablePropertiesString(level_tp_strings[level], &level_tps[level]); |
443 | 700 | sum_tp.data_size += level_tps[level].data_size; |
444 | 700 | sum_tp.data_index_size += level_tps[level].data_index_size; |
445 | 700 | sum_tp.filter_size += level_tps[level].filter_size; |
446 | 700 | sum_tp.filter_index_size += level_tps[level].filter_index_size; |
447 | 700 | sum_tp.raw_key_size += level_tps[level].raw_key_size; |
448 | 700 | sum_tp.raw_value_size += level_tps[level].raw_value_size; |
449 | 700 | sum_tp.num_data_blocks += level_tps[level].num_data_blocks; |
450 | 700 | sum_tp.num_entries += level_tps[level].num_entries; |
451 | 700 | sum_tp.num_filter_blocks += level_tps[level].num_filter_blocks; |
452 | 700 | sum_tp.num_data_index_blocks += level_tps[level].num_data_index_blocks; |
453 | 700 | } |
454 | 100 | db_->GetProperty(DB::Properties::kAggregatedTableProperties, &tp_string); |
455 | 100 | ParseTablePropertiesString(tp_string, &tp); |
456 | 100 | ASSERT_EQ(sum_tp.data_size, tp.data_size); |
457 | 100 | ASSERT_EQ(sum_tp.data_index_size, tp.data_index_size); |
458 | 100 | ASSERT_EQ(sum_tp.filter_size, tp.filter_size); |
459 | 100 | ASSERT_EQ(sum_tp.filter_index_size, tp.filter_index_size); |
460 | 100 | ASSERT_EQ(sum_tp.raw_key_size, tp.raw_key_size); |
461 | 100 | ASSERT_EQ(sum_tp.raw_value_size, tp.raw_value_size); |
462 | 100 | ASSERT_EQ(sum_tp.num_data_blocks, tp.num_data_blocks); |
463 | 100 | ASSERT_EQ(sum_tp.num_entries, tp.num_entries); |
464 | 100 | ASSERT_EQ(sum_tp.num_filter_blocks, tp.num_filter_blocks); |
465 | 100 | ASSERT_EQ(sum_tp.num_data_index_blocks, tp.num_data_index_blocks); |
466 | 100 | if (table > 3) { |
467 | 97 | GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize, |
468 | 97 | kKeysPerTable, table, kBloomBitsPerKey, |
469 | 97 | table_options.block_size); |
470 | | // Gives larger bias here as index block size, filter block size, |
471 | | // and data block size become much harder to estimate in this test. |
472 | 97 | VerifyTableProperties(tp, expected_tp, 0.5, 0.4, 0.4, 0.25); |
473 | 97 | } |
474 | 100 | } |
475 | 1 | } |
476 | | |
477 | 1 | TEST_F(DBPropertiesTest, NumImmutableMemTable) { |
478 | 5 | do { |
479 | 5 | Options options = CurrentOptions(); |
480 | 5 | WriteOptions writeOpt = WriteOptions(); |
481 | 5 | writeOpt.disableWAL = true; |
482 | 5 | options.max_write_buffer_number = 4; |
483 | 5 | options.min_write_buffer_number_to_merge = 3; |
484 | 5 | options.max_write_buffer_number_to_maintain = 4; |
485 | 5 | options.write_buffer_size = 1000000; |
486 | 5 | CreateAndReopenWithCF({"pikachu"}, options); |
487 | | |
488 | 5 | std::string big_value(1000000 * 2, 'x'); |
489 | 5 | std::string num; |
490 | 5 | SetPerfLevel(PerfLevel::kEnableTime); |
491 | 5 | ASSERT_TRUE(GetPerfLevel() == PerfLevel::kEnableTime); |
492 | | |
493 | 5 | ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k1", big_value)); |
494 | 5 | ASSERT_TRUE(dbfull()->GetProperty(handles_[1], |
495 | 5 | "rocksdb.num-immutable-mem-table", &num)); |
496 | 5 | ASSERT_EQ(num, "0"); |
497 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
498 | 5 | handles_[1], DB::Properties::kNumImmutableMemTableFlushed, &num)); |
499 | 5 | ASSERT_EQ(num, "0"); |
500 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
501 | 5 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
502 | 5 | ASSERT_EQ(num, "1"); |
503 | 5 | perf_context.Reset(); |
504 | 5 | Get(1, "k1"); |
505 | 5 | ASSERT_EQ(1, static_cast<int>(perf_context.get_from_memtable_count)); |
506 | | |
507 | 5 | ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k2", big_value)); |
508 | 5 | ASSERT_TRUE(dbfull()->GetProperty(handles_[1], |
509 | 5 | "rocksdb.num-immutable-mem-table", &num)); |
510 | 5 | ASSERT_EQ(num, "1"); |
511 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
512 | 5 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
513 | 5 | ASSERT_EQ(num, "1"); |
514 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
515 | 5 | handles_[1], "rocksdb.num-entries-imm-mem-tables", &num)); |
516 | 5 | ASSERT_EQ(num, "1"); |
517 | | |
518 | 5 | perf_context.Reset(); |
519 | 5 | Get(1, "k1"); |
520 | 5 | ASSERT_EQ(2, static_cast<int>(perf_context.get_from_memtable_count)); |
521 | 5 | perf_context.Reset(); |
522 | 5 | Get(1, "k2"); |
523 | 5 | ASSERT_EQ(1, static_cast<int>(perf_context.get_from_memtable_count)); |
524 | | |
525 | 5 | ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k3", big_value)); |
526 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
527 | 5 | handles_[1], "rocksdb.cur-size-active-mem-table", &num)); |
528 | 5 | ASSERT_TRUE(dbfull()->GetProperty(handles_[1], |
529 | 5 | "rocksdb.num-immutable-mem-table", &num)); |
530 | 5 | ASSERT_EQ(num, "2"); |
531 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
532 | 5 | handles_[1], "rocksdb.num-entries-active-mem-table", &num)); |
533 | 5 | ASSERT_EQ(num, "1"); |
534 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
535 | 5 | handles_[1], "rocksdb.num-entries-imm-mem-tables", &num)); |
536 | 5 | ASSERT_EQ(num, "2"); |
537 | 5 | perf_context.Reset(); |
538 | 5 | Get(1, "k2"); |
539 | 5 | ASSERT_EQ(2, static_cast<int>(perf_context.get_from_memtable_count)); |
540 | 5 | perf_context.Reset(); |
541 | 5 | Get(1, "k3"); |
542 | 5 | ASSERT_EQ(1, static_cast<int>(perf_context.get_from_memtable_count)); |
543 | 5 | perf_context.Reset(); |
544 | 5 | Get(1, "k1"); |
545 | 5 | ASSERT_EQ(3, static_cast<int>(perf_context.get_from_memtable_count)); |
546 | | |
547 | 5 | ASSERT_OK(Flush(1)); |
548 | 5 | ASSERT_TRUE(dbfull()->GetProperty(handles_[1], |
549 | 5 | "rocksdb.num-immutable-mem-table", &num)); |
550 | 5 | ASSERT_EQ(num, "0"); |
551 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
552 | 5 | handles_[1], DB::Properties::kNumImmutableMemTableFlushed, &num)); |
553 | 5 | ASSERT_EQ(num, "3"); |
554 | 5 | ASSERT_TRUE(dbfull()->GetProperty( |
555 | 5 | handles_[1], "rocksdb.cur-size-active-mem-table", &num)); |
556 | | // "192" is the size of the metadata of an empty skiplist, this would |
557 | | // break if we change the default skiplist implementation |
558 | 5 | ASSERT_EQ(num, "192"); |
559 | | |
560 | 5 | uint64_t int_num; |
561 | 5 | uint64_t base_total_size; |
562 | 5 | ASSERT_TRUE(dbfull()->GetIntProperty( |
563 | 5 | handles_[1], "rocksdb.estimate-num-keys", &base_total_size)); |
564 | | |
565 | 5 | ASSERT_OK(dbfull()->Delete(writeOpt, handles_[1], "k2")); |
566 | 5 | ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k3", "")); |
567 | 5 | ASSERT_OK(dbfull()->Delete(writeOpt, handles_[1], "k3")); |
568 | 5 | ASSERT_TRUE(dbfull()->GetIntProperty( |
569 | 5 | handles_[1], "rocksdb.num-deletes-active-mem-table", &int_num)); |
570 | 5 | ASSERT_EQ(int_num, 2U); |
571 | 5 | ASSERT_TRUE(dbfull()->GetIntProperty( |
572 | 5 | handles_[1], "rocksdb.num-entries-active-mem-table", &int_num)); |
573 | 5 | ASSERT_EQ(int_num, 3U); |
574 | | |
575 | 5 | ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k2", big_value)); |
576 | 5 | ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k2", big_value)); |
577 | 5 | ASSERT_TRUE(dbfull()->GetIntProperty( |
578 | 5 | handles_[1], "rocksdb.num-entries-imm-mem-tables", &int_num)); |
579 | 5 | ASSERT_EQ(int_num, 4U); |
580 | 5 | ASSERT_TRUE(dbfull()->GetIntProperty( |
581 | 5 | handles_[1], "rocksdb.num-deletes-imm-mem-tables", &int_num)); |
582 | 5 | ASSERT_EQ(int_num, 2U); |
583 | | |
584 | 5 | ASSERT_TRUE(dbfull()->GetIntProperty( |
585 | 5 | handles_[1], "rocksdb.estimate-num-keys", &int_num)); |
586 | 5 | ASSERT_EQ(int_num, base_total_size + 1); |
587 | | |
588 | 5 | SetPerfLevel(PerfLevel::kDisable); |
589 | 5 | ASSERT_TRUE(GetPerfLevel() == PerfLevel::kDisable); |
590 | 5 | } while (ChangeCompactOptions()); |
591 | 1 | } |
592 | | |
593 | 1 | TEST_F(DBPropertiesTest, GetProperty) { |
594 | | // Set sizes to both background thread pool to be 1 and block them. |
595 | 1 | env_->SetBackgroundThreads(1, Env::HIGH); |
596 | 1 | env_->SetBackgroundThreads(1, Env::LOW); |
597 | 1 | test::SleepingBackgroundTask sleeping_task_low; |
598 | 1 | env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task_low, |
599 | 1 | Env::Priority::LOW); |
600 | 1 | test::SleepingBackgroundTask sleeping_task_high; |
601 | 1 | env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, |
602 | 1 | &sleeping_task_high, Env::Priority::HIGH); |
603 | | |
604 | 1 | Options options = CurrentOptions(); |
605 | 1 | WriteOptions writeOpt = WriteOptions(); |
606 | 1 | writeOpt.disableWAL = true; |
607 | 1 | options.compaction_style = kCompactionStyleUniversal; |
608 | 1 | options.level0_file_num_compaction_trigger = 1; |
609 | 1 | options.compaction_options_universal.size_ratio = 50; |
610 | 1 | options.max_background_compactions = 1; |
611 | 1 | options.max_background_flushes = 1; |
612 | 1 | options.max_write_buffer_number = 10; |
613 | 1 | options.min_write_buffer_number_to_merge = 1; |
614 | 1 | options.max_write_buffer_number_to_maintain = 0; |
615 | 1 | options.write_buffer_size = 1000000; |
616 | 1 | Reopen(options); |
617 | | |
618 | 1 | std::string big_value(1000000 * 2, 'x'); |
619 | 1 | std::string num; |
620 | 1 | uint64_t int_num; |
621 | 1 | SetPerfLevel(PerfLevel::kEnableTime); |
622 | | |
623 | 1 | ASSERT_TRUE( |
624 | 1 | dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num)); |
625 | 1 | ASSERT_EQ(int_num, 0U); |
626 | 1 | ASSERT_TRUE( |
627 | 1 | dbfull()->GetIntProperty("rocksdb.estimate-live-data-size", &int_num)); |
628 | 1 | ASSERT_EQ(int_num, 0U); |
629 | | |
630 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k1", big_value)); |
631 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num)); |
632 | 1 | ASSERT_EQ(num, "0"); |
633 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.mem-table-flush-pending", &num)); |
634 | 1 | ASSERT_EQ(num, "0"); |
635 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.compaction-pending", &num)); |
636 | 1 | ASSERT_EQ(num, "0"); |
637 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num)); |
638 | 1 | ASSERT_EQ(num, "1"); |
639 | 1 | perf_context.Reset(); |
640 | | |
641 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k2", big_value)); |
642 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num)); |
643 | 1 | ASSERT_EQ(num, "1"); |
644 | 1 | ASSERT_OK(dbfull()->Delete(writeOpt, "k-non-existing")); |
645 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k3", big_value)); |
646 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num)); |
647 | 1 | ASSERT_EQ(num, "2"); |
648 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.mem-table-flush-pending", &num)); |
649 | 1 | ASSERT_EQ(num, "1"); |
650 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.compaction-pending", &num)); |
651 | 1 | ASSERT_EQ(num, "0"); |
652 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num)); |
653 | 1 | ASSERT_EQ(num, "2"); |
654 | | // Verify the same set of properties through GetIntProperty |
655 | 1 | ASSERT_TRUE( |
656 | 1 | dbfull()->GetIntProperty("rocksdb.num-immutable-mem-table", &int_num)); |
657 | 1 | ASSERT_EQ(int_num, 2U); |
658 | 1 | ASSERT_TRUE( |
659 | 1 | dbfull()->GetIntProperty("rocksdb.mem-table-flush-pending", &int_num)); |
660 | 1 | ASSERT_EQ(int_num, 1U); |
661 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.compaction-pending", &int_num)); |
662 | 1 | ASSERT_EQ(int_num, 0U); |
663 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num)); |
664 | 1 | ASSERT_EQ(int_num, 2U); |
665 | | |
666 | 1 | ASSERT_TRUE( |
667 | 1 | dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num)); |
668 | 1 | ASSERT_EQ(int_num, 0U); |
669 | | |
670 | 1 | sleeping_task_high.WakeUp(); |
671 | 1 | sleeping_task_high.WaitUntilDone(); |
672 | 1 | ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable()); |
673 | | |
674 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k4", big_value)); |
675 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k5", big_value)); |
676 | 1 | ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable()); |
677 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.mem-table-flush-pending", &num)); |
678 | 1 | ASSERT_EQ(num, "0"); |
679 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.compaction-pending", &num)); |
680 | 1 | ASSERT_EQ(num, "1"); |
681 | 1 | ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num)); |
682 | 1 | ASSERT_EQ(num, "4"); |
683 | | |
684 | 1 | ASSERT_TRUE( |
685 | 1 | dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num)); |
686 | 1 | ASSERT_GT(int_num, 0U); |
687 | | |
688 | 1 | sleeping_task_low.WakeUp(); |
689 | 1 | sleeping_task_low.WaitUntilDone(); |
690 | | |
691 | | // Wait for compaction to be done. This is important because otherwise RocksDB |
692 | | // might schedule a compaction when reopening the database, failing assertion |
693 | | // (A) as a result. |
694 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
695 | 1 | options.max_open_files = 10; |
696 | 1 | Reopen(options); |
697 | | // After reopening, no table reader is loaded, so no memory for table readers |
698 | 1 | ASSERT_TRUE( |
699 | 1 | dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num)); |
700 | 1 | ASSERT_EQ(int_num, 0U); // (A) |
701 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num)); |
702 | 1 | ASSERT_GT(int_num, 0U); |
703 | | |
704 | | // After reading a key, at least one table reader is loaded. |
705 | 1 | Get("k5"); |
706 | 1 | ASSERT_TRUE( |
707 | 1 | dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num)); |
708 | 1 | ASSERT_GT(int_num, 0U); |
709 | | |
710 | | // Test rocksdb.num-live-versions |
711 | 1 | { |
712 | 1 | options.level0_file_num_compaction_trigger = 20; |
713 | 1 | Reopen(options); |
714 | 1 | ASSERT_TRUE( |
715 | 1 | dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num)); |
716 | 1 | ASSERT_EQ(int_num, 1U); |
717 | | |
718 | | // Use an iterator to hold current version |
719 | 1 | std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions())); |
720 | | |
721 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k6", big_value)); |
722 | 1 | ASSERT_OK(Flush());; |
723 | 1 | ASSERT_TRUE( |
724 | 1 | dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num)); |
725 | 1 | ASSERT_EQ(int_num, 2U); |
726 | | |
727 | | // Use an iterator to hold current version |
728 | 1 | std::unique_ptr<Iterator> iter2(dbfull()->NewIterator(ReadOptions())); |
729 | | |
730 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k7", big_value)); |
731 | 1 | ASSERT_OK(Flush());; |
732 | 1 | ASSERT_TRUE( |
733 | 1 | dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num)); |
734 | 1 | ASSERT_EQ(int_num, 3U); |
735 | | |
736 | 1 | iter2.reset(); |
737 | 1 | ASSERT_TRUE( |
738 | 1 | dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num)); |
739 | 1 | ASSERT_EQ(int_num, 2U); |
740 | | |
741 | 1 | iter1.reset(); |
742 | 1 | ASSERT_TRUE( |
743 | 1 | dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num)); |
744 | 1 | ASSERT_EQ(int_num, 1U); |
745 | 1 | } |
746 | 1 | } |
747 | | |
748 | 1 | TEST_F(DBPropertiesTest, ApproximateMemoryUsage) { |
749 | 1 | const int kNumRounds = 10; |
750 | | // TODO(noetzli) kFlushesPerRound does not really correlate with how many |
751 | | // flushes happen. |
752 | 1 | const int kFlushesPerRound = 10; |
753 | 1 | const int kWritesPerFlush = 10; |
754 | 1 | const int kKeySize = 100; |
755 | 1 | const int kValueSize = 1000; |
756 | 1 | Options options; |
757 | 1 | options.write_buffer_size = 1000; // small write buffer |
758 | 1 | options.min_write_buffer_number_to_merge = 4; |
759 | 1 | options.compression = kNoCompression; |
760 | 1 | options.create_if_missing = true; |
761 | 1 | options = CurrentOptions(options); |
762 | 1 | DestroyAndReopen(options); |
763 | | |
764 | 1 | Random rnd(301); |
765 | | |
766 | 1 | std::vector<Iterator*> iters; |
767 | | |
768 | 1 | uint64_t active_mem; |
769 | 1 | uint64_t unflushed_mem; |
770 | 1 | uint64_t all_mem; |
771 | 1 | uint64_t prev_all_mem; |
772 | | |
773 | | // Phase 0. The verify the initial value of all these properties are the same |
774 | | // as we have no mem-tables. |
775 | 1 | dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem); |
776 | 1 | dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem); |
777 | 1 | dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem); |
778 | 1 | ASSERT_EQ(all_mem, active_mem); |
779 | 1 | ASSERT_EQ(all_mem, unflushed_mem); |
780 | | |
781 | | // Phase 1. Simply issue Put() and expect "cur-size-all-mem-tables" equals to |
782 | | // "size-all-mem-tables" |
783 | 11 | for (int r = 0; r < kNumRounds; ++r) { |
784 | 110 | for (int f = 0; f < kFlushesPerRound; ++f) { |
785 | 1.10k | for (int w = 0; w < kWritesPerFlush; ++w) { |
786 | 1.00k | ASSERT_OK(Put(RandomString(&rnd, kKeySize), RandomString(&rnd, kValueSize))); |
787 | 1.00k | } |
788 | 100 | } |
789 | | // Make sure that there is no flush between getting the two properties. |
790 | 10 | ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable()); |
791 | 10 | dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem); |
792 | 10 | dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem); |
793 | | // in no iterator case, these two number should be the same. |
794 | 10 | ASSERT_EQ(unflushed_mem, all_mem); |
795 | 10 | } |
796 | 1 | prev_all_mem = all_mem; |
797 | | |
798 | | // Phase 2. Keep issuing Put() but also create new iterators. This time we |
799 | | // expect "size-all-mem-tables" > "cur-size-all-mem-tables". |
800 | 11 | for (int r = 0; r < kNumRounds; ++r) { |
801 | 10 | iters.push_back(db_->NewIterator(ReadOptions())); |
802 | 110 | for (int f = 0; f < kFlushesPerRound; ++f) { |
803 | 1.10k | for (int w = 0; w < kWritesPerFlush; ++w) { |
804 | 1.00k | ASSERT_OK(Put(RandomString(&rnd, kKeySize), RandomString(&rnd, kValueSize))); |
805 | 1.00k | } |
806 | 100 | } |
807 | | // Force flush to prevent flush from happening between getting the |
808 | | // properties or after getting the properties and before the new round. |
809 | 10 | ASSERT_OK(Flush());; |
810 | | |
811 | | // In the second round, add iterators. |
812 | 10 | dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem); |
813 | 10 | dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem); |
814 | 10 | dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem); |
815 | 10 | ASSERT_GT(all_mem, active_mem); |
816 | 10 | ASSERT_GT(all_mem, unflushed_mem); |
817 | 10 | ASSERT_GT(all_mem, prev_all_mem); |
818 | 10 | prev_all_mem = all_mem; |
819 | 10 | } |
820 | | |
821 | | // Phase 3. Delete iterators and expect "size-all-mem-tables" shrinks |
822 | | // whenever we release an iterator. |
823 | 10 | for (auto* iter : iters) { |
824 | 10 | delete iter; |
825 | 10 | dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem); |
826 | | // Expect the size shrinking |
827 | 10 | ASSERT_LT(all_mem, prev_all_mem); |
828 | 10 | prev_all_mem = all_mem; |
829 | 10 | } |
830 | | |
831 | | // Expect all these three counters to be the same. |
832 | 1 | dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem); |
833 | 1 | dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem); |
834 | 1 | dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem); |
835 | 1 | ASSERT_EQ(active_mem, unflushed_mem); |
836 | 1 | ASSERT_EQ(unflushed_mem, all_mem); |
837 | | |
838 | | // Phase 5. Reopen, and expect all these three counters to be the same again. |
839 | 1 | Reopen(options); |
840 | 1 | dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem); |
841 | 1 | dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem); |
842 | 1 | dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem); |
843 | 1 | ASSERT_EQ(active_mem, unflushed_mem); |
844 | 1 | ASSERT_EQ(unflushed_mem, all_mem); |
845 | 1 | } |
846 | | |
847 | 1 | TEST_F(DBPropertiesTest, EstimatePendingCompBytes) { |
848 | | // Set sizes to both background thread pool to be 1 and block them. |
849 | 1 | env_->SetBackgroundThreads(1, Env::HIGH); |
850 | 1 | env_->SetBackgroundThreads(1, Env::LOW); |
851 | 1 | test::SleepingBackgroundTask sleeping_task_low; |
852 | 1 | env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task_low, |
853 | 1 | Env::Priority::LOW); |
854 | | |
855 | 1 | Options options = CurrentOptions(); |
856 | 1 | WriteOptions writeOpt = WriteOptions(); |
857 | 1 | writeOpt.disableWAL = true; |
858 | 1 | options.compaction_style = kCompactionStyleLevel; |
859 | 1 | options.level0_file_num_compaction_trigger = 2; |
860 | 1 | options.max_background_compactions = 1; |
861 | 1 | options.max_background_flushes = 1; |
862 | 1 | options.max_write_buffer_number = 10; |
863 | 1 | options.min_write_buffer_number_to_merge = 1; |
864 | 1 | options.max_write_buffer_number_to_maintain = 0; |
865 | 1 | options.write_buffer_size = 1000000; |
866 | 1 | Reopen(options); |
867 | | |
868 | 1 | std::string big_value(1000000 * 2, 'x'); |
869 | 1 | std::string num; |
870 | 1 | uint64_t int_num; |
871 | | |
872 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k1", big_value)); |
873 | 1 | ASSERT_OK(Flush());; |
874 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty( |
875 | 1 | "rocksdb.estimate-pending-compaction-bytes", &int_num)); |
876 | 1 | ASSERT_EQ(int_num, 0U); |
877 | | |
878 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k2", big_value)); |
879 | 1 | ASSERT_OK(Flush());; |
880 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty( |
881 | 1 | "rocksdb.estimate-pending-compaction-bytes", &int_num)); |
882 | 1 | ASSERT_EQ(int_num, 0U); |
883 | | |
884 | 1 | ASSERT_OK(dbfull()->Put(writeOpt, "k3", big_value)); |
885 | 1 | ASSERT_OK(Flush());; |
886 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty( |
887 | 1 | "rocksdb.estimate-pending-compaction-bytes", &int_num)); |
888 | 1 | ASSERT_GT(int_num, 0U); |
889 | | |
890 | 1 | sleeping_task_low.WakeUp(); |
891 | 1 | sleeping_task_low.WaitUntilDone(); |
892 | | |
893 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
894 | 1 | ASSERT_TRUE(dbfull()->GetIntProperty( |
895 | 1 | "rocksdb.estimate-pending-compaction-bytes", &int_num)); |
896 | 1 | ASSERT_EQ(int_num, 0U); |
897 | 1 | } |
898 | | #endif // ROCKSDB_LITE |
899 | | |
900 | | class CountingUserTblPropCollector : public TablePropertiesCollector { |
901 | | public: |
902 | 0 | const char* Name() const override { return "CountingUserTblPropCollector"; } |
903 | | |
904 | 38 | Status Finish(UserCollectedProperties* properties) override { |
905 | 38 | std::string encoded; |
906 | 38 | PutVarint32(&encoded, count_); |
907 | 38 | *properties = UserCollectedProperties{ |
908 | 38 | {"CountingUserTblPropCollector", message_}, {"Count", encoded}, |
909 | 38 | }; |
910 | 38 | return Status::OK(); |
911 | 38 | } |
912 | | |
913 | | Status AddUserKey(const Slice& user_key, const Slice& value, EntryType type, |
914 | 308 | SequenceNumber seq, uint64_t file_size) override { |
915 | 308 | ++count_; |
916 | 308 | return Status::OK(); |
917 | 308 | } |
918 | | |
919 | 19 | UserCollectedProperties GetReadableProperties() const override { |
920 | 19 | return UserCollectedProperties{}; |
921 | 19 | } |
922 | | |
923 | | private: |
924 | | std::string message_ = "Rocksdb"; |
925 | | uint32_t count_ = 0; |
926 | | }; |
927 | | |
928 | | class CountingUserTblPropCollectorFactory |
929 | | : public TablePropertiesCollectorFactory { |
930 | | public: |
931 | | explicit CountingUserTblPropCollectorFactory( |
932 | | uint32_t expected_column_family_id) |
933 | | : expected_column_family_id_(expected_column_family_id), |
934 | 2 | num_created_(0) {} |
935 | | virtual TablePropertiesCollector* CreateTablePropertiesCollector( |
936 | 19 | TablePropertiesCollectorFactory::Context context) override { |
937 | 19 | EXPECT_EQ(expected_column_family_id_, context.column_family_id); |
938 | 19 | num_created_++; |
939 | 19 | return new CountingUserTblPropCollector(); |
940 | 19 | } |
941 | 4 | const char* Name() const override { |
942 | 4 | return "CountingUserTblPropCollectorFactory"; |
943 | 4 | } |
944 | 1 | void set_expected_column_family_id(uint32_t v) { |
945 | 1 | expected_column_family_id_ = v; |
946 | 1 | } |
947 | | uint32_t expected_column_family_id_; |
948 | | uint32_t num_created_; |
949 | | }; |
950 | | |
951 | | class CountingDeleteTabPropCollector : public TablePropertiesCollector { |
952 | | public: |
953 | 0 | const char* Name() const override { return "CountingDeleteTabPropCollector"; } |
954 | | |
955 | | Status AddUserKey(const Slice& user_key, const Slice& value, EntryType type, |
956 | 5.88k | SequenceNumber seq, uint64_t file_size) override { |
957 | 5.88k | if (type == kEntryDelete) { |
958 | 804 | num_deletes_++; |
959 | 804 | } |
960 | 5.88k | return Status::OK(); |
961 | 5.88k | } |
962 | | |
963 | 99 | bool NeedCompact() const override { return num_deletes_ > 10; } |
964 | | |
965 | 99 | UserCollectedProperties GetReadableProperties() const override { |
966 | 99 | return UserCollectedProperties{}; |
967 | 99 | } |
968 | | |
969 | 198 | Status Finish(UserCollectedProperties* properties) override { |
970 | 198 | *properties = |
971 | 198 | UserCollectedProperties{{"num_delete", ToString(num_deletes_)}}; |
972 | 198 | return Status::OK(); |
973 | 198 | } |
974 | | |
975 | | private: |
976 | | uint32_t num_deletes_ = 0; |
977 | | }; |
978 | | |
979 | | class CountingDeleteTabPropCollectorFactory |
980 | | : public TablePropertiesCollectorFactory { |
981 | | public: |
982 | | virtual TablePropertiesCollector* CreateTablePropertiesCollector( |
983 | 99 | TablePropertiesCollectorFactory::Context context) override { |
984 | 99 | return new CountingDeleteTabPropCollector(); |
985 | 99 | } |
986 | 3 | const char* Name() const override { |
987 | 3 | return "CountingDeleteTabPropCollectorFactory"; |
988 | 3 | } |
989 | | }; |
990 | | |
991 | | #ifndef ROCKSDB_LITE |
992 | 1 | TEST_F(DBPropertiesTest, GetUserDefinedTableProperties) { |
993 | 1 | Options options = CurrentOptions(); |
994 | 1 | options.level0_file_num_compaction_trigger = (1 << 30); |
995 | 1 | options.max_background_flushes = 0; |
996 | 1 | options.table_properties_collector_factories.resize(1); |
997 | 1 | std::shared_ptr<CountingUserTblPropCollectorFactory> collector_factory = |
998 | 1 | std::make_shared<CountingUserTblPropCollectorFactory>(0); |
999 | 1 | options.table_properties_collector_factories[0] = collector_factory; |
1000 | 1 | Reopen(options); |
1001 | | // Create 4 tables |
1002 | 5 | for (int table = 0; table < 4; ++table) { |
1003 | 50 | for (int i = 0; i < 10 + table; ++i) { |
1004 | 46 | ASSERT_OK(db_->Put(WriteOptions(), ToString(table * 100 + i), "val")); |
1005 | 46 | } |
1006 | 4 | ASSERT_OK(db_->Flush(FlushOptions())); |
1007 | 4 | } |
1008 | | |
1009 | 1 | TablePropertiesCollection props; |
1010 | 1 | ASSERT_OK(db_->GetPropertiesOfAllTables(&props)); |
1011 | 1 | ASSERT_EQ(4U, props.size()); |
1012 | 1 | uint32_t sum = 0; |
1013 | 4 | for (const auto& item : props) { |
1014 | 4 | auto& user_collected = item.second->user_collected_properties; |
1015 | 4 | ASSERT_TRUE(user_collected.find("CountingUserTblPropCollector") != |
1016 | 4 | user_collected.end()); |
1017 | 4 | ASSERT_EQ(user_collected.at("CountingUserTblPropCollector"), "Rocksdb"); |
1018 | 4 | ASSERT_TRUE(user_collected.find("Count") != user_collected.end()); |
1019 | 4 | Slice key(user_collected.at("Count")); |
1020 | 4 | uint32_t count; |
1021 | 4 | ASSERT_TRUE(GetVarint32(&key, &count)); |
1022 | 4 | sum += count; |
1023 | 4 | } |
1024 | 1 | ASSERT_EQ(10u + 11u + 12u + 13u, sum); |
1025 | | |
1026 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1027 | 1 | collector_factory->num_created_ = 0; |
1028 | 1 | ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr)); |
1029 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1030 | 1 | } |
1031 | | #endif // ROCKSDB_LITE |
1032 | | |
1033 | 1 | TEST_F(DBPropertiesTest, UserDefinedTablePropertiesContext) { |
1034 | 1 | Options options = CurrentOptions(); |
1035 | 1 | options.level0_file_num_compaction_trigger = 3; |
1036 | 1 | options.max_background_flushes = 0; |
1037 | 1 | options.table_properties_collector_factories.resize(1); |
1038 | 1 | std::shared_ptr<CountingUserTblPropCollectorFactory> collector_factory = |
1039 | 1 | std::make_shared<CountingUserTblPropCollectorFactory>(1); |
1040 | 1 | options.table_properties_collector_factories[0] = collector_factory, |
1041 | 1 | CreateAndReopenWithCF({"pikachu"}, options); |
1042 | | // Create 2 files |
1043 | 3 | for (int table = 0; table < 2; ++table) { |
1044 | 23 | for (int i = 0; i < 10 + table; ++i) { |
1045 | 21 | ASSERT_OK(Put(1, ToString(table * 100 + i), "val")); |
1046 | 21 | } |
1047 | 2 | ASSERT_OK(Flush(1)); |
1048 | 2 | } |
1049 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1050 | | |
1051 | 1 | collector_factory->num_created_ = 0; |
1052 | | // Trigger automatic compactions. |
1053 | 4 | for (int table = 0; table < 3; ++table) { |
1054 | 36 | for (int i = 0; i < 10 + table; ++i) { |
1055 | 33 | ASSERT_OK(Put(1, ToString(table * 100 + i), "val")); |
1056 | 33 | } |
1057 | 3 | ASSERT_OK(Flush(1)); |
1058 | 3 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
1059 | 3 | } |
1060 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1061 | | |
1062 | 1 | collector_factory->num_created_ = 0; |
1063 | 1 | ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1])); |
1064 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1065 | | |
1066 | | // Come back to write to default column family |
1067 | 1 | collector_factory->num_created_ = 0; |
1068 | 1 | collector_factory->set_expected_column_family_id(0); // default CF |
1069 | | // Create 4 tables in default column family |
1070 | 3 | for (int table = 0; table < 2; ++table) { |
1071 | 23 | for (int i = 0; i < 10 + table; ++i) { |
1072 | 21 | ASSERT_OK(Put(ToString(table * 100 + i), "val")); |
1073 | 21 | } |
1074 | 2 | ASSERT_OK(Flush());; |
1075 | 2 | } |
1076 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1077 | | |
1078 | 1 | collector_factory->num_created_ = 0; |
1079 | | // Trigger automatic compactions. |
1080 | 4 | for (int table = 0; table < 3; ++table) { |
1081 | 36 | for (int i = 0; i < 10 + table; ++i) { |
1082 | 33 | ASSERT_OK(Put(ToString(table * 100 + i), "val")); |
1083 | 33 | } |
1084 | 3 | ASSERT_OK(Flush());; |
1085 | 3 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
1086 | 3 | } |
1087 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1088 | | |
1089 | 1 | collector_factory->num_created_ = 0; |
1090 | 1 | ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr)); |
1091 | 1 | ASSERT_GT(collector_factory->num_created_, 0U); |
1092 | 1 | } |
1093 | | |
1094 | | #ifndef ROCKSDB_LITE |
1095 | 1 | TEST_F(DBPropertiesTest, TablePropertiesNeedCompactTest) { |
1096 | 1 | Random rnd(301); |
1097 | | |
1098 | 1 | Options options; |
1099 | 1 | options.create_if_missing = true; |
1100 | 1 | options.write_buffer_size = 4096; |
1101 | 1 | options.max_write_buffer_number = 8; |
1102 | 1 | options.level0_file_num_compaction_trigger = 2; |
1103 | 1 | options.level0_slowdown_writes_trigger = 2; |
1104 | 1 | options.level0_stop_writes_trigger = 4; |
1105 | 1 | options.target_file_size_base = 2048; |
1106 | 1 | options.max_bytes_for_level_base = 10240; |
1107 | 1 | options.max_bytes_for_level_multiplier = 4; |
1108 | 1 | options.soft_pending_compaction_bytes_limit = 1024 * 1024; |
1109 | 1 | options.num_levels = 8; |
1110 | | |
1111 | 1 | std::shared_ptr<TablePropertiesCollectorFactory> collector_factory = |
1112 | 1 | std::make_shared<CountingDeleteTabPropCollectorFactory>(); |
1113 | 1 | options.table_properties_collector_factories.resize(1); |
1114 | 1 | options.table_properties_collector_factories[0] = collector_factory; |
1115 | | |
1116 | 1 | DestroyAndReopen(options); |
1117 | | |
1118 | 1 | const int kMaxKey = 1000; |
1119 | 1.00k | for (int i = 0; i < kMaxKey; i++) { |
1120 | 1.00k | ASSERT_OK(Put(Key(i), RandomString(&rnd, 102))); |
1121 | 1.00k | ASSERT_OK(Put(Key(kMaxKey + i), RandomString(&rnd, 102))); |
1122 | 1.00k | } |
1123 | 1 | ASSERT_OK(Flush());; |
1124 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
1125 | 1 | if (NumTableFilesAtLevel(0) == 1) { |
1126 | | // Clear Level 0 so that when later flush a file with deletions, |
1127 | | // we don't trigger an organic compaction. |
1128 | 1 | ASSERT_OK(Put(Key(0), "")); |
1129 | 1 | ASSERT_OK(Put(Key(kMaxKey * 2), "")); |
1130 | 1 | ASSERT_OK(Flush());; |
1131 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
1132 | 1 | } |
1133 | 1 | ASSERT_EQ(NumTableFilesAtLevel(0), 0); |
1134 | | |
1135 | 1 | { |
1136 | 1 | int c = 0; |
1137 | 1 | std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions())); |
1138 | 1 | iter->Seek(Key(kMaxKey - 100)); |
1139 | 201 | while (iter->Valid() && iter->key().compare(Key(kMaxKey + 100)) < 0) { |
1140 | 200 | iter->Next(); |
1141 | 200 | ++c; |
1142 | 200 | } |
1143 | 1 | ASSERT_EQ(c, 200); |
1144 | 1 | } |
1145 | | |
1146 | 1 | ASSERT_OK(Delete(Key(0))); |
1147 | 201 | for (int i = kMaxKey - 100; i < kMaxKey + 100; i++) { |
1148 | 200 | ASSERT_OK(Delete(Key(i))); |
1149 | 200 | } |
1150 | 1 | ASSERT_OK(Delete(Key(kMaxKey * 2))); |
1151 | | |
1152 | 1 | ASSERT_OK(Flush());; |
1153 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
1154 | | |
1155 | 1 | { |
1156 | 1 | SetPerfLevel(PerfLevel::kEnableCount); |
1157 | 1 | perf_context.Reset(); |
1158 | 1 | int c = 0; |
1159 | 1 | std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions())); |
1160 | 1 | iter->Seek(Key(kMaxKey - 100)); |
1161 | 1 | while (iter->Valid() && iter->key().compare(Key(kMaxKey + 100)) < 0) { |
1162 | 0 | iter->Next(); |
1163 | 0 | } |
1164 | 1 | ASSERT_EQ(c, 0); |
1165 | 1 | ASSERT_LT(perf_context.internal_delete_skipped_count, 30u); |
1166 | 1 | ASSERT_LT(perf_context.internal_key_skipped_count, 30u); |
1167 | 1 | SetPerfLevel(PerfLevel::kDisable); |
1168 | 1 | } |
1169 | 1 | } |
1170 | | |
1171 | 1 | TEST_F(DBPropertiesTest, NeedCompactHintPersistentTest) { |
1172 | 1 | Random rnd(301); |
1173 | | |
1174 | 1 | Options options; |
1175 | 1 | options.create_if_missing = true; |
1176 | 1 | options.max_write_buffer_number = 8; |
1177 | 1 | options.level0_file_num_compaction_trigger = 10; |
1178 | 1 | options.level0_slowdown_writes_trigger = 10; |
1179 | 1 | options.level0_stop_writes_trigger = 10; |
1180 | 1 | options.disable_auto_compactions = true; |
1181 | | |
1182 | 1 | std::shared_ptr<TablePropertiesCollectorFactory> collector_factory = |
1183 | 1 | std::make_shared<CountingDeleteTabPropCollectorFactory>(); |
1184 | 1 | options.table_properties_collector_factories.resize(1); |
1185 | 1 | options.table_properties_collector_factories[0] = collector_factory; |
1186 | | |
1187 | 1 | DestroyAndReopen(options); |
1188 | | |
1189 | 1 | const int kMaxKey = 100; |
1190 | 101 | for (int i = 0; i < kMaxKey; i++) { |
1191 | 100 | ASSERT_OK(Put(Key(i), "")); |
1192 | 100 | } |
1193 | 1 | ASSERT_OK(Flush());; |
1194 | 1 | ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable()); |
1195 | | |
1196 | 99 | for (int i = 1; i < kMaxKey - 1; i++) { |
1197 | 98 | ASSERT_OK(Delete(Key(i))); |
1198 | 98 | } |
1199 | 1 | ASSERT_OK(Flush());; |
1200 | 1 | ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable()); |
1201 | 1 | ASSERT_EQ(NumTableFilesAtLevel(0), 2); |
1202 | | |
1203 | | // Restart the DB. Although number of files didn't reach |
1204 | | // options.level0_file_num_compaction_trigger, compaction should |
1205 | | // still be triggered because of the need-compaction hint. |
1206 | 1 | options.disable_auto_compactions = false; |
1207 | 1 | Reopen(options); |
1208 | 1 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
1209 | 1 | ASSERT_EQ(NumTableFilesAtLevel(0), 0); |
1210 | 1 | { |
1211 | 1 | SetPerfLevel(PerfLevel::kEnableCount); |
1212 | 1 | perf_context.Reset(); |
1213 | 1 | int c = 0; |
1214 | 1 | std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions())); |
1215 | 3 | for (iter->Seek(Key(0)); iter->Valid(); iter->Next()) { |
1216 | 2 | c++; |
1217 | 2 | } |
1218 | 1 | ASSERT_EQ(c, 2); |
1219 | 1 | ASSERT_EQ(perf_context.internal_delete_skipped_count, 0); |
1220 | | // We iterate every key twice. Is it a bug? |
1221 | 1 | ASSERT_LE(perf_context.internal_key_skipped_count, 2); |
1222 | 1 | SetPerfLevel(PerfLevel::kDisable); |
1223 | 1 | } |
1224 | 1 | } |
1225 | | #endif // ROCKSDB_LITE |
1226 | | } // namespace rocksdb |
1227 | | |
1228 | 13.2k | int main(int argc, char** argv) { |
1229 | 13.2k | rocksdb::port::InstallStackTraceHandler(); |
1230 | 13.2k | ::testing::InitGoogleTest(&argc, argv); |
1231 | 13.2k | return RUN_ALL_TESTS(); |
1232 | 13.2k | } |