mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Fix a few cases where SHAMap nodes don't get correctly written.
When we fetch a node from the database, we artificially mark it "old" so modifications are saved. New nodes are added to the dirty node tray if it is armed.
This commit is contained in:
@@ -48,7 +48,7 @@ SHAMap::SHAMap(SHAMapType t, uint32 seq) : mSeq(seq), mState(smsModifying), mTyp
|
|||||||
mTNByID[*root] = root;
|
mTNByID[*root] = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(0), mState(smsSynching), mType(t)
|
SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(1), mState(smsSynching), mType(t)
|
||||||
{ // FIXME: Need to acquire root node
|
{ // FIXME: Need to acquire root node
|
||||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||||
root->makeInner();
|
root->makeInner();
|
||||||
@@ -138,7 +138,8 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
|
|||||||
SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode)
|
SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode)
|
||||||
{
|
{
|
||||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.find(iNode);
|
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.find(iNode);
|
||||||
if (it == mTNByID.end()) return SHAMapTreeNode::pointer();
|
if (it == mTNByID.end())
|
||||||
|
return SHAMapTreeNode::pointer();
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +210,7 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
|
|||||||
node = fetchNodeExternal(id, hash);
|
node = fetchNodeExternal(id, hash);
|
||||||
if (!mTNByID.insert(std::make_pair(id, node)).second)
|
if (!mTNByID.insert(std::make_pair(id, node)).second)
|
||||||
assert(false);
|
assert(false);
|
||||||
|
trackNewNode(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +223,7 @@ SHAMapTreeNode* SHAMap::getNodePointer(const SHAMapNode& id, const uint256& hash
|
|||||||
SHAMapTreeNode::pointer node = fetchNodeExternal(id, hash);
|
SHAMapTreeNode::pointer node = fetchNodeExternal(id, hash);
|
||||||
if (!mTNByID.insert(std::make_pair(id, node)).second)
|
if (!mTNByID.insert(std::make_pair(id, node)).second)
|
||||||
assert(false);
|
assert(false);
|
||||||
|
trackNewNode(node);
|
||||||
return node.get();
|
return node.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,16 +233,25 @@ void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify)
|
|||||||
assert(node->getSeq() <= mSeq);
|
assert(node->getSeq() <= mSeq);
|
||||||
if (node && modify && (node->getSeq() != mSeq))
|
if (node && modify && (node->getSeq() != mSeq))
|
||||||
{ // have a CoW
|
{ // have a CoW
|
||||||
node = boost::make_shared<SHAMapTreeNode>(*node, mSeq);
|
assert(node->getSeq() < mSeq);
|
||||||
if (mDirtyNodes)
|
|
||||||
(*mDirtyNodes)[*node] = node;
|
node = boost::make_shared<SHAMapTreeNode>(*node, mSeq); // here's to the new node, same as the old node
|
||||||
assert(node->isValid());
|
assert(node->isValid());
|
||||||
|
|
||||||
mTNByID[*node] = node;
|
mTNByID[*node] = node;
|
||||||
if (node->isRoot())
|
if (node->isRoot())
|
||||||
root = node;
|
root = node;
|
||||||
|
if (mDirtyNodes)
|
||||||
|
(*mDirtyNodes)[*node] = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHAMap::trackNewNode(SHAMapTreeNode::pointer& node)
|
||||||
|
{
|
||||||
|
if (mDirtyNodes)
|
||||||
|
(*mDirtyNodes)[*node] = node;
|
||||||
|
}
|
||||||
|
|
||||||
SHAMapItem::SHAMapItem(const uint256& tag, const std::vector<unsigned char>& data)
|
SHAMapItem::SHAMapItem(const uint256& tag, const std::vector<unsigned char>& data)
|
||||||
: mTag(tag), mData(data)
|
: mTag(tag), mData(data)
|
||||||
{ ; }
|
{ ; }
|
||||||
@@ -594,6 +606,7 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
|||||||
assert(false);
|
assert(false);
|
||||||
throw std::runtime_error("invalid inner node");
|
throw std::runtime_error("invalid inner node");
|
||||||
}
|
}
|
||||||
|
trackNewNode(newNode);
|
||||||
node->setChildHash(branch, newNode->getNodeHash());
|
node->setChildHash(branch, newNode->getNodeHash());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -622,6 +635,7 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
|||||||
assert(false);
|
assert(false);
|
||||||
stack.push(node);
|
stack.push(node);
|
||||||
node = newNode;
|
node = newNode;
|
||||||
|
trackNewNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can add the two leaf nodes here
|
// we can add the two leaf nodes here
|
||||||
@@ -632,12 +646,14 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
|||||||
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||||
assert(false);
|
assert(false);
|
||||||
node->setChildHash(b1, newNode->getNodeHash()); // OPTIMIZEME hash op not needed
|
node->setChildHash(b1, newNode->getNodeHash()); // OPTIMIZEME hash op not needed
|
||||||
|
trackNewNode(newNode);
|
||||||
|
|
||||||
newNode = boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(b2), otherItem, type, mSeq);
|
newNode = boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(b2), otherItem, type, mSeq);
|
||||||
assert(newNode->isValid() && newNode->isLeaf());
|
assert(newNode->isValid() && newNode->isLeaf());
|
||||||
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
|
||||||
assert(false);
|
assert(false);
|
||||||
node->setChildHash(b2, newNode->getNodeHash());
|
node->setChildHash(b2, newNode->getNodeHash());
|
||||||
|
trackNewNode(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
dirtyUp(stack, tag, node->getNodeHash());
|
dirtyUp(stack, tag, node->getNodeHash());
|
||||||
@@ -703,8 +719,19 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, snfPREFIX);
|
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq - 1, snfPREFIX);
|
||||||
assert((ret->getNodeHash() == hash) && (id == *ret));
|
#ifdef DEBUG
|
||||||
|
if (id != *ret)
|
||||||
|
{
|
||||||
|
Log(lsFATAL) << "id:" << id << ", got:" << *ret;
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
if (ret->getNodeHash() != hash)
|
||||||
|
{
|
||||||
|
Log(lsFATAL) << "Hashes don't match";
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@@ -730,40 +757,37 @@ void SHAMap::fetchRoot(const uint256& hash)
|
|||||||
assert(root->getNodeHash() == hash);
|
assert(root->getNodeHash() == hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAMap::armDirty()
|
int SHAMap::armDirty()
|
||||||
{ // begin saving dirty nodes
|
{ // begin saving dirty nodes
|
||||||
++mSeq;
|
|
||||||
mDirtyNodes = boost::make_shared< boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> >();
|
mDirtyNodes = boost::make_shared< boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> >();
|
||||||
|
return ++mSeq;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq)
|
int SHAMap::flushDirty(SHADirtyMap& map, int maxNodes, HashedObjectType t, uint32 seq)
|
||||||
{
|
{
|
||||||
int flushed = 0;
|
int flushed = 0;
|
||||||
Serializer s;
|
Serializer s;
|
||||||
|
|
||||||
if (mDirtyNodes)
|
for(SHADirtyMap::iterator it = map.begin(); it != map.end(); it = map.erase(it))
|
||||||
{
|
{
|
||||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>& dirtyNodes = *mDirtyNodes;
|
// tLog(t == hotTRANSACTION_NODE, lsDEBUG) << "TX node write " << it->first;
|
||||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = dirtyNodes.begin();
|
// tLog(t == hotACCOUNT_NODE, lsDEBUG) << "STATE node write " << it->first;
|
||||||
while (it != dirtyNodes.end())
|
s.erase();
|
||||||
{
|
it->second->addRaw(s, snfPREFIX);
|
||||||
// tLog(mType == smtTRANSACTION, lsDEBUG) << "TX node write " << it->first;
|
assert(s.getSHA512Half() == it->second->getNodeHash());
|
||||||
// tLog(mType == smtSTATE, lsDEBUG) << "STATE node write " << it->first;
|
theApp->getHashedObjectStore().store(t, seq, s.peekData(), it->second->getNodeHash());
|
||||||
s.erase();
|
if (flushed++ >= maxNodes)
|
||||||
it->second->addRaw(s, snfPREFIX);
|
return flushed;
|
||||||
theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half());
|
|
||||||
if (flushed++ >= maxNodes)
|
|
||||||
return flushed;
|
|
||||||
it = dirtyNodes.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return flushed;
|
return flushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAMap::disarmDirty()
|
boost::shared_ptr<SHAMap::SHADirtyMap> SHAMap::disarmDirty()
|
||||||
{ // stop saving dirty nodes
|
{ // stop saving dirty nodes
|
||||||
mDirtyNodes = boost::shared_ptr< boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> >();
|
boost::shared_ptr<SHADirtyMap> ret;
|
||||||
|
ret.swap(mDirtyNodes);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& nodeID)
|
SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& nodeID)
|
||||||
|
|||||||
Reference in New Issue
Block a user