From 6f65c0a7d9bca7f7603f431faa0bcdd9ecd162b1 Mon Sep 17 00:00:00 2001 From: Andrew Kryczka Date: Wed, 15 May 2024 10:29:27 -0700 Subject: [PATCH] Add `Iterator` property "rocksdb.iterator.is-value-pinned" --- db/db_iter.cc | 10 ++++++++ db/db_iterator_test.cc | 23 +++++++++++++++---- include/rocksdb/iterator.h | 6 +++++ table/iterator.cc | 4 ++++ .../iterator_property_value_pinned.md | 1 + 5 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 unreleased_history/new_features/iterator_property_value_pinned.md diff --git a/db/db_iter.cc b/db/db_iter.cc index 63dabb9ca98..b42acc4bc6a 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -109,6 +109,16 @@ Status DBIter::GetProperty(std::string prop_name, std::string* prop) { *prop = "Iterator is not valid."; } return Status::OK(); + } else if (prop_name == "rocksdb.iterator.is-value-pinned") { + if (valid_) { + *prop = (pin_thru_lifetime_ && iter_.Valid() && + iter_.value().data() == value_.data()) + ? "1" + : "0"; + } else { + *prop = "Iterator is not valid."; + } + return Status::OK(); } else if (prop_name == "rocksdb.iterator.internal-key") { *prop = saved_key_.GetUserKey().ToString(); return Status::OK(); diff --git a/db/db_iterator_test.cc b/db/db_iterator_test.cc index 8247333b0ba..ef6a3efc273 100644 --- a/db/db_iterator_test.cc +++ b/db/db_iterator_test.cc @@ -133,11 +133,17 @@ TEST_P(DBIteratorTest, IteratorProperty) { ASSERT_NOK(iter->GetProperty("non_existing.value", &prop_value)); ASSERT_OK(iter->GetProperty("rocksdb.iterator.is-key-pinned", &prop_value)); ASSERT_EQ("0", prop_value); + ASSERT_OK( + iter->GetProperty("rocksdb.iterator.is-value-pinned", &prop_value)); + ASSERT_EQ("0", prop_value); ASSERT_OK(iter->GetProperty("rocksdb.iterator.internal-key", &prop_value)); ASSERT_EQ("1", prop_value); iter->Next(); ASSERT_OK(iter->GetProperty("rocksdb.iterator.is-key-pinned", &prop_value)); ASSERT_EQ("Iterator is not valid.", prop_value); + ASSERT_OK( + iter->GetProperty("rocksdb.iterator.is-value-pinned", &prop_value)); + ASSERT_EQ("Iterator is not valid.", prop_value); // Get internal key at which the iteration stopped (tombstone in this case). ASSERT_OK(iter->GetProperty("rocksdb.iterator.internal-key", &prop_value)); @@ -1680,12 +1686,15 @@ TEST_P(DBIteratorTest, PinnedDataIteratorMultipleFiles) { ro.pin_data = true; auto iter = NewIterator(ro); - std::vector> results; + std::vector> results; for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { std::string prop_value; ASSERT_OK(iter->GetProperty("rocksdb.iterator.is-key-pinned", &prop_value)); ASSERT_EQ("1", prop_value); - results.emplace_back(iter->key(), iter->value().ToString()); + ASSERT_OK( + iter->GetProperty("rocksdb.iterator.is-value-pinned", &prop_value)); + ASSERT_EQ("1", prop_value); + results.emplace_back(iter->key(), iter->value()); } ASSERT_EQ(results.size(), true_data.size()); @@ -1739,6 +1748,9 @@ TEST_P(DBIteratorTest, PinnedDataIteratorMergeOperator) { std::string prop_value; ASSERT_OK(iter->GetProperty("rocksdb.iterator.is-key-pinned", &prop_value)); ASSERT_EQ("1", prop_value); + ASSERT_OK( + iter->GetProperty("rocksdb.iterator.is-value-pinned", &prop_value)); + ASSERT_EQ("0", prop_value); results.emplace_back(iter->key(), iter->value().ToString()); } ASSERT_OK(iter->status()); @@ -1792,12 +1804,15 @@ TEST_P(DBIteratorTest, PinnedDataIteratorReadAfterUpdate) { } } - std::vector> results; + std::vector> results; for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { std::string prop_value; ASSERT_OK(iter->GetProperty("rocksdb.iterator.is-key-pinned", &prop_value)); ASSERT_EQ("1", prop_value); - results.emplace_back(iter->key(), iter->value().ToString()); + ASSERT_OK( + iter->GetProperty("rocksdb.iterator.is-value-pinned", &prop_value)); + ASSERT_EQ("1", prop_value); + results.emplace_back(iter->key(), iter->value()); } ASSERT_OK(iter->status()); diff --git a/include/rocksdb/iterator.h b/include/rocksdb/iterator.h index 4be130c0c82..b6e1d866728 100644 --- a/include/rocksdb/iterator.h +++ b/include/rocksdb/iterator.h @@ -78,6 +78,12 @@ class Iterator : public IteratorBase { // - Iterator created with ReadOptions::pin_data = true // - DB tables were created with // BlockBasedTableOptions::use_delta_encoding = false. + // Property "rocksdb.iterator.is-value-pinned": + // If returning "1", this means that the Slice returned by value() is valid + // as long as the iterator is not deleted. + // It is guaranteed to always return "1" if + // - Iterator created with ReadOptions::pin_data = true + // - The value is found in a `kTypeValue` record // Property "rocksdb.iterator.super-version-number": // LSM version used by the iterator. The same format as DB Property // kCurrentSuperVersionNumber. See its comment for more information. diff --git a/table/iterator.cc b/table/iterator.cc index 14e280a07b6..8306f5a0464 100644 --- a/table/iterator.cc +++ b/table/iterator.cc @@ -23,6 +23,10 @@ Status Iterator::GetProperty(std::string prop_name, std::string* prop) { *prop = "0"; return Status::OK(); } + if (prop_name == "rocksdb.iterator.is-value-pinned") { + *prop = "0"; + return Status::OK(); + } return Status::InvalidArgument("Unidentified property."); } diff --git a/unreleased_history/new_features/iterator_property_value_pinned.md b/unreleased_history/new_features/iterator_property_value_pinned.md new file mode 100644 index 00000000000..c0e083d3894 --- /dev/null +++ b/unreleased_history/new_features/iterator_property_value_pinned.md @@ -0,0 +1 @@ +* Added new `Iterator` property, "rocksdb.iterator.is-value-pinned", for checking whether the `Slice` returned by `Iterator::value()` can be used until the `Iterator` is destroyed.