Skip to content

Commit a390fd0

Browse files
xingbowangmeta-codesync[bot]
authored andcommitted
Track newer snapshot versions in RocksDB metadata reads
Summary: Add experimental `DB::GetWithMetadata()` and `DB::MultiGetWithMetadata()` APIs with opt-in timestamp and `newer_version_present` outputs. Append the new virtuals to `DB` to preserve existing vtable slot order, and forward them through `StackableDB`, BlobDB, TTL, compacted, read-only, secondary, C, and Java/JNI surfaces. For explicit-snapshot reads, sample a published sequence upper bound and scan through it while a read callback preserves the snapshot-visible result. Point writes and covering range tombstones in memtables and SSTs update per-key metadata. Row-cache lookups are bypassed only while sequence inspection is still required and replay uses the original snapshot sequence. Keep ordinary `Get()` / `MultiGet()` paths free of metadata discovery scans and context allocation. Reject newer-version tracking for `kPersistedTier` and transaction reads that require custom visibility callbacks. Latest reads without an explicit snapshot return false metadata. Integrate both metadata APIs into batched `db_stress`, including consistency validation for atomic batches, and add a `db_bench --read_with_metadata` mode for repeatable performance comparisons. Add the public API release note. Rebased onto latest remote master `b79bb51e6349` and resolved conflicts in the transaction and TTL wrappers/tests. This version also keeps the prior review-feedback fixes around metadata context mutation, compacted-DB output initialization, TTL MultiGet allocation, and MultiGet status preservation. This version applies clang-format fixes for the `check-format-and-targets` workflow without changing behavior. Differential Revision: D104182397
1 parent fcf382c commit a390fd0

54 files changed

Lines changed: 2950 additions & 160 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

db/c.cc

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2623,6 +2623,59 @@ char* rocksdb_get(rocksdb_t* db, const rocksdb_readoptions_t* options,
26232623
return result;
26242624
}
26252625

