diff --git a/common/xfer/plugin_spec.go b/common/xfer/plugin_spec.go index 17dc2372b9..45ff6961c5 100644 --- a/common/xfer/plugin_spec.go +++ b/common/xfer/plugin_spec.go @@ -7,8 +7,8 @@ import ( "sort" "github.com/davecgh/go-spew/spew" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" "github.com/weaveworks/scope/test/reflect" ) diff --git a/report/counters.go b/report/counters.go index 35f2c228e0..48919ae606 100644 --- a/report/counters.go +++ b/report/counters.go @@ -7,8 +7,8 @@ import ( "reflect" "sort" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" ) // Counters is a string->int map. diff --git a/report/edge_metadatas.go b/report/edge_metadatas.go index 4540d4ebf8..fd8d7a4487 100644 --- a/report/edge_metadatas.go +++ b/report/edge_metadatas.go @@ -8,8 +8,8 @@ import ( "sort" "strconv" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" ) // EdgeMetadatas collect metadata about each edge in a topology. Keys are the diff --git a/report/latest_map.go b/report/latest_map.go index 28c1d1b5ea..d45e119c7c 100644 --- a/report/latest_map.go +++ b/report/latest_map.go @@ -2,13 +2,12 @@ package report import ( "bytes" - "encoding/gob" "fmt" "sort" "time" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" ) // LatestMap is a persitent map which support latest-win merges. We have to @@ -169,7 +168,7 @@ func (m LatestMap) DeepEqual(n LatestMap) bool { } func (m LatestMap) toIntermediate() map[string]LatestEntry { - intermediate := map[string]LatestEntry{} + intermediate := make(map[string]LatestEntry, m.Size()) if m.Map != nil { m.Map.ForEach(func(key string, val interface{}) { intermediate[key] = val.(LatestEntry) @@ -178,14 +177,6 @@ func (m LatestMap) toIntermediate() map[string]LatestEntry { return intermediate } -func (m LatestMap) fromIntermediate(in map[string]LatestEntry) LatestMap { - out := ps.NewMap() - for k, v := range in { - out = out.Set(k, v) - } - return LatestMap{out} -} - // CodecEncodeSelf implements codec.Selfer func (m *LatestMap) CodecEncodeSelf(encoder *codec.Encoder) { if m.Map != nil { @@ -233,7 +224,7 @@ func (m *LatestMap) CodecDecodeSelf(decoder *codec.Decoder) { decoder.Decode(&value) } - out = out.Set(key, value) + out = out.UnsafeMutableSet(key, value) } z.DecSendContainerState(containerMapEnd) *m = LatestMap{out} @@ -248,20 +239,3 @@ func (LatestMap) MarshalJSON() ([]byte, error) { func (*LatestMap) UnmarshalJSON(b []byte) error { panic("UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead") } - -// GobEncode implements gob.Marshaller -func (m LatestMap) GobEncode() ([]byte, error) { - buf := bytes.Buffer{} - err := gob.NewEncoder(&buf).Encode(m.toIntermediate()) - return buf.Bytes(), err -} - -// GobDecode implements gob.Unmarshaller -func (m *LatestMap) GobDecode(input []byte) error { - in := map[string]LatestEntry{} - if err := gob.NewDecoder(bytes.NewBuffer(input)).Decode(&in); err != nil { - return err - } - *m = LatestMap{}.fromIntermediate(in) - return nil -} diff --git a/report/latest_map_internal_test.go b/report/latest_map_internal_test.go index ce8755e7e8..b5072f8b23 100644 --- a/report/latest_map_internal_test.go +++ b/report/latest_map_internal_test.go @@ -163,67 +163,39 @@ func TestLatestMapEncoding(t *testing.T) { Set("foo", now, "bar"). Set("bar", now, "baz") - { - gobs, err := want.GobEncode() - if err != nil { - t.Fatal(err) - } + for _, h := range []codec.Handle{ + codec.Handle(&codec.MsgpackHandle{}), + codec.Handle(&codec.JsonHandle{}), + } { + buf := &bytes.Buffer{} + encoder := codec.NewEncoder(buf, h) + want.CodecEncodeSelf(encoder) + decoder := codec.NewDecoder(buf, h) have := EmptyLatestMap - have.GobDecode(gobs) + have.CodecDecodeSelf(decoder) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } } - { - - for _, h := range []codec.Handle{ - codec.Handle(&codec.MsgpackHandle{}), - codec.Handle(&codec.JsonHandle{}), - } { - buf := &bytes.Buffer{} - encoder := codec.NewEncoder(buf, h) - want.CodecEncodeSelf(encoder) - decoder := codec.NewDecoder(buf, h) - have := EmptyLatestMap - have.CodecDecodeSelf(decoder) - if !reflect.DeepEqual(want, have) { - t.Error(test.Diff(want, have)) - } - } - } } func TestLatestMapEncodingNil(t *testing.T) { want := LatestMap{} - { - gobs, err := want.GobEncode() - if err != nil { - t.Fatal(err) - } + for _, h := range []codec.Handle{ + codec.Handle(&codec.MsgpackHandle{}), + codec.Handle(&codec.JsonHandle{}), + } { + buf := &bytes.Buffer{} + encoder := codec.NewEncoder(buf, h) + want.CodecEncodeSelf(encoder) + decoder := codec.NewDecoder(buf, h) have := EmptyLatestMap - have.GobDecode(gobs) - if have.Map == nil { - t.Error("Decoded LatestMap.psMap should not be nil") + have.CodecDecodeSelf(decoder) + if !reflect.DeepEqual(want, have) { + t.Error(test.Diff(want, have)) } } - { - - for _, h := range []codec.Handle{ - codec.Handle(&codec.MsgpackHandle{}), - codec.Handle(&codec.JsonHandle{}), - } { - buf := &bytes.Buffer{} - encoder := codec.NewEncoder(buf, h) - want.CodecEncodeSelf(encoder) - decoder := codec.NewDecoder(buf, h) - have := EmptyLatestMap - have.CodecDecodeSelf(decoder) - if !reflect.DeepEqual(want, have) { - t.Error(test.Diff(want, have)) - } - } - } } diff --git a/report/metrics.go b/report/metrics.go index 82b58826dc..8b66dcb6af 100644 --- a/report/metrics.go +++ b/report/metrics.go @@ -6,8 +6,8 @@ import ( "math" "time" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" ) // Metrics is a string->metric map. diff --git a/report/node_set.go b/report/node_set.go index 695dd6fc4f..c0e5c71685 100644 --- a/report/node_set.go +++ b/report/node_set.go @@ -7,8 +7,8 @@ import ( "sort" "github.com/davecgh/go-spew/spew" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" "github.com/weaveworks/scope/test/reflect" ) diff --git a/report/sets.go b/report/sets.go index 2fc68fa878..bd363e95eb 100644 --- a/report/sets.go +++ b/report/sets.go @@ -7,8 +7,8 @@ import ( "reflect" "sort" - "github.com/mndrix/ps" "github.com/ugorji/go/codec" + "github.com/weaveworks/ps" ) // Sets is a string->set-of-strings map. diff --git a/vendor/github.com/mndrix/ps/README.md b/vendor/github.com/mndrix/ps/README.md deleted file mode 100644 index 3d93018c84..0000000000 --- a/vendor/github.com/mndrix/ps/README.md +++ /dev/null @@ -1,8 +0,0 @@ -ps -== - -Persistent data structures for Go. See the [full package documentation](http://godoc.org/github.com/mndrix/ps) - -Install with - - go get github.com/mndrix/ps diff --git a/vendor/github.com/mndrix/ps/list_test.go b/vendor/github.com/mndrix/ps/list_test.go deleted file mode 100644 index 3eab4a7e83..0000000000 --- a/vendor/github.com/mndrix/ps/list_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package ps - -import "testing" - -func TestListImmutable(t *testing.T) { - // build some lists - one := NewList().Cons("first") - two := one.Cons("second") - zwei := one.Cons("zweite") - - // check each list's length - if size := one.Size(); size != 1 { - t.Errorf("one doesn't have 1 item, it has %d", size) - } - if size := two.Size(); size != 2 { - t.Errorf("two doesn't have 2 items, it has %d", size) - } - if size := zwei.Size(); size != 2 { - t.Errorf("zwei doesn't have 2 item, it has %d", size) - } - - // check each list's contents - if one.Head() != "first" { - t.Errorf("one has the wrong head") - } - if two.Head() != "second" { - t.Errorf("two has the wrong head") - } - if two.Tail().Head() != "first" { - t.Errorf("two has the wrong ending") - } - if zwei.Head() != "zweite" { - t.Errorf("zwei has the wrong head") - } - if zwei.Tail().Head() != "first" { - t.Errorf("zwei has the wrong ending") - } -} - -// benchmark making a really long list -func BenchmarkListCons(b *testing.B) { - l := NewList() - for i := 0; i < b.N; i++ { - l = l.Cons(i) - } -} diff --git a/vendor/github.com/mndrix/ps/map_test.go b/vendor/github.com/mndrix/ps/map_test.go deleted file mode 100644 index e780e6b6ea..0000000000 --- a/vendor/github.com/mndrix/ps/map_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package ps - -import . "strconv" - -import "testing" -import "sort" - -func TestMapNil(t *testing.T) { - m := NewMap() - keys := m.Keys() - if len(keys) != 0 { - t.Errorf("Empty map has keys") - } -} - -func TestMapImmutable(t *testing.T) { - // build a couple small maps - world := NewMap().Set("hello", "world") - kids := world.Set("hello", "kids") - - // both maps should still retain their data - if v, _ := world.Lookup("hello"); v != "world" { - t.Errorf("Set() modified the receiving map") - } - if size := world.Size(); size != 1 { - t.Errorf("world size is not 1 : %d", size) - } - if v, _ := kids.Lookup("hello"); v != "kids" { - t.Errorf("Set() did not modify the resulting map") - } - if size := kids.Size(); size != 1 { - t.Errorf("kids size is not 1 : %d", size) - } - - // both maps have the right keys - if keys := world.Keys(); len(keys) != 1 || keys[0] != "hello" { - t.Errorf("world has the wrong keys: %#v", keys) - } - if keys := kids.Keys(); len(keys) != 1 || keys[0] != "hello" { - t.Errorf("kids has the wrong keys: %#v", keys) - } - - // test deletion - empty := kids.Delete("hello") - if size := empty.Size(); size != 0 { - t.Errorf("empty size is not 1 : %d", size) - } - if keys := empty.Keys(); len(keys) != 0 { - t.Errorf("empty has the wrong keys: %#v", keys) - } -} - -func TestMapMultipleKeys(t *testing.T) { - // map with multiple keys each with pointer values - one := 1 - two := 2 - three := 3 - m := NewMap().Set("one", &one).Set("two", &two).Set("three", &three) - - // do we have the right number of keys? - keys := m.Keys() - if len(keys) != 3 { - t.Logf("wrong size keys: %d", len(keys)) - t.FailNow() - } - - // do we have the right keys? - sort.Strings(keys) - if keys[0] != "one" { - t.Errorf("unexpected key: %s", keys[0]) - } - if keys[1] != "three" { - t.Errorf("unexpected key: %s", keys[1]) - } - if keys[2] != "two" { - t.Errorf("unexpected key: %s", keys[2]) - } - - // do we have the right values? - vp, ok := m.Lookup("one") - if !ok { - t.Logf("missing value for one") - t.FailNow() - } - if v := vp.(*int); *v != 1 { - t.Errorf("wrong value: %d\n", *v) - } - vp, ok = m.Lookup("two") - if !ok { - t.Logf("missing value for two") - t.FailNow() - } - if v := vp.(*int); *v != 2 { - t.Errorf("wrong value: %d\n", *v) - } - vp, ok = m.Lookup("three") - if !ok { - t.Logf("missing value for three") - t.FailNow() - } - if v := vp.(*int); *v != 3 { - t.Errorf("wrong value: %d\n", *v) - } -} - -func TestMapManyKeys(t *testing.T) { - // build a map with many keys and values - count := 100 - m := NewMap() - for i := 0; i < count; i++ { - m = m.Set(Itoa(i), i) - } - - if m.Size() != 100 { - t.Errorf("Wrong number of keys: %d", m.Size()) - } - - m = m.Delete("42").Delete("7").Delete("19").Delete("99") - if m.Size() != 96 { - t.Errorf("Wrong number of keys: %d", m.Size()) - } - - for i := 43; i < 99; i++ { - v, ok := m.Lookup(Itoa(i)) - if !ok || v != i { - t.Errorf("Wrong value for key %d", i) - } - } -} - -func TestMapHashKey(t *testing.T) { - hash := hashKey("this is a key") - if hash != 10424450902216330915 { - t.Errorf("This isn't FNV-1a hashing: %d", hash) - } -} - -func BenchmarkMapSet(b *testing.B) { - m := NewMap() - for i := 0; i < b.N; i++ { - m = m.Set("foo", i) - } -} - -func BenchmarkMapDelete(b *testing.B) { - m := NewMap().Set("key", "value") - for i := 0; i < b.N; i++ { - m.Delete("key") - } -} - -func BenchmarkHashKey(b *testing.B) { - key := "this is a key" - for i := 0; i < b.N; i++ { - _ = hashKey(key) - } -} diff --git a/vendor/github.com/mndrix/ps/profile.sh b/vendor/github.com/mndrix/ps/profile.sh deleted file mode 100644 index f03df05a5a..0000000000 --- a/vendor/github.com/mndrix/ps/profile.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -go test -c -./ps.test -test.run=none -test.bench=$2 -test.$1profile=$1.profile diff --git a/vendor/github.com/mndrix/ps/LICENSE b/vendor/github.com/weaveworks/ps/LICENSE similarity index 100% rename from vendor/github.com/mndrix/ps/LICENSE rename to vendor/github.com/weaveworks/ps/LICENSE diff --git a/vendor/github.com/mndrix/ps/list.go b/vendor/github.com/weaveworks/ps/list.go similarity index 100% rename from vendor/github.com/mndrix/ps/list.go rename to vendor/github.com/weaveworks/ps/list.go diff --git a/vendor/github.com/mndrix/ps/map.go b/vendor/github.com/weaveworks/ps/map.go similarity index 77% rename from vendor/github.com/mndrix/ps/map.go rename to vendor/github.com/weaveworks/ps/map.go index 66a4edf32c..98918bff3f 100644 --- a/vendor/github.com/mndrix/ps/map.go +++ b/vendor/github.com/weaveworks/ps/map.go @@ -12,6 +12,7 @@ package ps import ( "bytes" "fmt" + "unsafe" ) // A Map associates unique keys (type string) with values (type Any). @@ -25,6 +26,13 @@ type Map interface { // This operation is O(log N) in the number of keys. Set(key string, value interface{}) Map + // UnsafeMutableSet returns the same map in which key and value are associated in-place. + // If the key didn't exist before, it's created; otherwise, the + // associated value is changed. + // This operation is O(log N) in the number of keys. + // Only use UnsafeMutableSet if you are the only reference-holder of the Map. + UnsafeMutableSet(key string, value interface{}) Map + // Delete returns a new map with the association for key, if any, removed. // This operation is O(log N) in the number of keys. Delete(key string) Map @@ -96,11 +104,38 @@ const ( prime64 uint64 = 1099511628211 ) +type unsafeString struct { + Data uintptr + Len int +} + +type unsafeSlice struct { + Data uintptr + Len int + Cap int +} + +var zeroByteSlice = []byte{} + +// bytesView returns a view of the string as a []byte. +// It doesn't incur allocation and copying caused by conversion but it's +// unsafe, use with care. +func bytesView(v string) []byte { + if len(v) == 0 { + return zeroByteSlice + } + + sx := (*unsafeString)(unsafe.Pointer(&v)) + bx := unsafeSlice{sx.Data, sx.Len, sx.Len} + return *(*[]byte)(unsafe.Pointer(&bx)) +} + // hashKey returns a hash code for a given string func hashKey(key string) uint64 { hash := offset64 - for _, codepoint := range key { - hash ^= uint64(codepoint) + + for _, b := range bytesView(key) { + hash ^= uint64(b) hash *= prime64 } return hash @@ -128,7 +163,10 @@ func setLowLevel(self *tree, partialHash, hash uint64, key string, value interfa m := self.clone() i := partialHash % childCount m.children[i] = setLowLevel(self.children[i], partialHash>>shiftSize, hash, key, value) - recalculateCount(m) + // update count if we added a new object + if m.children[i].count > self.children[i].count { + m.count++ + } return m } @@ -144,6 +182,45 @@ func setLowLevel(self *tree, partialHash, hash uint64, key string, value interfa return m } +// UnsafeMutableSet is the in-place mutable version of Set. Only use if +// you are the only reference-holder of the Map. +func (self *tree) UnsafeMutableSet(key string, value interface{}) Map { + hash := hashKey(key) + return mutableSetLowLevel(self, hash, hash, key, value) +} + +func mutableSetLowLevel(self *tree, partialHash, hash uint64, key string, value interface{}) *tree { + if self.IsNil() { // an empty tree is easy + m := self.clone() + m.count = 1 + m.hash = hash + m.key = key + m.value = value + return m + } + + if hash != self.hash { + i := partialHash % childCount + oldChildCount := self.children[i].count + self.children[i] = mutableSetLowLevel(self.children[i], partialHash>>shiftSize, hash, key, value) + // update count if we added a new object + if oldChildCount < self.children[i].count { + self.count++ + } + return self + } + + // did we find a hash collision? + if key != self.key { + oops := fmt.Sprintf("Hash collision between: '%s' and '%s'. Please report to https://github.com/mndrix/ps/issues/new", self.key, key) + panic(oops) + } + + // replacing a key's previous value + self.value = value + return self +} + // modifies a map by recalculating its key count based on the counts // of its subtrees func recalculateCount(m *tree) { diff --git a/vendor/manifest b/vendor/manifest index 5b8e12c7a5..9d33dc8f2a 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -939,13 +939,6 @@ "revision": "3d66e3747d22a77b24b119eb66e9d574ed99f86c", "branch": "master" }, - { - "importpath": "github.com/mndrix/ps", - "repository": "https://github.com/mndrix/ps", - "vcs": "", - "revision": "35fef6f28be7e47a87d8a71ef5b80cbf2c4c167a", - "branch": "master" - }, { "importpath": "github.com/nats-io/gnatsd/auth", "repository": "https://github.com/nats-io/gnatsd", @@ -1206,6 +1199,14 @@ "branch": "master", "path": "/odp" }, + { + "importpath": "github.com/weaveworks/ps", + "repository": "https://github.com/weaveworks/ps", + "vcs": "git", + "revision": "70d17b2d6f760345ef36a0748751eddf7290a92c", + "branch": "master", + "notests": true + }, { "importpath": "github.com/weaveworks/weave/common", "repository": "https://github.com/weaveworks/weave",