Skip to content

Commit e5f451c

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

File tree

2 files changed

+47
-31
lines changed

2 files changed

+47
-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: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ 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())
4245

4346
/// Create a new ``InMemoryTracer``.
4447
///
@@ -98,15 +101,17 @@ extension InMemoryTracer {
98101
kind: kind,
99102
startInstant: instant()
100103
) { finishedSpan in
101-
_activeSpans.withValue { $0[spanContext] = nil }
102-
_finishedSpans.withValue { $0.append(finishedSpan) }
104+
_state.withValue {
105+
$0.activeSpans[spanContext] = nil
106+
$0.finishedSpans.append(finishedSpan)
107+
}
103108
}
104-
_activeSpans.withValue { $0[spanContext] = span }
109+
_state.withValue { $0.activeSpans[spanContext] = span }
105110
return span
106111
}
107112

108113
public func forceFlush() {
109-
_numberOfForceFlushes.withValue { $0 += 1 }
114+
_state.withValue { $0.numberOfForceFlushes += 1 }
110115
}
111116
}
112117

@@ -116,48 +121,50 @@ extension InMemoryTracer {
116121

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

122127
/// Retrives a specific _active_ span, identified by the specific span, trace, and parent ID's
123128
/// stored in the `inMemorySpanContext`
124129
public func activeSpan(identifiedBy context: ServiceContext) -> InMemorySpan? {
125130
guard let spanContext = context.inMemorySpanContext else { return nil }
126-
return _activeSpans.withValue { $0[spanContext] }
131+
return _state.withValue { $0.activeSpans[spanContext] }
127132
}
128133

129134
/// Count of the number of times ``Tracer/forceFlush()`` was called on this tracer.
130135
public var numberOfForceFlushes: Int {
131-
_numberOfForceFlushes.withValue { $0 }
136+
_state.withValue { $0.numberOfForceFlushes }
132137
}
133138

134139
/// Gets, without removing, all the finished spans recorded by this tracer.
135140
///
136141
/// - SeeAlso: `popFinishedSpans()`
137142
public var finishedSpans: [FinishedInMemorySpan] {
138-
_finishedSpans.withValue { $0 }
143+
_state.withValue { $0.finishedSpans }
139144
}
140145

141146
/// Returns, and removes, all finished spans recorded by this tracer.
142147
public func popFinishedSpans() -> [FinishedInMemorySpan] {
143-
_finishedSpans.withValue { spans in
144-
defer { spans = [] }
145-
return spans
148+
_state.withValue { state in
149+
defer { state.finishedSpans = [] }
150+
return state.finishedSpans
146151
}
147152
}
148153

149154
/// Atomically clears any stored finished spans in this tracer.
150155
public func clearFinishedSpans() {
151-
_finishedSpans.withValue { $0 = [] }
156+
_state.withValue { $0.finishedSpans = [] }
152157
}
153158

154159
/// Clears all registered finished spans, as well as injections/extractions performed by this tracer.
155160
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 = [:] }
161+
_state.withValue {
162+
$0.finishedSpans = []
163+
$0.injections = []
164+
$0.extractions = []
165+
if includingActive {
166+
$0.activeSpans = [:]
167+
}
161168
}
162169
}
163170
}
@@ -185,19 +192,19 @@ extension InMemoryTracer {
185192

186193
if recordInjections {
187194
let injection = Injection(context: context, values: values)
188-
_injections.withValue { $0.append(injection) }
195+
_state.withValue { $0.injections.append(injection) }
189196
}
190197
}
191198

192199
/// Lists all recorded calls to this tracer's ``Instrument/inject(_:into:using:)`` method.
193200
/// This may be used to inspect what span identifiers are being propagated by this tracer.
194201
public var performedContextInjections: [Injection] {
195-
_injections.withValue { $0 }
202+
_state.withValue { $0.injections }
196203
}
197204

198205
/// Clear the list of recorded context injections (calls to ``Instrument/inject(_:into:using:)``).
199206
public func clearPerformedContextInjections() {
200-
_injections.withValue { $0 = [] }
207+
_state.withValue { $0.injections = [] }
201208
}
202209

203210
/// Represents a recorded call to the InMemoryTracer's ``Instrument/inject(_:into:using:)`` method.
@@ -219,7 +226,7 @@ extension InMemoryTracer {
219226
defer {
220227
if self.recordExtractions {
221228
let extraction = Extraction(carrier: carrier, context: context)
222-
_extractions.withValue { $0.append(extraction) }
229+
_state.withValue { $0.extractions.append(extraction) }
223230
}
224231
}
225232

@@ -235,7 +242,7 @@ extension InMemoryTracer {
235242
/// Lists all recorded calls to this tracer's ``Instrument/extract(_:into:using:)`` method.
236243
/// This may be used to inspect what span identifiers were extracted from an incoming carrier object into ``ServiceContext``.
237244
public var performedContextExtractions: [Extraction] {
238-
_extractions.withValue { $0 }
245+
_state.withValue { $0.extractions }
239246
}
240247

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

0 commit comments

Comments
 (0)