Merge pull request #137581 from aaron-prindle/fieldsv1-string-interning-impl

feat: add build-tag type switching for FieldsV1 to string that uses unique.Handle[string] for interning and associated tests
This commit is contained in:
Kubernetes Prow Robot
2026-03-12 00:45:59 +05:30
committed by GitHub
4 changed files with 595 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1_test
import (
"encoding/json"
"fmt"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var benchmarkPayloads = []string{
// Small managed fields payload
`{"f:metadata":{"f:labels":{"f:app":{}},"f:annotations":{"f:revision":{}}},"f:spec":{"f:replicas":{},"f:template":{"f:metadata":{"f:labels":{"f:app":{}}},"f:spec":{"f:containers":{"k:{\"name\":\"nginx\"}":{".":{},"f:image":{},"f:name":{}}}}}}}`,
// Larger, deeply nested valid JSON payload (representing complex managedFields)
`{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}},"f:labels":{".":{},"f:app.kubernetes.io/name":{}}},"f:spec":{"f:replicas":{},"f:selector":{},"f:template":{"f:metadata":{"f:labels":{".":{},"f:app.kubernetes.io/name":{}}},"f:spec":{"f:containers":{"k:{\"name\":\"app\"}":{".":{},"f:image":{},"f:name":{},"f:ports":{".":{},"k:{\"containerPort\":8080,\"protocol\":\"TCP\"}":{".":{},"f:containerPort":{},"f:protocol":{}}},"f:resources":{".":{},"f:limits":{".":{},"f:cpu":{},"f:memory":{}},"f:requests":{".":{},"f:cpu":{},"f:memory":{}}}}}}}}}`,
}
// BenchmarkDecodeDuplicate measures the allocation and speed of unmarshaling
// exactly identical payloads repeatedly, which is the most common case for
// heavily replicated resources (DaemonSets, ReplicaSets) in the API server.
func BenchmarkDecodeDuplicate(b *testing.B) {
for _, payload := range benchmarkPayloads {
b.Run(fmt.Sprintf("Size%d", len(payload)), func(b *testing.B) {
rawJSON := []byte(payload)
b.ResetTimer()
b.ReportAllocs()
var retained []metav1.FieldsV1
for j := 0; j < b.N; j++ {
var f metav1.FieldsV1
if err := json.Unmarshal(rawJSON, &f); err != nil {
b.Fatal(err)
}
retained = append(retained, f)
}
_ = retained
})
}
}
// BenchmarkDecodeUnique measures the allocation and speed of unmarshaling
// completely unique payloads to measure the worst-case interning overhead.
func BenchmarkDecodeUnique(b *testing.B) {
for _, payload := range benchmarkPayloads {
b.Run(fmt.Sprintf("Size%d", len(payload)), func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
var retained []metav1.FieldsV1
for j := 0; j < b.N; j++ {
// Inject the iteration counter to guarantee the string is unique
novelPayload := fmt.Appendf(nil, `{"f:iter":%d,%s`, j, payload[1:])
var f metav1.FieldsV1
if err := json.Unmarshal(novelPayload, &f); err != nil {
b.Fatal(err)
}
retained = append(retained, f)
}
_ = retained
})
}
}
// BenchmarkParallelDecode tests parallel deserialization of duplicate strings
// to verify lock contention behavior in highly concurrent environments.
func BenchmarkParallelDecode(b *testing.B) {
for _, payload := range benchmarkPayloads {
b.Run(fmt.Sprintf("Size%d", len(payload)), func(b *testing.B) {
rawJSON := []byte(payload)
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var f metav1.FieldsV1
if err := json.Unmarshal(rawJSON, &f); err != nil {
b.Fatal(err)
}
}
})
})
}
}
// BenchmarkEqual_Same measures the fast-path equality check for identical structs.
func BenchmarkEqual_Same(b *testing.B) {
f1 := metav1.NewFieldsV1(benchmarkPayloads[1])
f2 := metav1.NewFieldsV1(benchmarkPayloads[1])
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = f1.Equal(*f2)
}
}
// BenchmarkEqual_Different measures the fallback-path equality check for differing structs.
func BenchmarkEqual_Different(b *testing.B) {
f1 := metav1.NewFieldsV1(benchmarkPayloads[1])
f2 := metav1.NewFieldsV1(benchmarkPayloads[0])
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = f1.Equal(*f2)
}
}

View File

