@@ -30,13 +30,15 @@ import (
30
30
apiequality "k8s.io/apimachinery/pkg/api/equality"
31
31
apierrors "k8s.io/apimachinery/pkg/api/errors"
32
32
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33
+ "k8s.io/apimachinery/pkg/labels"
33
34
"k8s.io/apimachinery/pkg/runtime"
34
35
"k8s.io/apimachinery/pkg/types"
35
36
"k8s.io/apimachinery/pkg/util/sets"
36
37
"k8s.io/client-go/kubernetes"
37
38
resourcelisters "k8s.io/client-go/listers/resource/v1alpha3"
38
39
"k8s.io/client-go/util/retry"
39
40
"k8s.io/component-helpers/scheduling/corev1/nodeaffinity"
41
+ "k8s.io/dynamic-resource-allocation/cel"
40
42
"k8s.io/dynamic-resource-allocation/resourceclaim"
41
43
"k8s.io/dynamic-resource-allocation/structured"
42
44
"k8s.io/klog/v2"
@@ -85,7 +87,7 @@ type stateData struct {
85
87
informationsForClaim []informationForClaim
86
88
87
89
// nodeAllocations caches the result of Filter for the nodes.
88
- nodeAllocations map [string ][]* resourceapi.AllocationResult
90
+ nodeAllocations map [string ][]resourceapi.AllocationResult
89
91
}
90
92
91
93
func (d * stateData ) Clone () framework.StateData {
@@ -106,10 +108,12 @@ type DynamicResources struct {
106
108
enableAdminAccess bool
107
109
enableSchedulingQueueHint bool
108
110
109
- fh framework.Handle
110
- clientset kubernetes.Interface
111
- classLister resourcelisters.DeviceClassLister
112
- sliceLister resourcelisters.ResourceSliceLister
111
+ fh framework.Handle
112
+ clientset kubernetes.Interface
113
+ classLister resourcelisters.DeviceClassLister
114
+ sliceLister resourcelisters.ResourceSliceLister
115
+ celCache * cel.Cache
116
+ allocatedDevices * allocatedDevices
113
117
114
118
// claimAssumeCache enables temporarily storing a newer claim object
115
119
// while the scheduler has allocated it and the corresponding object
@@ -174,6 +178,7 @@ func New(ctx context.Context, plArgs runtime.Object, fh framework.Handle, fts fe
174
178
return & DynamicResources {}, nil
175
179
}
176
180
181
+ logger := klog .FromContext (ctx )
177
182
pl := & DynamicResources {
178
183
enabled : true ,
179
184
enableAdminAccess : fts .EnableDRAAdminAccess ,
@@ -184,8 +189,19 @@ func New(ctx context.Context, plArgs runtime.Object, fh framework.Handle, fts fe
184
189
classLister : fh .SharedInformerFactory ().Resource ().V1alpha3 ().DeviceClasses ().Lister (),
185
190
sliceLister : fh .SharedInformerFactory ().Resource ().V1alpha3 ().ResourceSlices ().Lister (),
186
191
claimAssumeCache : fh .ResourceClaimCache (),
192
+
193
+ // This is a LRU cache for compiled CEL expressions. The most
194
+ // recent 10 of them get reused across different scheduling
195
+ // cycles.
196
+ celCache : cel .NewCache (10 ),
197
+
198
+ allocatedDevices : newAllocatedDevices (logger ),
187
199
}
188
200
201
+ // Reacting to events is more efficient than iterating over the list
202
+ // repeatedly in PreFilter.
203
+ pl .claimAssumeCache .AddEventHandler (pl .allocatedDevices .handlers ())
204
+
189
205
return pl , nil
190
206
}
191
207
@@ -527,39 +543,41 @@ func (pl *DynamicResources) PreFilter(ctx context.Context, state *framework.Cycl
527
543
// expensive, we may have to maintain and update state more
528
544
// persistently.
529
545
//
530
- // Claims are treated as "allocated" if they are in the assume cache
531
- // or currently their allocation is in-flight.
532
- allocator , err := structured .NewAllocator (ctx , pl .enableAdminAccess , allocateClaims , & claimListerForAssumeCache {assumeCache : pl .claimAssumeCache , inFlightAllocations : & pl .inFlightAllocations }, pl .classLister , pl .sliceLister )
546
+ // Claims (and thus their devices) are treated as "allocated" if they are in the assume cache
547
+ // or currently their allocation is in-flight. This does not change
548
+ // during filtering, so we can determine that once.
549
+ allAllocatedDevices := pl .listAllAllocatedDevices (logger )
550
+ slices , err := pl .sliceLister .List (labels .Everything ())
551
+ if err != nil {
552
+ return nil , statusError (logger , err )
553
+ }
554
+ allocator , err := structured .NewAllocator (ctx , pl .enableAdminAccess , allocateClaims , allAllocatedDevices , pl .classLister , slices , pl .celCache )
533
555
if err != nil {
534
556
return nil , statusError (logger , err )
535
557
}
536
558
s .allocator = allocator
537
- s .nodeAllocations = make (map [string ][]* resourceapi.AllocationResult )
559
+ s .nodeAllocations = make (map [string ][]resourceapi.AllocationResult )
538
560
}
539
561
540
562
s .claims = claims
541
563
return nil , nil
542
564
}
543
565
544
- type claimListerForAssumeCache struct {
545
- assumeCache * assumecache.AssumeCache
546
- inFlightAllocations * sync.Map
547
- }
548
-
549
- func (cl * claimListerForAssumeCache ) ListAllAllocated () ([]* resourceapi.ResourceClaim , error ) {
550
- // Probably not worth adding an index for?
551
- objs := cl .assumeCache .List (nil )
552
- allocated := make ([]* resourceapi.ResourceClaim , 0 , len (objs ))
553
- for _ , obj := range objs {
554
- claim := obj .(* resourceapi.ResourceClaim )
555
- if obj , ok := cl .inFlightAllocations .Load (claim .UID ); ok {
556
- claim = obj .(* resourceapi.ResourceClaim )
557
- }
558
- if claim .Status .Allocation != nil {
559
- allocated = append (allocated , claim )
560
- }
561
- }
562
- return allocated , nil
566
+ func (pl * DynamicResources ) listAllAllocatedDevices (logger klog.Logger ) sets.Set [structured.DeviceID ] {
567
+ // Start with a fresh set that matches the current known state of the
568
+ // world according to the informers.
569
+ allocated := pl .allocatedDevices .Get ()
570
+
571
+ // Whatever is in flight also has to be checked.
572
+ pl .inFlightAllocations .Range (func (key , value any ) bool {
573
+ claim := value .(* resourceapi.ResourceClaim )
574
+ foreachAllocatedDevice (claim , func (deviceID structured.DeviceID ) {
575
+ logger .V (6 ).Info ("Device is in flight for allocation" , "device" , deviceID , "claim" , klog .KObj (claim ))
576
+ allocated .Insert (deviceID )
577
+ })
578
+ return true
579
+ })
580
+ return allocated
563
581
}
564
582
565
583
// PreFilterExtensions returns prefilter extensions, pod add and remove.
@@ -615,7 +633,7 @@ func (pl *DynamicResources) Filter(ctx context.Context, cs *framework.CycleState
615
633
}
616
634
617
635
// Use allocator to check the node and cache the result in case that the node is picked.
618
- var allocations []* resourceapi.AllocationResult
636
+ var allocations []resourceapi.AllocationResult
619
637
if state .allocator != nil {
620
638
allocCtx := ctx
621
639
if loggerV := logger .V (5 ); loggerV .Enabled () {
@@ -763,7 +781,7 @@ func (pl *DynamicResources) Reserve(ctx context.Context, cs *framework.CycleStat
763
781
if index < 0 {
764
782
return statusError (logger , fmt .Errorf ("internal error, claim %s with allocation not found" , claim .Name ))
765
783
}
766
- allocation := allocations [i ]
784
+ allocation := & allocations [i ]
767
785
state .informationsForClaim [index ].allocation = allocation
768
786
769
787
// Strictly speaking, we don't need to store the full modified object.
0 commit comments