RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
core/banker/migration/redis_old_types.cc
00001 #include <iostream>
00002 #include <string>
00003 #include <unordered_map>
00004 #include <vector>
00005 
00006 #include "soa/service/redis.h"
00007 
00008 #include "redis_utils.h"
00009 
00010 #include "redis_old_types.h"
00011 
00012 
00013 namespace {
00014 
00015 bool IsMoreOrLess(long long int value, long long int acceptedDelta)
00016 {
00017     int absolute(acceptedDelta >= 0 ? acceptedDelta : -acceptedDelta);
00018 
00019     return (value >= 0
00020             ? (value <= absolute)
00021             : (-value <= absolute));
00022 }
00023 
00024 }
00025 
00026 
00027 namespace RTBKIT {
00028 
00029 using namespace std;
00030 using namespace RTBKIT;
00031 using namespace Redis;
00032 
00033 
00034 const string CampaignsPrefix = "campaigns:";
00035 
00036 
00037 /* CAMPAIGN */
00038 Campaign::
00039 Campaign(const string & key,
00040          long long available, long long transferred)
00041     : key_(key),
00042       available_(available), transferred_(transferred)
00043 {
00044 }
00045 
00046 /* validate campaign numbers with strategies */
00047 bool
00048 Campaign::
00049 validateAll(int acceptedDelta)
00050     const
00051 {
00052     long long int transferred(0);
00053     bool allValid(true);
00054 
00055     for (const Strategy & strategy: strategies) {
00056         transferred += strategy.transferred_;
00057         allValid &= strategy.valid_;
00058     }
00059 
00060     string campaignKey(CampaignsPrefix + key_);
00061     if (!allValid) {
00062         cerr << "! campaign '" << campaignKey
00063              << "' contains invalid strategies"
00064              << endl;
00065         return false;
00066     }
00067  
00068     if (!IsMoreOrLess(transferred - transferred_,
00069                       (acceptedDelta * strategies.size()))) {
00070         cerr << "! campaign '" << campaignKey
00071              << "' has invalid 'transferred' value:"
00072              << endl
00073              << "    (computed) " << transferred
00074              << " != (stored) " << transferred_
00075              << endl;
00076         return false;
00077     }
00078 
00079     cerr << "- campaign '" << campaignKey
00080          << "' is valid and ready for conversion"
00081          << endl;
00082 
00083     return true;
00084 }
00085 
00086 void
00087 Campaign::
00088 load(AsyncConnection & redis)
00089 {
00090     string redisKey(CampaignsPrefix + key_);
00091     Command hmget = HMGET(redisKey);
00092     hmget.addArg("available");
00093     hmget.addArg("transferred");
00094 
00095     Result result = redis.exec(hmget);
00096     if (!result.ok()) {
00097         cerr << "! HMGET " + redisKey
00098              << ": error fetching result" << endl;
00099         return;
00100     }
00101     const Reply & reply = result.reply();
00102     if (reply.type() != ARRAY) {
00103         cerr << "! HMGET " + redisKey
00104              << ": unexpected reply type" << endl;
00105         return;
00106     }
00107     if (!GetRedisReplyAsInt(reply[0], available_)) {
00108         cerr << "! HMGET " + redisKey
00109              << ": value for 'available' cannot be converted to int"
00110              << endl;
00111         return;
00112     }
00113     if (!GetRedisReplyAsInt(reply[1], transferred_)) {
00114         cerr << "! HMGET " + redisKey
00115              << ": value for 'transferred' cannot be converted to int"
00116              << endl;
00117         return;
00118     };
00119     cerr << "- campaign '" + redisKey + "' properly loaded"
00120          << endl;
00121 }
00122 
00123 void
00124 Campaign::
00125 save(AsyncConnection & redis)
00126     const
00127 {
00128     string redisKey(CampaignsPrefix + key_);
00129 
00130     Command hmset = HMSET(redisKey);
00131     hmset.addArg("available");
00132     hmset.addArg(available_);
00133     hmset.addArg("transferred");
00134     hmset.addArg(transferred_);
00135 
00136     Result result = redis.exec(hmset);
00137     if (!result.ok()) {
00138         cerr << "! HMSET " + redisKey
00139              << ": error storing campaign keys" << endl;
00140         return;
00141     }
00142 
00143     cerr << "- campaign '" + redisKey + "' properly saved" << endl;
00144 }
00145 
00146 /* STRATEGY */
00147 Strategy::
00148 Strategy(const string & key, const string & campaignKey,
00149          long long available, long long spent, long long transferred)
00150     : key_(key), campaignKey_(campaignKey), valid_(false),
00151       available_(available), spent_(spent),
00152       transferred_(transferred)
00153 {
00154 }
00155 
00156 void
00157 Strategy::
00158 load(AsyncConnection & redis, int acceptedDelta)
00159 {
00160     string redisKey(CampaignsPrefix + campaignKey_ + ":" + key_);
00161     Command hmget = HMGET(redisKey);
00162     hmget.addArg("available");
00163     hmget.addArg("spent");
00164     hmget.addArg("transferred");
00165     Result result = redis.exec(hmget);
00166     if (!result.ok()) {
00167         cerr << "! HMGET " + redisKey
00168              << ": error fetching result" << endl;
00169         return;
00170     }
00171     const Reply & reply = result.reply();
00172     if (reply.type() != ARRAY) {
00173         cerr << "! HMGET " + redisKey
00174              << ": unexpected reply type" << endl;
00175         return;
00176     }
00177     if (!GetRedisReplyAsInt(reply[0], available_)) {
00178         cerr << "! HMGET " + redisKey
00179              << ": value for 'available' cannot be converted to int"
00180              << endl;
00181         return;
00182     }
00183     if (!GetRedisReplyAsInt(reply[1], spent_)) {
00184         cerr << "! HMGET " + redisKey
00185              << ": value for 'spent' cannot be converted to int"
00186              << endl;
00187         return;
00188     };
00189     if (!GetRedisReplyAsInt(reply[2], transferred_)) {
00190         cerr << "! HMGET " + redisKey
00191              << ": value for 'transferred' cannot be converted to int"
00192              << endl;
00193         return;
00194     };
00195 
00196     /* validation */
00197     if (transferred_ < 0
00198         // || !IsMoreOrLess(available_, acceptedDelta)
00199         || spent_ < 0) {
00200         cerr << "! strategy '" + redisKey + "' has one or more negative values:"
00201              << endl
00202              << "    transferred = " << transferred_
00203              << "; available = " << available_
00204              << "; spent = " << spent_
00205              << endl;
00206     }
00207 #if 0
00208     else if (!IsMoreOrLess((transferred_ - spent_) - available_,
00209                            acceptedDelta)) {
00210         long long int delta = (available_ + spent_) - transferred_;
00211         cerr << "! strategy '" + redisKey + "' is in an inconsistent state:"
00212              << endl
00213              << "    transferred = " << transferred_
00214              << "; available = " << available_
00215              << "; spent = " << spent_
00216              << endl
00217              << "    delta: " << delta
00218              << endl;
00219     }
00220 #endif
00221     else {
00222         cerr << "- strategy '" + redisKey + "' properly loaded and consistent"
00223              << endl;
00224         valid_ = true;
00225     }
00226 }
00227 
00228 void
00229 Strategy::
00230 save(AsyncConnection & redis)
00231     const
00232 {
00233     string redisKey(CampaignsPrefix + campaignKey_ + ":" + key_);
00234 
00235     if (!valid_) {
00236         cerr << "! skipped the saving of 'invalid' strategy '" + redisKey + "'"
00237              << endl;
00238         return;
00239     }
00240 
00241     Command hmset = HMSET(redisKey);
00242     hmset.addArg("available");
00243     hmset.addArg(available_);
00244     hmset.addArg("spent");
00245     hmset.addArg(spent_);
00246     hmset.addArg("transferred");
00247     hmset.addArg(transferred_);
00248 
00249     Result result = redis.exec(hmset);
00250     if (!result.ok()) {
00251         cerr << "! HMSET " + redisKey
00252              << ": error storing campaign keys" << endl;
00253         return;
00254     }
00255 
00256     cerr << "- strategy '" + redisKey + "' properly saved" << endl;
00257 }
00258 
00259 /* assign strategy to the right campaign */
00260 void Strategy::
00261 assignToParent(Campaigns & campaigns) const
00262 {
00263     if (campaigns.count(campaignKey_) == 0) {
00264         cerr << "! ignored strategy '"
00265              << CampaignsPrefix << campaignKey_ << ":" << key_
00266              << "' without corresponding campaign"
00267              << endl;
00268     }
00269     else {
00270         Campaign & campaign = campaigns.at(campaignKey_);
00271         campaign.strategies.push_back(*this);
00272     }
00273 }
00274 
00275 } // namespace RTBKIT
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator