RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
core/banker/banker.h
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 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator