Skip to content

🌱 refactor: replace slower and inefficient sorting functions #12473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions api/bootstrap/kubeadm/v1beta2/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
package v1beta2

import (
"sort"
"slices"
)

func (*KubeadmConfig) Hub() {}
Expand All @@ -38,11 +38,17 @@ func ConvertToArgs(in map[string]string) []Arg {
for k, v := range in {
args = append(args, Arg{Name: k, Value: v})
}
sort.Slice(args, func(i, j int) bool {
if args[i].Name == args[j].Name {
return args[i].Value < args[j].Value
slices.SortFunc(args, func(i, j Arg) int {
if i.Name == j.Name {
if i.Value < j.Value {
return 1
}
return -1
}
return args[i].Name < args[j].Name
if i.Name < j.Name {
return 1
}
return -1
})
return args
}
Expand Down
9 changes: 6 additions & 3 deletions cmd/clusterctl/client/cluster/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package cluster
import (
"context"
"fmt"
"sort"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -90,8 +90,11 @@ func (i *providerInstaller) Add(components repository.Components) {
i.installQueue = append(i.installQueue, components)

// Ensure Providers are installed in the following order: Core, Bootstrap, ControlPlane, Infrastructure.
sort.Slice(i.installQueue, func(a, b int) bool {
return i.installQueue[a].Type().Order() < i.installQueue[b].Type().Order()
slices.SortFunc(i.installQueue, func(a, b repository.Components) int {
if a.Type().Order() < b.Type().Order() {
return -1
}
return 1
})
}

Expand Down
23 changes: 16 additions & 7 deletions cmd/clusterctl/client/cluster/objectgraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package cluster
import (
"context"
"fmt"
"sort"
"slices"
"testing"

. "github.com/onsi/gomega"
Expand Down Expand Up @@ -2574,8 +2574,11 @@ func Test_objectGraph_setClusterTenants(t *testing.T) {
gb.setTenants()

gotClusters := gb.getClusters()
sort.Slice(gotClusters, func(i, j int) bool {
return gotClusters[i].identity.UID < gotClusters[j].identity.UID
slices.SortFunc(gotClusters, func(i, j *node) int {
if i.identity.UID < j.identity.UID {
return -1
}
return 1
})

g.Expect(gotClusters).To(HaveLen(len(tt.wantClusters)))
Expand Down Expand Up @@ -2673,8 +2676,11 @@ func Test_objectGraph_setCRSTenants(t *testing.T) {
gb.setTenants()

gotCRSs := gb.getCRSs()
sort.Slice(gotCRSs, func(i, j int) bool {
return gotCRSs[i].identity.UID < gotCRSs[j].identity.UID
slices.SortFunc(gotCRSs, func(i, j *node) int {
if i.identity.UID < j.identity.UID {
return -1
}
return 1
})

g.Expect(gotCRSs).To(HaveLen(len(tt.wantCRSs)))
Expand Down Expand Up @@ -2738,8 +2744,11 @@ func Test_objectGraph_setGlobalIdentityTenants(t *testing.T) {
gotIdentity = append(gotIdentity, n)
}
}
sort.Slice(gotIdentity, func(i, j int) bool {
return gotIdentity[i].identity.UID < gotIdentity[j].identity.UID
slices.SortFunc(gotIdentity, func(i, j *node) int {
if i.identity.UID < j.identity.UID {
return -1
}
return 1
})
g.Expect(gotIdentity).To(HaveLen(len(tt.wantIdentity)))

Expand Down
9 changes: 6 additions & 3 deletions cmd/clusterctl/client/cluster/upgrader.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package cluster

import (
"context"
"sort"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -398,8 +398,11 @@ func (u *providerUpgrader) doUpgrade(ctx context.Context, upgradePlan *UpgradePl

// Ensure Providers are updated in the following order: Core, Bootstrap, ControlPlane, Infrastructure.
providers := upgradePlan.Providers
sort.Slice(providers, func(a, b int) bool {
return providers[a].GetProviderType().Order() < providers[b].GetProviderType().Order()
slices.SortFunc(providers, func(a, b UpgradeItem) int {
if a.GetProviderType().Order() < b.GetProviderType().Order() {
return -1
}
return 1
})

if opts.EnableCRDStorageVersionMigration {
Expand Down
17 changes: 11 additions & 6 deletions cmd/clusterctl/client/cluster/upgrader_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package cluster
import (
"context"
"fmt"
"sort"
"slices"

"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/sets"
Expand Down Expand Up @@ -124,14 +124,19 @@ func (u *providerUpgrader) getUpgradeInfo(ctx context.Context, provider clusterc

func newUpgradeInfo(metadata *clusterctlv1.Metadata, currentVersion *version.Version, nextVersions []version.Version) *upgradeInfo {
// Sorts release series; this ensures also an implicit ordering of contract versions.
sort.Slice(metadata.ReleaseSeries, func(i, j int) bool {
return metadata.ReleaseSeries[i].Major < metadata.ReleaseSeries[j].Major ||
(metadata.ReleaseSeries[i].Major == metadata.ReleaseSeries[j].Major && metadata.ReleaseSeries[i].Minor < metadata.ReleaseSeries[j].Minor)
slices.SortFunc(metadata.ReleaseSeries, func(i, j clusterctlv1.ReleaseSeries) int {
if i.Major < j.Major || (i.Major == j.Major && i.Minor < j.Minor) {
return -1
}
return 1
})

// Sorts nextVersions.
sort.Slice(nextVersions, func(i, j int) bool {
return nextVersions[i].LessThan(&nextVersions[j])
slices.SortFunc(nextVersions, func(i, j version.Version) int {
if i.LessThan(&j) {
return -1
}
return 1
})

// Gets the current contract for the provider
Expand Down
9 changes: 6 additions & 3 deletions cmd/clusterctl/client/config/providers_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package config
import (
"net/url"
"os"
"sort"
"slices"
"strings"

"github.com/drone/envsubst/v2"
Expand Down Expand Up @@ -504,8 +504,11 @@ func (p *providersClient) List() ([]Provider, error) {
}

// ensure provider configurations are consistently sorted
sort.Slice(providers, func(i, j int) bool {
return providers[i].Less(providers[j])
slices.SortFunc(providers, func(i, j Provider) int {
if i.Less(j) {
return -1
}
return 1
})

return providers, nil
Expand Down
16 changes: 11 additions & 5 deletions cmd/clusterctl/client/config/providers_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package config

import (
"fmt"
"sort"
"slices"
"testing"

. "github.com/onsi/gomega"
Expand All @@ -36,14 +36,20 @@ func Test_providers_List(t *testing.T) {
}

defaults := p.defaults()
sort.Slice(defaults, func(i, j int) bool {
return defaults[i].Less(defaults[j])
slices.SortFunc(defaults, func(i, j Provider) int {
if i.Less(j) {
return -1
}
return 1
})

defaultsAndZZZ := append(defaults, NewProvider("zzz", "https://zzz/infrastructure-components.yaml", "InfrastructureProvider"))
// AddonProviders are at the end of the list so we want to make sure this InfrastructureProvider is before the AddonProviders.
sort.Slice(defaultsAndZZZ, func(i, j int) bool {
return defaultsAndZZZ[i].Less(defaultsAndZZZ[j])
slices.SortFunc(defaultsAndZZZ, func(i, j Provider) int {
if i.Less(j) {
return -1
}
return 1
})

defaultsWithOverride := append([]Provider{}, defaults...)
Expand Down
17 changes: 10 additions & 7 deletions cmd/clusterctl/client/repository/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package repository

import (
"fmt"
"sort"
"slices"
"strings"

"github.com/pkg/errors"
Expand Down Expand Up @@ -262,17 +262,20 @@ func NewComponents(input ComponentsInput) (Components, error) {
// Deploying cert-manager objects and especially Certificates before Mutating-
// ValidatingWebhookConfigurations and CRDs ensures cert-manager's ca-injector
// receives the event for the objects at the right time to inject the new CA.
sort.SliceStable(objs, func(i, j int) bool {
slices.SortStableFunc(objs, func(i, j unstructured.Unstructured) int {
// First prioritize Namespaces over everything.
if objs[i].GetKind() == "Namespace" {
return true
if i.GetKind() == "Namespace" {
return -1
}
if objs[j].GetKind() == "Namespace" {
return false
if j.GetKind() == "Namespace" {
return 1
}

// Second prioritize cert-manager objects.
return objs[i].GroupVersionKind().Group == "cert-manager.io"
if i.GroupVersionKind().Group == "cert-manager.io" {
return -1
}
return 1
})

return &components{
Expand Down
17 changes: 10 additions & 7 deletions cmd/clusterctl/client/repository/repository_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package repository

import (
"context"
"sort"
"slices"

"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -114,17 +114,20 @@ func latestPatchRelease(ctx context.Context, repo Repository, major, minor *int3
}

// Sort parsed versions by semantic version order.
sort.SliceStable(versionCandidates, func(i, j int) bool {
slices.SortStableFunc(versionCandidates, func(i, j *version.Version) int {
// Prioritize release versions over pre-releases. For example v1.0.0 > v2.0.0-alpha
// If both are pre-releases, sort by semantic version order as usual.
if versionCandidates[j].PreRelease() == "" && versionCandidates[i].PreRelease() != "" {
return false
if j.PreRelease() == "" && i.PreRelease() != "" {
return 1
}
if versionCandidates[i].PreRelease() == "" && versionCandidates[j].PreRelease() != "" {
return true
if i.PreRelease() == "" && j.PreRelease() != "" {
return -1
}

return versionCandidates[j].LessThan(versionCandidates[i])
if j.LessThan(i) {
return -1
}
return 1
})

// Limit the number of searchable versions by 5.
Expand Down
8 changes: 6 additions & 2 deletions cmd/clusterctl/client/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package tree

import (
"fmt"
"slices"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -149,8 +150,11 @@ func (od ObjectTree) Add(parent, obj client.Object, opts ...AddObjectOption) (ad

// The loop below will process the next node and decide if it belongs in a group. Since objects in the same group
// must have the same Kind, we sort by Kind so objects of the same Kind will be together in the list.
sort.Slice(siblings, func(i, j int) bool {
return siblings[i].GetObjectKind().GroupVersionKind().Kind < siblings[j].GetObjectKind().GroupVersionKind().Kind
slices.SortFunc(siblings, func(i, j client.Object) int {
if i.GetObjectKind().GroupVersionKind().Kind < j.GetObjectKind().GroupVersionKind().Kind {
return -1
}
return 1
})

for i := range siblings {
Expand Down
9 changes: 6 additions & 3 deletions cmd/clusterctl/client/tree/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package tree

import (
"fmt"
"sort"
"slices"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -116,8 +116,11 @@ func GetOtherV1Beta1Conditions(obj client.Object) []*clusterv1.Condition {
conditions = append(conditions, &c)
}
}
sort.Slice(conditions, func(i, j int) bool {
return conditions[i].Type < conditions[j].Type
slices.SortFunc(conditions, func(i, j *clusterv1.Condition) int {
if i.Type < j.Type {
return -1
}
return 1
})
return conditions
}
Expand Down
16 changes: 11 additions & 5 deletions cmd/clusterctl/client/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package client

import (
"context"
"sort"
"slices"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -288,11 +288,17 @@ func Test_clusterctlClient_ApplyUpgrade(t *testing.T) {

g.Expect(c.List(ctx, gotProviders)).To(Succeed())

sort.Slice(gotProviders.Items, func(i, j int) bool {
return gotProviders.Items[i].Name < gotProviders.Items[j].Name
slices.SortFunc(gotProviders.Items, func(i, j clusterctlv1.Provider) int {
if i.Name < j.Name {
return -1
}
return 1
})
sort.Slice(tt.wantProviders.Items, func(i, j int) bool {
return tt.wantProviders.Items[i].Name < tt.wantProviders.Items[j].Name
slices.SortFunc(tt.wantProviders.Items, func(i, j clusterctlv1.Provider) int {
if i.Name < j.Name {
return -1
}
return 1
})
for i := range gotProviders.Items {
tt.wantProviders.Items[i].ResourceVersion = gotProviders.Items[i].ResourceVersion
Expand Down
Loading