Path finding fixes:

Track path finding and order book creation time and latency.
Use a ledger snapshot for path finding.
You can't call getCurrentLedger from an unlocked context.
Pathfinding called from the transaction sign function held the master lock.
This commit is contained in:
JoelKatz
2013-02-12 20:39:00 -08:00
parent ef5069a706
commit cb111b6318
8 changed files with 62 additions and 28 deletions

View File

@@ -56,6 +56,8 @@ const char* Job::toString(JobType t)
case jtRPC: return "rpc"; case jtRPC: return "rpc";
case jtACCEPTLEDGER: return "acceptLedger"; case jtACCEPTLEDGER: return "acceptLedger";
case jtTXN_PROC: return "processTransaction"; case jtTXN_PROC: return "processTransaction";
case jtOB_SETUP: return "orderBookSetup";
case jtPATH_FIND: return "pathFind";
default: assert(false); return "unknown"; default: assert(false); return "unknown";
} }
} }

View File

@@ -37,13 +37,15 @@ enum JobType
jtDEATH = 14, // job of death, used internally jtDEATH = 14, // job of death, used internally
// special types not dispatched by the job pool // special types not dispatched by the job pool
jtPEER = 17, jtPEER = 24,
jtDISK = 18, jtDISK = 25,
jtRPC = 19, jtRPC = 26,
jtACCEPTLEDGER = 20, jtACCEPTLEDGER = 27,
jtTXN_PROC = 21, jtTXN_PROC = 28,
jtOB_SETUP = 29,
jtPATH_FIND = 30
}; // CAUTION: If you add new types, add them to JobType.cpp too }; // CAUTION: If you add new types, add them to JobType.cpp too
#define NUM_JOB_TYPES 24 #define NUM_JOB_TYPES 32
class Job class Job
{ {

View File

@@ -1,3 +1,8 @@
#ifndef ORDERBOOK_H
#define ORDERBOOK_H
#include "SerializedLedger.h" #include "SerializedLedger.h"
#include "NetworkOPs.h" #include "NetworkOPs.h"
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
@@ -34,4 +39,6 @@ public:
STAmount& getTakePrice(STAmount& takeAmount); STAmount& getTakePrice(STAmount& takeAmount);
}; };
#endif
// vim:ts=4 // vim:ts=4

View File

@@ -1,5 +1,6 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include "Application.h"
#include "OrderBookDB.h" #include "OrderBookDB.h"
#include "Log.h" #include "Log.h"
@@ -11,8 +12,10 @@ OrderBookDB::OrderBookDB()
} }
// TODO: this would be way faster if we could just look under the order dirs // TODO: this would be way faster if we could just look under the order dirs
void OrderBookDB::setup(Ledger::pointer ledger) void OrderBookDB::setup(Ledger::ref ledger)
{ {
LoadEvent::autoptr ev = theApp->getJobQueue().getLoadEventAP(jtOB_SETUP);
mXRPOrders.clear(); mXRPOrders.clear();
mIssuerMap.clear(); mIssuerMap.clear();
mKnownMap.clear(); mKnownMap.clear();

View File

@@ -1,3 +1,7 @@
#ifndef ORDERBOOK_DB_H
#define ORDERBOOK_DB_H
#include "Ledger.h" #include "Ledger.h"
#include "OrderBook.h" #include "OrderBook.h"
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
@@ -33,7 +37,7 @@ class OrderBookDB
public: public:
OrderBookDB(); OrderBookDB();
void setup(Ledger::pointer ledger); void setup(Ledger::ref ledger);
// return list of all orderbooks that want XRP // return list of all orderbooks that want XRP
std::vector<OrderBook::pointer>& getXRPInBooks(){ return mXRPOrders; } std::vector<OrderBook::pointer>& getXRPInBooks(){ return mXRPOrders; }
@@ -56,4 +60,6 @@ public:
}; };
#endif
// vim:ts=4 // vim:ts=4

View File

