diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 38741c937c..01d8153f60 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -283,15 +283,6 @@ {6f3085f6-dbe3-4622-a680-682787d0708c} - - {1b34e7e8-8260-488c-8d09-bdd3b474f9e3} - - - {19de3695-4341-49db-9da2-b220bc9e0149} - - - {67371f65-f9be-45b1-81e8-c83ef3336e5c} - {c429638b-4572-44e4-a48a-c18fdd094ae1} @@ -337,6 +328,15 @@ {6967f835-a1b0-47e3-9bd9-6fc8bd0f3df7} + + {1b34e7e8-8260-488c-8d09-bdd3b474f9e3} + + + {19de3695-4341-49db-9da2-b220bc9e0149} + + + {67371f65-f9be-45b1-81e8-c83ef3336e5c} + @@ -1330,10 +1330,10 @@ [2] Old Ripple\ripple_app\ledger - [1] Ripple\radmap + [1] Ripple\proto\radmap - [1] Ripple\radmap\impl + [1] Ripple\proto\radmap\impl [1] Ripple\common\impl @@ -3057,13 +3057,13 @@ [2] Old Ripple\ripple_basics\containers - [1] Ripple\radmap + [1] Ripple\proto\radmap - [1] Ripple\radmap\api + [1] Ripple\proto\radmap\api - [1] Ripple\radmap\api + [1] Ripple\proto\radmap\api [1] Ripple\common @@ -3507,10 +3507,10 @@ [2] Old Ripple\ripple_app\ledger - [1] Ripple\radmap + [1] Ripple\proto\radmap - [1] Ripple\radmap + [1] Ripple\proto\radmap [2] Old Ripple\ripple_rpc diff --git a/src/ripple/common/TaggedCache.h b/src/ripple/common/TaggedCache.h index 7e6aa36461..f554a1089c 100644 --- a/src/ripple/common/TaggedCache.h +++ b/src/ripple/common/TaggedCache.h @@ -145,7 +145,8 @@ public: float getHitRate () { lock_guard lock (m_mutex); - return (static_cast (m_hits) * 100) / (1.0f + m_hits + m_misses); + auto const total = static_cast (m_hits + m_misses); + return m_hits * (100.0f / std::max (1.0f, total)); } void clearStats () diff --git a/src/ripple_app/node/SqliteFactory.cpp b/src/ripple_app/node/SqliteFactory.cpp index 5b22750437..c1c64445df 100644 --- a/src/ripple_app/node/SqliteFactory.cpp +++ b/src/ripple_app/node/SqliteFactory.cpp @@ -194,7 +194,7 @@ public: statement.bind(1, to_string (object->getHash())); statement.bind(2, type); - statement.bind(3, object->getIndex()); + statement.bind(3, object->getLedgerIndex()); statement.bindStatic(4, object->getData()); } diff --git a/src/ripple_core/nodestore/README.md b/src/ripple_core/nodestore/README.md index 6ff4526c67..fa7a2558dd 100644 --- a/src/ripple_core/nodestore/README.md +++ b/src/ripple_core/nodestore/README.md @@ -1,25 +1,102 @@ - # NodeStore ## Introduction -The NodeStore provides an interface that stores, in a persistent database, the collection of -NodeObject that rippled uses as its primary representation of ledger items. +A `NodeObject` is a simple object that the Ledger uses to store entries. It is +comprised of a type, a hash, a ledger index and a blob. It can be uniquely +identified by the hash, which is a 256 bit hash of the blob. The blob is a +variable length block of serialized data. The type identifies what the blob +contains. The fields are as follows: + +* `mType` -## Module directory structure + An enumeration that determines what the blob holds. There are four + different types of objects stored. -nodestore -|-api // Public Interface -| -|-backend // Factory classes for various databases -| -|-impl // Private Implementation -| -|-test // Unit tests + * **ledger** + + A ledger header. -The NodeStore class is a simple object that the Ledger uses to store entries. It has a enumeration type, a hash, a ledger index and a Blob which stores arbritary data. + * **transaction** + + A signed transaction. + + * **account node** + + A node in a ledger's account state tree. + + * **transaction node** + + A node in a ledger's transaction tree. + +* `mHash` + A 256-bit hash of the blob. -# Document WIP notes +* `mLedgerIndex` + + An unsigned integer that uniquely identifies the ledger in which this + NodeObject appears. -If the MemoryFactory backend database is used, do we loose persistance? \ No newline at end of file +* `mData` + + A blob containing the payload. Stored in the following format. + +|Byte | | | +|:------|:--------------------|:-------------------------| +|0...3 |ledger index |32-bit big endian integer | +|4...7 |reserved ledger index|32-bit big endian integer | +|8 |type |NodeObjectType enumeration| +|9...end|data |body of the object data | +--- +The `NodeStore` provides an interface that stores, in a persistent database, a +collection of NodeObjects that rippled uses as its primary representation of +ledger entries. All ledger entries are stored as NodeObjects and as such, need +to be persisted between launches. If a NodeObject is accessed and is not in +memory, it will be retrieved from the database. + +## Backend + +The `NodeStore` implementation provides the `Backend` abstract interface, +which lets different key/value databases to be chosen at run-time. This allows +experimentation with different engines. Improvements in the performance of the +NodeStore are a constant area of research. The database can be specified in +the configuration file [node_db] section as follows. + +One or more lines of key / value pairs + +Example: +``` +type=RocksDB +path=rocksdb +compression=1 +``` +Choices for 'type' (not case-sensitive) + +* **HyperLevelDB** + + An improved version of LevelDB (preferred). + +* **LevelDB** + + Google's LevelDB database (deprecated). + +* **none** + + Use no backend. + +* **RocksDB** + + Facebook's RocksDB database, builds on LevelDB. + +* **SQLite** + + Use SQLite. + +'path' speficies where the backend will store its data files. + +Choices for 'compression' + +* **0** off + +* **1** on (default) \ No newline at end of file diff --git a/src/ripple_core/nodestore/api/Backend.h b/src/ripple_core/nodestore/api/Backend.h index bd889093df..f5c69f0aa7 100644 --- a/src/ripple_core/nodestore/api/Backend.h +++ b/src/ripple_core/nodestore/api/Backend.h @@ -23,7 +23,7 @@ namespace ripple { namespace NodeStore { -/** A backend used for the store. +/** A backend used for the NodeStore. The NodeStore uses a swappable backend so that other database systems can be tried. Different databases may offer various features such diff --git a/src/ripple_core/nodestore/api/Database.h b/src/ripple_core/nodestore/api/Database.h index 96631258f1..b18775887f 100644 --- a/src/ripple_core/nodestore/api/Database.h +++ b/src/ripple_core/nodestore/api/Database.h @@ -118,14 +118,17 @@ public: */ virtual int getWriteLoad () = 0; - // VFALCO TODO Document this. + /** Get the positive cache hits to total attempts ratio. */ virtual float getCacheHitRate () = 0; - // VFALCO TODO Document this. - // TODO Document the parameter meanings. + /** Set the maximum number of entries and maximum cache age for both caches. + + @param size Number of cache entries (0 = ignore) + @param age Maximum cache age in seconds + */ virtual void tune (int size, int age) = 0; - // VFALCO TODO Document this. + /** Remove expired entries from the positive and negative caches. */ virtual void sweep () = 0; }; diff --git a/src/ripple_core/nodestore/api/Manager.h b/src/ripple_core/nodestore/api/Manager.h index de15bebc6f..95baf635b3 100644 --- a/src/ripple_core/nodestore/api/Manager.h +++ b/src/ripple_core/nodestore/api/Manager.h @@ -23,7 +23,17 @@ namespace ripple { namespace NodeStore { -/** Singleton for managing NodeStore factories and back ends. */ +/** Singleton for managing NodeStore factories and back ends. + Create a Manager like this: + @code + NodeStore::DummyScheduler scheduler; + std::unique_ptr m (NodeStore::make_Manager()); + + std::unique_ptr nodeStore (m->make_Database ("nodeStore", + scheduler, LogPartition::getJournal (), 4, + getConfig ().nodeDatabase)); + @endcode +*/ class Manager { public: @@ -45,7 +55,7 @@ public: virtual std::unique_ptr make_Backend (Parameters const& parameters, Scheduler& scheduler, beast::Journal journal) = 0; - /** Construct a node store database. + /** Construct a NodeStore database. The parameters are key value pairs passed to the backend. The 'type' key must exist, it defines the choice of backend. Most diff --git a/src/ripple_core/nodestore/api/NodeObject.h b/src/ripple_core/nodestore/api/NodeObject.h index 290ff011ec..30a09070f7 100644 --- a/src/ripple_core/nodestore/api/NodeObject.h +++ b/src/ripple_core/nodestore/api/NodeObject.h @@ -34,13 +34,11 @@ enum NodeObjectType hotTRANSACTION_NODE = 4 }; -/** A blob of data with associated metadata, referenced by hash. - - The metadata includes the following: - - - Type of the blob - - The ledger index in which it appears - - The SHA 256 hash +/** A simple object that the Ledger uses to store entries. + NodeObjects are comprised of a type, a hash, a ledger index and a blob. + They can be uniquely identified by the hash, which is a SHA 256 of the + blob. The blob is a variable length block of serialized data. The type + identifies what the blob contains. @note No checking is performed to make sure the hash matches the data. @see SHAMap @@ -107,8 +105,7 @@ public: /** Retrieve the ledger index in which this object appears. */ - // VFALCO TODO rename to getLedgerIndex or getLedgerId - LedgerIndex getIndex () const; + LedgerIndex getLedgerIndex() const; /** Retrieve the binary data. */ diff --git a/src/ripple_core/nodestore/impl/BatchWriter.h b/src/ripple_core/nodestore/impl/BatchWriter.h index 0b453a4d68..a512d0cddc 100644 --- a/src/ripple_core/nodestore/impl/BatchWriter.h +++ b/src/ripple_core/nodestore/impl/BatchWriter.h @@ -34,10 +34,6 @@ namespace NodeStore { @see Scheduler */ -// VFALCO NOTE I'm not entirely happy having placed this here, -// because whoever needs to use NodeStore certainly doesn't -// need to see the implementation details of BatchWriter. -// class BatchWriter : private Task { public: diff --git a/src/ripple_core/nodestore/impl/EncodedBlob.cpp b/src/ripple_core/nodestore/impl/EncodedBlob.cpp index a35786def7..e8b9f01c9c 100644 --- a/src/ripple_core/nodestore/impl/EncodedBlob.cpp +++ b/src/ripple_core/nodestore/impl/EncodedBlob.cpp @@ -31,13 +31,13 @@ EncodedBlob::prepare (NodeObject::Ptr const& object) m_data.ensureSize (m_size); // These sizes must be the same! - static_bassert (sizeof (std::uint32_t) == sizeof (object->getIndex ())); + static_bassert (sizeof (std::uint32_t) == sizeof (object->getLedgerIndex ())); { std::uint32_t* buf = static_cast (m_data.getData ()); - buf [0] = beast::ByteOrder::swapIfLittleEndian (object->getIndex ()); - buf [1] = beast::ByteOrder::swapIfLittleEndian (object->getIndex ()); + buf [0] = beast::ByteOrder::swapIfLittleEndian (object->getLedgerIndex ()); + buf [1] = beast::ByteOrder::swapIfLittleEndian (object->getLedgerIndex ()); } { diff --git a/src/ripple_core/nodestore/impl/Manager.cpp b/src/ripple_core/nodestore/impl/Manager.cpp index 9c6819e61f..b134828c67 100644 --- a/src/ripple_core/nodestore/impl/Manager.cpp +++ b/src/ripple_core/nodestore/impl/Manager.cpp @@ -26,11 +26,9 @@ public: typedef std::vector > List; List m_list; - explicit ManagerImp (std::vector > factories) + explicit ManagerImp (std::vector >&& factories) : m_list (std::move (factories)) { - m_list.reserve (20); - add_known_factories (); } diff --git a/src/ripple_core/nodestore/impl/NodeObject.cpp b/src/ripple_core/nodestore/impl/NodeObject.cpp index 22896b59b1..cf5b3f19e3 100644 --- a/src/ripple_core/nodestore/impl/NodeObject.cpp +++ b/src/ripple_core/nodestore/impl/NodeObject.cpp @@ -59,7 +59,7 @@ NodeObject::getHash () const } LedgerIndex -NodeObject::getIndex () const +NodeObject::getLedgerIndex () const { return mLedgerIndex; } diff --git a/src/ripple_core/nodestore/tests/TestBase.h b/src/ripple_core/nodestore/tests/TestBase.h index c812bdd839..9b798437f5 100644 --- a/src/ripple_core/nodestore/tests/TestBase.h +++ b/src/ripple_core/nodestore/tests/TestBase.h @@ -162,7 +162,7 @@ public: Blob data (object->getData ()); db.store (object->getType (), - object->getIndex (), + object->getLedgerIndex (), std::move (data), object->getHash ()); } diff --git a/src/ripple_overlay/impl/PeerImp.h b/src/ripple_overlay/impl/PeerImp.h index c47f78a50b..b19ef7721f 100644 --- a/src/ripple_overlay/impl/PeerImp.h +++ b/src/ripple_overlay/impl/PeerImp.h @@ -1744,8 +1744,8 @@ private: if (obj.has_nodeid ()) newObj.set_index (obj.nodeid ()); - if (!reply.has_seq () && (hObj->getIndex () != 0)) - reply.set_seq (hObj->getIndex ()); + if (!reply.has_seq () && (hObj->getLedgerIndex () != 0)) + reply.set_seq (hObj->getLedgerIndex ()); } } }