Browse code

vendor.sh: bump go-patricia to 2.2.4 to fix leaks

Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>

unclejack authored on 2016/08/01 18:21:19
Showing 3 changed files
... ...
@@ -53,7 +53,7 @@ clone git github.com/gorilla/mux e444e69cbd
53 53
 clone git github.com/kr/pty 5cf931ef8f
54 54
 clone git github.com/mattn/go-shellwords v1.0.0
55 55
 clone git github.com/mattn/go-sqlite3 v1.1.0
56
-clone git github.com/tchap/go-patricia v2.1.0
56
+clone git github.com/tchap/go-patricia v2.2.4
57 57
 clone git github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
58 58
 # forked golang.org/x/net package includes a patch for lazy loading trace templates
59 59
 clone git golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://github.com/tonistiigi/net.git
... ...
@@ -5,16 +5,22 @@
5 5
 
6 6
 package patricia
7 7
 
8
-import "sort"
8
+import (
9
+	"fmt"
10
+	"io"
11
+	"sort"
12
+)
9 13
 
10 14
 type childList interface {
11 15
 	length() int
12 16
 	head() *Trie
13 17
 	add(child *Trie) childList
18
+	remove(b byte)
14 19
 	replace(b byte, child *Trie)
15
-	remove(child *Trie)
16 20
 	next(b byte) *Trie
17 21
 	walk(prefix *Prefix, visitor VisitorFunc) error
22
+	print(w io.Writer, indent int)
23
+	total() int
18 24
 }
19 25
 
20 26
 type tries []*Trie
... ...
@@ -38,7 +44,7 @@ type sparseChildList struct {
38 38
 
39 39
 func newSparseChildList(maxChildrenPerSparseNode int) childList {
40 40
 	return &sparseChildList{
41
-		children: make(tries, 0, DefaultMaxChildrenPerSparseNode),
41
+		children: make(tries, 0, maxChildrenPerSparseNode),
42 42
 	}
43 43
 }
44 44
 
... ...
@@ -61,26 +67,33 @@ func (list *sparseChildList) add(child *Trie) childList {
61 61
 	return newDenseChildList(list, child)
62 62
 }
63 63
 
64
-func (list *sparseChildList) replace(b byte, child *Trie) {
65
-	// Seek the child and replace it.
64
+func (list *sparseChildList) remove(b byte) {
66 65
 	for i, node := range list.children {
67 66
 		if node.prefix[0] == b {
68
-			list.children[i] = child
67
+			list.children, list.children[len(list.children)-1] =
68
+				append(list.children[:i], list.children[i+1:]...),
69
+				nil
69 70
 			return
70 71
 		}
71 72
 	}
73
+
74
+	// This is not supposed to be reached.
75
+	panic("removing non-existent child")
72 76
 }
73 77
 
74
-func (list *sparseChildList) remove(child *Trie) {
78
+func (list *sparseChildList) replace(b byte, child *Trie) {
79
+	// Make a consistency check.
80
+	if p0 := child.prefix[0]; p0 != b {
81
+		panic(fmt.Errorf("child prefix mismatch: %v != %v", p0, b))
82
+	}
83
+
84
+	// Seek the child and replace it.
75 85
 	for i, node := range list.children {
76
-		if node.prefix[0] == child.prefix[0] {
77
-			list.children = append(list.children[:i], list.children[i+1:]...)
86
+		if node.prefix[0] == b {
87
+			list.children[i] = child
78 88
 			return
79 89
 		}
80 90
 	}
81
-
82
-	// This is not supposed to be reached.
83
-	panic("removing non-existent child")
84 91
 }
85 92
 
86 93
 func (list *sparseChildList) next(b byte) *Trie {
... ...
@@ -120,10 +133,30 @@ func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
120 120
 	return nil
121 121
 }
122 122
 
123
+func (list *sparseChildList) total() int {
124
+	tot := 0
125
+	for _, child := range list.children {
126
+		if child != nil {
127
+			tot = tot + child.total()
128
+		}
129
+	}
130
+	return tot
131
+}
132
+
133
+func (list *sparseChildList) print(w io.Writer, indent int) {
134
+	for _, child := range list.children {
135
+		if child != nil {
136
+			child.print(w, indent)
137
+		}
138
+	}
139
+}
140
+
123 141
 type denseChildList struct {
124
-	min      int
125
-	max      int
126
-	children []*Trie
142
+	min         int
143
+	max         int
144
+	numChildren int
145
+	headIndex   int
146
+	children    []*Trie
127 147
 }
128 148
 
129 149
 func newDenseChildList(list *sparseChildList, child *Trie) childList {
... ...
@@ -155,57 +188,87 @@ func newDenseChildList(list *sparseChildList, child *Trie) childList {
155 155
 	}
156 156
 	children[int(child.prefix[0])-min] = child
157 157
 
158
-	return &denseChildList{min, max, children}
158
+	return &denseChildList{
159
+		min:         min,
160
+		max:         max,
161
+		numChildren: list.length() + 1,
162
+		headIndex:   0,
163
+		children:    children,
164
+	}
159 165
 }
160 166
 
161 167
 func (list *denseChildList) length() int {
162
-	return list.max - list.min + 1
168
+	return list.numChildren
163 169
 }
164 170
 
165 171
 func (list *denseChildList) head() *Trie {
166
-	return list.children[0]
172
+	return list.children[list.headIndex]
167 173
 }
168 174
 
169 175
 func (list *denseChildList) add(child *Trie) childList {
170 176
 	b := int(child.prefix[0])
177
+	var i int
171 178
 
172 179
 	switch {
173 180
 	case list.min <= b && b <= list.max:
174 181
 		if list.children[b-list.min] != nil {
175 182
 			panic("dense child list collision detected")
176 183
 		}
177
-		list.children[b-list.min] = child
184
+		i = b - list.min
185
+		list.children[i] = child
178 186
 
179 187
 	case b < list.min:
180 188
 		children := make([]*Trie, list.max-b+1)
181
-		children[0] = child
189
+		i = 0
190
+		children[i] = child
182 191
 		copy(children[list.min-b:], list.children)
183 192
 		list.children = children
184 193
 		list.min = b
185 194
 
186 195
 	default: // b > list.max
187 196
 		children := make([]*Trie, b-list.min+1)
188
-		children[b-list.min] = child
197
+		i = b - list.min
198
+		children[i] = child
189 199
 		copy(children, list.children)
190 200
 		list.children = children
191 201
 		list.max = b
192 202
 	}
193 203
 
204
+	list.numChildren++
205
+	if i < list.headIndex {
206
+		list.headIndex = i
207
+	}
194 208
 	return list
195 209
 }
196 210
 
197
-func (list *denseChildList) replace(b byte, child *Trie) {
198
-	list.children[int(b)-list.min] = nil
199
-	list.children[int(child.prefix[0])-list.min] = child
200
-}
201
-
202
-func (list *denseChildList) remove(child *Trie) {
203
-	i := int(child.prefix[0]) - list.min
211
+func (list *denseChildList) remove(b byte) {
212
+	i := int(b) - list.min
204 213
 	if list.children[i] == nil {
205 214
 		// This is not supposed to be reached.
206 215
 		panic("removing non-existent child")
207 216
 	}
217
+	list.numChildren--
208 218
 	list.children[i] = nil
219
+
220
+	// Update head index.
221
+	if i == list.headIndex {
222
+		for ; i < len(list.children); i++ {
223
+			if list.children[i] != nil {
224
+				list.headIndex = i
225
+				return
226
+			}
227
+		}
228
+	}
229
+}
230
+
231
+func (list *denseChildList) replace(b byte, child *Trie) {
232
+	// Make a consistency check.
233
+	if p0 := child.prefix[0]; p0 != b {
234
+		panic(fmt.Errorf("child prefix mismatch: %v != %v", p0, b))
235
+	}
236
+
237
+	// Replace the child.
238
+	list.children[int(b)-list.min] = child
209 239
 }
210 240
 
211 241
 func (list *denseChildList) next(b byte) *Trie {
... ...
@@ -242,3 +305,21 @@ func (list *denseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
242 242
 
243 243
 	return nil
244 244
 }
245
+
246
+func (list *denseChildList) print(w io.Writer, indent int) {
247
+	for _, child := range list.children {
248
+		if child != nil {
249
+			child.print(w, indent)
250
+		}
251
+	}
252
+}
253
+
254
+func (list *denseChildList) total() int {
255
+	tot := 0
256
+	for _, child := range list.children {
257
+		if child != nil {
258
+			tot = tot + child.total()
259
+		}
260
+	}
261
+	return tot
262
+}
... ...
@@ -6,7 +6,11 @@
6 6
 package patricia
7 7
 
8 8
 import (
9
+	"bytes"
9 10
 	"errors"
11
+	"fmt"
12
+	"io"
13
+	"strings"
10 14
 )
11 15
 
12 16
 //------------------------------------------------------------------------------
... ...
@@ -130,6 +134,21 @@ func (trie *Trie) Visit(visitor VisitorFunc) error {
130 130
 	return trie.walk(nil, visitor)
131 131
 }
132 132
 
133
+func (trie *Trie) size() int {
134
+	n := 0
135
+
136
+	trie.walk(nil, func(prefix Prefix, item Item) error {
137
+		n++
138
+		return nil
139
+	})
140
+
141
+	return n
142
+}
143
+
144
+func (trie *Trie) total() int {
145
+	return 1 + trie.children.total()
146
+}
147
+
133 148
 // VisitSubtree works much like Visit, but it only visits nodes matching prefix.
134 149
 func (trie *Trie) VisitSubtree(prefix Prefix, visitor VisitorFunc) error {
135 150
 	// Nil prefix not allowed.
... ...
@@ -219,11 +238,17 @@ func (trie *Trie) Delete(key Prefix) (deleted bool) {
219 219
 	}
220 220
 
221 221
 	// Find the relevant node.
222
-	parent, node, _, leftover := trie.findSubtree(key)
223
-	if len(leftover) != 0 {
222
+	path, found, _ := trie.findSubtreePath(key)
223
+	if !found {
224 224
 		return false
225 225
 	}
226 226
 
227
+	node := path[len(path)-1]
228
+	var parent *Trie
229
+	if len(path) != 1 {
230
+		parent = path[len(path)-2]
231
+	}
232
+
227 233
 	// If the item is already set to nil, there is nothing to do.
228 234
 	if node.item == nil {
229 235
 		return false
... ...
@@ -232,7 +257,53 @@ func (trie *Trie) Delete(key Prefix) (deleted bool) {
232 232
 	// Delete the item.
233 233
 	node.item = nil
234 234
 
235
-	// Compact since that might be possible now.
235
+	// Initialise i before goto.
236
+	// Will be used later in a loop.
237
+	i := len(path) - 1
238
+
239
+	// In case there are some child nodes, we cannot drop the whole subtree.
240
+	// We can try to compact nodes, though.
241
+	if node.children.length() != 0 {
242
+		goto Compact
243
+	}
244
+
245
+	// In case we are at the root, just reset it and we are done.
246
+	if parent == nil {
247
+		node.reset()
248
+		return true
249
+	}
250
+
251
+	// We can drop a subtree.
252
+	// Find the first ancestor that has its value set or it has 2 or more child nodes.
253
+	// That will be the node where to drop the subtree at.
254
+	for ; i >= 0; i-- {
255
+		if current := path[i]; current.item != nil || current.children.length() >= 2 {
256
+			break
257
+		}
258
+	}
259
+
260
+	// Handle the case when there is no such node.
261
+	// In other words, we can reset the whole tree.
262
+	if i == -1 {
263
+		path[0].reset()
264
+		return true
265
+	}
266
+
267
+	// We can just remove the subtree here.
268
+	node = path[i]
269
+	if i == 0 {
270
+		parent = nil
271
+	} else {
272
+		parent = path[i-1]
273
+	}
274
+	// i+1 is always a valid index since i is never pointing to the last node.
275
+	// The loop above skips at least the last node since we are sure that the item
276
+	// is set to nil and it has no children, othewise we would be compacting instead.
277
+	node.children.remove(path[i+1].prefix[0])
278
+
279
+Compact:
280
+	// The node is set to the first non-empty ancestor,
281
+	// so try to compact since that might be possible now.
236 282
 	if compacted := node.compact(); compacted != node {
237 283
 		if parent == nil {
238 284
 			*node = *compacted
... ...
@@ -267,18 +338,26 @@ func (trie *Trie) DeleteSubtree(prefix Prefix) (deleted bool) {
267 267
 
268 268
 	// If we are in the root of the trie, reset the trie.
269 269
 	if parent == nil {
270
-		root.prefix = nil
271
-		root.children = newSparseChildList(trie.maxPrefixPerNode)
270
+		root.reset()
272 271
 		return true
273 272
 	}
274 273
 
275 274
 	// Otherwise remove the root node from its parent.
276
-	parent.children.remove(root)
275
+	parent.children.remove(root.prefix[0])
277 276
 	return true
278 277
 }
279 278
 
280 279
 // Internal helper methods -----------------------------------------------------
281 280
 
281
+func (trie *Trie) empty() bool {
282
+	return trie.item == nil && trie.children.length() == 0
283
+}
284
+
285
+func (trie *Trie) reset() {
286
+	trie.prefix = nil
287
+	trie.children = newSparseChildList(trie.maxPrefixPerNode)
288
+}
289
+
282 290
 func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) {
283 291
 	// Nil prefix not allowed.
284 292
 	if key == nil {
... ...
@@ -425,6 +504,43 @@ func (trie *Trie) findSubtree(prefix Prefix) (parent *Trie, root *Trie, found bo
425 425
 	}
426 426
 }
427 427
 
428
+func (trie *Trie) findSubtreePath(prefix Prefix) (path []*Trie, found bool, leftover Prefix) {
429
+	// Find the subtree matching prefix.
430
+	root := trie
431
+	var subtreePath []*Trie
432
+	for {
433
+		// Append the current root to the path.
434
+		subtreePath = append(subtreePath, root)
435
+
436
+		// Compute what part of prefix matches.
437
+		common := root.longestCommonPrefixLength(prefix)
438
+		prefix = prefix[common:]
439
+
440
+		// We used up the whole prefix, subtree found.
441
+		if len(prefix) == 0 {
442
+			path = subtreePath
443
+			found = true
444
+			leftover = root.prefix[common:]
445
+			return
446
+		}
447
+
448
+		// Partial match means that there is no subtree matching prefix.
449
+		if common < len(root.prefix) {
450
+			leftover = root.prefix[common:]
451
+			return
452
+		}
453
+
454
+		// There is some prefix left, move to the children.
455
+		child := root.children.next(prefix[0])
456
+		if child == nil {
457
+			// There is nowhere to continue, there is no subtree matching prefix.
458
+			return
459
+		}
460
+
461
+		root = child
462
+	}
463
+}
464
+
428 465
 func (trie *Trie) walk(actualRootPrefix Prefix, visitor VisitorFunc) error {
429 466
 	var prefix Prefix
430 467
 	// Allocate a bit more space for prefix at the beginning.
... ...
@@ -459,6 +575,17 @@ func (trie *Trie) longestCommonPrefixLength(prefix Prefix) (i int) {
459 459
 	return
460 460
 }
461 461
 
462
+func (trie *Trie) dump() string {
463
+	writer := &bytes.Buffer{}
464
+	trie.print(writer, 0)
465
+	return writer.String()
466
+}
467
+
468
+func (trie *Trie) print(writer io.Writer, indent int) {
469
+	fmt.Fprintf(writer, "%s%s %v\n", strings.Repeat(" ", indent), string(trie.prefix), trie.item)
470
+	trie.children.print(writer, indent+2)
471
+}
472
+
462 473
 // Errors ----------------------------------------------------------------------
463 474
 
464 475
 var (