@@ -127,17 +127,21 @@ bool Pathfinder::bDefaultPath(const STPath& spPath)
return false; return false;
} }
Pathfinder::Pathfinder(const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID, const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount) Pathfinder::Pathfinder(Ledger::ref ledger,
: mSrcAccountID(uSrcAccountID.getAccountID()), const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID,
const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount)
: mLedger(ledger),
mSrcAccountID(uSrcAccountID.getAccountID()),
mDstAccountID(uDstAccountID.getAccountID()), mDstAccountID(uDstAccountID.getAccountID()),
mDstAmount(saDstAmount), mDstAmount(saDstAmount),
mSrcCurrencyID(uSrcCurrencyID), mSrcCurrencyID(uSrcCurrencyID),
mSrcIssuerID(uSrcIssuerID) mSrcIssuerID(uSrcIssuerID)
{ {
mLedger = theApp->getLedgerMaster().getCurrentLedger();
mSrcAmount = STAmount(uSrcCurrencyID, uSrcIssuerID, 1, 0); // -1/uSrcIssuerID/uSrcIssuerID mSrcAmount = STAmount(uSrcCurrencyID, uSrcIssuerID, 1, 0); // -1/uSrcIssuerID/uSrcIssuerID
theApp->getOrderBookDB().setup( theApp->getLedgerMaster().getCurrentLedger()); // TODO: have the orderbook update itself rather than rebuild it from scratch each time theApp->getOrderBookDB().setup(mLedger); // TODO: have the orderbook update itself rather than rebuild it from scratch each time
mLoadMonitor = theApp->getJobQueue().getLoadEvent(jtPATH_FIND);
// Construct the default path for later comparison. // Construct the default path for later comparison.

View File

@@ -44,6 +44,7 @@ class Pathfinder
//OrderBookDB mOrderBook; //OrderBookDB mOrderBook;
Ledger::pointer mLedger; Ledger::pointer mLedger;
PathState::pointer mPsDefault; PathState::pointer mPsDefault;
LoadEvent::pointer mLoadMonitor;
// std::list<PathOption::pointer> mBuildingPaths; // std::list<PathOption::pointer> mBuildingPaths;
// std::list<PathOption::pointer> mCompletePaths; // std::list<PathOption::pointer> mCompletePaths;
@@ -56,7 +57,9 @@ class Pathfinder
// void addPathOption(PathOption::pointer pathOption); // void addPathOption(PathOption::pointer pathOption);
public: public:
Pathfinder(const RippleAddress& srcAccountID, const RippleAddress& dstAccountID, const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount); Pathfinder(Ledger::ref ledger,
const RippleAddress& srcAccountID, const RippleAddress& dstAccountID,
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount);
bool findPaths(const unsigned int iMaxSteps, const unsigned int iMaxPaths, STPathSet& spsDst); bool findPaths(const unsigned int iMaxSteps, const unsigned int iMaxPaths, STPathSet& spsDst);

View File

@@ -177,22 +177,28 @@ Json::Value RPCHandler::transactionSign(Json::Value jvRequest, bool bSubmit)
return rpcError(rpcINVALID_PARAMS); return rpcError(rpcINVALID_PARAMS);
} }
Pathfinder pf(raSrcAddressID, dstAccountID, saSendMax.getCurrency(), saSendMax.getIssuer(), saSend); Ledger::pointer lSnapshot = boost::make_shared<Ledger>(
boost::ref(*theApp->getOPs().getCurrentLedger()), false);
if (!pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsPaths))
{ {
cLog(lsDEBUG) << "transactionSign: build_path: No paths found."; ScopedUnlock su(theApp->getMasterLock());
Pathfinder pf(lSnapshot, raSrcAddressID, dstAccountID,
saSendMax.getCurrency(), saSendMax.getIssuer(), saSend);
return rpcError(rpcNO_PATH); if (!pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsPaths))
} {
else cLog(lsDEBUG) << "transactionSign: build_path: No paths found.";
{
cLog(lsDEBUG) << "transactionSign: build_path: " << spsPaths.getJson(0);
}
if (!spsPaths.isEmpty()) return rpcError(rpcNO_PATH);
{ }
txJSON["Paths"]=spsPaths.getJson(0); else
{
cLog(lsDEBUG) << "transactionSign: build_path: " << spsPaths.getJson(0);
}
if (!spsPaths.isEmpty())
{
txJSON["Paths"]=spsPaths.getJson(0);
}
} }
} }
} }
@@ -1115,7 +1121,8 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest)
} }
} }
LedgerEntrySet lesSnapshot(lpCurrent); Ledger::pointer lSnapShot = boost::make_shared<Ledger>(boost::ref(*lpCurrent), false);
LedgerEntrySet lesSnapshot(lSnapShot);
ScopedUnlock su(theApp->getMasterLock()); // As long as we have a locked copy of the ledger, we can unlock. ScopedUnlock su(theApp->getMasterLock()); // As long as we have a locked copy of the ledger, we can unlock.
@@ -1148,7 +1155,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest)
} }
STPathSet spsComputed; STPathSet spsComputed;
Pathfinder pf(raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount); Pathfinder pf(lSnapShot, raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount);
if (!pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsComputed)) if (!pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsComputed))
{ {