]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/db_tailing_iter_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / db / db_tailing_iter_test.cc
CommitLineData
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 19namespace ROCKSDB_NAMESPACE {
7c673cae 20
1e59de90
TL
21class 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
28INSTANTIATE_TEST_CASE_P(DBTestTailingIterator, DBTestTailingIterator,
29 ::testing::Bool());
30
31TEST_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 53TEST_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 78TEST_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 139TEST_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 282TEST_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 326TEST_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 361TEST_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 387TEST_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 428TEST_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 476TEST_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 533TEST_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 558TEST_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
594int 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}