mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-19 20:46:42 +00:00
* chore * perfromance improvements Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * perfromance improvements Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat(performance): removed duplicate client calls from all admission paths Signed-off-by: Oliver Baehler <oliver@sudo-i.net> --------- Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
128 lines
2.6 KiB
Go
128 lines
2.6 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package utils
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
type requestReadKey struct {
|
|
key client.ObjectKey
|
|
objectType reflect.Type
|
|
}
|
|
|
|
type requestReadResult struct {
|
|
object client.Object
|
|
err error
|
|
ready chan struct{}
|
|
}
|
|
|
|
type requestCachingReader struct {
|
|
client.Reader
|
|
|
|
mu sync.Mutex
|
|
results map[requestReadKey]requestReadResult
|
|
}
|
|
|
|
// NewRequestCachingReader deduplicates identical direct reads made by handlers
|
|
// participating in one admission request. Results are deep-copied before they
|
|
// are returned so one handler cannot mutate the snapshot observed by another.
|
|
func NewRequestCachingReader(reader client.Reader) client.Reader {
|
|
return &requestCachingReader{
|
|
Reader: reader,
|
|
results: make(map[requestReadKey]requestReadResult),
|
|
}
|
|
}
|
|
|
|
func (r *requestCachingReader) Get(
|
|
ctx context.Context,
|
|
key client.ObjectKey,
|
|
obj client.Object,
|
|
opts ...client.GetOption,
|
|
) error {
|
|
if len(opts) > 0 {
|
|
return r.Reader.Get(ctx, key, obj, opts...)
|
|
}
|
|
|
|
cacheKey := requestReadKey{
|
|
key: key,
|
|
objectType: reflect.TypeOf(obj),
|
|
}
|
|
|
|
r.mu.Lock()
|
|
if result, found := r.results[cacheKey]; found {
|
|
r.mu.Unlock()
|
|
<-result.ready
|
|
|
|
r.mu.Lock()
|
|
result = r.results[cacheKey]
|
|
r.mu.Unlock()
|
|
|
|
if result.object != nil {
|
|
if err := copyClientObject(result.object, obj); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return result.err
|
|
}
|
|
|
|
result := requestReadResult{ready: make(chan struct{})}
|
|
r.results[cacheKey] = result
|
|
r.mu.Unlock()
|
|
|
|
err := r.Reader.Get(ctx, key, obj)
|
|
if err == nil {
|
|
copied, ok := obj.DeepCopyObject().(client.Object)
|
|
if !ok {
|
|
result.err = fmt.Errorf("deep copy of %T does not implement client.Object", obj)
|
|
|
|
r.mu.Lock()
|
|
r.results[cacheKey] = result
|
|
close(result.ready)
|
|
r.mu.Unlock()
|
|
|
|
return result.err
|
|
}
|
|
|
|
result.object = copied
|
|
}
|
|
|
|
result.err = err
|
|
|
|
r.mu.Lock()
|
|
r.results[cacheKey] = result
|
|
close(result.ready)
|
|
r.mu.Unlock()
|
|
|
|
return err
|
|
}
|
|
|
|
func copyClientObject(src, dst client.Object) error {
|
|
srcCopy, ok := src.DeepCopyObject().(client.Object)
|
|
if !ok {
|
|
return fmt.Errorf("deep copy of %T does not implement client.Object", src)
|
|
}
|
|
|
|
srcValue := reflect.ValueOf(srcCopy)
|
|
dstValue := reflect.ValueOf(dst)
|
|
|
|
if srcValue.Kind() != reflect.Pointer ||
|
|
dstValue.Kind() != reflect.Pointer ||
|
|
srcValue.Type() != dstValue.Type() ||
|
|
srcValue.IsNil() ||
|
|
dstValue.IsNil() {
|
|
return fmt.Errorf("cannot copy cached %T into %T", src, dst)
|
|
}
|
|
|
|
dstValue.Elem().Set(srcValue.Elem())
|
|
|
|
return nil
|
|
}
|