1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-08-10 22:31:50 +02:00

Use Distinct instead of Set for map keys (#5027)

This commit is contained in:
Tyler Yahn
2024-03-06 02:11:16 -08:00
committed by GitHub
parent da2949b7bb
commit fe9bab54b7
12 changed files with 196 additions and 143 deletions

View File

@@ -15,15 +15,24 @@ type (
// immutable set of attributes, with an internal cache for storing
// attribute encodings.
//
// This type supports the Equivalent method of comparison using values of
// type Distinct.
// This type will remain comparable for backwards compatibility. The
// equivalence of Sets across versions is not guaranteed to be stable.
// Prior versions may find two Sets to be equal or not when compared
// directly (i.e. ==), but subsequent versions may not. Users should use
// the Equals method to ensure stable equivalence checking.
//
// Users should also use the Distinct returned from Equivalent as a map key
// instead of a Set directly. In addition to that type providing guarantees
// on stable equivalence, it may also provide performance improvements.
Set struct {
equivalent Distinct
}
// Distinct wraps a variable-size array of KeyValue, constructed with keys
// in sorted order. This can be used as a map key or for equality checking
// between Sets.
// Distinct is a unique identifier of a Set.
//
// Distinct is designed to be ensures equivalence stability: comparisons
// will return the save value across versions. For this reason, Distinct
// should always be used as a map key instead of a Set.
Distinct struct {
iface interface{}
}

View File

@@ -95,7 +95,7 @@ func TestValue(t *testing.T) {
}
}
func TestSetComparability(t *testing.T) {
func TestEquivalence(t *testing.T) {
pairs := [][2]attribute.KeyValue{
{
attribute.Bool("Bool", true),
@@ -139,12 +139,39 @@ func TestSetComparability(t *testing.T) {
},
}
for _, p := range pairs {
s0, s1 := attribute.NewSet(p[0]), attribute.NewSet(p[1])
m := map[attribute.Set]struct{}{s0: {}}
_, ok := m[s1]
assert.Truef(t, ok, "%s not comparable", p[0].Value.Type())
}
t.Run("Distinct", func(t *testing.T) {
for _, p := range pairs {
s0, s1 := attribute.NewSet(p[0]), attribute.NewSet(p[1])
m := map[attribute.Distinct]struct{}{s0.Equivalent(): {}}
_, ok := m[s1.Equivalent()]
assert.Truef(t, ok, "Distinct comparison of %s type: not equivalent", p[0].Value.Type())
assert.Truef(
t,
ok,
"Distinct comparison of %s type: not equivalent: %s != %s",
p[0].Value.Type(),
s0.Encoded(attribute.DefaultEncoder()),
s1.Encoded(attribute.DefaultEncoder()),
)
}
})
t.Run("Set", func(t *testing.T) {
// Maintain backwards compatibility.
for _, p := range pairs {
s0, s1 := attribute.NewSet(p[0]), attribute.NewSet(p[1])
m := map[attribute.Set]struct{}{s0: {}}
_, ok := m[s1]
assert.Truef(
t,
ok,
"Set comparison of %s type: not equivalent: %s != %s",
p[0].Value.Type(),
s0.Encoded(attribute.DefaultEncoder()),
s1.Encoded(attribute.DefaultEncoder()),
)
}
})
}
func TestAsSlice(t *testing.T) {