Browse Source

Merge pull request #12943 from tianon/go-patricia-v2

Update go-patricia to 2.1.0
unclejack 10 years ago
parent
commit
175339ffb6

+ 1 - 1
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
 

+ 5 - 8
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)

+ 8 - 5
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"))

+ 22 - 8
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 {

+ 47 - 12
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
 	}
 

+ 1 - 1
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)
 		}

+ 8 - 8
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
 }
 

+ 14 - 0
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()