Fix bug when seeking backward against an out-of-bound iterator (#4187)

Summary:
92ee3350e0 introduces an out-of-bound check in BlockBasedTableIterator::Valid(). However, this flag is not reset when re-seeking in backward direction. This caused the iterator to be invalide by mistake. Fix it by always resetting the out-of-bound flag in every seek.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/4187

Differential Revision: D8996600

Pulled By: siying

fbshipit-source-id: b6235ea614f71381e50e7904c4fb036300604ac1
This commit is contained in:
Siying Dong 2018-07-25 17:03:39 -07:00 committed by Yanqin Jin
parent 9897e42813
commit 516faa0fa0
2 changed files with 30 additions and 1 deletions

View File

@ -2413,6 +2413,30 @@ TEST_P(DBIteratorTest, NonBlockingIterationBugRepro) {
EXPECT_TRUE(iter->status().IsIncomplete());
}
TEST_P(DBIteratorTest, SeekBackwardAfterOutOfUpperBound) {
Put("a", "");
Put("b", "");
Flush();
ReadOptions ropt;
Slice ub = "b";
ropt.iterate_upper_bound = &ub;
std::unique_ptr<Iterator> it(dbfull()->NewIterator(ropt));
it->SeekForPrev("a");
ASSERT_TRUE(it->Valid());
ASSERT_OK(it->status());
ASSERT_EQ("a", it->key().ToString());
it->Next();
ASSERT_FALSE(it->Valid());
ASSERT_OK(it->status());
it->SeekForPrev("a");
ASSERT_OK(it->status());
ASSERT_TRUE(it->Valid());
ASSERT_EQ("a", it->key().ToString());
}
INSTANTIATE_TEST_CASE_P(DBIteratorTestInstance, DBIteratorTest,
testing::Values(true, false));

View File

@ -1951,6 +1951,7 @@ bool BlockBasedTable::PrefixMayMatch(
template <class TBlockIter>
void BlockBasedTableIterator<TBlockIter>::Seek(const Slice& target) {
is_out_of_bound_ = false;
if (!CheckPrefixMayMatch(target)) {
ResetDataIter();
return;
@ -1980,6 +1981,7 @@ void BlockBasedTableIterator<TBlockIter>::Seek(const Slice& target) {
template <class TBlockIter>
void BlockBasedTableIterator<TBlockIter>::SeekForPrev(const Slice& target) {
is_out_of_bound_ = false;
if (!CheckPrefixMayMatch(target)) {
ResetDataIter();
return;
@ -2022,6 +2024,7 @@ void BlockBasedTableIterator<TBlockIter>::SeekForPrev(const Slice& target) {
template <class TBlockIter>
void BlockBasedTableIterator<TBlockIter>::SeekToFirst() {
is_out_of_bound_ = false;
SavePrevIndexValue();
index_iter_->SeekToFirst();
if (!index_iter_->Valid()) {
@ -2035,6 +2038,7 @@ void BlockBasedTableIterator<TBlockIter>::SeekToFirst() {
template <class TBlockIter>
void BlockBasedTableIterator<TBlockIter>::SeekToLast() {
is_out_of_bound_ = false;
SavePrevIndexValue();
index_iter_->SeekToLast();
if (!index_iter_->Valid()) {
@ -2113,7 +2117,7 @@ void BlockBasedTableIterator<TBlockIter>::InitDataBlock() {
template <class TBlockIter>
void BlockBasedTableIterator<TBlockIter>::FindKeyForward() {
is_out_of_bound_ = false;
assert(!is_out_of_bound_);
// TODO the while loop inherits from two-level-iterator. We don't know
// whether a block can be empty so it can be replaced by an "if".
while (!block_iter_.Valid()) {
@ -2153,6 +2157,7 @@ void BlockBasedTableIterator<TBlockIter>::FindKeyForward() {
template <class TBlockIter>
void BlockBasedTableIterator<TBlockIter>::FindKeyBackward() {
assert(!is_out_of_bound_);
while (!block_iter_.Valid()) {
if (!block_iter_.status().ok()) {
return;