Files
capsule/internal/webhook/utils/request_reader.go
T
Oliver BählerandGitHub 2252c530f4 feat(performance): removed duplicate client calls from all admission paths (#2054)
* 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>
2026-07-28 14:32:42 +02:00

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
}