diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index 8a7c28dec..b3d3a08d6 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -2009,45 +2009,46 @@ void NetworkOPs::getBookPage(Ledger::pointer lpLedger, const uint160& uTakerPays void NetworkOPs::makeFetchPack(Job&, boost::weak_ptr wPeer, boost::shared_ptr request, Ledger::pointer prevLedger, Ledger::pointer reqLedger) { - Peer::pointer peer = wPeer.lock(); - if (!peer) - return; - - ripple::TMGetObjectByHash reply; - reply.set_query(false); - if (request->has_seq()) - reply.set_seq(request->seq()); - reply.set_ledgerhash(reply.ledgerhash()); - - // WRITEME -#if 0 - std::list< std::pair > > pack1 = getSyncInfo(prevLedger->peekAccountStateMap(), - reqLedger->peekAccountStateMap(), 1024); - - typedef std::pair< uint256, std::vector > uvpair_t; - BOOST_FOREACH(uvpair_t& node, pack1) + try { - ripple::TMIndexedObject& newObj = *reply.add_objects(); - newObj.set_hash(node.first.begin(), 256 / 8); - newObj.set_data(&node.second[0], node.second.size()); - } + Peer::pointer peer = wPeer.lock(); + if (!peer) + return; - if (reqLedger->getAccountHash().isNonZero()) - { - SHAMapIterator it(*reqLedger->peekTransactionMap(), true, true); - for (SHAMapTreeNode* node = it.getNext(); node != NULL; node = it.getNext()) + ripple::TMGetObjectByHash reply; + reply.set_query(false); + if (request->has_seq()) + reply.set_seq(request->seq()); + reply.set_ledgerhash(reply.ledgerhash()); + + std::list pack = + reqLedger->peekAccountStateMap()->getFetchPack(prevLedger->peekAccountStateMap().get(), false, 1024); + BOOST_FOREACH(SHAMap::fetchPackEntry_t& node, pack) { - Serializer s; - node->addRaw(s, snfPREFIX); ripple::TMIndexedObject& newObj = *reply.add_objects(); - newObj.set_hash(node->getNodeHash().begin(), 256 / 8); - newObj.set_data(&s.peekData()[0], s.peekData().size()); + newObj.set_hash(node.first.begin(), 256 / 8); + newObj.set_data(&node.second[0], node.second.size()); } - } - PackedMessage::pointer msg = boost::make_shared(reply, ripple::mtGET_OBJECTS); - peer->sendPacket(msg, false); -#endif + if (reqLedger->getAccountHash().isNonZero() && (pack.size() < 768)) + { + pack = reqLedger->peekTransactionMap()->getFetchPack(NULL, true, 256); + BOOST_FOREACH(SHAMap::fetchPackEntry_t& node, pack) + { + ripple::TMIndexedObject& newObj = *reply.add_objects(); + newObj.set_hash(node.first.begin(), 256 / 8); + newObj.set_data(&node.second[0], node.second.size()); + } + } + + cLog(lsINFO) << "Built fetch pack with " << reply.objects().size() << " nodes"; + PackedMessage::pointer msg = boost::make_shared(reply, ripple::mtGET_OBJECTS); + peer->sendPacket(msg, false); + } + catch (...) + { + cLog(lsWARNING) << "Exception building fetch pach"; + } } // vim:ts=4 diff --git a/src/cpp/ripple/SHAMap.h b/src/cpp/ripple/SHAMap.h index 830eb0b14..147c36021 100644 --- a/src/cpp/ripple/SHAMap.h +++ b/src/cpp/ripple/SHAMap.h @@ -333,7 +333,6 @@ extern bool SMANCombine(SMAddNode& existing, const SMAddNode& additional); class SHAMap : public IS_INSTANCE(SHAMap) { -friend class SHAMapIterator; public: typedef boost::shared_ptr pointer; @@ -375,6 +374,7 @@ protected: SHAMapItem::pointer onlyBelow(SHAMapTreeNode*); void eraseChildren(SHAMapTreeNode::pointer); void dropBelow(SHAMapTreeNode*); + bool hasNode(const SHAMapNode& id, const uint256& hash); bool walkBranch(SHAMapTreeNode* node, SHAMapItem::ref otherMapItem, bool isFirstMap, SHAMapDiff& differences, int& maxCount); @@ -476,11 +476,11 @@ public: bool deepCompare(SHAMap& other); virtual void dump(bool withHashes = false); + typedef std::pair< uint256, std::vector > fetchPackEntry_t; + std::list getFetchPack(SHAMap* prior, bool includeLeaves, int max); + static void sweep() { fullBelowCache.sweep(); } }; -extern std::list< std::pair > > - getSyncInfo(SHAMap::pointer have, SHAMap::pointer want, int max); - #endif // vim:ts=4 diff --git a/src/cpp/ripple/SHAMapSync.cpp b/src/cpp/ripple/SHAMapSync.cpp index 9585af60a..c18b160d9 100644 --- a/src/cpp/ripple/SHAMapSync.cpp +++ b/src/cpp/ripple/SHAMapSync.cpp @@ -469,6 +469,81 @@ bool SHAMap::deepCompare(SHAMap& other) return true; } +bool SHAMap::hasNode(const SHAMapNode& nodeID, const uint256& nodeHash) +{ + SHAMapTreeNode* node = root.get(); + while (node->isInner() && (node->getDepth() <= nodeID.getDepth())) + { + int branch = node->selectBranch(nodeID.getNodeID()); + node = getNodePointer(node->getChildNodeID(branch), node->getChildHash(branch)); + } + return node->getNodeHash() == nodeHash; +} + +std::list SHAMap::getFetchPack(SHAMap* prior, bool includeLeaves, int max) +{ + std::list ret; + + if (root->isLeaf()) + { + if (includeLeaves && + (!prior || !prior->hasNode(*root, root->getNodeHash()))) + { + Serializer s; + root->addRaw(s, snfPREFIX); + ret.push_back(fetchPackEntry_t(root->getNodeHash(), s.peekData())); + } + return ret; + } + if (prior && (root->getNodeHash() == prior->root->getNodeHash())) + return ret; + + std::stack stack; // contains unexplored non-matching inner node entries + stack.push(root.get()); + + while (!stack.empty()) + { + SHAMapTreeNode* node = stack.top(); + stack.pop(); + + // 1) Add this node to the pack + Serializer s; + node->addRaw(s, snfPREFIX); + ret.push_back(fetchPackEntry_t(node->getNodeHash(), s.peekData())); + --max; + + // 2) push non-matching child inner nodes + for (int i = 0; i < 16; ++i) + { + if (!node->isEmptyBranch(i)) + { + const uint256& childHash = node->getChildHash(i); + SHAMapNode childID = node->getChildNodeID(i); + + SHAMapTreeNode *next = getNodePointer(childID, childHash); + if (next->isInner()) + { + if (!prior || !prior->hasNode(*next, childHash)) + stack.push(next); + } + else if (includeLeaves && (!prior || !prior->hasNode(childID, childHash))) + { + Serializer s; + node->addRaw(s, snfPREFIX); + ret.push_back(fetchPackEntry_t(node->getNodeHash(), s.peekData())); + --max; + } + } + } + + if (max <= 0) + break; + } + + cLog(lsINFO) << "Fetch pack has " << ret.size() << " entries"; + return ret; +} + #ifdef DEBUG #define SMS_DEBUG #endif