]>
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 | // Introduction of SyncPoint effectively disabled building and running this test | |
11 | // in Release build. | |
12 | // which is a pity, it is a good test | |
13 | #if !defined(ROCKSDB_LITE) | |
14 | ||
15 | #include "db/db_test_util.h" | |
16 | #include "db/forward_iterator.h" | |
17 | #include "port/stack_trace.h" | |
18 | ||
f67539c2 | 19 | namespace ROCKSDB_NAMESPACE { |
7c673cae | 20 | |
1e59de90 TL |
21 | class DBTestTailingIterator : public DBTestBase, |
22 | public ::testing::WithParamInterface<bool> { | |
7c673cae | 23 | public: |
20effc67 | 24 | DBTestTailingIterator() |
1e59de90 | 25 | : DBTestBase("db_tailing_iterator_test", /*env_do_fsync=*/true) {} |
7c673cae FG |
26 | }; |
27 | ||
1e59de90 TL |
28 | INSTANTIATE_TEST_CASE_P(DBTestTailingIterator, DBTestTailingIterator, |
29 | ::testing::Bool()); | |
30 | ||
31 | TEST_P(DBTestTailingIterator, TailingIteratorSingle) { | |
7c673cae FG |
32 | ReadOptions read_options; |
33 | read_options.tailing = true; | |
1e59de90 TL |
34 | if (GetParam()) { |
35 | read_options.async_io = true; | |
36 | } | |
7c673cae FG |
37 | |
38 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options)); | |
39 | iter->SeekToFirst(); | |
40 | ASSERT_TRUE(!iter->Valid()); | |
1e59de90 | 41 | ASSERT_OK(iter->status()); |
7c673cae FG |
42 | |
43 | // add a record and check that iter can see it | |
44 | ASSERT_OK(db_->Put(WriteOptions(), "mirko", "fodor")); | |
45 | iter->SeekToFirst(); | |
46 | ASSERT_TRUE(iter->Valid()); | |
47 | ASSERT_EQ(iter->key().ToString(), "mirko"); | |
48 | ||
49 | iter->Next(); | |
50 | ASSERT_TRUE(!iter->Valid()); | |
51 | } | |
52 | ||
1e59de90 | 53 | TEST_P(DBTestTailingIterator, TailingIteratorKeepAdding) { |
7c673cae FG |
54 | CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); |
55 | ReadOptions read_options; | |
56 | read_options.tailing = true; | |
1e59de90 TL |
57 | if (GetParam()) { |
58 | read_options.async_io = true; | |
59 | } | |
7c673cae | 60 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1])); |
1e59de90 | 61 | ASSERT_OK(iter->status()); |
7c673cae FG |
62 | std::string value(1024, 'a'); |
63 | ||
64 | const int num_records = 10000; | |
65 | for (int i = 0; i < num_records; ++i) { | |
66 | char buf[32]; | |
67 | snprintf(buf, sizeof(buf), "%016d", i); | |
68 | ||
69 | Slice key(buf, 16); | |
70 | ASSERT_OK(Put(1, key, value)); | |
71 | ||
72 | iter->Seek(key); | |
73 | ASSERT_TRUE(iter->Valid()); | |
74 | ASSERT_EQ(iter->key().compare(key), 0); | |
75 | } | |
76 | } | |
77 | ||
1e59de90 | 78 | TEST_P(DBTestTailingIterator, TailingIteratorSeekToNext) { |
7c673cae FG |
79 | CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); |
80 | ReadOptions read_options; | |
81 | read_options.tailing = true; | |
1e59de90 TL |
82 | if (GetParam()) { |
83 | read_options.async_io = true; | |
84 | } | |
7c673cae | 85 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1])); |
1e59de90 | 86 | ASSERT_OK(iter->status()); |
7c673cae | 87 | std::unique_ptr<Iterator> itern(db_->NewIterator(read_options, handles_[1])); |
1e59de90 | 88 | ASSERT_OK(itern->status()); |
7c673cae FG |
89 | std::string value(1024, 'a'); |
90 | ||
91 | const int num_records = 1000; | |
92 | for (int i = 1; i < num_records; ++i) { | |
93 | char buf1[32]; | |
94 | char buf2[32]; | |
95 | snprintf(buf1, sizeof(buf1), "00a0%016d", i * 5); | |
96 | ||
97 | Slice key(buf1, 20); | |
98 | ASSERT_OK(Put(1, key, value)); | |
99 | ||
100 | if (i % 100 == 99) { | |
101 | ASSERT_OK(Flush(1)); | |
102 | } | |
103 | ||
104 | snprintf(buf2, sizeof(buf2), "00a0%016d", i * 5 - 2); | |
105 | Slice target(buf2, 20); | |
106 | iter->Seek(target); | |
107 | ASSERT_TRUE(iter->Valid()); | |
108 | ASSERT_EQ(iter->key().compare(key), 0); | |
109 | if (i == 1) { | |
110 | itern->SeekToFirst(); | |
111 | } else { | |
112 | itern->Next(); | |
113 | } | |
114 | ASSERT_TRUE(itern->Valid()); | |
115 | ASSERT_EQ(itern->key().compare(key), 0); | |
116 | } | |
f67539c2 TL |
117 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks(); |
118 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing(); | |
7c673cae FG |
119 | for (int i = 2 * num_records; i > 0; --i) { |
120 | char buf1[32]; | |
121 | char buf2[32]; | |
122 | snprintf(buf1, sizeof(buf1), "00a0%016d", i * 5); | |
123 | ||
124 | Slice key(buf1, 20); | |
125 | ASSERT_OK(Put(1, key, value)); | |
126 | ||
127 | if (i % 100 == 99) { | |
128 | ASSERT_OK(Flush(1)); | |
129 | } | |
130 | ||
131 | snprintf(buf2, sizeof(buf2), "00a0%016d", i * 5 - 2); | |
132 | Slice target(buf2, 20); | |
133 | iter->Seek(target); | |
134 | ASSERT_TRUE(iter->Valid()); | |
135 | ASSERT_EQ(iter->key().compare(key), 0); | |
136 | } | |
137 | } | |
138 | ||
1e59de90 | 139 | TEST_P(DBTestTailingIterator, TailingIteratorTrimSeekToNext) { |
7c673cae FG |
140 | const uint64_t k150KB = 150 * 1024; |
141 | Options options; | |
142 | options.write_buffer_size = k150KB; | |
143 | options.max_write_buffer_number = 3; | |
144 | options.min_write_buffer_number_to_merge = 2; | |
145 | options.env = env_; | |
146 | CreateAndReopenWithCF({"pikachu"}, options); | |
147 | ReadOptions read_options; | |
148 | read_options.tailing = true; | |
1e59de90 TL |
149 | if (GetParam()) { |
150 | read_options.async_io = true; | |
151 | } | |
7c673cae FG |
152 | int num_iters, deleted_iters; |
153 | ||
154 | char bufe[32]; | |
155 | snprintf(bufe, sizeof(bufe), "00b0%016d", 0); | |
156 | Slice keyu(bufe, 20); | |
157 | read_options.iterate_upper_bound = &keyu; | |
158 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1])); | |
1e59de90 | 159 | ASSERT_OK(iter->status()); |
7c673cae | 160 | std::unique_ptr<Iterator> itern(db_->NewIterator(read_options, handles_[1])); |
1e59de90 | 161 | ASSERT_OK(itern->status()); |
7c673cae | 162 | std::unique_ptr<Iterator> iterh(db_->NewIterator(read_options, handles_[1])); |
1e59de90 | 163 | ASSERT_OK(iterh->status()); |
7c673cae FG |
164 | std::string value(1024, 'a'); |
165 | bool file_iters_deleted = false; | |
166 | bool file_iters_renewed_null = false; | |
167 | bool file_iters_renewed_copy = false; | |
f67539c2 | 168 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack( |
7c673cae FG |
169 | "ForwardIterator::SeekInternal:Return", [&](void* arg) { |
170 | ForwardIterator* fiter = reinterpret_cast<ForwardIterator*>(arg); | |
171 | ASSERT_TRUE(!file_iters_deleted || | |
172 | fiter->TEST_CheckDeletedIters(&deleted_iters, &num_iters)); | |
173 | }); | |
f67539c2 | 174 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack( |
7c673cae FG |
175 | "ForwardIterator::Next:Return", [&](void* arg) { |
176 | ForwardIterator* fiter = reinterpret_cast<ForwardIterator*>(arg); | |
177 | ASSERT_TRUE(!file_iters_deleted || | |
178 | fiter->TEST_CheckDeletedIters(&deleted_iters, &num_iters)); | |
179 | }); | |
f67539c2 | 180 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack( |
7c673cae | 181 | "ForwardIterator::RenewIterators:Null", |
11fdf7f2 | 182 | [&](void* /*arg*/) { file_iters_renewed_null = true; }); |
f67539c2 | 183 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack( |
7c673cae | 184 | "ForwardIterator::RenewIterators:Copy", |
11fdf7f2 | 185 | [&](void* /*arg*/) { file_iters_renewed_copy = true; }); |
f67539c2 | 186 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing(); |
7c673cae FG |
187 | const int num_records = 1000; |
188 | for (int i = 1; i < num_records; ++i) { | |
189 | char buf1[32]; | |
190 | char buf2[32]; | |
191 | char buf3[32]; | |
192 | char buf4[32]; | |
193 | snprintf(buf1, sizeof(buf1), "00a0%016d", i * 5); | |
194 | snprintf(buf3, sizeof(buf3), "00b0%016d", i * 5); | |
195 | ||
196 | Slice key(buf1, 20); | |
197 | ASSERT_OK(Put(1, key, value)); | |
198 | Slice keyn(buf3, 20); | |
199 | ASSERT_OK(Put(1, keyn, value)); | |
200 | ||
201 | if (i % 100 == 99) { | |
202 | ASSERT_OK(Flush(1)); | |
1e59de90 | 203 | ASSERT_OK(dbfull()->TEST_WaitForCompact()); |
7c673cae FG |
204 | if (i == 299) { |
205 | file_iters_deleted = true; | |
206 | } | |
207 | snprintf(buf4, sizeof(buf4), "00a0%016d", i * 5 / 2); | |
208 | Slice target(buf4, 20); | |
209 | iterh->Seek(target); | |
210 | ASSERT_TRUE(iter->Valid()); | |
211 | for (int j = (i + 1) * 5 / 2; j < i * 5; j += 5) { | |
212 | iterh->Next(); | |
213 | ASSERT_TRUE(iterh->Valid()); | |
214 | } | |
215 | if (i == 299) { | |
216 | file_iters_deleted = false; | |
217 | } | |
218 | } | |
219 | ||
220 | file_iters_deleted = true; | |
221 | snprintf(buf2, sizeof(buf2), "00a0%016d", i * 5 - 2); | |
222 | Slice target(buf2, 20); | |
223 | iter->Seek(target); | |
224 | ASSERT_TRUE(iter->Valid()); | |
225 | ASSERT_EQ(iter->key().compare(key), 0); | |
226 | ASSERT_LE(num_iters, 1); | |
227 | if (i == 1) { | |
228 | itern->SeekToFirst(); | |
229 | } else { | |
230 | itern->Next(); | |
231 | } | |
232 | ASSERT_TRUE(itern->Valid()); | |
233 | ASSERT_EQ(itern->key().compare(key), 0); | |
234 | ASSERT_LE(num_iters, 1); | |
235 | file_iters_deleted = false; | |
236 | } | |
237 | ASSERT_TRUE(file_iters_renewed_null); | |
238 | ASSERT_TRUE(file_iters_renewed_copy); | |
11fdf7f2 TL |
239 | iter = nullptr; |
240 | itern = nullptr; | |
241 | iterh = nullptr; | |
7c673cae FG |
242 | BlockBasedTableOptions table_options; |
243 | table_options.no_block_cache = true; | |
244 | table_options.block_cache_compressed = nullptr; | |
245 | options.table_factory.reset(NewBlockBasedTableFactory(table_options)); | |
246 | ReopenWithColumnFamilies({"default", "pikachu"}, options); | |
247 | read_options.read_tier = kBlockCacheTier; | |
248 | std::unique_ptr<Iterator> iteri(db_->NewIterator(read_options, handles_[1])); | |
1e59de90 | 249 | ASSERT_OK(iteri->status()); |
7c673cae FG |
250 | char buf5[32]; |
251 | snprintf(buf5, sizeof(buf5), "00a0%016d", (num_records / 2) * 5 - 2); | |
252 | Slice target1(buf5, 20); | |
253 | iteri->Seek(target1); | |
254 | ASSERT_TRUE(iteri->status().IsIncomplete()); | |
11fdf7f2 | 255 | iteri = nullptr; |
7c673cae FG |
256 | |
257 | read_options.read_tier = kReadAllTier; | |
258 | options.table_factory.reset(NewBlockBasedTableFactory()); | |
259 | ReopenWithColumnFamilies({"default", "pikachu"}, options); | |
260 | iter.reset(db_->NewIterator(read_options, handles_[1])); | |
1e59de90 | 261 | ASSERT_OK(iter->status()); |
7c673cae FG |
262 | for (int i = 2 * num_records; i > 0; --i) { |
263 | char buf1[32]; | |
264 | char buf2[32]; | |
265 | snprintf(buf1, sizeof(buf1), "00a0%016d", i * 5); | |
266 | ||
267 | Slice key(buf1, 20); | |
268 | ASSERT_OK(Put(1, key, value)); | |
269 | ||
270 | if (i % 100 == 99) { | |
271 | ASSERT_OK(Flush(1)); | |
272 | } | |
273 | ||
274 | snprintf(buf2, sizeof(buf2), "00a0%016d", i * 5 - 2); | |
275 | Slice target(buf2, 20); | |
276 | iter->Seek(target); | |
277 | ASSERT_TRUE(iter->Valid()); | |
278 | ASSERT_EQ(iter->key().compare(key), 0); | |
279 | } | |
280 | } | |
281 | ||
1e59de90 | 282 | TEST_P(DBTestTailingIterator, TailingIteratorDeletes) { |
7c673cae FG |
283 | CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); |
284 | ReadOptions read_options; | |
285 | read_options.tailing = true; | |
1e59de90 TL |
286 | if (GetParam()) { |
287 | read_options.async_io = true; | |
288 | } | |
7c673cae FG |
289 | |
290 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1])); | |
1e59de90 | 291 | ASSERT_OK(iter->status()); |
7c673cae FG |
292 | |
293 | // write a single record, read it using the iterator, then delete it | |
294 | ASSERT_OK(Put(1, "0test", "test")); | |
295 | iter->SeekToFirst(); | |
296 | ASSERT_TRUE(iter->Valid()); | |
297 | ASSERT_EQ(iter->key().ToString(), "0test"); | |
298 | ASSERT_OK(Delete(1, "0test")); | |
299 | ||
300 | // write many more records | |
301 | const int num_records = 10000; | |
302 | std::string value(1024, 'A'); | |
303 | ||
304 | for (int i = 0; i < num_records; ++i) { | |
305 | char buf[32]; | |
306 | snprintf(buf, sizeof(buf), "1%015d", i); | |
307 | ||
308 | Slice key(buf, 16); | |
309 | ASSERT_OK(Put(1, key, value)); | |
310 | } | |
311 | ||
312 | // force a flush to make sure that no records are read from memtable | |
313 | ASSERT_OK(Flush(1)); | |
314 | ||
315 | // skip "0test" | |
316 | iter->Next(); | |
317 | ||
318 | // make sure we can read all new records using the existing iterator | |
319 | int count = 0; | |
1e59de90 TL |
320 | for (; iter->Valid(); iter->Next(), ++count) |
321 | ; | |
7c673cae FG |
322 | |
323 | ASSERT_EQ(count, num_records); | |
324 | } | |
325 | ||
1e59de90 | 326 | TEST_P(DBTestTailingIterator, TailingIteratorPrefixSeek) { |
7c673cae FG |
327 | ReadOptions read_options; |
328 | read_options.tailing = true; | |
1e59de90 TL |
329 | if (GetParam()) { |
330 | read_options.async_io = true; | |
331 | } | |
7c673cae FG |
332 | Options options = CurrentOptions(); |
333 | options.create_if_missing = true; | |
334 | options.disable_auto_compactions = true; | |
335 | options.prefix_extractor.reset(NewFixedPrefixTransform(2)); | |
336 | options.memtable_factory.reset(NewHashSkipListRepFactory(16)); | |
337 | options.allow_concurrent_memtable_write = false; | |
338 | DestroyAndReopen(options); | |
339 | CreateAndReopenWithCF({"pikachu"}, options); | |
340 | ||
341 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1])); | |
1e59de90 | 342 | ASSERT_OK(iter->status()); |
7c673cae FG |
343 | ASSERT_OK(Put(1, "0101", "test")); |
344 | ||
345 | ASSERT_OK(Flush(1)); | |
346 | ||
347 | ASSERT_OK(Put(1, "0202", "test")); | |
348 | ||
349 | // Seek(0102) shouldn't find any records since 0202 has a different prefix | |
350 | iter->Seek("0102"); | |
351 | ASSERT_TRUE(!iter->Valid()); | |
352 | ||
353 | iter->Seek("0202"); | |
354 | ASSERT_TRUE(iter->Valid()); | |
355 | ASSERT_EQ(iter->key().ToString(), "0202"); | |
356 | ||
357 | iter->Next(); | |
358 | ASSERT_TRUE(!iter->Valid()); | |
359 | } | |
360 | ||
1e59de90 | 361 | TEST_P(DBTestTailingIterator, TailingIteratorIncomplete) { |
7c673cae FG |
362 | CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); |
363 | ReadOptions read_options; | |
364 | read_options.tailing = true; | |
1e59de90 TL |
365 | if (GetParam()) { |
366 | read_options.async_io = true; | |
367 | } | |
7c673cae FG |
368 | read_options.read_tier = kBlockCacheTier; |
369 | ||
370 | std::string key("key"); | |
371 | std::string value("value"); | |
372 | ||
373 | ASSERT_OK(db_->Put(WriteOptions(), key, value)); | |
374 | ||
375 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options)); | |
1e59de90 | 376 | ASSERT_OK(iter->status()); |
7c673cae FG |
377 | iter->SeekToFirst(); |
378 | // we either see the entry or it's not in cache | |
379 | ASSERT_TRUE(iter->Valid() || iter->status().IsIncomplete()); | |
380 | ||
381 | ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr)); | |
382 | iter->SeekToFirst(); | |
383 | // should still be true after compaction | |
384 | ASSERT_TRUE(iter->Valid() || iter->status().IsIncomplete()); | |
385 | } | |
386 | ||
1e59de90 | 387 | TEST_P(DBTestTailingIterator, TailingIteratorSeekToSame) { |
7c673cae FG |
388 | Options options = CurrentOptions(); |
389 | options.compaction_style = kCompactionStyleUniversal; | |
390 | options.write_buffer_size = 1000; | |
391 | CreateAndReopenWithCF({"pikachu"}, options); | |
392 | ||
393 | ReadOptions read_options; | |
394 | read_options.tailing = true; | |
1e59de90 TL |
395 | if (GetParam()) { |
396 | read_options.async_io = true; | |
397 | } | |
7c673cae FG |
398 | const int NROWS = 10000; |
399 | // Write rows with keys 00000, 00002, 00004 etc. | |
400 | for (int i = 0; i < NROWS; ++i) { | |
401 | char buf[100]; | |
1e59de90 | 402 | snprintf(buf, sizeof(buf), "%05d", 2 * i); |
7c673cae FG |
403 | std::string key(buf); |
404 | std::string value("value"); | |
405 | ASSERT_OK(db_->Put(WriteOptions(), key, value)); | |
406 | } | |
407 | ||
408 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options)); | |
1e59de90 | 409 | ASSERT_OK(iter->status()); |
7c673cae FG |
410 | // Seek to 00001. We expect to find 00002. |
411 | std::string start_key = "00001"; | |
412 | iter->Seek(start_key); | |
413 | ASSERT_TRUE(iter->Valid()); | |
414 | ||
415 | std::string found = iter->key().ToString(); | |
416 | ASSERT_EQ("00002", found); | |
417 | ||
418 | // Now seek to the same key. The iterator should remain in the same | |
419 | // position. | |
420 | iter->Seek(found); | |
421 | ASSERT_TRUE(iter->Valid()); | |
422 | ASSERT_EQ(found, iter->key().ToString()); | |
423 | } | |
424 | ||
425 | // Sets iterate_upper_bound and verifies that ForwardIterator doesn't call | |
426 | // Seek() on immutable iterators when target key is >= prev_key and all | |
427 | // iterators, including the memtable iterator, are over the upper bound. | |
1e59de90 | 428 | TEST_P(DBTestTailingIterator, TailingIteratorUpperBound) { |
7c673cae FG |
429 | CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); |
430 | ||
431 | const Slice upper_bound("20", 3); | |
432 | ReadOptions read_options; | |
433 | read_options.tailing = true; | |
434 | read_options.iterate_upper_bound = &upper_bound; | |
1e59de90 TL |
435 | if (GetParam()) { |
436 | read_options.async_io = true; | |
437 | } | |
7c673cae FG |
438 | ASSERT_OK(Put(1, "11", "11")); |
439 | ASSERT_OK(Put(1, "12", "12")); | |
440 | ASSERT_OK(Put(1, "22", "22")); | |
441 | ASSERT_OK(Flush(1)); // flush all those keys to an immutable SST file | |
442 | ||
443 | // Add another key to the memtable. | |
444 | ASSERT_OK(Put(1, "21", "21")); | |
445 | ||
446 | std::unique_ptr<Iterator> it(db_->NewIterator(read_options, handles_[1])); | |
1e59de90 | 447 | ASSERT_OK(it->status()); |
7c673cae FG |
448 | it->Seek("12"); |
449 | ASSERT_TRUE(it->Valid()); | |
450 | ASSERT_EQ("12", it->key().ToString()); | |
451 | ||
452 | it->Next(); | |
453 | // Not valid since "21" is over the upper bound. | |
454 | ASSERT_FALSE(it->Valid()); | |
1e59de90 | 455 | ASSERT_OK(it->status()); |
7c673cae FG |
456 | // This keeps track of the number of times NeedToSeekImmutable() was true. |
457 | int immutable_seeks = 0; | |
f67539c2 | 458 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack( |
7c673cae | 459 | "ForwardIterator::SeekInternal:Immutable", |
11fdf7f2 | 460 | [&](void* /*arg*/) { ++immutable_seeks; }); |
7c673cae FG |
461 | |
462 | // Seek to 13. This should not require any immutable seeks. | |
f67539c2 | 463 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing(); |
7c673cae | 464 | it->Seek("13"); |
f67539c2 | 465 | ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing(); |
7c673cae FG |
466 | |
467 | ASSERT_FALSE(it->Valid()); | |
1e59de90 TL |
468 | ASSERT_OK(it->status()); |
469 | if (GetParam()) { | |
470 | ASSERT_EQ(1, immutable_seeks); | |
471 | } else { | |
472 | ASSERT_EQ(0, immutable_seeks); | |
473 | } | |
7c673cae FG |
474 | } |
475 | ||
1e59de90 | 476 | TEST_P(DBTestTailingIterator, TailingIteratorGap) { |
7c673cae FG |
477 | // level 1: [20, 25] [35, 40] |
478 | // level 2: [10 - 15] [45 - 50] | |
479 | // level 3: [20, 30, 40] | |
480 | // Previously there is a bug in tailing_iterator that if there is a gap in | |
481 | // lower level, the key will be skipped if it is within the range between | |
482 | // the largest key of index n file and the smallest key of index n+1 file | |
483 | // if both file fit in that gap. In this example, 25 < key < 35 | |
484 | // https://github.com/facebook/rocksdb/issues/1372 | |
485 | CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); | |
486 | ||
487 | ReadOptions read_options; | |
488 | read_options.tailing = true; | |
1e59de90 TL |
489 | if (GetParam()) { |
490 | read_options.async_io = true; | |
491 | } | |
7c673cae FG |
492 | ASSERT_OK(Put(1, "20", "20")); |
493 | ASSERT_OK(Put(1, "30", "30")); | |
494 | ASSERT_OK(Put(1, "40", "40")); | |
495 | ASSERT_OK(Flush(1)); | |
496 | MoveFilesToLevel(3, 1); | |
497 | ||
498 | ASSERT_OK(Put(1, "10", "10")); | |
499 | ASSERT_OK(Put(1, "15", "15")); | |
500 | ASSERT_OK(Flush(1)); | |
501 | ASSERT_OK(Put(1, "45", "45")); | |
502 | ASSERT_OK(Put(1, "50", "50")); | |
503 | ASSERT_OK(Flush(1)); | |
504 | MoveFilesToLevel(2, 1); | |
505 | ||
506 | ASSERT_OK(Put(1, "20", "20")); | |
507 | ASSERT_OK(Put(1, "25", "25")); | |
508 | ASSERT_OK(Flush(1)); | |
509 | ASSERT_OK(Put(1, "35", "35")); | |
510 | ASSERT_OK(Put(1, "40", "40")); | |
511 | ASSERT_OK(Flush(1)); | |
512 | MoveFilesToLevel(1, 1); | |
513 | ||
514 | ColumnFamilyMetaData meta; | |
515 | db_->GetColumnFamilyMetaData(handles_[1], &meta); | |
516 | ||
517 | std::unique_ptr<Iterator> it(db_->NewIterator(read_options, handles_[1])); | |
518 | it->Seek("30"); | |
519 | ASSERT_TRUE(it->Valid()); | |
520 | ASSERT_EQ("30", it->key().ToString()); | |
521 | ||
522 | it->Next(); | |
523 | ASSERT_TRUE(it->Valid()); | |
524 | ASSERT_EQ("35", it->key().ToString()); | |
525 | ||
526 | it->Next(); | |
527 | ASSERT_TRUE(it->Valid()); | |
528 | ASSERT_EQ("40", it->key().ToString()); | |
1e59de90 TL |
529 | |
530 | ASSERT_OK(it->status()); | |
7c673cae FG |
531 | } |
532 | ||
1e59de90 | 533 | TEST_P(DBTestTailingIterator, SeekWithUpperBoundBug) { |
7c673cae FG |
534 | ReadOptions read_options; |
535 | read_options.tailing = true; | |
1e59de90 TL |
536 | if (GetParam()) { |
537 | read_options.async_io = true; | |
538 | } | |
7c673cae FG |
539 | const Slice upper_bound("cc", 3); |
540 | read_options.iterate_upper_bound = &upper_bound; | |
541 | ||
7c673cae FG |
542 | // 1st L0 file |
543 | ASSERT_OK(db_->Put(WriteOptions(), "aa", "SEEN")); | |
544 | ASSERT_OK(Flush()); | |
545 | ||
546 | // 2nd L0 file | |
547 | ASSERT_OK(db_->Put(WriteOptions(), "zz", "NOT-SEEN")); | |
548 | ASSERT_OK(Flush()); | |
549 | ||
550 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options)); | |
1e59de90 | 551 | ASSERT_OK(iter->status()); |
7c673cae FG |
552 | |
553 | iter->Seek("aa"); | |
554 | ASSERT_TRUE(iter->Valid()); | |
555 | ASSERT_EQ(iter->key().ToString(), "aa"); | |
556 | } | |
557 | ||
1e59de90 | 558 | TEST_P(DBTestTailingIterator, SeekToFirstWithUpperBoundBug) { |
7c673cae FG |
559 | ReadOptions read_options; |
560 | read_options.tailing = true; | |
1e59de90 TL |
561 | if (GetParam()) { |
562 | read_options.async_io = true; | |
563 | } | |
7c673cae FG |
564 | const Slice upper_bound("cc", 3); |
565 | read_options.iterate_upper_bound = &upper_bound; | |
566 | ||
7c673cae FG |
567 | // 1st L0 file |
568 | ASSERT_OK(db_->Put(WriteOptions(), "aa", "SEEN")); | |
569 | ASSERT_OK(Flush()); | |
570 | ||
571 | // 2nd L0 file | |
572 | ASSERT_OK(db_->Put(WriteOptions(), "zz", "NOT-SEEN")); | |
573 | ASSERT_OK(Flush()); | |
574 | ||
575 | std::unique_ptr<Iterator> iter(db_->NewIterator(read_options)); | |
1e59de90 | 576 | ASSERT_OK(iter->status()); |
7c673cae FG |
577 | |
578 | iter->SeekToFirst(); | |
579 | ASSERT_TRUE(iter->Valid()); | |
580 | ASSERT_EQ(iter->key().ToString(), "aa"); | |
581 | ||
582 | iter->Next(); | |
583 | ASSERT_FALSE(iter->Valid()); | |
584 | ||
585 | iter->SeekToFirst(); | |
586 | ASSERT_TRUE(iter->Valid()); | |
587 | ASSERT_EQ(iter->key().ToString(), "aa"); | |
588 | } | |
589 | ||
f67539c2 | 590 | } // namespace ROCKSDB_NAMESPACE |
7c673cae FG |
591 | |
592 | #endif // !defined(ROCKSDB_LITE) | |
593 | ||
594 | int main(int argc, char** argv) { | |
595 | #if !defined(ROCKSDB_LITE) | |
f67539c2 | 596 | ROCKSDB_NAMESPACE::port::InstallStackTraceHandler(); |
7c673cae FG |
597 | ::testing::InitGoogleTest(&argc, argv); |
598 | return RUN_ALL_TESTS(); | |
599 | #else | |
1e59de90 TL |
600 | (void)argc; |
601 | (void)argv; | |
7c673cae FG |
602 | return 0; |
603 | #endif | |
604 | } |