Repository: incubator-htrace
Updated Branches:
  refs/heads/master 33f71ec71 -> a06159b27


http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-core/src/test/java/org/apache/htrace/TestSpanId.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/test/java/org/apache/htrace/TestSpanId.java 
b/htrace-core/src/test/java/org/apache/htrace/TestSpanId.java
new file mode 100644
index 0000000..10e6cca
--- /dev/null
+++ b/htrace-core/src/test/java/org/apache/htrace/TestSpanId.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.htrace;
+
+import java.util.Random;
+import org.apache.htrace.SpanId;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestSpanId {
+  private void testRoundTrip(SpanId id) throws Exception {
+    String str = id.toString();
+    SpanId id2 = SpanId.fromString(str);
+    Assert.assertEquals(id, id2);
+  }
+
+  @Test
+  public void testToStringAndFromString() throws Exception {
+    testRoundTrip(SpanId.INVALID);
+    testRoundTrip(new SpanId(0x1234567812345678L, 0x1234567812345678L));
+    testRoundTrip(new SpanId(0xf234567812345678L, 0xf234567812345678L));
+    testRoundTrip(new SpanId(0xffffffffffffffffL, 0xffffffffffffffffL));
+    Random rand = new Random(12345);
+    for (int i = 0; i < 100; i++) {
+      testRoundTrip(new SpanId(rand.nextLong(), rand.nextLong()));
+    }
+  }
+
+  @Test
+  public void testValidAndInvalidIds() throws Exception {
+    Assert.assertFalse(SpanId.INVALID.isValid());
+    Assert.assertTrue(
+        new SpanId(0x1234567812345678L, 0x1234567812345678L).isValid());
+    Assert.assertTrue(
+        new SpanId(0xf234567812345678L, 0xf234567812345678L).isValid());
+  }
+
+  private void expectLessThan(SpanId a, SpanId b) throws Exception {
+    int cmp = a.compareTo(b);
+    Assert.assertTrue("Expected " + a + " to be less than " + b,
+        (cmp < 0));
+    int cmp2 = b.compareTo(a);
+    Assert.assertTrue("Expected " + b + " to be greater than " + a,
+        (cmp2 > 0));
+  }
+
+  @Test
+  public void testIdComparisons() throws Exception {
+    expectLessThan(new SpanId(0x0000000000000001L, 0x0000000000000001L),
+                   new SpanId(0x0000000000000001L, 0x0000000000000002L));
+    expectLessThan(new SpanId(0x0000000000000001L, 0x0000000000000001L),
+                   new SpanId(0x0000000000000002L, 0x0000000000000000L));
+    expectLessThan(SpanId.INVALID,
+                   new SpanId(0xffffffffffffffffL, 0xffffffffffffffffL));
+    expectLessThan(new SpanId(0x1234567812345678L, 0x1234567812345678L),
+                   new SpanId(0x1234567812345678L, 0xf234567812345678L));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-core/src/test/java/org/apache/htrace/TraceGraph.java
----------------------------------------------------------------------
diff --git a/htrace-core/src/test/java/org/apache/htrace/TraceGraph.java 
b/htrace-core/src/test/java/org/apache/htrace/TraceGraph.java
new file mode 100644
index 0000000..9004ea6
--- /dev/null
+++ b/htrace-core/src/test/java/org/apache/htrace/TraceGraph.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.htrace;
+
+import org.apache.htrace.impl.MilliSpan;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * Used to create the graph formed by spans.
+ */
+public class TraceGraph {
+  private static final Log LOG = LogFactory.getLog(Tracer.class);
+
+
+  public static class SpansByParent {
+    /**
+     * Compare two spans by span ID.
+     */
+    private static Comparator<Span> COMPARATOR =
+        new Comparator<Span>() {
+          @Override
+          public int compare(Span a, Span b) {
+            return a.getSpanId().compareTo(b.getSpanId());
+          }
+        };
+
+    private final TreeSet<Span> treeSet;
+
+    private final HashMap<SpanId, LinkedList<Span>> parentToSpans;
+
+    SpansByParent(Collection<Span> spans) {
+      TreeSet<Span> treeSet = new TreeSet<Span>(COMPARATOR);
+      parentToSpans = new HashMap<SpanId, LinkedList<Span>>();
+      for (Span span : spans) {
+        treeSet.add(span);
+        for (SpanId parent : span.getParents()) {
+          LinkedList<Span> list = parentToSpans.get(parent);
+          if (list == null) {
+            list = new LinkedList<Span>();
+            parentToSpans.put(parent, list);
+          }
+          list.add(span);
+        }
+        if (span.getParents().length == 0) {
+          LinkedList<Span> list = parentToSpans.get(SpanId.INVALID);
+          if (list == null) {
+            list = new LinkedList<Span>();
+            parentToSpans.put(SpanId.INVALID, list);
+          }
+          list.add(span);
+        }
+      }
+      this.treeSet = treeSet;
+    }
+
+    public List<Span> find(SpanId parentId) {
+      LinkedList<Span> spans = parentToSpans.get(parentId);
+      if (spans == null) {
+        return new LinkedList<Span>();
+      }
+      return spans;
+    }
+
+    public Iterator<Span> iterator() {
+      return Collections.unmodifiableSortedSet(treeSet).iterator();
+    }
+  }
+
+  public static class SpansByTracerId {
+    /**
+     * Compare two spans by process ID, and then by span ID.
+     */
+    private static Comparator<Span> COMPARATOR =
+        new Comparator<Span>() {
+          @Override
+          public int compare(Span a, Span b) {
+            int cmp = a.getTracerId().compareTo(b.getTracerId());
+            if (cmp != 0) {
+              return cmp;
+            }
+            return a.getSpanId().compareTo(b.getSpanId());
+          }
+        };
+
+    private final TreeSet<Span> treeSet;
+
+    SpansByTracerId(Collection<Span> spans) {
+      TreeSet<Span> treeSet = new TreeSet<Span>(COMPARATOR);
+      for (Span span : spans) {
+        treeSet.add(span);
+      }
+      this.treeSet = treeSet;
+    }
+
+    public List<Span> find(String tracerId) {
+      List<Span> spans = new ArrayList<Span>();
+      Span span = new MilliSpan.Builder().
+                    spanId(SpanId.INVALID).
+                    tracerId(tracerId).
+                    build();
+      while (true) {
+        span = treeSet.higher(span);
+        if (span == null) {
+          break;
+        }
+        if (span.getTracerId().equals(tracerId)) {
+          break;
+        }
+        spans.add(span);
+      }
+      return spans;
+    }
+
+    public Iterator<Span> iterator() {
+      return Collections.unmodifiableSortedSet(treeSet).iterator();
+    }
+  }
+
+  private final SpansByParent spansByParent;
+  private final SpansByTracerId spansByTracerId;
+
+  /**
+   * Create a new TraceGraph
+   *
+   * @param spans The collection of spans to use to create this TraceGraph. 
Should
+   *              have at least one root span.
+   */
+  public TraceGraph(Collection<Span> spans) {
+    this.spansByParent = new SpansByParent(spans);
+    this.spansByTracerId = new SpansByTracerId(spans);
+  }
+
+  public SpansByParent getSpansByParent() {
+    return spansByParent;
+  }
+
+  public SpansByTracerId getSpansByTracerId() {
+    return spansByTracerId;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder bld = new StringBuilder();
+    String prefix = "";
+    for (Iterator<Span> iter = spansByParent.iterator(); iter.hasNext();) {
+      Span span = iter.next();
+      bld.append(prefix).append(span.toString());
+      prefix = "\n";
+    }
+    return bld.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-core/src/test/java/org/apache/htrace/impl/TestMilliSpan.java
----------------------------------------------------------------------
diff --git 
a/htrace-core/src/test/java/org/apache/htrace/impl/TestMilliSpan.java 
b/htrace-core/src/test/java/org/apache/htrace/impl/TestMilliSpan.java
index 74ee562..9a0be4a 100644
--- a/htrace-core/src/test/java/org/apache/htrace/impl/TestMilliSpan.java
+++ b/htrace-core/src/test/java/org/apache/htrace/impl/TestMilliSpan.java
@@ -20,10 +20,10 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import org.apache.htrace.Span;
+import org.apache.htrace.SpanId;
 import org.apache.htrace.TimelineAnnotation;
 import org.junit.Test;
 
-import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -31,13 +31,13 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 public class TestMilliSpan {
   private void compareSpans(Span expected, Span got) throws Exception {
     assertEquals(expected.getStartTimeMillis(), got.getStartTimeMillis());
     assertEquals(expected.getStopTimeMillis(), got.getStopTimeMillis());
     assertEquals(expected.getDescription(), got.getDescription());
-    assertEquals(expected.getTraceId(), got.getTraceId());
     assertEquals(expected.getSpanId(), got.getSpanId());
     assertEquals(expected.getTracerId(), got.getTracerId());
     assertTrue(Arrays.equals(expected.getParents(), got.getParents()));
@@ -74,10 +74,10 @@ public class TestMilliSpan {
         description("foospan").
         begin(123L).
         end(456L).
-        parents(new long[] { 7L }).
+        parents(new SpanId[] { new SpanId(7L, 7L) }).
         tracerId("b2404.halxg.com:8080").
-        spanId(989L).
-        traceId(444).build();
+        spanId(new SpanId(7L, 8L)).
+        build();
     String json = span.toJson();
     MilliSpan dspan = MilliSpan.fromJson(json);
     compareSpans(span, dspan);
@@ -89,10 +89,10 @@ public class TestMilliSpan {
         description("foospan").
         begin(-1L).
         end(-1L).
-        parents(new long[] { -1L }).
+        parents(new SpanId[] { new SpanId(-1L, -1L) }).
         tracerId("b2404.halxg.com:8080").
-        spanId(-1L).
-        traceId(-1L).build();
+        spanId(new SpanId(-1L, -2L)).
+        build();
     String json = span.toJson();
     MilliSpan dspan = MilliSpan.fromJson(json);
     compareSpans(span, dspan);
@@ -100,15 +100,15 @@ public class TestMilliSpan {
 
   @Test
   public void testJsonSerializationWithRandomLongValue() throws Exception {
-    Random random = new SecureRandom();
+    SpanId parentId = SpanId.fromRandom();
     MilliSpan span = new MilliSpan.Builder().
         description("foospan").
-        begin(random.nextLong()).
-        end(random.nextLong()).
-        parents(new long[] { random.nextLong() }).
+        begin(ThreadLocalRandom.current().nextLong()).
+        end(ThreadLocalRandom.current().nextLong()).
+        parents(new SpanId[] { parentId }).
         tracerId("b2404.halxg.com:8080").
-        spanId(random.nextLong()).
-        traceId(random.nextLong()).build();
+        spanId(parentId.newChildId()).
+        build();
     String json = span.toJson();
     MilliSpan dspan = MilliSpan.fromJson(json);
     compareSpans(span, dspan);
@@ -120,10 +120,9 @@ public class TestMilliSpan {
         description("foospan").
         begin(300).
         end(400).
-        parents(new long[] { }).
+        parents(new SpanId[] { }).
         tracerId("b2408.halxg.com:8080").
-        spanId(111111111L).
-        traceId(4443);
+        spanId(new SpanId(111111111L, 111111111L));
     Map<String, String> traceInfo = new HashMap<String, String>();
     traceInfo.put("abc", "123");
     traceInfo.put("def", "456");

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-flume/src/main/java/org/apache/htrace/impl/FlumeSpanReceiver.java
----------------------------------------------------------------------
diff --git 
a/htrace-flume/src/main/java/org/apache/htrace/impl/FlumeSpanReceiver.java 
b/htrace-flume/src/main/java/org/apache/htrace/impl/FlumeSpanReceiver.java
index a1352ab..f930c02 100644
--- a/htrace-flume/src/main/java/org/apache/htrace/impl/FlumeSpanReceiver.java
+++ b/htrace-flume/src/main/java/org/apache/htrace/impl/FlumeSpanReceiver.java
@@ -173,9 +173,8 @@ public class FlumeSpanReceiver implements SpanReceiver {
           for (Span span : dequeuedSpans) {
             // Headers allow Flume to filter
             Map<String, String> headers = new HashMap<String, String>();
-            headers.put("TraceId",      Long.toString(span.getTraceId()));
-            headers.put("SpanId",       Long.toString(span.getSpanId()));
-            headers.put("TracerId",    span.getTracerId());
+            headers.put("SpanId",       span.toString());
+            headers.put("TracerId",     span.getTracerId());
             headers.put("Description",  span.getDescription());
 
             String body = span.toJson();

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-flume/src/test/java/org/apache/htrace/impl/TestFlumeSpanReceiver.java
----------------------------------------------------------------------
diff --git 
a/htrace-flume/src/test/java/org/apache/htrace/impl/TestFlumeSpanReceiver.java 
b/htrace-flume/src/test/java/org/apache/htrace/impl/TestFlumeSpanReceiver.java
index 6743c85..d144b62 100644
--- 
a/htrace-flume/src/test/java/org/apache/htrace/impl/TestFlumeSpanReceiver.java
+++ 
b/htrace-flume/src/test/java/org/apache/htrace/impl/TestFlumeSpanReceiver.java
@@ -19,6 +19,7 @@ package org.apache.htrace.impl;
 
 import org.apache.htrace.HTraceConfiguration;
 import org.apache.htrace.Span;
+import org.apache.htrace.SpanId;
 import org.apache.htrace.TraceCreator;
 import org.junit.Assert;
 import org.junit.Rule;
@@ -42,8 +43,7 @@ public class TestFlumeSpanReceiver {
 
     Span rootSpan = new MilliSpan.Builder().
         description("root").
-        traceId(1).
-        spanId(100).
+        spanId(new SpanId(100, 100)).
         tracerId("test").
         begin(System.currentTimeMillis()).
         build();

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-hbase/src/main/java/org/apache/htrace/impl/HBaseSpanReceiver.java
----------------------------------------------------------------------
diff --git 
a/htrace-hbase/src/main/java/org/apache/htrace/impl/HBaseSpanReceiver.java 
b/htrace-hbase/src/main/java/org/apache/htrace/impl/HBaseSpanReceiver.java
index beb96b5..381010f 100644
--- a/htrace-hbase/src/main/java/org/apache/htrace/impl/HBaseSpanReceiver.java
+++ b/htrace-hbase/src/main/java/org/apache/htrace/impl/HBaseSpanReceiver.java
@@ -208,17 +208,17 @@ public class HBaseSpanReceiver implements SpanReceiver {
         try {
           for (Span span : dequeuedSpans) {
             sbuilder.clear()
-                    .setTraceId(span.getTraceId())
+                    .setTraceId(span.getSpanId().getHigh())
                     .setStart(span.getStartTimeMillis())
                     .setStop(span.getStopTimeMillis())
-                    .setSpanId(span.getSpanId())
+                    .setSpanId(span.getSpanId().getLow())
                     .setProcessId(span.getTracerId())
                     .setDescription(span.getDescription());
 
             if (span.getParents().length == 0) {
               sbuilder.setParentId(0);
             } else if (span.getParents().length > 0) {
-              sbuilder.setParentId(span.getParents()[0]);
+              sbuilder.setParentId(span.getParents()[0].getLow());
               if (span.getParents().length > 1) {
                 LOG.error("error: HBaseSpanReceiver does not support spans " +
                     "with multiple parents.  Ignoring multiple parents for " +
@@ -231,7 +231,7 @@ public class HBaseSpanReceiver implements SpanReceiver {
                                             .setMessage(ta.getMessage())
                                             .build());
             }
-            Put put = new Put(Bytes.toBytes(span.getTraceId()));
+            Put put = new Put(Bytes.toBytes(span.getSpanId().getHigh()));
             put.add(HBaseSpanReceiver.this.cf,
                     sbuilder.build().toByteArray(),
                     null);
@@ -360,7 +360,7 @@ public class HBaseSpanReceiver implements SpanReceiver {
     Trace.addReceiver(receiver);
     TraceScope parent = Trace.startSpan("HBaseSpanReceiver.main.parent", 
Sampler.ALWAYS);
     Thread.sleep(10);
-    long traceid = parent.getSpan().getTraceId();
+    long traceid = parent.getSpan().getSpanId().getHigh();
     TraceScope child1 = Trace.startSpan("HBaseSpanReceiver.main.child.1");
     Thread.sleep(10);
     TraceScope child2 = Trace.startSpan("HBaseSpanReceiver.main.child.2", 
parent.getSpan());

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-hbase/src/test/java/org/apache/htrace/impl/TestHBaseSpanReceiver.java
----------------------------------------------------------------------
diff --git 
a/htrace-hbase/src/test/java/org/apache/htrace/impl/TestHBaseSpanReceiver.java 
b/htrace-hbase/src/test/java/org/apache/htrace/impl/TestHBaseSpanReceiver.java
index 5027891..2224599 100644
--- 
a/htrace-hbase/src/test/java/org/apache/htrace/impl/TestHBaseSpanReceiver.java
+++ 
b/htrace-hbase/src/test/java/org/apache/htrace/impl/TestHBaseSpanReceiver.java
@@ -38,11 +38,12 @@ import org.apache.hadoop.hbase.client.ResultScanner;
 import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.htrace.Span;
+import org.apache.htrace.SpanId;
 import org.apache.htrace.SpanReceiver;
 import org.apache.htrace.TimelineAnnotation;
 import org.apache.htrace.TraceCreator;
-import org.apache.htrace.TraceTree.SpansByParent;
-import org.apache.htrace.TraceTree;
+import org.apache.htrace.TraceGraph.SpansByParent;
+import org.apache.htrace.TraceGraph;
 import org.apache.htrace.protobuf.generated.SpanProtos;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -93,9 +94,9 @@ public class TestHBaseSpanReceiver {
       Assert.fail("failed to get spans from HBase. " + e.getMessage());
     }
 
-    TraceTree traceTree = new TraceTree(spans);
+    TraceGraph traceGraph = new TraceGraph(spans);
     Collection<Span> roots =
-        traceTree.getSpansByParent().find(0);
+        traceGraph.getSpansByParent().find(SpanId.INVALID);
     Assert.assertTrue("Trace tree must have roots", !roots.isEmpty());
     Assert.assertEquals(3, roots.size());
 
@@ -107,7 +108,7 @@ public class TestHBaseSpanReceiver {
     Assert.assertTrue(descs.keySet().contains(TraceCreator.SIMPLE_TRACE_ROOT));
     
Assert.assertTrue(descs.keySet().contains(TraceCreator.THREADED_TRACE_ROOT));
 
-    SpansByParent spansByParentId = traceTree.getSpansByParent();
+    SpansByParent spansByParentId = traceGraph.getSpansByParent();
     Span rpcRoot = descs.get(TraceCreator.RPC_TRACE_ROOT);
     Assert.assertEquals(1, spansByParentId.find(rpcRoot.getSpanId()).size());
     Span rpcChild1 = 
spansByParentId.find(rpcRoot.getSpanId()).iterator().next();
@@ -144,19 +145,14 @@ public class TestHBaseSpanReceiver {
     }
 
     @Override
-    public long getTraceId() {
-      return span.getTraceId();
-    }
-
-    @Override
-    public long[] getParents() {
+    public SpanId[] getParents() {
       return (span.getParentId() == 0L) ?
-        (new long[] {}) :
-        (new long[] { span.getParentId() });
+        (new SpanId[] {}) :
+        (new SpanId[] { new SpanId(span.getTraceId(), span.getParentId()) });
     }
 
     @Override
-    public void setParents(long[] parents) {
+    public void setParents(SpanId[] parents) {
       throw new UnsupportedOperationException();
     }
 
@@ -171,8 +167,8 @@ public class TestHBaseSpanReceiver {
     }
 
     @Override
-    public long getSpanId() {
-      return span.getSpanId();
+    public SpanId getSpanId() {
+      return new SpanId(span.getTraceId(), span.getSpanId());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/client/client.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/client/client.go 
b/htrace-htraced/go/src/org/apache/htrace/client/client.go
index ef827e8..5051d94 100644
--- a/htrace-htraced/go/src/org/apache/htrace/client/client.go
+++ b/htrace-htraced/go/src/org/apache/htrace/client/client.go
@@ -69,7 +69,7 @@ func (hcl *Client) GetServerInfo() (*common.ServerInfo, 
error) {
 
 // Get information about a trace span.  Returns nil, nil if the span was not 
found.
 func (hcl *Client) FindSpan(sid common.SpanId) (*common.Span, error) {
-       buf, rc, err := hcl.makeGetRequest(fmt.Sprintf("span/%016x", 
uint64(sid)))
+       buf, rc, err := hcl.makeGetRequest(fmt.Sprintf("span/%s", sid.String()))
        if err != nil {
                if rc == http.StatusNoContent {
                        return nil, nil
@@ -133,8 +133,8 @@ func (hcl *Client) writeSpansHttp(req 
*common.WriteSpansReq) error {
 
 // Find the child IDs of a given span ID.
 func (hcl *Client) FindChildren(sid common.SpanId, lim int) ([]common.SpanId, 
error) {
-       buf, _, err := 
hcl.makeGetRequest(fmt.Sprintf("span/%016x/children?lim=%d",
-               uint64(sid), lim))
+       buf, _, err := hcl.makeGetRequest(fmt.Sprintf("span/%s/children?lim=%d",
+               sid.String(), lim))
        if err != nil {
                return nil, err
        }
@@ -209,7 +209,7 @@ func (hcl *Client) DumpAll(lim int, out chan *common.Span) 
error {
        defer func() {
                close(out)
        }()
-       searchId := common.SpanId(0)
+       searchId := common.INVALID_SPAN_ID
        for {
                q := common.Query{
                        Lim: lim,
@@ -232,7 +232,7 @@ func (hcl *Client) DumpAll(lim int, out chan *common.Span) 
error {
                for i := range spans {
                        out <- &spans[i]
                }
-               searchId = spans[len(spans)-1].Id + 1
+               searchId = spans[len(spans)-1].Id.Next()
        }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/common/span.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/common/span.go 
b/htrace-htraced/go/src/org/apache/htrace/common/span.go
index 720c4cd..1716c5a 100644
--- a/htrace-htraced/go/src/org/apache/htrace/common/span.go
+++ b/htrace-htraced/go/src/org/apache/htrace/common/span.go
@@ -20,10 +20,11 @@
 package common
 
 import (
+       "bytes"
        "encoding/json"
        "errors"
        "fmt"
-       "strconv"
+       "hash/fnv"
 )
 
 //
@@ -43,18 +44,88 @@ type TimelineAnnotation struct {
        Msg  string `json:"m"`
 }
 
-type SpanId uint64
+type SpanId []byte
+
+var INVALID_SPAN_ID SpanId = make([]byte, 16) // all zeroes
 
 func (id SpanId) String() string {
-       return fmt.Sprintf("%016x", uint64(id))
+       return fmt.Sprintf("%02x%02x%02x%02x"+
+               "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+               id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8],
+               id[9], id[10], id[11], id[12], id[13], id[14], id[15])
+}
+
+func (id SpanId) Val() []byte {
+       return []byte(id)
 }
 
-func (id SpanId) Val() uint64 {
-       return uint64(id)
+func (id SpanId) FindProblem() string {
+       if id == nil {
+               return "The span ID is nil"
+       }
+       if len(id) != 16 {
+               return "The span ID is not exactly 16 bytes."
+       }
+       if bytes.Equal(id.Val(), INVALID_SPAN_ID.Val()) {
+               return "The span ID is all zeros."
+       }
+       return ""
+}
+
+func (id SpanId) ToArray() [16]byte {
+       var ret [16]byte
+       copy(ret[:], id.Val()[:])
+       return ret
+}
+
+// Return the next ID in lexicographical order.  For the maximum ID,
+// returns the minimum.
+func (id SpanId) Next() SpanId {
+       next := make([]byte, 16)
+       copy(next, id)
+       for i := len(next) - 1; i >= 0; i-- {
+               if next[i] == 0xff {
+                       next[i] = 0
+               } else {
+                       next[i] = next[i] + 1
+                       break
+               }
+       }
+       return next
+}
+
+// Return the previous ID in lexicographical order.  For the minimum ID,
+// returns the maximum ID.
+func (id SpanId) Prev() SpanId {
+       prev := make([]byte, 16)
+       copy(prev, id)
+       for i := len(prev) - 1; i >= 0; i-- {
+               if prev[i] == 0x00 {
+                       prev[i] = 0xff
+               } else {
+                       prev[i] = prev[i] - 1
+                       break
+               }
+       }
+       return prev
 }
 
 func (id SpanId) MarshalJSON() ([]byte, error) {
-       return []byte(`"` + fmt.Sprintf("%016x", uint64(id)) + `"`), nil
+       return []byte(`"` + id.String() + `"`), nil
+}
+
+func (id SpanId) Compare(other SpanId) int {
+       return bytes.Compare(id.Val(), other.Val())
+}
+
+func (id SpanId) Equal(other SpanId) bool {
+       return bytes.Equal(id.Val(), other.Val())
+}
+
+func (id SpanId) Hash32() uint32 {
+       h := fnv.New32a()
+       h.Write(id.Val())
+       return h.Sum32()
 }
 
 type SpanSlice []*Span
@@ -64,7 +135,7 @@ func (s SpanSlice) Len() int {
 }
 
 func (s SpanSlice) Less(i, j int) bool {
-       return s[i].Id < s[j].Id
+       return s[i].Id.Compare(s[j].Id) < 0
 }
 
 func (s SpanSlice) Swap(i, j int) {
@@ -78,7 +149,7 @@ func (s SpanIdSlice) Len() int {
 }
 
 func (s SpanIdSlice) Less(i, j int) bool {
-       return s[i] < s[j]
+       return s[i].Compare(s[j]) < 0
 }
 
 func (s SpanIdSlice) Swap(i, j int) {
@@ -98,11 +169,18 @@ func (id *SpanId) UnmarshalJSON(b []byte) error {
 }
 
 func (id *SpanId) FromString(str string) error {
-       v, err := strconv.ParseUint(str, 16, 64)
+       i := SpanId(make([]byte, 16))
+       n, err := fmt.Sscanf(str, "%02x%02x%02x%02x"+
+               "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+               &i[0], &i[1], &i[2], &i[3], &i[4], &i[5], &i[6], &i[7], &i[8],
+               &i[9], &i[10], &i[11], &i[12], &i[13], &i[14], &i[15])
        if err != nil {
                return err
        }
-       *id = SpanId(v)
+       if n != 16 {
+               return errors.New("Failed to find 16 hex digits in the SpanId")
+       }
+       *id = i
        return nil
 }
 
@@ -110,7 +188,6 @@ type SpanData struct {
        Begin               int64                `json:"b"`
        End                 int64                `json:"e"`
        Description         string               `json:"d"`
-       TraceId             SpanId               `json:"i"`
        Parents             []SpanId             `json:"p"`
        Info                TraceInfoMap         `json:"n,omitempty"`
        TracerId            string               `json:"r"`
@@ -118,7 +195,7 @@ type SpanData struct {
 }
 
 type Span struct {
-       Id SpanId `json:"s"`
+       Id SpanId `json:"a"`
        SpanData
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/common/span_test.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/common/span_test.go 
b/htrace-htraced/go/src/org/apache/htrace/common/span_test.go
index e3b44fe..9de7cee 100644
--- a/htrace-htraced/go/src/org/apache/htrace/common/span_test.go
+++ b/htrace-htraced/go/src/org/apache/htrace/common/span_test.go
@@ -20,33 +20,35 @@
 package common
 
 import (
+       "bytes"
+       "encoding/hex"
+       "fmt"
+       "github.com/ugorji/go/codec"
        "testing"
 )
 
 func TestSpanToJson(t *testing.T) {
        t.Parallel()
-       span := Span{Id: 2305843009213693952,
+       span := Span{Id: TestId("33f25a1a750a471db5bafa59309d7d6f"),
                SpanData: SpanData{
                        Begin:       123,
                        End:         456,
                        Description: "getFileDescriptors",
-                       TraceId:     999,
                        Parents:     []SpanId{},
                        TracerId:    "testTracerId",
                }}
        ExpectStrEqual(t,
-               
`{"s":"2000000000000000","b":123,"e":456,"d":"getFileDescriptors","i":"00000000000003e7","p":[],"r":"testTracerId"}`,
+               
`{"a":"33f25a1a750a471db5bafa59309d7d6f","b":123,"e":456,"d":"getFileDescriptors","p":[],"r":"testTracerId"}`,
                string(span.ToJson()))
 }
 
 func TestAnnotatedSpanToJson(t *testing.T) {
        t.Parallel()
-       span := Span{Id: 1305813009213693952,
+       span := Span{Id: TestId("11eace42e6404b40a7644214cb779a08"),
                SpanData: SpanData{
                        Begin:       1234,
                        End:         4567,
                        Description: "getFileDescriptors2",
-                       TraceId:     999,
                        Parents:     []SpanId{},
                        TracerId:    "testAnnotatedTracerId",
                        TimelineAnnotations: []TimelineAnnotation{
@@ -61,6 +63,54 @@ func TestAnnotatedSpanToJson(t *testing.T) {
                        },
                }}
        ExpectStrEqual(t,
-               
`{"s":"121f2e036d442000","b":1234,"e":4567,"d":"getFileDescriptors2","i":"00000000000003e7","p":[],"r":"testAnnotatedTracerId","t":[{"t":7777,"m":"contactedServer"},{"t":8888,"m":"passedFd"}]}`,
+               
`{"a":"11eace42e6404b40a7644214cb779a08","b":1234,"e":4567,"d":"getFileDescriptors2","p":[],"r":"testAnnotatedTracerId","t":[{"t":7777,"m":"contactedServer"},{"t":8888,"m":"passedFd"}]}`,
                string(span.ToJson()))
 }
+
+func TestSpanNext(t *testing.T) {
+       ExpectStrEqual(t, TestId("00000000000000000000000000000001").String(),
+               TestId("00000000000000000000000000000000").Next().String())
+       ExpectStrEqual(t, TestId("00000000000000000000000000f00000").String(),
+               TestId("00000000000000000000000000efffff").Next().String())
+       ExpectStrEqual(t, TestId("00000000000000000000000000000000").String(),
+               TestId("ffffffffffffffffffffffffffffffff").Next().String())
+}
+
+func TestSpanPrev(t *testing.T) {
+       ExpectStrEqual(t, TestId("00000000000000000000000000000000").String(),
+               TestId("00000000000000000000000000000001").Prev().String())
+       ExpectStrEqual(t, TestId("00000000000000000000000000efffff").String(),
+               TestId("00000000000000000000000000f00000").Prev().String())
+       ExpectStrEqual(t, TestId("ffffffffffffffffffffffffffffffff").String(),
+               TestId("00000000000000000000000000000000").Prev().String())
+}
+
+func TestSpanMsgPack(t *testing.T) {
+       span := Span{Id: TestId("33f25a1a750a471db5bafa59309d7d6f"),
+               SpanData: SpanData{
+                       Begin:       1234,
+                       End:         5678,
+                       Description: "getFileDescriptors",
+                       Parents:     []SpanId{},
+                       TracerId:   "testTracerId",
+               }}
+       mh := new(codec.MsgpackHandle)
+       mh.WriteExt = true
+       w := bytes.NewBuffer(make([]byte, 0, 2048))
+       enc := codec.NewEncoder(w, mh)
+       err := enc.Encode(span)
+       if err != nil {
+               t.Fatal("Error encoding span as msgpack: " + err.Error())
+       }
+       buf := w.Bytes()
+       fmt.Printf("span: %s\n", hex.EncodeToString(buf))
+       mh = new(codec.MsgpackHandle)
+       mh.WriteExt = true
+       dec := codec.NewDecoder(bytes.NewReader(buf), mh)
+       var span2 Span
+       err = dec.Decode(&span2)
+       if err != nil {
+               t.Fatal("Failed to reverse msgpack encoding for " + 
span.String())
+       }
+       ExpectSpansEqual(t, &span, &span2)
+}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/common/test_util.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/common/test_util.go 
b/htrace-htraced/go/src/org/apache/htrace/common/test_util.go
index 871c847..ec9151b 100644
--- a/htrace-htraced/go/src/org/apache/htrace/common/test_util.go
+++ b/htrace-htraced/go/src/org/apache/htrace/common/test_util.go
@@ -72,3 +72,12 @@ func ExpectStrEqual(t *testing.T, expect string, actual 
string) {
 func ExpectSpansEqual(t *testing.T, spanA *Span, spanB *Span) {
        ExpectStrEqual(t, string(spanA.ToJson()), string(spanB.ToJson()))
 }
+
+func TestId(str string) SpanId {
+       var spanId SpanId
+       err := spanId.FromString(str)
+       if err != nil {
+               panic(err.Error())
+       }
+       return spanId
+}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go 
b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
index 38cdb58..8fd7067 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
@@ -63,10 +63,10 @@ func main() {
        version := app.Command("version", "Print the version of this program.")
        serverInfo := app.Command("serverInfo", "Print information retrieved 
from an htraced server.")
        findSpan := app.Command("findSpan", "Print information about a trace 
span with a given ID.")
-       findSpanId := findSpan.Arg("id", "Span ID to find. Example: 
0x123456789abcdef").Required().Uint64()
+       findSpanId := findSpan.Arg("id", "Span ID to find. Example: 
be305e54-4534-2110-a0b2-e06b9effe112").Required().String()
        findChildren := app.Command("findChildren", "Print out the span IDs 
that are children of a given span ID.")
-       parentSpanId := findChildren.Arg("id", "Span ID to print children for. 
Example: 0x123456789abcdef").
-               Required().Uint64()
+       parentSpanId := findChildren.Arg("id", "Span ID to print children for. 
Example: be305e54-4534-2110-a0b2-e06b9effe112").
+               Required().String()
        childLim := findChildren.Flag("lim", "Maximum number of child IDs to 
print.").Default("20").Int()
        loadFile := app.Command("loadFile", "Write whitespace-separated JSON 
spans from a file to the server.")
        loadFilePath := loadFile.Arg("path",
@@ -123,9 +123,13 @@ func main() {
        case serverInfo.FullCommand():
                os.Exit(printServerInfo(hcl))
        case findSpan.FullCommand():
-               os.Exit(doFindSpan(hcl, common.SpanId(*findSpanId)))
+               var id *common.SpanId
+               id.FromString(*findSpanId)
+               os.Exit(doFindSpan(hcl, *id))
        case findChildren.FullCommand():
-               os.Exit(doFindChildren(hcl, common.SpanId(*parentSpanId), 
*childLim))
+               var id *common.SpanId
+               id.FromString(*parentSpanId)
+               os.Exit(doFindChildren(hcl, *id, *childLim))
        case loadJson.FullCommand():
                os.Exit(doLoadSpanJson(hcl, *loadJsonArg))
        case loadFile.FullCommand():

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htrace/file_test.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/file_test.go 
b/htrace-htraced/go/src/org/apache/htrace/htrace/file_test.go
index 6fd6789..98e5e6c 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htrace/file_test.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htrace/file_test.go
@@ -25,7 +25,6 @@ import (
        "io/ioutil"
        "org/apache/htrace/common"
        "org/apache/htrace/conf"
-       "org/apache/htrace/test"
        "os"
        "strings"
        "testing"
@@ -116,10 +115,10 @@ func TestFailureDeferringWriter(t *testing.T) {
 }
 
 func TestReadSpans(t *testing.T) {
-       SPAN_TEST_STR := `{"i":"bdd6d4ee48de59bf","s":"c0681027d3ea4928",` +
+       SPAN_TEST_STR := `{"a":"b9f2a1e07b6e4f16b0c2b27303b20e79",` +
                
`"b":1424736225037,"e":1424736225901,"d":"ClientNamenodeProtocol#getFileInfo",` 
+
-               `"r":"FsShell","p":["60538dfb4df91418"]}
-{"i":"bdd6d4ee48de59bf","s":"60538dfb4df91418","b":1424736224969,` +
+               `"r":"FsShell","p":["3afebdc0a13f4feb811cc5c0e42d30b1"]}
+{"a":"3afebdc0a13f4feb811cc5c0e42d30b1","b":1424736224969,` +
                
`"e":1424736225960,"d":"getFileInfo","r":"FsShell","p":[],"n":{"path":"/"}}
 `
        r := strings.NewReader(SPAN_TEST_STR)
@@ -129,20 +128,18 @@ func TestReadSpans(t *testing.T) {
        }
        SPAN_TEST_EXPECTED := common.SpanSlice{
                &common.Span{
-                       Id: test.SpanId("c0681027d3ea4928"),
+                       Id: common.TestId("b9f2a1e07b6e4f16b0c2b27303b20e79"),
                        SpanData: common.SpanData{
-                               TraceId:     test.SpanId("bdd6d4ee48de59bf"),
                                Begin:       1424736225037,
                                End:         1424736225901,
                                Description: 
"ClientNamenodeProtocol#getFileInfo",
                                TracerId:    "FsShell",
-                               Parents:     
[]common.SpanId{test.SpanId("60538dfb4df91418")},
+                               Parents:     
[]common.SpanId{common.TestId("3afebdc0a13f4feb811cc5c0e42d30b1")},
                        },
                },
                &common.Span{
-                       Id: test.SpanId("60538dfb4df91418"),
+                       Id: common.TestId("3afebdc0a13f4feb811cc5c0e42d30b1"),
                        SpanData: common.SpanData{
-                               TraceId:     test.SpanId("bdd6d4ee48de59bf"),
                                Begin:       1424736224969,
                                End:         1424736225960,
                                Description: "getFileInfo",

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htrace/graph.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/graph.go 
b/htrace-htraced/go/src/org/apache/htrace/htrace/graph.go
index dabf2df..024d973 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htrace/graph.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htrace/graph.go
@@ -64,32 +64,32 @@ func jsonSpanFileToDotFile(jsonFile string, dotFile string) 
error {
 // Create output in dotfile format from a set of spans.
 func spansToDot(spans common.SpanSlice, writer io.Writer) error {
        sort.Sort(spans)
-       idMap := make(map[common.SpanId]*common.Span)
+       idMap := make(map[[16]byte]*common.Span)
        for i := range spans {
                span := spans[i]
-               if idMap[span.Id] != nil {
+               if idMap[span.Id.ToArray()] != nil {
                        fmt.Fprintf(os.Stderr, "There were multiple spans 
listed which "+
                                "had ID %s.\nFirst:%s\nOther:%s\n", 
span.Id.String(),
-                               idMap[span.Id].ToJson(), span.ToJson())
+                               idMap[span.Id.ToArray()].ToJson(), 
span.ToJson())
                } else {
-                       idMap[span.Id] = span
+                       idMap[span.Id.ToArray()] = span
                }
        }
-       childMap := make(map[common.SpanId]common.SpanSlice)
+       childMap := make(map[[16]byte]common.SpanSlice)
        for i := range spans {
                child := spans[i]
                for j := range child.Parents {
-                       parent := idMap[child.Parents[j]]
+                       parent := idMap[child.Parents[j].ToArray()]
                        if parent == nil {
                                fmt.Fprintf(os.Stderr, "Can't find parent id %s 
for %s\n",
                                        child.Parents[j].String(), 
child.ToJson())
                        } else {
-                               children := childMap[parent.Id]
+                               children := childMap[parent.Id.ToArray()]
                                if children == nil {
                                        children = make(common.SpanSlice, 0)
                                }
                                children = append(children, child)
-                               childMap[parent.Id] = children
+                               childMap[parent.Id.ToArray()] = children
                        }
                }
        }
@@ -102,7 +102,7 @@ func spansToDot(spans common.SpanSlice, writer io.Writer) 
error {
        }
        // Write out the edges between nodes... the parent/children 
relationships
        for i := range spans {
-               children := childMap[spans[i].Id]
+               children := childMap[spans[i].Id.ToArray()]
                sort.Sort(children)
                if children != nil {
                        for c := range children {

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htrace/graph_test.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/graph_test.go 
b/htrace-htraced/go/src/org/apache/htrace/htrace/graph_test.go
index e614cec..621b3dc 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htrace/graph_test.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htrace/graph_test.go
@@ -22,16 +22,14 @@ package main
 import (
        "bytes"
        "org/apache/htrace/common"
-       "org/apache/htrace/test"
        "testing"
 )
 
 func TestSpansToDot(t *testing.T) {
        TEST_SPANS := common.SpanSlice{
                &common.Span{
-                       Id: test.SpanId("6af3cc058e5d829d"),
+                       Id: common.TestId("814c8ee0e7984be3a8af00ac64adccb6"),
                        SpanData: common.SpanData{
-                               TraceId:     test.SpanId("0e4716fe911244de"),
                                Begin:       1424813349020,
                                End:         1424813349134,
                                Description: "newDFSInputStream",
@@ -43,25 +41,23 @@ func TestSpansToDot(t *testing.T) {
                        },
                },
                &common.Span{
-                       Id: test.SpanId("75d16cc5b2c07d8a"),
+                       Id: common.TestId("cf2d5de696454548bc055d1e6024054c"),
                        SpanData: common.SpanData{
-                               TraceId:     test.SpanId("0e4716fe911244de"),
                                Begin:       1424813349025,
                                End:         1424813349133,
                                Description: "getBlockLocations",
                                TracerId:    "FsShell",
-                               Parents:     
[]common.SpanId{test.SpanId("6af3cc058e5d829d")},
+                               Parents:     
[]common.SpanId{common.TestId("814c8ee0e7984be3a8af00ac64adccb6")},
                        },
                },
                &common.Span{
-                       Id: test.SpanId("e2c7273efb280a8c"),
+                       Id: common.TestId("37623806f9c64483b834b8ea5d6b4827"),
                        SpanData: common.SpanData{
-                               TraceId:     test.SpanId("0e4716fe911244de"),
                                Begin:       1424813349027,
                                End:         1424813349073,
                                Description: 
"ClientNamenodeProtocol#getBlockLocations",
                                TracerId:    "FsShell",
-                               Parents:     
[]common.SpanId{test.SpanId("75d16cc5b2c07d8a")},
+                               Parents:     
[]common.SpanId{common.TestId("cf2d5de696454548bc055d1e6024054c")},
                        },
                },
        }
@@ -71,11 +67,11 @@ func TestSpansToDot(t *testing.T) {
                t.Fatalf("spansToDot failed: error %s\n", err.Error())
        }
        EXPECTED_STR := `digraph spans {
-  "6af3cc058e5d829d" [label="newDFSInputStream"];
-  "75d16cc5b2c07d8a" [label="getBlockLocations"];
-  "e2c7273efb280a8c" [label="ClientNamenodeProtocol#getBlockLocations"];
-  "6af3cc058e5d829d" -> "75d16cc5b2c07d8a";
-  "75d16cc5b2c07d8a" -> "e2c7273efb280a8c";
+  "37623806f9c64483b834b8ea5d6b4827" 
[label="ClientNamenodeProtocol#getBlockLocations"];
+  "814c8ee0e7984be3a8af00ac64adccb6" [label="newDFSInputStream"];
+  "cf2d5de696454548bc055d1e6024054c" [label="getBlockLocations"];
+  "814c8ee0e7984be3a8af00ac64adccb6" -> "cf2d5de696454548bc055d1e6024054c";
+  "cf2d5de696454548bc055d1e6024054c" -> "37623806f9c64483b834b8ea5d6b4827";
 }
 `
        if w.String() != EXPECTED_STR {

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
index 218c1c8..02a00f3 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
@@ -121,7 +121,7 @@ func TestClientOperations(t *testing.T) {
                t.Fatalf("FindChildren(%s) returned an invalid number of "+
                        "children: expected %d, got %d\n", parentId, 1, 
len(children))
        }
-       if children[0] != childSpan.Id {
+       if !children[0].Equal(childSpan.Id) {
                t.Fatalf("FindChildren(%s) returned an invalid child id: 
expected %s, "+
                        " got %s\n", parentId, childSpan.Id, children[0])
        }

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
index 48f02aa..5885168 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
@@ -22,6 +22,7 @@ package main
 import (
        "bytes"
        "encoding/gob"
+       "encoding/hex"
        "errors"
        "fmt"
        "github.com/jmhodges/levigo"
@@ -68,6 +69,7 @@ const CURRENT_LAYOUT_VERSION = 2
 var EMPTY_BYTE_BUF []byte = []byte{}
 
 const VERSION_KEY = 'v'
+
 const SPAN_ID_INDEX_PREFIX = 's'
 const BEGIN_TIME_INDEX_PREFIX = 'b'
 const END_TIME_INDEX_PREFIX = 'e'
@@ -90,56 +92,6 @@ func (stats *Statistics) Copy() *Statistics {
        }
 }
 
-// Translate an 8-byte value into a leveldb key.
-func makeKey(tag byte, val uint64) []byte {
-       return []byte{
-               tag,
-               byte(0xff & (val >> 56)),
-               byte(0xff & (val >> 48)),
-               byte(0xff & (val >> 40)),
-               byte(0xff & (val >> 32)),
-               byte(0xff & (val >> 24)),
-               byte(0xff & (val >> 16)),
-               byte(0xff & (val >> 8)),
-               byte(0xff & (val >> 0)),
-       }
-}
-
-func keyToInt(key []byte) uint64 {
-       var id uint64
-       id = (uint64(key[0]) << 56) |
-               (uint64(key[1]) << 48) |
-               (uint64(key[2]) << 40) |
-               (uint64(key[3]) << 32) |
-               (uint64(key[4]) << 24) |
-               (uint64(key[5]) << 16) |
-               (uint64(key[6]) << 8) |
-               (uint64(key[7]) << 0)
-       return id
-}
-
-func makeSecondaryKey(tag byte, fir uint64, sec uint64) []byte {
-       return []byte{
-               tag,
-               byte(0xff & (fir >> 56)),
-               byte(0xff & (fir >> 48)),
-               byte(0xff & (fir >> 40)),
-               byte(0xff & (fir >> 32)),
-               byte(0xff & (fir >> 24)),
-               byte(0xff & (fir >> 16)),
-               byte(0xff & (fir >> 8)),
-               byte(0xff & (fir >> 0)),
-               byte(0xff & (sec >> 56)),
-               byte(0xff & (sec >> 48)),
-               byte(0xff & (sec >> 40)),
-               byte(0xff & (sec >> 32)),
-               byte(0xff & (sec >> 24)),
-               byte(0xff & (sec >> 16)),
-               byte(0xff & (sec >> 8)),
-               byte(0xff & (sec >> 0)),
-       }
-}
-
 // A single directory containing a levelDB instance.
 type shard struct {
        // The data store that this shard is part of
@@ -186,6 +138,18 @@ func s2u64(val int64) uint64 {
        return ret
 }
 
+func u64toSlice(val uint64) []byte {
+       return []byte{
+               byte(0xff & (val >> 56)),
+               byte(0xff & (val >> 48)),
+               byte(0xff & (val >> 40)),
+               byte(0xff & (val >> 32)),
+               byte(0xff & (val >> 24)),
+               byte(0xff & (val >> 16)),
+               byte(0xff & (val >> 8)),
+               byte(0xff & (val >> 0))}
+}
+
 func (shd *shard) writeSpan(span *common.Span) error {
        batch := levigo.NewWriteBatch()
        defer batch.Close()
@@ -197,21 +161,27 @@ func (shd *shard) writeSpan(span *common.Span) error {
        if err != nil {
                return err
        }
-       batch.Put(makeKey(SPAN_ID_INDEX_PREFIX, span.Id.Val()), 
spanDataBuf.Bytes())
+       primaryKey :=
+               append([]byte{SPAN_ID_INDEX_PREFIX}, span.Id.Val()...)
+       batch.Put(primaryKey, spanDataBuf.Bytes())
 
        // Add this to the parent index.
        for parentIdx := range span.Parents {
-               batch.Put(makeSecondaryKey(PARENT_ID_INDEX_PREFIX,
-                       span.Parents[parentIdx].Val(), span.Id.Val()), 
EMPTY_BYTE_BUF)
+               key := append(append([]byte{PARENT_ID_INDEX_PREFIX},
+                       span.Parents[parentIdx].Val()...), span.Id.Val()...)
+               batch.Put(key, EMPTY_BYTE_BUF)
        }
 
        // Add to the other secondary indices.
-       batch.Put(makeSecondaryKey(BEGIN_TIME_INDEX_PREFIX, s2u64(span.Begin),
-               span.Id.Val()), EMPTY_BYTE_BUF)
-       batch.Put(makeSecondaryKey(END_TIME_INDEX_PREFIX, s2u64(span.End),
-               span.Id.Val()), EMPTY_BYTE_BUF)
-       batch.Put(makeSecondaryKey(DURATION_INDEX_PREFIX, 
s2u64(span.Duration()),
-               span.Id.Val()), EMPTY_BYTE_BUF)
+       beginTimeKey := append(append([]byte{BEGIN_TIME_INDEX_PREFIX},
+               u64toSlice(s2u64(span.Begin))...), span.Id.Val()...)
+       batch.Put(beginTimeKey, EMPTY_BYTE_BUF)
+       endTimeKey := append(append([]byte{END_TIME_INDEX_PREFIX},
+               u64toSlice(s2u64(span.End))...), span.Id.Val()...)
+       batch.Put(endTimeKey, EMPTY_BYTE_BUF)
+       durationKey := append(append([]byte{DURATION_INDEX_PREFIX},
+               u64toSlice(s2u64(span.Duration()))...), span.Id.Val()...)
+       batch.Put(durationKey, EMPTY_BYTE_BUF)
 
        err = shd.ldb.Write(shd.store.writeOpts, batch)
        if err != nil {
@@ -226,7 +196,7 @@ func (shd *shard) writeSpan(span *common.Span) error {
 
 func (shd *shard) FindChildren(sid common.SpanId, childIds []common.SpanId,
        lim int32) ([]common.SpanId, int32, error) {
-       searchKey := makeKey('p', sid.Val())
+       searchKey := append([]byte{PARENT_ID_INDEX_PREFIX}, sid.Val()...)
        iter := shd.ldb.NewIterator(shd.store.readOpts)
        defer iter.Close()
        iter.Seek(searchKey)
@@ -241,7 +211,7 @@ func (shd *shard) FindChildren(sid common.SpanId, childIds 
[]common.SpanId,
                if !bytes.HasPrefix(key, searchKey) {
                        break
                }
-               id := common.SpanId(keyToInt(key[9:]))
+               id := common.SpanId(key[17:])
                childIds = append(childIds, id)
                lim--
                iter.Next()
@@ -462,7 +432,7 @@ func (store *dataStore) Close() {
 
 // Get the index of the shard which stores the given spanId.
 func (store *dataStore) getShardIndex(sid common.SpanId) int {
-       return int(sid.Val() % uint64(len(store.shards)))
+       return int(sid.Hash32() % uint32(len(store.shards)))
 }
 
 func (store *dataStore) WriteSpan(span *common.Span) {
@@ -475,7 +445,8 @@ func (store *dataStore) FindSpan(sid common.SpanId) 
*common.Span {
 
 func (shd *shard) FindSpan(sid common.SpanId) *common.Span {
        lg := shd.store.lg
-       buf, err := shd.ldb.Get(shd.store.readOpts, makeKey('s', sid.Val()))
+       primaryKey := append([]byte{SPAN_ID_INDEX_PREFIX}, sid.Val()...)
+       buf, err := shd.ldb.Get(shd.store.readOpts, primaryKey)
        if err != nil {
                if strings.Index(err.Error(), "NotFound:") != -1 {
                        return nil
@@ -541,8 +512,7 @@ func (store *dataStore) FindChildren(sid common.SpanId, lim 
int32) []common.Span
 
 type predicateData struct {
        *common.Predicate
-       uintKey uint64
-       strKey  string
+       key []byte
 }
 
 func loadPredicateData(pred *common.Predicate) (*predicateData, error) {
@@ -558,11 +528,11 @@ func loadPredicateData(pred *common.Predicate) 
(*predicateData, error) {
                        return nil, errors.New(fmt.Sprintf("Unable to parse 
span id '%s': %s",
                                pred.Val, err.Error()))
                }
-               p.uintKey = id.Val()
+               p.key = id.Val()
                break
        case common.DESCRIPTION:
                // Any string is valid for a description.
-               p.strKey = pred.Val
+               p.key = []byte(pred.Val)
                break
        case common.BEGIN_TIME, common.END_TIME, common.DURATION:
                // Parse a base-10 signed numeric field.
@@ -571,11 +541,11 @@ func loadPredicateData(pred *common.Predicate) 
(*predicateData, error) {
                        return nil, errors.New(fmt.Sprintf("Unable to parse %s 
'%s': %s",
                                pred.Field, pred.Val, err.Error()))
                }
-               p.uintKey = s2u64(v)
+               p.key = u64toSlice(s2u64(v))
                break
        case common.TRACER_ID:
                // Any string is valid for a tracer ID.
-               p.strKey = pred.Val
+               p.key = []byte(pred.Val)
                break
        default:
                return nil, errors.New(fmt.Sprintf("Unknown field %s", 
pred.Field))
@@ -626,22 +596,22 @@ func (pred *predicateData) fieldIsNumeric() bool {
 }
 
 // Get the values that this predicate cares about for a given span.
-func (pred *predicateData) extractRelevantSpanData(span *common.Span) (uint64, 
string) {
+func (pred *predicateData) extractRelevantSpanData(span *common.Span) []byte {
        switch pred.Field {
        case common.SPAN_ID:
-               return span.Id.Val(), ""
+               return span.Id.Val()
        case common.DESCRIPTION:
-               return 0, span.Description
+               return []byte(span.Description)
        case common.BEGIN_TIME:
-               return s2u64(span.Begin), ""
+               return u64toSlice(s2u64(span.Begin))
        case common.END_TIME:
-               return s2u64(span.End), ""
+               return u64toSlice(s2u64(span.End))
        case common.DURATION:
-               return s2u64(span.Duration()), ""
+               return u64toSlice(s2u64(span.Duration()))
        case common.TRACER_ID:
-               return 0, span.TracerId
+               return []byte(span.TracerId)
        default:
-               panic(fmt.Sprintf("Field type %s isn't a 64-bit integer.", 
pred.Field))
+               panic(fmt.Sprintf("Unknown field type %s.", pred.Field))
        }
 }
 
@@ -656,56 +626,33 @@ func (pred *predicateData) spanPtrIsBefore(a 
*common.Span, b *common.Span) bool
                return true
        }
        // Compare the spans according to this predicate.
-       aInt, aStr := pred.extractRelevantSpanData(a)
-       bInt, bStr := pred.extractRelevantSpanData(b)
-       if pred.fieldIsNumeric() {
-               if pred.Op.IsDescending() {
-                       return aInt > bInt
-               } else {
-                       return aInt < bInt
-               }
+       aVal := pred.extractRelevantSpanData(a)
+       bVal := pred.extractRelevantSpanData(b)
+       cmp := bytes.Compare(aVal, bVal)
+       if pred.Op.IsDescending() {
+               return cmp > 0
        } else {
-               if pred.Op.IsDescending() {
-                       return aStr > bStr
-               } else {
-                       return aStr < bStr
-               }
+               return cmp < 0
        }
 }
 
 // Returns true if the predicate is satisfied by the given span.
 func (pred *predicateData) satisfiedBy(span *common.Span) bool {
-       intVal, strVal := pred.extractRelevantSpanData(span)
-       if pred.fieldIsNumeric() {
-               switch pred.Op {
-               case common.EQUALS:
-                       return intVal == pred.uintKey
-               case common.LESS_THAN_OR_EQUALS:
-                       return intVal <= pred.uintKey
-               case common.GREATER_THAN_OR_EQUALS:
-                       return intVal >= pred.uintKey
-               case common.GREATER_THAN:
-                       return intVal > pred.uintKey
-               default:
-                       panic(fmt.Sprintf("unknown Op type %s should have been 
caught "+
-                               "during normalization", pred.Op))
-               }
-       } else {
-               switch pred.Op {
-               case common.CONTAINS:
-                       return strings.Contains(strVal, pred.strKey)
-               case common.EQUALS:
-                       return strVal == pred.strKey
-               case common.LESS_THAN_OR_EQUALS:
-                       return strVal <= pred.strKey
-               case common.GREATER_THAN_OR_EQUALS:
-                       return strVal >= pred.strKey
-               case common.GREATER_THAN:
-                       return strVal > pred.strKey
-               default:
-                       panic(fmt.Sprintf("unknown Op type %s should have been 
caught "+
-                               "during normalization", pred.Op))
-               }
+       val := pred.extractRelevantSpanData(span)
+       switch pred.Op {
+       case common.CONTAINS:
+               return bytes.Contains(val, pred.key)
+       case common.EQUALS:
+               return bytes.Equal(val, pred.key)
+       case common.LESS_THAN_OR_EQUALS:
+               return bytes.Compare(val, pred.key) <= 0
+       case common.GREATER_THAN_OR_EQUALS:
+               return bytes.Compare(val, pred.key) >= 0
+       case common.GREATER_THAN:
+               return bytes.Compare(val, pred.key) > 0
+       default:
+               panic(fmt.Sprintf("unknown Op type %s should have been caught "+
+                       "during normalization", pred.Op))
        }
 }
 
@@ -746,7 +693,7 @@ func (pred *predicateData) createSource(store *dataStore, 
prev *common.Span) (*s
                // organized as [type-code][8b-secondary-key][8b-span-id], 
elements
                // with the same secondary index field are ordered by span ID.  
So we
                // create a 17-byte key incorporating the span ID from 'prev.'
-               var startId common.SpanId
+               startId := common.INVALID_SPAN_ID
                switch pred.Op {
                case common.EQUALS:
                        if pred.Field == common.SPAN_ID {
@@ -759,17 +706,17 @@ func (pred *predicateData) createSource(store *dataStore, 
prev *common.Span) (*s
                                lg.Debugf("Attempted to use a continuation 
token with an EQUALS "+
                                        "SPAN_ID query. %s.  Setting search id 
= 0",
                                        pred.Predicate.String())
-                               startId = 0
+                               startId = common.INVALID_SPAN_ID
                        } else {
                                // When doing an EQUALS search on a secondary 
index, the
                                // results are sorted by span id.
-                               startId = prev.Id + 1
+                               startId = prev.Id.Next()
                        }
                case common.LESS_THAN_OR_EQUALS:
                        // Subtract one from the previous span id.  Since the 
previous
                        // start ID will never be 0 (0 is an illegal span id), 
we'll never
                        // wrap around when doing this.
-                       startId = prev.Id - 1
+                       startId = prev.Id.Prev()
                case common.GREATER_THAN_OR_EQUALS:
                        // We can't add one to the span id, since the previous 
span ID
                        // might be the maximum value.  So just switch over to 
using
@@ -785,21 +732,22 @@ func (pred *predicateData) createSource(store *dataStore, 
prev *common.Span) (*s
                        panic(str)
                }
                if pred.Field == common.SPAN_ID {
-                       pred.uintKey = uint64(startId)
-                       searchKey = makeKey(src.keyPrefix, uint64(startId))
+                       pred.key = startId.Val()
+                       searchKey = append([]byte{src.keyPrefix}, 
startId.Val()...)
                } else {
                        // Start where the previous query left off.  This means 
adjusting
                        // our uintKey.
-                       pred.uintKey, _ = pred.extractRelevantSpanData(prev)
-                       searchKey = makeSecondaryKey(src.keyPrefix, 
pred.uintKey, uint64(startId))
+                       pred.key = pred.extractRelevantSpanData(prev)
+                       searchKey = append(append([]byte{src.keyPrefix}, 
pred.key...),
+                               startId.Val()...)
                }
                if lg.TraceEnabled() {
                        lg.Tracef("Handling continuation token %s for %s.  
startId=%d, "+
-                               "pred.uintKey=%d\n", prev, 
pred.Predicate.String(), startId,
-                               pred.uintKey)
+                               "pred.uintKey=%s\n", prev, 
pred.Predicate.String(), startId,
+                               hex.EncodeToString(pred.key))
                }
        } else {
-               searchKey = makeKey(src.keyPrefix, pred.uintKey)
+               searchKey = append([]byte{src.keyPrefix}, pred.key...)
        }
        for i := range src.iters {
                src.iters[i].Seek(searchKey)
@@ -866,7 +814,7 @@ func (src *source) populateNextFromShard(shardIdx int) {
                var sid common.SpanId
                if src.keyPrefix == SPAN_ID_INDEX_PREFIX {
                        // The span id maps to the span itself.
-                       sid = common.SpanId(keyToInt(key[1:]))
+                       sid = common.SpanId(key[1:17])
                        span, err = src.store.shards[shardIdx].decodeSpan(sid, 
iter.Value())
                        if err != nil {
                                lg.Debugf("Internal error decoding span %s in 
shard %d: %s\n",
@@ -875,7 +823,7 @@ func (src *source) populateNextFromShard(shardIdx int) {
                        }
                } else {
                        // With a secondary index, we have to look up the span 
by id.
-                       sid = common.SpanId(keyToInt(key[9:]))
+                       sid = common.SpanId(key[9:25])
                        span = src.store.shards[shardIdx].FindSpan(sid)
                        if span == nil {
                                lg.Debugf("Internal error rehydrating span %s 
in shard %d\n",
@@ -948,7 +896,7 @@ func (store *dataStore) obtainSource(preds 
*[]*predicateData, span *common.Span)
        // If there are no predicates that are indexed, read rows in order of 
span id.
        spanIdPred := common.Predicate{Op: common.GREATER_THAN_OR_EQUALS,
                Field: common.SPAN_ID,
-               Val:   "0000000000000000",
+               Val:   common.INVALID_SPAN_ID.String(),
        }
        spanIdPredData, err := loadPredicateData(&spanIdPred)
        if err != nil {

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htraced/datastore_test.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore_test.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore_test.go
index 0c122fd..0caa509 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore_test.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore_test.go
@@ -45,31 +45,28 @@ func TestCreateDatastore(t *testing.T) {
 }
 
 var SIMPLE_TEST_SPANS []common.Span = []common.Span{
-       common.Span{Id: 1,
+       common.Span{Id: common.TestId("00000000000000000000000000000001"),
                SpanData: common.SpanData{
                        Begin:       123,
                        End:         456,
                        Description: "getFileDescriptors",
-                       TraceId:     999,
                        Parents:     []common.SpanId{},
                        TracerId:    "firstd",
                }},
-       common.Span{Id: 2,
+       common.Span{Id: common.TestId("00000000000000000000000000000002"),
                SpanData: common.SpanData{
                        Begin:       125,
                        End:         200,
                        Description: "openFd",
-                       TraceId:     999,
-                       Parents:     []common.SpanId{1},
+                       Parents:     
[]common.SpanId{common.TestId("00000000000000000000000000000001")},
                        TracerId:    "secondd",
                }},
-       common.Span{Id: 3,
+       common.Span{Id: common.TestId("00000000000000000000000000000003"),
                SpanData: common.SpanData{
                        Begin:       200,
                        End:         456,
                        Description: "passFd",
-                       TraceId:     999,
-                       Parents:     []common.SpanId{1},
+                       Parents:     
[]common.SpanId{common.TestId("00000000000000000000000000000001")},
                        TracerId:    "thirdd",
                }},
 }
@@ -98,27 +95,27 @@ func TestDatastoreWriteAndRead(t *testing.T) {
        if ht.Store.GetStatistics().NumSpansWritten < 
uint64(len(SIMPLE_TEST_SPANS)) {
                t.Fatal()
        }
-       span := ht.Store.FindSpan(1)
+       span := 
ht.Store.FindSpan(common.TestId("00000000000000000000000000000001"))
        if span == nil {
                t.Fatal()
        }
-       if span.Id != 1 {
+       if !span.Id.Equal(common.TestId("00000000000000000000000000000001")) {
                t.Fatal()
        }
        common.ExpectSpansEqual(t, &SIMPLE_TEST_SPANS[0], span)
-       children := ht.Store.FindChildren(1, 1)
+       children := 
ht.Store.FindChildren(common.TestId("00000000000000000000000000000001"), 1)
        if len(children) != 1 {
                t.Fatalf("expected 1 child, but got %d\n", len(children))
        }
-       children = ht.Store.FindChildren(1, 2)
+       children = 
ht.Store.FindChildren(common.TestId("00000000000000000000000000000001"), 2)
        if len(children) != 2 {
                t.Fatalf("expected 2 children, but got %d\n", len(children))
        }
        sort.Sort(common.SpanIdSlice(children))
-       if children[0] != 2 {
+       if 
!children[0].Equal(common.TestId("00000000000000000000000000000002")) {
                t.Fatal()
        }
-       if children[1] != 3 {
+       if 
!children[1].Equal(common.TestId("00000000000000000000000000000003")) {
                t.Fatal()
        }
 }
@@ -258,7 +255,7 @@ func TestQueries3(t *testing.T) {
                        common.Predicate{
                                Op:    common.LESS_THAN_OR_EQUALS,
                                Field: common.SPAN_ID,
-                               Val:   "0",
+                               Val:   
common.TestId("00000000000000000000000000000000").String(),
                        },
                },
                Lim: 200,
@@ -269,7 +266,7 @@ func TestQueries3(t *testing.T) {
                        common.Predicate{
                                Op:    common.LESS_THAN_OR_EQUALS,
                                Field: common.SPAN_ID,
-                               Val:   "2",
+                               Val:   
common.TestId("00000000000000000000000000000002").String(),
                        },
                },
                Lim: 200,
@@ -477,7 +474,7 @@ func TestQueriesWithContinuationTokens1(t *testing.T) {
                        common.Predicate{
                                Op:    common.EQUALS,
                                Field: common.SPAN_ID,
-                               Val:   "1",
+                               Val:   
common.TestId("00000000000000000000000000000001").String(),
                        },
                },
                Lim:  100,
@@ -491,7 +488,7 @@ func TestQueriesWithContinuationTokens1(t *testing.T) {
                        common.Predicate{
                                Op:    common.LESS_THAN_OR_EQUALS,
                                Field: common.SPAN_ID,
-                               Val:   "2",
+                               Val:   
common.TestId("00000000000000000000000000000002").String(),
                        },
                },
                Lim:  100,

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htraced/hrpc.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/hrpc.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/hrpc.go
index 71b9625..354d064 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/hrpc.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/hrpc.go
@@ -193,6 +193,10 @@ func (hand *HrpcHandler) WriteSpans(req 
*common.WriteSpansReq,
                "defaultTrid = %s\n", len(req.Spans), req.DefaultTrid)
        for i := range req.Spans {
                span := req.Spans[i]
+               spanIdProblem := span.Id.FindProblem()
+               if spanIdProblem != "" {
+                       return errors.New(fmt.Sprintf("Invalid span ID: %s", 
spanIdProblem))
+               }
                if span.TracerId == "" {
                        span.TracerId = req.DefaultTrid
                }

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
index cd90038..66f78f8 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
@@ -76,14 +76,15 @@ type dataStoreHandler struct {
 
 func (hand *dataStoreHandler) parseSid(w http.ResponseWriter,
        str string) (common.SpanId, bool) {
-       val, err := strconv.ParseUint(str, 16, 64)
+       var id common.SpanId
+       err := id.FromString(str)
        if err != nil {
                writeError(hand.lg, w, http.StatusBadRequest,
                        fmt.Sprintf("Failed to parse span ID %s: %s", str, 
err.Error()))
                w.Write([]byte("Error parsing : " + err.Error()))
-               return 0, false
+               return common.INVALID_SPAN_ID, false
        }
-       return common.SpanId(val), true
+       return id, true
 }
 
 func (hand *dataStoreHandler) getReqField32(fieldName string, w 
http.ResponseWriter,

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/test/random.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/test/random.go 
b/htrace-htraced/go/src/org/apache/htrace/test/random.go
index 96a3e8b..540ea14 100644
--- a/htrace-htraced/go/src/org/apache/htrace/test/random.go
+++ b/htrace-htraced/go/src/org/apache/htrace/test/random.go
@@ -38,6 +38,15 @@ func NonZeroRand64(rnd *rand.Rand) int64 {
        }
 }
 
+func NonZeroRandSpanId(rnd *rand.Rand) common.SpanId {
+       var id common.SpanId
+       id = make([]byte, 16)
+       for i := 0; i < len(id); i++ {
+               id[i] = byte(rnd.Intn(0x100))
+       }
+       return id
+}
+
 func NonZeroRand32(rnd *rand.Rand) int32 {
        for {
                r := rnd.Int31()
@@ -60,12 +69,11 @@ func NewRandomSpan(rnd *rand.Rand, potentialParents 
[]*common.Span) *common.Span
                        parents = 
[]common.SpanId{potentialParents[parentIdx].Id}
                }
        }
-       return &common.Span{Id: common.SpanId(NonZeroRand64(rnd)),
+       return &common.Span{Id: NonZeroRandSpanId(rnd),
                SpanData: common.SpanData{
                        Begin:       NonZeroRand64(rnd),
                        End:         NonZeroRand64(rnd),
                        Description: "getFileDescriptors",
-                       TraceId:     common.SpanId(NonZeroRand64(rnd)),
                        Parents:     parents,
                        TracerId:    fmt.Sprintf("tracer%d", 
NonZeroRand32(rnd)),
                }}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/go/src/org/apache/htrace/test/util.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/test/util.go 
b/htrace-htraced/go/src/org/apache/htrace/test/util.go
deleted file mode 100644
index cc058e0..0000000
--- a/htrace-htraced/go/src/org/apache/htrace/test/util.go
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package test
-
-import (
-       "org/apache/htrace/common"
-)
-
-func SpanId(str string) common.SpanId {
-       var spanId common.SpanId
-       err := spanId.FromString(str)
-       if err != nil {
-               panic(err.Error())
-       }
-       return spanId
-}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedRESTReceiver.java
----------------------------------------------------------------------
diff --git 
a/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedRESTReceiver.java
 
b/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedRESTReceiver.java
index 35d1f09..99f2c50 100644
--- 
a/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedRESTReceiver.java
+++ 
b/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedRESTReceiver.java
@@ -28,6 +28,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.htrace.HTraceConfiguration;
 import org.apache.htrace.Span;
+import org.apache.htrace.SpanId;
 import org.apache.htrace.util.DataDir;
 import org.apache.htrace.util.HTracedProcess;
 import org.apache.htrace.util.TestUtil;
@@ -126,8 +127,8 @@ public class TestHTracedRESTReceiver {
     Span spans[] = new Span[NUM_SPANS];
     for (int i = 0; i < NUM_SPANS; i++) {
       MilliSpan.Builder builder = new MilliSpan.Builder().
-          parents(new long[]{1L}).
-          spanId(i);
+          parents(new SpanId[] { new SpanId(1L, 1L) }).
+          spanId(new SpanId(1L, i));
       if (i == NUM_SPANS - 1) {
         builder.tracerId("specialTrid");
       }
@@ -150,7 +151,8 @@ public class TestHTracedRESTReceiver {
             for (int i = 0; i < NUM_SPANS; i++) {
               // This is what the REST server expects when querying for a
               // span id.
-              String findSpan = String.format("span/%016x", i);
+              String findSpan = String.format("span/%s",
+                  new SpanId(1L, i).toString());
               ContentResponse response =
                   http.GET(restServerUrl + findSpan);
               String content = processGET(response);
@@ -160,7 +162,8 @@ public class TestHTracedRESTReceiver {
               }
               LOG.info("Got " + content + " for span " + i);
               MilliSpan dspan = MilliSpan.fromJson(content);
-              assertEquals((long)i, dspan.getSpanId());
+              assertEquals(new SpanId(1, i).toString(),
+                dspan.getSpanId().toString());
               // Every span should have the tracer ID we set in the
               // configuration... except for the last span, which had
               // a custom value set.

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-webapp/src/main/web/app/span.js
----------------------------------------------------------------------
diff --git a/htrace-webapp/src/main/web/app/span.js 
b/htrace-webapp/src/main/web/app/span.js
index b56a2c9..cd87543 100644
--- a/htrace-webapp/src/main/web/app/span.js
+++ b/htrace-webapp/src/main/web/app/span.js
@@ -20,7 +20,7 @@
 var htrace = htrace || {};
 
 // The invalid span ID, which is all zeroes.
-htrace.INVALID_SPAN_ID = "0000000000000000";
+htrace.INVALID_SPAN_ID = "00000000000000000000000000000000";
 
 // Convert an array of htrace.Span models into a comma-separated string.
 htrace.spanModelsToString = function(spans) {
@@ -81,8 +81,7 @@ htrace.Span = Backbone.Model.extend({
   // forced to be numbers.
   parse: function(response, options) {
     var span = {};
-    this.set("spanId", response.s ? response.s : htrace.INVALID_SPAN_ID);
-    this.set("traceId", response.i ? response.i : htrace.INVALID_SPAN_ID);
+    this.set("spanId", response.a ? response.a : htrace.INVALID_SPAN_ID);
     this.set("tracerId", response.r ? response.r : "");
     this.set("parents", response.p ? response.p : []);
     this.set("description", response.d ? response.d : "");
@@ -120,10 +119,7 @@ htrace.Span = Backbone.Model.extend({
   unparse: function() {
     var obj = { };
     if (!(this.get("spanId") === htrace.INVALID_SPAN_ID)) {
-      obj.s = this.get("spanId");
-    }
-    if (!(this.get("traceId") === htrace.INVALID_SPAN_ID)) {
-      obj.i = this.get("traceId");
+      obj.a = this.get("spanId");
     }
     if (!(this.get("tracerId") === "")) {
       obj.r = this.get("tracerId");

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-webapp/src/main/web/app/string.js
----------------------------------------------------------------------
diff --git a/htrace-webapp/src/main/web/app/string.js 
b/htrace-webapp/src/main/web/app/string.js
index b0dfb74..c9c514b 100644
--- a/htrace-webapp/src/main/web/app/string.js
+++ b/htrace-webapp/src/main/web/app/string.js
@@ -47,16 +47,12 @@ htrace.dateToString = function(val) {
   return moment.utc(val).format("YYYY-MM-DDTHH:mm:ss,SSS");
 };
 
-// Normalize a span ID into the format the server expects to see
-// (no leading 0x).
+// Normalize a span ID into the format the server expects to see--
+// i.e. something like 00000000000000000000000000000000.
 htrace.normalizeSpanId = function(str) {
-  // Strip off the 0x prefix, if there is one.
-  if (str.indexOf("0x") == 0) {
-    str = str.substring(2);
-  }
-  if (str.length != 16) {
+  if (str.length != 36) {
     throw "The length of '" + str + "' was " + str.length +
-      ", but span IDs must be 16 characters long.";
+      ", but span IDs must be 36 characters long.";
   }
   if (str.search(/[^0-9a-fA-F]/) != -1) {
     throw "Span IDs must contain only hexadecimal digits, but '" + str +

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/HTraceToZipkinConverter.java
----------------------------------------------------------------------
diff --git 
a/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/HTraceToZipkinConverter.java
 
b/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/HTraceToZipkinConverter.java
index f41ec10..3921370 100644
--- 
a/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/HTraceToZipkinConverter.java
+++ 
b/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/HTraceToZipkinConverter.java
@@ -110,15 +110,15 @@ public class HTraceToZipkinConverter {
     Endpoint ep = new Endpoint(ipv4Address, (short) getPort(serviceName), 
serviceName);
     List<Annotation> annotationList = createZipkinAnnotations(hTraceSpan, ep);
     List<BinaryAnnotation> binaryAnnotationList = 
createZipkinBinaryAnnotations(hTraceSpan, ep);
-    zipkinSpan.setTrace_id(hTraceSpan.getTraceId());
+    zipkinSpan.setTrace_id(hTraceSpan.getSpanId().getHigh());
     if (hTraceSpan.getParents().length > 0) {
       if (hTraceSpan.getParents().length > 1) {
         LOG.error("zipkin doesn't support spans with multiple parents.  
Omitting " +
             "other parents for " + hTraceSpan);
       }
-      zipkinSpan.setParent_id(hTraceSpan.getParents()[0]);
+      zipkinSpan.setParent_id(hTraceSpan.getParents()[0].getLow());
     }
-    zipkinSpan.setId(hTraceSpan.getSpanId());
+    zipkinSpan.setId(hTraceSpan.getSpanId().getLow());
     zipkinSpan.setName(hTraceSpan.getDescription());
     zipkinSpan.setAnnotations(annotationList);
     zipkinSpan.setBinary_annotations(binaryAnnotationList);

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/htrace-zipkin/src/test/java/org/apache/htrace/TestHTraceSpanToZipkinSpan.java
----------------------------------------------------------------------
diff --git 
a/htrace-zipkin/src/test/java/org/apache/htrace/TestHTraceSpanToZipkinSpan.java 
b/htrace-zipkin/src/test/java/org/apache/htrace/TestHTraceSpanToZipkinSpan.java
index 915bb89..579b98d 100644
--- 
a/htrace-zipkin/src/test/java/org/apache/htrace/TestHTraceSpanToZipkinSpan.java
+++ 
b/htrace-zipkin/src/test/java/org/apache/htrace/TestHTraceSpanToZipkinSpan.java
@@ -21,6 +21,7 @@ import com.twitter.zipkin.gen.zipkinCoreConstants;
 
 import org.apache.htrace.HTraceConfiguration;
 import org.apache.htrace.Span;
+import org.apache.htrace.SpanId;
 import org.apache.htrace.Trace;
 import org.apache.htrace.impl.MilliSpan;
 import org.apache.htrace.impl.POJOSpanReceiver;
@@ -48,9 +49,8 @@ public class TestHTraceSpanToZipkinSpan {
 
     Span rootSpan = new MilliSpan.Builder().
             description(ROOT_SPAN_DESC).
-            traceId(1).
-            parents(new long[] { } ).
-            spanId(100).
+            parents(new SpanId[] { } ).
+            spanId(new SpanId(100, 100)).
             tracerId("test").
             begin(System.currentTimeMillis()).
             build();
@@ -72,11 +72,13 @@ public class TestHTraceSpanToZipkinSpan {
   @Test
   public void testHTraceAnnotationTimestamp() throws IOException, 
InterruptedException {
 
-    String traceName = "testHTraceAnnotationTimestamp";
+    String tracerId = "testHTraceAnnotationTimestamp";
     long startTime = System.currentTimeMillis() * 1000;
     Span ms = new MilliSpan.Builder().
-        description(traceName).traceId(1).parents(new long[] { }).
-        spanId(2).tracerId(traceName).begin(System.currentTimeMillis()).
+        description(tracerId).parents(new SpanId[] { }).
+        spanId(new SpanId(2L, 2L)).
+        tracerId(tracerId).
+        begin(System.currentTimeMillis()).
         build();
 
     Thread.sleep(500);
@@ -117,19 +119,23 @@ public class TestHTraceSpanToZipkinSpan {
   @Test
   public void testHTraceDefaultPort() throws IOException {
     MilliSpan ms = new MilliSpan.Builder().description("test").
-                      traceId(1).parents(new long[] { 2 }).
-                      spanId(3).tracerId("hmaster").
-                      begin(System.currentTimeMillis()).build();
+                      parents(new SpanId[] { new SpanId(2L, 2L) }).
+                      spanId(new SpanId(2L, 3L)).
+                      tracerId("hmaster").
+                      begin(System.currentTimeMillis()).
+                      build();
     com.twitter.zipkin.gen.Span zs = new HTraceToZipkinConverter(12345, 
(short) -1).convert(ms);
     for (com.twitter.zipkin.gen.Annotation annotation:zs.getAnnotations()) {
       assertEquals((short)60000, annotation.getHost().getPort());
     }
 
     // make sure it's all lower cased
-    ms = new MilliSpan.Builder().description("test").traceId(1).
-                      parents(new long[] {2}).spanId(3).
+    ms = new MilliSpan.Builder().description("test").
+                      parents(new SpanId[] {new SpanId(2, 2)}).
+                      spanId(new SpanId(2, 3)).
                       tracerId("HregIonServer").
-                      begin(System.currentTimeMillis()).build();
+                      begin(System.currentTimeMillis()).
+                      build();
     zs = new HTraceToZipkinConverter(12345, (short) -1).convert(ms);
     for (com.twitter.zipkin.gen.Annotation annotation:zs.getAnnotations()) {
       assertEquals((short)60020, annotation.getHost().getPort());
@@ -137,13 +143,12 @@ public class TestHTraceSpanToZipkinSpan {
   }
 
   private void assertSpansAreEquivalent(Span s, com.twitter.zipkin.gen.Span 
zs) {
-    assertEquals(s.getTraceId(), zs.getTrace_id());
     assertTrue("zipkin doesn't support multiple parents to a single span.",
           s.getParents().length <= 1);
     if (s.getParents().length == 1) {
-      assertEquals(s.getParents()[0], zs.getParent_id());
+      assertEquals(s.getParents()[0].getLow(), zs.getParent_id());
     }
-    assertEquals(s.getSpanId(), zs.getId());
+    assertEquals(s.getSpanId().getLow(), zs.getId());
     Assert.assertNotNull(zs.getAnnotations());
     if (ROOT_SPAN_DESC.equals(zs.getName())) {
       assertEquals(5, zs.getAnnotations().size());// two start, two stop + one 
timeline annotation

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a06159b2/src/main/site/markdown/index.md
----------------------------------------------------------------------
diff --git a/src/main/site/markdown/index.md b/src/main/site/markdown/index.md
index 9b3034f..6198472 100644
--- a/src/main/site/markdown/index.md
+++ b/src/main/site/markdown/index.md
@@ -184,13 +184,11 @@ returned will be a child of the current span, otherwise 
it will start
 a new trace in the current thread (it will be a
 `ProcessRootMilliSpan`). All of the other `startSpan()` methods take some
 parameter describing the parent span of the span to be created. The
-versions that take a `TraceInfo` or a `long traceId` and `long
-parentId` will mostly be used when continuing a trace over RPC. The
-receiver of the RPC will check the message for the additional two
-`longs` and will call `startSpan()` if they are attached.  The last
-`startSpan()` takes a `Span parent`.  The result of `parent.child()`
-will be used for the new span.  `Span.child()` simply returns a span
-that is a child of `this`.
+version that takes a parent id will mostly be used when continuing a trace over
+RPC. The receiver of the RPC will check the message for the 128-bit parent 
trace
+ID and will call `startSpan()` if it is attached.  The last `startSpan()` takes
+a `Span parent`.  The result of `parent.child()` will be used for the new span.
+`Span.child()` simply returns a span that is a child of `this`.
 
 ###Span Receivers
 In order to use the tracing information consisting of spans,
@@ -260,11 +258,6 @@ SpanReceivers itself and calling 
.configure(HTraceConfiguration) on each
 one. The expectation now is that SpanReceiver implementations
 provide a constructor that takes a single parameter of HTraceConfiguration.
 
-HTRACE-16 refactors the TraceTree interface. The handy
-getRoots() method has been replaced with the less obvious
-getSpansByParent().find(Span.ROOT_SPAN_ID) and .getSpansByParentIdMap() is
-also an invocation of getSpansByParent().find().
-
 
 Publishing to Maven Central
 -------------------------------

Reply via email to