Optimize computing fields in pod

This commit is contained in:
Wojciech Tyczynski 2016-10-20 10:51:19 +02:00
parent d7e70bd448
commit c54d09d14e
4 changed files with 43 additions and 26 deletions

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
apistorage "k8s.io/kubernetes/pkg/storage" pkgstorage "k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/validation/field"
) )
@ -80,16 +80,31 @@ func (endpointsStrategy) AllowUnconditionalUpdate() bool {
} }
// MatchEndpoints returns a generic matcher for a given label and field selector. // MatchEndpoints returns a generic matcher for a given label and field selector.
func MatchEndpoints(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate { func MatchEndpoints(label labels.Selector, field fields.Selector) pkgstorage.SelectionPredicate {
return apistorage.SelectionPredicate{Label: label, Field: field, GetAttrs: EndpointsAttributes} return pkgstorage.SelectionPredicate{
} Label: label,
Field: field,
// EndpointsAttributes returns the attributes of an endpoint such that a GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
// SelectionPredicate can match appropriately.
func EndpointsAttributes(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) {
endpoints, ok := obj.(*api.Endpoints) endpoints, ok := obj.(*api.Endpoints)
if !ok { if !ok {
return nil, nil, fmt.Errorf("invalid object type %#v", obj) return nil, nil, fmt.Errorf("invalid object type %#v", obj)
} }
return endpoints.Labels, generic.ObjectMetaFieldsSet(&endpoints.ObjectMeta, true), nil
// Compute fields only if field selectors is non-empty
// (otherwise those won't be used).
// Those are generally also not needed if label selector does
// not match labels, but additional computation of it is expensive.
var endpointsFields fields.Set
if !field.Empty() {
endpointsFields = EndpointsToSelectableFields(endpoints)
}
return endpoints.Labels, endpointsFields, nil
},
}
}
// EndpointsToSelectableFields returns a field set that represents the object
// TODO: fields are not labels, and the validation rules for them do not apply.
func EndpointsToSelectableFields(endpoints *api.Endpoints) fields.Set {
return generic.ObjectMetaFieldsSet(&endpoints.ObjectMeta, true)
} }

View File

@ -25,14 +25,10 @@ import (
) )
func TestSelectableFieldLabelConversions(t *testing.T) { func TestSelectableFieldLabelConversions(t *testing.T) {
_, fieldsSet, err := EndpointsAttributes(&api.Endpoints{})
if err != nil {
t.Fatal(err)
}
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
registered.GroupOrDie(api.GroupName).GroupVersion.String(), registered.GroupOrDie(api.GroupName).GroupVersion.String(),
"Endpoints", "Endpoints",
fieldsSet, EndpointsToSelectableFields(&api.Endpoints{}),
nil, nil,
) )
} }

View File

@ -154,7 +154,16 @@ func MatchNode(label labels.Selector, field fields.Selector) pkgstorage.Selectio
if !ok { if !ok {
return nil, nil, fmt.Errorf("not a node") return nil, nil, fmt.Errorf("not a node")
} }
return labels.Set(nodeObj.ObjectMeta.Labels), NodeToSelectableFields(nodeObj), nil
// Compute fields only if field selectors is non-empty
// (otherwise those won't be used).
// Those are generally also not needed if label selector does
// not match labels, but additional computation of it is expensive.
var nodeFields fields.Set
if !field.Empty() {
nodeFields = NodeToSelectableFields(nodeObj)
}
return labels.Set(nodeObj.ObjectMeta.Labels), nodeFields, nil
}, },
IndexFields: []string{"metadata.name"}, IndexFields: []string{"metadata.name"},
} }

View File

@ -166,18 +166,15 @@ func MatchPod(label labels.Selector, field fields.Selector) storage.SelectionPre
return nil, nil, fmt.Errorf("not a pod") return nil, nil, fmt.Errorf("not a pod")
} }
// podLabels is already sitting there ready to be used. // Compute fields only if field selectors is non-empty
// podFields is not available directly and requires allocation of a map. // (otherwise those won't be used).
// Only bother if the fields might be useful to determining the match. // Those are generally also not needed if label selector does
// One common case is for a replication controller to set up a watch // not match labels, but additional computation of it is expensive.
// based on labels alone; in that case we can avoid allocating the field map.
// This is especially important in the apiserver.
podLabels := labels.Set(pod.ObjectMeta.Labels)
var podFields fields.Set var podFields fields.Set
if !field.Empty() && label.Matches(podLabels) { if !field.Empty() {
podFields = PodToSelectableFields(pod) podFields = PodToSelectableFields(pod)
} }
return podLabels, podFields, nil return labels.Set(pod.ObjectMeta.Labels), podFields, nil
}, },
IndexFields: []string{"spec.nodeName"}, IndexFields: []string{"spec.nodeName"},
} }