mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-18 22:40:35 +00:00
feat: optimize ListAll and ListAllByNamespace to return directly when nothing to select
Signed-off-by: likakuli <1154584512@qq.com>
This commit is contained in:
@@ -23,11 +23,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -115,6 +116,15 @@ func Nothing() Selector {
|
||||
return sharedNothingSelector
|
||||
}
|
||||
|
||||
// MatchesNothing only returns true for selectors which are definitively determined to match no objects.
|
||||
// This currently only detects the `labels.Nothing()` selector, but may change over time to detect more selectors that match no objects.
|
||||
//
|
||||
// Note: The current implementation does not check for selector conflict scenarios (e.g., a=a,a!=a).
|
||||
// Support for detecting such cases can be added in the future.
|
||||
func MatchesNothing(selector Selector) bool {
|
||||
return selector == sharedNothingSelector
|
||||
}
|
||||
|
||||
// NewSelector returns a nil selector
|
||||
func NewSelector() Selector {
|
||||
return internalSelector(nil)
|
||||
|
||||
@@ -1099,3 +1099,114 @@ func TestRequirementEqual(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchesNothing(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
selector string
|
||||
set map[string]string
|
||||
labelSelector Selector
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "MatchNothing should match Nothing()",
|
||||
labelSelector: Nothing(),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should match sharedNothingSelector",
|
||||
labelSelector: sharedNothingSelector,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match Everything()",
|
||||
labelSelector: Everything(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match sharedEverythingSelector",
|
||||
labelSelector: sharedEverythingSelector,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match empty set",
|
||||
set: map[string]string{},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty set",
|
||||
set: map[string]string{"key": "value"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match empty selector",
|
||||
selector: "",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - exists",
|
||||
selector: "a",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - not exists",
|
||||
selector: "!a",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - equals",
|
||||
selector: "a=b",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - not equals",
|
||||
selector: "a!=b",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - in",
|
||||
selector: "a in (b)",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - notin",
|
||||
selector: "a notin (b)",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - conflict exists and not exists",
|
||||
selector: "a,!a",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - conflict equals and not equals",
|
||||
selector: "a=b,a!=b",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "MatchNothing should not match non-empty selector - conflict in and notin",
|
||||
selector: "a in (b),a notin (b)",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < len(tests); i++ {
|
||||
if tests[i].labelSelector != nil {
|
||||
expectMatchNothing(t, tests[i].labelSelector, tests[i].want)
|
||||
} else if tests[i].set != nil {
|
||||
expectMatchNothing(t, SelectorFromSet(tests[i].set), tests[i].want)
|
||||
} else {
|
||||
selector, err := Parse(tests[i].selector)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to parse %v as a selector.\n", selector)
|
||||
}
|
||||
expectMatchNothing(t, selector, tests[i].want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func expectMatchNothing(t *testing.T, selector Selector, want bool) {
|
||||
if MatchesNothing(selector) != want {
|
||||
t.Errorf("Wanted %s to MatchNothing '%t', but it did not.\n", selector, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 labels.MatchesNothing(selector) {
|
||||
return nil
|
||||
}
|
||||
|
||||
selectAll := selector.Empty()
|
||||
for _, m := range store.List() {
|
||||
if selectAll {
|
||||
@@ -55,6 +59,10 @@ func ListAll(store Store, selector labels.Selector, appendFn AppendFunc) error {
|
||||
// calling appendFn on each one.
|
||||
// If a blank namespace (NamespaceAll) is specified, this delegates to ListAll().
|
||||
func ListAllByNamespace(indexer Indexer, namespace string, selector labels.Selector, appendFn AppendFunc) error {
|
||||
if labels.MatchesNothing(selector) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if namespace == metav1.NamespaceAll {
|
||||
return ListAll(indexer, selector, appendFn)
|
||||
}
|
||||
|
||||
@@ -138,3 +138,23 @@ func BenchmarkLister_Match_100k_100(b *testing.B) {
|
||||
func BenchmarkLister_Match_1M_100(b *testing.B) {
|
||||
benchmarkLister(b, 1000000, 100, map[string]string{"match": "true"})
|
||||
}
|
||||
|
||||
func benchmarkNothingLister(b *testing.B, numObjects int, numMatching int, labelSelector *metav1.LabelSelector) {
|
||||
store := mustCreateStore(numObjects, numMatching, nil)
|
||||
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
|
||||
if err != nil {
|
||||
b.Fatalf("LabelSelectorAsSelector returned an error: %v", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
err := ListAll(store, selector, func(m interface{}) {
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatalf("ListAll returned an error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLister_Match_1M_0(b *testing.B) {
|
||||
benchmarkNothingLister(b, 1000000, 0, nil)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user