Skip to content

Commit f87c5ba

Browse files
dmathieumx-psi
andauthored
Introduce SetLink on profiles (#13223)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description This is part of #13106 It introduces a new `SetLink` method, which allows setting a sample's link based on a specific dictionary. Related: #13197 --------- Co-authored-by: Pablo Baeyens <[email protected]>
1 parent 27e88dc commit f87c5ba

File tree

6 files changed

+308
-0
lines changed

6 files changed

+308
-0
lines changed

.chloggen/link-equal.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: enhancement
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
5+
component: pdata/pprofile
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: Introduce `Equal` method on the `Link` type
9+
10+
# One or more tracking issues or pull requests related to the change
11+
issues: [13223]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext:
17+
18+
# Optional: The change log or logs in which this entry should be included.
19+
# e.g. '[user]' or '[user, api]'
20+
# Include 'user' if the change is relevant to end users.
21+
# Include 'api' if there is a change to a library API.
22+
# Default: '[user]'
23+
change_logs: [api]

.chloggen/set-link.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: pdata/pprofile
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add new helper method `SetLink` to set a new link on a sample.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [13223]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [api]

pdata/pprofile/link.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"
5+
6+
// Equal checks equality with another Link
7+
func (l Link) Equal(val Link) bool {
8+
return l.TraceID() == val.TraceID() &&
9+
l.SpanID() == val.SpanID()
10+
}

pdata/pprofile/link_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package pprofile
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
11+
"go.opentelemetry.io/collector/pdata/pcommon"
12+
)
13+
14+
func TestLinkEqual(t *testing.T) {
15+
for _, tt := range []struct {
16+
name string
17+
orig Link
18+
dest Link
19+
want bool
20+
}{
21+
{
22+
name: "empty links",
23+
orig: NewLink(),
24+
dest: NewLink(),
25+
want: true,
26+
},
27+
{
28+
name: "non-empty identical links",
29+
orig: buildLink(
30+
pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}),
31+
pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
32+
),
33+
dest: buildLink(
34+
pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}),
35+
pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
36+
),
37+
want: true,
38+
},
39+
{
40+
name: "with different trace IDs",
41+
orig: buildLink(
42+
pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}),
43+
pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
44+
),
45+
dest: buildLink(
46+
pcommon.TraceID([16]byte{8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8}),
47+
pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
48+
),
49+
want: false,
50+
},
51+
{
52+
name: "with different span IDs",
53+
orig: buildLink(
54+
pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}),
55+
pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}),
56+
),
57+
dest: buildLink(
58+
pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}),
59+
pcommon.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}),
60+
),
61+
want: false,
62+
},
63+
} {
64+
t.Run(tt.name, func(t *testing.T) {
65+
if tt.want {
66+
assert.True(t, tt.orig.Equal(tt.dest))
67+
} else {
68+
assert.False(t, tt.orig.Equal(tt.dest))
69+
}
70+
})
71+
}
72+
}
73+
74+
func buildLink(traceID pcommon.TraceID, spanID pcommon.SpanID) Link {
75+
l := NewLink()
76+
l.SetTraceID(traceID)
77+
l.SetSpanID(spanID)
78+
return l
79+
}

pdata/pprofile/links.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"
5+
6+
import (
7+
"errors"
8+
"fmt"
9+
"math"
10+
)
11+
12+
var errTooManyLinkTableEntries = errors.New("too many entries in LinkTable")
13+
14+
// SetLink updates a LinkTable and a Sample's LinkIndex to
15+
// add or update a link.
16+
func SetLink(table LinkSlice, record Sample, li Link) error {
17+
idx := int(record.LinkIndex())
18+
if idx > 0 {
19+
if idx >= table.Len() {
20+
return fmt.Errorf("index value %d out of range for LinkIndex", idx)
21+
}
22+
mapAt := table.At(idx)
23+
if mapAt.Equal(li) {
24+
// Link already exists, nothing to do.
25+
return nil
26+
}
27+
}
28+
29+
for j, l := range table.All() {
30+
if l.Equal(li) {
31+
if j > math.MaxInt32 {
32+
return errTooManyLinkTableEntries
33+
}
34+
// Add the index of the existing link to the indices.
35+
record.SetLinkIndex(int32(j)) //nolint:gosec // G115 overflow checked
36+
return nil
37+
}
38+
}
39+
40+
if table.Len() >= math.MaxInt32 {
41+
return errTooManyLinkTableEntries
42+
}
43+
44+
li.CopyTo(table.AppendEmpty())
45+
record.SetLinkIndex(int32(table.Len() - 1)) //nolint:gosec // G115 overflow checked
46+
return nil
47+
}

