func (m *MigrateManager) HandleNodeStateChange(cluster *topo.Cluster) { // 如果存在迁移任务,先跳过,等结束后再处理 if len(m.tasks) > 0 { goto done } // 处理主节点的迁移任务重建 for _, node := range cluster.AllNodes() { if node.Fail { continue } // Wait a while if time.Now().Sub(m.lastTaskEndTime) < 5*time.Second { continue } for id, slots := range node.Migrating { // 根据slot生成ranges ranges := []topo.Range{} for _, slot := range slots { // 如果是自己 if id == node.Id { redis.SetSlot(node.Addr(), slot, redis.SLOT_STABLE, "") } else { ranges = append(ranges, topo.Range{Left: slot, Right: slot}) } } // Source source := node if !node.IsMaster() { srs := cluster.FindReplicaSetByNode(node.Id) if srs != nil { source = srs.Master } } // Target rs := cluster.FindReplicaSetByNode(id) if source.Fail || rs.Master.Fail { continue } _, err := m.CreateTask(source.Id, rs.Master.Id, ranges, cluster) if err != nil { log.Warningf(node.Addr(), "Can not recover migrate task, %v", err) } else { log.Warningf(node.Addr(), "Will recover migrating task for node %s(%s) with MIGRATING info"+ ", Task(Source:%s, Target:%s).", node.Id, node.Addr(), source.Addr(), rs.Master.Addr()) goto done } } for id, slots := range node.Importing { // 根据slot生成ranges ranges := []topo.Range{} for _, slot := range slots { // 如果是自己 if id == node.Id { redis.SetSlot(node.Addr(), slot, redis.SLOT_STABLE, "") } else { ranges = append(ranges, topo.Range{Left: slot, Right: slot}) } } // Target target := node if !node.IsMaster() { trs := cluster.FindReplicaSetByNode(node.Id) if trs != nil { target = trs.Master } } if target.IsStandbyMaster() { s := cluster.FindNodeBySlot(ranges[0].Left) if s != nil { log.Warningf(node.Addr(), "Reset migrate task target to %s(%s)", s.Id, s.Addr()) target = s } } // Source rs := cluster.FindReplicaSetByNode(id) if target.Fail || rs.Master.Fail { continue } _, err := m.CreateTask(rs.Master.Id, target.Id, ranges, cluster) if err != nil { log.Warningf(node.Addr(), "Can not recover migrate task, %v", err) } else { log.Warningf(node.Addr(), "Will recover migrating task for node %s(%s) with IMPORTING info"+ ", Task(Source:%s,Target:%s).", node.Id, node.Addr(), rs.Master.Addr(), target.Addr()) goto done } } } done: for _, task := range m.tasks { if task.CurrentState() != StateDone { m.handleTaskChange(task, cluster) } } }