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,65 @@ 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+ bool compat = true ;
90+ switch (reply->type ) {
91+ case REDIS_REPLY_NIL :
92+ // no version set
93+ freeReplyObject (reply);
94+ reply = static_cast <redisReply*>(redisCommand (Ctx, " SET cachetype %s" , ActiveOptionsStr.data ()));
95+ // TODO: Factor out all such snippets
96+ if (!reply || Ctx->err ) {
97+ llvm::report_fatal_error ((llvm::StringRef)" Redis error: " + Ctx->errstr );
98+ }
99+ break ;
100+ case REDIS_REPLY_STRING :
101+ {
102+ llvm::StringRef value = reply->str ;
103+ if (value != ActiveOptionsStr) {
104+ compat = false ;
105+ }
106+ }
107+ break ;
108+ default :
109+ compat = false ;
110+ }
111+
112+ return compat;
113+ }
114+
55115void KVStore::KVImpl::hIncrBy (llvm::StringRef Key, llvm::StringRef Field,
56116 int Incr) {
57117 redisReply *reply = (redisReply *)redisCommand (Ctx, " HINCRBY %s %s 1" ,
0 commit comments