mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 06:25:51 +00:00
Complete the SHAMap rewrite.
This commit is contained in:
7
SHAMap.h
7
SHAMap.h
@@ -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; }
|
||||||
@@ -228,6 +232,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:
|
||||||
|
|
||||||
// build new map
|
// build new map
|
||||||
|
|||||||
189
SHAMapDiff.cpp
189
SHAMapDiff.cpp
@@ -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)
|
|
||||||
{
|
|
||||||
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()<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
|
|
||||||
{ // 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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
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
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user