Files
rocksdb/db/version_util.cc
Josh Kang e292aa95b3 Allow skipping lmax index and filter block prefetches for external file ingestion
Summary:
Bulk external file ingestion can spend significant commit time prefetching index/filter blocks for large Lmax files. This adds `IngestExternalFileOptions::prefetch_lmax_index_and_filter_blocks` (default true) so bulk-load callers can defer that metadata prefetch when the cache doesn't need immediate warming. The option threads through `FileMetaData::skip_index_and_filter_blocks_prefetch` to drive the existing `LoadTableHandlers()` prefetch logic. Benchmarks show ~40% commit latency reduction (3459 → 2112 μs) and ~55% lower IO time (2560 → 1145 μs) when disabled.

Benchmarks:

```
db_bench --benchmarks=ingestexternalfile --num=2200000 --ingest_external_file_num_batches=1 --ingest_external_file_batch_size=1 --ingest_external_file_use_file_info=true --ingest_external_file_fill_cache=true --cache_index_and_filter_blocks=true --bloom_bits=10 --statistics=true --stats_level=3 --ingest_external_file_prefetch_lmax_index_and_filter_blocks=<true|false>
```

| `ingest_external_file_prefetch_lmax_index_and_filter_blocks` | `rocksdb.ingest.external.file.run.micros` | `rocksdb.table.open.io.micros` | index/filter cache adds | last-level read bytes |
| `true` | `3459 us` | `2560 us` | `1 / 1` | `3551559` |
| `false` | `2112 us` | `1145 us` | `0 / 0` | `1333` |

Reviewed By: xingbowang

Differential Revision: D108678511

fbshipit-source-id: e8951e3aad36cc0accffb33ecc3cc1b4aeb89459
2026-06-16 11:20:07 -07:00

100 lines
3.0 KiB
C++

// Copyright (c) Meta Platforms, Inc. and affiliates.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#include "db/version_util.h"
#include <atomic>
#include <functional>
#include <thread>
#include <utility>
#include <vector>
#include "db/internal_stats.h"
#include "db/table_cache.h"
#include "port/port.h"
#include "test_util/sync_point.h"
namespace ROCKSDB_NAMESPACE {
Status LoadTableHandlersHelper(
const std::vector<std::pair<FileMetaData*, int>>& files_meta,
TableCache* table_cache, const FileOptions& file_options,
const InternalKeyComparator& internal_comparator,
InternalStats* internal_stats, int max_threads,
bool prefetch_index_and_filter_in_cache,
const MutableCFOptions& mutable_cf_options,
size_t max_file_size_for_l0_meta_pin, const ReadOptions& read_options,
std::atomic<bool>* stop) {
assert(table_cache != nullptr);
std::atomic<size_t> next_file_meta_idx(0);
std::atomic<bool> has_error(false);
Status ret;
std::function<void()> load_handlers_func([&]() {
while (true) {
size_t file_idx = next_file_meta_idx.fetch_add(1);
if (has_error.load(std::memory_order_relaxed)) {
break;
}
if (file_idx >= files_meta.size()) {
break;
}
if (stop != nullptr && stop->load()) {
break;
}
auto* cache = table_cache->get_cache().get();
if (cache->GetCapacity() < TableCache::kInfiniteCapacity &&
cache->GetUsage() >= cache->GetCapacity()) {
break;
}
auto* file_meta = files_meta[file_idx].first;
int level = files_meta[file_idx].second;
TEST_SYNC_POINT_CALLBACK(
"VersionBuilder::Rep::LoadTableHandlers::BeforeFindTable", file_meta);
TableCache::TypedHandle* handle = nullptr;
TableReader* table_reader = nullptr;
const bool prefetch_index_and_filter_for_file =
prefetch_index_and_filter_in_cache &&
!file_meta->skip_index_and_filter_blocks_prefetch;
auto status = table_cache->FindTable(
read_options, file_options, internal_comparator, *file_meta, &handle,
mutable_cf_options, &table_reader, false /* no_io */,
internal_stats->GetFileReadHist(level), false /* skip_filters */,
level, prefetch_index_and_filter_for_file,
max_file_size_for_l0_meta_pin, file_meta->temperature,
true /* pin_table_handle */);
TEST_SYNC_POINT_CALLBACK(
"VersionBuilder::Rep::LoadTableHandlers::AfterFindTable", &status);
if (!status.ok()) {
bool expected = false;
if (has_error.compare_exchange_strong(expected, true)) {
ret = status;
}
}
}
});
std::vector<port::Thread> threads;
for (int i = 1; i < max_threads; i++) {
threads.emplace_back(load_handlers_func);
}
load_handlers_func();
for (auto& t : threads) {
t.join();
}
return ret;
}
} // namespace ROCKSDB_NAMESPACE