Skip to content

feat: optimize ListAll and ListAllByNamespace to return directly when nothing to select #132255

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

Merged
merged 1 commit into from
Jun 24, 2025

Conversation

likakuli
Copy link
Member

What type of PR is this?

/kind feature

What this PR does / why we need it:

The ListAll and ListAllByNamespace methods of the lister still perform a full (but ineffective) iteration even when the passed-in selector is labels.Nothing(). While it's possible to add a check at the call site to skip the operation when the selector is labels.Nothing(), this relies on developers to remember to do so, making it easy to miss such checks.
e.g.

func newAffinityTerm(pod *v1.Pod, term *v1.PodAffinityTerm) (*AffinityTerm, error) {
selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector)
if err != nil {
return nil, err
}
namespaces := getNamespacesFromPodAffinityTerm(pod, term)
nsSelector, err := metav1.LabelSelectorAsSelector(term.NamespaceSelector)
if err != nil {
return nil, err
}
return &AffinityTerm{Namespaces: namespaces, Selector: selector, TopologyKey: term.TopologyKey, NamespaceSelector: nsSelector}, nil
}

nsSelector will be labels.Nothing() if term.NamespaceSelector is nil.
func (pl *InterPodAffinity) mergeAffinityTermNamespacesIfNotEmpty(at *framework.AffinityTerm) error {
if at.NamespaceSelector.Empty() {
return nil
}
ns, err := pl.nsLister.List(at.NamespaceSelector)
if err != nil {
return err
}
for _, n := range ns {
at.Namespaces.Insert(n.Name)
}
at.NamespaceSelector = labels.Nothing()
return nil
}

at.NamespaceSelector is the nsSelector mentioned above. So when it is labels.Nothing(), it results in an unnecessary iteration over all namespaces when to call List function.

Which issue(s) this PR is related to:

Special notes for your reviewer:

Does this PR introduce a user-facing change?

NONE

Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:


@k8s-ci-robot k8s-ci-robot added release-note-none Denotes a PR that doesn't merit a release note. size/S Denotes a PR that changes 10-29 lines, ignoring generated files. kind/feature Categorizes issue or PR as related to a new feature. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Jun 12, 2025
@k8s-ci-robot
Copy link
Contributor

This issue is currently awaiting triage.

If a SIG or subproject determines this is a relevant issue, they will accept it by applying the triage/accepted label and provide further guidance.

The triage/accepted label can be added by org members by writing /triage accepted in a comment.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added the needs-priority Indicates a PR lacks a `priority/foo` label and requires one. label Jun 12, 2025
@k8s-ci-robot k8s-ci-robot added sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Jun 12, 2025
@likakuli
Copy link
Member Author

@liggitt kindly ping, can you pls help to review this pr, thanks

selector := labels.SelectorFromSet(label)
var selector labels.Selector
if label == nil {
selector = labels.Nothing()
Copy link
Member

@liggitt liggitt Jun 16, 2025

Choose a reason for hiding this comment

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

everywhere else, an empty labels map selects everything ...

// SelectorFromSet returns a Selector which will match exactly the given Set. A
// nil Set is considered equivalent to Everything().
func SelectorFromSet(ls Set) Selector {

making this switch so that an empty set selects nothing is really confusing and kind of breaking

Copy link
Member Author

Choose a reason for hiding this comment

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

not exactly
e.g.

func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
if ps == nil {
return labels.Nothing(), nil
}
if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 {
return labels.Everything(), nil
}

Copy link
Member

@liggitt liggitt Jun 16, 2025

Choose a reason for hiding this comment

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

a nil *LabelSelector means "match nothing"

an nil map[string]string label selector means "match everything"

@@ -32,6 +32,10 @@ type AppendFunc func(interface{})

// ListAll lists items in the store matching the given selector, calling appendFn on each one.
func ListAll(store Store, selector labels.Selector, appendFn AppendFunc) error {
if selector == labels.Nothing() {
Copy link
Member

Choose a reason for hiding this comment

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

Comparing an interface instance to a concrete value to determine if it is the special-case "match nothing" is a bit odd. I'm not sure whether it is better to add a new method to the labels.Selector interface so implementations can identify this case, or add a helper func MatchesNothing(selector labels.Selector) bool function to the labels package so we can keep the special comparison to the nothingSelector type local to the package.

cc @deads2k for an opinion

cc @munnerz who has spent some time thinking about optimizing / canonicalizing selectors (so something like matchExpressions: [{"key":"foo","operator":"Exists"}, {"key":"foo","operator":"DoesNotExist"}] would also correctly identify as matching nothing)

Copy link
Member Author

Choose a reason for hiding this comment

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

External callers might also need to check whether the selector is labels.Nothing(). Would it be ok to add a new function to the interface, similar to Empty()?

Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer func MatchesNothing(selector labels.Selector) with an implementation we can improve over time.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you all for the code review. The helper function has been added.

@likakuli likakuli force-pushed the feat-nothingfastreturn branch 2 times, most recently from 22bb2e4 to 01296b1 Compare June 19, 2025 02:59
@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jun 19, 2025
@likakuli likakuli force-pushed the feat-nothingfastreturn branch from 01296b1 to e8405e5 Compare June 20, 2025 03:49
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jun 20, 2025
@likakuli likakuli requested review from liggitt and deads2k June 23, 2025 02:17
@likakuli likakuli force-pushed the feat-nothingfastreturn branch from e8405e5 to 5a7e04b Compare June 24, 2025 13:13
@liggitt
Copy link
Member

liggitt commented Jun 24, 2025

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jun 24, 2025
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: 4124880b87ebe0f64250252dee71eadc7c199f63

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: liggitt, likakuli

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 24, 2025
@k8s-ci-robot k8s-ci-robot merged commit c379296 into kubernetes:master Jun 24, 2025
13 of 14 checks passed
@k8s-ci-robot k8s-ci-robot added this to the v1.34 milestone Jun 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. release-note-none Denotes a PR that doesn't merit a release note. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants