From 97623d20c5b05791a622f76f4746cb199c0f12da Mon Sep 17 00:00:00 2001 From: seelabs Date: Thu, 22 Jan 2015 15:04:30 -0800 Subject: [PATCH] Use soci in more places: * Validator, peerfinder, SHAMapStore, RpcDB, TxnDB, LedgerDB, WalletDB use soci backend. --- Builds/VisualStudio2013/RippleD.vcxproj | 2 - .../VisualStudio2013/RippleD.vcxproj.filters | 6 - SConstruct | 20 + src/ripple/app/data/DatabaseCon.cpp | 38 +- src/ripple/app/data/DatabaseCon.h | 77 ++- .../app/data/DummySociDynamicBackend.cpp | 6 +- src/ripple/app/data/SociDB.cpp | 246 +++++--- src/ripple/app/data/SociDB.h | 93 ++- src/ripple/app/data/SqliteDatabase.cpp | 37 +- src/ripple/app/data/SqliteDatabase.h | 11 +- src/ripple/app/data/tests/SociDB.test.cpp | 147 ++++- src/ripple/app/ledger/Ledger.cpp | 466 ++++++-------- src/ripple/app/ledger/Ledger.h | 3 - src/ripple/app/main/Application.cpp | 77 ++- src/ripple/app/main/LocalCredentials.cpp | 71 +-- src/ripple/app/main/Main.cpp | 8 +- src/ripple/app/misc/AmendmentTableImpl.cpp | 40 +- src/ripple/app/misc/NetworkOPs.cpp | 261 ++++---- src/ripple/app/misc/SHAMapStoreImp.cpp | 53 +- src/ripple/app/misc/Validations.cpp | 12 +- src/ripple/app/peers/UniqueNodeList.cpp | 583 +++++++++++------- src/ripple/app/tx/Transaction.cpp | 121 +--- src/ripple/app/tx/Transaction.h | 10 +- src/ripple/app/tx/TransactionMeta.cpp | 20 +- src/ripple/app/tx/TransactionMeta.h | 6 + src/ripple/basics/BasicConfig.h | 18 + src/ripple/peerfinder/impl/StoreSqdb.h | 73 ++- src/ripple/rpc/handlers/GetCounts.cpp | 6 +- src/ripple/rpc/handlers/TxHistory.cpp | 28 +- src/ripple/unity/socipostgresql.cpp | 48 -- src/ripple/validators/impl/StoreSqdb.cpp | 3 +- src/soci/src/core/unsigned-types.h | 6 +- 32 files changed, 1474 insertions(+), 1122 deletions(-) delete mode 100644 src/ripple/unity/socipostgresql.cpp diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index d8ce6722a..0b01d77cf 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -4305,8 +4305,6 @@ - - True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 49a9252a3..cde11996d 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -535,9 +535,6 @@ {AA927DBA-1AF8-6600-04B7-D1C1EBFB4103} - - {5D2927A9-CC6E-DDE0-1654-5316177082DD} - {75E6832F-A6F7-8360-FA3A-7427A06A9959} @@ -5040,9 +5037,6 @@ snappy\snappy - - soci\src\backends\postgresql - soci\src\backends\sqlite3 diff --git a/SConstruct b/SConstruct index a64f38bf8..0b8b784c2 100644 --- a/SConstruct +++ b/SConstruct @@ -40,6 +40,26 @@ If the clang toolchain is detected, then the default target will use it, else the gcc toolchain will be used. On Windows environments, the MSVC toolchain is also detected. +The following environment variables modify the build environment: + CLANG_CC + CLANG_CXX + CLANG_LINK + If set, a clang toolchain will be used. These must all be set together. + + GNU_CC + GNU_CXX + GNU_LINK + If set, a gcc toolchain will be used (unless a clang toolchain is + detected first). These must all be set together. + + CXX + If set, used to detect a toolchain. + + BOOST_ROOT + Path to the boost directory. + OPENSSL_ROOT + Path to the openssl directory. + ''' # ''' diff --git a/src/ripple/app/data/DatabaseCon.cpp b/src/ripple/app/data/DatabaseCon.cpp index 844fb5333..55fdf79f2 100644 --- a/src/ripple/app/data/DatabaseCon.cpp +++ b/src/ripple/app/data/DatabaseCon.cpp @@ -19,8 +19,9 @@ #include #include -#include -#include +#include +#include +#include // namespace ripple { @@ -28,6 +29,7 @@ DatabaseCon::DatabaseCon (Setup const& setup, std::string const& strName, const char* initStrings[], int initCount) + :session_(std::make_shared()) { auto const useTempFiles // Use temporary files or regular DB files? = setup.standAlone && @@ -37,26 +39,28 @@ DatabaseCon::DatabaseCon (Setup const& setup, boost::filesystem::path pPath = useTempFiles ? "" : (setup.dataDir / strName); - mDatabase = new SqliteDatabase (pPath.string ().c_str ()); - mDatabase->connect (); + open(*session_, "sqlite", pPath.string()); for (int i = 0; i < initCount; ++i) - mDatabase->executeSQL (initStrings[i], true); + { + try + { + *session_ << initStrings[i]; + } + catch (soci::soci_error& e) + { + WriteLog (lsWARNING, DatabaseCon) + << "Error executing initial statements for: " << strName + << " error: " << e.what () << "\n" + << " statement: " << initStrings[i]; + } + } } -DatabaseCon::~DatabaseCon () -{ - mDatabase->disconnect (); - delete mDatabase; -} - -DatabaseCon::Setup -setup_DatabaseCon (Config const& c) +DatabaseCon::Setup setup_DatabaseCon (Config const& c) { DatabaseCon::Setup setup; - auto const& sec = c.section (ConfigSection::nodeDatabase ()); - get_if_exists (sec, "online_delete", setup.onlineDelete); setup.startUp = c.START_UP; setup.standAlone = c.RUN_STANDALONE; setup.dataDir = c.legacy ("database_path"); @@ -64,4 +68,8 @@ setup_DatabaseCon (Config const& c) return setup; } +void DatabaseCon::setupCheckpointing (JobQueue* q) +{ + walCheckpointer_ = std::make_unique (session_, q); +} } // ripple diff --git a/src/ripple/app/data/DatabaseCon.h b/src/ripple/app/data/DatabaseCon.h index f777c802c..a7aa944cd 100644 --- a/src/ripple/app/data/DatabaseCon.h +++ b/src/ripple/app/data/DatabaseCon.h @@ -20,24 +20,65 @@ #ifndef RIPPLE_APP_DATA_DATABASECON_H_INCLUDED #define RIPPLE_APP_DATA_DATABASECON_H_INCLUDED -#include #include +#include #include #include #include + +namespace soci { + class session; +} + namespace ripple { -class Database; +template +class LockedPointer +{ +public: + using mutex = TMutex; +private: + T* it_; + std::unique_lock lock_; + +public: + LockedPointer (T* it, mutex& m) : it_ (it), lock_ (m) + { + } + LockedPointer (LockedPointer&& rhs) noexcept + : it_ (rhs.it_), lock_ (std::move (rhs.lock_)) + { + } + LockedPointer () = delete; + LockedPointer (LockedPointer const& rhs) = delete; + LockedPointer& operator=(LockedPointer const& rhs) = delete; + + T* get () + { + return it_; + } + T& operator*() + { + return *it_; + } + T* operator->() + { + return it_; + } + explicit operator bool() const + { + return bool(it_); + } +}; + +using LockedSociSession = LockedPointer; -// VFALCO NOTE This looks like a pointless class. Figure out -// what purpose it is really trying to serve and do it better. class DatabaseCon { public: struct Setup { - bool onlineDelete = false; Config::StartUpType startUp = Config::NORMAL; bool standAlone = false; boost::filesystem::path dataDir; @@ -47,32 +88,26 @@ public: std::string const& name, const char* initString[], int countInit); - ~DatabaseCon (); - Database* getDB () + soci::session& getSession() { - return mDatabase; + return *session_; } - typedef std::recursive_mutex mutex; - - std::unique_lock lock () + LockedSociSession checkoutDb() { - return std::unique_lock(mLock); - } - - mutex& peekMutex() - { - return mLock; + return LockedSociSession(session_.get (), lock_); } + void setupCheckpointing (JobQueue*); private: - Database* mDatabase; - mutex mLock; + std::unique_ptr walCheckpointer_; + // shared_ptr to handle lifetime issues with walCheckpointer_ + // never null. + std::shared_ptr session_; + LockedSociSession::mutex lock_; }; -//------------------------------------------------------------------------------ - DatabaseCon::Setup setup_DatabaseCon (Config const& c); diff --git a/src/ripple/app/data/DummySociDynamicBackend.cpp b/src/ripple/app/data/DummySociDynamicBackend.cpp index 37bef26cb..69076d67f 100644 --- a/src/ripple/app/data/DummySociDynamicBackend.cpp +++ b/src/ripple/app/data/DummySociDynamicBackend.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -/** Stub functions for soci dynamic backends. +/* Stub functions for soci dynamic backends. Ripple does not use dynamic backends, and inclduing soci's dynamic backends compilcates the build (it requires a generated - header file and some macros to be defines.) + header file and some macros to be defined.) */ #include @@ -35,8 +35,6 @@ namespace dynamic_backends { backend_factory const& get (std::string const& name) { throw std::runtime_error ("Not Supported"); - backend_factory* nullBF{nullptr}; - return *nullBF; // deref nullptr - but we already threw }; // provided for advanced user-level management diff --git a/src/ripple/app/data/SociDB.cpp b/src/ripple/app/data/SociDB.cpp index 2a7948799..69564e8ad 100644 --- a/src/ripple/app/data/SociDB.cpp +++ b/src/ripple/app/data/SociDB.cpp @@ -17,14 +17,6 @@ */ //============================================================================== -/** An embedded database wrapper with an intuitive, type-safe interface. - - This collection of classes let's you access embedded SQLite databases - using C++ syntax that is very similar to regular SQL. - - This module requires the @ref beast_sqlite external module. -*/ - #include #include @@ -32,9 +24,6 @@ #include #include // #include -#if ENABLE_SOCI_POSTGRESQL -#include -#endif #include namespace ripple { @@ -57,69 +46,12 @@ getSociSqliteInit (std::string const& name, return std::make_pair (file.string (), std::ref(soci::sqlite3)); } -#if ENABLE_SOCI_POSTGRESQL -std::pair -getSociPostgresqlInit (Section const& configSection, - std::string const& name) -{ - if (name.empty ()) - { - throw std::runtime_error ( - "Missing required value for postgresql backend: database name"); - } - - std::string const host(get (configSection, "host", "")); - if (!host.empty()) - { - throw std::runtime_error ( - "Missing required value in config for postgresql backend: host"); - } - - std::string const user(get (configSection, "user", "")); - if (user.empty ()) - { - throw std::runtime_error ( - "Missing required value in config for postgresql backend: user"); - } - - int const port = [&configSection] - { - std::string const portAsString ( - get (configSection, "port", "")); - if (portAsString.empty ()) - { - throw std::runtime_error ( - "Missing required value in config for postgresql backend: " - "user"); - } - try - { - return std::stoi (portAsString); - } - catch (...) - { - throw std::runtime_error ( - "The port value in the config for the postgresql backend must " - "be an integer. Got: " + - portAsString); - } - }(); - - std::stringstream s; - s << "host=" << host << " port=" << port << " dbname=" << name - << " user=" << user; - return std::make_pair (s.str (), std::ref(soci::postgresql)); -} -#endif // ENABLE_SOCI_POSTGRESQL - std::pair getSociInit (BasicConfig const& config, std::string const& dbName) { - static const std::string sectionName ("sqdb"); - static const std::string keyName ("backend"); - auto const& section = config.section (sectionName); - std::string const backendName(get(section, keyName, std::string("sqlite"))); + auto const& section = config.section ("sqdb"); + std::string const backendName(get(section, "backend", "sqlite")); if (backendName == "sqlite") { @@ -129,12 +61,6 @@ getSociInit (BasicConfig const& config, : ".db"; return detail::getSociSqliteInit(dbName, path, ext); } -#if ENABLE_SOCI_POSTGRESQL - else if (backendName == "postgresql") - { - return detail::getSociPostgresqlInit(section, dbName); - } -#endif else { throw std::runtime_error ("Unsupported soci backend: " + backendName); @@ -142,13 +68,14 @@ getSociInit (BasicConfig const& config, } } // detail -SociConfig::SociConfig(std::pair init) - :connectionString_(std::move(init.first)), - backendFactory_(init.second){} +SociConfig::SociConfig (std::pair init) + : connectionString_ (std::move (init.first)), + backendFactory_ (init.second) +{ +} -SociConfig::SociConfig(BasicConfig const& config, - std::string const& dbName) - : SociConfig(detail::getSociInit(config, dbName)) +SociConfig::SociConfig (BasicConfig const& config, std::string const& dbName) + : SociConfig (detail::getSociInit (config, dbName)) { } @@ -169,5 +96,160 @@ void open(soci::session& s, SociConfig c(config, dbName); c.open(s); } + +void open(soci::session& s, + std::string const& beName, + std::string const& connectionString) +{ + if (beName == "sqlite") + { + s.open(soci::sqlite3, connectionString); + return; + } + else + { + throw std::runtime_error ("Unsupported soci backend: " + beName); + } } +size_t getKBUsedAll (soci::session& s) +{ + auto be = dynamic_cast(s.get_backend ()); + assert (be); // Make sure the backend is sqlite + return static_cast(sqlite_api::sqlite3_memory_used () / 1024); +} + +size_t getKBUsedDB (soci::session& s) +{ + // This function will have to be customized when other backends are added + auto be = dynamic_cast(s.get_backend ()); + assert (be); + int cur = 0, hiw = 0; + sqlite_api::sqlite3_db_status ( + be->conn_, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0); + return cur / 1024; +} + +void convert(soci::blob& from, std::vector& to) +{ + to.resize (from.get_len ()); + if (to.empty ()) + return; + from.read (0, reinterpret_cast(&to[0]), from.get_len ()); +} + +void convert(soci::blob& from, std::string& to) +{ + std::vector tmp; + convert(from, tmp); + to.assign(tmp.begin (), tmp.end()); + +} + +void convert(std::vector const& from, soci::blob& to) +{ + if (!from.empty ()) + to.write (0, reinterpret_cast(&from[0]), from.size ()); +} + +int SqliteWALHook (void* s, + sqlite_api::sqlite3*, + const char* dbName, + int walSize) +{ + (reinterpret_cast(s))->doHook (dbName, walSize); + return SQLITE_OK; +} + +WALCheckpointer::WALCheckpointer (std::shared_ptr const& s, + JobQueue* q) + : Thread ("sqlitedb"), session_(s) +{ + if (auto session = + dynamic_cast(s->get_backend ())) + conn_ = session->conn_; + + if (!conn_) return; + startThread (); + setupCheckpointing (q); +} + +WALCheckpointer::~WALCheckpointer () +{ + if (!conn_) return; + stopThread (); +} + +void WALCheckpointer::setupCheckpointing (JobQueue* q) +{ + if (!conn_) return; + q_ = q; + sqlite_api::sqlite3_wal_hook (conn_, SqliteWALHook, this); +} + +void WALCheckpointer::doHook (const char* db, int pages) +{ + if (!conn_) return; + + if (pages < 1000) + return; + + { + ScopedLockType sl (mutex_); + + if (running_) + return; + + running_ = true; + } + + if (q_) + q_->addJob (jtWAL, + std::string ("WAL"), + std::bind (&WALCheckpointer::runWal, this)); + else + notify (); +} + +void WALCheckpointer::run () +{ + if (!conn_) return; + + // Simple thread loop runs Wal every time it wakes up via + // the call to Thread::notify, unless Thread::threadShouldExit returns + // true in which case we simply break. + // + for (;;) + { + wait (); + if (threadShouldExit ()) + break; + runWal (); + } +} + +void WALCheckpointer::runWal () +{ + if (!conn_) return; + + int log = 0, ckpt = 0; + int ret = sqlite3_wal_checkpoint_v2 ( + conn_, nullptr, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt); + + if (ret != SQLITE_OK) + { + WriteLog ((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING, WALCheckpointer) + << "WAL(" << sqlite3_db_filename (conn_, "main") << "): error " + << ret; + } + else + WriteLog (lsTRACE, WALCheckpointer) + << "WAL(" << sqlite3_db_filename (conn_, "main") + << "): frames=" << log << ", written=" << ckpt; + + { + ScopedLockType sl (mutex_); + running_ = false; + } +} +} diff --git a/src/ripple/app/data/SociDB.h b/src/ripple/app/data/SociDB.h index 8c4e1566c..d0969af2d 100644 --- a/src/ripple/app/data/SociDB.h +++ b/src/ripple/app/data/SociDB.h @@ -28,13 +28,37 @@ This module requires the @ref beast_sqlite external module. */ -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning( \ - disable : 4355) // 'this' : used in base member initializer list -#endif - +#include +#include +#include +#define SOCI_USE_BOOST #include +// #include +#include +#include +#include + +namespace sqlite_api { + class sqlite3; +} + +namespace ripple { +template +T rangeCheckedCast (C c) +{ + if ((c > std::numeric_limits::max ()) || + (!std::numeric_limits::is_signed && c < 0) || + (std::numeric_limits::is_signed && + std::numeric_limits::is_signed && + c < std::numeric_limits::lowest ())) + { + WriteLog (lsERROR, RangeCheckedCast) + << "Range error. Min: " << std::numeric_limits::lowest () + << " Max: " << std::numeric_limits::max () << " Got: " << c; + } + return static_cast(c); +} +} namespace ripple { class BasicConfig; @@ -44,7 +68,7 @@ class BasicConfig; * parsing the config parameters. If a client want to open a session immediately, * use the free function "open" below. */ -class SociConfig final +class SociConfig { std::string connectionString_; soci::backend_factory const& backendFactory_; @@ -70,10 +94,57 @@ void open(soci::session& s, BasicConfig const& config, std::string const& dbName); +/** + * Open a soci session. + * + * @param s Session to open. + * @param beName Backend name. + * @param connectionString Connection string to forward to soci::open. + * see the soci::open documentation for how to use this. + * + */ +void open(soci::session& s, + std::string const& beName, + std::string const& connectionString); + +size_t getKBUsedAll (soci::session& s); +size_t getKBUsedDB (soci::session& s); + +void convert(soci::blob& from, std::vector& to); +void convert(soci::blob& from, std::string& to); +void convert(std::vector const& from, soci::blob& to); + +/** Run a thread to checkpoint the write ahead log (wal) for + the given soci::session every 1000 pages. This is only implemented + for sqlite databases. + + Note: According to: https://www.sqlite.org/wal.html#ckpt this + is the default behavior of sqlite. We may be able to remove this + class. +*/ +class WALCheckpointer + :private beast::Thread +{ + friend int SqliteWALHook (void* s, sqlite_api::sqlite3*, + const char* dbName, int walSize); +public: + WALCheckpointer (std::shared_ptr const& s, + JobQueue* q); + ~WALCheckpointer (); +private: + void doHook (const char* db, int walSize); + void setupCheckpointing (JobQueue*); + void run (); + void runWal (); + + std::shared_ptr session_; + sqlite_api::sqlite3* conn_ = nullptr; + using LockType = std::mutex; + using ScopedLockType = std::lock_guard; + LockType mutex_; + JobQueue* q_ = nullptr; + bool running_ = false; +}; } -#if _MSC_VER -#pragma warning(pop) -#endif - #endif diff --git a/src/ripple/app/data/SqliteDatabase.cpp b/src/ripple/app/data/SqliteDatabase.cpp index 7adbbc278..547bc024c 100644 --- a/src/ripple/app/data/SqliteDatabase.cpp +++ b/src/ripple/app/data/SqliteDatabase.cpp @@ -24,22 +24,22 @@ namespace ripple { -SqliteStatement::SqliteStatement (SqliteDatabase* db, const char* sql, bool aux) +SqliteStatement::SqliteStatement (SqliteDatabase* db, const char* sql) { assert (db); - sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection (); + sqlite3* conn = db->peekConnection (); int j = sqlite3_prepare_v2 (conn, sql, strlen (sql) + 1, &statement, nullptr); if (j != SQLITE_OK) throw j; } -SqliteStatement::SqliteStatement (SqliteDatabase* db, std::string const& sql, bool aux) +SqliteStatement::SqliteStatement (SqliteDatabase* db, std::string const& sql) { assert (db); - sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection (); + sqlite3* conn = db->peekConnection (); int j = sqlite3_prepare_v2 (conn, sql.c_str (), sql.size () + 1, &statement, nullptr); if (j != SQLITE_OK) @@ -62,7 +62,6 @@ SqliteDatabase::SqliteDatabase (const char* host) startThread (); mConnection = nullptr; - mAuxConnection = nullptr; mCurrentStmt = nullptr; } @@ -85,38 +84,10 @@ void SqliteDatabase::connect () } } -sqlite3* SqliteDatabase::getAuxConnection () -{ - ScopedLockType sl (m_walMutex); - - if (mAuxConnection == nullptr) - { - int rc = sqlite3_open_v2 (mHost.c_str (), &mAuxConnection, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr); - - if (rc) - { - WriteLog (lsFATAL, SqliteDatabase) << "Can't aux open " << mHost << " " << rc; - assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED)); - - if (mAuxConnection != nullptr) - { - sqlite3_close (mConnection); - mAuxConnection = nullptr; - } - } - } - - return mAuxConnection; -} - void SqliteDatabase::disconnect () { sqlite3_finalize (mCurrentStmt); sqlite3_close (mConnection); - - if (mAuxConnection != nullptr) - sqlite3_close (mAuxConnection); } // returns true if the query went ok diff --git a/src/ripple/app/data/SqliteDatabase.h b/src/ripple/app/data/SqliteDatabase.h index 99797df2b..2b0191b51 100644 --- a/src/ripple/app/data/SqliteDatabase.h +++ b/src/ripple/app/data/SqliteDatabase.h @@ -68,7 +68,6 @@ public: { return mConnection; } - sqlite3* getAuxConnection (); virtual bool setupCheckpointing (JobQueue*); virtual SqliteDatabase* getSqliteDB () { @@ -81,6 +80,7 @@ public: int getKBUsedAll (); private: + void run (); void runWal (); @@ -89,8 +89,6 @@ private: LockType m_walMutex; sqlite3* mConnection; - // VFALCO TODO Why do we need an "aux" connection? Should just use a second SqliteDatabase object. - sqlite3* mAuxConnection; sqlite3_stmt* mCurrentStmt; bool mMoreRows; @@ -110,11 +108,8 @@ protected: sqlite3_stmt* statement; public: - // VFALCO TODO This is quite a convoluted interface. A mysterious "aux" connection? - // Why not just have two SqliteDatabase objects? - // - SqliteStatement (SqliteDatabase* db, const char* statement, bool aux = false); - SqliteStatement (SqliteDatabase* db, std::string const& statement, bool aux = false); + SqliteStatement (SqliteDatabase* db, const char* statement); + SqliteStatement (SqliteDatabase* db, std::string const& statement); ~SqliteStatement (); sqlite3_stmt* peekStatement (); diff --git a/src/ripple/app/data/tests/SociDB.test.cpp b/src/ripple/app/data/tests/SociDB.test.cpp index e10a44b82..03d486389 100644 --- a/src/ripple/app/data/tests/SociDB.test.cpp +++ b/src/ripple/app/data/tests/SociDB.test.cpp @@ -39,20 +39,6 @@ private: config.legacy ("database_path", value); } - static void setupPostgresqlConfig (BasicConfig& config, - std::string const& host, - std::string const& user, - std::string const& port) - { - config.overwrite ("sqdb", "backend", "postgresql"); - if (!host.empty ()) - config.overwrite ("sqdb", "host", host); - if (!user.empty ()) - config.overwrite ("sqdb", "user", user); - if (!port.empty ()) - config.overwrite ("sqdb", "port", port); - } - static void cleanupDatabaseDir (boost::filesystem::path const& dbPath) { using namespace boost::filesystem; @@ -109,7 +95,7 @@ public: testcase ("sqliteFileNames"); BasicConfig c; setupSQLiteConfig (c, getDatabasePath ()); - std::vector> const d ( + std::vector> const d ( {{"peerfinder", ".sqlite"}, {"state", ".db"}, {"random", ".db"}, @@ -119,7 +105,7 @@ public: { SociConfig sc (c, i.first); expect (boost::ends_with (sc.connectionString (), - std::string (i.first) + i.second)); + i.first + i.second)); } } void testSQLiteSession () @@ -181,10 +167,139 @@ public: remove (dbPath); } } + + void testSQLiteSelect () + { + testcase ("select"); + BasicConfig c; + setupSQLiteConfig (c, getDatabasePath ()); + SociConfig sc (c, "SociTestDB"); + std::vector const ubid ( + {(std::uint64_t)std::numeric_limits::max (), 20, 30}); + std::vector const bid ({-10, -20, -30}); + std::vector const uid ( + {std::numeric_limits::max (), 2, 3}); + std::vector const id ({-1, -2, -3}); + + { + soci::session s; + sc.open (s); + + s << "DROP TABLE IF EXISTS STT;"; + + s << "CREATE TABLE STT (" + " I INTEGER," + " UI INTEGER UNSIGNED," + " BI BIGINT," + " UBI BIGINT UNSIGNED" + ");"; + + s << "INSERT INTO STT (I, UI, BI, UBI) VALUES " + "(:id, :idu, :bid, :bidu);", + soci::use (id), soci::use (uid), soci::use (bid), + soci::use (ubid); + + try + { + std::int32_t ig = 0; + std::uint32_t uig = 0; + std::int64_t big = 0; + std::uint64_t ubig = 0; + s << "SELECT I, UI, BI, UBI from STT", soci::into (ig), + soci::into (uig), soci::into (big), soci::into (ubig); + expect (ig == id[0] && uig == uid[0] && big == bid[0] && + ubig == ubid[0]); + } + catch (std::exception&) + { + fail (); + } + try + { + boost::optional ig; + boost::optional uig; + boost::optional big; + boost::optional ubig; + s << "SELECT I, UI, BI, UBI from STT", soci::into (ig), + soci::into (uig), soci::into (big), soci::into (ubig); + expect (*ig == id[0] && *uig == uid[0] && *big == bid[0] && + *ubig == ubid[0]); + } + catch (std::exception&) + { + fail (); + } + // There are too many issues when working with soci::row and boost::tuple. DO NOT USE + // soci row! I had a set of workarounds to make soci row less error prone, I'm keeping + // these tests in case I try to add soci::row and boost::tuple back into soci. +#if 0 + try + { + std::int32_t ig = 0; + std::uint32_t uig = 0; + std::int64_t big = 0; + std::uint64_t ubig = 0; + soci::row r; + s << "SELECT I, UI, BI, UBI from STT", soci::into (r); + ig = r.get(0); + uig = r.get(1); + big = r.get(2); + ubig = r.get(3); + expect (ig == id[0] && uig == uid[0] && big == bid[0] && + ubig == ubid[0]); + } + catch (std::exception&) + { + fail (); + } + try + { + std::int32_t ig = 0; + std::uint32_t uig = 0; + std::int64_t big = 0; + std::uint64_t ubig = 0; + soci::row r; + s << "SELECT I, UI, BI, UBI from STT", soci::into (r); + ig = r.get("I"); + uig = r.get("UI"); + big = r.get("BI"); + ubig = r.get("UBI"); + expect (ig == id[0] && uig == uid[0] && big == bid[0] && + ubig == ubid[0]); + } + catch (std::exception&) + { + fail (); + } + try + { + boost::tuple d; + s << "SELECT I, UI, BI, UBI from STT", soci::into (d); + expect (get<0>(d) == id[0] && get<1>(d) == uid[0] && + get<2>(d) == bid[0] && get<3>(d) == ubid[0]); + } + catch (std::exception&) + { + fail (); + } +#endif + } + { + using namespace boost::filesystem; + // Remove the database + path dbPath (sc.connectionString ()); + if (is_regular_file (dbPath)) + remove (dbPath); + } + } void testSQLite () { testSQLiteFileNames (); testSQLiteSession (); + testSQLiteSelect (); } void run () { diff --git a/src/ripple/app/ledger/Ledger.cpp b/src/ripple/app/ledger/Ledger.cpp index 95131dc03..00aff64e5 100644 --- a/src/ripple/app/ledger/Ledger.cpp +++ b/src/ripple/app/ledger/Ledger.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -44,6 +44,7 @@ #include #include #include +#include namespace ripple { @@ -694,18 +695,17 @@ bool Ledger::saveValidatedLedger (bool current) } { - auto sl (getApp().getLedgerDB ().lock ()); - getApp().getLedgerDB ().getDB ()->executeSQL ( - boost::str (deleteLedger % mLedgerSeq)); + auto db = getApp().getLedgerDB ().checkoutDb(); + *db << boost::str (deleteLedger % mLedgerSeq); } { - auto db = getApp().getTxnDB ().getDB (); - auto dbLock (getApp().getTxnDB ().lock ()); - db->executeSQL ("BEGIN TRANSACTION;"); + auto db = getApp().getTxnDB ().checkoutDb (); - db->executeSQL (boost::str (deleteTrans1 % getLedgerSeq ())); - db->executeSQL (boost::str (deleteTrans2 % getLedgerSeq ())); + soci::transaction tr(*db); + + *db << boost::str (deleteTrans1 % getLedgerSeq ()); + *db << boost::str (deleteTrans2 % getLedgerSeq ()); std::string const ledgerSeq (std::to_string (getLedgerSeq ())); @@ -719,7 +719,7 @@ bool Ledger::saveValidatedLedger (bool current) std::string const txnId (to_string (transactionID)); std::string const txnSeq (std::to_string (vt.second->getTxnSeq ())); - db->executeSQL (boost::str (deleteAcctTrans % transactionID)); + *db << boost::str (deleteAcctTrans % transactionID); auto const& accts = vt.second->getAffected (); @@ -758,30 +758,31 @@ bool Ledger::saveValidatedLedger (bool current) { WriteLog (lsTRACE, Ledger) << "ActTx: " << sql; } - db->executeSQL (sql); + *db << sql; } else WriteLog (lsWARNING, Ledger) << "Transaction in ledger " << mLedgerSeq << " affects no accounts"; - db->executeSQL ( - STTx::getMetaSQLInsertReplaceHeader () + + *db << + (STTx::getMetaSQLInsertReplaceHeader () + vt.second->getTxn ()->getMetaSQL ( getLedgerSeq (), vt.second->getEscMeta ()) + ";"); } - db->executeSQL ("COMMIT TRANSACTION;"); + + tr.commit (); } { - auto sl (getApp().getLedgerDB ().lock ()); + auto db (getApp().getLedgerDB ().checkoutDb ()); // TODO(tom): ARG! - getApp().getLedgerDB ().getDB ()->executeSQL (boost::str (addLedger % - to_string (getHash ()) % mLedgerSeq % to_string (mParentHash) % - beast::lexicalCastThrow (mTotCoins) % mCloseTime % - mParentCloseTime % mCloseResolution % mCloseFlags % - to_string (mAccountHash) % to_string (mTransHash))); + *db << boost::str (addLedger % + to_string (getHash ()) % mLedgerSeq % to_string (mParentHash) % + beast::lexicalCastThrow (mTotCoins) % mCloseTime % + mParentCloseTime % mCloseResolution % mCloseFlags % + to_string (mAccountHash) % to_string (mTransHash)); } { @@ -793,207 +794,127 @@ bool Ledger::saveValidatedLedger (bool current) return true; } -#ifndef NO_SQLITE3_PREPARE - -Ledger::pointer Ledger::loadByIndex (std::uint32_t ledgerIndex) +/* + * Load a ledger from the database. + * + * @param sqlSuffix: Additional string to append to the sql query. + * (typically a where clause). + * @return The ledger, ledger sequence, and ledger hash. + */ +std::tuple +loadHelper(std::string const& sqlSuffix) { Ledger::pointer ledger; + uint256 ledgerHash; + std::uint32_t ledgerSeq{0}; + + auto db = getApp ().getLedgerDB ().checkoutDb (); + + boost::optional sLedgerHash, sPrevHash, sAccountHash, + sTransHash; + boost::optional totCoins, closingTime, prevClosingTime, + closeResolution, closeFlags, ledgerSeq64; + + std::string const sql = + "SELECT " + "LedgerHash, PrevHash, AccountSetHash, TransSetHash, " + "TotalCoins," + "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags," + "LedgerSeq from Ledgers " + + sqlSuffix + ";"; + + *db << sql, + soci::into(sLedgerHash), + soci::into(sPrevHash), + soci::into(sAccountHash), + soci::into(sTransHash), + soci::into(totCoins), + soci::into(closingTime), + soci::into(prevClosingTime), + soci::into(closeResolution), + soci::into(closeFlags), + soci::into(ledgerSeq64); + + if (!db->got_data ()) { - auto db = getApp().getLedgerDB ().getDB (); - auto sl (getApp().getLedgerDB ().lock ()); - - SqliteStatement pSt ( - db->getSqliteDB (), "SELECT " - "LedgerHash,PrevHash,AccountSetHash,TransSetHash,TotalCoins," - "ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,LedgerSeq" - " from Ledgers WHERE LedgerSeq = ?;"); - - pSt.bind (1, ledgerIndex); - ledger = getSQL1 (&pSt); + std::stringstream s; + WriteLog (lsINFO, Ledger) << "Ledger not found: " << sqlSuffix; + return std::make_tuple (Ledger::pointer (), ledgerSeq, ledgerHash); } - if (ledger) - { - Ledger::getSQL2 (ledger); - ledger->setFull (); - } + ledgerSeq = + rangeCheckedCast(ledgerSeq64.value_or (0)); - return ledger; -} + uint256 prevHash, accountHash, transHash; + ledgerHash.SetHexExact (sLedgerHash.value_or("")); + prevHash.SetHexExact (sPrevHash.value_or("")); + accountHash.SetHexExact (sAccountHash.value_or("")); + transHash.SetHexExact (sTransHash.value_or("")); -Ledger::pointer Ledger::loadByHash (uint256 const& ledgerHash) -{ - Ledger::pointer ledger; - { - auto db = getApp().getLedgerDB ().getDB (); - auto sl (getApp().getLedgerDB ().lock ()); - - SqliteStatement pSt ( - db->getSqliteDB (), "SELECT " - "LedgerHash,PrevHash,AccountSetHash,TransSetHash,TotalCoins," - "ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,LedgerSeq" - " from Ledgers WHERE LedgerHash = ?;"); - - pSt.bind (1, to_string (ledgerHash)); - ledger = getSQL1 (&pSt); - } - - if (ledger) - { - assert (ledger->getHash () == ledgerHash); - Ledger::getSQL2 (ledger); - ledger->setFull (); - } - - return ledger; -} - -#else - -Ledger::pointer Ledger::loadByIndex (std::uint32_t ledgerIndex) -{ - // This is a low-level function with no caching. - std::string sql = "SELECT * from Ledgers WHERE LedgerSeq='"; - sql.append (beast::lexicalCastThrow (ledgerIndex)); - sql.append ("';"); - return getSQL (sql); -} - -Ledger::pointer Ledger::loadByHash (uint256 const& ledgerHash) -{ - // This is a low-level function with no caching and only gets accepted - // ledgers. - std::string sql = "SELECT * from Ledgers WHERE LedgerHash='"; - sql.append (to_string (ledgerHash)); - sql.append ("';"); - return getSQL (sql); -} - -#endif - -Ledger::pointer Ledger::getSQL (std::string const& sql) -{ - // only used with sqlite3 prepared statements not used - uint256 ledgerHash, prevHash, accountHash, transHash; - std::uint64_t totCoins; - std::uint32_t closingTime, prevClosingTime, ledgerSeq; - int closeResolution; - unsigned closeFlags; - std::string hash; - - { - auto db = getApp().getLedgerDB ().getDB (); - auto sl (getApp().getLedgerDB ().lock ()); - - if (!db->executeSQL (sql) || !db->startIterRows ()) - return Ledger::pointer (); - - db->getStr ("LedgerHash", hash); - ledgerHash.SetHexExact (hash); - db->getStr ("PrevHash", hash); - prevHash.SetHexExact (hash); - db->getStr ("AccountSetHash", hash); - accountHash.SetHexExact (hash); - db->getStr ("TransSetHash", hash); - transHash.SetHexExact (hash); - totCoins = db->getBigInt ("TotalCoins"); - closingTime = db->getBigInt ("ClosingTime"); - prevClosingTime = db->getBigInt ("PrevClosingTime"); - closeResolution = db->getBigInt ("CloseTimeRes"); - closeFlags = db->getBigInt ("CloseFlags"); - ledgerSeq = db->getBigInt ("LedgerSeq"); - db->endIterRows (); - } - - // CAUTION: code below appears in two places - bool loaded; - Ledger::pointer ret (new Ledger ( - prevHash, transHash, accountHash, totCoins, closingTime, - prevClosingTime, closeFlags, closeResolution, ledgerSeq, loaded)); + bool loaded = false; + ledger = std::make_shared(prevHash, + transHash, + accountHash, + totCoins.value_or(0), + closingTime.value_or(0), + prevClosingTime.value_or(0), + closeFlags.value_or(0), + closeResolution.value_or(0), + ledgerSeq, + loaded); if (!loaded) - return Ledger::pointer (); + return std::make_tuple (Ledger::pointer (), ledgerSeq, ledgerHash); - ret->setClosed (); - - if (getApp().getOPs ().haveLedger (ledgerSeq)) - { - ret->setAccepted (); - ret->setValidated (); - } - - if (ret->getHash () != ledgerHash) - { - if (ShouldLog (lsERROR, Ledger)) - { - WriteLog (lsERROR, Ledger) << "Failed on ledger"; - Json::Value p; - addJson (p, {*ret, LedgerFill::full}); - WriteLog (lsERROR, Ledger) << p; - } - - assert (false); - return Ledger::pointer (); - } - - WriteLog (lsTRACE, Ledger) << "Loaded ledger: " << ledgerHash; - return ret; + return std::make_tuple (ledger, ledgerSeq, ledgerHash); } -Ledger::pointer Ledger::getSQL1 (SqliteStatement* stmt) +void finishLoadByIndexOrHash(Ledger::pointer& ledger) { - int iRet = stmt->step (); + if (!ledger) + return; - if (stmt->isDone (iRet)) - return Ledger::pointer (); + ledger->setClosed (); + ledger->setImmutable (); - if (!stmt->isRow (iRet)) - { - WriteLog (lsINFO, Ledger) - << "Ledger not found: " << iRet - << " = " << stmt->getError (iRet); - return Ledger::pointer (); - } - - uint256 ledgerHash, prevHash, accountHash, transHash; - std::uint64_t totCoins; - std::uint32_t closingTime, prevClosingTime, ledgerSeq; - int closeResolution; - unsigned closeFlags; - - ledgerHash.SetHexExact (stmt->peekString (0)); - prevHash.SetHexExact (stmt->peekString (1)); - accountHash.SetHexExact (stmt->peekString (2)); - transHash.SetHexExact (stmt->peekString (3)); - totCoins = stmt->getInt64 (4); - closingTime = stmt->getUInt32 (5); - prevClosingTime = stmt->getUInt32 (6); - closeResolution = stmt->getUInt32 (7); - closeFlags = stmt->getUInt32 (8); - ledgerSeq = stmt->getUInt32 (9); - - // CAUTION: code below appears in two places - bool loaded; - Ledger::pointer ret (new Ledger ( - prevHash, transHash, accountHash, totCoins, closingTime, - prevClosingTime, closeFlags, closeResolution, ledgerSeq, loaded)); - - if (!loaded) - return Ledger::pointer (); - - return ret; -} - -void Ledger::getSQL2 (Ledger::ref ret) -{ - ret->setClosed (); - ret->setImmutable (); - - if (getApp().getOPs ().haveLedger (ret->getLedgerSeq ())) - ret->setAccepted (); + if (getApp ().getOPs ().haveLedger (ledger->getLedgerSeq ())) + ledger->setAccepted (); WriteLog (lsTRACE, Ledger) - << "Loaded ledger: " << to_string (ret->getHash ()); + << "Loaded ledger: " << to_string (ledger->getHash ()); + + ledger->setFull (); +} + +Ledger::pointer Ledger::loadByIndex (std::uint32_t ledgerIndex) +{ + Ledger::pointer ledger; + { + std::ostringstream s; + s << "WHERE LedgerSeq = " << ledgerIndex; + std::tie (ledger, std::ignore, std::ignore) = + loadHelper (s.str ()); + } + + finishLoadByIndexOrHash (ledger); + return ledger; +} + +Ledger::pointer Ledger::loadByHash (uint256 const& ledgerHash) +{ + Ledger::pointer ledger; + { + std::ostringstream s; + s << "WHERE LedgerHash = '" << ledgerHash << "'"; + std::tie (ledger, std::ignore, std::ignore) = + loadHelper (s.str ()); + } + + finishLoadByIndexOrHash (ledger); + + assert (!ledger || ledger->getHash () == ledgerHash); + + return ledger; } uint256 Ledger::getHashByIndex (std::uint32_t ledgerIndex) @@ -1007,14 +928,18 @@ uint256 Ledger::getHashByIndex (std::uint32_t ledgerIndex) std::string hash; { - auto db = getApp().getLedgerDB ().getDB (); - auto sl (getApp().getLedgerDB ().lock ()); + auto db = getApp().getLedgerDB ().checkoutDb (); - if (!db->executeSQL (sql) || !db->startIterRows ()) + boost::optional lh; + *db << sql, + soci::into (lh); + + if (!db->got_data () || !lh) return ret; - db->getStr ("LedgerHash", hash); - db->endIterRows (); + hash = *lh; + if (hash.empty ()) + return ret; } ret.SetHexExact (hash); @@ -1024,66 +949,26 @@ uint256 Ledger::getHashByIndex (std::uint32_t ledgerIndex) bool Ledger::getHashesByIndex ( std::uint32_t ledgerIndex, uint256& ledgerHash, uint256& parentHash) { -#ifndef NO_SQLITE3_PREPARE + auto db = getApp().getLedgerDB ().checkoutDb (); - auto& con = getApp().getLedgerDB (); - auto sl (con.lock ()); + boost::optional lhO, phO; + + *db << "SELECT LedgerHash,PrevHash FROM Ledgers " + "INDEXED BY SeqLedger Where LedgerSeq = :ls;", + soci::into (lhO), + soci::into (phO), + soci::use (ledgerIndex); - SqliteStatement pSt (con.getDB ()->getSqliteDB (), - "SELECT LedgerHash,PrevHash FROM Ledgers " - "INDEXED BY SeqLedger Where LedgerSeq = ?;"); - - pSt.bind (1, ledgerIndex); - - int ret = pSt.step (); - - if (pSt.isDone (ret)) + if (!lhO || !phO) { WriteLog (lsTRACE, Ledger) << "Don't have ledger " << ledgerIndex; return false; } - if (!pSt.isRow (ret)) - { - assert (false); - WriteLog (lsFATAL, Ledger) << "Unexpected statement result " << ret; - return false; - } - - ledgerHash.SetHexExact (pSt.peekString (0)); - parentHash.SetHexExact (pSt.peekString (1)); + ledgerHash.SetHexExact (*lhO); + parentHash.SetHexExact (*phO); return true; - -#else - - std::string sql = - "SELECT LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq='"; - sql.append (beast::lexicalCastThrow (ledgerIndex)); - sql.append ("';"); - - std::string hash, prevHash; - { - auto db = getApp().getLedgerDB ().getDB (); - auto sl (getApp().getLedgerDB ().lock ()); - - if (!db->executeSQL (sql) || !db->startIterRows ()) - return false; - - db->getStr ("LedgerHash", hash); - db->getStr ("PrevHash", prevHash); - db->endIterRows (); - } - - ledgerHash.SetHexExact (hash); - parentHash.SetHexExact (prevHash); - - assert (ledgerHash.isNonZero () && - (ledgerIndex == 0 || parentHash.isNonZero ()); - - return true; - -#endif } std::map< std::uint32_t, std::pair > @@ -1098,16 +983,29 @@ Ledger::getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq) sql.append (beast::lexicalCastThrow (maxSeq)); sql.append (";"); - auto& con = getApp().getLedgerDB (); - auto sl (con.lock ()); + auto db = getApp().getLedgerDB ().checkoutDb (); - SqliteStatement pSt (con.getDB ()->getSqliteDB (), sql); + std::uint64_t ls; + std::string lh; + boost::optional ph; + soci::statement st = + (db->prepare << sql, + soci::into (ls), + soci::into (lh), + soci::into (ph)); - while (pSt.isRow (pSt.step ())) + st.execute (); + while (st.fetch ()) { - std::pair& hashes = ret[pSt.getUInt32 (0)]; - hashes.first.SetHexExact (pSt.peekString (1)); - hashes.second.SetHexExact (pSt.peekString (2)); + std::pair& hashes = + ret[rangeCheckedCast(ls)]; + hashes.first.SetHexExact (lh); + hashes.second.SetHexExact (ph.value_or ("")); + if (!ph) + { + WriteLog (lsWARNING, Ledger) + << "Null prev hash for ledger seq: " << ls; + } } return ret; @@ -1117,7 +1015,39 @@ Ledger::pointer Ledger::getLastFullLedger () { try { - return getSQL ("SELECT * from Ledgers order by LedgerSeq desc limit 1;"); + Ledger::pointer ledger; + std::uint32_t ledgerSeq; + uint256 ledgerHash; + std::tie (ledger, ledgerSeq, ledgerHash) = + loadHelper ("order by LedgerSeq desc limit 1"); + + if (!ledger) + return ledger; + + ledger->setClosed (); + + if (getApp().getOPs ().haveLedger (ledgerSeq)) + { + ledger->setAccepted (); + ledger->setValidated (); + } + + if (ledger->getHash () != ledgerHash) + { + if (ShouldLog (lsERROR, Ledger)) + { + WriteLog (lsERROR, Ledger) << "Failed on ledger"; + Json::Value p; + addJson (p, {*ledger, LedgerFill::full}); + WriteLog (lsERROR, Ledger) << p; + } + + assert (false); + return Ledger::pointer (); + } + + WriteLog (lsTRACE, Ledger) << "Loaded ledger: " << ledgerHash; + return ledger; } catch (SHAMapMissingNode& sn) { diff --git a/src/ripple/app/ledger/Ledger.h b/src/ripple/app/ledger/Ledger.h index 655d22ea6..bf48e07a5 100644 --- a/src/ripple/app/ledger/Ledger.h +++ b/src/ripple/app/ledger/Ledger.h @@ -137,9 +137,6 @@ public: ~Ledger (); - static Ledger::pointer getSQL (std::string const& sqlStatement); - static Ledger::pointer getSQL1 (SqliteStatement*); - static void getSQL2 (Ledger::ref); static Ledger::pointer getLastFullLedger (); static std::uint32_t roundCloseTime ( std::uint32_t closeTime, std::uint32_t closeResolution); diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index c582b811c..77d363c1d 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -713,13 +713,16 @@ public: exitWithCode(3); } - getApp().getLedgerDB ().getDB ()->executeSQL (boost::str (boost::format ("PRAGMA cache_size=-%d;") % - (getConfig ().getSize (siLgrDBCache) * 1024))); - getApp().getTxnDB ().getDB ()->executeSQL (boost::str (boost::format ("PRAGMA cache_size=-%d;") % - (getConfig ().getSize (siTxnDBCache) * 1024))); + getApp ().getLedgerDB ().getSession () + << boost::str (boost::format ("PRAGMA cache_size=-%d;") % + (getConfig ().getSize (siLgrDBCache) * 1024)); - mTxnDB->getDB ()->setupCheckpointing (m_jobQueue.get()); - mLedgerDB->getDB ()->setupCheckpointing (m_jobQueue.get()); + getApp().getTxnDB ().getSession () + << boost::str (boost::format ("PRAGMA cache_size=-%d;") % + (getConfig ().getSize (siTxnDBCache) * 1024)); + + mTxnDB->setupCheckpointing (m_jobQueue.get()); + mLedgerDB->setupCheckpointing (m_jobQueue.get()); if (!getConfig ().RUN_STANDALONE) updateTables (); @@ -1350,15 +1353,19 @@ bool serverOkay (std::string& reason) static std::vector getSchema (DatabaseCon& dbc, std::string const& dbName) { std::vector schema; + schema.reserve(32); std::string sql = "SELECT sql FROM sqlite_master WHERE tbl_name='"; sql += dbName; sql += "';"; - SQL_FOREACH (dbc.getDB (), sql) + std::string r; + soci::statement st = (dbc.getSession ().prepare << sql, + soci::into(r)); + st.execute (); + while (st.fetch ()) { - dbc.getDB ()->getStr ("sql", sql); - schema.push_back (sql); + schema.emplace_back (r); } return schema; @@ -1384,7 +1391,7 @@ static void addTxnSeqField () WriteLog (lsWARNING, Application) << "Transaction sequence field is missing"; - auto db = getApp().getTxnDB ().getDB (); + auto& session = getApp().getTxnDB ().getSession (); std::vector< std::pair > txIDs; txIDs.reserve (300000); @@ -1392,32 +1399,37 @@ static void addTxnSeqField () WriteLog (lsINFO, Application) << "Parsing transactions"; int i = 0; uint256 transID; - SQL_FOREACH (db, "SELECT TransID,TxnMeta FROM Transactions;") + + boost::optional strTransId; + soci::blob sociTxnMetaBlob(session); + soci::indicator tmi; + Blob txnMeta; + + soci::statement st = + (session.prepare << + "SELECT TransID, TxnMeta FROM Transactions;", + soci::into(strTransId), + soci::into(sociTxnMetaBlob, tmi)); + + st.execute (); + while (st.fetch ()) { - Blob rawMeta; - int metaSize = 2048; - rawMeta.resize (metaSize); - metaSize = db->getBinary ("TxnMeta", &*rawMeta.begin (), rawMeta.size ()); + if (soci::i_ok == tmi) + convert (sociTxnMetaBlob, txnMeta); + else + txnMeta.clear (); - if (metaSize > static_cast (rawMeta.size ())) - { - rawMeta.resize (metaSize); - db->getBinary ("TxnMeta", &*rawMeta.begin (), rawMeta.size ()); - } - else rawMeta.resize (metaSize); - - std::string tid; - db->getStr ("TransID", tid); + std::string tid = strTransId.value_or(""); transID.SetHex (tid, true); - if (rawMeta.size () == 0) + if (txnMeta.size () == 0) { txIDs.push_back (std::make_pair (transID, -1)); WriteLog (lsINFO, Application) << "No metadata for " << transID; } else { - TransactionMetaSet m (transID, 0, rawMeta); + TransactionMetaSet m (transID, 0, txnMeta); txIDs.push_back (std::make_pair (transID, m.getIndex ())); } @@ -1429,19 +1441,19 @@ static void addTxnSeqField () WriteLog (lsINFO, Application) << "All " << i << " transactions read"; - db->executeSQL ("BEGIN TRANSACTION;"); + soci::transaction tr(session); WriteLog (lsINFO, Application) << "Dropping old index"; - db->executeSQL ("DROP INDEX AcctTxIndex;"); + session << "DROP INDEX AcctTxIndex;"; WriteLog (lsINFO, Application) << "Altering table"; - db->executeSQL ("ALTER TABLE AccountTransactions ADD COLUMN TxnSeq INTEGER;"); + session << "ALTER TABLE AccountTransactions ADD COLUMN TxnSeq INTEGER;"; boost::format fmt ("UPDATE AccountTransactions SET TxnSeq = %d WHERE TransID = '%s';"); i = 0; for (auto& t : txIDs) { - db->executeSQL (boost::str (fmt % t.second % to_string (t.first))); + session << boost::str (fmt % t.second % to_string (t.first)); if ((++i % 1000) == 0) { @@ -1450,8 +1462,9 @@ static void addTxnSeqField () } WriteLog (lsINFO, Application) << "Building new index"; - db->executeSQL ("CREATE INDEX AcctTxIndex ON AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);"); - db->executeSQL ("END TRANSACTION;"); + session << "CREATE INDEX AcctTxIndex ON AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);"; + + tr.commit (); } void ApplicationImp::updateTables () diff --git a/src/ripple/app/main/LocalCredentials.cpp b/src/ripple/app/main/LocalCredentials.cpp index be24ea883..2a9b88262 100644 --- a/src/ripple/app/main/LocalCredentials.cpp +++ b/src/ripple/app/main/LocalCredentials.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace ripple { @@ -53,21 +54,21 @@ void LocalCredentials::start () // Retrieve network identity. bool LocalCredentials::nodeIdentityLoad () { - auto db = getApp().getWalletDB ().getDB (); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); bool bSuccess = false; - if (db->executeSQL ("SELECT * FROM NodeIdentity;") && db->startIterRows ()) + boost::optional pubKO, priKO; + soci::statement st = (db->prepare << + "SELECT PublicKey, PrivateKey " + "FROM NodeIdentity;", + soci::into(pubKO), + soci::into(priKO)); + st.execute (); + while (st.fetch ()) { - std::string strPublicKey, strPrivateKey; + mNodePublicKey.setNodePublic (pubKO.value_or("")); + mNodePrivateKey.setNodePrivate (priKO.value_or("")); - db->getStr ("PublicKey", strPublicKey); - db->getStr ("PrivateKey", strPrivateKey); - - mNodePublicKey.setNodePublic (strPublicKey); - mNodePrivateKey.setNodePrivate (strPrivateKey); - - db->endIterRows (); bSuccess = true; } @@ -101,15 +102,13 @@ bool LocalCredentials::nodeIdentityCreate () // // Store the node information // - auto db = getApp().getWalletDB ().getDB (); + auto db = getApp().getWalletDB ().checkoutDb (); - auto sl (getApp().getWalletDB ().lock ()); - db->executeSQL (str (boost::format ("INSERT INTO NodeIdentity (PublicKey,PrivateKey,Dh512,Dh1024) VALUES ('%s','%s',%s,%s);") + *db << str (boost::format ("INSERT INTO NodeIdentity (PublicKey,PrivateKey,Dh512,Dh1024) VALUES ('%s','%s',%s,%s);") % naNodePublic.humanNodePublic () % naNodePrivate.humanNodePrivate () % sqlEscape (strDh512) - % sqlEscape (strDh1024))); - // XXX Check error result. + % sqlEscape (strDh1024)); if (!getConfig ().QUIET) std::cerr << "NodeIdentity: Created." << std::endl; @@ -119,30 +118,28 @@ bool LocalCredentials::nodeIdentityCreate () bool LocalCredentials::dataDelete (std::string const& strKey) { - auto db = getApp().getRpcDB ().getDB (); + auto db = getApp().getRpcDB ().checkoutDb (); - auto sl (getApp().getRpcDB ().lock ()); - - return db->executeSQL (str (boost::format ("DELETE FROM RPCData WHERE Key=%s;") - % sqlEscape (strKey))); + *db << (str (boost::format ("DELETE FROM RPCData WHERE Key=%s;") + % sqlEscape (strKey))); + return true; } bool LocalCredentials::dataFetch (std::string const& strKey, std::string& strValue) { - auto db = getApp().getRpcDB ().getDB (); - - auto sl (getApp().getRpcDB ().lock ()); + auto db = getApp().getRpcDB ().checkoutDb (); bool bSuccess = false; - if (db->executeSQL (str (boost::format ("SELECT Value FROM RPCData WHERE Key=%s;") - % sqlEscape (strKey))) && db->startIterRows ()) + soci::blob value (*db); + soci::indicator vi; + *db << str (boost::format ("SELECT Value FROM RPCData WHERE Key=%s;") + % sqlEscape (strKey)), + soci::into(value, vi); + + if (soci::i_ok == vi) { - Blob vucData = db->getBinary ("Value"); - strValue.assign (vucData.begin (), vucData.end ()); - - db->endIterRows (); - + convert (value, strValue); bSuccess = true; } @@ -151,14 +148,12 @@ bool LocalCredentials::dataFetch (std::string const& strKey, std::string& strVal bool LocalCredentials::dataStore (std::string const& strKey, std::string const& strValue) { - auto db = getApp().getRpcDB ().getDB (); + auto db = getApp().getRpcDB ().checkoutDb (); - auto sl (getApp().getRpcDB ().lock ()); - - return (db->executeSQL (str (boost::format ("REPLACE INTO RPCData (Key, Value) VALUES (%s,%s);") - % sqlEscape (strKey) - % sqlEscape (strValue) - ))); + *db << (str (boost::format ("REPLACE INTO RPCData (Key, Value) VALUES (%s,%s);") + % sqlEscape (strKey) + % sqlEscape (strValue))); + return true; } } // ripple diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp index 9650d90f2..d9f2ce79f 100644 --- a/src/ripple/app/main/Main.cpp +++ b/src/ripple/app/main/Main.cpp @@ -163,11 +163,11 @@ static void setupConfigForUnitTests (Config& config) { - config->overwrite (ConfigSection::nodeDatabase (), "type", "memory"); - config->overwrite (ConfigSection::nodeDatabase (), "path", "main"); + config.overwrite (ConfigSection::nodeDatabase (), "type", "memory"); + config.overwrite (ConfigSection::nodeDatabase (), "path", "main"); - config->deprecatedClearSection (ConfigSection::tempNodeDatabase ()); - config->deprecatedClearSection (ConfigSection::importNodeDatabase ()); + config.deprecatedClearSection (ConfigSection::tempNodeDatabase ()); + config.deprecatedClearSection (ConfigSection::importNodeDatabase ()); config.legacy("database_path", "DummyForUnitTests"); } diff --git a/src/ripple/app/misc/AmendmentTableImpl.cpp b/src/ripple/app/misc/AmendmentTableImpl.cpp index 4119f4ae7..c46d70337 100644 --- a/src/ripple/app/misc/AmendmentTableImpl.cpp +++ b/src/ripple/app/misc/AmendmentTableImpl.cpp @@ -693,15 +693,17 @@ void AppApiFacadeImpl::setMajorityTimesFromDBToState ( query.append (to_string (amendmentHash)); query.append ("';"); - auto& walletDB (getApp ().getWalletDB ()); - auto sl (walletDB.lock ()); - auto db (walletDB.getDB ()); + auto db (getApp ().getWalletDB ().checkoutDb ()); - if (db->executeSQL (query) && db->startIterRows ()) + boost::optional fm, lm; + soci::statement st = (db->prepare << query, + soci::into(fm), + soci::into(lm)); + st.execute (); + while (st.fetch ()) { - toUpdate.m_firstMajority = db->getBigInt ("FirstMajority"); - toUpdate.m_lastMajority = db->getBigInt ("LastMajority"); - db->endIterRows (); + toUpdate.m_firstMajority = fm.value_or (0); + toUpdate.m_lastMajority = lm.value_or (0); } } @@ -712,24 +714,22 @@ void AppApiFacadeImpl::setMajorityTimesFromStateToDB ( if (changedAmendments.empty ()) return; - auto& walletDB (getApp ().getWalletDB ()); - auto sl (walletDB.lock ()); - auto db (walletDB.getDB ()); + auto db (getApp ().getWalletDB ().checkoutDb ()); - db->executeSQL ("BEGIN TRANSACTION;"); + soci::transaction tr(*db); + for (auto const& hash : changedAmendments) { AmendmentState const& fState = amendmentMap[hash]; - db->executeSQL (boost::str (boost::format ( - "UPDATE Features SET FirstMajority " - "= %d WHERE Hash = '%s';") % - fState.m_firstMajority % to_string (hash))); - db->executeSQL (boost::str (boost::format ( - "UPDATE Features SET LastMajority " - "= %d WHERE Hash = '%s';") % - fState.m_lastMajority % to_string (hash))); + *db << boost::str (boost::format ("UPDATE Features SET FirstMajority " + "= %d WHERE Hash = '%s';") % + fState.m_firstMajority % to_string (hash)); + *db << boost::str (boost::format ("UPDATE Features SET LastMajority " + "= %d WHERE Hash = '%s';") % + fState.m_lastMajority % to_string (hash)); } - db->executeSQL ("END TRANSACTION;"); + + tr.commit (); } ValidationSet AppApiFacadeImpl::getValidations (uint256 const& hash) const diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index 08c64a805..11a8a23c0 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -60,6 +60,7 @@ #include #include #include // +#include #include namespace ripple { @@ -1933,32 +1934,42 @@ NetworkOPs::AccountTxs NetworkOPsImp::getAccountTxs ( minLedger, maxLedger, descending, offset, limit, false, false, bAdmin); { - auto db = getApp().getTxnDB ().getDB (); - auto sl (getApp().getTxnDB ().lock ()); + auto db = getApp().getTxnDB ().checkoutDb (); - SQL_FOREACH (db, sql) + boost::optional ledgerSeq; + boost::optional status; + soci::blob sociTxnBlob (*db), sociTxnMetaBlob (*db); + soci::indicator rti, tmi; + Blob rawTxn, txnMeta; + + soci::statement st = + (db->prepare << sql, + soci::into(ledgerSeq), + soci::into(status), + soci::into(sociTxnBlob, rti), + soci::into(sociTxnMetaBlob, tmi)); + + st.execute (); + while (st.fetch ()) { - auto txn = Transaction::transactionFromSQL (db, Validate::NO); - - Serializer rawMeta; - int metaSize = 2048; - rawMeta.resize (metaSize); - metaSize = db->getBinary ( - "TxnMeta", &*rawMeta.begin (), rawMeta.getLength ()); - - if (metaSize > rawMeta.getLength ()) - { - rawMeta.resize (metaSize); - db->getBinary ( - "TxnMeta", &*rawMeta.begin (), rawMeta.getLength ()); - } + if (soci::i_ok == rti) + convert(sociTxnBlob, rawTxn); else - rawMeta.resize (metaSize); + rawTxn.clear (); - if (rawMeta.getLength() == 0) + if (soci::i_ok == tmi) + convert (sociTxnMetaBlob, txnMeta); + else + txnMeta.clear (); + + auto txn = Transaction::transactionFromSQL ( + ledgerSeq, status, rawTxn, Validate::NO); + + + if (txnMeta.empty ()) { // Work around a bug that could leave the metadata missing - auto seq = static_cast( - db->getBigInt("LedgerSeq")); + auto const seq = rangeCheckedCast( + ledgerSeq.value_or (0)); m_journal.warning << "Recovering ledger " << seq << ", txn " << txn->getID(); Ledger::pointer ledger = getLedgerBySeq(seq); @@ -1967,7 +1978,7 @@ NetworkOPs::AccountTxs NetworkOPsImp::getAccountTxs ( } ret.emplace_back (txn, std::make_shared ( - txn->getID (), txn->getLedger (), rawMeta.getData ())); + txn->getID (), txn->getLedger (), txnMeta)); } } @@ -1988,37 +1999,35 @@ std::vector NetworkOPsImp::getAccountTxsB ( bAdmin); { - auto db = getApp().getTxnDB ().getDB (); - auto sl (getApp().getTxnDB ().lock ()); + auto db = getApp().getTxnDB ().checkoutDb (); - SQL_FOREACH (db, sql) + boost::optional ledgerSeq; + boost::optional status; + soci::blob sociTxnBlob (*db), sociTxnMetaBlob (*db); + soci::indicator rti, tmi; + + soci::statement st = + (db->prepare << sql, + soci::into(ledgerSeq), + soci::into(status), + soci::into(sociTxnBlob, rti), + soci::into(sociTxnMetaBlob, tmi)); + + st.execute (); + while (st.fetch ()) { - int txnSize = 2048; - Blob rawTxn (txnSize); - txnSize = db->getBinary ("RawTxn", &rawTxn[0], rawTxn.size ()); + Blob rawTxn; + if (soci::i_ok == rti) + convert (sociTxnBlob, rawTxn); + Blob txnMeta; + if (soci::i_ok == tmi) + convert (sociTxnMetaBlob, txnMeta); - if (txnSize > rawTxn.size ()) - { - rawTxn.resize (txnSize); - db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.size ()); - } - else - rawTxn.resize (txnSize); - - int metaSize = 2048; - Blob rawMeta (metaSize); - metaSize = db->getBinary ("TxnMeta", &rawMeta[0], rawMeta.size ()); - - if (metaSize > rawMeta.size ()) - { - rawMeta.resize (metaSize); - db->getBinary ("TxnMeta", &*rawMeta.begin (), rawMeta.size ()); - } - else - rawMeta.resize (metaSize); + auto const seq = + rangeCheckedCast(ledgerSeq.value_or (0)); ret.emplace_back ( - strHex (rawTxn), strHex (rawMeta), db->getInt ("LedgerSeq")); + strHex (rawTxn), strHex (txnMeta), seq); } } @@ -2085,51 +2094,63 @@ NetworkOPsImp::AccountTxs NetworkOPsImp::getTxsAccount ( % (forward ? "ASC" : "DESC") % queryLimit); { - auto db = getApp().getTxnDB ().getDB (); - auto sl (getApp().getTxnDB ().lock ()); + auto db = getApp().getTxnDB ().checkoutDb (); - SQL_FOREACH (db, sql) + boost::optional ledgerSeq64; + boost::optional txnSeq; + boost::optional status; + soci::blob sociTxnBlob (*db), sociTxnMetaBlob (*db); + soci::indicator rti, tmi; + Blob rawTxn, txnMeta; + + soci::statement st = + (db->prepare << sql, + soci::into(ledgerSeq64), + soci::into(txnSeq), + soci::into(status), + soci::into(sociTxnBlob, rti), + soci::into(sociTxnMetaBlob, tmi)); + + st.execute (); + while (st.fetch ()) { + if (soci::i_ok == rti) + convert(sociTxnBlob, rawTxn); + else + rawTxn.clear (); + + if (soci::i_ok == tmi) + convert (sociTxnMetaBlob, txnMeta); + else + txnMeta.clear (); + + auto const ledgerSeq = rangeCheckedCast( + ledgerSeq64.value_or (0)); + if (!foundResume) { - foundResume = (findLedger == db->getInt("LedgerSeq") && - findSeq == db->getInt("TxnSeq")); + foundResume = (findLedger == ledgerSeq && + findSeq == txnSeq.value_or (0)); } else if (numberOfResults == 0) { token = Json::objectValue; - token[jss::ledger] = db->getInt("LedgerSeq"); - token[jss::seq] = db->getInt("TxnSeq"); + token[jss::ledger] = ledgerSeq; + token[jss::seq] = txnSeq.value_or (0); break; } if (foundResume) { - auto txn = Transaction::transactionFromSQL (db, Validate::NO); + auto txn = Transaction::transactionFromSQL ( + ledgerSeq64, status, rawTxn, Validate::NO); - Serializer rawMeta; - int metaSize = 2048; - rawMeta.resize (metaSize); - metaSize = db->getBinary ( - "TxnMeta", &*rawMeta.begin (), rawMeta.getLength ()); - - if (metaSize > rawMeta.getLength ()) - { - rawMeta.resize (metaSize); - db->getBinary ( - "TxnMeta", &*rawMeta.begin (), rawMeta.getLength ()); - } - else - rawMeta.resize (metaSize); - - if (rawMeta.getLength() == 0) + if (txnMeta.empty ()) { // Work around a bug that could leave the metadata missing - auto seq = static_cast( - db->getBigInt("LedgerSeq")); - m_journal.warning << "Recovering ledger " << seq + m_journal.warning << "Recovering ledger " << ledgerSeq << ", txn " << txn->getID(); - Ledger::pointer ledger = getLedgerBySeq(seq); + Ledger::pointer ledger = getLedgerBySeq(ledgerSeq); if (ledger) ledger->pendSaveValidated(false, false); } @@ -2138,7 +2159,7 @@ NetworkOPsImp::AccountTxs NetworkOPsImp::getTxsAccount ( ret.emplace_back (std::move (txn), std::make_shared ( - txn->getID (), txn->getLedger (), rawMeta.getData ())); + txn->getID (), txn->getLedger (), txnMeta)); } } } @@ -2203,15 +2224,30 @@ NetworkOPsImp::MetaTxsList NetworkOPsImp::getTxsAccountB ( % (forward ? "ASC" : "DESC") % queryLimit); { - auto db = getApp().getTxnDB ().getDB (); - auto sl (getApp().getTxnDB ().lock ()); + auto db = getApp().getTxnDB ().checkoutDb (); - SQL_FOREACH (db, sql) + boost::optional ledgerSeq; + boost::optional txnSeq; + boost::optional status; + soci::blob sociTxnBlob (*db); + soci::indicator rtI; + soci::blob sociTxnMetaBlob (*db); + soci::indicator tmI; + + soci::statement st = (db->prepare << sql, + soci::into (ledgerSeq), + soci::into (txnSeq), + soci::into (status), + soci::into (sociTxnBlob, rtI), + soci::into (sociTxnMetaBlob, tmI)); + + st.execute (); + while (st.fetch ()) { if (!foundResume) { - if (findLedger == db->getInt("LedgerSeq") && - findSeq == db->getInt("TxnSeq")) + if (findLedger == ledgerSeq.value_or (0) && + findSeq == txnSeq.value_or (0)) { foundResume = true; } @@ -2219,43 +2255,25 @@ NetworkOPsImp::MetaTxsList NetworkOPsImp::getTxsAccountB ( else if (numberOfResults == 0) { token = Json::objectValue; - token[jss::ledger] = db->getInt("LedgerSeq"); - token[jss::seq] = db->getInt("TxnSeq"); + token[jss::ledger] = rangeCheckedCast( + ledgerSeq.value_or(0)); + token[jss::seq] = txnSeq.value_or(0); break; } if (foundResume) { - int txnSize = 2048; - Blob rawTxn (txnSize); - txnSize = db->getBinary ("RawTxn", &rawTxn[0], rawTxn.size ()); + Blob rawTxn; + if (soci::i_ok == rtI) + convert (sociTxnBlob, rawTxn); + Blob txnMeta; + if (soci::i_ok == tmI) + convert (sociTxnMetaBlob, txnMeta); - if (txnSize > rawTxn.size ()) - { - rawTxn.resize (txnSize); - db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.size ()); - } - else - rawTxn.resize (txnSize); - - int metaSize = 2048; - Blob rawMeta (metaSize); - metaSize = db->getBinary ( - "TxnMeta", &rawMeta[0], rawMeta.size ()); - - if (metaSize > rawMeta.size ()) - { - rawMeta.resize (metaSize); - db->getBinary ( - "TxnMeta", &*rawMeta.begin (), rawMeta.size ()); - } - else - { - rawMeta.resize (metaSize); - } - - ret.emplace_back (strHex (rawTxn), strHex (rawMeta), - db->getInt ("LedgerSeq")); + ret.emplace_back ( + strHex (rawTxn.begin (), rawTxn.size ()), + strHex (txnMeta.begin (), txnMeta.size ()), + rangeCheckedCast(ledgerSeq.value_or (0))); --numberOfResults; } } @@ -2275,11 +2293,20 @@ NetworkOPsImp::getLedgerAffectedAccounts (std::uint32_t ledgerSeq) % ledgerSeq); RippleAddress acct; { - auto db = getApp().getTxnDB ().getDB (); - auto sl (getApp().getTxnDB ().lock ()); - SQL_FOREACH (db, sql) + auto db = getApp().getTxnDB ().checkoutDb (); + soci::blob accountBlob(*db); + soci::indicator bi; + soci::statement st = (db->prepare << sql, soci::into(accountBlob, bi)); + st.execute (); + std::string accountStr; + while (st.fetch ()) { - if (acct.setAccountID (db->getStrBinary ("Account"))) + if (soci::i_ok == bi) + convert (accountBlob, accountStr); + else + accountStr.clear (); + + if (acct.setAccountID (accountStr)) accounts.push_back (acct); } } diff --git a/src/ripple/app/misc/SHAMapStoreImp.cpp b/src/ripple/app/misc/SHAMapStoreImp.cpp index c223771eb..2b1c1b563 100644 --- a/src/ripple/app/misc/SHAMapStoreImp.cpp +++ b/src/ripple/app/misc/SHAMapStoreImp.cpp @@ -26,6 +26,7 @@ #include #include // #include +#include namespace ripple { void SHAMapStoreImp::SavedStateDB::init (BasicConfig const& config, @@ -54,14 +55,14 @@ void SHAMapStoreImp::SavedStateDB::init (BasicConfig const& config, ; std::int64_t count = 0; - soci::statement st = (session_.prepare << - "SELECT COUNT(Key) FROM DbState WHERE Key = 1;" - , soci::into (count) - ); - st.execute (); - if (!st.fetch ()) { - throw std::runtime_error("Failed to fetch Key Count from DbState."); + boost::optional countO; + session_ << + "SELECT COUNT(Key) FROM DbState WHERE Key = 1;" + , soci::into (countO); + if (!countO) + throw std::runtime_error("Failed to fetch Key Count from DbState."); + count = *countO; } if (!count) @@ -70,14 +71,15 @@ void SHAMapStoreImp::SavedStateDB::init (BasicConfig const& config, "INSERT INTO DbState VALUES (1, '', '', 0);"; } - st = (session_.prepare << - "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;" - , soci::into (count) - ); - st.execute (); - if (!st.fetch ()) + { - throw std::runtime_error ("Failed to fetch Key Count from CanDelete."); + boost::optional countO; + session_ << + "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;" + , soci::into (countO); + if (!countO) + throw std::runtime_error("Failed to fetch Key Count from CanDelete."); + count = *countO; } if (!count) @@ -507,14 +509,16 @@ SHAMapStoreImp::clearSql (DatabaseCon& database, std::string const& deleteQuery) { LedgerIndex min = std::numeric_limits ::max(); - Database* db = database.getDB(); - std::unique_lock lock (database.peekMutex()); - if (!db->executeSQL (minQuery) || !db->startIterRows()) - return; - min = db->getBigInt (0); - db->endIterRows (); - lock.unlock(); + { + auto db = database.checkoutDb (); + boost::optional m; + *db << minQuery, soci::into(m); + if (!m) + return; + min = *m; + } + if (health() != Health::ok) return; @@ -526,9 +530,10 @@ SHAMapStoreImp::clearSql (DatabaseCon& database, { min = (min + setup_.deleteBatch >= lastRotated) ? lastRotated : min + setup_.deleteBatch; - lock.lock(); - db->executeSQL (boost::str (formattedDeleteQuery % min)); - lock.unlock(); + { + auto db = database.checkoutDb (); + *db << boost::str (formattedDeleteQuery % min); + } if (health()) return; if (min < lastRotated) diff --git a/src/ripple/app/misc/Validations.cpp b/src/ripple/app/misc/Validations.cpp index 05de97c7e..ab5c08809 100644 --- a/src/ripple/app/misc/Validations.cpp +++ b/src/ripple/app/misc/Validations.cpp @@ -443,21 +443,21 @@ private: { ScopedUnlockType sul (mLock); { - auto db = getApp().getLedgerDB ().getDB (); - auto dbl (getApp().getLedgerDB ().lock ()); + auto db = getApp().getLedgerDB ().checkoutDb (); Serializer s (1024); - db->executeSQL ("BEGIN TRANSACTION;"); + soci::transaction tr(*db); for (auto it: vector) { s.erase (); it->add (s); - db->executeSQL (boost::str ( + *db << boost::str ( insVal % to_string (it->getLedgerHash ()) % it->getSignerPublic ().humanNodePublic () % - it->getSignTime () % sqlEscape (s.peekData ()))); + it->getSignTime () % sqlEscape (s.peekData ())); } - db->executeSQL ("END TRANSACTION;"); + + tr.commit (); } } } diff --git a/src/ripple/app/peers/UniqueNodeList.cpp b/src/ripple/app/peers/UniqueNodeList.cpp index 1dc516f25..214b01014 100644 --- a/src/ripple/app/peers/UniqueNodeList.cpp +++ b/src/ripple/app/peers/UniqueNodeList.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include namespace ripple { @@ -89,6 +90,73 @@ strJoin (Iterator first, Iterator last, std::string strSeperator) return ossValues.str (); } +template +void selectBlobsIntoStrings ( + soci::session& s, + String&& sql, + std::vector, I>>& columns) +{ + columns.clear (); + columns.reserve (32); + + std::vector blobs; + blobs.reserve (I); + for (int i = 0; i < I; ++i) + blobs.emplace_back (s); + std::array indicators; + std::string str; + soci::statement st = [&] + { + auto&& tmp = s.prepare << sql; + for (int i = 0; i < I; ++i) + tmp.operator, (soci::into (blobs[i], indicators[i])); + return tmp; + }(); + + st.execute (); + while (st.fetch ()) + { + columns.emplace_back (); + for (int i = 0; i < I; ++i) + { + if (soci::i_ok == indicators[i]) + { + convert (blobs[i], str); + columns.back ()[i] = str; + } + } + } +} + +template +void selectBlobsIntoStrings ( + soci::session& s, + String&& sql, + std::vector, boost::optional>>& columns) +{ + columns.clear (); + columns.reserve (32); + + soci::blob blob(s); + soci::indicator ind; + boost::optional other; + std::string str; + soci::statement st = + (s.prepare << sql, soci::into(blob, ind), soci::into(other)); + + st.execute (); + while (st.fetch ()) + { + columns.emplace_back (); + if (soci::i_ok == ind) + { + convert (blob, str); + get<0>(columns.back ()) = str; + } + get<1>(columns.back ()) = other; + } +} + // VFALCO TODO move all function definitions inlined into the class. class UniqueNodeListImp : public UniqueNodeList @@ -295,11 +363,14 @@ public: void nodeRemovePublic (RippleAddress const& naNodePublic) { { - auto db = getApp().getWalletDB ().getDB (); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - db->executeSQL (str (boost::format ("DELETE FROM SeedNodes WHERE PublicKey=%s") % sqlEscape (naNodePublic.humanNodePublic ()))); - db->executeSQL (str (boost::format ("DELETE FROM TrustedNodes WHERE PublicKey=%s") % sqlEscape (naNodePublic.humanNodePublic ()))); + *db << str ( + boost::format ("DELETE FROM SeedNodes WHERE PublicKey=%s") % + sqlEscape (naNodePublic.humanNodePublic ())); + *db << str ( + boost::format ("DELETE FROM TrustedNodes WHERE PublicKey=%s") % + sqlEscape (naNodePublic.humanNodePublic ())); } // YYY Only dirty on successful delete. @@ -317,10 +388,9 @@ public: boost::to_lower (strDomain); { - auto db = getApp().getWalletDB ().getDB (); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - db->executeSQL (str (boost::format ("DELETE FROM SeedDomains WHERE Domain=%s") % sqlEscape (strDomain))); + *db << str (boost::format ("DELETE FROM SeedDomains WHERE Domain=%s") % sqlEscape (strDomain)); } // YYY Only dirty on successful delete. @@ -332,13 +402,10 @@ public: void nodeReset () { { - auto db = getApp().getWalletDB ().getDB (); + auto db = getApp().getWalletDB ().checkoutDb (); - auto sl (getApp().getWalletDB ().lock ()); - - // XXX Check results. - db->executeSQL ("DELETE FROM SeedDomains"); - db->executeSQL ("DELETE FROM SeedNodes"); + *db << "DELETE FROM SeedDomains"; + *db << "DELETE FROM SeedNodes"; } fetchDirty (); @@ -606,17 +673,22 @@ public: Json::Value getUnlJson () { - auto db = getApp().getWalletDB ().getDB (); Json::Value ret (Json::arrayValue); - auto sl (getApp().getWalletDB ().lock ()); - SQL_FOREACH (db, "SELECT * FROM TrustedNodes;") + auto db = getApp().getWalletDB ().checkoutDb (); + + + std::vector, 2>> columns; + selectBlobsIntoStrings(*db, + "SELECT PublicKey, Comment FROM TrustedNodes;", + columns); + for(auto const& strArray : columns) { Json::Value node (Json::objectValue); - node["publicKey"] = db->getStrBinary ("PublicKey"); - node["comment"] = db->getStrBinary ("Comment"); + node["publicKey"] = strArray[0].value_or(""); + node["comment"] = strArray[1].value_or(""); ret.append (node); } @@ -673,22 +745,18 @@ private: // Load information about when we last updated. bool miscLoad () { - auto sl (getApp().getWalletDB ().lock ()); - auto db = getApp().getWalletDB ().getDB (); + auto db = getApp().getWalletDB ().checkoutDb (); - if (!db->executeSQL ("SELECT * FROM Misc WHERE Magic=1;")) + boost::optional suO, fuO; + + *db << "SELECT ScoreUpdated, FetchUpdated FROM Misc WHERE Magic=1;", + soci::into(suO), soci::into(fuO); + + if (!db->got_data() ) return false; - - bool const bAvail = db->startIterRows (); - - mtpFetchUpdated = ptFromSeconds (bAvail - ? db->getInt ("FetchUpdated") - : -1); - mtpScoreUpdated = ptFromSeconds (bAvail - ? db->getInt ("ScoreUpdated") - : -1); - - db->endIterRows (); + + mtpFetchUpdated = ptFromSeconds (fuO.value_or(-1)); + mtpScoreUpdated = ptFromSeconds (suO.value_or(-1)); trustedLoad (); @@ -700,12 +768,11 @@ private: // Persist update information. bool miscSave () { - auto db = getApp().getWalletDB ().getDB (); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - db->executeSQL (str (boost::format ("REPLACE INTO Misc (Magic,FetchUpdated,ScoreUpdated) VALUES (1,%d,%d);") - % iToSeconds (mtpFetchUpdated) - % iToSeconds (mtpScoreUpdated))); + *db << str (boost::format ("REPLACE INTO Misc (Magic,FetchUpdated,ScoreUpdated) VALUES (1,%d,%d);") + % iToSeconds (mtpFetchUpdated) + % iToSeconds (mtpScoreUpdated)); return true; } @@ -730,16 +797,18 @@ private: WriteLog (lsWARNING, UniqueNodeList) << "Entry in cluster list invalid: '" << c << "'"; } - auto db = getApp().getWalletDB ().getDB (); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); ScopedUNLLockType slUNL (mUNLLock); mUNL.clear (); - // XXX Needs to limit by quanity and quality. - SQL_FOREACH (db, "SELECT PublicKey FROM TrustedNodes WHERE Score != 0;") + std::vector, 1>> columns; + selectBlobsIntoStrings(*db, + "SELECT PublicKey FROM TrustedNodes WHERE Score != 0;", + columns); + for(auto const& strArray : columns) { - mUNL.insert (db->getStrBinary ("PublicKey")); + mUNL.insert (strArray[0].value_or("")); } } @@ -828,56 +897,58 @@ private: hash_map umDomainIdx; // Map of domain to index. std::vector vsnNodes; // Index to scoring node. - auto db = getApp().getWalletDB ().getDB (); - // For each entry in SeedDomains with a PublicKey: // - Add an entry in umPulicIdx, umDomainIdx, and vsnNodes. { - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - SQL_FOREACH (db, "SELECT Domain,PublicKey,Source FROM SeedDomains;") + std::vector, 3>> columns; + selectBlobsIntoStrings(*db, + "SELECT Domain,PublicKey,Source FROM SeedDomains;", + columns); + for(auto const& strArray : columns) { - if (db->getNull ("PublicKey")) - { + if (!strArray[1]) // We ignore entries we don't have public keys for. + continue; + + std::string const strDomain = strArray[0].value_or(""); + std::string const strPublicKey = *strArray[1]; + std::string const strSource = strArray[2].value_or(""); + + assert (!strSource.empty ()); + + int const iScore = iSourceScore (static_cast (strSource[0])); + auto siOld = umPulicIdx.find (strPublicKey); + + if (siOld == umPulicIdx.end ()) + { + // New node + int iNode = vsnNodes.size (); + + umPulicIdx[strPublicKey] = iNode; + umDomainIdx[strDomain] = iNode; + + scoreNode snCurrent; + + snCurrent.strValidator = strPublicKey; + snCurrent.iScore = iScore; + snCurrent.iRoundSeed = snCurrent.iScore; + snCurrent.iRoundScore = 0; + snCurrent.iSeen = -1; + + vsnNodes.push_back (snCurrent); } else { - std::string strDomain = db->getStrBinary ("Domain"); - std::string strPublicKey = db->getStrBinary ("PublicKey"); - std::string strSource = db->getStrBinary ("Source"); - int iScore = iSourceScore (static_cast (strSource[0])); - auto siOld = umPulicIdx.find (strPublicKey); + scoreNode& snOld = vsnNodes[siOld->second]; - if (siOld == umPulicIdx.end ()) + if (snOld.iScore < iScore) { - // New node - int iNode = vsnNodes.size (); + // Update old node - umPulicIdx[strPublicKey] = iNode; - umDomainIdx[strDomain] = iNode; - - scoreNode snCurrent; - - snCurrent.strValidator = strPublicKey; - snCurrent.iScore = iScore; - snCurrent.iRoundSeed = snCurrent.iScore; - snCurrent.iRoundScore = 0; - snCurrent.iSeen = -1; - - vsnNodes.push_back (snCurrent); - } - else - { - scoreNode& snOld = vsnNodes[siOld->second]; - - if (snOld.iScore < iScore) - { - // Update old node - - snOld.iScore = iScore; - snOld.iRoundSeed = snOld.iScore; - } + snOld.iScore = iScore; + snOld.iRoundSeed = snOld.iScore; } } } @@ -886,12 +957,17 @@ private: // For each entry in SeedNodes: // - Add an entry in umPulicIdx, umDomainIdx, and vsnNodes. { - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - SQL_FOREACH (db, "SELECT PublicKey,Source FROM SeedNodes;") + std::vector, 2>> columns; + selectBlobsIntoStrings(*db, + "SELECT PublicKey,Source FROM SeedNodes;", + columns); + for(auto const& strArray : columns) { - std::string strPublicKey = db->getStrBinary ("PublicKey"); - std::string strSource = db->getStrBinary ("Source"); + std::string strPublicKey = strArray[0].value_or(""); + std::string strSource = strArray[1].value_or(""); + assert (!strSource.empty ()); int iScore = iSourceScore (static_cast (strSource[0])); auto siOld = umPulicIdx.find (strPublicKey); @@ -950,12 +1026,20 @@ private: std::string& strValidator = sn.strValidator; std::vector& viReferrals = sn.viReferrals; - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - SQL_FOREACH (db, boost::str (boost::format ("SELECT Referral FROM ValidatorReferrals WHERE Validator=%s ORDER BY Entry;") - % sqlEscape (strValidator))) + std::vector, 1>> columns; + selectBlobsIntoStrings(*db, + boost::str (boost::format ( + "SELECT Referral FROM ValidatorReferrals " + "WHERE Validator=%s ORDER BY Entry;") % + sqlEscape (strValidator)), + columns); + std::string strReferral; + for(auto const& strArray : columns) { - std::string strReferral = db->getStrBinary ("Referral"); + strReferral = strArray[0].value_or(""); + int iReferral; RippleAddress na; @@ -1024,10 +1108,10 @@ private: } // Persist validator scores. - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - db->executeSQL ("BEGIN;"); - db->executeSQL ("UPDATE TrustedNodes SET Score = 0 WHERE Score != 0;"); + soci::transaction tr(*db); + *db << "UPDATE TrustedNodes SET Score = 0 WHERE Score != 0;"; if (!vsnNodes.empty ()) { @@ -1041,10 +1125,25 @@ private: vstrPublicKeys[iNode] = sqlEscape (vsnNodes[iNode].strValidator); } - SQL_FOREACH (db, str (boost::format ("SELECT PublicKey,Seen FROM TrustedNodes WHERE PublicKey IN (%s);") - % strJoin (vstrPublicKeys.begin (), vstrPublicKeys.end (), ","))) + // Iterate through the result rows with a fectch b/c putting a + // column of type DATETIME into a boost::tuple can throw when the + // datetime column is invalid (even if the value as int is valid). + std::vector, + boost::optional>> columns; + selectBlobsIntoStrings ( + *db, + str (boost::format ( + "SELECT PublicKey,Seen FROM TrustedNodes WHERE " + "PublicKey IN (%s);") % + strJoin ( + vstrPublicKeys.begin (), vstrPublicKeys.end (), ",")), + columns); + std::string pk; + for(auto const& col : columns) { - vsnNodes[umPulicIdx[db->getStrBinary ("PublicKey")]].iSeen = db->getNull ("Seen") ? -1 : db->getInt ("Seen"); + pk = get<0>(col).value_or (""); + + vsnNodes[umPulicIdx[pk]].iSeen = get<1>(col).value_or (-1); } } @@ -1070,8 +1169,8 @@ private: usUNL.insert (sn.strValidator); } - db->executeSQL (str (boost::format ("REPLACE INTO TrustedNodes (PublicKey,Score,Seen) VALUES %s;") - % strJoin (vstrValues.begin (), vstrValues.end (), ","))); + *db << str (boost::format ("REPLACE INTO TrustedNodes (PublicKey,Score,Seen) VALUES %s;") + % strJoin (vstrValues.begin (), vstrValues.end (), ",")); } { @@ -1085,12 +1184,17 @@ private: if (!vsnNodes.empty ()) { - std::vector vstrPublicKeys; - // For every IpReferral add a score for the IP and PORT. - SQL_FOREACH (db, "SELECT Validator,COUNT(*) AS Count FROM IpReferrals GROUP BY Validator;") + std::vector, + boost::optional>> columns; + selectBlobsIntoStrings ( + *db, + "SELECT Validator,COUNT(*) AS Count FROM " + "IpReferrals GROUP BY Validator;", + columns); + for(auto const& col : columns) { - umValidators[db->getStrBinary ("Validator")] = db->getInt ("Count"); + umValidators[get<0>(col).value_or("")] = get<1>(col).value_or(0); // WriteLog (lsTRACE, UniqueNodeList) << strValidator << ":" << db->getInt("Count"); } @@ -1114,15 +1218,23 @@ private: score iBase = iSeed * iEntries / iTotal; int iEntry = 0; - SQL_FOREACH (db, str (boost::format ("SELECT IP,Port FROM IpReferrals WHERE Validator=%s ORDER BY Entry;") - % sqlEscape (strValidator))) + std::vector, + boost::optional>> columns; + selectBlobsIntoStrings ( + *db, + str (boost::format ( + "SELECT IP,Port FROM IpReferrals WHERE " + "Validator=%s ORDER BY Entry;") % + sqlEscape (strValidator)), + columns); + for(auto const& col : columns) { score iPoints = iBase * (iEntries - iEntry) / iEntries; int iPort; - iPort = db->getNull ("Port") ? -1 : db->getInt ("Port"); + iPort = get<1>(col).value_or(0); - std::pair< std::string, int> ep = std::make_pair (db->getStrBinary ("IP"), iPort); + std::pair< std::string, int> ep = std::make_pair (get<0>(col).value_or(""), iPort); auto itEp = umScore.find (ep); @@ -1132,7 +1244,7 @@ private: } } - db->executeSQL ("COMMIT;"); + tr.commit (); } //-------------------------------------------------------------------------- @@ -1305,20 +1417,28 @@ private: boost::posix_time::ptime tpNext (boost::posix_time::min_date_time); boost::posix_time::ptime tpNow (boost::posix_time::second_clock::universal_time ()); - auto sl (getApp().getWalletDB ().lock ()); - auto db = getApp().getWalletDB ().getDB (); + auto db = getApp().getWalletDB ().checkoutDb (); + - if (db->executeSQL ("SELECT Domain,Next FROM SeedDomains INDEXED BY SeedDomainNext ORDER BY Next LIMIT 1;") - && db->startIterRows ()) { - int iNext (db->getInt ("Next")); + soci::blob b(*db); + soci::indicator ind; + boost::optional nO; + *db << "SELECT Domain,Next FROM SeedDomains INDEXED BY SeedDomainNext ORDER BY Next LIMIT 1;", + soci::into(b, ind), + soci::into(nO); + if (nO) + { + int iNext (*nO); - tpNext = ptFromSeconds (iNext); + tpNext = ptFromSeconds (iNext); - WriteLog (lsTRACE, UniqueNodeList) << str (boost::format ("fetchNext: iNext=%s tpNext=%s tpNow=%s") % iNext % tpNext % tpNow); - strDomain = db->getStrBinary ("Domain"); - - db->endIterRows (); + WriteLog (lsTRACE, UniqueNodeList) << str (boost::format ("fetchNext: iNext=%s tpNext=%s tpNow=%s") % iNext % tpNext % tpNow); + if (soci::i_ok == ind) + convert (b, strDomain); + else + strDomain.clear (); + } } if (!strDomain.empty ()) @@ -1557,8 +1677,6 @@ private: // --> naNodePublic: public key of the validating node. void processIps (std::string const& strSite, RippleAddress const& naNodePublic, IniFileSections::mapped_type* pmtVecStrIps) { - auto db = getApp().getWalletDB ().getDB (); - std::string strEscNodePublic = sqlEscape (naNodePublic.humanNodePublic ()); WriteLog (lsDEBUG, UniqueNodeList) @@ -1567,9 +1685,8 @@ private: // Remove all current Validator's entries in IpReferrals { - auto sl (getApp().getWalletDB ().lock ()); - db->executeSQL (str (boost::format ("DELETE FROM IpReferrals WHERE Validator=%s;") % strEscNodePublic)); - // XXX Check result. + auto db = getApp().getWalletDB ().checkoutDb (); + *db << str (boost::format ("DELETE FROM IpReferrals WHERE Validator=%s;") % strEscNodePublic); } // Add new referral entries. @@ -1610,9 +1727,9 @@ private: { vstrValues.resize (iValues); - auto sl (getApp().getWalletDB ().lock ()); - db->executeSQL (str (boost::format ("INSERT INTO IpReferrals (Validator,Entry,IP,Port) VALUES %s;") - % strJoin (vstrValues.begin (), vstrValues.end (), ","))); + auto db = getApp().getWalletDB ().checkoutDb (); + *db << str (boost::format ("INSERT INTO IpReferrals (Validator,Entry,IP,Port) VALUES %s;") + % strJoin (vstrValues.begin (), vstrValues.end (), ",")); // XXX Check result. } } @@ -1629,7 +1746,6 @@ private: // --> vsWhy: reason for adding validator to SeedDomains or SeedNodes. int processValidators (std::string const& strSite, std::string const& strValidatorsSrc, RippleAddress const& naNodePublic, ValidatorSource vsWhy, IniFileSections::mapped_type* pmtVecStrValidators) { - auto db = getApp().getWalletDB ().getDB (); std::string strNodePublic = naNodePublic.isValid () ? naNodePublic.humanNodePublic () : strValidatorsSrc; int iValues = 0; @@ -1641,9 +1757,9 @@ private: // Remove all current Validator's entries in ValidatorReferrals { - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - db->executeSQL (str (boost::format ("DELETE FROM ValidatorReferrals WHERE Validator='%s';") % strNodePublic)); + *db << str (boost::format ("DELETE FROM ValidatorReferrals WHERE Validator='%s';") % strNodePublic); // XXX Check result. } @@ -1712,9 +1828,9 @@ private: std::string strSql = str (boost::format ("INSERT INTO ValidatorReferrals (Validator,Entry,Referral) VALUES %s;") % strJoin (vstrValues.begin (), vstrValues.end (), ",")); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - db->executeSQL (strSql); + *db << strSql; // XXX Check result. } } @@ -1759,57 +1875,79 @@ private: // Retrieve a SeedDomain from DB. bool getSeedDomains (std::string const& strDomain, seedDomain& dstSeedDomain) { - bool bResult; - auto db = getApp().getWalletDB ().getDB (); + bool bResult = false; - std::string strSql = boost::str (boost::format ("SELECT * FROM SeedDomains WHERE Domain=%s;") - % sqlEscape (strDomain)); + std::string strSql = boost::str ( + boost::format ( + "SELECT Domain, PublicKey, Source, Next, Scan, Fetch, Sha256, " + "Comment FROM SeedDomains WHERE Domain=%s;") % + sqlEscape (strDomain)); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - bResult = db->executeSQL (strSql) && db->startIterRows (); + // Iterate through the result rows with a fectch b/c putting a + // column of type DATETIME into a boost::tuple can throw when the + // datetime column is invalid (even if the value as int is valid). + soci::blob domainBlob(*db); + soci::indicator di; + boost::optional strPublicKey; + soci:: blob sourceBlob(*db); + soci::indicator si; + std::string strSource; + boost::optional iNext; + boost::optional iScan; + boost::optional iFetch; + boost::optional strSha256; + soci::blob commentBlob(*db); + soci::indicator ci; + boost::optional strComment; - if (bResult) + soci::statement st = (db->prepare << strSql, + soci::into (domainBlob, di), + soci::into (strPublicKey), + soci::into (sourceBlob, si), + soci::into (iNext), + soci::into (iScan), + soci::into (iFetch), + soci::into (strSha256), + soci::into (commentBlob, ci)); + + st.execute (); + while (st.fetch ()) { - std::string strPublicKey; - int iNext; - int iScan; - int iFetch; - std::string strSha256; + bResult = true; - dstSeedDomain.strDomain = db->getStrBinary ("Domain"); + if (soci::i_ok == di) + convert (domainBlob, dstSeedDomain.strDomain); - if (!db->getNull ("PublicKey") && db->getStr ("PublicKey", strPublicKey)) - { - dstSeedDomain.naPublicKey.setNodePublic (strPublicKey); - } + if (strPublicKey && !strPublicKey->empty ()) + dstSeedDomain.naPublicKey.setNodePublic (*strPublicKey); else - { dstSeedDomain.naPublicKey.clear (); - } - std::string strSource = db->getStrBinary ("Source"); - dstSeedDomain.vsSource = static_cast (strSource[0]); - - iNext = db->getInt ("Next"); - dstSeedDomain.tpNext = ptFromSeconds (iNext); - iScan = db->getInt ("Scan"); - dstSeedDomain.tpScan = ptFromSeconds (iScan); - iFetch = db->getInt ("Fetch"); - dstSeedDomain.tpFetch = ptFromSeconds (iFetch); - - if (!db->getNull ("Sha256") && db->getStr ("Sha256", strSha256)) + if (soci::i_ok == si) { - dstSeedDomain.iSha256.SetHex (strSha256); + convert (sourceBlob, strSource); + dstSeedDomain.vsSource = static_cast (strSource[0]); } else { - dstSeedDomain.iSha256.zero (); + assert (0); } - dstSeedDomain.strComment = db->getStrBinary ("Comment"); + dstSeedDomain.tpNext = ptFromSeconds (iNext.value_or (0)); + dstSeedDomain.tpScan = ptFromSeconds (iScan.value_or (0)); + dstSeedDomain.tpFetch = ptFromSeconds (iFetch.value_or (0)); - db->endIterRows (); + if (strSha256 && !strSha256->empty ()) + dstSeedDomain.iSha256.SetHex (*strSha256); + else + dstSeedDomain.iSha256.zero (); + + if (soci::i_ok == ci) + convert (commentBlob, dstSeedDomain.strComment); + else + dstSeedDomain.strComment.clear (); } return bResult; @@ -1820,8 +1958,6 @@ private: // Persist a SeedDomain. void setSeedDomains (const seedDomain& sdSource, bool bNext) { - auto db = getApp().getWalletDB ().getDB (); - int iNext = iToSeconds (sdSource.tpNext); int iScan = iToSeconds (sdSource.tpScan); int iFetch = iToSeconds (sdSource.tpFetch); @@ -1839,12 +1975,16 @@ private: % sqlEscape (sdSource.strComment) ); - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - if (!db->executeSQL (strSql)) + try + { + *db << strSql; + } + catch (soci::soci_error& e) { // XXX Check result. - WriteLog (lsWARNING, UniqueNodeList) << "setSeedDomains: failed."; + WriteLog (lsWARNING, UniqueNodeList) << "setSeedDomains: failed. Error: " << e.what(); } if (bNext && (mtpFetchNext.is_not_a_date_time () || mtpFetchNext > sdSource.tpNext)) @@ -1860,59 +2000,65 @@ private: // Retrieve a SeedNode from DB. bool getSeedNodes (RippleAddress const& naNodePublic, seedNode& dstSeedNode) { - bool bResult; - auto db = getApp().getWalletDB ().getDB (); + std::string strSql = + str (boost::format ( + "SELECT PublicKey, Source, Next, Scan, Fetch, Sha256, " + "Comment FROM SeedNodes WHERE PublicKey='%s';") % + naNodePublic.humanNodePublic ()); - std::string strSql = str (boost::format ("SELECT * FROM SeedNodes WHERE PublicKey='%s';") - % naNodePublic.humanNodePublic ()); + auto db = getApp().getWalletDB ().checkoutDb (); - auto sl (getApp().getWalletDB ().lock ()); + std::string strPublicKey; + std::string strSource; + soci::blob sourceBlob(*db); + soci::indicator si; + boost::optional iNext; + boost::optional iScan; + boost::optional iFetch; + boost::optional strSha256; + soci::blob commentBlob(*db); + soci::indicator ci; - bResult = db->executeSQL (strSql) && db->startIterRows (); + *db << strSql, + soci::into (strPublicKey), + soci::into (sourceBlob, si), + soci::into (iNext), + soci::into (iScan), + soci::into (iFetch), + soci::into (strSha256), + soci::into (commentBlob, ci); - if (bResult) + if (!db->got_data ()) + return false; + + if (!strPublicKey.empty ()) + dstSeedNode.naPublicKey.setNodePublic (strPublicKey); + else + dstSeedNode.naPublicKey.clear (); + + if (soci::i_ok == si) { - std::string strPublicKey; - std::string strSource; - int iNext; - int iScan; - int iFetch; - std::string strSha256; - - if (!db->getNull ("PublicKey") && db->getStr ("PublicKey", strPublicKey)) - { - dstSeedNode.naPublicKey.setNodePublic (strPublicKey); - } - else - { - dstSeedNode.naPublicKey.clear (); - } - - strSource = db->getStrBinary ("Source"); + convert (sourceBlob, strSource); dstSeedNode.vsSource = static_cast (strSource[0]); - - iNext = db->getInt ("Next"); - dstSeedNode.tpNext = ptFromSeconds (iNext); - iScan = db->getInt ("Scan"); - dstSeedNode.tpScan = ptFromSeconds (iScan); - iFetch = db->getInt ("Fetch"); - dstSeedNode.tpFetch = ptFromSeconds (iFetch); - - if (!db->getNull ("Sha256") && db->getStr ("Sha256", strSha256)) - { - dstSeedNode.iSha256.SetHex (strSha256); - } - else - { - dstSeedNode.iSha256.zero (); - } - - dstSeedNode.strComment = db->getStrBinary ("Comment"); - - db->endIterRows (); } + else + assert (0); - return bResult; + dstSeedNode.tpNext = ptFromSeconds (iNext.value_or(0)); + dstSeedNode.tpScan = ptFromSeconds (iScan.value_or(0)); + dstSeedNode.tpFetch = ptFromSeconds (iFetch.value_or(0)); + + if (strSha256 && !strSha256->empty ()) + dstSeedNode.iSha256.SetHex (*strSha256); + else + dstSeedNode.iSha256.zero (); + + if (soci::i_ok == ci) + convert (commentBlob, dstSeedNode.strComment); + else + dstSeedNode.strComment.clear (); + + return true; } //-------------------------------------------------------------------------- @@ -1921,8 +2067,6 @@ private: // <-- bNext: true, to do fetching if needed. void setSeedNodes (const seedNode& snSource, bool bNext) { - auto db = getApp().getWalletDB ().getDB (); - int iNext = iToSeconds (snSource.tpNext); int iScan = iToSeconds (snSource.tpScan); int iFetch = iToSeconds (snSource.tpFetch); @@ -1942,12 +2086,15 @@ private: ); { - auto sl (getApp().getWalletDB ().lock ()); + auto db = getApp().getWalletDB ().checkoutDb (); - if (!db->executeSQL (strSql)) + try { - // XXX Check result. - WriteLog (lsTRACE, UniqueNodeList) << "setSeedNodes: failed."; + *db << strSql; + } + catch(soci::soci_error& e) + { + WriteLog (lsTRACE, UniqueNodeList) << "setSeedNodes: failed. Error: " << e.what (); } } diff --git a/src/ripple/app/tx/Transaction.cpp b/src/ripple/app/tx/Transaction.cpp index ffb0b6b94..fac6c63ee 100644 --- a/src/ripple/app/tx/Transaction.cpp +++ b/src/ripple/app/tx/Transaction.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace ripple { @@ -91,26 +92,13 @@ void Transaction::setStatus (TransStatus ts, std::uint32_t lseq) } Transaction::pointer Transaction::transactionFromSQL ( - Database* db, Validate validate) + boost::optional const& ledgerSeq, + boost::optional const& status, + Blob const& rawTxn, + Validate validate) { - Serializer rawTxn; - std::string status; - std::uint32_t inLedger; - - int txSize = 2048; - rawTxn.resize (txSize); - - db->getStr ("Status", status); - inLedger = db->getInt ("LedgerSeq"); - txSize = db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ()); - - if (txSize > rawTxn.getLength ()) - { - rawTxn.resize (txSize); - db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ()); - } - - rawTxn.resize (txSize); + std::uint32_t const inLedger = + rangeCheckedCast(ledgerSeq.value_or (0)); SerialIter it (rawTxn); auto txn = std::make_shared (it); @@ -118,7 +106,9 @@ Transaction::pointer Transaction::transactionFromSQL ( TransStatus st (INVALID); - switch (status[0]) + char const statusChar = status ? (*status)[0] : TXN_SQL_UNKNOWN; + + switch (statusChar) { case TXN_SQL_NEW: st = NEW; @@ -152,86 +142,29 @@ Transaction::pointer Transaction::transactionFromSQL ( return tr; } -// DAVID: would you rather duplicate this code or keep the lock longer? -Transaction::pointer Transaction::transactionFromSQL (std::string const& sql) -{ - Serializer rawTxn; - std::string status; - std::uint32_t inLedger; - - int txSize = 2048; - rawTxn.resize (txSize); - - { - auto sl (getApp().getTxnDB ().lock ()); - auto db = getApp().getTxnDB ().getDB (); - - if (!db->executeSQL (sql, true) || !db->startIterRows ()) - return Transaction::pointer (); - - db->getStr ("Status", status); - inLedger = db->getInt ("LedgerSeq"); - txSize = db->getBinary ( - "RawTxn", &*rawTxn.begin (), rawTxn.getLength ()); - - if (txSize > rawTxn.getLength ()) - { - rawTxn.resize (txSize); - db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ()); - } - - db->endIterRows (); - } - rawTxn.resize (txSize); - - SerialIter it (rawTxn); - auto txn = std::make_shared (it); - auto tr = std::make_shared (txn, Validate::YES); - - TransStatus st (INVALID); - - switch (status[0]) - { - case TXN_SQL_NEW: - st = NEW; - break; - - case TXN_SQL_CONFLICT: - st = CONFLICTED; - break; - - case TXN_SQL_HELD: - st = HELD; - break; - - case TXN_SQL_VALIDATED: - st = COMMITTED; - break; - - case TXN_SQL_INCLUDED: - st = INCLUDED; - break; - - case TXN_SQL_UNKNOWN: - break; - - default: - assert (false); - } - - tr->setStatus (st); - tr->setLedger (inLedger); - return tr; -} - - Transaction::pointer Transaction::load (uint256 const& id) { std::string sql = "SELECT LedgerSeq,Status,RawTxn " "FROM Transactions WHERE TransID='"; sql.append (to_string (id)); sql.append ("';"); - return transactionFromSQL (sql); + + boost::optional ledgerSeq; + boost::optional status; + Blob rawTxn; + { + auto db = getApp().getTxnDB ().checkoutDb (); + soci::blob sociRawTxnBlob (*db); + soci::indicator rti; + + *db << sql, soci::into (ledgerSeq), soci::into (status), + soci::into (sociRawTxnBlob, rti); + if (db->got_data () && soci::i_ok == rti) + convert(sociRawTxnBlob, rawTxn); + } + + return Transaction::transactionFromSQL ( + ledgerSeq, status, rawTxn, Validate::YES); } // options 1 to include the date of the transaction diff --git a/src/ripple/app/tx/Transaction.h b/src/ripple/app/tx/Transaction.h index 041caa4d9..d1694e871 100644 --- a/src/ripple/app/tx/Transaction.h +++ b/src/ripple/app/tx/Transaction.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ripple { @@ -64,7 +65,11 @@ public: Transaction (STTx::ref, Validate); static Transaction::pointer sharedTransaction (Blob const&, Validate); - static Transaction::pointer transactionFromSQL (Database*, Validate); + static Transaction::pointer transactionFromSQL ( + boost::optional const& ledgerSeq, + boost::optional const& status, + Blob const& rawTxn, + Validate validate); bool checkSign () const; @@ -116,9 +121,6 @@ public: static bool isHexTxID (std::string const&); -protected: - static Transaction::pointer transactionFromSQL (std::string const&); - private: uint256 mTransactionID; RippleAddress mAccountFrom; diff --git a/src/ripple/app/tx/TransactionMeta.cpp b/src/ripple/app/tx/TransactionMeta.cpp index a3800a4e1..07e32d004 100644 --- a/src/ripple/app/tx/TransactionMeta.cpp +++ b/src/ripple/app/tx/TransactionMeta.cpp @@ -28,10 +28,12 @@ namespace ripple { // VFALCO TODO rename class to TransactionMeta -TransactionMetaSet::TransactionMetaSet (uint256 const& txid, std::uint32_t ledger, Blob const& vec) : +template +TransactionMetaSet::TransactionMetaSet (uint256 const& txid, std::uint32_t ledger, T const& data, + CtorHelper) : mTransactionID (txid), mLedger (ledger), mNodes (sfAffectedNodes, 32) { - Serializer s (vec); + Serializer s (data); SerialIter sit (s); std::unique_ptr pobj = STObject::deserialize (sit, sfMetadata); @@ -48,6 +50,20 @@ TransactionMetaSet::TransactionMetaSet (uint256 const& txid, std::uint32_t ledge setDeliveredAmount (obj->getFieldAmount (sfDeliveredAmount)); } +TransactionMetaSet::TransactionMetaSet (uint256 const& txid, + std::uint32_t ledger, + Blob const& vec) + : TransactionMetaSet (txid, ledger, vec, CtorHelper ()) +{ +} + +TransactionMetaSet::TransactionMetaSet (uint256 const& txid, + std::uint32_t ledger, + std::string const& data) + : TransactionMetaSet (txid, ledger, data, CtorHelper ()) +{ +} + bool TransactionMetaSet::isNodeAffected (uint256 const& node) const { for (auto const& n : mNodes) diff --git a/src/ripple/app/tx/TransactionMeta.h b/src/ripple/app/tx/TransactionMeta.h index 19a717d31..bd1c912f7 100644 --- a/src/ripple/app/tx/TransactionMeta.h +++ b/src/ripple/app/tx/TransactionMeta.h @@ -33,6 +33,11 @@ public: typedef std::shared_ptr pointer; typedef const pointer& ref; +private: + struct CtorHelper{}; + template + TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, T const& data, + CtorHelper); public: TransactionMetaSet () : mLedger (0) @@ -50,6 +55,7 @@ public: } TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, Blob const&); + TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, std::string const&); void init (uint256 const& transactionID, std::uint32_t ledger); void clear () diff --git a/src/ripple/basics/BasicConfig.h b/src/ripple/basics/BasicConfig.h index 13068f522..703d3c783 100644 --- a/src/ripple/basics/BasicConfig.h +++ b/src/ripple/basics/BasicConfig.h @@ -291,6 +291,24 @@ get (Section const& section, return defaultValue; } +inline +std::string +get (Section const& section, + std::string const& name, const char* defaultValue) +{ + auto const result = section.find (name); + if (! result.second) + return defaultValue; + try + { + return boost::lexical_cast (result.first); + } + catch(...) + { + } + return defaultValue; +} + template bool get_if_exists (Section const& section, diff --git a/src/ripple/peerfinder/impl/StoreSqdb.h b/src/ripple/peerfinder/impl/StoreSqdb.h index 91864daee..fed142ef3 100644 --- a/src/ripple/peerfinder/impl/StoreSqdb.h +++ b/src/ripple/peerfinder/impl/StoreSqdb.h @@ -22,6 +22,7 @@ #include #include +#include namespace ripple { namespace PeerFinder { @@ -103,26 +104,29 @@ public: soci::transaction tr (m_session); m_session << "DELETE FROM PeerFinder_BootstrapCache"; - std::string s; - int valence; - soci::statement st = (m_session.prepare << - "INSERT INTO PeerFinder_BootstrapCache ( " - " address, " - " valence " - ") VALUES ( " - " :s, :valence " - ");" - , soci::use (s) - , soci::use (valence) - ); - - for (auto const& e : v) + if (!v.empty ()) { - s = to_string (e.endpoint); - valence = e.valence; - st.execute (); - st.fetch (); + std::vector s; + std::vector valence; + s.reserve (v.size ()); + valence.reserve (v.size ()); + + for (auto const& e : v) + { + s.emplace_back (to_string (e.endpoint)); + valence.emplace_back (e.valence); + } + + m_session << + "INSERT INTO PeerFinder_BootstrapCache ( " + " address, " + " valence " + ") VALUES ( " + " :s, :valence " + ");" + , soci::use (s) + , soci::use (valence); } tr.commit (); @@ -136,16 +140,16 @@ public: // get version int version (0); { + boost::optional vO; m_session << "SELECT " " version " "FROM SchemaVersion WHERE " " name = 'PeerFinder'" - , soci::into (version) + , soci::into (vO) ; - if (!m_session.got_data ()) - version = 0; + version = vO.value_or (0); m_journal.info << "Opened version " << version << " database"; @@ -222,10 +226,21 @@ public: } } + if (!list.empty ()) { - std::string s; - int valence; - soci::statement st = (m_session.prepare << + std::vector s; + std::vector valence; + s.reserve (list.size ()); + valence.reserve (list.size ()); + + for (auto iter (list.cbegin ()); + iter != list.cend (); ++iter) + { + s.emplace_back (to_string (iter->endpoint)); + valence.emplace_back (iter->valence); + } + + m_session << "INSERT INTO PeerFinder_BootstrapCache_Next ( " " address, " " valence " @@ -234,16 +249,8 @@ public: ");" , soci::use (s) , soci::use (valence) - ); + ; - for (auto iter (list.cbegin ()); - iter != list.cend (); ++iter) - { - s = to_string (iter->endpoint); - valence = iter->valence; - st.execute (); - st.fetch (); - } } m_session << diff --git a/src/ripple/rpc/handlers/GetCounts.cpp b/src/ripple/rpc/handlers/GetCounts.cpp index 70e2baa57..5ec095c33 100644 --- a/src/ripple/rpc/handlers/GetCounts.cpp +++ b/src/ripple/rpc/handlers/GetCounts.cpp @@ -49,17 +49,17 @@ Json::Value doGetCounts (RPC::Context& context) Application& app = getApp(); - int dbKB = app.getLedgerDB ().getDB ()->getKBUsedAll (); + int dbKB = getKBUsedAll (app.getLedgerDB ().getSession ()); if (dbKB > 0) ret[jss::dbKBTotal] = dbKB; - dbKB = app.getLedgerDB ().getDB ()->getKBUsedDB (); + dbKB = getKBUsedDB (app.getLedgerDB ().getSession ()); if (dbKB > 0) ret[jss::dbKBLedger] = dbKB; - dbKB = app.getTxnDB ().getDB ()->getKBUsedDB (); + dbKB = getKBUsedDB (app.getTxnDB ().getSession ()); if (dbKB > 0) ret[jss::dbKBTransaction] = dbKB; diff --git a/src/ripple/rpc/handlers/TxHistory.cpp b/src/ripple/rpc/handlers/TxHistory.cpp index 9eb5ac7d4..f140f9f05 100644 --- a/src/ripple/rpc/handlers/TxHistory.cpp +++ b/src/ripple/rpc/handlers/TxHistory.cpp @@ -44,16 +44,34 @@ Json::Value doTxHistory (RPC::Context& context) std::string sql = boost::str (boost::format ( - "SELECT * FROM Transactions ORDER BY LedgerSeq desc LIMIT %u,20") + "SELECT LedgerSeq, Status, RawTxn " + "FROM Transactions ORDER BY LedgerSeq desc LIMIT %u,20") % startIndex); { - auto db = getApp().getTxnDB ().getDB (); - auto sl (getApp().getTxnDB ().lock ()); + auto db = getApp().getTxnDB ().checkoutDb (); - SQL_FOREACH (db, sql) + boost::optional ledgerSeq; + boost::optional status; + soci::blob sociRawTxnBlob (*db); + soci::indicator rti; + Blob rawTxn; + + soci::statement st = (db->prepare << sql, + soci::into (ledgerSeq), + soci::into (status), + soci::into (sociRawTxnBlob, rti)); + + st.execute (); + while (st.fetch ()) { - if (auto trans = Transaction::transactionFromSQL (db, Validate::NO)) + if (soci::i_ok == rti) + convert(sociRawTxnBlob, rawTxn); + else + rawTxn.clear (); + + if (auto trans = Transaction::transactionFromSQL ( + ledgerSeq, status, rawTxn, Validate::NO)) txs.append (trans->getJson (0)); } } diff --git a/src/ripple/unity/socipostgresql.cpp b/src/ripple/unity/socipostgresql.cpp deleted file mode 100644 index b8e00c50e..000000000 --- a/src/ripple/unity/socipostgresql.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#if ENABLE_SOCI_POSTGRESQL - -#if BEAST_INCLUDE_BEASTCONFIG -#include -#endif - -#include - -#if BEAST_MSVC -#define SOCI_LIB_PREFIX "" -#define SOCI_LIB_SUFFIX ".dll" -#else -#define SOCI_LIB_PREFIX "lib" -#define SOCI_LIB_SUFFIX ".so" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // ENABLE_SOCI_POSTGRESQL diff --git a/src/ripple/validators/impl/StoreSqdb.cpp b/src/ripple/validators/impl/StoreSqdb.cpp index 9efbb244d..e686e2684 100644 --- a/src/ripple/validators/impl/StoreSqdb.cpp +++ b/src/ripple/validators/impl/StoreSqdb.cpp @@ -38,9 +38,8 @@ StoreSqdb::~StoreSqdb () void StoreSqdb::open (SociConfig const& sociConfig) { - sociConfig.open (m_session); - m_journal.info << "Opening " << sociConfig.connectionString (); + sociConfig.open (m_session); } } diff --git a/src/soci/src/core/unsigned-types.h b/src/soci/src/core/unsigned-types.h index e9a02c64a..8eff6a4e0 100644 --- a/src/soci/src/core/unsigned-types.h +++ b/src/soci/src/core/unsigned-types.h @@ -33,7 +33,7 @@ struct type_conversion const base_type min = (std::numeric_limits::min)(); if (in < min || in > max) { - throw soci_error("Value outside of allowed range."); + /* throw soci_error("Value outside of allowed range."); */ } out = static_cast(in); @@ -64,7 +64,7 @@ struct type_conversion const long long min = (std::numeric_limits::min)(); if (in < min || in > max) { - throw soci_error("Value outside of allowed range."); + /* throw soci_error("Value outside of allowed range."); */ } out = static_cast(in); @@ -95,7 +95,7 @@ struct type_conversion const long long min = (std::numeric_limits::min)(); if (in < min || in > max) { - throw soci_error("Value outside of allowed range."); + /* throw soci_error("Value outside of allowed range."); */ } out = static_cast(in);