Improve performance of some RPC ledger commands using visitors.

Adds SHAMap::visitLeaves and Ledger::visitStateItems
This commit is contained in:
JoelKatz
2013-10-04 11:50:22 -07:00
parent 86f662aa4a
commit 37bcf7899e
4 changed files with 82 additions and 17 deletions

View File

@@ -990,6 +990,16 @@ void Ledger::addJson (Json::Value& ret, int options)
ret["ledger"] = getJson (options);
}
static void stateItemTagAppender(Json::Value& value, SHAMapItem::ref smi)
{
value.append (smi->getTag ().GetHex ());
}
static void stateItemFullAppender(Json::Value& value, SLE::ref sle)
{
value.append (sle->getJson (0));
}
Json::Value Ledger::getJson (int options)
{
Json::Value ledger (Json::objectValue);
@@ -1077,23 +1087,11 @@ Json::Value Ledger::getJson (int options)
if (mAccountStateMap && (bFull || isSetBit (options, LEDGER_JSON_DUMP_STATE)))
{
Json::Value state (Json::arrayValue);
SHAMap::ScopedLockType l (mAccountStateMap->peekMutex (), __FILE__, __LINE__);
for (SHAMapItem::pointer item = mAccountStateMap->peekFirstItem (); !!item;
item = mAccountStateMap->peekNextItem (item->getTag ()))
{
if (bFull || isSetBit (options, LEDGER_JSON_EXPAND))
{
SerializerIterator sit (item->peekSerializer ());
SerializedLedgerEntry sle (sit, item->getTag ());
state.append (sle.getJson (0));
}
else
state.append (item->getTag ().GetHex ());
}
ledger["accountState"] = state;
Json::Value& state = (ledger["accountState"] = Json::arrayValue);
if (bFull || isSetBit (options, LEDGER_JSON_EXPAND))
visitStateItems(BIND_TYPE(stateItemFullAppender, beast::ref(state), P_1));
else
mAccountStateMap->visitLeaves(BIND_TYPE(stateItemTagAppender, beast::ref(state), P_1));
}
return ledger;
@@ -1236,6 +1234,17 @@ void Ledger::visitAccountItems (const uint160& accountID, FUNCTION_TYPE<void (SL
}
static void visitHelper (FUNCTION_TYPE<void (SLE::ref)>& function, SHAMapItem::ref item)
{
function (boost::make_shared<SLE> (item->peekSerializer (), item->getTag ()));
}
void Ledger::visitStateItems (FUNCTION_TYPE<void (SLE::ref)> function)
{
if (mAccountStateMap)
mAccountStateMap->visitLeaves(BIND_TYPE(&visitHelper, beast::ref(function), P_1));
}
/*
// VFALCO: A proof of concept for making an iterator instead of a visitor
class AccountItemIterator

View File

@@ -260,6 +260,7 @@ public:
SLE::pointer getAccountRoot (const RippleAddress & naAccountID);
void updateSkipList ();
void visitAccountItems (const uint160 & acctID, FUNCTION_TYPE<void (SLE::ref)>);
void visitStateItems (FUNCTION_TYPE<void (SLE::ref)>);
// database functions (low-level)
static Ledger::pointer loadByIndex (uint32 ledgerIndex);

View File

@@ -109,6 +109,7 @@ public:
SHAMapItem::pointer peekNextItem (uint256 const& );
SHAMapItem::pointer peekNextItem (uint256 const& , SHAMapTreeNode::TNType & type);
SHAMapItem::pointer peekPrevItem (uint256 const& );
void visitLeaves(FUNCTION_TYPE<void (SHAMapItem::ref)>);
// comparison/sync functions
void getMissingNodes (std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& hashes, int max,

View File

@@ -24,6 +24,60 @@ static const uint256 uZero;
KeyCache <uint256, UptimeTimerAdapter> SHAMap::fullBelowCache ("fullBelowCache", 524288, 240);
void SHAMap::visitLeaves (FUNCTION_TYPE<void (SHAMapItem::ref item)> function)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
assert (root->isValid ());
if (!root || root->isEmpty ())
return;
if (!root->isInner ())
{
function (root->peekItem ());
return;
}
typedef std::pair<int, SHAMapTreeNode*> posPair;
std::stack<posPair> stack;
SHAMapTreeNode* node = root.get ();
int pos = 0;
while (1)
{
while (pos < 16)
{
if (node->isEmptyBranch (pos))
++pos;
else
{
SHAMapTreeNode* child = getNodePointerNT (node->getChildNodeID (pos), node->getChildHash (pos));
if (child->isLeaf ())
{
function (child->peekItem ());
++pos;
}
else
{
if (pos != 15)
stack.push (posPair (pos + 1, node)); // save next position
node = child;
pos = 0;
}
}
}
if (stack.empty ())
break;
pos = stack.top ().first;
node = stack.top ().second;
stack.pop ();
}
}
void SHAMap::getMissingNodes (std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& hashes, int max,
SHAMapSyncFilter* filter)
{