@@ -55,6 +55,7 @@ TEST_F(DBIteratorTest, IteratorProperty) {
5555 Options options = CurrentOptions ();
5656 CreateAndReopenWithCF ({" pikachu" }, options);
5757 Put (1 , " 1" , " 2" );
58+ Delete (1 , " 2" );
5859 ReadOptions ropt;
5960 ropt.pin_data = false ;
6061 {
@@ -64,9 +65,15 @@ TEST_F(DBIteratorTest, IteratorProperty) {
6465 ASSERT_NOK (iter->GetProperty (" non_existing.value" , &prop_value));
6566 ASSERT_OK (iter->GetProperty (" rocksdb.iterator.is-key-pinned" , &prop_value));
6667 ASSERT_EQ (" 0" , prop_value);
68+ ASSERT_OK (iter->GetProperty (" rocksdb.iterator.internal-key" , &prop_value));
69+ ASSERT_EQ (" 1" , prop_value);
6770 iter->Next ();
6871 ASSERT_OK (iter->GetProperty (" rocksdb.iterator.is-key-pinned" , &prop_value));
6972 ASSERT_EQ (" Iterator is not valid." , prop_value);
73+
74+ // Get internal key at which the iteration stopped (tombstone in this case).
75+ ASSERT_OK (iter->GetProperty (" rocksdb.iterator.internal-key" , &prop_value));
76+ ASSERT_EQ (" 2" , prop_value);
7077 }
7178 Close ();
7279}
@@ -2157,6 +2164,48 @@ TEST_F(DBIteratorTest, SkipStatistics) {
21572164 ASSERT_EQ (skip_count, TestGetTickerCount (options, NUMBER_ITER_SKIP));
21582165}
21592166
2167+ TEST_F (DBIteratorTest, SeekAfterHittingManyInternalKeys) {
2168+ Options options = CurrentOptions ();
2169+ DestroyAndReopen (options);
2170+ ReadOptions ropts;
2171+ ropts.max_skippable_internal_keys = 2 ;
2172+
2173+ Put (" 1" , " val_1" );
2174+ // Add more tombstones than max_skippable_internal_keys so that Next() fails.
2175+ Delete (" 2" );
2176+ Delete (" 3" );
2177+ Delete (" 4" );
2178+ Delete (" 5" );
2179+ Put (" 6" , " val_6" );
2180+
2181+ unique_ptr<Iterator> iter (db_->NewIterator (ropts));
2182+ iter->SeekToFirst ();
2183+
2184+ ASSERT_TRUE (iter->Valid ());
2185+ ASSERT_EQ (iter->key ().ToString (), " 1" );
2186+ ASSERT_EQ (iter->value ().ToString (), " val_1" );
2187+
2188+ // This should fail as incomplete due to too many non-visible internal keys on
2189+ // the way to the next valid user key.
2190+ iter->Next ();
2191+ ASSERT_TRUE (!iter->Valid ());
2192+ ASSERT_TRUE (iter->status ().IsIncomplete ());
2193+
2194+ // Get the internal key at which Next() failed.
2195+ std::string prop_value;
2196+ ASSERT_OK (iter->GetProperty (" rocksdb.iterator.internal-key" , &prop_value));
2197+ ASSERT_EQ (" 4" , prop_value);
2198+
2199+ // Create a new iterator to seek to the internal key.
2200+ unique_ptr<Iterator> iter2 (db_->NewIterator (ropts));
2201+ iter2->Seek (prop_value);
2202+ ASSERT_TRUE (iter2->Valid ());
2203+ ASSERT_OK (iter2->status ());
2204+
2205+ ASSERT_EQ (iter2->key ().ToString (), " 6" );
2206+ ASSERT_EQ (iter2->value ().ToString (), " val_6" );
2207+ }
2208+
21602209} // namespace rocksdb
21612210
21622211int main (int argc, char ** argv) {
0 commit comments