1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #25283 from unclejack/bump_go_patricia_2.2.4

vendor.sh: bump go-patricia to 2.2.4 to fix leaks
This commit is contained in:
Alexander Morozov 2016-08-01 09:32:21 -07:00 committed by GitHub
commit ccbdc16b8e
3 changed files with 246 additions and 38 deletions

View file

@ -53,7 +53,7 @@ clone git github.com/gorilla/mux e444e69cbd
clone git github.com/kr/pty 5cf931ef8f
clone git github.com/mattn/go-shellwords v1.0.0
clone git github.com/mattn/go-sqlite3 v1.1.0
clone git github.com/tchap/go-patricia v2.1.0
clone git github.com/tchap/go-patricia v2.2.4
clone git github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
# forked golang.org/x/net package includes a patch for lazy loading trace templates
clone git golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://github.com/tonistiigi/net.git

View file

@ -5,16 +5,22 @@
package patricia
import "sort"
import (
"fmt"
"io"
"sort"
)
type childList interface {
length() int
head() *Trie
add(child *Trie) childList
remove(b byte)
replace(b byte, child *Trie)
remove(child *Trie)
next(b byte) *Trie
walk(prefix *Prefix, visitor VisitorFunc) error
print(w io.Writer, indent int)
total() int
}
type tries []*Trie
@ -38,7 +44,7 @@ type sparseChildList struct {
func newSparseChildList(maxChildrenPerSparseNode int) childList {
return &sparseChildList{
children: make(tries, 0, DefaultMaxChildrenPerSparseNode),
children: make(tries, 0, maxChildrenPerSparseNode),
}
}
@ -61,7 +67,26 @@ func (list *sparseChildList) add(child *Trie) childList {
return newDenseChildList(list, child)
}
func (list *sparseChildList) remove(b byte) {
for i, node := range list.children {
if node.prefix[0] == b {
list.children, list.children[len(list.children)-1] =
append(list.children[:i], list.children[i+1:]...),
nil
return
}
}
// This is not supposed to be reached.
panic("removing non-existent child")
}
func (list *sparseChildList) replace(b byte, child *Trie) {
// Make a consistency check.
if p0 := child.prefix[0]; p0 != b {
panic(fmt.Errorf("child prefix mismatch: %v != %v", p0, b))
}
// Seek the child and replace it.
for i, node := range list.children {
if node.prefix[0] == b {
@ -71,18 +96,6 @@ func (list *sparseChildList) replace(b byte, child *Trie) {
}
}
func (list *sparseChildList) remove(child *Trie) {
for i, node := range list.children {
if node.prefix[0] == child.prefix[0] {
list.children = append(list.children[:i], list.children[i+1:]...)
return
}
}
// This is not supposed to be reached.
panic("removing non-existent child")
}
func (list *sparseChildList) next(b byte) *Trie {
for _, child := range list.children {
if child.prefix[0] == b {
@ -120,10 +133,30 @@ func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
return nil
}
func (list *sparseChildList) total() int {
tot := 0
for _, child := range list.children {
if child != nil {
tot = tot + child.total()
}
}
return tot
}
func (list *sparseChildList) print(w io.Writer, indent int) {
for _, child := range list.children {
if child != nil {
child.print(w, indent)
}
}
}
type denseChildList struct {
min int
max int
children []*Trie
min int
max int
numChildren int
headIndex int
children []*Trie
}
func newDenseChildList(list *sparseChildList, child *Trie) childList {
@ -155,57 +188,87 @@ func newDenseChildList(list *sparseChildList, child *Trie) childList {
}
children[int(child.prefix[0])-min] = child
return &denseChildList{min, max, children}
return &denseChildList{
min: min,
max: max,
numChildren: list.length() + 1,
headIndex: 0,
children: children,
}
}
func (list *denseChildList) length() int {
return list.max - list.min + 1
return list.numChildren
}
func (list *denseChildList) head() *Trie {
return list.children[0]
return list.children[list.headIndex]
}
func (list *denseChildList) add(child *Trie) childList {
b := int(child.prefix[0])
var i int
switch {
case list.min <= b && b <= list.max:
if list.children[b-list.min] != nil {
panic("dense child list collision detected")
}
list.children[b-list.min] = child
i = b - list.min
list.children[i] = child
case b < list.min:
children := make([]*Trie, list.max-b+1)
children[0] = child
i = 0
children[i] = child
copy(children[list.min-b:], list.children)
list.children = children
list.min = b
default: // b > list.max
children := make([]*Trie, b-list.min+1)
children[b-list.min] = child
i = b - list.min
children[i] = child
copy(children, list.children)
list.children = children
list.max = b
}
list.numChildren++
if i < list.headIndex {
list.headIndex = i
}
return list
}
func (list *denseChildList) replace(b byte, child *Trie) {
list.children[int(b)-list.min] = nil
list.children[int(child.prefix[0])-list.min] = child
}
func (list *denseChildList) remove(child *Trie) {
i := int(child.prefix[0]) - list.min
func (list *denseChildList) remove(b byte) {
i := int(b) - list.min
if list.children[i] == nil {
// This is not supposed to be reached.
panic("removing non-existent child")
}
list.numChildren--
list.children[i] = nil
// Update head index.
if i == list.headIndex {
for ; i < len(list.children); i++ {
if list.children[i] != nil {
list.headIndex = i
return
}
}
}
}
func (list *denseChildList) replace(b byte, child *Trie) {
// Make a consistency check.
if p0 := child.prefix[0]; p0 != b {
panic(fmt.Errorf("child prefix mismatch: %v != %v", p0, b))
}
// Replace the child.
list.children[int(b)-list.min] = child
}
func (list *denseChildList) next(b byte) *Trie {
@ -242,3 +305,21 @@ func (list *denseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
return nil
}
func (list *denseChildList) print(w io.Writer, indent int) {
for _, child := range list.children {
if child != nil {
child.print(w, indent)
}
}
}
func (list *denseChildList) total() int {
tot := 0
for _, child := range list.children {
if child != nil {
tot = tot + child.total()
}
}
return tot
}

View file

@ -6,7 +6,11 @@
package patricia
import (
"bytes"
"errors"
"fmt"
"io"
"strings"
)
//------------------------------------------------------------------------------
@ -130,6 +134,21 @@ func (trie *Trie) Visit(visitor VisitorFunc) error {
return trie.walk(nil, visitor)
}
func (trie *Trie) size() int {
n := 0
trie.walk(nil, func(prefix Prefix, item Item) error {
n++
return nil
})
return n
}
func (trie *Trie) total() int {
return 1 + trie.children.total()
}
// VisitSubtree works much like Visit, but it only visits nodes matching prefix.
func (trie *Trie) VisitSubtree(prefix Prefix, visitor VisitorFunc) error {
// Nil prefix not allowed.
@ -219,11 +238,17 @@ func (trie *Trie) Delete(key Prefix) (deleted bool) {
}
// Find the relevant node.
parent, node, _, leftover := trie.findSubtree(key)
if len(leftover) != 0 {
path, found, _ := trie.findSubtreePath(key)
if !found {
return false
}
node := path[len(path)-1]
var parent *Trie
if len(path) != 1 {
parent = path[len(path)-2]
}
// If the item is already set to nil, there is nothing to do.
if node.item == nil {
return false
@ -232,7 +257,53 @@ func (trie *Trie) Delete(key Prefix) (deleted bool) {
// Delete the item.
node.item = nil
// Compact since that might be possible now.
// Initialise i before goto.
// Will be used later in a loop.
i := len(path) - 1
// In case there are some child nodes, we cannot drop the whole subtree.
// We can try to compact nodes, though.
if node.children.length() != 0 {
goto Compact
}
// In case we are at the root, just reset it and we are done.
if parent == nil {
node.reset()
return true
}
// We can drop a subtree.
// Find the first ancestor that has its value set or it has 2 or more child nodes.
// That will be the node where to drop the subtree at.
for ; i >= 0; i-- {
if current := path[i]; current.item != nil || current.children.length() >= 2 {
break
}
}
// Handle the case when there is no such node.
// In other words, we can reset the whole tree.
if i == -1 {
path[0].reset()
return true
}
// We can just remove the subtree here.
node = path[i]
if i == 0 {
parent = nil
} else {
parent = path[i-1]
}
// i+1 is always a valid index since i is never pointing to the last node.
// The loop above skips at least the last node since we are sure that the item
// is set to nil and it has no children, othewise we would be compacting instead.
node.children.remove(path[i+1].prefix[0])
Compact:
// The node is set to the first non-empty ancestor,
// so try to compact since that might be possible now.
if compacted := node.compact(); compacted != node {
if parent == nil {
*node = *compacted
@ -267,18 +338,26 @@ 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(trie.maxPrefixPerNode)
root.reset()
return true
}
// Otherwise remove the root node from its parent.
parent.children.remove(root)
parent.children.remove(root.prefix[0])
return true
}
// Internal helper methods -----------------------------------------------------
func (trie *Trie) empty() bool {
return trie.item == nil && trie.children.length() == 0
}
func (trie *Trie) reset() {
trie.prefix = nil
trie.children = newSparseChildList(trie.maxPrefixPerNode)
}
func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) {
// Nil prefix not allowed.
if key == nil {
@ -425,6 +504,43 @@ func (trie *Trie) findSubtree(prefix Prefix) (parent *Trie, root *Trie, found bo
}
}
func (trie *Trie) findSubtreePath(prefix Prefix) (path []*Trie, found bool, leftover Prefix) {
// Find the subtree matching prefix.
root := trie
var subtreePath []*Trie
for {
// Append the current root to the path.
subtreePath = append(subtreePath, root)
// Compute what part of prefix matches.
common := root.longestCommonPrefixLength(prefix)
prefix = prefix[common:]
// We used up the whole prefix, subtree found.
if len(prefix) == 0 {
path = subtreePath
found = true
leftover = root.prefix[common:]
return
}
// Partial match means that there is no subtree matching prefix.
if common < len(root.prefix) {
leftover = root.prefix[common:]
return
}
// There is some prefix left, move to the children.
child := root.children.next(prefix[0])
if child == nil {
// There is nowhere to continue, there is no subtree matching prefix.
return
}
root = child
}
}
func (trie *Trie) walk(actualRootPrefix Prefix, visitor VisitorFunc) error {
var prefix Prefix
// Allocate a bit more space for prefix at the beginning.
@ -459,6 +575,17 @@ func (trie *Trie) longestCommonPrefixLength(prefix Prefix) (i int) {
return
}
func (trie *Trie) dump() string {
writer := &bytes.Buffer{}
trie.print(writer, 0)
return writer.String()
}
func (trie *Trie) print(writer io.Writer, indent int) {
fmt.Fprintf(writer, "%s%s %v\n", strings.Repeat(" ", indent), string(trie.prefix), trie.item)
trie.children.print(writer, indent+2)
}
// Errors ----------------------------------------------------------------------
var (