diff --git a/SHAMap.cpp b/SHAMap.cpp index e5e8d5622b..7e0d9ee808 100644 --- a/SHAMap.cpp +++ b/SHAMap.cpp @@ -4,35 +4,30 @@ #include -SHAMap::SHAMap(int leafDataSize, int leafDataOffset) : mLeafDataSize(leafDataSize), mLeafDataOffset(leafDataOffset) +SHAMap::SHAMap() { ; } -void SHAMap::dirtyUp(const uint256& id, const std::vector& 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::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; itsetChildHash((*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& 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; iisEmptyBranch(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 rawNode; // is it in backing store - if(!fetchNode(hash, id, rawNode)) return SHAMapLeafNode::pointer(); + std::vector 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; iaddUpdateItem(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 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 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::reverse_iterator rit=path.rbegin(); rit=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& path) +SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent, const uint256& id) { int depth=lowestParent.getDepth(); for(int depth=lowestParent.getDepth(); depth 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 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 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 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 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 &) +bool SHAMap::fetchInnerNode(const uint256&, const SHAMapNode&, std::vector&) { return false; } -bool SHAMap::writeNode(const uint256 &, const SHAMapNode &, const std::vector &) +bool SHAMap::fetchLeafNode(const uint256&, const SHAMapNode&, std::vector&) +{ + return false; +} + +bool SHAMap::writeInnerNode(const uint256&, const SHAMapNode&, const std::vector&) { return true; } -void SHAMap::badNode(const uint256 &, const SHAMapNode &) +bool SHAMap::writeLeafNode(const uint256&, const SHAMapNode&, const std::vector&) { - return; + return true; } - void SHAMap::dump() { } +static std::vectorIntToVUC(int i) +{ + std::vector 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(); } diff --git a/SHAMap.h b/SHAMap.h index 950150f9ae..e2c5a90ae1 100644 --- a/SHAMap.h +++ b/SHAMap.h @@ -188,18 +188,16 @@ private: std::map mLeafByID; std::map mInnerNodeByID; boost::shared_ptr > mDirtyLeafNodes; - boost::shared_ptr > mDirtyInnerNodes; + boost::shared_ptr > mDirtyInnerNodes; SHAMapInnerNode::pointer root; protected: - void dirtyUp(const uint256& id, const std::vector& path); + void dirtyUp(const uint256 &id); - SHAMapLeafNode::pointer createLeaf(const SHAMapInnerNode& lowestParent, const uint256& id, - std::vector& 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& 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& rawNode); - virtual bool writeNode(const uint256& hash, const SHAMapNode& id, const std::vector& rawNode); - virtual void badNode(const uint256& hash, const SHAMapNode& id); + virtual bool fetchInnerNode(const uint256& hash, const SHAMapNode& id, std::vector& rawNode); + virtual bool fetchLeafNode(const uint256& hash, const SHAMapNode& id, std::vector& nodeData); + virtual bool writeInnerNode(const uint256& hash, const SHAMapNode& id, const std::vector& rawNode); + virtual bool writeLeafNode(const uint256& hash, const SHAMapNode& id, const std::vector& rawNode); static bool TestSHAMap(); virtual void dump(void); diff --git a/SHAMapNodes.cpp b/SHAMapNodes.cpp index 62681623cb..86c228a177 100644 --- a/SHAMapNodes.cpp +++ b/SHAMapNodes.cpp @@ -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)