All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brave.internal.extra.Extra Maven / Gradle / Ivy

There is a newer version: 6.0.3
Show newest version
/*
 * Copyright 2013-2020 The OpenZipkin Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package brave.internal.extra;

import brave.internal.Nullable;
import brave.propagation.TraceContext;
import brave.propagation.TraceContextOrSamplingFlags;
import java.util.Arrays;

/**
 * Holds extended state in {@link TraceContext#extra()} or {@link TraceContextOrSamplingFlags#extra()}.
 *
 * 

Implementations copy-on-write when changing {@linkplain #state} to prevent a child context * from affecting its parent. * * @param Use a final type as otherwise tools like {@link TraceContext#findExtra(Class)} will * not work. In most cases, the type should be package private. * @param The factory that {@link ExtraFactory#create() creates} this instance. */ // We handle dynamic vs fixed state internally as it.. // * hides generic type complexity // * gives us a lock not exposed to users // * allows findExtra(ExtraFieldsSubtype.class) public abstract class Extra, F extends ExtraFactory> { protected final F factory; // compared by reference to ensure same configuration /** * Updates like {@link #tryToClaim(long, long)} lock on this object, as should any non-atomic * {@link #state} updates. */ protected final Object lock = new Object(); /** * Lock on {@link #lock} when comparing existing values for a state update that happens after * {@link #mergeStateKeepingOursOnConflict(Extra)}. */ protected volatile Object state; long traceId; long spanId; // guarded by lock protected Extra(F factory) { if (factory == null) throw new NullPointerException("factory == null"); this.factory = factory; this.state = factory.initialState; } /** * {@code this} instance is newly provisioned, but may have non-empty state. Compare its * {@linkplain Extra#state state} vs theirs and copy their properties. * *

As typical in this type, treat state copy-on-write, but do not add overhead unnecessarily. * For example, if properties are the same, return without copying. * *

Ex 1: If state is a map, and ours includes {@code A -> 1, B -> 2} and so does theirs, * do not make a copy, just return either. *

Ex 1: If state is a map, and ours includes {@code A -> 1, B -> 2} and theirs * includes {@code A -> 2, D -> 1}, create a new state of {@code A -> 1, B -> 2, D -> 1}. * *

Note: This operation does not need to {@linkplain #lock lock} as long as changes * happen before updating {@link #state}. See MemoryVisibility * for details on "happens before" and volatile fields. */ protected abstract void mergeStateKeepingOursOnConflict(E that); /** Fields are extracted before a context is created. We need to lazy set the context */ final boolean tryToClaim(long traceId, long spanId) { synchronized (lock) { if (this.traceId == 0L) { this.traceId = traceId; this.spanId = spanId; return true; } return this.traceId == traceId && this.spanId == spanId; } } /** * Only {@linkplain #state state} is used in {@link #equals(Object)}. For example, return {@link * Arrays#equals(Object[], Object[])}, if the state is {@code Object[]}. * * @param thatState {@linkplain #state state} being compared. It is from the same type as this. */ protected abstract boolean stateEquals(Object thatState); /** * Only {@linkplain #state state} is used in {@link #hashCode()}. For example, return {@link * Arrays#hashCode(Object[])}, if the state is {@code Object[]}. */ protected abstract int stateHashCode(); /** * Only {@linkplain #state state} is used in {@link #hashCode()}. For example, return {@link * Arrays#toString(Object[])}, if the state is {@code Object[]}. */ protected abstract String stateString(); // Implemented for equals when nothing was extracted @Override public final boolean equals(Object o) { if (o == this) return true; // Extra fields should be equal on exact type, not subtype. // Otherwise, consolidation doesn't work if (!getClass().isInstance(o)) return false; return stateEquals(((E) o).state); } @Override public final int hashCode() { return stateHashCode(); } @Override public final String toString() { return getClass().getSimpleName() + "{" + stateString() + "}"; } static boolean equal(@Nullable Object a, @Nullable Object b) { return a == null ? b == null : a.equals(b); // Java 6 can't use Objects.equals() } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy