diff --git a/pkg/controller/instanceset/instance_util.go b/pkg/controller/instanceset/instance_util.go index 3ddf299e166..40f29e27d39 100644 --- a/pkg/controller/instanceset/instance_util.go +++ b/pkg/controller/instanceset/instance_util.go @@ -82,8 +82,7 @@ func parseParentNameAndOrdinal(s string) (string, int) { // reverse it if reverse==true func sortObjects[T client.Object](objects []T, rolePriorityMap map[string]int, reverse bool) { getRolePriorityFunc := func(i int) int { - role := strings.ToLower(objects[i].GetLabels()[constant.RoleLabelKey]) - return rolePriorityMap[role] + return getRolePriority(rolePriorityMap, objects[i].GetLabels()[constant.RoleLabelKey]) } // cache the parent names and ordinals to accelerate the parsing process when there is a massive number of Pods. diff --git a/pkg/controller/instanceset/update_plan.go b/pkg/controller/instanceset/update_plan.go index 39c0c3158a6..dc473b8d2b7 100644 --- a/pkg/controller/instanceset/update_plan.go +++ b/pkg/controller/instanceset/update_plan.go @@ -154,11 +154,12 @@ func (p *realUpdatePlan) buildBestEffortParallelUpdatePlan(rolePriorityMap map[s quorumPriority := math.MaxInt32 leaderPriority := 0 for _, role := range p.its.Spec.Roles { - if rolePriorityMap[role.Name] > leaderPriority { - leaderPriority = rolePriorityMap[role.Name] + rolePriority := getRolePriority(rolePriorityMap, role.Name) + if rolePriority > leaderPriority { + leaderPriority = rolePriority } - if role.ParticipatesInQuorum && quorumPriority > rolePriorityMap[role.Name] { - quorumPriority = rolePriorityMap[role.Name] + if role.ParticipatesInQuorum && quorumPriority > rolePriority { + quorumPriority = rolePriority } } @@ -167,7 +168,7 @@ func (p *realUpdatePlan) buildBestEffortParallelUpdatePlan(rolePriorityMap map[s podList := p.pods for i, pod := range podList { roleName := getRoleName(&pod) - if rolePriorityMap[roleName] < quorumPriority { + if getRolePriority(rolePriorityMap, roleName) < quorumPriority { vertex := &model.ObjectVertex{Obj: &podList[i]} p.dag.AddConnect(preVertex, vertex) currentVertex = vertex @@ -181,7 +182,7 @@ func (p *realUpdatePlan) buildBestEffortParallelUpdatePlan(rolePriorityMap map[s followerCount := 0 for _, pod := range podList { roleName := getRoleName(&pod) - if rolePriorityMap[roleName] < leaderPriority { + if getRolePriority(rolePriorityMap, roleName) < leaderPriority { followerCount++ } } diff --git a/pkg/controller/instanceset/update_plan_test.go b/pkg/controller/instanceset/update_plan_test.go index 1d86f6a5e38..2375bd4903d 100644 --- a/pkg/controller/instanceset/update_plan_test.go +++ b/pkg/controller/instanceset/update_plan_test.go @@ -170,6 +170,26 @@ var _ = Describe("update plan test.", func() { checkPlan(expectedPlan, true) }) + It("should preserve best effort parallel layers with mixed-case roles", func() { + its.Spec.MemberUpdateStrategy = ptr.To(workloads.BestEffortParallelUpdateStrategy) + its.Spec.Roles = []workloads.ReplicaRole{ + {Name: "Follower", ParticipatesInQuorum: true, UpdatePriority: 1}, + {Name: "Leader", ParticipatesInQuorum: true, UpdatePriority: 2}, + } + for _, pod := range []*corev1.Pod{pod0, pod3, pod6} { + pod.Labels[RoleLabelKey] = "Follower" + } + pod5.Labels[RoleLabelKey] = "Leader" + + expectedPlan := [][]*corev1.Pod{ + {pod4, pod2, pod1}, + {pod6}, + {pod3, pod0}, + {pod5}, + } + checkPlan(expectedPlan, true) + }) + It("should work well with role-less and heterogeneous pods", func() { By("build a serial plan with role-less and heterogeneous pods") its.Spec.MemberUpdateStrategy = ptr.To(workloads.SerialUpdateStrategy) diff --git a/pkg/controller/instanceset/utils.go b/pkg/controller/instanceset/utils.go index edc75c866eb..04f1654156e 100644 --- a/pkg/controller/instanceset/utils.go +++ b/pkg/controller/instanceset/utils.go @@ -53,13 +53,16 @@ func ComposeRolePriorityMap(roles []workloads.ReplicaRole) map[string]int { return rolePriorityMap } +func getRolePriority(rolePriorityMap map[string]int, roleName string) int { + return rolePriorityMap[strings.ToLower(roleName)] +} + // SortPods sorts pods by their role priority // e.g.: unknown -> empty -> learner -> follower1 -> follower2 -> leader, with follower1.Name > follower2.Name // reverse it if reverse==true func SortPods(pods []corev1.Pod, rolePriorityMap map[string]int, reverse bool) { getRolePriorityFunc := func(i int) int { - role := getRoleName(&pods[i]) - return rolePriorityMap[role] + return getRolePriority(rolePriorityMap, getRoleName(&pods[i])) } getNameNOrdinalFunc := func(i int) (string, int) { return parseParentNameAndOrdinal(pods[i].GetName())