Skip to content
This repository was archived by the owner on Oct 30, 2025. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion lib/KVStore/KVStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,72 @@
#include "llvm/Support/CommandLine.h"
#include "hiredis.h"

#include <sstream>

using namespace llvm;
using namespace souper;

static cl::opt<unsigned> RedisPort("souper-redis-port", cl::init(6379),
cl::desc("Redis server port (default=6379)"));

namespace {

std::vector<std::string> getActiveOptions(StringMap<cl::Option*> &Opts) {
std::vector<std::string> ActiveOptions;

for (auto &K : Opts.keys()) {
if (Opts[K]->getNumOccurrences()) {
std::string StrValue;

// cl::opt<unsigned>
if (K == "souper-exhaustive-synthesis-num-instructions") {
auto Val = static_cast<cl::opt<unsigned> *>(Opts[K]);
StrValue = K.str() + "=" + std::to_string(Val->getValue());
}
// cl::opt<bool, true> with default=false
else if (K == "souper-use-alive") {
auto Val = static_cast<cl::opt<bool, true> *>(Opts[K]);
StrValue = K.str() + "=" + (Val->getValue() ? "true" : "false");
}
// cl::opt<bool> 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<cl::opt<bool> *>(Opts[K]);
if (Val->getValue())
StrValue = K.str() + "=true";
}
// cl::opt<int>
else if (K == "souper-synthesis-comp-num") {
auto Val = static_cast<cl::opt<int> *>(Opts[K]);
StrValue = K.str() + "=" + std::to_string(Val->getValue());
}
// cl::opt<std::string>
else if (K == "souper-synthesis-comps") {
auto Val = static_cast<cl::opt<std::string> *>(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();
Expand All @@ -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<redisReply*>(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<cl::Option*> &Opts = cl::getRegisteredOptions();
std::vector<std::string> ActiveOptions = getActiveOptions(Opts);
std::sort(ActiveOptions.begin(), ActiveOptions.end());
std::ostringstream ActiveOptionsOSS;
const char *delim = ";";
std::copy(ActiveOptions.begin(), ActiveOptions.end(),
std::ostream_iterator<std::string>(ActiveOptionsOSS, delim));
std::string ActiveOptionsStr = ActiveOptionsOSS.str();

switch(reply->type) {
case REDIS_REPLY_NIL:
// no version set
freeReplyObject(reply);
reply = static_cast<redisReply*>(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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line is dead code, please remove

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not a dead code.

  1. note that REDIS_REPLY_NIL and REDIS_REPLY_STRING don't return anything when things are compatible --- they just break out of the switch case and let this statement return true.
  2. Even if I put return statements to return true as described in (1), compiler will emit warning saying that control reaches end of non-void statement as we don't disable Wreturn-type from our CMake config (which is fine).

}

void KVStore::KVImpl::hIncrBy(llvm::StringRef Key, llvm::StringRef Field,
int Incr) {
redisReply *reply = (redisReply *)redisCommand(Ctx, "HINCRBY %s %s 1",
Expand Down