Skip to content

Commit fc53ac8

Browse files
author
anand76
committed
Fix data block upper bound checking for iterator reseek case (facebook#5883)
Summary: When an iterator reseek happens with the user specifying a new iterate_upper_bound in ReadOptions, and the new seek position is at the end of the same data block, the Seek() ends up using a stale value of data_block_within_upper_bound_ and may return incorrect results. Pull Request resolved: facebook#5883 Test Plan: Added a new test case DBIteratorTest.IterReseekNewUpperBound. Verified that it failed due to the assertion failure without the fix, and passes with the fix. Differential Revision: D17752740 Pulled By: anand1976 fbshipit-source-id: f9b635ff5d6aeb0e1bef102cf8b2f900efd378e3
1 parent 2060a00 commit fc53ac8

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

db/db_iterator_test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,33 @@ TEST_P(DBIteratorTest, IterSeekBeforePrev) {
182182
delete iter;
183183
}
184184

185+
TEST_P(DBIteratorTest, IterReseekNewUpperBound) {
186+
Random rnd(301);
187+
Options options = CurrentOptions();
188+
BlockBasedTableOptions table_options;
189+
table_options.block_size = 1024;
190+
table_options.block_size_deviation = 50;
191+
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
192+
options.compression = kNoCompression;
193+
Reopen(options);
194+
195+
ASSERT_OK(Put("a", RandomString(&rnd, 400)));
196+
ASSERT_OK(Put("aabb", RandomString(&rnd, 400)));
197+
ASSERT_OK(Put("aaef", RandomString(&rnd, 400)));
198+
ASSERT_OK(Put("b", RandomString(&rnd, 400)));
199+
dbfull()->Flush(FlushOptions());
200+
ReadOptions opts;
201+
Slice ub = Slice("aa");
202+
opts.iterate_upper_bound = &ub;
203+
auto iter = NewIterator(opts);
204+
iter->Seek(Slice("a"));
205+
ub = Slice("b");
206+
iter->Seek(Slice("aabc"));
207+
ASSERT_TRUE(iter->Valid());
208+
ASSERT_EQ(iter->key().ToString(), "aaef");
209+
delete iter;
210+
}
211+
185212
TEST_P(DBIteratorTest, IterSeekForPrevBeforeNext) {
186213
ASSERT_OK(Put("a", "b"));
187214
ASSERT_OK(Put("c", "d"));

table/block_based/block_based_table_reader.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2706,11 +2706,21 @@ void BlockBasedTableIterator<TBlockIter, TValue>::SeekImpl(
27062706
// Index contains the first key of the block, and it's >= target.
27072707
// We can defer reading the block.
27082708
is_at_first_key_from_index_ = true;
2709+
// ResetDataIter() will invalidate block_iter_. Thus, there is no need to
2710+
// call CheckDataBlockWithinUpperBound() to check for iterate_upper_bound
2711+
// as that will be done later when the data block is actually read.
27092712
ResetDataIter();
27102713
} else {
27112714
// Need to use the data block.
27122715
if (!same_block) {
27132716
InitDataBlock();
2717+
} else {
2718+
// When the user does a reseek, the iterate_upper_bound might have
2719+
// changed. CheckDataBlockWithinUpperBound() needs to be called
2720+
// explicitly if the reseek ends up in the same data block.
2721+
// If the reseek ends up in a different block, InitDataBlock() will do
2722+
// the iterator upper bound check.
2723+
CheckDataBlockWithinUpperBound();
27142724
}
27152725

27162726
if (target) {
@@ -2721,7 +2731,6 @@ void BlockBasedTableIterator<TBlockIter, TValue>::SeekImpl(
27212731
FindKeyForward();
27222732
}
27232733

2724-
CheckDataBlockWithinUpperBound();
27252734
CheckOutOfBound();
27262735

27272736
if (target) {

0 commit comments

Comments
 (0)