Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use CLUSTERX command to set cluster topology #324

Merged
merged 2 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
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
78 changes: 55 additions & 23 deletions src/redis_cmd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4140,24 +4140,11 @@ class CommandCluster : public Commander {
Status Parse(const std::vector<std::string> &args) override {
subcommand_ = Util::ToLower(args[1]);

if (args.size() == 2 && (subcommand_ == "nodes" || subcommand_ == "version" ||
subcommand_ == "slots" || subcommand_ == "info")) return Status::OK();
if (args.size() == 2 && (subcommand_ == "nodes" || subcommand_ == "slots"
|| subcommand_ == "info")) return Status::OK();
if (subcommand_ == "keyslot" && args_.size() == 3) return Status::OK();
if (subcommand_ == "setnodeid" && args_.size() == 3 &&
args_[2].size() == kClusetNodeIdLen) return Status::OK();
if (subcommand_ == "setnodes" && args_.size() >= 4) {
nodes_str_ = args_[2];
set_version_ = atoll(args_[3].c_str());
if (set_version_ < 0) return Status(Status::RedisParseErr, "Invalid version");
if (args_.size() == 4) return Status::OK();
if (args_.size() == 5 && strcasecmp(args_[4].c_str(), "force") == 0) {
force_ = true;
return Status::OK();
}
return Status(Status::RedisParseErr, "Invalid setnodes options");
}
return Status(Status::RedisParseErr,
"CLUSTER command, CLUSTER VERSION|INFO|NODES|SLOTS|KEYSLOT|SETNODEID|SETNODES");
"CLUSTER command, CLUSTER INFO|NODES|SLOTS|KEYSLOT");
}

Status Execute(Server *svr, Connection *conn, std::string *output) override {
Expand All @@ -4174,13 +4161,6 @@ class CommandCluster : public Commander {
if (subcommand_ == "keyslot") {
auto slot_id = GetSlotNumFromKey(args_[2]);
*output = Redis::Integer(slot_id);
} else if (subcommand_ == "setnodes") {
Status s = svr->cluster_->SetClusterNodes(nodes_str_, set_version_, force_);
if (s.IsOK()) {
*output = Redis::SimpleString("OK");
} else {
*output = Redis::Error(s.Msg());
}
} else if (subcommand_ == "slots") {
std::vector<SlotInfo> infos;
Status s = svr->cluster_->GetSlotsInfo(&infos);
Expand Down Expand Up @@ -4216,6 +4196,57 @@ class CommandCluster : public Commander {
} else {
*output = Redis::Error(s.Msg());
}
} else {
*output = Redis::Error("Invalid cluster command options");
}
return Status::OK();
}

private:
std::string subcommand_;
};

