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
5fb4adba
"doc/AuthCommand.html" did not exist on "37be27653817f0c4c18d695ceea082e0bb7bf462"
Unverified
Commit
5fb4adba
authored
Oct 27, 2021
by
Wen Hui
Committed by
GitHub
Oct 26, 2021
Browse files
New Cluster Command: CLUSTER DELSLOTSRANGE and CLUSTER ADDSLOTSRANGE (#9445)
parent
37dc2f13
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/cluster.c
View file @
5fb4adba
...
@@ -4440,6 +4440,42 @@ static int isReplicaAvailable(clusterNode *node) {
...
@@ -4440,6 +4440,42 @@ static int isReplicaAvailable(clusterNode *node) {
return (repl_offset != 0);
return (repl_offset != 0);
}
}
int checkSlotAssignmentsOrReply(client *c, unsigned char *slots, int del, int start_slot, int end_slot) {
int slot;
for (slot = start_slot; slot <= end_slot; slot++) {
if (del && server.cluster->slots[slot] == NULL) {
addReplyErrorFormat(c,"Slot %d is already unassigned", slot);
return C_ERR;
} else if (!del && server.cluster->slots[slot]) {
addReplyErrorFormat(c,"Slot %d is already busy", slot);
return C_ERR;
}
if (slots[slot]++ == 1) {
addReplyErrorFormat(c,"Slot %d specified multiple times",(int)slot);
return C_ERR;
}
}
return C_OK;
}
void clusterUpdateSlots(client *c, unsigned char *slots, int del) {
int j;
for (j = 0; j < CLUSTER_SLOTS; j++) {
if (slots[j]) {
int retval;
/* If this slot was set as importing we can clear this
* state as now we are the real owner of the slot. */
if (server.cluster->importing_slots_from[j])
server.cluster->importing_slots_from[j] = NULL;
retval = del ? clusterDelSlot(j) :
clusterAddSlot(myself,j);
serverAssertWithInfo(c,NULL,retval == C_OK);
}
}
}
void addNodeReplyForClusterSlot(client *c, clusterNode *node, int start_slot, int end_slot) {
void addNodeReplyForClusterSlot(client *c, clusterNode *node, int start_slot, int end_slot) {
int i, nested_elements = 3; /* slots (2) + master addr (1) */
int i, nested_elements = 3; /* slots (2) + master addr (1) */
void *nested_replylen = addReplyDeferredLen(c);
void *nested_replylen = addReplyDeferredLen(c);
...
@@ -4517,6 +4553,8 @@ void clusterCommand(client *c) {
...
@@ -4517,6 +4553,8 @@ void clusterCommand(client *c) {
const char *help[] = {
const char *help[] = {
"ADDSLOTS <slot> [<slot> ...]",
"ADDSLOTS <slot> [<slot> ...]",
" Assign slots to current node.",
" Assign slots to current node.",
"ADDSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]",
" Assign slots which are between <start-slot> and <end-slot> to current node.",
"BUMPEPOCH",
"BUMPEPOCH",
" Advance the cluster config epoch.",
" Advance the cluster config epoch.",
"COUNT-FAILURE-REPORTS <node-id>",
"COUNT-FAILURE-REPORTS <node-id>",
...
@@ -4525,6 +4563,8 @@ void clusterCommand(client *c) {
...
@@ -4525,6 +4563,8 @@ void clusterCommand(client *c) {
" Return the number of keys in <slot>.",
" Return the number of keys in <slot>.",
"DELSLOTS <slot> [<slot> ...]",
"DELSLOTS <slot> [<slot> ...]",
" Delete slots information from current node.",
" Delete slots information from current node.",
"DELSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]",
" Delete slots information which are between <start-slot> and <end-slot> from current node.",
"FAILOVER [FORCE|TAKEOVER]",
"FAILOVER [FORCE|TAKEOVER]",
" Promote current replica node to being a master.",
" Promote current replica node to being a master.",
"FORGET <node-id>",
"FORGET <node-id>",
...
@@ -4624,43 +4664,62 @@ NULL
...
@@ -4624,43 +4664,62 @@ NULL
int del = !strcasecmp(c->argv[1]->ptr,"delslots");
int del = !strcasecmp(c->argv[1]->ptr,"delslots");
memset(slots,0,CLUSTER_SLOTS);
memset(slots,0,CLUSTER_SLOTS);
/* Check that all the arguments are parseable and that all the
/* Check that all the arguments are parseable.*/
* slots are not already busy. */
for (j = 2; j < c->argc; j++) {
for (j = 2; j < c->argc; j++) {
if ((slot = getSlotOrReply(c,c->argv[j])) ==
-1
) {
if ((slot = getSlotOrReply(c,c->argv[j])) ==
C_ERR
) {
zfree(slots);
zfree(slots);
return;
return;
}
}
if (del && server.cluster->slots[slot] == NULL) {
}
addReplyErrorFormat(c,"Slot %d is already unassigned", slot);
/* Check that the slots are not already busy. */
for (j = 2; j < c->argc; j++) {
slot = getSlotOrReply(c,c->argv[j]);
if (checkSlotAssignmentsOrReply(c, slots, del, slot, slot) == C_ERR) {
zfree(slots);
zfree(slots);
return;
return;
} else if (!del && server.cluster->slots[slot]) {
}
addReplyErrorFormat(c,"Slot %d is already busy", slot);
}
clusterUpdateSlots(c, slots, del);
zfree(slots);
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG);
addReply(c,shared.ok);
} else if ((!strcasecmp(c->argv[1]->ptr,"addslotsrange") ||
!strcasecmp(c->argv[1]->ptr,"delslotsrange")) && c->argc >= 4) {
if (c->argc % 2 == 1) {
addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
c->cmd->name);
return;
}
/* CLUSTER ADDSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...] */
/* CLUSTER DELSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...] */
int j, startslot, endslot;
unsigned char *slots = zmalloc(CLUSTER_SLOTS);
int del = !strcasecmp(c->argv[1]->ptr,"delslotsrange");
memset(slots,0,CLUSTER_SLOTS);
/* Check that all the arguments are parseable and that all the
* slots are not already busy. */
for (j = 2; j < c->argc; j += 2) {
if ((startslot = getSlotOrReply(c,c->argv[j])) == C_ERR) {
zfree(slots);
zfree(slots);
return;
return;
}
}
if (slots[slot]++ == 1) {
if ((endslot = getSlotOrReply(c,c->argv[j+1])) == C_ERR) {
addReplyErrorFormat(c,"Slot %d specified multiple times",
zfree(slots);
(int)slot);
return;
}
if (startslot > endslot) {
addReplyErrorFormat(c,"start slot number %d is greater than end slot number %d", startslot, endslot);
zfree(slots);
zfree(slots);
return;
return;
}
}
}
for (j = 0; j < CLUSTER_SLOTS; j++) {
if (slots[j]) {
int retval;
/* If this slot was set as importing we can clear this
* state as now we are the real owner of the slot. */
if (server.cluster->importing_slots_from[j])
server.cluster->importing_slots_from[j] = NULL;
retval = del ? clusterDelSlot(j
)
:
if (checkSlotAssignmentsOrReply(c, slots, del, startslot, endslot) == C_ERR
)
{
clusterAddSlot(myself,j
);
zfree(slots
);
serverAssertWithInfo(c,NULL,retval == C_OK)
;
return
;
}
}
}
}
clusterUpdateSlots(c, slots, del);
zfree(slots);
zfree(slots);
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG);
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG);
addReply(c,shared.ok);
addReply(c,shared.ok);
...
...
tests/cluster/tests/23-multiple-slot-operations.tcl
0 → 100644
View file @
5fb4adba
# Check the multiple slot add and remove commands
source
"../tests/includes/init-tests.tcl"
proc cluster_allocate_with_continuous_slots
{
n
}
{
R 0 cluster ADDSLOTSRANGE 0 3276
R 1 cluster ADDSLOTSRANGE 3277 6552
R 2 cluster ADDSLOTSRANGE 6553 9828
R 3 cluster ADDSLOTSRANGE 9829 13104
R 4 cluster ADDSLOTSRANGE 13105 16383
}
proc cluster_create_with_continuous_slots
{
masters slaves
}
{
cluster_allocate_with_continuous_slots $masters
if
{
$slaves
}
{
cluster_allocate_slaves $masters $slaves
}
assert_cluster_state ok
}
test
"Create a 5 nodes cluster"
{
cluster_create_with_continuous_slots 5 5
}
test
"Cluster should start ok"
{
assert_cluster_state ok
}
set master1
[
Rn 0
]
set master2
[
Rn 1
]
set master3
[
Rn 2
]
set master4
[
Rn 3
]
set master5
[
Rn 4
]
test
"Continuous slots distribution"
{
assert_match
"* 0-3276*"
[
$master1
CLUSTER NODES
]
assert_match
"* 3277-6552*"
[
$master2
CLUSTER NODES
]
assert_match
"* 6553-9828*"
[
$master3
CLUSTER NODES
]
assert_match
"* 9829-13104*"
[
$master4
CLUSTER NODES
]
assert_match
"* 13105-16383*"
[
$master5
CLUSTER NODES
]
assert_match
"*0 3276*"
[
$master1
CLUSTER SLOTS
]
assert_match
"*3277 6552*"
[
$master2
CLUSTER SLOTS
]
assert_match
"*6553 9828*"
[
$master3
CLUSTER SLOTS
]
assert_match
"*9829 13104*"
[
$master4
CLUSTER SLOTS
]
assert_match
"*13105 16383*"
[
$master5
CLUSTER SLOTS
]
$master1 CLUSTER DELSLOTSRANGE 3001 3050
assert_match
"* 0-3000 3051-3276*"
[
$master1
CLUSTER NODES
]
assert_match
"*0 3000*3051 3276*"
[
$master1
CLUSTER SLOTS
]
$master2 CLUSTER DELSLOTSRANGE 5001 5500
assert_match
"* 3277-5000 5501-6552*"
[
$master2
CLUSTER NODES
]
assert_match
"*3277 5000*5501 6552*"
[
$master2
CLUSTER SLOTS
]
$master3 CLUSTER DELSLOTSRANGE 7001 7100 8001 8500
assert_match
"* 6553-7000 7101-8000 8501-9828*"
[
$master3
CLUSTER NODES
]
assert_match
"*6553 7000*7101 8000*8501 9828*"
[
$master3
CLUSTER SLOTS
]
$master4 CLUSTER DELSLOTSRANGE 11001 12000 12101 12200
assert_match
"* 9829-11000 12001-12100 12201-13104*"
[
$master4
CLUSTER NODES
]
assert_match
"*9829 11000*12001 12100*12201 13104*"
[
$master4
CLUSTER SLOTS
]
$master5 CLUSTER DELSLOTSRANGE 13501 14000 15001 16000
assert_match
"* 13105-13500 14001-15000 16001-16383*"
[
$master5
CLUSTER NODES
]
assert_match
"*13105 13500*14001 15000*16001 16383*"
[
$master5
CLUSTER SLOTS
]
}
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