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:
parent
18f538038a
commit
2a81633da2
@ -2413,6 +2413,30 @@ TEST_P(DBIteratorTest, NonBlockingIterationBugRepro) {
|
|||||||
EXPECT_TRUE(iter->status().IsIncomplete());
|
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,
|
INSTANTIATE_TEST_CASE_P(DBIteratorTestInstance, DBIteratorTest,
|
||||||
testing::Values(true, false));
|
testing::Values(true, false));
|
||||||
|
|
||||||
|
@ -1991,6 +1991,7 @@ bool BlockBasedTable::PrefixMayMatch(
|
|||||||
|
|
||||||
template <class TBlockIter>
|
template <class TBlockIter>
|
||||||
void BlockBasedTableIterator<TBlockIter>::Seek(const Slice& target) {
|
void BlockBasedTableIterator<TBlockIter>::Seek(const Slice& target) {
|
||||||
|
is_out_of_bound_ = false;
|
||||||
if (!CheckPrefixMayMatch(target)) {
|
if (!CheckPrefixMayMatch(target)) {
|
||||||
ResetDataIter();
|
ResetDataIter();
|
||||||
return;
|
return;
|
||||||
@ -2020,6 +2021,7 @@ void BlockBasedTableIterator<TBlockIter>::Seek(const Slice& target) {
|
|||||||
|
|
||||||
template <class TBlockIter>
|
template <class TBlockIter>
|
||||||
void BlockBasedTableIterator<TBlockIter>::SeekForPrev(const Slice& target) {
|
void BlockBasedTableIterator<TBlockIter>::SeekForPrev(const Slice& target) {
|
||||||
|
is_out_of_bound_ = false;
|
||||||
if (!CheckPrefixMayMatch(target)) {
|
if (!CheckPrefixMayMatch(target)) {
|
||||||
ResetDataIter();
|
ResetDataIter();
|
||||||
return;
|
return;
|
||||||
@ -2062,6 +2064,7 @@ void BlockBasedTableIterator<TBlockIter>::SeekForPrev(const Slice& target) {
|
|||||||
|
|
||||||
template <class TBlockIter>
|
template <class TBlockIter>
|
||||||
void BlockBasedTableIterator<TBlockIter>::SeekToFirst() {
|
void BlockBasedTableIterator<TBlockIter>::SeekToFirst() {
|
||||||
|
is_out_of_bound_ = false;
|
||||||
SavePrevIndexValue();
|
SavePrevIndexValue();
|
||||||
index_iter_->SeekToFirst();
|
index_iter_->SeekToFirst();
|
||||||
if (!index_iter_->Valid()) {
|
if (!index_iter_->Valid()) {
|
||||||
@ -2075,6 +2078,7 @@ void BlockBasedTableIterator<TBlockIter>::SeekToFirst() {
|
|||||||
|
|
||||||
template <class TBlockIter>
|
template <class TBlockIter>
|
||||||
void BlockBasedTableIterator<TBlockIter>::SeekToLast() {
|
void BlockBasedTableIterator<TBlockIter>::SeekToLast() {
|
||||||
|
is_out_of_bound_ = false;
|
||||||
SavePrevIndexValue();
|
SavePrevIndexValue();
|
||||||
index_iter_->SeekToLast();
|
index_iter_->SeekToLast();
|
||||||
if (!index_iter_->Valid()) {
|
if (!index_iter_->Valid()) {
|
||||||
@ -2153,7 +2157,7 @@ void BlockBasedTableIterator<TBlockIter>::InitDataBlock() {
|
|||||||
|
|
||||||
template <class TBlockIter>
|
template <class TBlockIter>
|
||||||
void BlockBasedTableIterator<TBlockIter>::FindKeyForward() {
|
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
|
// 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".
|
// whether a block can be empty so it can be replaced by an "if".
|
||||||
while (!block_iter_.Valid()) {
|
while (!block_iter_.Valid()) {
|
||||||
@ -2193,6 +2197,7 @@ void BlockBasedTableIterator<TBlockIter>::FindKeyForward() {
|
|||||||
|
|
||||||
template <class TBlockIter>
|
template <class TBlockIter>
|
||||||
void BlockBasedTableIterator<TBlockIter>::FindKeyBackward() {
|
void BlockBasedTableIterator<TBlockIter>::FindKeyBackward() {
|
||||||
|
assert(!is_out_of_bound_);
|
||||||
while (!block_iter_.Valid()) {
|
while (!block_iter_.Valid()) {
|
||||||
if (!block_iter_.status().ok()) {
|
if (!block_iter_.status().ok()) {
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user