Fix a bug where GetEntity would expose a blob reference (#11162)

Summary:
The patch fixes a feature interaction bug between BlobDB and the `GetEntity` API:
without the patch, `GetEntity` would return the blob reference (wrapped into a
single-column entity) instead of the actual blob value.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11162

Test Plan: `make check`

Reviewed By: akankshamahajan15

Differential Revision: D42854092

Pulled By: ltamasi

fbshipit-source-id: f750d0ff57def107da16f545077ddce9860ff21a
oxigraph-8.1.1
Levi Tamasi 2 years ago committed by Facebook GitHub Bot
parent 94e3beec77
commit a82021c3d0
  1. 1
      HISTORY.md
  2. 22
      db/blob/db_blob_basic_test.cc
  3. 47
      db/version_set.cc

@ -8,6 +8,7 @@
* Fixed a data race on `ColumnFamilyData::flush_reason` caused by concurrent flushes. * Fixed a data race on `ColumnFamilyData::flush_reason` caused by concurrent flushes.
* Fixed an issue in `Get` and `MultiGet` when user-defined timestamps is enabled in combination with BlobDB. * Fixed an issue in `Get` and `MultiGet` when user-defined timestamps is enabled in combination with BlobDB.
* Fixed some atypical behaviors for `LockWAL()` such as allowing concurrent/recursive use and not expecting `UnlockWAL()` after non-OK result. See API comments. * Fixed some atypical behaviors for `LockWAL()` such as allowing concurrent/recursive use and not expecting `UnlockWAL()` after non-OK result. See API comments.
* Fixed a feature interaction bug where for blobs `GetEntity` would expose the blob reference instead of the blob value.
### Feature Removal ### Feature Removal
* Remove RocksDB Lite. * Remove RocksDB Lite.

@ -1772,6 +1772,28 @@ TEST_F(DBBlobBasicTest, WarmCacheWithBlobsSecondary) {
1); 1);
} }
TEST_F(DBBlobBasicTest, GetEntityBlob) {
Options options = GetDefaultOptions();
options.enable_blob_files = true;
options.min_blob_size = 0;
Reopen(options);
constexpr char key[] = "key";
constexpr char blob_value[] = "blob_value";
ASSERT_OK(Put(key, blob_value));
ASSERT_OK(Flush());
PinnableWideColumns result;
ASSERT_OK(
db_->GetEntity(ReadOptions(), db_->DefaultColumnFamily(), key, &result));
WideColumns expected_columns{{kDefaultWideColumnName, blob_value}};
ASSERT_EQ(result.columns(), expected_columns);
}
class DBBlobWithTimestampTest : public DBBasicTestWithTimestampBase { class DBBlobWithTimestampTest : public DBBasicTestWithTimestampBase {
protected: protected:
DBBlobWithTimestampTest() DBBlobWithTimestampTest()

@ -2339,23 +2339,38 @@ void Version::Get(const ReadOptions& read_options, const LookupKey& k,
PERF_COUNTER_BY_LEVEL_ADD(user_key_return_count, 1, PERF_COUNTER_BY_LEVEL_ADD(user_key_return_count, 1,
fp.GetHitFileLevel()); fp.GetHitFileLevel());
if (is_blob_index) { if (is_blob_index && do_merge && (value || columns)) {
if (do_merge && value) { assert(!columns ||
TEST_SYNC_POINT_CALLBACK("Version::Get::TamperWithBlobIndex", (!columns->columns().empty() &&
value); columns->columns().front().name() == kDefaultWideColumnName));
constexpr FilePrefetchBuffer* prefetch_buffer = nullptr; Slice blob_index =
constexpr uint64_t* bytes_read = nullptr; value ? *value : columns->columns().front().value();
*status = TEST_SYNC_POINT_CALLBACK("Version::Get::TamperWithBlobIndex",
GetBlob(read_options, get_context.ukey_to_get_blob_value(), &blob_index);
*value, prefetch_buffer, value, bytes_read);
if (!status->ok()) { constexpr FilePrefetchBuffer* prefetch_buffer = nullptr;
if (status->IsIncomplete()) {
get_context.MarkKeyMayExist(); PinnableSlice result;
}
return; constexpr uint64_t* bytes_read = nullptr;
*status = GetBlob(read_options, get_context.ukey_to_get_blob_value(),
blob_index, prefetch_buffer, &result, bytes_read);
if (!status->ok()) {
if (status->IsIncomplete()) {
get_context.MarkKeyMayExist();
} }
return;
}
if (value) {
*value = std::move(result);
} else {
assert(columns);
columns->Reset();
columns->SetPlainValue(result);
} }
} }

Loading…
Cancel
Save