Skip to content

Commit adc1fd9

Browse files
committed
[InMemory] Simplify locking and avoid double-storing same values
1 parent 7dcf986 commit adc1fd9

File tree

2 files changed

+48
-31
lines changed

2 files changed

+48
-31
lines changed

Sources/InMemoryTracing/InMemorySpan.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import Tracing
2020
public struct InMemorySpan: Span {
2121

2222
public let context: ServiceContext
23-
public let spanContext: InMemorySpanContext
23+
public var spanContext: InMemorySpanContext {
24+
context.inMemorySpanContext!
25+
}
2426

2527
/// The ID of the overall trace this span belongs to.
2628
public var traceID: String {
@@ -57,8 +59,9 @@ public struct InMemorySpan: Span {
5759
onEnd: @escaping @Sendable (FinishedInMemorySpan) -> Void
5860
) {
5961
self._operationName = LockedValueBox(operationName)
62+
var context = context
63+
context.inMemorySpanContext = spanContext
6064
self.context = context
61-
self.spanContext = spanContext
6265
self.kind = kind
6366
self.startInstant = startInstant
6467
self.onEnd = onEnd
@@ -143,7 +146,6 @@ public struct InMemorySpan: Span {
143146
let finishedSpan = FinishedInMemorySpan(
144147
operationName: operationName,
145148
context: context,
146-
spanContext: spanContext,
147149
kind: kind,
148150
startInstant: startInstant,
149151
endInstant: instant(),
@@ -169,7 +171,14 @@ public struct FinishedInMemorySpan: Sendable {
169171
public var operationName: String
170172

171173
public var context: ServiceContext
172-
public var spanContext: InMemorySpanContext
174+
public var spanContext: InMemorySpanContext {
175+
get {
176+
context.inMemorySpanContext!
177+
}
178+
set {
179+
context.inMemorySpanContext = newValue
180+
}
181+
}
173182

174183
/// The ID of the overall trace this span belongs to.
175184
public var traceID: String {

Sources/InMemoryTracing/InMemoryTracer.swift

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@ public struct InMemoryTracer: Tracer {
3333
public let recordInjections: Bool
3434
public let recordExtractions: Bool
3535

36-
private let _activeSpans = LockedValueBox<[InMemorySpanContext: InMemorySpan]>([:])
37-
private let _finishedSpans = LockedValueBox<[FinishedInMemorySpan]>([])
38-
private let _numberOfForceFlushes = LockedValueBox<Int>(0)
36+
struct State {
37+
var _activeSpans: [InMemorySpanContext: InMemorySpan] = [:]
38+
var _finishedSpans: [FinishedInMemorySpan] = []
39+
var _numberOfForceFlushes: Int = 0
3940

40-
private let _injections = LockedValueBox<[Injection]>([])
41-
private let _extractions = LockedValueBox<[Extraction]>([])
41+
var _injections: [Injection] = []
42+
var _extractions: [Extraction] = []
43+
}
44+
var _state = LockedValueBox<State>(.init())
45+
4246

4347
/// Create a new ``InMemoryTracer``.
4448
///
@@ -98,15 +102,17 @@ extension InMemoryTracer {
98102
kind: kind,
99103
startInstant: instant()
100104
) { finishedSpan in
101-
_activeSpans.withValue { $0[spanContext] = nil }
102-
_finishedSpans.withValue { $0.append(finishedSpan) }
105+
_state.withValue {
106+
$0._activeSpans[spanContext] = nil
107+
$0._finishedSpans.append(finishedSpan)
108+
}
103109
}
104-
_activeSpans.withValue { $0[spanContext] = span }
110+
_state.withValue { $0._activeSpans[spanContext] = span }
105111
return span
106112
}
107113

108114
public func forceFlush() {
109-
_numberOfForceFlushes.withValue { $0 += 1 }
115+
_state.withValue { $0._numberOfForceFlushes += 1 }
110116
}
111117
}
112118

@@ -116,48 +122,50 @@ extension InMemoryTracer {
116122

117123
/// Array of active spans, i.e. spans which have been started but have not yet finished (by calling `Span/end()`).
118124
public var activeSpans: [InMemorySpan] {
119-
_activeSpans.withValue { active in Array(active.values) }
125+
_state.withValue { Array($0._activeSpans.values) }
120126
}
121127

122128
/// Retrives a specific _active_ span, identified by the specific span, trace, and parent ID's
123129
/// stored in the `inMemorySpanContext`
124130
public func activeSpan(identifiedBy context: ServiceContext) -> InMemorySpan? {
125131
guard let spanContext = context.inMemorySpanContext else { return nil }
126-
return _activeSpans.withValue { $0[spanContext] }
132+
return _state.withValue { $0._activeSpans[spanContext] }
127133
}
128134

129135
/// Count of the number of times ``Tracer/forceFlush()`` was called on this tracer.
130136
public var numberOfForceFlushes: Int {
131-
_numberOfForceFlushes.withValue { $0 }
137+
_state.withValue { $0._numberOfForceFlushes }
132138
}
133139

134140
/// Gets, without removing, all the finished spans recorded by this tracer.
135141
///
136142
/// - SeeAlso: `popFinishedSpans()`
137143
public var finishedSpans: [FinishedInMemorySpan] {
138-
_finishedSpans.withValue { $0 }
144+
_state.withValue { $0._finishedSpans }
139145
}
140146

141147
/// Returns, and removes, all finished spans recorded by this tracer.
142148
public func popFinishedSpans() -> [FinishedInMemorySpan] {
143-
_finishedSpans.withValue { spans in
144-
defer { spans = [] }
145-
return spans
149+
_state.withValue { state in
150+
defer { state._finishedSpans = [] }
151+
return state._finishedSpans
146152
}
147153
}
148154

149155
/// Atomically clears any stored finished spans in this tracer.
150156
public func clearFinishedSpans() {
151-
_finishedSpans.withValue { $0 = [] }
157+
_state.withValue { $0._finishedSpans = [] }
152158
}
153159

154160
/// Clears all registered finished spans, as well as injections/extractions performed by this tracer.
155161
public func clearAll(includingActive: Bool = false) {
156-
_finishedSpans.withValue { $0 = [] }
157-
_injections.withValue { $0 = [] }
158-
_extractions.withValue { $0 = [] }
159-
if includingActive {
160-
_activeSpans.withValue { $0 = [:] }
162+
_state.withValue {
163+
$0._finishedSpans = []
164+
$0._injections = []
165+
$0._extractions = []
166+
if includingActive {
167+
$0._activeSpans = [:]
168+
}
161169
}
162170
}
163171
}
@@ -185,19 +193,19 @@ extension InMemoryTracer {
185193

186194
if recordInjections {
187195
let injection = Injection(context: context, values: values)
188-
_injections.withValue { $0.append(injection) }
196+
_state.withValue { $0._injections.append(injection) }
189197
}
190198
}
191199

192200
/// Lists all recorded calls to this tracer's ``Instrument/inject(_:into:using:)`` method.
193201
/// This may be used to inspect what span identifiers are being propagated by this tracer.
194202
public var performedContextInjections: [Injection] {
195-
_injections.withValue { $0 }
203+
_state.withValue { $0._injections }
196204
}
197205

198206
/// Clear the list of recorded context injections (calls to ``Instrument/inject(_:into:using:)``).
199207
public func clearPerformedContextInjections() {
200-
_injections.withValue { $0 = [] }
208+
_state.withValue { $0._injections = [] }
201209
}
202210

203211
/// Represents a recorded call to the InMemoryTracer's ``Instrument/inject(_:into:using:)`` method.
@@ -219,7 +227,7 @@ extension InMemoryTracer {
219227
defer {
220228
if self.recordExtractions {
221229
let extraction = Extraction(carrier: carrier, context: context)
222-
_extractions.withValue { $0.append(extraction) }
230+
_state.withValue { $0._extractions.append(extraction) }
223231
}
224232
}
225233

@@ -235,7 +243,7 @@ extension InMemoryTracer {
235243
/// Lists all recorded calls to this tracer's ``Instrument/extract(_:into:using:)`` method.
236244
/// This may be used to inspect what span identifiers were extracted from an incoming carrier object into ``ServiceContext``.
237245
public var performedContextExtractions: [Extraction] {
238-
_extractions.withValue { $0 }
246+
_state.withValue { $0._extractions }
239247
}
240248

241249
/// Represents a recorded call to the InMemoryTracer's ``Instrument/extract(_:into:using:)`` method.

0 commit comments

Comments
 (0)