#include "rocksdb/perf_context.h"
#include "table/block_based/flush_block_policy.h"
#include "util/random.h"
+#include "utilities/merge_operators/string_append/stringappend2.h"
namespace ROCKSDB_NAMESPACE {
class DBIteratorTest : public DBTestBase,
public testing::WithParamInterface<bool> {
public:
- DBIteratorTest() : DBTestBase("/db_iterator_test", /*env_do_fsync=*/true) {}
+ DBIteratorTest() : DBTestBase("db_iterator_test", /*env_do_fsync=*/true) {}
Iterator* NewIterator(const ReadOptions& read_options,
ColumnFamilyHandle* column_family = nullptr) {
// The test needs to be changed if kPersistedTier is supported in iterator.
Options options = CurrentOptions();
CreateAndReopenWithCF({"pikachu"}, options);
- Put(1, "1", "2");
- Delete(1, "2");
+ ASSERT_OK(Put(1, "1", "2"));
+ ASSERT_OK(Delete(1, "2"));
ReadOptions ropt;
ropt.pin_data = false;
{
TEST_P(DBIteratorTest, NonBlockingIteration) {
do {
ReadOptions non_blocking_opts, regular_opts;
- Options options = CurrentOptions();
+ anon::OptionsOverride options_override;
+ options_override.full_block_cache = true;
+ Options options = CurrentOptions(options_override);
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
non_blocking_opts.read_tier = kBlockCacheTier;
+
CreateAndReopenWithCF({"pikachu"}, options);
// write one kv to the database.
ASSERT_OK(Put(1, "a", "b"));
TEST_P(DBIteratorTest, IterSeekBeforePrev) {
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("0", "f"));
ASSERT_OK(Put("1", "h"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("2", "j"));
auto iter = NewIterator(ReadOptions());
iter->Seek(Slice("c"));
ASSERT_OK(Put("aabb", rnd.RandomString(400)));
ASSERT_OK(Put("aaef", rnd.RandomString(400)));
ASSERT_OK(Put("b", rnd.RandomString(400)));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ReadOptions opts;
Slice ub = Slice("aa");
opts.iterate_upper_bound = &ub;
TEST_P(DBIteratorTest, IterSeekForPrevBeforeNext) {
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("0", "f"));
ASSERT_OK(Put("1", "h"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("2", "j"));
auto iter = NewIterator(ReadOptions());
iter->SeekForPrev(Slice("0"));
std::string MakeLongKey(size_t length, char c) {
return std::string(length, c);
}
-} // namespace
+} // anonymous namespace
TEST_P(DBIteratorTest, IterLongKeys) {
ASSERT_OK(Put(MakeLongKey(20, 0), "0"));
ASSERT_OK(Put(MakeLongKey(32, 2), "2"));
ASSERT_OK(Put("a", "b"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put(MakeLongKey(50, 1), "1"));
ASSERT_OK(Put(MakeLongKey(127, 3), "3"));
ASSERT_OK(Put(MakeLongKey(64, 4), "4"));
TEST_P(DBIteratorTest, IterNextWithNewerSeq) {
ASSERT_OK(Put("0", "0"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
ASSERT_OK(Put("d", "e"));
TEST_P(DBIteratorTest, IterPrevWithNewerSeq) {
ASSERT_OK(Put("0", "0"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
ASSERT_OK(Put("d", "e"));
TEST_P(DBIteratorTest, IterPrevWithNewerSeq2) {
ASSERT_OK(Put("0", "0"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
ASSERT_OK(Put("e", "f"));
iter->SeekForPrev("foo");
ASSERT_EQ(IterStatus(iter), "(invalid)");
+ ASSERT_OK(iter->status());
+
delete iter;
} while (ChangeCompactOptions());
}
delete iter;
}
+TEST_F(DBIteratorTest, ReseekUponDirectionChange) {
+ Options options = GetDefaultOptions();
+ options.create_if_missing = true;
+ options.prefix_extractor.reset(NewFixedPrefixTransform(1));
+ options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
+ options.merge_operator.reset(
+ new StringAppendTESTOperator(/*delim_char=*/' '));
+ DestroyAndReopen(options);
+ ASSERT_OK(Put("foo", "value"));
+ ASSERT_OK(Put("bar", "value"));
+ {
+ std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
+ it->SeekToLast();
+ it->Prev();
+ it->Next();
+ }
+ ASSERT_EQ(1,
+ options.statistics->getTickerCount(NUMBER_OF_RESEEKS_IN_ITERATION));
+
+ const std::string merge_key("good");
+ ASSERT_OK(Put(merge_key, "orig"));
+ ASSERT_OK(Merge(merge_key, "suffix"));
+ {
+ std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
+ it->Seek(merge_key);
+ ASSERT_TRUE(it->Valid());
+ const uint64_t prev_reseek_count =
+ options.statistics->getTickerCount(NUMBER_OF_RESEEKS_IN_ITERATION);
+ it->Prev();
+ ASSERT_EQ(prev_reseek_count + 1, options.statistics->getTickerCount(
+ NUMBER_OF_RESEEKS_IN_ITERATION));
+ }
+}
+
TEST_P(DBIteratorTest, IterSmallAndLargeMix) {
do {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
TEST_P(DBIteratorTest, IteratorPinsRef) {
do {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
- Put(1, "foo", "hello");
+ ASSERT_OK(Put(1, "foo", "hello"));
// Get iterator that will yield the current contents of the DB.
Iterator* iter = NewIterator(ReadOptions(), handles_[1]);
// Write to force compactions
- Put(1, "foo", "newvalue1");
+ ASSERT_OK(Put(1, "foo", "newvalue1"));
for (int i = 0; i < 100; i++) {
// 100K values
ASSERT_OK(Put(1, Key(i), Key(i) + std::string(100000, 'v')));
}
- Put(1, "foo", "newvalue2");
+ ASSERT_OK(Put(1, "foo", "newvalue2"));
iter->SeekToFirst();
ASSERT_TRUE(iter->Valid());
TEST_P(DBIteratorTest, IteratorDeleteAfterCfDelete) {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
- Put(1, "foo", "delete-cf-then-delete-iter");
- Put(1, "hello", "value2");
+ ASSERT_OK(Put(1, "foo", "delete-cf-then-delete-iter"));
+ ASSERT_OK(Put(1, "hello", "value2"));
ColumnFamilyHandle* cf = handles_[1];
ReadOptions ro;
ASSERT_EQ(IterStatus(iter), "foo->delete-cf-then-delete-iter");
// delete CF handle
- db_->DestroyColumnFamilyHandle(cf);
+ EXPECT_OK(db_->DestroyColumnFamilyHandle(cf));
handles_.erase(std::begin(handles_) + 1);
// delete Iterator after CF handle is deleted
TEST_P(DBIteratorTest, IteratorDeleteAfterCfDrop) {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
- Put(1, "foo", "drop-cf-then-delete-iter");
+ ASSERT_OK(Put(1, "foo", "drop-cf-then-delete-iter"));
ReadOptions ro;
ColumnFamilyHandle* cf = handles_[1];
ASSERT_EQ(IterStatus(iter), "foo->drop-cf-then-delete-iter");
// drop and delete CF
- db_->DropColumnFamily(cf);
- db_->DestroyColumnFamilyHandle(cf);
+ EXPECT_OK(db_->DropColumnFamily(cf));
+ EXPECT_OK(db_->DestroyColumnFamilyHandle(cf));
handles_.erase(std::begin(handles_) + 1);
// delete Iterator after CF handle is dropped
iter->Next();
ASSERT_TRUE(iter->Valid());
- ASSERT_EQ(static_cast<int>(get_perf_context()->internal_delete_skipped_count), 2);
+ ASSERT_EQ(
+ static_cast<int>(get_perf_context()->internal_delete_skipped_count), 2);
// now testing with iterate_bound
Slice prefix("c");
// even though the key is deleted
// hence internal_delete_skipped_count should be 0
ASSERT_TRUE(!iter->Valid());
- ASSERT_EQ(static_cast<int>(get_perf_context()->internal_delete_skipped_count), 0);
+ ASSERT_EQ(
+ static_cast<int>(get_perf_context()->internal_delete_skipped_count), 0);
}
}
// write three entries with different keys using Merge()
WriteOptions wopts;
- db_->Merge(wopts, "1", "data1");
- db_->Merge(wopts, "2", "data2");
- db_->Merge(wopts, "3", "data3");
+ ASSERT_OK(db_->Merge(wopts, "1", "data1"));
+ ASSERT_OK(db_->Merge(wopts, "2", "data2"));
+ ASSERT_OK(db_->Merge(wopts, "3", "data3"));
std::unique_ptr<Iterator> it(NewIterator(ReadOptions()));
if (run_config == TestConfig::FLUSH_EVERY_1000) {
if (i && i % 1000 == 0) {
- Flush();
+ ASSERT_OK(Flush());
}
}
}
Close();
Reopen(options);
} else if (run_config == TestConfig::COMPACT_BEFORE_READ) {
- db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
+ ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
}
ReadOptions ro;
}
delete iter;
-}
+ }
};
+#if !defined(ROCKSDB_VALGRIND_RUN) || defined(ROCKSDB_FULL_VALGRIND_RUN)
TEST_P(DBIteratorTestForPinnedData, PinnedDataIteratorRandomizedNormal) {
PinnedDataIteratorRandomized(TestConfig::NORMAL);
}
+#endif // !defined(ROCKSDB_VALGRIND_RUN) || defined(ROCKSDB_FULL_VALGRIND_RUN)
TEST_P(DBIteratorTestForPinnedData, PinnedDataIteratorRandomizedCLoseAndOpen) {
PinnedDataIteratorRandomized(TestConfig::CLOSE_AND_OPEN);
PinnedDataIteratorRandomized(TestConfig::FLUSH_EVERY_1000);
}
+INSTANTIATE_TEST_CASE_P(DBIteratorTestForPinnedDataInstance,
+ DBIteratorTestForPinnedData,
+ testing::Values(true, false));
+
#ifndef ROCKSDB_LITE
TEST_P(DBIteratorTest, PinnedDataIteratorMultipleFiles) {
Options options = CurrentOptions();
Iterator* iter = NewIterator(ro);
iter->SeekForPrev("c2");
ASSERT_TRUE(!iter->Valid());
+ ASSERT_OK(iter->status());
delete iter;
}
}
Iterator* iter = NewIterator(ro);
iter->SeekForPrev("c2");
ASSERT_TRUE(!iter->Valid());
+ ASSERT_OK(iter->status());
delete iter;
}
}
ASSERT_EQ(TestGetTickerCount(options, NUMBER_DB_PREV), (uint64_t)total_prev);
ASSERT_EQ(TestGetTickerCount(options, NUMBER_DB_PREV_FOUND),
(uint64_t)total_prev_found);
- ASSERT_EQ(TestGetTickerCount(options, ITER_BYTES_READ), (uint64_t)total_bytes);
-
+ ASSERT_EQ(TestGetTickerCount(options, ITER_BYTES_READ),
+ (uint64_t)total_bytes);
}
TEST_P(DBIteratorTest, ReadAhead) {
std::string value(1024, 'a');
for (int i = 0; i < 100; i++) {
- Put(Key(i), value);
+ ASSERT_OK(Put(Key(i), value));
}
ASSERT_OK(Flush());
MoveFilesToLevel(2);
for (int i = 0; i < 100; i++) {
- Put(Key(i), value);
+ ASSERT_OK(Put(Key(i), value));
}
ASSERT_OK(Flush());
MoveFilesToLevel(1);
for (int i = 0; i < 100; i++) {
- Put(Key(i), value);
+ ASSERT_OK(Put(Key(i), value));
}
ASSERT_OK(Flush());
#ifndef ROCKSDB_LITE
EXPECT_EQ(get_perf_context()->internal_merge_count, 0);
EXPECT_GE(get_perf_context()->internal_recent_skipped_count, 2);
EXPECT_GE(get_perf_context()->seek_on_memtable_count, 2);
- EXPECT_EQ(1, options.statistics->getTickerCount(
- NUMBER_OF_RESEEKS_IN_ITERATION));
+ EXPECT_EQ(1,
+ options.statistics->getTickerCount(NUMBER_OF_RESEEKS_IN_ITERATION));
}
TEST_P(DBIteratorTest, Refresh) {
ASSERT_OK(Put("x", "y"));
std::unique_ptr<Iterator> iter(NewIterator(ReadOptions()));
+ ASSERT_OK(iter->status());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(iter->key().compare(Slice("x")), 0);
iter->Next();
ASSERT_FALSE(iter->Valid());
- iter->Refresh();
+ ASSERT_OK(iter->status());
+ ASSERT_OK(iter->Refresh());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
iter->Next();
ASSERT_FALSE(iter->Valid());
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("m", "n"));
iter->Next();
ASSERT_FALSE(iter->Valid());
- iter->Refresh();
+ ASSERT_OK(iter->status());
+ ASSERT_OK(iter->Refresh());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
ReadOptions options;
options.snapshot = snapshot;
Iterator* iter = NewIterator(options);
+ ASSERT_OK(iter->status());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
iter->Next();
ASSERT_FALSE(iter->Valid());
- Status s;
- s = iter->Refresh();
+ ASSERT_OK(iter->status());
+ Status s = iter->Refresh();
ASSERT_TRUE(s.IsNotSupported());
db_->ReleaseSnapshot(snapshot);
delete iter;
TEST_P(DBIteratorTest, TableFilter) {
ASSERT_OK(Put("a", "1"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("b", "2"));
ASSERT_OK(Put("c", "3"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("d", "4"));
ASSERT_OK(Put("e", "5"));
ASSERT_OK(Put("f", "6"));
- dbfull()->Flush(FlushOptions());
+ EXPECT_OK(dbfull()->Flush(FlushOptions()));
// Ensure the table_filter callback is called once for each table.
{
}
ASSERT_EQ(count, 3);
delete iter;
- skip_count += 8; // 3 deletes + 3 original keys + 2 lower in sequence
+ skip_count += 8; // 3 deletes + 3 original keys + 2 lower in sequence
ASSERT_EQ(skip_count, TestGetTickerCount(options, NUMBER_ITER_SKIP));
iter = NewIterator(ReadOptions());
}
ASSERT_EQ(count, 3);
delete iter;
- skip_count += 8; // Same as above, but in reverse order
+ skip_count += 8; // Same as above, but in reverse order
ASSERT_EQ(skip_count, TestGetTickerCount(options, NUMBER_ITER_SKIP));
ASSERT_OK(Put("aa", "1"));
iter = NewIterator(ro);
count = 0;
- for(iter->Seek("aa"); iter->Valid(); iter->Next()) {
+ for (iter->Seek("aa"); iter->Valid(); iter->Next()) {
ASSERT_OK(iter->status());
count++;
}
ASSERT_EQ(count, 1);
delete iter;
- skip_count += 6; // 3 deletes + 3 original keys
+ skip_count += 6; // 3 deletes + 3 original keys
ASSERT_EQ(skip_count, TestGetTickerCount(options, NUMBER_ITER_SKIP));
iter = NewIterator(ro);
count = 0;
- for(iter->SeekToLast(); iter->Valid(); iter->Prev()) {
+ for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
ASSERT_OK(iter->status());
count++;
}
ReadOptions ropts;
ropts.max_skippable_internal_keys = 2;
- Put("1", "val_1");
+ ASSERT_OK(Put("1", "val_1"));
// Add more tombstones than max_skippable_internal_keys so that Next() fails.
- Delete("2");
- Delete("3");
- Delete("4");
- Delete("5");
- Put("6", "val_6");
+ ASSERT_OK(Delete("2"));
+ ASSERT_OK(Delete("3"));
+ ASSERT_OK(Delete("4"));
+ ASSERT_OK(Delete("5"));
+ ASSERT_OK(Put("6", "val_6"));
std::unique_ptr<Iterator> iter(NewIterator(ropts));
iter->SeekToFirst();
DestroyAndReopen(options);
// Two records in sst file, each in its own block.
- Put("b", "");
- Put("d", "");
- Flush();
+ ASSERT_OK(Put("b", ""));
+ ASSERT_OK(Put("d", ""));
+ ASSERT_OK(Flush());
// Create a nonblocking iterator before writing to memtable.
ReadOptions ropt;
// Overwrite a key in memtable many times to hit
// max_sequential_skip_in_iterations (which is 8 by default).
for (int i = 0; i < 20; ++i) {
- Put("c", "");
+ ASSERT_OK(Put("c", ""));
}
// Load the second block in sst file into the block cache.
}
TEST_P(DBIteratorTest, SeekBackwardAfterOutOfUpperBound) {
- Put("a", "");
- Put("b", "");
- Flush();
+ ASSERT_OK(Put("a", ""));
+ ASSERT_OK(Put("b", ""));
+ ASSERT_OK(Flush());
ReadOptions ropt;
Slice ub = "b";
ASSERT_OK(iter->status());
}
+TEST_P(DBIteratorTest, Blob) {
+ Options options = CurrentOptions();
+ options.enable_blob_files = true;
+ options.max_sequential_skip_in_iterations = 2;
+ options.statistics = CreateDBStatistics();
+
+ Reopen(options);
+
+ // Note: we have 4 KVs (3 of which are hidden) for key "b" and
+ // max_sequential_skip_in_iterations is set to 2. Thus, we need to do a reseek
+ // anytime we move from "b" to "c" or vice versa.
+ ASSERT_OK(Put("a", "va"));
+ ASSERT_OK(Flush());
+ ASSERT_OK(Put("b", "vb0"));
+ ASSERT_OK(Flush());
+ ASSERT_OK(Put("b", "vb1"));
+ ASSERT_OK(Flush());
+ ASSERT_OK(Put("b", "vb2"));
+ ASSERT_OK(Flush());
+ ASSERT_OK(Put("b", "vb3"));
+ ASSERT_OK(Flush());
+ ASSERT_OK(Put("c", "vc"));
+ ASSERT_OK(Flush());
+
+ std::unique_ptr<Iterator> iter_guard(NewIterator(ReadOptions()));
+ Iterator* const iter = iter_guard.get();
+
+ iter->SeekToFirst();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 0);
+ ASSERT_EQ(IterStatus(iter), "a->va");
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 0);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 1);
+ ASSERT_EQ(IterStatus(iter), "c->vc");
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 1);
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
+ iter->SeekToFirst();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 1);
+ ASSERT_EQ(IterStatus(iter), "a->va");
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 1);
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
+
+ iter->SeekToLast();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 1);
+ ASSERT_EQ(IterStatus(iter), "c->vc");
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "a->va");
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
+ iter->SeekToLast();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "c->vc");
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
+
+ iter->Seek("");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "a->va");
+ iter->Seek("a");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "a->va");
+ iter->Seek("ax");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+
+ iter->SeekForPrev("d");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "c->vc");
+ iter->SeekForPrev("c");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 2);
+ ASSERT_EQ(IterStatus(iter), "c->vc");
+ iter->SeekForPrev("bx");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 3);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+
+ iter->Seek("b");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 3);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+ iter->Seek("z");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 3);
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
+ iter->SeekForPrev("b");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 4);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+ iter->SeekForPrev("");
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 4);
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
+
+ // Switch from reverse to forward
+ iter->SeekToLast();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 4);
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 5);
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 5);
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 6);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+
+ // Switch from forward to reverse
+ iter->SeekToFirst();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 6);
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 6);
+ iter->Next();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 7);
+ iter->Prev();
+ ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 8);
+ ASSERT_EQ(IterStatus(iter), "b->vb3");
+}
+
INSTANTIATE_TEST_CASE_P(DBIteratorTestInstance, DBIteratorTest,
testing::Values(true, false));
uint64_t num_versions =
CurrentOptions().max_sequential_skip_in_iterations + 10;
for (uint64_t i = 0; i < num_versions; i++) {
- ASSERT_OK(Put("bar", ToString(i)));
+ ASSERT_OK(Put("bar", std::to_string(i)));
}
SequenceNumber seq3 = db_->GetLatestSequenceNumber();
TestReadCallback callback2(seq3);
ASSERT_TRUE(iter->Valid());
ASSERT_OK(iter->status());
ASSERT_EQ("bar", iter->key());
- ASSERT_EQ(ToString(num_versions - 1), iter->value());
+ ASSERT_EQ(std::to_string(num_versions - 1), iter->value());
delete iter;
}
}
}
+TEST_F(DBIteratorTest, IteratorRefreshReturnSV) {
+ Options options = CurrentOptions();
+ options.disable_auto_compactions = true;
+ DestroyAndReopen(options);
+ ASSERT_OK(
+ db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
+ std::unique_ptr<Iterator> iter{db_->NewIterator(ReadOptions())};
+ SyncPoint::GetInstance()->SetCallBack(
+ "ArenaWrappedDBIter::Refresh:SV", [&](void*) {
+ ASSERT_OK(db_->Put(WriteOptions(), "dummy", "new SV"));
+ // This makes the local SV obselete.
+ ASSERT_OK(Flush());
+ SyncPoint::GetInstance()->DisableProcessing();
+ });
+ SyncPoint::GetInstance()->EnableProcessing();
+ ASSERT_OK(iter->Refresh());
+ iter.reset();
+ // iter used to not cleanup SV, so the Close() below would hit an assertion
+ // error.
+ Close();
+}
+
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {