@@ -72,10 +72,10 @@ type predicateMetadata struct {
72
72
73
73
topologyPairsAntiAffinityPodsMap * topologyPairsMaps
74
74
// A map of topology pairs to a list of Pods that can potentially match
75
- // the affinity rules of the "pod" and its inverse.
75
+ // the affinity terms of the "pod" and its inverse.
76
76
topologyPairsPotentialAffinityPods * topologyPairsMaps
77
77
// A map of topology pairs to a list of Pods that can potentially match
78
- // the anti-affinity rules of the "pod" and its inverse.
78
+ // the anti-affinity terms of the "pod" and its inverse.
79
79
topologyPairsPotentialAntiAffinityPods * topologyPairsMaps
80
80
serviceAffinityInUse bool
81
81
serviceAffinityMatchingPodList []* v1.Pod
@@ -130,11 +130,14 @@ func (pfactory *PredicateMetadataFactory) GetMetadata(pod *v1.Pod, nodeNameToInf
130
130
if pod == nil {
131
131
return nil
132
132
}
133
- topologyPairsMaps , err := getMatchingTopologyPairs (pod , nodeNameToInfoMap )
133
+ // existingPodAntiAffinityMap will be used later for efficient check on existing pods' anti-affinity
134
+ existingPodAntiAffinityMap , err := getTPMapMatchingExistingAntiAffinity (pod , nodeNameToInfoMap )
134
135
if err != nil {
135
136
return nil
136
137
}
137
- topologyPairsAffinityPodsMaps , topologyPairsAntiAffinityPodsMaps , err := getPodsMatchingAffinity (pod , nodeNameToInfoMap )
138
+ // incomingPodAffinityMap will be used later for efficient check on incoming pod's affinity
139
+ // incomingPodAntiAffinityMap will be used later for efficient check on incoming pod's anti-affinity
140
+ incomingPodAffinityMap , incomingPodAntiAffinityMap , err := getTPMapMatchingIncomingAffinityAntiAffinity (pod , nodeNameToInfoMap )
138
141
if err != nil {
139
142
glog .Errorf ("[predicate meta data generation] error finding pods that match affinity terms: %v" , err )
140
143
return nil
@@ -144,9 +147,9 @@ func (pfactory *PredicateMetadataFactory) GetMetadata(pod *v1.Pod, nodeNameToInf
144
147
podBestEffort : isPodBestEffort (pod ),
145
148
podRequest : GetResourceRequest (pod ),
146
149
podPorts : schedutil .GetContainerPorts (pod ),
147
- topologyPairsPotentialAffinityPods : topologyPairsAffinityPodsMaps ,
148
- topologyPairsPotentialAntiAffinityPods : topologyPairsAntiAffinityPodsMaps ,
149
- topologyPairsAntiAffinityPodsMap : topologyPairsMaps ,
150
+ topologyPairsPotentialAffinityPods : incomingPodAffinityMap ,
151
+ topologyPairsPotentialAntiAffinityPods : incomingPodAntiAffinityMap ,
152
+ topologyPairsAntiAffinityPodsMap : existingPodAntiAffinityMap ,
150
153
}
151
154
for predicateName , precomputeFunc := range predicateMetadataProducers {
152
155
glog .V (10 ).Infof ("Precompute: %v" , predicateName )
@@ -185,6 +188,9 @@ func (topologyPairsMaps *topologyPairsMaps) removePod(deletedPod *v1.Pod) {
185
188
}
186
189
187
190
func (topologyPairsMaps * topologyPairsMaps ) appendMaps (toAppend * topologyPairsMaps ) {
191
+ if toAppend == nil {
192
+ return
193
+ }
188
194
for pair := range toAppend .topologyPairToPods {
189
195
for pod := range toAppend .topologyPairToPods [pair ] {
190
196
topologyPairsMaps .addTopologyPair (pair , pod )
@@ -232,13 +238,11 @@ func (meta *predicateMetadata) AddPod(addedPod *v1.Pod, nodeInfo *schedulercache
232
238
return fmt .Errorf ("invalid node in nodeInfo" )
233
239
}
234
240
// Add matching anti-affinity terms of the addedPod to the map.
235
- topologyPairsMaps , err := getMatchingTopologyPairsOfExistingPod (meta .pod , addedPod , nodeInfo .Node ())
241
+ topologyPairsMaps , err := getMatchingAntiAffinityTopologyPairsOfPod (meta .pod , addedPod , nodeInfo .Node ())
236
242
if err != nil {
237
243
return err
238
244
}
239
- if len (topologyPairsMaps .podToTopologyPairs ) > 0 {
240
- meta .topologyPairsAntiAffinityPodsMap .appendMaps (topologyPairsMaps )
241
- }
245
+ meta .topologyPairsAntiAffinityPodsMap .appendMaps (topologyPairsMaps )
242
246
// Add the pod to nodeNameToMatchingAffinityPods and nodeNameToMatchingAntiAffinityPods if needed.
243
247
affinity := meta .pod .Spec .Affinity
244
248
podNodeName := addedPod .Spec .NodeName
@@ -325,8 +329,8 @@ func getAffinityTermProperties(pod *v1.Pod, terms []v1.PodAffinityTerm) (propert
325
329
return properties , nil
326
330
}
327
331
328
- // podMatchesAffinityTermProperties return true IFF the given pod matches all the given properties.
329
- func podMatchesAffinityTermProperties (pod * v1.Pod , properties []* affinityTermProperties ) bool {
332
+ // podMatchesAllAffinityTermProperties returns true IFF the given pod matches all the given properties.
333
+ func podMatchesAllAffinityTermProperties (pod * v1.Pod , properties []* affinityTermProperties ) bool {
330
334
if len (properties ) == 0 {
331
335
return false
332
336
}
@@ -338,11 +342,71 @@ func podMatchesAffinityTermProperties(pod *v1.Pod, properties []*affinityTermPro
338
342
return true
339
343
}
340
344
341
- // getPodsMatchingAffinity finds existing Pods that match affinity terms of the given "pod".
342
- // It ignores topology. It returns a set of Pods that are checked later by the affinity
343
- // predicate. With this set of pods available, the affinity predicate does not
345
+ // podMatchesAnyAffinityTermProperties returns true if the given pod matches any given property.
346
+ func podMatchesAnyAffinityTermProperties (pod * v1.Pod , properties []* affinityTermProperties ) bool {
347
+ if len (properties ) == 0 {
348
+ return false
349
+ }
350
+ for _ , property := range properties {
351
+ if priorityutil .PodMatchesTermsNamespaceAndSelector (pod , property .namespaces , property .selector ) {
352
+ return true
353
+ }
354
+ }
355
+ return false
356
+ }
357
+
358
+ // getTPMapMatchingExistingAntiAffinity calculates the following for each existing pod on each node:
359
+ // (1) Whether it has PodAntiAffinity
360
+ // (2) Whether any AffinityTerm matches the incoming pod
361
+ func getTPMapMatchingExistingAntiAffinity (pod * v1.Pod , nodeInfoMap map [string ]* schedulercache.NodeInfo ) (* topologyPairsMaps , error ) {
362
+ allNodeNames := make ([]string , 0 , len (nodeInfoMap ))
363
+ for name := range nodeInfoMap {
364
+ allNodeNames = append (allNodeNames , name )
365
+ }
366
+
367
+ var lock sync.Mutex
368
+ var firstError error
369
+
370
+ topologyMaps := newTopologyPairsMaps ()
371
+
372
+ appendTopologyPairsMaps := func (toAppend * topologyPairsMaps ) {
373
+ lock .Lock ()
374
+ defer lock .Unlock ()
375
+ topologyMaps .appendMaps (toAppend )
376
+ }
377
+ catchError := func (err error ) {
378
+ lock .Lock ()
379
+ defer lock .Unlock ()
380
+ if firstError == nil {
381
+ firstError = err
382
+ }
383
+ }
384
+
385
+ processNode := func (i int ) {
386
+ nodeInfo := nodeInfoMap [allNodeNames [i ]]
387
+ node := nodeInfo .Node ()
388
+ if node == nil {
389
+ catchError (fmt .Errorf ("node not found" ))
390
+ return
391
+ }
392
+ for _ , existingPod := range nodeInfo .PodsWithAffinity () {
393
+ existingPodTopologyMaps , err := getMatchingAntiAffinityTopologyPairsOfPod (pod , existingPod , node )
394
+ if err != nil {
395
+ catchError (err )
396
+ return
397
+ }
398
+ appendTopologyPairsMaps (existingPodTopologyMaps )
399
+ }
400
+ }
401
+ workqueue .Parallelize (16 , len (allNodeNames ), processNode )
402
+ return topologyMaps , firstError
403
+ }
404
+
405
+ // getTPMapMatchingIncomingAffinityAntiAffinity finds existing Pods that match affinity terms of the given "pod".
406
+ // It returns a topologyPairsMaps that are checked later by the affinity
407
+ // predicate. With this topologyPairsMaps available, the affinity predicate does not
344
408
// need to check all the pods in the cluster.
345
- func getPodsMatchingAffinity (pod * v1.Pod , nodeInfoMap map [string ]* schedulercache.NodeInfo ) (topologyPairsAffinityPodsMaps * topologyPairsMaps , topologyPairsAntiAffinityPodsMaps * topologyPairsMaps , err error ) {
409
+ func getTPMapMatchingIncomingAffinityAntiAffinity (pod * v1.Pod , nodeInfoMap map [string ]* schedulercache.NodeInfo ) (topologyPairsAffinityPodsMaps * topologyPairsMaps , topologyPairsAntiAffinityPodsMaps * topologyPairsMaps , err error ) {
346
410
allNodeNames := make ([]string , 0 , len (nodeInfoMap ))
347
411
348
412
affinity := pod .Spec .Affinity
@@ -377,17 +441,13 @@ func getPodsMatchingAffinity(pod *v1.Pod, nodeInfoMap map[string]*schedulercache
377
441
}
378
442
}
379
443
380
- affinityProperties , err := getAffinityTermProperties (pod , GetPodAffinityTerms (affinity .PodAffinity ))
381
- if err != nil {
382
- return nil , nil , err
383
- }
384
- antiAffinityProperties , err := getAffinityTermProperties (pod , GetPodAntiAffinityTerms (affinity .PodAntiAffinity ))
444
+ affinityTerms := GetPodAffinityTerms (affinity .PodAffinity )
445
+ affinityProperties , err := getAffinityTermProperties (pod , affinityTerms )
385
446
if err != nil {
386
447
return nil , nil , err
387
448
}
388
-
389
- affinityTerms := GetPodAffinityTerms (affinity .PodAffinity )
390
449
antiAffinityTerms := GetPodAntiAffinityTerms (affinity .PodAntiAffinity )
450
+
391
451
processNode := func (i int ) {
392
452
nodeInfo := nodeInfoMap [allNodeNames [i ]]
393
453
node := nodeInfo .Node ()
@@ -399,7 +459,7 @@ func getPodsMatchingAffinity(pod *v1.Pod, nodeInfoMap map[string]*schedulercache
399
459
nodeTopologyPairsAntiAffinityPodsMaps := newTopologyPairsMaps ()
400
460
for _ , existingPod := range nodeInfo .Pods () {
401
461
// Check affinity properties.
402
- if podMatchesAffinityTermProperties (existingPod , affinityProperties ) {
462
+ if podMatchesAllAffinityTermProperties (existingPod , affinityProperties ) {
403
463
for _ , term := range affinityTerms {
404
464
if topologyValue , ok := node .Labels [term .TopologyKey ]; ok {
405
465
pair := topologyPair {key : term .TopologyKey , value : topologyValue }
@@ -408,8 +468,14 @@ func getPodsMatchingAffinity(pod *v1.Pod, nodeInfoMap map[string]*schedulercache
408
468
}
409
469
}
410
470
// Check anti-affinity properties.
411
- if podMatchesAffinityTermProperties (existingPod , antiAffinityProperties ) {
412
- for _ , term := range antiAffinityTerms {
471
+ for _ , term := range antiAffinityTerms {
472
+ namespaces := priorityutil .GetNamespacesFromPodAffinityTerm (pod , & term )
473
+ selector , err := metav1 .LabelSelectorAsSelector (term .LabelSelector )
474
+ if err != nil {
475
+ catchError (err )
476
+ return
477
+ }
478
+ if priorityutil .PodMatchesTermsNamespaceAndSelector (existingPod , namespaces , selector ) {
413
479
if topologyValue , ok := node .Labels [term .TopologyKey ]; ok {
414
480
pair := topologyPair {key : term .TopologyKey , value : topologyValue }
415
481
nodeTopologyPairsAntiAffinityPodsMaps .addTopologyPair (pair , existingPod )
@@ -425,7 +491,7 @@ func getPodsMatchingAffinity(pod *v1.Pod, nodeInfoMap map[string]*schedulercache
425
491
return topologyPairsAffinityPodsMaps , topologyPairsAntiAffinityPodsMaps , firstError
426
492
}
427
493
428
- // podMatchesAffinity returns true if "targetPod" matches any affinity rule of
494
+ // targetPodMatchesAffinityOfPod returns true if "targetPod" matches ALL affinity terms of
429
495
// "pod". Similar to getPodsMatchingAffinity, this function does not check topology.
430
496
// So, whether the targetPod actually matches or not needs further checks for a specific
431
497
// node.
@@ -439,11 +505,11 @@ func targetPodMatchesAffinityOfPod(pod, targetPod *v1.Pod) bool {
439
505
glog .Errorf ("error in getting affinity properties of Pod %v" , pod .Name )
440
506
return false
441
507
}
442
- return podMatchesAffinityTermProperties (targetPod , affinityProperties )
508
+ return podMatchesAllAffinityTermProperties (targetPod , affinityProperties )
443
509
}
444
510
445
- // targetPodMatchesAntiAffinityOfPod returns true if "targetPod" matches any anti-affinity
446
- // rule of "pod". Similar to getPodsMatchingAffinity, this function does not check topology.
511
+ // targetPodMatchesAntiAffinityOfPod returns true if "targetPod" matches ANY anti-affinity
512
+ // term of "pod". Similar to getPodsMatchingAffinity, this function does not check topology.
447
513
// So, whether the targetPod actually matches or not needs further checks for a specific
448
514
// node.
449
515
func targetPodMatchesAntiAffinityOfPod (pod , targetPod * v1.Pod ) bool {
@@ -456,5 +522,5 @@ func targetPodMatchesAntiAffinityOfPod(pod, targetPod *v1.Pod) bool {
456
522
glog .Errorf ("error in getting anti-affinity properties of Pod %v" , pod .Name )
457
523
return false
458
524
}
459
- return podMatchesAffinityTermProperties (targetPod , properties )
525
+ return podMatchesAnyAffinityTermProperties (targetPod , properties )
460
526
}
0 commit comments