io.opentelemetry.exporter.internal.marshal.MarshalerContext Maven / Gradle / Ivy
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.internal.marshal;
import io.opentelemetry.api.trace.SpanId;
import io.opentelemetry.api.trace.TraceId;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.annotation.Nullable;
/**
* Class for keeping marshaling state. The state consists of integers, that we call sizes, and
* objects, that we call data. Both integers and objects can be read from the state in the order
* they were added (first in, first out). Additionally, this class provides various pools and caches
* for objects that can be reused between marshalling attempts.
*
* This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public final class MarshalerContext {
private final boolean marshalStringNoAllocation;
private final boolean marshalStringUnsafe;
private int[] sizes = new int[16];
private int sizeReadIndex;
private int sizeWriteIndex;
private Object[] data = new Object[16];
private int dataReadIndex;
private int dataWriteIndex;
public MarshalerContext() {
this(/* marshalStringNoAllocation= */ true, /* marshalStringUnsafe= */ true);
}
public MarshalerContext(boolean marshalStringNoAllocation, boolean marshalStringUnsafe) {
this.marshalStringNoAllocation = marshalStringNoAllocation;
this.marshalStringUnsafe = marshalStringUnsafe;
}
public boolean marshalStringNoAllocation() {
return marshalStringNoAllocation;
}
public boolean marshalStringUnsafe() {
return marshalStringUnsafe;
}
public void addSize(int size) {
growSizeIfNeeded();
sizes[sizeWriteIndex++] = size;
}
public int addSize() {
growSizeIfNeeded();
return sizeWriteIndex++;
}
private void growSizeIfNeeded() {
if (sizeWriteIndex == sizes.length) {
int[] newSizes = new int[sizes.length * 2];
System.arraycopy(sizes, 0, newSizes, 0, sizes.length);
sizes = newSizes;
}
}
public void setSize(int index, int size) {
sizes[index] = size;
}
public int getSize() {
return sizes[sizeReadIndex++];
}
public void addData(@Nullable Object o) {
growDataIfNeeded();
data[dataWriteIndex++] = o;
}
private void growDataIfNeeded() {
if (dataWriteIndex == data.length) {
Object[] newData = new Object[data.length * 2];
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
}
}
public T getData(Class type) {
return type.cast(data[dataReadIndex++]);
}
private final IdPool traceIdPool = new IdPool(TraceId.getLength() / 2);
/** Returns a buffer that can be used to hold a trace id. */
public byte[] getTraceIdBuffer() {
return traceIdPool.get();
}
private final IdPool spanIdPool = new IdPool(SpanId.getLength() / 2);
/** Returns a buffer that can be used to hold a span id. */
public byte[] getSpanIdBuffer() {
return spanIdPool.get();
}
private static class IdPool {
private final List pool = new ArrayList<>();
int index;
final int idSize;
IdPool(int idSize) {
this.idSize = idSize;
}
byte[] get() {
if (index < pool.size()) {
return pool.get(index++);
}
byte[] result = new byte[idSize];
pool.add(result);
index++;
return result;
}
void reset() {
index = 0;
}
}
private final Pool