Skip to content

Commit d4fd8ee

Browse files
committed
remove sortFunc in favor of compareFunc; Find() has to take ResourceId
1 parent 01ec9d1 commit d4fd8ee

File tree

5 files changed

+129
-92
lines changed

5 files changed

+129
-92
lines changed

contrib/pkg/sets/sets.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ func TypedKey(id ezkube.ResourceId) string {
2828
type ResourceSet interface {
2929
Keys() sets.String
3030
List(filterResource ...func(ezkube.ResourceId) bool) []ezkube.ResourceId
31-
UnsortedList(filterResource ...func(ezkube.ResourceId) bool) []ezkube.ResourceId
3231
Map() Resources
3332
Insert(resource ...ezkube.ResourceId)
3433
Equal(set ResourceSet) bool
@@ -81,12 +80,6 @@ func (t *threadSafeResourceSet) List(filterResource ...func(ezkube.ResourceId) b
8180
return t.set.List(filterResource...)
8281
}
8382

84-
func (t *threadSafeResourceSet) UnsortedList(filterResource ...func(ezkube.ResourceId) bool) []ezkube.ResourceId {
85-
t.lock.RLock()
86-
defer t.lock.RUnlock()
87-
return t.set.UnsortedList(filterResource...)
88-
}
89-
9083
func (t *threadSafeResourceSet) Map() Resources {
9184
t.lock.RLock()
9285
defer t.lock.RUnlock()

contrib/pkg/sets/sets_bench_test.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"reflect"
99
"sort"
10-
"strconv"
1110
"strings"
1211
"testing"
1312
"time"
@@ -32,19 +31,25 @@ func BenchmarkResourcesSet100000(b *testing.B) { benchmarkResourcesSet(100000, b
3231
func benchmarkResourcesSet(count int, b *testing.B) {
3332
resources := make([]*things_test_io_v1.Paint, count)
3433
for i := 0; i < count; i++ {
34+
clusterName := ""
35+
if i%3 == 0 {
36+
clusterName = "cluster-2"
37+
} else {
38+
clusterName = "cluster-1"
39+
}
3540
resources[i] = &things_test_io_v1.Paint{
3641
ObjectMeta: metav1.ObjectMeta{
3742
Name: fmt.Sprintf("name-%d", i),
3843
Namespace: fmt.Sprintf("namespace-%d", i),
39-
Annotations: map[string]string{ezkube.ClusterAnnotation: "random-cluster"},
44+
Annotations: map[string]string{ezkube.ClusterAnnotation: clusterName},
4045
CreationTimestamp: metav1.Time{Time: metav1.Now().Time.Add(time.Duration(i))},
4146
},
4247
}
4348
}
4449

4550
for n := 0; n < b.N; n++ {
4651
// s := v1sets.NewPaintSet(ezkube.CreationTimestampAscending, ezkube.CreationTimestampsCompare)
47-
s := v2sets.NewResourceSet[*things_test_io_v1.Paint](ezkube.ObjectsAscending, ezkube.CompareObjects)
52+
s := v2sets.NewResourceSet[*things_test_io_v1.Paint](ezkube.ResourceIdsCompare)
4853
s.Insert(resources...)
4954

5055
// SortByCreationTime(l) // only for map implementation
@@ -68,8 +73,12 @@ const filterAfter = 19999
6873

6974
// skip iterating resources > 20001
7075
func filterResource(resource *things_test_io_v1.Paint) bool {
71-
i, _ := strconv.Atoi(strings.Split(resource.GetName(), "-")[1])
72-
return i > filterAfter
76+
// i, _ := strconv.Atoi(strings.Split(resource.GetName(), "-")[1])
77+
// return i > filterAfter
78+
if ezkube.GetClusterName(resource) == "cluster-1" {
79+
return false
80+
}
81+
return true
7382
}
7483

7584
// SortByCreationTime accepts a slice of client.Object instances and sorts it by creation timestamp in ascending order.

contrib/pkg/sets/sets_internal.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,13 @@ func (r Resources) Map() map[string]ezkube.ResourceId {
134134
// The set is sorted based on the sortFunc. If sortFunc is nil, the set will be unsorted.
135135
func (r *Resources) Insert(resources ...ezkube.ResourceId) {
136136
for _, resource := range resources {
137-
insertIndex := sort.Search(r.Length(), func(i int) bool { return r.sortFunc(resource, r.set[i]) })
137+
insertIndex := sort.Search(r.Length(), func(i int) bool { return r.compareFunc(resource, r.set[i]) < 0 })
138138

139139
// if the resource is already in the set, replace it
140140
if insertIndex < len(r.set) && r.compareFunc(resource, r.set[insertIndex]) == 0 {
141141
r.set[insertIndex] = resource
142142
return
143143
}
144-
if r.sortFunc == nil {
145-
r.set = append(r.set, resource)
146-
return
147-
}
148144

149145
// insert the resource at the determined index
150146
r.set = slices.Insert(r.set, insertIndex, resource)
@@ -263,7 +259,7 @@ func (r1 Resources) Intersection(r2 Resources) Resources {
263259
// Has returns true if and only if item is contained in the set.
264260
func (r *Resources) Has(item ezkube.ResourceId) bool {
265261
i := sort.Search(r.Length(), func(i int) bool {
266-
return ezkube.CompareResourceIds(r.set[i], item) >= 0
262+
return r.compareFunc(r.set[i], item) >= 0
267263
})
268264
return i < r.Length() && r.compareFunc(r.set[i], item) == 0
269265
}

contrib/pkg/sets/v2/sets.go

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@ import (
1616
type ResourceSet[T client.Object] interface {
1717
// Get the set stored keys
1818
Keys() sets.Set[string]
19-
// List of resources stored in the set. Pass an optional filter function to filter on the list.
19+
// List returns an iterator for the set.
20+
// Pass an optional filter function to skip iteration on specific entries; Note: index will still progress.
2021
List(filterResource ...func(T) bool) iter.Seq2[int, T]
2122
// Return the Set as a map of key to resource.
2223
Map() map[string]T
2324
// Insert a resource into the set.
2425
Insert(resource ...T)
2526
// Compare the equality of the keys in two sets (not the resources themselves)
2627
Equal(set ResourceSet[T]) bool
27-
// Check if the set contains a key matching the resource (not the resource itself)
28+
// Check if the set contains the resource. Uses the compare func to determine equality.
2829
Has(resource T) bool
29-
// Delete the key matching the resource
30+
// Delete the matching resource. Uses the compare func to determine equality.
3031
Delete(resource T)
3132
// Return the union with the provided set
3233
Union(set ResourceSet[T]) ResourceSet[T]
@@ -35,15 +36,17 @@ type ResourceSet[T client.Object] interface {
3536
// Return the intersection with the provided set
3637
Intersection(set ResourceSet[T]) ResourceSet[T]
3738
// Find the resource with the given ID
38-
Find(id T) (T, error)
39+
Find(resource ezkube.ResourceId) (T, error)
3940
// Get the length of the set
40-
Length() int
41+
Len() int
4142
// returns the generic implementation of the set
4243
Generic() sk_sets.ResourceSet
4344
// returns the delta between this and and another ResourceSet[T]
4445
Delta(newSet ResourceSet[T]) sk_sets.ResourceDelta
4546
// Clone returns a deep copy of the set
4647
Clone() ResourceSet[T]
48+
// Get the compare function used by the set
49+
GetCompareFunc() func(a, b client.Object) int
4750
}
4851

4952
// ResourceDelta represents the set of changes between two ResourceSets.
@@ -64,18 +67,15 @@ func (r *ResourceDelta[T]) DeltaV1() sk_sets.ResourceDelta {
6467
type resourceSet[T client.Object] struct {
6568
lock sync.RWMutex
6669
set []T
67-
sortFunc func(toInsert, existing client.Object) bool
6870
compareFunc func(a, b client.Object) int
6971
}
7072

7173
func NewResourceSet[T client.Object](
72-
sortFunc func(toInsert, existing client.Object) bool,
7374
compareFunc func(a, b client.Object) int,
7475
resources ...T,
7576
) ResourceSet[T] {
7677
rs := &resourceSet[T]{
7778
set: []T{},
78-
sortFunc: sortFunc,
7979
compareFunc: compareFunc,
8080
}
8181
rs.Insert(resources...)
@@ -122,22 +122,18 @@ func (s *resourceSet[T]) Map() map[string]T {
122122

123123
// Insert adds items to the set.
124124
// If an item is already in the set, it is overwritten.
125-
// The set is sorted based on the sortFunc. If sortFunc is nil, the set will be unsorted.
125+
// The set is sorted based on the compare func.
126126
func (s *resourceSet[T]) Insert(resources ...T) {
127127
s.lock.RLock()
128128
defer s.lock.RUnlock()
129129
for _, resource := range resources {
130-
insertIndex := sort.Search(len(s.set), func(i int) bool { return s.sortFunc(resource, s.set[i]) })
130+
insertIndex := sort.Search(len(s.set), func(i int) bool { return s.compareFunc(resource, s.set[i]) < 0 })
131131

132132
// if the resource is already in the set, replace it
133133
if insertIndex < len(s.set) && s.compareFunc(resource, s.set[insertIndex]) == 0 {
134134
s.set[insertIndex] = resource
135135
return
136136
}
137-
if s.sortFunc == nil {
138-
s.set = append(s.set, resource)
139-
return
140-
}
141137

142138
// insert the resource at the determined index
143139
s.set = slices.Insert(s.set, insertIndex, resource)
@@ -148,7 +144,7 @@ func (s *resourceSet[T]) Has(resource T) bool {
148144
s.lock.RLock()
149145
defer s.lock.RUnlock()
150146
i := sort.Search(len(s.set), func(i int) bool {
151-
return ezkube.CompareResourceIds(s.set[i], resource) >= 0
147+
return s.compareFunc(s.set[i], resource) >= 0
152148
})
153149
return i < len(s.set) && s.compareFunc(s.set[i], resource) == 0
154150
}
@@ -167,11 +163,9 @@ func (s *resourceSet[T]) Delete(resource T) {
167163
i := sort.Search(len(s.set), func(i int) bool {
168164
return s.compareFunc(s.set[i], resource) >= 0
169165
})
170-
if found := i < len(s.set) && s.compareFunc(s.set[i], resource) == 0; !found {
171-
return
166+
if i != len(s.set) && s.compareFunc(s.set[i], resource) == 0 {
167+
s.set = slices.Delete(s.set, i, i+1)
172168
}
173-
174-
s.set = slices.Delete(s.set, i, i+1)
175169
}
176170

177171
func (s *resourceSet[T]) Union(set ResourceSet[T]) ResourceSet[T] {
@@ -180,7 +174,6 @@ func (s *resourceSet[T]) Union(set ResourceSet[T]) ResourceSet[T] {
180174
list = append(list, resource.(T))
181175
}
182176
return NewResourceSet[T](
183-
s.sortFunc,
184177
s.compareFunc,
185178
list...,
186179
)
@@ -189,7 +182,7 @@ func (s *resourceSet[T]) Union(set ResourceSet[T]) ResourceSet[T] {
189182
func (s *resourceSet[T]) Difference(set ResourceSet[T]) ResourceSet[T] {
190183
s.lock.RLock()
191184
defer s.lock.RUnlock()
192-
result := NewResourceSet[T](s.sortFunc, s.compareFunc)
185+
result := NewResourceSet[T](s.compareFunc)
193186
for _, resource := range s.set {
194187
if !set.Has(resource) {
195188
result.Insert(resource)
@@ -202,13 +195,13 @@ func (s *resourceSet[T]) Intersection(set ResourceSet[T]) ResourceSet[T] {
202195
s.lock.RLock()
203196
defer s.lock.RUnlock()
204197
var walk, other ResourceSet[T]
205-
result := NewResourceSet[T](s.sortFunc, s.compareFunc)
206-
if len(s.set) < set.Length() {
207-
walk = NewResourceSet(s.sortFunc, s.compareFunc, s.set...)
198+
result := NewResourceSet[T](s.compareFunc)
199+
if len(s.set) < set.Len() {
200+
walk = NewResourceSet(s.compareFunc, s.set...)
208201
other = set
209202
} else {
210203
walk = set
211-
other = NewResourceSet(s.sortFunc, s.compareFunc, s.set...)
204+
other = NewResourceSet(s.compareFunc, s.set...)
212205
}
213206
for _, key := range walk.List() {
214207
if other.Has(key) {
@@ -218,33 +211,31 @@ func (s *resourceSet[T]) Intersection(set ResourceSet[T]) ResourceSet[T] {
218211
return result
219212
}
220213

221-
func (s *resourceSet[T]) Find(id T) (T, error) {
214+
// this is only possible when the compare func is ezkube.ResourceIdsCompare
215+
// otherwise the set won't be sorted to allow for binary search
216+
func (s *resourceSet[T]) Find(resource ezkube.ResourceId) (T, error) {
222217
s.lock.RLock()
223218
defer s.lock.RUnlock()
224-
key := sk_sets.Key(id)
219+
desired_key := sk_sets.Key(resource)
225220
i := sort.Search(len(s.set), func(i int) bool {
226-
return key <= sk_sets.Key(s.set[i])
221+
return sk_sets.Key(s.set[i]) >= desired_key
227222
})
228-
var resource T
229-
if i < len(s.set) {
230-
resource = s.set[i]
231-
}
232-
if i != len(s.set) && sk_sets.Key(resource) == key {
233-
return resource, nil
223+
var found T
224+
if i < len(s.set) && sk_sets.Key(s.set[i]) == desired_key {
225+
return s.set[i], nil
234226
}
235-
236-
return resource, sk_sets.NotFoundErr(resource, id)
227+
return found, sk_sets.NotFoundErr(found, resource)
237228
}
238229

239-
func (s *resourceSet[T]) Length() int {
230+
func (s *resourceSet[T]) Len() int {
240231
s.lock.RLock()
241232
defer s.lock.RUnlock()
242233
return len(s.set)
243234
}
244235

245236
// note that this function will currently panic if called for a ResourceSet[T] containing non-runtime.Objects
246237
func (oldSet *resourceSet[T]) Delta(newSet ResourceSet[T]) sk_sets.ResourceDelta {
247-
updated, removed := NewResourceSet[T](oldSet.sortFunc, oldSet.compareFunc), NewResourceSet[T](oldSet.sortFunc, oldSet.compareFunc)
238+
updated, removed := NewResourceSet[T](oldSet.compareFunc), NewResourceSet[T](oldSet.compareFunc)
248239

249240
// find objects updated or removed
250241
for _, resource := range oldSet.set {
@@ -279,25 +270,26 @@ func (oldSet *resourceSet[T]) Delta(newSet ResourceSet[T]) sk_sets.ResourceDelta
279270
// Create a clone of the current set
280271
// note that this function will currently panic if called for a ResourceSet[T] containing non-runtime.Objects
281272
func (oldSet *resourceSet[T]) Clone() ResourceSet[T] {
282-
new := NewResourceSet[T](oldSet.sortFunc, oldSet.compareFunc)
283-
oldSet.List(func(oldObj T) bool {
273+
new := NewResourceSet[T](oldSet.compareFunc)
274+
275+
for _, oldObj := range oldSet.List() {
284276
copy := oldObj.DeepCopyObject().(T)
285277
new.Insert(copy)
286-
return true
287-
})
278+
}
288279
return new
289280
}
290281

291282
func (s *resourceSet[T]) Generic() sk_sets.ResourceSet {
292-
genericSortFunc := func(toInsert, existing interface{}) bool {
293-
return s.sortFunc(toInsert.(T), existing.(T))
294-
}
295283
genericCompareFunc := func(a, b interface{}) int {
296284
return s.compareFunc(a.(T), b.(T))
297285
}
298-
set := sk_sets.NewResourceSet(genericSortFunc, genericCompareFunc)
286+
set := sk_sets.NewResourceSet(nil, genericCompareFunc)
299287
for _, v := range s.List() {
300288
set.Insert(v)
301289
}
302290
return set
303291
}
292+
293+
func (s *resourceSet[T]) GetCompareFunc() func(a, b client.Object) int {
294+
return s.compareFunc
295+
}

0 commit comments

Comments
 (0)