Leverage a private object monitor lock instead of synchronizing on "this". (#612)
* Leverage a ReentrantReadWriteLock instead of synchronizing on this. * remove lazy init of events * just use a basic synchronized block * appease checkstyle * small tweaks, post-rebase * fix synchronized after rebase
This commit is contained in:
parent
db0812c50b
commit
8aeada6b54
|
|
@ -47,14 +47,13 @@ import javax.annotation.concurrent.ThreadSafe;
|
||||||
/** Implementation for the {@link Span} class that records trace events. */
|
/** Implementation for the {@link Span} class that records trace events. */
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(Tracer.class.getName());
|
private static final Logger logger = Logger.getLogger(Tracer.class.getName());
|
||||||
|
|
||||||
// Contains the identifiers associated with this Span.
|
// Contains the identifiers associated with this Span.
|
||||||
private final SpanContext context;
|
private final SpanContext context;
|
||||||
// The parent SpanId of this span. Invalid if this is a root span.
|
// The parent SpanId of this span. Invalid if this is a root span.
|
||||||
private final SpanId parentSpanId;
|
private final SpanId parentSpanId;
|
||||||
// Active trace configs when the Span was created.
|
|
||||||
private final TraceConfig traceConfig;
|
|
||||||
// Handler called when the span starts and ends.
|
// Handler called when the span starts and ends.
|
||||||
private final SpanProcessor spanProcessor;
|
private final SpanProcessor spanProcessor;
|
||||||
// The displayed name of the span.
|
// The displayed name of the span.
|
||||||
|
|
@ -63,7 +62,10 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
// Number of links recorded.
|
// Number of links recorded.
|
||||||
private final int totalRecordedLinks;
|
private final int totalRecordedLinks;
|
||||||
|
|
||||||
@GuardedBy("this")
|
// Lock used to internally guard the mutable state of this instance
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
private String name;
|
private String name;
|
||||||
// The kind of the span.
|
// The kind of the span.
|
||||||
private final Kind kind;
|
private final Kind kind;
|
||||||
|
|
@ -77,28 +79,26 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
// The start time of the span.
|
// The start time of the span.
|
||||||
private final long startNanoTime;
|
private final long startNanoTime;
|
||||||
// Set of recorded attributes. DO NOT CALL any other method that changes the ordering of events.
|
// Set of recorded attributes. DO NOT CALL any other method that changes the ordering of events.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
@Nullable
|
private final AttributesWithCapacity attributes;
|
||||||
private AttributesWithCapacity attributes;
|
|
||||||
// List of recorded events.
|
// List of recorded events.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
@Nullable
|
private final EvictingQueue<TimedEvent> events;
|
||||||
private EvictingQueue<TimedEvent> events;
|
|
||||||
// Number of events recorded.
|
// Number of events recorded.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
private int totalRecordedEvents = 0;
|
private int totalRecordedEvents = 0;
|
||||||
// The number of children.
|
// The number of children.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
private int numberOfChildren;
|
private int numberOfChildren;
|
||||||
// The status of the span.
|
// The status of the span.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private Status status;
|
private Status status;
|
||||||
// The end time of the span.
|
// The end time of the span.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
private long endNanoTime;
|
private long endNanoTime;
|
||||||
// True if the span is ended.
|
// True if the span is ended.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
private boolean hasBeenEnded;
|
private boolean hasBeenEnded;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -202,7 +202,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +214,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
* @return the end nano time.
|
* @return the end nano time.
|
||||||
*/
|
*/
|
||||||
private long getEndNanoTime() {
|
private long getEndNanoTime() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return getEndNanoTimeInternal();
|
return getEndNanoTimeInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -226,7 +226,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Status getStatus() {
|
Status getStatus() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return getStatusWithDefault();
|
return getStatusWithDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -237,8 +237,8 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
* @return The TimedEvents for this span.
|
* @return The TimedEvents for this span.
|
||||||
*/
|
*/
|
||||||
private List<TimedEvent> getTimedEvents() {
|
private List<TimedEvent> getTimedEvents() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return events == null ? Collections.<TimedEvent>emptyList() : new ArrayList<>(events);
|
return new ArrayList<>(events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,7 +249,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<Link> getLinks() {
|
List<Link> getLinks() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (links == null) {
|
if (links == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
@ -274,8 +274,8 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Map<String, AttributeValue> getAttributes() {
|
Map<String, AttributeValue> getAttributes() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return Collections.unmodifiableMap(getInitializedAttributes());
|
return Collections.unmodifiableMap(attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,16 +286,18 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
* @return the latency of the {@code Span} in nanos.
|
* @return the latency of the {@code Span} in nanos.
|
||||||
*/
|
*/
|
||||||
long getLatencyNs() {
|
long getLatencyNs() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return getEndNanoTimeInternal() - startNanoTime;
|
return getEndNanoTimeInternal() - startNanoTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use getEndNanoTimeInternal to avoid over-locking.
|
// Use getEndNanoTimeInternal to avoid over-locking.
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
private long getEndNanoTimeInternal() {
|
private long getEndNanoTimeInternal() {
|
||||||
|
synchronized (lock) {
|
||||||
return hasBeenEnded ? endNanoTime : clock.nanoTime();
|
return hasBeenEnded ? endNanoTime : clock.nanoTime();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the kind of this {@code Span}.
|
* Returns the kind of this {@code Span}.
|
||||||
|
|
@ -351,12 +353,12 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
public void setAttribute(String key, AttributeValue value) {
|
public void setAttribute(String key, AttributeValue value) {
|
||||||
Preconditions.checkNotNull(key, "key");
|
Preconditions.checkNotNull(key, "key");
|
||||||
Preconditions.checkNotNull(value, "value");
|
Preconditions.checkNotNull(value, "value");
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenEnded) {
|
if (hasBeenEnded) {
|
||||||
logger.log(Level.FINE, "Calling setAttribute() on an ended Span.");
|
logger.log(Level.FINE, "Calling setAttribute() on an ended Span.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getInitializedAttributes().putAttribute(key, value);
|
attributes.putAttribute(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,12 +393,12 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTimedEvent(TimedEvent timedEvent) {
|
private void addTimedEvent(TimedEvent timedEvent) {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenEnded) {
|
if (hasBeenEnded) {
|
||||||
logger.log(Level.FINE, "Calling addEvent() on an ended Span.");
|
logger.log(Level.FINE, "Calling addEvent() on an ended Span.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getInitializedEvents().add(timedEvent);
|
events.add(timedEvent);
|
||||||
totalRecordedEvents++;
|
totalRecordedEvents++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -404,7 +406,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(Status status) {
|
public void setStatus(Status status) {
|
||||||
Preconditions.checkNotNull(status, "status");
|
Preconditions.checkNotNull(status, "status");
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenEnded) {
|
if (hasBeenEnded) {
|
||||||
logger.log(Level.FINE, "Calling setStatus() on an ended Span.");
|
logger.log(Level.FINE, "Calling setStatus() on an ended Span.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -416,7 +418,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
@Override
|
@Override
|
||||||
public void updateName(String name) {
|
public void updateName(String name) {
|
||||||
Preconditions.checkNotNull(name, "name");
|
Preconditions.checkNotNull(name, "name");
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenEnded) {
|
if (hasBeenEnded) {
|
||||||
logger.log(Level.FINE, "Calling updateName() on an ended Span.");
|
logger.log(Level.FINE, "Calling updateName() on an ended Span.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -438,7 +440,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endInternal() {
|
private void endInternal() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenEnded) {
|
if (hasBeenEnded) {
|
||||||
logger.log(Level.FINE, "Calling end() on an ended Span.");
|
logger.log(Level.FINE, "Calling end() on an ended Span.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -460,7 +462,7 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChild() {
|
void addChild() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (hasBeenEnded) {
|
if (hasBeenEnded) {
|
||||||
logger.log(Level.FINE, "Calling end() on an ended Span.");
|
logger.log(Level.FINE, "Calling end() on an ended Span.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -469,30 +471,17 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("lock")
|
||||||
private AttributesWithCapacity getInitializedAttributes() {
|
|
||||||
if (attributes == null) {
|
|
||||||
attributes = new AttributesWithCapacity(traceConfig.getMaxNumberOfAttributes());
|
|
||||||
}
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GuardedBy("this")
|
|
||||||
private EvictingQueue<TimedEvent> getInitializedEvents() {
|
|
||||||
if (events == null) {
|
|
||||||
events = EvictingQueue.create(traceConfig.getMaxNumberOfEvents());
|
|
||||||
}
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GuardedBy("this")
|
|
||||||
private Status getStatusWithDefault() {
|
private Status getStatusWithDefault() {
|
||||||
|
synchronized (lock) {
|
||||||
return status == null ? Status.OK : status;
|
return status == null ? Status.OK : status;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A map implementation with a fixed capacity that drops events when the map gets full. Eviction
|
// A map implementation with a fixed capacity that drops events when the map gets full. Eviction
|
||||||
// is based on the access order.
|
// is based on the access order.
|
||||||
static final class AttributesWithCapacity extends LinkedHashMap<String, AttributeValue> {
|
static final class AttributesWithCapacity extends LinkedHashMap<String, AttributeValue> {
|
||||||
|
|
||||||
private final long capacity;
|
private final long capacity;
|
||||||
private int totalRecordedAttributes = 0;
|
private int totalRecordedAttributes = 0;
|
||||||
// Here because -Werror complains about this: [serial] serializable class AttributesWithCapacity
|
// Here because -Werror complains about this: [serial] serializable class AttributesWithCapacity
|
||||||
|
|
@ -545,7 +534,6 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
this.totalRecordedLinks = totalRecordedLinks;
|
this.totalRecordedLinks = totalRecordedLinks;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
this.traceConfig = traceConfig;
|
|
||||||
this.spanProcessor = spanProcessor;
|
this.spanProcessor = spanProcessor;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
|
|
@ -554,15 +542,15 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
this.timestampConverter =
|
this.timestampConverter =
|
||||||
timestampConverter != null ? timestampConverter : TimestampConverter.now(clock);
|
timestampConverter != null ? timestampConverter : TimestampConverter.now(clock);
|
||||||
startNanoTime = clock.nanoTime();
|
startNanoTime = clock.nanoTime();
|
||||||
if (!attributes.isEmpty()) {
|
this.attributes = new AttributesWithCapacity(traceConfig.getMaxNumberOfAttributes());
|
||||||
getInitializedAttributes().putAll(attributes);
|
this.attributes.putAll(attributes);
|
||||||
}
|
this.events = EvictingQueue.create(traceConfig.getMaxNumberOfEvents());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("NoFinalizer")
|
@SuppressWarnings("NoFinalizer")
|
||||||
@Override
|
@Override
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
if (!hasBeenEnded) {
|
if (!hasBeenEnded) {
|
||||||
logger.log(Level.SEVERE, "Span " + name + " is GC'ed without being ended.");
|
logger.log(Level.SEVERE, "Span " + name + " is GC'ed without being ended.");
|
||||||
}
|
}
|
||||||
|
|
@ -582,14 +570,14 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
int getNumberOfChildren() {
|
int getNumberOfChildren() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return numberOfChildren;
|
return numberOfChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
int getTotalRecordedEvents() {
|
int getTotalRecordedEvents() {
|
||||||
synchronized (this) {
|
synchronized (lock) {
|
||||||
return totalRecordedEvents;
|
return totalRecordedEvents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue