Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
56cf4138
Unverified
Commit
56cf4138
authored
Mar 01, 2019
by
Salvatore Sanfilippo
Committed by
GitHub
Mar 01, 2019
Browse files
Merge pull request #5888 from artix75/cluster_backup
Cluster Manager (redis-cli): new "backup" command
parents
537d8592
e6156a39
Changes
1
Show whitespace changes
Inline
Side-by-side
src/redis-cli.c
View file @
56cf4138
...
@@ -177,6 +177,7 @@ typedef struct clusterManagerCommand {
...
@@ -177,6 +177,7 @@ typedef struct clusterManagerCommand {
int timeout;
int timeout;
int pipeline;
int pipeline;
float threshold;
float threshold;
char *backup_dir;
} clusterManagerCommand;
} clusterManagerCommand;
static void createClusterManagerCommand(char *cmdname, int argc, char **argv);
static void createClusterManagerCommand(char *cmdname, int argc, char **argv);
...
@@ -2056,6 +2057,7 @@ static int clusterManagerCommandSetTimeout(int argc, char **argv);
...
@@ -2056,6 +2057,7 @@ static int clusterManagerCommandSetTimeout(int argc, char **argv);
static int clusterManagerCommandImport(int argc, char **argv);
static int clusterManagerCommandImport(int argc, char **argv);
static int clusterManagerCommandCall(int argc, char **argv);
static int clusterManagerCommandCall(int argc, char **argv);
static int clusterManagerCommandHelp(int argc, char **argv);
static int clusterManagerCommandHelp(int argc, char **argv);
static int clusterManagerCommandBackup(int argc, char **argv);
typedef struct clusterManagerCommandDef {
typedef struct clusterManagerCommandDef {
char *name;
char *name;
...
@@ -2088,9 +2090,12 @@ clusterManagerCommandDef clusterManagerCommands[] = {
...
@@ -2088,9 +2090,12 @@ clusterManagerCommandDef clusterManagerCommands[] = {
"host:port milliseconds", NULL},
"host:port milliseconds", NULL},
{"import", clusterManagerCommandImport, 1, "host:port",
{"import", clusterManagerCommandImport, 1, "host:port",
"from <arg>,copy,replace"},
"from <arg>,copy,replace"},
{"backup", clusterManagerCommandBackup, 2, "host:port backup_directory",
NULL},
{"help", clusterManagerCommandHelp, 0, NULL, NULL}
{"help", clusterManagerCommandHelp, 0, NULL, NULL}
};
};
static void getRDB(clusterManagerNode *node);
static void createClusterManagerCommand(char *cmdname, int argc, char **argv) {
static void createClusterManagerCommand(char *cmdname, int argc, char **argv) {
clusterManagerCommand *cmd = &config.cluster_manager_command;
clusterManagerCommand *cmd = &config.cluster_manager_command;
...
@@ -2260,6 +2265,16 @@ static clusterManagerNode *clusterManagerNewNode(char *ip, int port) {
...
@@ -2260,6 +2265,16 @@ static clusterManagerNode *clusterManagerNewNode(char *ip, int port) {
return node;
return node;
}
}
static sds clusterManagerGetNodeRDBFilename(clusterManagerNode *node) {
assert(config.cluster_manager_command.backup_dir);
sds filename = sdsnew(config.cluster_manager_command.backup_dir);
if (filename[sdslen(filename)] - 1 != '/')
filename = sdscat(filename, "/");
filename = sdscatprintf(filename, "redis-node-%s-%d-%s.rdb", node->ip,
node->port, node->name);
return filename;
}
/* Check whether reply is NULL or its type is REDIS_REPLY_ERROR. In the
/* Check whether reply is NULL or its type is REDIS_REPLY_ERROR. In the
* latest case, if the 'err' arg is not NULL, it gets allocated with a copy
* latest case, if the 'err' arg is not NULL, it gets allocated with a copy
* of reply error (it's up to the caller function to free it), elsewhere
* of reply error (it's up to the caller function to free it), elsewhere
...
@@ -2680,6 +2695,51 @@ static sds clusterManagerNodeSlotsString(clusterManagerNode *node) {
...
@@ -2680,6 +2695,51 @@ static sds clusterManagerNodeSlotsString(clusterManagerNode *node) {
return slots;
return slots;
}
}
static sds clusterManagerNodeGetJSON(clusterManagerNode *node,
unsigned long error_count)
{
sds json = sdsempty();
sds replicate = sdsempty();
if (node->replicate)
replicate = sdscatprintf(replicate, "\"%s\"", node->replicate);
else
replicate = sdscat(replicate, "null");
sds slots = clusterManagerNodeSlotsString(node);
sds flags = clusterManagerNodeFlagString(node);
char *p = slots;
while ((p = strchr(p, '-')) != NULL)
*(p++) = ',';
json = sdscatprintf(json,
" {\n"
" \"name\": \"%s\",\n"
" \"host\": \"%s\",\n"
" \"port\": %d,\n"
" \"replicate\": %s,\n"
" \"slots\": [%s],\n"
" \"slots_count\": %d,\n"
" \"flags\": \"%s\",\n"
" \"current_epoch\": %llu",
node->name,
node->ip,
node->port,
replicate,
slots,
node->slots_count,
flags,
node->current_epoch
);
if (error_count > 0) {
json = sdscatprintf(json, ",\n \"cluster_errors\": %lu",
error_count);
}
json = sdscat(json, "\n }");
sdsfree(replicate);
sdsfree(slots);
sdsfree(flags);
return json;
}
/* -----------------------------------------------------------------------------
/* -----------------------------------------------------------------------------
* Key space handling
* Key space handling
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
...
@@ -6053,6 +6113,70 @@ invalid_args:
...
@@ -6053,6 +6113,70 @@ invalid_args:
return 0;
return 0;
}
}
static int clusterManagerCommandBackup(int argc, char **argv) {
UNUSED(argc);
int success = 1, port = 0;
char *ip = NULL;
if (!getClusterHostFromCmdArgs(1, argv, &ip, &port)) goto invalid_args;
clusterManagerNode *refnode = clusterManagerNewNode(ip, port);
if (!clusterManagerLoadInfoFromNode(refnode, 0)) return 0;
int no_issues = clusterManagerCheckCluster(0);
int cluster_errors_count = (no_issues ? 0 :
listLength(cluster_manager.errors));
config.cluster_manager_command.backup_dir = argv[1];
/* TODO: check if backup_dir is a valid directory. */
sds json = sdsnew("[\n");
int first_node = 0;
listIter li;
listNode *ln;
listRewind(cluster_manager.nodes, &li);
while ((ln = listNext(&li)) != NULL) {
if (!first_node) first_node = 1;
else json = sdscat(json, ",\n");
clusterManagerNode *node = ln->value;
sds node_json = clusterManagerNodeGetJSON(node, cluster_errors_count);
json = sdscat(json, node_json);
sdsfree(node_json);
if (node->replicate)
continue;
clusterManagerLogInfo(">>> Node %s:%d -> Saving RDB...\n",
node->ip, node->port);
fflush(stdout);
getRDB(node);
}
json = sdscat(json, "\n]");
sds jsonpath = sdsnew(config.cluster_manager_command.backup_dir);
if (jsonpath[sdslen(jsonpath) - 1] != '/')
jsonpath = sdscat(jsonpath, "/");
jsonpath = sdscat(jsonpath, "nodes.json");
fflush(stdout);
clusterManagerLogInfo("Saving cluster configuration to: %s\n", jsonpath);
FILE *out = fopen(jsonpath, "w+");
if (!out) {
clusterManagerLogErr("Could not save nodes to: %s\n", jsonpath);
success = 0;
goto cleanup;
}
fputs(json, out);
fclose(out);
cleanup:
sdsfree(json);
sdsfree(jsonpath);
if (success) {
if (!no_issues) {
clusterManagerLogWarn("*** Cluster seems to have some problems, "
"please be aware of it if you're going "
"to restore this backup.\n");
}
clusterManagerLogOk("[OK] Backup created into: %s\n",
config.cluster_manager_command.backup_dir);
} else clusterManagerLogOk("[ERR] Failed to back cluster!\n");
return success;
invalid_args:
fprintf(stderr, CLUSTER_MANAGER_INVALID_HOST_ARG);
return 0;
}
static int clusterManagerCommandHelp(int argc, char **argv) {
static int clusterManagerCommandHelp(int argc, char **argv) {
UNUSED(argc);
UNUSED(argc);
UNUSED(argv);
UNUSED(argv);
...
@@ -6445,9 +6569,17 @@ static void slaveMode(void) {
...
@@ -6445,9 +6569,17 @@ static void slaveMode(void) {
/* This function implements --rdb, so it uses the replication protocol in order
/* This function implements --rdb, so it uses the replication protocol in order
* to fetch the RDB file from a remote server. */
* to fetch the RDB file from a remote server. */
static void getRDB(void) {
static void getRDB(clusterManagerNode *node) {
int s = context->fd;
int s, fd;
int fd;
char *filename;
if (node != NULL) {
assert(node->context);
s = node->context->fd;
filename = clusterManagerGetNodeRDBFilename(node);
} else {
s = context->fd;
filename = config.rdb_filename;
}
static char eofmark[RDB_EOF_MARK_SIZE];
static char eofmark[RDB_EOF_MARK_SIZE];
static char lastbytes[RDB_EOF_MARK_SIZE];
static char lastbytes[RDB_EOF_MARK_SIZE];
static int usemark = 0;
static int usemark = 0;
...
@@ -6458,20 +6590,20 @@ static void getRDB(void) {
...
@@ -6458,20 +6590,20 @@ static void getRDB(void) {
payload = ULLONG_MAX;
payload = ULLONG_MAX;
memset(lastbytes,0,RDB_EOF_MARK_SIZE);
memset(lastbytes,0,RDB_EOF_MARK_SIZE);
usemark = 1;
usemark = 1;
fprintf(stderr,"SYNC sent to master, writing bytes of bulk transfer
until EOF marker to '%s'\n",
fprintf(stderr,"SYNC sent to master, writing bytes of bulk transfer
"
config.rdb_
filename);
"until EOF marker to '%s'\n",
filename);
} else {
} else {
fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n",
fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n",
payload,
config.rdb_
filename);
payload, filename);
}
}
/* Write to file. */
/* Write to file. */
if (!strcmp(
config.rdb_
filename,"-")) {
if (!strcmp(filename,"-")) {
fd = STDOUT_FILENO;
fd = STDOUT_FILENO;
} else {
} else {
fd = open(
config.rdb_
filename, O_CREAT|O_WRONLY, 0644);
fd = open(filename, O_CREAT|O_WRONLY, 0644);
if (fd == -1) {
if (fd == -1) {
fprintf(stderr, "Error opening '%s': %s\n",
config.rdb_
filename,
fprintf(stderr, "Error opening '%s': %s\n", filename,
strerror(errno));
strerror(errno));
exit(1);
exit(1);
}
}
...
@@ -6517,6 +6649,11 @@ static void getRDB(void) {
...
@@ -6517,6 +6649,11 @@ static void getRDB(void) {
close(s); /* Close the file descriptor ASAP as fsync() may take time. */
close(s); /* Close the file descriptor ASAP as fsync() may take time. */
fsync(fd);
fsync(fd);
close(fd);
close(fd);
fprintf(stderr,"Transfer finished with success.\n");
if (node) {
sdsfree(filename);
return;
}
exit(0);
exit(0);
}
}
...
@@ -7526,6 +7663,7 @@ int main(int argc, char **argv) {
...
@@ -7526,6 +7663,7 @@ int main(int argc, char **argv) {
config.cluster_manager_command.pipeline = CLUSTER_MANAGER_MIGRATE_PIPELINE;
config.cluster_manager_command.pipeline = CLUSTER_MANAGER_MIGRATE_PIPELINE;
config.cluster_manager_command.threshold =
config.cluster_manager_command.threshold =
CLUSTER_MANAGER_REBALANCE_THRESHOLD;
CLUSTER_MANAGER_REBALANCE_THRESHOLD;
config.cluster_manager_command.backup_dir = NULL;
pref.hints = 1;
pref.hints = 1;
spectrum_palette = spectrum_palette_color;
spectrum_palette = spectrum_palette_color;
...
@@ -7577,7 +7715,7 @@ int main(int argc, char **argv) {
...
@@ -7577,7 +7715,7 @@ int main(int argc, char **argv) {
if (config.getrdb_mode) {
if (config.getrdb_mode) {
if (cliConnect(0) == REDIS_ERR) exit(1);
if (cliConnect(0) == REDIS_ERR) exit(1);
sendCapa();
sendCapa();
getRDB();
getRDB(
NULL
);
}
}
/* Pipe mode */
/* Pipe mode */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment