1717#include " llvm/Support/CommandLine.h"
1818#include " hiredis.h"
1919
20+ #include < sstream>
21+
2022using namespace llvm ;
2123using namespace souper ;
2224
@@ -26,7 +28,12 @@ static cl::opt<unsigned> RedisPort("souper-redis-port", cl::init(6379),
2628namespace souper {
2729
2830class KVStore ::KVImpl {
29- redisContext *Ctx;
31+ redisContext *Ctx = 0 ;
32+
33+ private:
34+ // checks if current redis database is compatible with current version of souper
35+ bool checkCompatibility ();
36+
3037public:
3138 KVImpl ();
3239 ~KVImpl ();
@@ -46,12 +53,59 @@ KVStore::KVImpl::KVImpl() {
4653 llvm::report_fatal_error ((llvm::StringRef)" Redis connection error: " +
4754 Ctx->errstr + " \n " );
4855 }
56+
57+ if (!checkCompatibility ()) {
58+ llvm::report_fatal_error (" Redis database on port %d is incompatible." , RedisPort);
59+ }
4960}
5061
5162KVStore::KVImpl::~KVImpl () {
5263 redisFree (Ctx);
5364}
5465
66+ bool KVStore::KVImpl::checkCompatibility () {
67+ assert (Ctx && " Cannot check compatibility on an uninitialized database." );
68+
69+ redisReply *reply = static_cast <redisReply*>(redisCommand (Ctx, " GET cachetype" ));
70+ if (!reply || Ctx->err ) {
71+ llvm::report_fatal_error ((llvm::StringRef)" Redis error: " + Ctx->errstr );
72+ }
73+
74+ // get all current command line used
75+ StringMap<cl::Option*> &Opts = cl::getRegisteredOptions ();
76+ std::vector<std::string> ActiveOptions;
77+ for (auto &K : Opts.keys ()) {
78+ if (Opts[K]->getNumOccurrences () && K.find (" -debug-level" ) == StringRef::npos) {
79+ ActiveOptions.emplace_back (K.str ());
80+ }
81+ }
82+ std::sort (ActiveOptions.begin (), ActiveOptions.end ());
83+ std::ostringstream ActiveOptionsOSS;
84+ const char *delim = " ," ;
85+ std::copy (ActiveOptions.begin (), ActiveOptions.end (),
86+ std::ostream_iterator<std::string>(ActiveOptionsOSS, delim));
87+ std::string ActiveOptionsStr = ActiveOptionsOSS.str ();
88+
89+ switch (reply->type ) {
90+ case REDIS_REPLY_NIL:
91+ // no version set
92+ freeReplyObject (reply);
93+ reply = static_cast <redisReply*>(redisCommand (Ctx, " SET cachetype %s" , ActiveOptionsStr.data ()));
94+ // TODO: Factor out all such snippets
95+ if (!reply || Ctx->err ) {
96+ llvm::report_fatal_error ((llvm::StringRef)" Redis error: " + Ctx->errstr );
97+ }
98+ break ;
99+ case REDIS_REPLY_STRING:
100+ if (llvm::StringRef value = reply->str ; value != ActiveOptionsStr)
101+ return false ;
102+ break ;
103+ default : return false ;
104+ }
105+
106+ return true ;
107+ }
108+
55109void KVStore::KVImpl::hIncrBy (llvm::StringRef Key, llvm::StringRef Field,
56110 int Incr) {
57111 redisReply *reply = (redisReply *)redisCommand (Ctx, " HINCRBY %s %s 1" ,
0 commit comments