summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2016-05-02 16:41:56 +0200
committerantirez <antirez@gmail.com>2016-05-05 14:00:23 +0200
commitd8679070b8d41df8cfa88584086b3b0910ecf10b (patch)
treee67409f6cfbd462272e89b630da7852e63b8ab16
parentca300f2d14f89cddfcf91480ff8a81ba00f1431f (diff)
downloadredis-d8679070b8d41df8cfa88584086b3b0910ecf10b.tar.gz
New masters with slots are now targets of migration if others are.
This fixes issue #3043. Before this fix, after a complete resharding of a master slots to other nodes, the master remains empty and the slaves migrate away to other masters with non-zero nodes. However the old master now empty, is no longer considered a target for migration, because the system has no way to tell it had slaves in the past. This fix leaves the algorithm used in the past untouched, but adds a new rule. When a new or old master which is empty and without slaves, are assigend with their first slot, if other masters in the cluster have slaves, they are automatically considered to be targets for replicas migration.
-rw-r--r--src/cluster.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/src/cluster.c b/src/cluster.c
index 14e8b321f..46dc27b2e 100644
--- a/src/cluster.c
+++ b/src/cluster.c
@@ -3356,11 +3356,45 @@ void bitmapClearBit(unsigned char *bitmap, int pos) {
bitmap[byte] &= ~(1<<bit);
}
+/* Return non-zero if there is at least one master with slaves in the cluster.
+ * Otherwise zero is returned. Used by clusterNodeSetSlotBit() to set the
+ * MIGRATE_TO flag the when a master gets the first slot. */
+int clusterMastersHaveSlaves(void) {
+ dictIterator *di = dictGetSafeIterator(server.cluster->nodes);
+ dictEntry *de;
+ int slaves = 0;
+ while((de = dictNext(di)) != NULL) {
+ clusterNode *node = dictGetVal(de);
+
+ if (nodeIsSlave(node)) continue;
+ slaves += node->numslaves;
+ }
+ dictReleaseIterator(di);
+ return slaves != 0;
+}
+
/* Set the slot bit and return the old value. */
int clusterNodeSetSlotBit(clusterNode *n, int slot) {
int old = bitmapTestBit(n->slots,slot);
bitmapSetBit(n->slots,slot);
- if (!old) n->numslots++;
+ if (!old) {
+ n->numslots++;
+ /* When a master gets its first slot, even if it has no slaves,
+ * it gets flagged with MIGRATE_TO, that is, the master is a valid
+ * target for replicas migration, if and only if at least one of
+ * the other masters has slaves right now.
+ *
+ * Normally masters are valid targerts of replica migration if:
+ * 1. The used to have slaves (but no longer have).
+ * 2. They are slaves failing over a master that used to have slaves.
+ *
+ * However new masters with slots assigned are considered valid
+ * migration tagets if the rest of the cluster is not a slave-less.
+ *
+ * See https://github.com/antirez/redis/issues/3043 for more info. */
+ if (n->numslots == 1 && clusterMastersHaveSlaves())
+ n->flags |= REDIS_NODE_MIGRATE_TO;
+ }
return old;
}