Refactor NodeStore

This commit is contained in:
Vinnie Falco
2013-07-16 08:07:18 -07:00
parent 664ed784e5
commit ad933bae9c
8 changed files with 202 additions and 20 deletions

View File

@@ -11,6 +11,8 @@ Vinnie's Short List (Changes day to day)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
- Replace base_uint and uintXXX with UnsignedInteger
- Rewrite boost program_options in Beast - Rewrite boost program_options in Beast
- Examples for different backend key/value config settings - Examples for different backend key/value config settings

View File

@@ -32,6 +32,80 @@ NodeObject::NodeObject (
{ {
} }
NodeObject::NodeObject (void const* key, void const* value, int valueBytes)
{
DecodedBlob decoded (key, value, valueBytes);
if (decoded.success)
{
mType = decoded.objectType;
mHash = uint256 (key);
mLedgerIndex = decoded.ledgerIndex;
mData = Blob (decoded.objectData, decoded.objectData + decoded.dataBytes);
}
else
{
// VFALCO TODO Write the hex version of key to the string for diagnostics.
String s;
s << "NodeStore:: DecodedBlob failed";
Throw (s);
}
}
NodeObject::DecodedBlob::DecodedBlob (void const* key, void const* value, int valueBytes)
{
/* Data format:
Bytes
0...3 LedgerIndex 32-bit big endian integer
4...7 Unused? An unused copy of the LedgerIndex
8 char One of NodeObjectType
9...end The body of the object data
*/
success = false;
key = key;
// VFALCO NOTE Ledger indexes should have started at 1
ledgerIndex = LedgerIndex (-1);
objectType = hotUNKNOWN;
objectData = nullptr;
dataBytes = bmin (0, valueBytes - 9);
if (dataBytes > 4)
{
LedgerIndex const* index = static_cast <LedgerIndex const*> (value);
ledgerIndex = ByteOrder::swapIfLittleEndian (*index);
}
// VFALCO NOTE What about bytes 4 through 7 inclusive?
if (dataBytes > 8)
{
unsigned char const* byte = static_cast <unsigned char const*> (value);
objectType = static_cast <NodeObjectType> (byte [8]);
}
if (dataBytes > 9)
{
objectData = static_cast <unsigned char const*> (value) + 9;
switch (objectType)
{
case hotUNKNOWN:
default:
break;
case hotLEDGER:
case hotTRANSACTION:
case hotACCOUNT_NODE:
case hotTRANSACTION_NODE:
success = true;
break;
}
}
}
NodeObjectType NodeObject::getType () const NodeObjectType NodeObject::getType () const
{ {
return mType; return mType;

View File

@@ -34,6 +34,14 @@ class NodeObject : public CountedObject <NodeObject>
public: public:
static char const* getCountedObjectName () { return "NodeObject"; } static char const* getCountedObjectName () { return "NodeObject"; }
/** The type used to hold the hash.
The hahes are fixed size, SHA256.
@note The key size can be retrieved with `Hash::sizeInBytes`
*/
typedef UnsignedInteger <32> Hash;
typedef boost::shared_ptr <NodeObject> pointer; typedef boost::shared_ptr <NodeObject> pointer;
typedef pointer const& ref; typedef pointer const& ref;
@@ -42,20 +50,54 @@ public:
@note A copy of the data is created. @note A copy of the data is created.
*/ */
NodeObject (NodeObjectType type, NodeObject (NodeObjectType type,
LedgerIndex ledgerIndex, LedgerIndex ledgerIndex,
Blob const & binaryDataToCopy, Blob const & binaryDataToCopy,
uint256 const & hash); uint256 const & hash);
/** Create from an area of memory. /** Create from an area of memory.
@note A copy of the data is created. @note A copy of the data is created.
*/ */
NodeObject (NodeObjectType type, NodeObject (NodeObjectType type,
LedgerIndex ledgerIndex, LedgerIndex ledgerIndex,
void const * bufferToCopy, void const * bufferToCopy,
int bytesInBuffer, int bytesInBuffer,
uint256 const & hash); uint256 const & hash);
/** Create from a key/value blob.
This is the format in which a NodeObject is stored in the
persistent storage layer.
@see NodeStore
*/
NodeObject (void const* key, void const* value, int valueBytes);
/** Parsed key/value blob into NodeObject components.
This will extract the information required to construct
a NodeObject. It also does consistency checking and returns
the result, so it is possible to determine if the data
is corrupted without throwing an exception. Note all forms
of corruption are detected so further analysis will be
needed to eliminate false positives.
This is the format in which a NodeObject is stored in the
persistent storage layer.
*/
struct DecodedBlob
{
DecodedBlob (void const* key, void const* value, int valueBytes);
bool success;
void const* key;
LedgerIndex ledgerIndex;
NodeObjectType objectType;
unsigned char const* objectData;
int dataBytes;
};
/** Retrieve the type of this object. /** Retrieve the type of this object.
*/ */
NodeObjectType getType () const; NodeObjectType getType () const;
@@ -74,10 +116,10 @@ public:
Blob const& getData () const; Blob const& getData () const;
private: private:
NodeObjectType const mType; NodeObjectType mType;
uint256 const mHash; uint256 mHash;
LedgerIndex const mLedgerIndex; LedgerIndex mLedgerIndex;
Blob const mData; Blob mData;
}; };
#endif #endif

View File

@@ -193,7 +193,7 @@ NodeObject::pointer NodeStore::retrieve (uint256 const& hash)
if (m_fastBackend) if (m_fastBackend)
{ {
obj = m_fastBackend->retrieve (hash); obj = retrieve (m_fastBackend, hash);
if (obj) if (obj)
{ {
@@ -203,16 +203,26 @@ NodeObject::pointer NodeStore::retrieve (uint256 const& hash)
} }
{ {
LoadEvent::autoptr event (getApp().getJobQueue ().getLoadEventAP (jtHO_READ, "HOS::retrieve")); // m_hooks->onRetrieveBegin ()
obj = m_backend->retrieve(hash);
if (!obj) // VFALCO TODO Why is this an autoptr? Why can't it just be a plain old object?
//
LoadEvent::autoptr event (getApp().getJobQueue ().getLoadEventAP (jtHO_READ, "HOS::retrieve"));
obj = retrieve (m_backend, hash);
if (obj == nullptr)
{ {
m_negativeCache.add (hash); m_negativeCache.add (hash);
return obj;
// VFALCO TODO Eliminate return from middle of function
return obj; // VFALCO NOTE This is nullptr, why return obj?
} }
} }
// VFALCO NOTE What does this do?
m_cache.canonicalize (hash, obj); m_cache.canonicalize (hash, obj);
if (m_fastBackend) if (m_fastBackend)
@@ -223,6 +233,13 @@ NodeObject::pointer NodeStore::retrieve (uint256 const& hash)
return obj; return obj;
} }
//------------------------------------------------------------------------------
NodeObject::pointer NodeStore::retrieve (Backend* backend, uint256 const& hash)
{
return backend->retrieve (hash);
}
void NodeStore::importVisitor ( void NodeStore::importVisitor (
std::vector <NodeObject::pointer>& objects, std::vector <NodeObject::pointer>& objects,
NodeObject::pointer object) NodeObject::pointer object)

View File

@@ -19,13 +19,18 @@ public:
*/ */
// VFALCO TODO Make this a tunable parameter in the key value pairs // VFALCO TODO Make this a tunable parameter in the key value pairs
bulkWriteBatchSize = 128 bulkWriteBatchSize = 128
/** Size of the fixed keys, in bytes.
*/
,keyBytes = 32 // 256 bit hash
}; };
/** Interface to inform callers of cetain activities. /** Interface to inform callers of cetain activities.
*/ */
class Hooks class Hooks
{ {
virtual void on virtual void onRetrieveBegin () { }
virtual void onRetrieveEnd () { }
}; };
/** Back end used for the store. /** Back end used for the store.
@@ -43,11 +48,19 @@ public:
// It should just deal with a fixed key and raw data. // It should just deal with a fixed key and raw data.
// //
virtual bool store (NodeObject::ref); virtual bool store (NodeObject::ref);
//virtual bool put (void const* key, void const* value, int valueBytes) { return false; }
/** Retrieve an individual object. /** Retrieve an individual object.
*/ */
virtual NodeObject::pointer retrieve (uint256 const &hash) = 0; virtual NodeObject::pointer retrieve (uint256 const &hash) = 0;
struct GetCallback
{
virtual void* getBufferForValue (int valueBytes) = 0;
};
virtual bool get (void const* key, GetCallback* callback) { return false; }
// Visit every object in the database // Visit every object in the database
// This function will only be called during an import operation // This function will only be called during an import operation
// //
@@ -161,6 +174,8 @@ public:
int import (String sourceBackendParameters); int import (String sourceBackendParameters);
private: private:
NodeObject::pointer retrieve (Backend* backend, uint256 const& hash);
void importVisitor (std::vector <NodeObject::pointer>& objects, NodeObject::pointer object); void importVisitor (std::vector <NodeObject::pointer>& objects, NodeObject::pointer object);
static Backend* createBackend (String const& parameters); static Backend* createBackend (String const& parameters);

