mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
Merge pull request #112648 from howardjohn/set/optimize-set-selector
Optimize turning a Set into a Selector
This commit is contained in:
commit
d4e38325ae
@ -77,6 +77,8 @@ func (ls Set) AsValidatedSelector() (Selector, error) {
|
|||||||
// perform any validation.
|
// perform any validation.
|
||||||
// According to our measurements this is significantly faster
|
// According to our measurements this is significantly faster
|
||||||
// in codepaths that matter at high scale.
|
// in codepaths that matter at high scale.
|
||||||
|
// Note: this method copies the Set; if the Set is immutable, consider wrapping it with ValidatedSetSelector
|
||||||
|
// instead, which does not copy.
|
||||||
func (ls Set) AsSelectorPreValidated() Selector {
|
func (ls Set) AsSelectorPreValidated() Selector {
|
||||||
return SelectorFromValidatedSet(ls)
|
return SelectorFromValidatedSet(ls)
|
||||||
}
|
}
|
||||||
|
@ -948,6 +948,8 @@ func ValidatedSelectorFromSet(ls Set) (Selector, error) {
|
|||||||
// SelectorFromValidatedSet returns a Selector which will match exactly the given Set.
|
// SelectorFromValidatedSet returns a Selector which will match exactly the given Set.
|
||||||
// A nil and empty Sets are considered equivalent to Everything().
|
// A nil and empty Sets are considered equivalent to Everything().
|
||||||
// It assumes that Set is already validated and doesn't do any validation.
|
// It assumes that Set is already validated and doesn't do any validation.
|
||||||
|
// Note: this method copies the Set; if the Set is immutable, consider wrapping it with ValidatedSetSelector
|
||||||
|
// instead, which does not copy.
|
||||||
func SelectorFromValidatedSet(ls Set) Selector {
|
func SelectorFromValidatedSet(ls Set) Selector {
|
||||||
if ls == nil || len(ls) == 0 {
|
if ls == nil || len(ls) == 0 {
|
||||||
return internalSelector{}
|
return internalSelector{}
|
||||||
@ -969,3 +971,76 @@ func SelectorFromValidatedSet(ls Set) Selector {
|
|||||||
func ParseToRequirements(selector string, opts ...field.PathOption) ([]Requirement, error) {
|
func ParseToRequirements(selector string, opts ...field.PathOption) ([]Requirement, error) {
|
||||||
return parse(selector, field.ToPath(opts...))
|
return parse(selector, field.ToPath(opts...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatedSetSelector wraps a Set, allowing it to implement the Selector interface. Unlike
|
||||||
|
// Set.AsSelectorPreValidated (which copies the input Set), this type simply wraps the underlying
|
||||||
|
// Set. As a result, it is substantially more efficient. A nil and empty Sets are considered
|
||||||
|
// equivalent to Everything().
|
||||||
|
//
|
||||||
|
// Callers MUST ensure the underlying Set is not mutated, and that it is already validated. If these
|
||||||
|
// constraints are not met, Set.AsValidatedSelector should be preferred
|
||||||
|
//
|
||||||
|
// None of the Selector methods mutate the underlying Set, but Add() and Requirements() convert to
|
||||||
|
// the less optimized version.
|
||||||
|
type ValidatedSetSelector Set
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) Matches(labels Labels) bool {
|
||||||
|
for k, v := range s {
|
||||||
|
if !labels.Has(k) || v != labels.Get(k) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) Empty() bool {
|
||||||
|
return len(s) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) String() string {
|
||||||
|
keys := make([]string, 0, len(s))
|
||||||
|
for k := range s {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
// Ensure deterministic output
|
||||||
|
sort.Strings(keys)
|
||||||
|
b := strings.Builder{}
|
||||||
|
for i, key := range keys {
|
||||||
|
v := s[key]
|
||||||
|
b.Grow(len(key) + 2 + len(v))
|
||||||
|
if i != 0 {
|
||||||
|
b.WriteString(",")
|
||||||
|
}
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteString("=")
|
||||||
|
b.WriteString(v)
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) Add(r ...Requirement) Selector {
|
||||||
|
return s.toFullSelector().Add(r...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) Requirements() (requirements Requirements, selectable bool) {
|
||||||
|
return s.toFullSelector().Requirements()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) DeepCopySelector() Selector {
|
||||||
|
res := make(ValidatedSetSelector, len(s))
|
||||||
|
for k, v := range s {
|
||||||
|
res[k] = v
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) RequiresExactMatch(label string) (value string, found bool) {
|
||||||
|
v, f := s[label]
|
||||||
|
return v, f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ValidatedSetSelector) toFullSelector() Selector {
|
||||||
|
return SelectorFromValidatedSet(Set(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Selector = ValidatedSetSelector{}
|
||||||
|
@ -809,11 +809,70 @@ func BenchmarkSelectorFromValidatedSet(b *testing.B) {
|
|||||||
"foo": "foo",
|
"foo": "foo",
|
||||||
"bar": "bar",
|
"bar": "bar",
|
||||||
}
|
}
|
||||||
|
matchee := Set(map[string]string{
|
||||||
|
"foo": "foo",
|
||||||
|
"bar": "bar",
|
||||||
|
"extra": "label",
|
||||||
|
})
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
if SelectorFromValidatedSet(set).Empty() {
|
s := SelectorFromValidatedSet(set)
|
||||||
|
if s.Empty() {
|
||||||
b.Errorf("Unexpected selector")
|
b.Errorf("Unexpected selector")
|
||||||
}
|
}
|
||||||
|
if !s.Matches(matchee) {
|
||||||
|
b.Errorf("Unexpected match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSetSelector(b *testing.B) {
|
||||||
|
set := map[string]string{
|
||||||
|
"foo": "foo",
|
||||||
|
"bar": "bar",
|
||||||
|
}
|
||||||
|
matchee := Set(map[string]string{
|
||||||
|
"foo": "foo",
|
||||||
|
"bar": "bar",
|
||||||
|
"extra": "label",
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
s := ValidatedSetSelector(set)
|
||||||
|
if s.Empty() {
|
||||||
|
b.Errorf("Unexpected selector")
|
||||||
|
}
|
||||||
|
if !s.Matches(matchee) {
|
||||||
|
b.Errorf("Unexpected match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetSelectorString(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
set Set
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Set{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Set{"app": "foo"},
|
||||||
|
"app=foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Set{"app": "foo", "a": "b"},
|
||||||
|
"a=b,app=foo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range cases {
|
||||||
|
t.Run(tt.out, func(t *testing.T) {
|
||||||
|
if got := ValidatedSetSelector(tt.set).String(); tt.out != got {
|
||||||
|
t.Fatalf("expected %v, got %v", tt.out, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user