diff --git a/hack/vendor.sh b/hack/vendor.sh index 50cff1690f49e5b586060d43a1b756750e38ff9d..4e8bbefc05a70fcc2c0f6a9db5453448a8cfc5e5 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -45,7 +45,7 @@ clone git github.com/gorilla/context 14f550f51a clone git github.com/gorilla/mux e444e69cbd -clone git github.com/tchap/go-patricia v1.0.1 +clone git github.com/tchap/go-patricia v2.1.0 clone hg code.google.com/p/go.net 84a4013f96e0 diff --git a/pkg/truncindex/truncindex.go b/pkg/truncindex/truncindex.go index 73c7e24fb47e2027b1dd1e4024ac2b1cd52a90a8..9aae5c0d08f5efa3effa35dcd4fe9492d72e9208 100644 --- a/pkg/truncindex/truncindex.go +++ b/pkg/truncindex/truncindex.go @@ -14,12 +14,6 @@ var ( ErrAmbiguousPrefix = errors.New("Multiple IDs found with provided prefix") ) -func init() { - // Change patricia max prefix per node length, - // because our len(ID) always 64 - patricia.MaxPrefixPerNode = 64 -} - // TruncIndex allows the retrieval of string identifiers by any of their unique prefixes. // This is used to retrieve image and container IDs by more convenient shorthand prefixes. type TruncIndex struct { @@ -31,8 +25,11 @@ type TruncIndex struct { // NewTruncIndex creates a new TruncIndex and initializes with a list of IDs func NewTruncIndex(ids []string) (idx *TruncIndex) { idx = &TruncIndex{ - ids: make(map[string]struct{}), - trie: patricia.NewTrie(), + ids: make(map[string]struct{}), + + // Change patricia max prefix per node length, + // because our len(ID) always 64 + trie: patricia.NewTrie(patricia.MaxPrefixPerNode(64)), } for _, id := range ids { idx.addID(id) diff --git a/vendor/src/github.com/tchap/go-patricia/README.md b/vendor/src/github.com/tchap/go-patricia/README.md index 11ee4612d326f19fcfa7efa370429d0ae0b57390..9d6ebc43a58895aaa1a6dd521dc82b2fc55cfec4 100644 --- a/vendor/src/github.com/tchap/go-patricia/README.md +++ b/vendor/src/github.com/tchap/go-patricia/README.md @@ -50,9 +50,12 @@ printItem := func(prefix patricia.Prefix, item patricia.Item) error { return nil } -// Create a new tree. +// Create a new default trie (using the default parameter values). trie := NewTrie() +// Create a new custom trie. +trie := NewTrie(MaxPrefixPerNode(16), MaxChildrenPerSparseNode(10)) + // Insert some items. trie.Insert(Prefix("Pepa Novak"), 1) trie.Insert(Prefix("Pepa Sindelar"), 2) @@ -67,12 +70,12 @@ key = Prefix("Karel") fmt.Printf("Anybody called %q here? %v\n", key, trie.MatchSubtree(key)) // Anybody called "Karel" here? true -// Walk the tree. +// Walk the tree in alphabetical order. trie.Visit(printItem) +// "Karel Hynek Macha": 4 +// "Karel Macha": 3 // "Pepa Novak": 1 // "Pepa Sindelar": 2 -// "Karel Macha": 3 -// "Karel Hynek Macha": 4 // Walk a subtree. trie.VisitSubtree(Prefix("Pepa"), printItem) @@ -96,8 +99,8 @@ trie.Delete(Prefix("Karel Macha")) // Walk again. trie.Visit(printItem) -// "Pepa Sindelar": 2 // "Karel Hynek Macha": 10 +// "Pepa Sindelar": 2 // Delete a subtree. trie.DeleteSubtree(Prefix("Pepa")) diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/children.go b/vendor/src/github.com/tchap/go-patricia/patricia/children.go index 07d332633514b2fee1675be1aa7815ec3d6c8360..a204b0c8a905c96ba6aeded9b713062f0c26ffbb 100644 --- a/vendor/src/github.com/tchap/go-patricia/patricia/children.go +++ b/vendor/src/github.com/tchap/go-patricia/patricia/children.go @@ -5,11 +5,7 @@ package patricia -// Max prefix length that is kept in a single trie node. -var MaxPrefixPerNode = 10 - -// Max children to keep in a node in the sparse mode. -const MaxChildrenPerSparseNode = 8 +import "sort" type childList interface { length() int @@ -21,13 +17,28 @@ type childList interface { walk(prefix *Prefix, visitor VisitorFunc) error } +type tries []*Trie + +func (t tries) Len() int { + return len(t) +} + +func (t tries) Less(i, j int) bool { + strings := sort.StringSlice{string(t[i].prefix), string(t[j].prefix)} + return strings.Less(0, 1) +} + +func (t tries) Swap(i, j int) { + t[i], t[j] = t[j], t[i] +} + type sparseChildList struct { - children []*Trie + children tries } -func newSparseChildList() childList { +func newSparseChildList(maxChildrenPerSparseNode int) childList { return &sparseChildList{ - children: make([]*Trie, 0, MaxChildrenPerSparseNode), + children: make(tries, 0, DefaultMaxChildrenPerSparseNode), } } @@ -82,6 +93,9 @@ func (list *sparseChildList) next(b byte) *Trie { } func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error { + + sort.Sort(list.children) + for _, child := range list.children { *prefix = append(*prefix, child.prefix...) if child.item != nil { diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go index 8fcbcdf426c60bab0833761a815fb1322c40f51f..a8c3786b62ec6576fe2ab3afb5ff6e70ed5e4c7b 100644 --- a/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go @@ -13,6 +13,11 @@ import ( // Trie //------------------------------------------------------------------------------ +const ( + DefaultMaxPrefixPerNode = 10 + DefaultMaxChildrenPerSparseNode = 8 +) + type ( Prefix []byte Item interface{} @@ -27,15 +32,44 @@ type Trie struct { prefix Prefix item Item + maxPrefixPerNode int + maxChildrenPerSparseNode int + children childList } // Public API ------------------------------------------------------------------ +type Option func(*Trie) + // Trie constructor. -func NewTrie() *Trie { - return &Trie{ - children: newSparseChildList(), +func NewTrie(options ...Option) *Trie { + trie := &Trie{} + + for _, opt := range options { + opt(trie) + } + + if trie.maxPrefixPerNode <= 0 { + trie.maxPrefixPerNode = DefaultMaxPrefixPerNode + } + if trie.maxChildrenPerSparseNode <= 0 { + trie.maxChildrenPerSparseNode = DefaultMaxChildrenPerSparseNode + } + + trie.children = newSparseChildList(trie.maxChildrenPerSparseNode) + return trie +} + +func MaxPrefixPerNode(value int) Option { + return func(trie *Trie) { + trie.maxPrefixPerNode = value + } +} + +func MaxChildrenPerSparseNode(value int) Option { + return func(trie *Trie) { + trie.maxChildrenPerSparseNode = value } } @@ -85,7 +119,8 @@ func (trie *Trie) MatchSubtree(key Prefix) (matched bool) { return } -// Visit calls visitor on every node containing a non-nil item. +// Visit calls visitor on every node containing a non-nil item +// in alphabetical order. // // If an error is returned from visitor, the function stops visiting the tree // and returns that error, unless it is a special error - SkipSubtree. In that @@ -233,7 +268,7 @@ func (trie *Trie) DeleteSubtree(prefix Prefix) (deleted bool) { // If we are in the root of the trie, reset the trie. if parent == nil { root.prefix = nil - root.children = newSparseChildList() + root.children = newSparseChildList(trie.maxPrefixPerNode) return true } @@ -257,12 +292,12 @@ func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) { ) if node.prefix == nil { - if len(key) <= MaxPrefixPerNode { + if len(key) <= trie.maxPrefixPerNode { node.prefix = key goto InsertItem } - node.prefix = key[:MaxPrefixPerNode] - key = key[MaxPrefixPerNode:] + node.prefix = key[:trie.maxPrefixPerNode] + key = key[trie.maxPrefixPerNode:] goto AppendChild } @@ -306,14 +341,14 @@ AppendChild: // This loop starts with empty node.prefix that needs to be filled. for len(key) != 0 { child := NewTrie() - if len(key) <= MaxPrefixPerNode { + if len(key) <= trie.maxPrefixPerNode { child.prefix = key node.children = node.children.add(child) node = child goto InsertItem } else { - child.prefix = key[:MaxPrefixPerNode] - key = key[MaxPrefixPerNode:] + child.prefix = key[:trie.maxPrefixPerNode] + key = key[trie.maxPrefixPerNode:] node.children = node.children.add(child) node = child } @@ -344,7 +379,7 @@ func (trie *Trie) compact() *Trie { } // Make sure the combined prefixes fit into a single node. - if len(trie.prefix)+len(child.prefix) > MaxPrefixPerNode { + if len(trie.prefix)+len(child.prefix) > trie.maxPrefixPerNode { return trie } diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go index 346e9a66cbb029e6632440c0f5ed157748053d0e..96089fceb44c41d1ed3cd7e77d12c3a6b98265c8 100644 --- a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go @@ -55,7 +55,7 @@ func TestTrie_InsertDensePreceeding(t *testing.T) { trie := NewTrie() start := byte(70) // create a dense node - for i := byte(0); i <= MaxChildrenPerSparseNode; i++ { + for i := byte(0); i <= DefaultMaxChildrenPerSparseNode; i++ { if !trie.Insert(Prefix([]byte{start + i}), true) { t.Errorf("insert failed, prefix=%v", start+i) } diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go index 27f3c878b57228b758081ee9aec85d8414c9e2fe..b35c9e2ef5ee7b93c5118122c68a40d9dc80c72b 100644 --- a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go @@ -300,10 +300,10 @@ func TestTrie_VisitReturnError(t *testing.T) { someErr := errors.New("Something exploded") if err := trie.Visit(func(prefix Prefix, item Item) error { t.Logf("VISITING prefix=%q, item=%v", prefix, item) - if item.(int) == 0 { + if item.(int) == 3 { return someErr } - if item.(int) != 0 { + if item.(int) != 3 { t.Errorf("Unexpected prefix encountered, %q", prefix) } return nil @@ -598,10 +598,10 @@ func ExampleTrie() { // Walk the tree. trie.Visit(printItem) + // "Karel Hynek Macha": 4 + // "Karel Macha": 3 // "Pepa Novak": 1 // "Pepa Sindelar": 2 - // "Karel Macha": 3 - // "Karel Hynek Macha": 4 // Walk a subtree. trie.VisitSubtree(Prefix("Pepa"), printItem) @@ -625,8 +625,8 @@ func ExampleTrie() { // Walk again. trie.Visit(printItem) - // "Pepa Sindelar": 2 // "Karel Hynek Macha": 10 + // "Pepa Sindelar": 2 // Delete a subtree. trie.DeleteSubtree(Prefix("Pepa")) @@ -638,16 +638,16 @@ func ExampleTrie() { // Output: // "Pepa Novak" present? true // Anybody called "Karel" here? true + // "Karel Hynek Macha": 4 + // "Karel Macha": 3 // "Pepa Novak": 1 // "Pepa Sindelar": 2 - // "Karel Macha": 3 - // "Karel Hynek Macha": 4 // "Pepa Novak": 1 // "Pepa Sindelar": 2 // "Karel Hynek Macha": 10 // "Karel Hynek Macha": 10 - // "Pepa Sindelar": 2 // "Karel Hynek Macha": 10 + // "Pepa Sindelar": 2 // "Karel Hynek Macha": 10 } diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go index ce5ae378fa487c3eb6676a856cdd2491298880fa..12c441b621dedcef43a4bcf2c66fbd6c239e49bf 100644 --- a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go @@ -13,6 +13,20 @@ import ( // Tests ----------------------------------------------------------------------- +func TestTrie_ConstructorOptions(t *testing.T) { + trie := NewTrie(MaxPrefixPerNode(16), MaxChildrenPerSparseNode(10)) + + if trie.maxPrefixPerNode != 16 { + t.Errorf("Unexpected trie.maxPrefixPerNode value, expected=%v, got=%v", + 16, trie.maxPrefixPerNode) + } + + if trie.maxChildrenPerSparseNode != 10 { + t.Errorf("Unexpected trie.maxChildrenPerSparseNode value, expected=%v, got=%v", + 10, trie.maxChildrenPerSparseNode) + } +} + func TestTrie_GetNonexistentPrefix(t *testing.T) { trie := NewTrie()