1717#include " llvm/Support/CommandLine.h"
1818#include " hiredis.h"
1919
20+ #include < sstream>
21+
2022using namespace llvm ;
2123using namespace souper ;
2224
2325static cl::opt<unsigned > RedisPort (" souper-redis-port" , cl::init(6379 ),
2426 cl::desc(" Redis server port (default=6379)" ));
2527
28+ namespace {
29+
30+ std::vector<std::string> getActiveOptions (StringMap<cl::Option*> &Opts) {
31+ std::vector<std::string> ActiveOptions;
32+
33+ for (auto &K : Opts.keys ()) {
34+ if (Opts[K]->getNumOccurrences ()) {
35+ std::string StrValue;
36+
37+ // cl::opt<unsigned>
38+ if (K == " souper-exhaustive-synthesis-num-instructions" ) {
39+ auto Val = static_cast <cl::opt<unsigned > *>(Opts[K]);
40+ StrValue = K.str () + " =" + std::to_string (Val->getValue ());
41+ }
42+ // cl::opt<bool, true> with default=false
43+ else if (K == " souper-use-alive" ) {
44+ auto Val = static_cast <cl::opt<bool , true > *>(Opts[K]);
45+ StrValue = K.str () + " =" + (Val->getValue () ? " true" : " false" );
46+ }
47+ // cl::opt<bool> with default=false
48+ else if (K == " souper-lsb-pruning" ||
49+ K == " souper-dataflow-pruning" ||
50+ K == " souper-synthesis-const-with-cegis" ||
51+ K == " souper-synthesis-ignore-cost" ) {
52+ auto Val = static_cast <cl::opt<bool > *>(Opts[K]);
53+ if (Val->getValue ())
54+ StrValue = K.str () + " =true" ;
55+ }
56+ // cl::opt<int>
57+ else if (K == " souper-synthesis-comp-num" ) {
58+ auto Val = static_cast <cl::opt<int > *>(Opts[K]);
59+ StrValue = K.str () + " =" + std::to_string (Val->getValue ());
60+ }
61+ // cl::opt<std::string>
62+ else if (K == " souper-synthesis-comps" ) {
63+ auto Val = static_cast <cl::opt<std::string> *>(Opts[K]);
64+ StrValue = K.str () + " =" + Val->getValue ();
65+ }
66+
67+ if (!StrValue.empty ())
68+ ActiveOptions.emplace_back (StrValue);
69+ }
70+ }
71+
72+ return ActiveOptions;
73+ }
74+
75+ } // anon ns
76+
2677namespace souper {
2778
2879class KVStore ::KVImpl {
29- redisContext *Ctx;
80+ redisContext *Ctx = 0 ;
81+
82+ private:
83+ // checks if current redis database is compatible with current version of souper
84+ bool checkCompatibility ();
85+
3086public:
3187 KVImpl ();
3288 ~KVImpl ();
@@ -46,12 +102,54 @@ KVStore::KVImpl::KVImpl() {
46102 llvm::report_fatal_error ((llvm::StringRef)" Redis connection error: " +
47103 Ctx->errstr + " \n " );
48104 }
105+
106+ if (!checkCompatibility ()) {
107+ llvm::report_fatal_error (" Redis cache on port " + std::to_string (RedisPort) + " is incompatible." );
108+ }
49109}
50110
51111KVStore::KVImpl::~KVImpl () {
52112 redisFree (Ctx);
53113}
54114
115+ bool KVStore::KVImpl::checkCompatibility () {
116+ assert (Ctx && " Cannot check compatibility on an uninitialized database." );
117+
118+ redisReply *reply = static_cast <redisReply*>(redisCommand (Ctx, " GET cachetype" ));
119+ if (!reply || Ctx->err ) {
120+ llvm::report_fatal_error ((llvm::StringRef)" Redis error: " + Ctx->errstr );
121+ }
122+
123+ // get all current command line used
124+ StringMap<cl::Option*> &Opts = cl::getRegisteredOptions ();
125+ std::vector<std::string> ActiveOptions = getActiveOptions (Opts);
126+ std::sort (ActiveOptions.begin (), ActiveOptions.end ());
127+ std::ostringstream ActiveOptionsOSS;
128+ const char *delim = " ;" ;
129+ std::copy (ActiveOptions.begin (), ActiveOptions.end (),
130+ std::ostream_iterator<std::string>(ActiveOptionsOSS, delim));
131+ std::string ActiveOptionsStr = ActiveOptionsOSS.str ();
132+
133+ switch (reply->type ) {
134+ case REDIS_REPLY_NIL:
135+ // no version set
136+ freeReplyObject (reply);
137+ reply = static_cast <redisReply*>(redisCommand (Ctx, " SET cachetype %s" , ActiveOptionsStr.data ()));
138+ // TODO: Factor out all such snippets
139+ if (!reply || Ctx->err ) {
140+ llvm::report_fatal_error ((llvm::StringRef)" Redis error: " + Ctx->errstr );
141+ }
142+ break ;
143+ case REDIS_REPLY_STRING:
144+ if (llvm::StringRef value = reply->str ; value != ActiveOptionsStr)
145+ return false ;
146+ break ;
147+ default : return false ;
148+ }
149+
150+ return true ;
151+ }
152+
55153void KVStore::KVImpl::hIncrBy (llvm::StringRef Key, llvm::StringRef Field,
56154 int Incr) {
57155 redisReply *reply = (redisReply *)redisCommand (Ctx, " HINCRBY %s %s 1" ,
0 commit comments