瀏覽代碼

libnetwork: use go-immutable-radix instead of radix

This commit allows to remove dependency on the mutable version armon/go-radix.

The go-immutable-radix package is better maintained.

It is likely that a bit more memory will be used when using the
immutable version, though discarded nodes are being reused in a pool.
These changes happen when networks are added/removed or nodes come and
go in a cluster, so we are still talking about a relatively low
frequency event.

The major changes compared to the old radix are when modifying (insert
or delete) a tree, and those are pretty self-contained: we replace the
entire immutable tree under a lock.

Signed-off-by: Tibor Vass <teabee89@gmail.com>
Tibor Vass 2 年之前
父節點
當前提交
eaa74497b8

+ 4 - 4
libnetwork/networkdb/cluster.go

@@ -396,7 +396,7 @@ func (nDB *NetworkDB) reapTableEntries() {
 	// The lock is taken at the beginning of the cycle and the deletion is inline
 	// The lock is taken at the beginning of the cycle and the deletion is inline
 	for _, nid := range nodeNetworks {
 	for _, nid := range nodeNetworks {
 		nDB.Lock()
 		nDB.Lock()
-		nDB.indexes[byNetwork].WalkPrefix("/"+nid, func(path string, v interface{}) bool {
+		nDB.indexes[byNetwork].Root().WalkPrefix([]byte("/"+nid), func(path []byte, v interface{}) bool {
 			// timeCompensation compensate in case the lock took some time to be released
 			// timeCompensation compensate in case the lock took some time to be released
 			timeCompensation := time.Since(cycleStart)
 			timeCompensation := time.Since(cycleStart)
 			entry, ok := v.(*entry)
 			entry, ok := v.(*entry)
@@ -411,7 +411,7 @@ func (nDB *NetworkDB) reapTableEntries() {
 				return false
 				return false
 			}
 			}
 
 
-			params := strings.Split(path[1:], "/")
+			params := strings.Split(string(path[1:]), "/")
 			nid := params[0]
 			nid := params[0]
 			tname := params[1]
 			tname := params[1]
 			key := params[2]
 			key := params[2]
@@ -629,7 +629,7 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b
 	}
 	}
 
 
 	for _, nid := range networks {
 	for _, nid := range networks {
-		nDB.indexes[byNetwork].WalkPrefix("/"+nid, func(path string, v interface{}) bool {
+		nDB.indexes[byNetwork].Root().WalkPrefix([]byte("/"+nid), func(path []byte, v interface{}) bool {
 			entry, ok := v.(*entry)
 			entry, ok := v.(*entry)
 			if !ok {
 			if !ok {
 				return false
 				return false
@@ -640,7 +640,7 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b
 				eType = TableEventTypeDelete
 				eType = TableEventTypeDelete
 			}
 			}
 
 
-			params := strings.Split(path[1:], "/")
+			params := strings.Split(string(path[1:]), "/")
 			tEvent := TableEvent{
 			tEvent := TableEvent{
 				Type:      eType,
 				Type:      eType,
 				LTime:     entry.ltime,
 				LTime:     entry.ltime,

+ 22 - 21
libnetwork/networkdb/networkdb.go

@@ -10,10 +10,10 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
-	"github.com/armon/go-radix"
 	"github.com/docker/docker/libnetwork/types"
 	"github.com/docker/docker/libnetwork/types"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/go-events"
 	"github.com/docker/go-events"
+	iradix "github.com/hashicorp/go-immutable-radix"
 	"github.com/hashicorp/memberlist"
 	"github.com/hashicorp/memberlist"
 	"github.com/hashicorp/serf/serf"
 	"github.com/hashicorp/serf/serf"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
@@ -43,7 +43,7 @@ type NetworkDB struct {
 
 
 	// All the tree index (byTable, byNetwork) that we maintain
 	// All the tree index (byTable, byNetwork) that we maintain
 	// the db.
 	// the db.
-	indexes map[int]*radix.Tree
+	indexes map[int]*iradix.Tree
 
 
 	// Memberlist we use to drive the cluster.
 	// Memberlist we use to drive the cluster.
 	memberlist *memberlist.Memberlist
 	memberlist *memberlist.Memberlist
@@ -255,7 +255,7 @@ func New(c *Config) (*NetworkDB, error) {
 
 
 	nDB := &NetworkDB{
 	nDB := &NetworkDB{
 		config:         c,
 		config:         c,
-		indexes:        make(map[int]*radix.Tree),
+		indexes:        make(map[int]*iradix.Tree),
 		networks:       make(map[string]map[string]*network),
 		networks:       make(map[string]map[string]*network),
 		nodes:          make(map[string]*node),
 		nodes:          make(map[string]*node),
 		failedNodes:    make(map[string]*node),
 		failedNodes:    make(map[string]*node),
@@ -265,8 +265,8 @@ func New(c *Config) (*NetworkDB, error) {
 		broadcaster:    events.NewBroadcaster(),
 		broadcaster:    events.NewBroadcaster(),
 	}
 	}
 
 
-	nDB.indexes[byTable] = radix.New()
-	nDB.indexes[byNetwork] = radix.New()
+	nDB.indexes[byTable] = iradix.New()
+	nDB.indexes[byNetwork] = iradix.New()
 
 
 	logrus.Infof("New memberlist node - Node:%v will use memberlist nodeID:%v with config:%+v", c.Hostname, c.NodeID, c)
 	logrus.Infof("New memberlist node - Node:%v will use memberlist nodeID:%v with config:%+v", c.Hostname, c.NodeID, c)
 	if err := nDB.clusterInit(); err != nil {
 	if err := nDB.clusterInit(); err != nil {
@@ -348,7 +348,7 @@ func (nDB *NetworkDB) GetEntry(tname, nid, key string) ([]byte, error) {
 }
 }
 
 
 func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) {
 func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) {
-	e, ok := nDB.indexes[byTable].Get(fmt.Sprintf("/%s/%s/%s", tname, nid, key))
+	e, ok := nDB.indexes[byTable].Get([]byte(fmt.Sprintf("/%s/%s/%s", tname, nid, key)))
 	if !ok {
 	if !ok {
 		return nil, types.NotFoundErrorf("could not get entry in table %s with network id %s and key %s", tname, nid, key)
 		return nil, types.NotFoundErrorf("could not get entry in table %s with network id %s and key %s", tname, nid, key)
 	}
 	}
@@ -422,12 +422,13 @@ type TableElem struct {
 // returns a map of keys and values
 // returns a map of keys and values
 func (nDB *NetworkDB) GetTableByNetwork(tname, nid string) map[string]*TableElem {
 func (nDB *NetworkDB) GetTableByNetwork(tname, nid string) map[string]*TableElem {
 	entries := make(map[string]*TableElem)
 	entries := make(map[string]*TableElem)
-	nDB.indexes[byTable].WalkPrefix(fmt.Sprintf("/%s/%s", tname, nid), func(k string, v interface{}) bool {
+	nDB.indexes[byTable].Root().WalkPrefix([]byte(fmt.Sprintf("/%s/%s", tname, nid)), func(k []byte, v interface{}) bool {
 		entry := v.(*entry)
 		entry := v.(*entry)
 		if entry.deleting {
 		if entry.deleting {
 			return false
 			return false
 		}
 		}
-		key := k[strings.LastIndex(k, "/")+1:]
+		key := string(k)
+		key = key[strings.LastIndex(key, "/")+1:]
 		entries[key] = &TableElem{Value: entry.value, owner: entry.node}
 		entries[key] = &TableElem{Value: entry.value, owner: entry.node}
 		return false
 		return false
 	})
 	})
@@ -499,10 +500,10 @@ func (nDB *NetworkDB) deleteNodeNetworkEntries(nid, node string) {
 	// Indicates if the delete is triggered for the local node
 	// Indicates if the delete is triggered for the local node
 	isNodeLocal := node == nDB.config.NodeID
 	isNodeLocal := node == nDB.config.NodeID
 
 
-	nDB.indexes[byNetwork].WalkPrefix("/"+nid,
-		func(path string, v interface{}) bool {
+	nDB.indexes[byNetwork].Root().WalkPrefix([]byte("/"+nid),
+		func(path []byte, v interface{}) bool {
 			oldEntry := v.(*entry)
 			oldEntry := v.(*entry)
-			params := strings.Split(path[1:], "/")
+			params := strings.Split(string(path[1:]), "/")
 			nid := params[0]
 			nid := params[0]
 			tname := params[1]
 			tname := params[1]
 			key := params[2]
 			key := params[2]
@@ -554,13 +555,13 @@ func (nDB *NetworkDB) deleteNodeNetworkEntries(nid, node string) {
 }
 }
 
 
 func (nDB *NetworkDB) deleteNodeTableEntries(node string) {
 func (nDB *NetworkDB) deleteNodeTableEntries(node string) {
-	nDB.indexes[byTable].Walk(func(path string, v interface{}) bool {
+	nDB.indexes[byTable].Root().Walk(func(path []byte, v interface{}) bool {
 		oldEntry := v.(*entry)
 		oldEntry := v.(*entry)
 		if oldEntry.node != node {
 		if oldEntry.node != node {
 			return false
 			return false
 		}
 		}
 
 
-		params := strings.Split(path[1:], "/")
+		params := strings.Split(string(path[1:]), "/")
 		tname := params[0]
 		tname := params[0]
 		nid := params[1]
 		nid := params[1]
 		key := params[2]
 		key := params[2]
@@ -580,8 +581,8 @@ func (nDB *NetworkDB) deleteNodeTableEntries(node string) {
 func (nDB *NetworkDB) WalkTable(tname string, fn func(string, string, []byte, bool) bool) error {
 func (nDB *NetworkDB) WalkTable(tname string, fn func(string, string, []byte, bool) bool) error {
 	nDB.RLock()
 	nDB.RLock()
 	values := make(map[string]interface{})
 	values := make(map[string]interface{})
-	nDB.indexes[byTable].WalkPrefix("/"+tname, func(path string, v interface{}) bool {
-		values[path] = v
+	nDB.indexes[byTable].Root().WalkPrefix([]byte("/"+tname), func(path []byte, v interface{}) bool {
+		values[string(path)] = v
 		return false
 		return false
 	})
 	})
 	nDB.RUnlock()
 	nDB.RUnlock()
@@ -751,9 +752,9 @@ func (nDB *NetworkDB) updateLocalNetworkTime() {
 
 
 // createOrUpdateEntry this function handles the creation or update of entries into the local
 // createOrUpdateEntry this function handles the creation or update of entries into the local
 // tree store. It is also used to keep in sync the entries number of the network (all tables are aggregated)
 // tree store. It is also used to keep in sync the entries number of the network (all tables are aggregated)
-func (nDB *NetworkDB) createOrUpdateEntry(nid, tname, key string, entry interface{}) (bool, bool) {
-	_, okTable := nDB.indexes[byTable].Insert(fmt.Sprintf("/%s/%s/%s", tname, nid, key), entry)
-	_, okNetwork := nDB.indexes[byNetwork].Insert(fmt.Sprintf("/%s/%s/%s", nid, tname, key), entry)
+func (nDB *NetworkDB) createOrUpdateEntry(nid, tname, key string, entry interface{}) (okTable bool, okNetwork bool) {
+	nDB.indexes[byTable], _, okTable = nDB.indexes[byTable].Insert([]byte(fmt.Sprintf("/%s/%s/%s", tname, nid, key)), entry)
+	nDB.indexes[byNetwork], _, okNetwork = nDB.indexes[byNetwork].Insert([]byte(fmt.Sprintf("/%s/%s/%s", nid, tname, key)), entry)
 	if !okNetwork {
 	if !okNetwork {
 		// Add only if it is an insert not an update
 		// Add only if it is an insert not an update
 		n, ok := nDB.networks[nDB.config.NodeID][nid]
 		n, ok := nDB.networks[nDB.config.NodeID][nid]
@@ -766,9 +767,9 @@ func (nDB *NetworkDB) createOrUpdateEntry(nid, tname, key string, entry interfac
 
 
 // deleteEntry this function handles the deletion of entries into the local tree store.
 // deleteEntry this function handles the deletion of entries into the local tree store.
 // It is also used to keep in sync the entries number of the network (all tables are aggregated)
 // It is also used to keep in sync the entries number of the network (all tables are aggregated)
-func (nDB *NetworkDB) deleteEntry(nid, tname, key string) (bool, bool) {
-	_, okTable := nDB.indexes[byTable].Delete(fmt.Sprintf("/%s/%s/%s", tname, nid, key))
-	_, okNetwork := nDB.indexes[byNetwork].Delete(fmt.Sprintf("/%s/%s/%s", nid, tname, key))
+func (nDB *NetworkDB) deleteEntry(nid, tname, key string) (okTable bool, okNetwork bool) {
+	nDB.indexes[byTable], _, okTable = nDB.indexes[byTable].Delete([]byte(fmt.Sprintf("/%s/%s/%s", tname, nid, key)))
+	nDB.indexes[byNetwork], _, okNetwork = nDB.indexes[byNetwork].Delete([]byte(fmt.Sprintf("/%s/%s/%s", nid, tname, key)))
 	if okNetwork {
 	if okNetwork {
 		// Remove only if the delete is successful
 		// Remove only if the delete is successful
 		n, ok := nDB.networks[nDB.config.NodeID][nid]
 		n, ok := nDB.networks[nDB.config.NodeID][nid]

+ 0 - 1
vendor.mod

@@ -15,7 +15,6 @@ require (
 	github.com/Microsoft/go-winio v0.5.2
 	github.com/Microsoft/go-winio v0.5.2
 	github.com/Microsoft/hcsshim v0.9.5
 	github.com/Microsoft/hcsshim v0.9.5
 	github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91
 	github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91
-	github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c
 	github.com/aws/aws-sdk-go v1.37.0
 	github.com/aws/aws-sdk-go v1.37.0
 	github.com/bsphere/le_go v0.0.0-20200109081728-fc06dab2caa8
 	github.com/bsphere/le_go v0.0.0-20200109081728-fc06dab2caa8
 	github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5
 	github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5

+ 0 - 2
vendor.sum

@@ -146,8 +146,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
 github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
 github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
 github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
 github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M=
-github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
 github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
 github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk=
 github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk=

+ 0 - 22
vendor/github.com/armon/go-radix/.gitignore

@@ -1,22 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe

+ 0 - 6
vendor/github.com/armon/go-radix/.travis.yml

@@ -1,6 +0,0 @@
-language: go
-arch:
-  - amd64
-  - ppc64le
-go:
-  - tip

+ 0 - 20
vendor/github.com/armon/go-radix/LICENSE

@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Armon Dadgar
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 0 - 38
vendor/github.com/armon/go-radix/README.md

@@ -1,38 +0,0 @@
-go-radix [![Build Status](https://travis-ci.org/armon/go-radix.png)](https://travis-ci.org/armon/go-radix)
-=========
-
-Provides the `radix` package that implements a [radix tree](http://en.wikipedia.org/wiki/Radix_tree).
-The package only provides a single `Tree` implementation, optimized for sparse nodes.
-
-As a radix tree, it provides the following:
- * O(k) operations. In many cases, this can be faster than a hash table since
-   the hash function is an O(k) operation, and hash tables have very poor cache locality.
- * Minimum / Maximum value lookups
- * Ordered iteration
-
-For an immutable variant, see [go-immutable-radix](https://github.com/hashicorp/go-immutable-radix).
-
-Documentation
-=============
-
-The full documentation is available on [Godoc](http://godoc.org/github.com/armon/go-radix).
-
-Example
-=======
-
-Below is a simple example of usage
-
-```go
-// Create a tree
-r := radix.New()
-r.Insert("foo", 1)
-r.Insert("bar", 2)
-r.Insert("foobar", 2)
-
-// Find the longest prefix match
-m, _, _ := r.LongestPrefix("foozip")
-if m != "foo" {
-    panic("should be foo")
-}
-```
-

+ 0 - 561
vendor/github.com/armon/go-radix/radix.go

@@ -1,561 +0,0 @@
-package radix
-
-import (
-	"sort"
-	"strings"
-)
-
-// WalkFn is used when walking the tree. Takes a
-// key and value, returning if iteration should
-// be terminated.
-type WalkFn func(s string, v interface{}) bool
-
-// leafNode is used to represent a value
-type leafNode struct {
-	key string
-	val interface{}
-}
-
-// edge is used to represent an edge node
-type edge struct {
-	label byte
-	node  *node
-}
-
-type node struct {
-	// leaf is used to store possible leaf
-	leaf *leafNode
-
-	// prefix is the common prefix we ignore
-	prefix string
-
-	// Edges should be stored in-order for iteration.
-	// We avoid a fully materialized slice to save memory,
-	// since in most cases we expect to be sparse
-	edges edges
-}
-
-func (n *node) isLeaf() bool {
-	return n.leaf != nil
-}
-
-func (n *node) addEdge(e edge) {
-	num := len(n.edges)
-	idx := sort.Search(num, func(i int) bool {
-		return n.edges[i].label >= e.label
-	})
-
-	n.edges = append(n.edges, edge{})
-	copy(n.edges[idx+1:], n.edges[idx:])
-	n.edges[idx] = e
-}
-
-func (n *node) updateEdge(label byte, node *node) {
-	num := len(n.edges)
-	idx := sort.Search(num, func(i int) bool {
-		return n.edges[i].label >= label
-	})
-	if idx < num && n.edges[idx].label == label {
-		n.edges[idx].node = node
-		return
-	}
-	panic("replacing missing edge")
-}
-
-func (n *node) getEdge(label byte) *node {
-	num := len(n.edges)
-	idx := sort.Search(num, func(i int) bool {
-		return n.edges[i].label >= label
-	})
-	if idx < num && n.edges[idx].label == label {
-		return n.edges[idx].node
-	}
-	return nil
-}
-
-func (n *node) delEdge(label byte) {
-	num := len(n.edges)
-	idx := sort.Search(num, func(i int) bool {
-		return n.edges[i].label >= label
-	})
-	if idx < num && n.edges[idx].label == label {
-		copy(n.edges[idx:], n.edges[idx+1:])
-		n.edges[len(n.edges)-1] = edge{}
-		n.edges = n.edges[:len(n.edges)-1]
-	}
-}
-
-type edges []edge
-
-func (e edges) Len() int {
-	return len(e)
-}
-
-func (e edges) Less(i, j int) bool {
-	return e[i].label < e[j].label
-}
-
-func (e edges) Swap(i, j int) {
-	e[i], e[j] = e[j], e[i]
-}
-
-func (e edges) Sort() {
-	sort.Sort(e)
-}
-
-// Tree implements a radix tree. This can be treated as a
-// Dictionary abstract data type. The main advantage over
-// a standard hash map is prefix-based lookups and
-// ordered iteration,
-type Tree struct {
-	root *node
-	size int
-}
-
-// New returns an empty Tree
-func New() *Tree {
-	return NewFromMap(nil)
-}
-
-// NewFromMap returns a new tree containing the keys
-// from an existing map
-func NewFromMap(m map[string]interface{}) *Tree {
-	t := &Tree{root: &node{}}
-	for k, v := range m {
-		t.Insert(k, v)
-	}
-	return t
-}
-
-// Len is used to return the number of elements in the tree
-func (t *Tree) Len() int {
-	return t.size
-}
-
-// longestPrefix finds the length of the shared prefix
-// of two strings
-func longestPrefix(k1, k2 string) int {
-	max := len(k1)
-	if l := len(k2); l < max {
-		max = l
-	}
-	var i int
-	for i = 0; i < max; i++ {
-		if k1[i] != k2[i] {
-			break
-		}
-	}
-	return i
-}
-
-// Insert is used to add a newentry or update
-// an existing entry. Returns true if an existing record is updated.
-func (t *Tree) Insert(s string, v interface{}) (interface{}, bool) {
-	var parent *node
-	n := t.root
-	search := s
-	for {
-		// Handle key exhaution
-		if len(search) == 0 {
-			if n.isLeaf() {
-				old := n.leaf.val
-				n.leaf.val = v
-				return old, true
-			}
-
-			n.leaf = &leafNode{
-				key: s,
-				val: v,
-			}
-			t.size++
-			return nil, false
-		}
-
-		// Look for the edge
-		parent = n
-		n = n.getEdge(search[0])
-
-		// No edge, create one
-		if n == nil {
-			e := edge{
-				label: search[0],
-				node: &node{
-					leaf: &leafNode{
-						key: s,
-						val: v,
-					},
-					prefix: search,
-				},
-			}
-			parent.addEdge(e)
-			t.size++
-			return nil, false
-		}
-
-		// Determine longest prefix of the search key on match
-		commonPrefix := longestPrefix(search, n.prefix)
-		if commonPrefix == len(n.prefix) {
-			search = search[commonPrefix:]
-			continue
-		}
-
-		// Split the node
-		t.size++
-		child := &node{
-			prefix: search[:commonPrefix],
-		}
-		parent.updateEdge(search[0], child)
-
-		// Restore the existing node
-		child.addEdge(edge{
-			label: n.prefix[commonPrefix],
-			node:  n,
-		})
-		n.prefix = n.prefix[commonPrefix:]
-
-		// Create a new leaf node
-		leaf := &leafNode{
-			key: s,
-			val: v,
-		}
-
-		// If the new key is a subset, add to this node
-		search = search[commonPrefix:]
-		if len(search) == 0 {
-			child.leaf = leaf
-			return nil, false
-		}
-
-		// Create a new edge for the node
-		child.addEdge(edge{
-			label: search[0],
-			node: &node{
-				leaf:   leaf,
-				prefix: search,
-			},
-		})
-		return nil, false
-	}
-}
-
-// Delete is used to delete a key, returning the previous
-// value and if it was deleted
-func (t *Tree) Delete(s string) (interface{}, bool) {
-	var parent *node
-	var label byte
-	n := t.root
-	search := s
-	for {
-		// Check for key exhaution
-		if len(search) == 0 {
-			if !n.isLeaf() {
-				break
-			}
-			goto DELETE
-		}
-
-		// Look for an edge
-		parent = n
-		label = search[0]
-		n = n.getEdge(label)
-		if n == nil {
-			break
-		}
-
-		// Consume the search prefix
-		if strings.HasPrefix(search, n.prefix) {
-			search = search[len(n.prefix):]
-		} else {
-			break
-		}
-	}
-	return nil, false
-
-DELETE:
-	// Delete the leaf
-	leaf := n.leaf
-	n.leaf = nil
-	t.size--
-
-	// Check if we should delete this node from the parent
-	if parent != nil && len(n.edges) == 0 {
-		parent.delEdge(label)
-	}
-
-	// Check if we should merge this node
-	if n != t.root && len(n.edges) == 1 {
-		n.mergeChild()
-	}
-
-	// Check if we should merge the parent's other child
-	if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() {
-		parent.mergeChild()
-	}
-
-	return leaf.val, true
-}
-
-// DeletePrefix is used to delete the subtree under a prefix
-// Returns how many nodes were deleted
-// Use this to delete large subtrees efficiently
-func (t *Tree) DeletePrefix(s string) int {
-	return t.deletePrefix(nil, t.root, s)
-}
-
-// delete does a recursive deletion
-func (t *Tree) deletePrefix(parent, n *node, prefix string) int {
-	// Check for key exhaustion
-	if len(prefix) == 0 {
-		// Remove the leaf node
-		subTreeSize := 0
-		//recursively walk from all edges of the node to be deleted
-		recursiveWalk(n, func(s string, v interface{}) bool {
-			subTreeSize++
-			return false
-		})
-		if n.isLeaf() {
-			n.leaf = nil
-		}
-		n.edges = nil // deletes the entire subtree
-
-		// Check if we should merge the parent's other child
-		if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() {
-			parent.mergeChild()
-		}
-		t.size -= subTreeSize
-		return subTreeSize
-	}
-
-	// Look for an edge
-	label := prefix[0]
-	child := n.getEdge(label)
-	if child == nil || (!strings.HasPrefix(child.prefix, prefix) && !strings.HasPrefix(prefix, child.prefix)) {
-		return 0
-	}
-
-	// Consume the search prefix
-	if len(child.prefix) > len(prefix) {
-		prefix = prefix[len(prefix):]
-	} else {
-		prefix = prefix[len(child.prefix):]
-	}
-	return t.deletePrefix(n, child, prefix)
-}
-
-func (n *node) mergeChild() {
-	e := n.edges[0]
-	child := e.node
-	n.prefix = n.prefix + child.prefix
-	n.leaf = child.leaf
-	n.edges = child.edges
-}
-
-// Get is used to lookup a specific key, returning
-// the value and if it was found
-func (t *Tree) Get(s string) (interface{}, bool) {
-	n := t.root
-	search := s
-	for {
-		// Check for key exhaution
-		if len(search) == 0 {
-			if n.isLeaf() {
-				return n.leaf.val, true
-			}
-			break
-		}
-
-		// Look for an edge
-		n = n.getEdge(search[0])
-		if n == nil {
-			break
-		}
-
-		// Consume the search prefix
-		if strings.HasPrefix(search, n.prefix) {
-			search = search[len(n.prefix):]
-		} else {
-			break
-		}
-	}
-	return nil, false
-}
-
-// LongestPrefix is like Get, but instead of an
-// exact match, it will return the longest prefix match.
-func (t *Tree) LongestPrefix(s string) (string, interface{}, bool) {
-	var last *leafNode
-	n := t.root
-	search := s
-	for {
-		// Look for a leaf node
-		if n.isLeaf() {
-			last = n.leaf
-		}
-
-		// Check for key exhaution
-		if len(search) == 0 {
-			break
-		}
-
-		// Look for an edge
-		n = n.getEdge(search[0])
-		if n == nil {
-			break
-		}
-
-		// Consume the search prefix
-		if strings.HasPrefix(search, n.prefix) {
-			search = search[len(n.prefix):]
-		} else {
-			break
-		}
-	}
-	if last != nil {
-		return last.key, last.val, true
-	}
-	return "", nil, false
-}
-
-// Minimum is used to return the minimum value in the tree
-func (t *Tree) Minimum() (string, interface{}, bool) {
-	n := t.root
-	for {
-		if n.isLeaf() {
-			return n.leaf.key, n.leaf.val, true
-		}
-		if len(n.edges) > 0 {
-			n = n.edges[0].node
-		} else {
-			break
-		}
-	}
-	return "", nil, false
-}
-
-// Maximum is used to return the maximum value in the tree
-func (t *Tree) Maximum() (string, interface{}, bool) {
-	n := t.root
-	for {
-		if num := len(n.edges); num > 0 {
-			n = n.edges[num-1].node
-			continue
-		}
-		if n.isLeaf() {
-			return n.leaf.key, n.leaf.val, true
-		}
-		break
-	}
-	return "", nil, false
-}
-
-// Walk is used to walk the tree
-func (t *Tree) Walk(fn WalkFn) {
-	recursiveWalk(t.root, fn)
-}
-
-// WalkPrefix is used to walk the tree under a prefix
-func (t *Tree) WalkPrefix(prefix string, fn WalkFn) {
-	n := t.root
-	search := prefix
-	for {
-		// Check for key exhaustion
-		if len(search) == 0 {
-			recursiveWalk(n, fn)
-			return
-		}
-
-		// Look for an edge
-		n = n.getEdge(search[0])
-		if n == nil {
-			return
-		}
-
-		// Consume the search prefix
-		if strings.HasPrefix(search, n.prefix) {
-			search = search[len(n.prefix):]
-			continue
-		}
-		if strings.HasPrefix(n.prefix, search) {
-			// Child may be under our search prefix
-			recursiveWalk(n, fn)
-		}
-		return
-	}
-}
-
-// WalkPath is used to walk the tree, but only visiting nodes
-// from the root down to a given leaf. Where WalkPrefix walks
-// all the entries *under* the given prefix, this walks the
-// entries *above* the given prefix.
-func (t *Tree) WalkPath(path string, fn WalkFn) {
-	n := t.root
-	search := path
-	for {
-		// Visit the leaf values if any
-		if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
-			return
-		}
-
-		// Check for key exhaution
-		if len(search) == 0 {
-			return
-		}
-
-		// Look for an edge
-		n = n.getEdge(search[0])
-		if n == nil {
-			return
-		}
-
-		// Consume the search prefix
-		if strings.HasPrefix(search, n.prefix) {
-			search = search[len(n.prefix):]
-		} else {
-			break
-		}
-	}
-}
-
-// recursiveWalk is used to do a pre-order walk of a node
-// recursively. Returns true if the walk should be aborted
-func recursiveWalk(n *node, fn WalkFn) bool {
-	// Visit the leaf values if any
-	if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
-		return true
-	}
-
-	// Recurse on the children
-	i := 0
-	k := len(n.edges) // keeps track of number of edges in previous iteration
-	for i < k {
-		e := n.edges[i]
-		if recursiveWalk(e.node, fn) {
-			return true
-		}
-		// It is a possibility that the WalkFn modified the node we are
-		// iterating on. If there are no more edges, mergeChild happened,
-		// so the last edge became the current node n, on which we'll
-		// iterate one last time.
-		if len(n.edges) == 0 {
-			return recursiveWalk(n, fn)
-		}
-		// If there are now less edges than in the previous iteration,
-		// then do not increment the loop index, since the current index
-		// points to a new edge. Otherwise, get to the next index.
-		if len(n.edges) >= k {
-			i++
-		}
-		k = len(n.edges)
-	}
-	return false
-}
-
-// ToMap is used to walk the tree and convert it into a map
-func (t *Tree) ToMap() map[string]interface{} {
-	out := make(map[string]interface{}, t.size)
-	t.Walk(func(k string, v interface{}) bool {
-		out[k] = v
-		return false
-	})
-	return out
-}

+ 0 - 3
vendor/modules.txt

@@ -68,9 +68,6 @@ github.com/armon/circbuf
 # github.com/armon/go-metrics v0.4.1
 # github.com/armon/go-metrics v0.4.1
 ## explicit; go 1.12
 ## explicit; go 1.12
 github.com/armon/go-metrics
 github.com/armon/go-metrics
-# github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c
-## explicit
-github.com/armon/go-radix
 # github.com/aws/aws-sdk-go v1.37.0
 # github.com/aws/aws-sdk-go v1.37.0
 ## explicit; go 1.11
 ## explicit; go 1.11
 github.com/aws/aws-sdk-go/aws
 github.com/aws/aws-sdk-go/aws