diff --git a/db/db_iter.cc b/db/db_iter.cc index 8626a4f81..dff251a40 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -1433,9 +1433,8 @@ void DBIter::SetSavedKeyToSeekForPrevTarget(const Slice& target) { if (timestamp_size_ > 0) { const std::string kTsMax(timestamp_size_, '\xff'); Slice ts = kTsMax; - saved_key_.UpdateInternalKey( - kMaxSequenceNumber, kValueTypeForSeekForPrev, - timestamp_lb_ != nullptr ? timestamp_lb_ : &ts); + saved_key_.UpdateInternalKey(kMaxSequenceNumber, kValueTypeForSeekForPrev, + &ts); } } } @@ -1637,24 +1636,15 @@ void DBIter::SeekToLast() { if (iterate_upper_bound_ != nullptr) { // Seek to last key strictly less than ReadOptions.iterate_upper_bound. SeekForPrev(*iterate_upper_bound_); - const bool is_ikey = (timestamp_size_ > 0 && timestamp_lb_ != nullptr); +#ifndef NDEBUG Slice k = Valid() ? key() : Slice(); - if (is_ikey && Valid()) { + if (Valid() && timestamp_size_ > 0 && timestamp_lb_) { k.remove_suffix(kNumInternalBytes + timestamp_size_); } - while (Valid() && 0 == user_comparator_.CompareWithoutTimestamp( - *iterate_upper_bound_, /*a_has_ts=*/false, k, - /*b_has_ts=*/false)) { - ReleaseTempPinnedData(); - ResetBlobValue(); - ResetValueAndColumns(); - PrevInternal(nullptr); - - k = key(); - if (is_ikey) { - k.remove_suffix(kNumInternalBytes + timestamp_size_); - } - } + assert(!Valid() || user_comparator_.CompareWithoutTimestamp( + k, /*a_has_ts=*/false, *iterate_upper_bound_, + /*b_has_ts=*/false) < 0); +#endif return; } diff --git a/db/db_with_timestamp_basic_test.cc b/db/db_with_timestamp_basic_test.cc index 31ebb25c2..4b8132df3 100644 --- a/db/db_with_timestamp_basic_test.cc +++ b/db/db_with_timestamp_basic_test.cc @@ -3892,6 +3892,32 @@ TEST_F(DBBasicTestWithTimestamp, RangeTombstoneApproximateSize) { std::numeric_limits::max() /* max_file_num_to_ignore */, "" /*trim_ts*/)); } + +TEST_F(DBBasicTestWithTimestamp, IterSeekToLastWithIterateUpperbound) { + // Test for a bug fix where DBIter::SeekToLast() could fail when + // iterate_upper_bound and iter_start_ts are both set. + Options options = CurrentOptions(); + const size_t kTimestampSize = Timestamp(0, 0).size(); + TestComparator test_cmp(kTimestampSize); + options.comparator = &test_cmp; + DestroyAndReopen(options); + + ASSERT_OK(db_->Put(WriteOptions(), Key(1), Timestamp(2, 0), "val")); + ReadOptions ro; + std::string k = Key(1); + Slice k_slice = k; + ro.iterate_upper_bound = &k_slice; + std::string ts = Timestamp(3, 0); + Slice read_ts = ts; + ro.timestamp = &read_ts; + std::string start_ts = Timestamp(0, 0); + Slice start_ts_slice = start_ts; + ro.iter_start_ts = &start_ts_slice; + std::unique_ptr iter{db_->NewIterator(ro)}; + iter->SeekToLast(); + ASSERT_FALSE(iter->Valid()); + ASSERT_OK(iter->status()); +} } // namespace ROCKSDB_NAMESPACE int main(int argc, char** argv) {