@@ -1,3 +1,5 @@
//go:build !fieldsv1string
/*
Copyright The Kubernetes Authors.

View File

@@ -0,0 +1,113 @@
//go:build fieldsv1string
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"strings"
"unique"
)
// FieldsV1 stores a set of fields in a data structure like a Trie, in JSON format.
//
// Each key is either a '.' representing the field itself, and will always map to an empty set,
// or a string representing a sub-field or item. The string will follow one of these four formats:
// 'f:<name>', where <name> is the name of a field in a struct, or key in a map
// 'v:<value>', where <value> is the exact json formatted value of a list item
// 'i:<index>', where <index> is position of a item in a list
// 'k:<keys>', where <keys> is a map of a list item's key fields to their unique values
// If a key maps to an empty Fields value, the field that key represents is part of the set.
//
// The exact format is defined in sigs.k8s.io/structured-merge-diff
// +k8s:deepcopy-gen=false
// +protobuf.options.marshal=false
// +protobuf.options.(gogoproto.goproto_stringer)=false
type FieldsV1 struct {
// The zero value of a unique.Handle[string] has an uninitialized underlying pointer.
// Calling .Value() on it panics. We must explicitly check for this uninitialized
// state (f.handle == unique.Handle[string]{}) across accessors to safely support
// uninitialized metav1.FieldsV1{} objects.
// See ongoing golang discussion related to this here: https://github.com/golang/go/issues/73344
handle unique.Handle[string]
}
func (f FieldsV1) String() string {
if f.handle == (unique.Handle[string]{}) {
return ""
}
return f.handle.Value()
}
func (f FieldsV1) Equal(f2 FieldsV1) bool {
if f.handle == f2.handle {
return true
}
// An uninitialized FieldsV1 compared to an explicitly empty
// FieldsV1 (unique.Make("") will fail the handle check above.
// Evaluate string contents directly as well to maintain parity with legacy
// bytes.Equal(nil, []byte{}) == true behavior.
return f.GetRawString() == f2.GetRawString()
}
func (f *FieldsV1) GetRawReader() FieldsV1Reader {
if f == nil || f.handle == (unique.Handle[string]{}) {
return strings.NewReader("")
}
return strings.NewReader(f.handle.Value())
}
// GetRawBytes returns the raw bytes.
// These may or may not be a copy of the underlying bytes.
// If mutating the underlying bytes is desired, the returned bytes may be mutated and then passed to SetRawBytes().
// If mutating the underlying bytes is not desired, make a copy of the returned bytes.
func (f *FieldsV1) GetRawBytes() []byte {
if f == nil || f.handle == (unique.Handle[string]{}) {
return nil
}
return []byte(f.handle.Value())
}
// GetRawString returns the raw data as a string.
func (f *FieldsV1) GetRawString() string {
if f == nil || f.handle == (unique.Handle[string]{}) {
return ""
}
return f.handle.Value()
}
// SetRawBytes sets the raw bytes. It does not retain the passed-in byte slice.
func (f *FieldsV1) SetRawBytes(b []byte) {
if f != nil {
f.handle = unique.Make(string(b))
}
}
// SetRawString sets the raw data from a string.
func (f *FieldsV1) SetRawString(s string) {
if f != nil {
f.handle = unique.Make(s)
}
}
func NewFieldsV1(raw string) *FieldsV1 {
return &FieldsV1{handle: unique.Make(raw)}
}
func (f *FieldsV1) DeepCopyInto(out *FieldsV1) {
*out = *f
}

View File

@@ -0,0 +1,362 @@
//go:build fieldsv1string
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1_test
import (
"bytes"
"encoding/json"
"io"
"testing"
"unsafe"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// requireInterned fails the test if the two strings do not point to the exact same memory address.
func requireInterned(t *testing.T, a, b string) {
t.Helper()
ptrA := unsafe.StringData(a)
ptrB := unsafe.StringData(b)
if ptrA != ptrB {
t.Fatalf("Expected strings to be interned (same memory address) but pointers differ: %p != %p", ptrA, ptrB)
}
}
func TestFieldsV1_String(t *testing.T) {
for _, tc := range []struct {
name string
f metav1.FieldsV1
expected string
}{
{
name: "zero value handle",
f: metav1.FieldsV1{},
expected: "",
},
{
name: "initialized empty handle",
f: *metav1.NewFieldsV1(""),
expected: "",
},
{
name: "valid payload",
f: *metav1.NewFieldsV1(`{"f:app":{}}`),
expected: `{"f:app":{}}`,
},
} {
t.Run(tc.name, func(t *testing.T) {
if got := tc.f.String(); got != tc.expected {
t.Errorf("expected %q, got %q", tc.expected, got)
}
})
}
}
func TestFieldsV1_Equal(t *testing.T) {
valid := *metav1.NewFieldsV1(`{"f:app":{}}`)
validClone := *metav1.NewFieldsV1(`{"f:app":{}}`)
different := *metav1.NewFieldsV1(`{"f:other":{}}`)
for _, tc := range []struct {
name string
a metav1.FieldsV1
b metav1.FieldsV1
expected bool
}{
{"both zero value", metav1.FieldsV1{}, metav1.FieldsV1{}, true},
{"zero value and initialized empty handle", metav1.FieldsV1{}, *metav1.NewFieldsV1(""), true},
{"identical valid payloads", valid, validClone, true},
{"different payloads", valid, different, false},
{"zero value and valid payload", metav1.FieldsV1{}, valid, false},
} {
t.Run(tc.name, func(t *testing.T) {
if got := tc.a.Equal(tc.b); got != tc.expected {
t.Errorf("expected Equal() to be %v, got %v", tc.expected, got)
}
// Commutative property
if got := tc.b.Equal(tc.a); got != tc.expected {
t.Errorf("expected Equal() commutative to be %v, got %v", tc.expected, got)
}
})
}
}
func TestFieldsV1_GetRawReader(t *testing.T) {
for _, tc := range []struct {
name string
f *metav1.FieldsV1
expected []byte
}{
{"nil receiver", nil, []byte("")},
{"zero value handle", &metav1.FieldsV1{}, []byte("")},
{"initialized empty handle", metav1.NewFieldsV1(""), []byte("")},
{"valid payload", metav1.NewFieldsV1(`{"f:app":{}}`), []byte(`{"f:app":{}}`)},
} {
t.Run(tc.name, func(t *testing.T) {
reader := tc.f.GetRawReader()
got, err := io.ReadAll(reader)
if err != nil {
t.Fatalf("unexpected error reading from RawReader: %v", err)
}
if !bytes.Equal(got, tc.expected) {
t.Errorf("expected %q, got %q", tc.expected, got)
}
})
}
}
func TestFieldsV1_GetRawBytes(t *testing.T) {
for _, tc := range []struct {
name string
f *metav1.FieldsV1
expected []byte
}{
{"nil receiver", nil, nil},
{"zero value handle", &metav1.FieldsV1{}, nil},
{"initialized empty handle", metav1.NewFieldsV1(""), []byte{}},
{"valid payload", metav1.NewFieldsV1(`{"f:app":{}}`), []byte(`{"f:app":{}}`)},
} {
t.Run(tc.name, func(t *testing.T) {
got := tc.f.GetRawBytes()
if !bytes.Equal(got, tc.expected) {
t.Errorf("expected %v, got %v", tc.expected, got)
}
// Explicitly check for nil
if tc.expected == nil && got != nil {
t.Errorf("expected strict nil, got %v", got)
}
})
}
t.Run("mutation safety", func(t *testing.T) {
f := metav1.NewFieldsV1(`{"f:app":{}}`)
b := f.GetRawBytes()
// Mutate the returned bytes
b[2] = 'X'
// The original interned string must remain unchanged
if got := f.GetRawString(); got != `{"f:app":{}}` {
t.Errorf("GetRawBytes returned an unisolated slice! Mutating it corrupted the handle. Got: %s", got)
}
})
}
func TestFieldsV1_GetRawString(t *testing.T) {
for _, tc := range []struct {
name string
f *metav1.FieldsV1
expected string
}{
{"nil receiver", nil, ""},
{"zero value handle", &metav1.FieldsV1{}, ""},
{"initialized empty handle", metav1.NewFieldsV1(""), ""},
{"valid payload", metav1.NewFieldsV1(`{"f:app":{}}`), `{"f:app":{}}`},
} {
t.Run(tc.name, func(t *testing.T) {
if got := tc.f.GetRawString(); got != tc.expected {
t.Errorf("expected %q, got %q", tc.expected, got)
}
})
}
}
func TestFieldsV1_SetRawBytes(t *testing.T) {
t.Run("nil receiver", func(t *testing.T) {
var f *metav1.FieldsV1 // nil
f.SetRawBytes([]byte("test")) // Should not panic
})
t.Run("empty slice input", func(t *testing.T) {
f := &metav1.FieldsV1{}
f.SetRawBytes([]byte{})
if f.GetRawString() != "" {
t.Errorf("Expected empty string, got %q", f.GetRawString())
}
})
t.Run("nil slice input", func(t *testing.T) {
f := &metav1.FieldsV1{}
f.SetRawBytes(nil)
if f.GetRawString() != "" {
t.Errorf("Expected empty string, got %q", f.GetRawString())
}
})
t.Run("interning behavior", func(t *testing.T) {
payload := []byte(`{"f:app":{}}`)
// Two distinct slices with identical content
b1 := append([]byte(nil), payload...)
b2 := append([]byte(nil), payload...)
f1 := &metav1.FieldsV1{}
f1.SetRawBytes(b1)
f2 := &metav1.FieldsV1{}
f2.SetRawBytes(b2)
if f1.GetRawString() != string(payload) {
t.Errorf("Expected GetRawString to match payload, got %q", f1.GetRawString())
}
requireInterned(t, f1.GetRawString(), f2.GetRawString())
})
}
func TestFieldsV1_SetRawString(t *testing.T) {
t.Run("nil receiver", func(t *testing.T) {
var f *metav1.FieldsV1 // nil
f.SetRawString("test") // Should not panic
})
t.Run("interning behavior", func(t *testing.T) {
payload := `{"f:app":{}}`
// Force string copy to avoid compiler static string optimization if possible
s1 := string(append([]byte(nil), payload...))
s2 := string(append([]byte(nil), payload...))
f1 := &metav1.FieldsV1{}
f1.SetRawString(s1)
f2 := &metav1.FieldsV1{}
f2.SetRawString(s2)
requireInterned(t, f1.GetRawString(), f2.GetRawString())
})
}
func TestFieldsV1_NewFieldsV1(t *testing.T) {
t.Run("interning behavior", func(t *testing.T) {
payload := `{"f:app":{}}`
s1 := string(append([]byte(nil), payload...))
s2 := string(append([]byte(nil), payload...))
f1 := metav1.NewFieldsV1(s1)
f2 := metav1.NewFieldsV1(s2)
requireInterned(t, f1.GetRawString(), f2.GetRawString())
})
}
func TestFieldsV1_DeepCopyInto(t *testing.T) {
t.Run("preserves interning", func(t *testing.T) {
orig := metav1.NewFieldsV1(`{"f:app":{}}`)
var clone metav1.FieldsV1
orig.DeepCopyInto(&clone)
if orig.GetRawString() != clone.GetRawString() {
t.Fatalf("Expected strings to match after DeepCopyInto, got %q and %q", orig.GetRawString(), clone.GetRawString())
}
requireInterned(t, orig.GetRawString(), clone.GetRawString())
})
t.Run("zero value deep copy", func(t *testing.T) {
var orig metav1.FieldsV1
var clone metav1.FieldsV1
orig.DeepCopyInto(&clone)
if clone.GetRawString() != "" {
t.Errorf("Expected empty string from cloned zero-value, got %q", clone.GetRawString())
}
if !orig.Equal(clone) {
t.Errorf("Expected original zero-value and its clone to be equal")
}
})
t.Run("independence after deep copy", func(t *testing.T) {
orig := metav1.NewFieldsV1(`{"f:app":{}}`)
var clone metav1.FieldsV1
orig.DeepCopyInto(&clone)
// Modify the clone
clone.SetRawString(`{"f:new":{}}`)
// The original should be completely untouched
if got := orig.GetRawString(); got != `{"f:app":{}}` {
t.Errorf("DeepCopyInto failed to isolate clone! Modifying clone corrupted original. Got: %s", got)
}
})
}
func TestFieldsV1_UnmarshalInterning(t *testing.T) {
jsonPayload := []byte(`{"f:metadata":{"f:labels":{"f:app":{}}}}`)
orig := metav1.NewFieldsV1(string(jsonPayload))
protoPayload, err := orig.Marshal()
if err != nil {
t.Fatalf("Failed to marshal protobuf payload during setup: %v", err)
}
cborPayload, err := orig.MarshalCBOR()
if err != nil {
t.Fatalf("Failed to marshal CBOR payload during setup: %v", err)
}
tests := []struct {
name string
payload []byte
unmarshal func(t *testing.T, f *metav1.FieldsV1, payload []byte)
}{
{
name: "json unmarshal",
payload: jsonPayload,
unmarshal: func(t *testing.T, f *metav1.FieldsV1, payload []byte) {
if err := json.Unmarshal(payload, f); err != nil {
t.Fatalf("JSON Unmarshal failed: %v", err)
}
},
},
{
name: "protobuf unmarshal",
payload: protoPayload,
unmarshal: func(t *testing.T, f *metav1.FieldsV1, payload []byte) {
if err := f.Unmarshal(payload); err != nil {
t.Fatalf("Protobuf Unmarshal failed: %v", err)
}
},
},
{
name: "cbor unmarshal",
payload: cborPayload,
unmarshal: func(t *testing.T, f *metav1.FieldsV1, payload []byte) {
if err := f.UnmarshalCBOR(payload); err != nil {
t.Fatalf("CBOR Unmarshal failed: %v", err)
}
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Ensure independent slice memory
b1 := append([]byte(nil), tc.payload...)
b2 := append([]byte(nil), tc.payload...)
var f1 metav1.FieldsV1
var f2 metav1.FieldsV1
tc.unmarshal(t, &f1, b1)
tc.unmarshal(t, &f2, b2)
requireInterned(t, f1.GetRawString(), f2.GetRawString())
})
}
}