diff --git a/go.mod b/go.mod index a55b60c360..1fbe3298d0 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/openshift/operator-framework-olm go 1.17 require ( + github.com/blang/semver/v4 v4.0.0 github.com/go-bindata/go-bindata/v3 v3.1.3 github.com/go-logr/logr v0.4.0 github.com/golang/mock v1.6.0 @@ -57,8 +58,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/cgroups v1.0.3 // indirect github.com/containerd/containerd v1.5.13 // indirect github.com/containerd/continuity v0.1.0 // indirect diff --git a/go.sum b/go.sum index b14714e67b..594f43221a 100644 --- a/go.sum +++ b/go.sum @@ -205,8 +205,9 @@ github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6 github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= diff --git a/pkg/package-server-manager/config.go b/pkg/package-server-manager/config.go index 1e8a2c79c5..5ef355020d 100644 --- a/pkg/package-server-manager/config.go +++ b/pkg/package-server-manager/config.go @@ -11,6 +11,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/pointer" + + "github.com/openshift/operator-framework-olm/pkg/manifests" ) func getReplicas(ha bool) int32 { @@ -61,8 +63,61 @@ func getTopologyModeFromInfra(infra *configv1.Infrastructure) bool { } // ensureCSV is responsible for ensuring the state of the @csv ClusterServiceVersion custom +// resource matches that of the codified defaults and high availability configurations, where +// codified defaults are defined by the csv returned by the manifests.NewPackageServerCSV +// function. +func ensureCSV(log logr.Logger, image string, csv *olmv1alpha1.ClusterServiceVersion, highlyAvailableMode bool) (bool, error) { + expectedCSV, err := manifests.NewPackageServerCSV( + manifests.WithName(csv.Name), + manifests.WithNamespace(csv.Namespace), + manifests.WithImage(image), + ) + if err != nil { + return false, err + } + + ensureCSVHighAvailability(image, expectedCSV, highlyAvailableMode) + + var modified bool + + for k, v := range expectedCSV.GetLabels() { + if csv.GetLabels() == nil { + csv.SetLabels(make(map[string]string)) + } + if vv, ok := csv.GetLabels()[k]; !ok || vv != v { + log.Info("setting expected label", "key", k, "value", v) + csv.ObjectMeta.Labels[k] = v + modified = true + } + } + + for k, v := range expectedCSV.GetAnnotations() { + if csv.GetAnnotations() == nil { + csv.SetAnnotations(make(map[string]string)) + } + if vv, ok := csv.GetAnnotations()[k]; !ok || vv != v { + log.Info("setting expected annotation", "key", k, "value", v) + csv.ObjectMeta.Annotations[k] = v + modified = true + } + } + + if !reflect.DeepEqual(expectedCSV.Spec, csv.Spec) { + log.Info("updating csv spec") + csv.Spec = expectedCSV.Spec + modified = true + } + + if modified { + log.V(3).Info("csv has been modified") + } + + return modified, err +} + +// ensureCSVHighAvailability is responsible for ensuring the state of the @csv ClusterServiceVersion custom // resource matches the expected state based on any high availability expectations being exposed. -func ensureCSV(log logr.Logger, image string, csv *olmv1alpha1.ClusterServiceVersion, highlyAvailableMode bool) bool { +func ensureCSVHighAvailability(image string, csv *olmv1alpha1.ClusterServiceVersion, highlyAvailableMode bool) { var modified bool deploymentSpecs := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs @@ -70,52 +125,29 @@ func ensureCSV(log logr.Logger, image string, csv *olmv1alpha1.ClusterServiceVer currentImage := deployment.Template.Spec.Containers[0].Image if currentImage != image { - log.Info("updating the image", "old", currentImage, "new", image) deployment.Template.Spec.Containers[0].Image = image modified = true } expectedReplicas := getReplicas(highlyAvailableMode) if *deployment.Replicas != expectedReplicas { - log.Info("updating the replica count", "old", deployment.Replicas, "new", expectedReplicas) deployment.Replicas = pointer.Int32Ptr(expectedReplicas) modified = true } expectedRolloutConfiguration := getRolloutStrategy(highlyAvailableMode) if !reflect.DeepEqual(deployment.Strategy.RollingUpdate, expectedRolloutConfiguration) { - log.Info("updating the rollout strategy") deployment.Strategy.RollingUpdate = expectedRolloutConfiguration modified = true } expectedAffinityConfiguration := getAntiAffinityConfig(highlyAvailableMode) if !reflect.DeepEqual(deployment.Template.Spec.Affinity, expectedAffinityConfiguration) { - log.Info("updating the pod anti-affinity configuration") deployment.Template.Spec.Affinity = expectedAffinityConfiguration modified = true } if modified { - log.V(3).Info("csv has been modified") csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec = *deployment } - - return modified -} - -func validateCSV(log logr.Logger, csv *olmv1alpha1.ClusterServiceVersion) bool { - deploymentSpecs := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs - if len(deploymentSpecs) != 1 { - log.Info("csv contains more than one or zero nested deployment specs") - return false - } - - deployment := &deploymentSpecs[0].Spec - if len(deployment.Template.Spec.Containers) != 1 { - log.Info("csv contains more than one container") - return false - } - - return true } diff --git a/pkg/package-server-manager/controller.go b/pkg/package-server-manager/controller.go index 9930fac50f..90499bb063 100644 --- a/pkg/package-server-manager/controller.go +++ b/pkg/package-server-manager/controller.go @@ -18,6 +18,7 @@ package controllers import ( "context" + "fmt" "sync" "github.com/go-logr/logr" @@ -85,11 +86,12 @@ func (r *PackageServerCSVReconciler) Reconcile(ctx context.Context, req ctrl.Req res, err := controllerutil.CreateOrUpdate(ctx, r.Client, required, func() error { return reconcileCSV(r.Log, r.Image, required, highAvailabilityMode) }) + + log.Info("reconciliation result", "res", res) if err != nil { log.Error(err, "failed to create or update the packageserver csv") return ctrl.Result{}, nil } - log.Info("reconciliation result", "res", res) return ctrl.Result{}, nil } @@ -98,19 +100,13 @@ func reconcileCSV(log logr.Logger, image string, csv *olmv1alpha1.ClusterService if csv.ObjectMeta.CreationTimestamp.IsZero() { log.Info("attempting to create the packageserver csv") } - if !validateCSV(log, csv) { - log.Info("updating invalid csv to use the default configuration") - tmp, err := manifests.NewPackageServerCSV( - manifests.WithName(csv.Name), - manifests.WithNamespace(csv.Namespace), - manifests.WithImage(image), - ) - if err != nil { - return err - } - csv.Spec = tmp.Spec + + modified, err := ensureCSV(log, image, csv, highAvailabilityMode) + if err != nil { + return fmt.Errorf("error ensuring CSV: %v", err) } - if !ensureCSV(log, image, csv, highAvailabilityMode) { + + if !modified { log.V(3).Info("no further updates are necessary to the packageserver csv") } diff --git a/pkg/package-server-manager/controller_test.go b/pkg/package-server-manager/controller_test.go index 4ca1e4d340..f91a5f2281 100644 --- a/pkg/package-server-manager/controller_test.go +++ b/pkg/package-server-manager/controller_test.go @@ -3,8 +3,10 @@ package controllers import ( "testing" + semver "github.com/blang/semver/v4" configv1 "github.com/openshift/api/config/v1" "github.com/openshift/operator-framework-olm/pkg/manifests" + "github.com/operator-framework/api/pkg/lib/version" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" @@ -72,10 +74,39 @@ func intOrStr(val int) *intstr.IntOrString { return &tmp } +type testCSVOption func(*olmv1alpha1.ClusterServiceVersion) + +func withVersion(v semver.Version) func(*olmv1alpha1.ClusterServiceVersion) { + return func(csv *olmv1alpha1.ClusterServiceVersion) { + csv.Spec.Version = version.OperatorVersion{v} + } +} + +func withDescription(description string) func(*olmv1alpha1.ClusterServiceVersion) { + return func(csv *olmv1alpha1.ClusterServiceVersion) { + csv.Spec.Description = description + } +} + +func withAffinity(affinity *corev1.Affinity) func(*olmv1alpha1.ClusterServiceVersion) { + return func(csv *olmv1alpha1.ClusterServiceVersion) { + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Affinity = affinity + } +} +func withRollingUpdateStrategy(strategy *appsv1.RollingUpdateDeployment) func(*olmv1alpha1.ClusterServiceVersion) { + return func(csv *olmv1alpha1.ClusterServiceVersion) { + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Strategy.RollingUpdate = strategy + } +} + +func withReplicas(replicas *int32) func(*olmv1alpha1.ClusterServiceVersion) { + return func(csv *olmv1alpha1.ClusterServiceVersion) { + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Replicas = replicas + } +} + func newTestCSV( - replicas *int32, - strategy *appsv1.RollingUpdateDeployment, - affinity *corev1.Affinity, + options ...testCSVOption, ) *olmv1alpha1.ClusterServiceVersion { csv, err := manifests.NewPackageServerCSV( manifests.WithName(name), @@ -84,11 +115,10 @@ func newTestCSV( if err != nil { return nil } - deployment := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec - deployment.Template.Spec.Affinity = affinity - deployment.Replicas = replicas - deployment.Strategy.RollingUpdate = strategy - csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec = deployment + + for _, o := range options { + o(csv) + } return csv } @@ -133,74 +163,94 @@ func TestEnsureCSV(t *testing.T) { singleReplicas := pointer.Int32(singleReplicaCount) image := getImageFromManifest() + type wanted struct { + expectedBool bool + expectedErr error + } + tt := []struct { name string inputCSV *olmv1alpha1.ClusterServiceVersion expectedCSV *olmv1alpha1.ClusterServiceVersion highlyAvailable bool - want bool + want wanted }{ { name: "Modified/HighlyAvailable/CorrectReplicasIncorrectRolling", - want: true, + want: wanted{true, nil}, highlyAvailable: true, - inputCSV: newTestCSV(defaultReplicas, emptyRollout, defaultAffinity), - expectedCSV: newTestCSV(defaultReplicas, defaultRollout, defaultAffinity), + inputCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(defaultAffinity)), + expectedCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(defaultAffinity)), }, { name: "Modified/HighlyAvailable/IncorrectReplicasCorrectRolling", - want: true, + want: wanted{true, nil}, highlyAvailable: true, - inputCSV: newTestCSV(singleReplicas, defaultRollout, defaultAffinity), - expectedCSV: newTestCSV(defaultReplicas, defaultRollout, defaultAffinity), + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(defaultAffinity)), + expectedCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(defaultAffinity)), }, { name: "Modified/HighlyAvailable/IncorrectPodAntiAffinity", - want: true, + want: wanted{true, nil}, highlyAvailable: true, - inputCSV: newTestCSV(singleReplicas, defaultRollout, newPodAffinity(&corev1.PodAntiAffinity{ + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(newPodAffinity(&corev1.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ { Weight: 1, }, }, - })), - expectedCSV: newTestCSV(defaultReplicas, defaultRollout, defaultAffinity), + }))), + expectedCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(defaultAffinity)), }, { name: "NotModified/HighlyAvailable", - want: false, + want: wanted{false, nil}, highlyAvailable: true, - inputCSV: newTestCSV(defaultReplicas, defaultRollout, defaultAffinity), - expectedCSV: newTestCSV(defaultReplicas, defaultRollout, defaultAffinity), + inputCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(defaultAffinity)), + expectedCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(defaultAffinity)), }, + { name: "Modified/SingleReplica/CorrectReplicasIncorrectRolling", - want: true, + want: wanted{true, nil}, highlyAvailable: false, - inputCSV: newTestCSV(singleReplicas, defaultRollout, &corev1.Affinity{}), - expectedCSV: newTestCSV(singleReplicas, emptyRollout, &corev1.Affinity{}), + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(defaultRollout), withAffinity(&corev1.Affinity{})), + expectedCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), }, { name: "Modified/SingleReplica/IncorrectReplicasCorrectRolling", - want: true, + want: wanted{true, nil}, highlyAvailable: false, - inputCSV: newTestCSV(defaultReplicas, emptyRollout, &corev1.Affinity{}), - expectedCSV: newTestCSV(singleReplicas, emptyRollout, &corev1.Affinity{}), + inputCSV: newTestCSV(withReplicas(defaultReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), + expectedCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), }, { name: "Modified/SingleReplica/IncorrectPodAntiAffinity", - want: true, + want: wanted{true, nil}, + highlyAvailable: false, + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(defaultAffinity)), + expectedCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), + }, + { + name: "Modified/SingleReplica/IncorrectVersion", + want: wanted{true, nil}, + highlyAvailable: false, + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{}), withVersion(semver.Version{Major: 0, Minor: 0, Patch: 0})), + expectedCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), + }, + { + name: "Modified/SingleReplica/IncorrectDescription", + want: wanted{true, nil}, highlyAvailable: false, - inputCSV: newTestCSV(singleReplicas, emptyRollout, defaultAffinity), - expectedCSV: newTestCSV(singleReplicas, emptyRollout, &corev1.Affinity{}), + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{}), withDescription("foo")), + expectedCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), }, { name: "NotModified/SingleReplica", - want: false, + want: wanted{false, nil}, highlyAvailable: false, - inputCSV: newTestCSV(singleReplicas, emptyRollout, &corev1.Affinity{}), - expectedCSV: newTestCSV(singleReplicas, emptyRollout, &corev1.Affinity{}), + inputCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), + expectedCSV: newTestCSV(withReplicas(singleReplicas), withRollingUpdateStrategy(emptyRollout), withAffinity(&corev1.Affinity{})), }, } @@ -208,8 +258,9 @@ func TestEnsureCSV(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - got := ensureCSV(logger, image, tc.inputCSV, tc.highlyAvailable) - require.EqualValues(t, tc.want, got) + gotBool, gotErr := ensureCSV(logger, image, tc.inputCSV, tc.highlyAvailable) + require.EqualValues(t, tc.want.expectedBool, gotBool) + require.EqualValues(t, tc.want.expectedErr, gotErr) require.EqualValues(t, tc.inputCSV.Spec, tc.expectedCSV.Spec) }) } diff --git a/vendor/github.com/cespare/xxhash/v2/.travis.yml b/vendor/github.com/cespare/xxhash/v2/.travis.yml deleted file mode 100644 index c516ea88da..0000000000 --- a/vendor/github.com/cespare/xxhash/v2/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: go -go: - - "1.x" - - master -env: - - TAGS="" - - TAGS="-tags purego" -script: go test $TAGS -v ./... diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md index 2fd8693c21..792b4a60b3 100644 --- a/vendor/github.com/cespare/xxhash/v2/README.md +++ b/vendor/github.com/cespare/xxhash/v2/README.md @@ -1,7 +1,7 @@ # xxhash -[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash) -[![Build Status](https://travis-ci.org/cespare/xxhash.svg?branch=master)](https://travis-ci.org/cespare/xxhash) +[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2) +[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml) xxhash is a Go implementation of the 64-bit [xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a @@ -64,4 +64,6 @@ $ go test -benchtime 10s -bench '/xxhash,direct,bytes' - [InfluxDB](https://github.com/influxdata/influxdb) - [Prometheus](https://github.com/prometheus/prometheus) +- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) - [FreeCache](https://github.com/coocood/freecache) +- [FastCache](https://github.com/VictoriaMetrics/fastcache) diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go index db0b35fbe3..15c835d541 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash.go @@ -193,7 +193,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error { b, d.v4 = consumeUint64(b) b, d.total = consumeUint64(b) copy(d.mem[:], b) - b = b[len(d.mem):] d.n = int(d.total % uint64(len(d.mem))) return nil } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s index d580e32aed..be8db5bf79 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s @@ -6,7 +6,7 @@ // Register allocation: // AX h -// CX pointer to advance through b +// SI pointer to advance through b // DX n // BX loop end // R8 v1, k1 @@ -16,39 +16,39 @@ // R12 tmp // R13 prime1v // R14 prime2v -// R15 prime4v +// DI prime4v -// round reads from and advances the buffer pointer in CX. +// round reads from and advances the buffer pointer in SI. // It assumes that R13 has prime1v and R14 has prime2v. #define round(r) \ - MOVQ (CX), R12 \ - ADDQ $8, CX \ + MOVQ (SI), R12 \ + ADDQ $8, SI \ IMULQ R14, R12 \ ADDQ R12, r \ ROLQ $31, r \ IMULQ R13, r // mergeRound applies a merge round on the two registers acc and val. -// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v. +// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v. #define mergeRound(acc, val) \ IMULQ R14, val \ ROLQ $31, val \ IMULQ R13, val \ XORQ val, acc \ IMULQ R13, acc \ - ADDQ R15, acc + ADDQ DI, acc // func Sum64(b []byte) uint64 TEXT ·Sum64(SB), NOSPLIT, $0-32 // Load fixed primes. MOVQ ·prime1v(SB), R13 MOVQ ·prime2v(SB), R14 - MOVQ ·prime4v(SB), R15 + MOVQ ·prime4v(SB), DI // Load slice. - MOVQ b_base+0(FP), CX + MOVQ b_base+0(FP), SI MOVQ b_len+8(FP), DX - LEAQ (CX)(DX*1), BX + LEAQ (SI)(DX*1), BX // The first loop limit will be len(b)-32. SUBQ $32, BX @@ -65,14 +65,14 @@ TEXT ·Sum64(SB), NOSPLIT, $0-32 XORQ R11, R11 SUBQ R13, R11 - // Loop until CX > BX. + // Loop until SI > BX. blockLoop: round(R8) round(R9) round(R10) round(R11) - CMPQ CX, BX + CMPQ SI, BX JLE blockLoop MOVQ R8, AX @@ -100,16 +100,16 @@ noBlocks: afterBlocks: ADDQ DX, AX - // Right now BX has len(b)-32, and we want to loop until CX > len(b)-8. + // Right now BX has len(b)-32, and we want to loop until SI > len(b)-8. ADDQ $24, BX - CMPQ CX, BX + CMPQ SI, BX JG fourByte wordLoop: // Calculate k1. - MOVQ (CX), R8 - ADDQ $8, CX + MOVQ (SI), R8 + ADDQ $8, SI IMULQ R14, R8 ROLQ $31, R8 IMULQ R13, R8 @@ -117,18 +117,18 @@ wordLoop: XORQ R8, AX ROLQ $27, AX IMULQ R13, AX - ADDQ R15, AX + ADDQ DI, AX - CMPQ CX, BX + CMPQ SI, BX JLE wordLoop fourByte: ADDQ $4, BX - CMPQ CX, BX + CMPQ SI, BX JG singles - MOVL (CX), R8 - ADDQ $4, CX + MOVL (SI), R8 + ADDQ $4, SI IMULQ R13, R8 XORQ R8, AX @@ -138,19 +138,19 @@ fourByte: singles: ADDQ $4, BX - CMPQ CX, BX + CMPQ SI, BX JGE finalize singlesLoop: - MOVBQZX (CX), R12 - ADDQ $1, CX + MOVBQZX (SI), R12 + ADDQ $1, SI IMULQ ·prime5v(SB), R12 XORQ R12, AX ROLQ $11, AX IMULQ R13, AX - CMPQ CX, BX + CMPQ SI, BX JL singlesLoop finalize: @@ -179,9 +179,9 @@ TEXT ·writeBlocks(SB), NOSPLIT, $0-40 MOVQ ·prime2v(SB), R14 // Load slice. - MOVQ b_base+8(FP), CX + MOVQ b_base+8(FP), SI MOVQ b_len+16(FP), DX - LEAQ (CX)(DX*1), BX + LEAQ (SI)(DX*1), BX SUBQ $32, BX // Load vN from d. @@ -199,7 +199,7 @@ blockLoop: round(R10) round(R11) - CMPQ CX, BX + CMPQ SI, BX JLE blockLoop // Copy vN back to d. @@ -208,8 +208,8 @@ blockLoop: MOVQ R10, 16(AX) MOVQ R11, 24(AX) - // The number of bytes written is CX minus the old base pointer. - SUBQ b_base+8(FP), CX - MOVQ CX, ret+32(FP) + // The number of bytes written is SI minus the old base pointer. + SUBQ b_base+8(FP), SI + MOVQ SI, ret+32(FP) RET diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go index 53bf76efbc..376e0ca2e4 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go @@ -6,41 +6,52 @@ package xxhash import ( - "reflect" "unsafe" ) -// Notes: +// In the future it's possible that compiler optimizations will make these +// XxxString functions unnecessary by realizing that calls such as +// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205. +// If that happens, even if we keep these functions they can be replaced with +// the trivial safe code. + +// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is: // -// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ -// for some discussion about these unsafe conversions. +// var b []byte +// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) +// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data +// bh.Len = len(s) +// bh.Cap = len(s) // -// In the future it's possible that compiler optimizations will make these -// unsafe operations unnecessary: https://golang.org/issue/2205. +// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough +// weight to this sequence of expressions that any function that uses it will +// not be inlined. Instead, the functions below use a different unsafe +// conversion designed to minimize the inliner weight and allow both to be +// inlined. There is also a test (TestInlining) which verifies that these are +// inlined. // -// Both of these wrapper functions still incur function call overhead since they -// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write -// for strings to squeeze out a bit more speed. Mid-stack inlining should -// eventually fix this. +// See https://github.com/golang/go/issues/42739 for discussion. // Sum64String computes the 64-bit xxHash digest of s. // It may be faster than Sum64([]byte(s)) by avoiding a copy. func Sum64String(s string) uint64 { - var b []byte - bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data - bh.Len = len(s) - bh.Cap = len(s) + b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) return Sum64(b) } // WriteString adds more data to d. It always returns len(s), nil. // It may be faster than Write([]byte(s)) by avoiding a copy. func (d *Digest) WriteString(s string) (n int, err error) { - var b []byte - bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data - bh.Len = len(s) - bh.Cap = len(s) - return d.Write(b) + d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))) + // d.Write always returns len(s), nil. + // Ignoring the return output and returning these fixed values buys a + // savings of 6 in the inliner's cost model. + return len(s), nil +} + +// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout +// of the first two words is the same as the layout of a string. +type sliceHeader struct { + s string + cap int } diff --git a/vendor/modules.txt b/vendor/modules.txt index c855f14779..7173baad47 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -99,7 +99,7 @@ github.com/blang/semver # github.com/blang/semver/v4 v4.0.0 ## explicit; go 1.14 github.com/blang/semver/v4 -# github.com/cespare/xxhash/v2 v2.1.1 +# github.com/cespare/xxhash/v2 v2.1.2 ## explicit; go 1.11 github.com/cespare/xxhash/v2 # github.com/containerd/cgroups v1.0.3