![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* banker.h -*- C++ -*- 00002 Sunil Rottoo, May 2012 00003 Copyright (c) 2012 Datacratic. All rights reserved. 00004 00005 Class to deal with accounting in the router. 00006 */ 00007 00008 #ifndef __rtb_router__banker_h__ 00009 #define __rtb_router__banker_h__ 00010 00011 #include <string> 00012 #include <set> 00013 #include <unordered_map> 00014 #include "soa/jsoncpp/json.h" 00015 #include "soa/types/date.h" 00016 #include "jml/arch/spinlock.h" 00017 #include "jml/arch/exception.h" 00018 #include "soa/service/service_base.h" 00019 #include <future> 00020 #include "rtbkit/common/currency.h" 00021 #include "jml/arch/futex.h" 00022 #include "jml/arch/backtrace.h" 00023 #include "account.h" 00024 00025 namespace Datacratic { 00026 namespace JS { 00027 class NullBankerJS; 00028 } // namespace JS 00029 } // namespace Datacratic 00030 00031 namespace RTBKIT { 00032 00033 template<typename T> 00034 struct BankerSyncResult: boost::noncopyable { 00035 BankerSyncResult() 00036 { 00037 done = 0; 00038 exc = nullptr; 00039 } 00040 00041 int done; 00042 std::exception_ptr exc; 00043 T result; 00044 00045 operator std::function<void (std::exception_ptr, T && result)> () 00046 { 00047 return [=] (std::exception_ptr exc, T && result) 00048 { 00049 using namespace std; 00050 if (this->done) { 00051 cerr << "already done budget result" << endl; 00052 ML::backtrace(); 00053 abort(); 00054 } 00055 //cerr << "done result " << this << endl; 00056 this->exc = exc; 00057 this->done = 1; 00058 this->result = std::move(result); 00059 ML::futex_wake(this->done); 00060 }; 00061 } 00062 00063 T && get() 00064 { 00065 while (!done) 00066 ML::futex_wait(done, 0); 00067 if (exc) 00068 std::rethrow_exception(exc); 00069 return std::move(result); 00070 } 00071 }; 00072 00073 template<> 00074 struct BankerSyncResult<void> : boost::noncopyable { 00075 BankerSyncResult() 00076 { 00077 done = 0; 00078 exc = nullptr; 00079 } 00080 00081 int done; 00082 std::exception_ptr exc; 00083 00084 operator std::function<void (std::exception_ptr)> () 00085 { 00086 return [=] (std::exception_ptr exc) 00087 { 00088 using namespace std; 00089 if (this->done) { 00090 cerr << "already done budget result" << endl; 00091 ML::backtrace(); 00092 abort(); 00093 } 00094 //cerr << "done result " << this << endl; 00095 this->exc = exc; 00096 this->done = 1; 00097 ML::futex_wake(this->done); 00098 }; 00099 } 00100 00101 void get() 00102 { 00103 while (!done) 00104 ML::futex_wait(done, 0); 00105 if (exc) 00106 std::rethrow_exception(exc); 00107 } 00108 }; 00109 00110 00111 00112 00113 /*****************************************************************************/ 00114 /* BUDGET CONTROLLER */ 00115 /*****************************************************************************/ 00116 00117 struct BudgetController { 00118 00119 BudgetController(); 00120 virtual ~BudgetController(); 00121 00122 00123 /*************************************************************************/ 00124 /* BUDGET INTERFACE */ 00125 /*************************************************************************/ 00126 00127 typedef std::function<void (std::exception_ptr)> OnBudgetResult; 00128 00134 virtual void addAccount(const AccountKey & account, 00135 const OnBudgetResult & onResult); 00136 00137 virtual void addAccountSync(const AccountKey & account); 00138 00150 virtual void topupTransfer(const AccountKey & account, 00151 CurrencyPool amount, 00152 const OnBudgetResult & onResult); 00153 00154 virtual void topupTransferSync(const AccountKey & account, 00155 CurrencyPool amount); 00156 00170 virtual void setBudget(const std::string & topLevelAccount, 00171 CurrencyPool amount, 00172 const OnBudgetResult & onResult); 00173 00174 virtual void setBudgetSync(const std::string & topLevelAccount, 00175 CurrencyPool amount); 00176 00191 virtual void addBudget(const std::string & topLevelAccount, 00192 CurrencyPool amount, 00193 const OnBudgetResult & onResult); 00194 00195 virtual void addBudgetSync(const std::string & topLevelAccount, 00196 CurrencyPool amount); 00197 00198 CurrencyPool budgetLimits; 00199 }; 00200 00201 00202 /*****************************************************************************/ 00203 /* ACCOUNTANT */ 00204 /*****************************************************************************/ 00205 00210 struct Accountant { 00211 virtual void sync() {} 00212 00213 virtual std::vector<AccountKey> 00214 getAccountListSync(const AccountKey & prefix, 00215 int depth); 00216 00217 virtual void 00218 getAccountList(const AccountKey & prefix, 00219 int depth, 00220 std::function<void (std::exception_ptr, 00221 std::vector<AccountKey> &&)> onResult); 00222 00223 virtual AccountSummary 00224 getAccountSummarySync(const AccountKey & account, 00225 int depth); 00226 00227 virtual void 00228 getAccountSummary(const AccountKey & account, 00229 int depth, 00230 std::function<void (std::exception_ptr, 00231 AccountSummary &&)> onResult); 00232 00233 virtual Account 00234 getAccountSync(const AccountKey & account); 00235 00236 virtual void getAccount(const AccountKey & account, 00237 std::function<void (std::exception_ptr, 00238 Account &&)> onResult); 00239 }; 00240 00241 /*****************************************************************************/ 00242 /* BANKER */ 00243 /*****************************************************************************/ 00244 00247 class Banker { 00248 public: 00249 Banker() 00250 { 00251 } 00252 00253 virtual ~Banker(); 00254 00255 00256 typedef std::function<void (std::exception_ptr)> OnBudgetResult; 00257 00258 00259 /*************************************************************************/ 00260 /* REGISTRATION INTERFACE */ 00261 /*************************************************************************/ 00262 00263 virtual ShadowAccount 00264 addSpendAccountSync(const AccountKey & account, 00265 CurrencyPool accountFloat = CurrencyPool()); 00266 00267 virtual void 00268 addSpendAccount(const AccountKey & account, 00269 CurrencyPool accountFloat, 00270 std::function<void (std::exception_ptr, ShadowAccount&&)> onDone); 00271 00272 00273 /*************************************************************************/ 00274 /* SPEND INTERFACE */ 00275 /*************************************************************************/ 00276 00277 /* 00278 * authorize the spending for a bid for the specified amount. If there are 00279 * not enough funds we return false. 00280 * Note that the amount is subtracted from the pool of available funds. 00281 * 00282 * @param campaign The campaign that this applies to 00283 * @param strategy The strategy that is bidding on this item 00284 * @param item Identifier for the bid request 00285 * @param amount the amount we want to bid 00286 * 00287 * Note that there is no asynchronous interface. Authorization must be 00288 * extremely fast and synchronous. 00289 */ 00290 virtual bool authorizeBid(const AccountKey & account, 00291 const std::string & item, 00292 Amount amount) = 0; 00293 00294 /* 00295 * Cancel the bid that was previously authorized. If we fail to find the bid 00296 * we return false.Otherwise we return the bid amount to the available pool 00297 * @param campaign The campaign that this applies to 00298 * @param strategy The strategy that is bidding on this item 00299 * @param item Identifier for the bid request 00300 * 00301 */ 00302 virtual void cancelBid(const AccountKey & account, 00303 const std::string & item) 00304 { 00305 return commitBid(account, item, Amount(), LineItems()); 00306 } 00307 00308 virtual void winBid(const AccountKey & account, 00309 const std::string & item, 00310 Amount amountPaid, 00311 const LineItems & lineItems = LineItems()) 00312 { 00313 return commitBid(account, item, amountPaid, lineItems); 00314 } 00315 00316 virtual void attachBid(const AccountKey & account, 00317 const std::string & item, 00318 Amount amountAuthorized) = 0; 00319 00320 virtual Amount detachBid(const AccountKey & account, 00321 const std::string & item) = 0; 00322 00326 virtual void commitBid(const AccountKey & account, 00327 const std::string & item, 00328 Amount amountPaid, 00329 const LineItems & lineItems) = 0; 00330 00331 /* 00332 * This is for the case when bids come in late. In this case because of the 00333 * fact that all bids are cancelled if they time out (tryCancelBid) we will 00334 * unconditionally reduce the amount available for the strategy. 00335 */ 00336 virtual void forceWinBid(const AccountKey & account, 00337 Amount amountPaid, 00338 const LineItems & lineItems) = 0; 00339 00340 /*************************************************************************/ 00341 /* INFORMATION */ 00342 /*************************************************************************/ 00343 00345 virtual void sync() {} 00346 00347 00348 /*************************************************************************/ 00349 /* LOGGING */ 00350 /*************************************************************************/ 00351 virtual void logBidEvents(const Datacratic::EventRecorder & eventRecorder) 00352 { 00353 } 00354 00355 protected: 00356 // For the supplied campaign make sure that the numbers match 00357 virtual void sanityCheck(const std::string &campaign) const 00358 { 00359 } 00360 }; 00361 00362 enum class BankerError { 00363 INVALID_CAMPAIGN, 00364 CAMPAIGN_NOT_FOUND, 00365 STRATEGY_NOT_FOUND, 00366 INVALID_STRATEGY, 00367 INSUFFICIENT_FUNDS, 00368 LOWER_THAN_TRANSFERRED, 00369 EXCEEDS_MAX, 00370 TOO_LOW, 00371 ACCOUNTING_MISMATCH, 00372 DATABASE_ERROR 00373 }; 00374 00375 /*****************************************************************************/ 00376 /* BANKER EXCEPTION */ 00377 /*****************************************************************************/ 00378 00379 struct BankerException: public ML::Exception { 00380 00381 // List of error conditions. Please update the errorToString method if adding new elements 00382 BankerException(const std::string &msg, const BankerError &error); 00383 00384 static std::string errorToString(const BankerError &error); 00385 00386 BankerError error_; 00387 }; 00388 00389 00390 } // namespace RTBKIT 00391 00392 #endif /* __rtb_router__banker_h__ */ 00393