@@ -20,7 +20,7 @@ import (
20
20
"fmt"
21
21
"hash/fnv"
22
22
"math/rand"
23
- "sort "
23
+ "slices "
24
24
"strconv"
25
25
"strings"
26
26
@@ -39,8 +39,14 @@ import (
39
39
"k8s.io/klog/v2"
40
40
)
41
41
42
+ type topologySegment struct {
43
+ Key , Value string
44
+ }
45
+
42
46
// topologyTerm represents a single term where its topology key value pairs are AND'd together.
43
- type topologyTerm map [string ]string
47
+ //
48
+ // Be sure to sort after construction for compare() and subset() to work properly.
49
+ type topologyTerm []topologySegment
44
50
45
51
func GenerateVolumeNodeAffinity (accessibleTopology []* csi.Topology ) * v1.VolumeNodeAffinity {
46
52
if len (accessibleTopology ) == 0 {
@@ -417,12 +423,12 @@ func flatten(allowedTopologies []v1.TopologySelectorTerm) []topologyTerm {
417
423
418
424
if len (oldTerms ) == 0 {
419
425
// No previous terms to distribute over. Simply append the new term.
420
- newTerms = append (newTerms , topologyTerm {selectorExpression .Key : v })
426
+ newTerms = append (newTerms , topologyTerm {{ selectorExpression .Key , v } })
421
427
} else {
422
428
for _ , oldTerm := range oldTerms {
423
429
// "Distribute" by adding an entry to the term
424
- newTerm := oldTerm . clone ( )
425
- newTerm [ selectorExpression .Key ] = v
430
+ newTerm := slices . Clone ( oldTerm )
431
+ newTerm = append ( newTerm , topologySegment { selectorExpression .Key , v })
426
432
newTerms = append (newTerms , newTerm )
427
433
}
428
434
}
@@ -435,6 +441,9 @@ func flatten(allowedTopologies []v1.TopologySelectorTerm) []topologyTerm {
435
441
finalTerms = append (finalTerms , oldTerms ... )
436
442
}
437
443
444
+ for _ , term := range finalTerms {
445
+ term .sort ()
446
+ }
438
447
return finalTerms
439
448
}
440
449
@@ -456,9 +465,7 @@ func deduplicate(terms []topologyTerm) []topologyTerm {
456
465
// either the primary term (if specified) or term at shiftIndex is the first in the list.
457
466
func sortAndShift (terms []topologyTerm , primary topologyTerm , shiftIndex uint32 ) []topologyTerm {
458
467
var preferredTerms []topologyTerm
459
- sort .Slice (terms , func (i , j int ) bool {
460
- return terms [i ].less (terms [j ])
461
- })
468
+ slices .SortFunc (terms , topologyTerm .compare )
462
469
if primary == nil {
463
470
preferredTerms = append (terms [shiftIndex :], terms [:shiftIndex ]... )
464
471
} else {
@@ -482,14 +489,15 @@ func getTopologyKeys(csiNode *storagev1.CSINode, driverName string) []string {
482
489
}
483
490
484
491
func getTopologyFromNode (node * v1.Node , topologyKeys []string ) (term topologyTerm , isMissingKey bool ) {
485
- term = make (topologyTerm )
492
+ term = make (topologyTerm , 0 , len ( topologyKeys ) )
486
493
for _ , key := range topologyKeys {
487
494
v , ok := node .Labels [key ]
488
495
if ! ok {
489
496
return nil , true
490
497
}
491
- term [ key ] = v
498
+ term = append ( term , topologySegment { key , v })
492
499
}
500
+ term .sort ()
493
501
return term , false
494
502
}
495
503
@@ -514,12 +522,15 @@ func buildTopologyKeySelector(topologyKeys []string) (labels.Selector, error) {
514
522
return selector , nil
515
523
}
516
524
517
- func (t topologyTerm ) clone () topologyTerm {
518
- ret := make (topologyTerm )
519
- for k , v := range t {
520
- ret [k ] = v
521
- }
522
- return ret
525
+ func (t topologyTerm ) sort () {
526
+ slices .SortFunc (t , func (a , b topologySegment ) int {
527
+ r := strings .Compare (a .Key , b .Key )
528
+ if r != 0 {
529
+ return r
530
+ }
531
+ // Should not happen currently. We may support multi-value in the future?
532
+ return strings .Compare (a .Value , b .Value )
533
+ })
523
534
}
524
535
525
536
// "<k1>#<v1>,<k2>#<v2>,..."
@@ -533,37 +544,61 @@ func (t topologyTerm) clone() topologyTerm {
533
544
// Note that both '#' and ',' are less than '/', '-', '_', '.', [A-Z0-9a-z]
534
545
func (t topologyTerm ) hash () string {
535
546
var segments []string
536
- for k , v := range t {
537
- segments = append (segments , k + "#" + v )
547
+ for _ , k := range t {
548
+ segments = append (segments , k . Key + "#" + k . Value )
538
549
}
539
550
540
- sort .Strings (segments )
541
551
return strings .Join (segments , "," )
542
552
}
543
553
544
- func (t topologyTerm ) less (other topologyTerm ) bool {
545
- return t .hash () < other .hash ()
554
+ func (t topologyTerm ) compare (other topologyTerm ) int {
555
+ if len (t ) != len (other ) {
556
+ return len (t ) - len (other )
557
+ }
558
+ for i , k1 := range t {
559
+ k2 := other [i ]
560
+ r := strings .Compare (k1 .Key , k2 .Key )
561
+ if r != 0 {
562
+ return r
563
+ }
564
+ r = strings .Compare (k1 .Value , k2 .Value )
565
+ if r != 0 {
566
+ return r
567
+ }
568
+ }
569
+ return 0
546
570
}
547
571
548
572
func (t topologyTerm ) subset (other topologyTerm ) bool {
549
- for key , tv := range t {
550
- v , ok := other [key ]
551
- if ! ok || v != tv {
573
+ if len (t ) == 0 {
574
+ return true
575
+ }
576
+ j := 0
577
+ for _ , k2 := range other {
578
+ k1 := t [j ]
579
+ if k1 .Key != k2 .Key {
580
+ continue
581
+ }
582
+ if k1 .Value != k2 .Value {
552
583
return false
553
584
}
585
+ j ++
586
+ if j == len (t ) {
587
+ // All segments in t have been checked and is present in other.
588
+ return true
589
+ }
554
590
}
555
-
556
- return true
557
- }
558
-
559
- func (t topologyTerm ) equal (other topologyTerm ) bool {
560
- return t .hash () == other .hash ()
591
+ return false
561
592
}
562
593
563
594
func toCSITopology (terms []topologyTerm ) []* csi.Topology {
564
- var out []* csi.Topology
595
+ out := make ( []* csi.Topology , 0 , len ( terms ))
565
596
for _ , term := range terms {
566
- out = append (out , & csi.Topology {Segments : term })
597
+ segs := make (map [string ]string , len (term ))
598
+ for _ , k := range term {
599
+ segs [k .Key ] = k .Value
600
+ }
601
+ out = append (out , & csi.Topology {Segments : segs })
567
602
}
568
603
return out
569
604
}
0 commit comments