add a redis tool for redis cluster

This commit is contained in:
ubuntu14 2015-04-19 07:15:30 -07:00
parent 82fb1f34ad
commit 0140b69dd1
22 changed files with 1631 additions and 90 deletions

View File

@ -458,6 +458,20 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redis_client_cluster", "lib
{FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "redis_tools", "redis_tools", "{C8535C82-3DCB-472E-9E8F-DA769D9375B1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redis_builder", "app\redis_tools\redis_builder\redis_builder_vc2012.vcxproj", "{D90DCF51-E219-4BD8-A032-076335675F58}"
ProjectSection(ProjectDependencies) = postProject
{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}
{B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}
{FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{C65ABD0D-658D-4FE6-8221-4400B8387F27}"
ProjectSection(SolutionItems) = preProject
changes.txt = changes.txt
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -1537,6 +1551,21 @@ Global
{E3280617-6D0D-4639-9014-31BCD4ADFADC}.Template|Win32.ActiveCfg = DebugDll|Win32
{E3280617-6D0D-4639-9014-31BCD4ADFADC}.Template|Win32.Build.0 = DebugDll|Win32
{E3280617-6D0D-4639-9014-31BCD4ADFADC}.Template|x64.ActiveCfg = DebugDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Debug|Win32.ActiveCfg = Debug|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Debug|Win32.Build.0 = Debug|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Debug|x64.ActiveCfg = Debug|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.DebugDll|Win32.ActiveCfg = DebugDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.DebugDll|Win32.Build.0 = DebugDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.DebugDll|x64.ActiveCfg = DebugDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Release|Win32.ActiveCfg = Release|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Release|Win32.Build.0 = Release|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Release|x64.ActiveCfg = Release|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Releasedll|Win32.Build.0 = ReleaseDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Releasedll|x64.ActiveCfg = ReleaseDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Template|Win32.ActiveCfg = DebugDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Template|Win32.Build.0 = DebugDll|Win32
{D90DCF51-E219-4BD8-A032-076335675F58}.Template|x64.ActiveCfg = DebugDll|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1602,6 +1631,7 @@ Global
{4B58485B-D846-4485-9C5E-7F2304D71701} = {267F658E-44AF-4080-8577-EFCE99A5E030}
{D232833B-57A9-4167-B37C-A4594953F93D} = {3CC8D45A-8E3F-4F5C-A7DF-4D8027E4EA9C}
{84376B60-FF20-4FD0-967E-C568FC2FBC53} = {3CC8D45A-8E3F-4F5C-A7DF-4D8027E4EA9C}
{C8535C82-3DCB-472E-9E8F-DA769D9375B1} = {3CC8D45A-8E3F-4F5C-A7DF-4D8027E4EA9C}
{3C74E826-5E72-48A1-9DFD-777F4A7C9E1F} = {D232833B-57A9-4167-B37C-A4594953F93D}
{B59C7CB6-5708-4522-B833-CEB160AA4817} = {D232833B-57A9-4167-B37C-A4594953F93D}
{2DABFAD1-114B-4F96-9185-DC0C56A3662D} = {C799E376-2F01-4877-AF18-7F3CC8B95792}
@ -1623,5 +1653,6 @@ Global
{97BC2502-5B1C-44B4-8809-83A268306FA1} = {14531A45-383C-4CCF-870B-B5C867A314F2}
{5EA23ADB-6481-4CA1-9C31-7D92036DFD47} = {14531A45-383C-4CCF-870B-B5C867A314F2}
{E3280617-6D0D-4639-9014-31BCD4ADFADC} = {14531A45-383C-4CCF-870B-B5C867A314F2}
{D90DCF51-E219-4BD8-A032-076335675F58} = {C8535C82-3DCB-472E-9E8F-DA769D9375B1}
EndGlobalSection
EndGlobal

6
app/redis_tools/Makefile Normal file
View File

@ -0,0 +1,6 @@
all:
@(cd redis_builder; make)
clean:
@(cd redis_builder; make clean)

View File

@ -0,0 +1,5 @@
include ./Makefile.in
ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD)
EXTLIBS += -L/usr/local/lib -liconv
endif
PROG = redis_builder

View File

@ -0,0 +1,113 @@
CC = g++
CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \
-Wno-long-long \
-Wpointer-arith -Werror -Wshadow -O3 \
-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO
###########################################################
#Check system:
# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX
SYSLIB = -lpthread -lcrypt -lz
CHECKSYSRES = @echo "Unknow system type!";exit 1
UNIXNAME = $(shell uname -sm)
OSTYPE = $(shell uname -p)
RPATH = linux64
ifeq ($(CC),)
CC = gcc
endif
# For FreeBSD
ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD)
ifeq ($(findstring gcc, $(CC)), gcc)
CFLAGS += -Wstrict-prototypes
endif
CFLAGS += -DFREEBSD -D_REENTRANT
SYSLIB = -lcrypt -lpthread -lz
RPATH = freebsd
endif
#Path for Linux
ifeq ($(findstring Linux, $(UNIXNAME)), Linux)
ifeq ($CC, "gcc")
CFLAGS += -Wstrict-prototypes
endif
ifeq ($(findstring i686, $(OSTYPE)), i686)
RPATH = linux32
endif
ifeq ($(findstring x86_64, $(OSTYPE)), x86_64)
RPATH = linux64
endif
CFLAGS += -DLINUX2 -D_REENTRANT
endif
#Path for SunOS
ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS)
ifeq ($(findstring 86, $(UNIXNAME)), 86)
SYSLIB += -lsocket -lnsl -lrt
endif
ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u)
SYSLIB += -lsocket -lnsl -lrt
endif
ifeq ($CC, "gcc")
CFLAGS += -Wstrict-prototypes
endif
CFLAGS += -DSUNOS5 -D_REENTRANT
RPATH = sunos_x86
endif
#Path for HP-UX
ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX)
ifeq ($CC, "gcc")
CFLAGS += -Wstrict-prototypes
endif
CFLAGS += -DHP_UX -DHPUX11
PLAT_NAME=hp-ux
endif
#Find system type.
ifneq ($(SYSPATH),)
CHECKSYSRES = @echo "System is $(shell uname -sm)"
endif
###########################################################
CFLAGS += -I../../../lib_acl/include -I../../../lib_protocol/include \
-I../../../lib_acl_cpp/include -I.
EXTLIBS =
LDFLAGS = -L../../../lib_acl_cpp/lib -l_acl_cpp \
-L../../../lib_protocol/lib -l_protocol \
-L../../../lib_acl/lib -l_acl \
$(EXTLIBS) $(SYSLIB) -rdynamic
COMPILE = $(CC) $(CFLAGS)
LINK = $(CC) $(OBJ) $(LDFLAGS)
###########################################################
OBJ_PATH = .
#Project's objs
SRC = $(wildcard *.cpp) $(wildcard pull_mode/*.cpp) $(wildcard push_mode/*.cpp)
OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC)))
$(OBJ_PATH)/%.o: %.cpp
$(COMPILE) $< -o $@
$(OBJ_PATH)/%.o: pull_mode/%.cpp
$(COMPILE) $< -o $@
$(OBJ_PATH)/%.o: push_mode/%.cpp
$(COMPILE) $< -o $@
.PHONY = all clean
all: RM $(OBJ)
$(LINK) -o $(PROG)
@echo ""
@echo "All ok! Output:$(PROG)"
@echo ""
RM:
rm -f $(PROG)
clean:
rm -f $(PROG)
rm -f $(OBJ)
install:
cp $(PROG) ../../../dist/master/libexec/$(RPATH)/
cp $(PROG).cf ../../../dist/master/conf/service/
###########################################################

View File

@ -0,0 +1,47 @@
A redis tool for redis cluster, which can help to build a new redis cluster,
add one new redis node to the existing one or cluster, show the information
of the redis cluster about nodes and slots. Below are the using method of
the tool:
1) show help information:
./redis_build -h
usage: redis_builder.exe -h[help]
-s redis_addr[ip:port]
-a cmd[nodes|slots|create|add_node|del_node|node_id]
-N new_node[ip:port]
-S [add node as slave]
-f configure_file
for samples:
./redis_builder -s 127.0.0.1:6379 -a create -f cluster.xml
./redis_builder -s 127.0.0.1:6379 -a nodes
./redis_builder -s 127.0.0.1:6379 -a slots
./redis_builder -s 127.0.0.1:6379 -a del_node -I node_id
./redis_builder -s 127.0.0.1:6379 -a node_id
./redis_builder -s 127.0.0.1:6379 -a add_node -N 127.0.0.1:6380 -S
2) build a new redis cluster after all of the redis nodes started:
./redis_builder -a create -f cluster.xml
the cluster.xml's content just like:
<?xml version="1.0"?>
<xml>
<node addr = "192.168.136.172:16380">
<node addr = "192.168.136.172:16381" />
<node addr = "192.168.136.172:16382" />
</node>
<node addr = "192.168.136.172:16383">
<node addr = "192.168.136.172:16384" />
<node addr = "192.168.136.172:16385" />
</node>
<node addr = "192.168.136.172:16386">
<node addr = "192.168.136.172:16387" />
<node addr = "192.168.136.172:16388" />
</node>
</xml>
3) add a new slave redis node to the master node:
./redis_builder -s 127.0.0.1:6379 -a add_node -S -N 127.0.0.1:6380
'-s' specifys the existing master node,
'-S' specifys the new redis node added was as a slave node,
'-N' specify the new redis addr to be added
'-a' specify the cmd of this tool

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<xml>
<node addr = "192.168.136.172:16380">
<node addr = "192.168.136.172:16381" />
<node addr = "192.168.136.172:16382" />
</node>
<node addr = "192.168.136.172:16383">
<node addr = "192.168.136.172:16384" />
<node addr = "192.168.136.172:16385" />
</node>
<node addr = "192.168.136.172:16386">
<node addr = "192.168.136.172:16387" />
<node addr = "192.168.136.172:16388" />
</node>
</xml>

View File

@ -0,0 +1,146 @@
#include "stdafx.h"
#include "redis_status.h"
#include "redis_builder.h"
//////////////////////////////////////////////////////////////////////////
static void usage(const char* procname)
{
printf("usage: %s -h[help]\r\n"
"-s redis_addr[ip:port]\r\n"
"-a cmd[nodes|slots|create|add_node|del_node|node_id]\r\n"
"-N new_node[ip:port]\r\n"
"-S [add node as slave]\r\n"
"-f configure_file\r\n",
procname);
printf("\r\nfor samples:\r\n"
"%s -s 127.0.0.1:6379 -a create -f cluster.xml\r\n"
"%s -s 127.0.0.1:6379 -a nodes\r\n"
"%s -s 127.0.0.1:6379 -a slots\r\n"
"%s -s 127.0.0.1:6379 -a del_node -I node_id\r\n"
"%s -s 127.0.0.1:6379 -a node_id\r\n"
"%s -s 127.0.0.1:6379 -a add_node -N 127.0.0.1:6380 -S\r\n",
procname, procname, procname, procname, procname, procname);
}
int main(int argc, char* argv[])
{
// initiation the acl library
acl::acl_cpp_init();
acl::log::stdout_open(true);
int ch;
bool add_slave = false;
acl::string addr, cmd, conf, new_addr, node_id;
while ((ch = getopt(argc, argv, "hs:a:f:N:SI:")) > 0)
{
switch (ch)
{
case 'h':
usage(argv[0]);
return 0;
case 's':
addr = optarg;
break;
case 'a':
cmd = optarg;
break;
case 'f':
conf = optarg;
break;
case 'N':
new_addr = optarg;
break;
case 'S':
add_slave = true;
break;
case 'I':
node_id = optarg;
break;
default:
break;
}
}
int conn_timeout = 10, rw_timeout = 120;
acl::redis_client client(addr, conn_timeout, rw_timeout);
acl::redis redis(&client);
if (cmd == "nodes")
{
if (addr.empty())
{
printf("usage: %s -s ip:port -a nodes\r\n", argv[0]);
goto END;
}
redis_status status(addr, conn_timeout, rw_timeout);
status.show_nodes(redis);
}
else if (cmd == "slots")
{
if (addr.empty())
{
printf("usage: %s -a ip:port -a slots\r\n", argv[0]);
goto END;
}
redis_status status(addr, conn_timeout, rw_timeout);
status.show_slots(redis);
}
else if (cmd == "create")
{
if (conf.empty())
{
printf("usage: %s -a create -f cluster.xml\r\n", argv[0]);
goto END;
}
redis_builder builder;
builder.build(conf.c_str());
}
else if (cmd == "add_node")
{
if (addr.empty() || new_addr.empty())
{
printf("usage: %s -s ip:port -a add_node -N ip:port -S\r\n", argv[0]);
goto END;
}
redis_builder builder;
builder.add_node(addr, new_addr, add_slave);
}
else if (cmd == "del_node")
{
if (addr.empty() || node_id.empty())
{
printf("usage: %s -s ip:port -a del_node -I nod_id\r\n", argv[0]);
goto END;
}
redis_builder builder;
builder.del_node(addr, node_id);
}
else if (cmd == "node_id")
{
if (addr.empty())
{
printf("usage: %s -s ip:port -a node_id\r\n", argv[0]);
goto END;
}
node_id.clear();
redis_builder builder;
if (builder.get_node_id(addr, node_id) == false)
printf("can't get node id, addr: %s\r\n", addr.c_str());
else
printf("addr: %s, node_id: %s\r\n", addr.c_str(),
node_id.c_str());
}
else
printf("unknown cmd: %s\r\n", cmd.c_str());
END:
#ifdef WIN32
printf("enter any key to exit\r\n");
getchar();
#endif
return 0;
}

View File

@ -0,0 +1,548 @@
#include "stdafx.h"
#include "redis_status.h"
#include "redis_builder.h"
#define MAX_SLOTS 16384
redis_builder::redis_builder(int meet_wait /* = 100 */)
: meet_wait_(meet_wait)
, last_check_(0)
{
}
redis_builder::~redis_builder(void)
{
std::vector<acl::redis_node*>::iterator it = masters_.begin();
for (; it != masters_.end(); ++it)
delete *it;
}
//////////////////////////////////////////////////////////////////////////
bool redis_builder::add_node(const char* addr,
const char* new_node_addr, bool slave)
{
acl::redis_client client(new_node_addr);
acl::redis redis(&client);
acl::string buf(addr);
const std::vector<acl::string>& tokens = buf.split2(":");
if (tokens.size() != 2)
{
printf("invalid addr: %s\r\n", addr);
return false;
}
// CLUSTER MEET master node
if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str())))
{
printf("cluster meet %s %s error: %s\r\n",
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) == true)
break;
acl_doze(meet_wait_);
}
if (!slave)
return true;
acl::string node_id;
if (get_node_id(addr, node_id) == false)
{
printf("can't get master(%s)'s node_id\r\n", addr);
return false;
}
if (redis.cluster_replicate(node_id.c_str()) == false)
{
printf("cluster replicate id: %s, error: %s, "
"master_addr: %s, slave_addr: %s\r\n",
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);
acl::redis redis(&client);
if (redis.cluster_forget(node_id) == false)
{
printf("del node: %s error: %s, addr: %s\r\n",
node_id, redis.result_error(), addr);
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool redis_builder::build(const char* conf)
{
if (load(conf) == false)
return false;
if (masters_.empty())
{
printf("no nodes available\r\n");
return false;
}
printf("===================================================\r\n");
return build_cluster();
}
bool redis_builder::load(const char* conf)
{
acl::string buf;
// load xml information from local file
if (acl::ifstream::load(conf, &buf) == false)
{
printf("load configure error: %s, file: %s\r\n",
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::xml xml(buf.c_str());
// get the master redis nodes
const char* tags = "xml/node";
const std::vector<acl::xml_node*>& nodes = xml.getElementsByTags(tags);
if (nodes.empty())
{
printf("nodes null\r\n");
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("no addr in the master node\r\n");
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_slave(*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_slave(acl::xml_node& node)
{
const char* addr = node.attr_value("addr");
if (addr == NULL || *addr == 0)
{
printf("no addr in the slave addr\r\n");
return NULL;
}
printf("\tslave: %s\r\n", addr);
acl::redis_node* slave = new acl::redis_node;
slave->set_addr(addr);
return slave;
}
bool redis_builder::build_cluster()
{
if (masters_.empty())
{
printf("no master available!\r\n");
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) == false)
return false;
begin = end + 1;
end = end + range;
}
it = masters_.begin();
acl::redis_client client((*it)->get_addr());
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) == false)
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()) == false)
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("can't get cluster nodes, addr: %s\r\n",
client.get_stream()->get_peer(true));
return false;
}
redis_status::show_nodes(nodes);
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("invalid master_addr: %s\r\n", node.get_addr());
return false;
}
if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str())))
{
printf("cluster meet %s %s error: %s\r\n",
tokens[0].c_str(), tokens[1].c_str(),
redis.result_error());
return false;
}
while (true)
{
if (cluster_meeting(redis, node.get_addr()) == true)
break;
acl_doze(meet_wait_);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool redis_builder::build_master(acl::redis_node& master)
{
acl::redis_client client(master.get_addr());
acl::redis redis(&client);
if (master_set_slots(redis, master) == false)
return false;
const char* id = myself_id(redis);
if (id == NULL || *id == 0)
{
printf("null id, master addr: %s\r\n", master.get_addr());
return false;
}
master.set_id(id);
printf("Build master: %s, %s\r\n", id, 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) == false)
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());
acl::redis redis(&client);
const char* master_addr = master.get_addr();
if (master_addr == NULL || *master_addr == 0)
{
printf("master addr null\r\n");
return false;
}
acl::string buf(master_addr);
const std::vector<acl::string>& tokens = buf.split2(":");
if (tokens.size() != 2)
{
printf("invalid master_addr: %s\r\n", master_addr);
return false;
}
// CLUSTER MEET master node
if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str())))
{
printf("cluster meet %s %s error: %s\r\n",
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) == true)
break;
acl_doze(meet_wait_);
}
if (redis.cluster_replicate(master.get_id()) == false)
{
printf("cluster replicate id: %s, error: %s, addr: %s\r\n",
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("connection disconnected!\r\n");
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("can't get cluster nodes, addr: %s\r\n", 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("invalid slots's size: %d, addr: %s\r\n",
(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) == false)
{
printf("addslots error: %s, addr: %s, slots: %d, %d\r\n",
redis.result_error(), master.get_addr(),
(int) min_slot, (int) max_slot);
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool redis_builder::get_node_id(const char* addr, acl::string& node_id)
{
acl::redis_client client(addr);
acl::redis redis(&client);
const char* ptr = myself_id(redis);
if (ptr == NULL || *ptr == 0)
{
printf("null node_id from addr: %s\r\n", addr);
return false;
}
node_id = ptr;
return true;
}
const char* redis_builder::myself_id(acl::redis& redis)
{
acl::socket_stream* conn = redis.get_client()->get_stream();
if (conn == NULL)
{
printf("connection disconnected!\r\n");
return NULL;
}
const char* addr = conn->get_peer(true);
const std::map<acl::string, acl::redis_node*>* nodes =
redis.cluster_nodes();
if (nodes == NULL)
{
printf("cluster_nodes null, addr: %s\r\n", addr);
return NULL;
}
std::map<acl::string, acl::redis_node*>::const_iterator it;
for (it = nodes->begin(); it != nodes->end(); ++it)
{
const acl::redis_node* node = it->second;
if (node->is_myself())
return node->get_id();
}
printf("cluster_nodes no myself id, addr: %s\r\n", addr);
return NULL;
}

View File

@ -0,0 +1,59 @@
#pragma once
#include <vector>
#include <map>
class redis_builder
{
public:
redis_builder(int meet_wait = 100);
~redis_builder(void);
bool build(const char* conf);
bool add_node(const char* addr, const char* new_node_addr, bool slave);
bool del_node(const char* addr, const char* node_id);
// get the node's id of the given addr
bool get_node_id(const char* addr, acl::string& node_id);
// get the current node's ID
const char* myself_id(acl::redis& redis);
private:
int meet_wait_;
std::vector<acl::redis_node*> masters_;
time_t last_check_;
// load the cluster.xml configure and create redis nodes for creating
bool load(const char* conf);
// create one master node according to one xml node of configure
acl::redis_node* create_master(acl::xml_node& node);
// create one slave node
acl::redis_node* create_slave(acl::xml_node& node);
// begin build the redis cluster, connect all redis nodes
bool build_cluster();
// allocate slots for every master, and let its slaves connect
// to their master node
bool build_master(acl::redis_node& master);
// let one node meet to another one
bool cluster_meet(acl::redis& redis, const acl::redis_node& node);
// check the MEET status between the current node and the other one
bool cluster_meeting(acl::redis& redis, const char* addr);
// add slots to one master node
bool master_set_slots(acl::redis& redis, acl::redis_node& master);
// add one slave to its master node, let the slave MEET its master,
// and make the slave REPLICATE its master.
bool add_slave(const acl::redis_node& master,
const acl::redis_node& slave);
// check if the given addr was in the node's slave
acl::redis_node* find_slave(const acl::redis_node* node,
const char* addr, size_t& nslaves);
};

View File

@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dispatch_manager", "dispatch_manager_vc2012.vcxproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugDll|Win32 = DebugDll|Win32
Release|Win32 = Release|Win32
ReleaseDll|Win32 = ReleaseDll|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.ActiveCfg = Debug|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.Build.0 = Debug|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.ActiveCfg = DebugDll|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.Build.0 = DebugDll|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.ActiveCfg = Release|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.Build.0 = Release|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32
{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugDll|Win32">
<Configuration>DebugDll</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseDll|Win32">
<Configuration>ReleaseDll</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D90DCF51-E219-4BD8-A032-076335675F58}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>redis_builder</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDll|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDll|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugDll|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDll|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>Debug\</OutDir>
<IntDir>Debug\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>Release\</OutDir>
<IntDir>Release\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDll|Win32'">
<OutDir>$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDll|Win32'">
<OutDir>$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>Create</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)redis_builder.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)redis_builder.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>Create</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>lib_acl_cpp_vc2012.lib;lib_acl_vc2012.lib;lib_protocol_vc2012.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)redis_builder.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDll|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>Create</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)redis_builder.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<PreBuildEvent>
<Command>copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y
copy ..\..\..\dist\lib\win32\lib_acl_cpp.dll $(OutDir) /Y
copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugDll|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>Create</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>lib_acl_cpp_d.lib;lib_acl_d.lib;lib_protocol_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)redis_builder.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)redis_builder.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<PreBuildEvent>
<Command>copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y
copy ..\..\..\dist\lib\win32\lib_acl_cpp.dll $(OutDir) /Y
copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="redis_builder.cpp" />
<ClCompile Include="redis_status.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="redis_builder.h" />
<ClInclude Include="redis_status.h" />
<ClInclude Include="stdafx.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="redis_builder.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="redis_status.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="redis_builder.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="redis_status.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,120 @@
#include "stdafx.h"
#include "redis_status.h"
redis_status::redis_status(const char* addr, int conn_timeout, int rw_timeout)
: addr_(addr)
, conn_timeout_(conn_timeout)
, rw_timeout_(rw_timeout)
{
}
redis_status::~redis_status(void)
{
}
//////////////////////////////////////////////////////////////////////////
void redis_status::show_nodes()
{
acl::redis_client client(addr_, conn_timeout_, rw_timeout_);
acl::redis redis(&client);
show_nodes(redis);
}
void redis_status::show_nodes(acl::redis& redis)
{
const std::map<acl::string, acl::redis_node*>* masters;
if ((masters = redis.cluster_nodes())== NULL)
printf("can't get cluster nodes\r\n");
else
show_nodes(masters);
}
void redis_status::show_slave_nodes(
const std::vector<acl::redis_node*>& slaves)
{
std::vector<acl::redis_node*>::const_iterator cit;
for (cit = slaves.begin(); cit != slaves.end(); ++cit)
{
printf("slave, id: %s, addr: %s, master_id: %s\r\n",
(*cit)->get_id(), (*cit)->get_addr(),
(*cit)->get_master_id());
}
}
void redis_status::show_master_slots(const acl::redis_node* master)
{
const std::vector<std::pair<size_t, size_t> >& slots =
master->get_slots();
std::vector<std::pair<size_t, size_t> >::const_iterator cit;
for (cit = slots.begin(); cit != slots.end(); ++cit)
printf("slots range: %d-%d\r\n",
(int) (*cit).first, (int) (*cit).second);
}
bool redis_status::show_nodes(
const std::map<acl::string, acl::redis_node*>* masters)
{
const std::vector<acl::redis_node*>* slaves;
std::map<acl::string, acl::redis_node*>::const_iterator cit;
for (cit = masters->begin(); cit != masters->end(); ++cit)
{
if (cit != masters->begin())
printf("---------------------------------------\r\n");
printf("master, id: %s, addr: %s\r\n",
cit->first.c_str(), cit->second->get_addr());
show_master_slots(cit->second);
slaves = cit->second->get_slaves();
show_slave_nodes(*slaves);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void redis_status::show_slots()
{
acl::redis_client client(addr_, conn_timeout_, rw_timeout_);
acl::redis redis(&client);
show_slots(redis);
}
bool redis_status::show_slots(acl::redis& redis)
{
const std::vector<acl::redis_slot*>* slots = redis.cluster_slots();
if (slots == NULL)
return false;
std::vector<acl::redis_slot*>::const_iterator cit;
for (cit = slots->begin(); cit != slots->end(); ++cit)
{
printf("=========================================\r\n");
printf("master: ip: %s, port: %d, slots: %d - %d\r\n",
(*cit)->get_ip(), (*cit)->get_port(),
(int) (*cit)->get_slot_min(),
(int) (*cit)->get_slot_max());
show_slaves_slots(*cit);
}
return true;
}
void redis_status::show_slaves_slots(const acl::redis_slot* slot)
{
const std::vector<acl::redis_slot*>& slaves = slot->get_slaves();
std::vector<acl::redis_slot*>::const_iterator cit;
for (cit = slaves.begin(); cit != slaves.end(); ++cit)
{
printf("slave: ip: %s, port: %d, slots: %d - %d\r\n",
(*cit)->get_ip(), (*cit)->get_port(),
(int) (*cit)->get_slot_min(),
(int) (*cit)->get_slot_max());
}
}

View File

@ -0,0 +1,24 @@
#pragma once
class redis_status
{
public:
redis_status(const char* addr, int conn_timeout, int rw_timeout);
~redis_status(void);
void show_nodes();
static void show_nodes(acl::redis& redis);
static bool show_nodes(const std::map<acl::string,
acl::redis_node*>* masters);
static void show_master_slots(const acl::redis_node* master);
static void show_slave_nodes(const std::vector<acl::redis_node*>& slaves);
void show_slots();
static bool show_slots(acl::redis& redis);
static void show_slaves_slots(const acl::redis_slot* slot);
private:
acl::string addr_;
int conn_timeout_;
int rw_timeout_;
};

View File

@ -0,0 +1,8 @@
// stdafx.cpp : 只包括标准包含文件的源文件
// master_threads.pch 将成为预编译头
// stdafx.obj 将包含预编译类型信息
#include "stdafx.h"
// TODO: 在 STDAFX.H 中
//引用任何所需的附加头文件,而不是在此文件中引用

View File

@ -0,0 +1,16 @@
// stdafx.h : 标准系统包含文件的包含文件,
// 或是常用但不常更改的项目特定的包含文件
//
#pragma once
//#include <iostream>
//#include <tchar.h>
// TODO: 在此处引用程序要求的附加头文件
#include "acl_cpp/lib_acl.hpp"
#include "lib_acl.h"

View File

@ -1,5 +1,8 @@
修改历史列表:
------------------------------------------------------------------------
82) 2015.4.19
82.1) app/redis_tools: 用于 redis 集群管理的工具
81) 2015.3.29 --- acl 3.1.1 版本发布!
80) 2015.2.8

