Commit eb3cc064 authored by Georgios Bitzes's avatar Georgios Bitzes
Browse files

Implement SMOVE

parent 26a6d003
Pipeline #332675 passed with stages
in 24 minutes and 49 seconds
......@@ -67,6 +67,7 @@ struct cmdMapInit {
redis_cmd_map["hdel"] = {RedisCommand::HDEL, CommandType::WRITE};
redis_cmd_map["sadd"] = {RedisCommand::SADD, CommandType::WRITE};
redis_cmd_map["srem"] = {RedisCommand::SREM, CommandType::WRITE};
redis_cmd_map["smove"] = {RedisCommand::SMOVE, CommandType::WRITE};
redis_cmd_map["lpush"] = {RedisCommand::LPUSH, CommandType::WRITE};
redis_cmd_map["lpop"] = {RedisCommand::LPOP, CommandType::WRITE};
redis_cmd_map["rpush"] = {RedisCommand::RPUSH, CommandType::WRITE};
......
......@@ -63,6 +63,7 @@ enum class RedisCommand {
SADD,
SISMEMBER,
SREM,
SMOVE,
SMEMBERS,
SCARD,
SSCAN,
......
......@@ -167,6 +167,13 @@ RedisEncodedResponse RedisDispatcher::dispatchWrite(StagingArea &stagingArea, Re
if(!st.ok()) return Formatter::fromStatus(st);
return Formatter::integer(count);
}
case RedisCommand::SMOVE: {
if(request.size() != 4) return errArgs(request);
int64_t count = 0;
rocksdb::Status st = store.smove(stagingArea, request[1], request[2], request[3], count);
if(!st.ok()) return Formatter::fromStatus(st);
return Formatter::integer(count);
}
case RedisCommand::LPUSH: {
if(request.size() < 3) return errArgs(request);
int64_t length;
......
......@@ -505,6 +505,40 @@ rocksdb::Status StateMachine::srem(StagingArea &stagingArea, const std::string &
return operation.finalize(operation.keySize() - removed);
}
rocksdb::Status StateMachine::smove(StagingArea &stagingArea, const std::string &source, const std::string &destination, const std::string &element, int64_t &outcome) {
WriteOperation operation1(stagingArea, source, KeyType::kSet);
if(!operation1.valid()) return wrong_type();
WriteOperation operation2(stagingArea, destination, KeyType::kSet);
if(!operation2.valid()) {
operation1.finalize(operation1.keySize());
return wrong_type();
}
if(operation1.deleteField(element)) {
outcome = 1;
operation1.finalize(operation1.keySize() - 1);
if(operation2.fieldExists(element)) {
// No-op
operation2.finalize(operation2.keySize());
}
else {
operation2.writeField(element, "1");
operation2.finalize(operation2.keySize() + 1);
}
return rocksdb::Status::OK();
}
// No operation performed, item does not exist
outcome = 0;
operation1.finalize(operation1.keySize());
operation2.finalize(operation2.keySize());
return rocksdb::Status::OK();
}
rocksdb::Status StateMachine::smembers(StagingArea &stagingArea, const std::string &key, std::vector<std::string> &members) {
if(!assertKeyType(stagingArea, key, KeyType::kSet)) return wrong_type();
......
......@@ -66,6 +66,7 @@ public:
rocksdb::Status sadd(StagingArea &stagingArea, const std::string &key, const VecIterator &start, const VecIterator &end, int64_t &added);
rocksdb::Status srem(StagingArea &stagingArea, const std::string &key, const VecIterator &start, const VecIterator &end, int64_t &removed);
rocksdb::Status smove(StagingArea &stagingArea, const std::string &source, const std::string &destination, const std::string &element, int64_t &outcome);
rocksdb::Status lpush(StagingArea &stagingArea, const std::string &key, const VecIterator &start, const VecIterator &end, int64_t &length);
rocksdb::Status rpush(StagingArea &stagingArea, const std::string &key, const VecIterator &start, const VecIterator &end, int64_t &length);
......
......@@ -851,6 +851,52 @@ TEST_F(Raft_e2e, hincrbymulti) {
ASSERT_REPLY(tunnel(leaderID)->exec("hget", "h4", "h8"), "13");
}
TEST_F(Raft_e2e, smove) {
spinup(0); spinup(1); spinup(2);
RETRY_ASSERT_TRUE(checkStateConsensus(0, 1, 2));
int leaderID = getLeaderID();
ASSERT_REPLY(tunnel(leaderID)->exec("sadd", "set1", "i1", "i2", "i3", "i4", "i5"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set1"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("sadd", "set2", "t1", "t2", "t3", "t4", "t5"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set2"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("set", "mykey", "myval"), "OK");
ASSERT_REPLY(tunnel(leaderID)->exec("smove", "set1", "mykey", "i1"), "ERR Invalid argument: WRONGTYPE Operation against a key holding the wrong kind of value");
ASSERT_REPLY(tunnel(leaderID)->exec("smove", "mykey", "set1", "i1"), "ERR Invalid argument: WRONGTYPE Operation against a key holding the wrong kind of value");
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set1"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set2"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("smove", "set1", "set2", "i1"), 1);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set1"), 4);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set2"), 6);
ASSERT_REPLY(tunnel(leaderID)->exec("smembers", "set1"), make_vec("i2", "i3", "i4", "i5"));
ASSERT_REPLY(tunnel(leaderID)->exec("smembers", "set2"), make_vec("i1", "t1", "t2", "t3", "t4", "t5"));
ASSERT_REPLY(tunnel(leaderID)->exec("smove", "set1", "set2", "not-existing"), 0);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set1"), 4);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set2"), 6);
ASSERT_REPLY(tunnel(leaderID)->exec("sadd", "set1", "i1"), 1);
ASSERT_REPLY(tunnel(leaderID)->exec("smembers", "set1"), make_vec("i1", "i2", "i3", "i4", "i5"));
ASSERT_REPLY(tunnel(leaderID)->exec("smembers", "set2"), make_vec("i1", "t1", "t2", "t3", "t4", "t5"));
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set1"), 5);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set2"), 6);
ASSERT_REPLY(tunnel(leaderID)->exec("smove", "set1", "set2", "i1"), 1);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set1"), 4);
ASSERT_REPLY(tunnel(leaderID)->exec("scard", "set2"), 6);
ASSERT_REPLY(tunnel(leaderID)->exec("smembers", "set1"), make_vec("i2", "i3", "i4", "i5"));
ASSERT_REPLY(tunnel(leaderID)->exec("smembers", "set2"), make_vec("i1", "t1", "t2", "t3", "t4", "t5"));
}
TEST_F(Raft_e2e, sscan) {
spinup(0); spinup(1); spinup(2);
RETRY_ASSERT_TRUE(checkStateConsensus(0, 1, 2));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment