diff --git a/src/ripple_app/ledger/Ledger.cpp b/src/ripple_app/ledger/Ledger.cpp index c17ca7bfc..62076fe83 100644 --- a/src/ripple_app/ledger/Ledger.cpp +++ b/src/ripple_app/ledger/Ledger.cpp @@ -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& function, SHAMapItem::ref item) +{ + function (boost::make_shared (item->peekSerializer (), item->getTag ())); +} + +void Ledger::visitStateItems (FUNCTION_TYPE 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 diff --git a/src/ripple_app/ledger/Ledger.h b/src/ripple_app/ledger/Ledger.h index e96adb1b4..9e1751314 100644 --- a/src/ripple_app/ledger/Ledger.h +++ b/src/ripple_app/ledger/Ledger.h @@ -260,6 +260,7 @@ public: SLE::pointer getAccountRoot (const RippleAddress & naAccountID); void updateSkipList (); void visitAccountItems (const uint160 & acctID, FUNCTION_TYPE); + void visitStateItems (FUNCTION_TYPE); // database functions (low-level) static Ledger::pointer loadByIndex (uint32 ledgerIndex); diff --git a/src/ripple_app/shamap/SHAMap.h b/src/ripple_app/shamap/SHAMap.h index 04625fa22..14c11f19d 100644 --- a/src/ripple_app/shamap/SHAMap.h +++ b/src/ripple_app/shamap/SHAMap.h @@ -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); // comparison/sync functions void getMissingNodes (std::vector& nodeIDs, std::vector& hashes, int max, diff --git a/src/ripple_app/shamap/SHAMapSync.cpp b/src/ripple_app/shamap/SHAMapSync.cpp index c67f4e7ad..1c16e31e5 100644 --- a/src/ripple_app/shamap/SHAMapSync.cpp +++ b/src/ripple_app/shamap/SHAMapSync.cpp @@ -24,6 +24,60 @@ static const uint256 uZero; KeyCache SHAMap::fullBelowCache ("fullBelowCache", 524288, 240); +void SHAMap::visitLeaves (FUNCTION_TYPE function) +{ + ScopedLockType sl (mLock, __FILE__, __LINE__); + + assert (root->isValid ()); + + if (!root || root->isEmpty ()) + return; + + if (!root->isInner ()) + { + function (root->peekItem ()); + return; + } + + typedef std::pair posPair; + + std::stack 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& nodeIDs, std::vector& hashes, int max, SHAMapSyncFilter* filter) {