mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 11:15:56 +00:00
Use NuDB context with backends
This commit is contained in:
committed by
Nik Bougalis
parent
89b3bf0796
commit
a988b3224f
@@ -11,8 +11,8 @@ env:
|
||||
# to boost's .tar.gz.
|
||||
- LCOV_ROOT=$HOME/lcov
|
||||
- GDB_ROOT=$HOME/gdb
|
||||
- BOOST_ROOT=$HOME/boost_1_67_0
|
||||
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.gz'
|
||||
- BOOST_ROOT=$HOME/boost_1_70_0
|
||||
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.70.0/boost_1_70_0.tar.gz'
|
||||
|
||||
addons:
|
||||
apt:
|
||||
|
||||
@@ -17,7 +17,7 @@ need these software components
|
||||
| [Visual Studio 2017](README.md#install-visual-studio-2017)| 15.5.4 |
|
||||
| [Git for Windows](README.md#install-git-for-windows)| 2.16.1 |
|
||||
| [OpenSSL Library](README.md#install-openssl) | 1.0.2n |
|
||||
| [Boost library](README.md#build-boost) | 1.67.0 |
|
||||
| [Boost library](README.md#build-boost) | 1.70.0 |
|
||||
| [CMake for Windows](README.md#optional-install-cmake-for-windows)* | 3.12 |
|
||||
|
||||
\* Only needed if not using the integrated CMake in VS 2017 and prefer generating dedicated project/solution files.
|
||||
@@ -78,13 +78,13 @@ to get the correct 32-/64-bit variant.
|
||||
|
||||
### Build Boost
|
||||
|
||||
Boost 1.67 or later is required.
|
||||
Boost 1.70 or later is required.
|
||||
|
||||
After [downloading boost](http://www.boost.org/users/download/) and unpacking it
|
||||
to `c:\lib`. As of this writing, the most recent version of boost is 1.68.0,
|
||||
which will unpack into a directory named `boost_1_68_0`. We recommended either
|
||||
to `c:\lib`. As of this writing, the most recent version of boost is 1.70.0,
|
||||
which will unpack into a directory named `boost_1_70_0`. We recommended either
|
||||
renaming this directory to `boost`, or creating a junction link `mklink /J boost
|
||||
boost_1_68_0`, so that you can more easily switch between versions.
|
||||
boost_1_70_0`, so that you can more easily switch between versions.
|
||||
|
||||
Next, open **Developer Command Prompt** and type the following commands
|
||||
|
||||
@@ -214,7 +214,7 @@ execute the following commands within your `rippled` cloned repository:
|
||||
```
|
||||
mkdir build\cmake
|
||||
cd build\cmake
|
||||
cmake ..\.. -G"Visual Studio 15 2017 Win64" -DBOOST_ROOT="C:\lib\boost_1_68_0" -DOPENSSL_ROOT="C:\lib\OpenSSL-Win64"
|
||||
cmake ..\.. -G"Visual Studio 15 2017 Win64" -DBOOST_ROOT="C:\lib\boost_1_70_0" -DOPENSSL_ROOT="C:\lib\OpenSSL-Win64"
|
||||
```
|
||||
Now launch Visual Studio 2017 and select **File | Open | Project/Solution**.
|
||||
Navigate to the `build\cmake` folder created above and select the `rippled.sln`
|
||||
|
||||
@@ -25,14 +25,14 @@ protobuf will give errors.
|
||||
|
||||
### Build Boost
|
||||
|
||||
Boost 1.67 or later is required. We recommend downloading and compiling boost
|
||||
Boost 1.70 or later is required. We recommend downloading and compiling boost
|
||||
with the following process: After changing to the directory where
|
||||
you wish to download and compile boost, run
|
||||
|
||||
```
|
||||
$ wget https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz
|
||||
$ tar -xzf boost_1_68_0.tar.gz
|
||||
$ cd boost_1_68_0
|
||||
$ wget https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz
|
||||
$ tar -xzf boost_1_70_0.tar.gz
|
||||
$ cd boost_1_70_0
|
||||
$ ./bootstrap.sh
|
||||
$ ./b2 headers
|
||||
$ ./b2 -j<Num Parallel>
|
||||
@@ -81,14 +81,14 @@ git checkout develop
|
||||
If you didn't persistently set the `BOOST_ROOT` environment variable to the
|
||||
directory in which you compiled boost, then you should set it temporarily.
|
||||
|
||||
For example, you built Boost in your home directory `~/boost_1_68_0`, you
|
||||
For example, you built Boost in your home directory `~/boost_1_70_0`, you
|
||||
would do for any shell in which you want to build:
|
||||
|
||||
```
|
||||
export BOOST_ROOT=~/boost_1_68_0
|
||||
export BOOST_ROOT=~/boost_1_70_0
|
||||
```
|
||||
|
||||
Alternatively, you can add `DBOOST_ROOT=~/boost_1_68_0` to the command line when
|
||||
Alternatively, you can add `DBOOST_ROOT=~/boost_1_70_0` to the command line when
|
||||
invoking `cmake`.
|
||||
|
||||
### Generate and Build
|
||||
|
||||
@@ -60,11 +60,11 @@ brew install git cmake pkg-config protobuf openssl ninja
|
||||
|
||||
### Build Boost
|
||||
|
||||
Boost 1.67 or later is required.
|
||||
Boost 1.70 or later is required.
|
||||
|
||||
We want to compile boost with clang/libc++
|
||||
|
||||
Download [a release](https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.bz2)
|
||||
Download [a release](https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.bz2)
|
||||
|
||||
Extract it to a folder, making note of where, open a terminal, then:
|
||||
|
||||
@@ -120,11 +120,11 @@ If you didn't persistently set the `BOOST_ROOT` environment variable to the
|
||||
root of the extracted directory above, then you should set it temporarily.
|
||||
|
||||
For example, assuming your username were `Abigail` and you extracted Boost
|
||||
1.68.0 in `/Users/Abigail/Downloads/boost_1_68_0`, you would do for any
|
||||
1.70.0 in `/Users/Abigail/Downloads/boost_1_70_0`, you would do for any
|
||||
shell in which you want to build:
|
||||
|
||||
```
|
||||
export BOOST_ROOT=/Users/Abigail/Downloads/boost_1_68_0
|
||||
export BOOST_ROOT=/Users/Abigail/Downloads/boost_1_70_0
|
||||
```
|
||||
|
||||
### Generate and Build
|
||||
|
||||
@@ -714,7 +714,7 @@ if (static AND NOT APPLE)
|
||||
else ()
|
||||
set (Boost_USE_STATIC_RUNTIME OFF)
|
||||
endif ()
|
||||
find_package (Boost 1.67 REQUIRED
|
||||
find_package (Boost 1.70 REQUIRED
|
||||
COMPONENTS
|
||||
chrono
|
||||
context
|
||||
@@ -749,15 +749,6 @@ target_link_libraries (ripple_boost
|
||||
Boost::system
|
||||
Boost::thread)
|
||||
|
||||
# workaround for xcode 10.2 and boost < 1.69
|
||||
# once we require Boost 1.69 or higher, this can be removed
|
||||
# see: https://github.com/boostorg/asio/commit/43874d5
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND
|
||||
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.1.10010043 AND
|
||||
Boost_VERSION LESS 106900)
|
||||
target_compile_definitions (opts INTERFACE BOOST_ASIO_HAS_STD_STRING_VIEW)
|
||||
endif ()
|
||||
|
||||
#[===================================================================[
|
||||
NIH dep: openssl
|
||||
#]===================================================================]
|
||||
@@ -1419,8 +1410,8 @@ if (is_root_project) # NuDB not needed in the case of xrpl_core inclusion build
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.11)
|
||||
FetchContent_Declare(
|
||||
nudb_src
|
||||
GIT_REPOSITORY https://github.com/vinniefalco/NuDB.git
|
||||
GIT_TAG 1.0.0
|
||||
GIT_REPOSITORY https://github.com/CPPAlliance/NuDB.git
|
||||
GIT_TAG 2.0.1
|
||||
)
|
||||
FetchContent_GetProperties(nudb_src)
|
||||
if(NOT nudb_src_POPULATED)
|
||||
@@ -1430,8 +1421,8 @@ if (is_root_project) # NuDB not needed in the case of xrpl_core inclusion build
|
||||
else ()
|
||||
ExternalProject_Add (nudb_src
|
||||
PREFIX ${nih_cache_path}
|
||||
GIT_REPOSITORY https://github.com/vinniefalco/NuDB.git
|
||||
GIT_TAG 1.0.0
|
||||
GIT_REPOSITORY https://github.com/CPPAlliance/NuDB.git
|
||||
GIT_TAG 2.0.1
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
|
||||
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@@ -202,7 +202,7 @@ try {
|
||||
"NIH_CACHE_ROOT=${cdir}/.nih_c"])
|
||||
if (compiler == 'msvc') {
|
||||
env_vars.addAll([
|
||||
'BOOST_ROOT=c:\\lib\\boost_1_67',
|
||||
'BOOST_ROOT=c:\\lib\\boost_1_70',
|
||||
'PROJECT_NAME=rippled',
|
||||
'MSBUILDDISABLENODEREUSE=1', // this ENV setting is probably redundant since we also pass /nr:false to msbuild
|
||||
'OPENSSL_ROOT=c:\\OpenSSL-Win64'])
|
||||
@@ -219,7 +219,7 @@ try {
|
||||
'LCOV_ROOT=""',
|
||||
'PATH+CMAKE_BIN=/opt/local/cmake',
|
||||
'GDB_ROOT=/opt/local/gdb',
|
||||
'BOOST_ROOT=/opt/local/boost_1_67_0',
|
||||
'BOOST_ROOT=/opt/local/boost_1_70_0',
|
||||
"USE_CCACHE=${ucc}"])
|
||||
}
|
||||
|
||||
|
||||
@@ -868,18 +868,10 @@
|
||||
# ...
|
||||
#
|
||||
# Example:
|
||||
# type=nudb
|
||||
# path=db/shards/nudb
|
||||
#
|
||||
# The "type" field must be present and controls the choice of backend:
|
||||
#
|
||||
# type = NuDB
|
||||
# NuDB is recommended for shards.
|
||||
#
|
||||
# type = RocksDB
|
||||
#
|
||||
# Required keys:
|
||||
# path Location to store the database (all types)
|
||||
# path Location to store the database
|
||||
#
|
||||
# max_size_gb Maximum disk space the database will utilize (in gigabytes)
|
||||
#
|
||||
@@ -1193,7 +1185,6 @@ advisory_delete=0
|
||||
# NuDB requires SSD storage. Helpful information can be found here
|
||||
# https://ripple.com/build/history-sharding
|
||||
#[shard_db]
|
||||
#type=NuDB
|
||||
#path=/var/lib/rippled/db/shards/nudb
|
||||
#max_size_gb=500
|
||||
|
||||
|
||||
@@ -109,11 +109,18 @@ public:
|
||||
/** Remove contents on disk upon destruction. */
|
||||
virtual void setDeletePath() = 0;
|
||||
|
||||
/** Perform consistency checks on database .*/
|
||||
/** Perform consistency checks on database. */
|
||||
virtual void verify() = 0;
|
||||
|
||||
/** Returns the number of file handles the backend expects to need */
|
||||
/** Returns the number of file handles the backend expects to need. */
|
||||
virtual int fdlimit() const = 0;
|
||||
|
||||
/** Returns true if the backend uses permanent storage. */
|
||||
bool
|
||||
backed() const
|
||||
{
|
||||
return fdlimit();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/nodestore/Backend.h>
|
||||
#include <ripple/nodestore/Scheduler.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <nudb/store.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -42,14 +43,37 @@ public:
|
||||
/** Create an instance of this factory's backend.
|
||||
|
||||
@param keyBytes The fixed number of bytes per key.
|
||||
@param keyValues A set of key/value configuration pairs.
|
||||
@param parameters A set of key/value configuration pairs.
|
||||
@param scheduler The scheduler to use for running tasks.
|
||||
@return A pointer to the Backend object.
|
||||
*/
|
||||
virtual
|
||||
std::unique_ptr <Backend>
|
||||
createInstance (size_t keyBytes, Section const& parameters,
|
||||
Scheduler& scheduler, beast::Journal journal) = 0;
|
||||
createInstance (
|
||||
size_t keyBytes,
|
||||
Section const& parameters,
|
||||
Scheduler& scheduler,
|
||||
beast::Journal journal) = 0;
|
||||
|
||||
/** Create an instance of this factory's backend.
|
||||
|
||||
@param keyBytes The fixed number of bytes per key.
|
||||
@param parameters A set of key/value configuration pairs.
|
||||
@param scheduler The scheduler to use for running tasks.
|
||||
@param context The context used by database.
|
||||
@return A pointer to the Backend object.
|
||||
*/
|
||||
virtual
|
||||
std::unique_ptr <Backend>
|
||||
createInstance (
|
||||
size_t keyBytes,
|
||||
Section const& parameters,
|
||||
Scheduler& scheduler,
|
||||
nudb::context& context,
|
||||
beast::Journal journal)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -40,9 +40,6 @@ class NuDBBackend
|
||||
: public Backend
|
||||
{
|
||||
public:
|
||||
// This needs to be tuned for the
|
||||
// distribution of data sizes.
|
||||
static constexpr std::size_t arena_alloc_size = megabytes(16);
|
||||
static constexpr std::size_t currentType = 1;
|
||||
|
||||
beast::Journal j_;
|
||||
@@ -52,8 +49,11 @@ public:
|
||||
std::atomic <bool> deletePath_;
|
||||
Scheduler& scheduler_;
|
||||
|
||||
NuDBBackend (int keyBytes, Section const& keyValues,
|
||||
Scheduler& scheduler, beast::Journal journal)
|
||||
NuDBBackend (
|
||||
size_t keyBytes,
|
||||
Section const& keyValues,
|
||||
Scheduler& scheduler,
|
||||
beast::Journal journal)
|
||||
: j_(journal)
|
||||
, keyBytes_ (keyBytes)
|
||||
, name_ (get<std::string>(keyValues, "path"))
|
||||
@@ -65,6 +65,24 @@ public:
|
||||
"nodestore: Missing path in NuDB backend");
|
||||
}
|
||||
|
||||
NuDBBackend (
|
||||
size_t keyBytes,
|
||||
Section const& keyValues,
|
||||
Scheduler& scheduler,
|
||||
nudb::context& context,
|
||||
beast::Journal journal)
|
||||
: j_(journal)
|
||||
, keyBytes_ (keyBytes)
|
||||
, name_ (get<std::string>(keyValues, "path"))
|
||||
, db_ (context)
|
||||
, deletePath_(false)
|
||||
, scheduler_ (scheduler)
|
||||
{
|
||||
if (name_.empty())
|
||||
Throw<std::runtime_error> (
|
||||
"nodestore: Missing path in NuDB backend");
|
||||
}
|
||||
|
||||
~NuDBBackend () override
|
||||
{
|
||||
close();
|
||||
@@ -278,7 +296,6 @@ public:
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
|
||||
/** Returns the number of file handles the backend expects to need */
|
||||
int
|
||||
fdlimit() const override
|
||||
{
|
||||
@@ -317,6 +334,18 @@ public:
|
||||
return std::make_unique <NuDBBackend> (
|
||||
keyBytes, keyValues, scheduler, journal);
|
||||
}
|
||||
|
||||
std::unique_ptr <Backend>
|
||||
createInstance (
|
||||
size_t keyBytes,
|
||||
Section const& keyValues,
|
||||
Scheduler& scheduler,
|
||||
nudb::context& context,
|
||||
beast::Journal journal) override
|
||||
{
|
||||
return std::make_unique <NuDBBackend> (
|
||||
keyBytes, keyValues, scheduler, context, journal);
|
||||
}
|
||||
};
|
||||
|
||||
static NuDBFactory nuDBFactory;
|
||||
|
||||
@@ -34,64 +34,94 @@ namespace NodeStore {
|
||||
|
||||
constexpr std::uint32_t DatabaseShard::ledgersPerShardDefault;
|
||||
|
||||
DatabaseShardImp::DatabaseShardImp(Application& app,
|
||||
std::string const& name, Stoppable& parent, Scheduler& scheduler,
|
||||
int readThreads, Section const& config, beast::Journal j)
|
||||
DatabaseShardImp::DatabaseShardImp(
|
||||
Application& app,
|
||||
std::string const& name,
|
||||
Stoppable& parent,
|
||||
Scheduler& scheduler,
|
||||
int readThreads,
|
||||
Section const& config,
|
||||
beast::Journal j)
|
||||
: DatabaseShard(name, parent, scheduler, readThreads, config, j)
|
||||
, app_(app)
|
||||
, ctx_(std::make_unique<nudb::context>())
|
||||
, config_(config)
|
||||
, dir_(get<std::string>(config, "path"))
|
||||
, backendName_(Manager::instance().find(
|
||||
get<std::string>(config_, "type"))->getName())
|
||||
get<std::string>(config, "type", "nudb"))->getName())
|
||||
, maxDiskSpace_(get<std::uint64_t>(config, "max_size_gb") << 30)
|
||||
, ledgersPerShard_(get<std::uint32_t>(
|
||||
config, "ledgers_per_shard", ledgersPerShardDefault))
|
||||
, earliestShardIndex_(seqToShardIndex(earliestSeq()))
|
||||
, avgShardSz_(ledgersPerShard_ * (192 * 1024))
|
||||
{
|
||||
if (ledgersPerShard_ == 0 || ledgersPerShard_ % 256 != 0)
|
||||
Throw<std::runtime_error>(
|
||||
"ledgers_per_shard must be a multiple of 256");
|
||||
ctx_->start();
|
||||
}
|
||||
|
||||
DatabaseShardImp::~DatabaseShardImp()
|
||||
{
|
||||
// Stop threads before data members are destroyed
|
||||
stopThreads();
|
||||
|
||||
// Close backend databases before destroying the context
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
complete_.clear();
|
||||
if (incomplete_)
|
||||
incomplete_.reset();
|
||||
preShards_.clear();
|
||||
ctx_.reset();
|
||||
}
|
||||
|
||||
bool
|
||||
DatabaseShardImp::init()
|
||||
{
|
||||
using namespace boost::filesystem;
|
||||
using namespace boost::beast::detail;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
if (init_)
|
||||
{
|
||||
assert(false);
|
||||
JLOG(j_.error()) <<
|
||||
"Already initialized";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find backend type and file handle requirement
|
||||
try
|
||||
{
|
||||
fdLimit_ = Manager::instance().make_Backend(
|
||||
config_, scheduler_, j_)->fdlimit();
|
||||
}
|
||||
catch (std::exception const&)
|
||||
if (ledgersPerShard_ == 0 || ledgersPerShard_ % 256 != 0)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"Invalid or missing shard store "
|
||||
"type specified in [shard_db]";
|
||||
"ledgers_per_shard must be a multiple of 256";
|
||||
return false;
|
||||
}
|
||||
|
||||
backed_ = static_cast<bool>(fdLimit_);
|
||||
if (!backed_)
|
||||
// NuDB is the default and only supported permanent storage backend
|
||||
// "Memory" and "none" types are supported for tests
|
||||
if (!iequals(backendName_, "NuDB") &&
|
||||
!iequals(backendName_, "Memory") &&
|
||||
!iequals(backendName_, "none"))
|
||||
{
|
||||
init_ = true;
|
||||
return true;
|
||||
JLOG(j_.error()) <<
|
||||
"Unsupported shard store type: " << backendName_;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// Find backend file handle requirement
|
||||
auto factory {Manager::instance().find(backendName_)};
|
||||
if (!factory)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"Failed to create shard store type " << backendName_;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto backend {factory->createInstance(NodeObject::keyBytes,
|
||||
config_, scheduler_, *ctx_, j_)};
|
||||
backed_ = backend->backed();
|
||||
if (!backed_)
|
||||
{
|
||||
init_ = true;
|
||||
return true;
|
||||
}
|
||||
fdLimit_ = backend->fdlimit();
|
||||
}
|
||||
|
||||
try
|
||||
@@ -136,7 +166,7 @@ DatabaseShardImp::init()
|
||||
|
||||
auto shard {std::make_unique<Shard>(
|
||||
*this, shardIndex, cacheSz_, cacheAge_, j_)};
|
||||
if (!shard->open(config_, scheduler_))
|
||||
if (!shard->open(config_, scheduler_, *ctx_))
|
||||
return false;
|
||||
|
||||
usedDiskSpace_ += shard->fileSize();
|
||||
@@ -220,7 +250,7 @@ DatabaseShardImp::prepareLedger(std::uint32_t validLedgerSeq)
|
||||
1, static_cast<int>(complete_.size() + 1)))};
|
||||
incomplete_ = std::make_unique<Shard>(
|
||||
*this, *shardIndex, sz, cacheAge_, j_);
|
||||
if (!incomplete_->open(config_, scheduler_))
|
||||
if (!incomplete_->open(config_, scheduler_, *ctx_))
|
||||
{
|
||||
incomplete_.reset();
|
||||
return boost::none;
|
||||
@@ -380,7 +410,7 @@ DatabaseShardImp::importShard(std::uint32_t shardIndex,
|
||||
if(it == preShards_.end())
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"Invalid shard index " << std::to_string(shardIndex);
|
||||
"Invalid shard index " << shardIndex;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -394,16 +424,20 @@ DatabaseShardImp::importShard(std::uint32_t shardIndex,
|
||||
*this, shardIndex, cacheSz_, cacheAge_, j_)};
|
||||
auto fail = [&](std::string msg)
|
||||
{
|
||||
JLOG(j_.error()) << msg;
|
||||
shard.release();
|
||||
if (!msg.empty())
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"Import shard " << shardIndex << ": " << msg;
|
||||
}
|
||||
shard.reset();
|
||||
move(dstDir, srcDir);
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!shard->open(config_, scheduler_))
|
||||
return fail("Failure");
|
||||
if (!shard->open(config_, scheduler_, *ctx_))
|
||||
return fail({});
|
||||
if (!shard->complete())
|
||||
return fail("Incomplete shard");
|
||||
return fail("incomplete shard");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -412,7 +446,7 @@ DatabaseShardImp::importShard(std::uint32_t shardIndex,
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
return fail(std::string("exception: ") + e.what());
|
||||
return fail(e.what());
|
||||
}
|
||||
|
||||
// Validate shard ledgers
|
||||
@@ -716,7 +750,7 @@ DatabaseShardImp::import(Database& source)
|
||||
auto const shardDir {dir_ / std::to_string(shardIndex)};
|
||||
auto shard = std::make_unique<Shard>(
|
||||
*this, shardIndex, shardCacheSz, cacheAge_, j_);
|
||||
if (!shard->open(config_, scheduler_))
|
||||
if (!shard->open(config_, scheduler_, *ctx_))
|
||||
{
|
||||
shard.reset();
|
||||
continue;
|
||||
@@ -1087,6 +1121,7 @@ DatabaseShardImp::updateStats(std::lock_guard<std::mutex>&)
|
||||
}
|
||||
else if(incomplete_)
|
||||
filesPerShard = incomplete_->fdlimit();
|
||||
|
||||
if (!backed_)
|
||||
return;
|
||||
|
||||
|
||||
@@ -31,11 +31,18 @@ class DatabaseShardImp : public DatabaseShard
|
||||
public:
|
||||
DatabaseShardImp() = delete;
|
||||
DatabaseShardImp(DatabaseShardImp const&) = delete;
|
||||
DatabaseShardImp(DatabaseShardImp&&) = delete;
|
||||
DatabaseShardImp& operator=(DatabaseShardImp const&) = delete;
|
||||
DatabaseShardImp& operator=(DatabaseShardImp&&) = delete;
|
||||
|
||||
DatabaseShardImp(Application& app, std::string const& name,
|
||||
Stoppable& parent, Scheduler& scheduler, int readThreads,
|
||||
Section const& config, beast::Journal j);
|
||||
DatabaseShardImp(
|
||||
Application& app,
|
||||
std::string const& name,
|
||||
Stoppable& parent,
|
||||
Scheduler& scheduler,
|
||||
int readThreads,
|
||||
Section const& config,
|
||||
beast::Journal j);
|
||||
|
||||
~DatabaseShardImp() override;
|
||||
|
||||
@@ -161,6 +168,9 @@ private:
|
||||
mutable std::mutex m_;
|
||||
bool init_ {false};
|
||||
|
||||
// The context shared with all shard backend databases
|
||||
std::unique_ptr<nudb::context> ctx_;
|
||||
|
||||
// Complete shards
|
||||
std::map<std::uint32_t, std::unique_ptr<Shard>> complete_;
|
||||
|
||||
|
||||
@@ -49,79 +49,66 @@ Shard::Shard(DatabaseShard const& db, std::uint32_t index,
|
||||
}
|
||||
|
||||
bool
|
||||
Shard::open(Section config, Scheduler& scheduler)
|
||||
Shard::open(Section config, Scheduler& scheduler, nudb::context& ctx)
|
||||
{
|
||||
assert(!backend_);
|
||||
using namespace boost::filesystem;
|
||||
using namespace boost::beast::detail;
|
||||
|
||||
bool dirPreexist;
|
||||
bool dirEmpty;
|
||||
try
|
||||
{
|
||||
if (!exists(dir_))
|
||||
{
|
||||
dirPreexist = false;
|
||||
dirEmpty = true;
|
||||
}
|
||||
else if (is_directory(dir_))
|
||||
{
|
||||
dirPreexist = true;
|
||||
dirEmpty = is_empty(dir_);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"path exists as file: " << dir_.string();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
std::string const type (get<std::string>(config, "type", "nudb"));
|
||||
auto factory {Manager::instance().find(type)};
|
||||
if (!factory)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"shard " + std::to_string(index_) + " exception: " + e.what();
|
||||
"shard " << index_ <<
|
||||
": failed to create shard store type " << type;
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto const preexist {exists(dir_, ec)};
|
||||
if (ec)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"shard " << index_ << ": " << ec.message();
|
||||
return false;
|
||||
}
|
||||
|
||||
config.set("path", dir_.string());
|
||||
backend_ = factory->createInstance(
|
||||
NodeObject::keyBytes, config, scheduler, ctx, j_);
|
||||
|
||||
auto fail = [&](std::string msg)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"shard " << std::to_string(index_) << " error: " << msg;
|
||||
|
||||
if (!dirPreexist)
|
||||
removeAll(dir_, j_);
|
||||
else if (dirEmpty)
|
||||
if (!msg.empty())
|
||||
{
|
||||
for (auto const& p : recursive_directory_iterator(dir_))
|
||||
removeAll(p.path(), j_);
|
||||
JLOG(j_.error()) <<
|
||||
"shard " << index_ << ": " << msg;
|
||||
}
|
||||
if (!preexist)
|
||||
removeAll(dir_, j_);
|
||||
return false;
|
||||
};
|
||||
|
||||
config.set("path", dir_.string());
|
||||
try
|
||||
{
|
||||
backend_ = Manager::instance().make_Backend(
|
||||
config, scheduler, j_);
|
||||
backend_->open(!dirPreexist || dirEmpty);
|
||||
backend_->open(!preexist);
|
||||
|
||||
if (backend_->fdlimit() == 0)
|
||||
if (!backend_->backed())
|
||||
return true;
|
||||
|
||||
if (!dirPreexist || dirEmpty)
|
||||
if (!preexist)
|
||||
{
|
||||
// New shard, create a control file
|
||||
if (!saveControl())
|
||||
return fail("failure");
|
||||
return fail({});
|
||||
}
|
||||
else if (is_regular_file(control_))
|
||||
{
|
||||
// Incomplete shard, inspect control file
|
||||
std::ifstream ifs(control_.string());
|
||||
if (!ifs.is_open())
|
||||
{
|
||||
return fail("shard " + std::to_string(index_) +
|
||||
", unable to open control file");
|
||||
}
|
||||
return fail("failed to open control file");
|
||||
|
||||
boost::archive::text_iarchive ar(ifs);
|
||||
ar & storedSeqs_;
|
||||
@@ -130,15 +117,14 @@ Shard::open(Section config, Scheduler& scheduler)
|
||||
if (boost::icl::first(storedSeqs_) < firstSeq_ ||
|
||||
boost::icl::last(storedSeqs_) > lastSeq_)
|
||||
{
|
||||
return fail("shard " + std::to_string(index_) +
|
||||
": Invalid control file");
|
||||
return fail("invalid control file");
|
||||
}
|
||||
|
||||
if (boost::icl::length(storedSeqs_) >= maxLedgers_)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"shard " << index_ <<
|
||||
" found control file for complete shard";
|
||||
": found control file for complete shard";
|
||||
storedSeqs_.clear();
|
||||
complete_ = true;
|
||||
remove_all(control_);
|
||||
@@ -155,9 +141,7 @@ Shard::open(Section config, Scheduler& scheduler)
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.error()) <<
|
||||
"shard " << std::to_string(index_) << " error: " << e.what();
|
||||
return false;
|
||||
return fail(e.what());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -177,7 +161,7 @@ Shard::setStored(std::shared_ptr<Ledger const> const& l)
|
||||
}
|
||||
if (boost::icl::length(storedSeqs_) >= maxLedgers_ - 1)
|
||||
{
|
||||
if (backend_->fdlimit() != 0)
|
||||
if (backend_->backed())
|
||||
{
|
||||
if (!removeAll(control_, j_))
|
||||
return false;
|
||||
@@ -212,7 +196,7 @@ Shard::setStored(std::shared_ptr<Ledger const> const& l)
|
||||
{
|
||||
storedSeqs_.insert(l->info().seq);
|
||||
lastStored_ = l;
|
||||
if (backend_->fdlimit() != 0 && !saveControl())
|
||||
if (backend_->backed() && !saveControl())
|
||||
return false;
|
||||
|
||||
JLOG(j_.debug()) <<
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <ripple/nodestore/NodeObject.h>
|
||||
#include <ripple/nodestore/Scheduler.h>
|
||||
|
||||
#include <nudb/nudb.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
@@ -69,7 +70,7 @@ public:
|
||||
std::chrono::seconds cacheAge, beast::Journal& j);
|
||||
|
||||
bool
|
||||
open(Section config, Scheduler& scheduler);
|
||||
open(Section config, Scheduler& scheduler, nudb::context& ctx);
|
||||
|
||||
bool
|
||||
setStored(std::shared_ptr<Ledger const> const& l);
|
||||
|
||||
Reference in New Issue
Block a user