Skip to content

Commit d1b78eb

Browse files
committed
merge: Add flag to skip comparison after apply
Currently we have an expensive (especially since the parent commit) comparison after applying an object. This is mostly unuseful considering that we have a piece of code in kubernetes that removes entries that are no-ops. Provide a new flag so that the comparison can be disabled, especially since the comparison is done somewhere else, and the comparison is not good enough anyway. ``` BenchmarkOperations/Pod/ApplyTwice-8 267 437527 ns/op 110382 B/op 2722 allocs/op BenchmarkOperations/Pod/ApplyTwiceNoCompare-8 289 412029 ns/op 106516 B/op 2619 allocs/op BenchmarkOperations/Node/ApplyTwice-8 176 828565 ns/op 155376 B/op 3557 allocs/op BenchmarkOperations/Node/ApplyTwiceNoCompare-8 100 1179327 ns/op 149046 B/op 3370 allocs/op BenchmarkOperations/Endpoints/ApplyTwice-8 50 2268639 ns/op 208438 B/op 4402 allocs/op BenchmarkOperations/Endpoints/ApplyTwiceNoCompare-8 126 921992 ns/op 110419 B/op 2347 allocs/op BenchmarkOperations/Node100%override/ApplyTwice-8 174 669942 ns/op 155305 B/op 3556 allocs/op BenchmarkOperations/Node100%override/ApplyTwiceNoCompare-8 190 634832 ns/op 149025 B/op 3369 allocs/op BenchmarkOperations/Node10%override/ApplyTwice-8 157 691645 ns/op 155316 B/op 3557 allocs/op BenchmarkOperations/Node10%override/ApplyTwiceNoCompare-8 186 635949 ns/op 149036 B/op 3370 allocs/op BenchmarkOperations/Endpoints100%override/ApplyTwice-8 63 1811443 ns/op 208261 B/op 4400 allocs/op BenchmarkOperations/Endpoints100%override/ApplyTwiceNoCompare-8 127 932614 ns/op 110431 B/op 2347 allocs/op BenchmarkOperations/Endpoints10%override/ApplyTwice-8 58 1903112 ns/op 208359 B/op 4401 allocs/op BenchmarkOperations/Endpoints10%override/ApplyTwiceNoCompare-8 124 957186 ns/op 110426 B/op 2347 allocs/op BenchmarkOperations/PrometheusCRD/ApplyTwice-8 30 3843649 ns/op 983421 B/op 21105 allocs/op BenchmarkOperations/PrometheusCRD/ApplyTwiceNoCompare-8 34 3500118 ns/op 935164 B/op 19987 allocs/op BenchmarkOperations/apiresourceimport/ApplyTwice-8 7 15743401 ns/op 3650892 B/op 83842 allocs/op BenchmarkOperations/apiresourceimport/ApplyTwiceNoCompare-8 7 15123009 ns/op 3566088 B/op 81776 allocs/op ```
1 parent 6310a8a commit d1b78eb

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

