mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-16 01:40:52 +08:00
691 lines
17 KiB
C++
691 lines
17 KiB
C++
#include "stdafx.h"
|
|
#include "redis_status.h"
|
|
#include "redis_util.h"
|
|
#include "redis_builder.h"
|
|
|
|
#define MAX_SLOTS 16384
|
|
|
|
redis_builder::redis_builder(const char* passwd /* = NULL */, int meet_wait /* = 100 */)
|
|
: meet_wait_(meet_wait)
|
|
, last_check_(0)
|
|
{
|
|
if (passwd && *passwd) {
|
|
passwd_ = passwd;
|
|
}
|
|
}
|
|
|
|
redis_builder::~redis_builder(void)
|
|
{
|
|
redis_util::free_nodes(masters_);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
bool redis_builder::add_node(const char* addr,
|
|
const char* new_node_addr, bool slave)
|
|
{
|
|
acl::redis_client client(new_node_addr);
|
|
client.set_password(passwd_);
|
|
acl::redis redis(&client);
|
|
|
|
acl::string buf(addr);
|
|
const std::vector<acl::string>& tokens = buf.split2(":");
|
|
if (tokens.size() != 2) {
|
|
printf("%s: invalid addr: %s\r\n", __FUNCTION__, addr);
|
|
return false;
|
|
}
|
|
|
|
// CLUSTER MEET master node
|
|
if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str()))) {
|
|
printf("%s: cluster meet %s %s error: %s\r\n", __FUNCTION__,
|
|
tokens[0].c_str(), tokens[1].c_str(),
|
|
redis.result_error());
|
|
return false;
|
|
}
|
|
|
|
// wait for the master recognizing the slave
|
|
while (true) {
|
|
if (cluster_meeting(redis, addr)) {
|
|
break;
|
|
}
|
|
acl_doze(meet_wait_);
|
|
}
|
|
|
|
if (!slave) {
|
|
return true;
|
|
}
|
|
|
|
acl::string node_id;
|
|
if (!redis_util::get_node_id(addr, node_id, passwd_)) {
|
|
printf("%s: can't get master(%s)'s node_id\r\n",
|
|
__FUNCTION__, addr);
|
|
return false;
|
|
}
|
|
|
|
if (!redis.cluster_replicate(node_id.c_str())) {
|
|
printf("%s: cluster replicate id: %s, error: %s, "
|
|
"master_addr: %s, slave_addr: %s\r\n",
|
|
__FUNCTION__, node_id.c_str(), redis.result_error(),
|
|
addr, new_node_addr);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool redis_builder::del_node(const char* addr, const char* node_id)
|
|
{
|
|
acl::redis_client client(addr);
|
|
client.set_password(passwd_);
|
|
acl::redis redis(&client);
|
|
if (!redis.cluster_forget(node_id)) {
|
|
printf("%s: del node: %s error: %s, addr: %s\r\n",
|
|
__FUNCTION__, node_id, redis.result_error(), addr);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
bool redis_builder::build(const char* conf, size_t replicas, bool just_display)
|
|
{
|
|
if (!load(conf, replicas)) {
|
|
return false;
|
|
}
|
|
|
|
if (masters_.empty()) {
|
|
printf("%s: no nodes available\r\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
printf("===================================================\r\n");
|
|
|
|
redis_util::print_nodes(0, masters_);
|
|
|
|
if (just_display) {
|
|
return true;
|
|
}
|
|
|
|
return build_cluster();
|
|
}
|
|
|
|
bool redis_builder::load(const char* conf, size_t replicas)
|
|
{
|
|
acl::string buf;
|
|
|
|
// load xml information from local file
|
|
if (!acl::ifstream::load(conf, &buf)) {
|
|
printf("%s: load configure error: %s, file: %s\r\n",
|
|
__FUNCTION__, acl::last_serror(), conf);
|
|
return false;
|
|
}
|
|
/* <xml>
|
|
* <node addr="ip:port">
|
|
* <node addr="ip:port" />
|
|
* <node addr="ip:port" />
|
|
* ...
|
|
* </node>
|
|
* <node addr="ip:port">
|
|
* <node addr="ip:port" />
|
|
* <node addr="ip:port" />
|
|
* ...
|
|
* </node>
|
|
* ...
|
|
* </xml>
|
|
*/
|
|
// parse the xml data
|
|
acl::xml1 xml(buf.c_str());
|
|
|
|
if (replicas > 0) {
|
|
return create_cluster(xml, replicas);
|
|
} else {
|
|
return create_cluster(xml);
|
|
}
|
|
}
|
|
|
|
bool redis_builder::create_cluster(acl::xml& xml, size_t replicas)
|
|
{
|
|
const char* tag = "node";
|
|
const std::vector<acl::xml_node*>& nodes = xml.getElementsByTagName(tag);
|
|
|
|
if (nodes.empty()) {
|
|
printf("%s: nodes null\r\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
std::vector<acl::redis_node*> redis_nodes;
|
|
|
|
std::vector<acl::xml_node*>::const_iterator cit;
|
|
for (cit = nodes.begin(); cit != nodes.end(); ++cit) {
|
|
acl::redis_node* n = create_node(**cit);
|
|
if (n != NULL) {
|
|
redis_nodes.push_back(n);
|
|
}
|
|
}
|
|
|
|
size_t mod = redis_nodes.size() % (replicas + 1);
|
|
if (replicas > 0 && mod != 0) {
|
|
printf("%s: nodes' size(%d) %% replicas + 1(%d) is %d != 0\r\n",
|
|
__FUNCTION__, (int) redis_nodes.size(),
|
|
(int) replicas + 1, (int) mod);
|
|
std::vector<acl::redis_node*>::iterator it;
|
|
for (it = redis_nodes.begin(); it != redis_nodes.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::map<acl::string, size_t> master_addrs;
|
|
std::map<acl::string, size_t> all_addrs;
|
|
acl::redis_node* master, *slave;
|
|
acl::string ip;
|
|
while (true) {
|
|
master = peek_master(redis_nodes, master_addrs);
|
|
if (master == NULL) {
|
|
break;
|
|
}
|
|
masters_.push_back(master);
|
|
|
|
assert(redis_util::get_ip(master->get_addr(), ip));
|
|
all_addrs[ip]++;
|
|
|
|
for (size_t i = 0; i < replicas; i++) {
|
|
slave = peek_slave(master->get_addr(),
|
|
redis_nodes, all_addrs);
|
|
if (slave != NULL) {
|
|
master->add_slave(slave);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
acl::redis_node* redis_builder::peek_master(std::vector<acl::redis_node*>& nodes,
|
|
std::map<acl::string, size_t>& addrs)
|
|
{
|
|
// at first, find the addr not be as a master
|
|
acl::string ip;
|
|
std::vector<acl::redis_node*>::iterator it, next;
|
|
for (it = nodes.begin(), next = it; it != nodes.end(); it = next) {
|
|
++next;
|
|
const char* addr = (*it)->get_addr();
|
|
if (!redis_util::get_ip(addr, ip)) {
|
|
printf("%s: delete invalid addr: %s\r\n",
|
|
__FUNCTION__, addr);
|
|
delete *it;
|
|
nodes.erase(it);
|
|
continue;
|
|
}
|
|
if (addrs.find(ip) != addrs.end()) {
|
|
continue;
|
|
}
|
|
acl::redis_node* master = *it;
|
|
addrs[ip]++;
|
|
nodes.erase(it);
|
|
return master;
|
|
}
|
|
|
|
// then, find the addr in which masters are the least
|
|
size_t n = 100000;
|
|
acl::string min_addr;
|
|
std::vector<acl::redis_node*>::iterator min_node = nodes.end();
|
|
std::map<acl::string, size_t>::iterator iter_addr;
|
|
for (it = nodes.begin(); it != nodes.end(); ++it) {
|
|
const char* addr = (*it)->get_addr();
|
|
assert(redis_util::get_ip(addr, ip));
|
|
iter_addr = addrs.find(ip);
|
|
assert(iter_addr != addrs.end());
|
|
if (iter_addr->second <= n) {
|
|
n = iter_addr->second;
|
|
min_addr = ip;
|
|
min_node = it;
|
|
}
|
|
}
|
|
|
|
if (min_addr.empty() || min_node == nodes.end()) {
|
|
return NULL;
|
|
}
|
|
|
|
addrs[min_addr]++;
|
|
acl::redis_node* master = *min_node;
|
|
nodes.erase(min_node);
|
|
return master;
|
|
}
|
|
|
|
acl::redis_node* redis_builder::peek_slave(const char* master_addr,
|
|
std::vector<acl::redis_node*>& nodes,
|
|
std::map<acl::string, size_t>& addrs)
|
|
{
|
|
acl::string master_ip;
|
|
assert(redis_util::get_ip(master_addr, master_ip));
|
|
|
|
acl::string ip;
|
|
std::vector<acl::redis_node*> slaves;
|
|
std::vector<acl::redis_node*>::iterator it, next;
|
|
for (it = nodes.begin(), next = it; it != nodes.end(); it = next) {
|
|
++next;
|
|
const char* addr = (*it)->get_addr();
|
|
if (!redis_util::get_ip(addr, ip)) {
|
|
printf("%s: delete invalid addr: %s\r\n",
|
|
__FUNCTION__, addr);
|
|
delete *it;
|
|
nodes.erase(it);
|
|
continue;
|
|
}
|
|
if (ip == master_ip) {
|
|
continue;
|
|
}
|
|
slaves.push_back(*it);
|
|
}
|
|
|
|
if (slaves.empty()) {
|
|
//printf("not found valid slave node for master: %s\r\n",
|
|
// master_addr);
|
|
for (it = nodes.begin(); it != nodes.end(); ++it)
|
|
slaves.push_back(*it);
|
|
}
|
|
|
|
size_t n = 100000;
|
|
acl::string min_addr;
|
|
acl::redis_node* slave = NULL;
|
|
|
|
std::map<acl::string, size_t>::iterator iter_addr;
|
|
for (it = slaves.begin(); it != slaves.end(); ++it) {
|
|
const char* addr = (*it)->get_addr();
|
|
assert(redis_util::get_ip(addr, ip));
|
|
iter_addr = addrs.find(ip);
|
|
if (iter_addr == addrs.end()) {
|
|
min_addr = ip;
|
|
slave = *it;
|
|
break;
|
|
}
|
|
if (iter_addr->second <= n) {
|
|
n = iter_addr->second;
|
|
min_addr = ip;
|
|
slave = *it;
|
|
}
|
|
}
|
|
|
|
if (min_addr.empty() || slave == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
addrs[min_addr]++;
|
|
bool found = false;
|
|
|
|
for (it = nodes.begin(); it != nodes.end(); ++it) {
|
|
if (*it == slave) {
|
|
nodes.erase(it);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(found);
|
|
return slave;
|
|
}
|
|
|
|
bool redis_builder::create_cluster(acl::xml& xml)
|
|
{
|
|
// get the master redis nodes
|
|
const char* tags = "xml/node";
|
|
const std::vector<acl::xml_node*>& nodes = xml.getElementsByTags(tags);
|
|
|
|
if (nodes.empty()) {
|
|
printf("%s: nodes null\r\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
// iterate all the master nodes including their's slaves
|
|
std::vector<acl::xml_node*>::const_iterator cit;
|
|
for (cit = nodes.begin(); cit != nodes.end(); ++cit) {
|
|
acl::redis_node* master = create_master(**cit);
|
|
if (master != NULL) {
|
|
masters_.push_back(master);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
acl::redis_node* redis_builder::create_master(acl::xml_node& node)
|
|
{
|
|
const char* addr = node.attr_value("addr");
|
|
if (addr == NULL || *addr == 0) {
|
|
printf("%s: no addr in the master node\r\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
//printf(">>> master: %s\r\n", addr);
|
|
|
|
acl::redis_node* master = new acl::redis_node;
|
|
master->set_addr(addr);
|
|
|
|
// iterate all the slaves of the master, and add them to master
|
|
acl::xml_node* child = node.first_child();
|
|
while (child != NULL) {
|
|
acl::redis_node* slave = create_node(*child);
|
|
if (slave != NULL) {
|
|
master->add_slave(slave);
|
|
}
|
|
child = node.next_child();
|
|
}
|
|
|
|
//const std::vector<acl::redis_node*>* slaves = master->get_slaves();
|
|
//printf(">>>slave's size: %d\r\n", (int) slaves->size());
|
|
return master;
|
|
}
|
|
|
|
acl::redis_node* redis_builder::create_node(acl::xml_node& node)
|
|
{
|
|
const char* addr = node.attr_value("addr");
|
|
if (addr == NULL || *addr == 0) {
|
|
printf("%s: no addr in the node\r\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
//printf("%s: node: %s\r\n", __FUNCTION__, addr);
|
|
acl::redis_node* slave = new acl::redis_node;
|
|
slave->set_addr(addr);
|
|
return slave;
|
|
}
|
|
|
|
bool redis_builder::build_cluster()
|
|
{
|
|
if (masters_.empty()) {
|
|
printf("%s: no master available!\r\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
size_t range = MAX_SLOTS / masters_.size();
|
|
size_t begin = 0, end = MAX_SLOTS % masters_.size() + range -1;
|
|
|
|
// build every master node, and connect all of its slaves.
|
|
|
|
std::vector<acl::redis_node*>::iterator it;
|
|
for (it = masters_.begin(); it != masters_.end(); ++it) {
|
|
if (it != masters_.begin()) {
|
|
printf("----------------------------------------\r\n");
|
|
}
|
|
|
|
(*it)->add_slot_range(begin, end);
|
|
if (!build_master(**it)) {
|
|
return false;
|
|
}
|
|
begin = end + 1;
|
|
end = end + range;
|
|
}
|
|
|
|
it = masters_.begin();
|
|
acl::redis_client client((*it)->get_addr());
|
|
client.set_password(passwd_);
|
|
acl::redis master(&client);
|
|
|
|
// let one master to connect all other master nodes
|
|
|
|
printf("===================================================\r\n");
|
|
printf("Meeting all masters and slaves ...\r\n");
|
|
|
|
std::vector<acl::redis_node*> all_slaves;
|
|
std::vector<acl::redis_node*>::const_iterator cit;
|
|
|
|
for (++it; it != masters_.end(); ++it) {
|
|
if (!cluster_meet(master, **it)) {
|
|
return false;
|
|
}
|
|
const std::vector<acl::redis_node*>* slaves = (*it)->get_slaves();
|
|
for (cit = slaves->begin(); cit != slaves->end(); ++cit) {
|
|
all_slaves.push_back(*cit);
|
|
}
|
|
}
|
|
|
|
while (true) {
|
|
int nwait = 0;
|
|
for (cit = all_slaves.begin(); cit != all_slaves.end(); ++cit) {
|
|
if ((*cit)->is_connected()) {
|
|
continue;
|
|
}
|
|
if (!cluster_meeting(master, (*cit)->get_addr())) {
|
|
nwait++;
|
|
} else {
|
|
(*cit)->set_connected(true);
|
|
}
|
|
}
|
|
if (nwait == 0) {
|
|
break;
|
|
}
|
|
acl_doze(meet_wait_);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
printf("===================================================\r\n");
|
|
printf("All nodes of cluster:\r\n");
|
|
|
|
const std::map<acl::string, acl::redis_node*>* nodes;
|
|
if ((nodes = master.cluster_nodes())== NULL) {
|
|
printf("%s: can't get cluster nodes, addr: %s\r\n",
|
|
__FUNCTION__, client.get_stream()->get_peer(true));
|
|
return false;
|
|
}
|
|
|
|
#ifdef ACL_UNIX
|
|
redis_status::show_nodes_tree(*nodes);
|
|
#else
|
|
redis_status::show_nodes(nodes);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool redis_builder::cluster_meet(acl::redis& redis, const acl::redis_node& node)
|
|
{
|
|
acl::string buf(node.get_addr());
|
|
const std::vector<acl::string>& tokens = buf.split2(":");
|
|
if (tokens.size() != 2) {
|
|
printf("%s: invalid addr: %s\r\n",
|
|
__FUNCTION__, node.get_addr());
|
|
return false;
|
|
}
|
|
|
|
if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str()))) {
|
|
printf("%s: cluster meet %s %s error: %s\r\n",
|
|
__FUNCTION__, tokens[0].c_str(), tokens[1].c_str(),
|
|
redis.result_error());
|
|
return false;
|
|
}
|
|
|
|
while (true) {
|
|
if (cluster_meeting(redis, node.get_addr())) {
|
|
break;
|
|
}
|
|
acl_doze(meet_wait_);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
bool redis_builder::build_master(acl::redis_node& master)
|
|
{
|
|
acl::redis_client client(master.get_addr());
|
|
client.set_password(passwd_);
|
|
acl::redis redis(&client);
|
|
|
|
if (!master_set_slots(redis, master)) {
|
|
return false;
|
|
}
|
|
|
|
acl::string id;
|
|
if (!redis_util::get_node_id(redis, id)) {
|
|
printf("%s: null id, master addr: %s\r\n",
|
|
__FUNCTION__, master.get_addr());
|
|
return false;
|
|
}
|
|
master.set_id(id.c_str());
|
|
|
|
printf("Build master: %s, %s\r\n", id.c_str(), master.get_addr());
|
|
|
|
const std::vector<acl::redis_node*>* slaves = master.get_slaves();
|
|
std::vector<acl::redis_node*>::const_iterator cit;
|
|
for (cit = slaves->begin(); cit != slaves->end(); ++cit) {
|
|
if (!add_slave(master, **cit)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
printf("Build master OK\r\n");
|
|
return true;
|
|
}
|
|
|
|
bool redis_builder::add_slave(const acl::redis_node& master,
|
|
const acl::redis_node& slave)
|
|
{
|
|
acl::redis_client client(slave.get_addr());
|
|
client.set_password(passwd_);
|
|
acl::redis redis(&client);
|
|
const char* master_addr = master.get_addr();
|
|
if (master_addr == NULL || *master_addr == 0) {
|
|
printf("%s: master addr null\r\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
acl::string buf(master_addr);
|
|
const std::vector<acl::string>& tokens = buf.split2(":");
|
|
if (tokens.size() != 2) {
|
|
printf("%s: invalid master_addr: %s\r\n",
|
|
__FUNCTION__, master_addr);
|
|
return false;
|
|
}
|
|
|
|
// CLUSTER MEET master node
|
|
if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str()))) {
|
|
printf("%s: cluster meet %s %s error: %s\r\n",
|
|
__FUNCTION__, tokens[0].c_str(), tokens[1].c_str(),
|
|
redis.result_error());
|
|
return false;
|
|
}
|
|
|
|
// wait for the master recognizing the slave
|
|
while (true) {
|
|
if (cluster_meeting(redis, master_addr)) {
|
|
break;
|
|
}
|
|
acl_doze(meet_wait_);
|
|
}
|
|
|
|
if (!redis.cluster_replicate(master.get_id())) {
|
|
printf("%s: cluster replicate id: %s, error: %s, addr: %s\r\n",
|
|
__FUNCTION__, master.get_id(), redis.result_error(),
|
|
slave.get_addr());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
acl::redis_node* redis_builder::find_slave(const acl::redis_node* node,
|
|
const char* addr, size_t& nslaves)
|
|
{
|
|
const std::vector<acl::redis_node*>* slaves = node->get_slaves();
|
|
nslaves += slaves->size();
|
|
std::vector<acl::redis_node*>::const_iterator cit;
|
|
for (cit = slaves->begin(); cit != slaves->end(); ++cit) {
|
|
if (strcasecmp((*cit)->get_addr(), addr) == 0) {
|
|
return *cit;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool redis_builder::cluster_meeting(acl::redis& redis, const char* addr)
|
|
{
|
|
acl::socket_stream* conn = redis.get_client()->get_stream();
|
|
if (conn == NULL) {
|
|
printf("%s: connection disconnected!\r\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
const char* myaddr = conn->get_peer(true);
|
|
const std::map<acl::string, acl::redis_node*>* nodes;
|
|
if ((nodes = redis.cluster_nodes())== NULL) {
|
|
printf("%s: can't get cluster nodes, addr: %s\r\n",
|
|
__FUNCTION__, myaddr);
|
|
return false;
|
|
}
|
|
|
|
size_t nslaves = 0;
|
|
acl::redis_node* node = NULL;
|
|
std::map<acl::string, acl::redis_node*>::const_iterator cit;
|
|
for (cit = nodes->begin(); cit != nodes->end(); ++cit) {
|
|
if (strcasecmp(cit->second->get_addr(), addr) == 0) {
|
|
node = cit->second;
|
|
break;
|
|
}
|
|
|
|
node = find_slave(cit->second, addr, nslaves);
|
|
if (node != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (node == NULL) {
|
|
//show_nodes(nodes);
|
|
|
|
time_t now = time(NULL);
|
|
if (now - last_check_ >= 1) {
|
|
printf("%s waiting for %s, nodes: %d, %d\r\n", myaddr,
|
|
addr, (int) nodes->size(), (int) nslaves);
|
|
last_check_ = now;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const char* type = node->get_type();
|
|
if (strcasecmp(type, "slave") && strcasecmp(type, "master")) {
|
|
time_t now = time(NULL);
|
|
if (now - last_check_ >= 1) {
|
|
printf("%s meeting with %s, status: %s\r\n",
|
|
myaddr, addr, type);
|
|
last_check_ = now;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
printf("%s meet with %s OK, status: %s\r\n", myaddr, addr, type);
|
|
return true;
|
|
}
|
|
|
|
bool redis_builder::master_set_slots(acl::redis& redis,
|
|
acl::redis_node& master)
|
|
{
|
|
const std::vector<std::pair<size_t, size_t> >& slots
|
|
= master.get_slots();
|
|
if (slots.size() != 1) {
|
|
printf("%s: invalid slots's size: %d, addr: %s\r\n",
|
|
__FUNCTION__, (int) slots.size(), master.get_addr());
|
|
return false;
|
|
}
|
|
const std::pair<size_t, size_t> slot = slots[0];
|
|
size_t min_slot = slot.first, max_slot = slot.second;
|
|
size_t n = max_slot - min_slot + 1;
|
|
int *slot_array = (int*) malloc(sizeof(int) * n);
|
|
for (size_t i = 0; i < n; i++) {
|
|
slot_array[i] = (int)min_slot;
|
|
min_slot++;
|
|
}
|
|
|
|
if (!redis.cluster_addslots(slot_array, n)) {
|
|
printf("%s: addslots error: %s, addr: %s, slots: %d, %d\r\n",
|
|
__FUNCTION__, redis.result_error(), master.get_addr(),
|
|
(int) min_slot, (int) max_slot);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|