mirror of
				https://github.com/Xahau/xahaud.git
				synced 2025-11-04 10:45:50 +00:00 
			
		
		
		
	Implement Shard SQLite support
This commit is contained in:
		
				
					committed by
					
						
						Nik Bougalis
					
				
			
			
				
	
			
			
			
						parent
						
							008fc5155a
						
					
				
				
					commit
					66fad62e66
				
			@@ -2086,7 +2086,6 @@ else ()
 | 
			
		||||
    src/ripple/app/main/Application.cpp
 | 
			
		||||
    src/ripple/app/main/BasicApp.cpp
 | 
			
		||||
    src/ripple/app/main/CollectorManager.cpp
 | 
			
		||||
    src/ripple/app/main/DBInit.cpp
 | 
			
		||||
    src/ripple/app/main/LoadManager.cpp
 | 
			
		||||
    src/ripple/app/main/Main.cpp
 | 
			
		||||
    src/ripple/app/main/NodeIdentity.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -582,7 +582,7 @@ public:
 | 
			
		||||
    void signalStop() override;
 | 
			
		||||
    bool checkSigs() const override;
 | 
			
		||||
    void checkSigs(bool) override;
 | 
			
		||||
    int fdlimit () const override;
 | 
			
		||||
    int fdRequired() const override;
 | 
			
		||||
 | 
			
		||||
    //--------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
