PendingSpans extends WeakConcurrentMap<TraceContext, PendingSpan> { public PendingSpan getOrCreate( @Nullable TraceContext parent, TraceContext context, boolean start) { PendingSpan result = get(context); if (result != null) return result; MutableSpan span = new MutableSpan(context, defaultSpan); PendingSpan parentSpan = parent != null ? get(parent) : null; TickClock clock; if (parentSpan != null) { TraceContext parentContext = parentSpan.context(); if (parentContext != null) parent = parentContext; clock = parentSpan.clock; if (start) span.startTimestamp(clock.currentTimeMicroseconds()); } else { long currentTimeMicroseconds = this.clock.currentTimeMicroseconds(); clock = new TickClock(currentTimeMicroseconds, System.nanoTime()); if (start) span.startTimestamp(currentTimeMicroseconds); } PendingSpan newSpan = new PendingSpan(context, span, clock); PendingSpan previousSpan = putIfProbablyAbsent(context, newSpan); if (previousSpan != null) return previousSpan; assert parent != null || context.isLocalRoot() : "Bug (or unexpected call to internal code): parent can only be null in a local root!"; spanHandler.begin(newSpan.handlerContext, newSpan.span, parentSpan != null ? parentSpan.handlerContext : null); return newSpan; } PendingSpans(MutableSpan defaultSpan, Clock clock, SpanHandler spanHandler,
    AtomicBoolean noop); @Nullable PendingSpan get(TraceContext context); PendingSpan getOrCreate(
    @Nullable TraceContext parent, TraceContext context, boolean start); void abandon(TraceContext context); void flush(TraceContext context); void finish(TraceContext context, long timestamp);  }
@Test public void getOrCreate_lazyCreatesASpan() { PendingSpan span = pendingSpans.getOrCreate(null, context, false); assertThat(span).isNotNull(); }
@Test public void getOrCreate_reusesClockFromParent() { TraceContext trace = context; TraceContext traceJoin = trace.toBuilder().shared(true).build(); TraceContext trace2 = context.toBuilder().traceId(2L).build(); TraceContext traceChild = TraceContext.newBuilder().traceId(1L).parentId(trace.spanId()).spanId(3L).build(); PendingSpan traceSpan = pendingSpans.getOrCreate(null, trace, false); PendingSpan traceJoinSpan = pendingSpans.getOrCreate(trace, traceJoin, false); PendingSpan trace2Span = pendingSpans.getOrCreate(null, trace2, false); PendingSpan traceChildSpan = pendingSpans.getOrCreate(trace, traceChild, false); assertThat(traceSpan.clock).isSameAs(traceChildSpan.clock); assertThat(traceSpan.clock).isSameAs(traceJoinSpan.clock); assertThat(traceSpan.clock).isNotSameAs(trace2Span.clock); }
@Test public void getOrCreate_cachesReference() { PendingSpan span = pendingSpans.getOrCreate(null, context, false); assertThat(pendingSpans.getOrCreate(null, context, false)).isSameAs(span); }
@Test public void getOrCreate_splitsSharedServerDataFromClient() { TraceContext context2 = context.toBuilder().shared(true).build(); assertThat(pendingSpans.getOrCreate(null, context, false)).isNotEqualTo( pendingSpans.getOrCreate(null, context2, false)); }
@Test public void remove_doesntReport() { pendingSpans.getOrCreate(null, context, false); pendingSpans.remove(context); assertThat(spans).isEmpty(); }