From 7ee0b28302cfa720ef2e89b3bf34d7dff4fd5600 Mon Sep 17 00:00:00 2001 From: Dmitrii Anoshin Date: Fri, 6 Oct 2023 08:56:20 -0700 Subject: [PATCH] [pdata] Introduce runtime safeguards to catch incorrect pdata mutations (#8494) This change introduces an option to enable runtime assertions to catch unintentional pdata mutations in components that are claimed as non-mutating pdata. Without these assertions, runtime errors may still occur, but thrown by unrelated components, making it very difficult to troubleshoot. For now, this doesn't change the default behavior. It just introduces a new method on `[Metrics/Traces|Logs].Shared()` that returns pdata marked as shared. The method will be applied to fan-out consumers in the next PR. Later, if we want to remove the need of `MutatesData` capability, we can introduce another method `[Metrics/Traces|Logs].Exclusive()` which returns a copy of the pdata if it's shared. This change unblocks the 1.0 release by implementing the original solution proposed by @bogdandrutu in https://github.com/open-telemetry/opentelemetry-collector/issues/6794. Going forward, we may introduce a copy-on-write solution that doesn't require the runtime assertions. That will likely be part of the 2.0 release. --- .chloggen/pdata-mutation-assertions.yaml | 19 +++++ .../cmd/pdatagen/internal/base_fields.go | 72 ++++++++++++++----- .../cmd/pdatagen/internal/base_slices.go | 41 ++++++++--- .../cmd/pdatagen/internal/base_structs.go | 40 ++++++++--- .../internal/primitive_slice_structs.go | 44 +++++++++++- pdata/internal/generated_wrapper_byteslice.go | 11 ++- .../generated_wrapper_float64slice.go | 11 ++- .../generated_wrapper_instrumentationscope.go | 16 +++-- pdata/internal/generated_wrapper_resource.go | 16 +++-- .../internal/generated_wrapper_uint64slice.go | 11 ++- pdata/internal/state.go | 22 ++++++ pdata/internal/wrapper_logs.go | 21 ++++-- pdata/internal/wrapper_map.go | 14 ++-- pdata/internal/wrapper_metrics.go | 21 ++++-- pdata/internal/wrapper_slice.go | 17 +++-- pdata/internal/wrapper_traces.go | 21 ++++-- pdata/internal/wrapper_tracestate.go | 14 ++-- pdata/internal/wrapper_value.go | 14 ++-- pdata/pcommon/generated_byteslice.go | 14 +++- pdata/pcommon/generated_byteslice_test.go | 23 ++++++ pdata/pcommon/generated_float64slice.go | 14 +++- pdata/pcommon/generated_float64slice_test.go | 23 ++++++ .../pcommon/generated_instrumentationscope.go | 19 +++-- .../generated_instrumentationscope_test.go | 16 +++++ pdata/pcommon/generated_resource.go | 17 +++-- pdata/pcommon/generated_resource_test.go | 8 +++ pdata/pcommon/generated_uint64slice.go | 14 +++- pdata/pcommon/generated_uint64slice_test.go | 23 ++++++ pdata/pcommon/map.go | 49 +++++++++---- pdata/pcommon/map_test.go | 44 +++++++++++- pdata/pcommon/slice.go | 24 +++++-- pdata/pcommon/slice_test.go | 28 +++++++- pdata/pcommon/trace_state.go | 11 ++- pdata/pcommon/value.go | 68 ++++++++++++------ pdata/pcommon/value_test.go | 52 +++++++++++--- pdata/plog/generated_logrecord.go | 25 +++++-- pdata/plog/generated_logrecord_test.go | 13 +++- pdata/plog/generated_logrecordslice.go | 24 +++++-- pdata/plog/generated_logrecordslice_test.go | 19 ++++- pdata/plog/generated_resourcelogs.go | 18 +++-- pdata/plog/generated_resourcelogs_test.go | 14 +++- pdata/plog/generated_resourcelogsslice.go | 24 +++++-- .../plog/generated_resourcelogsslice_test.go | 19 ++++- pdata/plog/generated_scopelogs.go | 18 +++-- pdata/plog/generated_scopelogs_test.go | 14 +++- pdata/plog/generated_scopelogsslice.go | 24 +++++-- pdata/plog/generated_scopelogsslice_test.go | 19 ++++- pdata/plog/logs.go | 10 ++- pdata/plog/logs_test.go | 57 +++++++++++++++ .../generated_exportpartialsuccess.go | 16 +++-- .../generated_exportpartialsuccess_test.go | 18 +++++ pdata/plog/plogotlp/grpc.go | 10 ++- pdata/plog/plogotlp/request.go | 16 +++-- pdata/plog/plogotlp/response.go | 12 +++- pdata/pmetric/generated_exemplar.go | 20 ++++-- pdata/pmetric/generated_exemplar_test.go | 11 ++- pdata/pmetric/generated_exemplarslice.go | 21 ++++-- pdata/pmetric/generated_exemplarslice_test.go | 19 ++++- .../pmetric/generated_exponentialhistogram.go | 17 +++-- .../generated_exponentialhistogram_test.go | 8 ++- ...generated_exponentialhistogramdatapoint.go | 33 ++++++--- ...ated_exponentialhistogramdatapoint_test.go | 31 ++++++-- ...ed_exponentialhistogramdatapointbuckets.go | 16 +++-- ...ponentialhistogramdatapointbuckets_test.go | 18 +++++ ...ated_exponentialhistogramdatapointslice.go | 24 +++++-- ...exponentialhistogramdatapointslice_test.go | 19 ++++- pdata/pmetric/generated_gauge.go | 16 +++-- pdata/pmetric/generated_gauge_test.go | 10 ++- pdata/pmetric/generated_histogram.go | 17 +++-- pdata/pmetric/generated_histogram_test.go | 8 ++- pdata/pmetric/generated_histogramdatapoint.go | 31 +++++--- .../generated_histogramdatapoint_test.go | 11 ++- .../generated_histogramdatapointslice.go | 24 +++++-- .../generated_histogramdatapointslice_test.go | 19 ++++- pdata/pmetric/generated_metric.go | 42 +++++++---- pdata/pmetric/generated_metric_test.go | 34 ++++++++- pdata/pmetric/generated_metricslice.go | 24 +++++-- pdata/pmetric/generated_metricslice_test.go | 19 ++++- pdata/pmetric/generated_numberdatapoint.go | 22 ++++-- .../pmetric/generated_numberdatapoint_test.go | 15 +++- .../pmetric/generated_numberdatapointslice.go | 24 +++++-- .../generated_numberdatapointslice_test.go | 19 ++++- pdata/pmetric/generated_resourcemetrics.go | 18 +++-- .../pmetric/generated_resourcemetrics_test.go | 14 +++- .../pmetric/generated_resourcemetricsslice.go | 24 +++++-- .../generated_resourcemetricsslice_test.go | 19 ++++- pdata/pmetric/generated_scopemetrics.go | 18 +++-- pdata/pmetric/generated_scopemetrics_test.go | 14 +++- pdata/pmetric/generated_scopemetricsslice.go | 24 +++++-- .../generated_scopemetricsslice_test.go | 19 ++++- pdata/pmetric/generated_sum.go | 18 +++-- pdata/pmetric/generated_sum_test.go | 10 ++- pdata/pmetric/generated_summary.go | 16 +++-- pdata/pmetric/generated_summary_test.go | 10 ++- pdata/pmetric/generated_summarydatapoint.go | 22 ++++-- .../generated_summarydatapoint_test.go | 14 +++- .../generated_summarydatapointslice.go | 24 +++++-- .../generated_summarydatapointslice_test.go | 19 ++++- ...nerated_summarydatapointvalueatquantile.go | 16 +++-- ...ed_summarydatapointvalueatquantile_test.go | 22 ++++++ ...ed_summarydatapointvalueatquantileslice.go | 24 +++++-- ...mmarydatapointvalueatquantileslice_test.go | 19 ++++- pdata/pmetric/metrics.go | 10 ++- pdata/pmetric/metrics_test.go | 63 ++++++++++++++++ .../generated_exportpartialsuccess.go | 16 +++-- .../generated_exportpartialsuccess_test.go | 22 ++++++ pdata/pmetric/pmetricotlp/grpc.go | 10 ++- pdata/pmetric/pmetricotlp/request.go | 16 +++-- pdata/pmetric/pmetricotlp/response.go | 12 +++- pdata/ptrace/generated_resourcespans.go | 18 +++-- pdata/ptrace/generated_resourcespans_test.go | 14 +++- pdata/ptrace/generated_resourcespansslice.go | 24 +++++-- .../generated_resourcespansslice_test.go | 19 ++++- pdata/ptrace/generated_scopespans.go | 18 +++-- pdata/ptrace/generated_scopespans_test.go | 14 +++- pdata/ptrace/generated_scopespansslice.go | 24 +++++-- .../ptrace/generated_scopespansslice_test.go | 19 ++++- pdata/ptrace/generated_span.go | 33 ++++++--- pdata/ptrace/generated_span_test.go | 23 ++++-- pdata/ptrace/generated_spanevent.go | 18 +++-- pdata/ptrace/generated_spanevent_test.go | 12 +++- pdata/ptrace/generated_spaneventslice.go | 24 +++++-- pdata/ptrace/generated_spaneventslice_test.go | 19 ++++- pdata/ptrace/generated_spanlink.go | 20 ++++-- pdata/ptrace/generated_spanlink_test.go | 12 +++- pdata/ptrace/generated_spanlinkslice.go | 24 +++++-- pdata/ptrace/generated_spanlinkslice_test.go | 19 ++++- pdata/ptrace/generated_spanslice.go | 24 +++++-- pdata/ptrace/generated_spanslice_test.go | 19 ++++- pdata/ptrace/generated_status.go | 16 +++-- pdata/ptrace/generated_status_test.go | 10 +++ .../generated_exportpartialsuccess.go | 16 +++-- .../generated_exportpartialsuccess_test.go | 22 ++++++ pdata/ptrace/ptraceotlp/grpc.go | 10 ++- pdata/ptrace/ptraceotlp/request.go | 16 +++-- pdata/ptrace/ptraceotlp/response.go | 12 +++- pdata/ptrace/traces.go | 10 ++- pdata/ptrace/traces_test.go | 63 ++++++++++++++++ 138 files changed, 2358 insertions(+), 541 deletions(-) create mode 100644 .chloggen/pdata-mutation-assertions.yaml create mode 100644 pdata/internal/state.go diff --git a/.chloggen/pdata-mutation-assertions.yaml b/.chloggen/pdata-mutation-assertions.yaml new file mode 100644 index 00000000000..502b17a0222 --- /dev/null +++ b/.chloggen/pdata-mutation-assertions.yaml @@ -0,0 +1,19 @@ +# 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 + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Introduce runtime assertions to catch incorrect pdata mutations + +# One or more tracking issues or pull requests related to the change +issues: [6794] + +# (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: | + This change introduces an option to enable runtime assertions to catch unintentional pdata mutations in components + that are claimed as non-mutating pdata. Without these assertions, runtime errors may still occur, but thrown by + unrelated components, making it very difficult to troubleshoot. diff --git a/pdata/internal/cmd/pdatagen/internal/base_fields.go b/pdata/internal/cmd/pdatagen/internal/base_fields.go index 79efc70efd2..bef53889922 100644 --- a/pdata/internal/cmd/pdatagen/internal/base_fields.go +++ b/pdata/internal/cmd/pdatagen/internal/base_fields.go @@ -12,9 +12,15 @@ import ( const accessorSliceTemplate = `// {{ .fieldName }} returns the {{ .fieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { {{- if .isCommon }} - return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }})) + return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }} + {{- if .isBaseStructCommon -}} + , internal.Get{{ .structName }}State(internal.{{ .structName }}(ms)) + {{- else -}} + , ms.state + {{- end -}} + )) {{- else }} - return new{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }}) + return new{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }}, ms.state) {{- end }} }` @@ -36,14 +42,14 @@ const setTestValueTemplate = `{{ if .isCommon -}} {{- else -}} fillTest{{ .returnType }}(new {{- end -}} - {{ .returnType }}(&tv.orig.{{ .fieldName }}))` + {{ .returnType }}(&tv.orig.{{ .fieldName }}, tv.state))` const accessorsMessageValueTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { {{- if .isCommon }} - return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }})) + return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }}, ms.state)) {{- else }} - return new{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }}) + return new{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }}, ms.state) {{- end }} }` @@ -65,12 +71,13 @@ func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType // Set{{ .fieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .fieldName }}(v {{ .returnType }}) { + ms.{{ .stateAccessor }}.AssertMutable() ms.{{ .origAccessor }}.{{ .fieldName }} = v }` const accessorsPrimitiveSliceTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { - return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }})) + return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldName }}, ms.state)) }` const oneOfTypeAccessorTemplate = `// {{ .typeFuncName }} returns the type of the {{ .lowerOriginFieldName }} for this {{ .structName }}. @@ -108,7 +115,7 @@ func (ms {{ .structName }}) {{ .fieldName }}() {{ .returnType }} { if !ok { return {{ .returnType }}{} } - return new{{ .returnType }}(v.{{ .fieldName }}) + return new{{ .returnType }}(v.{{ .fieldName }}, ms.state) } // SetEmpty{{ .fieldName }} sets an empty {{ .lowerFieldName }} to this {{ .structName }}. @@ -117,9 +124,10 @@ func (ms {{ .structName }}) {{ .fieldName }}() {{ .returnType }} { // // Calling this function on zero-initialized {{ .structName }} will cause a panic. func (ms {{ .structName }}) SetEmpty{{ .fieldName }}() {{ .returnType }} { + ms.state.AssertMutable() val := &{{ .originFieldPackageName }}.{{ .fieldName }}{} ms.orig.{{ .originOneOfFieldName }} = &{{ .originStructType }}{{ "{" }}{{ .fieldName }}: val} - return new{{ .returnType }}(val) + return new{{ .returnType }}(val, ms.state) }` const accessorsOneOfMessageTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { @@ -127,6 +135,8 @@ const accessorsOneOfMessageTestTemplate = `func Test{{ .structName }}_{{ .fieldN fillTest{{ .returnType }}(ms.SetEmpty{{ .fieldName }}()) assert.Equal(t, {{ .typeName }}, ms.{{ .originOneOfTypeFuncName }}()) assert.Equal(t, generateTest{{ .returnType }}(), ms.{{ .fieldName }}()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { new{{ .structName }}(&{{ .originStructName }}{}, &sharedState).SetEmpty{{ .fieldName }}() }) } func Test{{ .structName }}_CopyTo_{{ .fieldName }}(t *testing.T) { @@ -135,6 +145,8 @@ func Test{{ .structName }}_CopyTo_{{ .fieldName }}(t *testing.T) { dest := New{{ .structName }}() ms.CopyTo(dest) assert.Equal(t, ms, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(new{{ .structName }}(&{{ .originStructName }}{}, &sharedState)) }) }` const copyToValueOneOfMessageTemplate = ` case {{ .typeName }}: @@ -147,6 +159,7 @@ func (ms {{ .structName }}) {{ .accessorFieldName }}() {{ .returnType }} { // Set{{ .accessorFieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .accessorFieldName }}(v {{ .returnType }}) { + ms.state.AssertMutable() ms.orig.{{ .originOneOfFieldName }} = &{{ .originStructType }}{ {{ .originFieldName }}: v, } @@ -158,6 +171,8 @@ const accessorsOneOfPrimitiveTestTemplate = `func Test{{ .structName }}_{{ .acce ms.Set{{ .accessorFieldName }}({{ .testValue }}) assert.Equal(t, {{ .testValue }}, ms.{{ .accessorFieldName }}()) assert.Equal(t, {{ .typeName }}, ms.{{ .originOneOfTypeFuncName }}()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { new{{ .structName }}(&{{ .originStructName }}{}, &sharedState).Set{{ .accessorFieldName }}({{ .testValue }}) }) }` const accessorsPrimitiveTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { @@ -165,6 +180,8 @@ const accessorsPrimitiveTestTemplate = `func Test{{ .structName }}_{{ .fieldName assert.Equal(t, {{ .defaultVal }}, ms.{{ .fieldName }}()) ms.Set{{ .fieldName }}({{ .testValue }}) assert.Equal(t, {{ .testValue }}, ms.{{ .fieldName }}()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { new{{ .structName }}(&{{ .originStructName }}{}, &sharedState).Set{{ .fieldName }}({{ .testValue }}) }) }` const accessorsPrimitiveTypedTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. @@ -174,6 +191,7 @@ func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType // Set{{ .fieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .fieldName }}(v {{ .packageName }}{{ .returnType }}) { + ms.state.AssertMutable() ms.orig.{{ .originFieldName }} = {{ .rawType }}(v) }` @@ -205,11 +223,13 @@ func (ms {{ .structName }}) Has{{ .fieldName }}() bool { // Set{{ .fieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .fieldName }}(v {{ .returnType }}) { + ms.state.AssertMutable() ms.orig.{{ .fieldName }}_ = &{{ .originStructType }}{{ "{" }}{{ .fieldName }}: v} } // Remove{{ .fieldName }} removes the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Remove{{ .fieldName }}() { + ms.state.AssertMutable() ms.orig.{{ .fieldName }}_ = nil }` @@ -281,6 +301,7 @@ func (sf *sliceField) templateFields(ms *messageValueStruct) map[string]any { }(), "returnType": sf.returnSlice.getName(), "origAccessor": origAccessor(ms), + "stateAccessor": stateAccessor(ms), "isCommon": usedByOtherDataTypes(sf.returnSlice.getPackageName()), "isBaseStructCommon": usedByOtherDataTypes(ms.packageName), } @@ -337,7 +358,8 @@ func (mf *messageValueField) templateFields(ms *messageValueStruct) map[string]a } return "" }(), - "origAccessor": origAccessor(ms), + "origAccessor": origAccessor(ms), + "stateAccessor": stateAccessor(ms), } } @@ -378,14 +400,16 @@ func (pf *primitiveField) GenerateCopyToValue(_ *messageValueStruct) string { func (pf *primitiveField) templateFields(ms *messageValueStruct) map[string]any { return map[string]any{ - "structName": ms.getName(), - "packageName": "", - "defaultVal": pf.defaultVal, - "fieldName": pf.fieldName, - "lowerFieldName": strings.ToLower(pf.fieldName), - "testValue": pf.testVal, - "returnType": pf.returnType, - "origAccessor": origAccessor(ms), + "structName": ms.getName(), + "packageName": "", + "defaultVal": pf.defaultVal, + "fieldName": pf.fieldName, + "lowerFieldName": strings.ToLower(pf.fieldName), + "testValue": pf.testVal, + "returnType": pf.returnType, + "origAccessor": origAccessor(ms), + "stateAccessor": stateAccessor(ms), + "originStructName": ms.originFullName, } } @@ -513,6 +537,7 @@ func (psf *primitiveSliceField) templateFields(ms *messageValueStruct) map[strin "lowerFieldName": strings.ToLower(psf.fieldName), "testValue": psf.testVal, "origAccessor": origAccessor(ms), + "stateAccessor": stateAccessor(ms), } } @@ -576,6 +601,7 @@ func (of *oneOfField) templateFields(ms *messageValueStruct) map[string]any { "originFieldName": of.originFieldName, "lowerOriginFieldName": strings.ToLower(of.originFieldName), "origAccessor": origAccessor(ms), + "stateAccessor": stateAccessor(ms), "values": of.values, "originTypePrefix": ms.originFullName + "_", } @@ -653,6 +679,7 @@ func (opv *oneOfPrimitiveValue) templateFields(ms *messageValueStruct, of *oneOf "returnType": opv.returnType, "originFieldName": opv.originFieldName, "originOneOfFieldName": of.originFieldName, + "originStructName": ms.originFullName, "originStructType": ms.originFullName + "_" + opv.originFieldName, } } @@ -687,7 +714,7 @@ func (omv *oneOfMessageValue) GenerateTests(ms *messageValueStruct, of *oneOfFie func (omv *oneOfMessageValue) GenerateSetWithTestValue(ms *messageValueStruct, of *oneOfField) string { return "\ttv.orig." + of.originFieldName + " = &" + ms.originFullName + "_" + omv.fieldName + "{" + omv. fieldName + ": &" + omv.originFieldPackageName + "." + omv.fieldName + "{}}\n" + - "\tfillTest" + omv.returnMessage.structName + "(new" + omv.fieldName + "(tv.orig.Get" + omv.fieldName + "()))" + "\tfillTest" + omv.returnMessage.structName + "(new" + omv.fieldName + "(tv.orig.Get" + omv.fieldName + "(), tv.state))" } func (omv *oneOfMessageValue) GenerateCopyToValue(ms *messageValueStruct, of *oneOfField, sb *bytes.Buffer) { @@ -713,6 +740,7 @@ func (omv *oneOfMessageValue) templateFields(ms *messageValueStruct, of *oneOfFi "originOneOfTypeFuncName": of.typeFuncName(), "lowerFieldName": strings.ToLower(omv.fieldName), "originFieldPackageName": omv.originFieldPackageName, + "originStructName": ms.originFullName, "originStructType": ms.originFullName + "_" + omv.fieldName, } } @@ -764,6 +792,7 @@ func (opv *optionalPrimitiveValue) templateFields(ms *messageValueStruct) map[st "lowerFieldName": strings.ToLower(opv.fieldName), "testValue": opv.testVal, "returnType": opv.returnType, + "originStructName": ms.originFullName, "originStructType": ms.originFullName + "_" + opv.fieldName, } } @@ -776,3 +805,10 @@ func origAccessor(bs *messageValueStruct) string { } return "orig" } + +func stateAccessor(bs *messageValueStruct) string { + if usedByOtherDataTypes(bs.packageName) { + return "getState()" + } + return "state" +} diff --git a/pdata/internal/cmd/pdatagen/internal/base_slices.go b/pdata/internal/cmd/pdatagen/internal/base_slices.go index 0521076d881..cc3671796a7 100644 --- a/pdata/internal/cmd/pdatagen/internal/base_slices.go +++ b/pdata/internal/cmd/pdatagen/internal/base_slices.go @@ -17,17 +17,19 @@ const sliceTemplate = `// {{ .structName }} logically represents a slice of {{ . // Important: zero-initialized instance is not valid for use. type {{ .structName }} struct { orig *[]{{ .originElementType }} + state *internal.State } -func new{{ .structName }}(orig *[]{{ .originElementType }}) {{ .structName }} { - return {{ .structName }}{orig} +func new{{ .structName }}(orig *[]{{ .originElementType }}, state *internal.State) {{ .structName }} { + return {{ .structName }}{orig: orig, state: state} } // New{{ .structName }} creates a {{ .structName }} with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func New{{ .structName }}() {{ .structName }} { orig := []{{ .originElementType }}(nil) - return new{{ .structName }}(&orig) + state := internal.StateMutable + return new{{ .structName }}(&orig, &state) } // Len returns the number of elements in the slice. @@ -60,6 +62,7 @@ func (es {{ .structName }}) At(i int) {{ .elementName }} { // // Here should set all the values for e. // } func (es {{ .structName }}) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -73,6 +76,7 @@ func (es {{ .structName }}) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty {{ .elementName }}. // It returns the newly added {{ .elementName }}. func (es {{ .structName }}) AppendEmpty() {{ .elementName }} { + es.state.AssertMutable() *es.orig = append(*es.orig, {{ .emptyOriginElement }}) return es.At(es.Len() - 1) } @@ -80,6 +84,8 @@ func (es {{ .structName }}) AppendEmpty() {{ .elementName }} { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es {{ .structName }}) MoveAndAppendTo(dest {{ .structName }}) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -92,6 +98,7 @@ func (es {{ .structName }}) MoveAndAppendTo(dest {{ .structName }}) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es {{ .structName }}) RemoveIf(f func({{ .elementName }}) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -112,6 +119,7 @@ func (es {{ .structName }}) RemoveIf(f func({{ .elementName }}) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { @@ -119,7 +127,7 @@ func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { {{- if eq .type "sliceOfPtrs" }} for i := range *es.orig { - new{{ .elementName }}((*es.orig)[i]).CopyTo(new{{ .elementName }}((*dest.orig)[i])) + new{{ .elementName }}((*es.orig)[i], es.state).CopyTo(new{{ .elementName }}((*dest.orig)[i], dest.state)) } return } @@ -127,7 +135,7 @@ func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { wrappers := make([]*{{ .originName }}, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - new{{ .elementName }}((*es.orig)[i]).CopyTo(new{{ .elementName }}(wrappers[i])) + new{{ .elementName }}((*es.orig)[i], es.state).CopyTo(new{{ .elementName }}(wrappers[i], dest.state)) } *dest.orig = wrappers @@ -136,7 +144,7 @@ func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { (*dest.orig) = make([]{{ .originElementType }}, srcLen) } for i := range *es.orig { - {{ .newElement }}.CopyTo(new{{ .elementName }}(&(*dest.orig)[i])) + {{ .newElement }}.CopyTo(new{{ .elementName }}(&(*dest.orig)[i], dest.state)) } {{- end }} } @@ -146,6 +154,7 @@ func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { // provided less function so that two instances of {{ .structName }} // can be compared. func (es {{ .structName }}) Sort(less func(a, b {{ .elementName }}) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } {{- end }}` @@ -153,7 +162,8 @@ func (es {{ .structName }}) Sort(less func(a, b {{ .elementName }}) bool) { const sliceTestTemplate = `func Test{{ .structName }}(t *testing.T) { es := New{{ .structName }}() assert.Equal(t, 0, es.Len()) - es = new{{ .structName }}(&[]{{ .originElementType }}{}) + state := internal.StateMutable + es = new{{ .structName }}(&[]{{ .originElementType }}{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := New{{ .elementName }}() @@ -167,6 +177,19 @@ const sliceTestTemplate = `func Test{{ .structName }}(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func Test{{ .structName }}ReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := new{{ .structName }}(&[]{{ .originElementType }}{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := New{{ .structName }}() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func Test{{ .structName }}_CopyTo(t *testing.T) { dest := New{{ .structName }}() // Test CopyTo to empty @@ -324,7 +347,7 @@ func (ss *sliceOfPtrs) templateFields() map[string]any { "originName": ss.element.originFullName, "originElementType": "*" + ss.element.originFullName, "emptyOriginElement": "&" + ss.element.originFullName + "{}", - "newElement": "new" + ss.element.structName + "((*es.orig)[i])", + "newElement": "new" + ss.element.structName + "((*es.orig)[i], es.state)", } } @@ -376,7 +399,7 @@ func (ss *sliceOfValues) templateFields() map[string]any { "originName": ss.element.originFullName, "originElementType": ss.element.originFullName, "emptyOriginElement": ss.element.originFullName + "{}", - "newElement": "new" + ss.element.structName + "(&(*es.orig)[i])", + "newElement": "new" + ss.element.structName + "(&(*es.orig)[i], es.state)", } } diff --git a/pdata/internal/cmd/pdatagen/internal/base_structs.go b/pdata/internal/cmd/pdatagen/internal/base_structs.go index fe247969c5e..859bb4d7c05 100644 --- a/pdata/internal/cmd/pdatagen/internal/base_structs.go +++ b/pdata/internal/cmd/pdatagen/internal/base_structs.go @@ -21,14 +21,15 @@ type {{ .structName }} internal.{{ .structName }} {{- else }} type {{ .structName }} struct { orig *{{ .originName }} + state *internal.State } {{- end }} -func new{{ .structName }}(orig *{{ .originName }}) {{ .structName }} { +func new{{ .structName }}(orig *{{ .originName }}, state *internal.State) {{ .structName }} { {{- if .isCommon }} - return {{ .structName }}(internal.New{{ .structName }}(orig)) + return {{ .structName }}(internal.New{{ .structName }}(orig, state)) {{- else }} - return {{ .structName }}{orig} + return {{ .structName }}{orig: orig, state: state} {{- end }} } @@ -37,12 +38,15 @@ func new{{ .structName }}(orig *{{ .originName }}) {{ .structName }} { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func New{{ .structName }}() {{ .structName }} { - return new{{ .structName }}(&{{ .originName }}{}) + state := internal.StateMutable + return new{{ .structName }}(&{{ .originName }}{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) { + ms.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() + dest.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() *dest.{{ .origAccessor }} = *ms.{{ .origAccessor }} *ms.{{ .origAccessor }} = {{ .originName }}{} } @@ -51,6 +55,10 @@ func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) { func (ms {{ .structName }}) getOrig() *{{ .originName }} { return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms)) } + +func (ms {{ .structName }}) getState() *internal.State { + return internal.Get{{ .structName }}State(internal.{{ .structName }}(ms)) +} {{- end }} {{ range .fields -}} @@ -59,9 +67,10 @@ func (ms {{ .structName }}) getOrig() *{{ .originName }} { // CopyTo copies all properties from the current struct overriding the destination. func (ms {{ .structName }}) CopyTo(dest {{ .structName }}) { -{{- range .fields }} -{{ .GenerateCopyToValue $.messageStruct }} -{{- end }} + dest.{{- if .isCommon }}getState(){{ else }}state{{ end }}.AssertMutable() + {{- range .fields }} + {{ .GenerateCopyToValue $.messageStruct }} + {{- end }} }` const messageValueTestTemplate = ` @@ -71,6 +80,9 @@ func Test{{ .structName }}_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, New{{ .structName }}(), ms) assert.Equal(t, {{ .generateTestData }}, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(new{{ .structName }}(&{{ .originName }}{}, &sharedState)) }) + assert.Panics(t, func() { new{{ .structName }}(&{{ .originName }}{}, &sharedState).MoveTo(dest) }) } func Test{{ .structName }}_CopyTo(t *testing.T) { @@ -81,6 +93,8 @@ func Test{{ .structName }}_CopyTo(t *testing.T) { orig = {{ .generateTestData }} orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(new{{ .structName }}(&{{ .originName }}{}, &sharedState)) }) } {{ range .fields }} @@ -90,8 +104,9 @@ func Test{{ .structName }}_CopyTo(t *testing.T) { const messageValueGenerateTestTemplate = `func {{ upperIfInternal "g" }}enerateTest{{ .structName }}() {{ .structName }} { {{- if .isCommon }} orig := {{ .originName }}{} + state := StateMutable {{- end }} - tv := New{{ .structName }}({{ if .isCommon }}&orig{{ end }}) + tv := New{{ .structName }}({{ if .isCommon }}&orig, &state{{ end }}) {{ upperIfInternal "f" }}illTest{{ .structName }}(tv) return tv } @@ -105,14 +120,19 @@ func {{ upperIfInternal "f" }}illTest{{ .structName }}(tv {{ .structName }}) { const messageValueAliasTemplate = ` type {{ .structName }} struct { orig *{{ .originName }} + state *State } func GetOrig{{ .structName }}(ms {{ .structName }}) *{{ .originName }} { return ms.orig } -func New{{ .structName }}(orig *{{ .originName }}) {{ .structName }} { - return {{ .structName }}{orig: orig} +func Get{{ .structName }}State(ms {{ .structName }}) *State { + return ms.state +} + +func New{{ .structName }}(orig *{{ .originName }}, state *State) {{ .structName }} { + return {{ .structName }}{orig: orig, state: state} }` type baseStruct interface { diff --git a/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go b/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go index cbca8c08355..6428e545c52 100644 --- a/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go +++ b/pdata/internal/cmd/pdatagen/internal/primitive_slice_structs.go @@ -20,10 +20,15 @@ func (ms {{ .structName }}) getOrig() *[]{{ .itemType }} { return internal.GetOrig{{ .structName }}(internal.{{ .structName }}(ms)) } +func (ms {{ .structName }}) getState() *internal.State { + return internal.Get{{ .structName }}State(internal.{{ .structName }}(ms)) +} + // New{{ .structName }} creates a new empty {{ .structName }}. func New{{ .structName }}() {{ .structName }} { orig := []{{ .itemType }}(nil) - return {{ .structName }}(internal.New{{ .structName }}(&orig)) + state := internal.StateMutable + return {{ .structName }}(internal.New{{ .structName }}(&orig, &state)) } // AsRaw returns a copy of the []{{ .itemType }} slice. @@ -33,6 +38,7 @@ func (ms {{ .structName }}) AsRaw() []{{ .itemType }} { // FromRaw copies raw []{{ .itemType }} into the slice {{ .structName }}. func (ms {{ .structName }}) FromRaw(val []{{ .itemType }}) { + ms.getState().AssertMutable() *ms.getOrig() = copy{{ .structName }}(*ms.getOrig(), val) } @@ -51,6 +57,7 @@ func (ms {{ .structName }}) At(i int) {{ .itemType }} { // SetAt sets {{ .itemType }} item at particular index. // Equivalent of {{ .lowerStructName }}[i] = val func (ms {{ .structName }}) SetAt(i int, val {{ .itemType }}) { + ms.getState().AssertMutable() (*ms.getOrig())[i] = val } @@ -61,6 +68,7 @@ func (ms {{ .structName }}) SetAt(i int, val {{ .itemType }}) { // copy(buf, {{ .lowerStructName }}) // {{ .lowerStructName }} = buf func (ms {{ .structName }}) EnsureCapacity(newCap int) { + ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return @@ -74,18 +82,22 @@ func (ms {{ .structName }}) EnsureCapacity(newCap int) { // Append appends extra elements to {{ .structName }}. // Equivalent of {{ .lowerStructName }} = append({{ .lowerStructName }}, elms...) func (ms {{ .structName }}) Append(elms ...{{ .itemType }}) { + ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // CopyTo copies all elements from the current slice overriding the destination. func (ms {{ .structName }}) CopyTo(dest {{ .structName }}) { + dest.getState().AssertMutable() *dest.getOrig() = copy{{ .structName }}(*dest.getOrig(), *ms.getOrig()) } @@ -125,6 +137,27 @@ const immutableSliceTestTemplate = `func TestNew{{ .structName }}(t *testing.T) assert.Equal(t, {{ .itemType }}(1), mv.At(0)) } +func Test{{ .structName }}ReadOnly(t *testing.T) { + raw := []{{ .itemType }}{1, 2, 3} + state := internal.StateReadOnly + ms := {{ .structName }}(internal.New{{ .structName }}(&raw, &state)) + + assert.Equal(t, 3, ms.Len()) + assert.Equal(t, {{ .itemType }}(1), ms.At(0)) + assert.Panics(t, func() { ms.Append(1) }) + assert.Panics(t, func() { ms.EnsureCapacity(2) }) + assert.Equal(t, raw, ms.AsRaw()) + assert.Panics(t, func() { ms.FromRaw(raw) }) + + ms2 := New{{ .structName }}() + ms.CopyTo(ms2) + assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) + assert.Panics(t, func() { ms2.CopyTo(ms) }) + + assert.Panics(t, func() { ms.MoveTo(ms2) }) + assert.Panics(t, func() { ms2.MoveTo(ms) }) +} + func Test{{ .structName }}Append(t *testing.T) { ms := New{{ .structName }}() ms.FromRaw([]{{ .itemType }}{1, 2, 3}) @@ -144,14 +177,19 @@ func Test{{ .structName }}EnsureCapacity(t *testing.T) { const primitiveSliceInternalTemplate = ` type {{ .structName }} struct { orig *[]{{ .itemType }} + state *State } func GetOrig{{ .structName }}(ms {{ .structName }}) *[]{{ .itemType }} { return ms.orig } -func New{{ .structName }}(orig *[]{{ .itemType }}) {{ .structName }} { - return {{ .structName }}{orig: orig} +func Get{{ .structName }}State(ms {{ .structName }}) *State { + return ms.state +} + +func New{{ .structName }}(orig *[]{{ .itemType }}, state *State) {{ .structName }} { + return {{ .structName }}{orig: orig, state: state} }` // primitiveSliceStruct generates a struct for a slice of primitive value elements. The structs are always generated diff --git a/pdata/internal/generated_wrapper_byteslice.go b/pdata/internal/generated_wrapper_byteslice.go index 83beaf9c6ab..ea3a3d95cd1 100644 --- a/pdata/internal/generated_wrapper_byteslice.go +++ b/pdata/internal/generated_wrapper_byteslice.go @@ -7,13 +7,18 @@ package internal type ByteSlice struct { - orig *[]byte + orig *[]byte + state *State } func GetOrigByteSlice(ms ByteSlice) *[]byte { return ms.orig } -func NewByteSlice(orig *[]byte) ByteSlice { - return ByteSlice{orig: orig} +func GetByteSliceState(ms ByteSlice) *State { + return ms.state +} + +func NewByteSlice(orig *[]byte, state *State) ByteSlice { + return ByteSlice{orig: orig, state: state} } diff --git a/pdata/internal/generated_wrapper_float64slice.go b/pdata/internal/generated_wrapper_float64slice.go index 1204adf5dd3..88d6c33d78e 100644 --- a/pdata/internal/generated_wrapper_float64slice.go +++ b/pdata/internal/generated_wrapper_float64slice.go @@ -7,13 +7,18 @@ package internal type Float64Slice struct { - orig *[]float64 + orig *[]float64 + state *State } func GetOrigFloat64Slice(ms Float64Slice) *[]float64 { return ms.orig } -func NewFloat64Slice(orig *[]float64) Float64Slice { - return Float64Slice{orig: orig} +func GetFloat64SliceState(ms Float64Slice) *State { + return ms.state +} + +func NewFloat64Slice(orig *[]float64, state *State) Float64Slice { + return Float64Slice{orig: orig, state: state} } diff --git a/pdata/internal/generated_wrapper_instrumentationscope.go b/pdata/internal/generated_wrapper_instrumentationscope.go index 951e60cea12..89b995bc98f 100644 --- a/pdata/internal/generated_wrapper_instrumentationscope.go +++ b/pdata/internal/generated_wrapper_instrumentationscope.go @@ -11,20 +11,26 @@ import ( ) type InstrumentationScope struct { - orig *otlpcommon.InstrumentationScope + orig *otlpcommon.InstrumentationScope + state *State } func GetOrigInstrumentationScope(ms InstrumentationScope) *otlpcommon.InstrumentationScope { return ms.orig } -func NewInstrumentationScope(orig *otlpcommon.InstrumentationScope) InstrumentationScope { - return InstrumentationScope{orig: orig} +func GetInstrumentationScopeState(ms InstrumentationScope) *State { + return ms.state +} + +func NewInstrumentationScope(orig *otlpcommon.InstrumentationScope, state *State) InstrumentationScope { + return InstrumentationScope{orig: orig, state: state} } func GenerateTestInstrumentationScope() InstrumentationScope { orig := otlpcommon.InstrumentationScope{} - tv := NewInstrumentationScope(&orig) + state := StateMutable + tv := NewInstrumentationScope(&orig, &state) FillTestInstrumentationScope(tv) return tv } @@ -32,6 +38,6 @@ func GenerateTestInstrumentationScope() InstrumentationScope { func FillTestInstrumentationScope(tv InstrumentationScope) { tv.orig.Name = "test_name" tv.orig.Version = "test_version" - FillTestMap(NewMap(&tv.orig.Attributes)) + FillTestMap(NewMap(&tv.orig.Attributes, tv.state)) tv.orig.DroppedAttributesCount = uint32(17) } diff --git a/pdata/internal/generated_wrapper_resource.go b/pdata/internal/generated_wrapper_resource.go index 0f91d02ede6..354b2457ba7 100644 --- a/pdata/internal/generated_wrapper_resource.go +++ b/pdata/internal/generated_wrapper_resource.go @@ -11,25 +11,31 @@ import ( ) type Resource struct { - orig *otlpresource.Resource + orig *otlpresource.Resource + state *State } func GetOrigResource(ms Resource) *otlpresource.Resource { return ms.orig } -func NewResource(orig *otlpresource.Resource) Resource { - return Resource{orig: orig} +func GetResourceState(ms Resource) *State { + return ms.state +} + +func NewResource(orig *otlpresource.Resource, state *State) Resource { + return Resource{orig: orig, state: state} } func GenerateTestResource() Resource { orig := otlpresource.Resource{} - tv := NewResource(&orig) + state := StateMutable + tv := NewResource(&orig, &state) FillTestResource(tv) return tv } func FillTestResource(tv Resource) { - FillTestMap(NewMap(&tv.orig.Attributes)) + FillTestMap(NewMap(&tv.orig.Attributes, tv.state)) tv.orig.DroppedAttributesCount = uint32(17) } diff --git a/pdata/internal/generated_wrapper_uint64slice.go b/pdata/internal/generated_wrapper_uint64slice.go index 6190251307a..fed633ae260 100644 --- a/pdata/internal/generated_wrapper_uint64slice.go +++ b/pdata/internal/generated_wrapper_uint64slice.go @@ -7,13 +7,18 @@ package internal type UInt64Slice struct { - orig *[]uint64 + orig *[]uint64 + state *State } func GetOrigUInt64Slice(ms UInt64Slice) *[]uint64 { return ms.orig } -func NewUInt64Slice(orig *[]uint64) UInt64Slice { - return UInt64Slice{orig: orig} +func GetUInt64SliceState(ms UInt64Slice) *State { + return ms.state +} + +func NewUInt64Slice(orig *[]uint64, state *State) UInt64Slice { + return UInt64Slice{orig: orig, state: state} } diff --git a/pdata/internal/state.go b/pdata/internal/state.go new file mode 100644 index 00000000000..f10de5eadf1 --- /dev/null +++ b/pdata/internal/state.go @@ -0,0 +1,22 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package internal // import "go.opentelemetry.io/collector/pdata/internal" + +// State defines an ownership state of pmetric.Metrics, plog.Logs or ptrace.Traces. +type State int32 + +const ( + // StateMutable indicates that the data is exclusive to the current consumer. + StateMutable State = iota + + // StateReadOnly indicates that the data is shared with other consumers. + StateReadOnly +) + +// AssertMutable panics if the state is not StateMutable. +func (state *State) AssertMutable() { + if *state != StateMutable { + panic("invalid access to shared data") + } +} diff --git a/pdata/internal/wrapper_logs.go b/pdata/internal/wrapper_logs.go index b102ff70489..6b6c076cca6 100644 --- a/pdata/internal/wrapper_logs.go +++ b/pdata/internal/wrapper_logs.go @@ -9,15 +9,24 @@ import ( ) type Logs struct { - orig *otlpcollectorlog.ExportLogsServiceRequest + orig *otlpcollectorlog.ExportLogsServiceRequest + state *State } func GetOrigLogs(ms Logs) *otlpcollectorlog.ExportLogsServiceRequest { return ms.orig } -func NewLogs(orig *otlpcollectorlog.ExportLogsServiceRequest) Logs { - return Logs{orig: orig} +func GetLogsState(ms Logs) *State { + return ms.state +} + +func SetLogsState(ms Logs, state State) { + *ms.state = state +} + +func NewLogs(orig *otlpcollectorlog.ExportLogsServiceRequest, state *State) Logs { + return Logs{orig: orig, state: state} } // LogsToProto internal helper to convert Logs to protobuf representation. @@ -28,8 +37,10 @@ func LogsToProto(l Logs) otlplogs.LogsData { } // LogsFromProto internal helper to convert protobuf representation to Logs. +// This function set exclusive state assuming that it's called only once per Logs. func LogsFromProto(orig otlplogs.LogsData) Logs { - return Logs{orig: &otlpcollectorlog.ExportLogsServiceRequest{ + state := StateMutable + return NewLogs(&otlpcollectorlog.ExportLogsServiceRequest{ ResourceLogs: orig.ResourceLogs, - }} + }, &state) } diff --git a/pdata/internal/wrapper_map.go b/pdata/internal/wrapper_map.go index 8eece9e7dbd..23a1c9056c8 100644 --- a/pdata/internal/wrapper_map.go +++ b/pdata/internal/wrapper_map.go @@ -8,20 +8,26 @@ import ( ) type Map struct { - orig *[]otlpcommon.KeyValue + orig *[]otlpcommon.KeyValue + state *State } func GetOrigMap(ms Map) *[]otlpcommon.KeyValue { return ms.orig } -func NewMap(orig *[]otlpcommon.KeyValue) Map { - return Map{orig: orig} +func GetMapState(ms Map) *State { + return ms.state +} + +func NewMap(orig *[]otlpcommon.KeyValue, state *State) Map { + return Map{orig: orig, state: state} } func GenerateTestMap() Map { var orig []otlpcommon.KeyValue - ms := NewMap(&orig) + state := StateMutable + ms := NewMap(&orig, &state) FillTestMap(ms) return ms } diff --git a/pdata/internal/wrapper_metrics.go b/pdata/internal/wrapper_metrics.go index 95b3001e77b..85be497ea5c 100644 --- a/pdata/internal/wrapper_metrics.go +++ b/pdata/internal/wrapper_metrics.go @@ -9,15 +9,24 @@ import ( ) type Metrics struct { - orig *otlpcollectormetrics.ExportMetricsServiceRequest + orig *otlpcollectormetrics.ExportMetricsServiceRequest + state *State } func GetOrigMetrics(ms Metrics) *otlpcollectormetrics.ExportMetricsServiceRequest { return ms.orig } -func NewMetrics(orig *otlpcollectormetrics.ExportMetricsServiceRequest) Metrics { - return Metrics{orig: orig} +func GetMetricsState(ms Metrics) *State { + return ms.state +} + +func SetMetricsState(ms Metrics, state State) { + *ms.state = state +} + +func NewMetrics(orig *otlpcollectormetrics.ExportMetricsServiceRequest, state *State) Metrics { + return Metrics{orig: orig, state: state} } // MetricsToProto internal helper to convert Metrics to protobuf representation. @@ -28,8 +37,10 @@ func MetricsToProto(l Metrics) otlpmetrics.MetricsData { } // MetricsFromProto internal helper to convert protobuf representation to Metrics. +// This function set exclusive state assuming that it's called only once per Metrics. func MetricsFromProto(orig otlpmetrics.MetricsData) Metrics { - return Metrics{orig: &otlpcollectormetrics.ExportMetricsServiceRequest{ + state := StateMutable + return NewMetrics(&otlpcollectormetrics.ExportMetricsServiceRequest{ ResourceMetrics: orig.ResourceMetrics, - }} + }, &state) } diff --git a/pdata/internal/wrapper_slice.go b/pdata/internal/wrapper_slice.go index cfeed739742..2f366199a25 100644 --- a/pdata/internal/wrapper_slice.go +++ b/pdata/internal/wrapper_slice.go @@ -8,20 +8,26 @@ import ( ) type Slice struct { - orig *[]otlpcommon.AnyValue + orig *[]otlpcommon.AnyValue + state *State } func GetOrigSlice(ms Slice) *[]otlpcommon.AnyValue { return ms.orig } -func NewSlice(orig *[]otlpcommon.AnyValue) Slice { - return Slice{orig: orig} +func GetSliceState(ms Slice) *State { + return ms.state +} + +func NewSlice(orig *[]otlpcommon.AnyValue, state *State) Slice { + return Slice{orig: orig, state: state} } func GenerateTestSlice() Slice { orig := []otlpcommon.AnyValue{} - tv := NewSlice(&orig) + state := StateMutable + tv := NewSlice(&orig, &state) FillTestSlice(tv) return tv } @@ -29,6 +35,7 @@ func GenerateTestSlice() Slice { func FillTestSlice(tv Slice) { *tv.orig = make([]otlpcommon.AnyValue, 7) for i := 0; i < 7; i++ { - FillTestValue(NewValue(&(*tv.orig)[i])) + state := StateMutable + FillTestValue(NewValue(&(*tv.orig)[i], &state)) } } diff --git a/pdata/internal/wrapper_traces.go b/pdata/internal/wrapper_traces.go index f8d29dba788..5a4cdadbde0 100644 --- a/pdata/internal/wrapper_traces.go +++ b/pdata/internal/wrapper_traces.go @@ -9,15 +9,24 @@ import ( ) type Traces struct { - orig *otlpcollectortrace.ExportTraceServiceRequest + orig *otlpcollectortrace.ExportTraceServiceRequest + state *State } func GetOrigTraces(ms Traces) *otlpcollectortrace.ExportTraceServiceRequest { return ms.orig } -func NewTraces(orig *otlpcollectortrace.ExportTraceServiceRequest) Traces { - return Traces{orig: orig} +func GetTracesState(ms Traces) *State { + return ms.state +} + +func SetTracesState(ms Traces, state State) { + *ms.state = state +} + +func NewTraces(orig *otlpcollectortrace.ExportTraceServiceRequest, state *State) Traces { + return Traces{orig: orig, state: state} } // TracesToProto internal helper to convert Traces to protobuf representation. @@ -28,8 +37,10 @@ func TracesToProto(l Traces) otlptrace.TracesData { } // TracesFromProto internal helper to convert protobuf representation to Traces. +// This function set exclusive state assuming that it's called only once per Traces. func TracesFromProto(orig otlptrace.TracesData) Traces { - return Traces{orig: &otlpcollectortrace.ExportTraceServiceRequest{ + state := StateMutable + return NewTraces(&otlpcollectortrace.ExportTraceServiceRequest{ ResourceSpans: orig.ResourceSpans, - }} + }, &state) } diff --git a/pdata/internal/wrapper_tracestate.go b/pdata/internal/wrapper_tracestate.go index 3a86a11848b..1a2f79f89d8 100644 --- a/pdata/internal/wrapper_tracestate.go +++ b/pdata/internal/wrapper_tracestate.go @@ -4,20 +4,26 @@ package internal // import "go.opentelemetry.io/collector/pdata/internal" type TraceState struct { - orig *string + orig *string + state *State } func GetOrigTraceState(ms TraceState) *string { return ms.orig } -func NewTraceState(orig *string) TraceState { - return TraceState{orig: orig} +func GetTraceStateState(ms TraceState) *State { + return ms.state +} + +func NewTraceState(orig *string, state *State) TraceState { + return TraceState{orig: orig, state: state} } func GenerateTestTraceState() TraceState { var orig string - ms := NewTraceState(&orig) + state := StateMutable + ms := NewTraceState(&orig, &state) FillTestTraceState(ms) return ms } diff --git a/pdata/internal/wrapper_value.go b/pdata/internal/wrapper_value.go index 9fd9064de67..0d5225052d5 100644 --- a/pdata/internal/wrapper_value.go +++ b/pdata/internal/wrapper_value.go @@ -8,15 +8,20 @@ import ( ) type Value struct { - orig *otlpcommon.AnyValue + orig *otlpcommon.AnyValue + state *State } func GetOrigValue(ms Value) *otlpcommon.AnyValue { return ms.orig } -func NewValue(orig *otlpcommon.AnyValue) Value { - return Value{orig: orig} +func GetValueState(ms Value) *State { + return ms.state +} + +func NewValue(orig *otlpcommon.AnyValue, state *State) Value { + return Value{orig: orig, state: state} } func FillTestValue(dest Value) { @@ -25,7 +30,8 @@ func FillTestValue(dest Value) { func GenerateTestValue() Value { var orig otlpcommon.AnyValue - ms := NewValue(&orig) + state := StateMutable + ms := NewValue(&orig, &state) FillTestValue(ms) return ms } diff --git a/pdata/pcommon/generated_byteslice.go b/pdata/pcommon/generated_byteslice.go index 34126d9d4e2..cbb64987d2b 100644 --- a/pdata/pcommon/generated_byteslice.go +++ b/pdata/pcommon/generated_byteslice.go @@ -21,10 +21,15 @@ func (ms ByteSlice) getOrig() *[]byte { return internal.GetOrigByteSlice(internal.ByteSlice(ms)) } +func (ms ByteSlice) getState() *internal.State { + return internal.GetByteSliceState(internal.ByteSlice(ms)) +} + // NewByteSlice creates a new empty ByteSlice. func NewByteSlice() ByteSlice { orig := []byte(nil) - return ByteSlice(internal.NewByteSlice(&orig)) + state := internal.StateMutable + return ByteSlice(internal.NewByteSlice(&orig, &state)) } // AsRaw returns a copy of the []byte slice. @@ -34,6 +39,7 @@ func (ms ByteSlice) AsRaw() []byte { // FromRaw copies raw []byte into the slice ByteSlice. func (ms ByteSlice) FromRaw(val []byte) { + ms.getState().AssertMutable() *ms.getOrig() = copyByteSlice(*ms.getOrig(), val) } @@ -52,6 +58,7 @@ func (ms ByteSlice) At(i int) byte { // SetAt sets byte item at particular index. // Equivalent of byteSlice[i] = val func (ms ByteSlice) SetAt(i int, val byte) { + ms.getState().AssertMutable() (*ms.getOrig())[i] = val } @@ -62,6 +69,7 @@ func (ms ByteSlice) SetAt(i int, val byte) { // copy(buf, byteSlice) // byteSlice = buf func (ms ByteSlice) EnsureCapacity(newCap int) { + ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return @@ -75,18 +83,22 @@ func (ms ByteSlice) EnsureCapacity(newCap int) { // Append appends extra elements to ByteSlice. // Equivalent of byteSlice = append(byteSlice, elms...) func (ms ByteSlice) Append(elms ...byte) { + ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms ByteSlice) MoveTo(dest ByteSlice) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // CopyTo copies all elements from the current slice overriding the destination. func (ms ByteSlice) CopyTo(dest ByteSlice) { + dest.getState().AssertMutable() *dest.getOrig() = copyByteSlice(*dest.getOrig(), *ms.getOrig()) } diff --git a/pdata/pcommon/generated_byteslice_test.go b/pdata/pcommon/generated_byteslice_test.go index b45c958bfc4..9594e0d11d5 100644 --- a/pdata/pcommon/generated_byteslice_test.go +++ b/pdata/pcommon/generated_byteslice_test.go @@ -10,6 +10,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" ) func TestNewByteSlice(t *testing.T) { @@ -43,6 +45,27 @@ func TestNewByteSlice(t *testing.T) { assert.Equal(t, byte(1), mv.At(0)) } +func TestByteSliceReadOnly(t *testing.T) { + raw := []byte{1, 2, 3} + state := internal.StateReadOnly + ms := ByteSlice(internal.NewByteSlice(&raw, &state)) + + assert.Equal(t, 3, ms.Len()) + assert.Equal(t, byte(1), ms.At(0)) + assert.Panics(t, func() { ms.Append(1) }) + assert.Panics(t, func() { ms.EnsureCapacity(2) }) + assert.Equal(t, raw, ms.AsRaw()) + assert.Panics(t, func() { ms.FromRaw(raw) }) + + ms2 := NewByteSlice() + ms.CopyTo(ms2) + assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) + assert.Panics(t, func() { ms2.CopyTo(ms) }) + + assert.Panics(t, func() { ms.MoveTo(ms2) }) + assert.Panics(t, func() { ms2.MoveTo(ms) }) +} + func TestByteSliceAppend(t *testing.T) { ms := NewByteSlice() ms.FromRaw([]byte{1, 2, 3}) diff --git a/pdata/pcommon/generated_float64slice.go b/pdata/pcommon/generated_float64slice.go index 54db0af8fa4..83a07ccf483 100644 --- a/pdata/pcommon/generated_float64slice.go +++ b/pdata/pcommon/generated_float64slice.go @@ -21,10 +21,15 @@ func (ms Float64Slice) getOrig() *[]float64 { return internal.GetOrigFloat64Slice(internal.Float64Slice(ms)) } +func (ms Float64Slice) getState() *internal.State { + return internal.GetFloat64SliceState(internal.Float64Slice(ms)) +} + // NewFloat64Slice creates a new empty Float64Slice. func NewFloat64Slice() Float64Slice { orig := []float64(nil) - return Float64Slice(internal.NewFloat64Slice(&orig)) + state := internal.StateMutable + return Float64Slice(internal.NewFloat64Slice(&orig, &state)) } // AsRaw returns a copy of the []float64 slice. @@ -34,6 +39,7 @@ func (ms Float64Slice) AsRaw() []float64 { // FromRaw copies raw []float64 into the slice Float64Slice. func (ms Float64Slice) FromRaw(val []float64) { + ms.getState().AssertMutable() *ms.getOrig() = copyFloat64Slice(*ms.getOrig(), val) } @@ -52,6 +58,7 @@ func (ms Float64Slice) At(i int) float64 { // SetAt sets float64 item at particular index. // Equivalent of float64Slice[i] = val func (ms Float64Slice) SetAt(i int, val float64) { + ms.getState().AssertMutable() (*ms.getOrig())[i] = val } @@ -62,6 +69,7 @@ func (ms Float64Slice) SetAt(i int, val float64) { // copy(buf, float64Slice) // float64Slice = buf func (ms Float64Slice) EnsureCapacity(newCap int) { + ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return @@ -75,18 +83,22 @@ func (ms Float64Slice) EnsureCapacity(newCap int) { // Append appends extra elements to Float64Slice. // Equivalent of float64Slice = append(float64Slice, elms...) func (ms Float64Slice) Append(elms ...float64) { + ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms Float64Slice) MoveTo(dest Float64Slice) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // CopyTo copies all elements from the current slice overriding the destination. func (ms Float64Slice) CopyTo(dest Float64Slice) { + dest.getState().AssertMutable() *dest.getOrig() = copyFloat64Slice(*dest.getOrig(), *ms.getOrig()) } diff --git a/pdata/pcommon/generated_float64slice_test.go b/pdata/pcommon/generated_float64slice_test.go index 72653c7281f..7d2dd87bece 100644 --- a/pdata/pcommon/generated_float64slice_test.go +++ b/pdata/pcommon/generated_float64slice_test.go @@ -10,6 +10,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" ) func TestNewFloat64Slice(t *testing.T) { @@ -43,6 +45,27 @@ func TestNewFloat64Slice(t *testing.T) { assert.Equal(t, float64(1), mv.At(0)) } +func TestFloat64SliceReadOnly(t *testing.T) { + raw := []float64{1, 2, 3} + state := internal.StateReadOnly + ms := Float64Slice(internal.NewFloat64Slice(&raw, &state)) + + assert.Equal(t, 3, ms.Len()) + assert.Equal(t, float64(1), ms.At(0)) + assert.Panics(t, func() { ms.Append(1) }) + assert.Panics(t, func() { ms.EnsureCapacity(2) }) + assert.Equal(t, raw, ms.AsRaw()) + assert.Panics(t, func() { ms.FromRaw(raw) }) + + ms2 := NewFloat64Slice() + ms.CopyTo(ms2) + assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) + assert.Panics(t, func() { ms2.CopyTo(ms) }) + + assert.Panics(t, func() { ms.MoveTo(ms2) }) + assert.Panics(t, func() { ms2.MoveTo(ms) }) +} + func TestFloat64SliceAppend(t *testing.T) { ms := NewFloat64Slice() ms.FromRaw([]float64{1, 2, 3}) diff --git a/pdata/pcommon/generated_instrumentationscope.go b/pdata/pcommon/generated_instrumentationscope.go index 4df1eeaed1d..8a5d23b549f 100644 --- a/pdata/pcommon/generated_instrumentationscope.go +++ b/pdata/pcommon/generated_instrumentationscope.go @@ -20,8 +20,8 @@ import ( // Important: zero-initialized instance is not valid for use. type InstrumentationScope internal.InstrumentationScope -func newInstrumentationScope(orig *otlpcommon.InstrumentationScope) InstrumentationScope { - return InstrumentationScope(internal.NewInstrumentationScope(orig)) +func newInstrumentationScope(orig *otlpcommon.InstrumentationScope, state *internal.State) InstrumentationScope { + return InstrumentationScope(internal.NewInstrumentationScope(orig, state)) } // NewInstrumentationScope creates a new empty InstrumentationScope. @@ -29,12 +29,15 @@ func newInstrumentationScope(orig *otlpcommon.InstrumentationScope) Instrumentat // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewInstrumentationScope() InstrumentationScope { - return newInstrumentationScope(&otlpcommon.InstrumentationScope{}) + state := internal.StateMutable + return newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms InstrumentationScope) MoveTo(dest InstrumentationScope) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = otlpcommon.InstrumentationScope{} } @@ -43,6 +46,10 @@ func (ms InstrumentationScope) getOrig() *otlpcommon.InstrumentationScope { return internal.GetOrigInstrumentationScope(internal.InstrumentationScope(ms)) } +func (ms InstrumentationScope) getState() *internal.State { + return internal.GetInstrumentationScopeState(internal.InstrumentationScope(ms)) +} + // Name returns the name associated with this InstrumentationScope. func (ms InstrumentationScope) Name() string { return ms.getOrig().Name @@ -50,6 +57,7 @@ func (ms InstrumentationScope) Name() string { // SetName replaces the name associated with this InstrumentationScope. func (ms InstrumentationScope) SetName(v string) { + ms.getState().AssertMutable() ms.getOrig().Name = v } @@ -60,12 +68,13 @@ func (ms InstrumentationScope) Version() string { // SetVersion replaces the version associated with this InstrumentationScope. func (ms InstrumentationScope) SetVersion(v string) { + ms.getState().AssertMutable() ms.getOrig().Version = v } // Attributes returns the Attributes associated with this InstrumentationScope. func (ms InstrumentationScope) Attributes() Map { - return Map(internal.NewMap(&ms.getOrig().Attributes)) + return Map(internal.NewMap(&ms.getOrig().Attributes, internal.GetInstrumentationScopeState(internal.InstrumentationScope(ms)))) } // DroppedAttributesCount returns the droppedattributescount associated with this InstrumentationScope. @@ -75,11 +84,13 @@ func (ms InstrumentationScope) DroppedAttributesCount() uint32 { // SetDroppedAttributesCount replaces the droppedattributescount associated with this InstrumentationScope. func (ms InstrumentationScope) SetDroppedAttributesCount(v uint32) { + ms.getState().AssertMutable() ms.getOrig().DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms InstrumentationScope) CopyTo(dest InstrumentationScope) { + dest.getState().AssertMutable() dest.SetName(ms.Name()) dest.SetVersion(ms.Version()) ms.Attributes().CopyTo(dest.Attributes()) diff --git a/pdata/pcommon/generated_instrumentationscope_test.go b/pdata/pcommon/generated_instrumentationscope_test.go index 849b75e7bfb..8dc46fe69c4 100644 --- a/pdata/pcommon/generated_instrumentationscope_test.go +++ b/pdata/pcommon/generated_instrumentationscope_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1" ) func TestInstrumentationScope_MoveTo(t *testing.T) { @@ -20,6 +21,9 @@ func TestInstrumentationScope_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewInstrumentationScope(), ms) assert.Equal(t, InstrumentationScope(internal.GenerateTestInstrumentationScope()), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &sharedState)) }) + assert.Panics(t, func() { newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &sharedState).MoveTo(dest) }) } func TestInstrumentationScope_CopyTo(t *testing.T) { @@ -30,6 +34,8 @@ func TestInstrumentationScope_CopyTo(t *testing.T) { orig = InstrumentationScope(internal.GenerateTestInstrumentationScope()) orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &sharedState)) }) } func TestInstrumentationScope_Name(t *testing.T) { @@ -37,6 +43,8 @@ func TestInstrumentationScope_Name(t *testing.T) { assert.Equal(t, "", ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &sharedState).SetName("test_name") }) } func TestInstrumentationScope_Version(t *testing.T) { @@ -44,6 +52,10 @@ func TestInstrumentationScope_Version(t *testing.T) { assert.Equal(t, "", ms.Version()) ms.SetVersion("test_version") assert.Equal(t, "test_version", ms.Version()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &sharedState).SetVersion("test_version") + }) } func TestInstrumentationScope_Attributes(t *testing.T) { @@ -58,4 +70,8 @@ func TestInstrumentationScope_DroppedAttributesCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedAttributesCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newInstrumentationScope(&otlpcommon.InstrumentationScope{}, &sharedState).SetDroppedAttributesCount(uint32(17)) + }) } diff --git a/pdata/pcommon/generated_resource.go b/pdata/pcommon/generated_resource.go index c701fb5c55a..12e6cfa7f3b 100644 --- a/pdata/pcommon/generated_resource.go +++ b/pdata/pcommon/generated_resource.go @@ -20,8 +20,8 @@ import ( // Important: zero-initialized instance is not valid for use. type Resource internal.Resource -func newResource(orig *otlpresource.Resource) Resource { - return Resource(internal.NewResource(orig)) +func newResource(orig *otlpresource.Resource, state *internal.State) Resource { + return Resource(internal.NewResource(orig, state)) } // NewResource creates a new empty Resource. @@ -29,12 +29,15 @@ func newResource(orig *otlpresource.Resource) Resource { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResource() Resource { - return newResource(&otlpresource.Resource{}) + state := internal.StateMutable + return newResource(&otlpresource.Resource{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Resource) MoveTo(dest Resource) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = otlpresource.Resource{} } @@ -43,9 +46,13 @@ func (ms Resource) getOrig() *otlpresource.Resource { return internal.GetOrigResource(internal.Resource(ms)) } +func (ms Resource) getState() *internal.State { + return internal.GetResourceState(internal.Resource(ms)) +} + // Attributes returns the Attributes associated with this Resource. func (ms Resource) Attributes() Map { - return Map(internal.NewMap(&ms.getOrig().Attributes)) + return Map(internal.NewMap(&ms.getOrig().Attributes, internal.GetResourceState(internal.Resource(ms)))) } // DroppedAttributesCount returns the droppedattributescount associated with this Resource. @@ -55,11 +62,13 @@ func (ms Resource) DroppedAttributesCount() uint32 { // SetDroppedAttributesCount replaces the droppedattributescount associated with this Resource. func (ms Resource) SetDroppedAttributesCount(v uint32) { + ms.getState().AssertMutable() ms.getOrig().DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms Resource) CopyTo(dest Resource) { + dest.getState().AssertMutable() ms.Attributes().CopyTo(dest.Attributes()) dest.SetDroppedAttributesCount(ms.DroppedAttributesCount()) } diff --git a/pdata/pcommon/generated_resource_test.go b/pdata/pcommon/generated_resource_test.go index b806227b617..a7af5300fe8 100644 --- a/pdata/pcommon/generated_resource_test.go +++ b/pdata/pcommon/generated_resource_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlpresource "go.opentelemetry.io/collector/pdata/internal/data/protogen/resource/v1" ) func TestResource_MoveTo(t *testing.T) { @@ -20,6 +21,9 @@ func TestResource_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewResource(), ms) assert.Equal(t, Resource(internal.GenerateTestResource()), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newResource(&otlpresource.Resource{}, &sharedState)) }) + assert.Panics(t, func() { newResource(&otlpresource.Resource{}, &sharedState).MoveTo(dest) }) } func TestResource_CopyTo(t *testing.T) { @@ -30,6 +34,8 @@ func TestResource_CopyTo(t *testing.T) { orig = Resource(internal.GenerateTestResource()) orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newResource(&otlpresource.Resource{}, &sharedState)) }) } func TestResource_Attributes(t *testing.T) { @@ -44,4 +50,6 @@ func TestResource_DroppedAttributesCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedAttributesCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newResource(&otlpresource.Resource{}, &sharedState).SetDroppedAttributesCount(uint32(17)) }) } diff --git a/pdata/pcommon/generated_uint64slice.go b/pdata/pcommon/generated_uint64slice.go index f3656929ccc..1344ca35bcf 100644 --- a/pdata/pcommon/generated_uint64slice.go +++ b/pdata/pcommon/generated_uint64slice.go @@ -21,10 +21,15 @@ func (ms UInt64Slice) getOrig() *[]uint64 { return internal.GetOrigUInt64Slice(internal.UInt64Slice(ms)) } +func (ms UInt64Slice) getState() *internal.State { + return internal.GetUInt64SliceState(internal.UInt64Slice(ms)) +} + // NewUInt64Slice creates a new empty UInt64Slice. func NewUInt64Slice() UInt64Slice { orig := []uint64(nil) - return UInt64Slice(internal.NewUInt64Slice(&orig)) + state := internal.StateMutable + return UInt64Slice(internal.NewUInt64Slice(&orig, &state)) } // AsRaw returns a copy of the []uint64 slice. @@ -34,6 +39,7 @@ func (ms UInt64Slice) AsRaw() []uint64 { // FromRaw copies raw []uint64 into the slice UInt64Slice. func (ms UInt64Slice) FromRaw(val []uint64) { + ms.getState().AssertMutable() *ms.getOrig() = copyUInt64Slice(*ms.getOrig(), val) } @@ -52,6 +58,7 @@ func (ms UInt64Slice) At(i int) uint64 { // SetAt sets uint64 item at particular index. // Equivalent of uInt64Slice[i] = val func (ms UInt64Slice) SetAt(i int, val uint64) { + ms.getState().AssertMutable() (*ms.getOrig())[i] = val } @@ -62,6 +69,7 @@ func (ms UInt64Slice) SetAt(i int, val uint64) { // copy(buf, uInt64Slice) // uInt64Slice = buf func (ms UInt64Slice) EnsureCapacity(newCap int) { + ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return @@ -75,18 +83,22 @@ func (ms UInt64Slice) EnsureCapacity(newCap int) { // Append appends extra elements to UInt64Slice. // Equivalent of uInt64Slice = append(uInt64Slice, elms...) func (ms UInt64Slice) Append(elms ...uint64) { + ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms UInt64Slice) MoveTo(dest UInt64Slice) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // CopyTo copies all elements from the current slice overriding the destination. func (ms UInt64Slice) CopyTo(dest UInt64Slice) { + dest.getState().AssertMutable() *dest.getOrig() = copyUInt64Slice(*dest.getOrig(), *ms.getOrig()) } diff --git a/pdata/pcommon/generated_uint64slice_test.go b/pdata/pcommon/generated_uint64slice_test.go index e2cc4ccf774..9120f84b5e2 100644 --- a/pdata/pcommon/generated_uint64slice_test.go +++ b/pdata/pcommon/generated_uint64slice_test.go @@ -10,6 +10,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" ) func TestNewUInt64Slice(t *testing.T) { @@ -43,6 +45,27 @@ func TestNewUInt64Slice(t *testing.T) { assert.Equal(t, uint64(1), mv.At(0)) } +func TestUInt64SliceReadOnly(t *testing.T) { + raw := []uint64{1, 2, 3} + state := internal.StateReadOnly + ms := UInt64Slice(internal.NewUInt64Slice(&raw, &state)) + + assert.Equal(t, 3, ms.Len()) + assert.Equal(t, uint64(1), ms.At(0)) + assert.Panics(t, func() { ms.Append(1) }) + assert.Panics(t, func() { ms.EnsureCapacity(2) }) + assert.Equal(t, raw, ms.AsRaw()) + assert.Panics(t, func() { ms.FromRaw(raw) }) + + ms2 := NewUInt64Slice() + ms.CopyTo(ms2) + assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) + assert.Panics(t, func() { ms2.CopyTo(ms) }) + + assert.Panics(t, func() { ms.MoveTo(ms2) }) + assert.Panics(t, func() { ms2.MoveTo(ms) }) +} + func TestUInt64SliceAppend(t *testing.T) { ms := NewUInt64Slice() ms.FromRaw([]uint64{1, 2, 3}) diff --git a/pdata/pcommon/map.go b/pdata/pcommon/map.go index 8e1b2bbccb6..c41aa9175a3 100644 --- a/pdata/pcommon/map.go +++ b/pdata/pcommon/map.go @@ -16,25 +16,32 @@ type Map internal.Map // NewMap creates a Map with 0 elements. func NewMap() Map { orig := []otlpcommon.KeyValue(nil) - return Map(internal.NewMap(&orig)) + state := internal.StateMutable + return Map(internal.NewMap(&orig, &state)) } func (m Map) getOrig() *[]otlpcommon.KeyValue { return internal.GetOrigMap(internal.Map(m)) } -func newMap(orig *[]otlpcommon.KeyValue) Map { - return Map(internal.NewMap(orig)) +func (m Map) getState() *internal.State { + return internal.GetMapState(internal.Map(m)) +} + +func newMap(orig *[]otlpcommon.KeyValue, state *internal.State) Map { + return Map(internal.NewMap(orig, state)) } // Clear erases any existing entries in this Map instance. func (m Map) Clear() { + m.getState().AssertMutable() *m.getOrig() = nil } // EnsureCapacity increases the capacity of this Map instance, if necessary, // to ensure that it can hold at least the number of elements specified by the capacity argument. func (m Map) EnsureCapacity(capacity int) { + m.getState().AssertMutable() oldOrig := *m.getOrig() if capacity <= cap(oldOrig) { return @@ -54,15 +61,16 @@ func (m Map) Get(key string) (Value, bool) { for i := range *m.getOrig() { akv := &(*m.getOrig())[i] if akv.Key == key { - return newValue(&akv.Value), true + return newValue(&akv.Value, m.getState()), true } } - return newValue(nil), false + return newValue(nil, m.getState()), false } // Remove removes the entry associated with the key and returns true if the key // was present in the map, otherwise returns false. func (m Map) Remove(key string) bool { + m.getState().AssertMutable() for i := range *m.getOrig() { akv := &(*m.getOrig())[i] if akv.Key == key { @@ -76,10 +84,11 @@ func (m Map) Remove(key string) bool { // RemoveIf removes the entries for which the function in question returns true func (m Map) RemoveIf(f func(string, Value) bool) { + m.getState().AssertMutable() newLen := 0 for i := 0; i < len(*m.getOrig()); i++ { akv := &(*m.getOrig())[i] - if f(akv.Key, newValue(&akv.Value)) { + if f(akv.Key, newValue(&akv.Value, m.getState())) { continue } if newLen == i { @@ -96,18 +105,20 @@ func (m Map) RemoveIf(f func(string, Value) bool) { // PutEmpty inserts or updates an empty value to the map under given key // and return the updated/inserted value. func (m Map) PutEmpty(k string) Value { + m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.getOrig().Value = nil - return newValue(av.getOrig()) + return newValue(av.getOrig(), m.getState()) } *m.getOrig() = append(*m.getOrig(), otlpcommon.KeyValue{Key: k}) - return newValue(&(*m.getOrig())[len(*m.getOrig())-1].Value) + return newValue(&(*m.getOrig())[len(*m.getOrig())-1].Value, m.getState()) } // PutStr performs the Insert or Update action. The Value is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutStr(k string, v string) { + m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetStr(v) } else { @@ -119,6 +130,7 @@ func (m Map) PutStr(k string, v string) { // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutInt(k string, v int64) { + m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetInt(v) } else { @@ -130,6 +142,7 @@ func (m Map) PutInt(k string, v int64) { // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutDouble(k string, v float64) { + m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetDouble(v) } else { @@ -141,6 +154,7 @@ func (m Map) PutDouble(k string, v float64) { // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutBool(k string, v bool) { + m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetBool(v) } else { @@ -150,35 +164,38 @@ func (m Map) PutBool(k string, v bool) { // PutEmptyBytes inserts or updates an empty byte slice under given key and returns it. func (m Map) PutEmptyBytes(k string) ByteSlice { + m.getState().AssertMutable() bv := otlpcommon.AnyValue_BytesValue{} if av, existing := m.Get(k); existing { av.getOrig().Value = &bv } else { *m.getOrig() = append(*m.getOrig(), otlpcommon.KeyValue{Key: k, Value: otlpcommon.AnyValue{Value: &bv}}) } - return ByteSlice(internal.NewByteSlice(&bv.BytesValue)) + return ByteSlice(internal.NewByteSlice(&bv.BytesValue, m.getState())) } // PutEmptyMap inserts or updates an empty map under given key and returns it. func (m Map) PutEmptyMap(k string) Map { + m.getState().AssertMutable() kvl := otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{Values: []otlpcommon.KeyValue(nil)}} if av, existing := m.Get(k); existing { av.getOrig().Value = &kvl } else { *m.getOrig() = append(*m.getOrig(), otlpcommon.KeyValue{Key: k, Value: otlpcommon.AnyValue{Value: &kvl}}) } - return Map(internal.NewMap(&kvl.KvlistValue.Values)) + return Map(internal.NewMap(&kvl.KvlistValue.Values, m.getState())) } // PutEmptySlice inserts or updates an empty slice under given key and returns it. func (m Map) PutEmptySlice(k string) Slice { + m.getState().AssertMutable() vl := otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{Values: []otlpcommon.AnyValue(nil)}} if av, existing := m.Get(k); existing { av.getOrig().Value = &vl } else { *m.getOrig() = append(*m.getOrig(), otlpcommon.KeyValue{Key: k, Value: otlpcommon.AnyValue{Value: &vl}}) } - return Slice(internal.NewSlice(&vl.ArrayValue.Values)) + return Slice(internal.NewSlice(&vl.ArrayValue.Values, m.getState())) } // Len returns the length of this map. @@ -199,7 +216,7 @@ func (m Map) Len() int { func (m Map) Range(f func(k string, v Value) bool) { for i := range *m.getOrig() { kv := &(*m.getOrig())[i] - if !f(kv.Key, Value(internal.NewValue(&kv.Value))) { + if !f(kv.Key, Value(internal.NewValue(&kv.Value, m.getState()))) { break } } @@ -207,6 +224,7 @@ func (m Map) Range(f func(k string, v Value) bool) { // CopyTo copies all elements from the current map overriding the destination. func (m Map) CopyTo(dest Map) { + dest.getState().AssertMutable() newLen := len(*m.getOrig()) oldCap := cap(*dest.getOrig()) if newLen <= oldCap { @@ -216,7 +234,7 @@ func (m Map) CopyTo(dest Map) { akv := &(*m.getOrig())[i] destAkv := &(*dest.getOrig())[i] destAkv.Key = akv.Key - newValue(&akv.Value).CopyTo(newValue(&destAkv.Value)) + newValue(&akv.Value, m.getState()).CopyTo(newValue(&destAkv.Value, dest.getState())) } return } @@ -226,7 +244,7 @@ func (m Map) CopyTo(dest Map) { for i := range *m.getOrig() { akv := &(*m.getOrig())[i] origs[i].Key = akv.Key - newValue(&akv.Value).CopyTo(newValue(&origs[i].Value)) + newValue(&akv.Value, m.getState()).CopyTo(newValue(&origs[i].Value, dest.getState())) } *dest.getOrig() = origs } @@ -243,6 +261,7 @@ func (m Map) AsRaw() map[string]any { // FromRaw overrides this Map instance from a standard go map. func (m Map) FromRaw(rawMap map[string]any) error { + m.getState().AssertMutable() if len(rawMap) == 0 { *m.getOrig() = nil return nil @@ -253,7 +272,7 @@ func (m Map) FromRaw(rawMap map[string]any) error { ix := 0 for k, iv := range rawMap { origs[ix].Key = k - errs = multierr.Append(errs, newValue(&origs[ix].Value).FromRaw(iv)) + errs = multierr.Append(errs, newValue(&origs[ix].Value, m.getState()).FromRaw(iv)) ix++ } *m.getOrig() = origs diff --git a/pdata/pcommon/map_test.go b/pdata/pcommon/map_test.go index 28f5a600906..59922a54819 100644 --- a/pdata/pcommon/map_test.go +++ b/pdata/pcommon/map_test.go @@ -17,7 +17,8 @@ func TestMap(t *testing.T) { val, exist := NewMap().Get("test_key") assert.False(t, exist) - assert.EqualValues(t, newValue(nil), val) + state := internal.StateMutable + assert.EqualValues(t, newValue(nil, &state), val) putString := NewMap() putString.PutStr("k", "v") @@ -52,6 +53,44 @@ func TestMap(t *testing.T) { assert.EqualValues(t, NewMap(), removeMap) } +func TestMapReadOnly(t *testing.T) { + state := internal.StateReadOnly + m := newMap(&[]otlpcommon.KeyValue{ + {Key: "k1", Value: otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: "v1"}}}, + }, &state) + + assert.Equal(t, 1, m.Len()) + + v, ok := m.Get("k1") + assert.True(t, ok) + assert.EqualValues(t, "v1", v.Str()) + + m.Range(func(k string, v Value) bool { + assert.Equal(t, "k1", k) + assert.Equal(t, "v1", v.Str()) + return true + }) + + assert.Panics(t, func() { m.PutStr("k2", "v2") }) + assert.Panics(t, func() { m.PutInt("k2", 123) }) + assert.Panics(t, func() { m.PutDouble("k2", 1.23) }) + assert.Panics(t, func() { m.PutBool("k2", true) }) + assert.Panics(t, func() { m.PutEmptyBytes("k2") }) + assert.Panics(t, func() { m.PutEmptyMap("k2") }) + assert.Panics(t, func() { m.PutEmptySlice("k2") }) + assert.Panics(t, func() { m.Remove("k1") }) + assert.Panics(t, func() { m.RemoveIf(func(k string, v Value) bool { return true }) }) + assert.Panics(t, func() { m.EnsureCapacity(2) }) + + m2 := NewMap() + m.CopyTo(m2) + assert.Equal(t, m2.AsRaw(), m.AsRaw()) + assert.Panics(t, func() { NewMap().CopyTo(m) }) + + assert.Equal(t, map[string]any{"k1": "v1"}, m.AsRaw()) + assert.Panics(t, func() { _ = m.FromRaw(map[string]any{"k1": "v1"}) }) +} + func TestMapPutEmpty(t *testing.T) { m := NewMap() v := m.PutEmpty("k1") @@ -148,7 +187,8 @@ func TestMapWithEmpty(t *testing.T) { Value: otlpcommon.AnyValue{Value: nil}, }, } - sm := newMap(&origWithNil) + state := internal.StateMutable + sm := newMap(&origWithNil, &state) val, exist := sm.Get("test_key") assert.True(t, exist) assert.EqualValues(t, ValueTypeStr, val.Type()) diff --git a/pdata/pcommon/slice.go b/pdata/pcommon/slice.go index 97e0cf777d1..5352ff44d5f 100644 --- a/pdata/pcommon/slice.go +++ b/pdata/pcommon/slice.go @@ -19,19 +19,24 @@ import ( // Important: zero-initialized instance is not valid for use. type Slice internal.Slice -func newSlice(orig *[]otlpcommon.AnyValue) Slice { - return Slice(internal.NewSlice(orig)) +func newSlice(orig *[]otlpcommon.AnyValue, state *internal.State) Slice { + return Slice(internal.NewSlice(orig, state)) } func (es Slice) getOrig() *[]otlpcommon.AnyValue { return internal.GetOrigSlice(internal.Slice(es)) } +func (es Slice) getState() *internal.State { + return internal.GetSliceState(internal.Slice(es)) +} + // NewSlice creates a Slice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSlice() Slice { orig := []otlpcommon.AnyValue(nil) - return Slice(internal.NewSlice(&orig)) + state := internal.StateMutable + return Slice(internal.NewSlice(&orig, &state)) } // Len returns the number of elements in the slice. @@ -50,11 +55,12 @@ func (es Slice) Len() int { // ... // Do something with the element // } func (es Slice) At(ix int) Value { - return newValue(&(*es.getOrig())[ix]) + return newValue(&(*es.getOrig())[ix], es.getState()) } // CopyTo copies all elements from the current slice overriding the destination. func (es Slice) CopyTo(dest Slice) { + dest.getState().AssertMutable() srcLen := es.Len() destCap := cap(*dest.getOrig()) if srcLen <= destCap { @@ -64,7 +70,7 @@ func (es Slice) CopyTo(dest Slice) { } for i := range *es.getOrig() { - newValue(&(*es.getOrig())[i]).CopyTo(newValue(&(*dest.getOrig())[i])) + newValue(&(*es.getOrig())[i], es.getState()).CopyTo(newValue(&(*dest.getOrig())[i], dest.getState())) } } @@ -81,6 +87,7 @@ func (es Slice) CopyTo(dest Slice) { // // Here should set all the values for e. // } func (es Slice) EnsureCapacity(newCap int) { + es.getState().AssertMutable() oldCap := cap(*es.getOrig()) if newCap <= oldCap { return @@ -94,6 +101,7 @@ func (es Slice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty Value. // It returns the newly added Value. func (es Slice) AppendEmpty() Value { + es.getState().AssertMutable() *es.getOrig() = append(*es.getOrig(), otlpcommon.AnyValue{}) return es.At(es.Len() - 1) } @@ -101,6 +109,8 @@ func (es Slice) AppendEmpty() Value { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es Slice) MoveAndAppendTo(dest Slice) { + es.getState().AssertMutable() + dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *es.getOrig() @@ -113,6 +123,7 @@ func (es Slice) MoveAndAppendTo(dest Slice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es Slice) RemoveIf(f func(Value) bool) { + es.getState().AssertMutable() newLen := 0 for i := 0; i < len(*es.getOrig()); i++ { if f(es.At(i)) { @@ -141,6 +152,7 @@ func (es Slice) AsRaw() []any { // FromRaw copies []any into the Slice. func (es Slice) FromRaw(rawSlice []any) error { + es.getState().AssertMutable() if len(rawSlice) == 0 { *es.getOrig() = nil return nil @@ -148,7 +160,7 @@ func (es Slice) FromRaw(rawSlice []any) error { var errs error origs := make([]otlpcommon.AnyValue, len(rawSlice)) for ix, iv := range rawSlice { - errs = multierr.Append(errs, newValue(&origs[ix]).FromRaw(iv)) + errs = multierr.Append(errs, newValue(&origs[ix], es.getState()).FromRaw(iv)) } *es.getOrig() = origs return errs diff --git a/pdata/pcommon/slice_test.go b/pdata/pcommon/slice_test.go index 181ab8fc433..f2db959248c 100644 --- a/pdata/pcommon/slice_test.go +++ b/pdata/pcommon/slice_test.go @@ -15,11 +15,12 @@ import ( func TestSlice(t *testing.T) { es := NewSlice() assert.Equal(t, 0, es.Len()) - es = newSlice(&[]otlpcommon.AnyValue{}) + state := internal.StateMutable + es = newSlice(&[]otlpcommon.AnyValue{}, &state) assert.Equal(t, 0, es.Len()) es.EnsureCapacity(7) - emptyVal := newValue(&otlpcommon.AnyValue{}) + emptyVal := newValue(&otlpcommon.AnyValue{}, &state) testVal := Value(internal.GenerateTestValue()) assert.Equal(t, 7, cap(*es.getOrig())) for i := 0; i < es.Len(); i++ { @@ -30,6 +31,29 @@ func TestSlice(t *testing.T) { } } +func TestSliceReadOnly(t *testing.T) { + state := internal.StateReadOnly + es := newSlice(&[]otlpcommon.AnyValue{{Value: &otlpcommon.AnyValue_IntValue{IntValue: 3}}}, &state) + + assert.Equal(t, 1, es.Len()) + assert.Equal(t, int64(3), es.At(0).Int()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + + es2 := NewSlice() + es.CopyTo(es2) + assert.Equal(t, es.AsRaw(), es2.AsRaw()) + assert.Panics(t, func() { es2.CopyTo(es) }) + + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) + + assert.Panics(t, func() { es.RemoveIf(func(el Value) bool { return false }) }) + + assert.Equal(t, []any{int64(3)}, es.AsRaw()) + assert.Panics(t, func() { _ = es.FromRaw([]any{3}) }) +} + func TestSlice_CopyTo(t *testing.T) { dest := NewSlice() // Test CopyTo to empty diff --git a/pdata/pcommon/trace_state.go b/pdata/pcommon/trace_state.go index 440b4b1ade5..dd163629cb7 100644 --- a/pdata/pcommon/trace_state.go +++ b/pdata/pcommon/trace_state.go @@ -11,13 +11,18 @@ import ( type TraceState internal.TraceState func NewTraceState() TraceState { - return TraceState(internal.NewTraceState(new(string))) + state := internal.StateMutable + return TraceState(internal.NewTraceState(new(string), &state)) } func (ms TraceState) getOrig() *string { return internal.GetOrigTraceState(internal.TraceState(ms)) } +func (ms TraceState) getState() *internal.State { + return internal.GetTraceStateState(internal.TraceState(ms)) +} + // AsRaw returns the string representation of the tracestate in w3c-trace-context format: https://www.w3.org/TR/trace-context/#tracestate-header func (ms TraceState) AsRaw() string { return *ms.getOrig() @@ -25,17 +30,21 @@ func (ms TraceState) AsRaw() string { // FromRaw copies the string representation in w3c-trace-context format of the tracestate into this TraceState. func (ms TraceState) FromRaw(v string) { + ms.getState().AssertMutable() *ms.getOrig() = v } // MoveTo moves the TraceState instance overriding the destination // and resetting the current instance to its zero value. func (ms TraceState) MoveTo(dest TraceState) { + ms.getState().AssertMutable() + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() *ms.getOrig() = "" } // CopyTo copies the TraceState instance overriding the destination. func (ms TraceState) CopyTo(dest TraceState) { + dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() } diff --git a/pdata/pcommon/value.go b/pdata/pcommon/value.go index f59b708695f..2e0443dd3b2 100644 --- a/pdata/pcommon/value.go +++ b/pdata/pcommon/value.go @@ -71,52 +71,64 @@ type Value internal.Value // NewValueEmpty creates a new Value with an empty value. func NewValueEmpty() Value { - return newValue(&otlpcommon.AnyValue{}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{}, &state) } // NewValueStr creates a new Value with the given string value. func NewValueStr(v string) Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: v}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: v}}, &state) } // NewValueInt creates a new Value with the given int64 value. func NewValueInt(v int64) Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_IntValue{IntValue: v}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_IntValue{IntValue: v}}, &state) } // NewValueDouble creates a new Value with the given float64 value. func NewValueDouble(v float64) Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_DoubleValue{DoubleValue: v}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_DoubleValue{DoubleValue: v}}, &state) } // NewValueBool creates a new Value with the given bool value. func NewValueBool(v bool) Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BoolValue{BoolValue: v}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BoolValue{BoolValue: v}}, &state) } // NewValueMap creates a new Value of map type. func NewValueMap() Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}}, &state) } // NewValueSlice creates a new Value of array type. func NewValueSlice() Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}}, &state) } // NewValueBytes creates a new empty Value of byte type. func NewValueBytes() Value { - return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BytesValue{BytesValue: nil}}) + state := internal.StateMutable + return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BytesValue{BytesValue: nil}}, &state) } -func newValue(orig *otlpcommon.AnyValue) Value { - return Value(internal.NewValue(orig)) +func newValue(orig *otlpcommon.AnyValue, state *internal.State) Value { + return Value(internal.NewValue(orig, state)) } func (v Value) getOrig() *otlpcommon.AnyValue { return internal.GetOrigValue(internal.Value(v)) } +func (v Value) getState() *internal.State { + return internal.GetValueState(internal.Value(v)) +} + func (v Value) FromRaw(iv any) error { switch tv := iv.(type) { case nil: @@ -222,7 +234,7 @@ func (v Value) Map() Map { if kvlist == nil { return Map{} } - return newMap(&kvlist.Values) + return newMap(&kvlist.Values, internal.GetValueState(internal.Value(v))) } // Slice returns the slice value associated with this Value. @@ -235,7 +247,7 @@ func (v Value) Slice() Slice { if arr == nil { return Slice{} } - return newSlice(&arr.Values) + return newSlice(&arr.Values, internal.GetValueState(internal.Value(v))) } // Bytes returns the ByteSlice value associated with this Value. @@ -248,7 +260,7 @@ func (v Value) Bytes() ByteSlice { if !ok { return ByteSlice{} } - return ByteSlice(internal.NewByteSlice(&bv.BytesValue)) + return ByteSlice(internal.NewByteSlice(&bv.BytesValue, internal.GetValueState(internal.Value(v)))) } // SetStr replaces the string value associated with this Value, @@ -257,6 +269,7 @@ func (v Value) Bytes() ByteSlice { // fmt.Stringer interface by the corresponding getter method. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetStr(sv string) { + v.getState().AssertMutable() v.getOrig().Value = &otlpcommon.AnyValue_StringValue{StringValue: sv} } @@ -264,6 +277,7 @@ func (v Value) SetStr(sv string) { // it also changes the type to be ValueTypeInt. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetInt(iv int64) { + v.getState().AssertMutable() v.getOrig().Value = &otlpcommon.AnyValue_IntValue{IntValue: iv} } @@ -271,6 +285,7 @@ func (v Value) SetInt(iv int64) { // it also changes the type to be ValueTypeDouble. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetDouble(dv float64) { + v.getState().AssertMutable() v.getOrig().Value = &otlpcommon.AnyValue_DoubleValue{DoubleValue: dv} } @@ -278,35 +293,40 @@ func (v Value) SetDouble(dv float64) { // it also changes the type to be ValueTypeBool. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetBool(bv bool) { + v.getState().AssertMutable() v.getOrig().Value = &otlpcommon.AnyValue_BoolValue{BoolValue: bv} } // SetEmptyBytes sets value to an empty byte slice and returns it. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetEmptyBytes() ByteSlice { + v.getState().AssertMutable() bv := otlpcommon.AnyValue_BytesValue{BytesValue: nil} v.getOrig().Value = &bv - return ByteSlice(internal.NewByteSlice(&bv.BytesValue)) + return ByteSlice(internal.NewByteSlice(&bv.BytesValue, v.getState())) } // SetEmptyMap sets value to an empty map and returns it. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetEmptyMap() Map { + v.getState().AssertMutable() kv := &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}} v.getOrig().Value = kv - return newMap(&kv.KvlistValue.Values) + return newMap(&kv.KvlistValue.Values, v.getState()) } // SetEmptySlice sets value to an empty slice and returns it. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetEmptySlice() Slice { + v.getState().AssertMutable() av := &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}} v.getOrig().Value = av - return newSlice(&av.ArrayValue.Values) + return newSlice(&av.ArrayValue.Values, v.getState()) } // CopyTo copies the Value instance overriding the destination. func (v Value) CopyTo(dest Value) { + dest.getState().AssertMutable() destOrig := dest.getOrig() switch ov := v.getOrig().Value.(type) { case *otlpcommon.AnyValue_KvlistValue: @@ -320,7 +340,7 @@ func (v Value) CopyTo(dest Value) { return } // Deep copy to dest. - newMap(&ov.KvlistValue.Values).CopyTo(newMap(&kv.KvlistValue.Values)) + newMap(&ov.KvlistValue.Values, v.getState()).CopyTo(newMap(&kv.KvlistValue.Values, dest.getState())) case *otlpcommon.AnyValue_ArrayValue: av, ok := destOrig.Value.(*otlpcommon.AnyValue_ArrayValue) if !ok { @@ -332,7 +352,7 @@ func (v Value) CopyTo(dest Value) { return } // Deep copy to dest. - newSlice(&ov.ArrayValue.Values).CopyTo(newSlice(&av.ArrayValue.Values)) + newSlice(&ov.ArrayValue.Values, v.getState()).CopyTo(newSlice(&av.ArrayValue.Values, dest.getState())) case *otlpcommon.AnyValue_BytesValue: bv, ok := destOrig.Value.(*otlpcommon.AnyValue_BytesValue) if !ok { @@ -438,28 +458,32 @@ func (v Value) AsRaw() any { func newKeyValueString(k string, v string) otlpcommon.KeyValue { orig := otlpcommon.KeyValue{Key: k} - akv := newValue(&orig.Value) + state := internal.StateMutable + akv := newValue(&orig.Value, &state) akv.SetStr(v) return orig } func newKeyValueInt(k string, v int64) otlpcommon.KeyValue { orig := otlpcommon.KeyValue{Key: k} - akv := newValue(&orig.Value) + state := internal.StateMutable + akv := newValue(&orig.Value, &state) akv.SetInt(v) return orig } func newKeyValueDouble(k string, v float64) otlpcommon.KeyValue { orig := otlpcommon.KeyValue{Key: k} - akv := newValue(&orig.Value) + state := internal.StateMutable + akv := newValue(&orig.Value, &state) akv.SetDouble(v) return orig } func newKeyValueBool(k string, v bool) otlpcommon.KeyValue { orig := otlpcommon.KeyValue{Key: k} - akv := newValue(&orig.Value) + state := internal.StateMutable + akv := newValue(&orig.Value, &state) akv.SetBool(v) return orig } diff --git a/pdata/pcommon/value_test.go b/pdata/pcommon/value_test.go index 1a4ed8fea4d..9d2e5f439ee 100644 --- a/pdata/pcommon/value_test.go +++ b/pdata/pcommon/value_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/pdata/internal" otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1" ) @@ -44,6 +45,36 @@ func TestValue(t *testing.T) { assert.EqualValues(t, ValueTypeSlice, v.Type()) } +func TestValueReadOnly(t *testing.T) { + state := internal.StateReadOnly + v := newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: "v"}}, &state) + + assert.EqualValues(t, ValueTypeStr, v.Type()) + assert.EqualValues(t, "v", v.Str()) + assert.EqualValues(t, 0, v.Int()) + assert.EqualValues(t, 0, v.Double()) + assert.False(t, v.Bool()) + assert.EqualValues(t, ByteSlice{}, v.Bytes()) + assert.EqualValues(t, Map{}, v.Map()) + assert.EqualValues(t, Slice{}, v.Slice()) + + assert.EqualValues(t, "v", v.AsString()) + + assert.Panics(t, func() { v.SetStr("abc") }) + assert.Panics(t, func() { v.SetInt(123) }) + assert.Panics(t, func() { v.SetDouble(3.4) }) + assert.Panics(t, func() { v.SetBool(true) }) + assert.Panics(t, func() { v.SetEmptyBytes() }) + assert.Panics(t, func() { v.SetEmptyMap() }) + assert.Panics(t, func() { v.SetEmptySlice() }) + + v2 := NewValueEmpty() + v.CopyTo(v2) + assert.Equal(t, v.AsRaw(), v2.AsRaw()) + assert.Panics(t, func() { v2.CopyTo(v) }) + +} + func TestValueType(t *testing.T) { assert.EqualValues(t, "Empty", ValueTypeEmpty.String()) assert.EqualValues(t, "Str", ValueTypeStr.String()) @@ -128,7 +159,8 @@ func TestValueMap(t *testing.T) { // Test nil KvlistValue case for Map() func. orig := &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: nil}} - m1 = newValue(orig) + state := internal.StateMutable + m1 = newValue(orig, &state) assert.EqualValues(t, Map{}, m1.Map()) } @@ -165,8 +197,9 @@ func TestValueSlice(t *testing.T) { assert.EqualValues(t, "somestr", v.Str()) // Test nil values case for Slice() func. - a1 = newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: nil}}) - assert.EqualValues(t, newSlice(nil), a1.Slice()) + state := internal.StateMutable + a1 = newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: nil}}, &state) + assert.EqualValues(t, newSlice(nil, nil), a1.Slice()) } func TestNilOrigSetValue(t *testing.T) { @@ -200,26 +233,28 @@ func TestNilOrigSetValue(t *testing.T) { } func TestValue_CopyTo(t *testing.T) { + state := internal.StateMutable + // Test nil KvlistValue case for Map() func. dest := NewValueEmpty() orig := &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: nil}} - newValue(orig).CopyTo(dest) + newValue(orig, &state).CopyTo(dest) assert.Nil(t, dest.getOrig().Value.(*otlpcommon.AnyValue_KvlistValue).KvlistValue) // Test nil ArrayValue case for Slice() func. dest = NewValueEmpty() orig = &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: nil}} - newValue(orig).CopyTo(dest) + newValue(orig, &state).CopyTo(dest) assert.Nil(t, dest.getOrig().Value.(*otlpcommon.AnyValue_ArrayValue).ArrayValue) // Test copy empty value. orig = &otlpcommon.AnyValue{} - newValue(orig).CopyTo(dest) + newValue(orig, &state).CopyTo(dest) assert.Nil(t, dest.getOrig().Value) av := NewValueEmpty() destVal := otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_IntValue{}} - av.CopyTo(newValue(&destVal)) + av.CopyTo(newValue(&destVal, &state)) assert.EqualValues(t, nil, destVal.Value) } @@ -228,7 +263,8 @@ func TestSliceWithNilValues(t *testing.T) { {}, {Value: &otlpcommon.AnyValue_StringValue{StringValue: "test_value"}}, } - sm := newSlice(&origWithNil) + state := internal.StateMutable + sm := newSlice(&origWithNil, &state) val := sm.At(0) assert.EqualValues(t, ValueTypeEmpty, val.Type()) diff --git a/pdata/plog/generated_logrecord.go b/pdata/plog/generated_logrecord.go index a20f3027b0b..5e9984a244c 100644 --- a/pdata/plog/generated_logrecord.go +++ b/pdata/plog/generated_logrecord.go @@ -21,11 +21,12 @@ import ( // Must use NewLogRecord function to create new instances. // Important: zero-initialized instance is not valid for use. type LogRecord struct { - orig *otlplogs.LogRecord + orig *otlplogs.LogRecord + state *internal.State } -func newLogRecord(orig *otlplogs.LogRecord) LogRecord { - return LogRecord{orig} +func newLogRecord(orig *otlplogs.LogRecord, state *internal.State) LogRecord { + return LogRecord{orig: orig, state: state} } // NewLogRecord creates a new empty LogRecord. @@ -33,12 +34,15 @@ func newLogRecord(orig *otlplogs.LogRecord) LogRecord { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewLogRecord() LogRecord { - return newLogRecord(&otlplogs.LogRecord{}) + state := internal.StateMutable + return newLogRecord(&otlplogs.LogRecord{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms LogRecord) MoveTo(dest LogRecord) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlplogs.LogRecord{} } @@ -50,6 +54,7 @@ func (ms LogRecord) ObservedTimestamp() pcommon.Timestamp { // SetObservedTimestamp replaces the observedtimestamp associated with this LogRecord. func (ms LogRecord) SetObservedTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.ObservedTimeUnixNano = uint64(v) } @@ -60,6 +65,7 @@ func (ms LogRecord) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this LogRecord. func (ms LogRecord) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -70,6 +76,7 @@ func (ms LogRecord) TraceID() pcommon.TraceID { // SetTraceID replaces the traceid associated with this LogRecord. func (ms LogRecord) SetTraceID(v pcommon.TraceID) { + ms.state.AssertMutable() ms.orig.TraceId = data.TraceID(v) } @@ -80,6 +87,7 @@ func (ms LogRecord) SpanID() pcommon.SpanID { // SetSpanID replaces the spanid associated with this LogRecord. func (ms LogRecord) SetSpanID(v pcommon.SpanID) { + ms.state.AssertMutable() ms.orig.SpanId = data.SpanID(v) } @@ -90,6 +98,7 @@ func (ms LogRecord) Flags() LogRecordFlags { // SetFlags replaces the flags associated with this LogRecord. func (ms LogRecord) SetFlags(v LogRecordFlags) { + ms.state.AssertMutable() ms.orig.Flags = uint32(v) } @@ -100,6 +109,7 @@ func (ms LogRecord) SeverityText() string { // SetSeverityText replaces the severitytext associated with this LogRecord. func (ms LogRecord) SetSeverityText(v string) { + ms.state.AssertMutable() ms.orig.SeverityText = v } @@ -110,17 +120,18 @@ func (ms LogRecord) SeverityNumber() SeverityNumber { // SetSeverityNumber replaces the severitynumber associated with this LogRecord. func (ms LogRecord) SetSeverityNumber(v SeverityNumber) { + ms.state.AssertMutable() ms.orig.SeverityNumber = otlplogs.SeverityNumber(v) } // Body returns the body associated with this LogRecord. func (ms LogRecord) Body() pcommon.Value { - return pcommon.Value(internal.NewValue(&ms.orig.Body)) + return pcommon.Value(internal.NewValue(&ms.orig.Body, ms.state)) } // Attributes returns the Attributes associated with this LogRecord. func (ms LogRecord) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this LogRecord. @@ -130,11 +141,13 @@ func (ms LogRecord) DroppedAttributesCount() uint32 { // SetDroppedAttributesCount replaces the droppedattributescount associated with this LogRecord. func (ms LogRecord) SetDroppedAttributesCount(v uint32) { + ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms LogRecord) CopyTo(dest LogRecord) { + dest.state.AssertMutable() dest.SetObservedTimestamp(ms.ObservedTimestamp()) dest.SetTimestamp(ms.Timestamp()) dest.SetTraceID(ms.TraceID()) diff --git a/pdata/plog/generated_logrecord_test.go b/pdata/plog/generated_logrecord_test.go index 9ff261d1044..81447572ac3 100644 --- a/pdata/plog/generated_logrecord_test.go +++ b/pdata/plog/generated_logrecord_test.go @@ -23,6 +23,9 @@ func TestLogRecord_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewLogRecord(), ms) assert.Equal(t, generateTestLogRecord(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newLogRecord(&otlplogs.LogRecord{}, &sharedState)) }) + assert.Panics(t, func() { newLogRecord(&otlplogs.LogRecord{}, &sharedState).MoveTo(dest) }) } func TestLogRecord_CopyTo(t *testing.T) { @@ -33,6 +36,8 @@ func TestLogRecord_CopyTo(t *testing.T) { orig = generateTestLogRecord() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newLogRecord(&otlplogs.LogRecord{}, &sharedState)) }) } func TestLogRecord_ObservedTimestamp(t *testing.T) { @@ -80,6 +85,8 @@ func TestLogRecord_SeverityText(t *testing.T) { assert.Equal(t, "", ms.SeverityText()) ms.SetSeverityText("INFO") assert.Equal(t, "INFO", ms.SeverityText()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newLogRecord(&otlplogs.LogRecord{}, &sharedState).SetSeverityText("INFO") }) } func TestLogRecord_SeverityNumber(t *testing.T) { @@ -108,6 +115,8 @@ func TestLogRecord_DroppedAttributesCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedAttributesCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newLogRecord(&otlplogs.LogRecord{}, &sharedState).SetDroppedAttributesCount(uint32(17)) }) } func generateTestLogRecord() LogRecord { @@ -124,7 +133,7 @@ func fillTestLogRecord(tv LogRecord) { tv.orig.Flags = 1 tv.orig.SeverityText = "INFO" tv.orig.SeverityNumber = otlplogs.SeverityNumber(5) - internal.FillTestValue(internal.NewValue(&tv.orig.Body)) - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestValue(internal.NewValue(&tv.orig.Body, tv.state)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.DroppedAttributesCount = uint32(17) } diff --git a/pdata/plog/generated_logrecordslice.go b/pdata/plog/generated_logrecordslice.go index 6c564822d6e..e177d1af788 100644 --- a/pdata/plog/generated_logrecordslice.go +++ b/pdata/plog/generated_logrecordslice.go @@ -9,6 +9,7 @@ package plog import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewLogRecordSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type LogRecordSlice struct { - orig *[]*otlplogs.LogRecord + orig *[]*otlplogs.LogRecord + state *internal.State } -func newLogRecordSlice(orig *[]*otlplogs.LogRecord) LogRecordSlice { - return LogRecordSlice{orig} +func newLogRecordSlice(orig *[]*otlplogs.LogRecord, state *internal.State) LogRecordSlice { + return LogRecordSlice{orig: orig, state: state} } // NewLogRecordSlice creates a LogRecordSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewLogRecordSlice() LogRecordSlice { orig := []*otlplogs.LogRecord(nil) - return newLogRecordSlice(&orig) + state := internal.StateMutable + return newLogRecordSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es LogRecordSlice) Len() int { // ... // Do something with the element // } func (es LogRecordSlice) At(i int) LogRecord { - return newLogRecord((*es.orig)[i]) + return newLogRecord((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es LogRecordSlice) At(i int) LogRecord { // // Here should set all the values for e. // } func (es LogRecordSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es LogRecordSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty LogRecord. // It returns the newly added LogRecord. func (es LogRecordSlice) AppendEmpty() LogRecord { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlplogs.LogRecord{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es LogRecordSlice) AppendEmpty() LogRecord { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es LogRecordSlice) MoveAndAppendTo(dest LogRecordSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es LogRecordSlice) MoveAndAppendTo(dest LogRecordSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es LogRecordSlice) RemoveIf(f func(LogRecord) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es LogRecordSlice) RemoveIf(f func(LogRecord) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es LogRecordSlice) CopyTo(dest LogRecordSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newLogRecord((*es.orig)[i]).CopyTo(newLogRecord((*dest.orig)[i])) + newLogRecord((*es.orig)[i], es.state).CopyTo(newLogRecord((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es LogRecordSlice) CopyTo(dest LogRecordSlice) { wrappers := make([]*otlplogs.LogRecord, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newLogRecord((*es.orig)[i]).CopyTo(newLogRecord(wrappers[i])) + newLogRecord((*es.orig)[i], es.state).CopyTo(newLogRecord(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es LogRecordSlice) CopyTo(dest LogRecordSlice) { // provided less function so that two instances of LogRecordSlice // can be compared. func (es LogRecordSlice) Sort(less func(a, b LogRecord) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/plog/generated_logrecordslice_test.go b/pdata/plog/generated_logrecordslice_test.go index 183b88601b2..ff47a245987 100644 --- a/pdata/plog/generated_logrecordslice_test.go +++ b/pdata/plog/generated_logrecordslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" ) func TestLogRecordSlice(t *testing.T) { es := NewLogRecordSlice() assert.Equal(t, 0, es.Len()) - es = newLogRecordSlice(&[]*otlplogs.LogRecord{}) + state := internal.StateMutable + es = newLogRecordSlice(&[]*otlplogs.LogRecord{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewLogRecord() @@ -32,6 +34,19 @@ func TestLogRecordSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestLogRecordSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newLogRecordSlice(&[]*otlplogs.LogRecord{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewLogRecordSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestLogRecordSlice_CopyTo(t *testing.T) { dest := NewLogRecordSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestLogRecordSlice(es LogRecordSlice) { *es.orig = make([]*otlplogs.LogRecord, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlplogs.LogRecord{} - fillTestLogRecord(newLogRecord((*es.orig)[i])) + fillTestLogRecord(newLogRecord((*es.orig)[i], es.state)) } } diff --git a/pdata/plog/generated_resourcelogs.go b/pdata/plog/generated_resourcelogs.go index 870d53a6373..1d240e03975 100644 --- a/pdata/plog/generated_resourcelogs.go +++ b/pdata/plog/generated_resourcelogs.go @@ -20,11 +20,12 @@ import ( // Must use NewResourceLogs function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceLogs struct { - orig *otlplogs.ResourceLogs + orig *otlplogs.ResourceLogs + state *internal.State } -func newResourceLogs(orig *otlplogs.ResourceLogs) ResourceLogs { - return ResourceLogs{orig} +func newResourceLogs(orig *otlplogs.ResourceLogs, state *internal.State) ResourceLogs { + return ResourceLogs{orig: orig, state: state} } // NewResourceLogs creates a new empty ResourceLogs. @@ -32,19 +33,22 @@ func newResourceLogs(orig *otlplogs.ResourceLogs) ResourceLogs { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceLogs() ResourceLogs { - return newResourceLogs(&otlplogs.ResourceLogs{}) + state := internal.StateMutable + return newResourceLogs(&otlplogs.ResourceLogs{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceLogs) MoveTo(dest ResourceLogs) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlplogs.ResourceLogs{} } // Resource returns the resource associated with this ResourceLogs. func (ms ResourceLogs) Resource() pcommon.Resource { - return pcommon.Resource(internal.NewResource(&ms.orig.Resource)) + return pcommon.Resource(internal.NewResource(&ms.orig.Resource, ms.state)) } // SchemaUrl returns the schemaurl associated with this ResourceLogs. @@ -54,16 +58,18 @@ func (ms ResourceLogs) SchemaUrl() string { // SetSchemaUrl replaces the schemaurl associated with this ResourceLogs. func (ms ResourceLogs) SetSchemaUrl(v string) { + ms.state.AssertMutable() ms.orig.SchemaUrl = v } // ScopeLogs returns the ScopeLogs associated with this ResourceLogs. func (ms ResourceLogs) ScopeLogs() ScopeLogsSlice { - return newScopeLogsSlice(&ms.orig.ScopeLogs) + return newScopeLogsSlice(&ms.orig.ScopeLogs, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceLogs) CopyTo(dest ResourceLogs) { + dest.state.AssertMutable() ms.Resource().CopyTo(dest.Resource()) dest.SetSchemaUrl(ms.SchemaUrl()) ms.ScopeLogs().CopyTo(dest.ScopeLogs()) diff --git a/pdata/plog/generated_resourcelogs_test.go b/pdata/plog/generated_resourcelogs_test.go index c0c051ba292..8f705a26816 100644 --- a/pdata/plog/generated_resourcelogs_test.go +++ b/pdata/plog/generated_resourcelogs_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestResourceLogs_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewResourceLogs(), ms) assert.Equal(t, generateTestResourceLogs(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newResourceLogs(&otlplogs.ResourceLogs{}, &sharedState)) }) + assert.Panics(t, func() { newResourceLogs(&otlplogs.ResourceLogs{}, &sharedState).MoveTo(dest) }) } func TestResourceLogs_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestResourceLogs_CopyTo(t *testing.T) { orig = generateTestResourceLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newResourceLogs(&otlplogs.ResourceLogs{}, &sharedState)) }) } func TestResourceLogs_Resource(t *testing.T) { @@ -44,6 +50,10 @@ func TestResourceLogs_SchemaUrl(t *testing.T) { assert.Equal(t, "", ms.SchemaUrl()) ms.SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.5.0", ms.SchemaUrl()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newResourceLogs(&otlplogs.ResourceLogs{}, &sharedState).SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") + }) } func TestResourceLogs_ScopeLogs(t *testing.T) { @@ -60,7 +70,7 @@ func generateTestResourceLogs() ResourceLogs { } func fillTestResourceLogs(tv ResourceLogs) { - internal.FillTestResource(internal.NewResource(&tv.orig.Resource)) + internal.FillTestResource(internal.NewResource(&tv.orig.Resource, tv.state)) tv.orig.SchemaUrl = "https://opentelemetry.io/schemas/1.5.0" - fillTestScopeLogsSlice(newScopeLogsSlice(&tv.orig.ScopeLogs)) + fillTestScopeLogsSlice(newScopeLogsSlice(&tv.orig.ScopeLogs, tv.state)) } diff --git a/pdata/plog/generated_resourcelogsslice.go b/pdata/plog/generated_resourcelogsslice.go index 19bd2e58ddc..4f1680a0f6a 100644 --- a/pdata/plog/generated_resourcelogsslice.go +++ b/pdata/plog/generated_resourcelogsslice.go @@ -9,6 +9,7 @@ package plog import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewResourceLogsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceLogsSlice struct { - orig *[]*otlplogs.ResourceLogs + orig *[]*otlplogs.ResourceLogs + state *internal.State } -func newResourceLogsSlice(orig *[]*otlplogs.ResourceLogs) ResourceLogsSlice { - return ResourceLogsSlice{orig} +func newResourceLogsSlice(orig *[]*otlplogs.ResourceLogs, state *internal.State) ResourceLogsSlice { + return ResourceLogsSlice{orig: orig, state: state} } // NewResourceLogsSlice creates a ResourceLogsSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceLogsSlice() ResourceLogsSlice { orig := []*otlplogs.ResourceLogs(nil) - return newResourceLogsSlice(&orig) + state := internal.StateMutable + return newResourceLogsSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ResourceLogsSlice) Len() int { // ... // Do something with the element // } func (es ResourceLogsSlice) At(i int) ResourceLogs { - return newResourceLogs((*es.orig)[i]) + return newResourceLogs((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ResourceLogsSlice) At(i int) ResourceLogs { // // Here should set all the values for e. // } func (es ResourceLogsSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ResourceLogsSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ResourceLogs. // It returns the newly added ResourceLogs. func (es ResourceLogsSlice) AppendEmpty() ResourceLogs { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlplogs.ResourceLogs{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ResourceLogsSlice) AppendEmpty() ResourceLogs { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceLogsSlice) MoveAndAppendTo(dest ResourceLogsSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ResourceLogsSlice) MoveAndAppendTo(dest ResourceLogsSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceLogsSlice) RemoveIf(f func(ResourceLogs) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ResourceLogsSlice) RemoveIf(f func(ResourceLogs) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceLogsSlice) CopyTo(dest ResourceLogsSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newResourceLogs((*es.orig)[i]).CopyTo(newResourceLogs((*dest.orig)[i])) + newResourceLogs((*es.orig)[i], es.state).CopyTo(newResourceLogs((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ResourceLogsSlice) CopyTo(dest ResourceLogsSlice) { wrappers := make([]*otlplogs.ResourceLogs, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newResourceLogs((*es.orig)[i]).CopyTo(newResourceLogs(wrappers[i])) + newResourceLogs((*es.orig)[i], es.state).CopyTo(newResourceLogs(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ResourceLogsSlice) CopyTo(dest ResourceLogsSlice) { // provided less function so that two instances of ResourceLogsSlice // can be compared. func (es ResourceLogsSlice) Sort(less func(a, b ResourceLogs) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/plog/generated_resourcelogsslice_test.go b/pdata/plog/generated_resourcelogsslice_test.go index 3c4d2ba81fc..993a597f119 100644 --- a/pdata/plog/generated_resourcelogsslice_test.go +++ b/pdata/plog/generated_resourcelogsslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" ) func TestResourceLogsSlice(t *testing.T) { es := NewResourceLogsSlice() assert.Equal(t, 0, es.Len()) - es = newResourceLogsSlice(&[]*otlplogs.ResourceLogs{}) + state := internal.StateMutable + es = newResourceLogsSlice(&[]*otlplogs.ResourceLogs{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceLogs() @@ -32,6 +34,19 @@ func TestResourceLogsSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestResourceLogsSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newResourceLogsSlice(&[]*otlplogs.ResourceLogs{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewResourceLogsSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestResourceLogsSlice_CopyTo(t *testing.T) { dest := NewResourceLogsSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestResourceLogsSlice(es ResourceLogsSlice) { *es.orig = make([]*otlplogs.ResourceLogs, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlplogs.ResourceLogs{} - fillTestResourceLogs(newResourceLogs((*es.orig)[i])) + fillTestResourceLogs(newResourceLogs((*es.orig)[i], es.state)) } } diff --git a/pdata/plog/generated_scopelogs.go b/pdata/plog/generated_scopelogs.go index c4d399103b2..6e45a9627f8 100644 --- a/pdata/plog/generated_scopelogs.go +++ b/pdata/plog/generated_scopelogs.go @@ -20,11 +20,12 @@ import ( // Must use NewScopeLogs function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeLogs struct { - orig *otlplogs.ScopeLogs + orig *otlplogs.ScopeLogs + state *internal.State } -func newScopeLogs(orig *otlplogs.ScopeLogs) ScopeLogs { - return ScopeLogs{orig} +func newScopeLogs(orig *otlplogs.ScopeLogs, state *internal.State) ScopeLogs { + return ScopeLogs{orig: orig, state: state} } // NewScopeLogs creates a new empty ScopeLogs. @@ -32,19 +33,22 @@ func newScopeLogs(orig *otlplogs.ScopeLogs) ScopeLogs { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeLogs() ScopeLogs { - return newScopeLogs(&otlplogs.ScopeLogs{}) + state := internal.StateMutable + return newScopeLogs(&otlplogs.ScopeLogs{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeLogs) MoveTo(dest ScopeLogs) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlplogs.ScopeLogs{} } // Scope returns the scope associated with this ScopeLogs. func (ms ScopeLogs) Scope() pcommon.InstrumentationScope { - return pcommon.InstrumentationScope(internal.NewInstrumentationScope(&ms.orig.Scope)) + return pcommon.InstrumentationScope(internal.NewInstrumentationScope(&ms.orig.Scope, ms.state)) } // SchemaUrl returns the schemaurl associated with this ScopeLogs. @@ -54,16 +58,18 @@ func (ms ScopeLogs) SchemaUrl() string { // SetSchemaUrl replaces the schemaurl associated with this ScopeLogs. func (ms ScopeLogs) SetSchemaUrl(v string) { + ms.state.AssertMutable() ms.orig.SchemaUrl = v } // LogRecords returns the LogRecords associated with this ScopeLogs. func (ms ScopeLogs) LogRecords() LogRecordSlice { - return newLogRecordSlice(&ms.orig.LogRecords) + return newLogRecordSlice(&ms.orig.LogRecords, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeLogs) CopyTo(dest ScopeLogs) { + dest.state.AssertMutable() ms.Scope().CopyTo(dest.Scope()) dest.SetSchemaUrl(ms.SchemaUrl()) ms.LogRecords().CopyTo(dest.LogRecords()) diff --git a/pdata/plog/generated_scopelogs_test.go b/pdata/plog/generated_scopelogs_test.go index 5b58c00dd80..181513ffa59 100644 --- a/pdata/plog/generated_scopelogs_test.go +++ b/pdata/plog/generated_scopelogs_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestScopeLogs_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewScopeLogs(), ms) assert.Equal(t, generateTestScopeLogs(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newScopeLogs(&otlplogs.ScopeLogs{}, &sharedState)) }) + assert.Panics(t, func() { newScopeLogs(&otlplogs.ScopeLogs{}, &sharedState).MoveTo(dest) }) } func TestScopeLogs_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestScopeLogs_CopyTo(t *testing.T) { orig = generateTestScopeLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newScopeLogs(&otlplogs.ScopeLogs{}, &sharedState)) }) } func TestScopeLogs_Scope(t *testing.T) { @@ -44,6 +50,10 @@ func TestScopeLogs_SchemaUrl(t *testing.T) { assert.Equal(t, "", ms.SchemaUrl()) ms.SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.5.0", ms.SchemaUrl()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newScopeLogs(&otlplogs.ScopeLogs{}, &sharedState).SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") + }) } func TestScopeLogs_LogRecords(t *testing.T) { @@ -60,7 +70,7 @@ func generateTestScopeLogs() ScopeLogs { } func fillTestScopeLogs(tv ScopeLogs) { - internal.FillTestInstrumentationScope(internal.NewInstrumentationScope(&tv.orig.Scope)) + internal.FillTestInstrumentationScope(internal.NewInstrumentationScope(&tv.orig.Scope, tv.state)) tv.orig.SchemaUrl = "https://opentelemetry.io/schemas/1.5.0" - fillTestLogRecordSlice(newLogRecordSlice(&tv.orig.LogRecords)) + fillTestLogRecordSlice(newLogRecordSlice(&tv.orig.LogRecords, tv.state)) } diff --git a/pdata/plog/generated_scopelogsslice.go b/pdata/plog/generated_scopelogsslice.go index be34e05f135..6ab9ec5212b 100644 --- a/pdata/plog/generated_scopelogsslice.go +++ b/pdata/plog/generated_scopelogsslice.go @@ -9,6 +9,7 @@ package plog import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewScopeLogsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeLogsSlice struct { - orig *[]*otlplogs.ScopeLogs + orig *[]*otlplogs.ScopeLogs + state *internal.State } -func newScopeLogsSlice(orig *[]*otlplogs.ScopeLogs) ScopeLogsSlice { - return ScopeLogsSlice{orig} +func newScopeLogsSlice(orig *[]*otlplogs.ScopeLogs, state *internal.State) ScopeLogsSlice { + return ScopeLogsSlice{orig: orig, state: state} } // NewScopeLogsSlice creates a ScopeLogsSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeLogsSlice() ScopeLogsSlice { orig := []*otlplogs.ScopeLogs(nil) - return newScopeLogsSlice(&orig) + state := internal.StateMutable + return newScopeLogsSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ScopeLogsSlice) Len() int { // ... // Do something with the element // } func (es ScopeLogsSlice) At(i int) ScopeLogs { - return newScopeLogs((*es.orig)[i]) + return newScopeLogs((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ScopeLogsSlice) At(i int) ScopeLogs { // // Here should set all the values for e. // } func (es ScopeLogsSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ScopeLogsSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ScopeLogs. // It returns the newly added ScopeLogs. func (es ScopeLogsSlice) AppendEmpty() ScopeLogs { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlplogs.ScopeLogs{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ScopeLogsSlice) AppendEmpty() ScopeLogs { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeLogsSlice) MoveAndAppendTo(dest ScopeLogsSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ScopeLogsSlice) MoveAndAppendTo(dest ScopeLogsSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeLogsSlice) RemoveIf(f func(ScopeLogs) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ScopeLogsSlice) RemoveIf(f func(ScopeLogs) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeLogsSlice) CopyTo(dest ScopeLogsSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newScopeLogs((*es.orig)[i]).CopyTo(newScopeLogs((*dest.orig)[i])) + newScopeLogs((*es.orig)[i], es.state).CopyTo(newScopeLogs((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ScopeLogsSlice) CopyTo(dest ScopeLogsSlice) { wrappers := make([]*otlplogs.ScopeLogs, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newScopeLogs((*es.orig)[i]).CopyTo(newScopeLogs(wrappers[i])) + newScopeLogs((*es.orig)[i], es.state).CopyTo(newScopeLogs(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ScopeLogsSlice) CopyTo(dest ScopeLogsSlice) { // provided less function so that two instances of ScopeLogsSlice // can be compared. func (es ScopeLogsSlice) Sort(less func(a, b ScopeLogs) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/plog/generated_scopelogsslice_test.go b/pdata/plog/generated_scopelogsslice_test.go index a18b1e9e34c..12678c7b4fc 100644 --- a/pdata/plog/generated_scopelogsslice_test.go +++ b/pdata/plog/generated_scopelogsslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" ) func TestScopeLogsSlice(t *testing.T) { es := NewScopeLogsSlice() assert.Equal(t, 0, es.Len()) - es = newScopeLogsSlice(&[]*otlplogs.ScopeLogs{}) + state := internal.StateMutable + es = newScopeLogsSlice(&[]*otlplogs.ScopeLogs{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeLogs() @@ -32,6 +34,19 @@ func TestScopeLogsSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestScopeLogsSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newScopeLogsSlice(&[]*otlplogs.ScopeLogs{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewScopeLogsSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestScopeLogsSlice_CopyTo(t *testing.T) { dest := NewScopeLogsSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestScopeLogsSlice(es ScopeLogsSlice) { *es.orig = make([]*otlplogs.ScopeLogs, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlplogs.ScopeLogs{} - fillTestScopeLogs(newScopeLogs((*es.orig)[i])) + fillTestScopeLogs(newScopeLogs((*es.orig)[i], es.state)) } } diff --git a/pdata/plog/logs.go b/pdata/plog/logs.go index f637077ddb4..a6187fbc0f6 100644 --- a/pdata/plog/logs.go +++ b/pdata/plog/logs.go @@ -13,7 +13,8 @@ import ( type Logs internal.Logs func newLogs(orig *otlpcollectorlog.ExportLogsServiceRequest) Logs { - return Logs(internal.NewLogs(orig)) + state := internal.StateMutable + return Logs(internal.NewLogs(orig, &state)) } func (ms Logs) getOrig() *otlpcollectorlog.ExportLogsServiceRequest { @@ -47,5 +48,10 @@ func (ms Logs) LogRecordCount() int { // ResourceLogs returns the ResourceLogsSlice associated with this Logs. func (ms Logs) ResourceLogs() ResourceLogsSlice { - return newResourceLogsSlice(&ms.getOrig().ResourceLogs) + return newResourceLogsSlice(&ms.getOrig().ResourceLogs, internal.GetLogsState(internal.Logs(ms))) +} + +// MarkReadOnly marks the Logs as shared so that no further modifications can be done on it. +func (ms Logs) MarkReadOnly() { + internal.SetLogsState(internal.Logs(ms), internal.StateReadOnly) } diff --git a/pdata/plog/logs_test.go b/pdata/plog/logs_test.go index f2ec1bb78b1..6eeefcf509c 100644 --- a/pdata/plog/logs_test.go +++ b/pdata/plog/logs_test.go @@ -5,6 +5,7 @@ package plog import ( "testing" + "time" gogoproto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" @@ -13,6 +14,7 @@ import ( otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1" otlplogs "go.opentelemetry.io/collector/pdata/internal/data/protogen/logs/v1" + "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLogRecordCount(t *testing.T) { @@ -112,3 +114,58 @@ func TestLogsCopyTo(t *testing.T) { logs.CopyTo(logsCopy) assert.EqualValues(t, logs, logsCopy) } + +func TestReadOnlyLogsInvalidUsage(t *testing.T) { + logs := NewLogs() + res := logs.ResourceLogs().AppendEmpty().Resource() + res.Attributes().PutStr("k1", "v1") + logs.MarkReadOnly() + assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) +} + +func BenchmarkLogsUsage(b *testing.B) { + logs := NewLogs() + fillTestResourceLogsSlice(logs.ResourceLogs()) + + ts := pcommon.NewTimestampFromTime(time.Now()) + + b.ReportAllocs() + b.ResetTimer() + + for bb := 0; bb < b.N; bb++ { + for i := 0; i < logs.ResourceLogs().Len(); i++ { + rl := logs.ResourceLogs().At(i) + res := rl.Resource() + res.Attributes().PutStr("foo", "bar") + v, ok := res.Attributes().Get("foo") + assert.True(b, ok) + assert.Equal(b, "bar", v.Str()) + v.SetStr("new-bar") + assert.Equal(b, "new-bar", v.Str()) + res.Attributes().Remove("foo") + for j := 0; j < rl.ScopeLogs().Len(); j++ { + sl := rl.ScopeLogs().At(j) + sl.Scope().SetName("new_test_name") + assert.Equal(b, "new_test_name", sl.Scope().Name()) + for k := 0; k < sl.LogRecords().Len(); k++ { + lr := sl.LogRecords().At(k) + lr.Body().SetStr("new_body") + assert.Equal(b, "new_body", lr.Body().Str()) + lr.SetTimestamp(ts) + assert.Equal(b, ts, lr.Timestamp()) + } + lr := sl.LogRecords().AppendEmpty() + lr.Body().SetStr("another_log_record") + lr.SetTimestamp(ts) + lr.SetObservedTimestamp(ts) + lr.SetSeverityText("info") + lr.SetSeverityNumber(SeverityNumberInfo) + lr.Attributes().PutStr("foo", "bar") + lr.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) + sl.LogRecords().RemoveIf(func(lr LogRecord) bool { + return lr.Body().Str() == "another_log_record" + }) + } + } + } +} diff --git a/pdata/plog/plogotlp/generated_exportpartialsuccess.go b/pdata/plog/plogotlp/generated_exportpartialsuccess.go index 5ab21e08897..bcf420c9120 100644 --- a/pdata/plog/plogotlp/generated_exportpartialsuccess.go +++ b/pdata/plog/plogotlp/generated_exportpartialsuccess.go @@ -7,6 +7,7 @@ package plogotlp import ( + "go.opentelemetry.io/collector/pdata/internal" otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { - orig *otlpcollectorlog.ExportLogsPartialSuccess + orig *otlpcollectorlog.ExportLogsPartialSuccess + state *internal.State } -func newExportPartialSuccess(orig *otlpcollectorlog.ExportLogsPartialSuccess) ExportPartialSuccess { - return ExportPartialSuccess{orig} +func newExportPartialSuccess(orig *otlpcollectorlog.ExportLogsPartialSuccess, state *internal.State) ExportPartialSuccess { + return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. @@ -30,12 +32,15 @@ func newExportPartialSuccess(orig *otlpcollectorlog.ExportLogsPartialSuccess) Ex // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { - return newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}) + state := internal.StateMutable + return newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpcollectorlog.ExportLogsPartialSuccess{} } @@ -47,6 +52,7 @@ func (ms ExportPartialSuccess) RejectedLogRecords() int64 { // SetRejectedLogRecords replaces the rejectedlogrecords associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedLogRecords(v int64) { + ms.state.AssertMutable() ms.orig.RejectedLogRecords = v } @@ -57,11 +63,13 @@ func (ms ExportPartialSuccess) ErrorMessage() string { // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { + ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { + dest.state.AssertMutable() dest.SetRejectedLogRecords(ms.RejectedLogRecords()) dest.SetErrorMessage(ms.ErrorMessage()) } diff --git a/pdata/plog/plogotlp/generated_exportpartialsuccess_test.go b/pdata/plog/plogotlp/generated_exportpartialsuccess_test.go index 9df7e89b7d3..9b0fee581a1 100644 --- a/pdata/plog/plogotlp/generated_exportpartialsuccess_test.go +++ b/pdata/plog/plogotlp/generated_exportpartialsuccess_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { @@ -18,6 +21,11 @@ func TestExportPartialSuccess_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}, &sharedState)) }) + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}, &sharedState).MoveTo(dest) + }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { @@ -28,6 +36,8 @@ func TestExportPartialSuccess_CopyTo(t *testing.T) { orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}, &sharedState)) }) } func TestExportPartialSuccess_RejectedLogRecords(t *testing.T) { @@ -35,6 +45,10 @@ func TestExportPartialSuccess_RejectedLogRecords(t *testing.T) { assert.Equal(t, int64(0), ms.RejectedLogRecords()) ms.SetRejectedLogRecords(int64(13)) assert.Equal(t, int64(13), ms.RejectedLogRecords()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}, &sharedState).SetRejectedLogRecords(int64(13)) + }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { @@ -42,6 +56,10 @@ func TestExportPartialSuccess_ErrorMessage(t *testing.T) { assert.Equal(t, "", ms.ErrorMessage()) ms.SetErrorMessage("error message") assert.Equal(t, "error message", ms.ErrorMessage()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectorlog.ExportLogsPartialSuccess{}, &sharedState).SetErrorMessage("error message") + }) } func generateTestExportPartialSuccess() ExportPartialSuccess { diff --git a/pdata/plog/plogotlp/grpc.go b/pdata/plog/plogotlp/grpc.go index 4a7e66cb852..35d9fd85fcd 100644 --- a/pdata/plog/plogotlp/grpc.go +++ b/pdata/plog/plogotlp/grpc.go @@ -10,6 +10,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "go.opentelemetry.io/collector/pdata/internal" otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1" "go.opentelemetry.io/collector/pdata/internal/otlp" ) @@ -39,7 +40,11 @@ type grpcClient struct { func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) - return ExportResponse{orig: rsp}, err + if err != nil { + return ExportResponse{}, err + } + state := internal.StateMutable + return ExportResponse{orig: rsp, state: &state}, err } func (c *grpcClient) unexported() {} @@ -79,6 +84,7 @@ type rawLogsServer struct { func (s rawLogsServer) Export(ctx context.Context, request *otlpcollectorlog.ExportLogsServiceRequest) (*otlpcollectorlog.ExportLogsServiceResponse, error) { otlp.MigrateLogs(request.ResourceLogs) - rsp, err := s.srv.Export(ctx, ExportRequest{orig: request}) + state := internal.StateMutable + rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: &state}) return rsp.orig, err } diff --git a/pdata/plog/plogotlp/request.go b/pdata/plog/plogotlp/request.go index 786d83b7c44..0401846ab2e 100644 --- a/pdata/plog/plogotlp/request.go +++ b/pdata/plog/plogotlp/request.go @@ -18,19 +18,27 @@ var jsonUnmarshaler = &plog.JSONUnmarshaler{} // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for plog.Logs data. type ExportRequest struct { - orig *otlpcollectorlog.ExportLogsServiceRequest + orig *otlpcollectorlog.ExportLogsServiceRequest + state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { - return ExportRequest{orig: &otlpcollectorlog.ExportLogsServiceRequest{}} + state := internal.StateMutable + return ExportRequest{ + orig: &otlpcollectorlog.ExportLogsServiceRequest{}, + state: &state, + } } // NewExportRequestFromLogs returns a ExportRequest from plog.Logs. // Because ExportRequest is a wrapper for plog.Logs, // any changes to the provided Logs struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromLogs(ld plog.Logs) ExportRequest { - return ExportRequest{orig: internal.GetOrigLogs(internal.Logs(ld))} + return ExportRequest{ + orig: internal.GetOrigLogs(internal.Logs(ld)), + state: internal.GetLogsState(internal.Logs(ld)), + } } // MarshalProto marshals ExportRequest into proto bytes. @@ -67,5 +75,5 @@ func (ms ExportRequest) UnmarshalJSON(data []byte) error { } func (ms ExportRequest) Logs() plog.Logs { - return plog.Logs(internal.NewLogs(ms.orig)) + return plog.Logs(internal.NewLogs(ms.orig, ms.state)) } diff --git a/pdata/plog/plogotlp/response.go b/pdata/plog/plogotlp/response.go index 439c2560ffa..3aa9a3856a9 100644 --- a/pdata/plog/plogotlp/response.go +++ b/pdata/plog/plogotlp/response.go @@ -8,18 +8,24 @@ import ( jsoniter "github.com/json-iterator/go" + "go.opentelemetry.io/collector/pdata/internal" otlpcollectorlog "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/logs/v1" "go.opentelemetry.io/collector/pdata/internal/json" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportResponse struct { - orig *otlpcollectorlog.ExportLogsServiceResponse + orig *otlpcollectorlog.ExportLogsServiceResponse + state *internal.State } // NewExportResponse returns an empty ExportResponse. func NewExportResponse() ExportResponse { - return ExportResponse{orig: &otlpcollectorlog.ExportLogsServiceResponse{}} + state := internal.StateMutable + return ExportResponse{ + orig: &otlpcollectorlog.ExportLogsServiceResponse{}, + state: &state, + } } // MarshalProto marshals ExportResponse into proto bytes. @@ -51,7 +57,7 @@ func (ms ExportResponse) UnmarshalJSON(data []byte) error { // PartialSuccess returns the ExportPartialSuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { - return newExportPartialSuccess(&ms.orig.PartialSuccess) + return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } func (ms ExportResponse) unmarshalJsoniter(iter *jsoniter.Iterator) { diff --git a/pdata/pmetric/generated_exemplar.go b/pdata/pmetric/generated_exemplar.go index 461ddb21056..9937a1b500f 100644 --- a/pdata/pmetric/generated_exemplar.go +++ b/pdata/pmetric/generated_exemplar.go @@ -24,11 +24,12 @@ import ( // Must use NewExemplar function to create new instances. // Important: zero-initialized instance is not valid for use. type Exemplar struct { - orig *otlpmetrics.Exemplar + orig *otlpmetrics.Exemplar + state *internal.State } -func newExemplar(orig *otlpmetrics.Exemplar) Exemplar { - return Exemplar{orig} +func newExemplar(orig *otlpmetrics.Exemplar, state *internal.State) Exemplar { + return Exemplar{orig: orig, state: state} } // NewExemplar creates a new empty Exemplar. @@ -36,12 +37,15 @@ func newExemplar(orig *otlpmetrics.Exemplar) Exemplar { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExemplar() Exemplar { - return newExemplar(&otlpmetrics.Exemplar{}) + state := internal.StateMutable + return newExemplar(&otlpmetrics.Exemplar{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Exemplar) MoveTo(dest Exemplar) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.Exemplar{} } @@ -53,6 +57,7 @@ func (ms Exemplar) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this Exemplar. func (ms Exemplar) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -75,6 +80,7 @@ func (ms Exemplar) DoubleValue() float64 { // SetDoubleValue replaces the double associated with this Exemplar. func (ms Exemplar) SetDoubleValue(v float64) { + ms.state.AssertMutable() ms.orig.Value = &otlpmetrics.Exemplar_AsDouble{ AsDouble: v, } @@ -87,6 +93,7 @@ func (ms Exemplar) IntValue() int64 { // SetIntValue replaces the int associated with this Exemplar. func (ms Exemplar) SetIntValue(v int64) { + ms.state.AssertMutable() ms.orig.Value = &otlpmetrics.Exemplar_AsInt{ AsInt: v, } @@ -94,7 +101,7 @@ func (ms Exemplar) SetIntValue(v int64) { // FilteredAttributes returns the FilteredAttributes associated with this Exemplar. func (ms Exemplar) FilteredAttributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.FilteredAttributes)) + return pcommon.Map(internal.NewMap(&ms.orig.FilteredAttributes, ms.state)) } // TraceID returns the traceid associated with this Exemplar. @@ -104,6 +111,7 @@ func (ms Exemplar) TraceID() pcommon.TraceID { // SetTraceID replaces the traceid associated with this Exemplar. func (ms Exemplar) SetTraceID(v pcommon.TraceID) { + ms.state.AssertMutable() ms.orig.TraceId = data.TraceID(v) } @@ -114,11 +122,13 @@ func (ms Exemplar) SpanID() pcommon.SpanID { // SetSpanID replaces the spanid associated with this Exemplar. func (ms Exemplar) SetSpanID(v pcommon.SpanID) { + ms.state.AssertMutable() ms.orig.SpanId = data.SpanID(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Exemplar) CopyTo(dest Exemplar) { + dest.state.AssertMutable() dest.SetTimestamp(ms.Timestamp()) switch ms.ValueType() { case ExemplarValueTypeDouble: diff --git a/pdata/pmetric/generated_exemplar_test.go b/pdata/pmetric/generated_exemplar_test.go index 5b9868a6752..b9f8ce27c81 100644 --- a/pdata/pmetric/generated_exemplar_test.go +++ b/pdata/pmetric/generated_exemplar_test.go @@ -23,6 +23,9 @@ func TestExemplar_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExemplar(), ms) assert.Equal(t, generateTestExemplar(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newExemplar(&otlpmetrics.Exemplar{}, &sharedState)) }) + assert.Panics(t, func() { newExemplar(&otlpmetrics.Exemplar{}, &sharedState).MoveTo(dest) }) } func TestExemplar_CopyTo(t *testing.T) { @@ -33,6 +36,8 @@ func TestExemplar_CopyTo(t *testing.T) { orig = generateTestExemplar() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newExemplar(&otlpmetrics.Exemplar{}, &sharedState)) }) } func TestExemplar_Timestamp(t *testing.T) { @@ -54,6 +59,8 @@ func TestExemplar_DoubleValue(t *testing.T) { ms.SetDoubleValue(float64(17.13)) assert.Equal(t, float64(17.13), ms.DoubleValue()) assert.Equal(t, ExemplarValueTypeDouble, ms.ValueType()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newExemplar(&otlpmetrics.Exemplar{}, &sharedState).SetDoubleValue(float64(17.13)) }) } func TestExemplar_IntValue(t *testing.T) { @@ -62,6 +69,8 @@ func TestExemplar_IntValue(t *testing.T) { ms.SetIntValue(int64(17)) assert.Equal(t, int64(17), ms.IntValue()) assert.Equal(t, ExemplarValueTypeInt, ms.ValueType()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newExemplar(&otlpmetrics.Exemplar{}, &sharedState).SetIntValue(int64(17)) }) } func TestExemplar_FilteredAttributes(t *testing.T) { @@ -96,7 +105,7 @@ func generateTestExemplar() Exemplar { func fillTestExemplar(tv Exemplar) { tv.orig.TimeUnixNano = 1234567890 tv.orig.Value = &otlpmetrics.Exemplar_AsInt{AsInt: int64(17)} - internal.FillTestMap(internal.NewMap(&tv.orig.FilteredAttributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.FilteredAttributes, tv.state)) tv.orig.TraceId = data.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) tv.orig.SpanId = data.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}) } diff --git a/pdata/pmetric/generated_exemplarslice.go b/pdata/pmetric/generated_exemplarslice.go index f39db94477b..733341c36b5 100644 --- a/pdata/pmetric/generated_exemplarslice.go +++ b/pdata/pmetric/generated_exemplarslice.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -18,18 +19,20 @@ import ( // Must use NewExemplarSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ExemplarSlice struct { - orig *[]otlpmetrics.Exemplar + orig *[]otlpmetrics.Exemplar + state *internal.State } -func newExemplarSlice(orig *[]otlpmetrics.Exemplar) ExemplarSlice { - return ExemplarSlice{orig} +func newExemplarSlice(orig *[]otlpmetrics.Exemplar, state *internal.State) ExemplarSlice { + return ExemplarSlice{orig: orig, state: state} } // NewExemplarSlice creates a ExemplarSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewExemplarSlice() ExemplarSlice { orig := []otlpmetrics.Exemplar(nil) - return newExemplarSlice(&orig) + state := internal.StateMutable + return newExemplarSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -48,7 +51,7 @@ func (es ExemplarSlice) Len() int { // ... // Do something with the element // } func (es ExemplarSlice) At(i int) Exemplar { - return newExemplar(&(*es.orig)[i]) + return newExemplar(&(*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -64,6 +67,7 @@ func (es ExemplarSlice) At(i int) Exemplar { // // Here should set all the values for e. // } func (es ExemplarSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -77,6 +81,7 @@ func (es ExemplarSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty Exemplar. // It returns the newly added Exemplar. func (es ExemplarSlice) AppendEmpty() Exemplar { + es.state.AssertMutable() *es.orig = append(*es.orig, otlpmetrics.Exemplar{}) return es.At(es.Len() - 1) } @@ -84,6 +89,8 @@ func (es ExemplarSlice) AppendEmpty() Exemplar { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ExemplarSlice) MoveAndAppendTo(dest ExemplarSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -96,6 +103,7 @@ func (es ExemplarSlice) MoveAndAppendTo(dest ExemplarSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ExemplarSlice) RemoveIf(f func(Exemplar) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -115,6 +123,7 @@ func (es ExemplarSlice) RemoveIf(f func(Exemplar) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ExemplarSlice) CopyTo(dest ExemplarSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { @@ -123,6 +132,6 @@ func (es ExemplarSlice) CopyTo(dest ExemplarSlice) { (*dest.orig) = make([]otlpmetrics.Exemplar, srcLen) } for i := range *es.orig { - newExemplar(&(*es.orig)[i]).CopyTo(newExemplar(&(*dest.orig)[i])) + newExemplar(&(*es.orig)[i], es.state).CopyTo(newExemplar(&(*dest.orig)[i], dest.state)) } } diff --git a/pdata/pmetric/generated_exemplarslice_test.go b/pdata/pmetric/generated_exemplarslice_test.go index 3eb96c12b80..7cda639f638 100644 --- a/pdata/pmetric/generated_exemplarslice_test.go +++ b/pdata/pmetric/generated_exemplarslice_test.go @@ -11,13 +11,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestExemplarSlice(t *testing.T) { es := NewExemplarSlice() assert.Equal(t, 0, es.Len()) - es = newExemplarSlice(&[]otlpmetrics.Exemplar{}) + state := internal.StateMutable + es = newExemplarSlice(&[]otlpmetrics.Exemplar{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewExemplar() @@ -31,6 +33,19 @@ func TestExemplarSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestExemplarSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newExemplarSlice(&[]otlpmetrics.Exemplar{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewExemplarSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestExemplarSlice_CopyTo(t *testing.T) { dest := NewExemplarSlice() // Test CopyTo to empty @@ -117,6 +132,6 @@ func fillTestExemplarSlice(es ExemplarSlice) { *es.orig = make([]otlpmetrics.Exemplar, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = otlpmetrics.Exemplar{} - fillTestExemplar(newExemplar(&(*es.orig)[i])) + fillTestExemplar(newExemplar(&(*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_exponentialhistogram.go b/pdata/pmetric/generated_exponentialhistogram.go index 5fd275b9554..18ba20d7377 100644 --- a/pdata/pmetric/generated_exponentialhistogram.go +++ b/pdata/pmetric/generated_exponentialhistogram.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -19,11 +20,12 @@ import ( // Must use NewExponentialHistogram function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogram struct { - orig *otlpmetrics.ExponentialHistogram + orig *otlpmetrics.ExponentialHistogram + state *internal.State } -func newExponentialHistogram(orig *otlpmetrics.ExponentialHistogram) ExponentialHistogram { - return ExponentialHistogram{orig} +func newExponentialHistogram(orig *otlpmetrics.ExponentialHistogram, state *internal.State) ExponentialHistogram { + return ExponentialHistogram{orig: orig, state: state} } // NewExponentialHistogram creates a new empty ExponentialHistogram. @@ -31,12 +33,15 @@ func newExponentialHistogram(orig *otlpmetrics.ExponentialHistogram) Exponential // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExponentialHistogram() ExponentialHistogram { - return newExponentialHistogram(&otlpmetrics.ExponentialHistogram{}) + state := internal.StateMutable + return newExponentialHistogram(&otlpmetrics.ExponentialHistogram{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExponentialHistogram) MoveTo(dest ExponentialHistogram) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.ExponentialHistogram{} } @@ -48,16 +53,18 @@ func (ms ExponentialHistogram) AggregationTemporality() AggregationTemporality { // SetAggregationTemporality replaces the aggregationtemporality associated with this ExponentialHistogram. func (ms ExponentialHistogram) SetAggregationTemporality(v AggregationTemporality) { + ms.state.AssertMutable() ms.orig.AggregationTemporality = otlpmetrics.AggregationTemporality(v) } // DataPoints returns the DataPoints associated with this ExponentialHistogram. func (ms ExponentialHistogram) DataPoints() ExponentialHistogramDataPointSlice { - return newExponentialHistogramDataPointSlice(&ms.orig.DataPoints) + return newExponentialHistogramDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExponentialHistogram) CopyTo(dest ExponentialHistogram) { + dest.state.AssertMutable() dest.SetAggregationTemporality(ms.AggregationTemporality()) ms.DataPoints().CopyTo(dest.DataPoints()) } diff --git a/pdata/pmetric/generated_exponentialhistogram_test.go b/pdata/pmetric/generated_exponentialhistogram_test.go index 543e53626cb..cc46edbb536 100644 --- a/pdata/pmetric/generated_exponentialhistogram_test.go +++ b/pdata/pmetric/generated_exponentialhistogram_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,6 +21,9 @@ func TestExponentialHistogram_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExponentialHistogram(), ms) assert.Equal(t, generateTestExponentialHistogram(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newExponentialHistogram(&otlpmetrics.ExponentialHistogram{}, &sharedState)) }) + assert.Panics(t, func() { newExponentialHistogram(&otlpmetrics.ExponentialHistogram{}, &sharedState).MoveTo(dest) }) } func TestExponentialHistogram_CopyTo(t *testing.T) { @@ -30,6 +34,8 @@ func TestExponentialHistogram_CopyTo(t *testing.T) { orig = generateTestExponentialHistogram() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newExponentialHistogram(&otlpmetrics.ExponentialHistogram{}, &sharedState)) }) } func TestExponentialHistogram_AggregationTemporality(t *testing.T) { @@ -55,5 +61,5 @@ func generateTestExponentialHistogram() ExponentialHistogram { func fillTestExponentialHistogram(tv ExponentialHistogram) { tv.orig.AggregationTemporality = otlpmetrics.AggregationTemporality(1) - fillTestExponentialHistogramDataPointSlice(newExponentialHistogramDataPointSlice(&tv.orig.DataPoints)) + fillTestExponentialHistogramDataPointSlice(newExponentialHistogramDataPointSlice(&tv.orig.DataPoints, tv.state)) } diff --git a/pdata/pmetric/generated_exponentialhistogramdatapoint.go b/pdata/pmetric/generated_exponentialhistogramdatapoint.go index 4736787c680..859a08b28d6 100644 --- a/pdata/pmetric/generated_exponentialhistogramdatapoint.go +++ b/pdata/pmetric/generated_exponentialhistogramdatapoint.go @@ -23,11 +23,12 @@ import ( // Must use NewExponentialHistogramDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogramDataPoint struct { - orig *otlpmetrics.ExponentialHistogramDataPoint + orig *otlpmetrics.ExponentialHistogramDataPoint + state *internal.State } -func newExponentialHistogramDataPoint(orig *otlpmetrics.ExponentialHistogramDataPoint) ExponentialHistogramDataPoint { - return ExponentialHistogramDataPoint{orig} +func newExponentialHistogramDataPoint(orig *otlpmetrics.ExponentialHistogramDataPoint, state *internal.State) ExponentialHistogramDataPoint { + return ExponentialHistogramDataPoint{orig: orig, state: state} } // NewExponentialHistogramDataPoint creates a new empty ExponentialHistogramDataPoint. @@ -35,19 +36,22 @@ func newExponentialHistogramDataPoint(orig *otlpmetrics.ExponentialHistogramData // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExponentialHistogramDataPoint() ExponentialHistogramDataPoint { - return newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}) + state := internal.StateMutable + return newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExponentialHistogramDataPoint) MoveTo(dest ExponentialHistogramDataPoint) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.ExponentialHistogramDataPoint{} } // Attributes returns the Attributes associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this ExponentialHistogramDataPoint. @@ -57,6 +61,7 @@ func (ms ExponentialHistogramDataPoint) StartTimestamp() pcommon.Timestamp { // SetStartTimestamp replaces the starttimestamp associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetStartTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } @@ -67,6 +72,7 @@ func (ms ExponentialHistogramDataPoint) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -77,6 +83,7 @@ func (ms ExponentialHistogramDataPoint) Count() uint64 { // SetCount replaces the count associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetCount(v uint64) { + ms.state.AssertMutable() ms.orig.Count = v } @@ -87,6 +94,7 @@ func (ms ExponentialHistogramDataPoint) Scale() int32 { // SetScale replaces the scale associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetScale(v int32) { + ms.state.AssertMutable() ms.orig.Scale = v } @@ -97,22 +105,23 @@ func (ms ExponentialHistogramDataPoint) ZeroCount() uint64 { // SetZeroCount replaces the zerocount associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetZeroCount(v uint64) { + ms.state.AssertMutable() ms.orig.ZeroCount = v } // Positive returns the positive associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Positive() ExponentialHistogramDataPointBuckets { - return newExponentialHistogramDataPointBuckets(&ms.orig.Positive) + return newExponentialHistogramDataPointBuckets(&ms.orig.Positive, ms.state) } // Negative returns the negative associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Negative() ExponentialHistogramDataPointBuckets { - return newExponentialHistogramDataPointBuckets(&ms.orig.Negative) + return newExponentialHistogramDataPointBuckets(&ms.orig.Negative, ms.state) } // Exemplars returns the Exemplars associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Exemplars() ExemplarSlice { - return newExemplarSlice(&ms.orig.Exemplars) + return newExemplarSlice(&ms.orig.Exemplars, ms.state) } // Flags returns the flags associated with this ExponentialHistogramDataPoint. @@ -122,6 +131,7 @@ func (ms ExponentialHistogramDataPoint) Flags() DataPointFlags { // SetFlags replaces the flags associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetFlags(v DataPointFlags) { + ms.state.AssertMutable() ms.orig.Flags = uint32(v) } @@ -138,11 +148,13 @@ func (ms ExponentialHistogramDataPoint) HasSum() bool { // SetSum replaces the sum associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetSum(v float64) { + ms.state.AssertMutable() ms.orig.Sum_ = &otlpmetrics.ExponentialHistogramDataPoint_Sum{Sum: v} } // RemoveSum removes the sum associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) RemoveSum() { + ms.state.AssertMutable() ms.orig.Sum_ = nil } @@ -159,11 +171,13 @@ func (ms ExponentialHistogramDataPoint) HasMin() bool { // SetMin replaces the min associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetMin(v float64) { + ms.state.AssertMutable() ms.orig.Min_ = &otlpmetrics.ExponentialHistogramDataPoint_Min{Min: v} } // RemoveMin removes the min associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) RemoveMin() { + ms.state.AssertMutable() ms.orig.Min_ = nil } @@ -180,16 +194,19 @@ func (ms ExponentialHistogramDataPoint) HasMax() bool { // SetMax replaces the max associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetMax(v float64) { + ms.state.AssertMutable() ms.orig.Max_ = &otlpmetrics.ExponentialHistogramDataPoint_Max{Max: v} } // RemoveMax removes the max associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) RemoveMax() { + ms.state.AssertMutable() ms.orig.Max_ = nil } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExponentialHistogramDataPoint) CopyTo(dest ExponentialHistogramDataPoint) { + dest.state.AssertMutable() ms.Attributes().CopyTo(dest.Attributes()) dest.SetStartTimestamp(ms.StartTimestamp()) dest.SetTimestamp(ms.Timestamp()) diff --git a/pdata/pmetric/generated_exponentialhistogramdatapoint_test.go b/pdata/pmetric/generated_exponentialhistogramdatapoint_test.go index 1962853ff9c..792add966c4 100644 --- a/pdata/pmetric/generated_exponentialhistogramdatapoint_test.go +++ b/pdata/pmetric/generated_exponentialhistogramdatapoint_test.go @@ -22,6 +22,13 @@ func TestExponentialHistogramDataPoint_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExponentialHistogramDataPoint(), ms) assert.Equal(t, generateTestExponentialHistogramDataPoint(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.MoveTo(newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState)) + }) + assert.Panics(t, func() { + newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState).MoveTo(dest) + }) } func TestExponentialHistogramDataPoint_CopyTo(t *testing.T) { @@ -32,6 +39,10 @@ func TestExponentialHistogramDataPoint_CopyTo(t *testing.T) { orig = generateTestExponentialHistogramDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.CopyTo(newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState)) + }) } func TestExponentialHistogramDataPoint_Attributes(t *testing.T) { @@ -62,6 +73,10 @@ func TestExponentialHistogramDataPoint_Count(t *testing.T) { assert.Equal(t, uint64(0), ms.Count()) ms.SetCount(uint64(17)) assert.Equal(t, uint64(17), ms.Count()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState).SetCount(uint64(17)) + }) } func TestExponentialHistogramDataPoint_Scale(t *testing.T) { @@ -69,6 +84,10 @@ func TestExponentialHistogramDataPoint_Scale(t *testing.T) { assert.Equal(t, int32(0), ms.Scale()) ms.SetScale(int32(4)) assert.Equal(t, int32(4), ms.Scale()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState).SetScale(int32(4)) + }) } func TestExponentialHistogramDataPoint_ZeroCount(t *testing.T) { @@ -76,6 +95,10 @@ func TestExponentialHistogramDataPoint_ZeroCount(t *testing.T) { assert.Equal(t, uint64(0), ms.ZeroCount()) ms.SetZeroCount(uint64(201)) assert.Equal(t, uint64(201), ms.ZeroCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExponentialHistogramDataPoint(&otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState).SetZeroCount(uint64(201)) + }) } func TestExponentialHistogramDataPoint_Positive(t *testing.T) { @@ -142,15 +165,15 @@ func generateTestExponentialHistogramDataPoint() ExponentialHistogramDataPoint { } func fillTestExponentialHistogramDataPoint(tv ExponentialHistogramDataPoint) { - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.StartTimeUnixNano = 1234567890 tv.orig.TimeUnixNano = 1234567890 tv.orig.Count = uint64(17) tv.orig.Scale = int32(4) tv.orig.ZeroCount = uint64(201) - fillTestExponentialHistogramDataPointBuckets(newExponentialHistogramDataPointBuckets(&tv.orig.Positive)) - fillTestExponentialHistogramDataPointBuckets(newExponentialHistogramDataPointBuckets(&tv.orig.Negative)) - fillTestExemplarSlice(newExemplarSlice(&tv.orig.Exemplars)) + fillTestExponentialHistogramDataPointBuckets(newExponentialHistogramDataPointBuckets(&tv.orig.Positive, tv.state)) + fillTestExponentialHistogramDataPointBuckets(newExponentialHistogramDataPointBuckets(&tv.orig.Negative, tv.state)) + fillTestExemplarSlice(newExemplarSlice(&tv.orig.Exemplars, tv.state)) tv.orig.Flags = 1 tv.orig.Sum_ = &otlpmetrics.ExponentialHistogramDataPoint_Sum{Sum: float64(17.13)} tv.orig.Min_ = &otlpmetrics.ExponentialHistogramDataPoint_Min{Min: float64(9.23)} diff --git a/pdata/pmetric/generated_exponentialhistogramdatapointbuckets.go b/pdata/pmetric/generated_exponentialhistogramdatapointbuckets.go index c0e1532909a..7acfbc627f3 100644 --- a/pdata/pmetric/generated_exponentialhistogramdatapointbuckets.go +++ b/pdata/pmetric/generated_exponentialhistogramdatapointbuckets.go @@ -20,11 +20,12 @@ import ( // Must use NewExponentialHistogramDataPointBuckets function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogramDataPointBuckets struct { - orig *otlpmetrics.ExponentialHistogramDataPoint_Buckets + orig *otlpmetrics.ExponentialHistogramDataPoint_Buckets + state *internal.State } -func newExponentialHistogramDataPointBuckets(orig *otlpmetrics.ExponentialHistogramDataPoint_Buckets) ExponentialHistogramDataPointBuckets { - return ExponentialHistogramDataPointBuckets{orig} +func newExponentialHistogramDataPointBuckets(orig *otlpmetrics.ExponentialHistogramDataPoint_Buckets, state *internal.State) ExponentialHistogramDataPointBuckets { + return ExponentialHistogramDataPointBuckets{orig: orig, state: state} } // NewExponentialHistogramDataPointBuckets creates a new empty ExponentialHistogramDataPointBuckets. @@ -32,12 +33,15 @@ func newExponentialHistogramDataPointBuckets(orig *otlpmetrics.ExponentialHistog // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExponentialHistogramDataPointBuckets() ExponentialHistogramDataPointBuckets { - return newExponentialHistogramDataPointBuckets(&otlpmetrics.ExponentialHistogramDataPoint_Buckets{}) + state := internal.StateMutable + return newExponentialHistogramDataPointBuckets(&otlpmetrics.ExponentialHistogramDataPoint_Buckets{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExponentialHistogramDataPointBuckets) MoveTo(dest ExponentialHistogramDataPointBuckets) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.ExponentialHistogramDataPoint_Buckets{} } @@ -49,16 +53,18 @@ func (ms ExponentialHistogramDataPointBuckets) Offset() int32 { // SetOffset replaces the offset associated with this ExponentialHistogramDataPointBuckets. func (ms ExponentialHistogramDataPointBuckets) SetOffset(v int32) { + ms.state.AssertMutable() ms.orig.Offset = v } // BucketCounts returns the bucketcounts associated with this ExponentialHistogramDataPointBuckets. func (ms ExponentialHistogramDataPointBuckets) BucketCounts() pcommon.UInt64Slice { - return pcommon.UInt64Slice(internal.NewUInt64Slice(&ms.orig.BucketCounts)) + return pcommon.UInt64Slice(internal.NewUInt64Slice(&ms.orig.BucketCounts, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExponentialHistogramDataPointBuckets) CopyTo(dest ExponentialHistogramDataPointBuckets) { + dest.state.AssertMutable() dest.SetOffset(ms.Offset()) ms.BucketCounts().CopyTo(dest.BucketCounts()) } diff --git a/pdata/pmetric/generated_exponentialhistogramdatapointbuckets_test.go b/pdata/pmetric/generated_exponentialhistogramdatapointbuckets_test.go index c1119861dbd..faf6e529f33 100644 --- a/pdata/pmetric/generated_exponentialhistogramdatapointbuckets_test.go +++ b/pdata/pmetric/generated_exponentialhistogramdatapointbuckets_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestExponentialHistogramDataPointBuckets_MoveTo(t *testing.T) { @@ -18,6 +21,13 @@ func TestExponentialHistogramDataPointBuckets_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExponentialHistogramDataPointBuckets(), ms) assert.Equal(t, generateTestExponentialHistogramDataPointBuckets(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.MoveTo(newExponentialHistogramDataPointBuckets(&otlpmetrics.ExponentialHistogramDataPoint_Buckets{}, &sharedState)) + }) + assert.Panics(t, func() { + newExponentialHistogramDataPointBuckets(&otlpmetrics.ExponentialHistogramDataPoint_Buckets{}, &sharedState).MoveTo(dest) + }) } func TestExponentialHistogramDataPointBuckets_CopyTo(t *testing.T) { @@ -28,6 +38,10 @@ func TestExponentialHistogramDataPointBuckets_CopyTo(t *testing.T) { orig = generateTestExponentialHistogramDataPointBuckets() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.CopyTo(newExponentialHistogramDataPointBuckets(&otlpmetrics.ExponentialHistogramDataPoint_Buckets{}, &sharedState)) + }) } func TestExponentialHistogramDataPointBuckets_Offset(t *testing.T) { @@ -35,6 +49,10 @@ func TestExponentialHistogramDataPointBuckets_Offset(t *testing.T) { assert.Equal(t, int32(0), ms.Offset()) ms.SetOffset(int32(909)) assert.Equal(t, int32(909), ms.Offset()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExponentialHistogramDataPointBuckets(&otlpmetrics.ExponentialHistogramDataPoint_Buckets{}, &sharedState).SetOffset(int32(909)) + }) } func TestExponentialHistogramDataPointBuckets_BucketCounts(t *testing.T) { diff --git a/pdata/pmetric/generated_exponentialhistogramdatapointslice.go b/pdata/pmetric/generated_exponentialhistogramdatapointslice.go index f2141d1e5c8..94ec5265658 100644 --- a/pdata/pmetric/generated_exponentialhistogramdatapointslice.go +++ b/pdata/pmetric/generated_exponentialhistogramdatapointslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewExponentialHistogramDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogramDataPointSlice struct { - orig *[]*otlpmetrics.ExponentialHistogramDataPoint + orig *[]*otlpmetrics.ExponentialHistogramDataPoint + state *internal.State } -func newExponentialHistogramDataPointSlice(orig *[]*otlpmetrics.ExponentialHistogramDataPoint) ExponentialHistogramDataPointSlice { - return ExponentialHistogramDataPointSlice{orig} +func newExponentialHistogramDataPointSlice(orig *[]*otlpmetrics.ExponentialHistogramDataPoint, state *internal.State) ExponentialHistogramDataPointSlice { + return ExponentialHistogramDataPointSlice{orig: orig, state: state} } // NewExponentialHistogramDataPointSlice creates a ExponentialHistogramDataPointSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewExponentialHistogramDataPointSlice() ExponentialHistogramDataPointSlice { orig := []*otlpmetrics.ExponentialHistogramDataPoint(nil) - return newExponentialHistogramDataPointSlice(&orig) + state := internal.StateMutable + return newExponentialHistogramDataPointSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ExponentialHistogramDataPointSlice) Len() int { // ... // Do something with the element // } func (es ExponentialHistogramDataPointSlice) At(i int) ExponentialHistogramDataPoint { - return newExponentialHistogramDataPoint((*es.orig)[i]) + return newExponentialHistogramDataPoint((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ExponentialHistogramDataPointSlice) At(i int) ExponentialHistogramDataP // // Here should set all the values for e. // } func (es ExponentialHistogramDataPointSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ExponentialHistogramDataPointSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ExponentialHistogramDataPoint. // It returns the newly added ExponentialHistogramDataPoint. func (es ExponentialHistogramDataPointSlice) AppendEmpty() ExponentialHistogramDataPoint { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.ExponentialHistogramDataPoint{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ExponentialHistogramDataPointSlice) AppendEmpty() ExponentialHistogramD // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ExponentialHistogramDataPointSlice) MoveAndAppendTo(dest ExponentialHistogramDataPointSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ExponentialHistogramDataPointSlice) MoveAndAppendTo(dest ExponentialHis // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ExponentialHistogramDataPointSlice) RemoveIf(f func(ExponentialHistogramDataPoint) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ExponentialHistogramDataPointSlice) RemoveIf(f func(ExponentialHistogra // CopyTo copies all elements from the current slice overriding the destination. func (es ExponentialHistogramDataPointSlice) CopyTo(dest ExponentialHistogramDataPointSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newExponentialHistogramDataPoint((*es.orig)[i]).CopyTo(newExponentialHistogramDataPoint((*dest.orig)[i])) + newExponentialHistogramDataPoint((*es.orig)[i], es.state).CopyTo(newExponentialHistogramDataPoint((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ExponentialHistogramDataPointSlice) CopyTo(dest ExponentialHistogramDat wrappers := make([]*otlpmetrics.ExponentialHistogramDataPoint, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newExponentialHistogramDataPoint((*es.orig)[i]).CopyTo(newExponentialHistogramDataPoint(wrappers[i])) + newExponentialHistogramDataPoint((*es.orig)[i], es.state).CopyTo(newExponentialHistogramDataPoint(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ExponentialHistogramDataPointSlice) CopyTo(dest ExponentialHistogramDat // provided less function so that two instances of ExponentialHistogramDataPointSlice // can be compared. func (es ExponentialHistogramDataPointSlice) Sort(less func(a, b ExponentialHistogramDataPoint) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_exponentialhistogramdatapointslice_test.go b/pdata/pmetric/generated_exponentialhistogramdatapointslice_test.go index 6fd8a3f6de0..7c938c6ee22 100644 --- a/pdata/pmetric/generated_exponentialhistogramdatapointslice_test.go +++ b/pdata/pmetric/generated_exponentialhistogramdatapointslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestExponentialHistogramDataPointSlice(t *testing.T) { es := NewExponentialHistogramDataPointSlice() assert.Equal(t, 0, es.Len()) - es = newExponentialHistogramDataPointSlice(&[]*otlpmetrics.ExponentialHistogramDataPoint{}) + state := internal.StateMutable + es = newExponentialHistogramDataPointSlice(&[]*otlpmetrics.ExponentialHistogramDataPoint{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewExponentialHistogramDataPoint() @@ -32,6 +34,19 @@ func TestExponentialHistogramDataPointSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestExponentialHistogramDataPointSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newExponentialHistogramDataPointSlice(&[]*otlpmetrics.ExponentialHistogramDataPoint{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewExponentialHistogramDataPointSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestExponentialHistogramDataPointSlice_CopyTo(t *testing.T) { dest := NewExponentialHistogramDataPointSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestExponentialHistogramDataPointSlice(es ExponentialHistogramDataPoint *es.orig = make([]*otlpmetrics.ExponentialHistogramDataPoint, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.ExponentialHistogramDataPoint{} - fillTestExponentialHistogramDataPoint(newExponentialHistogramDataPoint((*es.orig)[i])) + fillTestExponentialHistogramDataPoint(newExponentialHistogramDataPoint((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_gauge.go b/pdata/pmetric/generated_gauge.go index 6c74325b6de..ba572f9ca57 100644 --- a/pdata/pmetric/generated_gauge.go +++ b/pdata/pmetric/generated_gauge.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewGauge function to create new instances. // Important: zero-initialized instance is not valid for use. type Gauge struct { - orig *otlpmetrics.Gauge + orig *otlpmetrics.Gauge + state *internal.State } -func newGauge(orig *otlpmetrics.Gauge) Gauge { - return Gauge{orig} +func newGauge(orig *otlpmetrics.Gauge, state *internal.State) Gauge { + return Gauge{orig: orig, state: state} } // NewGauge creates a new empty Gauge. @@ -30,22 +32,26 @@ func newGauge(orig *otlpmetrics.Gauge) Gauge { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewGauge() Gauge { - return newGauge(&otlpmetrics.Gauge{}) + state := internal.StateMutable + return newGauge(&otlpmetrics.Gauge{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Gauge) MoveTo(dest Gauge) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.Gauge{} } // DataPoints returns the DataPoints associated with this Gauge. func (ms Gauge) DataPoints() NumberDataPointSlice { - return newNumberDataPointSlice(&ms.orig.DataPoints) + return newNumberDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Gauge) CopyTo(dest Gauge) { + dest.state.AssertMutable() ms.DataPoints().CopyTo(dest.DataPoints()) } diff --git a/pdata/pmetric/generated_gauge_test.go b/pdata/pmetric/generated_gauge_test.go index 30b517cd05b..e1506be119b 100644 --- a/pdata/pmetric/generated_gauge_test.go +++ b/pdata/pmetric/generated_gauge_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestGauge_MoveTo(t *testing.T) { @@ -18,6 +21,9 @@ func TestGauge_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewGauge(), ms) assert.Equal(t, generateTestGauge(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newGauge(&otlpmetrics.Gauge{}, &sharedState)) }) + assert.Panics(t, func() { newGauge(&otlpmetrics.Gauge{}, &sharedState).MoveTo(dest) }) } func TestGauge_CopyTo(t *testing.T) { @@ -28,6 +34,8 @@ func TestGauge_CopyTo(t *testing.T) { orig = generateTestGauge() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newGauge(&otlpmetrics.Gauge{}, &sharedState)) }) } func TestGauge_DataPoints(t *testing.T) { @@ -44,5 +52,5 @@ func generateTestGauge() Gauge { } func fillTestGauge(tv Gauge) { - fillTestNumberDataPointSlice(newNumberDataPointSlice(&tv.orig.DataPoints)) + fillTestNumberDataPointSlice(newNumberDataPointSlice(&tv.orig.DataPoints, tv.state)) } diff --git a/pdata/pmetric/generated_histogram.go b/pdata/pmetric/generated_histogram.go index a32114b86ed..950fb13127e 100644 --- a/pdata/pmetric/generated_histogram.go +++ b/pdata/pmetric/generated_histogram.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewHistogram function to create new instances. // Important: zero-initialized instance is not valid for use. type Histogram struct { - orig *otlpmetrics.Histogram + orig *otlpmetrics.Histogram + state *internal.State } -func newHistogram(orig *otlpmetrics.Histogram) Histogram { - return Histogram{orig} +func newHistogram(orig *otlpmetrics.Histogram, state *internal.State) Histogram { + return Histogram{orig: orig, state: state} } // NewHistogram creates a new empty Histogram. @@ -30,12 +32,15 @@ func newHistogram(orig *otlpmetrics.Histogram) Histogram { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewHistogram() Histogram { - return newHistogram(&otlpmetrics.Histogram{}) + state := internal.StateMutable + return newHistogram(&otlpmetrics.Histogram{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Histogram) MoveTo(dest Histogram) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.Histogram{} } @@ -47,16 +52,18 @@ func (ms Histogram) AggregationTemporality() AggregationTemporality { // SetAggregationTemporality replaces the aggregationtemporality associated with this Histogram. func (ms Histogram) SetAggregationTemporality(v AggregationTemporality) { + ms.state.AssertMutable() ms.orig.AggregationTemporality = otlpmetrics.AggregationTemporality(v) } // DataPoints returns the DataPoints associated with this Histogram. func (ms Histogram) DataPoints() HistogramDataPointSlice { - return newHistogramDataPointSlice(&ms.orig.DataPoints) + return newHistogramDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Histogram) CopyTo(dest Histogram) { + dest.state.AssertMutable() dest.SetAggregationTemporality(ms.AggregationTemporality()) ms.DataPoints().CopyTo(dest.DataPoints()) } diff --git a/pdata/pmetric/generated_histogram_test.go b/pdata/pmetric/generated_histogram_test.go index b710fddbca0..8eb2dc9dda4 100644 --- a/pdata/pmetric/generated_histogram_test.go +++ b/pdata/pmetric/generated_histogram_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,6 +21,9 @@ func TestHistogram_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewHistogram(), ms) assert.Equal(t, generateTestHistogram(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newHistogram(&otlpmetrics.Histogram{}, &sharedState)) }) + assert.Panics(t, func() { newHistogram(&otlpmetrics.Histogram{}, &sharedState).MoveTo(dest) }) } func TestHistogram_CopyTo(t *testing.T) { @@ -30,6 +34,8 @@ func TestHistogram_CopyTo(t *testing.T) { orig = generateTestHistogram() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newHistogram(&otlpmetrics.Histogram{}, &sharedState)) }) } func TestHistogram_AggregationTemporality(t *testing.T) { @@ -55,5 +61,5 @@ func generateTestHistogram() Histogram { func fillTestHistogram(tv Histogram) { tv.orig.AggregationTemporality = otlpmetrics.AggregationTemporality(1) - fillTestHistogramDataPointSlice(newHistogramDataPointSlice(&tv.orig.DataPoints)) + fillTestHistogramDataPointSlice(newHistogramDataPointSlice(&tv.orig.DataPoints, tv.state)) } diff --git a/pdata/pmetric/generated_histogramdatapoint.go b/pdata/pmetric/generated_histogramdatapoint.go index 204e7edd523..22dc32344a2 100644 --- a/pdata/pmetric/generated_histogramdatapoint.go +++ b/pdata/pmetric/generated_histogramdatapoint.go @@ -20,11 +20,12 @@ import ( // Must use NewHistogramDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type HistogramDataPoint struct { - orig *otlpmetrics.HistogramDataPoint + orig *otlpmetrics.HistogramDataPoint + state *internal.State } -func newHistogramDataPoint(orig *otlpmetrics.HistogramDataPoint) HistogramDataPoint { - return HistogramDataPoint{orig} +func newHistogramDataPoint(orig *otlpmetrics.HistogramDataPoint, state *internal.State) HistogramDataPoint { + return HistogramDataPoint{orig: orig, state: state} } // NewHistogramDataPoint creates a new empty HistogramDataPoint. @@ -32,19 +33,22 @@ func newHistogramDataPoint(orig *otlpmetrics.HistogramDataPoint) HistogramDataPo // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewHistogramDataPoint() HistogramDataPoint { - return newHistogramDataPoint(&otlpmetrics.HistogramDataPoint{}) + state := internal.StateMutable + return newHistogramDataPoint(&otlpmetrics.HistogramDataPoint{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms HistogramDataPoint) MoveTo(dest HistogramDataPoint) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.HistogramDataPoint{} } // Attributes returns the Attributes associated with this HistogramDataPoint. func (ms HistogramDataPoint) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this HistogramDataPoint. @@ -54,6 +58,7 @@ func (ms HistogramDataPoint) StartTimestamp() pcommon.Timestamp { // SetStartTimestamp replaces the starttimestamp associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetStartTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } @@ -64,6 +69,7 @@ func (ms HistogramDataPoint) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -74,22 +80,23 @@ func (ms HistogramDataPoint) Count() uint64 { // SetCount replaces the count associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetCount(v uint64) { + ms.state.AssertMutable() ms.orig.Count = v } // BucketCounts returns the bucketcounts associated with this HistogramDataPoint. func (ms HistogramDataPoint) BucketCounts() pcommon.UInt64Slice { - return pcommon.UInt64Slice(internal.NewUInt64Slice(&ms.orig.BucketCounts)) + return pcommon.UInt64Slice(internal.NewUInt64Slice(&ms.orig.BucketCounts, ms.state)) } // ExplicitBounds returns the explicitbounds associated with this HistogramDataPoint. func (ms HistogramDataPoint) ExplicitBounds() pcommon.Float64Slice { - return pcommon.Float64Slice(internal.NewFloat64Slice(&ms.orig.ExplicitBounds)) + return pcommon.Float64Slice(internal.NewFloat64Slice(&ms.orig.ExplicitBounds, ms.state)) } // Exemplars returns the Exemplars associated with this HistogramDataPoint. func (ms HistogramDataPoint) Exemplars() ExemplarSlice { - return newExemplarSlice(&ms.orig.Exemplars) + return newExemplarSlice(&ms.orig.Exemplars, ms.state) } // Flags returns the flags associated with this HistogramDataPoint. @@ -99,6 +106,7 @@ func (ms HistogramDataPoint) Flags() DataPointFlags { // SetFlags replaces the flags associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetFlags(v DataPointFlags) { + ms.state.AssertMutable() ms.orig.Flags = uint32(v) } @@ -115,11 +123,13 @@ func (ms HistogramDataPoint) HasSum() bool { // SetSum replaces the sum associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetSum(v float64) { + ms.state.AssertMutable() ms.orig.Sum_ = &otlpmetrics.HistogramDataPoint_Sum{Sum: v} } // RemoveSum removes the sum associated with this HistogramDataPoint. func (ms HistogramDataPoint) RemoveSum() { + ms.state.AssertMutable() ms.orig.Sum_ = nil } @@ -136,11 +146,13 @@ func (ms HistogramDataPoint) HasMin() bool { // SetMin replaces the min associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetMin(v float64) { + ms.state.AssertMutable() ms.orig.Min_ = &otlpmetrics.HistogramDataPoint_Min{Min: v} } // RemoveMin removes the min associated with this HistogramDataPoint. func (ms HistogramDataPoint) RemoveMin() { + ms.state.AssertMutable() ms.orig.Min_ = nil } @@ -157,16 +169,19 @@ func (ms HistogramDataPoint) HasMax() bool { // SetMax replaces the max associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetMax(v float64) { + ms.state.AssertMutable() ms.orig.Max_ = &otlpmetrics.HistogramDataPoint_Max{Max: v} } // RemoveMax removes the max associated with this HistogramDataPoint. func (ms HistogramDataPoint) RemoveMax() { + ms.state.AssertMutable() ms.orig.Max_ = nil } // CopyTo copies all properties from the current struct overriding the destination. func (ms HistogramDataPoint) CopyTo(dest HistogramDataPoint) { + dest.state.AssertMutable() ms.Attributes().CopyTo(dest.Attributes()) dest.SetStartTimestamp(ms.StartTimestamp()) dest.SetTimestamp(ms.Timestamp()) diff --git a/pdata/pmetric/generated_histogramdatapoint_test.go b/pdata/pmetric/generated_histogramdatapoint_test.go index 8cb8dcd96cc..716cebd4cbf 100644 --- a/pdata/pmetric/generated_histogramdatapoint_test.go +++ b/pdata/pmetric/generated_histogramdatapoint_test.go @@ -22,6 +22,9 @@ func TestHistogramDataPoint_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewHistogramDataPoint(), ms) assert.Equal(t, generateTestHistogramDataPoint(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newHistogramDataPoint(&otlpmetrics.HistogramDataPoint{}, &sharedState)) }) + assert.Panics(t, func() { newHistogramDataPoint(&otlpmetrics.HistogramDataPoint{}, &sharedState).MoveTo(dest) }) } func TestHistogramDataPoint_CopyTo(t *testing.T) { @@ -32,6 +35,8 @@ func TestHistogramDataPoint_CopyTo(t *testing.T) { orig = generateTestHistogramDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newHistogramDataPoint(&otlpmetrics.HistogramDataPoint{}, &sharedState)) }) } func TestHistogramDataPoint_Attributes(t *testing.T) { @@ -62,6 +67,8 @@ func TestHistogramDataPoint_Count(t *testing.T) { assert.Equal(t, uint64(0), ms.Count()) ms.SetCount(uint64(17)) assert.Equal(t, uint64(17), ms.Count()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newHistogramDataPoint(&otlpmetrics.HistogramDataPoint{}, &sharedState).SetCount(uint64(17)) }) } func TestHistogramDataPoint_BucketCounts(t *testing.T) { @@ -130,13 +137,13 @@ func generateTestHistogramDataPoint() HistogramDataPoint { } func fillTestHistogramDataPoint(tv HistogramDataPoint) { - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.StartTimeUnixNano = 1234567890 tv.orig.TimeUnixNano = 1234567890 tv.orig.Count = uint64(17) tv.orig.BucketCounts = []uint64{1, 2, 3} tv.orig.ExplicitBounds = []float64{1, 2, 3} - fillTestExemplarSlice(newExemplarSlice(&tv.orig.Exemplars)) + fillTestExemplarSlice(newExemplarSlice(&tv.orig.Exemplars, tv.state)) tv.orig.Flags = 1 tv.orig.Sum_ = &otlpmetrics.HistogramDataPoint_Sum{Sum: float64(17.13)} tv.orig.Min_ = &otlpmetrics.HistogramDataPoint_Min{Min: float64(9.23)} diff --git a/pdata/pmetric/generated_histogramdatapointslice.go b/pdata/pmetric/generated_histogramdatapointslice.go index 27a018ed89b..47b02e17f78 100644 --- a/pdata/pmetric/generated_histogramdatapointslice.go +++ b/pdata/pmetric/generated_histogramdatapointslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewHistogramDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type HistogramDataPointSlice struct { - orig *[]*otlpmetrics.HistogramDataPoint + orig *[]*otlpmetrics.HistogramDataPoint + state *internal.State } -func newHistogramDataPointSlice(orig *[]*otlpmetrics.HistogramDataPoint) HistogramDataPointSlice { - return HistogramDataPointSlice{orig} +func newHistogramDataPointSlice(orig *[]*otlpmetrics.HistogramDataPoint, state *internal.State) HistogramDataPointSlice { + return HistogramDataPointSlice{orig: orig, state: state} } // NewHistogramDataPointSlice creates a HistogramDataPointSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewHistogramDataPointSlice() HistogramDataPointSlice { orig := []*otlpmetrics.HistogramDataPoint(nil) - return newHistogramDataPointSlice(&orig) + state := internal.StateMutable + return newHistogramDataPointSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es HistogramDataPointSlice) Len() int { // ... // Do something with the element // } func (es HistogramDataPointSlice) At(i int) HistogramDataPoint { - return newHistogramDataPoint((*es.orig)[i]) + return newHistogramDataPoint((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es HistogramDataPointSlice) At(i int) HistogramDataPoint { // // Here should set all the values for e. // } func (es HistogramDataPointSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es HistogramDataPointSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty HistogramDataPoint. // It returns the newly added HistogramDataPoint. func (es HistogramDataPointSlice) AppendEmpty() HistogramDataPoint { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.HistogramDataPoint{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es HistogramDataPointSlice) AppendEmpty() HistogramDataPoint { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es HistogramDataPointSlice) MoveAndAppendTo(dest HistogramDataPointSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es HistogramDataPointSlice) MoveAndAppendTo(dest HistogramDataPointSlice) // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es HistogramDataPointSlice) RemoveIf(f func(HistogramDataPoint) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es HistogramDataPointSlice) RemoveIf(f func(HistogramDataPoint) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es HistogramDataPointSlice) CopyTo(dest HistogramDataPointSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newHistogramDataPoint((*es.orig)[i]).CopyTo(newHistogramDataPoint((*dest.orig)[i])) + newHistogramDataPoint((*es.orig)[i], es.state).CopyTo(newHistogramDataPoint((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es HistogramDataPointSlice) CopyTo(dest HistogramDataPointSlice) { wrappers := make([]*otlpmetrics.HistogramDataPoint, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newHistogramDataPoint((*es.orig)[i]).CopyTo(newHistogramDataPoint(wrappers[i])) + newHistogramDataPoint((*es.orig)[i], es.state).CopyTo(newHistogramDataPoint(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es HistogramDataPointSlice) CopyTo(dest HistogramDataPointSlice) { // provided less function so that two instances of HistogramDataPointSlice // can be compared. func (es HistogramDataPointSlice) Sort(less func(a, b HistogramDataPoint) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_histogramdatapointslice_test.go b/pdata/pmetric/generated_histogramdatapointslice_test.go index 390b7277d7c..bcf4305b993 100644 --- a/pdata/pmetric/generated_histogramdatapointslice_test.go +++ b/pdata/pmetric/generated_histogramdatapointslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestHistogramDataPointSlice(t *testing.T) { es := NewHistogramDataPointSlice() assert.Equal(t, 0, es.Len()) - es = newHistogramDataPointSlice(&[]*otlpmetrics.HistogramDataPoint{}) + state := internal.StateMutable + es = newHistogramDataPointSlice(&[]*otlpmetrics.HistogramDataPoint{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewHistogramDataPoint() @@ -32,6 +34,19 @@ func TestHistogramDataPointSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestHistogramDataPointSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newHistogramDataPointSlice(&[]*otlpmetrics.HistogramDataPoint{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewHistogramDataPointSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestHistogramDataPointSlice_CopyTo(t *testing.T) { dest := NewHistogramDataPointSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestHistogramDataPointSlice(es HistogramDataPointSlice) { *es.orig = make([]*otlpmetrics.HistogramDataPoint, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.HistogramDataPoint{} - fillTestHistogramDataPoint(newHistogramDataPoint((*es.orig)[i])) + fillTestHistogramDataPoint(newHistogramDataPoint((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_metric.go b/pdata/pmetric/generated_metric.go index aba0d8e04df..839628520df 100644 --- a/pdata/pmetric/generated_metric.go +++ b/pdata/pmetric/generated_metric.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -19,11 +20,12 @@ import ( // Must use NewMetric function to create new instances. // Important: zero-initialized instance is not valid for use. type Metric struct { - orig *otlpmetrics.Metric + orig *otlpmetrics.Metric + state *internal.State } -func newMetric(orig *otlpmetrics.Metric) Metric { - return Metric{orig} +func newMetric(orig *otlpmetrics.Metric, state *internal.State) Metric { + return Metric{orig: orig, state: state} } // NewMetric creates a new empty Metric. @@ -31,12 +33,15 @@ func newMetric(orig *otlpmetrics.Metric) Metric { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewMetric() Metric { - return newMetric(&otlpmetrics.Metric{}) + state := internal.StateMutable + return newMetric(&otlpmetrics.Metric{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Metric) MoveTo(dest Metric) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.Metric{} } @@ -48,6 +53,7 @@ func (ms Metric) Name() string { // SetName replaces the name associated with this Metric. func (ms Metric) SetName(v string) { + ms.state.AssertMutable() ms.orig.Name = v } @@ -58,6 +64,7 @@ func (ms Metric) Description() string { // SetDescription replaces the description associated with this Metric. func (ms Metric) SetDescription(v string) { + ms.state.AssertMutable() ms.orig.Description = v } @@ -68,6 +75,7 @@ func (ms Metric) Unit() string { // SetUnit replaces the unit associated with this Metric. func (ms Metric) SetUnit(v string) { + ms.state.AssertMutable() ms.orig.Unit = v } @@ -100,7 +108,7 @@ func (ms Metric) Gauge() Gauge { if !ok { return Gauge{} } - return newGauge(v.Gauge) + return newGauge(v.Gauge, ms.state) } // SetEmptyGauge sets an empty gauge to this Metric. @@ -109,9 +117,10 @@ func (ms Metric) Gauge() Gauge { // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptyGauge() Gauge { + ms.state.AssertMutable() val := &otlpmetrics.Gauge{} ms.orig.Data = &otlpmetrics.Metric_Gauge{Gauge: val} - return newGauge(val) + return newGauge(val, ms.state) } // Sum returns the sum associated with this Metric. @@ -125,7 +134,7 @@ func (ms Metric) Sum() Sum { if !ok { return Sum{} } - return newSum(v.Sum) + return newSum(v.Sum, ms.state) } // SetEmptySum sets an empty sum to this Metric. @@ -134,9 +143,10 @@ func (ms Metric) Sum() Sum { // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptySum() Sum { + ms.state.AssertMutable() val := &otlpmetrics.Sum{} ms.orig.Data = &otlpmetrics.Metric_Sum{Sum: val} - return newSum(val) + return newSum(val, ms.state) } // Histogram returns the histogram associated with this Metric. @@ -150,7 +160,7 @@ func (ms Metric) Histogram() Histogram { if !ok { return Histogram{} } - return newHistogram(v.Histogram) + return newHistogram(v.Histogram, ms.state) } // SetEmptyHistogram sets an empty histogram to this Metric. @@ -159,9 +169,10 @@ func (ms Metric) Histogram() Histogram { // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptyHistogram() Histogram { + ms.state.AssertMutable() val := &otlpmetrics.Histogram{} ms.orig.Data = &otlpmetrics.Metric_Histogram{Histogram: val} - return newHistogram(val) + return newHistogram(val, ms.state) } // ExponentialHistogram returns the exponentialhistogram associated with this Metric. @@ -175,7 +186,7 @@ func (ms Metric) ExponentialHistogram() ExponentialHistogram { if !ok { return ExponentialHistogram{} } - return newExponentialHistogram(v.ExponentialHistogram) + return newExponentialHistogram(v.ExponentialHistogram, ms.state) } // SetEmptyExponentialHistogram sets an empty exponentialhistogram to this Metric. @@ -184,9 +195,10 @@ func (ms Metric) ExponentialHistogram() ExponentialHistogram { // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptyExponentialHistogram() ExponentialHistogram { + ms.state.AssertMutable() val := &otlpmetrics.ExponentialHistogram{} ms.orig.Data = &otlpmetrics.Metric_ExponentialHistogram{ExponentialHistogram: val} - return newExponentialHistogram(val) + return newExponentialHistogram(val, ms.state) } // Summary returns the summary associated with this Metric. @@ -200,7 +212,7 @@ func (ms Metric) Summary() Summary { if !ok { return Summary{} } - return newSummary(v.Summary) + return newSummary(v.Summary, ms.state) } // SetEmptySummary sets an empty summary to this Metric. @@ -209,13 +221,15 @@ func (ms Metric) Summary() Summary { // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptySummary() Summary { + ms.state.AssertMutable() val := &otlpmetrics.Summary{} ms.orig.Data = &otlpmetrics.Metric_Summary{Summary: val} - return newSummary(val) + return newSummary(val, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Metric) CopyTo(dest Metric) { + dest.state.AssertMutable() dest.SetName(ms.Name()) dest.SetDescription(ms.Description()) dest.SetUnit(ms.Unit()) diff --git a/pdata/pmetric/generated_metric_test.go b/pdata/pmetric/generated_metric_test.go index 3dfdedd8627..920891b6096 100644 --- a/pdata/pmetric/generated_metric_test.go +++ b/pdata/pmetric/generated_metric_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,6 +21,9 @@ func TestMetric_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewMetric(), ms) assert.Equal(t, generateTestMetric(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).MoveTo(dest) }) } func TestMetric_CopyTo(t *testing.T) { @@ -30,6 +34,8 @@ func TestMetric_CopyTo(t *testing.T) { orig = generateTestMetric() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) } func TestMetric_Name(t *testing.T) { @@ -37,6 +43,8 @@ func TestMetric_Name(t *testing.T) { assert.Equal(t, "", ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetName("test_name") }) } func TestMetric_Description(t *testing.T) { @@ -44,6 +52,8 @@ func TestMetric_Description(t *testing.T) { assert.Equal(t, "", ms.Description()) ms.SetDescription("test_description") assert.Equal(t, "test_description", ms.Description()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetDescription("test_description") }) } func TestMetric_Unit(t *testing.T) { @@ -51,6 +61,8 @@ func TestMetric_Unit(t *testing.T) { assert.Equal(t, "", ms.Unit()) ms.SetUnit("1") assert.Equal(t, "1", ms.Unit()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetUnit("1") }) } func TestMetric_Type(t *testing.T) { @@ -63,6 +75,8 @@ func TestMetric_Gauge(t *testing.T) { fillTestGauge(ms.SetEmptyGauge()) assert.Equal(t, MetricTypeGauge, ms.Type()) assert.Equal(t, generateTestGauge(), ms.Gauge()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetEmptyGauge() }) } func TestMetric_CopyTo_Gauge(t *testing.T) { @@ -71,6 +85,8 @@ func TestMetric_CopyTo_Gauge(t *testing.T) { dest := NewMetric() ms.CopyTo(dest) assert.Equal(t, ms, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) } func TestMetric_Sum(t *testing.T) { @@ -78,6 +94,8 @@ func TestMetric_Sum(t *testing.T) { fillTestSum(ms.SetEmptySum()) assert.Equal(t, MetricTypeSum, ms.Type()) assert.Equal(t, generateTestSum(), ms.Sum()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetEmptySum() }) } func TestMetric_CopyTo_Sum(t *testing.T) { @@ -86,6 +104,8 @@ func TestMetric_CopyTo_Sum(t *testing.T) { dest := NewMetric() ms.CopyTo(dest) assert.Equal(t, ms, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) } func TestMetric_Histogram(t *testing.T) { @@ -93,6 +113,8 @@ func TestMetric_Histogram(t *testing.T) { fillTestHistogram(ms.SetEmptyHistogram()) assert.Equal(t, MetricTypeHistogram, ms.Type()) assert.Equal(t, generateTestHistogram(), ms.Histogram()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetEmptyHistogram() }) } func TestMetric_CopyTo_Histogram(t *testing.T) { @@ -101,6 +123,8 @@ func TestMetric_CopyTo_Histogram(t *testing.T) { dest := NewMetric() ms.CopyTo(dest) assert.Equal(t, ms, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) } func TestMetric_ExponentialHistogram(t *testing.T) { @@ -108,6 +132,8 @@ func TestMetric_ExponentialHistogram(t *testing.T) { fillTestExponentialHistogram(ms.SetEmptyExponentialHistogram()) assert.Equal(t, MetricTypeExponentialHistogram, ms.Type()) assert.Equal(t, generateTestExponentialHistogram(), ms.ExponentialHistogram()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetEmptyExponentialHistogram() }) } func TestMetric_CopyTo_ExponentialHistogram(t *testing.T) { @@ -116,6 +142,8 @@ func TestMetric_CopyTo_ExponentialHistogram(t *testing.T) { dest := NewMetric() ms.CopyTo(dest) assert.Equal(t, ms, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) } func TestMetric_Summary(t *testing.T) { @@ -123,6 +151,8 @@ func TestMetric_Summary(t *testing.T) { fillTestSummary(ms.SetEmptySummary()) assert.Equal(t, MetricTypeSummary, ms.Type()) assert.Equal(t, generateTestSummary(), ms.Summary()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newMetric(&otlpmetrics.Metric{}, &sharedState).SetEmptySummary() }) } func TestMetric_CopyTo_Summary(t *testing.T) { @@ -131,6 +161,8 @@ func TestMetric_CopyTo_Summary(t *testing.T) { dest := NewMetric() ms.CopyTo(dest) assert.Equal(t, ms, dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newMetric(&otlpmetrics.Metric{}, &sharedState)) }) } func generateTestMetric() Metric { @@ -144,5 +176,5 @@ func fillTestMetric(tv Metric) { tv.orig.Description = "test_description" tv.orig.Unit = "1" tv.orig.Data = &otlpmetrics.Metric_Sum{Sum: &otlpmetrics.Sum{}} - fillTestSum(newSum(tv.orig.GetSum())) + fillTestSum(newSum(tv.orig.GetSum(), tv.state)) } diff --git a/pdata/pmetric/generated_metricslice.go b/pdata/pmetric/generated_metricslice.go index a4e3b7940cf..30d2e0c1f67 100644 --- a/pdata/pmetric/generated_metricslice.go +++ b/pdata/pmetric/generated_metricslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewMetricSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type MetricSlice struct { - orig *[]*otlpmetrics.Metric + orig *[]*otlpmetrics.Metric + state *internal.State } -func newMetricSlice(orig *[]*otlpmetrics.Metric) MetricSlice { - return MetricSlice{orig} +func newMetricSlice(orig *[]*otlpmetrics.Metric, state *internal.State) MetricSlice { + return MetricSlice{orig: orig, state: state} } // NewMetricSlice creates a MetricSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewMetricSlice() MetricSlice { orig := []*otlpmetrics.Metric(nil) - return newMetricSlice(&orig) + state := internal.StateMutable + return newMetricSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es MetricSlice) Len() int { // ... // Do something with the element // } func (es MetricSlice) At(i int) Metric { - return newMetric((*es.orig)[i]) + return newMetric((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es MetricSlice) At(i int) Metric { // // Here should set all the values for e. // } func (es MetricSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es MetricSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty Metric. // It returns the newly added Metric. func (es MetricSlice) AppendEmpty() Metric { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.Metric{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es MetricSlice) AppendEmpty() Metric { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es MetricSlice) MoveAndAppendTo(dest MetricSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es MetricSlice) MoveAndAppendTo(dest MetricSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es MetricSlice) RemoveIf(f func(Metric) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es MetricSlice) RemoveIf(f func(Metric) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es MetricSlice) CopyTo(dest MetricSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newMetric((*es.orig)[i]).CopyTo(newMetric((*dest.orig)[i])) + newMetric((*es.orig)[i], es.state).CopyTo(newMetric((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es MetricSlice) CopyTo(dest MetricSlice) { wrappers := make([]*otlpmetrics.Metric, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newMetric((*es.orig)[i]).CopyTo(newMetric(wrappers[i])) + newMetric((*es.orig)[i], es.state).CopyTo(newMetric(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es MetricSlice) CopyTo(dest MetricSlice) { // provided less function so that two instances of MetricSlice // can be compared. func (es MetricSlice) Sort(less func(a, b Metric) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_metricslice_test.go b/pdata/pmetric/generated_metricslice_test.go index 49470381cca..cb89ca8beab 100644 --- a/pdata/pmetric/generated_metricslice_test.go +++ b/pdata/pmetric/generated_metricslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestMetricSlice(t *testing.T) { es := NewMetricSlice() assert.Equal(t, 0, es.Len()) - es = newMetricSlice(&[]*otlpmetrics.Metric{}) + state := internal.StateMutable + es = newMetricSlice(&[]*otlpmetrics.Metric{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewMetric() @@ -32,6 +34,19 @@ func TestMetricSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestMetricSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newMetricSlice(&[]*otlpmetrics.Metric{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewMetricSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestMetricSlice_CopyTo(t *testing.T) { dest := NewMetricSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestMetricSlice(es MetricSlice) { *es.orig = make([]*otlpmetrics.Metric, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.Metric{} - fillTestMetric(newMetric((*es.orig)[i])) + fillTestMetric(newMetric((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_numberdatapoint.go b/pdata/pmetric/generated_numberdatapoint.go index 67caecd618e..bc47c4747d1 100644 --- a/pdata/pmetric/generated_numberdatapoint.go +++ b/pdata/pmetric/generated_numberdatapoint.go @@ -20,11 +20,12 @@ import ( // Must use NewNumberDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type NumberDataPoint struct { - orig *otlpmetrics.NumberDataPoint + orig *otlpmetrics.NumberDataPoint + state *internal.State } -func newNumberDataPoint(orig *otlpmetrics.NumberDataPoint) NumberDataPoint { - return NumberDataPoint{orig} +func newNumberDataPoint(orig *otlpmetrics.NumberDataPoint, state *internal.State) NumberDataPoint { + return NumberDataPoint{orig: orig, state: state} } // NewNumberDataPoint creates a new empty NumberDataPoint. @@ -32,19 +33,22 @@ func newNumberDataPoint(orig *otlpmetrics.NumberDataPoint) NumberDataPoint { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewNumberDataPoint() NumberDataPoint { - return newNumberDataPoint(&otlpmetrics.NumberDataPoint{}) + state := internal.StateMutable + return newNumberDataPoint(&otlpmetrics.NumberDataPoint{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms NumberDataPoint) MoveTo(dest NumberDataPoint) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.NumberDataPoint{} } // Attributes returns the Attributes associated with this NumberDataPoint. func (ms NumberDataPoint) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this NumberDataPoint. @@ -54,6 +58,7 @@ func (ms NumberDataPoint) StartTimestamp() pcommon.Timestamp { // SetStartTimestamp replaces the starttimestamp associated with this NumberDataPoint. func (ms NumberDataPoint) SetStartTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } @@ -64,6 +69,7 @@ func (ms NumberDataPoint) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this NumberDataPoint. func (ms NumberDataPoint) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -86,6 +92,7 @@ func (ms NumberDataPoint) DoubleValue() float64 { // SetDoubleValue replaces the double associated with this NumberDataPoint. func (ms NumberDataPoint) SetDoubleValue(v float64) { + ms.state.AssertMutable() ms.orig.Value = &otlpmetrics.NumberDataPoint_AsDouble{ AsDouble: v, } @@ -98,6 +105,7 @@ func (ms NumberDataPoint) IntValue() int64 { // SetIntValue replaces the int associated with this NumberDataPoint. func (ms NumberDataPoint) SetIntValue(v int64) { + ms.state.AssertMutable() ms.orig.Value = &otlpmetrics.NumberDataPoint_AsInt{ AsInt: v, } @@ -105,7 +113,7 @@ func (ms NumberDataPoint) SetIntValue(v int64) { // Exemplars returns the Exemplars associated with this NumberDataPoint. func (ms NumberDataPoint) Exemplars() ExemplarSlice { - return newExemplarSlice(&ms.orig.Exemplars) + return newExemplarSlice(&ms.orig.Exemplars, ms.state) } // Flags returns the flags associated with this NumberDataPoint. @@ -115,11 +123,13 @@ func (ms NumberDataPoint) Flags() DataPointFlags { // SetFlags replaces the flags associated with this NumberDataPoint. func (ms NumberDataPoint) SetFlags(v DataPointFlags) { + ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms NumberDataPoint) CopyTo(dest NumberDataPoint) { + dest.state.AssertMutable() ms.Attributes().CopyTo(dest.Attributes()) dest.SetStartTimestamp(ms.StartTimestamp()) dest.SetTimestamp(ms.Timestamp()) diff --git a/pdata/pmetric/generated_numberdatapoint_test.go b/pdata/pmetric/generated_numberdatapoint_test.go index c54c8adffc3..2c7cedd7ff6 100644 --- a/pdata/pmetric/generated_numberdatapoint_test.go +++ b/pdata/pmetric/generated_numberdatapoint_test.go @@ -22,6 +22,9 @@ func TestNumberDataPoint_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewNumberDataPoint(), ms) assert.Equal(t, generateTestNumberDataPoint(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newNumberDataPoint(&otlpmetrics.NumberDataPoint{}, &sharedState)) }) + assert.Panics(t, func() { newNumberDataPoint(&otlpmetrics.NumberDataPoint{}, &sharedState).MoveTo(dest) }) } func TestNumberDataPoint_CopyTo(t *testing.T) { @@ -32,6 +35,8 @@ func TestNumberDataPoint_CopyTo(t *testing.T) { orig = generateTestNumberDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newNumberDataPoint(&otlpmetrics.NumberDataPoint{}, &sharedState)) }) } func TestNumberDataPoint_Attributes(t *testing.T) { @@ -68,6 +73,10 @@ func TestNumberDataPoint_DoubleValue(t *testing.T) { ms.SetDoubleValue(float64(17.13)) assert.Equal(t, float64(17.13), ms.DoubleValue()) assert.Equal(t, NumberDataPointValueTypeDouble, ms.ValueType()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newNumberDataPoint(&otlpmetrics.NumberDataPoint{}, &sharedState).SetDoubleValue(float64(17.13)) + }) } func TestNumberDataPoint_IntValue(t *testing.T) { @@ -76,6 +85,8 @@ func TestNumberDataPoint_IntValue(t *testing.T) { ms.SetIntValue(int64(17)) assert.Equal(t, int64(17), ms.IntValue()) assert.Equal(t, NumberDataPointValueTypeInt, ms.ValueType()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newNumberDataPoint(&otlpmetrics.NumberDataPoint{}, &sharedState).SetIntValue(int64(17)) }) } func TestNumberDataPoint_Exemplars(t *testing.T) { @@ -100,10 +111,10 @@ func generateTestNumberDataPoint() NumberDataPoint { } func fillTestNumberDataPoint(tv NumberDataPoint) { - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.StartTimeUnixNano = 1234567890 tv.orig.TimeUnixNano = 1234567890 tv.orig.Value = &otlpmetrics.NumberDataPoint_AsDouble{AsDouble: float64(17.13)} - fillTestExemplarSlice(newExemplarSlice(&tv.orig.Exemplars)) + fillTestExemplarSlice(newExemplarSlice(&tv.orig.Exemplars, tv.state)) tv.orig.Flags = 1 } diff --git a/pdata/pmetric/generated_numberdatapointslice.go b/pdata/pmetric/generated_numberdatapointslice.go index 777a7209424..13cd71b7278 100644 --- a/pdata/pmetric/generated_numberdatapointslice.go +++ b/pdata/pmetric/generated_numberdatapointslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewNumberDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type NumberDataPointSlice struct { - orig *[]*otlpmetrics.NumberDataPoint + orig *[]*otlpmetrics.NumberDataPoint + state *internal.State } -func newNumberDataPointSlice(orig *[]*otlpmetrics.NumberDataPoint) NumberDataPointSlice { - return NumberDataPointSlice{orig} +func newNumberDataPointSlice(orig *[]*otlpmetrics.NumberDataPoint, state *internal.State) NumberDataPointSlice { + return NumberDataPointSlice{orig: orig, state: state} } // NewNumberDataPointSlice creates a NumberDataPointSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewNumberDataPointSlice() NumberDataPointSlice { orig := []*otlpmetrics.NumberDataPoint(nil) - return newNumberDataPointSlice(&orig) + state := internal.StateMutable + return newNumberDataPointSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es NumberDataPointSlice) Len() int { // ... // Do something with the element // } func (es NumberDataPointSlice) At(i int) NumberDataPoint { - return newNumberDataPoint((*es.orig)[i]) + return newNumberDataPoint((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es NumberDataPointSlice) At(i int) NumberDataPoint { // // Here should set all the values for e. // } func (es NumberDataPointSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es NumberDataPointSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty NumberDataPoint. // It returns the newly added NumberDataPoint. func (es NumberDataPointSlice) AppendEmpty() NumberDataPoint { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.NumberDataPoint{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es NumberDataPointSlice) AppendEmpty() NumberDataPoint { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es NumberDataPointSlice) MoveAndAppendTo(dest NumberDataPointSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es NumberDataPointSlice) MoveAndAppendTo(dest NumberDataPointSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es NumberDataPointSlice) RemoveIf(f func(NumberDataPoint) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es NumberDataPointSlice) RemoveIf(f func(NumberDataPoint) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es NumberDataPointSlice) CopyTo(dest NumberDataPointSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newNumberDataPoint((*es.orig)[i]).CopyTo(newNumberDataPoint((*dest.orig)[i])) + newNumberDataPoint((*es.orig)[i], es.state).CopyTo(newNumberDataPoint((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es NumberDataPointSlice) CopyTo(dest NumberDataPointSlice) { wrappers := make([]*otlpmetrics.NumberDataPoint, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newNumberDataPoint((*es.orig)[i]).CopyTo(newNumberDataPoint(wrappers[i])) + newNumberDataPoint((*es.orig)[i], es.state).CopyTo(newNumberDataPoint(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es NumberDataPointSlice) CopyTo(dest NumberDataPointSlice) { // provided less function so that two instances of NumberDataPointSlice // can be compared. func (es NumberDataPointSlice) Sort(less func(a, b NumberDataPoint) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_numberdatapointslice_test.go b/pdata/pmetric/generated_numberdatapointslice_test.go index aeda43533f8..6bc35ff03c2 100644 --- a/pdata/pmetric/generated_numberdatapointslice_test.go +++ b/pdata/pmetric/generated_numberdatapointslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestNumberDataPointSlice(t *testing.T) { es := NewNumberDataPointSlice() assert.Equal(t, 0, es.Len()) - es = newNumberDataPointSlice(&[]*otlpmetrics.NumberDataPoint{}) + state := internal.StateMutable + es = newNumberDataPointSlice(&[]*otlpmetrics.NumberDataPoint{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewNumberDataPoint() @@ -32,6 +34,19 @@ func TestNumberDataPointSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestNumberDataPointSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newNumberDataPointSlice(&[]*otlpmetrics.NumberDataPoint{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewNumberDataPointSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestNumberDataPointSlice_CopyTo(t *testing.T) { dest := NewNumberDataPointSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestNumberDataPointSlice(es NumberDataPointSlice) { *es.orig = make([]*otlpmetrics.NumberDataPoint, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.NumberDataPoint{} - fillTestNumberDataPoint(newNumberDataPoint((*es.orig)[i])) + fillTestNumberDataPoint(newNumberDataPoint((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_resourcemetrics.go b/pdata/pmetric/generated_resourcemetrics.go index 520de76c9c3..43622f3f806 100644 --- a/pdata/pmetric/generated_resourcemetrics.go +++ b/pdata/pmetric/generated_resourcemetrics.go @@ -20,11 +20,12 @@ import ( // Must use NewResourceMetrics function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceMetrics struct { - orig *otlpmetrics.ResourceMetrics + orig *otlpmetrics.ResourceMetrics + state *internal.State } -func newResourceMetrics(orig *otlpmetrics.ResourceMetrics) ResourceMetrics { - return ResourceMetrics{orig} +func newResourceMetrics(orig *otlpmetrics.ResourceMetrics, state *internal.State) ResourceMetrics { + return ResourceMetrics{orig: orig, state: state} } // NewResourceMetrics creates a new empty ResourceMetrics. @@ -32,19 +33,22 @@ func newResourceMetrics(orig *otlpmetrics.ResourceMetrics) ResourceMetrics { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceMetrics() ResourceMetrics { - return newResourceMetrics(&otlpmetrics.ResourceMetrics{}) + state := internal.StateMutable + return newResourceMetrics(&otlpmetrics.ResourceMetrics{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceMetrics) MoveTo(dest ResourceMetrics) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.ResourceMetrics{} } // Resource returns the resource associated with this ResourceMetrics. func (ms ResourceMetrics) Resource() pcommon.Resource { - return pcommon.Resource(internal.NewResource(&ms.orig.Resource)) + return pcommon.Resource(internal.NewResource(&ms.orig.Resource, ms.state)) } // SchemaUrl returns the schemaurl associated with this ResourceMetrics. @@ -54,16 +58,18 @@ func (ms ResourceMetrics) SchemaUrl() string { // SetSchemaUrl replaces the schemaurl associated with this ResourceMetrics. func (ms ResourceMetrics) SetSchemaUrl(v string) { + ms.state.AssertMutable() ms.orig.SchemaUrl = v } // ScopeMetrics returns the ScopeMetrics associated with this ResourceMetrics. func (ms ResourceMetrics) ScopeMetrics() ScopeMetricsSlice { - return newScopeMetricsSlice(&ms.orig.ScopeMetrics) + return newScopeMetricsSlice(&ms.orig.ScopeMetrics, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceMetrics) CopyTo(dest ResourceMetrics) { + dest.state.AssertMutable() ms.Resource().CopyTo(dest.Resource()) dest.SetSchemaUrl(ms.SchemaUrl()) ms.ScopeMetrics().CopyTo(dest.ScopeMetrics()) diff --git a/pdata/pmetric/generated_resourcemetrics_test.go b/pdata/pmetric/generated_resourcemetrics_test.go index d7bba42cc98..7bdfec11beb 100644 --- a/pdata/pmetric/generated_resourcemetrics_test.go +++ b/pdata/pmetric/generated_resourcemetrics_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestResourceMetrics_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewResourceMetrics(), ms) assert.Equal(t, generateTestResourceMetrics(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newResourceMetrics(&otlpmetrics.ResourceMetrics{}, &sharedState)) }) + assert.Panics(t, func() { newResourceMetrics(&otlpmetrics.ResourceMetrics{}, &sharedState).MoveTo(dest) }) } func TestResourceMetrics_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestResourceMetrics_CopyTo(t *testing.T) { orig = generateTestResourceMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newResourceMetrics(&otlpmetrics.ResourceMetrics{}, &sharedState)) }) } func TestResourceMetrics_Resource(t *testing.T) { @@ -44,6 +50,10 @@ func TestResourceMetrics_SchemaUrl(t *testing.T) { assert.Equal(t, "", ms.SchemaUrl()) ms.SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.5.0", ms.SchemaUrl()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newResourceMetrics(&otlpmetrics.ResourceMetrics{}, &sharedState).SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") + }) } func TestResourceMetrics_ScopeMetrics(t *testing.T) { @@ -60,7 +70,7 @@ func generateTestResourceMetrics() ResourceMetrics { } func fillTestResourceMetrics(tv ResourceMetrics) { - internal.FillTestResource(internal.NewResource(&tv.orig.Resource)) + internal.FillTestResource(internal.NewResource(&tv.orig.Resource, tv.state)) tv.orig.SchemaUrl = "https://opentelemetry.io/schemas/1.5.0" - fillTestScopeMetricsSlice(newScopeMetricsSlice(&tv.orig.ScopeMetrics)) + fillTestScopeMetricsSlice(newScopeMetricsSlice(&tv.orig.ScopeMetrics, tv.state)) } diff --git a/pdata/pmetric/generated_resourcemetricsslice.go b/pdata/pmetric/generated_resourcemetricsslice.go index 4f089354bda..b25fdc721ad 100644 --- a/pdata/pmetric/generated_resourcemetricsslice.go +++ b/pdata/pmetric/generated_resourcemetricsslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewResourceMetricsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceMetricsSlice struct { - orig *[]*otlpmetrics.ResourceMetrics + orig *[]*otlpmetrics.ResourceMetrics + state *internal.State } -func newResourceMetricsSlice(orig *[]*otlpmetrics.ResourceMetrics) ResourceMetricsSlice { - return ResourceMetricsSlice{orig} +func newResourceMetricsSlice(orig *[]*otlpmetrics.ResourceMetrics, state *internal.State) ResourceMetricsSlice { + return ResourceMetricsSlice{orig: orig, state: state} } // NewResourceMetricsSlice creates a ResourceMetricsSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceMetricsSlice() ResourceMetricsSlice { orig := []*otlpmetrics.ResourceMetrics(nil) - return newResourceMetricsSlice(&orig) + state := internal.StateMutable + return newResourceMetricsSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ResourceMetricsSlice) Len() int { // ... // Do something with the element // } func (es ResourceMetricsSlice) At(i int) ResourceMetrics { - return newResourceMetrics((*es.orig)[i]) + return newResourceMetrics((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ResourceMetricsSlice) At(i int) ResourceMetrics { // // Here should set all the values for e. // } func (es ResourceMetricsSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ResourceMetricsSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ResourceMetrics. // It returns the newly added ResourceMetrics. func (es ResourceMetricsSlice) AppendEmpty() ResourceMetrics { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.ResourceMetrics{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ResourceMetricsSlice) AppendEmpty() ResourceMetrics { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceMetricsSlice) MoveAndAppendTo(dest ResourceMetricsSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ResourceMetricsSlice) MoveAndAppendTo(dest ResourceMetricsSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceMetricsSlice) RemoveIf(f func(ResourceMetrics) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ResourceMetricsSlice) RemoveIf(f func(ResourceMetrics) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceMetricsSlice) CopyTo(dest ResourceMetricsSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newResourceMetrics((*es.orig)[i]).CopyTo(newResourceMetrics((*dest.orig)[i])) + newResourceMetrics((*es.orig)[i], es.state).CopyTo(newResourceMetrics((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ResourceMetricsSlice) CopyTo(dest ResourceMetricsSlice) { wrappers := make([]*otlpmetrics.ResourceMetrics, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newResourceMetrics((*es.orig)[i]).CopyTo(newResourceMetrics(wrappers[i])) + newResourceMetrics((*es.orig)[i], es.state).CopyTo(newResourceMetrics(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ResourceMetricsSlice) CopyTo(dest ResourceMetricsSlice) { // provided less function so that two instances of ResourceMetricsSlice // can be compared. func (es ResourceMetricsSlice) Sort(less func(a, b ResourceMetrics) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_resourcemetricsslice_test.go b/pdata/pmetric/generated_resourcemetricsslice_test.go index acf358f91bd..869f7a37503 100644 --- a/pdata/pmetric/generated_resourcemetricsslice_test.go +++ b/pdata/pmetric/generated_resourcemetricsslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestResourceMetricsSlice(t *testing.T) { es := NewResourceMetricsSlice() assert.Equal(t, 0, es.Len()) - es = newResourceMetricsSlice(&[]*otlpmetrics.ResourceMetrics{}) + state := internal.StateMutable + es = newResourceMetricsSlice(&[]*otlpmetrics.ResourceMetrics{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceMetrics() @@ -32,6 +34,19 @@ func TestResourceMetricsSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestResourceMetricsSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newResourceMetricsSlice(&[]*otlpmetrics.ResourceMetrics{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewResourceMetricsSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestResourceMetricsSlice_CopyTo(t *testing.T) { dest := NewResourceMetricsSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestResourceMetricsSlice(es ResourceMetricsSlice) { *es.orig = make([]*otlpmetrics.ResourceMetrics, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.ResourceMetrics{} - fillTestResourceMetrics(newResourceMetrics((*es.orig)[i])) + fillTestResourceMetrics(newResourceMetrics((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_scopemetrics.go b/pdata/pmetric/generated_scopemetrics.go index f4ea50a31f8..1151c36dae3 100644 --- a/pdata/pmetric/generated_scopemetrics.go +++ b/pdata/pmetric/generated_scopemetrics.go @@ -20,11 +20,12 @@ import ( // Must use NewScopeMetrics function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeMetrics struct { - orig *otlpmetrics.ScopeMetrics + orig *otlpmetrics.ScopeMetrics + state *internal.State } -func newScopeMetrics(orig *otlpmetrics.ScopeMetrics) ScopeMetrics { - return ScopeMetrics{orig} +func newScopeMetrics(orig *otlpmetrics.ScopeMetrics, state *internal.State) ScopeMetrics { + return ScopeMetrics{orig: orig, state: state} } // NewScopeMetrics creates a new empty ScopeMetrics. @@ -32,19 +33,22 @@ func newScopeMetrics(orig *otlpmetrics.ScopeMetrics) ScopeMetrics { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeMetrics() ScopeMetrics { - return newScopeMetrics(&otlpmetrics.ScopeMetrics{}) + state := internal.StateMutable + return newScopeMetrics(&otlpmetrics.ScopeMetrics{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeMetrics) MoveTo(dest ScopeMetrics) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.ScopeMetrics{} } // Scope returns the scope associated with this ScopeMetrics. func (ms ScopeMetrics) Scope() pcommon.InstrumentationScope { - return pcommon.InstrumentationScope(internal.NewInstrumentationScope(&ms.orig.Scope)) + return pcommon.InstrumentationScope(internal.NewInstrumentationScope(&ms.orig.Scope, ms.state)) } // SchemaUrl returns the schemaurl associated with this ScopeMetrics. @@ -54,16 +58,18 @@ func (ms ScopeMetrics) SchemaUrl() string { // SetSchemaUrl replaces the schemaurl associated with this ScopeMetrics. func (ms ScopeMetrics) SetSchemaUrl(v string) { + ms.state.AssertMutable() ms.orig.SchemaUrl = v } // Metrics returns the Metrics associated with this ScopeMetrics. func (ms ScopeMetrics) Metrics() MetricSlice { - return newMetricSlice(&ms.orig.Metrics) + return newMetricSlice(&ms.orig.Metrics, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeMetrics) CopyTo(dest ScopeMetrics) { + dest.state.AssertMutable() ms.Scope().CopyTo(dest.Scope()) dest.SetSchemaUrl(ms.SchemaUrl()) ms.Metrics().CopyTo(dest.Metrics()) diff --git a/pdata/pmetric/generated_scopemetrics_test.go b/pdata/pmetric/generated_scopemetrics_test.go index 4734e7efc50..451c4743657 100644 --- a/pdata/pmetric/generated_scopemetrics_test.go +++ b/pdata/pmetric/generated_scopemetrics_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestScopeMetrics_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewScopeMetrics(), ms) assert.Equal(t, generateTestScopeMetrics(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newScopeMetrics(&otlpmetrics.ScopeMetrics{}, &sharedState)) }) + assert.Panics(t, func() { newScopeMetrics(&otlpmetrics.ScopeMetrics{}, &sharedState).MoveTo(dest) }) } func TestScopeMetrics_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestScopeMetrics_CopyTo(t *testing.T) { orig = generateTestScopeMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newScopeMetrics(&otlpmetrics.ScopeMetrics{}, &sharedState)) }) } func TestScopeMetrics_Scope(t *testing.T) { @@ -44,6 +50,10 @@ func TestScopeMetrics_SchemaUrl(t *testing.T) { assert.Equal(t, "", ms.SchemaUrl()) ms.SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.5.0", ms.SchemaUrl()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newScopeMetrics(&otlpmetrics.ScopeMetrics{}, &sharedState).SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") + }) } func TestScopeMetrics_Metrics(t *testing.T) { @@ -60,7 +70,7 @@ func generateTestScopeMetrics() ScopeMetrics { } func fillTestScopeMetrics(tv ScopeMetrics) { - internal.FillTestInstrumentationScope(internal.NewInstrumentationScope(&tv.orig.Scope)) + internal.FillTestInstrumentationScope(internal.NewInstrumentationScope(&tv.orig.Scope, tv.state)) tv.orig.SchemaUrl = "https://opentelemetry.io/schemas/1.5.0" - fillTestMetricSlice(newMetricSlice(&tv.orig.Metrics)) + fillTestMetricSlice(newMetricSlice(&tv.orig.Metrics, tv.state)) } diff --git a/pdata/pmetric/generated_scopemetricsslice.go b/pdata/pmetric/generated_scopemetricsslice.go index 90cc4979e53..d2bbe61085c 100644 --- a/pdata/pmetric/generated_scopemetricsslice.go +++ b/pdata/pmetric/generated_scopemetricsslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewScopeMetricsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeMetricsSlice struct { - orig *[]*otlpmetrics.ScopeMetrics + orig *[]*otlpmetrics.ScopeMetrics + state *internal.State } -func newScopeMetricsSlice(orig *[]*otlpmetrics.ScopeMetrics) ScopeMetricsSlice { - return ScopeMetricsSlice{orig} +func newScopeMetricsSlice(orig *[]*otlpmetrics.ScopeMetrics, state *internal.State) ScopeMetricsSlice { + return ScopeMetricsSlice{orig: orig, state: state} } // NewScopeMetricsSlice creates a ScopeMetricsSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeMetricsSlice() ScopeMetricsSlice { orig := []*otlpmetrics.ScopeMetrics(nil) - return newScopeMetricsSlice(&orig) + state := internal.StateMutable + return newScopeMetricsSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ScopeMetricsSlice) Len() int { // ... // Do something with the element // } func (es ScopeMetricsSlice) At(i int) ScopeMetrics { - return newScopeMetrics((*es.orig)[i]) + return newScopeMetrics((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ScopeMetricsSlice) At(i int) ScopeMetrics { // // Here should set all the values for e. // } func (es ScopeMetricsSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ScopeMetricsSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ScopeMetrics. // It returns the newly added ScopeMetrics. func (es ScopeMetricsSlice) AppendEmpty() ScopeMetrics { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.ScopeMetrics{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ScopeMetricsSlice) AppendEmpty() ScopeMetrics { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeMetricsSlice) MoveAndAppendTo(dest ScopeMetricsSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ScopeMetricsSlice) MoveAndAppendTo(dest ScopeMetricsSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeMetricsSlice) RemoveIf(f func(ScopeMetrics) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ScopeMetricsSlice) RemoveIf(f func(ScopeMetrics) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeMetricsSlice) CopyTo(dest ScopeMetricsSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newScopeMetrics((*es.orig)[i]).CopyTo(newScopeMetrics((*dest.orig)[i])) + newScopeMetrics((*es.orig)[i], es.state).CopyTo(newScopeMetrics((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ScopeMetricsSlice) CopyTo(dest ScopeMetricsSlice) { wrappers := make([]*otlpmetrics.ScopeMetrics, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newScopeMetrics((*es.orig)[i]).CopyTo(newScopeMetrics(wrappers[i])) + newScopeMetrics((*es.orig)[i], es.state).CopyTo(newScopeMetrics(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ScopeMetricsSlice) CopyTo(dest ScopeMetricsSlice) { // provided less function so that two instances of ScopeMetricsSlice // can be compared. func (es ScopeMetricsSlice) Sort(less func(a, b ScopeMetrics) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_scopemetricsslice_test.go b/pdata/pmetric/generated_scopemetricsslice_test.go index f6a4c3f5960..b0903bc256e 100644 --- a/pdata/pmetric/generated_scopemetricsslice_test.go +++ b/pdata/pmetric/generated_scopemetricsslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestScopeMetricsSlice(t *testing.T) { es := NewScopeMetricsSlice() assert.Equal(t, 0, es.Len()) - es = newScopeMetricsSlice(&[]*otlpmetrics.ScopeMetrics{}) + state := internal.StateMutable + es = newScopeMetricsSlice(&[]*otlpmetrics.ScopeMetrics{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeMetrics() @@ -32,6 +34,19 @@ func TestScopeMetricsSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestScopeMetricsSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newScopeMetricsSlice(&[]*otlpmetrics.ScopeMetrics{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewScopeMetricsSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestScopeMetricsSlice_CopyTo(t *testing.T) { dest := NewScopeMetricsSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestScopeMetricsSlice(es ScopeMetricsSlice) { *es.orig = make([]*otlpmetrics.ScopeMetrics, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.ScopeMetrics{} - fillTestScopeMetrics(newScopeMetrics((*es.orig)[i])) + fillTestScopeMetrics(newScopeMetrics((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_sum.go b/pdata/pmetric/generated_sum.go index 13cfe7d3f75..7def0749aa5 100644 --- a/pdata/pmetric/generated_sum.go +++ b/pdata/pmetric/generated_sum.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewSum function to create new instances. // Important: zero-initialized instance is not valid for use. type Sum struct { - orig *otlpmetrics.Sum + orig *otlpmetrics.Sum + state *internal.State } -func newSum(orig *otlpmetrics.Sum) Sum { - return Sum{orig} +func newSum(orig *otlpmetrics.Sum, state *internal.State) Sum { + return Sum{orig: orig, state: state} } // NewSum creates a new empty Sum. @@ -30,12 +32,15 @@ func newSum(orig *otlpmetrics.Sum) Sum { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSum() Sum { - return newSum(&otlpmetrics.Sum{}) + state := internal.StateMutable + return newSum(&otlpmetrics.Sum{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Sum) MoveTo(dest Sum) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.Sum{} } @@ -47,6 +52,7 @@ func (ms Sum) AggregationTemporality() AggregationTemporality { // SetAggregationTemporality replaces the aggregationtemporality associated with this Sum. func (ms Sum) SetAggregationTemporality(v AggregationTemporality) { + ms.state.AssertMutable() ms.orig.AggregationTemporality = otlpmetrics.AggregationTemporality(v) } @@ -57,16 +63,18 @@ func (ms Sum) IsMonotonic() bool { // SetIsMonotonic replaces the ismonotonic associated with this Sum. func (ms Sum) SetIsMonotonic(v bool) { + ms.state.AssertMutable() ms.orig.IsMonotonic = v } // DataPoints returns the DataPoints associated with this Sum. func (ms Sum) DataPoints() NumberDataPointSlice { - return newNumberDataPointSlice(&ms.orig.DataPoints) + return newNumberDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Sum) CopyTo(dest Sum) { + dest.state.AssertMutable() dest.SetAggregationTemporality(ms.AggregationTemporality()) dest.SetIsMonotonic(ms.IsMonotonic()) ms.DataPoints().CopyTo(dest.DataPoints()) diff --git a/pdata/pmetric/generated_sum_test.go b/pdata/pmetric/generated_sum_test.go index f2590feea06..98f3574b10f 100644 --- a/pdata/pmetric/generated_sum_test.go +++ b/pdata/pmetric/generated_sum_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,6 +21,9 @@ func TestSum_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSum(), ms) assert.Equal(t, generateTestSum(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newSum(&otlpmetrics.Sum{}, &sharedState)) }) + assert.Panics(t, func() { newSum(&otlpmetrics.Sum{}, &sharedState).MoveTo(dest) }) } func TestSum_CopyTo(t *testing.T) { @@ -30,6 +34,8 @@ func TestSum_CopyTo(t *testing.T) { orig = generateTestSum() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newSum(&otlpmetrics.Sum{}, &sharedState)) }) } func TestSum_AggregationTemporality(t *testing.T) { @@ -45,6 +51,8 @@ func TestSum_IsMonotonic(t *testing.T) { assert.Equal(t, false, ms.IsMonotonic()) ms.SetIsMonotonic(true) assert.Equal(t, true, ms.IsMonotonic()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSum(&otlpmetrics.Sum{}, &sharedState).SetIsMonotonic(true) }) } func TestSum_DataPoints(t *testing.T) { @@ -63,5 +71,5 @@ func generateTestSum() Sum { func fillTestSum(tv Sum) { tv.orig.AggregationTemporality = otlpmetrics.AggregationTemporality(1) tv.orig.IsMonotonic = true - fillTestNumberDataPointSlice(newNumberDataPointSlice(&tv.orig.DataPoints)) + fillTestNumberDataPointSlice(newNumberDataPointSlice(&tv.orig.DataPoints, tv.state)) } diff --git a/pdata/pmetric/generated_summary.go b/pdata/pmetric/generated_summary.go index bea3b764b5d..64fbffbefd3 100644 --- a/pdata/pmetric/generated_summary.go +++ b/pdata/pmetric/generated_summary.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewSummary function to create new instances. // Important: zero-initialized instance is not valid for use. type Summary struct { - orig *otlpmetrics.Summary + orig *otlpmetrics.Summary + state *internal.State } -func newSummary(orig *otlpmetrics.Summary) Summary { - return Summary{orig} +func newSummary(orig *otlpmetrics.Summary, state *internal.State) Summary { + return Summary{orig: orig, state: state} } // NewSummary creates a new empty Summary. @@ -30,22 +32,26 @@ func newSummary(orig *otlpmetrics.Summary) Summary { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSummary() Summary { - return newSummary(&otlpmetrics.Summary{}) + state := internal.StateMutable + return newSummary(&otlpmetrics.Summary{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Summary) MoveTo(dest Summary) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.Summary{} } // DataPoints returns the DataPoints associated with this Summary. func (ms Summary) DataPoints() SummaryDataPointSlice { - return newSummaryDataPointSlice(&ms.orig.DataPoints) + return newSummaryDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Summary) CopyTo(dest Summary) { + dest.state.AssertMutable() ms.DataPoints().CopyTo(dest.DataPoints()) } diff --git a/pdata/pmetric/generated_summary_test.go b/pdata/pmetric/generated_summary_test.go index 2f81ead8807..c592870ef8b 100644 --- a/pdata/pmetric/generated_summary_test.go +++ b/pdata/pmetric/generated_summary_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestSummary_MoveTo(t *testing.T) { @@ -18,6 +21,9 @@ func TestSummary_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSummary(), ms) assert.Equal(t, generateTestSummary(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newSummary(&otlpmetrics.Summary{}, &sharedState)) }) + assert.Panics(t, func() { newSummary(&otlpmetrics.Summary{}, &sharedState).MoveTo(dest) }) } func TestSummary_CopyTo(t *testing.T) { @@ -28,6 +34,8 @@ func TestSummary_CopyTo(t *testing.T) { orig = generateTestSummary() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newSummary(&otlpmetrics.Summary{}, &sharedState)) }) } func TestSummary_DataPoints(t *testing.T) { @@ -44,5 +52,5 @@ func generateTestSummary() Summary { } func fillTestSummary(tv Summary) { - fillTestSummaryDataPointSlice(newSummaryDataPointSlice(&tv.orig.DataPoints)) + fillTestSummaryDataPointSlice(newSummaryDataPointSlice(&tv.orig.DataPoints, tv.state)) } diff --git a/pdata/pmetric/generated_summarydatapoint.go b/pdata/pmetric/generated_summarydatapoint.go index 51177d69cbd..0f0f6dd1e99 100644 --- a/pdata/pmetric/generated_summarydatapoint.go +++ b/pdata/pmetric/generated_summarydatapoint.go @@ -20,11 +20,12 @@ import ( // Must use NewSummaryDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPoint struct { - orig *otlpmetrics.SummaryDataPoint + orig *otlpmetrics.SummaryDataPoint + state *internal.State } -func newSummaryDataPoint(orig *otlpmetrics.SummaryDataPoint) SummaryDataPoint { - return SummaryDataPoint{orig} +func newSummaryDataPoint(orig *otlpmetrics.SummaryDataPoint, state *internal.State) SummaryDataPoint { + return SummaryDataPoint{orig: orig, state: state} } // NewSummaryDataPoint creates a new empty SummaryDataPoint. @@ -32,19 +33,22 @@ func newSummaryDataPoint(orig *otlpmetrics.SummaryDataPoint) SummaryDataPoint { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSummaryDataPoint() SummaryDataPoint { - return newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}) + state := internal.StateMutable + return newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SummaryDataPoint) MoveTo(dest SummaryDataPoint) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.SummaryDataPoint{} } // Attributes returns the Attributes associated with this SummaryDataPoint. func (ms SummaryDataPoint) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this SummaryDataPoint. @@ -54,6 +58,7 @@ func (ms SummaryDataPoint) StartTimestamp() pcommon.Timestamp { // SetStartTimestamp replaces the starttimestamp associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetStartTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } @@ -64,6 +69,7 @@ func (ms SummaryDataPoint) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -74,6 +80,7 @@ func (ms SummaryDataPoint) Count() uint64 { // SetCount replaces the count associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetCount(v uint64) { + ms.state.AssertMutable() ms.orig.Count = v } @@ -84,12 +91,13 @@ func (ms SummaryDataPoint) Sum() float64 { // SetSum replaces the sum associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetSum(v float64) { + ms.state.AssertMutable() ms.orig.Sum = v } // QuantileValues returns the QuantileValues associated with this SummaryDataPoint. func (ms SummaryDataPoint) QuantileValues() SummaryDataPointValueAtQuantileSlice { - return newSummaryDataPointValueAtQuantileSlice(&ms.orig.QuantileValues) + return newSummaryDataPointValueAtQuantileSlice(&ms.orig.QuantileValues, ms.state) } // Flags returns the flags associated with this SummaryDataPoint. @@ -99,11 +107,13 @@ func (ms SummaryDataPoint) Flags() DataPointFlags { // SetFlags replaces the flags associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetFlags(v DataPointFlags) { + ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms SummaryDataPoint) CopyTo(dest SummaryDataPoint) { + dest.state.AssertMutable() ms.Attributes().CopyTo(dest.Attributes()) dest.SetStartTimestamp(ms.StartTimestamp()) dest.SetTimestamp(ms.Timestamp()) diff --git a/pdata/pmetric/generated_summarydatapoint_test.go b/pdata/pmetric/generated_summarydatapoint_test.go index b82d6104991..fce1e638d41 100644 --- a/pdata/pmetric/generated_summarydatapoint_test.go +++ b/pdata/pmetric/generated_summarydatapoint_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestSummaryDataPoint_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSummaryDataPoint(), ms) assert.Equal(t, generateTestSummaryDataPoint(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}, &sharedState)) }) + assert.Panics(t, func() { newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}, &sharedState).MoveTo(dest) }) } func TestSummaryDataPoint_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestSummaryDataPoint_CopyTo(t *testing.T) { orig = generateTestSummaryDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}, &sharedState)) }) } func TestSummaryDataPoint_Attributes(t *testing.T) { @@ -61,6 +67,8 @@ func TestSummaryDataPoint_Count(t *testing.T) { assert.Equal(t, uint64(0), ms.Count()) ms.SetCount(uint64(17)) assert.Equal(t, uint64(17), ms.Count()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}, &sharedState).SetCount(uint64(17)) }) } func TestSummaryDataPoint_Sum(t *testing.T) { @@ -68,6 +76,8 @@ func TestSummaryDataPoint_Sum(t *testing.T) { assert.Equal(t, float64(0.0), ms.Sum()) ms.SetSum(float64(17.13)) assert.Equal(t, float64(17.13), ms.Sum()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSummaryDataPoint(&otlpmetrics.SummaryDataPoint{}, &sharedState).SetSum(float64(17.13)) }) } func TestSummaryDataPoint_QuantileValues(t *testing.T) { @@ -92,11 +102,11 @@ func generateTestSummaryDataPoint() SummaryDataPoint { } func fillTestSummaryDataPoint(tv SummaryDataPoint) { - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.StartTimeUnixNano = 1234567890 tv.orig.TimeUnixNano = 1234567890 tv.orig.Count = uint64(17) tv.orig.Sum = float64(17.13) - fillTestSummaryDataPointValueAtQuantileSlice(newSummaryDataPointValueAtQuantileSlice(&tv.orig.QuantileValues)) + fillTestSummaryDataPointValueAtQuantileSlice(newSummaryDataPointValueAtQuantileSlice(&tv.orig.QuantileValues, tv.state)) tv.orig.Flags = 1 } diff --git a/pdata/pmetric/generated_summarydatapointslice.go b/pdata/pmetric/generated_summarydatapointslice.go index 57e895e3265..e8aa51de096 100644 --- a/pdata/pmetric/generated_summarydatapointslice.go +++ b/pdata/pmetric/generated_summarydatapointslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewSummaryDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPointSlice struct { - orig *[]*otlpmetrics.SummaryDataPoint + orig *[]*otlpmetrics.SummaryDataPoint + state *internal.State } -func newSummaryDataPointSlice(orig *[]*otlpmetrics.SummaryDataPoint) SummaryDataPointSlice { - return SummaryDataPointSlice{orig} +func newSummaryDataPointSlice(orig *[]*otlpmetrics.SummaryDataPoint, state *internal.State) SummaryDataPointSlice { + return SummaryDataPointSlice{orig: orig, state: state} } // NewSummaryDataPointSlice creates a SummaryDataPointSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSummaryDataPointSlice() SummaryDataPointSlice { orig := []*otlpmetrics.SummaryDataPoint(nil) - return newSummaryDataPointSlice(&orig) + state := internal.StateMutable + return newSummaryDataPointSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es SummaryDataPointSlice) Len() int { // ... // Do something with the element // } func (es SummaryDataPointSlice) At(i int) SummaryDataPoint { - return newSummaryDataPoint((*es.orig)[i]) + return newSummaryDataPoint((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es SummaryDataPointSlice) At(i int) SummaryDataPoint { // // Here should set all the values for e. // } func (es SummaryDataPointSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es SummaryDataPointSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty SummaryDataPoint. // It returns the newly added SummaryDataPoint. func (es SummaryDataPointSlice) AppendEmpty() SummaryDataPoint { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.SummaryDataPoint{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es SummaryDataPointSlice) AppendEmpty() SummaryDataPoint { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SummaryDataPointSlice) MoveAndAppendTo(dest SummaryDataPointSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es SummaryDataPointSlice) MoveAndAppendTo(dest SummaryDataPointSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SummaryDataPointSlice) RemoveIf(f func(SummaryDataPoint) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es SummaryDataPointSlice) RemoveIf(f func(SummaryDataPoint) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es SummaryDataPointSlice) CopyTo(dest SummaryDataPointSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newSummaryDataPoint((*es.orig)[i]).CopyTo(newSummaryDataPoint((*dest.orig)[i])) + newSummaryDataPoint((*es.orig)[i], es.state).CopyTo(newSummaryDataPoint((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es SummaryDataPointSlice) CopyTo(dest SummaryDataPointSlice) { wrappers := make([]*otlpmetrics.SummaryDataPoint, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newSummaryDataPoint((*es.orig)[i]).CopyTo(newSummaryDataPoint(wrappers[i])) + newSummaryDataPoint((*es.orig)[i], es.state).CopyTo(newSummaryDataPoint(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es SummaryDataPointSlice) CopyTo(dest SummaryDataPointSlice) { // provided less function so that two instances of SummaryDataPointSlice // can be compared. func (es SummaryDataPointSlice) Sort(less func(a, b SummaryDataPoint) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_summarydatapointslice_test.go b/pdata/pmetric/generated_summarydatapointslice_test.go index 3c917e4bfb4..10a12b45e5a 100644 --- a/pdata/pmetric/generated_summarydatapointslice_test.go +++ b/pdata/pmetric/generated_summarydatapointslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestSummaryDataPointSlice(t *testing.T) { es := NewSummaryDataPointSlice() assert.Equal(t, 0, es.Len()) - es = newSummaryDataPointSlice(&[]*otlpmetrics.SummaryDataPoint{}) + state := internal.StateMutable + es = newSummaryDataPointSlice(&[]*otlpmetrics.SummaryDataPoint{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewSummaryDataPoint() @@ -32,6 +34,19 @@ func TestSummaryDataPointSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestSummaryDataPointSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newSummaryDataPointSlice(&[]*otlpmetrics.SummaryDataPoint{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewSummaryDataPointSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestSummaryDataPointSlice_CopyTo(t *testing.T) { dest := NewSummaryDataPointSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestSummaryDataPointSlice(es SummaryDataPointSlice) { *es.orig = make([]*otlpmetrics.SummaryDataPoint, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.SummaryDataPoint{} - fillTestSummaryDataPoint(newSummaryDataPoint((*es.orig)[i])) + fillTestSummaryDataPoint(newSummaryDataPoint((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/generated_summarydatapointvalueatquantile.go b/pdata/pmetric/generated_summarydatapointvalueatquantile.go index c32d24d1d11..b4e1fe08f7b 100644 --- a/pdata/pmetric/generated_summarydatapointvalueatquantile.go +++ b/pdata/pmetric/generated_summarydatapointvalueatquantile.go @@ -7,6 +7,7 @@ package pmetric import ( + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewSummaryDataPointValueAtQuantile function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPointValueAtQuantile struct { - orig *otlpmetrics.SummaryDataPoint_ValueAtQuantile + orig *otlpmetrics.SummaryDataPoint_ValueAtQuantile + state *internal.State } -func newSummaryDataPointValueAtQuantile(orig *otlpmetrics.SummaryDataPoint_ValueAtQuantile) SummaryDataPointValueAtQuantile { - return SummaryDataPointValueAtQuantile{orig} +func newSummaryDataPointValueAtQuantile(orig *otlpmetrics.SummaryDataPoint_ValueAtQuantile, state *internal.State) SummaryDataPointValueAtQuantile { + return SummaryDataPointValueAtQuantile{orig: orig, state: state} } // NewSummaryDataPointValueAtQuantile creates a new empty SummaryDataPointValueAtQuantile. @@ -30,12 +32,15 @@ func newSummaryDataPointValueAtQuantile(orig *otlpmetrics.SummaryDataPoint_Value // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSummaryDataPointValueAtQuantile() SummaryDataPointValueAtQuantile { - return newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}) + state := internal.StateMutable + return newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SummaryDataPointValueAtQuantile) MoveTo(dest SummaryDataPointValueAtQuantile) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpmetrics.SummaryDataPoint_ValueAtQuantile{} } @@ -47,6 +52,7 @@ func (ms SummaryDataPointValueAtQuantile) Quantile() float64 { // SetQuantile replaces the quantile associated with this SummaryDataPointValueAtQuantile. func (ms SummaryDataPointValueAtQuantile) SetQuantile(v float64) { + ms.state.AssertMutable() ms.orig.Quantile = v } @@ -57,11 +63,13 @@ func (ms SummaryDataPointValueAtQuantile) Value() float64 { // SetValue replaces the value associated with this SummaryDataPointValueAtQuantile. func (ms SummaryDataPointValueAtQuantile) SetValue(v float64) { + ms.state.AssertMutable() ms.orig.Value = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms SummaryDataPointValueAtQuantile) CopyTo(dest SummaryDataPointValueAtQuantile) { + dest.state.AssertMutable() dest.SetQuantile(ms.Quantile()) dest.SetValue(ms.Value()) } diff --git a/pdata/pmetric/generated_summarydatapointvalueatquantile_test.go b/pdata/pmetric/generated_summarydatapointvalueatquantile_test.go index 7b0510c5da1..2dd02c799cf 100644 --- a/pdata/pmetric/generated_summarydatapointvalueatquantile_test.go +++ b/pdata/pmetric/generated_summarydatapointvalueatquantile_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestSummaryDataPointValueAtQuantile_MoveTo(t *testing.T) { @@ -18,6 +21,13 @@ func TestSummaryDataPointValueAtQuantile_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSummaryDataPointValueAtQuantile(), ms) assert.Equal(t, generateTestSummaryDataPointValueAtQuantile(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.MoveTo(newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &sharedState)) + }) + assert.Panics(t, func() { + newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &sharedState).MoveTo(dest) + }) } func TestSummaryDataPointValueAtQuantile_CopyTo(t *testing.T) { @@ -28,6 +38,10 @@ func TestSummaryDataPointValueAtQuantile_CopyTo(t *testing.T) { orig = generateTestSummaryDataPointValueAtQuantile() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.CopyTo(newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &sharedState)) + }) } func TestSummaryDataPointValueAtQuantile_Quantile(t *testing.T) { @@ -35,6 +49,10 @@ func TestSummaryDataPointValueAtQuantile_Quantile(t *testing.T) { assert.Equal(t, float64(0.0), ms.Quantile()) ms.SetQuantile(float64(17.13)) assert.Equal(t, float64(17.13), ms.Quantile()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &sharedState).SetQuantile(float64(17.13)) + }) } func TestSummaryDataPointValueAtQuantile_Value(t *testing.T) { @@ -42,6 +60,10 @@ func TestSummaryDataPointValueAtQuantile_Value(t *testing.T) { assert.Equal(t, float64(0.0), ms.Value()) ms.SetValue(float64(17.13)) assert.Equal(t, float64(17.13), ms.Value()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newSummaryDataPointValueAtQuantile(&otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &sharedState).SetValue(float64(17.13)) + }) } func generateTestSummaryDataPointValueAtQuantile() SummaryDataPointValueAtQuantile { diff --git a/pdata/pmetric/generated_summarydatapointvalueatquantileslice.go b/pdata/pmetric/generated_summarydatapointvalueatquantileslice.go index 3c424944b6a..21343f8ce5b 100644 --- a/pdata/pmetric/generated_summarydatapointvalueatquantileslice.go +++ b/pdata/pmetric/generated_summarydatapointvalueatquantileslice.go @@ -9,6 +9,7 @@ package pmetric import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewSummaryDataPointValueAtQuantileSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPointValueAtQuantileSlice struct { - orig *[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile + orig *[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile + state *internal.State } -func newSummaryDataPointValueAtQuantileSlice(orig *[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile) SummaryDataPointValueAtQuantileSlice { - return SummaryDataPointValueAtQuantileSlice{orig} +func newSummaryDataPointValueAtQuantileSlice(orig *[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile, state *internal.State) SummaryDataPointValueAtQuantileSlice { + return SummaryDataPointValueAtQuantileSlice{orig: orig, state: state} } // NewSummaryDataPointValueAtQuantileSlice creates a SummaryDataPointValueAtQuantileSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSummaryDataPointValueAtQuantileSlice() SummaryDataPointValueAtQuantileSlice { orig := []*otlpmetrics.SummaryDataPoint_ValueAtQuantile(nil) - return newSummaryDataPointValueAtQuantileSlice(&orig) + state := internal.StateMutable + return newSummaryDataPointValueAtQuantileSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es SummaryDataPointValueAtQuantileSlice) Len() int { // ... // Do something with the element // } func (es SummaryDataPointValueAtQuantileSlice) At(i int) SummaryDataPointValueAtQuantile { - return newSummaryDataPointValueAtQuantile((*es.orig)[i]) + return newSummaryDataPointValueAtQuantile((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es SummaryDataPointValueAtQuantileSlice) At(i int) SummaryDataPointValueAt // // Here should set all the values for e. // } func (es SummaryDataPointValueAtQuantileSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es SummaryDataPointValueAtQuantileSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty SummaryDataPointValueAtQuantile. // It returns the newly added SummaryDataPointValueAtQuantile. func (es SummaryDataPointValueAtQuantileSlice) AppendEmpty() SummaryDataPointValueAtQuantile { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlpmetrics.SummaryDataPoint_ValueAtQuantile{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es SummaryDataPointValueAtQuantileSlice) AppendEmpty() SummaryDataPointVal // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SummaryDataPointValueAtQuantileSlice) MoveAndAppendTo(dest SummaryDataPointValueAtQuantileSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es SummaryDataPointValueAtQuantileSlice) MoveAndAppendTo(dest SummaryDataP // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SummaryDataPointValueAtQuantileSlice) RemoveIf(f func(SummaryDataPointValueAtQuantile) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es SummaryDataPointValueAtQuantileSlice) RemoveIf(f func(SummaryDataPointV // CopyTo copies all elements from the current slice overriding the destination. func (es SummaryDataPointValueAtQuantileSlice) CopyTo(dest SummaryDataPointValueAtQuantileSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newSummaryDataPointValueAtQuantile((*es.orig)[i]).CopyTo(newSummaryDataPointValueAtQuantile((*dest.orig)[i])) + newSummaryDataPointValueAtQuantile((*es.orig)[i], es.state).CopyTo(newSummaryDataPointValueAtQuantile((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es SummaryDataPointValueAtQuantileSlice) CopyTo(dest SummaryDataPointValue wrappers := make([]*otlpmetrics.SummaryDataPoint_ValueAtQuantile, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newSummaryDataPointValueAtQuantile((*es.orig)[i]).CopyTo(newSummaryDataPointValueAtQuantile(wrappers[i])) + newSummaryDataPointValueAtQuantile((*es.orig)[i], es.state).CopyTo(newSummaryDataPointValueAtQuantile(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es SummaryDataPointValueAtQuantileSlice) CopyTo(dest SummaryDataPointValue // provided less function so that two instances of SummaryDataPointValueAtQuantileSlice // can be compared. func (es SummaryDataPointValueAtQuantileSlice) Sort(less func(a, b SummaryDataPointValueAtQuantile) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/pmetric/generated_summarydatapointvalueatquantileslice_test.go b/pdata/pmetric/generated_summarydatapointvalueatquantileslice_test.go index 20f7c439efe..5ad949f10d1 100644 --- a/pdata/pmetric/generated_summarydatapointvalueatquantileslice_test.go +++ b/pdata/pmetric/generated_summarydatapointvalueatquantileslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlpmetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/metrics/v1" ) func TestSummaryDataPointValueAtQuantileSlice(t *testing.T) { es := NewSummaryDataPointValueAtQuantileSlice() assert.Equal(t, 0, es.Len()) - es = newSummaryDataPointValueAtQuantileSlice(&[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile{}) + state := internal.StateMutable + es = newSummaryDataPointValueAtQuantileSlice(&[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewSummaryDataPointValueAtQuantile() @@ -32,6 +34,19 @@ func TestSummaryDataPointValueAtQuantileSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestSummaryDataPointValueAtQuantileSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newSummaryDataPointValueAtQuantileSlice(&[]*otlpmetrics.SummaryDataPoint_ValueAtQuantile{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewSummaryDataPointValueAtQuantileSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestSummaryDataPointValueAtQuantileSlice_CopyTo(t *testing.T) { dest := NewSummaryDataPointValueAtQuantileSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestSummaryDataPointValueAtQuantileSlice(es SummaryDataPointValueAtQuan *es.orig = make([]*otlpmetrics.SummaryDataPoint_ValueAtQuantile, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlpmetrics.SummaryDataPoint_ValueAtQuantile{} - fillTestSummaryDataPointValueAtQuantile(newSummaryDataPointValueAtQuantile((*es.orig)[i])) + fillTestSummaryDataPointValueAtQuantile(newSummaryDataPointValueAtQuantile((*es.orig)[i], es.state)) } } diff --git a/pdata/pmetric/metrics.go b/pdata/pmetric/metrics.go index d72997a1bc4..5a8c0f29974 100644 --- a/pdata/pmetric/metrics.go +++ b/pdata/pmetric/metrics.go @@ -13,7 +13,8 @@ import ( type Metrics internal.Metrics func newMetrics(orig *otlpcollectormetrics.ExportMetricsServiceRequest) Metrics { - return Metrics(internal.NewMetrics(orig)) + state := internal.StateMutable + return Metrics(internal.NewMetrics(orig, &state)) } func (ms Metrics) getOrig() *otlpcollectormetrics.ExportMetricsServiceRequest { @@ -32,7 +33,7 @@ func (ms Metrics) CopyTo(dest Metrics) { // ResourceMetrics returns the ResourceMetricsSlice associated with this Metrics. func (ms Metrics) ResourceMetrics() ResourceMetricsSlice { - return newResourceMetricsSlice(&ms.getOrig().ResourceMetrics) + return newResourceMetricsSlice(&ms.getOrig().ResourceMetrics, internal.GetMetricsState(internal.Metrics(ms))) } // MetricCount calculates the total number of metrics. @@ -78,3 +79,8 @@ func (ms Metrics) DataPointCount() (dataPointCount int) { } return } + +// MarkReadOnly marks the Metrics as shared so that no further modifications can be done on it. +func (ms Metrics) MarkReadOnly() { + internal.SetMetricsState(internal.Metrics(ms), internal.StateReadOnly) +} diff --git a/pdata/pmetric/metrics_test.go b/pdata/pmetric/metrics_test.go index 811123aa00f..9b2b5c2b70d 100644 --- a/pdata/pmetric/metrics_test.go +++ b/pdata/pmetric/metrics_test.go @@ -5,6 +5,7 @@ package pmetric import ( "testing" + "time" gogoproto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" @@ -635,6 +636,14 @@ func TestMetricsCopyTo(t *testing.T) { assert.EqualValues(t, metrics, metricsCopy) } +func TestReadOnlyMetricsInvalidUsage(t *testing.T) { + metrics := NewMetrics() + res := metrics.ResourceMetrics().AppendEmpty().Resource() + res.Attributes().PutStr("k1", "v1") + metrics.MarkReadOnly() + assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) +} + func BenchmarkOtlpToFromInternal_PassThrough(b *testing.B) { req := &otlpcollectormetrics.ExportMetricsServiceRequest{ ResourceMetrics: []*otlpmetrics.ResourceMetrics{ @@ -931,3 +940,57 @@ func generateMetricsEmptyDataPoints() Metrics { }, }) } + +func BenchmarkMetricsUsage(b *testing.B) { + metrics := NewMetrics() + fillTestResourceMetricsSlice(metrics.ResourceMetrics()) + + ts := pcommon.NewTimestampFromTime(time.Now()) + + b.ReportAllocs() + b.ResetTimer() + + for bb := 0; bb < b.N; bb++ { + for i := 0; i < metrics.ResourceMetrics().Len(); i++ { + rm := metrics.ResourceMetrics().At(i) + res := rm.Resource() + res.Attributes().PutStr("foo", "bar") + v, ok := res.Attributes().Get("foo") + assert.True(b, ok) + assert.Equal(b, "bar", v.Str()) + v.SetStr("new-bar") + assert.Equal(b, "new-bar", v.Str()) + res.Attributes().Remove("foo") + for j := 0; j < rm.ScopeMetrics().Len(); j++ { + sm := rm.ScopeMetrics().At(j) + for k := 0; k < sm.Metrics().Len(); k++ { + m := sm.Metrics().At(k) + m.SetName("new_metric_name") + assert.Equal(b, "new_metric_name", m.Name()) + assert.Equal(b, MetricTypeSum, m.Type()) + m.Sum().SetAggregationTemporality(AggregationTemporalityCumulative) + assert.Equal(b, AggregationTemporalityCumulative, m.Sum().AggregationTemporality()) + m.Sum().SetIsMonotonic(true) + assert.True(b, m.Sum().IsMonotonic()) + for l := 0; l < m.Sum().DataPoints().Len(); l++ { + dp := m.Sum().DataPoints().At(l) + dp.SetIntValue(123) + assert.Equal(b, int64(123), dp.IntValue()) + assert.Equal(b, NumberDataPointValueTypeInt, dp.ValueType()) + dp.SetStartTimestamp(ts) + assert.Equal(b, ts, dp.StartTimestamp()) + } + dp := m.Sum().DataPoints().AppendEmpty() + dp.Attributes().PutStr("foo", "bar") + dp.SetDoubleValue(123) + dp.SetStartTimestamp(ts) + dp.SetTimestamp(ts) + m.Sum().DataPoints().RemoveIf(func(dp NumberDataPoint) bool { + _, ok := dp.Attributes().Get("foo") + return ok + }) + } + } + } + } +} diff --git a/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess.go b/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess.go index d528e6e8f46..60aa6a03e95 100644 --- a/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess.go +++ b/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess.go @@ -7,6 +7,7 @@ package pmetricotlp import ( + "go.opentelemetry.io/collector/pdata/internal" otlpcollectormetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/metrics/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { - orig *otlpcollectormetrics.ExportMetricsPartialSuccess + orig *otlpcollectormetrics.ExportMetricsPartialSuccess + state *internal.State } -func newExportPartialSuccess(orig *otlpcollectormetrics.ExportMetricsPartialSuccess) ExportPartialSuccess { - return ExportPartialSuccess{orig} +func newExportPartialSuccess(orig *otlpcollectormetrics.ExportMetricsPartialSuccess, state *internal.State) ExportPartialSuccess { + return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. @@ -30,12 +32,15 @@ func newExportPartialSuccess(orig *otlpcollectormetrics.ExportMetricsPartialSucc // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { - return newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}) + state := internal.StateMutable + return newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpcollectormetrics.ExportMetricsPartialSuccess{} } @@ -47,6 +52,7 @@ func (ms ExportPartialSuccess) RejectedDataPoints() int64 { // SetRejectedDataPoints replaces the rejecteddatapoints associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedDataPoints(v int64) { + ms.state.AssertMutable() ms.orig.RejectedDataPoints = v } @@ -57,11 +63,13 @@ func (ms ExportPartialSuccess) ErrorMessage() string { // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { + ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { + dest.state.AssertMutable() dest.SetRejectedDataPoints(ms.RejectedDataPoints()) dest.SetErrorMessage(ms.ErrorMessage()) } diff --git a/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess_test.go b/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess_test.go index a351ba048fa..e6345f60413 100644 --- a/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess_test.go +++ b/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpcollectormetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/metrics/v1" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { @@ -18,6 +21,13 @@ func TestExportPartialSuccess_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.MoveTo(newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}, &sharedState)) + }) + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}, &sharedState).MoveTo(dest) + }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { @@ -28,6 +38,10 @@ func TestExportPartialSuccess_CopyTo(t *testing.T) { orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.CopyTo(newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}, &sharedState)) + }) } func TestExportPartialSuccess_RejectedDataPoints(t *testing.T) { @@ -35,6 +49,10 @@ func TestExportPartialSuccess_RejectedDataPoints(t *testing.T) { assert.Equal(t, int64(0), ms.RejectedDataPoints()) ms.SetRejectedDataPoints(int64(13)) assert.Equal(t, int64(13), ms.RejectedDataPoints()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}, &sharedState).SetRejectedDataPoints(int64(13)) + }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { @@ -42,6 +60,10 @@ func TestExportPartialSuccess_ErrorMessage(t *testing.T) { assert.Equal(t, "", ms.ErrorMessage()) ms.SetErrorMessage("error message") assert.Equal(t, "error message", ms.ErrorMessage()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectormetrics.ExportMetricsPartialSuccess{}, &sharedState).SetErrorMessage("error message") + }) } func generateTestExportPartialSuccess() ExportPartialSuccess { diff --git a/pdata/pmetric/pmetricotlp/grpc.go b/pdata/pmetric/pmetricotlp/grpc.go index be9d946b3c8..98d864d7371 100644 --- a/pdata/pmetric/pmetricotlp/grpc.go +++ b/pdata/pmetric/pmetricotlp/grpc.go @@ -10,6 +10,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "go.opentelemetry.io/collector/pdata/internal" otlpcollectormetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/metrics/v1" "go.opentelemetry.io/collector/pdata/internal/otlp" ) @@ -39,7 +40,11 @@ type grpcClient struct { func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) - return ExportResponse{orig: rsp}, err + if err != nil { + return ExportResponse{}, err + } + state := internal.StateMutable + return ExportResponse{orig: rsp, state: &state}, err } func (c *grpcClient) unexported() {} @@ -79,6 +84,7 @@ type rawMetricsServer struct { func (s rawMetricsServer) Export(ctx context.Context, request *otlpcollectormetrics.ExportMetricsServiceRequest) (*otlpcollectormetrics.ExportMetricsServiceResponse, error) { otlp.MigrateMetrics(request.ResourceMetrics) - rsp, err := s.srv.Export(ctx, ExportRequest{orig: request}) + state := internal.StateMutable + rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: &state}) return rsp.orig, err } diff --git a/pdata/pmetric/pmetricotlp/request.go b/pdata/pmetric/pmetricotlp/request.go index 060b6e5bb07..4cca31a609f 100644 --- a/pdata/pmetric/pmetricotlp/request.go +++ b/pdata/pmetric/pmetricotlp/request.go @@ -17,19 +17,27 @@ var jsonUnmarshaler = &pmetric.JSONUnmarshaler{} // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for pmetric.Metrics data. type ExportRequest struct { - orig *otlpcollectormetrics.ExportMetricsServiceRequest + orig *otlpcollectormetrics.ExportMetricsServiceRequest + state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { - return ExportRequest{orig: &otlpcollectormetrics.ExportMetricsServiceRequest{}} + state := internal.StateMutable + return ExportRequest{ + orig: &otlpcollectormetrics.ExportMetricsServiceRequest{}, + state: &state, + } } // NewExportRequestFromMetrics returns a ExportRequest from pmetric.Metrics. // Because ExportRequest is a wrapper for pmetric.Metrics, // any changes to the provided Metrics struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromMetrics(md pmetric.Metrics) ExportRequest { - return ExportRequest{orig: internal.GetOrigMetrics(internal.Metrics(md))} + return ExportRequest{ + orig: internal.GetOrigMetrics(internal.Metrics(md)), + state: internal.GetMetricsState(internal.Metrics(md)), + } } // MarshalProto marshals ExportRequest into proto bytes. @@ -62,5 +70,5 @@ func (ms ExportRequest) UnmarshalJSON(data []byte) error { } func (ms ExportRequest) Metrics() pmetric.Metrics { - return pmetric.Metrics(internal.NewMetrics(ms.orig)) + return pmetric.Metrics(internal.NewMetrics(ms.orig, ms.state)) } diff --git a/pdata/pmetric/pmetricotlp/response.go b/pdata/pmetric/pmetricotlp/response.go index 4e9d6bfe169..e928400f317 100644 --- a/pdata/pmetric/pmetricotlp/response.go +++ b/pdata/pmetric/pmetricotlp/response.go @@ -8,18 +8,24 @@ import ( jsoniter "github.com/json-iterator/go" + "go.opentelemetry.io/collector/pdata/internal" otlpcollectormetrics "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/metrics/v1" "go.opentelemetry.io/collector/pdata/internal/json" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportResponse struct { - orig *otlpcollectormetrics.ExportMetricsServiceResponse + orig *otlpcollectormetrics.ExportMetricsServiceResponse + state *internal.State } // NewExportResponse returns an empty ExportResponse. func NewExportResponse() ExportResponse { - return ExportResponse{orig: &otlpcollectormetrics.ExportMetricsServiceResponse{}} + state := internal.StateMutable + return ExportResponse{ + orig: &otlpcollectormetrics.ExportMetricsServiceResponse{}, + state: &state, + } } // MarshalProto marshals ExportResponse into proto bytes. @@ -51,7 +57,7 @@ func (ms ExportResponse) UnmarshalJSON(data []byte) error { // PartialSuccess returns the ExportLogsPartialSuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { - return newExportPartialSuccess(&ms.orig.PartialSuccess) + return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } func (ms ExportResponse) unmarshalJsoniter(iter *jsoniter.Iterator) { diff --git a/pdata/ptrace/generated_resourcespans.go b/pdata/ptrace/generated_resourcespans.go index b86cca53402..fc2ed01dbbc 100644 --- a/pdata/ptrace/generated_resourcespans.go +++ b/pdata/ptrace/generated_resourcespans.go @@ -20,11 +20,12 @@ import ( // Must use NewResourceSpans function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceSpans struct { - orig *otlptrace.ResourceSpans + orig *otlptrace.ResourceSpans + state *internal.State } -func newResourceSpans(orig *otlptrace.ResourceSpans) ResourceSpans { - return ResourceSpans{orig} +func newResourceSpans(orig *otlptrace.ResourceSpans, state *internal.State) ResourceSpans { + return ResourceSpans{orig: orig, state: state} } // NewResourceSpans creates a new empty ResourceSpans. @@ -32,19 +33,22 @@ func newResourceSpans(orig *otlptrace.ResourceSpans) ResourceSpans { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceSpans() ResourceSpans { - return newResourceSpans(&otlptrace.ResourceSpans{}) + state := internal.StateMutable + return newResourceSpans(&otlptrace.ResourceSpans{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceSpans) MoveTo(dest ResourceSpans) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlptrace.ResourceSpans{} } // Resource returns the resource associated with this ResourceSpans. func (ms ResourceSpans) Resource() pcommon.Resource { - return pcommon.Resource(internal.NewResource(&ms.orig.Resource)) + return pcommon.Resource(internal.NewResource(&ms.orig.Resource, ms.state)) } // SchemaUrl returns the schemaurl associated with this ResourceSpans. @@ -54,16 +58,18 @@ func (ms ResourceSpans) SchemaUrl() string { // SetSchemaUrl replaces the schemaurl associated with this ResourceSpans. func (ms ResourceSpans) SetSchemaUrl(v string) { + ms.state.AssertMutable() ms.orig.SchemaUrl = v } // ScopeSpans returns the ScopeSpans associated with this ResourceSpans. func (ms ResourceSpans) ScopeSpans() ScopeSpansSlice { - return newScopeSpansSlice(&ms.orig.ScopeSpans) + return newScopeSpansSlice(&ms.orig.ScopeSpans, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceSpans) CopyTo(dest ResourceSpans) { + dest.state.AssertMutable() ms.Resource().CopyTo(dest.Resource()) dest.SetSchemaUrl(ms.SchemaUrl()) ms.ScopeSpans().CopyTo(dest.ScopeSpans()) diff --git a/pdata/ptrace/generated_resourcespans_test.go b/pdata/ptrace/generated_resourcespans_test.go index 0fb248b3aba..2300c04f63e 100644 --- a/pdata/ptrace/generated_resourcespans_test.go +++ b/pdata/ptrace/generated_resourcespans_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestResourceSpans_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewResourceSpans(), ms) assert.Equal(t, generateTestResourceSpans(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newResourceSpans(&otlptrace.ResourceSpans{}, &sharedState)) }) + assert.Panics(t, func() { newResourceSpans(&otlptrace.ResourceSpans{}, &sharedState).MoveTo(dest) }) } func TestResourceSpans_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestResourceSpans_CopyTo(t *testing.T) { orig = generateTestResourceSpans() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newResourceSpans(&otlptrace.ResourceSpans{}, &sharedState)) }) } func TestResourceSpans_Resource(t *testing.T) { @@ -44,6 +50,10 @@ func TestResourceSpans_SchemaUrl(t *testing.T) { assert.Equal(t, "", ms.SchemaUrl()) ms.SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.5.0", ms.SchemaUrl()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newResourceSpans(&otlptrace.ResourceSpans{}, &sharedState).SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") + }) } func TestResourceSpans_ScopeSpans(t *testing.T) { @@ -60,7 +70,7 @@ func generateTestResourceSpans() ResourceSpans { } func fillTestResourceSpans(tv ResourceSpans) { - internal.FillTestResource(internal.NewResource(&tv.orig.Resource)) + internal.FillTestResource(internal.NewResource(&tv.orig.Resource, tv.state)) tv.orig.SchemaUrl = "https://opentelemetry.io/schemas/1.5.0" - fillTestScopeSpansSlice(newScopeSpansSlice(&tv.orig.ScopeSpans)) + fillTestScopeSpansSlice(newScopeSpansSlice(&tv.orig.ScopeSpans, tv.state)) } diff --git a/pdata/ptrace/generated_resourcespansslice.go b/pdata/ptrace/generated_resourcespansslice.go index 5c625fb781f..e9185f7328a 100644 --- a/pdata/ptrace/generated_resourcespansslice.go +++ b/pdata/ptrace/generated_resourcespansslice.go @@ -9,6 +9,7 @@ package ptrace import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewResourceSpansSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceSpansSlice struct { - orig *[]*otlptrace.ResourceSpans + orig *[]*otlptrace.ResourceSpans + state *internal.State } -func newResourceSpansSlice(orig *[]*otlptrace.ResourceSpans) ResourceSpansSlice { - return ResourceSpansSlice{orig} +func newResourceSpansSlice(orig *[]*otlptrace.ResourceSpans, state *internal.State) ResourceSpansSlice { + return ResourceSpansSlice{orig: orig, state: state} } // NewResourceSpansSlice creates a ResourceSpansSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceSpansSlice() ResourceSpansSlice { orig := []*otlptrace.ResourceSpans(nil) - return newResourceSpansSlice(&orig) + state := internal.StateMutable + return newResourceSpansSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ResourceSpansSlice) Len() int { // ... // Do something with the element // } func (es ResourceSpansSlice) At(i int) ResourceSpans { - return newResourceSpans((*es.orig)[i]) + return newResourceSpans((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ResourceSpansSlice) At(i int) ResourceSpans { // // Here should set all the values for e. // } func (es ResourceSpansSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ResourceSpansSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ResourceSpans. // It returns the newly added ResourceSpans. func (es ResourceSpansSlice) AppendEmpty() ResourceSpans { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlptrace.ResourceSpans{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ResourceSpansSlice) AppendEmpty() ResourceSpans { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceSpansSlice) MoveAndAppendTo(dest ResourceSpansSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ResourceSpansSlice) MoveAndAppendTo(dest ResourceSpansSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceSpansSlice) RemoveIf(f func(ResourceSpans) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ResourceSpansSlice) RemoveIf(f func(ResourceSpans) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceSpansSlice) CopyTo(dest ResourceSpansSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newResourceSpans((*es.orig)[i]).CopyTo(newResourceSpans((*dest.orig)[i])) + newResourceSpans((*es.orig)[i], es.state).CopyTo(newResourceSpans((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ResourceSpansSlice) CopyTo(dest ResourceSpansSlice) { wrappers := make([]*otlptrace.ResourceSpans, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newResourceSpans((*es.orig)[i]).CopyTo(newResourceSpans(wrappers[i])) + newResourceSpans((*es.orig)[i], es.state).CopyTo(newResourceSpans(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ResourceSpansSlice) CopyTo(dest ResourceSpansSlice) { // provided less function so that two instances of ResourceSpansSlice // can be compared. func (es ResourceSpansSlice) Sort(less func(a, b ResourceSpans) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/ptrace/generated_resourcespansslice_test.go b/pdata/ptrace/generated_resourcespansslice_test.go index db8e3b1c7e4..aa7bdf738a9 100644 --- a/pdata/ptrace/generated_resourcespansslice_test.go +++ b/pdata/ptrace/generated_resourcespansslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) func TestResourceSpansSlice(t *testing.T) { es := NewResourceSpansSlice() assert.Equal(t, 0, es.Len()) - es = newResourceSpansSlice(&[]*otlptrace.ResourceSpans{}) + state := internal.StateMutable + es = newResourceSpansSlice(&[]*otlptrace.ResourceSpans{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceSpans() @@ -32,6 +34,19 @@ func TestResourceSpansSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestResourceSpansSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newResourceSpansSlice(&[]*otlptrace.ResourceSpans{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewResourceSpansSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestResourceSpansSlice_CopyTo(t *testing.T) { dest := NewResourceSpansSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestResourceSpansSlice(es ResourceSpansSlice) { *es.orig = make([]*otlptrace.ResourceSpans, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlptrace.ResourceSpans{} - fillTestResourceSpans(newResourceSpans((*es.orig)[i])) + fillTestResourceSpans(newResourceSpans((*es.orig)[i], es.state)) } } diff --git a/pdata/ptrace/generated_scopespans.go b/pdata/ptrace/generated_scopespans.go index 81926f24004..6ea0d82fd68 100644 --- a/pdata/ptrace/generated_scopespans.go +++ b/pdata/ptrace/generated_scopespans.go @@ -20,11 +20,12 @@ import ( // Must use NewScopeSpans function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeSpans struct { - orig *otlptrace.ScopeSpans + orig *otlptrace.ScopeSpans + state *internal.State } -func newScopeSpans(orig *otlptrace.ScopeSpans) ScopeSpans { - return ScopeSpans{orig} +func newScopeSpans(orig *otlptrace.ScopeSpans, state *internal.State) ScopeSpans { + return ScopeSpans{orig: orig, state: state} } // NewScopeSpans creates a new empty ScopeSpans. @@ -32,19 +33,22 @@ func newScopeSpans(orig *otlptrace.ScopeSpans) ScopeSpans { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeSpans() ScopeSpans { - return newScopeSpans(&otlptrace.ScopeSpans{}) + state := internal.StateMutable + return newScopeSpans(&otlptrace.ScopeSpans{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeSpans) MoveTo(dest ScopeSpans) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlptrace.ScopeSpans{} } // Scope returns the scope associated with this ScopeSpans. func (ms ScopeSpans) Scope() pcommon.InstrumentationScope { - return pcommon.InstrumentationScope(internal.NewInstrumentationScope(&ms.orig.Scope)) + return pcommon.InstrumentationScope(internal.NewInstrumentationScope(&ms.orig.Scope, ms.state)) } // SchemaUrl returns the schemaurl associated with this ScopeSpans. @@ -54,16 +58,18 @@ func (ms ScopeSpans) SchemaUrl() string { // SetSchemaUrl replaces the schemaurl associated with this ScopeSpans. func (ms ScopeSpans) SetSchemaUrl(v string) { + ms.state.AssertMutable() ms.orig.SchemaUrl = v } // Spans returns the Spans associated with this ScopeSpans. func (ms ScopeSpans) Spans() SpanSlice { - return newSpanSlice(&ms.orig.Spans) + return newSpanSlice(&ms.orig.Spans, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeSpans) CopyTo(dest ScopeSpans) { + dest.state.AssertMutable() ms.Scope().CopyTo(dest.Scope()) dest.SetSchemaUrl(ms.SchemaUrl()) ms.Spans().CopyTo(dest.Spans()) diff --git a/pdata/ptrace/generated_scopespans_test.go b/pdata/ptrace/generated_scopespans_test.go index c470e8f11fc..21b665aed27 100644 --- a/pdata/ptrace/generated_scopespans_test.go +++ b/pdata/ptrace/generated_scopespans_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestScopeSpans_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewScopeSpans(), ms) assert.Equal(t, generateTestScopeSpans(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newScopeSpans(&otlptrace.ScopeSpans{}, &sharedState)) }) + assert.Panics(t, func() { newScopeSpans(&otlptrace.ScopeSpans{}, &sharedState).MoveTo(dest) }) } func TestScopeSpans_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestScopeSpans_CopyTo(t *testing.T) { orig = generateTestScopeSpans() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newScopeSpans(&otlptrace.ScopeSpans{}, &sharedState)) }) } func TestScopeSpans_Scope(t *testing.T) { @@ -44,6 +50,10 @@ func TestScopeSpans_SchemaUrl(t *testing.T) { assert.Equal(t, "", ms.SchemaUrl()) ms.SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.5.0", ms.SchemaUrl()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newScopeSpans(&otlptrace.ScopeSpans{}, &sharedState).SetSchemaUrl("https://opentelemetry.io/schemas/1.5.0") + }) } func TestScopeSpans_Spans(t *testing.T) { @@ -60,7 +70,7 @@ func generateTestScopeSpans() ScopeSpans { } func fillTestScopeSpans(tv ScopeSpans) { - internal.FillTestInstrumentationScope(internal.NewInstrumentationScope(&tv.orig.Scope)) + internal.FillTestInstrumentationScope(internal.NewInstrumentationScope(&tv.orig.Scope, tv.state)) tv.orig.SchemaUrl = "https://opentelemetry.io/schemas/1.5.0" - fillTestSpanSlice(newSpanSlice(&tv.orig.Spans)) + fillTestSpanSlice(newSpanSlice(&tv.orig.Spans, tv.state)) } diff --git a/pdata/ptrace/generated_scopespansslice.go b/pdata/ptrace/generated_scopespansslice.go index 622d29be2c9..2afdcf4dfc3 100644 --- a/pdata/ptrace/generated_scopespansslice.go +++ b/pdata/ptrace/generated_scopespansslice.go @@ -9,6 +9,7 @@ package ptrace import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewScopeSpansSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeSpansSlice struct { - orig *[]*otlptrace.ScopeSpans + orig *[]*otlptrace.ScopeSpans + state *internal.State } -func newScopeSpansSlice(orig *[]*otlptrace.ScopeSpans) ScopeSpansSlice { - return ScopeSpansSlice{orig} +func newScopeSpansSlice(orig *[]*otlptrace.ScopeSpans, state *internal.State) ScopeSpansSlice { + return ScopeSpansSlice{orig: orig, state: state} } // NewScopeSpansSlice creates a ScopeSpansSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeSpansSlice() ScopeSpansSlice { orig := []*otlptrace.ScopeSpans(nil) - return newScopeSpansSlice(&orig) + state := internal.StateMutable + return newScopeSpansSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es ScopeSpansSlice) Len() int { // ... // Do something with the element // } func (es ScopeSpansSlice) At(i int) ScopeSpans { - return newScopeSpans((*es.orig)[i]) + return newScopeSpans((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es ScopeSpansSlice) At(i int) ScopeSpans { // // Here should set all the values for e. // } func (es ScopeSpansSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es ScopeSpansSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty ScopeSpans. // It returns the newly added ScopeSpans. func (es ScopeSpansSlice) AppendEmpty() ScopeSpans { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlptrace.ScopeSpans{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es ScopeSpansSlice) AppendEmpty() ScopeSpans { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeSpansSlice) MoveAndAppendTo(dest ScopeSpansSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es ScopeSpansSlice) MoveAndAppendTo(dest ScopeSpansSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeSpansSlice) RemoveIf(f func(ScopeSpans) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es ScopeSpansSlice) RemoveIf(f func(ScopeSpans) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeSpansSlice) CopyTo(dest ScopeSpansSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newScopeSpans((*es.orig)[i]).CopyTo(newScopeSpans((*dest.orig)[i])) + newScopeSpans((*es.orig)[i], es.state).CopyTo(newScopeSpans((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es ScopeSpansSlice) CopyTo(dest ScopeSpansSlice) { wrappers := make([]*otlptrace.ScopeSpans, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newScopeSpans((*es.orig)[i]).CopyTo(newScopeSpans(wrappers[i])) + newScopeSpans((*es.orig)[i], es.state).CopyTo(newScopeSpans(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es ScopeSpansSlice) CopyTo(dest ScopeSpansSlice) { // provided less function so that two instances of ScopeSpansSlice // can be compared. func (es ScopeSpansSlice) Sort(less func(a, b ScopeSpans) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/ptrace/generated_scopespansslice_test.go b/pdata/ptrace/generated_scopespansslice_test.go index 950e481913c..1c3fa931bf1 100644 --- a/pdata/ptrace/generated_scopespansslice_test.go +++ b/pdata/ptrace/generated_scopespansslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) func TestScopeSpansSlice(t *testing.T) { es := NewScopeSpansSlice() assert.Equal(t, 0, es.Len()) - es = newScopeSpansSlice(&[]*otlptrace.ScopeSpans{}) + state := internal.StateMutable + es = newScopeSpansSlice(&[]*otlptrace.ScopeSpans{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeSpans() @@ -32,6 +34,19 @@ func TestScopeSpansSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestScopeSpansSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newScopeSpansSlice(&[]*otlptrace.ScopeSpans{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewScopeSpansSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestScopeSpansSlice_CopyTo(t *testing.T) { dest := NewScopeSpansSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestScopeSpansSlice(es ScopeSpansSlice) { *es.orig = make([]*otlptrace.ScopeSpans, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlptrace.ScopeSpans{} - fillTestScopeSpans(newScopeSpans((*es.orig)[i])) + fillTestScopeSpans(newScopeSpans((*es.orig)[i], es.state)) } } diff --git a/pdata/ptrace/generated_span.go b/pdata/ptrace/generated_span.go index 6b76b7efd40..a836da8a2dd 100644 --- a/pdata/ptrace/generated_span.go +++ b/pdata/ptrace/generated_span.go @@ -22,11 +22,12 @@ import ( // Must use NewSpan function to create new instances. // Important: zero-initialized instance is not valid for use. type Span struct { - orig *otlptrace.Span + orig *otlptrace.Span + state *internal.State } -func newSpan(orig *otlptrace.Span) Span { - return Span{orig} +func newSpan(orig *otlptrace.Span, state *internal.State) Span { + return Span{orig: orig, state: state} } // NewSpan creates a new empty Span. @@ -34,12 +35,15 @@ func newSpan(orig *otlptrace.Span) Span { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSpan() Span { - return newSpan(&otlptrace.Span{}) + state := internal.StateMutable + return newSpan(&otlptrace.Span{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Span) MoveTo(dest Span) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlptrace.Span{} } @@ -51,6 +55,7 @@ func (ms Span) TraceID() pcommon.TraceID { // SetTraceID replaces the traceid associated with this Span. func (ms Span) SetTraceID(v pcommon.TraceID) { + ms.state.AssertMutable() ms.orig.TraceId = data.TraceID(v) } @@ -61,12 +66,13 @@ func (ms Span) SpanID() pcommon.SpanID { // SetSpanID replaces the spanid associated with this Span. func (ms Span) SetSpanID(v pcommon.SpanID) { + ms.state.AssertMutable() ms.orig.SpanId = data.SpanID(v) } // TraceState returns the tracestate associated with this Span. func (ms Span) TraceState() pcommon.TraceState { - return pcommon.TraceState(internal.NewTraceState(&ms.orig.TraceState)) + return pcommon.TraceState(internal.NewTraceState(&ms.orig.TraceState, ms.state)) } // ParentSpanID returns the parentspanid associated with this Span. @@ -76,6 +82,7 @@ func (ms Span) ParentSpanID() pcommon.SpanID { // SetParentSpanID replaces the parentspanid associated with this Span. func (ms Span) SetParentSpanID(v pcommon.SpanID) { + ms.state.AssertMutable() ms.orig.ParentSpanId = data.SpanID(v) } @@ -86,6 +93,7 @@ func (ms Span) Name() string { // SetName replaces the name associated with this Span. func (ms Span) SetName(v string) { + ms.state.AssertMutable() ms.orig.Name = v } @@ -96,6 +104,7 @@ func (ms Span) Kind() SpanKind { // SetKind replaces the kind associated with this Span. func (ms Span) SetKind(v SpanKind) { + ms.state.AssertMutable() ms.orig.Kind = otlptrace.Span_SpanKind(v) } @@ -106,6 +115,7 @@ func (ms Span) StartTimestamp() pcommon.Timestamp { // SetStartTimestamp replaces the starttimestamp associated with this Span. func (ms Span) SetStartTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } @@ -116,12 +126,13 @@ func (ms Span) EndTimestamp() pcommon.Timestamp { // SetEndTimestamp replaces the endtimestamp associated with this Span. func (ms Span) SetEndTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.EndTimeUnixNano = uint64(v) } // Attributes returns the Attributes associated with this Span. func (ms Span) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this Span. @@ -131,12 +142,13 @@ func (ms Span) DroppedAttributesCount() uint32 { // SetDroppedAttributesCount replaces the droppedattributescount associated with this Span. func (ms Span) SetDroppedAttributesCount(v uint32) { + ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // Events returns the Events associated with this Span. func (ms Span) Events() SpanEventSlice { - return newSpanEventSlice(&ms.orig.Events) + return newSpanEventSlice(&ms.orig.Events, ms.state) } // DroppedEventsCount returns the droppedeventscount associated with this Span. @@ -146,12 +158,13 @@ func (ms Span) DroppedEventsCount() uint32 { // SetDroppedEventsCount replaces the droppedeventscount associated with this Span. func (ms Span) SetDroppedEventsCount(v uint32) { + ms.state.AssertMutable() ms.orig.DroppedEventsCount = v } // Links returns the Links associated with this Span. func (ms Span) Links() SpanLinkSlice { - return newSpanLinkSlice(&ms.orig.Links) + return newSpanLinkSlice(&ms.orig.Links, ms.state) } // DroppedLinksCount returns the droppedlinkscount associated with this Span. @@ -161,16 +174,18 @@ func (ms Span) DroppedLinksCount() uint32 { // SetDroppedLinksCount replaces the droppedlinkscount associated with this Span. func (ms Span) SetDroppedLinksCount(v uint32) { + ms.state.AssertMutable() ms.orig.DroppedLinksCount = v } // Status returns the status associated with this Span. func (ms Span) Status() Status { - return newStatus(&ms.orig.Status) + return newStatus(&ms.orig.Status, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Span) CopyTo(dest Span) { + dest.state.AssertMutable() dest.SetTraceID(ms.TraceID()) dest.SetSpanID(ms.SpanID()) ms.TraceState().CopyTo(dest.TraceState()) diff --git a/pdata/ptrace/generated_span_test.go b/pdata/ptrace/generated_span_test.go index b971dd3294a..634adf7ddcb 100644 --- a/pdata/ptrace/generated_span_test.go +++ b/pdata/ptrace/generated_span_test.go @@ -23,6 +23,9 @@ func TestSpan_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSpan(), ms) assert.Equal(t, generateTestSpan(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newSpan(&otlptrace.Span{}, &sharedState)) }) + assert.Panics(t, func() { newSpan(&otlptrace.Span{}, &sharedState).MoveTo(dest) }) } func TestSpan_CopyTo(t *testing.T) { @@ -33,6 +36,8 @@ func TestSpan_CopyTo(t *testing.T) { orig = generateTestSpan() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newSpan(&otlptrace.Span{}, &sharedState)) }) } func TestSpan_TraceID(t *testing.T) { @@ -70,6 +75,8 @@ func TestSpan_Name(t *testing.T) { assert.Equal(t, "", ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpan(&otlptrace.Span{}, &sharedState).SetName("test_name") }) } func TestSpan_Kind(t *testing.T) { @@ -108,6 +115,8 @@ func TestSpan_DroppedAttributesCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedAttributesCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpan(&otlptrace.Span{}, &sharedState).SetDroppedAttributesCount(uint32(17)) }) } func TestSpan_Events(t *testing.T) { @@ -122,6 +131,8 @@ func TestSpan_DroppedEventsCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedEventsCount()) ms.SetDroppedEventsCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedEventsCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpan(&otlptrace.Span{}, &sharedState).SetDroppedEventsCount(uint32(17)) }) } func TestSpan_Links(t *testing.T) { @@ -136,6 +147,8 @@ func TestSpan_DroppedLinksCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedLinksCount()) ms.SetDroppedLinksCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedLinksCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpan(&otlptrace.Span{}, &sharedState).SetDroppedLinksCount(uint32(17)) }) } func TestSpan_Status(t *testing.T) { @@ -153,17 +166,17 @@ func generateTestSpan() Span { func fillTestSpan(tv Span) { tv.orig.TraceId = data.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) tv.orig.SpanId = data.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}) - internal.FillTestTraceState(internal.NewTraceState(&tv.orig.TraceState)) + internal.FillTestTraceState(internal.NewTraceState(&tv.orig.TraceState, tv.state)) tv.orig.ParentSpanId = data.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}) tv.orig.Name = "test_name" tv.orig.Kind = otlptrace.Span_SpanKind(3) tv.orig.StartTimeUnixNano = 1234567890 tv.orig.EndTimeUnixNano = 1234567890 - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.DroppedAttributesCount = uint32(17) - fillTestSpanEventSlice(newSpanEventSlice(&tv.orig.Events)) + fillTestSpanEventSlice(newSpanEventSlice(&tv.orig.Events, tv.state)) tv.orig.DroppedEventsCount = uint32(17) - fillTestSpanLinkSlice(newSpanLinkSlice(&tv.orig.Links)) + fillTestSpanLinkSlice(newSpanLinkSlice(&tv.orig.Links, tv.state)) tv.orig.DroppedLinksCount = uint32(17) - fillTestStatus(newStatus(&tv.orig.Status)) + fillTestStatus(newStatus(&tv.orig.Status, tv.state)) } diff --git a/pdata/ptrace/generated_spanevent.go b/pdata/ptrace/generated_spanevent.go index 06da71a3425..a35c88ae93d 100644 --- a/pdata/ptrace/generated_spanevent.go +++ b/pdata/ptrace/generated_spanevent.go @@ -21,11 +21,12 @@ import ( // Must use NewSpanEvent function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanEvent struct { - orig *otlptrace.Span_Event + orig *otlptrace.Span_Event + state *internal.State } -func newSpanEvent(orig *otlptrace.Span_Event) SpanEvent { - return SpanEvent{orig} +func newSpanEvent(orig *otlptrace.Span_Event, state *internal.State) SpanEvent { + return SpanEvent{orig: orig, state: state} } // NewSpanEvent creates a new empty SpanEvent. @@ -33,12 +34,15 @@ func newSpanEvent(orig *otlptrace.Span_Event) SpanEvent { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSpanEvent() SpanEvent { - return newSpanEvent(&otlptrace.Span_Event{}) + state := internal.StateMutable + return newSpanEvent(&otlptrace.Span_Event{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SpanEvent) MoveTo(dest SpanEvent) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlptrace.Span_Event{} } @@ -50,6 +54,7 @@ func (ms SpanEvent) Timestamp() pcommon.Timestamp { // SetTimestamp replaces the timestamp associated with this SpanEvent. func (ms SpanEvent) SetTimestamp(v pcommon.Timestamp) { + ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } @@ -60,12 +65,13 @@ func (ms SpanEvent) Name() string { // SetName replaces the name associated with this SpanEvent. func (ms SpanEvent) SetName(v string) { + ms.state.AssertMutable() ms.orig.Name = v } // Attributes returns the Attributes associated with this SpanEvent. func (ms SpanEvent) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this SpanEvent. @@ -75,11 +81,13 @@ func (ms SpanEvent) DroppedAttributesCount() uint32 { // SetDroppedAttributesCount replaces the droppedattributescount associated with this SpanEvent. func (ms SpanEvent) SetDroppedAttributesCount(v uint32) { + ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms SpanEvent) CopyTo(dest SpanEvent) { + dest.state.AssertMutable() dest.SetTimestamp(ms.Timestamp()) dest.SetName(ms.Name()) ms.Attributes().CopyTo(dest.Attributes()) diff --git a/pdata/ptrace/generated_spanevent_test.go b/pdata/ptrace/generated_spanevent_test.go index af403e1fc24..24ad7de4d1c 100644 --- a/pdata/ptrace/generated_spanevent_test.go +++ b/pdata/ptrace/generated_spanevent_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" + otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -21,6 +22,9 @@ func TestSpanEvent_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSpanEvent(), ms) assert.Equal(t, generateTestSpanEvent(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newSpanEvent(&otlptrace.Span_Event{}, &sharedState)) }) + assert.Panics(t, func() { newSpanEvent(&otlptrace.Span_Event{}, &sharedState).MoveTo(dest) }) } func TestSpanEvent_CopyTo(t *testing.T) { @@ -31,6 +35,8 @@ func TestSpanEvent_CopyTo(t *testing.T) { orig = generateTestSpanEvent() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newSpanEvent(&otlptrace.Span_Event{}, &sharedState)) }) } func TestSpanEvent_Timestamp(t *testing.T) { @@ -46,6 +52,8 @@ func TestSpanEvent_Name(t *testing.T) { assert.Equal(t, "", ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpanEvent(&otlptrace.Span_Event{}, &sharedState).SetName("test_name") }) } func TestSpanEvent_Attributes(t *testing.T) { @@ -60,6 +68,8 @@ func TestSpanEvent_DroppedAttributesCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedAttributesCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpanEvent(&otlptrace.Span_Event{}, &sharedState).SetDroppedAttributesCount(uint32(17)) }) } func generateTestSpanEvent() SpanEvent { @@ -71,6 +81,6 @@ func generateTestSpanEvent() SpanEvent { func fillTestSpanEvent(tv SpanEvent) { tv.orig.TimeUnixNano = 1234567890 tv.orig.Name = "test_name" - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.DroppedAttributesCount = uint32(17) } diff --git a/pdata/ptrace/generated_spaneventslice.go b/pdata/ptrace/generated_spaneventslice.go index d78c8ee1735..28a443ea990 100644 --- a/pdata/ptrace/generated_spaneventslice.go +++ b/pdata/ptrace/generated_spaneventslice.go @@ -9,6 +9,7 @@ package ptrace import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewSpanEventSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanEventSlice struct { - orig *[]*otlptrace.Span_Event + orig *[]*otlptrace.Span_Event + state *internal.State } -func newSpanEventSlice(orig *[]*otlptrace.Span_Event) SpanEventSlice { - return SpanEventSlice{orig} +func newSpanEventSlice(orig *[]*otlptrace.Span_Event, state *internal.State) SpanEventSlice { + return SpanEventSlice{orig: orig, state: state} } // NewSpanEventSlice creates a SpanEventSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSpanEventSlice() SpanEventSlice { orig := []*otlptrace.Span_Event(nil) - return newSpanEventSlice(&orig) + state := internal.StateMutable + return newSpanEventSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es SpanEventSlice) Len() int { // ... // Do something with the element // } func (es SpanEventSlice) At(i int) SpanEvent { - return newSpanEvent((*es.orig)[i]) + return newSpanEvent((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es SpanEventSlice) At(i int) SpanEvent { // // Here should set all the values for e. // } func (es SpanEventSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es SpanEventSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty SpanEvent. // It returns the newly added SpanEvent. func (es SpanEventSlice) AppendEmpty() SpanEvent { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlptrace.Span_Event{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es SpanEventSlice) AppendEmpty() SpanEvent { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanEventSlice) MoveAndAppendTo(dest SpanEventSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es SpanEventSlice) MoveAndAppendTo(dest SpanEventSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SpanEventSlice) RemoveIf(f func(SpanEvent) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es SpanEventSlice) RemoveIf(f func(SpanEvent) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es SpanEventSlice) CopyTo(dest SpanEventSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newSpanEvent((*es.orig)[i]).CopyTo(newSpanEvent((*dest.orig)[i])) + newSpanEvent((*es.orig)[i], es.state).CopyTo(newSpanEvent((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es SpanEventSlice) CopyTo(dest SpanEventSlice) { wrappers := make([]*otlptrace.Span_Event, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newSpanEvent((*es.orig)[i]).CopyTo(newSpanEvent(wrappers[i])) + newSpanEvent((*es.orig)[i], es.state).CopyTo(newSpanEvent(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es SpanEventSlice) CopyTo(dest SpanEventSlice) { // provided less function so that two instances of SpanEventSlice // can be compared. func (es SpanEventSlice) Sort(less func(a, b SpanEvent) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/ptrace/generated_spaneventslice_test.go b/pdata/ptrace/generated_spaneventslice_test.go index 76161623897..86da67e1332 100644 --- a/pdata/ptrace/generated_spaneventslice_test.go +++ b/pdata/ptrace/generated_spaneventslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) func TestSpanEventSlice(t *testing.T) { es := NewSpanEventSlice() assert.Equal(t, 0, es.Len()) - es = newSpanEventSlice(&[]*otlptrace.Span_Event{}) + state := internal.StateMutable + es = newSpanEventSlice(&[]*otlptrace.Span_Event{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewSpanEvent() @@ -32,6 +34,19 @@ func TestSpanEventSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestSpanEventSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newSpanEventSlice(&[]*otlptrace.Span_Event{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewSpanEventSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestSpanEventSlice_CopyTo(t *testing.T) { dest := NewSpanEventSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestSpanEventSlice(es SpanEventSlice) { *es.orig = make([]*otlptrace.Span_Event, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlptrace.Span_Event{} - fillTestSpanEvent(newSpanEvent((*es.orig)[i])) + fillTestSpanEvent(newSpanEvent((*es.orig)[i], es.state)) } } diff --git a/pdata/ptrace/generated_spanlink.go b/pdata/ptrace/generated_spanlink.go index 89454fb8fcb..57015671b3c 100644 --- a/pdata/ptrace/generated_spanlink.go +++ b/pdata/ptrace/generated_spanlink.go @@ -23,11 +23,12 @@ import ( // Must use NewSpanLink function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanLink struct { - orig *otlptrace.Span_Link + orig *otlptrace.Span_Link + state *internal.State } -func newSpanLink(orig *otlptrace.Span_Link) SpanLink { - return SpanLink{orig} +func newSpanLink(orig *otlptrace.Span_Link, state *internal.State) SpanLink { + return SpanLink{orig: orig, state: state} } // NewSpanLink creates a new empty SpanLink. @@ -35,12 +36,15 @@ func newSpanLink(orig *otlptrace.Span_Link) SpanLink { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSpanLink() SpanLink { - return newSpanLink(&otlptrace.Span_Link{}) + state := internal.StateMutable + return newSpanLink(&otlptrace.Span_Link{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SpanLink) MoveTo(dest SpanLink) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlptrace.Span_Link{} } @@ -52,6 +56,7 @@ func (ms SpanLink) TraceID() pcommon.TraceID { // SetTraceID replaces the traceid associated with this SpanLink. func (ms SpanLink) SetTraceID(v pcommon.TraceID) { + ms.state.AssertMutable() ms.orig.TraceId = data.TraceID(v) } @@ -62,17 +67,18 @@ func (ms SpanLink) SpanID() pcommon.SpanID { // SetSpanID replaces the spanid associated with this SpanLink. func (ms SpanLink) SetSpanID(v pcommon.SpanID) { + ms.state.AssertMutable() ms.orig.SpanId = data.SpanID(v) } // TraceState returns the tracestate associated with this SpanLink. func (ms SpanLink) TraceState() pcommon.TraceState { - return pcommon.TraceState(internal.NewTraceState(&ms.orig.TraceState)) + return pcommon.TraceState(internal.NewTraceState(&ms.orig.TraceState, ms.state)) } // Attributes returns the Attributes associated with this SpanLink. func (ms SpanLink) Attributes() pcommon.Map { - return pcommon.Map(internal.NewMap(&ms.orig.Attributes)) + return pcommon.Map(internal.NewMap(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this SpanLink. @@ -82,11 +88,13 @@ func (ms SpanLink) DroppedAttributesCount() uint32 { // SetDroppedAttributesCount replaces the droppedattributescount associated with this SpanLink. func (ms SpanLink) SetDroppedAttributesCount(v uint32) { + ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms SpanLink) CopyTo(dest SpanLink) { + dest.state.AssertMutable() dest.SetTraceID(ms.TraceID()) dest.SetSpanID(ms.SpanID()) ms.TraceState().CopyTo(dest.TraceState()) diff --git a/pdata/ptrace/generated_spanlink_test.go b/pdata/ptrace/generated_spanlink_test.go index b0bbb58a78a..7e5ec2cdb82 100644 --- a/pdata/ptrace/generated_spanlink_test.go +++ b/pdata/ptrace/generated_spanlink_test.go @@ -13,6 +13,7 @@ import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/data" + otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" "go.opentelemetry.io/collector/pdata/pcommon" ) @@ -22,6 +23,9 @@ func TestSpanLink_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewSpanLink(), ms) assert.Equal(t, generateTestSpanLink(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newSpanLink(&otlptrace.Span_Link{}, &sharedState)) }) + assert.Panics(t, func() { newSpanLink(&otlptrace.Span_Link{}, &sharedState).MoveTo(dest) }) } func TestSpanLink_CopyTo(t *testing.T) { @@ -32,6 +36,8 @@ func TestSpanLink_CopyTo(t *testing.T) { orig = generateTestSpanLink() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newSpanLink(&otlptrace.Span_Link{}, &sharedState)) }) } func TestSpanLink_TraceID(t *testing.T) { @@ -68,6 +74,8 @@ func TestSpanLink_DroppedAttributesCount(t *testing.T) { assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(17)) assert.Equal(t, uint32(17), ms.DroppedAttributesCount()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newSpanLink(&otlptrace.Span_Link{}, &sharedState).SetDroppedAttributesCount(uint32(17)) }) } func generateTestSpanLink() SpanLink { @@ -79,7 +87,7 @@ func generateTestSpanLink() SpanLink { func fillTestSpanLink(tv SpanLink) { tv.orig.TraceId = data.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) tv.orig.SpanId = data.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}) - internal.FillTestTraceState(internal.NewTraceState(&tv.orig.TraceState)) - internal.FillTestMap(internal.NewMap(&tv.orig.Attributes)) + internal.FillTestTraceState(internal.NewTraceState(&tv.orig.TraceState, tv.state)) + internal.FillTestMap(internal.NewMap(&tv.orig.Attributes, tv.state)) tv.orig.DroppedAttributesCount = uint32(17) } diff --git a/pdata/ptrace/generated_spanlinkslice.go b/pdata/ptrace/generated_spanlinkslice.go index 19d75a4807b..5a543c375e4 100644 --- a/pdata/ptrace/generated_spanlinkslice.go +++ b/pdata/ptrace/generated_spanlinkslice.go @@ -9,6 +9,7 @@ package ptrace import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewSpanLinkSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanLinkSlice struct { - orig *[]*otlptrace.Span_Link + orig *[]*otlptrace.Span_Link + state *internal.State } -func newSpanLinkSlice(orig *[]*otlptrace.Span_Link) SpanLinkSlice { - return SpanLinkSlice{orig} +func newSpanLinkSlice(orig *[]*otlptrace.Span_Link, state *internal.State) SpanLinkSlice { + return SpanLinkSlice{orig: orig, state: state} } // NewSpanLinkSlice creates a SpanLinkSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSpanLinkSlice() SpanLinkSlice { orig := []*otlptrace.Span_Link(nil) - return newSpanLinkSlice(&orig) + state := internal.StateMutable + return newSpanLinkSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es SpanLinkSlice) Len() int { // ... // Do something with the element // } func (es SpanLinkSlice) At(i int) SpanLink { - return newSpanLink((*es.orig)[i]) + return newSpanLink((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es SpanLinkSlice) At(i int) SpanLink { // // Here should set all the values for e. // } func (es SpanLinkSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es SpanLinkSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty SpanLink. // It returns the newly added SpanLink. func (es SpanLinkSlice) AppendEmpty() SpanLink { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlptrace.Span_Link{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es SpanLinkSlice) AppendEmpty() SpanLink { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanLinkSlice) MoveAndAppendTo(dest SpanLinkSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es SpanLinkSlice) MoveAndAppendTo(dest SpanLinkSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SpanLinkSlice) RemoveIf(f func(SpanLink) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es SpanLinkSlice) RemoveIf(f func(SpanLink) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es SpanLinkSlice) CopyTo(dest SpanLinkSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newSpanLink((*es.orig)[i]).CopyTo(newSpanLink((*dest.orig)[i])) + newSpanLink((*es.orig)[i], es.state).CopyTo(newSpanLink((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es SpanLinkSlice) CopyTo(dest SpanLinkSlice) { wrappers := make([]*otlptrace.Span_Link, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newSpanLink((*es.orig)[i]).CopyTo(newSpanLink(wrappers[i])) + newSpanLink((*es.orig)[i], es.state).CopyTo(newSpanLink(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es SpanLinkSlice) CopyTo(dest SpanLinkSlice) { // provided less function so that two instances of SpanLinkSlice // can be compared. func (es SpanLinkSlice) Sort(less func(a, b SpanLink) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/ptrace/generated_spanlinkslice_test.go b/pdata/ptrace/generated_spanlinkslice_test.go index 3ab05bfa547..9ad8f4dc276 100644 --- a/pdata/ptrace/generated_spanlinkslice_test.go +++ b/pdata/ptrace/generated_spanlinkslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) func TestSpanLinkSlice(t *testing.T) { es := NewSpanLinkSlice() assert.Equal(t, 0, es.Len()) - es = newSpanLinkSlice(&[]*otlptrace.Span_Link{}) + state := internal.StateMutable + es = newSpanLinkSlice(&[]*otlptrace.Span_Link{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewSpanLink() @@ -32,6 +34,19 @@ func TestSpanLinkSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestSpanLinkSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newSpanLinkSlice(&[]*otlptrace.Span_Link{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewSpanLinkSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestSpanLinkSlice_CopyTo(t *testing.T) { dest := NewSpanLinkSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestSpanLinkSlice(es SpanLinkSlice) { *es.orig = make([]*otlptrace.Span_Link, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlptrace.Span_Link{} - fillTestSpanLink(newSpanLink((*es.orig)[i])) + fillTestSpanLink(newSpanLink((*es.orig)[i], es.state)) } } diff --git a/pdata/ptrace/generated_spanslice.go b/pdata/ptrace/generated_spanslice.go index 5b39aacb073..9724e22516e 100644 --- a/pdata/ptrace/generated_spanslice.go +++ b/pdata/ptrace/generated_spanslice.go @@ -9,6 +9,7 @@ package ptrace import ( "sort" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) @@ -20,18 +21,20 @@ import ( // Must use NewSpanSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanSlice struct { - orig *[]*otlptrace.Span + orig *[]*otlptrace.Span + state *internal.State } -func newSpanSlice(orig *[]*otlptrace.Span) SpanSlice { - return SpanSlice{orig} +func newSpanSlice(orig *[]*otlptrace.Span, state *internal.State) SpanSlice { + return SpanSlice{orig: orig, state: state} } // NewSpanSlice creates a SpanSlice with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSpanSlice() SpanSlice { orig := []*otlptrace.Span(nil) - return newSpanSlice(&orig) + state := internal.StateMutable + return newSpanSlice(&orig, &state) } // Len returns the number of elements in the slice. @@ -50,7 +53,7 @@ func (es SpanSlice) Len() int { // ... // Do something with the element // } func (es SpanSlice) At(i int) Span { - return newSpan((*es.orig)[i]) + return newSpan((*es.orig)[i], es.state) } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. @@ -66,6 +69,7 @@ func (es SpanSlice) At(i int) Span { // // Here should set all the values for e. // } func (es SpanSlice) EnsureCapacity(newCap int) { + es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return @@ -79,6 +83,7 @@ func (es SpanSlice) EnsureCapacity(newCap int) { // AppendEmpty will append to the end of the slice an empty Span. // It returns the newly added Span. func (es SpanSlice) AppendEmpty() Span { + es.state.AssertMutable() *es.orig = append(*es.orig, &otlptrace.Span{}) return es.At(es.Len() - 1) } @@ -86,6 +91,8 @@ func (es SpanSlice) AppendEmpty() Span { // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanSlice) MoveAndAppendTo(dest SpanSlice) { + es.state.AssertMutable() + dest.state.AssertMutable() if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig @@ -98,6 +105,7 @@ func (es SpanSlice) MoveAndAppendTo(dest SpanSlice) { // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SpanSlice) RemoveIf(f func(Span) bool) { + es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { @@ -117,12 +125,13 @@ func (es SpanSlice) RemoveIf(f func(Span) bool) { // CopyTo copies all elements from the current slice overriding the destination. func (es SpanSlice) CopyTo(dest SpanSlice) { + dest.state.AssertMutable() srcLen := es.Len() destCap := cap(*dest.orig) if srcLen <= destCap { (*dest.orig) = (*dest.orig)[:srcLen:destCap] for i := range *es.orig { - newSpan((*es.orig)[i]).CopyTo(newSpan((*dest.orig)[i])) + newSpan((*es.orig)[i], es.state).CopyTo(newSpan((*dest.orig)[i], dest.state)) } return } @@ -130,7 +139,7 @@ func (es SpanSlice) CopyTo(dest SpanSlice) { wrappers := make([]*otlptrace.Span, srcLen) for i := range *es.orig { wrappers[i] = &origs[i] - newSpan((*es.orig)[i]).CopyTo(newSpan(wrappers[i])) + newSpan((*es.orig)[i], es.state).CopyTo(newSpan(wrappers[i], dest.state)) } *dest.orig = wrappers } @@ -139,5 +148,6 @@ func (es SpanSlice) CopyTo(dest SpanSlice) { // provided less function so that two instances of SpanSlice // can be compared. func (es SpanSlice) Sort(less func(a, b Span) bool) { + es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } diff --git a/pdata/ptrace/generated_spanslice_test.go b/pdata/ptrace/generated_spanslice_test.go index 0417d2cbd25..1ae585b996f 100644 --- a/pdata/ptrace/generated_spanslice_test.go +++ b/pdata/ptrace/generated_spanslice_test.go @@ -12,13 +12,15 @@ import ( "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) func TestSpanSlice(t *testing.T) { es := NewSpanSlice() assert.Equal(t, 0, es.Len()) - es = newSpanSlice(&[]*otlptrace.Span{}) + state := internal.StateMutable + es = newSpanSlice(&[]*otlptrace.Span{}, &state) assert.Equal(t, 0, es.Len()) emptyVal := NewSpan() @@ -32,6 +34,19 @@ func TestSpanSlice(t *testing.T) { assert.Equal(t, 7, es.Len()) } +func TestSpanSliceReadOnly(t *testing.T) { + sharedState := internal.StateReadOnly + es := newSpanSlice(&[]*otlptrace.Span{}, &sharedState) + assert.Equal(t, 0, es.Len()) + assert.Panics(t, func() { es.AppendEmpty() }) + assert.Panics(t, func() { es.EnsureCapacity(2) }) + es2 := NewSpanSlice() + es.CopyTo(es2) + assert.Panics(t, func() { es2.CopyTo(es) }) + assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) + assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) +} + func TestSpanSlice_CopyTo(t *testing.T) { dest := NewSpanSlice() // Test CopyTo to empty @@ -134,6 +149,6 @@ func fillTestSpanSlice(es SpanSlice) { *es.orig = make([]*otlptrace.Span, 7) for i := 0; i < 7; i++ { (*es.orig)[i] = &otlptrace.Span{} - fillTestSpan(newSpan((*es.orig)[i])) + fillTestSpan(newSpan((*es.orig)[i], es.state)) } } diff --git a/pdata/ptrace/generated_status.go b/pdata/ptrace/generated_status.go index c0850997b22..2b3e66a92d0 100644 --- a/pdata/ptrace/generated_status.go +++ b/pdata/ptrace/generated_status.go @@ -7,6 +7,7 @@ package ptrace import ( + "go.opentelemetry.io/collector/pdata/internal" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) @@ -19,11 +20,12 @@ import ( // Must use NewStatus function to create new instances. // Important: zero-initialized instance is not valid for use. type Status struct { - orig *otlptrace.Status + orig *otlptrace.Status + state *internal.State } -func newStatus(orig *otlptrace.Status) Status { - return Status{orig} +func newStatus(orig *otlptrace.Status, state *internal.State) Status { + return Status{orig: orig, state: state} } // NewStatus creates a new empty Status. @@ -31,12 +33,15 @@ func newStatus(orig *otlptrace.Status) Status { // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewStatus() Status { - return newStatus(&otlptrace.Status{}) + state := internal.StateMutable + return newStatus(&otlptrace.Status{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Status) MoveTo(dest Status) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlptrace.Status{} } @@ -48,6 +53,7 @@ func (ms Status) Code() StatusCode { // SetCode replaces the code associated with this Status. func (ms Status) SetCode(v StatusCode) { + ms.state.AssertMutable() ms.orig.Code = otlptrace.Status_StatusCode(v) } @@ -58,11 +64,13 @@ func (ms Status) Message() string { // SetMessage replaces the message associated with this Status. func (ms Status) SetMessage(v string) { + ms.state.AssertMutable() ms.orig.Message = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms Status) CopyTo(dest Status) { + dest.state.AssertMutable() dest.SetCode(ms.Code()) dest.SetMessage(ms.Message()) } diff --git a/pdata/ptrace/generated_status_test.go b/pdata/ptrace/generated_status_test.go index b3a960f62f1..97d158ef4b3 100644 --- a/pdata/ptrace/generated_status_test.go +++ b/pdata/ptrace/generated_status_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" ) func TestStatus_MoveTo(t *testing.T) { @@ -18,6 +21,9 @@ func TestStatus_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewStatus(), ms) assert.Equal(t, generateTestStatus(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.MoveTo(newStatus(&otlptrace.Status{}, &sharedState)) }) + assert.Panics(t, func() { newStatus(&otlptrace.Status{}, &sharedState).MoveTo(dest) }) } func TestStatus_CopyTo(t *testing.T) { @@ -28,6 +34,8 @@ func TestStatus_CopyTo(t *testing.T) { orig = generateTestStatus() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { ms.CopyTo(newStatus(&otlptrace.Status{}, &sharedState)) }) } func TestStatus_Code(t *testing.T) { @@ -43,6 +51,8 @@ func TestStatus_Message(t *testing.T) { assert.Equal(t, "", ms.Message()) ms.SetMessage("cancelled") assert.Equal(t, "cancelled", ms.Message()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { newStatus(&otlptrace.Status{}, &sharedState).SetMessage("cancelled") }) } func generateTestStatus() Status { diff --git a/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess.go b/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess.go index 5fb974d187c..50cf0c805e8 100644 --- a/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess.go +++ b/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess.go @@ -7,6 +7,7 @@ package ptraceotlp import ( + "go.opentelemetry.io/collector/pdata/internal" otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1" ) @@ -18,11 +19,12 @@ import ( // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { - orig *otlpcollectortrace.ExportTracePartialSuccess + orig *otlpcollectortrace.ExportTracePartialSuccess + state *internal.State } -func newExportPartialSuccess(orig *otlpcollectortrace.ExportTracePartialSuccess) ExportPartialSuccess { - return ExportPartialSuccess{orig} +func newExportPartialSuccess(orig *otlpcollectortrace.ExportTracePartialSuccess, state *internal.State) ExportPartialSuccess { + return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. @@ -30,12 +32,15 @@ func newExportPartialSuccess(orig *otlpcollectortrace.ExportTracePartialSuccess) // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { - return newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}) + state := internal.StateMutable + return newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}, &state) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { + ms.state.AssertMutable() + dest.state.AssertMutable() *dest.orig = *ms.orig *ms.orig = otlpcollectortrace.ExportTracePartialSuccess{} } @@ -47,6 +52,7 @@ func (ms ExportPartialSuccess) RejectedSpans() int64 { // SetRejectedSpans replaces the rejectedspans associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedSpans(v int64) { + ms.state.AssertMutable() ms.orig.RejectedSpans = v } @@ -57,11 +63,13 @@ func (ms ExportPartialSuccess) ErrorMessage() string { // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { + ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { + dest.state.AssertMutable() dest.SetRejectedSpans(ms.RejectedSpans()) dest.SetErrorMessage(ms.ErrorMessage()) } diff --git a/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess_test.go b/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess_test.go index a32ade473c3..927f0897e1b 100644 --- a/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess_test.go +++ b/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess_test.go @@ -10,6 +10,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/collector/pdata/internal" + otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { @@ -18,6 +21,13 @@ func TestExportPartialSuccess_MoveTo(t *testing.T) { ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.MoveTo(newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}, &sharedState)) + }) + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}, &sharedState).MoveTo(dest) + }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { @@ -28,6 +38,10 @@ func TestExportPartialSuccess_CopyTo(t *testing.T) { orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + ms.CopyTo(newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}, &sharedState)) + }) } func TestExportPartialSuccess_RejectedSpans(t *testing.T) { @@ -35,6 +49,10 @@ func TestExportPartialSuccess_RejectedSpans(t *testing.T) { assert.Equal(t, int64(0), ms.RejectedSpans()) ms.SetRejectedSpans(int64(13)) assert.Equal(t, int64(13), ms.RejectedSpans()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}, &sharedState).SetRejectedSpans(int64(13)) + }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { @@ -42,6 +60,10 @@ func TestExportPartialSuccess_ErrorMessage(t *testing.T) { assert.Equal(t, "", ms.ErrorMessage()) ms.SetErrorMessage("error message") assert.Equal(t, "error message", ms.ErrorMessage()) + sharedState := internal.StateReadOnly + assert.Panics(t, func() { + newExportPartialSuccess(&otlpcollectortrace.ExportTracePartialSuccess{}, &sharedState).SetErrorMessage("error message") + }) } func generateTestExportPartialSuccess() ExportPartialSuccess { diff --git a/pdata/ptrace/ptraceotlp/grpc.go b/pdata/ptrace/ptraceotlp/grpc.go index fec514eb62c..b768b08e67a 100644 --- a/pdata/ptrace/ptraceotlp/grpc.go +++ b/pdata/ptrace/ptraceotlp/grpc.go @@ -10,6 +10,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "go.opentelemetry.io/collector/pdata/internal" otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1" "go.opentelemetry.io/collector/pdata/internal/otlp" ) @@ -40,7 +41,11 @@ type grpcClient struct { // Export implements the Client interface. func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) - return ExportResponse{orig: rsp}, err + if err != nil { + return ExportResponse{}, err + } + state := internal.StateMutable + return ExportResponse{orig: rsp, state: &state}, err } func (c *grpcClient) unexported() {} @@ -80,6 +85,7 @@ type rawTracesServer struct { func (s rawTracesServer) Export(ctx context.Context, request *otlpcollectortrace.ExportTraceServiceRequest) (*otlpcollectortrace.ExportTraceServiceResponse, error) { otlp.MigrateTraces(request.ResourceSpans) - rsp, err := s.srv.Export(ctx, ExportRequest{orig: request}) + state := internal.StateMutable + rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: &state}) return rsp.orig, err } diff --git a/pdata/ptrace/ptraceotlp/request.go b/pdata/ptrace/ptraceotlp/request.go index ae9f57100f7..0bdafc8a3af 100644 --- a/pdata/ptrace/ptraceotlp/request.go +++ b/pdata/ptrace/ptraceotlp/request.go @@ -18,19 +18,27 @@ var jsonUnmarshaler = &ptrace.JSONUnmarshaler{} // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for ptrace.Traces data. type ExportRequest struct { - orig *otlpcollectortrace.ExportTraceServiceRequest + orig *otlpcollectortrace.ExportTraceServiceRequest + state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { - return ExportRequest{orig: &otlpcollectortrace.ExportTraceServiceRequest{}} + state := internal.StateMutable + return ExportRequest{ + orig: &otlpcollectortrace.ExportTraceServiceRequest{}, + state: &state, + } } // NewExportRequestFromTraces returns a ExportRequest from ptrace.Traces. // Because ExportRequest is a wrapper for ptrace.Traces, // any changes to the provided Traces struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromTraces(td ptrace.Traces) ExportRequest { - return ExportRequest{orig: internal.GetOrigTraces(internal.Traces(td))} + return ExportRequest{ + orig: internal.GetOrigTraces(internal.Traces(td)), + state: internal.GetTracesState(internal.Traces(td)), + } } // MarshalProto marshals ExportRequest into proto bytes. @@ -67,5 +75,5 @@ func (ms ExportRequest) UnmarshalJSON(data []byte) error { } func (ms ExportRequest) Traces() ptrace.Traces { - return ptrace.Traces(internal.NewTraces(ms.orig)) + return ptrace.Traces(internal.NewTraces(ms.orig, ms.state)) } diff --git a/pdata/ptrace/ptraceotlp/response.go b/pdata/ptrace/ptraceotlp/response.go index 3301131fd0a..b1417971e9d 100644 --- a/pdata/ptrace/ptraceotlp/response.go +++ b/pdata/ptrace/ptraceotlp/response.go @@ -8,18 +8,24 @@ import ( jsoniter "github.com/json-iterator/go" + "go.opentelemetry.io/collector/pdata/internal" otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1" "go.opentelemetry.io/collector/pdata/internal/json" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportResponse struct { - orig *otlpcollectortrace.ExportTraceServiceResponse + orig *otlpcollectortrace.ExportTraceServiceResponse + state *internal.State } // NewExportResponse returns an empty ExportResponse. func NewExportResponse() ExportResponse { - return ExportResponse{orig: &otlpcollectortrace.ExportTraceServiceResponse{}} + state := internal.StateMutable + return ExportResponse{ + orig: &otlpcollectortrace.ExportTraceServiceResponse{}, + state: &state, + } } // MarshalProto marshals ExportResponse into proto bytes. @@ -64,7 +70,7 @@ func (ms ExportResponse) unmarshalJsoniter(iter *jsoniter.Iterator) { // PartialSuccess returns the ExportLogsPartialSuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { - return newExportPartialSuccess(&ms.orig.PartialSuccess) + return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } func (ms ExportPartialSuccess) unmarshalJsoniter(iter *jsoniter.Iterator) { diff --git a/pdata/ptrace/traces.go b/pdata/ptrace/traces.go index 8f1f1c7fe8a..0d8294098a6 100644 --- a/pdata/ptrace/traces.go +++ b/pdata/ptrace/traces.go @@ -13,7 +13,8 @@ import ( type Traces internal.Traces func newTraces(orig *otlpcollectortrace.ExportTraceServiceRequest) Traces { - return Traces(internal.NewTraces(orig)) + state := internal.StateMutable + return Traces(internal.NewTraces(orig, &state)) } func (ms Traces) getOrig() *otlpcollectortrace.ExportTraceServiceRequest { @@ -46,5 +47,10 @@ func (ms Traces) SpanCount() int { // ResourceSpans returns the ResourceSpansSlice associated with this Metrics. func (ms Traces) ResourceSpans() ResourceSpansSlice { - return newResourceSpansSlice(&ms.getOrig().ResourceSpans) + return newResourceSpansSlice(&ms.getOrig().ResourceSpans, internal.GetTracesState(internal.Traces(ms))) +} + +// MarkReadOnly marks the Traces as shared so that no further modifications can be done on it. +func (ms Traces) MarkReadOnly() { + internal.SetTracesState(internal.Traces(ms), internal.StateReadOnly) } diff --git a/pdata/ptrace/traces_test.go b/pdata/ptrace/traces_test.go index 6145ca7b995..a09e4844d15 100644 --- a/pdata/ptrace/traces_test.go +++ b/pdata/ptrace/traces_test.go @@ -5,6 +5,7 @@ package ptrace import ( "testing" + "time" gogoproto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" @@ -13,6 +14,7 @@ import ( otlpcollectortrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/collector/trace/v1" otlptrace "go.opentelemetry.io/collector/pdata/internal/data/protogen/trace/v1" + "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSpanCount(t *testing.T) { @@ -113,3 +115,64 @@ func TestTracesCopyTo(t *testing.T) { traces.CopyTo(tracesCopy) assert.EqualValues(t, traces, tracesCopy) } + +func TestReadOnlyTracesInvalidUsage(t *testing.T) { + traces := NewTraces() + res := traces.ResourceSpans().AppendEmpty().Resource() + res.Attributes().PutStr("k1", "v1") + traces.MarkReadOnly() + assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) +} + +func BenchmarkTracesUsage(b *testing.B) { + traces := NewTraces() + fillTestResourceSpansSlice(traces.ResourceSpans()) + ts := pcommon.NewTimestampFromTime(time.Now()) + + b.ReportAllocs() + b.ResetTimer() + + for bb := 0; bb < b.N; bb++ { + for i := 0; i < traces.ResourceSpans().Len(); i++ { + rs := traces.ResourceSpans().At(i) + res := rs.Resource() + res.Attributes().PutStr("foo", "bar") + v, ok := res.Attributes().Get("foo") + assert.True(b, ok) + assert.Equal(b, "bar", v.Str()) + v.SetStr("new-bar") + assert.Equal(b, "new-bar", v.Str()) + res.Attributes().Remove("foo") + for j := 0; j < rs.ScopeSpans().Len(); j++ { + iss := rs.ScopeSpans().At(j) + iss.Scope().SetName("new_test_name") + assert.Equal(b, "new_test_name", iss.Scope().Name()) + for k := 0; k < iss.Spans().Len(); k++ { + s := iss.Spans().At(k) + s.SetName("new_span") + assert.Equal(b, "new_span", s.Name()) + s.SetStartTimestamp(ts) + assert.Equal(b, ts, s.StartTimestamp()) + s.SetEndTimestamp(ts) + assert.Equal(b, ts, s.EndTimestamp()) + s.SetTraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) + assert.Equal(b, pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), s.TraceID()) + s.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) + assert.Equal(b, pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), s.SpanID()) + } + s := iss.Spans().AppendEmpty() + s.SetName("another_span") + s.SetStartTimestamp(ts) + s.SetEndTimestamp(ts) + s.SetTraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) + s.SetParentSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) + s.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) + s.Attributes().PutStr("foo1", "bar1") + s.Attributes().PutStr("foo2", "bar2") + iss.Spans().RemoveIf(func(lr Span) bool { + return lr.Name() == "another_span" + }) + } + } + } +}