Complete NodeStore documentation

* Complete README.md
* Add missing doxygen
* Fix getHitRate bug
This commit is contained in:
Miguel Portilla
2014-05-08 10:59:03 -04:00
committed by Vinnie Falco
parent 3ca9646329
commit 06d6e4901e
14 changed files with 145 additions and 63 deletions

View File

@@ -283,15 +283,6 @@
<Filter Include="[1] Ripple\common\impl"> <Filter Include="[1] Ripple\common\impl">
<UniqueIdentifier>{6f3085f6-dbe3-4622-a680-682787d0708c}</UniqueIdentifier> <UniqueIdentifier>{6f3085f6-dbe3-4622-a680-682787d0708c}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="[1] Ripple\radmap">
<UniqueIdentifier>{1b34e7e8-8260-488c-8d09-bdd3b474f9e3}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\radmap\api">
<UniqueIdentifier>{19de3695-4341-49db-9da2-b220bc9e0149}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\radmap\impl">
<UniqueIdentifier>{67371f65-f9be-45b1-81e8-c83ef3336e5c}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\peerfinder\sim"> <Filter Include="[1] Ripple\peerfinder\sim">
<UniqueIdentifier>{c429638b-4572-44e4-a48a-c18fdd094ae1}</UniqueIdentifier> <UniqueIdentifier>{c429638b-4572-44e4-a48a-c18fdd094ae1}</UniqueIdentifier>
</Filter> </Filter>
@@ -337,6 +328,15 @@
<Filter Include="[1] Ripple\websocket"> <Filter Include="[1] Ripple\websocket">
<UniqueIdentifier>{6967f835-a1b0-47e3-9bd9-6fc8bd0f3df7}</UniqueIdentifier> <UniqueIdentifier>{6967f835-a1b0-47e3-9bd9-6fc8bd0f3df7}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="[1] Ripple\proto\radmap">
<UniqueIdentifier>{1b34e7e8-8260-488c-8d09-bdd3b474f9e3}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\proto\radmap\api">
<UniqueIdentifier>{19de3695-4341-49db-9da2-b220bc9e0149}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\proto\radmap\impl">
<UniqueIdentifier>{67371f65-f9be-45b1-81e8-c83ef3336e5c}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\ripple_basics\containers\RangeSet.cpp"> <ClCompile Include="..\..\src\ripple_basics\containers\RangeSet.cpp">
@@ -1330,10 +1330,10 @@
<Filter>[2] Old Ripple\ripple_app\ledger</Filter> <Filter>[2] Old Ripple\ripple_app\ledger</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ripple\radmap\ripple_radmap.cpp"> <ClCompile Include="..\..\src\ripple\radmap\ripple_radmap.cpp">
<Filter>[1] Ripple\radmap</Filter> <Filter>[1] Ripple\proto\radmap</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ripple\radmap\impl\BasicFullBelowCache.cpp"> <ClCompile Include="..\..\src\ripple\radmap\impl\BasicFullBelowCache.cpp">
<Filter>[1] Ripple\radmap\impl</Filter> <Filter>[1] Ripple\proto\radmap\impl</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ripple\common\impl\KeyCache.cpp"> <ClCompile Include="..\..\src\ripple\common\impl\KeyCache.cpp">
<Filter>[1] Ripple\common\impl</Filter> <Filter>[1] Ripple\common\impl</Filter>
@@ -3057,13 +3057,13 @@
<Filter>[2] Old Ripple\ripple_basics\containers</Filter> <Filter>[2] Old Ripple\ripple_basics\containers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\radmap\ripple_radmap.h"> <ClInclude Include="..\..\src\ripple\radmap\ripple_radmap.h">
<Filter>[1] Ripple\radmap</Filter> <Filter>[1] Ripple\proto\radmap</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\radmap\api\BasicFullBelowCache.h"> <ClInclude Include="..\..\src\ripple\radmap\api\BasicFullBelowCache.h">
<Filter>[1] Ripple\radmap\api</Filter> <Filter>[1] Ripple\proto\radmap\api</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\radmap\api\Tuning.h"> <ClInclude Include="..\..\src\ripple\radmap\api\Tuning.h">
<Filter>[1] Ripple\radmap\api</Filter> <Filter>[1] Ripple\proto\radmap\api</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\common\KeyCache.h"> <ClInclude Include="..\..\src\ripple\common\KeyCache.h">
<Filter>[1] Ripple\common</Filter> <Filter>[1] Ripple\common</Filter>
@@ -3507,10 +3507,10 @@
<Filter>[2] Old Ripple\ripple_app\ledger</Filter> <Filter>[2] Old Ripple\ripple_app\ledger</Filter>
</None> </None>
<None Include="..\..\src\ripple\radmap\README.md"> <None Include="..\..\src\ripple\radmap\README.md">
<Filter>[1] Ripple\radmap</Filter> <Filter>[1] Ripple\proto\radmap</Filter>
</None> </None>
<None Include="..\..\src\ripple\radmap\TODO.md"> <None Include="..\..\src\ripple\radmap\TODO.md">
<Filter>[1] Ripple\radmap</Filter> <Filter>[1] Ripple\proto\radmap</Filter>
</None> </None>
<None Include="..\..\src\ripple_rpc\README.md"> <None Include="..\..\src\ripple_rpc\README.md">
<Filter>[2] Old Ripple\ripple_rpc</Filter> <Filter>[2] Old Ripple\ripple_rpc</Filter>

