diff --git a/experimental/tracer/vendor/github.com/msackman/skiplist/LICENSE b/experimental/tracer/vendor/github.com/msackman/skiplist/LICENSE new file mode 100644 index 000000000..872daf759 --- /dev/null +++ b/experimental/tracer/vendor/github.com/msackman/skiplist/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Matthew Sackman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/experimental/tracer/vendor/github.com/msackman/skiplist/README.md b/experimental/tracer/vendor/github.com/msackman/skiplist/README.md new file mode 100644 index 000000000..4c5f8d87c --- /dev/null +++ b/experimental/tracer/vendor/github.com/msackman/skiplist/README.md @@ -0,0 +1,2 @@ +Skiplist implementation for Go. Comes with tests. Currently no docs, +but it's pretty obvious stuff. \ No newline at end of file diff --git a/experimental/tracer/vendor/github.com/msackman/skiplist/skiplist.go b/experimental/tracer/vendor/github.com/msackman/skiplist/skiplist.go new file mode 100644 index 000000000..4f568f49e --- /dev/null +++ b/experimental/tracer/vendor/github.com/msackman/skiplist/skiplist.go @@ -0,0 +1,429 @@ +package skiplist + +import ( + "fmt" + "math" + "math/rand" + "strings" +) + +const ( + p = 0.3 + defaultDepth = 2 +) + +type Comparable interface { + LessThan(Comparable) bool + Equal(Comparable) bool +} + +type SkipList struct { + length uint + terminus *Node + levelProbabilities []float32 + curCapacity uint + curDepth uint + nodes []Node + localRand *rand.Rand +} + +type Node struct { + Key Comparable + Value interface{} + heightRand float32 + prev *Node + nexts []*Node + skiplist *SkipList +} + +func New(rng *rand.Rand) *SkipList { + depth := defaultDepth + + terminus := &Node{ + heightRand: 0, + nexts: make([]*Node, depth), + } + terminus.prev = terminus + for idx := 0; idx < len(terminus.nexts); idx++ { + terminus.nexts[idx] = terminus + } + s := &SkipList{ + length: 0, + terminus: terminus, + curDepth: uint(depth), + localRand: rng, + } + s.levelProbabilities = []float32{p} + terminus.skiplist = s + s.determineCapacity() + + // s.validate() + + return s +} + +func (s *SkipList) determineCapacity() { + base := float64(1.0) / p + capacity := math.Pow(base, float64(s.curDepth)) + s.curCapacity = uint(math.Floor(capacity)) +} + +func (s *SkipList) chooseNumLevels() (float32, int) { + r := s.localRand.Float32() + max := len(s.levelProbabilities) + for idx := 0; idx < max; idx++ { + if r > s.levelProbabilities[idx] { + return r, idx + 1 + } + } + return r, max + 1 +} + +func (s *SkipList) ensureCapacity() { + // defer s.validate() + if s.length < s.curCapacity { + return + } + + threshold := p * s.levelProbabilities[s.curDepth-2] + s.curDepth++ + s.levelProbabilities = append(s.levelProbabilities, threshold) + + s.determineCapacity() + + // cur and next are just used to walk through the list at lvl. prev + // records the last node that made it up to the new level. + cur := s.terminus + lvl := len(cur.nexts) - 1 + prev := cur + for { + next := cur.nexts[lvl] + if cur.heightRand <= threshold { + cur.nexts = append(cur.nexts, s.terminus) + prev.nexts[lvl+1] = cur + prev = cur + } + if next == s.terminus { + break + } else { + cur = next + } + } +} + +func (s *SkipList) getNode() *Node { + l := len(s.nodes) + if l == 0 { + l = int(s.curCapacity) + s.nodes = make([]Node, l) + } + l-- + n := &s.nodes[l] + s.nodes = s.nodes[:l] + return n +} + +func (s *SkipList) getEqOrLessThan(cur *Node, k Comparable, captureDescent bool) (*Node, []*Node) { + // defer s.validate() + + if s.length == 0 { + return s.terminus, nil + } + if cur != s.terminus { + if k.Equal(cur.Key) { + return cur, nil + } + if k.LessThan(cur.Key) { + return s.getEqOrLessThan(s.terminus, k, captureDescent) + } + } + // 1. Travel, not-descending, as far as possible + lvl := len(cur.nexts) - 1 + for { + n := cur.nexts[lvl] + if n == s.terminus { + break + } + if n.Key.LessThan(k) { + cur = n + lvl = len(cur.nexts) - 1 + } else if n.Key.Equal(k) { + return n, nil + } else { + break + } + } + // 2. Now descend as needed + var descent []*Node + if captureDescent { + descent = make([]*Node, lvl+1) + descent[lvl] = cur + } + for lvl--; lvl >= 0; lvl-- { + for { + n := cur.nexts[lvl] + if n == s.terminus { + break + } + if n.Key.LessThan(k) { + cur = n + } else if n.Key.Equal(k) { + return n, descent + } else { + break + } + } + if captureDescent { + descent[lvl] = cur + } + } + return cur, descent +} + +func (s *SkipList) insert(cur *Node, k Comparable, v interface{}, n *Node) *Node { + // defer s.validate() + + // do this first even though we may not need to - if we do it after + // the getEqOrLessThan call, we may break descent. + s.ensureCapacity() + cur, descent := s.getEqOrLessThan(cur, k, true) + if cur != s.terminus && cur.Key.Equal(k) { + cur.Value = v + return cur + } + // We didn't find k, so cur will be the node immediately prior to + // where k should go. + heightRand, height := s.chooseNumLevels() + if n == nil { + n = s.getNode() + } + n.Key = k + n.Value = v + n.heightRand = heightRand + n.nexts = make([]*Node, height) + n.prev = cur + n.skiplist = s + + if len(cur.nexts) >= len(n.nexts) { + for idx := 0; idx < len(n.nexts); idx++ { + n.nexts[idx] = cur.nexts[idx] + cur.nexts[idx] = n + } + } else { + // Descent may capture only part of the path: it may be shorter + // than levels (in the case where the original cur is != + // s.terminus) and we reached the correct location without + // travelling up very far. However, because we didn't find k, we + // know that all the "lower" levels of descent will be populated + // (where "lower" is "closer to [0]"), so we just need to fill in + // the "top". + if len(n.nexts) > len(descent) { + _, extra := s.getEqOrLessThan(s.terminus, descent[len(descent)-1].Key, true) + // Aside: because we know we'll find that Key, all the lower + // indices of extra will be nil. + descent = append(descent, extra[len(descent):]...) + } + for idx := 0; idx < len(n.nexts); idx++ { + n.nexts[idx] = descent[idx].nexts[idx] + descent[idx].nexts[idx] = n + } + } + n._next().prev = n + s.length++ + return n +} + +func (s *SkipList) remove(cur *Node, k Comparable) interface{} { + // defer s.validate() + + n, _ := s.getEqOrLessThan(cur, k, false) + if n == s.terminus || !n.Key.Equal(k) { + return nil + } + s.removeNode(n) + n.nullify() + return n.Value +} + +func (s *SkipList) removeNode(n *Node) { + // defer s.validate() + + p := n.prev + n._next().prev = p + s.length-- + for idx := 0; idx < len(p.nexts) && idx < len(n.nexts); idx++ { + p.nexts[idx] = n.nexts[idx] + } + if len(p.nexts) < len(n.nexts) { + _, descent := s.getEqOrLessThan(s.terminus, p.Key, true) + // because we know we're going to find Key, the lower indices + // of descent will be nil. But we know p == n.prev, so all of + // those pointers will be to n anyway, which we've already + // dealt with in the previous loop. + for idx := len(p.nexts); idx < len(n.nexts); idx++ { + descent[idx].nexts[idx] = n.nexts[idx] + } + } +} + +func (s *SkipList) reposition(cur *Node, k Comparable) { + // defer s.validate() + + needsMove := false + if cur != s.terminus { + if cur.prev != s.terminus && !cur.prev.Key.LessThan(k) { + needsMove = true + } else if n := cur._next(); n != s.terminus && !k.LessThan(n.Key) { + needsMove = true + } + } + if needsMove { + s.removeNode(cur) + cur.Key = k + s.insert(cur.prev, cur.Key, cur.Value, cur) + } +} + +func (s *SkipList) First() *Node { + return s.terminus.Next() +} + +func (s *SkipList) Last() *Node { + return s.terminus.Prev() +} + +func (s *SkipList) Insert(k Comparable, v interface{}) *Node { + return s.insert(s.terminus, k, v, nil) +} + +func (s *SkipList) Get(k Comparable) *Node { + return s.terminus.Get(k) +} + +func (s *SkipList) Remove(k Comparable) interface{} { + return s.remove(s.terminus, k) +} + +func (s *SkipList) Len() uint { + return s.length +} + +// NB: this destroys t. Do not use t after this. +func (s *SkipList) Merge(t *SkipList) { + // defer s.validate() + + cur := s.terminus + for n := t.First(); n != nil; { + m := n.Next() // need to save this out before we destroy it in the insert + cur = s.insert(cur, n.Key, n.Value, n) + n = m + } +} + +func (s *SkipList) validate() { + visited := make(map[*Node]bool, int(s.length)) + cur := s.terminus + visited[cur] = true + l := uint(0) + for { + if cur != s.terminus { + l++ + } + if cur._next().prev != cur { + panic(fmt.Sprintf("Node (%v) has next pointer to %v, which has prev pointer to %v", cur, cur._next(), cur._next().prev)) + } + if cur.prev._next() != cur { + panic(fmt.Sprintf("Node (%v) has prev pointer to %v, which has next pointer to %v", cur, cur.prev, cur.prev._next())) + } + for h, n := range cur.nexts { + if h >= len(n.nexts) { + panic(fmt.Sprintf("Node (%v) has next pointer at level %v pointing down to node (%v) which has %v height", cur, h, n, len(n.nexts))) + } + } + n := cur._next() + if n == s.terminus { + break + } + if visited[n] { + panic(fmt.Sprintf("Node (%v) has next as %v which is already visited!", cur, n)) + } + if cur != s.terminus && !cur.Key.LessThan(n.Key) { + panic(fmt.Sprintf("Node keys in wrong order: expecting %v < %v", cur.Key, n.Key)) + } + if n.prev != cur { + panic(fmt.Sprintf("Node (%v) has next (%v) which does not point back correctly", cur, n)) + } + cur = n + } + if l != s.length { + panic(fmt.Sprintf("length is wrong: counted %v but length is %v", l, s.length)) + } +} + +func (n *Node) Get(k Comparable) *Node { + m, _ := n.skiplist.getEqOrLessThan(n, k, false) + if m != n.skiplist.terminus && m.Key.Equal(k) { + return m + } else { + return nil + } +} + +func (n *Node) Insert(k Comparable, v interface{}) *Node { + return n.skiplist.insert(n, k, v, nil) +} + +func (n *Node) Remove() interface{} { + return n.skiplist.remove(n, n.Key) +} + +func (n *Node) _next() *Node { + return n.nexts[0] +} + +func (n *Node) Next() *Node { + if m := n.nexts[0]; m != n.skiplist.terminus { + return m + } else { + return nil + } +} + +func (n *Node) Prev() *Node { + if m := n.prev; m != n.skiplist.terminus { + return m + } else { + return nil + } +} + +func (n *Node) Reposition(k Comparable) { + n.skiplist.reposition(n, k) +} + +func (n *Node) nullify() { + // this is called when n is removed from the skiplist. It's really + // just to ensure that if someone has a reference to n lying + // around, they can't use it. + n.prev = nil + n.nexts = nil + n.skiplist = nil +} + +func (s *SkipList) String() string { + strs := make([]string, 1, s.length+1) + strs[0] = fmt.Sprint(s.terminus) + for cur := s.terminus._next(); cur != s.terminus; cur = cur._next() { + strs = append(strs, fmt.Sprint(cur)) + } + return fmt.Sprintf("Skiplist of length %v (counted: %v), levelProbabilities %v, and nodes:\n\t[%v]", + s.length, len(strs)-1, s.levelProbabilities, strings.Join(strs, ",\n\t ")) +} + +func (n *Node) String() string { + strs := make([]string, len(n.nexts)) + for idx := 0; idx < len(strs); idx++ { + strs[idx] = fmt.Sprint(n.nexts[idx].Key) + } + return fmt.Sprintf("%v -> %v (nexts: [%v])", n.Key, n.Value, strings.Join(strs, ", ")) +} diff --git a/experimental/tracer/vendor/github.com/msackman/skiplist/skiplist_test.go b/experimental/tracer/vendor/github.com/msackman/skiplist/skiplist_test.go new file mode 100644 index 000000000..84bf112ed --- /dev/null +++ b/experimental/tracer/vendor/github.com/msackman/skiplist/skiplist_test.go @@ -0,0 +1,315 @@ +package skiplist + +import ( + "math/rand" + "os" + "strconv" + "testing" +) + +type intKey int + +func (sk intKey) LessThan(b Comparable) bool { + return sk < b.(intKey) +} + +func (sk intKey) Equal(b Comparable) bool { + return sk == b.(intKey) +} + +const ( + keyValsLen = 1000000 +) + +var ( + rng = rand.New(rand.NewSource(0)) + keyVals = make(map[intKey]string) + indices = make([]intKey, keyValsLen) +) + +func TestAddFromEmptyRoot(t *testing.T) { + for idx := 0; idx < 10; idx++ { + s := New(rng) + for idy := 0; idy < idx; idy++ { + k := indices[idy] + v := keyVals[k] + n := s.Insert(k, v) + if n.Key != k || n.Value != v { + t.Fatal("Key or Value of inserted pair changed!", k, v, n) + } + if m := s.Get(k); n != m { + t.Fatal("Node changed for just inserted value:", n, m) + } + if s.Len() != uint(idy+1) { + t.Fatal("Incorrect length") + } + } + } +} + +func TestAddFromEmptyRel(t *testing.T) { + for idx := 0; idx < 10; idx++ { + s := New(rng) + var n *Node + for idy := 0; idy < idx; idy++ { + k := indices[idy] + v := keyVals[k] + if n == nil { + n = s.Insert(k, v) + } else { + n = n.Insert(k, v) + } + if n.Key != k || n.Value != v { + t.Fatal("Key or Value of inserted pair changed!", k, v, n) + } + if m := n.Get(k); n != m { + t.Fatal("Node changed for just inserted value:", n, m) + } + if p := n.Prev(); p != nil { + if m := p.Get(k); n != m { + t.Fatal("Node changed for just inserted value:", n, m) + } + } + if s.Len() != uint(idy+1) { + t.Fatal("Incorrect length") + } + } + } +} + +func TestDupInsert(t *testing.T) { + s := New(rng) + for idx := 0; idx < 10; idx++ { + for idy := 0; idy < idx; idy++ { + k := indices[idy] + v := keyVals[k] + if n := s.Insert(k, v); n.Key != k || n.Value != v { + t.Fatal("Key or Value of inserted pair changed!", k, v, n) + } + } + } +} + +func TestGetMissingEmpty(t *testing.T) { + s := New(rng) + for idx := 0; idx < 10; idx++ { + k := indices[idx] + if n := s.Get(k); n != nil { + t.Fatal("Expected not to find elem") + } + } +} + +func TestGetMissingNonEmpty(t *testing.T) { + s := New(rng) + for idx := 0; idx < 20; idx++ { + k := indices[idx] + v := keyVals[k] + if idx%2 == 0 { + s.Insert(k, v) + } else { + if n := s.Get(k); n != nil { + t.Fatal("Expected not to find elem") + } + } + } +} + +func TestRemoveRoot(t *testing.T) { + s := New(rng) + for idx := 0; idx < 20; idx++ { + k := indices[idx] + v := keyVals[k] + s.Insert(k, v) + } + for idx := 0; idx < 20; idx++ { + k := indices[idx] + v := keyVals[k] + if u := s.Remove(k); u != v { + t.Fatal("Wrong value returned:", u, v) + } + if int(s.Len()) != 19-idx { + t.Fatal("Wrong length") + } + } +} + +func TestRemoveSelf(t *testing.T) { + s := New(rng) + ns := []*Node{} + for idx := 0; idx < 20; idx++ { + k := indices[idx] + v := keyVals[k] + ns = append(ns, s.Insert(k, v)) + } + for idx, n := range ns { + k := indices[idx] + v := keyVals[k] + if u := n.Remove(); u != v { + t.Fatal("Wrong value returned:", u, v) + } + if int(s.Len()) != len(ns)-idx-1 { + t.Fatal("Wrong length") + } + } +} + +func TestRemoveMissing(t *testing.T) { + s := New(rng) + for idx := 0; idx < 20; idx++ { + k := indices[idx] + v := keyVals[k] + s.Insert(k, v) + } + for idx := 0; idx < 20; idx++ { + for idy := 0; idy < idx; idy++ { + k := indices[idy] + v := keyVals[k] + u := s.Remove(k) + if idy+1 == idx { + if u != v { + t.Fatal("Wrong value returned:", u, v) + } + } else { + if u != nil { + t.Fatal("Wrong value returned - expected nil:", u) + } + } + } + } + if s.Len() != 1 { + t.Fatal("Wrong length") + } +} + +func TestFirstLast(t *testing.T) { + s := New(rng) + if s.First() != nil || s.Last() != nil { + t.Fatal("Expected nil for First and Last on empty list") + } + var min, max intKey + for idx := 0; idx < 200; idx++ { + k := indices[idx] + v := keyVals[k] + s.Insert(k, v) + if idx == 0 { + min, max = k, k + } else { + if k < min { + min = k + } + if k > max { + max = k + } + } + } + if f := s.First(); f.Key != min { + t.Fatal("Did not get minimum key back for first", min, f) + } + if l := s.Last(); l.Key != max { + t.Fatal("Did not get maximum key back for last", max, l) + } +} + +func TestMerge(t *testing.T) { + s0 := New(rng) + s1 := New(rng) + lim := 1000 + for idx := 0; idx < lim; idx++ { + if idx%2 == 0 { + s0.Insert(intKey(idx), idx) + } else { + s1.Insert(intKey(idx), idx) + } + } + s0.Merge(s1) + if int(s0.Len()) != lim { + t.Fatal("Wrong len after merge", s0.Len()) + } + cur := s0.First() + for idx := 0; idx < lim; idx++ { + if cur.Value.(int) != idx { + t.Fatal("Wrong value: ", cur.Value) + } + if cur != s0.Get(cur.Key) { + t.Fatal("Internal failure: ", cur) + } + cur = cur.Next() + } +} + +func TestReposition(t *testing.T) { + s := New(rng) + lim := 200 + for idx := 0; idx < lim; idx++ { + s.Insert(intKey(idx*5), idx) + } + for idx := lim - 1; idx >= 0; idx-- { + n := s.Get(intKey(idx * 5)) + if n == nil { + t.Fatal("Unable to find node") + } + n.Reposition(intKey((idx * 5) - 11)) + } + n := s.First() + for idx := 0; idx < lim; idx++ { + if n.Value != idx { + t.Fatal("Wrong value", idx, n) + } + n = n.Next() + } + if n != nil { + t.Fatal("Too many values!") + } +} + +func BenchmarkAdd08192(b *testing.B) { benchmarkAdd(8192, b) } +func BenchmarkAdd16384(b *testing.B) { benchmarkAdd(16384, b) } +func BenchmarkAdd32768(b *testing.B) { benchmarkAdd(32768, b) } +func BenchmarkAdd65536(b *testing.B) { benchmarkAdd(65536, b) } + +func benchmarkAdd(initial int, b *testing.B) { + s := populate(New(rng), 0, initial) + b.ResetTimer() + populateFast(s, initial, b.N) +} + +func BenchmarkGet08192(b *testing.B) { benchmarkGet(8192, b) } +func BenchmarkGet16384(b *testing.B) { benchmarkGet(16384, b) } +func BenchmarkGet32768(b *testing.B) { benchmarkGet(32768, b) } +func BenchmarkGet65536(b *testing.B) { benchmarkGet(65536, b) } + +func benchmarkGet(initial int, b *testing.B) { + s := populate(New(rng), 0, initial) + b.ResetTimer() + for idx := 0; idx < b.N; idx++ { + s.Get(indices[idx%initial]) + } +} + +func populate(s *SkipList, offset, lim int) *SkipList { + for idx := 0; idx < lim; idx++ { + k := indices[(offset+idx)%len(indices)] + v := keyVals[k] + s.Insert(k, v) + } + return s +} + +func populateFast(s *SkipList, offset, lim int) *SkipList { + for idx := 0; idx < lim; idx++ { + n := idx + offset + s.Insert(intKey(n), n) + } + return s +} + +func TestMain(m *testing.M) { + for idx := 0; idx < keyValsLen; idx++ { + keyVals[intKey(idx)] = strconv.FormatInt(int64(idx), 3) + } + for idx, k := range rand.Perm(keyValsLen) { + indices[idx] = intKey(k) + } + os.Exit(m.Run()) +} diff --git a/experimental/tracer/vendor/manifest b/experimental/tracer/vendor/manifest new file mode 100644 index 000000000..0005f2ddc --- /dev/null +++ b/experimental/tracer/vendor/manifest @@ -0,0 +1,11 @@ +{ + "version": 0, + "dependencies": [ + { + "importpath": "github.com/msackman/skiplist", + "repository": "https://github.com/msackman/skiplist", + "revision": "57733164b18444c51f63e9a80f1693961dde8036", + "branch": "master" + } + ] +} \ No newline at end of file