@@ -858,12 +858,12 @@ public:
 | 
			
		||||
            // transaction database
 | 
			
		||||
            mTxnDB = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                TxnDBName,
 | 
			
		||||
                TxnDBInit,
 | 
			
		||||
                TxnDBCount);
 | 
			
		||||
                TxDBName,
 | 
			
		||||
                TxDBPragma,
 | 
			
		||||
                TxDBInit);
 | 
			
		||||
            mTxnDB->getSession() <<
 | 
			
		||||
                boost::str(boost::format("PRAGMA cache_size=-%d;") %
 | 
			
		||||
                (config_->getSize(siTxnDBCache) * kilobytes(1)));
 | 
			
		||||
                kilobytes(config_->getSize(siTxnDBCache)));
 | 
			
		||||
            mTxnDB->setupCheckpointing(m_jobQueue.get(), logs());
 | 
			
		||||
 | 
			
		||||
            if (!setup.standAlone ||
 | 
			
		||||
@@ -900,20 +900,20 @@ public:
 | 
			
		||||
            // ledger database
 | 
			
		||||
            mLedgerDB = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                LedgerDBName,
 | 
			
		||||
                LedgerDBInit,
 | 
			
		||||
                LedgerDBCount);
 | 
			
		||||
                LgrDBName,
 | 
			
		||||
                LgrDBPragma,
 | 
			
		||||
                LgrDBInit);
 | 
			
		||||
            mLedgerDB->getSession() <<
 | 
			
		||||
                boost::str(boost::format("PRAGMA cache_size=-%d;") %
 | 
			
		||||
                (config_->getSize(siLgrDBCache) * kilobytes(1)));
 | 
			
		||||
                kilobytes(config_->getSize(siLgrDBCache)));
 | 
			
		||||
            mLedgerDB->setupCheckpointing(m_jobQueue.get(), logs());
 | 
			
		||||
 | 
			
		||||
            // wallet database
 | 
			
		||||
            mWalletDB = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                WalletDBName,
 | 
			
		||||
                WalletDBInit,
 | 
			
		||||
                WalletDBCount);
 | 
			
		||||
                std::array<char const*, 0>(),
 | 
			
		||||
                WalletDBInit);
 | 
			
		||||
        }
 | 
			
		||||
        catch (std::exception const& e)
 | 
			
		||||
        {
 | 
			
		||||
@@ -963,11 +963,8 @@ public:
 | 
			
		||||
        family().treecache().setTargetAge(
 | 
			
		||||
            seconds{config_->getSize(siTreeCacheAge)});
 | 
			
		||||
 | 
			
		||||
        if (shardStore_)
 | 
			
		||||
        if (sFamily_)
 | 
			
		||||
        {
 | 
			
		||||
            shardStore_->tune(
 | 
			
		||||
                config_->getSize(siNodeCacheSize),
 | 
			
		||||
                seconds{config_->getSize(siNodeCacheAge)});
 | 
			
		||||
            sFamily_->treecache().setTargetSize(
 | 
			
		||||
                config_->getSize(siTreeCacheSize));
 | 
			
		||||
            sFamily_->treecache().setTargetAge(
 | 
			
		||||
@@ -1174,9 +1171,10 @@ public:
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            DatabaseCon::Setup dbSetup = setup_DatabaseCon(*config_);
 | 
			
		||||
            boost::filesystem::path dbPath = dbSetup.dataDir / TxnDBName;
 | 
			
		||||
            boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
 | 
			
		||||
            boost::system::error_code ec;
 | 
			
		||||
            boost::optional<std::uint64_t> dbSize = boost::filesystem::file_size(dbPath, ec);
 | 
			
		||||
            boost::optional<std::uint64_t> dbSize =
 | 
			
		||||
                boost::filesystem::file_size(dbPath, ec);
 | 
			
		||||
            if (ec)
 | 
			
		||||
            {
 | 
			
		||||
                JLOG(m_journal.error())
 | 
			
		||||
@@ -1632,7 +1630,7 @@ void ApplicationImp::checkSigs(bool check)
 | 
			
		||||
    checkSigs_ = check;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ApplicationImp::fdlimit() const
 | 
			
		||||
int ApplicationImp::fdRequired() const
 | 
			
		||||
{
 | 
			
		||||
    // Standard handles, config file, misc I/O etc:
 | 
			
		||||
    int needed = 128;
 | 
			
		||||
@@ -1642,10 +1640,10 @@ int ApplicationImp::fdlimit() const
 | 
			
		||||
 | 
			
		||||
    // the number of fds needed by the backend (internally
 | 
			
		||||
    // doubled if online delete is enabled).
 | 
			
		||||
    needed += std::max(5, m_shaMapStore->fdlimit());
 | 
			
		||||
    needed += std::max(5, m_shaMapStore->fdRequired());
 | 
			
		||||
 | 
			
		||||
    if (shardStore_)
 | 
			
		||||
        needed += shardStore_->fdlimit();
 | 
			
		||||
        needed += shardStore_->fdRequired();
 | 
			
		||||
 | 
			
		||||
    // One fd per incoming connection a port can accept, or
 | 
			
		||||
    // if no limit is set, assume it'll handle 256 clients.
 | 
			
		||||
 
 | 
			
		||||
@@ -183,8 +183,8 @@ public:
 | 
			
		||||
 | 
			
		||||
    virtual beast::Journal journal (std::string const& name) = 0;
 | 
			
		||||
 | 
			
		||||
    /* Returns the number of file descriptors the application wants */
 | 
			
		||||
    virtual int fdlimit () const = 0;
 | 
			
		||||
    /* Returns the number of file descriptors the application needs */
 | 
			
		||||
    virtual int fdRequired() const = 0;
 | 
			
		||||
 | 
			
		||||
    /** Retrieve the "wallet database" */
 | 
			
		||||
    virtual DatabaseCon& getWalletDB () = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,149 +0,0 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    This file is part of rippled: https://github.com/ripple/rippled
 | 
			
		||||
    Copyright (c) 2012, 2013 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.
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#include <ripple/app/main/DBInit.h>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
// Transaction database holds transactions and public keys
 | 
			
		||||
const char* TxnDBName = "transaction.db";
 | 
			
		||||
const char* TxnDBInit[] =
 | 
			
		||||
{
 | 
			
		||||
    "PRAGMA page_size=4096;",
 | 
			
		||||
    "PRAGMA synchronous=NORMAL;",
 | 
			
		||||
    "PRAGMA journal_mode=WAL;",
 | 
			
		||||
    "PRAGMA journal_size_limit=1582080;",
 | 
			
		||||
    "PRAGMA max_page_count=2147483646;",
 | 
			
		||||
 | 
			
		||||
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
 | 
			
		||||
    "PRAGMA mmap_size=17179869184;",
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    "BEGIN TRANSACTION;",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS Transactions (                \
 | 
			
		||||
        TransID     CHARACTER(64) PRIMARY KEY,  \
 | 
			
		||||
        TransType   CHARACTER(24),              \
 | 
			
		||||
        FromAcct    CHARACTER(35),              \
 | 
			
		||||
        FromSeq     BIGINT UNSIGNED,            \
 | 
			
		||||
        LedgerSeq   BIGINT UNSIGNED,            \
 | 
			
		||||
        Status      CHARACTER(1),               \
 | 
			
		||||
        RawTxn      BLOB,                       \
 | 
			
		||||
        TxnMeta     BLOB                        \
 | 
			
		||||
    );",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS TxLgrIndex ON                 \
 | 
			
		||||
        Transactions(LedgerSeq);",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS AccountTransactions (         \
 | 
			
		||||
        TransID     CHARACTER(64),              \
 | 
			
		||||
        Account     CHARACTER(64),              \
 | 
			
		||||
        LedgerSeq   BIGINT UNSIGNED,            \
 | 
			
		||||
        TxnSeq      INTEGER                     \
 | 
			
		||||
    );",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS AcctTxIDIndex ON              \
 | 
			
		||||
        AccountTransactions(TransID);",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS AcctTxIndex ON                \
 | 
			
		||||
        AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS AcctLgrIndex ON               \
 | 
			
		||||
        AccountTransactions(LedgerSeq, Account, TransID);",
 | 
			
		||||
 | 
			
		||||
    "END TRANSACTION;"
 | 
			
		||||
};
 | 
			
		||||
int TxnDBCount = std::extent<decltype(TxnDBInit)>::value;
 | 
			
		||||
 | 
			
		||||
// Ledger database holds ledgers and ledger confirmations
 | 
			
		||||
const char* LedgerDBName = "ledger.db";
 | 
			
		||||
const char* LedgerDBInit[] =
 | 
			
		||||
{
 | 
			
		||||
    "PRAGMA synchronous=NORMAL;",
 | 
			
		||||
    "PRAGMA journal_mode=WAL;",
 | 
			
		||||
    "PRAGMA journal_size_limit=1582080;",
 | 
			
		||||
 | 
			
		||||
    "BEGIN TRANSACTION;",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS Ledgers (           \
 | 
			
		||||
        LedgerHash      CHARACTER(64) PRIMARY KEY,  \
 | 
			
		||||
        LedgerSeq       BIGINT UNSIGNED,            \
 | 
			
		||||
        PrevHash        CHARACTER(64),              \
 | 
			
		||||
        TotalCoins      BIGINT UNSIGNED,            \
 | 
			
		||||
        ClosingTime     BIGINT UNSIGNED,            \
 | 
			
		||||
        PrevClosingTime BIGINT UNSIGNED,            \
 | 
			
		||||
        CloseTimeRes    BIGINT UNSIGNED,            \
 | 
			
		||||
        CloseFlags      BIGINT UNSIGNED,            \
 | 
			
		||||
        AccountSetHash  CHARACTER(64),              \
 | 
			
		||||
        TransSetHash    CHARACTER(64)               \
 | 
			
		||||
    );",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS SeqLedger ON Ledgers(LedgerSeq);",
 | 
			
		||||
 | 
			
		||||
    // Old table and indexes no longer needed
 | 
			
		||||
    "DROP TABLE IF EXISTS Validations;",
 | 
			
		||||
 | 
			
		||||
    "END TRANSACTION;"
 | 
			
		||||
};
 | 
			
		||||
int LedgerDBCount = std::extent<decltype(LedgerDBInit)>::value;
 | 
			
		||||
 | 
			
		||||
const char* WalletDBName = "wallet.db";
 | 
			
		||||
const char* WalletDBInit[] =
 | 
			
		||||
{
 | 
			
		||||
    "BEGIN TRANSACTION;",
 | 
			
		||||
 | 
			
		||||
    // A node's identity must be persisted, including
 | 
			
		||||
    // for clustering purposes. This table holds one
 | 
			
		||||
    // entry: the server's unique identity, but the
 | 
			
		||||
    // value can be overriden by specifying a node
 | 
			
		||||
    // identity in the config file using a [node_seed]
 | 
			
		||||
    // entry.
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS NodeIdentity (      \
 | 
			
		||||
        PublicKey       CHARACTER(53),              \
 | 
			
		||||
        PrivateKey      CHARACTER(52)               \
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    // Peer reservations.
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS PeerReservations (     \
 | 
			
		||||
        PublicKey       CHARACTER(53) UNIQUE NOT NULL, \
 | 
			
		||||
        Description     CHARACTER(64) NOT NULL         \
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    // Validator Manifests
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS ValidatorManifests ( \
 | 
			
		||||
        RawData          BLOB NOT NULL               \
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS PublisherManifests ( \
 | 
			
		||||
        RawData          BLOB NOT NULL               \
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    // Old tables that were present in wallet.db and we
 | 
			
		||||
    // no longer need or use.
 | 
			
		||||
    "DROP INDEX IF EXISTS SeedNodeNext;",
 | 
			
		||||
    "DROP INDEX IF EXISTS SeedDomainNext;",
 | 
			
		||||
    "DROP TABLE IF EXISTS Features;",
 | 
			
		||||
    "DROP TABLE IF EXISTS TrustedNodes;",
 | 
			
		||||
    "DROP TABLE IF EXISTS ValidatorReferrals;",
 | 
			
		||||
    "DROP TABLE IF EXISTS IpReferrals;",
 | 
			
		||||
    "DROP TABLE IF EXISTS SeedNodes;",
 | 
			
		||||
    "DROP TABLE IF EXISTS SeedDomains;",
 | 
			
		||||
    "DROP TABLE IF EXISTS Misc;",
 | 
			
		||||
 | 
			
		||||
    "END TRANSACTION;"
 | 
			
		||||
};
 | 
			
		||||
int WalletDBCount = std::extent<decltype(WalletDBInit)>::value;
 | 
			
		||||
 | 
			
		||||
} // ripple
 | 
			
		||||
@@ -20,20 +20,145 @@
 | 
			
		||||
#ifndef RIPPLE_APP_DATA_DBINIT_H_INCLUDED
 | 
			
		||||
#define RIPPLE_APP_DATA_DBINIT_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
// VFALCO TODO Tidy these up into a class with functions and return types.
 | 
			
		||||
extern const char* TxnDBName;
 | 
			
		||||
extern const char* TxnDBInit[];
 | 
			
		||||
extern int TxnDBCount;
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
extern const char* LedgerDBName;
 | 
			
		||||
extern const char* LedgerDBInit[];
 | 
			
		||||
extern int LedgerDBCount;
 | 
			
		||||
// Ledger database holds ledgers and ledger confirmations
 | 
			
		||||
static constexpr auto LgrDBName {"ledger.db"};
 | 
			
		||||
 | 
			
		||||
extern const char* WalletDBName;
 | 
			
		||||
extern const char* WalletDBInit[];
 | 
			
		||||
extern int WalletDBCount;
 | 
			
		||||
static constexpr
 | 
			
		||||
std::array<char const*, 3> LgrDBPragma {{
 | 
			
		||||
    "PRAGMA synchronous=NORMAL;",
 | 
			
		||||
    "PRAGMA journal_mode=WAL;",
 | 
			
		||||
    "PRAGMA journal_size_limit=1582080;"
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
static constexpr
 | 
			
		||||
std::array<char const*, 5> LgrDBInit {{
 | 
			
		||||
    "BEGIN TRANSACTION;",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS Ledgers (           \
 | 
			
		||||
        LedgerHash      CHARACTER(64) PRIMARY KEY,  \
 | 
			
		||||
        LedgerSeq       BIGINT UNSIGNED,            \
 | 
			
		||||
        PrevHash        CHARACTER(64),              \
 | 
			
		||||
        TotalCoins      BIGINT UNSIGNED,            \
 | 
			
		||||
        ClosingTime     BIGINT UNSIGNED,            \
 | 
			
		||||
        PrevClosingTime BIGINT UNSIGNED,            \
 | 
			
		||||
        CloseTimeRes    BIGINT UNSIGNED,            \
 | 
			
		||||
        CloseFlags      BIGINT UNSIGNED,            \
 | 
			
		||||
        AccountSetHash  CHARACTER(64),              \
 | 
			
		||||
        TransSetHash    CHARACTER(64)               \
 | 
			
		||||
    );",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS SeqLedger ON Ledgers(LedgerSeq);",
 | 
			
		||||
 | 
			
		||||
    // Old table and indexes no longer needed
 | 
			
		||||
    "DROP TABLE IF EXISTS Validations;",
 | 
			
		||||
 | 
			
		||||
    "END TRANSACTION;"
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Transaction database holds transactions and public keys
 | 
			
		||||
static constexpr auto TxDBName {"transaction.db"};
 | 
			
		||||
 | 
			
		||||
static constexpr
 | 
			
		||||
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
 | 
			
		||||
    std::array<char const*, 6> TxDBPragma {{
 | 
			
		||||
#else
 | 
			
		||||
    std::array<char const*, 5> TxDBPragma {{
 | 
			
		||||
#endif
 | 
			
		||||
    "PRAGMA page_size=4096;",
 | 
			
		||||
    "PRAGMA synchronous=NORMAL;",
 | 
			
		||||
    "PRAGMA journal_mode=WAL;",
 | 
			
		||||
    "PRAGMA journal_size_limit=1582080;",
 | 
			
		||||
    "PRAGMA max_page_count=2147483646;",
 | 
			
		||||
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
 | 
			
		||||
    "PRAGMA mmap_size=17179869184;"
 | 
			
		||||
#endif
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
static constexpr
 | 
			
		||||
std::array<char const*, 8> TxDBInit {{
 | 
			
		||||
    "BEGIN TRANSACTION;",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS Transactions (          \
 | 
			
		||||
        TransID     CHARACTER(64) PRIMARY KEY,          \
 | 
			
		||||
        TransType   CHARACTER(24),                      \
 | 
			
		||||
        FromAcct    CHARACTER(35),                      \
 | 
			
		||||
        FromSeq     BIGINT UNSIGNED,                    \
 | 
			
		||||
        LedgerSeq   BIGINT UNSIGNED,                    \
 | 
			
		||||
        Status      CHARACTER(1),                       \
 | 
			
		||||
        RawTxn      BLOB,                               \
 | 
			
		||||
        TxnMeta     BLOB                                \
 | 
			
		||||
    );",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS TxLgrIndex ON           \
 | 
			
		||||
        Transactions(LedgerSeq);",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS AccountTransactions (   \
 | 
			
		||||
        TransID     CHARACTER(64),                      \
 | 
			
		||||
        Account     CHARACTER(64),                      \
 | 
			
		||||
        LedgerSeq   BIGINT UNSIGNED,                    \
 | 
			
		||||
        TxnSeq      INTEGER                             \
 | 
			
		||||
    );",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS AcctTxIDIndex ON        \
 | 
			
		||||
        AccountTransactions(TransID);",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS AcctTxIndex ON          \
 | 
			
		||||
        AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);",
 | 
			
		||||
    "CREATE INDEX IF NOT EXISTS AcctLgrIndex ON         \
 | 
			
		||||
        AccountTransactions(LedgerSeq, Account, TransID);",
 | 
			
		||||
 | 
			
		||||
    "END TRANSACTION;"
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Pragma for Ledger and Transaction databases with complete shards
 | 
			
		||||
static constexpr
 | 
			
		||||
std::array<char const*, 2> CompleteShardDBPragma {{
 | 
			
		||||
    "PRAGMA synchronous=OFF;",
 | 
			
		||||
    "PRAGMA journal_mode=OFF;"
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
static constexpr auto WalletDBName {"wallet.db"};
 | 
			
		||||
 | 
			
		||||
static constexpr
 | 
			
		||||
std::array<char const*, 6> WalletDBInit {{
 | 
			
		||||
    "BEGIN TRANSACTION;",
 | 
			
		||||
 | 
			
		||||
    // A node's identity must be persisted, including
 | 
			
		||||
    // for clustering purposes. This table holds one
 | 
			
		||||
    // entry: the server's unique identity, but the
 | 
			
		||||
    // value can be overriden by specifying a node
 | 
			
		||||
    // identity in the config file using a [node_seed]
 | 
			
		||||
    // entry.
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS NodeIdentity (			\
 | 
			
		||||
        PublicKey       CHARACTER(53),					\
 | 
			
		||||
        PrivateKey      CHARACTER(52)					\
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    // Peer reservations
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS PeerReservations (		\
 | 
			
		||||
        PublicKey       CHARACTER(53) UNIQUE NOT NULL,	\
 | 
			
		||||
        Description     CHARACTER(64) NOT NULL			\
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    // Validator Manifests
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS ValidatorManifests (	\
 | 
			
		||||
        RawData          BLOB NOT NULL					\
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    "CREATE TABLE IF NOT EXISTS PublisherManifests (	\
 | 
			
		||||
        RawData          BLOB NOT NULL					\
 | 
			
		||||
    );",
 | 
			
		||||
 | 
			
		||||
    "END TRANSACTION;"
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
} // ripple
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -489,9 +489,12 @@ int run (int argc, char** argv)
 | 
			
		||||
            std::cerr << "vacuum not applicable in standalone mode.\n";
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        boost::filesystem::path dbPath = dbSetup.dataDir / TxnDBName;
 | 
			
		||||
        auto txnDB = std::make_unique<DatabaseCon> (dbSetup, TxnDBName,
 | 
			
		||||
            TxnDBInit, TxnDBCount);
 | 
			
		||||
        boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
 | 
			
		||||
        auto txnDB = std::make_unique<DatabaseCon>(
 | 
			
		||||
            dbSetup,
 | 
			
		||||
            TxDBName,
 | 
			
		||||
            TxDBPragma,
 | 
			
		||||
            TxDBInit);
 | 
			
		||||
        if (txnDB.get() == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            std::cerr << "Cannot create connection to " << dbPath.string() <<
 | 
			
		||||
@@ -711,7 +714,7 @@ int run (int argc, char** argv)
 | 
			
		||||
        // With our configuration parsed, ensure we have
 | 
			
		||||
        // enough file descriptors available:
 | 
			
		||||
        if (!adjustDescriptorLimit(
 | 
			
		||||
            app->fdlimit(),
 | 
			
		||||
            app->fdRequired(),
 | 
			
		||||
            app->logs().journal("Application")))
 | 
			
		||||
        {
 | 
			
		||||
            StopSustain();
 | 
			
		||||
 
 | 
			
		||||
@@ -62,8 +62,8 @@ public:
 | 
			
		||||
    /** Highest ledger that may be deleted. */
 | 
			
		||||
    virtual LedgerIndex getCanDelete() = 0;
 | 
			
		||||
 | 
			
		||||
    /** The number of files that are needed. */
 | 
			
		||||
    virtual int fdlimit() const = 0;
 | 
			
		||||
    /** Returns the number of file descriptors that are needed. */
 | 
			
		||||
    virtual int fdRequired() const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -254,7 +254,7 @@ SHAMapStoreImp::makeNodeStore(std::string const& name, std::int32_t readThreads)
 | 
			
		||||
            std::move(archiveBackend),
 | 
			
		||||
            app_.config().section(ConfigSection::nodeDatabase()),
 | 
			
		||||
            app_.logs().journal(nodeStoreName_));
 | 
			
		||||
        fdlimit_ += dbr->fdlimit();
 | 
			
		||||
        fdRequired_ += dbr->fdRequired();
 | 
			
		||||
        dbRotating_ = dbr.get();
 | 
			
		||||
        db.reset(dynamic_cast<NodeStore::Database*>(dbr.release()));
 | 
			
		||||
    }
 | 
			
		||||
@@ -267,7 +267,7 @@ SHAMapStoreImp::makeNodeStore(std::string const& name, std::int32_t readThreads)
 | 
			
		||||
            app_.getJobQueue(),
 | 
			
		||||
            app_.config().section(ConfigSection::nodeDatabase()),
 | 
			
		||||
            app_.logs().journal(nodeStoreName_));
 | 
			
		||||
        fdlimit_ += db->fdlimit();
 | 
			
		||||
        fdRequired_ += db->fdRequired();
 | 
			
		||||
    }
 | 
			
		||||
    return db;
 | 
			
		||||
}
 | 
			
		||||
@@ -298,9 +298,9 @@ SHAMapStoreImp::rendezvous() const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
SHAMapStoreImp::fdlimit () const
 | 
			
		||||
SHAMapStoreImp::fdRequired() const
 | 
			
		||||
{
 | 
			
		||||
    return fdlimit_;
 | 
			
		||||
    return fdRequired_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include <ripple/app/ledger/LedgerMaster.h>
 | 
			
		||||
#include <ripple/core/DatabaseCon.h>
 | 
			
		||||
#include <ripple/nodestore/DatabaseRotating.h>
 | 
			
		||||
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +98,7 @@ private:
 | 
			
		||||
    std::shared_ptr<Ledger const> newLedger_;
 | 
			
		||||
    std::atomic<bool> working_;
 | 
			
		||||
    std::atomic <LedgerIndex> canDelete_;
 | 
			
		||||
    int fdlimit_ = 0;
 | 
			
		||||
    int fdRequired_ = 0;
 | 
			
		||||
 | 
			
		||||
    std::uint32_t deleteInterval_ = 0;
 | 
			
		||||
    bool advisoryDelete_ = false;
 | 
			
		||||
@@ -172,7 +173,7 @@ public:
 | 
			
		||||
    void onLedgerClosed (std::shared_ptr<Ledger const> const& ledger) override;
 | 
			
		||||
 | 
			
		||||
    void rendezvous() const override;
 | 
			
		||||
    int fdlimit() const override;
 | 
			
		||||
    int fdRequired() const override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // callback for visitNodes
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ class Rules;
 | 
			
		||||
 | 
			
		||||
enum SizedItemName
 | 
			
		||||
{
 | 
			
		||||
    siSweepInterval,
 | 
			
		||||
    siSweepInterval = 0,
 | 
			
		||||
    siNodeCacheSize,
 | 
			
		||||
    siNodeCacheAge,
 | 
			
		||||
    siTreeCacheSize,
 | 
			
		||||
@@ -56,14 +56,32 @@ enum SizedItemName
 | 
			
		||||
    siLedgerFetch,
 | 
			
		||||
    siHashNodeDBCache,
 | 
			
		||||
    siTxnDBCache,
 | 
			
		||||
    siLgrDBCache,
 | 
			
		||||
    siLgrDBCache
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SizedItem
 | 
			
		||||
{
 | 
			
		||||
    SizedItemName   item;
 | 
			
		||||
    int             sizes[5];
 | 
			
		||||
};
 | 
			
		||||
static constexpr
 | 
			
		||||
std::array<std::array<int, 5>, 13> sizedItems
 | 
			
		||||
{{
 | 
			
		||||
    //  tiny      small   medium  large   huge
 | 
			
		||||
    {{  10,       30,     60,     90,     120     }}, // siSweepInterval
 | 
			
		||||
    {{  2,        3,      5,      5,      8       }}, // siLedgerFetch
 | 
			
		||||
 | 
			
		||||
    {{  16384,    32768,  131072, 262144, 524288  }}, // siNodeCacheSize
 | 
			
		||||
    {{  60,       90,     120,    900,    1800    }}, // siNodeCacheAge
 | 
			
		||||
 | 
			
		||||
    {{  128000,   256000, 512000, 768000, 2048000 }}, // siTreeCacheSize
 | 
			
		||||
    {{  30,       60,     90,     120,    900     }}, // siTreeCacheAge
 | 
			
		||||
 | 
			
		||||
    {{  4096,     8192,   16384,  65536,  131072  }}, // siSLECacheSize
 | 
			
		||||
    {{  30,       60,     90,     120,    300     }}, // siSLECacheAge
 | 
			
		||||
 | 
			
		||||
    {{  32,       128,    256,    384,    768     }}, // siLedgerSize
 | 
			
		||||
    {{  30,       90,     180,    240,    900     }}, // siLedgerAge
 | 
			
		||||
 | 
			
		||||
    {{  4,        12,     24,     64,     128     }}, // siHashNodeDBCache
 | 
			
		||||
    {{  4,        12,     24,     64,     128     }}, // siTxnDBCache
 | 
			
		||||
    {{  4,        8,      16,     32,     128     }}  // siLgrDBCache
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
//  This entire derived class is deprecated.
 | 
			
		||||
//  For new config information use the style implied
 | 
			
		||||
@@ -182,11 +200,23 @@ public:
 | 
			
		||||
    std::unordered_set<uint256, beast::uhash<>> features;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Config()
 | 
			
		||||
    : j_ {beast::Journal::getNullSink()}
 | 
			
		||||
    { }
 | 
			
		||||
    Config() : j_ {beast::Journal::getNullSink()} {}
 | 
			
		||||
 | 
			
		||||
    static
 | 
			
		||||
    int
 | 
			
		||||
    getSize(SizedItemName item, std::uint32_t nodeSize)
 | 
			
		||||
    {
 | 
			
		||||
        assert(item < sizedItems.size() && nodeSize < sizedItems[item].size());
 | 
			
		||||
        return sizedItems[item][nodeSize];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int
 | 
			
		||||
    getSize(SizedItemName item) const
 | 
			
		||||
    {
 | 
			
		||||
        assert(item < sizedItems.size());
 | 
			
		||||
        return getSize(item, NODE_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int getSize (SizedItemName) const;
 | 
			
		||||
    /* Be very careful to make sure these bool params
 | 
			
		||||
        are in the right order. */
 | 
			
		||||
    void setup (std::string const& strConf, bool bQuiet,
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +20,13 @@
 | 
			
		||||
#ifndef RIPPLE_APP_DATA_DATABASECON_H_INCLUDED
 | 
			
		||||
#define RIPPLE_APP_DATA_DATABASECON_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <ripple/app/main/DBInit.h>
 | 
			
		||||
#include <ripple/core/Config.h>
 | 
			
		||||
#include <ripple/core/SociDB.h>
 | 
			
		||||
#include <boost/filesystem/path.hpp>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace soci {
 | 
			
		||||
    class session;
 | 
			
		||||
}
 | 
			
		||||
@@ -86,10 +86,43 @@ public:
 | 
			
		||||
        boost::filesystem::path dataDir;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DatabaseCon (Setup const& setup,
 | 
			
		||||
                 std::string const& name,
 | 
			
		||||
                 const char* initString[],
 | 
			
		||||
                 int countInit);
 | 
			
		||||
    template<std::size_t N, std::size_t M>
 | 
			
		||||
    DatabaseCon(
 | 
			
		||||
        Setup const& setup,
 | 
			
		||||
        std::string const& DBName,
 | 
			
		||||
        std::array<char const*, N> const& pragma,
 | 
			
		||||
        std::array<char const*, M> const& initSQL)
 | 
			
		||||
    {
 | 
			
		||||
        // Use temporary files or regular DB files?
 | 
			
		||||
        auto const useTempFiles =
 | 
			
		||||
            setup.standAlone &&
 | 
			
		||||
            setup.startUp != Config::LOAD &&
 | 
			
		||||
            setup.startUp != Config::LOAD_FILE &&
 | 
			
		||||
            setup.startUp != Config::REPLAY;
 | 
			
		||||
        boost::filesystem::path pPath =
 | 
			
		||||
            useTempFiles ? "" : (setup.dataDir / DBName);
 | 
			
		||||
 | 
			
		||||
        open(session_, "sqlite", pPath.string());
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            for (auto const& p : pragma)
 | 
			
		||||
            {
 | 
			
		||||
                soci::statement st = session_.prepare << p;
 | 
			
		||||
                st.execute(true);
 | 
			
		||||
            }
 | 
			
		||||
            for (auto const& sql : initSQL)
 | 
			
		||||
            {
 | 
			
		||||
                soci::statement st = session_.prepare << sql;
 | 
			
		||||
                st.execute(true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (soci::soci_error&)
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: We should at least log this error. It is annoying to wire
 | 
			
		||||
            // a logger into every context, but there are other solutions.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    soci::session& getSession()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -559,42 +559,6 @@ void Config::loadFromString (std::string const& fileContents)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Config::getSize (SizedItemName item) const
 | 
			
		||||
{
 | 
			
		||||
    SizedItem sizeTable[] =   //    tiny    small   medium  large       huge
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        { siSweepInterval,      {   10,     30,     60,     90,         120     } },
 | 
			
		||||
 | 
			
		||||
        { siLedgerFetch,        {   2,      3,      5,      5,          8       } },
 | 
			
		||||
 | 
			
		||||
        { siNodeCacheSize,      {   16384,  32768,  131072, 262144,     524288  } },
 | 
			
		||||
        { siNodeCacheAge,       {   60,     90,     120,    900,        1800    } },
 | 
			
		||||
 | 
			
		||||
        { siTreeCacheSize,      {   128000, 256000, 512000, 768000,     2048000 } },
 | 
			
		||||
        { siTreeCacheAge,       {   30,     60,     90,     120,        900     } },
 | 
			
		||||
 | 
			
		||||
        { siSLECacheSize,       {   4096,   8192,   16384,  65536,      131072  } },
 | 
			
		||||
        { siSLECacheAge,        {   30,     60,     90,     120,        300     } },
 | 
			
		||||
 | 
			
		||||
        { siLedgerSize,         {   32,     128,    256,    384,        768     } },
 | 
			
		||||
        { siLedgerAge,          {   30,     90,     180,    240,        900     } },
 | 
			
		||||
 | 
			
		||||
        { siHashNodeDBCache,    {   4,      12,     24,     64,         128     } },
 | 
			
		||||
        { siTxnDBCache,         {   4,      12,     24,     64,         128     } },
 | 
			
		||||
        { siLgrDBCache,         {   4,      8,      16,     32,         128     } },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < (sizeof (sizeTable) / sizeof (SizedItem)); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        if (sizeTable[i].item == item)
 | 
			
		||||
            return sizeTable[i].sizes[NODE_SIZE];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert (false);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
boost::filesystem::path Config::getDebugLogFile () const
 | 
			
		||||
{
 | 
			
		||||
    auto log_file = DEBUG_LOGFILE;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,38 +25,6 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
DatabaseCon::DatabaseCon (
 | 
			
		||||
    Setup const& setup,
 | 
			
		||||
    std::string const& strName,
 | 
			
		||||
    const char* initStrings[],
 | 
			
		||||
    int initCount)
 | 
			
		||||
{
 | 
			
		||||
    auto const useTempFiles  // Use temporary files or regular DB files?
 | 
			
		||||
        = setup.standAlone &&
 | 
			
		||||
          setup.startUp != Config::LOAD &&
 | 
			
		||||
          setup.startUp != Config::LOAD_FILE &&
 | 
			
		||||
          setup.startUp != Config::REPLAY;
 | 
			
		||||
    boost::filesystem::path pPath = useTempFiles
 | 
			
		||||
        ? "" : (setup.dataDir / strName);
 | 
			
		||||
 | 
			
		||||
    open (session_, "sqlite", pPath.string());
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < initCount; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            soci::statement st = session_.prepare <<
 | 
			
		||||
                initStrings[i];
 | 
			
		||||
            st.execute(true);
 | 
			
		||||
        }
 | 
			
		||||
        catch (soci::soci_error&)
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: We should at least log this error. It is annoying to wire
 | 
			
		||||
            // a logger into every context, but there are other solutions.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DatabaseCon::Setup setup_DatabaseCon (Config const& c)
 | 
			
		||||
{
 | 
			
		||||
    DatabaseCon::Setup setup;
 | 
			
		||||
 
 | 
			
		||||
@@ -112,14 +112,14 @@ public:
 | 
			
		||||
    /** Perform consistency checks on database. */
 | 
			
		||||
    virtual void verify() = 0;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of file handles the backend expects to need. */
 | 
			
		||||
    virtual int fdlimit() const = 0;
 | 
			
		||||
    /** Returns the number of file descriptors the backend expects to need. */
 | 
			
		||||
    virtual int fdRequired() const = 0;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the backend uses permanent storage. */
 | 
			
		||||
    bool
 | 
			
		||||
    backed() const
 | 
			
		||||
    {
 | 
			
		||||
        return fdlimit();
 | 
			
		||||
        return fdRequired();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -204,9 +204,9 @@ public:
 | 
			
		||||
    std::uint32_t
 | 
			
		||||
    getFetchSize() const { return fetchSz_; }
 | 
			
		||||
 | 
			
		||||
    /** Return the number of files needed by our backend(s) */
 | 
			
		||||
    /** Returns the number of file descriptors the database expects to need */
 | 
			
		||||
    int
 | 
			
		||||
    fdlimit() const { return fdLimit_; }
 | 
			
		||||
    fdRequired() const { return fdRequired_; }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    onStop() override;
 | 
			
		||||
@@ -222,7 +222,7 @@ public:
 | 
			
		||||
protected:
 | 
			
		||||
    beast::Journal j_;
 | 
			
		||||
    Scheduler& scheduler_;
 | 
			
		||||
    int fdLimit_ {0};
 | 
			
		||||
    int fdRequired_ {0};
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    stopThreads();
 | 
			
		||||
 
 | 
			
		||||
@@ -191,7 +191,7 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int
 | 
			
		||||
    fdlimit() const override
 | 
			
		||||
    fdRequired() const override
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -297,7 +297,7 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int
 | 
			
		||||
    fdlimit() const override
 | 
			
		||||
    fdRequired() const override
 | 
			
		||||
    {
 | 
			
		||||
        return 3;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -98,9 +98,9 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of file handles the backend expects to need */
 | 
			
		||||
    /** Returns the number of file descriptors the backend expects to need */
 | 
			
		||||
    int
 | 
			
		||||
    fdlimit() const override
 | 
			
		||||
    fdRequired() const override
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ public:
 | 
			
		||||
    BatchWriter m_batch;
 | 
			
		||||
    std::string m_name;
 | 
			
		||||
    std::unique_ptr <rocksdb::DB> m_db;
 | 
			
		||||
    int fdlimit_ = 2048;
 | 
			
		||||
    int fdRequired_ = 2048;
 | 
			
		||||
    rocksdb::Options m_options;
 | 
			
		||||
 | 
			
		||||
    RocksDBBackend (int keyBytes, Section const& keyValues,
 | 
			
		||||
@@ -128,7 +128,7 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (get_if_exists (keyValues, "open_files", m_options.max_open_files))
 | 
			
		||||
            fdlimit_ = m_options.max_open_files;
 | 
			
		||||
            fdRequired_ = m_options.max_open_files;
 | 
			
		||||
 | 
			
		||||
        if (keyValues.exists ("file_size_mb"))
 | 
			
		||||
        {
 | 
			
		||||
@@ -405,11 +405,11 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of file handles the backend expects to need */
 | 
			
		||||
    /** Returns the number of file descriptors the backend expects to need */
 | 
			
		||||
    int
 | 
			
		||||
    fdlimit() const override
 | 
			
		||||
    fdRequired() const override
 | 
			
		||||
    {
 | 
			
		||||
        return fdlimit_;
 | 
			
		||||
        return fdRequired_;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,9 +42,9 @@ DatabaseRotatingImp::DatabaseRotatingImp(
 | 
			
		||||
    , archiveBackend_(std::move(archiveBackend))
 | 
			
		||||
{
 | 
			
		||||
    if (writableBackend_)
 | 
			
		||||
        fdLimit_ += writableBackend_->fdlimit();
 | 
			
		||||
        fdRequired_ += writableBackend_->fdRequired();
 | 
			
		||||
    if (archiveBackend_)
 | 
			
		||||
        fdLimit_ += archiveBackend_->fdlimit();
 | 
			
		||||
        fdRequired_ += archiveBackend_->fdRequired();
 | 
			
		||||
    setParent(parent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -157,7 +157,7 @@ public:
 | 
			
		||||
    getCacheHitRate() override;
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    tune(int size, std::chrono::seconds age) override;
 | 
			
		||||
    tune(int size, std::chrono::seconds age) override {};
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    sweep() override;
 | 
			
		||||
@@ -194,11 +194,11 @@ private:
 | 
			
		||||
    // The name associated with the backend used with the shard store
 | 
			
		||||
    std::string backendName_;
 | 
			
		||||
 | 
			
		||||
    // Maximum disk space the DB can use (in bytes)
 | 
			
		||||
    std::uint64_t maxDiskSpace_;
 | 
			
		||||
    // Maximum storage space the shard store can utilize (in bytes)
 | 
			
		||||
    std::uint64_t maxFileSz_;
 | 
			
		||||
 | 
			
		||||
    // Disk space used to store the shards (in bytes)
 | 
			
		||||
    std::uint64_t usedDiskSpace_ {0};
 | 
			
		||||
    // Storage space utilized by the shard store (in bytes)
 | 
			
		||||
    std::uint64_t fileSz_ {0};
 | 
			
		||||
 | 
			
		||||
    // Each shard stores 16384 ledgers. The earliest shard may store
 | 
			
		||||
    // less if the earliest ledger sequence truncates its beginning.
 | 
			
		||||
@@ -208,16 +208,12 @@ private:
 | 
			
		||||
    // The earliest shard index
 | 
			
		||||
    std::uint32_t const earliestShardIndex_;
 | 
			
		||||
 | 
			
		||||
    // Average disk space a shard requires (in bytes)
 | 
			
		||||
    std::uint64_t avgShardSz_;
 | 
			
		||||
 | 
			
		||||
    // Shard cache tuning
 | 
			
		||||
    int cacheSz_ {shardCacheSz};
 | 
			
		||||
    std::chrono::seconds cacheAge_ {shardCacheAge};
 | 
			
		||||
    // Average storage space required by a shard (in bytes)
 | 
			
		||||
    std::uint64_t avgShardFileSz_;
 | 
			
		||||
 | 
			
		||||
    // File name used to mark shards being imported from node store
 | 
			
		||||
    static constexpr auto importMarker_ = "import";
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<NodeObject>
 | 
			
		||||
    fetchFrom(uint256 const& hash, std::uint32_t seq) override;
 | 
			
		||||
 | 
			
		||||
@@ -233,23 +229,19 @@ private:
 | 
			
		||||
    findShardIndexToAdd(std::uint32_t validLedgerSeq,
 | 
			
		||||
        std::lock_guard<std::mutex>&);
 | 
			
		||||
 | 
			
		||||
    // Updates stats
 | 
			
		||||
    // Set storage and file descriptor usage stats
 | 
			
		||||
    // Lock must be held
 | 
			
		||||
    void
 | 
			
		||||
    updateStats(std::lock_guard<std::mutex>&);
 | 
			
		||||
    setFileStats(std::lock_guard<std::mutex>&);
 | 
			
		||||
 | 
			
		||||
    // Update status string
 | 
			
		||||
    // Lock must be held
 | 
			
		||||
    void
 | 
			
		||||
    updateStatus(std::lock_guard<std::mutex>&);
 | 
			
		||||
 | 
			
		||||
    std::pair<std::shared_ptr<PCache>, std::shared_ptr<NCache>>
 | 
			
		||||
    selectCache(std::uint32_t seq);
 | 
			
		||||
 | 
			
		||||
    // Returns the tune cache size divided by the number of shards
 | 
			
		||||
    // Lock must be held
 | 
			
		||||
    int
 | 
			
		||||
    calcTargetCacheSz(std::lock_guard<std::mutex>&) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::max(shardCacheSz, cacheSz_ / std::max(
 | 
			
		||||
            1, static_cast<int>(complete_.size() + (incomplete_ ? 1 : 0))));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns available storage space
 | 
			
		||||
    std::uint64_t
 | 
			
		||||
    available() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,27 +19,31 @@
 | 
			
		||||
 | 
			
		||||
#include <ripple/nodestore/impl/Shard.h>
 | 
			
		||||
#include <ripple/app/ledger/InboundLedger.h>
 | 
			
		||||
#include <ripple/app/main/DBInit.h>
 | 
			
		||||
#include <ripple/basics/StringUtilities.h>
 | 
			
		||||
#include <ripple/core/ConfigSections.h>
 | 
			
		||||
#include <ripple/nodestore/impl/DatabaseShardImp.h>
 | 
			
		||||
#include <ripple/nodestore/Manager.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
#include <boost/range/adaptor/transformed.hpp>
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
namespace NodeStore {
 | 
			
		||||
 | 
			
		||||
Shard::Shard(DatabaseShard const& db, std::uint32_t index,
 | 
			
		||||
    int cacheSz, std::chrono::seconds cacheAge, beast::Journal& j)
 | 
			
		||||
    : index_(index)
 | 
			
		||||
Shard::Shard(
 | 
			
		||||
    Application& app,
 | 
			
		||||
    DatabaseShard const& db,
 | 
			
		||||
    std::uint32_t index,
 | 
			
		||||
    beast::Journal& j)
 | 
			
		||||
    : app_(app)
 | 
			
		||||
    , index_(index)
 | 
			
		||||
    , firstSeq_(db.firstLedgerSeq(index))
 | 
			
		||||
    , lastSeq_(std::max(firstSeq_, db.lastLedgerSeq(index)))
 | 
			
		||||
    , maxLedgers_(index == db.earliestShardIndex() ?
 | 
			
		||||
        lastSeq_ - firstSeq_ + 1 : db.ledgersPerShard())
 | 
			
		||||
    , pCache_(std::make_shared<PCache>(
 | 
			
		||||
        "shard " + std::to_string(index_),
 | 
			
		||||
        cacheSz, cacheAge, stopwatch(), j))
 | 
			
		||||
    , nCache_(std::make_shared<NCache>(
 | 
			
		||||
        "shard " + std::to_string(index_),
 | 
			
		||||
        stopwatch(), cacheSz, cacheAge))
 | 
			
		||||
    , dir_(db.getRootDir() / std::to_string(index_))
 | 
			
		||||
    , control_(dir_ / controlFileName)
 | 
			
		||||
    , j_(j)
 | 
			
		||||
@@ -49,38 +53,47 @@ Shard::Shard(DatabaseShard const& db, std::uint32_t index,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::open(Section config, Scheduler& scheduler, nudb::context& ctx)
 | 
			
		||||
Shard::open(Scheduler& scheduler, nudb::context& ctx)
 | 
			
		||||
{
 | 
			
		||||
    assert(!backend_);
 | 
			
		||||
    using namespace boost::filesystem;
 | 
			
		||||
    using namespace boost::beast::detail;
 | 
			
		||||
 | 
			
		||||
    std::string const type (get<std::string>(config, "type", "nudb"));
 | 
			
		||||
    Config const& config {app_.config()};
 | 
			
		||||
    Section section {config.section(ConfigSection::shardDatabase())};
 | 
			
		||||
    std::string const type (get<std::string>(section, "type", "nudb"));
 | 
			
		||||
    auto factory {Manager::instance().find(type)};
 | 
			
		||||
    if (!factory)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            ": failed to create shard store type " << type;
 | 
			
		||||
            " failed to create backend type " << type;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    config.set("path", dir_.string());
 | 
			
		||||
    section.set("path", dir_.string());
 | 
			
		||||
    backend_ = factory->createInstance(
 | 
			
		||||
        NodeObject::keyBytes, config, scheduler, ctx, j_);
 | 
			
		||||
        NodeObject::keyBytes, section, scheduler, ctx, j_);
 | 
			
		||||
 | 
			
		||||
    auto const preexist {exists(dir_)};
 | 
			
		||||
    auto fail = [&](std::string msg)
 | 
			
		||||
    auto fail = [this, preexist](std::string const& msg)
 | 
			
		||||
    {
 | 
			
		||||
        pCache_.reset();
 | 
			
		||||
        nCache_.reset();
 | 
			
		||||
        backend_.reset();
 | 
			
		||||
        lgrSQLiteDB_.reset();
 | 
			
		||||
        txSQLiteDB_.reset();
 | 
			
		||||
        storedSeqs_.clear();
 | 
			
		||||
        lastStored_.reset();
 | 
			
		||||
 | 
			
		||||
        if (!preexist)
 | 
			
		||||
            removeAll(dir_, j_);
 | 
			
		||||
 | 
			
		||||
        if (!msg.empty())
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "shard " << index_ << ": " << msg;
 | 
			
		||||
                "shard " << index_ << " " << msg;
 | 
			
		||||
        }
 | 
			
		||||
        if (backend_)
 | 
			
		||||
            backend_->close();
 | 
			
		||||
        if (!preexist)
 | 
			
		||||
            removeAll(dir_, j_);
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -112,100 +125,84 @@ Shard::open(Section config, Scheduler& scheduler, nudb::context& ctx)
 | 
			
		||||
                if (boost::icl::first(storedSeqs_) < firstSeq_ ||
 | 
			
		||||
                    boost::icl::last(storedSeqs_) > lastSeq_)
 | 
			
		||||
                {
 | 
			
		||||
                    return fail("invalid control file");
 | 
			
		||||
                    return fail("has an invalid control file");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (boost::icl::length(storedSeqs_) >= maxLedgers_)
 | 
			
		||||
                {
 | 
			
		||||
                    JLOG(j_.error()) <<
 | 
			
		||||
                    JLOG(j_.warn()) <<
 | 
			
		||||
                        "shard " << index_ <<
 | 
			
		||||
                        ": found control file for complete shard";
 | 
			
		||||
                    storedSeqs_.clear();
 | 
			
		||||
                    complete_ = true;
 | 
			
		||||
                        " has a control file for complete shard";
 | 
			
		||||
                    setComplete();
 | 
			
		||||
                    remove_all(control_);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            complete_ = true;
 | 
			
		||||
            setComplete();
 | 
			
		||||
 | 
			
		||||
        // Calculate file foot print of backend files
 | 
			
		||||
        for (auto const& p : recursive_directory_iterator(dir_))
 | 
			
		||||
            if (!is_directory(p))
 | 
			
		||||
                fileSize_ += file_size(p);
 | 
			
		||||
        setCache();
 | 
			
		||||
        if (!initSQLite() || !setFileStats())
 | 
			
		||||
            return fail({});
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception const& e)
 | 
			
		||||
    {
 | 
			
		||||
        return fail(e.what());
 | 
			
		||||
        return fail(std::string("exception ") +
 | 
			
		||||
            e.what() + " in function " + __func__);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::setStored(std::shared_ptr<Ledger const> const& l)
 | 
			
		||||
Shard::setStored(std::shared_ptr<Ledger const> const& ledger)
 | 
			
		||||
{
 | 
			
		||||
    assert(backend_&& !complete_);
 | 
			
		||||
    if (boost::icl::contains(storedSeqs_, l->info().seq))
 | 
			
		||||
    if (boost::icl::contains(storedSeqs_, ledger->info().seq))
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.debug()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            " ledger seq " << l->info().seq <<
 | 
			
		||||
            " already stored";
 | 
			
		||||
            " has ledger sequence " << ledger->info().seq << " already stored";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!setSQLiteStored(ledger))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // Check if the shard is complete
 | 
			
		||||
    if (boost::icl::length(storedSeqs_) >= maxLedgers_ - 1)
 | 
			
		||||
    {
 | 
			
		||||
        setComplete();
 | 
			
		||||
        if (backend_->backed())
 | 
			
		||||
        {
 | 
			
		||||
            if (!removeAll(control_, j_))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            // Update file foot print of backend files
 | 
			
		||||
            using namespace boost::filesystem;
 | 
			
		||||
            std::uint64_t sz {0};
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                for (auto const& p : recursive_directory_iterator(dir_))
 | 
			
		||||
                    if (!is_directory(p))
 | 
			
		||||
                        sz += file_size(p);
 | 
			
		||||
            }
 | 
			
		||||
            catch (const filesystem_error& e)
 | 
			
		||||
            {
 | 
			
		||||
                JLOG(j_.error()) <<
 | 
			
		||||
                    "exception: " << e.what();
 | 
			
		||||
                fileSize_ = std::max(fileSize_, sz);
 | 
			
		||||
            setCache();
 | 
			
		||||
            if (!initSQLite() || !setFileStats())
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            fileSize_ = sz;
 | 
			
		||||
        }
 | 
			
		||||
        complete_ = true;
 | 
			
		||||
        storedSeqs_.clear();
 | 
			
		||||
 | 
			
		||||
        JLOG(j_.debug()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            " ledger seq " << l->info().seq <<
 | 
			
		||||
            " stored. Shard complete";
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        storedSeqs_.insert(l->info().seq);
 | 
			
		||||
        lastStored_ = l;
 | 
			
		||||
        storedSeqs_.insert(ledger->info().seq);
 | 
			
		||||
        if (backend_->backed() && !saveControl())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        JLOG(j_.debug()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            " ledger seq " << l->info().seq <<
 | 
			
		||||
            " stored";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JLOG(j_.debug()) <<
 | 
			
		||||
        "shard " << index_ <<
 | 
			
		||||
        " stored ledger sequence " << ledger->info().seq <<
 | 
			
		||||
        (complete_ ? " and is complete" : "");
 | 
			
		||||
 | 
			
		||||
    lastStored_ = ledger;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
boost::optional<std::uint32_t>
 | 
			
		||||
Shard::prepare()
 | 
			
		||||
{
 | 
			
		||||
    assert(backend_);
 | 
			
		||||
    if (storedSeqs_.empty())
 | 
			
		||||
         return lastSeq_;
 | 
			
		||||
    return prevMissing(storedSeqs_, 1 + lastSeq_, firstSeq_);
 | 
			
		||||
@@ -214,6 +211,7 @@ Shard::prepare()
 | 
			
		||||
bool
 | 
			
		||||
Shard::contains(std::uint32_t seq) const
 | 
			
		||||
{
 | 
			
		||||
    assert(backend_);
 | 
			
		||||
    if (seq < firstSeq_ || seq > lastSeq_)
 | 
			
		||||
        return false;
 | 
			
		||||
    if (complete_)
 | 
			
		||||
@@ -221,44 +219,53 @@ Shard::contains(std::uint32_t seq) const
 | 
			
		||||
    return boost::icl::contains(storedSeqs_, seq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Shard::sweep()
 | 
			
		||||
{
 | 
			
		||||
    assert(backend_);
 | 
			
		||||
    pCache_->sweep();
 | 
			
		||||
    nCache_->sweep();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::validate(Application& app)
 | 
			
		||||
Shard::validate()
 | 
			
		||||
{
 | 
			
		||||
    uint256 hash;
 | 
			
		||||
    std::uint32_t seq;
 | 
			
		||||
    std::shared_ptr<Ledger> l;
 | 
			
		||||
    std::shared_ptr<Ledger> ledger;
 | 
			
		||||
    auto fail = [this](std::string const& msg)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) << "shard " << index_ << " " << msg;
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Find the hash of the last ledger in this shard
 | 
			
		||||
    {
 | 
			
		||||
        std::tie(l, seq, hash) = loadLedgerHelper(
 | 
			
		||||
        std::tie(ledger, seq, hash) = loadLedgerHelper(
 | 
			
		||||
            "WHERE LedgerSeq >= " + std::to_string(lastSeq_) +
 | 
			
		||||
            " order by LedgerSeq desc limit 1", app, false);
 | 
			
		||||
        if (!l)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "shard " << index_ <<
 | 
			
		||||
                " unable to validate. No lookup data";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
            " order by LedgerSeq desc limit 1", app_, false);
 | 
			
		||||
        if (!ledger)
 | 
			
		||||
            return fail("is unable to validate due to lacking lookup data");
 | 
			
		||||
 | 
			
		||||
        if (seq != lastSeq_)
 | 
			
		||||
        {
 | 
			
		||||
            l->setImmutable(app.config());
 | 
			
		||||
            ledger->setImmutable(app_.config());
 | 
			
		||||
            boost::optional<uint256> h;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                h = hashOfSeq(*l, lastSeq_, j_);
 | 
			
		||||
                h = hashOfSeq(*ledger, lastSeq_, j_);
 | 
			
		||||
            }
 | 
			
		||||
            catch (std::exception const& e)
 | 
			
		||||
            {
 | 
			
		||||
                JLOG(j_.error()) <<
 | 
			
		||||
                    "exception: " << e.what();
 | 
			
		||||
                return false;
 | 
			
		||||
                return fail(std::string("exception ") +
 | 
			
		||||
                    e.what() + " in function " + __func__);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!h)
 | 
			
		||||
            {
 | 
			
		||||
                JLOG(j_.error()) <<
 | 
			
		||||
                    "shard " << index_ <<
 | 
			
		||||
                    " No hash for last ledger seq " << lastSeq_;
 | 
			
		||||
                return false;
 | 
			
		||||
                return fail("is missing hash for last ledger sequence " +
 | 
			
		||||
                    std::to_string(lastSeq_));
 | 
			
		||||
            }
 | 
			
		||||
            hash = *h;
 | 
			
		||||
            seq = lastSeq_;
 | 
			
		||||
@@ -266,9 +273,8 @@ Shard::validate(Application& app)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JLOG(j_.debug()) <<
 | 
			
		||||
        "Validating shard " << index_ <<
 | 
			
		||||
        " ledgers " << firstSeq_ <<
 | 
			
		||||
        "-" << lastSeq_;
 | 
			
		||||
        "shard " << index_ <<
 | 
			
		||||
        " has ledger sequences " << firstSeq_ << "-" << lastSeq_;
 | 
			
		||||
 | 
			
		||||
    // Use a short age to keep memory consumption low
 | 
			
		||||
    auto const savedAge {pCache_->getTargetAge()};
 | 
			
		||||
@@ -282,44 +288,45 @@ Shard::validate(Application& app)
 | 
			
		||||
        auto nObj = valFetch(hash);
 | 
			
		||||
        if (!nObj)
 | 
			
		||||
            break;
 | 
			
		||||
        l = std::make_shared<Ledger>(
 | 
			
		||||
        ledger = std::make_shared<Ledger>(
 | 
			
		||||
            InboundLedger::deserializeHeader(makeSlice(nObj->getData()),
 | 
			
		||||
                true), app.config(), *app.shardFamily());
 | 
			
		||||
        if (l->info().hash != hash || l->info().seq != seq)
 | 
			
		||||
                true), app_.config(), *app_.shardFamily());
 | 
			
		||||
        if (ledger->info().seq != seq)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "ledger seq " << seq <<
 | 
			
		||||
                " hash " << hash <<
 | 
			
		||||
                " cannot be a ledger";
 | 
			
		||||
            fail("encountered invalid ledger sequence " + std::to_string(seq));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        l->stateMap().setLedgerSeq(seq);
 | 
			
		||||
        l->txMap().setLedgerSeq(seq);
 | 
			
		||||
        l->setImmutable(app.config());
 | 
			
		||||
        if (!l->stateMap().fetchRoot(
 | 
			
		||||
            SHAMapHash {l->info().accountHash}, nullptr))
 | 
			
		||||
        if (ledger->info().hash != hash)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "ledger seq " << seq <<
 | 
			
		||||
                " missing Account State root";
 | 
			
		||||
            fail("encountered invalid ledger hash " + to_string(hash) +
 | 
			
		||||
                " on sequence " + std::to_string(seq));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (l->info().txHash.isNonZero())
 | 
			
		||||
        ledger->stateMap().setLedgerSeq(seq);
 | 
			
		||||
        ledger->txMap().setLedgerSeq(seq);
 | 
			
		||||
        ledger->setImmutable(app_.config());
 | 
			
		||||
        if (!ledger->stateMap().fetchRoot(
 | 
			
		||||
            SHAMapHash {ledger->info().accountHash}, nullptr))
 | 
			
		||||
        {
 | 
			
		||||
            if (!l->txMap().fetchRoot(
 | 
			
		||||
                SHAMapHash {l->info().txHash}, nullptr))
 | 
			
		||||
            fail("is missing root STATE node on sequence " +
 | 
			
		||||
                std::to_string(seq));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (ledger->info().txHash.isNonZero())
 | 
			
		||||
        {
 | 
			
		||||
            if (!ledger->txMap().fetchRoot(
 | 
			
		||||
                SHAMapHash {ledger->info().txHash}, nullptr))
 | 
			
		||||
            {
 | 
			
		||||
                JLOG(j_.error()) <<
 | 
			
		||||
                    "ledger seq " << seq <<
 | 
			
		||||
                    " missing TX root";
 | 
			
		||||
                fail("is missing root TXN node on sequence " +
 | 
			
		||||
                    std::to_string(seq));
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!valLedger(l, next))
 | 
			
		||||
        if (!valLedger(ledger, next))
 | 
			
		||||
            break;
 | 
			
		||||
        hash = l->info().parentHash;
 | 
			
		||||
        hash = ledger->info().parentHash;
 | 
			
		||||
        --seq;
 | 
			
		||||
        next = l;
 | 
			
		||||
        next = ledger;
 | 
			
		||||
        if (seq % 128 == 0)
 | 
			
		||||
            pCache_->sweep();
 | 
			
		||||
    }
 | 
			
		||||
@@ -330,79 +337,87 @@ Shard::validate(Application& app)
 | 
			
		||||
 | 
			
		||||
    if (seq >= firstSeq_)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            (complete_ ? " is invalid, failed" : " is incomplete, stopped") <<
 | 
			
		||||
            " at seq " << seq <<
 | 
			
		||||
            " hash " << hash;
 | 
			
		||||
        return false;
 | 
			
		||||
        return fail(std::string(" is ") +
 | 
			
		||||
            (complete_ ? "invalid, failed" : "incomplete, stopped") +
 | 
			
		||||
            " on hash " + to_string(hash) + " on sequence " +
 | 
			
		||||
            std::to_string(seq));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JLOG(j_.debug()) <<
 | 
			
		||||
        "shard " << index_ <<
 | 
			
		||||
        " is complete.";
 | 
			
		||||
        "shard " << index_ << " is valid and complete";
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::valLedger(std::shared_ptr<Ledger const> const& l,
 | 
			
		||||
Shard::valLedger(std::shared_ptr<Ledger const> const& ledger,
 | 
			
		||||
    std::shared_ptr<Ledger const> const& next)
 | 
			
		||||
{
 | 
			
		||||
    if (l->info().hash.isZero() || l->info().accountHash.isZero())
 | 
			
		||||
    auto fail = [this](std::string const& msg)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) <<
 | 
			
		||||
            "invalid ledger";
 | 
			
		||||
        JLOG(j_.error()) << "shard " << index_ << " " << msg;
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (ledger->info().hash.isZero())
 | 
			
		||||
    {
 | 
			
		||||
        return fail("encountered a zero ledger hash on sequence " +
 | 
			
		||||
            std::to_string(ledger->info().seq));
 | 
			
		||||
    }
 | 
			
		||||
    if (ledger->info().accountHash.isZero())
 | 
			
		||||
    {
 | 
			
		||||
        return fail("encountered a zero account hash on sequence " +
 | 
			
		||||
            std::to_string(ledger->info().seq));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool error {false};
 | 
			
		||||
    auto f = [&, this](SHAMapAbstractNode& node) {
 | 
			
		||||
    auto f = [this, &error](SHAMapAbstractNode& node)
 | 
			
		||||
    {
 | 
			
		||||
        if (!valFetch(node.getNodeHash().as_uint256()))
 | 
			
		||||
            error = true;
 | 
			
		||||
        return !error;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Validate the state map
 | 
			
		||||
    if (l->stateMap().getHash().isNonZero())
 | 
			
		||||
    if (ledger->stateMap().getHash().isNonZero())
 | 
			
		||||
    {
 | 
			
		||||
        if (!l->stateMap().isValid())
 | 
			
		||||
        if (!ledger->stateMap().isValid())
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "invalid state map";
 | 
			
		||||
            return false;
 | 
			
		||||
            return fail("has an invalid state map on sequence " +
 | 
			
		||||
                std::to_string(ledger->info().seq));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            if (next && next->info().parentHash == l->info().hash)
 | 
			
		||||
                l->stateMap().visitDifferences(&next->stateMap(), f);
 | 
			
		||||
            if (next && next->info().parentHash == ledger->info().hash)
 | 
			
		||||
                ledger->stateMap().visitDifferences(&next->stateMap(), f);
 | 
			
		||||
            else
 | 
			
		||||
                l->stateMap().visitNodes(f);
 | 
			
		||||
                ledger->stateMap().visitNodes(f);
 | 
			
		||||
        }
 | 
			
		||||
        catch (std::exception const& e)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "exception: " << e.what();
 | 
			
		||||
            return false;
 | 
			
		||||
            return fail(std::string("exception ") +
 | 
			
		||||
                e.what() + " in function " + __func__);
 | 
			
		||||
        }
 | 
			
		||||
        if (error)
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    // Validate the tx map
 | 
			
		||||
    if (l->info().txHash.isNonZero())
 | 
			
		||||
    // Validate the transaction map
 | 
			
		||||
    if (ledger->info().txHash.isNonZero())
 | 
			
		||||
    {
 | 
			
		||||
        if (!l->txMap().isValid())
 | 
			
		||||
        if (!ledger->txMap().isValid())
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "invalid transaction map";
 | 
			
		||||
            return false;
 | 
			
		||||
            return fail("has an invalid transaction map on sequence " +
 | 
			
		||||
                std::to_string(ledger->info().seq));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            l->txMap().visitNodes(f);
 | 
			
		||||
            ledger->txMap().visitNodes(f);
 | 
			
		||||
        }
 | 
			
		||||
        catch (std::exception const& e)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "exception: " << e.what();
 | 
			
		||||
            return false;
 | 
			
		||||
            return fail(std::string("exception ") +
 | 
			
		||||
                e.what() + " in function " + __func__);
 | 
			
		||||
        }
 | 
			
		||||
        if (error)
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -415,6 +430,11 @@ Shard::valFetch(uint256 const& hash)
 | 
			
		||||
{
 | 
			
		||||
    assert(backend_);
 | 
			
		||||
    std::shared_ptr<NodeObject> nObj;
 | 
			
		||||
    auto fail = [this](std::string const& msg)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) << "shard " << index_ << " " << msg;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        switch (backend_->fetch(hash.begin(), &nObj))
 | 
			
		||||
@@ -423,29 +443,324 @@ Shard::valFetch(uint256 const& hash)
 | 
			
		||||
            break;
 | 
			
		||||
        case notFound:
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "NodeObject not found. hash " << hash;
 | 
			
		||||
            fail("is missing node object on hash " + to_string(hash));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case dataCorrupt:
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "NodeObject is corrupt. hash " << hash;
 | 
			
		||||
            fail("has a corrupt node object on hash " + to_string(hash));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "unknown error. hash " << hash;
 | 
			
		||||
            fail("encountered unknown error on hash " + to_string(hash));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception const& e)
 | 
			
		||||
    {
 | 
			
		||||
        fail(std::string("exception ") +
 | 
			
		||||
            e.what() + " in function " + __func__);
 | 
			
		||||
    }
 | 
			
		||||
    return nObj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Shard::setComplete()
 | 
			
		||||
{
 | 
			
		||||
    storedSeqs_.clear();
 | 
			
		||||
    complete_ = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Shard::setCache()
 | 
			
		||||
{
 | 
			
		||||
    // complete shards use the smallest cache and
 | 
			
		||||
    // fastest expiration to reduce memory consumption.
 | 
			
		||||
    // The incomplete shard is set according to configuration.
 | 
			
		||||
    if (!pCache_)
 | 
			
		||||
    {
 | 
			
		||||
        auto const name {"shard " + std::to_string(index_)};
 | 
			
		||||
        auto const sz {complete_ ?
 | 
			
		||||
            Config::getSize(siNodeCacheSize, 0) :
 | 
			
		||||
            app_.config().getSize(siNodeCacheSize)};
 | 
			
		||||
        auto const age {std::chrono::seconds{complete_ ?
 | 
			
		||||
            Config::getSize(siNodeCacheAge, 0) :
 | 
			
		||||
            app_.config().getSize(siNodeCacheAge)}};
 | 
			
		||||
 | 
			
		||||
        pCache_ = std::make_shared<PCache>(name, sz, age, stopwatch(), j_);
 | 
			
		||||
        nCache_ = std::make_shared<NCache>(name, stopwatch(), sz, age);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        auto const sz {Config::getSize(siNodeCacheSize, 0)};
 | 
			
		||||
        pCache_->setTargetSize(sz);
 | 
			
		||||
        nCache_->setTargetSize(sz);
 | 
			
		||||
 | 
			
		||||
        auto const age {std::chrono::seconds{
 | 
			
		||||
            Config::getSize(siNodeCacheAge, 0)}};
 | 
			
		||||
        pCache_->setTargetAge(age);
 | 
			
		||||
        nCache_->setTargetAge(age);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::initSQLite()
 | 
			
		||||
{
 | 
			
		||||
    Config const& config {app_.config()};
 | 
			
		||||
    DatabaseCon::Setup setup;
 | 
			
		||||
    setup.startUp = config.START_UP;
 | 
			
		||||
    setup.standAlone = config.standalone();
 | 
			
		||||
    setup.dataDir = dir_;
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        if (complete_)
 | 
			
		||||
        {
 | 
			
		||||
            using namespace boost::filesystem;
 | 
			
		||||
 | 
			
		||||
            // Remove WAL files if they exist
 | 
			
		||||
            for (auto const& d : directory_iterator(dir_))
 | 
			
		||||
            {
 | 
			
		||||
                if (is_regular_file(d) &&
 | 
			
		||||
                    boost::iends_with(extension(d), "-wal"))
 | 
			
		||||
                {
 | 
			
		||||
                    // Closing the session forces a checkpoint
 | 
			
		||||
                    if (!lgrSQLiteDB_)
 | 
			
		||||
                    {
 | 
			
		||||
                        lgrSQLiteDB_ = std::make_unique <DatabaseCon>(
 | 
			
		||||
                            setup,
 | 
			
		||||
                            LgrDBName,
 | 
			
		||||
                            LgrDBPragma,
 | 
			
		||||
                            LgrDBInit);
 | 
			
		||||
                    }
 | 
			
		||||
                    lgrSQLiteDB_->getSession().close();
 | 
			
		||||
 | 
			
		||||
                    if (!txSQLiteDB_)
 | 
			
		||||
                    {
 | 
			
		||||
                        txSQLiteDB_ = std::make_unique <DatabaseCon>(
 | 
			
		||||
                            setup,
 | 
			
		||||
                            TxDBName,
 | 
			
		||||
                            TxDBPragma,
 | 
			
		||||
                            TxDBInit);
 | 
			
		||||
                    }
 | 
			
		||||
                    txSQLiteDB_->getSession().close();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            lgrSQLiteDB_ = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                LgrDBName,
 | 
			
		||||
                CompleteShardDBPragma,
 | 
			
		||||
                LgrDBInit);
 | 
			
		||||
            lgrSQLiteDB_->getSession() <<
 | 
			
		||||
                boost::str(boost::format("PRAGMA cache_size=-%d;") %
 | 
			
		||||
                kilobytes(Config::getSize(siLgrDBCache, 0)));
 | 
			
		||||
 | 
			
		||||
            txSQLiteDB_ = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                TxDBName,
 | 
			
		||||
                CompleteShardDBPragma,
 | 
			
		||||
                TxDBInit);
 | 
			
		||||
            txSQLiteDB_->getSession() <<
 | 
			
		||||
                boost::str(boost::format("PRAGMA cache_size=-%d;") %
 | 
			
		||||
                kilobytes(Config::getSize(siTxnDBCache, 0)));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // The incomplete shard uses a Write Ahead Log for performance
 | 
			
		||||
            lgrSQLiteDB_ = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                LgrDBName,
 | 
			
		||||
                LgrDBPragma,
 | 
			
		||||
                LgrDBInit);
 | 
			
		||||
            lgrSQLiteDB_->getSession() <<
 | 
			
		||||
                boost::str(boost::format("PRAGMA cache_size=-%d;") %
 | 
			
		||||
                kilobytes(config.getSize(siLgrDBCache)));
 | 
			
		||||
            lgrSQLiteDB_->setupCheckpointing(&app_.getJobQueue(), app_.logs());
 | 
			
		||||
 | 
			
		||||
            txSQLiteDB_ = std::make_unique <DatabaseCon>(
 | 
			
		||||
                setup,
 | 
			
		||||
                TxDBName,
 | 
			
		||||
                TxDBPragma,
 | 
			
		||||
                TxDBInit);
 | 
			
		||||
            txSQLiteDB_->getSession() <<
 | 
			
		||||
                boost::str(boost::format("PRAGMA cache_size=-%d;") %
 | 
			
		||||
                kilobytes(config.getSize(siTxnDBCache)));
 | 
			
		||||
            txSQLiteDB_->setupCheckpointing(&app_.getJobQueue(), app_.logs());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception const& e)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) <<
 | 
			
		||||
            "exception: " << e.what();
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            " exception " << e.what() <<
 | 
			
		||||
            " in function " << __func__;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return nObj;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::setSQLiteStored(std::shared_ptr<Ledger const> const& ledger)
 | 
			
		||||
{
 | 
			
		||||
    auto const seq {ledger->info().seq};
 | 
			
		||||
    assert(backend_ && !complete_);
 | 
			
		||||
    assert(!boost::icl::contains(storedSeqs_, seq));
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            auto& session {txSQLiteDB_->getSession()};
 | 
			
		||||
            soci::transaction tr(session);
 | 
			
		||||
 | 
			
		||||
            session <<
 | 
			
		||||
                "DELETE FROM Transactions WHERE LedgerSeq = :seq;"
 | 
			
		||||
                , soci::use(seq);
 | 
			
		||||
            session <<
 | 
			
		||||
                "DELETE FROM AccountTransactions WHERE LedgerSeq = :seq;"
 | 
			
		||||
                , soci::use(seq);
 | 
			
		||||
 | 
			
		||||
            if (ledger->info().txHash.isNonZero())
 | 
			
		||||
            {
 | 
			
		||||
                auto const sSeq {std::to_string(seq)};
 | 
			
		||||
                if (!ledger->txMap().isValid())
 | 
			
		||||
                {
 | 
			
		||||
                    JLOG(j_.error()) <<
 | 
			
		||||
                        "shard " << index_ <<
 | 
			
		||||
                        " has an invalid transaction map" <<
 | 
			
		||||
                        " on sequence " << sSeq;
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                for (auto const& item : ledger->txs)
 | 
			
		||||
                {
 | 
			
		||||
                    auto const txID {item.first->getTransactionID()};
 | 
			
		||||
                    auto const sTxID {to_string(txID)};
 | 
			
		||||
                    auto const txMeta {std::make_shared<TxMeta>(
 | 
			
		||||
                        txID, ledger->seq(), *item.second)};
 | 
			
		||||
 | 
			
		||||
                    session <<
 | 
			
		||||
                        "DELETE FROM AccountTransactions WHERE TransID = :txID;"
 | 
			
		||||
                        , soci::use(sTxID);
 | 
			
		||||
 | 
			
		||||
                    auto const& accounts = txMeta->getAffectedAccounts(j_);
 | 
			
		||||
                    if (!accounts.empty())
 | 
			
		||||
                    {
 | 
			
		||||
                        auto const s(boost::str(boost::format(
 | 
			
		||||
                            "('%s','%s',%s,%s)")
 | 
			
		||||
                            % sTxID
 | 
			
		||||
                            % "%s"
 | 
			
		||||
                            % sSeq
 | 
			
		||||
                            % std::to_string(txMeta->getIndex())));
 | 
			
		||||
                        std::string sql;
 | 
			
		||||
                        sql.reserve((accounts.size() + 1) * 128);
 | 
			
		||||
                        sql = "INSERT INTO AccountTransactions "
 | 
			
		||||
                            "(TransID, Account, LedgerSeq, TxnSeq) VALUES ";
 | 
			
		||||
                        sql += boost::algorithm::join(
 | 
			
		||||
                            accounts | boost::adaptors::transformed(
 | 
			
		||||
                                [&](AccountID const& accountID)
 | 
			
		||||
                                {
 | 
			
		||||
                                    return boost::str(boost::format(s)
 | 
			
		||||
                                        % ripple::toBase58(accountID));
 | 
			
		||||
                                }),
 | 
			
		||||
                                ",");
 | 
			
		||||
                        sql += ';';
 | 
			
		||||
                        session << sql;
 | 
			
		||||
 | 
			
		||||
                        JLOG(j_.trace()) <<
 | 
			
		||||
                            "shard " << index_ <<
 | 
			
		||||
                            " account transaction: " << sql;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        JLOG(j_.warn()) <<
 | 
			
		||||
                            "shard " << index_ <<
 | 
			
		||||
                            " transaction in ledger " << sSeq <<
 | 
			
		||||
                            " affects no accounts";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Serializer s;
 | 
			
		||||
                    item.second->add(s);
 | 
			
		||||
                    session <<
 | 
			
		||||
                       (STTx::getMetaSQLInsertReplaceHeader() +
 | 
			
		||||
                           item.first->getMetaSQL(
 | 
			
		||||
                               seq,
 | 
			
		||||
                               sqlEscape(std::move(s.modData())))
 | 
			
		||||
                           + ';');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            tr.commit ();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto& session {lgrSQLiteDB_->getSession()};
 | 
			
		||||
        soci::transaction tr(session);
 | 
			
		||||
 | 
			
		||||
        session <<
 | 
			
		||||
            "DELETE FROM Ledgers WHERE LedgerSeq = :seq;"
 | 
			
		||||
            , soci::use(seq);
 | 
			
		||||
        session <<
 | 
			
		||||
            "INSERT OR REPLACE INTO Ledgers ("
 | 
			
		||||
                "LedgerHash, LedgerSeq, PrevHash, TotalCoins, ClosingTime,"
 | 
			
		||||
                "PrevClosingTime, CloseTimeRes, CloseFlags, AccountSetHash,"
 | 
			
		||||
                "TransSetHash)"
 | 
			
		||||
            "VALUES ("
 | 
			
		||||
                ":ledgerHash, :ledgerSeq, :prevHash, :totalCoins, :closingTime,"
 | 
			
		||||
                ":prevClosingTime, :closeTimeRes, :closeFlags, :accountSetHash,"
 | 
			
		||||
                ":transSetHash);",
 | 
			
		||||
            soci::use(to_string(ledger->info().hash)),
 | 
			
		||||
            soci::use(seq),
 | 
			
		||||
            soci::use(to_string(ledger->info().parentHash)),
 | 
			
		||||
            soci::use(to_string(ledger->info().drops)),
 | 
			
		||||
            soci::use(ledger->info().closeTime.time_since_epoch().count()),
 | 
			
		||||
            soci::use(ledger->info().parentCloseTime.time_since_epoch().count()),
 | 
			
		||||
            soci::use(ledger->info().closeTimeResolution.count()),
 | 
			
		||||
            soci::use(ledger->info().closeFlags),
 | 
			
		||||
            soci::use(to_string(ledger->info().accountHash)),
 | 
			
		||||
            soci::use(to_string(ledger->info().txHash));
 | 
			
		||||
 | 
			
		||||
        tr.commit();
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception const& e)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            " exception " << e.what() <<
 | 
			
		||||
            " in function " << __func__;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Shard::setFileStats()
 | 
			
		||||
{
 | 
			
		||||
    fileSz_ = 0;
 | 
			
		||||
    fdRequired_ = 0;
 | 
			
		||||
    if (backend_->backed())
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            using namespace boost::filesystem;
 | 
			
		||||
            for (auto const& d : directory_iterator(dir_))
 | 
			
		||||
            {
 | 
			
		||||
                if (is_regular_file(d))
 | 
			
		||||
                {
 | 
			
		||||
                    fileSz_ += file_size(d);
 | 
			
		||||
                    ++fdRequired_;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (std::exception const& e)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG(j_.error()) <<
 | 
			
		||||
                "shard " << index_ <<
 | 
			
		||||
                " exception " << e.what() <<
 | 
			
		||||
                " in function " << __func__;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
@@ -455,10 +770,10 @@ Shard::saveControl()
 | 
			
		||||
    if (!ofs.is_open())
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.fatal()) <<
 | 
			
		||||
            "shard " << index_ <<
 | 
			
		||||
            " unable to save control file";
 | 
			
		||||
            "shard " << index_ << " is unable to save control file";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boost::archive::text_oarchive ar(ofs);
 | 
			
		||||
    ar & storedSeqs_;
 | 
			
		||||
    return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
#include <ripple/app/ledger/Ledger.h>
 | 
			
		||||
#include <ripple/basics/BasicConfig.h>
 | 
			
		||||
#include <ripple/basics/RangeSet.h>
 | 
			
		||||
#include <ripple/core/DatabaseCon.h>
 | 
			
		||||
#include <ripple/nodestore/NodeObject.h>
 | 
			
		||||
#include <ripple/nodestore/Scheduler.h>
 | 
			
		||||
 | 
			
		||||
@@ -66,14 +67,17 @@ class DatabaseShard;
 | 
			
		||||
class Shard
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Shard(DatabaseShard const& db, std::uint32_t index, int cacheSz,
 | 
			
		||||
        std::chrono::seconds cacheAge, beast::Journal& j);
 | 
			
		||||
    Shard(
 | 
			
		||||
        Application& app,
 | 
			
		||||
        DatabaseShard const& db,
 | 
			
		||||
        std::uint32_t index,
 | 
			
		||||
        beast::Journal& j);
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
    open(Section config, Scheduler& scheduler, nudb::context& ctx);
 | 
			
		||||
    open(Scheduler& scheduler, nudb::context& ctx);
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
    setStored(std::shared_ptr<Ledger const> const& l);
 | 
			
		||||
    setStored(std::shared_ptr<Ledger const> const& ledger);
 | 
			
		||||
 | 
			
		||||
    boost::optional<std::uint32_t>
 | 
			
		||||
    prepare();
 | 
			
		||||
@@ -81,40 +85,35 @@ public:
 | 
			
		||||
    bool
 | 
			
		||||
    contains(std::uint32_t seq) const;
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    sweep();
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
    validate(Application& app);
 | 
			
		||||
    validate();
 | 
			
		||||
 | 
			
		||||
    std::uint32_t
 | 
			
		||||
    index() const {return index_;}
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
    complete() const {return complete_;}
 | 
			
		||||
    complete() const {assert(backend_); return complete_;}
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<PCache>&
 | 
			
		||||
    pCache() {return pCache_;}
 | 
			
		||||
    pCache() {assert(backend_); return pCache_;}
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<NCache>&
 | 
			
		||||
    nCache() {return nCache_;}
 | 
			
		||||
    nCache() {assert(backend_); return nCache_;}
 | 
			
		||||
 | 
			
		||||
    std::uint64_t
 | 
			
		||||
    fileSize() const {return fileSize_;}
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Backend> const&
 | 
			
		||||
    getBackend() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(backend_);
 | 
			
		||||
        return backend_;
 | 
			
		||||
    }
 | 
			
		||||
    fileSize() const {assert(backend_); return fileSz_;}
 | 
			
		||||
 | 
			
		||||
    std::uint32_t
 | 
			
		||||
    fdlimit() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(backend_);
 | 
			
		||||
        return backend_->fdlimit();
 | 
			
		||||
    }
 | 
			
		||||
    fdRequired() const {assert(backend_); return fdRequired_;}
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Backend> const&
 | 
			
		||||
    getBackend() const {assert(backend_); return backend_;}
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Ledger const>
 | 
			
		||||
    lastStored() {return lastStored_;}
 | 
			
		||||
    lastStored() {assert(backend_); return lastStored_;}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class boost::serialization::access;
 | 
			
		||||
@@ -126,6 +125,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    static constexpr auto controlFileName = "control.txt";
 | 
			
		||||
 | 
			
		||||
    Application& app_;
 | 
			
		||||
 | 
			
		||||
    // Shard Index
 | 
			
		||||
    std::uint32_t const index_;
 | 
			
		||||
 | 
			
		||||
@@ -152,12 +153,21 @@ private:
 | 
			
		||||
    // Path to control file
 | 
			
		||||
    boost::filesystem::path const control_;
 | 
			
		||||
 | 
			
		||||
    // Disk space utilized by the shard
 | 
			
		||||
    std::uint64_t fileSize_ {0};
 | 
			
		||||
    // Storage space utilized by the shard
 | 
			
		||||
    std::uint64_t fileSz_;
 | 
			
		||||
 | 
			
		||||
    // Number of file descriptors required by the shard
 | 
			
		||||
    std::uint32_t fdRequired_;
 | 
			
		||||
 | 
			
		||||
    // NuDB key/value store for node objects
 | 
			
		||||
    std::shared_ptr<Backend> backend_;
 | 
			
		||||
 | 
			
		||||
    // Ledger SQLite database used for indexes
 | 
			
		||||
    std::unique_ptr<DatabaseCon> lgrSQLiteDB_;
 | 
			
		||||
 | 
			
		||||
    // Transaction SQLite database used for indexes
 | 
			
		||||
    std::unique_ptr<DatabaseCon> txSQLiteDB_;
 | 
			
		||||
 | 
			
		||||
    beast::Journal j_;
 | 
			
		||||
 | 
			
		||||
    // True if shard has its entire ledger range stored
 | 
			
		||||
@@ -172,7 +182,7 @@ private:
 | 
			
		||||
    // Validate this ledger by walking its SHAMaps
 | 
			
		||||
    // and verifying each merkle tree
 | 
			
		||||
    bool
 | 
			
		||||
    valLedger(std::shared_ptr<Ledger const> const& l,
 | 
			
		||||
    valLedger(std::shared_ptr<Ledger const> const& ledger,
 | 
			
		||||
        std::shared_ptr<Ledger const> const& next);
 | 
			
		||||
 | 
			
		||||
    // Fetches from the backend and will log
 | 
			
		||||
@@ -180,9 +190,25 @@ private:
 | 
			
		||||
    std::shared_ptr<NodeObject>
 | 
			
		||||
    valFetch(uint256 const& hash);
 | 
			
		||||
 | 
			
		||||
    // Calculate the file foot print of the backend files
 | 
			
		||||
    // Marks shard immutable, having stored all of its ledgers
 | 
			
		||||
    void
 | 
			
		||||
    updateFileSize();
 | 
			
		||||
    setComplete();
 | 
			
		||||
 | 
			
		||||
    // Set the backend cache
 | 
			
		||||
    void
 | 
			
		||||
    setCache();
 | 
			
		||||
 | 
			
		||||
    // Open/Create SQLite databases
 | 
			
		||||
    bool
 | 
			
		||||
    initSQLite();
 | 
			
		||||
 | 
			
		||||
    // Create SQLite entries for a ledger stored in this shard's backend
 | 
			
		||||
    bool
 | 
			
		||||
    setSQLiteStored(std::shared_ptr<Ledger const> const& ledger);
 | 
			
		||||
 | 
			
		||||
    // Set storage and file descriptor usage stats
 | 
			
		||||
    bool
 | 
			
		||||
    setFileStats();
 | 
			
		||||
 | 
			
		||||
    // Save the control file for an incomplete shard
 | 
			
		||||
    bool
 | 
			
		||||
 
 | 
			
		||||
@@ -34,8 +34,6 @@ enum
 | 
			
		||||
 | 
			
		||||
// Expiration time for cached nodes
 | 
			
		||||
std::chrono::seconds constexpr cacheTargetAge = std::chrono::minutes{5};
 | 
			
		||||
auto constexpr shardCacheSz = 16384;
 | 
			
		||||
std::chrono::seconds constexpr shardCacheAge = std::chrono::minutes{1};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,4 +21,3 @@
 | 
			
		||||
#include <ripple/app/main/Application.cpp>
 | 
			
		||||
#include <ripple/app/main/BasicApp.cpp>
 | 
			
		||||
#include <ripple/app/main/CollectorManager.cpp>
 | 
			
		||||
#include <ripple/app/main/DBInit.cpp>
 | 
			
		||||
 
 | 
			
		||||
@@ -227,7 +227,11 @@ public:
 | 
			
		||||
        {
 | 
			
		||||
            DatabaseCon::Setup setup;
 | 
			
		||||
            setup.dataDir = getDatabasePath ();
 | 
			
		||||
            DatabaseCon dbCon(setup, dbName, WalletDBInit, WalletDBCount);
 | 
			
		||||
            DatabaseCon dbCon(
 | 
			
		||||
                setup,
 | 
			
		||||
                dbName.data(),
 | 
			
		||||
                std::array<char const*, 0>(),
 | 
			
		||||
                WalletDBInit);
 | 
			
		||||
 | 
			
		||||
            auto getPopulatedManifests =
 | 
			
		||||
                [](ManifestCache const& cache) -> std::vector<Manifest const*>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user