diff --git a/pkg/scheduler/framework/types_test.go b/pkg/scheduler/framework/types_test.go index 6f5cda24aff..3e91e64a3db 100644 --- a/pkg/scheduler/framework/types_test.go +++ b/pkg/scheduler/framework/types_test.go @@ -1308,14 +1308,20 @@ func TestSetNodeDeclaredFeatures(t *testing.T) { gotFeatures := ni.GetNodeDeclaredFeatures() if !tt.featureGateEnabled { if !gotFeatures.IsEmpty() { - got := ndfFramework.Unmap(gotFeatures) + got, err := ndfFramework.Unmap(gotFeatures) + if err != nil { + t.Fatalf("Failed to unmap features: %v", err) + } t.Errorf("Expected GetNodeDeclaredFeatures() to return nil; got %v", got) } return } expected := ndfFramework.MustMapSorted(tt.expectedFeatures) if !gotFeatures.Equal(expected) { - got := ndfFramework.Unmap(gotFeatures) + got, err := ndfFramework.Unmap(gotFeatures) + if err != nil { + t.Fatalf("Failed to unmap features: %v", err) + } t.Errorf("SetNode() or GetNodeDeclaredFeatures() unexpected result, got: %v, want: %v", got, tt.expectedFeatures) } }) diff --git a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset.go b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset.go index 5b2f38bb5c3..ad749b457ca 100644 --- a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset.go +++ b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset.go @@ -18,6 +18,7 @@ package nodedeclaredfeatures import ( "fmt" + "math/bits" "slices" ) @@ -91,16 +92,19 @@ func (m *FeatureMapper) mapSorted(sortedFeatures []string, ignoreUnknown bool) ( } // Unmap returns the names of the features set in the FeatureSet (sorted). -func (m *FeatureMapper) Unmap(s FeatureSet) []string { - if s.IsEmpty() { - return nil +func (m *FeatureMapper) Unmap(s FeatureSet) ([]string, error) { + if s.size != len(m.registeredFeatures) { + return nil, fmt.Errorf("feature size mismatch! s.size=%d; len(m.registeredFeatures)=%d", s.size, len(m.registeredFeatures)) } var keys []string - for i, k := range m.registeredFeatures { - if s.Get(i) { - keys = append(keys, k) + for i, w := range s.words { + for w != 0 { + t := bits.TrailingZeros64(w) // Find the index of the least significant bit. + index := i*64 + t + keys = append(keys, m.registeredFeatures[index]) + w &^= 1 << uint(t) // Clear the least significant bit. } } - return keys + return keys, nil } diff --git a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset_test.go b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset_test.go index b82d9e68757..24217934aeb 100644 --- a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset_test.go +++ b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/featureset_test.go @@ -117,8 +117,11 @@ func TestFeatureMapper(t *testing.T) { } } - // Test Unmap - unmapped := mapper.Unmap(fs) + // Test Unmap and UnmapSparse + unmapped, err := mapper.Unmap(fs) + if err != nil { + t.Fatalf("unexpected Unmap error: %v", err) + } if len(unmapped) != tt.expectedSet.Len() { t.Errorf("len(unmapped) = %d, want %d", len(unmapped), tt.expectedSet.Len()) } diff --git a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework.go b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework.go index 4f7046f5c13..285a2edbb65 100644 --- a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework.go +++ b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework.go @@ -143,7 +143,10 @@ func (f *Framework) MatchNodeFeatureSet(requiredFeatures FeatureSet, nodeFeature } diff, _ := requiredFeatures.Difference(nodeFeatures) // Difference will error IFF IsSubset also does, so we can ignore the error here. - unsatisfiedRequirements := f.Unmap(diff) + unsatisfiedRequirements, err := f.Unmap(diff) + if err != nil { + return nil, err + } return &MatchResult{IsMatch: false, UnsatisfiedRequirements: unsatisfiedRequirements}, nil } diff --git a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework_test.go b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework_test.go index 9ba0c6dabd2..0bdf368a220 100644 --- a/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework_test.go +++ b/staging/src/k8s.io/component-helpers/nodedeclaredfeatures/framework_test.go @@ -318,7 +318,10 @@ func TestInferForPodScheduling(t *testing.T) { if err != nil { t.Fatalf("unexpected error %v", err) } - unmappedReqs := framework.Unmap(reqs) + unmappedReqs, err := framework.Unmap(reqs) + if err != nil { + t.Fatalf("unexpected error %v", err) + } if !reflect.DeepEqual(tc.expectedReqs, unmappedReqs) { t.Errorf("expected %#v, got %#v", tc.expectedReqs, unmappedReqs) } @@ -467,7 +470,10 @@ func TestInferForPodUpdate(t *testing.T) { if err != nil { t.Fatalf("unexpected error %v", err) } - unmappedReqs := framework.Unmap(reqs) + unmappedReqs, err := framework.Unmap(reqs) + if err != nil { + t.Fatalf("unexpected error %v", err) + } if !reflect.DeepEqual(tc.expectedReqs, unmappedReqs) { t.Errorf("expected %#v, got %#v", tc.expectedReqs, unmappedReqs) }