From f0ebbc30c67e803f3711894b2345a43e201da04c 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 | 100 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/lib/KVStore/KVStore.cpp b/lib/KVStore/KVStore.cpp index de5868a3f..6a12d795a 100644 --- a/lib/KVStore/KVStore.cpp +++ b/lib/KVStore/KVStore.cpp @@ -17,16 +17,72 @@ #include "llvm/Support/CommandLine.h" #include "hiredis.h" +#include + using namespace llvm; using namespace souper; static cl::opt RedisPort("souper-redis-port", cl::init(6379), cl::desc("Redis server port (default=6379)")); +namespace { + + std::vector getActiveOptions(StringMap &Opts) { + std::vector ActiveOptions; + + for (auto &K : Opts.keys()) { + if (Opts[K]->getNumOccurrences()) { + std::string StrValue; + + // cl::opt + if (K == "souper-exhaustive-synthesis-num-instructions") { + auto Val = static_cast *>(Opts[K]); + StrValue = K.str() + "=" + std::to_string(Val->getValue()); + } + // cl::opt with default=false + else if (K == "souper-use-alive") { + auto Val = static_cast *>(Opts[K]); + StrValue = K.str() + "=" + (Val->getValue() ? "true" : "false"); + } + // cl::opt with default=false + else if (K == "souper-lsb-pruning" || + K == "souper-dataflow-pruning" || + K == "souper-synthesis-const-with-cegis" || + K == "souper-synthesis-ignore-cost") { + auto Val = static_cast *>(Opts[K]); + if (Val->getValue()) + StrValue = K.str() + "=true"; + } + // cl::opt + else if (K == "souper-synthesis-comp-num") { + auto Val = static_cast *>(Opts[K]); + StrValue = K.str() + "=" + std::to_string(Val->getValue()); + } + // cl::opt + else if (K == "souper-synthesis-comps") { + auto Val = static_cast *>(Opts[K]); + StrValue = K.str() + "=" + Val->getValue(); + } + + if (!StrValue.empty()) + ActiveOptions.emplace_back(StrValue); + } + } + + return ActiveOptions; + } + +} // anon ns + 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 +102,54 @@ KVStore::KVImpl::KVImpl() { llvm::report_fatal_error((llvm::StringRef)"Redis connection error: " + Ctx->errstr + "\n"); } + + if (!checkCompatibility()) { + llvm::report_fatal_error("Redis cache on port " + std::to_string(RedisPort) + " is incompatible."); + } } 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 = getActiveOptions(Opts); + 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(); + + 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: + if (llvm::StringRef value = reply->str; value != ActiveOptionsStr) + return false; + break; + default: return false; + } + + return true; +} + void KVStore::KVImpl::hIncrBy(llvm::StringRef Key, llvm::StringRef Field, int Incr) { redisReply *reply = (redisReply *)redisCommand(Ctx, "HINCRBY %s %s 1",