in src/cluster/cluster.cc [735:850]
Status Cluster::parseClusterNodes(const std::string &nodes_str, ClusterNodes *nodes,
std::unordered_map<int, std::string> *slots_nodes) {
std::vector<std::string> nodes_info = util::Split(nodes_str, "\n");
if (nodes_info.empty()) {
return {Status::ClusterInvalidInfo, errInvalidClusterNodeInfo};
}
nodes->clear();
// Parse all nodes
for (const auto &node_str : nodes_info) {
std::vector<std::string> fields = util::Split(node_str, " ");
if (fields.size() < 5) {
return {Status::ClusterInvalidInfo, errInvalidClusterNodeInfo};
}
// 1) node id
if (fields[0].size() != kClusterNodeIdLen) {
return {Status::ClusterInvalidInfo, errInvalidNodeID};
}
std::string id = fields[0];
// 2) host, TODO(@shooterit): check host is valid
std::string host = fields[1];
// 3) port
auto parse_result = ParseInt<uint16_t>(fields[2], 10);
if (!parse_result) {
return {Status::ClusterInvalidInfo, "Invalid cluster node port"};
}
int port = *parse_result;
// 4) role
int role = 0;
if (util::EqualICase(fields[3], "master")) {
role = kClusterMaster;
} else if (util::EqualICase(fields[3], "slave") || util::EqualICase(fields[3], "replica")) {
role = kClusterSlave;
} else {
return {Status::ClusterInvalidInfo, "Invalid cluster node role"};
}
// 5) master id
std::string master_id = fields[4];
if ((role == kClusterMaster && master_id != "-") ||
(role == kClusterSlave && master_id.size() != kClusterNodeIdLen)) {
return {Status::ClusterInvalidInfo, errInvalidNodeID};
}
std::bitset<kClusterSlots> slots;
if (role == kClusterSlave) {
if (fields.size() != 5) {
return {Status::ClusterInvalidInfo, errInvalidClusterNodeInfo};
} else {
// Create slave node
(*nodes)[id] = std::make_shared<ClusterNode>(id, host, port, role, master_id, slots);
continue;
}
}
// 6) slot info
auto valid_range = NumericRange<int>{0, kClusterSlots - 1};
const std::regex node_id_regex(R"(\b[a-fA-F0-9]{40}\b)");
for (unsigned i = 5; i < fields.size(); i++) {
std::vector<std::string> ranges = util::Split(fields[i], "-");
if (ranges.size() == 1) {
if (std::regex_match(fields[i], node_id_regex)) {
return {Status::ClusterInvalidInfo, "Invalid nodes definition: Missing newline between node entries."};
}
auto parse_start = ParseInt<int>(ranges[0], valid_range, 10);
if (!parse_start) {
return {Status::ClusterInvalidInfo, errSlotOutOfRange};
}
int start = *parse_start;
slots.set(start, true);
if (role == kClusterMaster) {
if (slots_nodes->find(start) != slots_nodes->end()) {
return {Status::ClusterInvalidInfo, errSlotOverlapped};
} else {
(*slots_nodes)[start] = id;
}
}
} else if (ranges.size() == 2) {
auto parse_start = ParseInt<int>(ranges[0], valid_range, 10);
auto parse_stop = ParseInt<int>(ranges[1], valid_range, 10);
if (!parse_start || !parse_stop || *parse_start >= *parse_stop) {
return {Status::ClusterInvalidInfo, errSlotOutOfRange};
}
int start = *parse_start;
int stop = *parse_stop;
for (int j = start; j <= stop; j++) {
slots.set(j, true);
if (role == kClusterMaster) {
if (slots_nodes->find(j) != slots_nodes->end()) {
return {Status::ClusterInvalidInfo, errSlotOverlapped};
} else {
(*slots_nodes)[j] = id;
}
}
}
} else {
return {Status::ClusterInvalidInfo, errSlotOutOfRange};
}
}
// Create master node
(*nodes)[id] = std::make_shared<ClusterNode>(id, host, port, role, master_id, slots);
}
return Status::OK();
}