View File

@ -1,6 +1,9 @@
修改历史列表:
------------------------------------------------------------------------
301) 2015.4.19
301.1) feature: 完善了 redis_cluster 集群管理类
300) 2015.4.12
300.1) comment: 完善了 redis 模块的英文注释

View File

@ -301,10 +301,9 @@ private:
std::map<string, redis_node*> masters_;
redis_node* get_node(string& line);
redis_node* get_master_node(std::vector<string>& tokens);
void add_slot_range(redis_node* node, char* slots);
redis_node* get_slave_node(std::vector<string>& tokens);
void free_masters();
redis_node* get_slave(const std::vector<string>& tokens);
private:
std::vector<redis_node*> slaves_;

View File

@ -16,32 +16,79 @@ class ACL_CPP_API redis_node
{
public:
/**
*
* constructor
* @param id {const char*} redis
* the unique ID for one redis node in the redis cluster
* @param addr {const char*} redis
* the listening addr for one redis node in redis cluster
* 使 set_id set_addr
* redis set_xxx
*/
redis_node(const char* id, const char* addr);
redis_node(const redis_node& node);
redis_node();
~redis_node();
/**
* ID
* set the node's ID
* @param id {const char*} redis
* the unique ID for one redis node in the reids cluster
* @return {redis_node&}
*/
redis_node& set_id(const char* id);
/**
*
* set the node's listening addr
* @param addr {const char*} redis ip:port
* the listening addr of one redis node in the reids cluster
* @return {redis_node&}
*/
redis_node& set_addr(const char* addr);
/**
*
* set the current node's type
* @param type {const char*}
* @return {redis_node&}
*/
redis_node& set_type(const char* type);
/**
*
* set if the current node is belonging to the current connection
* @param yesno {bool}
* @return {redis_node&}
*/
redis_node& set_myself(bool yesno);
/**
*
* setting current slave node's master node
* @param master {const redis_node*}
* the redis master node of the current slave in cluster
* @return {redis_node&}
*/
void set_master(const redis_node* master);
redis_node& set_master(const redis_node* master);
/**
*
* set the current node being in handshaking status
* @param yesno {bool}
* @return {redis_node&}
*/
redis_node& set_handshaking(bool yesno);
/**
* 线
* set the node been connected in the cluster
* @param yesno {bool}
* @return {redis_node&}
*/
redis_node& set_connected(bool yesno);
/**
*
* setting current node's master node when the node is slave node
* @param id {const char*}
* the unique ID of the master node
* @return {redis_node&}
*/
void set_master_id(const char* id);
redis_node& set_master_id(const char* id);
/**
*
@ -89,6 +136,46 @@ public:
*/
const std::vector<std::pair<size_t, size_t> >& get_slots() const;
/**
*
* get the node's type
* @return {const char*}
*/
const char* get_type() const
{
return type_.c_str();
}
/**
*
* check if the node belongs to the current connection
* @return {bool}
*/
bool is_myself() const
{
return myself_;
}
/**
*
* check if the node is in handshaking status
* @return {bool}
*/
bool is_handshaking() const
{
return handshaking_;
}
/**
* 线
* check if the node is connected in the cluster
* @return {bool}
*/
bool is_connected() const
{
return connected_;
}
/**
*
* get the current slave's master node
@ -116,7 +203,7 @@ public:
*/
const std::vector<redis_node*>* get_slaves() const
{
return (master_ && master_ == this) ? &slaves_ : NULL;
return &slaves_;
}
/**
@ -152,6 +239,10 @@ public:
private:
string id_;
string addr_;
string type_;
bool myself_;
bool handshaking_;
bool connected_;
const redis_node* master_;
string master_id_;
std::vector<redis_node*> slaves_;

View File

@ -638,8 +638,7 @@ const std::vector<redis_node*>* redis_cluster::cluster_slaves(const char* node)
node_type = ptr + 1;
if (strcasecmp(node_type, "slave") != 0)
continue;
redis_node* slave = get_slave_node(tokens);
redis_node* slave = get_slave(tokens);
if (slave != NULL)
slaves_.push_back(slave);
}
@ -647,6 +646,21 @@ const std::vector<redis_node*>* redis_cluster::cluster_slaves(const char* node)
return &slaves_;
}
redis_node* redis_cluster::get_slave(const std::vector<string>& tokens)
{
if (tokens.size() < 8)
return NULL;
redis_node* node = NEW redis_node;
node->set_id(tokens[0].c_str());
node->set_addr(tokens[1].c_str());
node->set_myself(false);
node->set_connected(strcasecmp(tokens[7].c_str(), "connected") == 0);
node->set_master_id(tokens[3].c_str());
node->set_type("slave");
return node;
}
void redis_cluster::free_slaves()
{
std::vector<redis_node*>::iterator it = slaves_.begin();
@ -712,51 +726,61 @@ const std::map<string, redis_node*>* redis_cluster::cluster_nodes()
// 94e5d32cbcc9539cc1539078ca372094c14f9f49 127.0.0.1:16380 myself,master - 0 0 1 connected 0-9 11-5460
// e7b21f65e8d0d6e82dee026de29e499bb518db36 127.0.0.1:16381 slave d52ea3cb4cdf7294ac1fb61c696ae6483377bcfc 0 1428410625373 73 connected
// 6a78b47b2e150693fc2bed8578a7ca88b8f1e04c 127.0.0.1:16383 myself,slave 94e5d32cbcc9539cc1539078ca372094c14f9f49 0 0 4 connected
// 70a2cd8936a3d28d94b4915afd94ea69a596376a :16381 myself,master - 0 0 0 connected
redis_node* redis_cluster::get_node(string& line)
{
std::vector<string>& tokens = line.split2(" ");
if (tokens.size() < 3)
if (tokens.size() < 8)
{
logger_warn("invalid tokens's size: %d < 8",
(int) tokens.size());
return NULL;
}
bool myself = false;
char* node_type = tokens[2].c_str();
char* ptr = strchr(node_type, ',');
if (ptr != NULL && *(ptr + 1) != 0)
node_type = ptr + 1;
{
*ptr++ = 0;
if (strcasecmp(node_type, "myself") == 0)
myself = true;
node_type = ptr;
}
redis_node* node = NEW redis_node;
node->set_id(tokens[0].c_str());
node->set_addr(tokens[1].c_str());
node->set_myself(myself);
node->set_connected(strcasecmp(tokens[7].c_str(), "connected") == 0);
node->set_master_id(tokens[3].c_str());
if (strcasecmp(node_type, "master") == 0)
return get_master_node(tokens);
{
node->set_master(node);
node->set_type("master");
masters_[tokens[0]] = node;
size_t n = tokens.size();
for (size_t i = 8; i < n; i++)
add_slot_range(node, tokens[i].c_str());
}
else if (strcasecmp(node_type, "slave") == 0)
return get_slave_node(tokens);
node->set_type("slave");
else if (strcasecmp(node_type, "handshake") == 0)
{
node->set_master(node);
node->set_type("handshake");
node->set_handshaking(true);
masters_[tokens[0]] = node;
size_t n = tokens.size();
for (size_t i = 8; i < n; i++)
add_slot_range(node, tokens[i].c_str());
}
else
{
logger_error("unknown node type: %s", node_type);
return NULL;
}
}
logger_warn("unknown node type: %s", node_type);
redis_node* redis_cluster::get_master_node(std::vector<string>& tokens)
{
if (tokens.size() < 9)
{
logger_warn("invalid tokens's size: %d", (int) tokens.size());
return NULL;
}
std::map<string, redis_node*>::const_iterator cit;
if ((cit = masters_.find(tokens[0].c_str())) != masters_.end())
{
logger_warn("already exists master: %s", tokens[0].c_str());
return NULL;
}
redis_node* node = NEW redis_node(tokens[0].c_str(), tokens[1].c_str());
node->set_master(node);
masters_[tokens[0]] = node;
size_t n = tokens.size();
for (size_t i = 8; i < n; i++)
add_slot_range(node, tokens[i].c_str());
return node;
}
@ -783,19 +807,6 @@ void redis_cluster::add_slot_range(redis_node* node, char* slots)
node->add_slot_range(slot_min, slot_max);
}
redis_node* redis_cluster::get_slave_node(std::vector<string>& tokens)
{
if (tokens.size() < 4)
{
logger_warn("invalid tokens's size: %d", (int) tokens.size());
return NULL;
}
redis_node* node = NEW redis_node(tokens[0].c_str(), tokens[1].c_str());
node->set_master_id(tokens[3].c_str());
return node;
}
void redis_cluster::free_masters()
{
std::map<string, redis_node*>::iterator it = masters_.begin();

View File

@ -5,31 +5,12 @@
namespace acl
{
redis_node::redis_node(const char* id, const char* addr)
: id_(id)
, addr_(addr)
redis_node::redis_node()
: myself_(false)
, handshaking_(false)
, connected_(false)
, master_(NULL)
{
}
redis_node::redis_node(const redis_node& node)
{
id_ = node.get_id();
addr_ = node.get_addr();
master_ = node.get_master();
const std::vector<redis_node*>* slaves = node.get_slaves();
if (slaves != NULL)
{
std::vector<redis_node*>::const_iterator cit;
for (cit = slaves_.begin(); cit != slaves_.end(); ++cit)
slaves_.push_back(*cit);
}
const std::vector<std::pair<size_t, size_t> >& slots = node.get_slots();
std::vector<std::pair<size_t, size_t> >::const_iterator cit2;
for (cit2 = slots.begin(); cit2 != slots.end(); ++cit2)
slots_.push_back(*cit2);
}
redis_node::~redis_node()
@ -37,15 +18,53 @@ redis_node::~redis_node()
}
void redis_node::set_master(const redis_node* master)
redis_node& redis_node::set_id(const char* id)
{
master_ = master;
id_ = id;
return *this;
}
void redis_node::set_master_id(const char* id)
redis_node& redis_node::set_addr(const char* addr)
{
addr_ = addr;
return *this;
}
redis_node& redis_node::set_type(const char* type)
{
type_ = type;
return *this;
}
redis_node& redis_node::set_myself(bool yesno)
{
myself_ = yesno;
return *this;
}
redis_node& redis_node::set_handshaking(bool yesno)
{
handshaking_ = yesno;
return *this;
}
redis_node& redis_node::set_connected(bool yesno)
{
connected_ = yesno;
return *this;
}
redis_node& redis_node::set_master(const redis_node* master)
{
master_ = master;
return *this;
}
redis_node& redis_node::set_master_id(const char* id)
{
if (id && *id)
master_id_ = id;
return *this;
}
bool redis_node::add_slave(redis_node* slave)
@ -55,11 +74,20 @@ bool redis_node::add_slave(redis_node* slave)
std::vector<redis_node*>::const_iterator cit;
for (cit = slaves_.begin(); cit != slaves_.end(); ++cit)
{
if (*cit == slave
|| strcmp(slave->get_id(), (*cit)->get_id()) == 0)
if (*cit == slave)
{
logger_warn("slave exists, id: %s, addr: %s",
(*cit)->get_id(), (*cit)->get_addr());
printf("slave exists: %s, id: %s, addr: %s\r\n",
slave->get_id(), (*cit)->get_id(),
(*cit)->get_addr());
return false;
}
if ((*slave->get_id()) == 0)
continue;
if (strcmp(slave->get_id(), (*cit)->get_id()) == 0)
{
printf("slave exists: %s, id: %s, addr: %s\r\n",
slave->get_id(), (*cit)->get_id(),
(*cit)->get_addr());
return false;
}
}