internal/fixture/state.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ type TestCase struct {
537537
Managed fieldpath.ManagedFields
538538
// Set to true if the test case needs the union behavior enabled.
539539
RequiresUnions bool
540+
// ReportInputOnNoop if we don't want to compare the output and
541+
// always return it.
542+
ReturnInputOnNoop bool
540543
// IgnoredFields containing the set to ignore for every version
541544
IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
542545
}
@@ -569,13 +572,16 @@ func (tc TestCase) PreprocessOperations(parser Parser) error {
569572
// TestWithConverter once and reset the benchmark, to make sure the test case
570573
// actually passes..
571574
func (tc TestCase) BenchWithConverter(parser Parser, converter merge.Converter) error {
575+
updaterBuilder := merge.UpdaterBuilder{
576+
Converter: converter,
577+
IgnoredFields: tc.IgnoredFields,
578+
ReturnInputOnNoop: tc.ReturnInputOnNoop,
579+
EnableUnions: tc.RequiresUnions,
580+
}
572581
state := State{
573-
Updater: &merge.Updater{Converter: converter, IgnoredFields: tc.IgnoredFields},
582+
Updater: updaterBuilder.BuildUpdater(),
574583
Parser: parser,
575584
}
576-
if tc.RequiresUnions {
577-
state.Updater.EnableUnionFeature()
578-
}
579585
// We currently don't have any test that converts, we can take
580586
// care of that later.
581587
for i, ops := range tc.Ops {
@@ -589,13 +595,16 @@ func (tc TestCase) BenchWithConverter(parser Parser, converter merge.Converter)
589595

590596
// TestWithConverter runs the test-case using the given parser and converter.
591597
func (tc TestCase) TestWithConverter(parser Parser, converter merge.Converter) error {
598+
updaterBuilder := merge.UpdaterBuilder{
599+
Converter: converter,
600+
IgnoredFields: tc.IgnoredFields,
601+
ReturnInputOnNoop: tc.ReturnInputOnNoop,
602+
EnableUnions: tc.RequiresUnions,
603+
}
592604
state := State{
593-
Updater: &merge.Updater{Converter: converter, IgnoredFields: tc.IgnoredFields},
605+
Updater: updaterBuilder.BuildUpdater(),
594606
Parser: parser,
595607
}
596-
if tc.RequiresUnions {
597-
state.Updater.EnableUnionFeature()
598-
}
599608
for i, ops := range tc.Ops {
600609
err := ops.run(&state)
601610
if err != nil {

merge/real_test.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ func BenchmarkOperations(b *testing.B) {
108108
b.Run(bench.name, func(b *testing.B) {
109109
obj := typed.YAMLObject(read(testdata(bench.filename)))
110110
tests := []struct {
111-
name string
112-
ops []Operation
111+
name string
112+
returnInputonNoop bool
113+
ops []Operation
113114
}{
114115
{
115116
name: "Create",
@@ -146,6 +147,22 @@ func BenchmarkOperations(b *testing.B) {
146147
},
147148
},
148149
},
150+
{
151+
name: "ApplyTwiceNoCompare",
152+
returnInputonNoop: true,
153+
ops: []Operation{
154+
Apply{
155+
Manager: "controller",
156+
APIVersion: "v1",
157+
Object: obj,
158+
},
159+
Apply{
160+
Manager: "other-controller",
161+
APIVersion: "v1",
162+
Object: obj,
163+
},
164+
},
165+
},
149166
{
150167
name: "Update",
151168
ops: []Operation{
@@ -180,7 +197,8 @@ func BenchmarkOperations(b *testing.B) {
180197
for _, test := range tests {
181198
b.Run(test.name, func(b *testing.B) {
182199
tc := TestCase{
183-
Ops: test.ops,
200+
Ops: test.ops,
201+
ReturnInputOnNoop: test.returnInputonNoop,
184202
}
185203
p := SameVersionParser{T: bench.parseType}
186204
tc.PreprocessOperations(p)

merge/update.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,50 @@ type Converter interface {
2828
IsMissingVersionError(error) bool
2929
}
3030

31+
// UpdateBuilder allows you to create a new Updater by exposing all of
32+
// the options and setting them once.
33+
type UpdaterBuilder struct {
34+
Converter Converter
35+
IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
36+
37+
EnableUnions bool
38+
39+
// Stop comparing the new object with old object after applying.
40+
// This was initially used to avoid spurious etcd update, but
41+
// since that's vastly inefficient, we've come-up with a better
42+
// way of doing that. Create this flag to stop it.
43+
// Comparing has become more expensive too now that we're not using
44+
// `Compare` but `value.Equals` so this gives an option to avoid it.
45+
ReturnInputOnNoop bool
46+
}
47+
48+
func (u *UpdaterBuilder) BuildUpdater() *Updater {
49+
return &Updater{
50+
Converter: u.Converter,
51+
IgnoredFields: u.IgnoredFields,
52+
enableUnions: u.EnableUnions,
53+
returnInputOnNoop: u.ReturnInputOnNoop,
54+
}
55+
}
56+
3157
// Updater is the object used to compute updated FieldSets and also
3258
// merge the object on Apply.
3359
type Updater struct {
34-
Converter Converter
60+
// Deprecated: This will eventually become private.
61+
Converter Converter
62+
63+
// Deprecated: This will eventually become private.
3564
IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
3665

3766
enableUnions bool
67+
68+
returnInputOnNoop bool
3869
}
3970

4071
// EnableUnionFeature turns on union handling. It is disabled by default until the
4172
// feature is complete.
73+
//
74+
// Deprecated: Use the builder instead.
4275
func (s *Updater) EnableUnionFeature() {
4376
s.enableUnions = true
4477
}
@@ -204,7 +237,7 @@ func (s *Updater) Apply(liveObject, configObject *typed.TypedValue, version fiel
204237
if err != nil {
205238
return nil, fieldpath.ManagedFields{}, err
206239
}
207-
if value.EqualsUsing(value.NewFreelistAllocator(), liveObject.AsValue(), newObject.AsValue()) {
240+
if !s.returnInputOnNoop && value.EqualsUsing(value.NewFreelistAllocator(), liveObject.AsValue(), newObject.AsValue()) {
208241
newObject = nil
209242
}
210243
return newObject, managers, nil

0 commit comments

Comments
 (0)