mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 09:17:53 +00:00
Use soci in more places:
* Validator, peerfinder, SHAMapStore, RpcDB, TxnDB, LedgerDB, WalletDB use soci backend.
This commit is contained in:
@@ -4305,8 +4305,6 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\snappy\snappy\snappy.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\soci\src\backends\postgresql\soci-postgresql.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\soci\src\backends\sqlite3\blob.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
||||
@@ -535,9 +535,6 @@
|
||||
<Filter Include="soci\src\backends">
|
||||
<UniqueIdentifier>{AA927DBA-1AF8-6600-04B7-D1C1EBFB4103}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="soci\src\backends\postgresql">
|
||||
<UniqueIdentifier>{5D2927A9-CC6E-DDE0-1654-5316177082DD}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="soci\src\backends\sqlite3">
|
||||
<UniqueIdentifier>{75E6832F-A6F7-8360-FA3A-7427A06A9959}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -5040,9 +5037,6 @@
|
||||
<ClInclude Include="..\..\src\snappy\snappy\snappy.h">
|
||||
<Filter>snappy\snappy</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\soci\src\backends\postgresql\soci-postgresql.h">
|
||||
<Filter>soci\src\backends\postgresql</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\soci\src\backends\sqlite3\blob.cpp">
|
||||
<Filter>soci\src\backends\sqlite3</Filter>
|
||||
</ClCompile>
|
||||
|
||||
20
SConstruct
20
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.
|
||||
|
||||
'''
|
||||
#
|
||||
'''
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/data/DatabaseCon.h>
|
||||
#include <ripple/app/data/SqliteDatabase.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/app/data/SociDB.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <beast/cxx14/memory.h> // <memory>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -28,6 +29,7 @@ DatabaseCon::DatabaseCon (Setup const& setup,
|
||||
std::string const& strName,
|
||||
const char* initStrings[],
|
||||
int initCount)
|
||||
:session_(std::make_shared<soci::session>())
|
||||
{
|
||||
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<WALCheckpointer> (session_, q);
|
||||
}
|
||||
} // ripple
|
||||
|
||||
@@ -20,24 +20,65 @@
|
||||
#ifndef RIPPLE_APP_DATA_DATABASECON_H_INCLUDED
|
||||
#define RIPPLE_APP_DATA_DATABASECON_H_INCLUDED
|
||||
|
||||
#include <ripple/app/data/Database.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/app/data/SociDB.h>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace soci {
|
||||
class session;
|
||||
}
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Database;
|
||||
template<class T, class TMutex>
|
||||
class LockedPointer
|
||||
{
|
||||
public:
|
||||
using mutex = TMutex;
|
||||
private:
|
||||
T* it_;
|
||||
std::unique_lock<mutex> 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<soci::session, std::recursive_mutex>;
|
||||
|
||||
// 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<mutex> lock ()
|
||||
LockedSociSession checkoutDb()
|
||||
{
|
||||
return std::unique_lock<mutex>(mLock);
|
||||
}
|
||||
|
||||
mutex& peekMutex()
|
||||
{
|
||||
return mLock;
|
||||
return LockedSociSession(session_.get (), lock_);
|
||||
}
|
||||
|
||||
void setupCheckpointing (JobQueue*);
|
||||
private:
|
||||
Database* mDatabase;
|
||||
mutex mLock;
|
||||
std::unique_ptr<WALCheckpointer> walCheckpointer_;
|
||||
// shared_ptr to handle lifetime issues with walCheckpointer_
|
||||
// never null.
|
||||
std::shared_ptr<soci::session> session_;
|
||||
LockedSociSession::mutex lock_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DatabaseCon::Setup
|
||||
setup_DatabaseCon (Config const& c);
|
||||
|
||||
|
||||
@@ -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 <BeastConfig.h>
|
||||
@@ -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
|
||||
|
||||
@@ -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 <BeastConfig.h>
|
||||
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
@@ -32,9 +24,6 @@
|
||||
#include <ripple/core/Config.h>
|
||||
#include <beast/cxx14/memory.h> // <memory>
|
||||
#include <backends/sqlite3/soci-sqlite3.h>
|
||||
#if ENABLE_SOCI_POSTGRESQL
|
||||
#include <backends/postgresql/soci-postgresql.h>
|
||||
#endif
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
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<std::string, soci::backend_factory const&>
|
||||
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 <std::string> (configSection, "host", ""));
|
||||
if (!host.empty())
|
||||
{
|
||||
throw std::runtime_error (
|
||||
"Missing required value in config for postgresql backend: host");
|
||||
}
|
||||
|
||||
std::string const user(get <std::string> (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 <std::string> (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<std::string, soci::backend_factory const&>
|
||||
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<std::string, soci::backend_factory const&> init)
|
||||
:connectionString_(std::move(init.first)),
|
||||
backendFactory_(init.second){}
|
||||
SociConfig::SociConfig (std::pair<std::string, soci::backend_factory const&> 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<soci::sqlite3_session_backend*>(s.get_backend ());
|
||||
assert (be); // Make sure the backend is sqlite
|
||||
return static_cast<int>(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<soci::sqlite3_session_backend*>(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<std::uint8_t>& to)
|
||||
{
|
||||
to.resize (from.get_len ());
|
||||
if (to.empty ())
|
||||
return;
|
||||
from.read (0, reinterpret_cast<char*>(&to[0]), from.get_len ());
|
||||
}
|
||||
|
||||
void convert(soci::blob& from, std::string& to)
|
||||
{
|
||||
std::vector<std::uint8_t> tmp;
|
||||
convert(from, tmp);
|
||||
to.assign(tmp.begin (), tmp.end());
|
||||
|
||||
}
|
||||
|
||||
void convert(std::vector<std::uint8_t> const& from, soci::blob& to)
|
||||
{
|
||||
if (!from.empty ())
|
||||
to.write (0, reinterpret_cast<char const*>(&from[0]), from.size ());
|
||||
}
|
||||
|
||||
int SqliteWALHook (void* s,
|
||||
sqlite_api::sqlite3*,
|
||||
const char* dbName,
|
||||
int walSize)
|
||||
{
|
||||
(reinterpret_cast<WALCheckpointer*>(s))->doHook (dbName, walSize);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
WALCheckpointer::WALCheckpointer (std::shared_ptr<soci::session> const& s,
|
||||
JobQueue* q)
|
||||
: Thread ("sqlitedb"), session_(s)
|
||||
{
|
||||
if (auto session =
|
||||
dynamic_cast<soci::sqlite3_session_backend*>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <ripple/basics/Log.h>
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <beast/threads/Thread.h>
|
||||
#define SOCI_USE_BOOST
|
||||
#include <core/soci.h>
|
||||
// #include <core/unsigned-types.h>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace sqlite_api {
|
||||
class sqlite3;
|
||||
}
|
||||
|
||||
namespace ripple {
|
||||
template <class T, class C>
|
||||
T rangeCheckedCast (C c)
|
||||
{
|
||||
if ((c > std::numeric_limits<T>::max ()) ||
|
||||
(!std::numeric_limits<T>::is_signed && c < 0) ||
|
||||
(std::numeric_limits<T>::is_signed &&
|
||||
std::numeric_limits<C>::is_signed &&
|
||||
c < std::numeric_limits<T>::lowest ()))
|
||||
{
|
||||
WriteLog (lsERROR, RangeCheckedCast)
|
||||
<< "Range error. Min: " << std::numeric_limits<T>::lowest ()
|
||||
<< " Max: " << std::numeric_limits<T>::max () << " Got: " << c;
|
||||
}
|
||||
return static_cast<T>(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<std::uint8_t>& to);
|
||||
void convert(soci::blob& from, std::string& to);
|
||||
void convert(std::vector<std::uint8_t> 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<soci::session> const& s,
|
||||
JobQueue* q);
|
||||
~WALCheckpointer ();
|
||||
private:
|
||||
void doHook (const char* db, int walSize);
|
||||
void setupCheckpointing (JobQueue*);
|
||||
void run ();
|
||||
void runWal ();
|
||||
|
||||
std::shared_ptr<soci::session> session_;
|
||||
sqlite_api::sqlite3* conn_ = nullptr;
|
||||
using LockType = std::mutex;
|
||||
using ScopedLockType = std::lock_guard<LockType>;
|
||||
LockType mutex_;
|
||||
JobQueue* q_ = nullptr;
|
||||
bool running_ = false;
|
||||
};
|
||||
}
|
||||
|
||||
#if _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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<std::pair<const char*, const char*>> const d (
|
||||
std::vector<std::pair<std::string, std::string>> 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<std::uint64_t> const ubid (
|
||||
{(std::uint64_t)std::numeric_limits<std::int64_t>::max (), 20, 30});
|
||||
std::vector<std::int64_t> const bid ({-10, -20, -30});
|
||||
std::vector<std::uint32_t> const uid (
|
||||
{std::numeric_limits<std::uint32_t>::max (), 2, 3});
|
||||
std::vector<std::int32_t> 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<std::int32_t> ig;
|
||||
boost::optional<std::uint32_t> uig;
|
||||
boost::optional<std::int64_t> big;
|
||||
boost::optional<std::uint64_t> 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<std::int32_t>(0);
|
||||
uig = r.get<std::uint32_t>(1);
|
||||
big = r.get<std::int64_t>(2);
|
||||
ubig = r.get<std::uint64_t>(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<std::int32_t>("I");
|
||||
uig = r.get<std::uint32_t>("UI");
|
||||
big = r.get<std::int64_t>("BI");
|
||||
ubig = r.get<std::uint64_t>("UBI");
|
||||
expect (ig == id[0] && uig == uid[0] && big == bid[0] &&
|
||||
ubig == ubid[0]);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
fail ();
|
||||
}
|
||||
try
|
||||
{
|
||||
boost::tuple<std::int32_t,
|
||||
std::uint32_t,
|
||||
std::int64_t,
|
||||
std::uint64_t> 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 ()
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <ripple/app/ledger/LedgerToJson.h>
|
||||
#include <ripple/app/ledger/OrderBookDB.h>
|
||||
#include <ripple/app/data/DatabaseCon.h>
|
||||
#include <ripple/app/data/SqliteDatabase.h>
|
||||
#include <ripple/app/data/SociDB.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/IHashRouter.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <ripple/protocol/HashPrefix.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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 <std::string> (mTotCoins) % mCloseTime %
|
||||
mParentCloseTime % mCloseResolution % mCloseFlags %
|
||||
to_string (mAccountHash) % to_string (mTransHash)));
|
||||
*db << boost::str (addLedger %
|
||||
to_string (getHash ()) % mLedgerSeq % to_string (mParentHash) %
|
||||
beast::lexicalCastThrow <std::string> (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<Ledger::pointer, std::uint32_t, uint256>
|
||||
loadHelper(std::string const& sqlSuffix)
|
||||
{
|
||||
Ledger::pointer ledger;
|
||||
uint256 ledgerHash;
|
||||
std::uint32_t ledgerSeq{0};
|
||||
|
||||
auto db = getApp ().getLedgerDB ().checkoutDb ();
|
||||
|
||||
boost::optional<std::string> sLedgerHash, sPrevHash, sAccountHash,
|
||||
sTransHash;
|
||||
boost::optional<std::uint64_t> 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<std::uint32_t>(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 <std::string> (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<Ledger>(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<std::string> 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 <std::string> 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 <std::string> (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<uint256, uint256> >
|
||||
@@ -1098,16 +983,29 @@ Ledger::getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq)
|
||||
sql.append (beast::lexicalCastThrow <std::string> (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<std::string> 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<uint256, uint256>& hashes = ret[pSt.getUInt32 (0)];
|
||||
hashes.first.SetHexExact (pSt.peekString (1));
|
||||
hashes.second.SetHexExact (pSt.peekString (2));
|
||||
std::pair<uint256, uint256>& hashes =
|
||||
ret[rangeCheckedCast<std::uint32_t>(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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<std::string> getSchema (DatabaseCon& dbc, std::string const& dbName)
|
||||
{
|
||||
std::vector<std::string> 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<uint256, int> > 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<std::string> 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<int> (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 ()
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/basics/make_SSLContext.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <iostream>
|
||||
|
||||
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<std::string> 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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::uint64_t> 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
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include <beast/module/core/thread/DeadlineTimer.h>
|
||||
#include <beast/module/core/system/SystemStats.h>
|
||||
#include <beast/cxx14/memory.h> // <memory>
|
||||
#include <boost/optional.hpp>
|
||||
#include <tuple>
|
||||
|
||||
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<std::uint64_t> ledgerSeq;
|
||||
boost::optional<std::string> 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<std::uint32_t>(
|
||||
db->getBigInt("LedgerSeq"));
|
||||
auto const seq = rangeCheckedCast<std::uint32_t>(
|
||||
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<TransactionMetaSet> (
|
||||
txn->getID (), txn->getLedger (), rawMeta.getData ()));
|
||||
txn->getID (), txn->getLedger (), txnMeta));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1988,37 +1999,35 @@ std::vector<NetworkOPsImp::txnMetaLedgerType> NetworkOPsImp::getAccountTxsB (
|
||||
bAdmin);
|
||||
|
||||
{
|
||||
auto db = getApp().getTxnDB ().getDB ();
|
||||
auto sl (getApp().getTxnDB ().lock ());
|
||||
auto db = getApp().getTxnDB ().checkoutDb ();
|
||||
|
||||
SQL_FOREACH (db, sql)
|
||||
boost::optional<std::uint64_t> ledgerSeq;
|
||||
boost::optional<std::string> 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<std::uint32_t>(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<std::uint64_t> ledgerSeq64;
|
||||
boost::optional<std::int32_t> txnSeq;
|
||||
boost::optional<std::string> 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<std::uint32_t>(
|
||||
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<std::uint32_t>(
|
||||
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<TransactionMetaSet> (
|
||||
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<std::int64_t> ledgerSeq;
|
||||
boost::optional<std::int32_t> txnSeq;
|
||||
boost::optional<std::string> 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<std::int32_t>(
|
||||
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<std::int32_t>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <boost/format.hpp>
|
||||
#include <beast/cxx14/memory.h> // <memory>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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<std::int64_t> 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<std::int64_t> 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 <LedgerIndex>::max();
|
||||
Database* db = database.getDB();
|
||||
|
||||
std::unique_lock <std::recursive_mutex> lock (database.peekMutex());
|
||||
if (!db->executeSQL (minQuery) || !db->startIterRows())
|
||||
return;
|
||||
min = db->getBigInt (0);
|
||||
db->endIterRows ();
|
||||
lock.unlock();
|
||||
{
|
||||
auto db = database.checkoutDb ();
|
||||
boost::optional<std::uint64_t> 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)
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <boost/date_time/posix_time/posix_time_io.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace ripple {
|
||||
@@ -89,6 +90,73 @@ strJoin (Iterator first, Iterator last, std::string strSeperator)
|
||||
return ossValues.str ();
|
||||
}
|
||||
|
||||
template <size_t I, class String>
|
||||
void selectBlobsIntoStrings (
|
||||
soci::session& s,
|
||||
String&& sql,
|
||||
std::vector<std::array<boost::optional<std::string>, I>>& columns)
|
||||
{
|
||||
columns.clear ();
|
||||
columns.reserve (32);
|
||||
|
||||
std::vector<soci::blob> blobs;
|
||||
blobs.reserve (I);
|
||||
for (int i = 0; i < I; ++i)
|
||||
blobs.emplace_back (s);
|
||||
std::array<soci::indicator, I> 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<class TOther, class String>
|
||||
void selectBlobsIntoStrings (
|
||||
soci::session& s,
|
||||
String&& sql,
|
||||
std::vector<std::tuple<boost::optional<std::string>, boost::optional<TOther>>>& columns)
|
||||
{
|
||||
columns.clear ();
|
||||
columns.reserve (32);
|
||||
|
||||
soci::blob blob(s);
|
||||
soci::indicator ind;
|
||||
boost::optional<TOther> 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<std::array<boost::optional<std::string>, 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<int> 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<std::array<boost::optional<std::string>, 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<std::string, int> umDomainIdx; // Map of domain to index.
|
||||
std::vector<scoreNode> 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<std::array<boost::optional<std::string>, 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<ValidatorSource> (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<ValidatorSource> (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<std::array<boost::optional<std::string>, 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<ValidatorSource> (strSource[0]));
|
||||
auto siOld = umPulicIdx.find (strPublicKey);
|
||||
|
||||
@@ -950,12 +1026,20 @@ private:
|
||||
std::string& strValidator = sn.strValidator;
|
||||
std::vector<int>& 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<std::array<boost::optional<std::string>, 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<std::tuple<boost::optional<std::string>,
|
||||
boost::optional<int>>> 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<std::string> 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<std::tuple<boost::optional<std::string>,
|
||||
boost::optional<std::int32_t>>> 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<std::tuple<boost::optional<std::string>,
|
||||
boost::optional<std::int32_t>>> 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<int> 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<std::string> strPublicKey;
|
||||
soci:: blob sourceBlob(*db);
|
||||
soci::indicator si;
|
||||
std::string strSource;
|
||||
boost::optional<int> iNext;
|
||||
boost::optional<int> iScan;
|
||||
boost::optional<int> iFetch;
|
||||
boost::optional<std::string> strSha256;
|
||||
soci::blob commentBlob(*db);
|
||||
soci::indicator ci;
|
||||
boost::optional<std::string> 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<ValidatorSource> (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<ValidatorSource> (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<int> iNext;
|
||||
boost::optional<int> iScan;
|
||||
boost::optional<int> iFetch;
|
||||
boost::optional<std::string> 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<ValidatorSource> (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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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<std::uint64_t> const& ledgerSeq,
|
||||
boost::optional<std::string> 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<std::uint32_t>(ledgerSeq.value_or (0));
|
||||
|
||||
SerialIter it (rawTxn);
|
||||
auto txn = std::make_shared<STTx> (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<STTx> (it);
|
||||
auto tr = std::make_shared<Transaction> (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<std::uint64_t> ledgerSeq;
|
||||
boost::optional<std::string> 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
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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<std::uint64_t> const& ledgerSeq,
|
||||
boost::optional<std::string> 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;
|
||||
|
||||
@@ -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<class T>
|
||||
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<STBase> 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)
|
||||
|
||||
@@ -33,6 +33,11 @@ public:
|
||||
typedef std::shared_ptr<TransactionMetaSet> pointer;
|
||||
typedef const pointer& ref;
|
||||
|
||||
private:
|
||||
struct CtorHelper{};
|
||||
template<class T>
|
||||
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 ()
|
||||
|
||||
@@ -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 <std::string> (result.first);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
get_if_exists (Section const& section,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <ripple/app/data/SociDB.h>
|
||||
#include <beast/utility/Debug.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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<std::string> s;
|
||||
std::vector<int> 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<int> 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<std::string> s;
|
||||
std::vector<int> 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 <<
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<std::uint64_t> ledgerSeq;
|
||||
boost::optional<std::string> 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <BeastConfig.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#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<backends/postgresql/blob.cpp>
|
||||
#include<backends/postgresql/common.cpp>
|
||||
#include<backends/postgresql/error.cpp>
|
||||
#include<backends/postgresql/factory.cpp>
|
||||
#include<backends/postgresql/row-id.cpp>
|
||||
#include<backends/postgresql/session.cpp>
|
||||
#include<backends/postgresql/standard-into-type.cpp>
|
||||
#include<backends/postgresql/standard-use-type.cpp>
|
||||
#include<backends/postgresql/statement.cpp>
|
||||
#include<backends/postgresql/vector-into-type.cpp>
|
||||
#include<backends/postgresql/vector-use-type.cpp>
|
||||
|
||||
#endif // ENABLE_SOCI_POSTGRESQL
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ struct type_conversion<unsigned char>
|
||||
const base_type min = (std::numeric_limits<unsigned char>::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<unsigned char>(in);
|
||||
@@ -64,7 +64,7 @@ struct type_conversion<unsigned short>
|
||||
const long long min = (std::numeric_limits<unsigned short>::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<unsigned short>(in);
|
||||
@@ -95,7 +95,7 @@ struct type_conversion<unsigned int>
|
||||
const long long min = (std::numeric_limits<unsigned int>::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<unsigned int>(in);
|
||||
|
||||
Reference in New Issue
Block a user