Complete the SHAMap rewrite.

This commit is contained in:
JoelKatz
2012-02-06 15:39:06 -08:00
parent 04cc08748e
commit 01983330d8
4 changed files with 78 additions and 117 deletions

View File

@@ -181,7 +181,11 @@ public:
// item node function // item node function
bool hasItem() const { return !!mItem; } bool hasItem() const { return !!mItem; }
SHAMapItem::pointer peekItem() { return mItem; } SHAMapItem::pointer peekItem() { return mItem; }
SHAMapItem::pointer getItem() const;
bool setItem(SHAMapItem::pointer& i, TNType type); bool setItem(SHAMapItem::pointer& i, TNType type);
const uint256& getTag() const { return mItem->getTag(); }
const std::vector<unsigned char>& peekData() { return mItem->peekData(); }
std::vector<unsigned char> getData() const { return mItem->getData(); }
// sync functions // sync functions
bool isFullBelow(void) const { return mFullBelow; } bool isFullBelow(void) const { return mFullBelow; }
@@ -227,6 +231,9 @@ protected:
SHAMapItem::pointer firstBelow(SHAMapTreeNode::pointer); SHAMapItem::pointer firstBelow(SHAMapTreeNode::pointer);
SHAMapItem::pointer lastBelow(SHAMapTreeNode::pointer); SHAMapItem::pointer lastBelow(SHAMapTreeNode::pointer);
bool walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherMapItem, bool isFirstMap,
SHAMapDiff& differences, int& maxCount);
public: public:

View File

@@ -43,7 +43,7 @@ bool SHAMap::walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherM
} }
else else
{ // This is a leaf node, process its item { // This is a leaf node, process its item
SHAMapItem::pointer item=node->peekItem(); SHAMapItem::pointer item=node->getItem();
if(otherMapItem && otherMapItem->getTag()<item->getTag()) if(otherMapItem && otherMapItem->getTag()<item->getTag())
{ // this item comes after the item from the other map, so add the other item { // 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()) else if(item->getTag()==otherMapItem->getTag())
{ {
if(item->getData()!=otherMapItem->getData()) if(item->peekData()!=otherMapItem->peekData())
{ // non-matching items { // non-matching items
if(isFirstMap) if(isFirstMap)
differences.insert(std::make_pair(otherMapItem->getTag(), 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 // return value: true=complete table of differences given, false=too many differences
// throws on corrupt tables or missing nodes // throws on corrupt tables or missing nodes
#if 0
// FIXME: Temporarily disabled
std::stack<SHAMapDiffNode> nodeStack; // track nodes we've pushed std::stack<SHAMapDiffNode> nodeStack; // track nodes we've pushed
nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash()));
ScopedLock sl(Lock()); ScopedLock sl(Lock());
if(getHash() == otherMap->getHash()) return true;
nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash()));
while(!nodeStack.empty()) while(!nodeStack.empty())
{ {
SHAMapDiffNode node(nodeStack.top()); SHAMapDiffNode dNode(nodeStack.top());
nodeStack.pop(); nodeStack.pop();
if(node.mOurHash!=node.mOtherHash)
{ SHAMapTreeNode::pointer ourNode=getNode(dNode.mNodeID, dNode.mOurHash, false);
if(node.mNodeID.isLeaf()) SHAMapTreeNode::pointer otherNode=otherMap->getNode(dNode.mNodeID, dNode.mOtherHash, false);
{ if(!ourNode || !otherNode) throw SHAMapException(MissingNode);
if(!node.mOurHash)
{ // leaf only in our tree if(ourNode->isLeaf() && otherNode->isLeaf())
SHAMapLeafNode::pointer thisNode=getLeaf(node.mNodeID, node.mOurHash, false); { // two leaves
for(SHAMapItem::pointer item=thisNode->firstItem(); item; item=thisNode->nextItem(item->getTag())) if(ourNode->getTag() == otherNode->getTag())
{ // items in leaf only in our tree {
differences.insert(std::make_pair(item->getTag(), if(ourNode->peekData()!=otherNode->peekData())
std::make_pair(item, SHAMapItem::pointer()))); {
if((--maxCount)<=0) return false; differences.insert(std::make_pair(ourNode->getTag(),
} std::make_pair(ourNode->getItem(), otherNode->getItem())));
} 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()<otherMapItem->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());
}
}
} }
} }
else else
{ // inner node different in two trees {
if(!node.mOurHash) differences.insert(std::make_pair(ourNode->getTag(),
{ // node only exist in our tree std::make_pair(ourNode->getItem(), SHAMapItem::pointer())));
SHAMapInnerNode::pointer thisNode=getInner(node.mNodeID, node.mOurHash, false); if((--maxCount)<=0) return false;
for(int i=0; i<32; i++) differences.insert(std::make_pair(otherNode->getTag(),
{ // push all existing branches onto the stack std::make_pair(SHAMapItem::pointer(), otherNode->getItem())));
if(!!thisNode->getChildHash(i)) if((--maxCount)<=0) return false;
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 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; return true;
} }

View File

@@ -282,6 +282,11 @@ bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type)
return getNodeHash()==hash; return getNodeHash()==hash;
} }
SHAMapItem::pointer SHAMapTreeNode::getItem() const
{
return boost::make_shared<SHAMapItem>(*mItem);
}
int SHAMapTreeNode::getBranchCount() const int SHAMapTreeNode::getBranchCount() const
{ {
int ret=0; int ret=0;

View File

@@ -303,7 +303,7 @@ bool SHAMap::syncTest()
SHAMap source, destination; SHAMap source, destination;
// add random data to the source map // add random data to the source map
int items=10+rand()%4000; int items=rand()%20000;
for(int i=0; i<items; i++) for(int i=0; i<items; i++)
{ {
Serializer s; Serializer s;