View File

@@ -343,6 +343,7 @@ bool TaggedCache<c_Key, c_Data, Timer>::del (const key_type& key, bool valid)
return ret; return ret;
} }
// VFALCO NOTE What does it mean to canonicalize the data?
template<typename c_Key, typename c_Data, class Timer> template<typename c_Key, typename c_Data, class Timer>
bool TaggedCache<c_Key, c_Data, Timer>::canonicalize (const key_type& key, boost::shared_ptr<c_Data>& data, bool replace) bool TaggedCache<c_Key, c_Data, Timer>::canonicalize (const key_type& key, boost::shared_ptr<c_Data>& data, bool replace)
{ {

View File

@@ -19,6 +19,10 @@ inline int Testuint256AdHoc (std::vector<std::string> vArg);
// We have to keep a separate base class without constructors // We have to keep a separate base class without constructors
// so the compiler will let us use it in a union // so the compiler will let us use it in a union
//
// VFALCO NOTE This class produces undefined behavior when
// BITS is not a multiple of 32!!!
//
template<unsigned int BITS> template<unsigned int BITS>
class base_uint class base_uint
{ {
@@ -30,6 +34,22 @@ protected:
unsigned int pn[WIDTH]; unsigned int pn[WIDTH];
public: public:
base_uint ()
{
}
/** Construct from a raw pointer.
The buffer pointed to by `data` must be at least 32 bytes.
*/
explicit base_uint (void const* data)
{
// BITS must be a multiple of 32
static_bassert ((BITS % 32) == 0);
memcpy (&pn [0], data, BITS / 8);
}
bool isZero () const bool isZero () const
{ {
for (int i = 0; i < WIDTH; i++) for (int i = 0; i < WIDTH; i++)
@@ -474,6 +494,11 @@ public:
*this = b; *this = b;
} }
explicit uint256 (void const* data)
: base_uint256 (data)
{
}
uint256& operator= (uint64 uHost) uint256& operator= (uint64 uHost)
{ {
zero (); zero ();
@@ -590,7 +615,7 @@ template<unsigned int BITS> inline std::ostream& operator<< (std::ostream& out,
inline int Testuint256AdHoc (std::vector<std::string> vArg) inline int Testuint256AdHoc (std::vector<std::string> vArg)
{ {
uint256 g (0); uint256 g (uint64 (0));
printf ("%s\n", g.ToString ().c_str ()); printf ("%s\n", g.ToString ().c_str ());
--g; --g;

View File

@@ -4,8 +4,14 @@
*/ */
//============================================================================== //==============================================================================
SHAMapTreeNode::SHAMapTreeNode (uint32 seq, const SHAMapNode& nodeID) : SHAMapNode (nodeID), mHash (0), SHAMapTreeNode::SHAMapTreeNode (uint32 seq, const SHAMapNode& nodeID)
mSeq (seq), mAccessSeq (seq), mType (tnERROR), mIsBranch (0), mFullBelow (false) : SHAMapNode (nodeID)
, mHash (uint64(0))
, mSeq (seq)
, mAccessSeq (seq)
, mType (tnERROR)
, mIsBranch (0)
, mFullBelow (false)
{ {
} }