mirror of
https://github.com/facebook/rocksdb.git
synced 2026-10-23 08:09:02 +03:00
Summary: Pull Request resolved: https://github.com/facebook/rocksdb/pull/15294 Why the change is required: `open_files_async` reduces startup latency by moving SST validation and table-reader opening to background work, but `DB::OpenAsSecondary()` still performed that work synchronously. Previous behavior: A secondary using `open_files_async=true` replayed its MANIFEST through `ReactiveVersionSet`, synchronously verified and opened every current SST, and only then returned. The option therefore provided no startup benefit for secondary instances. New behavior: `DB::OpenAsSecondary()` can now return after installing its initial read view and start initial SST validation and table-reader pinning through the existing asynchronous opener. With `max_open_files=-1`, the opener processes all current SSTs in the background; a finite table cache can stop the eager pass at capacity and validate remaining files on demand. Later `TryCatchUpWithPrimary()` rounds remain synchronous. Async-open failures notify listeners and are latched according to the existing severity and `paranoid_checks` policy. If an error is not latched, a later read retries the file access and reports a persistent failure. A latched error requires fixing the underlying problem and reopening the secondary. Read-only instances do not start write-oriented recovery. Implementation: Initial reactive MANIFEST replay can defer SST verification and handler loading. The deferral is immutable constructor state on `ReactiveVersionSet`, is cleared before catch-up mode, and is restricted to normal secondary recovery. `VersionBuilder::GetAndClearIntermediateFiles()` now moves out and clears its own historical add-then-delete bookkeeping so callers cannot accidentally retain stale state. Secondary open schedules the background opener after publishing the read view. Its context pins the captured Versions and column families, including retained secondary handles whose column family was subsequently dropped by the primary. Existing table-reader opening performs SST size and unique-ID validation, avoiding a separate serial metadata pass. Closing the DB or canceling background work safely cancels a queued opener or waits for a running opener. Read-only async-open errors use an ErrorHandler path that notifies listeners without automatic recovery. Secondary async open explicitly rejects FIFO compaction. Safety, compatibility, and limitations: The default `open_files_async=false` path and existing primary async-open behavior are unchanged. WAL and blob recovery, as well as later secondary catch-up, remain synchronous. Follower DB and `OpenAndCompact()` do not use this deferral. There are no file-format, ABI, or public API signature changes. Secondary async open requires `skip_stats_update_on_db_open=true` and does not support FIFO compaction. Applications must keep files accessible by coordinating deletion with the primary or by using an Env/FileSystem that delays physical deletion until every instance releases a file. With asynchronous opening, `max_open_files=-1` cannot guarantee every SST is pinned before `OpenAsSecondary()` returns; the table-files-only `max_open_files=-1` workaround applies only when asynchronous opening is disabled. No completion API is added. Validation covers initial deferral and pinning, synchronous catch-up, table-reader detection of physical-size mismatch, FIFO rejection, listener-adjusted errors and synchronous read retry, retained handles after primary column-family deletion, close and explicit cancellation with no HIGH-priority worker, stopping new table opens during shutdown, primary async open, follower isolation, and remote compaction. Linux Buck builds and focused tests passed. Cross-platform CI is pending, and `make check-sources` cannot run successfully in this Sapling checkout because its script requires Git. Reviewed By: pdillinger Differential Revision: D122417547 fbshipit-source-id: 91d408469c35c4ea21165c5e7db75068e65c2389
130 lines
5.2 KiB
C++
130 lines
5.2 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// 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).
|
|
//
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
//
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
|
|
#include "db/version_edit.h"
|
|
#include "rocksdb/file_system.h"
|
|
#include "rocksdb/metadata.h"
|
|
#include "rocksdb/slice_transform.h"
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
struct ImmutableCFOptions;
|
|
class TableCache;
|
|
class VersionStorageInfo;
|
|
class VersionEdit;
|
|
struct FileMetaData;
|
|
class InternalStats;
|
|
class Version;
|
|
class VersionSet;
|
|
class VersionEditHandler;
|
|
class ColumnFamilyData;
|
|
class CacheReservationManager;
|
|
|
|
// A helper class so we can efficiently apply a whole sequence
|
|
// of edits to a particular state without creating intermediate
|
|
// Versions that contain full copies of the intermediate state.
|
|
class VersionBuilder {
|
|
public:
|
|
VersionBuilder(const FileOptions& file_options,
|
|
const ImmutableCFOptions* ioptions, TableCache* table_cache,
|
|
VersionStorageInfo* base_vstorage, VersionSet* version_set,
|
|
std::shared_ptr<CacheReservationManager>
|
|
file_metadata_cache_res_mgr = nullptr,
|
|
ColumnFamilyData* cfd = nullptr,
|
|
VersionEditHandler* version_edit_handler = nullptr,
|
|
bool track_found_and_missing_files = false,
|
|
bool allow_incomplete_valid_version = false);
|
|
~VersionBuilder();
|
|
|
|
bool CheckConsistencyForNumLevels();
|
|
|
|
Status Apply(const VersionEdit* edit);
|
|
|
|
// Save the current Version to the provided `vstorage`.
|
|
Status SaveTo(VersionStorageInfo* vstorage) const;
|
|
|
|
// Load table handlers for newly added files in the builder. This does not
|
|
// load any files in the base storage.
|
|
Status LoadTableHandlers(InternalStats* internal_stats, int max_threads,
|
|
bool prefetch_index_and_filter_in_cache,
|
|
bool is_initial_load,
|
|
const MutableCFOptions& mutable_cf_options,
|
|
size_t max_file_size_for_l0_meta_pin,
|
|
const ReadOptions& read_options);
|
|
|
|
//============APIs only used by VersionEditHandlerPointInTime ============//
|
|
|
|
// The builder can find all the files to build a `Version`. Or if
|
|
// `allow_incomplete_valid_version_` is true and the version history is never
|
|
// edited in an atomic group, and only a suffix of L0 SST files and their
|
|
// associated blob files are missing.
|
|
// From the users' perspective, missing a suffix of L0 files means missing the
|
|
// user's most recently written data. So the remaining available files still
|
|
// presents a valid point in time view, although for some previous time.
|
|
// This validity check result will be cached and reused if the Version is not
|
|
// updated between two validity checks.
|
|
bool ValidVersionAvailable();
|
|
|
|
bool HasMissingFiles() const;
|
|
|
|
// When applying a sequence of VersionEdits, intermediate files are the ones
|
|
// that are added and then deleted. Returns the tracked files and clears them
|
|
// so that subsequent VersionEdits start with a clean state.
|
|
std::vector<std::string> GetAndClearIntermediateFiles();
|
|
|
|
// Clearing all the found files in this Version.
|
|
void ClearFoundFiles();
|
|
|
|
// Single-edit undo for building a Version reflecting the state *before* the
|
|
// most recent `Apply()`. On a valid->invalid negative edge,
|
|
// `RollbackLastApply()` reverts the builder to the pre-edit state (so
|
|
// `SaveTo`/`LoadTableHandlers` build the pre-edit Version), then
|
|
// `RedoLastApply()` restores the post-edit state to continue replay.
|
|
// `CommitLastApply()` finalizes the most recent `Apply()` (freeing files
|
|
// whose deletion was deferred) and must be called once per `Apply()`; it is a
|
|
// no-op if there is nothing pending. This replaces the previous per-edit
|
|
// whole-Rep save-point copy, which was quadratic over a MANIFEST.
|
|
void RollbackLastApply();
|
|
void RedoLastApply();
|
|
void CommitLastApply();
|
|
|
|
//======= End of APIs only used by VersionEditPointInTime==========//
|
|
|
|
private:
|
|
class Rep;
|
|
std::unique_ptr<Rep> rep_;
|
|
};
|
|
|
|
// A wrapper of version builder which references the current version in
|
|
// constructor and unref it in the destructor.
|
|
// Both of the constructor and destructor need to be called inside DB Mutex.
|
|
class BaseReferencedVersionBuilder {
|
|
public:
|
|
explicit BaseReferencedVersionBuilder(
|
|
ColumnFamilyData* cfd, VersionEditHandler* version_edit_handler = nullptr,
|
|
bool track_found_and_missing_files = false,
|
|
bool allow_incomplete_valid_version = false);
|
|
BaseReferencedVersionBuilder(
|
|
ColumnFamilyData* cfd, Version* v,
|
|
VersionEditHandler* version_edit_handler = nullptr,
|
|
bool track_found_and_missing_files = false,
|
|
bool allow_incomplete_valid_version = false);
|
|
~BaseReferencedVersionBuilder();
|
|
VersionBuilder* version_builder() const { return version_builder_.get(); }
|
|
|
|
private:
|
|
std::unique_ptr<VersionBuilder> version_builder_;
|
|
Version* version_;
|
|
};
|
|
} // namespace ROCKSDB_NAMESPACE
|