View File

@@ -145,7 +145,8 @@ public:
float getHitRate () float getHitRate ()
{ {
lock_guard lock (m_mutex); lock_guard lock (m_mutex);
return (static_cast<float> (m_hits) * 100) / (1.0f + m_hits + m_misses); auto const total = static_cast<float> (m_hits + m_misses);
return m_hits * (100.0f / std::max (1.0f, total));
} }
void clearStats () void clearStats ()

View File

@@ -194,7 +194,7 @@ public:
statement.bind(1, to_string (object->getHash())); statement.bind(1, to_string (object->getHash()));
statement.bind(2, type); statement.bind(2, type);
statement.bind(3, object->getIndex()); statement.bind(3, object->getLedgerIndex());
statement.bindStatic(4, object->getData()); statement.bindStatic(4, object->getData());
} }

View File

@@ -1,25 +1,102 @@
# NodeStore # NodeStore
## Introduction ## Introduction
The NodeStore provides an interface that stores, in a persistent database, the collection of A `NodeObject` is a simple object that the Ledger uses to store entries. It is
NodeObject that rippled uses as its primary representation of ledger items. 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 * **ledger**
|-api // Public Interface
| A ledger header.
|-backend // Factory classes for various databases
|
|-impl // Private Implementation
|
|-test // Unit tests
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? * `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)

View File

@@ -23,7 +23,7 @@
namespace ripple { namespace ripple {
namespace NodeStore { 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 The NodeStore uses a swappable backend so that other database systems
can be tried. Different databases may offer various features such can be tried. Different databases may offer various features such

View File

@@ -118,14 +118,17 @@ public:
*/ */
virtual int getWriteLoad () = 0; virtual int getWriteLoad () = 0;
// VFALCO TODO Document this. /** Get the positive cache hits to total attempts ratio. */
virtual float getCacheHitRate () = 0; virtual float getCacheHitRate () = 0;
// VFALCO TODO Document this. /** Set the maximum number of entries and maximum cache age for both caches.
// TODO Document the parameter meanings.
@param size Number of cache entries (0 = ignore)
@param age Maximum cache age in seconds
*/
virtual void tune (int size, int age) = 0; 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; virtual void sweep () = 0;
}; };

View File

@@ -23,7 +23,17 @@
namespace ripple { namespace ripple {
namespace NodeStore { 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 <NodeStore::Manager> m (NodeStore::make_Manager());
std::unique_ptr <NodeStore::Database> nodeStore (m->make_Database ("nodeStore",
scheduler, LogPartition::getJournal <NodeObject> (), 4,
getConfig ().nodeDatabase));
@endcode
*/
class Manager class Manager
{ {
public: public:
@@ -45,7 +55,7 @@ public:
virtual std::unique_ptr <Backend> make_Backend (Parameters const& parameters, virtual std::unique_ptr <Backend> make_Backend (Parameters const& parameters,
Scheduler& scheduler, beast::Journal journal) = 0; 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 The parameters are key value pairs passed to the backend. The
'type' key must exist, it defines the choice of backend. Most 'type' key must exist, it defines the choice of backend. Most

View File

@@ -34,13 +34,11 @@ enum NodeObjectType
hotTRANSACTION_NODE = 4 hotTRANSACTION_NODE = 4
}; };
/** A blob of data with associated metadata, referenced by 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.
The metadata includes the following: 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
- Type of the blob identifies what the blob contains.
- The ledger index in which it appears
- The SHA 256 hash
@note No checking is performed to make sure the hash matches the data. @note No checking is performed to make sure the hash matches the data.
@see SHAMap @see SHAMap
@@ -107,8 +105,7 @@ public:
/** Retrieve the ledger index in which this object appears. /** Retrieve the ledger index in which this object appears.
*/ */
// VFALCO TODO rename to getLedgerIndex or getLedgerId LedgerIndex getLedgerIndex() const;
LedgerIndex getIndex () const;
/** Retrieve the binary data. /** Retrieve the binary data.
*/ */

View File

@@ -34,10 +34,6 @@ namespace NodeStore {
@see Scheduler @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 class BatchWriter : private Task
{ {
public: public:

View File

@@ -31,13 +31,13 @@ EncodedBlob::prepare (NodeObject::Ptr const& object)
m_data.ensureSize (m_size); m_data.ensureSize (m_size);
// These sizes must be the same! // 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 <std::uint32_t*> (m_data.getData ()); std::uint32_t* buf = static_cast <std::uint32_t*> (m_data.getData ());
buf [0] = beast::ByteOrder::swapIfLittleEndian (object->getIndex ()); buf [0] = beast::ByteOrder::swapIfLittleEndian (object->getLedgerIndex ());
buf [1] = beast::ByteOrder::swapIfLittleEndian (object->getIndex ()); buf [1] = beast::ByteOrder::swapIfLittleEndian (object->getLedgerIndex ());
} }
{ {

View File

@@ -26,11 +26,9 @@ public:
typedef std::vector <std::unique_ptr <Factory>> List; typedef std::vector <std::unique_ptr <Factory>> List;
List m_list; List m_list;
explicit ManagerImp (std::vector <std::unique_ptr <Factory>> factories) explicit ManagerImp (std::vector <std::unique_ptr <Factory>>&& factories)
: m_list (std::move (factories)) : m_list (std::move (factories))
{ {
m_list.reserve (20);
add_known_factories (); add_known_factories ();
} }

View File

@@ -59,7 +59,7 @@ NodeObject::getHash () const
} }
LedgerIndex LedgerIndex
NodeObject::getIndex () const NodeObject::getLedgerIndex () const
{ {
return mLedgerIndex; return mLedgerIndex;
} }

View File

@@ -162,7 +162,7 @@ public:
Blob data (object->getData ()); Blob data (object->getData ());
db.store (object->getType (), db.store (object->getType (),
object->getIndex (), object->getLedgerIndex (),
std::move (data), std::move (data),
object->getHash ()); object->getHash ());
} }

View File

@@ -1744,8 +1744,8 @@ private:
if (obj.has_nodeid ()) if (obj.has_nodeid ())
newObj.set_index (obj.nodeid ()); newObj.set_index (obj.nodeid ());
if (!reply.has_seq () && (hObj->getIndex () != 0)) if (!reply.has_seq () && (hObj->getLedgerIndex () != 0))
reply.set_seq (hObj->getIndex ()); reply.set_seq (hObj->getLedgerIndex ());
} }
} }
} }