Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Don't create new sets when checking compatibility #1953

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions pkg/scheduling/requirement.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,46 @@ func (r *Requirement) Intersection(requirement *Requirement) *Requirement {
return &Requirement{Key: r.Key, values: values, complement: complement, greaterThan: greaterThan, lessThan: lessThan, MinValues: minValues}
}

// nolint:gocyclo
// HasIntersection is a more efficient implementation of Intersection
// It validates whether there is an intersection between the two requirements without actually creating the sets
// This prevents the garbage collector from having to spend cycles cleaning up all of these created set objects
func (r *Requirement) HasIntersection(requirement *Requirement) bool {
greaterThan := maxIntPtr(r.greaterThan, requirement.greaterThan)
lessThan := minIntPtr(r.lessThan, requirement.lessThan)
if greaterThan != nil && lessThan != nil && *greaterThan >= *lessThan {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just double checking - is this supposed to be *greaterThan >= *lessThan and not *greaterThan > *lessThan? Wouldn't there be an intersection if these exist and have overlap?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, because you are saying that a requirement is valid if, for instance -- elem > 4 and also elem < 4 -- there is no such value that satisfies both

return false
}
// Both requirements have a complement
if r.complement && requirement.complement {
return true
}
// Only one requirement has a complement
if r.complement && !requirement.complement {
for value := range requirement.values {
if !r.values.Has(value) && withinIntPtrs(value, greaterThan, lessThan) {
return true
}
}
return false
}
if !r.complement && requirement.complement {
for value := range r.values {
if !requirement.values.Has(value) && withinIntPtrs(value, greaterThan, lessThan) {
return true
}
}
return false
}
// Both requirements are non-complement requirements
for value := range r.values {
if requirement.values.Has(value) && withinIntPtrs(value, greaterThan, lessThan) {
return true
}
}
return false
}

func (r *Requirement) Any() string {
switch r.Operator() {
case corev1.NodeSelectorOpIn:
Expand Down
3 changes: 1 addition & 2 deletions pkg/scheduling/requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,7 @@ func (r Requirements) Intersects(requirements Requirements) (errs error) {
for key := range r.intersectKeys(requirements) {
existing := r.Get(key)
incoming := requirements.Get(key)
// There must be some value, except
if existing.Intersection(incoming).Len() == 0 {
if !existing.HasIntersection(incoming) {
// where the incoming requirement has operator { NotIn, DoesNotExist }
if operator := incoming.Operator(); operator == corev1.NodeSelectorOpNotIn || operator == corev1.NodeSelectorOpDoesNotExist {
// and the existing requirement has operator { NotIn, DoesNotExist }
Expand Down