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
Hide whitespace changes
Inline
Side-by-side
src/redis-cli.c
View file @
56cf4138
...
...
@@ -177,6 +177,7 @@ typedef struct clusterManagerCommand {
int
timeout
;
int
pipeline
;
float
threshold
;
char
*
backup_dir
;
}
clusterManagerCommand
;
static
void
createClusterManagerCommand
(
char
*
cmdname
,
int
argc
,
char
**
argv
);
...
...
@@ -2056,6 +2057,7 @@ static int clusterManagerCommandSetTimeout(int argc, char **argv);
static
int
clusterManagerCommandImport
(
int
argc
,
char
**
argv
);
static
int
clusterManagerCommandCall
(
int
argc
,
char
**
argv
);
static
int
clusterManagerCommandHelp
(
int
argc
,
char
**
argv
);
static
int
clusterManagerCommandBackup
(
int
argc
,
char
**
argv
);
typedef
struct
clusterManagerCommandDef
{
char
*
name
;
...
...
@@ -2088,9 +2090,12 @@ clusterManagerCommandDef clusterManagerCommands[] = {
"host:port milliseconds"
,
NULL
},
{
"import"
,
clusterManagerCommandImport
,
1
,
"host:port"
,
"from <arg>,copy,replace"
},
{
"backup"
,
clusterManagerCommandBackup
,
2
,
"host:port backup_directory"
,
NULL
},
{
"help"
,
clusterManagerCommandHelp
,
0
,
NULL
,
NULL
}
};
static
void
getRDB
(
clusterManagerNode
*
node
);
static
void
createClusterManagerCommand
(
char
*
cmdname
,
int
argc
,
char
**
argv
)
{
clusterManagerCommand
*
cmd
=
&
config
.
cluster_manager_command
;
...
...
@@ -2260,6 +2265,16 @@ static clusterManagerNode *clusterManagerNewNode(char *ip, int port) {
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
* 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
...
...
@@ -2680,6 +2695,51 @@ static sds clusterManagerNodeSlotsString(clusterManagerNode *node) {
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
* -------------------------------------------------------------------------- */
...
...
@@ -6053,6 +6113,70 @@ invalid_args:
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
)
{
UNUSED
(
argc
);
UNUSED
(
argv
);
...
...
@@ -6445,9 +6569,17 @@ static void slaveMode(void) {
/* This function implements --rdb, so it uses the replication protocol in order
* to fetch the RDB file from a remote server. */
static
void
getRDB
(
void
)
{
int
s
=
context
->
fd
;
int
fd
;
static
void
getRDB
(
clusterManagerNode
*
node
)
{
int
s
,
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
lastbytes
[
RDB_EOF_MARK_SIZE
];
static
int
usemark
=
0
;
...
...
@@ -6458,20 +6590,20 @@ static void getRDB(void) {
payload
=
ULLONG_MAX
;
memset
(
lastbytes
,
0
,
RDB_EOF_MARK_SIZE
);
usemark
=
1
;
fprintf
(
stderr
,
"SYNC sent to master, writing bytes of bulk transfer
until EOF marker to '%s'
\n
"
,
config
.
rdb_
filename
);
fprintf
(
stderr
,
"SYNC sent to master, writing bytes of bulk transfer
"
"until EOF marker to '%s'
\n
"
,
filename
);
}
else
{
fprintf
(
stderr
,
"SYNC sent to master, writing %llu bytes to '%s'
\n
"
,
payload
,
config
.
rdb_
filename
);
payload
,
filename
);
}
/* Write to file. */
if
(
!
strcmp
(
config
.
rdb_
filename
,
"-"
))
{
if
(
!
strcmp
(
filename
,
"-"
))
{
fd
=
STDOUT_FILENO
;
}
else
{
fd
=
open
(
config
.
rdb_
filename
,
O_CREAT
|
O_WRONLY
,
0644
);
fd
=
open
(
filename
,
O_CREAT
|
O_WRONLY
,
0644
);
if
(
fd
==
-
1
)
{
fprintf
(
stderr
,
"Error opening '%s': %s
\n
"
,
config
.
rdb_
filename
,
fprintf
(
stderr
,
"Error opening '%s': %s
\n
"
,
filename
,
strerror
(
errno
));
exit
(
1
);
}
...
...
@@ -6517,6 +6649,11 @@ static void getRDB(void) {
close
(
s
);
/* Close the file descriptor ASAP as fsync() may take time. */
fsync
(
fd
);
close
(
fd
);
fprintf
(
stderr
,
"Transfer finished with success.
\n
"
);
if
(
node
)
{
sdsfree
(
filename
);
return
;
}
exit
(
0
);
}
...
...
@@ -7526,6 +7663,7 @@ int main(int argc, char **argv) {
config
.
cluster_manager_command
.
pipeline
=
CLUSTER_MANAGER_MIGRATE_PIPELINE
;
config
.
cluster_manager_command
.
threshold
=
CLUSTER_MANAGER_REBALANCE_THRESHOLD
;
config
.
cluster_manager_command
.
backup_dir
=
NULL
;
pref
.
hints
=
1
;
spectrum_palette
=
spectrum_palette_color
;
...
...
@@ -7577,7 +7715,7 @@ int main(int argc, char **argv) {
if
(
config
.
getrdb_mode
)
{
if
(
cliConnect
(
0
)
==
REDIS_ERR
)
exit
(
1
);
sendCapa
();
getRDB
();
getRDB
(
NULL
);
}
/* 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