mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Continue implementation these classes.
This commit is contained in:
343
SHAMap.cpp
343
SHAMap.cpp
@@ -1,139 +1,250 @@
|
|||||||
|
#include "Serializer.h"
|
||||||
#include "BitcoinUtil.h"
|
#include "BitcoinUtil.h"
|
||||||
#include "SHAMap.h"
|
#include "SHAMap.h"
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
bool SHAMapNode::operator<(const SHAMapNode &s) const
|
SHAMap::SHAMap(int leafDataSize) : mLeafDataSize(leafDataSize)
|
||||||
{
|
|
||||||
if(s.mDepth<mDepth) return true;
|
|
||||||
if(s.mDepth>mDepth) return false;
|
|
||||||
return mNodeID<s.mNodeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAMapNode::operator>(const SHAMapNode &s) const
|
|
||||||
{
|
|
||||||
if(s.mDepth<mDepth) return false;
|
|
||||||
if(s.mDepth>mDepth) return true;
|
|
||||||
return mNodeID>s.mNodeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAMapNode::operator<=(const SHAMapNode &s) const
|
|
||||||
{
|
|
||||||
if(s.mDepth<mDepth) return true;
|
|
||||||
if(s.mDepth>mDepth) return false;
|
|
||||||
return mNodeID<=s.mNodeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAMapNode::operator>=(const SHAMapNode &s) const
|
|
||||||
{
|
|
||||||
if(s.mDepth<mDepth) return false;
|
|
||||||
if(s.mDepth>mDepth) return true;
|
|
||||||
return mNodeID>=s.mNodeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAMapNode::operator==(const SHAMapNode &s) const
|
|
||||||
{
|
|
||||||
return (s.mDepth==mDepth) && (s.mNodeID==mNodeID);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAMapNode::operator!=(const SHAMapNode &s) const
|
|
||||||
{
|
|
||||||
return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SHAMapNode::ClassInit()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char HexBuf[65];
|
|
||||||
|
|
||||||
for(i=0; i<64; i++) HexBuf[i]='0';
|
|
||||||
HexBuf[64]=0;
|
|
||||||
for(i=0; i<leafDepth; i++)
|
|
||||||
{
|
|
||||||
smMasks[i].SetHex(HexBuf);
|
|
||||||
HexBuf[2*i]='1';
|
|
||||||
HexBuf[2*i+1]='F';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAMapNode::SHAMapNode(int depth, const uint256 &hash)
|
|
||||||
{
|
|
||||||
assert(depth>=0 && depth<leafDepth);
|
|
||||||
mDepth=depth;
|
|
||||||
mNodeID=getNodeID(depth, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAMapNode SHAMapNode::getChildNodeID(int m)
|
|
||||||
{
|
|
||||||
assert(!isLeaf());
|
|
||||||
|
|
||||||
uint256 branch=m;
|
|
||||||
branch>>=(mDepth*8);
|
|
||||||
|
|
||||||
return SHAMapNode(mDepth+1, mNodeID | branch);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SHAMapNode::selectBranch(const uint256 &hash)
|
|
||||||
{
|
|
||||||
if(isLeaf()) // no nodes under this node
|
|
||||||
return -1;
|
|
||||||
if((hash&smMasks[mDepth])!=mNodeID)
|
|
||||||
return -1; // does not go under this node
|
|
||||||
|
|
||||||
uint256 selector=hash&smMasks[mDepth+1];
|
|
||||||
int branch=*(selector.begin()+mDepth);
|
|
||||||
|
|
||||||
assert(branch>=0 && branch<32);
|
|
||||||
return branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAMapLeafNode::SHAMapLeafNode(const SHAMapNode& nodeID) : SHAMapNode(nodeID), mHash(0)
|
|
||||||
{
|
{
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SHAMapLeafNode::hasItem(const uint256& item) const
|
void SHAMap::dirtyUp(const uint256& id, const std::vector<SHAMapInnerNode::pointer>& path)
|
||||||
{
|
{ // walk the tree up from through the inner nodes to the root
|
||||||
BOOST_FOREACH(const SHAMapItem& nodeItem, mItems)
|
// update linking hashes and add nodes to dirty list
|
||||||
if(nodeItem==item) return true;
|
std::vector<SHAMapInnerNode::pointer>::const_reverse_iterator it;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAMapLeafNode::addUpdateItem(const SHAMapItem& item)
|
it = path.rbegin();
|
||||||
{ // The node will almost never have more than one item in it
|
if(it == path.rend()) return;
|
||||||
std::list<SHAMapItem>::iterator it;
|
|
||||||
for(it=mItems.begin(); it!=mItems.end(); it++)
|
mDirtyInnerNodes[**it]=*it;
|
||||||
|
uint256 hVal=(*it)->getNodeHash();
|
||||||
|
if(hVal==0)
|
||||||
|
mInnerNodeByID.erase(**it);
|
||||||
|
|
||||||
|
for(++it; it<path.rend(); ++it)
|
||||||
{
|
{
|
||||||
if(*it==item)
|
if(!(*it)->setChildHash((*it)->selectBranch(id), hVal))
|
||||||
{
|
return;
|
||||||
if(it->peekData()==item.peekData())
|
mDirtyInnerNodes[**it]=*it;
|
||||||
return false; // no change
|
hVal = (*it)->getNodeHash();
|
||||||
it->updateData(item.peekData());
|
if(hVal == 0) mInnerNodeByID.erase(**it);
|
||||||
updateHash();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(*it>item) break;
|
|
||||||
}
|
}
|
||||||
mItems.insert(it, item);
|
assert(**it == *root);
|
||||||
updateHash();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SHAMapLeafNode::delItem(const uint256& tag)
|
SHAMapLeafNode::pointer SHAMap::checkCacheLeaf(const SHAMapNode& iNode)
|
||||||
{
|
{
|
||||||
std::list<SHAMapItem>::iterator it;
|
assert(iNode.isLeaf());
|
||||||
for(it=mItems.begin(); it!=mItems.end(); it++)
|
return mLeafByID[iNode];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
|
||||||
|
std::vector<SHAMapInnerNode::pointer>& path)
|
||||||
|
{ // walk down to the leaf that would contain this ID
|
||||||
|
// is leaf node in cache
|
||||||
|
SHAMapLeafNode::pointer ln=checkCacheLeaf(SHAMapNode(SHAMapNode::leafDepth, id));
|
||||||
|
if(ln != SHAMapLeafNode::pointer()) return ln;
|
||||||
|
|
||||||
|
// walk tree to leaf
|
||||||
|
SHAMapInnerNode::pointer inNode=root;
|
||||||
|
path.push_back(inNode);
|
||||||
|
|
||||||
|
for(int i=1; i<SHAMapNode::leafDepth; i++)
|
||||||
{
|
{
|
||||||
if(*it==tag)
|
int branch=inNode->selectBranch(id);
|
||||||
|
if(branch<0)
|
||||||
|
{ // somehow we got on the wrong branch
|
||||||
|
assert(false);
|
||||||
|
return SHAMapLeafNode::pointer();
|
||||||
|
}
|
||||||
|
if(inNode->isEmptyBranch(branch))
|
||||||
|
{ // no nodes below this one
|
||||||
|
if(!create) return SHAMapLeafNode::pointer();
|
||||||
|
return createLeaf(*inNode, id);
|
||||||
|
}
|
||||||
|
if(i!=(SHAMapNode::leafDepth)-1)
|
||||||
|
{ // child is another inner node
|
||||||
|
inNode=getInner(inNode->getChildNodeID(branch), inNode->getChildHash(branch));
|
||||||
|
if(inNode==NULL) return SHAMapLeafNode::pointer(); // we don't have the node
|
||||||
|
path.push_back(inNode);
|
||||||
|
}
|
||||||
|
else // child is leaf node
|
||||||
{
|
{
|
||||||
mItems.erase(it);
|
ln=getLeaf(inNode->getChildNodeID(branch), inNode->getChildHash(branch));
|
||||||
updateHash();
|
if(ln==NULL)
|
||||||
return true;
|
{
|
||||||
|
if(!create) return SHAMapLeafNode::pointer();
|
||||||
|
return createLeaf(*inNode, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return ln;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAMapLeafNode::updateHash(void)
|
SHAMapLeafNode::pointer SHAMap::getLeaf(const SHAMapNode &id, const uint256& hash)
|
||||||
|
{ // retrieve a leaf whose node hash is known
|
||||||
|
SHAMapLeafNode::pointer leaf=mLeafByID[id];
|
||||||
|
if(leaf != SHAMapLeafNode::pointer()) return leaf;
|
||||||
|
|
||||||
|
std::vector<unsigned char> rawNode;
|
||||||
|
if(!fetchNode(hash, id, rawNode)) return leaf;
|
||||||
|
|
||||||
|
leaf=SHAMapLeafNode::pointer(new SHAMapLeafNode(id));
|
||||||
|
// construct leaf WRITEME
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapInnerNode::pointer SHAMap::getInner(const SHAMapNode &id, const uint256& hash)
|
||||||
|
{ // retrieve an inner node whose node hash is known
|
||||||
|
SHAMapInnerNode::pointer node=mInnerNodeByID[id];
|
||||||
|
if(node != SHAMapInnerNode::pointer()) return node;
|
||||||
|
|
||||||
|
std::vector<unsigned char> rawNode;
|
||||||
|
if(!fetchNode(hash, id, rawNode)) return node;
|
||||||
|
|
||||||
|
node=SHAMapInnerNode::pointer(new SHAMapInnerNode(id, rawNode));
|
||||||
|
if(node->getNodeHash()!=hash)
|
||||||
|
{
|
||||||
|
badNode(hash, id);
|
||||||
|
return SHAMapInnerNode::pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
mInnerNodeByID[id]=node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapItem::pointer SHAMap::firstItem()
|
||||||
{
|
{
|
||||||
|
ScopedLock sl(mLock);
|
||||||
|
return firstBelow(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHAMapItem::pointer SHAMap::lastItem()
|
||||||
|
{
|
||||||
|
ScopedLock sl(mLock);
|
||||||
|
return lastBelow(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapItem::pointer SHAMap::firstBelow(SHAMapInnerNode::pointer Node)
|
||||||
|
{
|
||||||
|
const uint256 zero;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while(Node->isChildLeaf())
|
||||||
|
{
|
||||||
|
for(i=0; i<32; i++)
|
||||||
|
{
|
||||||
|
uint256 cHash(Node->getChildHash(i));
|
||||||
|
if(cHash!=zero)
|
||||||
|
{
|
||||||
|
Node=getInner(Node->getChildNodeID(i), cHash);
|
||||||
|
if(Node==SHAMapInnerNode::pointer()) return SHAMapItem::pointer();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i==32) return SHAMapItem::pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<32; i++)
|
||||||
|
{
|
||||||
|
uint256 cHash=Node->getChildHash(i);
|
||||||
|
if(cHash!=zero)
|
||||||
|
{
|
||||||
|
SHAMapLeafNode::pointer mLeaf=getLeaf(Node->getChildNodeID(i), cHash);
|
||||||
|
if(mLeaf==SHAMapLeafNode::pointer()) return SHAMapItem::pointer();
|
||||||
|
return mLeaf->firstItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SHAMapItem::pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapItem::pointer SHAMap::lastBelow(SHAMapInnerNode::pointer Node)
|
||||||
|
{
|
||||||
|
ScopedLock sl(mLock);
|
||||||
|
|
||||||
|
const uint256 zero;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while(Node->isChildLeaf())
|
||||||
|
{
|
||||||
|
for(i=31; i>=0; i--)
|
||||||
|
{
|
||||||
|
uint256 cHash(Node->getChildHash(i));
|
||||||
|
if(cHash!=0)
|
||||||
|
{
|
||||||
|
Node=getInner(Node->getChildNodeID(i), cHash);
|
||||||
|
if(Node==SHAMapInnerNode::pointer()) return SHAMapItem::pointer();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i<0) return SHAMapItem::pointer();
|
||||||
|
}
|
||||||
|
for(int i=31; i>=0; i--)
|
||||||
|
{
|
||||||
|
uint256 cHash=Node->getChildHash(i);
|
||||||
|
if(cHash!=zero)
|
||||||
|
{
|
||||||
|
SHAMapLeafNode::pointer mLeaf=getLeaf(Node->getChildNodeID(i), cHash);
|
||||||
|
if(mLeaf==SHAMapLeafNode::pointer()) return SHAMapItem::pointer();
|
||||||
|
return mLeaf->lastItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapItem::pointer SHAMap::nextItem(const SHAMapItem &)
|
||||||
|
{
|
||||||
|
// WRITEME
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapItem::pointer SHAMap::prevItem(const SHAMapItem &)
|
||||||
|
{
|
||||||
|
// WRITEME
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMap::hasItem(const uint256& id)
|
||||||
|
{ // does the tree have an item with this ID
|
||||||
|
ScopedLock sl(mLock);
|
||||||
|
std::vector<SHAMapInnerNode::pointer> path;
|
||||||
|
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path);
|
||||||
|
if(leaf == SHAMapLeafNode::pointer()) return false;
|
||||||
|
SHAMapItem::pointer item=leaf->findItem(id);
|
||||||
|
return item == SHAMapItem::pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMap::delItem(const uint256& id)
|
||||||
|
{ // delete the item with this ID
|
||||||
|
ScopedLock sl(mLock);
|
||||||
|
std::vector<SHAMapInnerNode::pointer> path;
|
||||||
|
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path);
|
||||||
|
if(leaf == SHAMapLeafNode::pointer()) return false;
|
||||||
|
if(!leaf->delItem(id)) return false;
|
||||||
|
dirtyUp(id, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMap::addItem(const SHAMapItem& item)
|
||||||
|
{ // add the specified item
|
||||||
|
ScopedLock sl(mLock);
|
||||||
|
std::vector<SHAMapInnerNode::pointer> path;
|
||||||
|
SHAMapLeafNode::pointer leaf=walkToLeaf(item.getTag(), true, path);
|
||||||
|
if(leaf == SHAMapLeafNode::pointer()) return false;
|
||||||
|
if(!leaf->addUpdateItem(item)) return false;
|
||||||
|
dirtyUp(item.getTag(), path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSHAMap()
|
||||||
|
{
|
||||||
|
uint256 h1, h2, h3, h4, h5;
|
||||||
|
h1.SetHex("436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe");
|
||||||
|
h2.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
|
||||||
|
h3.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||||
|
h4.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
|
||||||
|
h5.SetHex("092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
|
||||||
|
|
||||||
|
SHAMap sMap(32);
|
||||||
|
SHAMapItem i1(h1), i2(h2), i3(h3), i4(h4), i5(h5);
|
||||||
|
|
||||||
|
sMap.dump();
|
||||||
|
}
|
||||||
|
|||||||
83
SHAMap.h
83
SHAMap.h
@@ -2,6 +2,8 @@
|
|||||||
#define __SHAMAP__
|
#define __SHAMAP__
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/bimap.hpp>
|
#include <boost/bimap.hpp>
|
||||||
@@ -37,8 +39,9 @@ public:
|
|||||||
|
|
||||||
bool isRoot() const { return mDepth==0; }
|
bool isRoot() const { return mDepth==0; }
|
||||||
bool isLeaf() const { return mDepth==leafDepth; }
|
bool isLeaf() const { return mDepth==leafDepth; }
|
||||||
|
bool isChildLeaf() const { return mDepth<(leafDepth-1); }
|
||||||
bool isInner() const { return !isRoot() && !isLeaf(); }
|
bool isInner() const { return !isRoot() && !isLeaf(); }
|
||||||
virtual bool IsPopulated(void) const { return false; }
|
virtual bool isPopulated(void) const { return false; }
|
||||||
|
|
||||||
SHAMapNode getParentNodeID() { return SHAMapNode(mDepth-1, mNodeID); }
|
SHAMapNode getParentNodeID() { return SHAMapNode(mDepth-1, mNodeID); }
|
||||||
SHAMapNode getChildNodeID(int m);
|
SHAMapNode getChildNodeID(int m);
|
||||||
@@ -51,6 +54,8 @@ public:
|
|||||||
bool operator<=(const SHAMapNode &) const;
|
bool operator<=(const SHAMapNode &) const;
|
||||||
bool operator>=(const SHAMapNode &) const;
|
bool operator>=(const SHAMapNode &) const;
|
||||||
|
|
||||||
|
virtual void dump(void);
|
||||||
|
|
||||||
static void ClassInit();
|
static void ClassInit();
|
||||||
static uint256 getNodeID(int depth, const uint256 &hash);
|
static uint256 getNodeID(int depth, const uint256 &hash);
|
||||||
};
|
};
|
||||||
@@ -66,6 +71,7 @@ private:
|
|||||||
std::vector<unsigned char> mData;
|
std::vector<unsigned char> mData;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
SHAMapItem(const uint256 &tag); // tag is data
|
||||||
SHAMapItem(const uint256 &tag, const std::vector<unsigned char>& data);
|
SHAMapItem(const uint256 &tag, const std::vector<unsigned char>& data);
|
||||||
SHAMapItem(const std::vector<unsigned char>& data); // tag by hash
|
SHAMapItem(const std::vector<unsigned char>& data); // tag by hash
|
||||||
|
|
||||||
@@ -87,6 +93,7 @@ public:
|
|||||||
bool operator!=(const uint256& i) const { return mTag!=i; }
|
bool operator!=(const uint256& i) const { return mTag!=i; }
|
||||||
bool operator<=(const uint256& i) const { return mTag<=i; }
|
bool operator<=(const uint256& i) const { return mTag<=i; }
|
||||||
bool operator>=(const uint256& i) const { return mTag>=i; }
|
bool operator>=(const uint256& i) const { return mTag>=i; }
|
||||||
|
virtual void dump(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -101,7 +108,7 @@ private:
|
|||||||
uint256 mHash;
|
uint256 mHash;
|
||||||
std::list<SHAMapItem> mItems;
|
std::list<SHAMapItem> mItems;
|
||||||
|
|
||||||
void updateHash();
|
bool updateHash();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool addUpdateItem(const SHAMapItem&);
|
bool addUpdateItem(const SHAMapItem&);
|
||||||
@@ -111,15 +118,19 @@ protected:
|
|||||||
public:
|
public:
|
||||||
SHAMapLeafNode(const SHAMapNode& nodeID);
|
SHAMapLeafNode(const SHAMapNode& nodeID);
|
||||||
|
|
||||||
virtual bool IsPopulated(void) const { return true; }
|
virtual bool isPopulated(void) const { return true; }
|
||||||
|
|
||||||
const uint256& GetNodeHash() const { return mHash; }
|
const uint256& GetNodeHash() const { return mHash; }
|
||||||
bool isEmpty() const { return mItems.empty(); }
|
bool isEmpty() const { return mItems.empty(); }
|
||||||
int getItemCount() const { return mItems.size(); }
|
int getItemCount() const { return mItems.size(); }
|
||||||
const uint256& getHash(int m) const;
|
|
||||||
|
|
||||||
bool hasItem(const uint256 &item) const;
|
bool hasItem(const uint256 &item) const;
|
||||||
SHAMapItem::pointer findItem(const uint256 &tag);
|
SHAMapItem::pointer findItem(const uint256 &tag);
|
||||||
|
SHAMapItem::pointer firstItem();
|
||||||
|
SHAMapItem::pointer lastItem();
|
||||||
|
SHAMapItem::pointer nextItem(SHAMapItem::pointer);
|
||||||
|
|
||||||
|
virtual void dump(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -134,20 +145,24 @@ private:
|
|||||||
uint256 mHash;
|
uint256 mHash;
|
||||||
uint256 mHashes[32];
|
uint256 mHashes[32];
|
||||||
|
|
||||||
void updateHash();
|
bool updateHash();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setChildHash(int m, const uint256 &hash);
|
bool setChildHash(int m, const uint256 &hash);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SHAMapInnerNode(int Depth, const uint256 &NodeID);
|
SHAMapInnerNode(int Depth, const uint256 &NodeID);
|
||||||
|
SHAMapInnerNode(const SHAMapNode &id, const std::vector<unsigned char> &contents);
|
||||||
|
|
||||||
virtual bool isPopulated(void) const { return true; }
|
virtual bool isPopulated(void) const { return true; }
|
||||||
|
|
||||||
|
bool isEmptyBranch(int m) const { return mHashes[m]==0; }
|
||||||
const uint256& getNodeHash() const { return mHash; }
|
const uint256& getNodeHash() const { return mHash; }
|
||||||
const uint256& getChildHash(int m) const;
|
const uint256& getChildHash(int m) const;
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
};
|
|
||||||
|
|
||||||
|
virtual void dump(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class SHAMap
|
class SHAMap
|
||||||
@@ -156,13 +171,31 @@ public:
|
|||||||
typedef boost::shared_ptr<SHAMap> pointer;
|
typedef boost::shared_ptr<SHAMap> pointer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int mLeafDataSize;
|
||||||
mutable boost::recursive_mutex mLock;
|
mutable boost::recursive_mutex mLock;
|
||||||
std::map<SHAMapNode, SHAMapLeafNode> mLeafByID;
|
std::map<SHAMapNode, SHAMapLeafNode::pointer> mLeafByID;
|
||||||
std::map<SHAMapNode, SHAMapInnerNode> mInnerNodeByID;
|
std::map<SHAMapNode, SHAMapInnerNode::pointer> mInnerNodeByID;
|
||||||
boost::bimap<uint256, SHAMapNode> NodeHash;
|
std::map<SHAMapNode, SHAMapLeafNode::pointer> mDirtyLeafNodes;
|
||||||
|
std::map<SHAMapNode, SHAMapInnerNode::pointer> mDirtyInnerNodes;
|
||||||
|
|
||||||
|
SHAMapInnerNode::pointer root;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void dirtyUp(const uint256& id, const std::vector<SHAMapInnerNode::pointer>& path);
|
||||||
|
|
||||||
|
SHAMapLeafNode::pointer createLeaf(const SHAMapInnerNode& lowestParent, const uint256 &id);
|
||||||
|
SHAMapLeafNode::pointer checkCacheLeaf(const SHAMapNode &);
|
||||||
|
SHAMapLeafNode::pointer walkToLeaf(const uint256& id, bool create,
|
||||||
|
std::vector<SHAMapInnerNode::pointer>& path);
|
||||||
|
|
||||||
|
SHAMapLeafNode::pointer getLeaf(const SHAMapNode &id, const uint256& hash);
|
||||||
|
SHAMapInnerNode::pointer getInner(const SHAMapNode &id, const uint256& hash);
|
||||||
|
|
||||||
|
SHAMapItem::pointer firstBelow(SHAMapInnerNode::pointer);
|
||||||
|
SHAMapItem::pointer lastBelow(SHAMapInnerNode::pointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SHAMap();
|
SHAMap(int leafDataSize);
|
||||||
|
|
||||||
// hold the map stable across operations
|
// hold the map stable across operations
|
||||||
ScopedLock Lock() const { return ScopedLock(mLock); }
|
ScopedLock Lock() const { return ScopedLock(mLock); }
|
||||||
@@ -182,17 +215,16 @@ public:
|
|||||||
bool addRawNode(const SHAMapNode& nodeID, std::vector<unsigned char> rawNode);
|
bool addRawNode(const SHAMapNode& nodeID, std::vector<unsigned char> rawNode);
|
||||||
|
|
||||||
// normal hash access functions
|
// normal hash access functions
|
||||||
bool hasHash(const uint256 &hash);
|
bool hasItem(const uint256& id);
|
||||||
bool addHash(const uint256 &hash);
|
bool delItem(const uint256& id);
|
||||||
bool delHash(const uint256 &hash);
|
bool addItem(const SHAMapItem& item);
|
||||||
bool firstHash(uint256 &hash);
|
SHAMapItem::pointer getItem(const uint256 &id);
|
||||||
bool lastHash(uint256 &hash);
|
|
||||||
bool nextHash(uint256 &hash);
|
|
||||||
bool prevHash(uint256 &hash);
|
|
||||||
|
|
||||||
// direct mapping
|
// traverse functions
|
||||||
bool nodeToHash(const SHAMapNode &node, uint256 &hash);
|
SHAMapItem::pointer firstItem();
|
||||||
bool hashToNode(const uint256& hash, SHAMapNode &node);
|
SHAMapItem::pointer lastItem();
|
||||||
|
SHAMapItem::pointer nextItem(const SHAMapItem &);
|
||||||
|
SHAMapItem::pointer prevItem(const SHAMapItem &);
|
||||||
|
|
||||||
// comparison/sync functions
|
// comparison/sync functions
|
||||||
void getMissingNodes(std::vector<SHAMapNode> &nodeHashes, int max);
|
void getMissingNodes(std::vector<SHAMapNode> &nodeHashes, int max);
|
||||||
@@ -201,12 +233,15 @@ public:
|
|||||||
bool getNodeFat(const uint256 &hash, std::vector<uint256> &nodeHashes, int max);
|
bool getNodeFat(const uint256 &hash, std::vector<uint256> &nodeHashes, int max);
|
||||||
bool addKnownNode(const std::vector<unsigned char>& rawNode);
|
bool addKnownNode(const std::vector<unsigned char>& rawNode);
|
||||||
|
|
||||||
|
int flushDirty(int maxNodes);
|
||||||
|
|
||||||
// overloads for backed maps
|
// overloads for backed maps
|
||||||
virtual bool fetchNode(const uint256 &hash, std::vector<unsigned char>& rawNode);
|
virtual bool fetchNode(const uint256 &hash, const SHAMapNode &id, std::vector<unsigned char>& rawNode);
|
||||||
virtual bool writeNode(const uint256 &hash, const std::vector<unsigned char>& rawNode);
|
virtual bool writeNode(const uint256 &hash, const SHAMapNode &id, const std::vector<unsigned char>& rawNode);
|
||||||
virtual bool haveObject(const uint256 &hash);
|
virtual void badNode(const uint256 &hash, const SHAMapNode &id);
|
||||||
|
|
||||||
static bool TestSHAMap();
|
static bool TestSHAMap();
|
||||||
|
virtual void dump(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
192
SHAMapNodes.cpp
Normal file
192
SHAMapNodes.cpp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
#include "Serializer.h"
|
||||||
|
#include "BitcoinUtil.h"
|
||||||
|
#include "SHAMap.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
uint256 SHAMapNode::smMasks[11];
|
||||||
|
|
||||||
|
bool SHAMapNode::operator<(const SHAMapNode &s) const
|
||||||
|
{
|
||||||
|
if(s.mDepth<mDepth) return true;
|
||||||
|
if(s.mDepth>mDepth) return false;
|
||||||
|
return mNodeID<s.mNodeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapNode::operator>(const SHAMapNode &s) const
|
||||||
|
{
|
||||||
|
if(s.mDepth<mDepth) return false;
|
||||||
|
if(s.mDepth>mDepth) return true;
|
||||||
|
return mNodeID>s.mNodeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapNode::operator<=(const SHAMapNode &s) const
|
||||||
|
{
|
||||||
|
if(s.mDepth<mDepth) return true;
|
||||||
|
if(s.mDepth>mDepth) return false;
|
||||||
|
return mNodeID<=s.mNodeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapNode::operator>=(const SHAMapNode &s) const
|
||||||
|
{
|
||||||
|
if(s.mDepth<mDepth) return false;
|
||||||
|
if(s.mDepth>mDepth) return true;
|
||||||
|
return mNodeID>=s.mNodeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapNode::operator==(const SHAMapNode &s) const
|
||||||
|
{
|
||||||
|
return (s.mDepth==mDepth) && (s.mNodeID==mNodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapNode::operator!=(const SHAMapNode &s) const
|
||||||
|
{
|
||||||
|
return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAMapNode::ClassInit()
|
||||||
|
{ // set up the depth masks
|
||||||
|
int i;
|
||||||
|
char HexBuf[65];
|
||||||
|
|
||||||
|
for(i=0; i<64; i++) HexBuf[i]='0';
|
||||||
|
HexBuf[64]=0;
|
||||||
|
for(i=0; i<leafDepth; i++)
|
||||||
|
{
|
||||||
|
smMasks[i].SetHex(HexBuf);
|
||||||
|
HexBuf[2*i]='1';
|
||||||
|
HexBuf[2*i+1]='F';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 SHAMapNode::getNodeID(int depth, const uint256& hash)
|
||||||
|
{
|
||||||
|
assert(depth>=0 && depth<=leafDepth);
|
||||||
|
return hash & smMasks[depth];
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapNode::SHAMapNode(int depth, const uint256 &hash)
|
||||||
|
{ // canonicalize the hash to a node ID for this depth
|
||||||
|
assert(depth>=0 && depth<leafDepth);
|
||||||
|
mDepth = depth;
|
||||||
|
mNodeID = getNodeID(depth, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapNode SHAMapNode::getChildNodeID(int m)
|
||||||
|
{
|
||||||
|
assert(!isLeaf());
|
||||||
|
|
||||||
|
uint256 branch=m;
|
||||||
|
branch>>=(mDepth*8);
|
||||||
|
|
||||||
|
return SHAMapNode(mDepth+1, mNodeID | branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SHAMapNode::selectBranch(const uint256 &hash)
|
||||||
|
{
|
||||||
|
if(isLeaf()) // no nodes under this node
|
||||||
|
return -1;
|
||||||
|
if((hash&smMasks[mDepth])!=mNodeID)
|
||||||
|
return -1; // does not go under this node
|
||||||
|
|
||||||
|
uint256 selector=hash&smMasks[mDepth+1];
|
||||||
|
int branch=*(selector.begin()+mDepth);
|
||||||
|
|
||||||
|
assert(branch>=0 && branch<32);
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapLeafNode::SHAMapLeafNode(const SHAMapNode& nodeID) : SHAMapNode(nodeID), mHash(0)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapLeafNode::hasItem(const uint256& item) const
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(const SHAMapItem& nodeItem, mItems)
|
||||||
|
if(nodeItem==item) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapLeafNode::addUpdateItem(const SHAMapItem& item)
|
||||||
|
{ // The node will almost never have more than one item in it
|
||||||
|
std::list<SHAMapItem>::iterator it;
|
||||||
|
for(it=mItems.begin(); it!=mItems.end(); it++)
|
||||||
|
{
|
||||||
|
if(*it==item)
|
||||||
|
{
|
||||||
|
if(it->peekData()==item.peekData())
|
||||||
|
return false; // no change
|
||||||
|
it->updateData(item.peekData());
|
||||||
|
return updateHash();
|
||||||
|
}
|
||||||
|
if((*it)>item)
|
||||||
|
{
|
||||||
|
mItems.insert(it, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mItems.push_back(item);
|
||||||
|
return updateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapLeafNode::delItem(const uint256& tag)
|
||||||
|
{
|
||||||
|
std::list<SHAMapItem>::iterator it;
|
||||||
|
for(it=mItems.begin(); it!=mItems.end(); it++)
|
||||||
|
{
|
||||||
|
if(*it==tag)
|
||||||
|
{
|
||||||
|
mItems.erase(it);
|
||||||
|
return updateHash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapLeafNode::updateHash(void)
|
||||||
|
{
|
||||||
|
uint256 nh;
|
||||||
|
if(mItems.size()!=0) nh=0;
|
||||||
|
{
|
||||||
|
Serializer s;
|
||||||
|
BOOST_FOREACH(const SHAMapItem &mi, mItems)
|
||||||
|
s.addRaw(mi.peekData());
|
||||||
|
nh=s.getSHA512Half();
|
||||||
|
}
|
||||||
|
if(nh==mHash) return false;
|
||||||
|
mHash=nh;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapInnerNode::setChildHash(int m, const uint256 &hash)
|
||||||
|
{
|
||||||
|
assert( (m>=0) && (m<32) );
|
||||||
|
if(mHashes[m]==hash)
|
||||||
|
return false;
|
||||||
|
mHashes[m]=hash;
|
||||||
|
return updateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint256& SHAMapInnerNode::getChildHash(int m) const
|
||||||
|
{
|
||||||
|
assert( (m>=0) && (m<32) );
|
||||||
|
return mHashes[m];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAMapInnerNode::updateHash()
|
||||||
|
{
|
||||||
|
int nc=0;
|
||||||
|
Serializer s;
|
||||||
|
for(int i=0; i<32; i++)
|
||||||
|
{
|
||||||
|
if(mHashes[i]!=0) nc++;
|
||||||
|
s.add256(mHashes[i]);
|
||||||
|
}
|
||||||
|
uint256 nh=0;
|
||||||
|
if(nc!=0)
|
||||||
|
nh=s.getSHA512Half();
|
||||||
|
if(mHash==nh) return false;
|
||||||
|
mHash=nh;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user