class CommandClusterX : public Commander {
public:
Status Parse(const std::vector<std::string> &args) override {
subcommand_ = Util::ToLower(args[1]);

if (args.size() == 2 && (subcommand_ == "version")) return Status::OK();
if (subcommand_ == "setnodeid" && args_.size() == 3 &&
args_[2].size() == kClusetNodeIdLen) return Status::OK();
if (subcommand_ == "setnodes" && args_.size() >= 4) {
nodes_str_ = args_[2];
set_version_ = atoll(args_[3].c_str());
if (set_version_ < 0) return Status(Status::RedisParseErr, "Invalid version");
if (args_.size() == 4) return Status::OK();
if (args_.size() == 5 && strcasecmp(args_[4].c_str(), "force") == 0) {
force_ = true;
return Status::OK();
}
return Status(Status::RedisParseErr, "Invalid setnodes options");
}
return Status(Status::RedisParseErr,
"CLUSTERX command, CLUSTERX VERSION|SETNODEID|SETNODES");
}

Status Execute(Server *svr, Connection *conn, std::string *output) override {
if (svr->GetConfig()->cluster_enable_ == false) {
*output = Redis::Error("Cluster mode is not enabled");
return Status::OK();
}

if (!conn->IsAdmin()) {
*output = Redis::Error(errAdministorPermissionRequired);
return Status::OK();
}

if (subcommand_ == "setnodes") {
Status s = svr->cluster_->SetClusterNodes(nodes_str_, set_version_, force_);
if (s.IsOK()) {
*output = Redis::SimpleString("OK");
} else {
*output = Redis::Error(s.Msg());
}
} else if (subcommand_ == "setnodeid") {
Status s = svr->cluster_->SetNodeId(args_[2]);
if (s.IsOK()) {
Expand Down Expand Up @@ -4406,6 +4437,7 @@ CommandAttributes redisCommandTable[] = {
ADD_CMD("sirevrangebyvalue", -4, "read-only", 1, 1, 1, CommandSortedintRevRangeByValue),

ADD_CMD("cluster", -2, "cluster", 0, 0, 0, CommandCluster),
ADD_CMD("clusterx", -2, "cluster", 0, 0, 0, CommandClusterX),

ADD_CMD("compact", 1, "read-only", 0, 0, 0, CommandCompact),
ADD_CMD("bgsave", 1, "read-only", 0, 0, 0, CommandBGSave),
Expand Down
2 changes: 1 addition & 1 deletion src/redis_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ void Connection::ExecuteCommands(const std::vector<Redis::CommandTokens> &to_pro
// No lock guard, because 'exec' command has acquired 'WorkExclusivityGuard'
} else if (attributes->is_exclusive() ||
(cmd_name == "config" && cmd_tokens.size() == 2 && !strcasecmp(cmd_tokens[1].c_str(), "set")) ||
(config->cluster_enable_ && cmd_name == "cluster" && cmd_tokens.size() >= 2
(config->cluster_enable_ && cmd_name == "clusterx" && cmd_tokens.size() >= 2
&& Cluster::SubCommandIsExecExclusive(cmd_tokens[1]))) {
exclusivity = svr_->WorkExclusivityGuard();
} else {
Expand Down
30 changes: 15 additions & 15 deletions tests/tcl/tests/integration/cluster.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ start_server {tags {"cluster"} overrides {cluster-enable yes}} {

start_server {tags {"cluster"} overrides {cluster-enable yes}} {
set nodeid "07c37dfeb235213a872192d90877d0cd55635b91"
r cluster SETNODEID $nodeid
r clusterx SETNODEID $nodeid

test {basic function of cluster} {
# Cluster is not initialized
Expand All @@ -28,8 +28,8 @@ start_server {tags {"cluster"} overrides {cluster-enable yes}} {
# Set cluster nodes info
set port [srv port]
set nodes_str "$nodeid 127.0.0.1 $port master - 0-100"
r cluster setnodes $nodes_str 2
assert_equal 2 [r cluster version]
r clusterx setnodes $nodes_str 2
assert_equal 2 [r clusterx version]

# Get and check cluster nodes info
set output_nodes [r cluster nodes]
Expand All @@ -48,8 +48,8 @@ start_server {tags {"cluster"} overrides {cluster-enable yes}} {
# Set cluster nodes info
set port [srv port]
set nodes_str "07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1 $port master - 0-200"
r cluster setnodes $nodes_str 1 force
assert_equal 1 [r cluster version]
r clusterx setnodes $nodes_str 1 force
assert_equal 1 [r clusterx version]

set output_nodes [r cluster nodes]
assert_equal "0-200\n" [lindex [split $output_nodes " "] 8]
Expand All @@ -59,19 +59,19 @@ start_server {tags {"cluster"} overrides {cluster-enable yes}} {
catch {[r cluster no-subcommand]} err
assert_match "*CLUSTER*" $err

catch {[r cluster version a]} err
catch {[r clusterx version a]} err
assert_match "*CLUSTER*" $err

catch {[r cluster nodes a]} err
assert_match "*CLUSTER*" $err

catch {[r cluster setnodeid a]} err
catch {[r clusterx setnodeid a]} err
assert_match "*CLUSTER*" $err

catch {[r cluster setnodes a]} err
catch {[r clusterx setnodes a]} err
assert_match "*CLUSTER*" $err

catch {[r cluster setnodes a -1]} err
catch {[r clusterx setnodes a -1]} err
assert_match "*Invalid version*" $err
}
}
Expand All @@ -83,8 +83,8 @@ start_server {tags {"cluster"} overrides {cluster-enable yes}} {
set port [srv port]
set cluster_nodes "$nodeid $host $port master -"
set cluster_nodes "${cluster_nodes} 0-1 2 4-8191 8192 8193 10000 10002-11002 16381 16382-16383"
r cluster setnodes "$cluster_nodes" 1
r cluster setnodeid $nodeid
r clusterx setnodes "$cluster_nodes" 1
r clusterx setnodeid $nodeid
set ret [r cluster slots]
assert_equal 5 [llength $ret]

Expand Down Expand Up @@ -137,10 +137,10 @@ start_server {tags {"cluster"} overrides {cluster-enable yes}} {
set cluster_nodes "$cluster_nodes\n$node3_id $node3_host $node3_port slave $node2_id"

# node0 doesn't serve any slot, just like a router
$r0 cluster setnodes $cluster_nodes 1
$r1 cluster setnodes $cluster_nodes 1
$r2 cluster setnodes $cluster_nodes 1
$r3 cluster setnodes $cluster_nodes 1
$r0 clusterx setnodes $cluster_nodes 1
$r1 clusterx setnodes $cluster_nodes 1
$r2 clusterx setnodes $cluster_nodes 1
$r3 clusterx setnodes $cluster_nodes 1

test {cluster info command} {
set ret [$r1 cluster info]
Expand Down
4 changes: 2 additions & 2 deletions tests/tcl/tests/unit/command.tcl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
start_server {tags {"command"}} {
test {kvrocks has 159 commands currently} {
test {kvrocks has 160 commands currently} {
r command count
} {159}
} {160}

test {acquire GET command info by COMMAND INFO} {
set e [lindex [r command info get] 0]
Expand Down
4 changes: 2 additions & 2 deletions tools/try_cluster/try_cluster.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ then
sed -i.bak "s|dir.*|dir "node_${PORT}"|g" ${conf_file} && rm ${conf_file}.bak
$BIN_PATH/kvrocks -c ${conf_file}
sleep 0.5
redis-cli -h 127.0.0.1 -p $PORT cluster setnodeid ${node_id[$index]}
redis-cli -h 127.0.0.1 -p $PORT cluster setnodes "${cluster_nodes}" 1
redis-cli -h 127.0.0.1 -p $PORT clusterx setnodeid ${node_id[$index]}
redis-cli -h 127.0.0.1 -p $PORT clusterx setnodes "${cluster_nodes}" 1
if [ `expr $index % 2` == 1 ]
then
redis-cli -h 127.0.0.1 -p $PORT slaveof 127.0.0.1 $((PORT-1))
Expand Down