#pragma once #include #include #include #include #include #include #include #include namespace soci { class session; } namespace xrpl { class LockedSociSession { public: using mutex = std::recursive_mutex; private: std::shared_ptr session_; std::unique_lock lock_; public: LockedSociSession(std::shared_ptr 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 const* commonPragma() const { XRPL_ASSERT( !useGlobalPragma || globalPragma, "xrpl::DatabaseCon::Setup::commonPragma : consistent global " "pragma"); return useGlobalPragma && globalPragma ? globalPragma.get() : nullptr; } static std::unique_ptr const> globalPragma; std::array txPragma; std::array lgrPragma; }; struct CheckpointerSetup { JobQueue* jobQueue; Logs* logs; }; template DatabaseCon( Setup const& setup, std::string const& dbName, std::array const& pragma, std::array 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 DatabaseCon( Setup const& setup, std::string const& dbName, std::array const& pragma, std::array const& initSQL, CheckpointerSetup const& checkpointerSetup, beast::Journal journal) : DatabaseCon(setup, dbName, pragma, initSQL, journal) { setupCheckpointing(checkpointerSetup.jobQueue, *checkpointerSetup.logs); } template DatabaseCon( boost::filesystem::path const& dataDir, std::string const& dbName, std::array const& pragma, std::array const& initSQL, beast::Journal journal) : DatabaseCon(dataDir / dbName, nullptr, pragma, initSQL, journal) { } // Use this constructor to setup checkpointing template DatabaseCon( boost::filesystem::path const& dataDir, std::string const& dbName, std::array const& pragma, std::array 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 DatabaseCon( boost::filesystem::path const& pPath, std::vector const* commonPragma, std::array const& pragma, std::array const& initSQL, beast::Journal journal) : session_(std::make_shared()), 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 const session_; std::shared_ptr checkpointer_; beast::Journal const j_; }; // Return the checkpointer from its id. If the checkpointer no longer exists, an // nullptr is returned std::shared_ptr checkpointerFromId(std::uintptr_t id); } // namespace xrpl