From 3399c9fcb12555c2147f2fd3d62fb9959c80a2c2 Mon Sep 17 00:00:00 2001 From: Pranav Kant Date: Fri, 19 Apr 2019 14:33:15 -0600 Subject: [PATCH] Add support for checking cache incompatibility --- lib/KVStore/KVStore.cpp | 62 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/KVStore/KVStore.cpp b/lib/KVStore/KVStore.cpp index de5868a3f..c400d16f2 100644 --- a/lib/KVStore/KVStore.cpp +++ b/lib/KVStore/KVStore.cpp @@ -17,6 +17,8 @@ #include "llvm/Support/CommandLine.h" #include "hiredis.h" +#include + using namespace llvm; using namespace souper; @@ -26,7 +28,12 @@ static cl::opt RedisPort("souper-redis-port", cl::init(6379), namespace souper { class KVStore::KVImpl { - redisContext *Ctx; + redisContext *Ctx = 0; + +private: + // checks if current redis database is compatible with current version of souper + bool checkCompatibility(); + public: KVImpl(); ~KVImpl(); @@ -46,12 +53,65 @@ KVStore::KVImpl::KVImpl() { llvm::report_fatal_error((llvm::StringRef)"Redis connection error: " + Ctx->errstr + "\n"); } + + if (!checkCompatibility()) { + llvm::report_fatal_error("Redis database on port %d is incompatible.", RedisPort); + } } KVStore::KVImpl::~KVImpl() { redisFree(Ctx); } +bool KVStore::KVImpl::checkCompatibility() { + assert(Ctx && "Cannot check compatibility on an uninitialized database."); + + redisReply *reply = static_cast(redisCommand(Ctx, "GET cachetype")); + if (!reply || Ctx->err) { + llvm::report_fatal_error((llvm::StringRef)"Redis error: " + Ctx->errstr); + } + + // get all current command line used + StringMap &Opts = cl::getRegisteredOptions(); + std::vector ActiveOptions; + for (auto &K : Opts.keys()) { + if (Opts[K]->getNumOccurrences()) { + ActiveOptions.emplace_back(K.str()); + } + } + std::sort(ActiveOptions.begin(), ActiveOptions.end()); + std::ostringstream ActiveOptionsOSS; + const char *delim = ","; + std::copy(ActiveOptions.begin(), ActiveOptions.end(), + std::ostream_iterator(ActiveOptionsOSS, delim)); + std::string ActiveOptionsStr = ActiveOptionsOSS.str(); + + bool compat = true; + switch(reply->type) { + case REDIS_REPLY_NIL: + // no version set + freeReplyObject(reply); + reply = static_cast(redisCommand(Ctx, "SET cachetype %s", ActiveOptionsStr.data())); + // TODO: Factor out all such snippets + if (!reply || Ctx->err) { + llvm::report_fatal_error((llvm::StringRef)"Redis error: " + Ctx->errstr); + } + break; + case REDIS_REPLY_STRING: + { + llvm::StringRef value = reply->str; + if (value != ActiveOptionsStr) { + compat = false; + } + } + break; + default: + compat = false; + } + + return compat; +} + void KVStore::KVImpl::hIncrBy(llvm::StringRef Key, llvm::StringRef Field, int Incr) { redisReply *reply = (redisReply *)redisCommand(Ctx, "HINCRBY %s %s 1",