Copies all remaining bytes from src to dest. This is done without modifying the src's position. However, the
16 | * dest's position is updated.
17 | *
18 | * @param src the buffer to copy from. its position will not be updated.
19 | * @param dest the buffer to copy to. its position will be updated.
20 | */
21 | public static void copyTo(ByteBuffer src, ByteBuffer dest) {
22 | if (src == null || dest == null) {
23 | return;
24 | }
25 | if (src.hasArray()) {
26 | byte[] array = src.array();
27 | int offset = src.arrayOffset() + src.position();
28 | int length = src.remaining();
29 | dest.put(array, offset, length);
30 | } else {
31 | for (int i = src.position(); i < src.limit(); i++) {
32 | dest.put(src.get(i));
33 | }
34 | }
35 | }
36 |
37 | public static ByteBuffer copyWithPrefix(byte prefix, ByteBuffer src) {
38 | ByteBuffer buf = ByteBuffer.allocate(src.remaining() + 1);
39 | buf.put(prefix);
40 | copyTo(src, buf);
41 | buf.position(0);
42 | return buf;
43 | }
44 |
45 | /**
46 | * Copies the remaining bytes form src to a new byte buffer. This is done without modifying the src position. The
47 | * dest position will be 0.
48 | */
49 | public static ByteBuffer copyRemaining(ByteBuffer src) {
50 | ByteBuffer buf = ByteBuffer.allocate(src.remaining());
51 | copyTo(src, buf);
52 | buf.position(0);
53 | return buf;
54 | }
55 |
56 | /** Copies the remaining bytes form src to a byte array. This is done without modifying the src position. */
57 | public static byte[] copyRemainingBytes(ByteBuffer src) {
58 | return copyRemaining(src).array();
59 | }
60 |
61 | /** Read the remaining bytes from a bytebuffer as a string */
62 | public static String getString(ByteBuffer buf) {
63 | if (buf == null) {
64 | return null;
65 | }
66 |
67 | final byte[] array;
68 | final int offset;
69 | final int length = buf.remaining();
70 | if (buf.hasArray()) {
71 | array = buf.array();
72 | offset = buf.arrayOffset() + buf.position();
73 | } else {
74 | array = new byte[length];
75 | offset = 0;
76 | buf.get(array);
77 | }
78 | return new String(array, offset, length);
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/atomlayer/core/src/main/java/brown/tracingplane/atomlayer/MergeIterator.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Comparator;
5 | import java.util.Iterator;
6 | import java.util.List;
7 |
8 | /**
9 | *
10 | * Merges multiple iterators and produces elements according to the provided comparator.
11 | *
12 | *
13 | * The input iterators do not need to be sorted. However, if two iterators produce the same element at the same time,
14 | * the element will only be output once.
15 | *
16 | *
17 | *
18 | * eg, for inputs [1, 2, 3] and [0, 1, 2], the output will be [0, 1, 2, 3]
19 | * however, for inputs [1, 2, 1] and [1, 3, 2], the output will be [1, 2, 1, 3, 2]
20 | *
21 | *
22 | *
23 | * @param
24 | */
25 | public class MergeIterator implements Iterator {
26 |
27 | private class IteratorContainer {
28 |
29 | final Iterator extends T> it;
30 | T next;
31 |
32 | public IteratorContainer(Iterator extends T> it) {
33 | this.it = it;
34 | this.next = it.next();
35 | }
36 |
37 | void advance() {
38 | next = it.hasNext() ? it.next() : null;
39 | }
40 |
41 | }
42 |
43 | private final Comparator super T> comparator;
44 | private final List iterators;
45 | private final List iteratorsWithNextValue;
46 | private T nextValue = null;
47 |
48 | private MergeIterator(Comparator super T> comparator, int size) {
49 | this.comparator = comparator;
50 | this.iterators = new ArrayList<>(size);
51 | this.iteratorsWithNextValue = new ArrayList<>(size);
52 | this.nextValue = null;
53 | }
54 |
55 | public MergeIterator(Comparator super T> comparator, @SuppressWarnings("unchecked") Iterator... iterators) {
56 | this(comparator, iterators.length);
57 |
58 | for (Iterator it : iterators) {
59 | if (it != null && it.hasNext()) {
60 | this.iterators.add(new IteratorContainer(it));
61 | }
62 | }
63 |
64 | advance();
65 | }
66 |
67 | public MergeIterator(List> iterators, Comparator super T> comparator) {
68 | this(comparator, iterators.size());
69 |
70 | for (Iterator it : iterators) {
71 | if (it != null && it.hasNext()) {
72 | this.iterators.add(new IteratorContainer(it));
73 | }
74 | }
75 |
76 | advance();
77 | }
78 |
79 | private void advance() {
80 | // Advance all of the iterators that produced the previous value
81 | for (IteratorContainer it : iteratorsWithNextValue) {
82 | it.advance();
83 | if (it.next == null) {
84 | iterators.remove(it);
85 | }
86 | }
87 |
88 | // Get the next min value
89 | T next = null;
90 | for (IteratorContainer it : iterators) {
91 | int comparison = next == null ? -1 : comparator.compare(it.next, next);
92 | if (comparison < 0) {
93 | next = it.next;
94 | iteratorsWithNextValue.clear();
95 | iteratorsWithNextValue.add(it);
96 | } else if (comparison == 0) {
97 | iteratorsWithNextValue.add(it);
98 | }
99 | }
100 | nextValue = next;
101 | }
102 |
103 | @Override
104 | public boolean hasNext() {
105 | return nextValue != null;
106 | }
107 |
108 | @Override
109 | public T next() {
110 | T ret = nextValue;
111 | advance();
112 | return ret;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/atomlayer/core/src/main/java/brown/tracingplane/atomlayer/MergeTwoIterator.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import java.util.Comparator;
4 | import java.util.Iterator;
5 |
6 | /** Like {@link MergeIterator} but for two iterators only */
7 | public class MergeTwoIterator implements Iterator {
8 |
9 | private final Iterator a;
10 | private final Iterator b;
11 |
12 | private T nexta = null;
13 | private T nextb = null;
14 | private Comparator super T> comparator;
15 |
16 | public MergeTwoIterator(Iterator a, Iterator b, Comparator super T> comparator) {
17 | this.a = a;
18 | this.b = b;
19 | this.comparator = comparator;
20 | advanceA();
21 | advanceB();
22 | }
23 |
24 | private void advanceA() {
25 | if (a.hasNext()) {
26 | nexta = a.next();
27 | } else {
28 | nexta = null;
29 | }
30 | }
31 |
32 | private void advanceB() {
33 | if (b.hasNext()) {
34 | nextb = b.next();
35 | } else {
36 | nextb = null;
37 | }
38 | }
39 |
40 | @Override
41 | public boolean hasNext() {
42 | return nexta != null || nextb != null;
43 | }
44 |
45 | @Override
46 | public T next() {
47 | T result = null;
48 | if (nexta == null) {
49 | result = nextb;
50 | advanceB();
51 | } else if (nextb == null) {
52 | result = nexta;
53 | advanceA();
54 | } else {
55 | int comparison = comparator.compare(nexta, nextb);
56 | if (comparison < 0) {
57 | result = nexta;
58 | advanceA();
59 | } else if (comparison == 0) {
60 | result = nexta;
61 | advanceA();
62 | advanceB();
63 | } else {
64 | result = nextb;
65 | advanceB();
66 | }
67 | }
68 | return result;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/atomlayer/core/src/main/java/brown/tracingplane/atomlayer/StringUtils.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | /**
4 | * Want to avoid having apache commons as a dependency, so implement any functions used here
5 | */
6 | public class StringUtils {
7 |
8 | public static String join(Iterable> objects, String separator) {
9 | if (objects == null) return "";
10 | StringBuilder b = new StringBuilder();
11 | boolean first = true;
12 | for (Object s : objects) {
13 | if (!first) {
14 | b.append(separator);
15 | } else {
16 | first = false;
17 | }
18 | b.append(String.valueOf(s));
19 | }
20 | return b.toString();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/atomlayer/core/src/main/java/brown/tracingplane/atomlayer/TypeUtils.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | /**
8 | * Some useful utility methods related to bits and bytes
9 | */
10 | public class TypeUtils {
11 |
12 | private TypeUtils() {}
13 |
14 | public static String toBinaryString(byte b) {
15 | return String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
16 | }
17 |
18 | public static String toHexString(byte b) {
19 | return String.format("%2s", Integer.toHexString(b & 0xFF)).replace(' ', '0').toUpperCase();
20 | }
21 |
22 | public static byte makeByte(String bitPattern) {
23 | bitPattern = bitPattern.replaceAll(" ", "");
24 | int[] ints = new int[bitPattern.length()];
25 | for (int i = 0; i < bitPattern.length(); i++) {
26 | ints[i] = Integer.valueOf(bitPattern.substring(i, i + 1));
27 | }
28 | return makeByte(ints);
29 | }
30 |
31 | public static byte makeByte(int... bitPattern) {
32 | byte result = 0;
33 | for (int bit : bitPattern) {
34 | result = (byte) ((result << 1) ^ (bit == 0 ? 0 : 1));
35 | }
36 | return result;
37 | }
38 |
39 | public static int offset(byte mask) {
40 | for (int i = 1; i <= 8; i++) {
41 | if (((mask >> i) << i) != mask) {
42 | return i - 1;
43 | }
44 | }
45 | return 8;
46 | }
47 |
48 | public static String toBinaryString(ByteBuffer atom) {
49 | List binaryStrings = new ArrayList<>();
50 | for (int i = atom.position(); i < atom.limit(); i++) {
51 | binaryStrings.add(toBinaryString(atom.get(i)));
52 | }
53 | return String.format("[%s]", StringUtils.join(binaryStrings, ", "));
54 | }
55 |
56 | public static String toHexString(ByteBuffer atom) {
57 | List hexStrings = new ArrayList<>();
58 | for (int i = atom.position(); i < atom.limit(); i++) {
59 | hexStrings.add(toHexString(atom.get(i)));
60 | }
61 | return String.format("%s", StringUtils.join(hexStrings, ""));
62 | }
63 |
64 | public static String toBinaryString(Iterable atoms) {
65 | List binaryStrings = new ArrayList<>();
66 | for (ByteBuffer atom : atoms) {
67 | binaryStrings.add(toBinaryString(atom));
68 | }
69 | return String.format("[%s]", StringUtils.join(binaryStrings, ", "));
70 | }
71 |
72 | public static String toHexString(Iterable atoms) {
73 | return toHexString(atoms, ", ");
74 | }
75 |
76 | public static String toHexString(Iterable atoms, String atomSeparator) {
77 | List hexStrings = new ArrayList<>();
78 | for (ByteBuffer atom : atoms) {
79 | hexStrings.add(toHexString(atom));
80 | }
81 | return String.format("%s", StringUtils.join(hexStrings, atomSeparator));
82 | }
83 |
84 | public static String toHexString(byte[] serialize) {
85 | return toHexString(ByteBuffer.wrap(serialize));
86 | }
87 |
88 | public static String toHexString(String s) {
89 | List hexStrings = new ArrayList<>();
90 | for (byte b : s.getBytes()) {
91 | hexStrings.add("`" + toHexString(b) + "`");
92 | }
93 | return StringUtils.join(hexStrings, ",");
94 | }
95 |
96 | public static void main(String[] args) {
97 | int[] xs = { 12, 22, 30, 50, 80 };
98 | for (int x : xs) {
99 | System.out.println(toHexString((byte) x));
100 | }
101 | // System.out.println(toHexString("a"));
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/atomlayer/core/src/main/java/brown/tracingplane/atomlayer/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * Provides the Tracing Plane's core underlying data representation for {@link BaggageContext} based on atoms and
5 | * lexicographic merge.
6 | *
7 | *
8 | *
9 | * The key primitives provided by the Atom Layer are an intermediary data format for {@link BaggageContext}s based on
10 | * atoms, along with the default atom-based comparison and merge functions based on the lexicographic ordering of
11 | * atoms.
12 | *
13 | *
14 | *
15 | * The Atom Layer represents atoms using {@link ByteBuffer}s.
16 | *
17 | *
18 | *
19 | * This package also contains functions for encoding lexicographically consistent variable length integers.
20 | *
21 | *
22 | *
23 | * The Atom Layer provides an underlying representation for {@link BaggageContext} based on atoms. Other layers
24 | * of the tracing plane use atoms to construct data structures like sets and maps. Since the Atom Layer is an inner
25 | * layer of the Tracing Plane, it is not expected for users to have to deal with this layer directly.
26 | *
27 | *
28 | *
29 | * However, the Atom Layer does provide a minimal {@link BaggageContext} implementation that you can use to
30 | * propagate contexts. This implementation lets you propagate contexts, but you cannot update them or access their
31 | * content.
32 | *
33 | *
34 | *
35 | * The atom layer is based on the notion of atoms: an atom is an arbitrary array of zero or more bytes; and a
36 | * {@link BaggageContext} is an arbitrary array of atoms, by default empty. The interpretation of atoms is up to the
37 | * clients calling down to the atom layer, and an atom is indivisible by the atom layer. The ordering of atoms is also
38 | * up to clients; however, the atom layer's {@link BaggageProvider#join(BaggageContext, BaggageContext)} implementation
39 | * can affect the position of atoms.
40 | *
41 | */
42 | package brown.tracingplane.atomlayer;
43 |
--------------------------------------------------------------------------------
/atomlayer/core/src/test/java/brown/tracingplane/atomlayer/TestByteBuffers.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import java.nio.BufferOverflowException;
5 | import java.nio.ByteBuffer;
6 | import java.util.Random;
7 | import org.junit.Rule;
8 | import org.junit.Test;
9 | import org.junit.rules.ExpectedException;
10 | import brown.tracingplane.atomlayer.ByteBuffers;
11 |
12 | public class TestByteBuffers {
13 |
14 | @Rule
15 | public final ExpectedException exception = ExpectedException.none();
16 |
17 | @Test
18 | public void testCopyToAdvancesPositionOnlyInDest() {
19 | ByteBuffer src = ByteBuffer.allocate(10);
20 | ByteBuffer dest = ByteBuffer.allocate(10);
21 |
22 | ByteBuffers.copyTo(src, dest);
23 | assertEquals(0, src.position());
24 | assertEquals(10, dest.position());
25 | }
26 |
27 | @Test
28 | public void testCopyNulls() {
29 | ByteBuffers.copyTo(null, ByteBuffer.allocate(0));
30 | ByteBuffers.copyTo(ByteBuffer.allocate(0), null);
31 | ByteBuffers.copyTo(null, null);
32 | }
33 |
34 | @Test
35 | public void testCopyInsufficientSpace() {
36 | ByteBuffer src = ByteBuffer.allocate(10);
37 | ByteBuffer dest = ByteBuffer.allocate(5);
38 |
39 | exception.expect(BufferOverflowException.class);
40 | ByteBuffers.copyTo(src, dest);
41 | }
42 |
43 | @Test
44 | public void testCopyCorrect() {
45 | Random r = new Random(0);
46 |
47 | ByteBuffer src = ByteBuffer.allocate(200);
48 | r.nextBytes(src.array());
49 | src.position(77);
50 | src.limit(127);
51 |
52 | ByteBuffer dest = ByteBuffer.allocate(500);
53 | r.nextBytes(dest.array());
54 | dest.position(133);
55 | dest.limit(450);
56 |
57 | ByteBuffers.copyTo(src, dest);
58 | assertEquals(77, src.position());
59 | assertEquals(127, src.limit());
60 | assertEquals(183, dest.position());
61 | assertEquals(450, dest.limit());
62 |
63 | dest.position(133);
64 | dest.limit(183);
65 | assertEquals(src, dest);
66 | }
67 |
68 | @Test
69 | public void testCopyWithPrefix() {
70 | ByteBuffer buf = ByteBuffer.allocate(4);
71 | buf.putInt(0, 55);
72 |
73 | byte prefix = 109;
74 |
75 | ByteBuffer copied = ByteBuffers.copyWithPrefix(prefix, buf);
76 |
77 | assertEquals(prefix, copied.get());
78 | assertEquals(55, copied.getInt());
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/atomlayer/core/src/test/java/brown/tracingplane/atomlayer/TestMerge.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import static org.junit.Assert.assertTrue;
4 | import java.nio.ByteBuffer;
5 | import java.util.List;
6 | import org.junit.Test;
7 | import com.google.common.collect.Lists;
8 | import brown.tracingplane.atomlayer.Lexicographic;
9 | import brown.tracingplane.atomlayer.TypeUtils;
10 |
11 | public class TestMerge {
12 |
13 | private static ByteBuffer make(String... ss) {
14 | ByteBuffer buf = ByteBuffer.allocate(ss.length);
15 | for (String s : ss) {
16 | buf.put(TypeUtils.makeByte(s));
17 | }
18 | buf.rewind();
19 | return buf;
20 | }
21 |
22 | private static boolean equals(List a, List b) {
23 | if (a.size() != b.size()) {
24 | return false;
25 | }
26 | for (int i = 0; i < a.size(); i++) {
27 | if (Lexicographic.compare(a.get(i), b.get(i)) != 0) {
28 | return false;
29 | }
30 | }
31 | return true;
32 | }
33 |
34 | @Test
35 | public void testByteBufferListMergeUnion() {
36 | List a = Lists.newArrayList(make("00000000"));
37 |
38 | List b = Lists.newArrayList(make("11111111"));
39 |
40 | List expect = Lists.newArrayList(make("00000000"), make("11111111"));
41 |
42 | assertTrue(equals(Lexicographic.merge(a, b), expect));
43 | }
44 |
45 | @Test
46 | public void testByteBufferListMergeDuplicates() {
47 | List a = Lists.newArrayList(make("00000000"), make("11111111"));
48 |
49 | List b = Lists.newArrayList(make("00000000"), make("11111111"));
50 |
51 | List expect = Lists.newArrayList(make("00000000"), make("11111111"));
52 |
53 | assertTrue(equals(Lexicographic.merge(a, b), expect));
54 | }
55 |
56 | @Test
57 | public void testByteBufferListMergeDuplicatesTricky() {
58 | List a = Lists.newArrayList(make("00000000"), make("11111111"));
59 |
60 | List b = Lists.newArrayList(make("11111111"), make("00000000"));
61 |
62 | List expect = Lists.newArrayList(make("00000000"), make("11111111"), make("00000000"));
63 |
64 | assertTrue(equals(Lexicographic.merge(a, b), expect));
65 | }
66 |
67 | @Test
68 | public void testByteBufferListMergeVariableLength() {
69 | List a = Lists.newArrayList(make("00000000", "00000000", "00000000", "00000001"));
70 |
71 | List b = Lists.newArrayList(make("00000000", "00000000", "00000000", "00000001", "00000000"));
72 |
73 | List expect = Lists.newArrayList(make("00000000", "00000000", "00000000", "00000001"),
74 | make("00000000", "00000000", "00000000", "00000001", "00000000"));
75 |
76 | assertTrue(equals(Lexicographic.merge(a, b), expect));
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/atomlayer/core/src/test/java/brown/tracingplane/atomlayer/TestProtobufVarint.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import java.nio.BufferUnderflowException;
5 | import java.nio.ByteBuffer;
6 | import java.util.Random;
7 | import org.junit.Test;
8 | import brown.tracingplane.atomlayer.ProtobufVarint;
9 | import brown.tracingplane.atomlayer.ProtobufVarint.MalformedVarintException;
10 |
11 | public class TestProtobufVarint {
12 |
13 | @Test
14 | public void testVarintSize() {
15 | int numtests = 1000;
16 | Random r = new Random(0);
17 | for (int i = 0; i < 5; i++) {
18 | int min = (int) Math.pow(2, 7 * i);
19 | int max = (int) Math.min(Integer.MAX_VALUE, Math.pow(2, 7 * (i + 1)));
20 |
21 | for (int j = 0; j < numtests; j++) {
22 | int value = r.nextInt(max - min) + min;
23 | assertEquals(i + 1, ProtobufVarint.sizeOf(value));
24 | }
25 | }
26 | }
27 |
28 | @Test
29 | public void testVarintCorrect() throws MalformedVarintException, BufferUnderflowException {
30 | int numtests = 1000;
31 | Random r = new Random(0);
32 | for (int i = 0; i < 5; i++) {
33 | int min = (int) Math.pow(2, 7 * i);
34 | int max = (int) Math.min(Integer.MAX_VALUE, Math.pow(2, 7 * (i + 1)));
35 |
36 | for (int j = 0; j < numtests; j++) {
37 | int value = r.nextInt(max - min) + min;
38 |
39 | ByteBuffer b = ByteBuffer.allocate(i + 1);
40 | ProtobufVarint.writeRawVarint32(b, value);
41 | b.rewind();
42 |
43 | assertEquals(value, ProtobufVarint.readRawVarint32(b));
44 | }
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/atomlayer/core/src/test/java/brown/tracingplane/atomlayer/TestSerialization.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 | import java.nio.ByteBuffer;
6 | import java.util.ArrayList;
7 | import org.junit.Test;
8 | import brown.tracingplane.atomlayer.AtomLayerSerialization;
9 |
10 | public class TestSerialization {
11 |
12 | @Test
13 | public void testSerializeNulls() {
14 |
15 | assertNotNull(AtomLayerSerialization.serialize(null));
16 | assertNotNull(AtomLayerSerialization.serialize(new ArrayList()));
17 |
18 | assertEquals(0, AtomLayerSerialization.serialize(null).length);
19 | assertEquals(0, AtomLayerSerialization.serialize(new ArrayList()).length);
20 |
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/atomlayer/core/src/test/java/brown/tracingplane/atomlayer/TestUnsignedByteBuffer.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.atomlayer;
2 |
3 | import static org.junit.Assert.assertTrue;
4 | import java.nio.ByteBuffer;
5 | import java.util.Comparator;
6 | import org.junit.Test;
7 | import brown.tracingplane.atomlayer.TypeUtils;
8 | import brown.tracingplane.atomlayer.UnsignedByteBuffer;
9 |
10 | public class TestUnsignedByteBuffer {
11 |
12 | private static ByteBuffer make(String... ss) {
13 | ByteBuffer buf = ByteBuffer.allocate(ss.length);
14 | for (String s : ss) {
15 | buf.put(TypeUtils.makeByte(s));
16 | }
17 | buf.rewind();
18 | return buf;
19 | }
20 |
21 | @Test
22 | public void testUnsafeComparatorExists() {
23 | Comparator comparator = UnsignedByteBuffer.lexicographicalComparator();
24 |
25 | assertTrue(comparator instanceof UnsignedByteBuffer.LexicographicalComparatorHolder.UnsafeComparator);
26 | }
27 |
28 | @Test
29 | public void testJavaComparatorExists() {
30 | Comparator comparator = UnsignedByteBuffer.lexicographicalComparatorJavaImpl();
31 |
32 | assertTrue(comparator instanceof UnsignedByteBuffer.LexicographicalComparatorHolder.PureJavaComparator);
33 | }
34 |
35 | @Test
36 | public void testUnsafeComparator() {
37 | Comparator comparator = UnsignedByteBuffer.lexicographicalComparator();
38 |
39 | ByteBuffer a = make("0000 0000");
40 | ByteBuffer b = make("1000 0000");
41 |
42 | assertTrue(comparator.compare(a, a) == 0);
43 | assertTrue(comparator.compare(b, b) == 0);
44 | assertTrue(comparator.compare(a, b) < 0);
45 | assertTrue(comparator.compare(b, a) > 0);
46 | }
47 |
48 | @Test
49 | public void testUnsafeComparatorWithLong() {
50 | Comparator comparator = UnsignedByteBuffer.lexicographicalComparator();
51 |
52 | ByteBuffer a = make("0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000",
53 | "0000 0000", "0000 0000");
54 | ByteBuffer b = make("1000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000",
55 | "0000 0000", "0000 0000");
56 |
57 | assertTrue(comparator.compare(a, a) == 0);
58 | assertTrue(comparator.compare(b, b) == 0);
59 | assertTrue(comparator.compare(a, b) < 0);
60 | assertTrue(comparator.compare(b, a) > 0);
61 | }
62 |
63 | @Test
64 | public void testUnsafeComparatorWithLongAndRemaining() {
65 | Comparator comparator = UnsignedByteBuffer.lexicographicalComparator();
66 |
67 | ByteBuffer a = make("0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000",
68 | "0000 0000", "0000 0000");
69 | ByteBuffer b = make("0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000", "0000 0000",
70 | "0000 0000", "1000 0000");
71 |
72 | assertTrue(comparator.compare(a, a) == 0);
73 | assertTrue(comparator.compare(b, b) == 0);
74 | assertTrue(comparator.compare(a, b) < 0);
75 | assertTrue(comparator.compare(b, a) > 0);
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/atomlayer/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | atomlayer
6 | pom
7 |
8 | Atom Layer
9 |
10 |
11 | core
12 | baggagecontext-impl
13 |
14 |
15 |
16 | brown.tracingplane
17 | tracingplane-project
18 | 1.0
19 |
20 |
21 |
22 | ${basedir}/..
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/baggagecontext/api/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/baggagecontext/api/README.md:
--------------------------------------------------------------------------------
1 | # Tracing Plane - Core
2 |
3 | Defines two core Tracing Plane interfaces - `BaggageContext` and `BaggageProvider`.
4 |
5 | A `BaggageContext` supports several fundamental propagation operations, that are implemented by its `BaggageProvider`. They are:
6 |
7 | * `newInstance()` -- creates a new, empty `BaggageContext`. Depending on the `BaggageProvider`, it may choose to represent empty `BaggageContext` instances using null
8 | * `branch(BaggageContext)` -- creates a duplicate `BaggageContext`. Typically this just creates a copy. Changes made to the branched `BaggageContext` will not be visible in the original, and vice versa.
9 | * `join(BaggageContext, BaggageContext)` -- merges the values of two `BaggageContext` instances. If there is no conflicting data within the `BaggageContexts`, this resembles a union of their contents. However, if they both contain, e.g., values mapped to the same key, and those values differ, then the `BaggageProvider` must implement some sort of conflict resolution.
10 | * `serialize(BaggageContext)` -- serializes the `BaggageContext` to a binary representation. For a string-based representation, either use a `BaggageProvider`-specified representation, or `base64` encode the binary representation
11 | * `deserialize(BaggageContext)` -- corresponding deserialization method
12 | * `trim` -- trim is a special operation, that is exposed as `serialize(BaggageContext, maximumSerializedLength)`. `BaggageProvider` is expected to provide a serialization method that drops data if it exceeds a certain length threshold.
13 |
14 | The above methods only pertain to propagating `BaggageContext`. There are no methods for accessing `BaggageContext` data or values. The `BaggageProvider` is responsible for providing accessor interfaces.
15 |
16 | With respect to the Tracing Plane, we provide a concise, efficient implementation of all of these methods using a representation based on *atoms*.
--------------------------------------------------------------------------------
/baggagecontext/api/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | baggagecontext-api
6 | jar
7 |
8 | Baggage Context - API
9 |
10 |
11 | brown.tracingplane
12 | baggagecontext
13 | 1.0
14 |
15 |
16 |
17 | ${basedir}/../..
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/baggagecontext/api/src/main/java/brown/tracingplane/BaggageContext.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane;
2 |
3 | /**
4 | *
5 | * A {@link BaggageContext} is an opaque context object belonging to an execution. Baggage contexts are propagated
6 | * alongside requests as they execute -- they should be passed to new threads, included with work items (e.g.,
7 | * {@link java.lang.Runnable}, {@link java.util.concurrent.Callable}, etc.), serialized in network headers, and so on.
8 | *
9 | *
10 | *
11 | * {@link BaggageContext} objects have no direct methods for manipulating contexts or accessing data that they carry.
12 | * This is because, in the common case, a {@link BaggageContext} is typically empty, and an empty context is typically
13 | * implemented using null values.
14 | *
15 | *
16 | *
17 | * To propagate {@link BaggageContext} objects, call {@link BaggageProvider} methods such as
18 | * {@link BaggageProvider#branch(BaggageContext)}, {@link BaggageProvider#serialize(BaggageContext)}, etc.
19 | *
5 | * Factory for {@link BaggageProvider} instances; primarily used to configure the {@link BaggageProvider} used by the
6 | * {@link Baggage} static API.
7 | *
8 | *
9 | *
10 | * {@link BaggageProviderFactory} is expected to have a no-arg constructor so that it can be instantiated by reflection.
11 | *
3 | * Provides the main {@link BaggageContext} and {@link BaggageProvider} interfaces of the Tracing Plane
4 | *
5 | *
6 | *
7 | * At a high level, {@link BaggageContext} instances exist at the granularity of requests (or tasks, jobs, etc). The
8 | * purpose is to propagate a {@link BaggageContext} alongside each request while it executes. {@link BaggageContext}s
9 | * carry user-defined or tracing-tool defined data.
10 | *
11 | *
12 | *
13 | * {@link BaggageContext} instances should follow requests in a fine-grained manner. For example, if a request splits
14 | * off into multiple concurrent execution branches, then each branch of execution should receive its its own
15 | * {@link BaggageContext} instance, created by calling {@link BaggageProvider#branch(BaggageContext)} at the time the
16 | * request splits.
17 | *
18 | *
19 | *
20 | * Likewise, if multiple concurrent branches merge, or if some task is dependent upon multiple predecessors completing,
21 | * then {@link BaggageContext} instances can be merged using
22 | * {@link BaggageProvider#join(BaggageContext, BaggageContext)}.
23 | *
24 | *
25 | *
26 | * The Tracing Plane provides several {@link BaggageContext} implementations, the main implementation being
27 | * {@link brown.tracingplane.impl.BDLContext} in the {@link brown.tracingplane.bdl} package.
28 | *
29 | */
30 | package brown.tracingplane;
31 |
--------------------------------------------------------------------------------
/baggagecontext/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | baggagecontext
6 | pom
7 |
8 | Baggage Context
9 |
10 |
11 | api
12 | staticapi
13 | transitlayer
14 |
15 |
16 |
17 | brown.tracingplane
18 | tracingplane-project
19 | 1.0
20 |
21 |
22 |
23 | ${basedir}/..
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/baggagecontext/staticapi/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/baggagecontext/staticapi/README.md:
--------------------------------------------------------------------------------
1 | # Tracing Plane - Static API
2 |
3 | The Tracing Plane provides a static API `brown.tracingplane.Baggage` for manipulating `BaggageContext` instances. This static API is the main entry point for manipulating contexts directly. Supported methods are:
4 |
5 | * `newInstance()` -- creates a new, empty `BaggageContext`; possibly a `null` value
6 | * `branch(BaggageContext)` -- creates a duplicate `BaggageContext`. Typically this just creates a copy. Changes made to the branched `BaggageContext` will not be visible in the original, and vice versa.
7 | * `join(BaggageContext, BaggageContext)` -- merges the values of two `BaggageContext` instances. If there is no conflicting data within the `BaggageContexts`, this resembles a union of their contents. However, if they both contain, e.g., values mapped to the same key, and those values differ, then the `BaggageProvider` must implement some sort of conflict resolution.
8 | * `serialize(BaggageContext)` -- serializes the `BaggageContext` to a binary representation. For a string-based representation, either use a `BaggageProvider`-specified representation, or `base64` encode the binary representation
9 | * `deserialize(BaggageContext)` -- corresponding deserialization method
10 | * `trim` -- trim is a special operation, that is exposed as `serialize(BaggageContext, maximumSerializedLength)`. `BaggageProvider` is expected to provide a serialization method that drops data if it exceeds a certain length threshold.
11 |
12 | Example usage in code is, for example, to pass a `BaggageContext` to a new thread:
13 |
14 | BaggageContext currentContext;
15 | MyThread newThread = new MyThread(Baggage.branch(currentContext));
16 |
17 | Or to serialize a context for inclusion in network calls:
18 |
19 | BaggageContext currentContext;
20 | out.write(Baggage.serialize(currentContext));
21 |
22 | The Tracing Plane also provides an `ActiveBaggage` API that mirrors these method calls.
23 |
24 | Use of the `Baggage` static API depends on a `BaggageProvider` being configured. Typically, this is done automatically by the Tracing Plane distribution that you use. If this is not the case, or if you wish to override the `BaggageProvider` implementation being used, then you can set the `baggage.provider` property to the `BaggageProviderFactory` of your choice, e.g.,
25 |
26 | -Dbaggage.provider=brown.tracingplane.impl.NoOpBaggageContextProviderFactory
27 |
28 | or in the typesafe `application.conf`:
29 |
30 | baggage.provider = "brown.tracingplane.impl.NoOpBaggageContextProviderFactory"
--------------------------------------------------------------------------------
/baggagecontext/staticapi/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | baggagecontext-staticapi
6 | jar
7 |
8 | Baggage Context - Static API
9 |
10 |
11 | brown.tracingplane
12 | baggagecontext
13 | 1.0
14 |
15 |
16 |
17 | ${basedir}/../..
18 |
19 |
20 |
21 |
22 | brown.tracingplane
23 | baggagecontext-api
24 | ${project.version}
25 |
26 |
27 | org.slf4j
28 | slf4j-api
29 |
30 |
31 | org.slf4j
32 | slf4j-log4j12
33 |
34 |
35 | com.typesafe
36 | config
37 |
38 |
39 | junit
40 | junit
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/baggagecontext/staticapi/src/main/java/brown/tracingplane/impl/NoOpBaggageContextProvider.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.impl;
2 |
3 | import java.nio.ByteBuffer;
4 | import brown.tracingplane.BaggageContext;
5 | import brown.tracingplane.BaggageProvider;
6 |
7 | /**
8 | * A {@link BaggageProvider} implementation that always just returns null.
9 | */
10 | public class NoOpBaggageContextProvider implements BaggageProvider {
11 |
12 | @Override
13 | public boolean isValid(BaggageContext baggage) {
14 | return baggage == null;
15 | }
16 |
17 | @Override
18 | public BaggageContext newInstance() {
19 | return null;
20 | }
21 |
22 | @Override
23 | public void discard(BaggageContext baggage) {}
24 |
25 | @Override
26 | public BaggageContext branch(BaggageContext from) {
27 | return null;
28 | }
29 |
30 | @Override
31 | public BaggageContext join(BaggageContext left, BaggageContext right) {
32 | return null;
33 | }
34 |
35 | @Override
36 | public BaggageContext deserialize(byte[] serialized, int offset, int length) {
37 | return null;
38 | }
39 |
40 | @Override
41 | public BaggageContext deserialize(ByteBuffer buf) {
42 | return null;
43 | }
44 |
45 | @Override
46 | public byte[] serialize(BaggageContext baggage) {
47 | return null;
48 | }
49 |
50 | @Override
51 | public byte[] serialize(BaggageContext baggage, int maximumSerializedSize) {
52 | return null;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/baggagecontext/staticapi/src/main/java/brown/tracingplane/impl/NoOpBaggageContextProviderFactory.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.impl;
2 |
3 | import brown.tracingplane.BaggageContext;
4 | import brown.tracingplane.BaggageProvider;
5 | import brown.tracingplane.BaggageProviderFactory;
6 |
7 | /**
8 | * A {@link BaggageProvider} implementation that always just returns null.
9 | */
10 | public class NoOpBaggageContextProviderFactory implements BaggageProviderFactory {
11 |
12 | @Override
13 | public BaggageProvider extends BaggageContext> provider() {
14 | return new NoOpBaggageContextProvider();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/baggagecontext/staticapi/src/main/java/brown/tracingplane/impl/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Implementations of {@link BaggageContext} at several different points in the Tracing Plane.
4 | *
5 | *
6 | *
7 | * {@link AtomContext} is the most lightweight atom-based context, which provides no accessor or convenience methods for
8 | * manipulating data. {@link AtomContext} is purely for propagation (e.g., forwarding baggage contexts that you received
9 | * from other network calls).
10 | *
11 | *
12 | *
13 | * {@link NestedBaggageContext} extends the Atom Context and implements the Baggage Protocol, which gives nested data
14 | * structures.
15 | *
16 | *
17 | *
18 | * {@link BDLContext} is the full-featured baggage context, which provides interpretations for different data types
19 | * using atoms.
20 | *
21 | *
22 | */
23 | package brown.tracingplane.impl;
24 |
--------------------------------------------------------------------------------
/baggagecontext/staticapi/src/test/java/brown/tracingplane/impl/TestNoOpBaggageContextProvider.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.impl;
2 |
3 | import static org.junit.Assert.assertFalse;
4 | import static org.junit.Assert.assertNotNull;
5 | import static org.junit.Assert.assertNull;
6 | import static org.junit.Assert.assertTrue;
7 | import org.junit.Test;
8 | import brown.tracingplane.BaggageContext;
9 | import brown.tracingplane.BaggageProvider;
10 | import brown.tracingplane.BaggageProviderFactory;
11 |
12 | public class TestNoOpBaggageContextProvider {
13 |
14 | @Test
15 | public void testNoOpBaggageContextProviderFactory() {
16 | BaggageProviderFactory factory = new NoOpBaggageContextProviderFactory();
17 |
18 | BaggageProvider> provider = factory.provider();
19 | assertNotNull(provider);
20 | assertTrue(provider instanceof NoOpBaggageContextProvider);
21 | }
22 |
23 | @Test
24 | public void testNoOpBaggageContextProvider() {
25 | BaggageProvider> provider = new NoOpBaggageContextProvider();
26 |
27 | assertNull(provider.newInstance());
28 | assertNull(provider.branch(null));
29 | assertNull(provider.join(null, null));
30 | assertNull(provider.serialize(null));
31 | assertNull(provider.serialize(null, 0));
32 | assertNull(provider.deserialize(null));
33 | assertNull(provider.deserialize(null, 0, 0));
34 | assertTrue(provider.isValid(null));
35 |
36 | BaggageContext invalidContext = new BaggageContext() {};
37 | assertFalse(provider.isValid(invalidContext));
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/baggagecontext/transitlayer/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .settings
3 | .project
4 | bin
5 | target
6 | xtrace-data
7 | application.conf
--------------------------------------------------------------------------------
/baggagecontext/transitlayer/README.md:
--------------------------------------------------------------------------------
1 | # TracingPlane:BaggageContext/TransitLayer
2 |
3 | This package provides the following:
4 |
5 | * The core interfaces for the Tracing Plane's `TransitLayer` -- to enhance the existing `BaggageContext` and `Baggage` interfaces that exist in `BaggageContext/API` and `BaggageContext/StaticAPI`.
6 | * The out-of-the-box `TransitLayer` implementation, which is a NoOp and does nothing -- method calls are essentially ignored
7 | * A `TransitLayer` implementation based on thread-local variables. This is the recommended context propagation library to use with the tracing plane. It is the default `TransitLayer` implementation in the Tracing Plane distribution jars.
8 |
9 | ## Transit Layer
10 |
11 | The Tracing Plane provides an out-of-the-box context propagation library called the "Transit Layer". The Transit Layer uses thread-local storage to store `BaggageContext` instances for threads, and provides a static API in `brown.tracingplane.ActiveBaggage` that invokes transit layer methods. `ActiveBaggage` provides methods as follows:
12 |
13 | * `set(BaggageContext)` -- set the active `BaggageContext` for this thread
14 | * `get()` -- get the active `BaggageContext` for this thread
15 | * `take()` -- remove and return the active `BaggageContext` for this thread
16 | * `takeBytes()` -- remove, return, and serialize the active `BaggageContext` for this thread
17 | * `discard()` -- discard the active `BaggageContext` for this thread
18 |
19 | In addition to methods for manipulating the active baggage, the Transit Layer and `ActiveBaggage` interface provides methods mirroring those in the `Baggage` and `BaggageProvider` interfaces, to implicitly manipulate the current context:
20 |
21 | * `branch()` -- creates and returns a duplicate of the currently active `BaggageContext`.
22 | * `join(BaggageContext)` -- merges the values of some `BaggageContext` object into the active context.
23 |
24 | The Transit Layer is configurable, and alternative implementations can be used other than the out-of-the-box thread-local implementation. To provide a different implementation, simply implement the `TransitLayer` and `TransitLayerFactory` interfaces, then configure the factory class using the `baggage.transit` property, e.g.:
25 |
26 | -Dbaggage.transit=brown.tracingplane.impl.ThreadLocalTransitLayerFactory
27 |
28 | or, using typesafe config `application.conf`:
29 |
30 | baggage.transit = "brown.tracingplane.impl.ThreadLocalTransitLayerFactory"
--------------------------------------------------------------------------------
/baggagecontext/transitlayer/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | transitlayer
6 | jar
7 |
8 | Baggage Context - Transit Layer Impl
9 |
10 |
11 | brown.tracingplane
12 | baggagecontext
13 | 1.0
14 |
15 |
16 |
17 | ${basedir}/../..
18 |
19 |
20 |
21 |
22 | brown.tracingplane
23 | baggagecontext-staticapi
24 | ${project.version}
25 |
26 |
27 | org.slf4j
28 | slf4j-api
29 |
30 |
31 | org.slf4j
32 | slf4j-log4j12
33 |
34 |
35 | com.typesafe
36 | config
37 |
38 |
39 | junit
40 | junit
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/baggagecontext/transitlayer/src/main/java/brown/tracingplane/DefaultTransitLayer.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import com.typesafe.config.Config;
6 | import com.typesafe.config.ConfigException;
7 | import com.typesafe.config.ConfigFactory;
8 | import brown.tracingplane.impl.NoOpTransitLayerFactory;
9 | import brown.tracingplane.impl.ThreadLocalTransitLayer;
10 |
11 | /**
12 | *
13 | * Loads the {@link TransitLayerFactory} specified by baggage.transit using reflection.
14 | *
15 | */
16 | public class DefaultTransitLayer {
17 |
18 | private static final Logger log = LoggerFactory.getLogger(DefaultTransitLayer.class);
19 |
20 | private final TransitLayerFactory factory;
21 | private final TransitLayer transitlayer;
22 |
23 | /** Not instantiable */
24 | private DefaultTransitLayer() {
25 | Config config = ConfigFactory.load();
26 |
27 | TransitLayerFactory factory = null;
28 | if (!config.hasPath("baggage.transit")) {
29 | log.warn("No TransitLayerFactory has been configured using baggage.transit -- baggage propagation using the ActiveBaggage interface will be disabled");
30 | } else {
31 | try {
32 | String transitLayerClass = config.getString("baggage.transit");
33 |
34 | try {
35 | Object instantiated = Class.forName(transitLayerClass).newInstance();
36 |
37 | try {
38 | factory = (TransitLayerFactory) instantiated;
39 | } catch (ClassCastException e) {
40 | log.error("The configured baggage.transit should be an instance of TransitLayerFactory; found " +
41 | instantiated.getClass().getName());
42 | }
43 | } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
44 | log.error("Unable to instantiate TransitLayerFactory specified by baggage.transit " +
45 | transitLayerClass, e);
46 | }
47 |
48 | } catch (ConfigException.WrongType e) {
49 | Object v = config.getAnyRef("baggage.transit");
50 | log.error("Invalid baggage.transit has been configured -- baggage propagation using the ActiveBaggage interface will be disabled. Expected a string for baggage.provider, found " +
51 | v.getClass().getName() + ": " + v);
52 | }
53 | }
54 |
55 | if (factory == null) {
56 | this.factory = new NoOpTransitLayerFactory();
57 | this.transitlayer = this.factory.transitlayer();
58 | } else {
59 | this.factory = factory;
60 | this.transitlayer = this.factory.transitlayer();
61 | }
62 | }
63 |
64 | private static DefaultTransitLayer instance = null;
65 |
66 | private static DefaultTransitLayer instance() {
67 | if (instance == null) {
68 | synchronized (DefaultTransitLayer.class) {
69 | if (instance == null) {
70 | instance = new DefaultTransitLayer();
71 | }
72 | }
73 | }
74 | return instance;
75 | }
76 |
77 | /**
78 | * @return the configured {@link TransitLayer} instance. The default transit layer can be set using
79 | * -Dbaggage.transit. If no instance has been configured, this method will return a
80 | * {@link ThreadLocalTransitLayer} that uses simple thread-local storage to store baggage contexts.
81 | */
82 | public static TransitLayer get() {
83 | return instance().transitlayer;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/baggagecontext/transitlayer/src/main/java/brown/tracingplane/TransitLayerFactory.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane;
2 |
3 | /**
4 | *
5 | * Factory for {@link TransitLayer} instances; primarily used to configure the {@link TransitLayer} used by the
6 | * {@link ActiveBaggage} static API.
7 | *
8 | *
9 | *
10 | * {@link TransitLayerFactory} is expected to have a no-arg constructor so that it can be instantiated by reflection.
11 | *
10 | * A {@link TransitLayer} that does nothing. This is the default {@link TransitLayer} implementation that will be used
11 | * in lieu of anything else. If this is the {@link TransitLayer} implementation used, the effect is that any calls to
12 | * the {@link ActiveBaggage} interface will find that there is no active baggage.
13 | *
14 | *
15 | *
16 | * {@link NoOpTransitLayer} is typically going to be used at instrumentation time, prior to binding to a particular
17 | * implementation.
18 | *
19 | *
20 | *
21 | * If you intend to use a different instrumentation library altogether to propagate contexts (e.g., OpenTracing), then
22 | * you would either:
23 | *
24 | *
Implement a {@link TransitLayer} that opaquely proxies to your other instrumentation library
9 | * A {@link TransitLayer} that does nothing. This is the default {@link TransitLayer} implementation that will be used
10 | * if none is configured. If this is the {@link TransitLayer} implementation used, the effect is that any calls to the
11 | * {@link ActiveBaggage} interface will find that there is no active baggage.
12 | *
9 | * The {@link TransitLayerFactory} that creates {@link ThreadLocalTransitLayer} instances. If you need to manually
10 | * configure the {@link TransitLayer}, you would set baggage.transit to be this class, e.g.:
11 | *
12 | *
17 | * An implementation of {@link BaggageContext} that interprets atoms using the baggage protocol, which specifies a data
18 | * layout for nested bags.
19 | *
13 | * {@link BaggageProvider} for {@link NestedBaggageContext}, which extends {@link AtomContext} to interpret atoms as
14 | * nested data structures.
15 | *
5 | * The only additional option that we propagate is the merge behavior. We do not propagate serialize or branch
6 | * behaviors, as follows:
7 | *
8 | *
9 | *
10 | *
The main use case for specifying branch and serialize behaviors is to handle 'brittle' fields. The default
11 | * propagation behavior is `ignore and propagate`; however, you might want to override this to drop data in some
12 | * scenarios. For example, you might have a vector clock style component id in the baggage and could want to ensure that
13 | * only one side of the branch retains the ID.
14 | *
Because of this it could be argued that the baggage layer could have some options for specifying logic for when
15 | * baggage operations (branch, join, serialize) occur.
16 | *
The reason for implementing logic in the baggage layer is for when data traverses other processes that are
17 | * baggage compliant, but lack knowledge of the semantics of specific fields of the baggage
18 | *
However, when the baggage leaves the current process, it might traverse atom-compliant-only processes (ie,
19 | * non-baggage-compliant) that naively copy the data (because they adhere to `ignore and propagate`. This is
20 | * unavoidable. So we cannot provide guarantees for brittle fields outside of a process.
21 | *
Within a process, if the process knows how to add one of these brittle fields to the baggage, then it is implied
22 | * that the process knows the semantics of that field. Thus, the process also has control of when the baggage will
23 | * branch, join, and serialize within this process. This means it can interpose on the baggage via callbacks
24 | *
As a result, we argue that branch and serialize options are unnecessary and can be handled by callbacks
3 | * Defines an encoding scheme for nested data structures using atoms.
4 | *
5 | *
6 | *
7 | * The Baggage Protocol reads and writes {@link BaggageContext}s with a pre-order depth-first traversal. Starting from
8 | * the root of the tree, we first have data for that node, followed by child nodes. Child nodes can be addressed by
9 | * either statically defined indices, or by arbitrary-length key.
10 | *
11 | *
12 | *
13 | * The {@link BaggageReader} and {@link BaggageWriter} classes are used for reading and writing atoms for
14 | * {@link BaggageContext} instances.
15 | *
16 | *
17 | *
18 | * Details of the baggage protocol can be found on the project GitHub repository.
19 | *
20 | */
21 | package brown.tracingplane.baggageprotocol;
22 |
--------------------------------------------------------------------------------
/baggageprotocol/core/src/test/java/brown/tracingplane/baggageprotocol/BaggageTestCase.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.baggageprotocol;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 | import static org.junit.Assert.fail;
6 | import java.nio.ByteBuffer;
7 | import java.util.List;
8 | import java.util.Random;
9 | import org.junit.Before;
10 | import org.junit.Rule;
11 | import org.junit.rules.ExpectedException;
12 | import com.google.common.collect.Lists;
13 | import brown.tracingplane.atomlayer.AtomLayerException;
14 | import brown.tracingplane.atomlayer.ByteBuffers;
15 | import brown.tracingplane.baggageprotocol.AtomPrefixes.DataPrefix;
16 |
17 | public abstract class BaggageTestCase {
18 |
19 | @Rule
20 | public final ExpectedException exception = ExpectedException.none();
21 |
22 | final Random r = new Random(0);
23 |
24 | ByteBuffer randomBytes(int length) {
25 | byte[] bytes = new byte[length];
26 | r.nextBytes(bytes);
27 | return ByteBuffer.wrap(bytes);
28 | }
29 |
30 | BagKey.Indexed indexed(int index) {
31 | return (BagKey.Indexed) BagKey.indexed(index);
32 | }
33 |
34 | ByteBuffer dataAtom(ByteBuffer payload) {
35 | ByteBuffer atom = ByteBuffer.allocate(payload.remaining() + 1);
36 | atom.put(DataPrefix.prefix);
37 | ByteBuffers.copyTo(payload, atom);
38 | atom.flip();
39 | return atom;
40 | }
41 |
42 | ByteBuffer headerAtom(BagKey bagKey, int level) {
43 | return HeaderSerialization.serialize(bagKey, level);
44 | }
45 |
46 | List writeBag(BagKey key, ByteBuffer... contents) {
47 | BaggageWriter writer = BaggageWriter.create();
48 | writer.enter(key);
49 | for (ByteBuffer content : contents) {
50 | ByteBuffers.copyTo(content, writer.newDataAtom(content.remaining()));
51 | }
52 | writer.exit();
53 | return writer.atoms();
54 | }
55 |
56 | List writeBag(BagKey a, BagKey b, ByteBuffer... contents) {
57 | BaggageWriter writer = BaggageWriter.create();
58 | writer.enter(a);
59 | writer.enter(b);
60 | for (ByteBuffer content : contents) {
61 | ByteBuffers.copyTo(content, writer.newDataAtom(content.remaining()));
62 | }
63 | writer.exit();
64 | writer.exit();
65 | return writer.atoms();
66 | }
67 |
68 | @Before
69 | public void setRandomSeed() throws Exception {
70 | r.setSeed(0);
71 | };
72 |
73 | void assertOverflowPath(List overflowAtoms, BagKey... path) {
74 | assertOverflowPath(overflowAtoms, Lists. newArrayList(path));
75 | }
76 |
77 | void assertOverflowPath(List overflowAtoms, List keys) {
78 | assertNotNull(overflowAtoms);
79 | assertEquals(keys.size() + 1, overflowAtoms.size());
80 | for (int level = 0; level < keys.size(); level++) {
81 | BagKey key = keys.get(level);
82 | ByteBuffer atom = overflowAtoms.get(level);
83 | assertEquals(atom, HeaderSerialization.serialize(key, level));
84 | try {
85 | assertEquals(key, HeaderSerialization.parse(atom));
86 | } catch (AtomLayerException | BaggageLayerException e) {
87 | fail(e.getMessage());
88 | e.printStackTrace();
89 | }
90 | }
91 | assertEquals(BaggageProtocol.OVERFLOW_MARKER, overflowAtoms.get(keys.size()));
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/baggageprotocol/core/src/test/java/brown/tracingplane/baggageprotocol/TestBagKey.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.baggageprotocol;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import java.nio.ByteBuffer;
5 | import org.junit.Test;
6 | import brown.tracingplane.atomlayer.Lexicographic;
7 |
8 | public class TestBagKey {
9 |
10 | @Test
11 | public void testBagKeyComparison() {
12 | int[] indicesToTest =
13 | { Integer.MIN_VALUE, Short.MIN_VALUE, -10, -3, -1, 0, 1, 3, 10, Short.MAX_VALUE, Integer.MAX_VALUE };
14 | String[] keysToTest = { "", "a", "aaaaa", "hello", "hell", "boo" };
15 | ByteBuffer[] bufs = new ByteBuffer[keysToTest.length];
16 | for (int i = 0; i < keysToTest.length; i++) {
17 | bufs[i] = ByteBuffer.wrap(keysToTest[i].getBytes());
18 | }
19 |
20 | for (int i : indicesToTest) {
21 | for (int j : indicesToTest) {
22 | assertEquals(Integer.compare(i, j), BagKey.indexed(i).compareTo(BagKey.indexed(j)));
23 | }
24 | for (String key : keysToTest) {
25 | assertEquals(-1, BagKey.indexed(i).compareTo(BagKey.named(key)));
26 | assertEquals(1, BagKey.named(key).compareTo(BagKey.indexed(i)));
27 | }
28 | for (ByteBuffer buf : bufs) {
29 | assertEquals(-1, BagKey.indexed(i).compareTo(BagKey.keyed(buf)));
30 | assertEquals(1, BagKey.keyed(buf).compareTo(BagKey.indexed(i)));
31 | }
32 | }
33 |
34 | for (ByteBuffer a : bufs) {
35 | for (ByteBuffer b : bufs) {
36 | assertEquals(Lexicographic.compare(a, b), BagKey.keyed(a).compareTo(BagKey.keyed(b)));
37 | }
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/baggageprotocol/core/src/test/java/brown/tracingplane/baggageprotocol/TestBaggage02_EmptyBaggage.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.baggageprotocol;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertFalse;
5 | import static org.junit.Assert.assertNull;
6 | import org.junit.Test;
7 | import brown.tracingplane.baggageprotocol.BaggageLayerException.BaggageLayerRuntimeException;
8 |
9 | /**
10 | * Tests an empty baggage
11 | */
12 | public class TestBaggage02_EmptyBaggage extends BaggageTestCase {
13 |
14 | private BaggageReader makeBaggage() {
15 | BaggageWriter writer = BaggageWriter.create();
16 | return BaggageReader.create(writer.atoms());
17 | }
18 |
19 | @Test
20 | public void testNextData() {
21 | BaggageReader reader = makeBaggage();
22 | assertEquals(null, reader.nextData());
23 | }
24 |
25 | @Test
26 | public void testHasNext() {
27 | BaggageReader reader = makeBaggage();
28 | assertFalse(reader.hasNext());
29 | }
30 |
31 | @Test
32 | public void testHasData() {
33 | BaggageReader reader = makeBaggage();
34 | assertFalse(reader.hasData());
35 | }
36 |
37 | @Test
38 | public void testHasChild() {
39 | BaggageReader reader = makeBaggage();
40 | assertFalse(reader.hasChild());
41 | }
42 |
43 | @Test
44 | public void testEnter1() {
45 | BaggageReader reader = makeBaggage();
46 | assertNull(reader.enter());
47 | }
48 |
49 | @Test
50 | public void testEnter2() {
51 | BaggageReader reader = makeBaggage();
52 | assertFalse(reader.enter(indexed(3)));
53 | }
54 |
55 | @Test
56 | public void testExitThrowsException() {
57 | BaggageReader reader = makeBaggage();
58 | exception.expect(BaggageLayerRuntimeException.class);
59 | reader.exit();
60 | }
61 |
62 | @Test
63 | public void testNoUnprocessedData() {
64 | BaggageReader reader = makeBaggage();
65 | reader.nextData();
66 | assertNull(reader.unprocessedAtoms());
67 | }
68 |
69 | @Test
70 | public void testDidNotOverflow() {
71 | BaggageReader reader = makeBaggage();
72 |
73 | assertFalse(reader.didOverflow());
74 | reader.nextData();
75 | assertFalse(reader.didOverflow());
76 | }
77 |
78 | @Test
79 | public void testNoOverflow() {
80 | BaggageReader reader = makeBaggage();
81 |
82 | reader.nextData();
83 | assertNull(reader.overflowAtoms());
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/baggageprotocol/core/src/test/java/brown/tracingplane/baggageprotocol/TestBaggage07_EmptyBags.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.baggageprotocol;
2 |
3 | import static org.junit.Assert.assertFalse;
4 | import static org.junit.Assert.assertTrue;
5 | import java.nio.ByteBuffer;
6 | import java.util.List;
7 | import org.junit.Test;
8 | import com.google.common.collect.Lists;
9 | import brown.tracingplane.atomlayer.ByteBuffers;
10 |
11 | /**
12 | * Tests a baggage containing a bag that contains a bag that contains ...
13 | *
14 | * Checks that if an empty bag is added, then it isn't included in serialized form
15 | */
16 | public class TestBaggage07_EmptyBags extends BaggageTestCase {
17 |
18 | private final BagKey.Indexed A = indexed(4);
19 | private final BagKey.Indexed AA = indexed(9);
20 | private final BagKey.Indexed AAA = indexed(8282);
21 |
22 | private final List payloadA = Lists.newArrayList(randomBytes(100));
23 |
24 | private void writePayloads(BaggageWriter writer, List payloads) {
25 | payloads.forEach(p -> ByteBuffers.copyTo(p, writer.newDataAtom(p.remaining())));
26 | }
27 |
28 | private BaggageReader makeBaggage() {
29 | BaggageWriter writer = BaggageWriter.create();
30 |
31 | {
32 | writer.enter(A);
33 | writePayloads(writer, payloadA);
34 | writer.enter(AA).enter(AAA);
35 | writer.exit().exit();
36 | writer.exit();
37 | }
38 |
39 | return BaggageReader.create(writer.atoms());
40 | }
41 |
42 | @Test
43 | public void testEnter() {
44 | BaggageReader reader = makeBaggage();
45 | assertTrue(reader.enter(A));
46 | assertFalse(reader.enter(AA));
47 | assertFalse(reader.hasNext());
48 | reader.exit();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/baggageprotocol/core/src/test/java/brown/tracingplane/baggageprotocol/TestOverflowMarker.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.baggageprotocol;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertFalse;
5 | import static org.junit.Assert.assertNull;
6 | import static org.junit.Assert.assertTrue;
7 | import java.nio.ByteBuffer;
8 | import org.junit.Test;
9 | import brown.tracingplane.atomlayer.ByteBuffers;
10 |
11 | public class TestOverflowMarker extends BaggageTestCase {
12 |
13 | @Test
14 | public void testWriteReadSimple() {
15 | ByteBuffer contents = randomBytes(10);
16 |
17 | BaggageWriter writer = BaggageWriter.create();
18 | ByteBuffers.copyTo(contents, writer.newDataAtom(contents.remaining()));
19 | BaggageReader reader = BaggageReader.create(writer.atoms());
20 |
21 | assertFalse(reader.didOverflow());
22 | assertEquals(contents, reader.nextData());
23 | assertFalse(reader.didOverflow());
24 |
25 | reader.finish();
26 | assertNull(reader.overflowAtoms());
27 | }
28 |
29 | @Test
30 | public void testWriteReadSimpleWithOverflow() {
31 | ByteBuffer contents = randomBytes(10);
32 |
33 | BaggageWriter writer = BaggageWriter.create();
34 | writer.didOverflowHere(true);
35 | ByteBuffers.copyTo(contents, writer.newDataAtom(contents.remaining()));
36 | BaggageReader reader = BaggageReader.create(writer.atoms());
37 |
38 | assertTrue(reader.didOverflow());
39 | assertEquals(contents, reader.nextData());
40 | assertTrue(reader.didOverflow());
41 |
42 | reader.finish();
43 | assertOverflowPath(reader.overflowAtoms());
44 | }
45 |
46 | @Test
47 | public void testWriteReadSimpleWithOverflow2() {
48 | ByteBuffer contents = randomBytes(10);
49 | BagKey key = indexed(0);
50 |
51 | BaggageWriter writer = BaggageWriter.create();
52 | writer.enter(key);
53 | ByteBuffers.copyTo(contents, writer.newDataAtom(contents.remaining()));
54 | writer.didOverflowHere(true);
55 | BaggageReader reader = BaggageReader.create(writer.atoms());
56 |
57 | assertFalse(reader.didOverflow());
58 | assertEquals(key, reader.enter());
59 | assertFalse(reader.didOverflow());
60 | assertEquals(contents, reader.nextData());
61 | assertTrue(reader.didOverflow());
62 |
63 | reader.finish();
64 | assertOverflowPath(reader.overflowAtoms(), key);
65 | }
66 |
67 | @Test
68 | public void testFirstOverflowPathTaken() {
69 | BaggageWriter writer = BaggageWriter.create();
70 | writer.enter(indexed(3));
71 | writer.enter(indexed(5)).exit();
72 | writer.enter(indexed(6)).didOverflowHere(true).exit();
73 | writer.exit();
74 | writer.enter(indexed(10)).didOverflowHere(true).exit();
75 |
76 | BaggageReader reader = BaggageReader.create(writer.atoms());
77 | reader.finish();
78 | assertTrue(reader.didOverflow());
79 |
80 | assertOverflowPath(reader.overflowAtoms(), indexed(3), indexed(6));
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/baggageprotocol/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | baggageprotocol
6 | pom
7 |
8 | Baggage Protocol
9 |
10 |
11 | core
12 | baggagecontext-impl
13 |
14 |
15 |
16 | brown.tracingplane
17 | tracingplane-project
18 | 1.0
19 |
20 |
21 |
22 | ${basedir}/..
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .settings
3 | .project
4 | bin
5 | target
6 | xtrace-data
7 | application.conf
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | bdl-baggagecontext
6 | jar
7 |
8 | Baggage Definition Language - BaggageContext Impl
9 |
10 |
11 | brown.tracingplane
12 | bdl
13 | 1.0
14 |
15 |
16 |
17 | ${basedir}/../..
18 |
19 |
20 |
21 |
22 | brown.tracingplane
23 | bdl-core
24 | ${project.version}
25 |
26 |
27 | junit
28 | junit
29 |
30 |
31 | com.typesafe
32 | config
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/src/main/java/brown/tracingplane/BaggageListener.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane;
2 |
3 | import java.util.function.BiFunction;
4 | import java.util.function.Function;
5 | import brown.tracingplane.BaggageContext;
6 | import brown.tracingplane.BaggageProvider;
7 |
8 | /**
9 | * A {@link BaggageListener} is a callback handler that is invoked whenever core {@link BaggageProvider} functions
10 | * (branch, merge, etc.) are invoked. Baggage Listeners are able to manipulate baggage instances before and after the
11 | * functions are called.
12 | *
13 | * A {@link BaggageProvider} must support adding {@link BaggageListener}s.
14 | */
15 | public final class BaggageListener {
16 |
17 | /** BaggageListeners is not instantiable */
18 | private BaggageListener() {}
19 |
20 | /**
21 | * Wraps calls to {@link BaggageProvider#branch(BaggageContext)} so that the baggage instance(s) can be modified.
22 | */
23 | @FunctionalInterface
24 | public static interface BranchListener {
25 |
26 | /**
27 | * Invoked when {@link BaggageProvider#branch(BaggageContext)} is called. wrapped is the default
28 | * implementation of branch which should be called. This method can optionally perform additional logic before
29 | * or after invocation, or override its behavior completely.
30 | *
31 | * @param from a baggage context, possibly null
32 | * @param wrapped the default {@link BaggageProvider#branch(BaggageContext)} function
33 | * @return a baggage context branched from from, possibly null
34 | */
35 | public B branch(B from, Function wrapped);
36 | }
37 |
38 | /**
39 | * Wraps calls to {@link BaggageProvider#join(BaggageContext, BaggageContext)} so that baggage instance(s) can be
40 | * modified.
41 | */
42 | @FunctionalInterface
43 | public static interface JoinListener {
44 |
45 | /**
46 | * Invoked when {@link BaggageProvider#join(BaggageContext, BaggageContext)} is called. wrapped is
47 | * the default implementation of join which should be called. This method can optionally perform additional
48 | * logic before or after invocation, or override its behavior completely.
49 | *
50 | * @param left a {@link BaggageContext} instance, possibly null
51 | * @param right a {@link BaggageContext} instance, possibly null
52 | * @param next the default {@link BaggageProvider#join(BaggageContext, BaggageContext)} function
53 | * @return a baggage context with merged contents from left and right
54 | */
55 | public B join(B left, B right, BiFunction wrapped);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/src/main/java/brown/tracingplane/impl/BDLContextProviderFactory.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.impl;
2 |
3 | import brown.tracingplane.BaggageContext;
4 | import brown.tracingplane.BaggageProvider;
5 | import brown.tracingplane.BaggageProviderFactory;
6 |
7 | /**
8 | * {@link BaggageProviderFactory} for {@link BDLContextProvider}
9 | */
10 | public class BDLContextProviderFactory implements BaggageProviderFactory {
11 |
12 | @Override
13 | public BaggageProvider extends BaggageContext> provider() {
14 | return new BDLContextProvider(BaggageHandlerRegistry.instance);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | # The mapping of bags to baggage handlers is done via the 'bags' configuration key
2 | bag {
3 | # Example registration:
4 | # 10 = "brown.xtrace.XTraceBaggage"
5 | }
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/src/test/java/brown/tracingplane/impl/TestBBUtils.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.impl;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import org.junit.Test;
5 |
6 | public class TestBBUtils {
7 |
8 | @Test
9 | public void testSerializedSize() {
10 | assertEquals(0, BDLContextUtils.serializedSize(null));
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/bdl/baggagecontext-impl/src/test/java/brown/tracingplane/impl/TestBaggageRegistry.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.impl;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import org.junit.Test;
5 | import com.typesafe.config.Config;
6 | import com.typesafe.config.ConfigFactory;
7 | import com.typesafe.config.ConfigValueFactory;
8 | import brown.tracingplane.baggageprotocol.BagKey;
9 | import brown.tracingplane.baggageprotocol.BaggageReader;
10 | import brown.tracingplane.baggageprotocol.BaggageWriter;
11 | import brown.tracingplane.bdl.Bag;
12 | import brown.tracingplane.bdl.BaggageHandler;
13 |
14 | public class TestBaggageRegistry {
15 |
16 | @Test
17 | public void testEmptyByDefault() {
18 |
19 | BaggageHandlerRegistry defaultregistry = BaggageHandlerRegistry.create();
20 |
21 | assertEquals(0, defaultregistry.registrations.keys.length);
22 | assertEquals(0, defaultregistry.registrations.handlers.length);
23 |
24 | }
25 |
26 | private static class BaggageHandlerForTest implements BaggageHandler {
27 |
28 | @Override
29 | public BagForTest parse(BaggageReader reader) {
30 | return null;
31 | }
32 |
33 | @Override
34 | public void serialize(BaggageWriter writer, BagForTest instance) {}
35 |
36 | @Override
37 | public BagForTest join(BagForTest first, BagForTest second) {
38 | return null;
39 | }
40 |
41 | @Override
42 | public BagForTest branch(BagForTest from) {
43 | return null;
44 | }
45 |
46 | @Override
47 | public boolean isInstance(Bag bag) {
48 | return false;
49 | }
50 | }
51 |
52 | private static BaggageHandlerForTest handler = new BaggageHandlerForTest();
53 |
54 | private static class BagForTest implements Bag {
55 |
56 | @Override
57 | public BaggageHandler> handler() {
58 | return handler;
59 | }
60 |
61 | }
62 |
63 | @Test
64 | public void testHandlerReflection() {
65 | Config config =
66 | ConfigFactory.load().withValue("bag.30", ConfigValueFactory.fromAnyRef(BagForTest.class.getName()));
67 | BaggageHandlerRegistry registry = BaggageHandlerRegistry.create(config);
68 |
69 | assertEquals(1, registry.registrations.keys.length);
70 | assertEquals(1, registry.registrations.handlers.length);
71 | assertEquals(BagKey.indexed(30), registry.registrations.keys[0]);
72 | assertEquals(handler, registry.registrations.handlers[0]);
73 |
74 | BaggageHandlerForTest handler2 = new BaggageHandlerForTest();
75 | registry.doAdd(BagKey.indexed(5), handler2);
76 |
77 | assertEquals(2, registry.registrations.keys.length);
78 | assertEquals(2, registry.registrations.handlers.length);
79 | assertEquals(BagKey.indexed(5), registry.registrations.keys[0]);
80 | assertEquals(handler2, registry.registrations.handlers[0]);
81 | assertEquals(BagKey.indexed(30), registry.registrations.keys[1]);
82 | assertEquals(handler, registry.registrations.handlers[1]);
83 |
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/bdl/compiler/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .settings
3 | .project
4 | bin
5 | target
6 | xtrace-data
7 | application.conf
--------------------------------------------------------------------------------
/bdl/compiler/src/main/java/brown/tracingplane/bdl/compiler/BBC.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl.compiler;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Set;
6 | import org.apache.log4j.PropertyConfigurator;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import com.beust.jcommander.JCommander;
10 | import com.beust.jcommander.Parameter;
11 | import com.beust.jcommander.Parameters;
12 | import brown.tracingplane.bdl.compiler.JavaCompiler;
13 | import brown.tracingplane.bdl.compiler.Ast.BaggageBuffersDeclaration;
14 |
15 | public class BBC {
16 |
17 | public static final String version = "0.1.alpha";
18 |
19 | private static final Logger log = LoggerFactory.getLogger(BBC.class);
20 |
21 | /** Command line parameters */
22 | @Parameters(separators = "=")
23 | public static class Settings {
24 |
25 | @Parameter(names = { "--bag_path" },
26 | description = "Specify the directory in which to search for imports. May be specified multiple times; directories will be searched in order. If not given, the current working directory is used.")
27 | String bagPath = ".";
28 |
29 | @Parameter(names = { "--version" }, description = "Show version info and exit.")
30 | boolean version = false;
31 |
32 | @Parameter(names = { "-h", "--help" }, help = true)
33 | boolean help = false;
34 |
35 | @Parameter(names = { "--java_out" }, description = "Output directory to generate Java source files")
36 | String javaOut = null;
37 |
38 | @Parameter(description = "file1 file2 ...")
39 | List files = new ArrayList<>();
40 |
41 | }
42 |
43 | public static void compile(Settings settings) throws CompileException {
44 | Set linked = Linker.link(settings);
45 | if (settings.javaOut != null) {
46 | new JavaCompiler().compile(settings.javaOut, linked);
47 | }
48 | }
49 |
50 | public static void main(String[] args) {
51 | PropertyConfigurator.configure(BBC.class.getClassLoader().getResourceAsStream("log4j-bbcompiler.properties"));
52 |
53 | // Parse the args
54 | Settings settings = new Settings();
55 | JCommander jc = new JCommander(settings, args);
56 | jc.setProgramName("bbc");
57 |
58 | if (settings.help) {
59 | jc.usage();
60 | return;
61 | }
62 |
63 | if (settings.version) {
64 | System.out.println("bbc " + version);
65 | return;
66 | }
67 |
68 | if (settings.files.size() <= 0) {
69 | System.out.println("Missing input file.");
70 | return;
71 | }
72 |
73 | try {
74 | compile(settings);
75 | } catch (Exception e) {
76 | log.error(e.getMessage());
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/bdl/compiler/src/main/java/brown/tracingplane/bdl/compiler/Compiler.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl.compiler;
2 |
3 | import java.util.Collection;
4 | import brown.tracingplane.bdl.compiler.Ast.BaggageBuffersDeclaration;
5 | import brown.tracingplane.bdl.compiler.Ast.ObjectDeclaration;
6 |
7 | public interface Compiler {
8 |
9 | public default void compile(String outputDir, Collection bbDecls) {
10 | bbDecls.forEach(decl -> compile(outputDir, decl));
11 | }
12 |
13 | public default void compile(String outputDir, BaggageBuffersDeclaration bbDecl) {
14 | bbDecl.getObjectDeclarations().forEach(objectDecl -> compile(outputDir, objectDecl));
15 | }
16 |
17 | public void compile(String outputDir, ObjectDeclaration objectDecl);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/bdl/compiler/src/main/java/brown/tracingplane/bdl/compiler/FileUtils.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl.compiler;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.nio.charset.Charset;
7 | import java.util.List;
8 | import org.apache.commons.lang3.StringUtils;
9 | import com.google.common.collect.Lists;
10 |
11 | /** Useful methods to do with reading files */
12 | public class FileUtils {
13 |
14 | private FileUtils() {}
15 |
16 |
17 | public static List splitBagPath(String bagPath) {
18 | return Lists.newArrayList(StringUtils.split(bagPath, File.pathSeparator));
19 | }
20 |
21 | public static String joinBagPath(List bagPathElements) {
22 | return StringUtils.join(bagPathElements, File.pathSeparator);
23 | }
24 |
25 |
26 | /**
27 | * Simply gets the File object for the file with the specified name, but also checks if it exists and is readable
28 | * @param fileName the name of the file to get
29 | * @return a {@link File} object for this fileName or null if it could not be found
30 | */
31 | public static File getFile(String fileName) {
32 | File f = new File(fileName).getAbsoluteFile();
33 | if (f.exists() && f.isFile() && f.canRead()) {
34 | return f;
35 | } else {
36 | return null;
37 | }
38 | }
39 |
40 | /**
41 | * Search several directories for a file with the specified filename. Ignores files if they are not readable.
42 | *
43 | * @param fileName the name of the file to search for
44 | * @param directories directories to search
45 | * @return a {@link File} object for this fileName, or null if no file could be found in any of the directories
46 | */
47 | public static File findFile(String fileName, List directories) {
48 | for (String directory : directories) {
49 | File f = new File(directory, fileName);
50 | if (f.exists() && f.isFile() && f.canRead()) {
51 | return f;
52 | }
53 | }
54 | return null;
55 | }
56 |
57 | /**
58 | * Read the entire contents of a file as a String
59 | *
60 | * @param file the file to read
61 | * @return the contents of the file
62 | * @throws IOException if the file cannot be read for some reason
63 | */
64 | public static String readFully(File file) throws IOException {
65 | FileInputStream fis = new FileInputStream(file);
66 | byte[] data = new byte[(int) file.length()];
67 | fis.read(data);
68 | fis.close();
69 | return new String(data, Charset.defaultCharset());
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/bdl/compiler/src/main/resources/example.bb:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl.example;
2 |
3 | bag SimpleBag {
4 |
5 | set ids = 1;
6 | }
7 |
8 | bag SimpleBag2 {
9 |
10 | int32 first_field = 1;
11 | string second_field = 2;
12 | }
13 |
14 | bag ExampleBag {
15 |
16 | bool boolfield = 0;
17 |
18 | int32 int32field = 1;
19 | sint32 sint32field = 2;
20 | fixed32 fixed32field = 3;
21 | sfixed32 sfixed32field = 4;
22 |
23 | int64 int64field = 5;
24 | sint64 sint64field = 6;
25 | fixed64 fixed64field = 7;
26 | sfixed64 sfixed64field = 8;
27 |
28 | string stringfield = 9;
29 | bytes bytesfield = 10;
30 |
31 | set int32set = 11;
32 | set stringset = 12;
33 |
34 | SimpleBag simple_bag = 15;
35 |
36 | Set simple_bag_2 = 16;
37 |
38 |
39 | Map bag_map = 20;
40 |
41 | }
--------------------------------------------------------------------------------
/bdl/compiler/src/main/resources/log4j-bbcompiler.properties:
--------------------------------------------------------------------------------
1 | # Root logger option
2 | log4j.rootLogger=INFO, stdout
3 |
4 | # Direct log messages to stdout
5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
6 | log4j.appender.stdout.Target=System.out
7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
9 |
--------------------------------------------------------------------------------
/bdl/compiler/src/main/scala/brown/tracingplane/bdl/compiler/Parser.scala:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl.compiler
2 |
3 | import brown.tracingplane.bdl.compiler.Ast._
4 | import brown.tracingplane.bdl.compiler.Declarations._
5 | import fastparse.all._
6 | import org.apache.commons.lang3.StringUtils
7 |
8 | object Parser {
9 |
10 | /** One-line comment beginning with double slash */
11 | val comment1 = P( "//" ~ CharsWhile(_ != '\n') ~ "\n" ).map{ case _ => "\n" }
12 | val comment2 = P( "/*" ~ (!"*/" ~ AnyChar).rep ~ ("*/" | End) ).map{ case _ => "" }
13 | val trailingComment1 = P( "//" ~ AnyChar.rep ~ End ).map{ case _ => "" }
14 | val removeComments = P ( (comment1 | trailingComment1 | comment2 | AnyChar.!).rep ).map(_.mkString(""))
15 |
16 | @throws[ParseError]
17 | def parse[T](parser: P[T], text: String): T = {
18 | parser.parse(text) match {
19 | case failure: Parsed.Failure => throw ParseError(failure)
20 | case Parsed.Success(res, i) => {
21 | if (i == text.length()) {
22 | return res
23 | } else {
24 | val unexpected = StringUtils.abbreviate(text.substring(i), 20);
25 | throw new Exception("Unexpected text at index " + i + " \"" + unexpected + "\"");
26 | }
27 | }
28 | }
29 | }
30 |
31 | def removeComments(text: String): String = {
32 | return parse(removeComments, text);
33 | }
34 |
35 | @throws[ParseError]
36 | def parseBaggageBuffersFile(text: String): BaggageBuffersDeclaration = {
37 | val bbDecl = parse(bbDeclaration, removeComments(text))
38 | if (bbDecl.isEmpty) {
39 | throw new Exception("No BaggageBuffers declaration to parse")
40 | } else {
41 | return bbDecl
42 | }
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/bdl/core/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .settings
3 | .project
4 | bin
5 | target
6 | xtrace-data
7 | application.conf
--------------------------------------------------------------------------------
/bdl/core/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | brown.tracingplane
5 | bdl-core
6 | jar
7 |
8 | Baggage Definition Language - Core
9 |
10 |
11 | brown.tracingplane
12 | bdl
13 | 1.0
14 |
15 |
16 |
17 | ${basedir}/../..
18 |
19 |
20 |
21 |
22 | brown.tracingplane
23 | baggageprotocol-core
24 | ${project.version}
25 |
26 |
27 | junit
28 | junit
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/bdl/core/src/main/java/brown/tracingplane/bdl/BDLUtils.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.Set;
7 | import java.util.function.Function;
8 | import com.google.common.collect.Lists;
9 | import brown.tracingplane.atomlayer.StringUtils;
10 |
11 | public class BDLUtils {
12 |
13 | public static String toString(Set> set) {
14 | return set == null ? "{ }" : "{ " + StringUtils.join(set, ", ") + " }";
15 | }
16 |
17 | public static String toString(Map, V> map, Function valueToStringFunction) {
18 | if (map == null) {
19 | return "{ }";
20 | }
21 | List strings = new ArrayList<>();
22 | for (Object key : map.keySet()) {
23 | strings.add(String.valueOf(key) + " = " + map.get(key));
24 | }
25 | return formatChild(StringUtils.join(strings, "\n"));
26 | }
27 |
28 | public static String toString(Bag bag) {
29 | return bag == null ? "{ }" : formatChild(indent(bag.toString()));
30 | }
31 |
32 | public static String formatChild(String s) {
33 | return StringUtils.join(Lists.newArrayList("{", indent(s), "}"), "\n");
34 | }
35 |
36 | public static String indent(String s) {
37 | return s.replaceAll("(?m)^", " ");
38 | }
39 |
40 | /**
41 | * Equality comparison, using the provided default value if a or b are null
42 | * @param a an object instance, possibly null
43 | * @param b an object instance, possibly null
44 | * @param defaultValue the default value to use for a or b if they happen to be null
45 | * @return true if a and b are equal
46 | */
47 | public static boolean equals(T a, T b, T defaultValue) {
48 | if (a == null && b == null) {
49 | return true;
50 | } else if (a == null) {
51 | return b.equals(defaultValue);
52 | } else if (b == null) {
53 | return a.equals(defaultValue);
54 | } else {
55 | return a.equals(b);
56 | }
57 | }
58 |
59 | // This is a hack to add 'compaction' joins without deploying them to all the interfaces.
60 | // At this point in time it's still a question of whether compact joins are useful
61 | public static final ThreadLocal is_compaction = new ThreadLocal() {
62 | @Override public Boolean initialValue() {
63 | return false;
64 | }
65 | };
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/bdl/core/src/main/java/brown/tracingplane/bdl/Bag.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl;
2 |
3 | /**
4 | * The BDL compiler generates classes that implement this interface, Bag. They also generate BaggageHandler
5 | * implementations
6 | *
7 | * Bags are propagated by the Tracing Plane across all execution boundaries. They define semantics for branching,
8 | * joining, serializing, and trimming.
9 | */
10 | public interface Bag {
11 |
12 | BaggageHandler> handler();
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/bdl/core/src/main/java/brown/tracingplane/bdl/BaggageHandler.java:
--------------------------------------------------------------------------------
1 | package brown.tracingplane.bdl;
2 |
3 | import brown.tracingplane.baggageprotocol.BaggageWriter;
4 |
5 | /**
6 | *
7 | * Provides serialization, deserialization, branch, and merge logic for a bag type.
8 | *