mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Merge pull request #89575 from tnqn/improve-tracker
Improve fake clientset performance
This commit is contained in:
commit
c968317ebd
@ -75,9 +75,9 @@ func TestList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected := []unstructured.Unstructured{
|
expected := []unstructured.Unstructured{
|
||||||
*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
|
|
||||||
*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
|
*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
|
||||||
*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
|
*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
|
||||||
|
*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
|
||||||
}
|
}
|
||||||
if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
|
if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
|
||||||
t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
|
t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
|
||||||
|
@ -79,9 +79,9 @@ func TestList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected := []metav1.PartialObjectMetadata{
|
expected := []metav1.PartialObjectMetadata{
|
||||||
*newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-foo"),
|
|
||||||
*newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-bar"),
|
*newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-bar"),
|
||||||
*newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-baz"),
|
*newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-baz"),
|
||||||
|
*newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-foo"),
|
||||||
}
|
}
|
||||||
if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
|
if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
|
||||||
t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
|
t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
|
||||||
|
@ -19,6 +19,7 @@ package testing
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
@ -197,7 +198,7 @@ type tracker struct {
|
|||||||
scheme ObjectScheme
|
scheme ObjectScheme
|
||||||
decoder runtime.Decoder
|
decoder runtime.Decoder
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
objects map[schema.GroupVersionResource][]runtime.Object
|
objects map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object
|
||||||
// The value type of watchers is a map of which the key is either a namespace or
|
// The value type of watchers is a map of which the key is either a namespace or
|
||||||
// all/non namespace aka "" and its value is list of fake watchers.
|
// all/non namespace aka "" and its value is list of fake watchers.
|
||||||
// Manipulations on resources will broadcast the notification events into the
|
// Manipulations on resources will broadcast the notification events into the
|
||||||
@ -214,7 +215,7 @@ func NewObjectTracker(scheme ObjectScheme, decoder runtime.Decoder) ObjectTracke
|
|||||||
return &tracker{
|
return &tracker{
|
||||||
scheme: scheme,
|
scheme: scheme,
|
||||||
decoder: decoder,
|
decoder: decoder,
|
||||||
objects: make(map[schema.GroupVersionResource][]runtime.Object),
|
objects: make(map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object),
|
||||||
watchers: make(map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher),
|
watchers: make(map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,31 +283,15 @@ func (t *tracker) Get(gvr schema.GroupVersionResource, ns, name string) (runtime
|
|||||||
return nil, errNotFound
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchingObjs []runtime.Object
|
matchingObj, ok := objs[types.NamespacedName{Namespace: ns, Name: name}]
|
||||||
for _, obj := range objs {
|
if !ok {
|
||||||
acc, err := meta.Accessor(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if acc.GetNamespace() != ns {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if acc.GetName() != name {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
matchingObjs = append(matchingObjs, obj)
|
|
||||||
}
|
|
||||||
if len(matchingObjs) == 0 {
|
|
||||||
return nil, errNotFound
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
if len(matchingObjs) > 1 {
|
|
||||||
return nil, fmt.Errorf("more than one object matched gvr %s, ns: %q name: %q", gvr, ns, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only one object should match in the tracker if it works
|
// Only one object should match in the tracker if it works
|
||||||
// correctly, as Add/Update methods enforce kind/namespace/name
|
// correctly, as Add/Update methods enforce kind/namespace/name
|
||||||
// uniqueness.
|
// uniqueness.
|
||||||
obj := matchingObjs[0].DeepCopyObject()
|
obj := matchingObj.DeepCopyObject()
|
||||||
if status, ok := obj.(*metav1.Status); ok {
|
if status, ok := obj.(*metav1.Status); ok {
|
||||||
if status.Status != metav1.StatusSuccess {
|
if status.Status != metav1.StatusSuccess {
|
||||||
return nil, &errors.StatusError{ErrStatus: *status}
|
return nil, &errors.StatusError{ErrStatus: *status}
|
||||||
@ -405,29 +390,29 @@ func (t *tracker) add(gvr schema.GroupVersionResource, obj runtime.Object, ns st
|
|||||||
return errors.NewBadRequest(msg)
|
return errors.NewBadRequest(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, existingObj := range t.objects[gvr] {
|
_, ok := t.objects[gvr]
|
||||||
oldMeta, err := meta.Accessor(existingObj)
|
if !ok {
|
||||||
if err != nil {
|
t.objects[gvr] = make(map[types.NamespacedName]runtime.Object)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if oldMeta.GetNamespace() == newMeta.GetNamespace() && oldMeta.GetName() == newMeta.GetName() {
|
|
||||||
|
namespacedName := types.NamespacedName{Namespace: newMeta.GetNamespace(), Name: newMeta.GetName()}
|
||||||
|
if _, ok = t.objects[gvr][namespacedName]; ok {
|
||||||
if replaceExisting {
|
if replaceExisting {
|
||||||
for _, w := range t.getWatches(gvr, ns) {
|
for _, w := range t.getWatches(gvr, ns) {
|
||||||
w.Modify(obj)
|
w.Modify(obj)
|
||||||
}
|
}
|
||||||
t.objects[gvr][i] = obj
|
t.objects[gvr][namespacedName] = obj
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.NewAlreadyExists(gr, newMeta.GetName())
|
return errors.NewAlreadyExists(gr, newMeta.GetName())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if replaceExisting {
|
if replaceExisting {
|
||||||
// Tried to update but no matching object was found.
|
// Tried to update but no matching object was found.
|
||||||
return errors.NewNotFound(gr, newMeta.GetName())
|
return errors.NewNotFound(gr, newMeta.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
t.objects[gvr] = append(t.objects[gvr], obj)
|
t.objects[gvr][namespacedName] = obj
|
||||||
|
|
||||||
for _, w := range t.getWatches(gvr, ns) {
|
for _, w := range t.getWatches(gvr, ns) {
|
||||||
w.Add(obj)
|
w.Add(obj)
|
||||||
@ -457,35 +442,28 @@ func (t *tracker) Delete(gvr schema.GroupVersionResource, ns, name string) error
|
|||||||
t.lock.Lock()
|
t.lock.Lock()
|
||||||
defer t.lock.Unlock()
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
found := false
|
objs, ok := t.objects[gvr]
|
||||||
|
if !ok {
|
||||||
for i, existingObj := range t.objects[gvr] {
|
return errors.NewNotFound(gvr.GroupResource(), name)
|
||||||
objMeta, err := meta.Accessor(existingObj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if objMeta.GetNamespace() == ns && objMeta.GetName() == name {
|
|
||||||
obj := t.objects[gvr][i]
|
namespacedName := types.NamespacedName{Namespace: ns, Name: name}
|
||||||
t.objects[gvr] = append(t.objects[gvr][:i], t.objects[gvr][i+1:]...)
|
obj, ok := objs[namespacedName]
|
||||||
|
if !ok {
|
||||||
|
return errors.NewNotFound(gvr.GroupResource(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(objs, namespacedName)
|
||||||
for _, w := range t.getWatches(gvr, ns) {
|
for _, w := range t.getWatches(gvr, ns) {
|
||||||
w.Delete(obj)
|
w.Delete(obj)
|
||||||
}
|
}
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if found {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.NewNotFound(gvr.GroupResource(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// filterByNamespace returns all objects in the collection that
|
// filterByNamespace returns all objects in the collection that
|
||||||
// match provided namespace. Empty namespace matches
|
// match provided namespace. Empty namespace matches
|
||||||
// non-namespaced objects.
|
// non-namespaced objects.
|
||||||
func filterByNamespace(objs []runtime.Object, ns string) ([]runtime.Object, error) {
|
func filterByNamespace(objs map[types.NamespacedName]runtime.Object, ns string) ([]runtime.Object, error) {
|
||||||
var res []runtime.Object
|
var res []runtime.Object
|
||||||
|
|
||||||
for _, obj := range objs {
|
for _, obj := range objs {
|
||||||
@ -499,6 +477,15 @@ func filterByNamespace(objs []runtime.Object, ns string) ([]runtime.Object, erro
|
|||||||
res = append(res, obj)
|
res = append(res, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort res to get deterministic order.
|
||||||
|
sort.Slice(res, func(i, j int) bool {
|
||||||
|
acc1, _ := meta.Accessor(res[i])
|
||||||
|
acc2, _ := meta.Accessor(res[j])
|
||||||
|
if acc1.GetNamespace() != acc2.GetNamespace() {
|
||||||
|
return acc1.GetNamespace() < acc2.GetNamespace()
|
||||||
|
}
|
||||||
|
return acc1.GetName() < acc2.GetName()
|
||||||
|
})
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user