pdata/pprofile/links_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package pprofile
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
12+
"go.opentelemetry.io/collector/pdata/pcommon"
13+
)
14+
15+
func TestSetLink(t *testing.T) {
16+
table := NewLinkSlice()
17+
l := NewLink()
18+
l.SetTraceID(pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}))
19+
l2 := NewLink()
20+
l.SetTraceID(pcommon.TraceID([16]byte{2, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 2}))
21+
smpl := NewSample()
22+
23+
// Put a first link
24+
require.NoError(t, SetLink(table, smpl, l))
25+
assert.Equal(t, 1, table.Len())
26+
assert.Equal(t, int32(0), smpl.LinkIndex())
27+
28+
// Put the same link
29+
// This should be a no-op.
30+
require.NoError(t, SetLink(table, smpl, l))
31+
assert.Equal(t, 1, table.Len())
32+
assert.Equal(t, int32(0), smpl.LinkIndex())
33+
34+
// Set a new link
35+
// This sets the index and adds to the table.
36+
require.NoError(t, SetLink(table, smpl, l2))
37+
assert.Equal(t, 2, table.Len())
38+
assert.Equal(t, int32(table.Len()-1), smpl.LinkIndex()) //nolint:gosec // G115
39+
40+
// Set an existing link
41+
require.NoError(t, SetLink(table, smpl, l))
42+
assert.Equal(t, 2, table.Len())
43+
assert.Equal(t, int32(0), smpl.LinkIndex())
44+
// Set another existing link
45+
require.NoError(t, SetLink(table, smpl, l2))
46+
assert.Equal(t, 2, table.Len())
47+
assert.Equal(t, int32(table.Len()-1), smpl.LinkIndex()) //nolint:gosec // G115
48+
}
49+
50+
func TestSetLinkCurrentTooHigh(t *testing.T) {
51+
table := NewLinkSlice()
52+
smpl := NewSample()
53+
smpl.SetLinkIndex(42)
54+
55+
err := SetLink(table, smpl, NewLink())
56+
require.Error(t, err)
57+
assert.Equal(t, 0, table.Len())
58+
assert.Equal(t, int32(42), smpl.LinkIndex())
59+
}
60+
61+
func BenchmarkSetLink(b *testing.B) {
62+
for _, bb := range []struct {
63+
name string
64+
link Link
65+
66+
runBefore func(*testing.B, LinkSlice, Sample)
67+
}{
68+
{
69+
name: "with a new link",
70+
link: NewLink(),
71+
},
72+
{
73+
name: "with an existing link",
74+
link: func() Link {
75+
l := NewLink()
76+
l.SetTraceID(pcommon.NewTraceIDEmpty())
77+
return l
78+
}(),
79+
80+
runBefore: func(_ *testing.B, table LinkSlice, _ Sample) {
81+
l := table.AppendEmpty()
82+
l.SetTraceID(pcommon.NewTraceIDEmpty())
83+
},
84+
},
85+
{
86+
name: "with a duplicate link",
87+
link: NewLink(),
88+
89+
runBefore: func(_ *testing.B, table LinkSlice, obj Sample) {
90+
require.NoError(b, SetLink(table, obj, NewLink()))
91+
},
92+
},
93+
{
94+
name: "with a hundred links to loop through",
95+
link: func() Link {
96+
l := NewLink()
97+
l.SetTraceID(pcommon.NewTraceIDEmpty())
98+
return l
99+
}(),
100+
101+
runBefore: func(_ *testing.B, table LinkSlice, _ Sample) {
102+
for range 100 {
103+
table.AppendEmpty()
104+
}
105+
},
106+
},
107+
} {
108+
b.Run(bb.name, func(b *testing.B) {
109+
table := NewLinkSlice()
110+
obj := NewSample()
111+
112+
if bb.runBefore != nil {
113+
bb.runBefore(b, table, obj)
114+
}
115+
116+
b.ResetTimer()
117+
b.ReportAllocs()
118+
119+
for range b.N {
120+
_ = SetLink(table, obj, bb.link)
121+
}
122+
})
123+
}
124+
}

0 commit comments

Comments
 (0)