Continue implementation these classes.

This commit is contained in:
JoelKatz
2011-11-17 12:22:25 -08:00
parent 7137f759a9
commit e7bae43261
3 changed files with 481 additions and 143 deletions

View File

@@ -1,139 +1,250 @@
#include "Serializer.h"
#include "BitcoinUtil.h"
#include "SHAMap.h"
#include <boost/foreach.hpp>
bool SHAMapNode::operator<(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return true;
if(s.mDepth>mDepth) return false;
return mNodeID<s.mNodeID;
}
bool SHAMapNode::operator>(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return false;
if(s.mDepth>mDepth) return true;
return mNodeID>s.mNodeID;
}
bool SHAMapNode::operator<=(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return true;
if(s.mDepth>mDepth) return false;
return mNodeID<=s.mNodeID;
}
bool SHAMapNode::operator>=(const SHAMapNode &s) const
{
if(s.mDepth<mDepth) return false;
if(s.mDepth>mDepth) return true;
return mNodeID>=s.mNodeID;
}
bool SHAMapNode::operator==(const SHAMapNode &s) const
{
return (s.mDepth==mDepth) && (s.mNodeID==mNodeID);
}
bool SHAMapNode::operator!=(const SHAMapNode &s) const
{
return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID);
}
void SHAMapNode::ClassInit()
{
int i;
char HexBuf[65];
for(i=0; i<64; i++) HexBuf[i]='0';
HexBuf[64]=0;
for(i=0; i<leafDepth; i++)
{
smMasks[i].SetHex(HexBuf);
HexBuf[2*i]='1';
HexBuf[2*i+1]='F';
}
}
SHAMapNode::SHAMapNode(int depth, const uint256 &hash)
{
assert(depth>=0 && depth<leafDepth);
mDepth=depth;
mNodeID=getNodeID(depth, hash);
}
SHAMapNode SHAMapNode::getChildNodeID(int m)
{
assert(!isLeaf());
uint256 branch=m;
branch>>=(mDepth*8);
return SHAMapNode(mDepth+1, mNodeID | branch);
}
int SHAMapNode::selectBranch(const uint256 &hash)
{
if(isLeaf()) // no nodes under this node
return -1;
if((hash&smMasks[mDepth])!=mNodeID)
return -1; // does not go under this node
uint256 selector=hash&smMasks[mDepth+1];
int branch=*(selector.begin()+mDepth);
assert(branch>=0 && branch<32);
return branch;
}
SHAMapLeafNode::SHAMapLeafNode(const SHAMapNode& nodeID) : SHAMapNode(nodeID), mHash(0)
SHAMap::SHAMap(int leafDataSize) : mLeafDataSize(leafDataSize)
{
;
}
bool SHAMapLeafNode::hasItem(const uint256& item) const
{
BOOST_FOREACH(const SHAMapItem& nodeItem, mItems)
if(nodeItem==item) return true;
return false;
void SHAMap::dirtyUp(const uint256& id, const std::vector<SHAMapInnerNode::pointer>& path)
{ // walk the tree up from through the inner nodes to the root
// update linking hashes and add nodes to dirty list
std::vector<SHAMapInnerNode::pointer>::const_reverse_iterator it;
it = path.rbegin();
if(it == path.rend()) return;
mDirtyInnerNodes[**it]=*it;
uint256 hVal=(*it)->getNodeHash();
if(hVal==0)
mInnerNodeByID.erase(**it);
for(++it; it<path.rend(); ++it)
{
if(!(*it)->setChildHash((*it)->selectBranch(id), hVal))
return;
mDirtyInnerNodes[**it]=*it;
hVal = (*it)->getNodeHash();
if(hVal == 0) mInnerNodeByID.erase(**it);
}
assert(**it == *root);
}
bool SHAMapLeafNode::addUpdateItem(const SHAMapItem& item)
{ // The node will almost never have more than one item in it
std::list<SHAMapItem>::iterator it;
for(it=mItems.begin(); it!=mItems.end(); it++)
{
if(*it==item)
{
if(it->peekData()==item.peekData())
return false; // no change
it->updateData(item.peekData());
updateHash();
return true;
}
if(*it>item) break;
}
mItems.insert(it, item);
updateHash();
return true;
}
bool SHAMapLeafNode::delItem(const uint256& tag)
SHAMapLeafNode::pointer SHAMap::checkCacheLeaf(const SHAMapNode& iNode)
{
std::list<SHAMapItem>::iterator it;
for(it=mItems.begin(); it!=mItems.end(); it++)
assert(iNode.isLeaf());
return mLeafByID[iNode];
}
SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create,
std::vector<SHAMapInnerNode::pointer>& path)
{ // walk down to the leaf that would contain this ID
// is leaf node in cache
SHAMapLeafNode::pointer ln=checkCacheLeaf(SHAMapNode(SHAMapNode::leafDepth, id));
if(ln != SHAMapLeafNode::pointer()) return ln;
// walk tree to leaf
SHAMapInnerNode::pointer inNode=root;
path.push_back(inNode);
for(int i=1; i<SHAMapNode::leafDepth; i++)
{
if(*it==tag)
int branch=inNode->selectBranch(id);
if(branch<0)
{ // somehow we got on the wrong branch
assert(false);
return SHAMapLeafNode::pointer();
}
if(inNode->isEmptyBranch(branch))
{ // no nodes below this one
if(!create) return SHAMapLeafNode::pointer();
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) return SHAMapLeafNode::pointer(); // we don't have the node
path.push_back(inNode);
}
else // child is leaf node
{
mItems.erase(it);
updateHash();
return true;
ln=getLeaf(inNode->getChildNodeID(branch), inNode->getChildHash(branch));
if(ln==NULL)
{
if(!create) return SHAMapLeafNode::pointer();
return createLeaf(*inNode, id);
}
}
}
return false;
return ln;
}
void SHAMapLeafNode::updateHash(void)
SHAMapLeafNode::pointer SHAMap::getLeaf(const SHAMapNode &id, const uint256& hash)
{ // retrieve a leaf whose node hash is known
SHAMapLeafNode::pointer leaf=mLeafByID[id];
if(leaf != SHAMapLeafNode::pointer()) return leaf;
std::vector<unsigned char> rawNode;
if(!fetchNode(hash, id, rawNode)) return leaf;
leaf=SHAMapLeafNode::pointer(new SHAMapLeafNode(id));
// construct leaf WRITEME
return leaf;
}
SHAMapInnerNode::pointer SHAMap::getInner(const SHAMapNode &id, const uint256& hash)
{ // retrieve an inner node whose node hash is known
SHAMapInnerNode::pointer node=mInnerNodeByID[id];
if(node != SHAMapInnerNode::pointer()) return node;
std::vector<unsigned char> rawNode;
if(!fetchNode(hash, id, rawNode)) return node;
node=SHAMapInnerNode::pointer(new SHAMapInnerNode(id, rawNode));
if(node->getNodeHash()!=hash)
{
badNode(hash, id);
return SHAMapInnerNode::pointer();
}
mInnerNodeByID[id]=node;
return node;
}
SHAMapItem::pointer SHAMap::firstItem()
{
ScopedLock sl(mLock);
return firstBelow(root);
}
SHAMapItem::pointer SHAMap::lastItem()
{
ScopedLock sl(mLock);
return lastBelow(root);
}
SHAMapItem::pointer SHAMap::firstBelow(SHAMapInnerNode::pointer Node)
{
const uint256 zero;
int i;
while(Node->isChildLeaf())
{
for(i=0; i<32; i++)
{
uint256 cHash(Node->getChildHash(i));
if(cHash!=zero)
{
Node=getInner(Node->getChildNodeID(i), cHash);
if(Node==SHAMapInnerNode::pointer()) return SHAMapItem::pointer();
break;
}
}
if(i==32) return SHAMapItem::pointer();
}
for(int i=0; i<32; i++)
{
uint256 cHash=Node->getChildHash(i);
if(cHash!=zero)
{
SHAMapLeafNode::pointer mLeaf=getLeaf(Node->getChildNodeID(i), cHash);
if(mLeaf==SHAMapLeafNode::pointer()) return SHAMapItem::pointer();
return mLeaf->firstItem();
}
}
return SHAMapItem::pointer();
}
SHAMapItem::pointer SHAMap::lastBelow(SHAMapInnerNode::pointer Node)
{
ScopedLock sl(mLock);
const uint256 zero;
int i;
while(Node->isChildLeaf())
{
for(i=31; i>=0; i--)
{
uint256 cHash(Node->getChildHash(i));
if(cHash!=0)
{
Node=getInner(Node->getChildNodeID(i), cHash);
if(Node==SHAMapInnerNode::pointer()) return SHAMapItem::pointer();
break;
}
}
if(i<0) return SHAMapItem::pointer();
}
for(int i=31; i>=0; i--)
{
uint256 cHash=Node->getChildHash(i);
if(cHash!=zero)
{
SHAMapLeafNode::pointer mLeaf=getLeaf(Node->getChildNodeID(i), cHash);
if(mLeaf==SHAMapLeafNode::pointer()) return SHAMapItem::pointer();
return mLeaf->lastItem();
}
}
}
SHAMapItem::pointer SHAMap::nextItem(const SHAMapItem &)
{
// WRITEME
}
SHAMapItem::pointer SHAMap::prevItem(const SHAMapItem &)
{
// WRITEME
}
bool SHAMap::hasItem(const uint256& id)
{ // does the tree have an item with this ID
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path);
if(leaf == SHAMapLeafNode::pointer()) return false;
SHAMapItem::pointer item=leaf->findItem(id);
return item == SHAMapItem::pointer();
}
bool SHAMap::delItem(const uint256& id)
{ // delete the item with this ID
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path);
if(leaf == SHAMapLeafNode::pointer()) return false;
if(!leaf->delItem(id)) return false;
dirtyUp(id, path);
}
bool SHAMap::addItem(const SHAMapItem& item)
{ // add the specified item
ScopedLock sl(mLock);
std::vector<SHAMapInnerNode::pointer> path;
SHAMapLeafNode::pointer leaf=walkToLeaf(item.getTag(), true, path);
if(leaf == SHAMapLeafNode::pointer()) return false;
if(!leaf->addUpdateItem(item)) return false;
dirtyUp(item.getTag(), path);
}
void TestSHAMap()
{
uint256 h1, h2, h3, h4, h5;
h1.SetHex("436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe");
h2.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h3.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca8");
h4.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
h5.SetHex("092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
SHAMap sMap(32);
SHAMapItem i1(h1), i2(h2), i3(h3), i4(h4), i5(h5);
sMap.dump();
}