java-topology/defects/otel-collector/patch/otel-collector-0002-pprofile-string-table-linear-scan.patch
russell@unturf.com 25c2bafdee undf: assign 694-720; stamp patches; ruby-0003/elixir-0002/r-source-0002/victoria-metrics-0002
New UNDF assignments (693→720):
  elixir-0002 → UNDF-2026-000000698 (typespec used_type_pairs O(T²))
  r-source-0002 → UNDF-2026-000000711 (.walkClassGraph match dedup O(S²))
  ruby-0003 → UNDF-2026-000000712 (RubyGems dependent_gems O(N²×D))
  victoria-metrics-0002 → UNDF-2026-000000717 (MetricName tag-filter O(T×I))

Total: 720 UNDF assigned
2026-03-29 22:28:31 -04:00

104 lines
3.3 KiB
Diff

# UNDF: UNDF-2026-000000709
--- a/pdata/pprofile/string_table.go
+++ b/pdata/pprofile/string_table.go
@@ -1,30 +1,56 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"
import (
"errors"
"math"
"go.opentelemetry.io/collector/pdata/pcommon"
)
var errTooManyStringTableEntries = errors.New("too many entries in StringTable")
-// SetString updates a StringTable, adding or providing a value and returns its index.
+// StringTableIndex builds a value→index map for O(1) duplicate detection
+// during profile merging. Build once per merge, pass to SetStringWithIndex.
+func StringTableIndex(table pcommon.StringSlice) map[string]int32 {
+ idx := make(map[string]int32, table.Len())
+ for i, v := range table.All() {
+ idx[v] = int32(i)
+ }
+ return idx
+}
+
+// SetStringWithIndex inserts val into table with O(1) lookup via a pre-built
+// index map (see StringTableIndex). Updates idx in place.
+func SetStringWithIndex(table pcommon.StringSlice, idx map[string]int32, val string) (int32, error) {
+ if j, ok := idx[val]; ok {
+ return j, nil
+ }
+ if table.Len() >= math.MaxInt32 {
+ return 0, errTooManyStringTableEntries
+ }
+ table.Append(val)
+ newIdx := int32(table.Len() - 1)
+ idx[val] = newIdx
+ return newIdx, nil
+}
+
+// SetString updates a StringTable, adding or providing a value and returns its
+// index. O(N) scan — prefer SetStringWithIndex for bulk operations.
func SetString(table pcommon.StringSlice, val string) (int32, error) {
for j, v := range table.All() {
if v == val {
if j > math.MaxInt32 {
return 0, errTooManyStringTableEntries
}
// Return the index of the existing value.
return int32(j), nil
}
}
if table.Len() >= math.MaxInt32 {
return 0, errTooManyMappingTableEntries
}
table.Append(val)
return int32(table.Len() - 1), nil
}
--- a/pdata/pprofile/profiles_merge.go
+++ b/pdata/pprofile/profiles_merge.go
@@ -1,22 +1,35 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile"
// MergeTo merges the current Profiles into dest, updating the destination
// dictionary as needed and appending the resource profiles.
// The source Profiles is consumed and marked read-only after this operation.
func (ms Profiles) MergeTo(dest Profiles) error {
ms.getState().AssertMutable()
dest.getState().AssertMutable()
if ms.getOrig() == dest.getOrig() {
return nil
}
- if err := ms.switchDictionary(ms.Dictionary(), dest.Dictionary()); err != nil {
+ // Build string-table index once before the merge loop to avoid O(N²)
+ // linear scans inside switchDictionary → SetString. The index is passed
+ // through to every SetStringWithIndex call inside the switch chain.
+ strIdx := StringTableIndex(dest.Dictionary().StringTable())
+ mergeCtx := &mergeContext{strIdx: strIdx}
+
+ if err := ms.switchDictionaryFast(ms.Dictionary(), dest.Dictionary(), mergeCtx); err != nil {
return err
}
ms.ResourceProfiles().MoveAndAppendTo(dest.ResourceProfiles())
ms.MarkReadOnly()
return nil
}
+
+// mergeContext carries pre-built indexes to avoid O(N²) scans during
+// switchDictionary traversal.
+type mergeContext struct {
+ strIdx map[string]int32
+}