com.swirlds.common.io.streams.DebuggableMerkleDataInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-common Show documentation
Show all versions of swirlds-common Show documentation
Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.
/*
* Copyright (C) 2016-2024 Hedera Hashgraph, LLC
*
* 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 com.swirlds.common.io.streams;
import com.swirlds.base.function.CheckedFunction;
import com.swirlds.common.io.SelfSerializable;
import com.swirlds.common.io.streams.internal.SerializationOperation;
import com.swirlds.common.io.streams.internal.SerializationStack;
import com.swirlds.common.merkle.MerkleNode;
import com.swirlds.common.utility.ValueReference;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.Supplier;
/**
* A stream that performs the same role as a {@link MerkleDataInputStream} but with extra debug functionality. This
* debuggability adds overhead, so use of this stream should be limited to test environments or production environments
* where there is a known serialization problem (heaven forbid).
*/
public class DebuggableMerkleDataInputStream extends MerkleDataInputStream {
/**
* The stack trace contains the following elements:
*
*
* -
* index 0: a frame from inside the java thread API
*
* -
* index 1: a frame inside {@link #startOperation(SerializationOperation)}
*
* -
* index 2: the frame where {@link #startOperation(SerializationOperation)} is called
*
* -
* index 3: the original caller (this is the one we are interested in)
*
*
*/
private static final int STACK_TRACE_OFFSET = 3;
private final SerializationStack stack;
/**
* Create a new {@link MerkleDataInputStream} that has extra debug capability.
*
* @param in the base stream
*/
public DebuggableMerkleDataInputStream(final InputStream in) {
super(in);
final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
final StackTraceElement callLocation = stackTrace[STACK_TRACE_OFFSET];
stack = new SerializationStack(callLocation);
}
/**
* Create a formatted serialization stack trace string.
*
* @return a formatted stack trace, or an empty string if debug is disabled
*/
public String getFormattedStackTrace() {
return stack.generateSerializationStackTrace();
}
/**
* Get the serialization stack trace.
*
* @return the stack
*/
public SerializationStack getStack() {
return stack;
}
/**
* Record the start of an operation.
*
* @param operation the operation that is starting
*/
private void startOperation(final SerializationOperation operation) {
final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
final StackTraceElement callLocation = stackTrace[STACK_TRACE_OFFSET];
stack.startOperation(operation, callLocation);
}
/**
* Record when an operation finishes.
*/
private void finishOperation() {
stack.finishOperation();
}
/**
* {@inheritDoc}
*/
@Override
protected void recordClassId(final long classId) {
stack.setClassId(classId);
}
/**
* {@inheritDoc}
*/
@Override
protected void recordClass(final Object o) {
if (o != null) {
stack.setClass(o.getClass());
}
}
/**
* Record a short string that represents the object.
*
* @param value an object to be converted into a string
* @return the input object
*/
private T recordStringRepresentation(final T value) {
stack.setStringRepresentation(Objects.toString(value));
return value;
}
/**
* {@inheritDoc}
*/
@Override
public int read() throws IOException {
startOperation(SerializationOperation.READ);
try {
return super.read();
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public long skip(final long n) throws IOException {
startOperation(SerializationOperation.SKIP);
recordStringRepresentation(n);
try {
return super.skip(n);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public byte[] readAllBytes() throws IOException {
startOperation(SerializationOperation.READ_ALL_BYTES);
try {
return super.readAllBytes();
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public byte[] readNBytes(final int len) throws IOException {
startOperation(SerializationOperation.READ_N_BYTES);
try {
return super.readNBytes(len);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public int readNBytes(final byte[] b, final int off, final int len) throws IOException {
startOperation(SerializationOperation.READ_N_BYTES_ARRAY);
try {
return super.readNBytes(b, off, len);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public int skipBytes(final int n) throws IOException {
startOperation(SerializationOperation.SKIP_BYTES);
try {
return super.skipBytes(n);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public void skipNBytes(final long n) throws IOException {
startOperation(SerializationOperation.SKIP_N_BYTES);
try {
super.skipNBytes(n);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public void readFully(final byte[] b) throws IOException {
startOperation(SerializationOperation.READ_FULLY);
try {
super.readFully(b);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public void readFully(final byte[] b, final int off, final int len) throws IOException {
startOperation(SerializationOperation.READ_FULLY_OFFSET);
try {
super.readFully(b, off, len);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean readBoolean() throws IOException {
startOperation(SerializationOperation.READ_BOOLEAN);
try {
return recordStringRepresentation(super.readBoolean());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public byte readByte() throws IOException {
startOperation(SerializationOperation.READ_BYTE);
try {
return recordStringRepresentation(super.readByte());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public int readUnsignedByte() throws IOException {
startOperation(SerializationOperation.READ_UNSIGNED_BYTE);
try {
return recordStringRepresentation(super.readUnsignedByte());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public short readShort() throws IOException {
startOperation(SerializationOperation.READ_SHORT);
try {
return recordStringRepresentation(super.readShort());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public int readUnsignedShort() throws IOException {
startOperation(SerializationOperation.READ_UNSIGNED_SHORT);
try {
return recordStringRepresentation(super.readUnsignedShort());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public char readChar() throws IOException {
startOperation(SerializationOperation.READ_CHAR);
try {
return recordStringRepresentation(super.readChar());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public int readInt() throws IOException {
startOperation(SerializationOperation.READ_INT);
try {
return recordStringRepresentation(super.readInt());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public long readLong() throws IOException {
startOperation(SerializationOperation.READ_LONG);
try {
return recordStringRepresentation(super.readLong());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public float readFloat() throws IOException {
startOperation(SerializationOperation.READ_FLOAT);
try {
return recordStringRepresentation(super.readFloat());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public double readDouble() throws IOException {
startOperation(SerializationOperation.READ_DOUBLE);
try {
return recordStringRepresentation(super.readDouble());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public String readUTF() throws IOException {
startOperation(SerializationOperation.READ_UTF);
try {
return recordStringRepresentation(super.readUTF());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public byte[] readByteArray(final int maxLength, final boolean readChecksum) throws IOException {
startOperation(SerializationOperation.READ_BYTE_ARRAY);
try {
return super.readByteArray(maxLength, readChecksum);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public byte[] readByteArray(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_BYTE_ARRAY);
try {
return super.readByteArray(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public int[] readIntArray(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_INT_LIST);
try {
return super.readIntArray(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readIntList(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_INT_LIST);
try {
return super.readIntList(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public long[] readLongArray(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_LONG_LIST);
try {
return super.readLongArray(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readLongList(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_LONG_LIST);
try {
return super.readLongList(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readBooleanList(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_BOOLEAN_LIST);
try {
return super.readBooleanList(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public float[] readFloatArray(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_FLOAT_LIST);
try {
return super.readFloatArray(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readFloatList(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_FLOAT_LIST);
try {
return super.readFloatList(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public double[] readDoubleArray(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_DOUBLE_LIST);
try {
return super.readDoubleArray(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readDoubleList(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_DOUBLE_LIST);
try {
return super.readDoubleList(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public String[] readStringArray(final int maxLength, final int maxStringLength) throws IOException {
startOperation(SerializationOperation.READ_STRING_LIST);
try {
return super.readStringArray(maxLength, maxStringLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readStringList(final int maxLength, final int maxStringLength) throws IOException {
startOperation(SerializationOperation.READ_STRING_LIST);
try {
return super.readStringList(maxLength, maxStringLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public Instant readInstant() throws IOException {
startOperation(SerializationOperation.READ_INSTANT);
try {
return recordStringRepresentation(super.readInstant());
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public String readNormalisedString(final int maxLength) throws IOException {
startOperation(SerializationOperation.READ_NORMALISED_STRING);
try {
return super.readNormalisedString(maxLength);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public T readMerkleTree(final Path directory, final int maxNumberOfNodes)
throws IOException {
startOperation(SerializationOperation.READ_MERKLE_TREE);
try {
return super.readMerkleTree(directory, maxNumberOfNodes);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
protected void readNextNode(
final Path directory, final Map deserializedVersions)
throws IOException {
startOperation(SerializationOperation.READ_MERKLE_NODE);
try {
super.readNextNode(directory, deserializedVersions);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public T readSerializable() throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE);
try {
return super.readSerializable();
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public T readSerializable(
final boolean readClassId, @NonNull final Supplier serializableConstructor) throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE);
try {
return super.readSerializable(readClassId, serializableConstructor);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public void readSerializableIterableWithSize(
final int maxSize, @NonNull final Consumer callback, @Nullable final Set permissibleClassIds)
throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE_LIST);
try {
super.readSerializableIterableWithSize(maxSize, callback, permissibleClassIds);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public void readSerializableIterableWithSize(
final int size,
final boolean readClassId,
@NonNull final Supplier serializableConstructor,
@NonNull final Consumer callback,
@Nullable final Set permissibleClassIds)
throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE_LIST);
try {
super.readSerializableIterableWithSize(
size, readClassId, serializableConstructor, callback, permissibleClassIds);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
protected T readNextSerializableIteration(
final boolean allSameClass,
final boolean readClassId,
@NonNull final ValueReference classId,
@NonNull final ValueReference version,
@NonNull final CheckedFunction serializableConstructor,
@Nullable final Set permissibleClassIds)
throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE);
try {
return super.readNextSerializableIteration(
allSameClass, readClassId, classId, version, serializableConstructor, permissibleClassIds);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readSerializableList(
final int maxListSize, @Nullable final Set permissibleClassIds) throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE_LIST);
try {
return super.readSerializableList(maxListSize, permissibleClassIds);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public List readSerializableList(
final int maxListSize,
final boolean readClassId,
@NonNull final Supplier serializableConstructor,
@Nullable final Set permissibleClassIds)
throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE_LIST);
try {
return super.readSerializableList(maxListSize, readClassId, serializableConstructor, permissibleClassIds);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public T[] readSerializableArray(
@NonNull final IntFunction arrayConstructor,
final int maxListSize,
final boolean readClassId,
@Nullable final Set permissibleClassIds)
throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE_LIST);
try {
return super.readSerializableArray(arrayConstructor, maxListSize, readClassId, permissibleClassIds);
} finally {
finishOperation();
}
}
/**
* {@inheritDoc}
*/
@Override
public T[] readSerializableArray(
@NonNull final IntFunction arrayConstructor,
final int maxListSize,
final boolean readClassId,
@NonNull final Supplier serializableConstructor,
@Nullable final Set permissibleClassIds)
throws IOException {
startOperation(SerializationOperation.READ_SERIALIZABLE_LIST);
try {
return super.readSerializableArray(
arrayConstructor, maxListSize, readClassId, serializableConstructor, permissibleClassIds);
} finally {
finishOperation();
}
}
}