Skip to content

Introduce FromLocationIndices and PutLocation #13150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .chloggen/locations-read-write-table.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
component: pdata/pprofile

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add new helper methods `FromLocationIndices` and `PutLocation` to read and modify the content of locations.

# One or more tracking issues or pull requests related to the change
issues: [13150]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
3 changes: 0 additions & 3 deletions pdata/pprofile/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package pprofile

import (
"fmt"
"os"
"testing"

jsoniter "github.com/json-iterator/go"
Expand Down Expand Up @@ -133,7 +131,6 @@ func TestJSONUnmarshal(t *testing.T) {
func TestJSONMarshal(t *testing.T) {
encoder := &JSONMarshaler{}
jsonBuf, err := encoder.MarshalProfiles(profilesOTLP)
fmt.Fprintf(os.Stdout, "=================\n%#v\n----------------", string(jsonBuf))
require.NoError(t, err)
assert.JSONEq(t, profilesJSON, string(jsonBuf))
}
Expand Down
26 changes: 26 additions & 0 deletions pdata/pprofile/line.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"

// Equal checks equality with another LineSlice
func (l LineSlice) Equal(val LineSlice) bool {
if l.Len() != val.Len() {
return false
}

for i := range l.Len() {
if !l.At(i).Equal(val.At(i)) {
return false
}
}

return true
}

// Equal checks equality with another Line
func (l Line) Equal(val Line) bool {
return l.Column() == val.Column() &&
l.FunctionIndex() == val.FunctionIndex() &&
l.Line() == val.Line()
}
129 changes: 129 additions & 0 deletions pdata/pprofile/line_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package pprofile

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestLineSliceEqual(t *testing.T) {
for _, tt := range []struct {
name string
orig LineSlice
dest LineSlice
want bool
}{
{
name: "with empty slices",
orig: NewLineSlice(),
dest: NewLineSlice(),
want: true,
},
{
name: "with non-empty equal slices",
orig: func() LineSlice {
ls := NewLineSlice()
ls.AppendEmpty().SetLine(1)
return ls
}(),
dest: func() LineSlice {
ls := NewLineSlice()
ls.AppendEmpty().SetLine(1)
return ls
}(),
want: true,
},
{
name: "with different lengths",
orig: func() LineSlice {
ls := NewLineSlice()
ls.AppendEmpty()
return ls
}(),
dest: NewLineSlice(),
want: false,
},
{
name: "with non-equal slices",
orig: func() LineSlice {
ls := NewLineSlice()
ls.AppendEmpty().SetLine(2)
return ls
}(),
dest: func() LineSlice {
ls := NewLineSlice()
ls.AppendEmpty().SetLine(1)
return ls
}(),
want: false,
},
} {
t.Run(tt.name, func(t *testing.T) {
if tt.want {
assert.True(t, tt.orig.Equal(tt.dest))
} else {
assert.False(t, tt.orig.Equal(tt.dest))
}
})
}
}

func TestLineEqual(t *testing.T) {
for _, tt := range []struct {
name string
orig Line
dest Line
want bool
}{
{
name: "with empty lines",
orig: NewLine(),
dest: NewLine(),
want: true,
},
{
name: "with non-empty lines",
orig: buildLine(1, 2, 3),
dest: buildLine(1, 2, 3),
want: true,
},
{
name: "with non-equal column",
orig: buildLine(1, 2, 3),
dest: buildLine(2, 2, 3),
want: false,
},
{
name: "with non-equal function index",
orig: buildLine(1, 2, 3),
dest: buildLine(1, 3, 3),
want: false,
},
{
name: "with non-equal line",
orig: buildLine(1, 2, 3),
dest: buildLine(1, 2, 4),
want: false,
},
} {
t.Run(tt.name, func(t *testing.T) {
if tt.want {
assert.True(t, tt.orig.Equal(tt.dest))
} else {
assert.False(t, tt.orig.Equal(tt.dest))
}
})
}
}

func buildLine(col int64, funcIdx int32, line int64) Line {
l := NewLine()
l.SetColumn(col)
l.SetFunctionIndex(funcIdx)
l.SetLine(line)

return l
}
13 changes: 13 additions & 0 deletions pdata/pprofile/location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"

// Equal checks equality with another Location
func (l Location) Equal(val Location) bool {
return l.MappingIndex() == val.MappingIndex() &&
l.Address() == val.Address() &&
l.AttributeIndices().Equal(val.AttributeIndices()) &&
l.IsFolded() == val.IsFolded() &&
l.Line().Equal(val.Line())
}
80 changes: 80 additions & 0 deletions pdata/pprofile/location_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package pprofile

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestLocationEqual(t *testing.T) {
for _, tt := range []struct {
name string
orig Location
dest Location
want bool
}{
{
name: "empty locations",
orig: NewLocation(),
dest: NewLocation(),
want: true,
},
{
name: "non-empty locations",
orig: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
dest: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
want: true,
},
{
name: "with non-equal mapping index",
orig: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
dest: buildLocation(2, 2, []int32{3}, true, buildLine(1, 2, 3)),
want: false,
},
{
name: "with non-equal address",
orig: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
dest: buildLocation(1, 3, []int32{3}, true, buildLine(1, 2, 3)),
want: false,
},
{
name: "with non-equal attribute indices",
orig: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
dest: buildLocation(1, 2, []int32{5}, true, buildLine(1, 2, 3)),
want: false,
},
{
name: "with non-equal is folded",
orig: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
dest: buildLocation(1, 2, []int32{3}, false, buildLine(1, 2, 3)),
want: false,
},
{
name: "with non-equal lines",
orig: buildLocation(1, 2, []int32{3}, true, buildLine(4, 5, 6)),
dest: buildLocation(1, 2, []int32{3}, true, buildLine(1, 2, 3)),
want: false,
},
} {
t.Run(tt.name, func(t *testing.T) {
if tt.want {
assert.True(t, tt.orig.Equal(tt.dest))
} else {
assert.False(t, tt.orig.Equal(tt.dest))
}
})
}
}

func buildLocation(mapIdx int32, addr uint64, attrIdxs []int32, isFolded bool, line Line) Location {
l := NewLocation()
l.SetMappingIndex(mapIdx)
l.SetAddress(addr)
l.AttributeIndices().FromRaw(attrIdxs)
l.SetIsFolded(isFolded)
line.MoveTo(l.Line().AppendEmpty())
return l
}
65 changes: 65 additions & 0 deletions pdata/pprofile/locations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"

import (
"errors"
"fmt"
"math"
)

// FromLocationIndices builds a slice containing all the locations of a Profile.
// Updates made to the returned map will not be applied back to the Profile.
func FromLocationIndices(table LocationSlice, record Profile) LocationSlice {
m := NewLocationSlice()
m.EnsureCapacity(record.LocationIndices().Len())

for _, idx := range record.LocationIndices().All() {
l := table.At(int(idx))
l.CopyTo(m.AppendEmpty())
}

return m
}

var errTooManyLocationTableEntries = errors.New("too many entries in LocationTable")

// PutLocation updates a LocationTable and a Profile's LocationIndices to
// add or update a location.
func PutLocation(table LocationSlice, record Profile, loc Location) error {
for i, locIdx := range record.LocationIndices().All() {
idx := int(locIdx)
if idx < 0 || idx >= table.Len() {
return fmt.Errorf("index value %d out of range in LocationIndices[%d]", idx, i)
}
locAt := table.At(idx)
if locAt.Equal(loc) {
// Location already exists, nothing to do.
return nil
}
}

if record.LocationIndices().Len() >= math.MaxInt32 {
return errors.New("too many entries in LocationIndices")
}

Check warning on line 45 in pdata/pprofile/locations.go

View check run for this annotation

Codecov / codecov/patch

pdata/pprofile/locations.go#L44-L45

Added lines #L44 - L45 were not covered by tests

for j, a := range table.All() {
if a.Equal(loc) {
if j > math.MaxInt32 {
return errTooManyLocationTableEntries
}

Check warning on line 51 in pdata/pprofile/locations.go

View check run for this annotation

Codecov / codecov/patch

pdata/pprofile/locations.go#L50-L51

Added lines #L50 - L51 were not covered by tests
// Add the index of the existing location to the indices.
record.LocationIndices().Append(int32(j)) //nolint:gosec // overflow checked
return nil
}
}

if table.Len() >= math.MaxInt32 {
return errTooManyLocationTableEntries
}

Check warning on line 60 in pdata/pprofile/locations.go

View check run for this annotation

Codecov / codecov/patch

pdata/pprofile/locations.go#L59-L60

Added lines #L59 - L60 were not covered by tests

loc.CopyTo(table.AppendEmpty())
record.LocationIndices().Append(int32(table.Len() - 1)) //nolint:gosec // overflow checked
return nil
}
Loading
Loading