Commit ae56fce4 authored by Jonathan Mace's avatar Jonathan Mace

Remove old code

parent 74bf24bf
= Atom Layer =
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.brown.cs.systems.tracingplane</groupId>
<artifactId>atom-layer</artifactId>
<packaging>jar</packaging>
<name>Tracing Plane - Atom Layer</name>
<parent>
<groupId>edu.brown.cs.systems</groupId>
<artifactId>tracingplane-project</artifactId>
<version>0.1</version>
</parent>
<dependencies>
<dependency>
<groupId>edu.brown.cs.systems.tracingplane</groupId>
<artifactId>transit-layer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache.commons.version}</version>
</dependency>
</dependencies>
</project>
package edu.brown.cs.systems.tracingplane.atom_layer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.List;
import edu.brown.cs.systems.tracingplane.atom_layer.protocol.AtomLayerOverflow;
import edu.brown.cs.systems.tracingplane.atom_layer.protocol.AtomLayerSerialization;
import edu.brown.cs.systems.tracingplane.atom_layer.types.Lexicographic;
import edu.brown.cs.systems.tracingplane.transit_layer.Baggage;
import edu.brown.cs.systems.tracingplane.transit_layer.TransitLayer;
/**
* <p>
* The AtomLayer is an implementation of the {@link TransitLayer} that specifies some default behavior for how to
* branch, join, and serialize {@link Baggage}. The AtomLayer provides the minimal implementation necessary for an
* application to participate in the tracing plane. The AtomLayer enables an application to propagate {@link Baggage}
* without needing to know about what data it contains or the semantics of that data.
* </p>
*
* <p>
* The AtomLayer implementation of {@link Baggage} is {@link BaggageAtoms}, which is simply a list of <b>atoms</b>. At
* atom is an arbitrary-length array of bytes, and most of the APIs for dealing with atoms just use {@link ByteBuffer}
* objects for atoms. The AtomLayer is not responsible for understanding the contents of each individual atom. It simply
* sees baggage as a list of atoms. For example, it might receive baggage with the following atoms:
* </p>
*
* <pre>
* {@code
* [F8, 00]
* [00, 00, 00, 00, 00, 00, 00, 00, 07]
* [F8, 01]
* [00, 00, 00, 00, 00, 00, 00, 00, 0A]
* [00, 00, 00, 00, 00, 00, 00, 00, 14]}
* </pre>
*
* <p>
* The AtomLayer does not attempt to interpret the meaning of these bytes. However, it does specify logic for how to
* merge the atoms for multiple baggage instances, how to drop atoms if a baggage instance is too large, and how to
* serialize atoms, as follows:
* </p>
* <ul>
* <li>Atoms are serialized by prefixing the bytes of each atom with their length (encoded as a protobuf-style varint).
* For the example above, the serialized representation would be:
*
* <pre>
* {@code
* [ 02, F8, 00, // first atom length then payload
* 09, 00, 00, 00, 00, 00, 00, 00, 00, 07, // second atom length then payload
* 02, F8, 01, // third atom length then payload
* 09, 00, 00, 00, 00, 00, 00, 00, 00, 0A, // fourth atom length then payload
* 09, 00, 00, 00, 00, 00, 00, 00, 00, 14 ] // fifth atom length then payload
* }
* </pre>
*
* See the {@link AtomLayerSerialization} class for more information about serialization.</li>
* <li>If we have two baggage instances that are joining, we join the baggages by merging their atoms
* <b>lexicographically</b>. During the lexicographic merge, if we encounter duplicate atoms we only include the atom
* once. For example, suppose we have a second list of atoms:
*
* <pre>
* {@code
* [F8, 00]
* [00, 00, 00, 00, 00, 00, 00, 00, 07]
* [F8, 01]
* [00, 00, 00, 00, 00, 00, 00, 00, 0F]
* }
* </pre>
*
* The lexicographic merge of these second atoms with the first lot of atoms above would be:
*
* <pre>
* {@code
* [F8, 00]
* [00, 00, 00, 00, 00, 00, 00, 00, 07]
* [F8, 01]
* [00, 00, 00, 00, 00, 00, 00, 00, 0A]
* [00, 00, 00, 00, 00, 00, 00, 00, 0F]
* [00, 00, 00, 00, 00, 00, 00, 00, 14]
* }
* </pre>
*
* See the {@link Lexicographic} class for more information about lexicographic merging.</li>
* <li>If we need to reduce the size of baggage, we do so by dropping atoms from the end of the list of atoms. Some
* systems might have a hard upper limit on baggage size (e.g., no more than 100 bytes in size). Additionally, if atoms
* are dropped then an {@link BaggageAtoms#OVERFLOW_MARKER OVERFLOW_MARKER} should be appended to the end of the list of
* atoms. The overflow marker is the empty atom (e.g., zero-length atom) which is lexicographically smaller than all
* other atoms and therefore tracks the position in the baggage where data was dropped. For example, if our system was
* extremely capacity-conscious (say, 30 byte limit on baggage size), we would overflow the baggage as follows:
*
* <pre>
* {@code
* [F8, 00] // serialized size 3 (total 3)
* [00, 00, 00, 00, 00, 00, 00, 00, 07] // serialized size 10 (total 13)
* [F8, 01] // serialized size 3 (total 16)
* [00, 00, 00, 00, 00, 00, 00, 00, 0A] // serialized size 10 (total 26)
* [] // cannot include next atom, so put overflow marker (total 27)
* }
* </pre>
*
* See the {@link AtomLayerOverflow} class for more information about overflow.</li>
* </ul>
*
* <p>
* For a system to participate in the tracing plane, it must be capable of propagating at least two bytes of baggage.
* </p>
*
* <p>
* The methods in this class are similar to the methods defined by {@link TransitLayer}, with
* {@link #atoms(BaggageAtoms)} and {@link #wrap(List)} replacing {@link TransitLayer#serialize(Baggage)} and
* {@link TransitLayer#deserialize(byte[], int, int)}.
* </p>
*
* @param <B> Some implementation of {@link Baggage} used by this transit layer.
*/
public interface AtomLayer<B extends BaggageAtoms> extends TransitLayer<B> {
/**
* <p>
* Turn a list of atoms into a {@link BaggageAtoms} instance.
* </p>
*
* @param atoms The atom representation of a BaggageAtoms instance
* @return a parsed BaggageAtoms instance
*/
public B wrap(List<ByteBuffer> atoms);
/**
* <p>
* Get the atoms that comprise the provided baggage instance.
* </p>
*
* @param baggage a {@link BaggageAtoms} instance
* @return the atoms of this {@link BaggageAtoms} instance
*/
public List<ByteBuffer> atoms(B baggage);
@Override
public default B deserialize(byte[] serialized, int offset, int length) {
return wrap(AtomLayerSerialization.deserialize(serialized, offset, length));
}
@Override
public default B readFrom(InputStream in) throws IOException {
return wrap(AtomLayerSerialization.readFrom(in));
}
@Override
public default byte[] serialize(B baggage) {
return AtomLayerSerialization.serialize(atoms(baggage));
}
@Override
public default void writeTo(OutputStream out, B baggage) throws IOException {
AtomLayerSerialization.write(out, atoms(baggage));
}
@Override
public default byte[] serialize(B baggage, int maximumSerializedSize) {
return AtomLayerSerialization.serialize(atoms(baggage), maximumSerializedSize);
}
@Override
public default void writeTo(OutputStream out, B baggage, int maximumSerializedSize) throws IOException {
AtomLayerSerialization.write(out, atoms(baggage), maximumSerializedSize);
}
}
\ No newline at end of file
package edu.brown.cs.systems.tracingplane.atom_layer;
import java.nio.ByteBuffer;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.brown.cs.systems.tracingplane.transit_layer.Baggage;
/**
* This class just does type checking on {@link BaggageAtoms} instances to ensure they are compatible with the
* {@link AtomLayer} installed in the current process. In general, BaggageAtoms instances should never be created by any
* atom layer other than the one installed in the current process.
*/
public class AtomLayerCompatibility {
static final Logger log = LoggerFactory.getLogger(AtomLayerCompatibility.class);
public static <B extends BaggageAtoms> B wrap(AtomLayer<B> contextLayer, List<ByteBuffer> atoms) {
return contextLayer.wrap(atoms);
}
public static <B extends BaggageAtoms> List<ByteBuffer> atoms(AtomLayer<B> contextLayer, Baggage maybeAtoms) {
if (maybeAtoms instanceof BaggageAtoms) {
return atoms(contextLayer, (BaggageAtoms) maybeAtoms);
} else {
log.warn("incompatible Baggage to {}.atoms; {} is not instance of BaggageAtoms",
contextLayer.getClass().getName(), maybeAtoms.getClass().getName());
}
return null;
}
@SuppressWarnings("unchecked")
public static <B extends BaggageAtoms> List<ByteBuffer> atoms(AtomLayer<B> contextLayer, BaggageAtoms atoms) {
if (contextLayer.isInstance(atoms)) {
return contextLayer.atoms((B) atoms);
} else {
log.warn("incompatible BaggageAtoms to {}.atoms; BaggageAtoms class is {}",
contextLayer.getClass().getName(), atoms.getClass().getName());
}
return null;
}
}
package edu.brown.cs.systems.tracingplane.atom_layer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import edu.brown.cs.systems.tracingplane.atom_layer.impl.RawAtomLayerFactory;
/**
* Provides configuration of the {@link AtomLayer} using the TypeSafe Config. Configuration values can be overridden by
* placing an {@code application.conf} on the classpath or by specifying java flags, e.g.
* {@code -Dtracingplane.atom-layer.factory="factoryclass"}
*/
public class AtomLayerConfig {
private static final Logger log = LoggerFactory.getLogger(AtomLayerConfig.class);
private static final String ATOM_LAYER_IMPLEMENTATION_KEY = "tracingplane.atom-layer.factory";
public String atomLayerFactory;
public AtomLayerConfig() {
Config conf = ConfigFactory.load();
atomLayerFactory = conf.getString(ATOM_LAYER_IMPLEMENTATION_KEY);
try {
Class.forName(atomLayerFactory);
} catch (ClassNotFoundException e) {
log.error("The configured atom layer class {}=\"{}\" was not found; defaulting to raw atom layer",
ATOM_LAYER_IMPLEMENTATION_KEY, atomLayerFactory);
}
}
public AtomLayer<?> createAtomLayer() throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return ((AtomLayerFactory) Class.forName(atomLayerFactory).newInstance()).newAtomLayer();
}
private static AtomLayer<?> defaultAtomLayer = null;
public static synchronized AtomLayer<?> defaultAtomLayer() {
if (defaultAtomLayer == null) {
AtomLayerConfig config = new AtomLayerConfig();
try {
defaultAtomLayer = config.createAtomLayer();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
log.error(String.format("Unable to instantiate default atom layer factory %s, defaulting to %s",
config.atomLayerFactory, RawAtomLayerFactory.class.getName()));
defaultAtomLayer = new RawAtomLayerFactory().newAtomLayer();
}
}
return defaultAtomLayer;
}
}
package edu.brown.cs.systems.tracingplane.atom_layer;
import edu.brown.cs.systems.tracingplane.transit_layer.TransitLayer;
import edu.brown.cs.systems.tracingplane.transit_layer.TransitLayerFactory;
/**
* <p>
* All {@link AtomLayer} implementations should provide an {@link AtomLayerFactory} class for creating a default
* instance.
* </p>
*/
public interface AtomLayerFactory {
AtomLayer<?> newAtomLayer();
/**
* An implementation of {@link TransitLayerFactory} that returns the default configured {@link AtomLayer}
*/
public static class TransitLayerFactoryImpl implements TransitLayerFactory {
@Override
public TransitLayer<?> newTransitLayer() {
return AtomLayerConfig.defaultAtomLayer();
}
}
}
package edu.brown.cs.systems.tracingplane.atom_layer;
import java.nio.ByteBuffer;
import java.util.List;
import edu.brown.cs.systems.tracingplane.atom_layer.protocol.AtomLayerOverflow;
import edu.brown.cs.systems.tracingplane.atom_layer.protocol.AtomLayerSerialization;
import edu.brown.cs.systems.tracingplane.atom_layer.types.Lexicographic;
import edu.brown.cs.systems.tracingplane.transit_layer.Baggage;
/**
* <p>
* BaggageAtoms is an extension of {@link Baggage} for use by the {@link AtomLayer}. A BaggageAtoms instance is a list
* of <i>atoms</i>. At atom is an arbitrary-length array of bytes. The AtomLayer makes no attempt to interpret the
* meaning of each atom -- this is the job of higher layers such as the BaggageLayer. Atoms are the unit of granularity
* at the AtomLayer (e.g., an atom is indivisible).
* </p>
*
* <p>
* BaggageAtoms are a simple default representation of data that enables consistent propagation of data while traversing
* different thread, process, machine, and application boundaries. The AtomLayer specifies the following:</p>
* <ul>
* <li>The underlying serialization format of atoms, which is to prefix the bytes of each atom with their length
* (encoded as a protobuf-style varint). For example, with {@code byte[] a = new byte[10];} and
* {@code byte[] b = new byte[20];}, the serialized representation would be
* {@code [length=32][a.length=10][ a ][b.length=20][ b ]}. See {@link AtomLayerSerialization} for more information.
* </li>
* <li>The default merge behavior when two branches of an execution join. Two Baggage instances {@code a} and {@code b}
* are merged by <i>lexicographically</i> merging their respective atoms and dropping duplicates that are encountered.
* respective lists of atoms while dropping duplicates <i>as they are encountered</i>. See {@link Lexicographic} for
* more information.</li>
* <li>The default behavior for dropping atoms if a baggage instance is larger than permitted by a system. For example,
* if a system wants to keep headers less than a certain size, it might mean baggage must be less than 100 bytes in
* size. To trim baggage, atoms are dropped from the <b>end</b> of the list of atoms. If atoms are dropped, then an
* {@link BaggageAtoms#OVERFLOW_MARKER OVERFLOW_MARKER} should be appended to the end of the list of atoms. The overflow
* marker is the empty atom (e.g., zero-length atom) which is lexicographically smaller than all other atoms and
* therefore tracks the position in the baggage where data was dropped.</li>
* </ul>
*
* <p>
* Propagation of BaggageAtoms should still be done via the static methods in {@link Baggage}. However, there are
* several additional static methods available in this class.
* </p>
*
*/
public interface BaggageAtoms extends Baggage {
/**
* The overflow marker is a zero-length atom, used to indicate that an application had to drop some of the atoms in
* this baggage. The overflow marker is lexicographically smaller than all other atoms, so it 'holds' its position
* when merging with other atoms. This enables end-users to determine where in their atoms data might have been
* dropped.
*/
public static final ByteBuffer OVERFLOW_MARKER = AtomLayerOverflow.OVERFLOW_MARKER;
/**
* The {@link AtomLayer} implementation installed in the process.
*/
public static final AtomLayer<?> atomLayer = AtomLayerConfig.defaultAtomLayer();
/**
* <p>
* Turn a list of atoms into a {@link BaggageAtoms} instance.
* </p>
*
* <p>
* This method does <b>not</b> affect the current thread's baggage. To set the current thread's baggage, call
* {@link Baggage#set(Baggage)}, passing the wrapped {@link BaggageAtoms}, e.g.
* {@code Baggage.set(BaggageAtoms.wrap(atoms));}
* </p>
*
* @param atoms The atom representation of a BaggageAtoms instance, possibly null
* @return a parsed BaggageAtoms instance, possibly null
*/
public static BaggageAtoms wrap(List<ByteBuffer> atoms) {
return AtomLayerCompatibility.wrap(atomLayer, atoms);
}
/**
* <p>
* Get the atoms that comprise the provided baggage instance.
* </p>
*
* <p>
* To get the atoms of the current thread's baggage, use {@link #atoms()}.
* </p>
*
* @param baggage a BaggageAtoms instance, possibly null
* @return The atom representation of the BaggageAtoms instance, possibly null
*/
public static List<ByteBuffer> atoms(BaggageAtoms baggage) {
return AtomLayerCompatibility.atoms(atomLayer, baggage);
}
/**
* <p>
* Get the atoms that comprise the current thread's baggage.
* </p>
*
* @return The atom representation of the BaggageAtoms instance, possibly null
*/
public static List<ByteBuffer> atoms() {
return AtomLayerCompatibility.atoms(atomLayer, Baggage.get());
}
}
package edu.brown.cs.systems.tracingplane.atom_layer.impl;
import java.nio.ByteBuffer;
import java.util.List;
import edu.brown.cs.systems.tracingplane.atom_layer.AtomLayer;
import edu.brown.cs.systems.tracingplane.transit_layer.Baggage;
/**
* The simple implementation of the context layer that can be used in lieu of a full baggage layer. Simply merges bags
* lexicographically, removes duplicates, and supports overflow.
*/
public class RawAtomLayer implements AtomLayer<RawBaggageAtoms> {
@Override
public boolean isInstance(Baggage baggage) {
return baggage == null || baggage instanceof RawBaggageAtoms;
}
@Override
public RawBaggageAtoms newInstance() {
return null;
}
@Override
public void discard(RawBaggageAtoms baggage) {
if (baggage != null) {
baggage.discard();
}
}
@Override
public RawBaggageAtoms branch(RawBaggageAtoms from) {
if (from != null) {
return from.branch();
} else {
return null;
}
}
@Override
public RawBaggageAtoms join(RawBaggageAtoms left, RawBaggageAtoms right) {
if (left == null) {
return right;
} else if (right == null) {
return left;
} else {
return left.mergeWith(right);
}
}
@Override
public RawBaggageAtoms wrap(List<ByteBuffer> atoms) {
if (atoms == null || atoms.size() == 0) {
return null;
} else {
return new RawBaggageAtoms(atoms);
}
}
@Override
public List<ByteBuffer> atoms(RawBaggageAtoms baggage) {
if (baggage != null && baggage.contents.atoms != null && baggage.contents.atoms.size() > 0) {
return baggage.contents.atoms;
} else {
return null;
}
}