From 01983330d863ac6e3f863c7affd1f4c7f11fb3fe Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Feb 2012 15:39:06 -0800 Subject: [PATCH] Complete the SHAMap rewrite. --- SHAMap.h | 7 ++ SHAMapDiff.cpp | 181 +++++++++++++++++------------------------------- SHAMapNodes.cpp | 5 ++ SHAMapSync.cpp | 2 +- 4 files changed, 78 insertions(+), 117 deletions(-) diff --git a/SHAMap.h b/SHAMap.h index e5e0030c85..2e7b55d00c 100644 --- a/SHAMap.h +++ b/SHAMap.h @@ -181,7 +181,11 @@ public: // item node function bool hasItem() const { return !!mItem; } SHAMapItem::pointer peekItem() { return mItem; } + SHAMapItem::pointer getItem() const; bool setItem(SHAMapItem::pointer& i, TNType type); + const uint256& getTag() const { return mItem->getTag(); } + const std::vector& peekData() { return mItem->peekData(); } + std::vector getData() const { return mItem->getData(); } // sync functions bool isFullBelow(void) const { return mFullBelow; } @@ -227,6 +231,9 @@ protected: SHAMapItem::pointer firstBelow(SHAMapTreeNode::pointer); SHAMapItem::pointer lastBelow(SHAMapTreeNode::pointer); + + bool walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherMapItem, bool isFirstMap, + SHAMapDiff& differences, int& maxCount); public: diff --git a/SHAMapDiff.cpp b/SHAMapDiff.cpp index 01ac569adb..3f501d3c9f 100644 --- a/SHAMapDiff.cpp +++ b/SHAMapDiff.cpp @@ -43,7 +43,7 @@ bool SHAMap::walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherM } else { // This is a leaf node, process its item - SHAMapItem::pointer item=node->peekItem(); + SHAMapItem::pointer item=node->getItem(); if(otherMapItem && otherMapItem->getTag()getTag()) { // this item comes after the item from the other map, so add the other item @@ -67,7 +67,7 @@ bool SHAMap::walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherM } else if(item->getTag()==otherMapItem->getTag()) { - if(item->getData()!=otherMapItem->getData()) + if(item->peekData()!=otherMapItem->peekData()) { // non-matching items if(isFirstMap) differences.insert(std::make_pair(otherMapItem->getTag(), @@ -102,131 +102,80 @@ bool SHAMap::compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxC // return value: true=complete table of differences given, false=too many differences // throws on corrupt tables or missing nodes - - -#if 0 -// FIXME: Temporarily disabled - std::stack nodeStack; // track nodes we've pushed - nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash())); ScopedLock sl(Lock()); + if(getHash() == otherMap->getHash()) return true; + nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash())); + while(!nodeStack.empty()) { - SHAMapDiffNode node(nodeStack.top()); + SHAMapDiffNode dNode(nodeStack.top()); nodeStack.pop(); - if(node.mOurHash!=node.mOtherHash) - { - if(node.mNodeID.isLeaf()) - { - if(!node.mOurHash) - { // leaf only in our tree - SHAMapLeafNode::pointer thisNode=getLeaf(node.mNodeID, node.mOurHash, false); - for(SHAMapItem::pointer item=thisNode->firstItem(); item; item=thisNode->nextItem(item->getTag())) - { // items in leaf only in our tree - differences.insert(std::make_pair(item->getTag(), - std::make_pair(item, SHAMapItem::pointer()))); - if((--maxCount)<=0) return false; - } - } - else if(!node.mOtherHash) - { // leaf only in other tree - SHAMapLeafNode::pointer otherNode=otherMap->getLeaf(node.mNodeID, node.mOtherHash, false); - for(SHAMapItem::pointer item=otherNode->firstItem(); item; item=otherNode->nextItem(item->getTag())) - { // items in leaf only in our tree - differences.insert(std::make_pair(item->getTag(), - std::make_pair(SHAMapItem::pointer(), item))); - if((--maxCount)<=0) return false; - } - } - else - { // leaf in both trees, but differs - SHAMapLeafNode::pointer thisNode=getLeaf(node.mNodeID, node.mOurHash, false); - SHAMapLeafNode::pointer otherNode=otherMap->getLeaf(node.mNodeID, node.mOtherHash, false); - SHAMapItem::pointer ourItem=thisNode->firstItem(); - SHAMapItem::pointer otherMapItem=otherNode->firstItem(); - while(ourItem || otherMapItem) - { - if(!otherMapItem) - { // we have items, other tree does not - differences.insert(std::make_pair(ourItem->getTag(), - std::make_pair(ourItem, otherMapItem))); - if((--maxCount)<=0) return false; - otherMapItem=otherNode->nextItem(otherMapItem->getTag()); - } - else if(!ourItem) - { // we have no items, other tree does - differences.insert(std::make_pair(otherMapItem->getTag(), - std::make_pair(ourItem, otherMapItem))); - if((--maxCount)<=0) return false; - otherMapItem=thisNode->nextItem(otherMapItem->getTag()); - } - else if(ourItem->getTag()==otherMapItem->getTag()) - { // we have items with the same tag - if(ourItem->getData()!=otherMapItem->getData()) - { // different data - differences.insert(std::make_pair(ourItem->getTag(), - std::make_pair(ourItem, otherMapItem))); - if((--maxCount)<=0) return false; - } - ourItem=thisNode->nextItem(ourItem->getTag()); - otherMapItem=otherNode->nextItem(otherMapItem->getTag()); - } - else if(ourItem->getTag()getTag()) - { // our item comes first - differences.insert(std::make_pair(ourItem->getTag(), - std::make_pair(ourItem, SHAMapItem::pointer()))); - if((--maxCount)<=0) return false; - ourItem=thisNode->nextItem(ourItem->getTag()); - } - else - { // other item comes first - differences.insert(std::make_pair(otherMapItem->getTag(), - std::make_pair(SHAMapItem::pointer(), otherMapItem))); - if((--maxCount)<=0) return false; - otherMapItem=otherNode->nextItem(otherMapItem->getTag()); - } - } + + SHAMapTreeNode::pointer ourNode=getNode(dNode.mNodeID, dNode.mOurHash, false); + SHAMapTreeNode::pointer otherNode=otherMap->getNode(dNode.mNodeID, dNode.mOtherHash, false); + if(!ourNode || !otherNode) throw SHAMapException(MissingNode); + + if(ourNode->isLeaf() && otherNode->isLeaf()) + { // two leaves + if(ourNode->getTag() == otherNode->getTag()) + { + if(ourNode->peekData()!=otherNode->peekData()) + { + differences.insert(std::make_pair(ourNode->getTag(), + std::make_pair(ourNode->getItem(), otherNode->getItem()))); + if((--maxCount)<=0) return false; } } - else - { // inner node different in two trees - if(!node.mOurHash) - { // node only exist in our tree - SHAMapInnerNode::pointer thisNode=getInner(node.mNodeID, node.mOurHash, false); - for(int i=0; i<32; i++) - { // push all existing branches onto the stack - if(!!thisNode->getChildHash(i)) - nodeStack.push(SHAMapDiffNode(thisNode->getChildNodeID(i), - thisNode->getChildHash(i), uint256())); - } - } - else if(!node.mOtherHash) - { // node only exists in other tree - SHAMapInnerNode::pointer otherNode=otherMap->getInner(node.mNodeID, node.mOtherHash, false); - for(int i=0; i<32; i++) - { // push all existing branches onto the stack - if(!!otherNode->getChildHash(i)) - nodeStack.push(SHAMapDiffNode(otherNode->getChildNodeID(i), - uint256(), otherNode->getChildHash(i))); - } - } - else - { // node in both trees, but differs - SHAMapInnerNode::pointer thisNode=getInner(node.mNodeID, node.mOurHash, false); - SHAMapInnerNode::pointer otherNode=otherMap->getInner(node.mNodeID, node.mOtherHash, false); - for(int i=0; i<32; i++) - { // push all differing branches onto the stack - if(thisNode->getChildHash(i)!=otherNode->getChildHash(i)) - nodeStack.push(SHAMapDiffNode(thisNode->getChildNodeID(i), - thisNode->getChildHash(i), otherNode->getChildHash(i))); - } - } + else + { + differences.insert(std::make_pair(ourNode->getTag(), + std::make_pair(ourNode->getItem(), SHAMapItem::pointer()))); + if((--maxCount)<=0) return false; + differences.insert(std::make_pair(otherNode->getTag(), + std::make_pair(SHAMapItem::pointer(), otherNode->getItem()))); + if((--maxCount)<=0) return false; } } + else if(ourNode->isInner() && otherNode->isLeaf()) + { + if(!walkBranch(ourNode, otherNode->getItem(), true, differences, maxCount)) + return false; + } + else if(ourNode->isLeaf() && otherNode->isInner()) + { + if(!otherMap->walkBranch(otherNode, ourNode->getItem(), false, differences, maxCount)) + return false; + } + else if(ourNode->isInner() && otherNode->isInner()) + { + for(int i=0; i<16; i++) + if(ourNode->getChildHash(i) != otherNode->getChildHash(i) ) + { + if(!otherNode->getChildHash(i)) + { // We have a branch, the other tree does not + SHAMapTreeNode::pointer iNode=getNode(ourNode->getChildNodeID(i), + ourNode->getChildHash(i), false); + if(!iNode) throw SHAMapException(MissingNode); + if(!walkBranch(iNode, SHAMapItem::pointer(), true, differences, maxCount)) + return false; + } + else if(!ourNode->getChildHash(i)) + { // The other tree has a branch, we do not + SHAMapTreeNode::pointer iNode=otherMap->getNode(otherNode->getChildNodeID(i), + otherNode->getChildHash(i), false); + if(!iNode) throw SHAMapException(MissingNode); + if(!otherMap->walkBranch(iNode, SHAMapItem::pointer(), false, differences, maxCount)) + return false; + } + else // The two trees have different non-empty branches + nodeStack.push(SHAMapDiffNode(ourNode->getChildNodeID(i), + ourNode->getChildHash(i), otherNode->getChildHash(i))); + } + } + else assert(false); } -#endif - return true; } diff --git a/SHAMapNodes.cpp b/SHAMapNodes.cpp index 2bdd7d2856..44ff320540 100644 --- a/SHAMapNodes.cpp +++ b/SHAMapNodes.cpp @@ -282,6 +282,11 @@ bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type) return getNodeHash()==hash; } +SHAMapItem::pointer SHAMapTreeNode::getItem() const +{ + return boost::make_shared(*mItem); +} + int SHAMapTreeNode::getBranchCount() const { int ret=0; diff --git a/SHAMapSync.cpp b/SHAMapSync.cpp index e6643ee111..8035ae2f4d 100644 --- a/SHAMapSync.cpp +++ b/SHAMapSync.cpp @@ -303,7 +303,7 @@ bool SHAMap::syncTest() SHAMap source, destination; // add random data to the source map - int items=10+rand()%4000; + int items=rand()%20000; for(int i=0; i