diff --git a/hack/vendor.sh b/hack/vendor.sh index 50cff1690f..4e8bbefc05 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 73c7e24fb4..9aae5c0d08 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 11ee4612d3..9d6ebc43a5 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 07d3326335..a204b0c8a9 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 sparseChildList struct { - children []*Trie +type tries []*Trie + +func (t tries) Len() int { + return len(t) } -func newSparseChildList() childList { +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 tries +} + +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 8fcbcdf426..a8c3786b62 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 346e9a66cb..96089fceb4 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 27f3c878b5..b35c9e2ef5 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 - // "Pepa Novak": 1 - // "Pepa Sindelar": 2 - // "Karel Macha": 3 // "Karel Hynek Macha": 4 + // "Karel Macha": 3 + // "Pepa Novak": 1 + // "Pepa Sindelar": 2 // "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 ce5ae378fa..12c441b621 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()