Skip to content

Commit

Permalink
Update selectByGroups
Browse files Browse the repository at this point in the history
  • Loading branch information
hexiaofeng committed Aug 19, 2024
1 parent 693b26c commit a980117
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 30 deletions.
65 changes: 35 additions & 30 deletions pkg/scheduler/core/spreadconstraint/group_election.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ func (root *groupRoot) Elect() ([]*clusterv1alpha1.Cluster, error) {
election, err := root.selectCluster(root.Replicas)
if err != nil {
return nil, err
} else {
return toCluster(sortClusters(election.Clusters)), nil
} else if root.Replicas > 0 && election.Replicas < root.Replicas {
return nil, fmt.Errorf("no enough resource when selecting %d clusters", len(election.Clusters))
}
return toCluster(sortClusters(election.Clusters)), nil
}

// selectCluster method to select clusters based on the required replicas
func (node *groupNode) selectCluster(replicas int32) (*candidate, error) {
if node.Leaf {
return node.selectByClusters(replicas)
} else {
return node.selectByGroups(replicas)
}
return node.selectByGroups(replicas)
}

// selectByClusters selects clusters from the current group's Clusters list
Expand All @@ -49,7 +49,7 @@ func (node *groupNode) selectByClusters(replicas int32) (*candidate, error) {
Name: node.Name,
}
for _, cluster := range node.Clusters {
if replicas == InvalidReplicas || cluster.AvailableReplicas > 0 {
if replicas <= 0 || cluster.AvailableReplicas > 0 {
result.Clusters = append(result.Clusters, cluster)
}
}
Expand All @@ -62,23 +62,28 @@ func (node *groupNode) selectByClusters(replicas int32) (*candidate, error) {
func (node *groupNode) selectByGroups(replicas int32) (*candidate, error) {
if !node.Valid {
return nil, errors.New("the number of feasible clusters is less than spreadConstraint.MinGroups")
} else {
// the groups of valid nod are ordered by score desc.
var candidates []*candidate
// use DFS to find the best path
paths := node.findPaths(replicas)
if len(paths) == 0 {
return nil, fmt.Errorf("no enough resource when selecting %d %ss", node.MaxGroups, node.Constraint)
}
path := node.selectBest(paths)
}
// use DFS to find the best path
paths := node.findPaths(replicas)
if len(paths) == 0 {
return nil, fmt.Errorf("no enough resource when selecting %d %ss", node.MaxGroups, node.Constraint)
}

var results []*candidate
for _, path := range paths {
// TODO optimize
var candidates []*candidate
for _, node := range path.Nodes {
participant, _ := node.Group.selectCluster(ternary(replicas == InvalidReplicas, InvalidReplicas, node.Replicas))
candidates = append(candidates, participant)
candidate, _ := node.Group.selectCluster(ternary(replicas <= 0, replicas, replicas-path.Replicas+node.Replicas))
candidates = append(candidates, candidate)
}

return node.merge(candidates), nil
candidate := node.merge(candidates)
candidate.Id = path.Id
candidate.Name = node.Name
results = append(results, candidate)
}

return node.selectBest(results), nil
}

// findPaths finds all possible paths of groups that meet the required replicas using DFS.
Expand All @@ -88,8 +93,8 @@ func (node *groupNode) findPaths(replicas int32) (paths []*dfsPath) {
var dfsFunc func(int, *dfsPath)
dfsFunc = func(start int, current *dfsPath) {
length := current.length()
if replicas == InvalidReplicas && length == node.MaxGroups ||
(replicas != InvalidReplicas && current.Replicas >= replicas && length > 0 &&
if replicas <= 0 && length == node.MaxGroups ||
(replicas > 0 && current.Replicas >= replicas && length > 0 &&
(node.MinGroups <= 0 || length >= node.MinGroups)) {
paths = append(paths, current.next())
} else if length < node.MaxGroups {
Expand All @@ -106,22 +111,22 @@ func (node *groupNode) findPaths(replicas int32) (paths []*dfsPath) {
return paths
}

// selectBest selects the best path from the given paths based on the maximum score and replicas.
func (node *groupNode) selectBest(paths []*dfsPath) *dfsPath {
size := len(paths)
// selectBest selects the best candidates from the given candidates based on the maximum score and replicas.
func (node *groupNode) selectBest(candidates []*candidate) *candidate {
size := len(candidates)
if size == 0 {
return nil
} else if size > 1 {
sort.Slice(paths, func(i, j int) bool {
if paths[i].MaxScore != paths[j].MaxScore {
return paths[i].MaxScore > paths[j].MaxScore
} else if paths[i].Replicas != paths[j].Replicas {
return paths[i].Replicas > paths[j].Replicas
sort.Slice(candidates, func(i, j int) bool {
if candidates[i].MaxScore != candidates[j].MaxScore {
return candidates[i].MaxScore > candidates[j].MaxScore
} else if candidates[i].Replicas != candidates[j].Replicas {
return candidates[i].Replicas > candidates[j].Replicas
}
return paths[i].Id < paths[j].Id
return candidates[i].Id < candidates[j].Id
})
}
return paths[0]
return candidates[0]
}

// merge combines a list of candidate objects into a single candidate.
Expand Down
1 change: 1 addition & 0 deletions pkg/scheduler/core/spreadconstraint/group_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type groupBuilder struct {
// candidate represents a group with its name, highest cluster score, number of available replicas,
// and a list of clusters sorted by their maximum score in descending order.
type candidate struct {
Id int // Unique identifier for the candidate.

Check failure on line 61 in pkg/scheduler/core/spreadconstraint/group_type.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field Id should be ID (revive)
Name string // The name of the group.
MaxScore int64 // The highest cluster score in this group.
Replicas int32 // Number of available replicas in this group.
Expand Down

0 comments on commit a980117

Please sign in to comment.