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 10 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
}
73 changes: 73 additions & 0 deletions pdata/pprofile/locations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

import (
"errors"
"fmt"
"math"

"go.opentelemetry.io/collector/pdata/pcommon"
)

type locatable interface {
LocationIndices() pcommon.Int32Slice
}

// FromLocationIndices builds a slice containing all the locations of a record.
// The record can be any struct that implements a `LocationIndices` method.
// Updates made to the return map will not be applied back to the record.
func FromLocationIndices(table LocationSlice, record locatable) LocationSlice {
m := NewLocationSlice()
m.EnsureCapacity(record.LocationIndices().Len())

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

return m
}

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

// PutLocation updates a LocationTable and a record's LocationIndices to
// add or update a location.
// The record can be any struct that implements a `LocationIndices` method.
func PutLocation(table LocationSlice, record locatable, loc Location) error {
for i := range record.LocationIndices().All() {
idx := int(record.LocationIndices().At(i))
if idx < 0 || idx >= table.Len() {
return fmt.Errorf("index value %d out of range in LocationIndices[%d]", idx, i)
}
attr := table.At(idx)
if attr.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 53 in pdata/pprofile/locations.go

View check run for this annotation

Codecov / codecov/patch

pdata/pprofile/locations.go#L52-L53

Added lines #L52 - L53 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 59 in pdata/pprofile/locations.go

View check run for this annotation

Codecov / codecov/patch

pdata/pprofile/locations.go#L58-L59

Added lines #L58 - L59 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 68 in pdata/pprofile/locations.go

View check run for this annotation

Codecov / codecov/patch

pdata/pprofile/locations.go#L67-L68

Added lines #L67 - L68 were not covered by tests

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