mirror of
https://github.com/XRPLF/rippled.git
synced 2026-03-26 06:32:28 +00:00
235 lines
6.3 KiB
C++
235 lines
6.3 KiB
C++
#pragma once
|
|
|
|
#include <xrpl/core/PerfLog.h>
|
|
#include <xrpl/core/StartUpType.h>
|
|
#include <xrpl/rdb/DBInit.h>
|
|
#include <xrpl/rdb/SociDB.h>
|
|
|
|
#include <boost/filesystem/path.hpp>
|
|
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
|
|
namespace soci {
|
|
class session;
|
|
}
|
|
|
|
namespace xrpl {
|
|
|
|
class LockedSociSession
|
|
{
|
|
public:
|
|
using mutex = std::recursive_mutex;
|
|
|
|
private:
|
|
std::shared_ptr<soci::session> session_;
|
|
std::unique_lock<mutex> lock_;
|
|
|
|
public:
|
|
LockedSociSession(std::shared_ptr<soci::session> it, mutex& m)
|
|
: session_(std::move(it)), lock_(m)
|
|
{
|
|
}
|
|
LockedSociSession(LockedSociSession&& rhs) noexcept
|
|
: session_(std::move(rhs.session_)), lock_(std::move(rhs.lock_))
|
|
{
|
|
}
|
|
LockedSociSession() = delete;
|
|
LockedSociSession(LockedSociSession const& rhs) = delete;
|
|
LockedSociSession&
|
|
operator=(LockedSociSession const& rhs) = delete;
|
|
|
|
soci::session*
|
|
get()
|
|
{
|
|
return session_.get();
|
|
}
|
|
soci::session&
|
|
operator*()
|
|
{
|
|
return *session_;
|
|
}
|
|
soci::session*
|
|
operator->()
|
|
{
|
|
return session_.get();
|
|
}
|
|
explicit
|
|
operator bool() const
|
|
{
|
|
return bool(session_);
|
|
}
|
|
};
|
|
|
|
class DatabaseCon
|
|
{
|
|
public:
|
|
struct Setup
|
|
{
|
|
explicit Setup() = default;
|
|
|
|
StartUpType startUp = StartUpType::NORMAL;
|
|
bool standAlone = false;
|
|
boost::filesystem::path dataDir;
|
|
// Indicates whether or not to return the `globalPragma`
|
|
// from commonPragma()
|
|
bool useGlobalPragma = false;
|
|
|
|
std::vector<std::string> const*
|
|
commonPragma() const
|
|
{
|
|
XRPL_ASSERT(
|
|
!useGlobalPragma || globalPragma,
|
|
"xrpl::DatabaseCon::Setup::commonPragma : consistent global "
|
|
"pragma");
|
|
return useGlobalPragma && globalPragma ? globalPragma.get() : nullptr;
|
|
}
|
|
|
|
static std::unique_ptr<std::vector<std::string> const> globalPragma;
|
|
std::array<std::string, 4> txPragma;
|
|
std::array<std::string, 1> lgrPragma;
|
|
};
|
|
|
|
struct CheckpointerSetup
|
|
{
|
|
JobQueue* jobQueue;
|
|
Logs* logs;
|
|
};
|
|
|
|
template <std::size_t N, std::size_t M>
|
|
DatabaseCon(
|
|
Setup const& setup,
|
|
std::string const& dbName,
|
|
std::array<std::string, N> const& pragma,
|
|
std::array<char const*, M> const& initSQL,
|
|
beast::Journal journal)
|
|
// Use temporary files or regular DB files?
|
|
: DatabaseCon(
|
|
setup.standAlone && setup.startUp != StartUpType::LOAD &&
|
|
setup.startUp != StartUpType::LOAD_FILE &&
|
|
setup.startUp != StartUpType::REPLAY
|
|
? ""
|
|
: (setup.dataDir / dbName),
|
|
setup.commonPragma(),
|
|
pragma,
|
|
initSQL,
|
|
journal)
|
|
{
|
|
}
|
|
|
|
// Use this constructor to setup checkpointing
|
|
template <std::size_t N, std::size_t M>
|
|
DatabaseCon(
|
|
Setup const& setup,
|
|
std::string const& dbName,
|
|
std::array<std::string, N> const& pragma,
|
|
std::array<char const*, M> const& initSQL,
|
|
CheckpointerSetup const& checkpointerSetup,
|
|
beast::Journal journal)
|
|
: DatabaseCon(setup, dbName, pragma, initSQL, journal)
|
|
{
|
|
setupCheckpointing(checkpointerSetup.jobQueue, *checkpointerSetup.logs);
|
|
}
|
|
|
|
template <std::size_t N, std::size_t M>
|
|
DatabaseCon(
|
|
boost::filesystem::path const& dataDir,
|
|
std::string const& dbName,
|
|
std::array<std::string, N> const& pragma,
|
|
std::array<char const*, M> const& initSQL,
|
|
beast::Journal journal)
|
|
: DatabaseCon(dataDir / dbName, nullptr, pragma, initSQL, journal)
|
|
{
|
|
}
|
|
|
|
// Use this constructor to setup checkpointing
|
|
template <std::size_t N, std::size_t M>
|
|
DatabaseCon(
|
|
boost::filesystem::path const& dataDir,
|
|
std::string const& dbName,
|
|
std::array<std::string, N> const& pragma,
|
|
std::array<char const*, M> const& initSQL,
|
|
CheckpointerSetup const& checkpointerSetup,
|
|
beast::Journal journal)
|
|
: DatabaseCon(dataDir, dbName, pragma, initSQL, journal)
|
|
{
|
|
setupCheckpointing(checkpointerSetup.jobQueue, *checkpointerSetup.logs);
|
|
}
|
|
|
|
~DatabaseCon();
|
|
|
|
soci::session&
|
|
getSession()
|
|
{
|
|
return *session_;
|
|
}
|
|
|
|
LockedSociSession
|
|
checkoutDb()
|
|
{
|
|
using namespace std::chrono_literals;
|
|
LockedSociSession session = perf::measureDurationAndLog(
|
|
[&]() { return LockedSociSession(session_, lock_); }, "checkoutDb", 10ms, j_);
|
|
|
|
return session;
|
|
}
|
|
|
|
private:
|
|
void
|
|
setupCheckpointing(JobQueue*, Logs&);
|
|
|
|
template <std::size_t N, std::size_t M>
|
|
DatabaseCon(
|
|
boost::filesystem::path const& pPath,
|
|
std::vector<std::string> const* commonPragma,
|
|
std::array<std::string, N> const& pragma,
|
|
std::array<char const*, M> const& initSQL,
|
|
beast::Journal journal)
|
|
: session_(std::make_shared<soci::session>()), j_(journal)
|
|
{
|
|
open(*session_, "sqlite", pPath.string());
|
|
|
|
for (auto const& p : pragma)
|
|
{
|
|
soci::statement st = session_->prepare << p;
|
|
st.execute(true);
|
|
}
|
|
|
|
if (commonPragma)
|
|
{
|
|
for (auto const& p : *commonPragma)
|
|
{
|
|
soci::statement st = session_->prepare << p;
|
|
st.execute(true);
|
|
}
|
|
}
|
|
|
|
for (auto const& sql : initSQL)
|
|
{
|
|
soci::statement st = session_->prepare << sql;
|
|
st.execute(true);
|
|
}
|
|
}
|
|
|
|
LockedSociSession::mutex lock_;
|
|
|
|
// checkpointer may outlive the DatabaseCon when the checkpointer jobQueue
|
|
// callback locks a weak pointer and the DatabaseCon is then destroyed. In
|
|
// this case, the checkpointer needs to make sure it doesn't use an already
|
|
// destroyed session. Thus this class keeps a shared_ptr to the session (so
|
|
// the checkpointer can keep a weak_ptr) and the checkpointer is a
|
|
// shared_ptr in this class. session_ will never be null.
|
|
std::shared_ptr<soci::session> const session_;
|
|
std::shared_ptr<Checkpointer> checkpointer_;
|
|
|
|
beast::Journal const j_;
|
|
};
|
|
|
|
// Return the checkpointer from its id. If the checkpointer no longer exists, an
|
|
// nullptr is returned
|
|
std::shared_ptr<Checkpointer>
|
|
checkpointerFromId(std::uintptr_t id);
|
|
|
|
} // namespace xrpl
|