diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 1a292c9c3d..c4ce8867d9 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -154,6 +154,7 @@ tests.libxrpl > xrpl.ledger tests.libxrpl > xrpl.net xrpl.core > xrpl.basics xrpl.core > xrpl.json +xrpl.core > xrpl.ledger xrpl.json > xrpl.basics xrpl.ledger > xrpl.basics xrpl.ledger > xrpl.protocol diff --git a/.github/scripts/strategy-matrix/generate.py b/.github/scripts/strategy-matrix/generate.py index 0e44b1be54..75847b4d9d 100755 --- a/.github/scripts/strategy-matrix/generate.py +++ b/.github/scripts/strategy-matrix/generate.py @@ -51,22 +51,20 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: # Only generate a subset of configurations in PRs. if not all: # Debian: - # - Bookworm using GCC 13: Release and Unity on linux/amd64, set - # the reference fee to 500. - # - Bookworm using GCC 15: Debug and no Unity on linux/amd64, enable - # code coverage (which will be done below). - # - Bookworm using Clang 16: Debug and no Unity on linux/arm64, - # enable voidstar. - # - Bookworm using Clang 17: Release and no Unity on linux/amd64, - # set the reference fee to 1000. - # - Bookworm using Clang 20: Debug and Unity on linux/amd64. + # - Bookworm using GCC 13: Release on linux/amd64, set the reference + # fee to 500. + # - Bookworm using GCC 15: Debug on linux/amd64, enable code + # coverage (which will be done below). + # - Bookworm using Clang 16: Debug on linux/arm64, enable voidstar. + # - Bookworm using Clang 17: Release on linux/amd64, set the + # reference fee to 1000. + # - Bookworm using Clang 20: Debug on linux/amd64. if os["distro_name"] == "debian": skip = True if os["distro_version"] == "bookworm": if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13" and build_type == "Release" - and "-Dunity=ON" in cmake_args and architecture["platform"] == "linux/amd64" ): cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}" @@ -74,14 +72,12 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15" and build_type == "Debug" - and "-Dunity=OFF" in cmake_args and architecture["platform"] == "linux/amd64" ): skip = False if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16" and build_type == "Debug" - and "-Dunity=OFF" in cmake_args and architecture["platform"] == "linux/arm64" ): cmake_args = f"-Dvoidstar=ON {cmake_args}" @@ -89,7 +85,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-17" and build_type == "Release" - and "-Dunity=ON" in cmake_args and architecture["platform"] == "linux/amd64" ): cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}" @@ -97,7 +92,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20" and build_type == "Debug" - and "-Dunity=ON" in cmake_args and architecture["platform"] == "linux/amd64" ): skip = False @@ -105,15 +99,14 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: continue # RHEL: - # - 9 using GCC 12: Debug and Unity on linux/amd64. - # - 10 using Clang: Release and no Unity on linux/amd64. + # - 9 using GCC 12: Debug on linux/amd64. + # - 10 using Clang: Release on linux/amd64. if os["distro_name"] == "rhel": skip = True if os["distro_version"] == "9": if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" and build_type == "Debug" - and "-Dunity=ON" in cmake_args and architecture["platform"] == "linux/amd64" ): skip = False @@ -121,7 +114,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-any" and build_type == "Release" - and "-Dunity=OFF" in cmake_args and architecture["platform"] == "linux/amd64" ): skip = False @@ -129,17 +121,16 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: continue # Ubuntu: - # - Jammy using GCC 12: Debug and no Unity on linux/arm64. - # - Noble using GCC 14: Release and Unity on linux/amd64. - # - Noble using Clang 18: Debug and no Unity on linux/amd64. - # - Noble using Clang 19: Release and Unity on linux/arm64. + # - Jammy using GCC 12: Debug on linux/arm64. + # - Noble using GCC 14: Release on linux/amd64. + # - Noble using Clang 18: Debug on linux/amd64. + # - Noble using Clang 19: Release on linux/arm64. if os["distro_name"] == "ubuntu": skip = True if os["distro_version"] == "jammy": if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" and build_type == "Debug" - and "-Dunity=OFF" in cmake_args and architecture["platform"] == "linux/arm64" ): skip = False @@ -147,21 +138,18 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14" and build_type == "Release" - and "-Dunity=ON" in cmake_args and architecture["platform"] == "linux/amd64" ): skip = False if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-18" and build_type == "Debug" - and "-Dunity=OFF" in cmake_args and architecture["platform"] == "linux/amd64" ): skip = False if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-19" and build_type == "Release" - and "-Dunity=ON" in cmake_args and architecture["platform"] == "linux/arm64" ): skip = False @@ -169,20 +157,16 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: continue # MacOS: - # - Debug and no Unity on macos/arm64. + # - Debug on macos/arm64. if os["distro_name"] == "macos" and not ( - build_type == "Debug" - and "-Dunity=OFF" in cmake_args - and architecture["platform"] == "macos/arm64" + build_type == "Debug" and architecture["platform"] == "macos/arm64" ): continue # Windows: - # - Release and Unity on windows/amd64. + # - Release on windows/amd64. if os["distro_name"] == "windows" and not ( - build_type == "Release" - and "-Dunity=ON" in cmake_args - and architecture["platform"] == "windows/amd64" + build_type == "Release" and architecture["platform"] == "windows/amd64" ): continue @@ -209,18 +193,17 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: ): continue - # Enable code coverage for Debian Bookworm using GCC 15 in Debug and no - # Unity on linux/amd64 + # Enable code coverage for Debian Bookworm using GCC 15 in Debug on + # linux/amd64 if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15" and build_type == "Debug" - and "-Dunity=OFF" in cmake_args and architecture["platform"] == "linux/amd64" ): cmake_args = f"-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}" # Generate a unique name for the configuration, e.g. macos-arm64-debug - # or debian-bookworm-gcc-12-amd64-release-unity. + # or debian-bookworm-gcc-12-amd64-release. config_name = os["distro_name"] if (n := os["distro_version"]) != "": config_name += f"-{n}" @@ -234,8 +217,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: config_name += f"-{build_type.lower()}" if "-Dcoverage=ON" in cmake_args: config_name += "-coverage" - if "-Dunity=ON" in cmake_args: - config_name += "-unity" # Add the configuration to the list, with the most unique fields first, # so that they are easier to identify in the GitHub Actions UI, as long diff --git a/.github/scripts/strategy-matrix/linux.json b/.github/scripts/strategy-matrix/linux.json index e64a05f925..4943579be8 100644 --- a/.github/scripts/strategy-matrix/linux.json +++ b/.github/scripts/strategy-matrix/linux.json @@ -208,5 +208,5 @@ } ], "build_type": ["Debug", "Release"], - "cmake_args": ["-Dunity=OFF", "-Dunity=ON"] + "cmake_args": [""] } diff --git a/.github/scripts/strategy-matrix/macos.json b/.github/scripts/strategy-matrix/macos.json index 14b6089620..6fc44d0f80 100644 --- a/.github/scripts/strategy-matrix/macos.json +++ b/.github/scripts/strategy-matrix/macos.json @@ -15,8 +15,5 @@ } ], "build_type": ["Debug", "Release"], - "cmake_args": [ - "-Dunity=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5", - "-Dunity=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5" - ] + "cmake_args": ["-DCMAKE_POLICY_VERSION_MINIMUM=3.5"] } diff --git a/.github/scripts/strategy-matrix/windows.json b/.github/scripts/strategy-matrix/windows.json index 8637b31012..8c536c70f2 100644 --- a/.github/scripts/strategy-matrix/windows.json +++ b/.github/scripts/strategy-matrix/windows.json @@ -15,5 +15,5 @@ } ], "build_type": ["Debug", "Release"], - "cmake_args": ["-Dunity=OFF", "-Dunity=ON"] + "cmake_args": [""] } diff --git a/BUILD.md b/BUILD.md index f90aa0c148..35668aeabd 100644 --- a/BUILD.md +++ b/BUILD.md @@ -368,6 +368,36 @@ The workaround for this error is to add two lines to your profile: tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] ``` +### Set Up Ccache + +To speed up repeated compilations, we recommend that you install +[ccache](https://ccache.dev), a tool that wraps your compiler so that it can +cache build objects locally. + +#### Linux + +You can install it using the package manager, e.g. `sudo apt install ccache` +(Ubuntu) or `sudo dnf install ccache` (RHEL). + +#### macOS + +You can install it using Homebrew, i.e. `brew install ccache`. + +#### Windows + +You can install it using Chocolatey, i.e. `choco install ccache`. If you already +have Ccache installed, then `choco upgrade ccache` will update it to the latest +version. However, if you see an error such as: + +``` +terminate called after throwing an instance of 'std::bad_alloc' + what(): std::bad_alloc +C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(617,5): error MSB6006: "cl.exe" exited with code 3. +``` + +then please install a specific version of Ccache that we know works, via: `choco +install ccache --version 4.11.3 --allow-downgrade`. + ### Build and Test 1. Create a build directory and move into it. @@ -545,16 +575,10 @@ See [Sanitizers docs](./docs/build/sanitizers.md) for more details. | `assert` | OFF | Enable assertions. | | `coverage` | OFF | Prepare the coverage report. | | `tests` | OFF | Build tests. | -| `unity` | OFF | Configure a unity build. | | `xrpld` | OFF | Build the xrpld application, and not just the libxrpl library. | | `werr` | OFF | Treat compilation warnings as errors | | `wextra` | OFF | Enable additional compilation warnings | -[Unity builds][5] may be faster for the first build -(at the cost of much more memory) since they concatenate sources into fewer -translation units. Non-unity builds may be faster for incremental builds, -and can be helpful for detecting `#include` omissions. - ## Troubleshooting ### Conan @@ -621,7 +645,6 @@ If you want to experiment with a new package, follow these steps: [1]: https://github.com/conan-io/conan-center-index/issues/13168 [2]: https://en.cppreference.com/w/cpp/compiler_support/20 [3]: https://docs.conan.io/en/latest/getting_started.html -[5]: https://en.wikipedia.org/wiki/Unity_build [6]: https://github.com/boostorg/beast/issues/2648 [7]: https://github.com/boostorg/beast/issues/2661 [gcovr]: https://gcovr.com/en/stable/getting-started.html diff --git a/cmake/XrplAddTest.cmake b/cmake/XrplAddTest.cmake index 135b975a02..35189e203f 100644 --- a/cmake/XrplAddTest.cmake +++ b/cmake/XrplAddTest.cmake @@ -9,8 +9,5 @@ function (xrpl_add_test name) isolate_headers(${target} "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/tests/${name}" PRIVATE) - # Make sure the test isn't optimized away in unity builds - set_target_properties(${target} PROPERTIES UNITY_BUILD_MODE GROUP UNITY_BUILD_BATCH_SIZE 0) # Adjust as needed - add_test(NAME ${target} COMMAND ${target}) endfunction () diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index 0651b8e0d8..afefa8457d 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -4,12 +4,7 @@ include(target_protobuf_sources) -# Protocol buffers cannot participate in a unity build, -# because all the generated sources -# define a bunch of `static const` variables with the same names, -# so we just build them as a separate library. add_library(xrpl.libpb) -set_target_properties(xrpl.libpb PROPERTIES UNITY_BUILD OFF) target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp IMPORT_DIRS include/xrpl/proto PROTOS include/xrpl/proto/xrpl.proto) @@ -160,12 +155,4 @@ if (xrpld) # antithesis_instrumentation.h, which is not exported as INTERFACE target_include_directories(xrpld PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk) endif () - - # any files that don't play well with unity should be added here - if (tests) - set_source_files_properties( - # these two seem to produce conflicts in beast teardown template methods - src/test/rpc/ValidatorRPC_test.cpp src/test/ledger/Invariants_test.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION - TRUE) - endif () endif () diff --git a/cmake/XrplSettings.cmake b/cmake/XrplSettings.cmake index 6d332be19d..0957e41918 100644 --- a/cmake/XrplSettings.cmake +++ b/cmake/XrplSettings.cmake @@ -30,14 +30,6 @@ if (tests) endif () endif () -option(unity "Creates a build using UNITY support in cmake." OFF) -if (unity) - if (NOT is_ci) - set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") - endif () - set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build") -endif () - if (is_clang AND is_linux) option(voidstar "Enable Antithesis instrumentation." OFF) endif () diff --git a/conanfile.py b/conanfile.py index a7a19405de..35a461cec7 100644 --- a/conanfile.py +++ b/conanfile.py @@ -23,7 +23,6 @@ class Xrpl(ConanFile): "shared": [True, False], "static": [True, False], "tests": [True, False], - "unity": [True, False], "xrpld": [True, False], } @@ -55,7 +54,6 @@ class Xrpl(ConanFile): "shared": False, "static": True, "tests": False, - "unity": False, "xrpld": False, "date/*:header_only": True, "ed25519/*:shared": False, @@ -168,7 +166,6 @@ class Xrpl(ConanFile): tc.variables["rocksdb"] = self.options.rocksdb tc.variables["BUILD_SHARED_LIBS"] = self.options.shared tc.variables["static"] = self.options.static - tc.variables["unity"] = self.options.unity tc.variables["xrpld"] = self.options.xrpld tc.generate() diff --git a/include/xrpl/basics/rocksdb.h b/include/xrpl/basics/rocksdb.h index b9b89677f9..59a69a9b44 100644 --- a/include/xrpl/basics/rocksdb.h +++ b/include/xrpl/basics/rocksdb.h @@ -1,5 +1,5 @@ -#ifndef XRPL_UNITY_ROCKSDB_H_INCLUDED -#define XRPL_UNITY_ROCKSDB_H_INCLUDED +#ifndef XRPL_BASICS_ROCKSDB_H_INCLUDED +#define XRPL_BASICS_ROCKSDB_H_INCLUDED #if XRPL_ROCKSDB_AVAILABLE // #include diff --git a/include/xrpl/core/ServiceRegistry.h b/include/xrpl/core/ServiceRegistry.h new file mode 100644 index 0000000000..a70d96292c --- /dev/null +++ b/include/xrpl/core/ServiceRegistry.h @@ -0,0 +1,202 @@ +#ifndef XRPL_CORE_SERVICEREGISTRY_H_INCLUDED +#define XRPL_CORE_SERVICEREGISTRY_H_INCLUDED + +#include +#include +#include +#include + +namespace xrpl { + +// Forward declarations +namespace NodeStore { +class Database; +} +namespace Resource { +class Manager; +} +namespace perf { +class PerfLog; +} + +class AcceptedLedger; +class AmendmentTable; +class Cluster; +class CollectorManager; +class DatabaseCon; +class Family; +class HashRouter; +class InboundLedgers; +class InboundTransactions; +class JobQueue; +class LedgerCleaner; +class LedgerMaster; +class LedgerReplayer; +class LoadFeeTrack; +class LoadManager; +class ManifestCache; +class NetworkOPs; +class OpenLedger; +class OrderBookDB; +class Overlay; +class PathRequests; +class PeerReservationTable; +class PendingSaves; +class RelationalDatabase; +class ServerHandler; +class SHAMapStore; +class TimeKeeper; +class TransactionMaster; +class TxQ; +class ValidatorList; +class ValidatorSite; + +template +class Validations; +class RCLValidationsAdaptor; +using RCLValidations = Validations; + +using NodeCache = TaggedCache; + +/** Service registry for dependency injection. + + This abstract interface provides access to various services and components + used throughout the application. It separates the service locator pattern + from the Application lifecycle management. + + Components that need access to services can hold a reference to + ServiceRegistry rather than Application when they only need service + access and not lifecycle management. + +*/ +class ServiceRegistry +{ +public: + ServiceRegistry() = default; + virtual ~ServiceRegistry() = default; + + // Core infrastructure services + virtual CollectorManager& + getCollectorManager() = 0; + + virtual Family& + getNodeFamily() = 0; + + virtual TimeKeeper& + timeKeeper() = 0; + + virtual JobQueue& + getJobQueue() = 0; + + virtual NodeCache& + getTempNodeCache() = 0; + + virtual CachedSLEs& + cachedSLEs() = 0; + + // Protocol and validation services + virtual AmendmentTable& + getAmendmentTable() = 0; + + virtual HashRouter& + getHashRouter() = 0; + + virtual LoadFeeTrack& + getFeeTrack() = 0; + + virtual LoadManager& + getLoadManager() = 0; + + virtual RCLValidations& + getValidations() = 0; + + virtual ValidatorList& + validators() = 0; + + virtual ValidatorSite& + validatorSites() = 0; + + virtual ManifestCache& + validatorManifests() = 0; + + virtual ManifestCache& + publisherManifests() = 0; + + // Network services + virtual Overlay& + overlay() = 0; + + virtual Cluster& + cluster() = 0; + + virtual PeerReservationTable& + peerReservations() = 0; + + virtual Resource::Manager& + getResourceManager() = 0; + + // Storage services + virtual NodeStore::Database& + getNodeStore() = 0; + + virtual SHAMapStore& + getSHAMapStore() = 0; + + virtual RelationalDatabase& + getRelationalDatabase() = 0; + + // Ledger services + virtual InboundLedgers& + getInboundLedgers() = 0; + + virtual InboundTransactions& + getInboundTransactions() = 0; + + virtual TaggedCache& + getAcceptedLedgerCache() = 0; + + virtual LedgerMaster& + getLedgerMaster() = 0; + + virtual LedgerCleaner& + getLedgerCleaner() = 0; + + virtual LedgerReplayer& + getLedgerReplayer() = 0; + + virtual PendingSaves& + pendingSaves() = 0; + + virtual OpenLedger& + openLedger() = 0; + + virtual OpenLedger const& + openLedger() const = 0; + + // Transaction and operation services + virtual NetworkOPs& + getOPs() = 0; + + virtual OrderBookDB& + getOrderBookDB() = 0; + + virtual TransactionMaster& + getMasterTransaction() = 0; + + virtual TxQ& + getTxQ() = 0; + + virtual PathRequests& + getPathRequests() = 0; + + // Server services + virtual ServerHandler& + getServerHandler() = 0; + + virtual perf::PerfLog& + getPerfLog() = 0; +}; + +} // namespace xrpl + +#endif diff --git a/src/libxrpl/net/RegisterSSLCerts.cpp b/src/libxrpl/net/RegisterSSLCerts.cpp index a15472969e..1b97a17e5c 100644 --- a/src/libxrpl/net/RegisterSSLCerts.cpp +++ b/src/libxrpl/net/RegisterSSLCerts.cpp @@ -85,7 +85,8 @@ registerSSLCerts(boost::asio::ssl::context& ctx, boost::system::error_code& ec, // There is a very unpleasant interaction between and // openssl x509 types (namely the former has macros that stomp // on the latter), these undefs allow this TU to be safely used in -// unity builds without messing up subsequent TUs. +// unity builds without messing up subsequent TUs. Although we +// no longer use unity builds, leaving the undefs here does no harm. #if BOOST_OS_WINDOWS #undef X509_NAME #undef X509_EXTENSIONS diff --git a/src/xrpld/app/main/Application.h b/src/xrpld/app/main/Application.h index 07edd5f558..bb8bac8bbb 100644 --- a/src/xrpld/app/main/Application.h +++ b/src/xrpld/app/main/Application.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -91,7 +92,7 @@ class Validations; class RCLValidationsAdaptor; using RCLValidations = Validations; -class Application : public beast::PropertyStream::Source +class Application : public ServiceRegistry, public beast::PropertyStream::Source { public: /* VFALCO NOTE @@ -146,92 +147,12 @@ public: virtual boost::asio::io_context& getIOContext() = 0; - virtual CollectorManager& - getCollectorManager() = 0; - virtual Family& - getNodeFamily() = 0; - virtual TimeKeeper& - timeKeeper() = 0; - virtual JobQueue& - getJobQueue() = 0; - virtual NodeCache& - getTempNodeCache() = 0; - virtual CachedSLEs& - cachedSLEs() = 0; - virtual AmendmentTable& - getAmendmentTable() = 0; - virtual HashRouter& - getHashRouter() = 0; - virtual LoadFeeTrack& - getFeeTrack() = 0; - virtual LoadManager& - getLoadManager() = 0; - virtual Overlay& - overlay() = 0; - virtual TxQ& - getTxQ() = 0; - virtual ValidatorList& - validators() = 0; - virtual ValidatorSite& - validatorSites() = 0; - virtual ManifestCache& - validatorManifests() = 0; - virtual ManifestCache& - publisherManifests() = 0; - virtual Cluster& - cluster() = 0; - virtual PeerReservationTable& - peerReservations() = 0; - virtual RCLValidations& - getValidations() = 0; - virtual NodeStore::Database& - getNodeStore() = 0; - virtual InboundLedgers& - getInboundLedgers() = 0; - virtual InboundTransactions& - getInboundTransactions() = 0; - - virtual TaggedCache& - getAcceptedLedgerCache() = 0; - - virtual LedgerMaster& - getLedgerMaster() = 0; - virtual LedgerCleaner& - getLedgerCleaner() = 0; - virtual LedgerReplayer& - getLedgerReplayer() = 0; - virtual NetworkOPs& - getOPs() = 0; - virtual OrderBookDB& - getOrderBookDB() = 0; - virtual ServerHandler& - getServerHandler() = 0; - virtual TransactionMaster& - getMasterTransaction() = 0; - virtual perf::PerfLog& - getPerfLog() = 0; - virtual std::pair const& nodeIdentity() = 0; virtual std::optional getValidationPublicKey() const = 0; - virtual Resource::Manager& - getResourceManager() = 0; - virtual PathRequests& - getPathRequests() = 0; - virtual SHAMapStore& - getSHAMapStore() = 0; - virtual PendingSaves& - pendingSaves() = 0; - virtual OpenLedger& - openLedger() = 0; - virtual OpenLedger const& - openLedger() const = 0; - virtual RelationalDatabase& - getRelationalDatabase() = 0; - virtual std::chrono::milliseconds getIOLatency() = 0;