Skip to content

Commit 49fc046

Browse files
committed
Revert "Try alternative SpanCollection implementation"
This reverts commit 9b542fd6b89bfa0b31025d9587fd6f64df8aad03.
1 parent 685debf commit 49fc046

File tree

1 file changed

+55
-32
lines changed

1 file changed

+55
-32
lines changed

tracer/src/Datadog.Trace/Agent/SpanCollection.cs

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
using System.Collections.Generic;
1111
using System.Runtime.CompilerServices;
1212
using Datadog.Trace.SourceGenerators;
13+
#if NETFRAMEWORK
14+
using Datadog.Trace.VendoredMicrosoftCode.System.Runtime.CompilerServices.Unsafe;
15+
#endif
1316

1417
namespace Datadog.Trace.Agent;
1518

@@ -18,8 +21,7 @@ namespace Datadog.Trace.Agent;
1821
/// </summary>
1922
internal readonly struct SpanCollection : IEnumerable<Span>
2023
{
21-
private readonly Span? _span;
22-
private readonly Span[]? _spans;
24+
private readonly object? _values;
2325
public readonly int Count;
2426

2527
/// <summary>
@@ -28,7 +30,7 @@ namespace Datadog.Trace.Agent;
2830
/// <param name="value">The span to include in the collection.</param>
2931
public SpanCollection(Span value)
3032
{
31-
_span = value;
33+
_values = value;
3234
Count = 1;
3335
}
3436

@@ -38,7 +40,7 @@ public SpanCollection(Span value)
3840
/// <param name="arrayBuilderCapacity">The value to initializer</param>
3941
public SpanCollection(int arrayBuilderCapacity)
4042
{
41-
_spans = new Span[arrayBuilderCapacity];
43+
_values = new Span[arrayBuilderCapacity];
4244
Count = 0;
4345
}
4446

@@ -49,7 +51,7 @@ public SpanCollection(Span[] values, int count)
4951
{
5052
// We assume that the caller is "sensible" here, and doesn't set count > values.Length,
5153
// but that will get hit "safely" elsewhere if it happens
52-
_spans = values;
54+
_values = values;
5355
Count = count;
5456
}
5557

@@ -67,18 +69,20 @@ public Span? RootSpan
6769
[MethodImpl(MethodImplOptions.AggressiveInlining)]
6870
get
6971
{
70-
if (_span is not null)
72+
// Take local copy of _values so type checks remain valid even if the SpanCollection is overwritten in memory
73+
var value = _values;
74+
if (value is Span span)
7175
{
72-
return _span;
76+
return span;
7377
}
7478

75-
if (_spans is null)
79+
if (value is null)
7680
{
7781
return null;
7882
}
7983

8084
// Not Span, not null, can only be SpanArray
81-
return _spans[0];
85+
return Unsafe.As<Span[]>(value)[0];
8286
}
8387
}
8488

@@ -92,16 +96,19 @@ public Span this[int index]
9296
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9397
get
9498
{
95-
if (_span is not null)
99+
// Take local copy of _values so type checks remain valid even if the SpanCollection is overwritten in memory
100+
object? value = _values;
101+
if (index < Count)
96102
{
97-
if (index == 0)
103+
if (value is Span str)
98104
{
99-
return _span;
105+
return str;
106+
}
107+
else if (value != null)
108+
{
109+
// Not Span, not null, can only be Span[]
110+
return Unsafe.As<Span[]>(value)[index];
100111
}
101-
}
102-
else if (_spans is not null && index < Count)
103-
{
104-
return _spans[index];
105112
}
106113

107114
return OutOfBounds(); // throws
@@ -116,19 +123,23 @@ public Span this[int index]
116123
/// <returns>The concatenation of <paramref name="values"/> and <paramref name="value"/>.</returns>
117124
public static SpanCollection Append(in SpanCollection values, Span value)
118125
{
119-
if (values._span is not null)
126+
// Take local copy of _values so type checks remain valid even if the SpanCollection is overwritten in memory
127+
var current = values._values;
128+
if (current is null)
120129
{
121-
// We use a default capacity of 4 spans
122-
// 2 Spans would cover 25% not covered by single span case, 4 covers ~ 70%, 8 covers ~92%
123-
return new SpanCollection([values._span, value, null!, null!], 2);
130+
return new SpanCollection(value);
124131
}
125132

126-
if (values._spans is null)
133+
if (current is Span span)
127134
{
128-
return new SpanCollection(value);
135+
// We use a default capacity of 4 spans
136+
// 2 Spans would cover 25% not covered by single span case, 4 covers ~ 70%, 8 covers ~92%
137+
return new SpanCollection([span, value, null!, null!], 2);
129138
}
130139

131-
var array = GrowIfNeeded(values._spans, values.Count);
140+
// Not Span, not null, can only be Span[], so add the span
141+
var array = Unsafe.As<Span[]>(current);
142+
array = GrowIfNeeded(array, values.Count);
132143
array[values.Count] = value;
133144
return new SpanCollection(array, values.Count + 1);
134145
}
@@ -150,17 +161,20 @@ private static Span OutOfBounds()
150161
/// </remarks>
151162
public ArraySegment<Span> ToArray()
152163
{
153-
if (_spans is not null)
164+
// Take local copy of _values so type checks remain valid even if the SpanCollection is overwritten in memory
165+
object? value = _values;
166+
if (value is Span[] values)
154167
{
155-
return new ArraySegment<Span>(_spans, 0, Count);
168+
return new ArraySegment<Span>(values, 0, Count);
156169
}
157-
else if (_span is not null)
170+
else if (value != null)
158171
{
159-
return new ArraySegment<Span>([_span], 0, 1);
172+
// value not array, can only be Span
173+
return new ArraySegment<Span>([Unsafe.As<Span>(value)], 0, 1);
160174
}
161175
else
162176
{
163-
return new ArraySegment<Span>([], 0, 0);
177+
return new ArraySegment<Span>(Array.Empty<Span>(), 0, 0);
164178
}
165179
}
166180

@@ -183,7 +197,7 @@ private static Span[] GrowIfNeeded(Span[] array, int currentCount)
183197
/// <returns>An enumerator that can be used to iterate through the <see cref="SpanCollection" />.</returns>
184198
public Enumerator GetEnumerator()
185199
{
186-
return new Enumerator(_span, _spans, Count);
200+
return new Enumerator(_values, Count);
187201
}
188202

189203
/// <inheritdoc cref="GetEnumerator()" />
@@ -208,9 +222,9 @@ public struct Enumerator : IEnumerator<Span>
208222
private int _index;
209223
private Span? _current;
210224

211-
internal Enumerator(Span? span, Span[]? spans, int count)
225+
internal Enumerator(object? value, int count)
212226
{
213-
if (span is not null)
227+
if (value is Span span)
214228
{
215229
_values = null;
216230
_current = span;
@@ -219,13 +233,22 @@ internal Enumerator(Span? span, Span[]? spans, int count)
219233
else
220234
{
221235
_current = null;
222-
_values = spans;
236+
_values = Unsafe.As<Span[]>(value);
223237
_count = count;
224238
}
225239

226240
_index = 0;
227241
}
228242

243+
/// <summary>
244+
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
245+
/// </summary>
246+
/// <param name="values">The <see cref="SpanCollection"/> to enumerate.</param>
247+
public Enumerator(ref SpanCollection values)
248+
: this(values._values, values.Count)
249+
{
250+
}
251+
229252
/// <summary>
230253
/// Gets the element at the current position of the enumerator.
231254
/// </summary>

0 commit comments

Comments
 (0)