2626+
static char* rocksdb_get_with_metadata_impl(
2627+
rocksdb_t* db, const rocksdb_readoptions_t* options,
2628+
ColumnFamilyHandle* column_family, const char* key, size_t keylen,
2629+
size_t* vallen, char** timestamp, size_t* timestamp_len,
2630+
unsigned char* newer_version_present, char** errptr) {
2631+
ROCKSDB_NAMESPACE::OutputMetadata output_metadata;
2632+
if (timestamp != nullptr && timestamp_len != nullptr) {
2633+
output_metadata.WantTimestamp();
2634+
}
2635+
if (newer_version_present != nullptr) {
2636+
output_metadata.WantNewerVersionPresent();
2637+
}
2638+
2639+
PinnableSlice pinnable_val;
2640+
const Status s =
2641+
db->rep->GetWithMetadata(options->rep, column_family, Slice(key, keylen),
2642+
&pinnable_val, &output_metadata);
2643+
if (newer_version_present != nullptr) {
2644+
*newer_version_present = *output_metadata.newer_version_present ? 1 : 0;
2645+
}
2646+
2647+
char* result = nullptr;
2648+
if (s.ok()) {
2649+
*vallen = pinnable_val.size();
2650+
result = CopyString(pinnable_val);
2651+
if (output_metadata.timestamp.has_value()) {
2652+
*timestamp_len = output_metadata.timestamp->size();
2653+
*timestamp = CopyString(*output_metadata.timestamp);
2654+
}
2655+
} else {
2656+
*vallen = 0;
2657+
if (output_metadata.timestamp.has_value()) {
2658+
*timestamp = nullptr;
2659+
*timestamp_len = 0;
2660+
}
2661+
if (!s.IsNotFound()) {
2662+
SaveError(errptr, s);
2663+
}
2664+
}
2665+
return result;
2666+
}
2667+
2668+
char* rocksdb_get_with_metadata(rocksdb_t* db,
2669+
const rocksdb_readoptions_t* options,
2670+
const char* key, size_t keylen, size_t* vallen,
2671+
char** timestamp, size_t* timestamp_len,
2672+
unsigned char* newer_version_present,
2673+
char** errptr) {
2674+
return rocksdb_get_with_metadata_impl(
2675+
db, options, db->rep->DefaultColumnFamily(), key, keylen, vallen,
2676+
timestamp, timestamp_len, newer_version_present, errptr);
2677+
}
2678+
26262679
char* rocksdb_get_cf(rocksdb_t* db, const rocksdb_readoptions_t* options,
26272680
rocksdb_column_family_handle_t* column_family,
26282681
const char* key, size_t keylen, size_t* vallen,
@@ -2645,6 +2698,16 @@ char* rocksdb_get_cf(rocksdb_t* db, const rocksdb_readoptions_t* options,
26452698
return result;
26462699
}
26472700

2701+
char* rocksdb_get_cf_with_metadata(
2702+
rocksdb_t* db, const rocksdb_readoptions_t* options,
2703+
rocksdb_column_family_handle_t* column_family, const char* key,
2704+
size_t keylen, size_t* vallen, char** timestamp, size_t* timestamp_len,
2705+
unsigned char* newer_version_present, char** errptr) {
2706+
return rocksdb_get_with_metadata_impl(
2707+
db, options, column_family->rep, key, keylen, vallen, timestamp,
2708+
timestamp_len, newer_version_present, errptr);
2709+
}
2710+
26482711
char* rocksdb_get_with_ts(rocksdb_t* db, const rocksdb_readoptions_t* options,
26492712
const char* key, size_t keylen, size_t* vallen,
26502713
char** ts, size_t* tslen, char** errptr) {
@@ -2736,6 +2799,72 @@ void rocksdb_multi_get(rocksdb_t* db, const rocksdb_readoptions_t* options,
27362799
}
27372800
}
27382801

2802+
static void rocksdb_multi_get_with_metadata_impl(
2803+
rocksdb_t* db, const rocksdb_readoptions_t* options,
2804+
ColumnFamilyHandle* const* column_families, size_t num_keys,
2805+
const char* const* keys_list, const size_t* keys_list_sizes,
2806+
char** values_list, size_t* values_list_sizes, char** timestamp_list,
2807+
size_t* timestamp_list_sizes, unsigned char* newer_version_present,
2808+
char** errs) {
2809+
std::unique_ptr<Slice[]> keys(new Slice[num_keys]);
2810+
std::vector<PinnableSlice> values(num_keys);
2811+
std::vector<Status> statuses(num_keys);
2812+
for (size_t i = 0; i < num_keys; ++i) {
2813+
keys[i] = Slice(keys_list[i], keys_list_sizes[i]);
2814+
}
2815+
2816+
ROCKSDB_NAMESPACE::MultiGetOutputMetadata output_metadata;
2817+
if (timestamp_list != nullptr && timestamp_list_sizes != nullptr) {
2818+
output_metadata.WantTimestamps();
2819+
}
2820+
if (newer_version_present != nullptr) {
2821+
output_metadata.WantNewerVersionPresent();
2822+
}
2823+
db->rep->MultiGetWithMetadata(options->rep, num_keys, column_families,
2824+
keys.get(), values.data(), statuses.data(),
2825+
&output_metadata);
2826+
2827+
for (size_t i = 0; i < num_keys; ++i) {
2828+
if (newer_version_present != nullptr) {
2829+
newer_version_present[i] =
2830+
(*output_metadata.newer_version_present)[i] ? 1 : 0;
2831+
}
2832+
if (statuses[i].ok()) {
2833+
values_list[i] = CopyString(values[i]);
2834+
values_list_sizes[i] = values[i].size();
2835+
if (output_metadata.timestamps.has_value()) {
2836+
timestamp_list[i] = CopyString((*output_metadata.timestamps)[i]);
2837+
timestamp_list_sizes[i] = (*output_metadata.timestamps)[i].size();
2838+
}
2839+
errs[i] = nullptr;
2840+
} else {
2841+
values_list[i] = nullptr;
2842+
values_list_sizes[i] = 0;
2843+
if (output_metadata.timestamps.has_value()) {
2844+
timestamp_list[i] = nullptr;
2845+
timestamp_list_sizes[i] = 0;
2846+
}
2847+
errs[i] = statuses[i].IsNotFound()
2848+
? nullptr
2849+
: strdup(statuses[i].ToString().c_str());
2850+
}
2851+
}
2852+
}
2853+
2854+
void rocksdb_multi_get_with_metadata(
2855+
rocksdb_t* db, const rocksdb_readoptions_t* options, size_t num_keys,
2856+
const char* const* keys_list, const size_t* keys_list_sizes,
2857+
char** values_list, size_t* values_list_sizes, char** timestamp_list,
2858+
size_t* timestamp_list_sizes, unsigned char* newer_version_present,
2859+
char** errs) {
2860+
std::vector<ColumnFamilyHandle*> column_families(
2861+
num_keys, db->rep->DefaultColumnFamily());
2862+
rocksdb_multi_get_with_metadata_impl(
2863+
db, options, column_families.data(), num_keys, keys_list, keys_list_sizes,
2864+
values_list, values_list_sizes, timestamp_list, timestamp_list_sizes,
2865+
newer_version_present, errs);
2866+
}
2867+
27392868
void rocksdb_multi_get_with_ts(rocksdb_t* db,
27402869
const rocksdb_readoptions_t* options,
27412870
size_t num_keys, const char* const* keys_list,
@@ -2811,6 +2940,24 @@ void rocksdb_multi_get_cf(
28112940
}
28122941
}
28132942

2943+
void rocksdb_multi_get_cf_with_metadata(
2944+
rocksdb_t* db, const rocksdb_readoptions_t* options,
2945+
const rocksdb_column_family_handle_t* const* column_families,
2946+
size_t num_keys, const char* const* keys_list,
2947+
const size_t* keys_list_sizes, char** values_list,
2948+
size_t* values_list_sizes, char** timestamp_list,
2949+
size_t* timestamp_list_sizes, unsigned char* newer_version_present,
2950+
char** errs) {
2951+
std::vector<ColumnFamilyHandle*> cfs(num_keys);
2952+
for (size_t i = 0; i < num_keys; ++i) {
2953+
cfs[i] = column_families[i]->rep;
2954+
}
2955+
rocksdb_multi_get_with_metadata_impl(
2956+
db, options, cfs.data(), num_keys, keys_list, keys_list_sizes,
2957+
values_list, values_list_sizes, timestamp_list, timestamp_list_sizes,
2958+
newer_version_present, errs);
2959+
}
2960+
28142961
void rocksdb_multi_get_cf_with_ts(
28152962
rocksdb_t* db, const rocksdb_readoptions_t* options,
28162963
const rocksdb_column_family_handle_t* const* column_families,

db/c_test.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2474,6 +2474,35 @@ int main(int argc, char** argv) {
24742474
CheckNoError(err);
24752475
rocksdb_readoptions_set_snapshot(roptions, snap);
24762476
CheckGet(db, roptions, "foo", "hello");
2477+
2478+
size_t metadata_value_len = 0;
2479+
unsigned char newer_version_present = 0;
2480+
char* metadata_value =
2481+
rocksdb_get_with_metadata(db, roptions, "foo", 3, &metadata_value_len,
2482+
NULL, NULL, &newer_version_present, &err);
2483+
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
2484+
CheckNoError(err);
2485+
CheckEqual("hello", metadata_value, metadata_value_len);
2486+
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
2487+
CheckCondition(newer_version_present == 1);
2488+
Free(&metadata_value);
2489+
2490+
const char* metadata_keys[] = {"foo"};
2491+
const size_t metadata_key_sizes[] = {3};
2492+
char* metadata_values[1];
2493+
size_t metadata_value_sizes[1];
2494+
unsigned char newer_versions[1];
2495+
char* metadata_errors[1];
2496+
rocksdb_multi_get_with_metadata(
2497+
db, roptions, 1, metadata_keys, metadata_key_sizes, metadata_values,
2498+
metadata_value_sizes, NULL, NULL, newer_versions, metadata_errors);
2499+
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
2500+
CheckCondition(metadata_errors[0] == NULL);
2501+
CheckEqual("hello", metadata_values[0], metadata_value_sizes[0]);
2502+
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
2503+
CheckCondition(newer_versions[0] == 1);
2504+
Free(&metadata_values[0]);
2505+
24772506
rocksdb_readoptions_set_snapshot(roptions, NULL);
24782507
CheckGet(db, roptions, "foo", NULL);
24792508
rocksdb_release_snapshot(db, snap);

0 commit comments

Comments
 (0)