Simplify. Rewrite SHAMap::dirtyUp.

This commit is contained in:
JoelKatz
2011-11-23 23:45:26 -08:00
parent 51f3f4e1a4
commit 83b2f8b73a
3 changed files with 100 additions and 114 deletions

View File

@@ -4,35 +4,30 @@
#include <boost/foreach.hpp>
SHAMap::SHAMap(int leafDataSize, int leafDataOffset) : mLeafDataSize(leafDataSize), mLeafDataOffset(leafDataOffset)
SHAMap::SHAMap()
{
;
}
void SHAMap::dirtyUp(const uint256& id, const std::vector<SHAMapInnerNode::pointer>& path)
void SHAMap::dirtyUp(const uint256& id)
{ // walk the tree up from through the inner nodes to the root
// update linking hashes and add nodes to dirty list
if(mDirtyInnerNodes==NULL) return;
SHAMapLeafNode::pointer leaf=mLeafByID[SHAMapNode(SHAMapNode::leafDepth, id)];
if(!leaf) throw SHAMapException(MissingNode);
std::vector<SHAMapInnerNode::pointer>::const_reverse_iterator it;
uint256 hVal=leaf->getNodeHash();
if(mDirtyLeafNodes) (*mDirtyLeafNodes)[*leaf]=leaf;
if(!hVal) mLeafByID.erase(*leaf);
it = path.rbegin();
if(it == path.rend()) return;
(*mDirtyInnerNodes)[**it]=*it;
uint256 hVal=(*it)->getNodeHash();
if(hVal==0)
mInnerNodeByID.erase(**it);
for(++it; it<path.rend(); ++it)
{
if(!(*it)->setChildHash((*it)->selectBranch(id), hVal))
return;
(*mDirtyInnerNodes)[**it]=*it;
hVal = (*it)->getNodeHash();
if(hVal == 0) mInnerNodeByID.erase(**it);
for(int depth=SHAMapNode::leafDepth-1; depth>=0; depth--)
{ // walk up the tree to the root updating nodes
SHAMapInnerNode::pointer node=mInnerNodeByID[SHAMapNode(depth, leaf->getNodeID())];
if(!node) throw SHAMapException(MissingNode);
if(!node->setChildHash(node->selectBranch(id), hVal)) return;
if(mDirtyInnerNodes) (*mDirtyInnerNodes)[*node]=node;
hVal=node->getNodeHash();
if(!hVal) mInnerNodeByID.erase(*node);
}
assert(**it == *root);
}
SHAMapLeafNode::pointer SHAMap::checkCacheLeaf(const SHAMapNode& iNode)
@@ -42,8 +37,7 @@ SHAMapLeafNode::pointer SHAMap::checkCacheLeaf(const SHAMapNode& iNode)
}
SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
std::vector<SHAMapInnerNode::pointer>& path)
SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create)
{ // walk down to the leaf that would contain this ID
// is leaf node in cache
SHAMapLeafNode::pointer ln=checkCacheLeaf(SHAMapNode(SHAMapNode::leafDepth, id));
@@ -51,7 +45,6 @@ SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
// walk tree to leaf
SHAMapInnerNode::pointer inNode=root;
path.push_back(inNode);
for(int i=1; i<SHAMapNode::leafDepth; i++)
{
@@ -61,13 +54,12 @@ SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
if(inNode->isEmptyBranch(branch))
{ // no nodes below this one
if(!create) return SHAMapLeafNode::pointer();
return createLeaf(*inNode, id, path);
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) throw SHAMapException(InvalidNode);
path.push_back(inNode);
}
else // child is leaf node
{
@@ -75,7 +67,7 @@ SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
if(ln==NULL)
{
if(!create) return SHAMapLeafNode::pointer();
return createLeaf(*inNode, id, path);
return createLeaf(*inNode, id);
}
}
}
@@ -86,30 +78,23 @@ SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
SHAMapLeafNode::pointer SHAMap::getLeaf(const SHAMapNode &id, const uint256& hash)
{ // retrieve a leaf whose node hash is known
assert(!!hash);
if(!id.isLeaf()) return SHAMapLeafNode::pointer();
SHAMapLeafNode::pointer leaf=mLeafByID[id]; // is the leaf in memory
if(leaf) return leaf;
std::vector<unsigned char> rawNode; // is it in backing store
if(!fetchNode(hash, id, rawNode)) return SHAMapLeafNode::pointer();
std::vector<SHAMapItem::pointer> leafData; // is it in backing store
if(!fetchLeafNode(hash, id, leafData))
throw SHAMapException(MissingNode);
Serializer s(rawNode);
leaf=SHAMapLeafNode::pointer(new SHAMapLeafNode(id));
BOOST_FOREACH(SHAMapItem::pointer& item, leafData)
leaf->addUpdateItem(item);
for(int i=0; i<s.getLength(); i+=mLeafDataSize)
{
uint256 tag;
if(mLeafDataOffset<0)
{
Serializer inner;
inner.addRaw(s.getRaw(i, mLeafDataSize));
tag=inner.getSHA512Half();
}
else tag=s.get256(i+mLeafDataOffset);
leaf->addUpdateItem(SHAMapItem::pointer(new SHAMapItem(tag, s.getRaw(i, mLeafDataSize))));
}
leaf->updateHash();
mLeafByID[*leaf]=leaf;
assert(leaf->getNodeHash()==hash);
if(leaf->getNodeHash()!=hash) throw SHAMapException(InvalidNode);
mLeafByID[id]=leaf;
return leaf;
}
@@ -119,14 +104,11 @@ SHAMapInnerNode::pointer SHAMap::getInner(const SHAMapNode &id, const uint256& h
if(node) return node;
std::vector<unsigned char> rawNode;
if(!fetchNode(hash, id, rawNode)) return SHAMapInnerNode::pointer();
if(!fetchInnerNode(hash, id, rawNode)) throw SHAMapException(MissingNode);
node=SHAMapInnerNode::pointer(new SHAMapInnerNode(id, rawNode));
if(node->getNodeHash()!=hash)
{
badNode(hash, id);
return SHAMapInnerNode::pointer();
}
if(node->getNodeHash()!=hash) throw SHAMapException(InvalidNode);
mInnerNodeByID[id]=node;
return node;
}
@@ -221,39 +203,40 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
{ // Get a pointer to the next item in the tree after a given item - item must be in tree
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path);
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false);
if(!leaf) return SHAMapItem::pointer();
// is there another item in this leaf? (there almost never will be)
SHAMapItem::pointer next=leaf->nextItem(id);
if(next) return next;
for(std::vector<SHAMapInnerNode::pointer>::reverse_iterator rit=path.rbegin(); rit<path.rend(); ++rit)
for(int depth=SHAMapNode::leafDepth-1; depth>=0; depth++)
{ // walk up the tree until we find a node with a subsequent child
SHAMapInnerNode::pointer& node=*rit;
for(int i=node->selectBranch(id)+1; i<32; i++)
if(!!node->getChildHash(i))
{ // node has a subsequent child
SHAMapNode nextNode=node->getChildNodeID(i);
uint256 nextHash=node->getChildHash(i);
if(nextNode.isLeaf())
{ // this is a terminal inner node
leaf=getLeaf(nextNode, nextHash);
if(!leaf) throw SHAMapException(MissingNode);
next=leaf->firstItem();
if(!next) throw SHAMapException(InvalidNode);
return next;
}
// the next item is the first item below this node
SHAMapInnerNode::pointer inner=getInner(nextNode, nextHash);
if(!inner) throw SHAMapException(MissingNode);
SHAMapInnerNode::pointer node=mInnerNodeByID[SHAMapNode(depth, id)];
if(!node) throw SHAMapException(MissingNode);
for(int i=node->selectBranch(id)+1; i<32; i++)
if(!!node->getChildHash(i))
{ // node has a subsequent child
SHAMapNode nextNode(node->getChildNodeID(i));
const uint256& nextHash(node->getChildHash(i));
if(nextNode.isLeaf())
{ // this is a terminal inner node
leaf=getLeaf(nextNode, nextHash);
if(!leaf) throw SHAMapException(MissingNode);
next=leaf->firstItem();
if(!next) throw SHAMapException(InvalidNode);
return next;
}
// the next item is the first item below this node
SHAMapInnerNode::pointer inner=getInner(nextNode, nextHash);
if(!inner) throw SHAMapException(MissingNode);
next=firstBelow(inner);
if(!next) throw SHAMapException(InvalidNode);
return next;
}
}
}
// must be last item
@@ -265,15 +248,13 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id)
// WRITEME
}
SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent, const uint256& id,
std::vector<SHAMapInnerNode::pointer>& path)
SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent, const uint256& id)
{
int depth=lowestParent.getDepth();
for(int depth=lowestParent.getDepth(); depth<SHAMapNode::leafDepth; depth++)
{
SHAMapInnerNode::pointer newNode(new SHAMapInnerNode(SHAMapNode(++depth, id)));
mInnerNodeByID[*newNode]=newNode;
path.push_back(newNode);
}
SHAMapLeafNode::pointer newLeaf(new SHAMapLeafNode(SHAMapNode(SHAMapNode::leafDepth, id)));
@@ -284,8 +265,7 @@ SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent,
SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
{
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path);
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false);
if(!leaf) return SHAMapItem::pointer();
return leaf->findItem(id);
}
@@ -293,8 +273,7 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
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);
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false);
if(!leaf) return false;
SHAMapItem::pointer item=leaf->findItem(id);
return (bool) item;
@@ -303,34 +282,31 @@ bool SHAMap::hasItem(const uint256& id)
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);
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false);
if(!leaf) return false;
if(!leaf->delItem(id)) return false;
dirtyUp(id, path);
dirtyUp(id);
return true;
}
bool SHAMap::addGiveItem(const SHAMapItem::pointer item)
{ // add the specified item
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(item->getTag(), true, path);
SHAMapLeafNode::pointer leaf=walkToLeaf(item->getTag(), true);
if(!leaf) return false;
if(leaf->hasItem(item->getTag())) return false;
if(!leaf->addUpdateItem(item)) return false;
dirtyUp(item->getTag(), path);
dirtyUp(item->getTag());
return true;
}
bool SHAMap::updateGiveItem(SHAMapItem::pointer item)
{
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(item->getTag(), true, path);
SHAMapLeafNode::pointer leaf=walkToLeaf(item->getTag(), true);
if(!leaf) return false;
if(!leaf->addUpdateItem(item)) return false;
dirtyUp(item->getTag(), path);
dirtyUp(item->getTag());
return true;
}
@@ -340,37 +316,48 @@ void SHAMapItem::dump()
}
// overloads for backed maps
bool SHAMap::fetchNode(const uint256 &, const SHAMapNode &, std::vector<unsigned char> &)
bool SHAMap::fetchInnerNode(const uint256&, const SHAMapNode&, std::vector<unsigned char>&)
{
return false;
}
bool SHAMap::writeNode(const uint256 &, const SHAMapNode &, const std::vector<unsigned char> &)
bool SHAMap::fetchLeafNode(const uint256&, const SHAMapNode&, std::vector<SHAMapItem::pointer>&)
{
return false;
}
bool SHAMap::writeInnerNode(const uint256&, const SHAMapNode&, const std::vector<unsigned char>&)
{
return true;
}
void SHAMap::badNode(const uint256 &, const SHAMapNode &)
bool SHAMap::writeLeafNode(const uint256&, const SHAMapNode&, const std::vector<unsigned char>&)
{
return;
return true;
}
void SHAMap::dump()
{
}
static std::vector<unsigned char>IntToVUC(int i)
{
std::vector<unsigned char> vuc;
vuc.push_back((unsigned char) i);
return vuc;
}
bool SHAMap::TestSHAMap()
{
uint256 h1, h2, h3, h4, h5;
h1.SetHex("436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe");
h2.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h3.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca8");
h4.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h5.SetHex("092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h1.SetHex("092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h2.SetHex("436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe");
h3.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h4.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca8");
h5.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
SHAMap sMap(32);
// SHAMapItem i1(h1), i2(h2), i3(h3), i4(h4), i5(h5);
SHAMap sMap;
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
sMap.dump();
}

View File

@@ -188,18 +188,16 @@ private:
std::map<SHAMapNode, SHAMapLeafNode::pointer> mLeafByID;
std::map<SHAMapNode, SHAMapInnerNode::pointer> mInnerNodeByID;
boost::shared_ptr<std::map<SHAMapNode, SHAMapLeafNode::pointer> > mDirtyLeafNodes;
boost::shared_ptr<std::map<SHAMapNode, SHAMapInnerNode::pointer> > mDirtyInnerNodes;
boost::shared_ptr<std::map<SHAMapNode, SHAMapInnerNode::pointer> > mDirtyInnerNodes;
SHAMapInnerNode::pointer root;
protected:
void dirtyUp(const uint256& id, const std::vector<SHAMapInnerNode::pointer>& path);
void dirtyUp(const uint256 &id);
SHAMapLeafNode::pointer createLeaf(const SHAMapInnerNode& lowestParent, const uint256& id,
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 walkToLeaf(const uint256& id, bool create);
SHAMapLeafNode::pointer getLeaf(const SHAMapNode& id, const uint256& hash);
SHAMapInnerNode::pointer getInner(const SHAMapNode& id, const uint256& hash);
@@ -208,7 +206,7 @@ protected:
SHAMapItem::pointer lastBelow(SHAMapInnerNode::pointer);
public:
SHAMap(int leafDataSize=32, int leafDataOffset=-1);
SHAMap();
// hold the map stable across operations
ScopedLock Lock() const { return ScopedLock(mLock); }
@@ -260,9 +258,10 @@ public:
int flushDirty(int maxNodes);
// overloads for backed maps
virtual bool fetchNode(const uint256& hash, const SHAMapNode& id, std::vector<unsigned char>& rawNode);
virtual bool writeNode(const uint256& hash, const SHAMapNode& id, const std::vector<unsigned char>& rawNode);
virtual void badNode(const uint256& hash, const SHAMapNode& id);
virtual bool fetchInnerNode(const uint256& hash, const SHAMapNode& id, std::vector<unsigned char>& rawNode);
virtual bool fetchLeafNode(const uint256& hash, const SHAMapNode& id, std::vector<SHAMapItem::pointer>& nodeData);
virtual bool writeInnerNode(const uint256& hash, const SHAMapNode& id, const std::vector<unsigned char>& rawNode);
virtual bool writeLeafNode(const uint256& hash, const SHAMapNode& id, const std::vector<unsigned char>& rawNode);
static bool TestSHAMap();
virtual void dump(void);

View File

@@ -121,10 +121,10 @@ bool SHAMapLeafNode::addUpdateItem(SHAMapItem::pointer item)
SHAMapItem &nodeItem=**it;
if(nodeItem.getTag()==item->getTag())
{
if(nodeItem.peekData()==item->peekData())
return false; // no change
nodeItem.updateData(item->peekData());
return updateHash();
if(nodeItem.peekData()==item->peekData())
return false; // no change
nodeItem.updateData(item->peekData());
return updateHash();
}
if(nodeItem.getTag()>item->getTag())
{
@@ -184,7 +184,7 @@ SHAMapItem::pointer SHAMapLeafNode::lastItem(void)
bool SHAMapLeafNode::updateHash(void)
{
uint256 nh;
if(mItems.size()!=0) nh=0;
if(mItems.size()!=0)
{
Serializer s;
BOOST_FOREACH(const SHAMapItem::pointer &mi, mItems)