mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
potfix
This commit is contained in:
parent
dca2fd0f0f
commit
d3f689a01e
5 changed files with 370 additions and 335 deletions
412
pot/pot.go
412
pot/pot.go
|
|
@ -28,21 +28,20 @@ const (
|
|||
)
|
||||
|
||||
// Pot is the root node type, allows locked non-applicative manipulation
|
||||
type Pot struct {
|
||||
lock sync.RWMutex
|
||||
*pot
|
||||
}
|
||||
// type Pot struct {
|
||||
// lock sync.RWMutex
|
||||
// *Pot
|
||||
// }
|
||||
|
||||
// pot is the node type (same for root, branching node and leaf)
|
||||
type pot struct {
|
||||
// Pot is the node type (same for root, branching node and leaf)
|
||||
type Pot struct {
|
||||
pin Val
|
||||
bins []*pot
|
||||
bins []*Pot
|
||||
size int
|
||||
po int
|
||||
pof Pof
|
||||
}
|
||||
|
||||
// Val is the element type for pots
|
||||
// Val is the element type for Pots
|
||||
type Val interface{}
|
||||
|
||||
// Pof is the proximity order function
|
||||
|
|
@ -51,21 +50,15 @@ type Pof func(Val, Val, int) (int, bool)
|
|||
// NewPot constructor. Requires value of type Val to pin
|
||||
// and po to point to a span in the Val key
|
||||
// The pinned item counts towards the size
|
||||
func NewPot(v Val, po int, pof Pof) *Pot {
|
||||
func NewPot(v Val, po int) *Pot {
|
||||
var size int
|
||||
if v != nil {
|
||||
size++
|
||||
}
|
||||
if pof == nil {
|
||||
pof = DefaultPof(keylen)
|
||||
}
|
||||
return &Pot{
|
||||
pot: &pot{
|
||||
pin: v,
|
||||
po: po,
|
||||
size: size,
|
||||
pof: pof,
|
||||
},
|
||||
pin: v,
|
||||
po: po,
|
||||
size: size,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,67 +69,71 @@ func (t *Pot) Pin() Val {
|
|||
|
||||
// Size returns the number of values in the Pot
|
||||
func (t *Pot) Size() int {
|
||||
t.lock.RLock()
|
||||
defer t.lock.RUnlock()
|
||||
// t.lock.RLock()
|
||||
// defer t.lock.RUnlock()
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
return t.size
|
||||
}
|
||||
|
||||
// Add inserts v into the Pot and
|
||||
// returns the proximity order of v and a boolean
|
||||
// indicating if the item was found
|
||||
// Add locks the Pot while using applicative add on its pot
|
||||
func (t *Pot) Add(val Val) (po int, found bool) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
t.pot, po, found = add(t.pot, val)
|
||||
return po, found
|
||||
}
|
||||
// Add locks the Pot while using applicative add on its Pot
|
||||
// func (t *Pot) Add(val Val) (po int, found bool) {
|
||||
// // t.lock.Lock()
|
||||
// // defer t.lock.Unlock()
|
||||
// t.Pot, po, found = add(t.Pot, val)
|
||||
// return po, found
|
||||
// }
|
||||
|
||||
// Add called on (t, v) returns a new Pot that contains all the elements of t
|
||||
// plus the value v, using the applicative add
|
||||
// the second return value is the proximity order of the inserted element
|
||||
// the third is boolean indicating if the item was found
|
||||
// it only readlocks the Pot while reading its pot
|
||||
func Add(t *Pot, val Val) (*Pot, int, bool) {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
r, po, found := add(n, val)
|
||||
return &Pot{pot: r}, po, found
|
||||
// it only readlocks the Pot while reading its Pot
|
||||
func Add(t *Pot, val Val, pof Pof) (*Pot, int, bool) {
|
||||
// // t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// // t.lock.RUnlock()
|
||||
// r, po, found := add(n, val)
|
||||
// return &Pot{Pot: r}, po, found
|
||||
// // return &Pot{Pot: r}, po, found
|
||||
return add(t, val, pof)
|
||||
}
|
||||
|
||||
func (t *pot) clone() *pot {
|
||||
return &pot{
|
||||
func (t *Pot) clone() *Pot {
|
||||
return &Pot{
|
||||
pin: t.pin,
|
||||
size: t.size,
|
||||
po: t.po,
|
||||
bins: t.bins,
|
||||
pof: t.pof,
|
||||
}
|
||||
}
|
||||
|
||||
func add(t *pot, val Val) (*pot, int, bool) {
|
||||
var r *pot
|
||||
func add(t *Pot, val Val, pof Pof) (*Pot, int, bool) {
|
||||
var r *Pot
|
||||
if t == nil || t.pin == nil {
|
||||
r = t.clone()
|
||||
r.pin = val
|
||||
r.size++
|
||||
return r, 0, false
|
||||
}
|
||||
po, found := t.pof(t.pin, val, t.po)
|
||||
po, found := pof(t.pin, val, t.po)
|
||||
if found {
|
||||
r = t.clone()
|
||||
r.pin = val
|
||||
return r, po, true
|
||||
}
|
||||
|
||||
var p *pot
|
||||
var p *Pot
|
||||
var i, j int
|
||||
size := t.size
|
||||
for i < len(t.bins) {
|
||||
n := t.bins[i]
|
||||
if n.po == po {
|
||||
p, _, found = add(n, val)
|
||||
p, _, found = add(n, val, pof)
|
||||
if !found {
|
||||
size++
|
||||
}
|
||||
|
|
@ -151,23 +148,21 @@ func add(t *pot, val Val) (*pot, int, bool) {
|
|||
}
|
||||
if p == nil {
|
||||
size++
|
||||
p = &pot{
|
||||
p = &Pot{
|
||||
pin: val,
|
||||
size: 1,
|
||||
po: po,
|
||||
pof: t.pof,
|
||||
}
|
||||
}
|
||||
|
||||
bins := append([]*pot{}, t.bins[:i]...)
|
||||
bins := append([]*Pot{}, t.bins[:i]...)
|
||||
bins = append(bins, p)
|
||||
bins = append(bins, t.bins[j:]...)
|
||||
r = &pot{
|
||||
r = &Pot{
|
||||
pin: t.pin,
|
||||
size: size,
|
||||
po: t.po,
|
||||
bins: bins,
|
||||
pof: t.pof,
|
||||
}
|
||||
|
||||
return r, po, found
|
||||
|
|
@ -176,57 +171,56 @@ func add(t *pot, val Val) (*pot, int, bool) {
|
|||
// Remove called on (v) deletes v from the Pot and returns
|
||||
// the proximity order of v and a boolean value indicating
|
||||
// if the value was found
|
||||
// Remove locks Pot while using applicative remove on its pot
|
||||
func (t *Pot) Remove(val Val) (po int, found bool) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
t.pot, po, found = remove(t.pot, val)
|
||||
return po, found
|
||||
}
|
||||
// Remove locks Pot while using applicative remove on its Pot
|
||||
// func (t *Pot) Remove(val Val) (po int, found bool) {
|
||||
// // t.lock.Lock()
|
||||
// // defer t.lock.Unlock()
|
||||
// t.Pot, po, found = remove(t.Pot, val)
|
||||
// return po, found
|
||||
// }
|
||||
|
||||
// Remove called on (t, v) returns a new Pot that contains all the elements of t
|
||||
// minus the value v, using the applicative remove
|
||||
// the second return value is the proximity order of the inserted element
|
||||
// the third is boolean indicating if the item was found
|
||||
// it only readlocks the Pot while reading its pot
|
||||
func Remove(t *Pot, v Val) (*Pot, int, bool) {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
r, po, found := remove(n, v)
|
||||
return &Pot{pot: r}, po, found
|
||||
// it only readlocks the Pot while reading its Pot
|
||||
func Remove(t *Pot, v Val, pof Pof) (*Pot, int, bool) {
|
||||
// // t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// // t.lock.RUnlock()
|
||||
// r, po, found := remove(n, v)
|
||||
// return &Pot{Pot: r}, po, found
|
||||
return remove(t, v, pof)
|
||||
}
|
||||
|
||||
func remove(t *pot, val Val) (r *pot, po int, found bool) {
|
||||
func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) {
|
||||
size := t.size
|
||||
po, found = t.pof(t.pin, val, t.po)
|
||||
po, found = pof(t.pin, val, t.po)
|
||||
if found {
|
||||
size--
|
||||
if size == 0 {
|
||||
r = &pot{
|
||||
po: t.po,
|
||||
pof: t.pof,
|
||||
r = &Pot{
|
||||
po: t.po,
|
||||
}
|
||||
return r, po, true
|
||||
}
|
||||
i := len(t.bins) - 1
|
||||
last := t.bins[i]
|
||||
r = &pot{
|
||||
r = &Pot{
|
||||
pin: last.pin,
|
||||
bins: append(t.bins[:i], last.bins...),
|
||||
size: size,
|
||||
po: t.po,
|
||||
pof: t.pof,
|
||||
}
|
||||
return r, t.po, true
|
||||
}
|
||||
|
||||
var p *pot
|
||||
var p *Pot
|
||||
var i, j int
|
||||
for i < len(t.bins) {
|
||||
n := t.bins[i]
|
||||
if n.po == po {
|
||||
p, po, found = remove(n, val)
|
||||
p, po, found = remove(n, val, pof)
|
||||
if found {
|
||||
size--
|
||||
}
|
||||
|
|
@ -244,12 +238,11 @@ func remove(t *pot, val Val) (r *pot, po int, found bool) {
|
|||
bins = append(bins, p)
|
||||
}
|
||||
bins = append(bins, t.bins[j:]...)
|
||||
r = &pot{
|
||||
r = &Pot{
|
||||
pin: val,
|
||||
size: size,
|
||||
po: t.po,
|
||||
bins: bins,
|
||||
pof: t.pof,
|
||||
}
|
||||
return r, po, found
|
||||
}
|
||||
|
|
@ -258,149 +251,139 @@ func remove(t *pot, val Val) (r *pot, po int, found bool) {
|
|||
// and applies the function f to the value v at k or nil if the item is not found
|
||||
// if f returns nil, the element is removed
|
||||
// if f returns v' <> v then v' is inserted into the Pot
|
||||
// if v' == v the pot is not changed
|
||||
// if v' == v the Pot is not changed
|
||||
// it panics if v'.PO(k, 0) says v and k are not equal
|
||||
func (t *Pot) Swap(val Val, f func(v Val) Val) (po int, found bool, change bool) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
var t0 *pot
|
||||
t0, po, found, change = swap(t.pot, val, f)
|
||||
if change {
|
||||
t.pot = t0
|
||||
}
|
||||
return po, found, change
|
||||
}
|
||||
// func (t *Pot) Swap(val Val, f func(v Val) Val) (po int, found bool, change bool) {
|
||||
// t.lock.Lock()
|
||||
// defer t.lock.Unlock()
|
||||
// var t0 *Pot
|
||||
// t0, po, found, change = swap(t.Pot, val, f)
|
||||
// if change {
|
||||
// t.Pot = t0
|
||||
// }
|
||||
// return po, found, change
|
||||
// }
|
||||
|
||||
func swap(t *pot, k Val, f func(v Val) Val) (r *pot, po int, found bool, change bool) {
|
||||
// Swap is applicative add, change, remove on a Pot
|
||||
// func Swap(t *Pot, val Val, f func(v Val) Val) (_ *Pot, po int, found bool, change bool) {
|
||||
// var t0 *Pot
|
||||
// t0, po, found, change = swap(t.Pot, val, f)
|
||||
// return &Pot{Pot: t0}, po, found, change
|
||||
// }
|
||||
|
||||
// func swap(t *Pot, k Val, f func(v Val) Val) (r *Pot, po int, found bool, change bool) {
|
||||
func Swap(t *Pot, k Val, pof Pof, f func(v Val) Val) (r *Pot, po int, found bool, change bool) {
|
||||
var val Val
|
||||
if t == nil || t.pin == nil {
|
||||
if t.pin == nil {
|
||||
val = f(nil)
|
||||
if val == nil {
|
||||
return t, t.po, false, false
|
||||
}
|
||||
// if _, eq := t.pof(k, t.pin, t.po); !eq {
|
||||
// panic("value key mismatch")
|
||||
// }
|
||||
r = t.clone()
|
||||
r.pin = val
|
||||
r.size++
|
||||
return r, t.po, false, true
|
||||
return NewPot(val, t.po), t.po, false, true
|
||||
}
|
||||
size := t.size
|
||||
if k == nil {
|
||||
panic("k is nil")
|
||||
}
|
||||
po, found = t.pof(k, t.pin, t.po)
|
||||
po, found = pof(k, t.pin, t.po)
|
||||
if found {
|
||||
val = f(t.pin)
|
||||
if val == nil {
|
||||
size--
|
||||
if size == 0 {
|
||||
r = &pot{
|
||||
po: t.po,
|
||||
pof: t.pof,
|
||||
r = &Pot{
|
||||
po: t.po,
|
||||
}
|
||||
return r, po, true, true
|
||||
}
|
||||
i := len(t.bins) - 1
|
||||
last := t.bins[i]
|
||||
r = &pot{
|
||||
r = &Pot{
|
||||
pin: last.pin,
|
||||
bins: append(t.bins[:i], last.bins...),
|
||||
size: size,
|
||||
po: t.po,
|
||||
pof: t.pof,
|
||||
}
|
||||
return r, t.po, true, true
|
||||
// remove element
|
||||
} else if val == t.pin {
|
||||
return nil, po, true, false
|
||||
return t, po, true, false
|
||||
} else { // add element
|
||||
r = t.clone()
|
||||
r.pin = val
|
||||
return r, po, true, true
|
||||
}
|
||||
}
|
||||
|
||||
var p *pot
|
||||
var i, j int
|
||||
for i < len(t.bins) {
|
||||
n := t.bins[i]
|
||||
if n.po == po {
|
||||
p, po, found, change = swap(n, k, f)
|
||||
if !change {
|
||||
return nil, po, found, false
|
||||
}
|
||||
size += p.size - n.size
|
||||
j++
|
||||
break
|
||||
// recursive step
|
||||
var p *Pot
|
||||
n, i := t.getPos(po)
|
||||
if n != nil {
|
||||
p, po, found, change = Swap(n, k, pof, f)
|
||||
if !change {
|
||||
return t, po, found, false
|
||||
}
|
||||
if n.po > po {
|
||||
break
|
||||
}
|
||||
i++
|
||||
j++
|
||||
}
|
||||
if p == nil {
|
||||
val := f(nil)
|
||||
size += p.size - n.size
|
||||
} else {
|
||||
val = f(nil)
|
||||
if val == nil {
|
||||
return nil, po, false, false
|
||||
return t, po, false, false
|
||||
}
|
||||
if _, eq := pof(val, k, po); !eq {
|
||||
panic("invalid value")
|
||||
}
|
||||
size++
|
||||
p = &pot{
|
||||
p = &Pot{
|
||||
pin: val,
|
||||
size: 1,
|
||||
po: po,
|
||||
pof: t.pof,
|
||||
}
|
||||
}
|
||||
|
||||
bins := append([]*pot{}, t.bins[:i]...)
|
||||
bins := append([]*Pot{}, t.bins[:i]...)
|
||||
if p.pin != nil {
|
||||
bins = append(bins, p)
|
||||
}
|
||||
bins = append(bins, t.bins[j:]...)
|
||||
r = &pot{
|
||||
pin: t.pin,
|
||||
if i < len(t.bins) {
|
||||
bins = append(bins, t.bins[i+1:]...)
|
||||
}
|
||||
r = &Pot{
|
||||
pin: f(t.pin),
|
||||
size: size,
|
||||
po: t.po,
|
||||
bins: bins,
|
||||
pof: t.pof,
|
||||
}
|
||||
|
||||
return r, po, found, true
|
||||
}
|
||||
|
||||
// Merge called on (t1) changes t0 to contain all the elements of t1
|
||||
// it locks t0, but only readlocks t1 while taking its pot
|
||||
// it locks t0, but only readlocks t1 while taking its Pot
|
||||
// uses applicative union
|
||||
func (t *Pot) Merge(t1 *Pot) (c int) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
t1.lock.RLock()
|
||||
n1 := t1.pot
|
||||
t1.lock.RUnlock()
|
||||
t.pot, c = union(t.pot, n1)
|
||||
return c
|
||||
}
|
||||
// func (t *Pot) Merge(t1 *Pot) (c int) {
|
||||
// t.lock.Lock()
|
||||
// defer t.lock.Unlock()
|
||||
// t1.lock.RLock()
|
||||
// n1 := t1.Pot
|
||||
// t1.lock.RUnlock()
|
||||
// t.Pot, c = union(t.Pot, n1)
|
||||
// return c
|
||||
// }
|
||||
|
||||
// Union returns the union of t0 and t1
|
||||
// it only readlocks the Pot-s to read their pots and
|
||||
// it only readlocks the Pot-s to read their Pots and
|
||||
// calculates the union using the applicative union
|
||||
// the second return value is the number of common elements
|
||||
func Union(t0, t1 *Pot) (*Pot, int) {
|
||||
t0.lock.RLock()
|
||||
n0 := t0.pot
|
||||
t0.lock.RUnlock()
|
||||
t1.lock.RLock()
|
||||
n1 := t1.pot
|
||||
t1.lock.RUnlock()
|
||||
|
||||
p, c := union(n0, n1)
|
||||
return &Pot{pot: p}, c
|
||||
func Union(t0, t1 *Pot, pof Pof) (*Pot, int) {
|
||||
// t0.lock.RLock()
|
||||
// n0 := t0.Pot
|
||||
// t0.lock.RUnlock()
|
||||
// t1.lock.RLock()
|
||||
// n1 := t1.Pot
|
||||
// t1.lock.RUnlock()
|
||||
//
|
||||
// p, c := union(n0, n1)
|
||||
// return &Pot{Pot: p}, c
|
||||
return union(t0, t1, pof)
|
||||
}
|
||||
|
||||
func union(t0, t1 *pot) (*pot, int) {
|
||||
func union(t0, t1 *Pot, pof Pof) (*Pot, int) {
|
||||
if t0 == nil || t0.size == 0 {
|
||||
return t1, 0
|
||||
}
|
||||
|
|
@ -408,7 +391,7 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
return t0, 0
|
||||
}
|
||||
var pin Val
|
||||
var bins []*pot
|
||||
var bins []*Pot
|
||||
var mis []int
|
||||
wg := &sync.WaitGroup{}
|
||||
pin0 := t0.pin
|
||||
|
|
@ -418,12 +401,12 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
var i0, i1 int
|
||||
var common int
|
||||
|
||||
po, eq := t0.pof(pin0, pin1, 0)
|
||||
po, eq := pof(pin0, pin1, 0)
|
||||
|
||||
for {
|
||||
l0 := len(bins0)
|
||||
l1 := len(bins1)
|
||||
var n0, n1 *pot
|
||||
var n0, n1 *Pot
|
||||
var p0, p1 int
|
||||
var a0, a1 bool
|
||||
|
||||
|
|
@ -463,9 +446,9 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
ml := len(mis)
|
||||
mis = append(mis, 0)
|
||||
wg.Add(1)
|
||||
go func(b, m int, m0, m1 *pot) {
|
||||
go func(b, m int, m0, m1 *Pot) {
|
||||
defer wg.Done()
|
||||
bins[b], mis[m] = union(m0, m1)
|
||||
bins[b], mis[m] = union(m0, m1, pof)
|
||||
}(bl, ml, n0, n1)
|
||||
i0++
|
||||
i1++
|
||||
|
|
@ -488,15 +471,14 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
for _, n := range bins0[i:] {
|
||||
size0 += n.size
|
||||
}
|
||||
np := &pot{
|
||||
np := &Pot{
|
||||
pin: pin0,
|
||||
bins: bins0[i:],
|
||||
size: size0 + 1,
|
||||
po: po,
|
||||
pof: t0.pof,
|
||||
}
|
||||
|
||||
bins2 := []*pot{np}
|
||||
bins2 := []*Pot{np}
|
||||
if n0 == nil {
|
||||
pin0 = pin1
|
||||
po = maxkeylen + 1
|
||||
|
|
@ -507,7 +489,7 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
bins2 = append(bins2, n0.bins...)
|
||||
pin0 = pin1
|
||||
pin1 = n0.pin
|
||||
po, eq = t0.pof(pin0, pin1, n0.po)
|
||||
po, eq = pof(pin0, pin1, n0.po)
|
||||
|
||||
}
|
||||
bins0 = bins1
|
||||
|
|
@ -521,12 +503,11 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
for _, c := range mis {
|
||||
common += c
|
||||
}
|
||||
n := &pot{
|
||||
n := &Pot{
|
||||
pin: pin,
|
||||
bins: bins,
|
||||
size: t0.size + t1.size - common,
|
||||
po: t0.po,
|
||||
pof: t0.pof,
|
||||
}
|
||||
return n, common
|
||||
}
|
||||
|
|
@ -535,13 +516,14 @@ func union(t0, t1 *pot) (*pot, int) {
|
|||
// respecting an ordering
|
||||
// proximity > pinnedness
|
||||
func (t *Pot) Each(f func(Val, int) bool) bool {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
return n.each(f)
|
||||
// t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// t.lock.RUnlock()
|
||||
// return n.each(f)
|
||||
return t.each(f)
|
||||
}
|
||||
|
||||
func (t *pot) each(f func(Val, int) bool) bool {
|
||||
func (t *Pot) each(f func(Val, int) bool) bool {
|
||||
var next bool
|
||||
for _, n := range t.bins {
|
||||
if n == nil {
|
||||
|
|
@ -555,7 +537,7 @@ func (t *pot) each(f func(Val, int) bool) bool {
|
|||
return f(t.pin, t.po)
|
||||
}
|
||||
|
||||
// EachFrom called with (f, start) is a synchronous iterator over the elements of a pot
|
||||
// EachFrom called with (f, start) is a synchronous iterator over the elements of a Pot
|
||||
// within the inclusive range starting from proximity order start
|
||||
// the function argument is passed the value and the proximity order wrt the root pin
|
||||
// it does NOT include the pinned item of the root
|
||||
|
|
@ -564,13 +546,14 @@ func (t *pot) each(f func(Val, int) bool) bool {
|
|||
// the iteration ends if the function return false or there are no more elements
|
||||
// end of a po range can be implemented since po is passed to the function
|
||||
func (t *Pot) EachFrom(f func(Val, int) bool, po int) bool {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
return n.eachFrom(f, po)
|
||||
// t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// t.lock.RUnlock()
|
||||
// return n.eachFrom(f, po)
|
||||
return t.eachFrom(f, po)
|
||||
}
|
||||
|
||||
func (t *pot) eachFrom(f func(Val, int) bool, po int) bool {
|
||||
func (t *Pot) eachFrom(f func(Val, int) bool, po int) bool {
|
||||
var next bool
|
||||
_, lim := t.getPos(po)
|
||||
for i := lim; i < len(t.bins); i++ {
|
||||
|
|
@ -587,21 +570,22 @@ func (t *pot) eachFrom(f func(Val, int) bool, po int) bool {
|
|||
// subtree passing the proximity order and the size
|
||||
// the iteration continues until the function's return value is false
|
||||
// or there are no more subtries
|
||||
func (t *Pot) EachBin(val Val, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
n.eachBin(val, po, f)
|
||||
func (t *Pot) EachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) {
|
||||
// t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// t.lock.RUnlock()
|
||||
// n.eachBin(val, po, f)
|
||||
t.eachBin(val, pof, po, f)
|
||||
}
|
||||
|
||||
func (t *pot) eachBin(val Val, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) {
|
||||
func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) {
|
||||
if t == nil || t.size == 0 {
|
||||
return
|
||||
}
|
||||
spr, _ := t.pof(t.pin, val, t.po)
|
||||
spr, _ := pof(t.pin, val, t.po)
|
||||
_, lim := t.getPos(spr)
|
||||
var size int
|
||||
var n *pot
|
||||
var n *Pot
|
||||
for i := 0; i < lim; i++ {
|
||||
n = t.bins[i]
|
||||
size += n.size
|
||||
|
|
@ -633,34 +617,35 @@ func (t *pot) eachBin(val Val, po int, f func(int, int, func(func(val Val, i int
|
|||
return
|
||||
}
|
||||
if spo > spr {
|
||||
n.eachBin(val, spo, f)
|
||||
n.eachBin(val, pof, spo, f)
|
||||
}
|
||||
}
|
||||
|
||||
// EachNeighbour is a syncronous iterator over neighbours of any target val
|
||||
// the order of elements retrieved reflect proximity order to the target
|
||||
// TODO: add maximum proxbin to start range of iteration
|
||||
func (t *Pot) EachNeighbour(val Val, f func(Val, int) bool) bool {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
return n.eachNeighbour(val, f)
|
||||
func (t *Pot) EachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool {
|
||||
// t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// t.lock.RUnlock()
|
||||
// return n.eachNeighbour(val, f)
|
||||
return t.eachNeighbour(val, pof, f)
|
||||
}
|
||||
|
||||
func (t *pot) eachNeighbour(val Val, f func(Val, int) bool) bool {
|
||||
func (t *Pot) eachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool {
|
||||
if t == nil || t.size == 0 {
|
||||
return false
|
||||
}
|
||||
var next bool
|
||||
l := len(t.bins)
|
||||
var n *pot
|
||||
var n *Pot
|
||||
ir := l
|
||||
il := l
|
||||
po, eq := t.pof(t.pin, val, t.po)
|
||||
po, eq := pof(t.pin, val, t.po)
|
||||
if !eq {
|
||||
n, il = t.getPos(po)
|
||||
if n != nil {
|
||||
next = n.eachNeighbour(val, f)
|
||||
next = n.eachNeighbour(val, pof, f)
|
||||
if !next {
|
||||
return false
|
||||
}
|
||||
|
|
@ -698,19 +683,19 @@ func (t *pot) eachNeighbour(val Val, f func(Val, int) bool) bool {
|
|||
|
||||
// EachNeighbourAsync called on (val, max, maxPos, f, wait) is an asyncronous iterator
|
||||
// over elements not closer than maxPos wrt val.
|
||||
// val does not need to be match an element of the pot, but if it does, and
|
||||
// val does not need to be match an element of the Pot, but if it does, and
|
||||
// maxPos is keylength than it is included in the iteration
|
||||
// Calls to f are parallelised, the order of calls is undefined.
|
||||
// proximity order is respected in that there is no element in the pot that
|
||||
// proximity order is respected in that there is no element in the Pot that
|
||||
// is not visited if a closer node is visited.
|
||||
// The iteration is finished when max number of nearest nodes is visited
|
||||
// or if the entire there are no nodes not closer than maxPos that is not visited
|
||||
// if wait is true, the iterator returns only if all calls to f are finished
|
||||
// TODO: implement minPos for proper prox range iteration
|
||||
func (t *Pot) EachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int), wait bool) {
|
||||
t.lock.RLock()
|
||||
n := t.pot
|
||||
t.lock.RUnlock()
|
||||
func (t *Pot) EachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(Val, int), wait bool) {
|
||||
// t.lock.RLock()
|
||||
// n := t.Pot
|
||||
// t.lock.RUnlock()
|
||||
if max > t.size {
|
||||
max = t.size
|
||||
}
|
||||
|
|
@ -718,28 +703,25 @@ func (t *Pot) EachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int),
|
|||
if wait {
|
||||
wg = &sync.WaitGroup{}
|
||||
}
|
||||
_ = n.eachNeighbourAsync(val, max, maxPos, f, wg)
|
||||
// _ = n.eachNeighbourAsync(val, max, maxPos, f, wg)
|
||||
_ = t.eachNeighbourAsync(val, pof, max, maxPos, f, wg)
|
||||
if wait {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *pot) eachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int), wg *sync.WaitGroup) (extra int) {
|
||||
func (t *Pot) eachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(Val, int), wg *sync.WaitGroup) (extra int) {
|
||||
l := len(t.bins)
|
||||
var n *pot
|
||||
il := l
|
||||
ir := l
|
||||
// ic := l
|
||||
|
||||
po, eq := t.pof(t.pin, val, t.po)
|
||||
po, eq := pof(t.pin, val, t.po)
|
||||
|
||||
// if po is too close, set the pivot branch (pom) to maxPos
|
||||
pom := po
|
||||
if pom > maxPos {
|
||||
pom = maxPos
|
||||
}
|
||||
n, il = t.getPos(pom)
|
||||
ir = il
|
||||
n, il := t.getPos(pom)
|
||||
ir := il
|
||||
// if pivot branch exists and po is not too close, iterate on the pivot branch
|
||||
if pom == po {
|
||||
if n != nil {
|
||||
|
|
@ -750,7 +732,7 @@ func (t *pot) eachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int),
|
|||
}
|
||||
max -= m
|
||||
|
||||
extra = n.eachNeighbourAsync(val, m, maxPos, f, wg)
|
||||
extra = n.eachNeighbourAsync(val, pof, m, maxPos, f, wg)
|
||||
|
||||
} else {
|
||||
if !eq {
|
||||
|
|
@ -806,7 +788,7 @@ func (t *pot) eachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int),
|
|||
if wg != nil {
|
||||
wg.Add(m)
|
||||
}
|
||||
go func(pn *pot, pm int) {
|
||||
go func(pn *Pot, pm int) {
|
||||
pn.each(func(v Val, _ int) bool {
|
||||
if wg != nil {
|
||||
defer wg.Done()
|
||||
|
|
@ -833,7 +815,7 @@ func (t *pot) eachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int),
|
|||
if wg != nil {
|
||||
wg.Add(m)
|
||||
}
|
||||
go func(pn *pot, pm int) {
|
||||
go func(pn *Pot, pm int) {
|
||||
pn.each(func(v Val, _ int) bool {
|
||||
if wg != nil {
|
||||
defer wg.Done()
|
||||
|
|
@ -851,7 +833,7 @@ func (t *pot) eachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int),
|
|||
// getPos called on (n) returns the forking node at PO n and its index if it exists
|
||||
// otherwise nil
|
||||
// caller is suppoed to hold the lock
|
||||
func (t *pot) getPos(po int) (n *pot, i int) {
|
||||
func (t *Pot) getPos(po int) (n *Pot, i int) {
|
||||
for i, n = range t.bins {
|
||||
if po > n.po {
|
||||
continue
|
||||
|
|
@ -877,11 +859,11 @@ func need(m, max, extra int) (int, int, int) {
|
|||
return m, max, 0
|
||||
}
|
||||
|
||||
func (t *pot) String() string {
|
||||
func (t *Pot) String() string {
|
||||
return t.sstring("")
|
||||
}
|
||||
|
||||
func (t *pot) sstring(indent string) string {
|
||||
func (t *Pot) sstring(indent string) string {
|
||||
if t == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
|
|
|||
151
pot/pot_test.go
151
pot/pot_test.go
|
|
@ -19,7 +19,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
|
|
@ -34,7 +33,7 @@ const (
|
|||
)
|
||||
|
||||
func init() {
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||
}
|
||||
|
||||
type testAddr struct {
|
||||
|
|
@ -84,15 +83,18 @@ func indexes(t *Pot) (i []int, po []int) {
|
|||
return i, po
|
||||
}
|
||||
|
||||
func testAdd(t *Pot, n int, values ...string) {
|
||||
func testAdd(t *Pot, pof Pof, j int, values ...string) (_ *Pot, n int, f bool) {
|
||||
for i, val := range values {
|
||||
t.Add(newTestAddr(val, i+n))
|
||||
t, n, f = Add(t, newTestAddr(val, i+j), pof)
|
||||
// t.Add(newTestAddr(val, i+n))
|
||||
}
|
||||
return t, n, f
|
||||
}
|
||||
|
||||
// func RandomBoolAddress()
|
||||
func TestPotAdd(t *testing.T) {
|
||||
n := NewPot(newTestAddr("00111100", 0), 0, DefaultPof(8))
|
||||
pof := DefaultPof(8)
|
||||
n := NewPot(newTestAddr("00111100", 0), 0)
|
||||
// Pin set correctly
|
||||
exp := "00111100"
|
||||
got := Label(n.Pin())[:8]
|
||||
|
|
@ -106,7 +108,7 @@ func TestPotAdd(t *testing.T) {
|
|||
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
|
||||
}
|
||||
|
||||
testAdd(n, 1, "01111100", "00111100", "01111100", "00011100")
|
||||
n, _, _ = testAdd(n, pof, 1, "01111100", "00111100", "01111100", "00011100")
|
||||
// check size
|
||||
goti = n.Size()
|
||||
expi = 3
|
||||
|
|
@ -128,15 +130,16 @@ func TestPotAdd(t *testing.T) {
|
|||
|
||||
// func RandomBoolAddress()
|
||||
func TestPotRemove(t *testing.T) {
|
||||
n := NewPot(newTestAddr("00111100", 0), 0, DefaultPof(8))
|
||||
n.Remove(newTestAddr("00111100", 0))
|
||||
pof := DefaultPof(8)
|
||||
n := NewPot(newTestAddr("00111100", 0), 0)
|
||||
n, _, _ = Remove(n, newTestAddr("00111100", 0), pof)
|
||||
exp := "<nil>"
|
||||
got := Label(n.Pin())
|
||||
if got != exp {
|
||||
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got)
|
||||
}
|
||||
testAdd(n, 1, "00000000", "01111100", "00111100", "00011100")
|
||||
n.Remove(newTestAddr("00111100", 0))
|
||||
n, _, _ = testAdd(n, pof, 1, "00000000", "01111100", "00111100", "00011100")
|
||||
n, _, _ = Remove(n, newTestAddr("00111100", 0), pof)
|
||||
goti := n.Size()
|
||||
expi := 3
|
||||
if goti != expi {
|
||||
|
|
@ -154,8 +157,8 @@ func TestPotRemove(t *testing.T) {
|
|||
t.Fatalf("incorrect po-s in iteration over Pot. Expected %v, got %v", exp, got)
|
||||
}
|
||||
// remove again
|
||||
n.Remove(newTestAddr("00111100", 0))
|
||||
inds, po = indexes(n)
|
||||
n, _, _ = Remove(n, newTestAddr("00111100", 0), pof)
|
||||
inds, _ = indexes(n)
|
||||
got = fmt.Sprintf("%v", inds)
|
||||
exp = "[2 4]"
|
||||
if got != exp {
|
||||
|
|
@ -165,13 +168,14 @@ func TestPotRemove(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPotSwap(t *testing.T) {
|
||||
// t.Skip("")
|
||||
pof := DefaultPof(8)
|
||||
max := maxEachNeighbour
|
||||
n := NewPot(nil, 0, nil)
|
||||
n := NewPot(nil, 0)
|
||||
var m []*testAddr
|
||||
var found bool
|
||||
for j := 0; j < 2*max; {
|
||||
v := randomtestAddr(keylen, j)
|
||||
_, found := n.Add(v)
|
||||
n, _, found = Add(n, v, pof)
|
||||
if !found {
|
||||
m = append(m, v)
|
||||
j++
|
||||
|
|
@ -198,7 +202,7 @@ func TestPotSwap(t *testing.T) {
|
|||
return v
|
||||
}
|
||||
for _, val := range m {
|
||||
n.Swap(val, func(v Val) Val {
|
||||
n, _, _, _ = Swap(n, val, pof, func(v Val) Val {
|
||||
if v == nil {
|
||||
return val
|
||||
}
|
||||
|
|
@ -234,7 +238,7 @@ func checkPo(val Val, pof Pof) func(Val, int) error {
|
|||
}
|
||||
|
||||
func checkOrder(val Val) func(Val, int) error {
|
||||
var po int = keylen
|
||||
po := keylen
|
||||
return func(v Val, p int) error {
|
||||
if po < p {
|
||||
return fmt.Errorf("incorrect order for item %v in neighbour iteration for %v. PO %v > %v (previous max)", v, val, p, po)
|
||||
|
|
@ -260,10 +264,10 @@ func checkValues(m map[string]bool, val Val) func(Val, int) error {
|
|||
|
||||
var errNoCount = errors.New("not count")
|
||||
|
||||
func testPotEachNeighbour(n *Pot, val Val, expCount int, fs ...func(Val, int) error) error {
|
||||
func testPotEachNeighbour(n *Pot, pof Pof, val Val, expCount int, fs ...func(Val, int) error) error {
|
||||
var err error
|
||||
var count int
|
||||
n.EachNeighbour(val, func(v Val, po int) bool {
|
||||
n.EachNeighbour(val, pof, func(v Val, po int) bool {
|
||||
for _, f := range fs {
|
||||
err = f(v, po)
|
||||
if err != nil {
|
||||
|
|
@ -287,41 +291,43 @@ const (
|
|||
mergeTestChoose = 5
|
||||
)
|
||||
|
||||
func TestPotMergeOne(t *testing.T) {
|
||||
pot1 := NewPot(nil, 0, DefaultPof(2))
|
||||
pot1.Add(newTestAddr("10", 0))
|
||||
pot1.Add(newTestAddr("00", 0))
|
||||
pot2 := NewPot(nil, 0, DefaultPof(2))
|
||||
pot2.Add(newTestAddr("01", 0))
|
||||
pot1.Merge(pot2)
|
||||
count := 0
|
||||
pot1.Each(func(val Val, i int) bool {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
if count != 3 {
|
||||
t.Fatalf("expected count to be 3, got %d\n%v\n%v", count, pot2, pot1)
|
||||
}
|
||||
}
|
||||
//
|
||||
// func TestPotMergeOne(t *testing.T) {
|
||||
// pot1 := NewPot(nil, 0, DefaultPof(2))
|
||||
// pot1.Add(newTestAddr("10", 0))
|
||||
// pot1.Add(newTestAddr("00", 0))
|
||||
// pot2 := NewPot(nil, 0, DefaultPof(2))
|
||||
// pot2.Add(newTestAddr("01", 0))
|
||||
// pot1.Merge(pot2)
|
||||
// count := 0
|
||||
// pot1.Each(func(val Val, i int) bool {
|
||||
// count++
|
||||
// return true
|
||||
// })
|
||||
// if count != 3 {
|
||||
// t.Fatalf("expected count to be 3, got %d\n%v\n%v", count, pot2, pot1)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestPotMergeCommon(t *testing.T) {
|
||||
vs := make([]*testAddr, mergeTestCount)
|
||||
// vs := make([]*testAddr, mergeTestCount)
|
||||
pof := DefaultPof(maxkeylen)
|
||||
for i := 0; i < maxEachNeighbourTests; i++ {
|
||||
|
||||
for i := 0; i < len(vs); i++ {
|
||||
vs[i] = randomtestAddr(keylen, i)
|
||||
for j := 0; j < len(vs); j++ {
|
||||
vs[j] = randomtestAddr(keylen, j)
|
||||
}
|
||||
max0 := rand.Intn(mergeTestChoose) + 1
|
||||
max1 := rand.Intn(mergeTestChoose) + 1
|
||||
n0 := NewPot(nil, 0, nil)
|
||||
n1 := NewPot(nil, 0, nil)
|
||||
n0 := NewPot(nil, 0)
|
||||
n1 := NewPot(nil, 0)
|
||||
log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1))
|
||||
m := make(map[string]bool)
|
||||
var found bool
|
||||
for j := 0; j < max0; {
|
||||
r := rand.Intn(max0)
|
||||
v := vs[r]
|
||||
_, found := n0.Add(v)
|
||||
n0, _, found = Add(n0, v, pof)
|
||||
if !found {
|
||||
m[Label(v)] = false
|
||||
j++
|
||||
|
|
@ -332,7 +338,7 @@ func TestPotMergeCommon(t *testing.T) {
|
|||
for j := 0; j < max1; {
|
||||
r := rand.Intn(max1)
|
||||
v := vs[r]
|
||||
_, found := n1.Add(v)
|
||||
n1, _, found = Add(n1, v, pof)
|
||||
if !found {
|
||||
j++
|
||||
}
|
||||
|
|
@ -349,7 +355,7 @@ func TestPotMergeCommon(t *testing.T) {
|
|||
log.Trace(fmt.Sprintf("%v-0: pin: %v, size: %v", i, n0.Pin(), max0))
|
||||
log.Trace(fmt.Sprintf("%v-1: pin: %v, size: %v", i, n1.Pin(), max1))
|
||||
log.Trace(fmt.Sprintf("%v: merged tree size: %v, newly added: %v", i, expSize, expAdded))
|
||||
n, common := Union(n0, n1)
|
||||
n, common := Union(n0, n1, pof)
|
||||
added := n1.Size() - common
|
||||
size := n.Size()
|
||||
|
||||
|
|
@ -359,11 +365,11 @@ func TestPotMergeCommon(t *testing.T) {
|
|||
if expAdded != added {
|
||||
t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added)
|
||||
}
|
||||
if !checkDuplicates(n.pot) {
|
||||
if !checkDuplicates(n) {
|
||||
t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n)
|
||||
}
|
||||
for k := range m {
|
||||
_, found := n.Add(newTestAddr(k, 0))
|
||||
n, _, found := Add(n, newTestAddr(k, 0), pof)
|
||||
if !found {
|
||||
t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v\n%v", i, size, added, k, n)
|
||||
}
|
||||
|
|
@ -372,17 +378,20 @@ func TestPotMergeCommon(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPotMergeScale(t *testing.T) {
|
||||
pof := DefaultPof(maxkeylen)
|
||||
for i := 0; i < maxEachNeighbourTests; i++ {
|
||||
max0 := rand.Intn(maxEachNeighbour) + 1
|
||||
max1 := rand.Intn(maxEachNeighbour) + 1
|
||||
n0 := NewPot(nil, 0, nil)
|
||||
n1 := NewPot(nil, 0, nil)
|
||||
n0 := NewPot(nil, 0)
|
||||
n1 := NewPot(nil, 0)
|
||||
log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1))
|
||||
m := make(map[string]bool)
|
||||
var found bool
|
||||
for j := 0; j < max0; {
|
||||
v := randomtestAddr(keylen, j)
|
||||
// v := randomtestAddr(keylen, j)
|
||||
_, found := n0.Add(v)
|
||||
n0, _, found = Add(n0, v, pof)
|
||||
// _, found := n0.Add(v)
|
||||
if !found {
|
||||
m[Label(v)] = false
|
||||
j++
|
||||
|
|
@ -393,7 +402,8 @@ func TestPotMergeScale(t *testing.T) {
|
|||
for j := 0; j < max1; {
|
||||
v := randomtestAddr(keylen, j)
|
||||
// v := randomtestAddr(keylen, j)
|
||||
_, found := n1.Add(v)
|
||||
n1, _, found = Add(n1, v, pof)
|
||||
// _, found := n1.Add(v)
|
||||
if !found {
|
||||
j++
|
||||
}
|
||||
|
|
@ -410,7 +420,7 @@ func TestPotMergeScale(t *testing.T) {
|
|||
log.Trace(fmt.Sprintf("%v-0: pin: %v, size: %v", i, n0.Pin(), max0))
|
||||
log.Trace(fmt.Sprintf("%v-1: pin: %v, size: %v", i, n1.Pin(), max1))
|
||||
log.Trace(fmt.Sprintf("%v: merged tree size: %v, newly added: %v", i, expSize, expAdded))
|
||||
n, common := Union(n0, n1)
|
||||
n, common := Union(n0, n1, pof)
|
||||
added := n1.Size() - common
|
||||
size := n.Size()
|
||||
|
||||
|
|
@ -420,11 +430,11 @@ func TestPotMergeScale(t *testing.T) {
|
|||
if expAdded != added {
|
||||
t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added)
|
||||
}
|
||||
if !checkDuplicates(n.pot) {
|
||||
if !checkDuplicates(n) {
|
||||
t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n)
|
||||
}
|
||||
for k := range m {
|
||||
_, found := n.Add(newTestAddr(k, 0))
|
||||
n, _, found := Add(n, newTestAddr(k, 0), pof)
|
||||
if !found {
|
||||
t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v\n%v", i, size, added, k, n)
|
||||
}
|
||||
|
|
@ -432,7 +442,7 @@ func TestPotMergeScale(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkDuplicates(t *pot) bool {
|
||||
func checkDuplicates(t *Pot) bool {
|
||||
po := -1
|
||||
for _, c := range t.bins {
|
||||
if c == nil {
|
||||
|
|
@ -447,15 +457,16 @@ func checkDuplicates(t *pot) bool {
|
|||
}
|
||||
|
||||
func TestPotEachNeighbourSync(t *testing.T) {
|
||||
pof := DefaultPof(maxkeylen)
|
||||
for i := 0; i < maxEachNeighbourTests; i++ {
|
||||
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
|
||||
pin := randomTestAddr(keylen, 0)
|
||||
n := NewPot(pin, 0, nil)
|
||||
n := NewPot(pin, 0)
|
||||
m := make(map[string]bool)
|
||||
m[Label(pin)] = false
|
||||
for j := 1; j <= max; j++ {
|
||||
v := randomTestAddr(keylen, j)
|
||||
n.Add(v)
|
||||
n, _, _ = Add(n, v, pof)
|
||||
m[Label(v)] = false
|
||||
}
|
||||
|
||||
|
|
@ -466,14 +477,14 @@ func TestPotEachNeighbourSync(t *testing.T) {
|
|||
count := rand.Intn(size/2) + size/2
|
||||
val := randomTestAddr(keylen, max+1)
|
||||
log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count))
|
||||
err := testPotEachNeighbour(n, val, count, checkPo(val, n.pof), checkOrder(val), checkValues(m, val))
|
||||
err := testPotEachNeighbour(n, pof, val, count, checkPo(val, pof), checkOrder(val), checkValues(m, val))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
minPoFound := keylen
|
||||
maxPoNotFound := 0
|
||||
for k, found := range m {
|
||||
po, _ := n.pof(val, newTestAddr(k, 0), 0)
|
||||
po, _ := pof(val, newTestAddr(k, 0), 0)
|
||||
if found {
|
||||
if po < minPoFound {
|
||||
minPoFound = po
|
||||
|
|
@ -491,13 +502,15 @@ func TestPotEachNeighbourSync(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPotEachNeighbourAsync(t *testing.T) {
|
||||
pof := DefaultPof(maxkeylen)
|
||||
for i := 0; i < maxEachNeighbourTests; i++ {
|
||||
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
|
||||
n := NewPot(randomTestAddr(keylen, 0), 0, nil)
|
||||
n := NewPot(randomTestAddr(keylen, 0), 0)
|
||||
size := 1
|
||||
var found bool
|
||||
for j := 1; j <= max; j++ {
|
||||
v := randomTestAddr(keylen, j)
|
||||
_, found := n.Add(v)
|
||||
n, _, found = Add(n, v, pof)
|
||||
if !found {
|
||||
size++
|
||||
}
|
||||
|
|
@ -527,7 +540,7 @@ func TestPotEachNeighbourAsync(t *testing.T) {
|
|||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
testPotEachNeighbour(n, val, count, remember)
|
||||
testPotEachNeighbour(n, pof, val, count, remember)
|
||||
d := 0
|
||||
forget := func(v Val, po int) {
|
||||
mu.Lock()
|
||||
|
|
@ -536,7 +549,7 @@ func TestPotEachNeighbourAsync(t *testing.T) {
|
|||
delete(m, Label(v))
|
||||
}
|
||||
|
||||
n.EachNeighbourAsync(val, count, maxPos, forget, true)
|
||||
n.EachNeighbourAsync(val, pof, count, maxPos, forget, true)
|
||||
if d != msize {
|
||||
t.Fatalf("incorrect number of neighbour calls in async iterator. expected %v, got %v", msize, d)
|
||||
}
|
||||
|
|
@ -548,11 +561,13 @@ func TestPotEachNeighbourAsync(t *testing.T) {
|
|||
|
||||
func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
|
||||
t.ReportAllocs()
|
||||
pof := DefaultPof(maxkeylen)
|
||||
pin := randomTestAddr(keylen, 0)
|
||||
n := NewPot(pin, 0, nil)
|
||||
n := NewPot(pin, 0)
|
||||
var found bool
|
||||
for j := 1; j <= max; {
|
||||
v := randomTestAddr(keylen, j)
|
||||
_, found := n.Add(v)
|
||||
n, _, found = Add(n, v, pof)
|
||||
if !found {
|
||||
j++
|
||||
}
|
||||
|
|
@ -561,7 +576,7 @@ func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
|
|||
for i := 0; i < t.N; i++ {
|
||||
val := randomTestAddr(keylen, max+1)
|
||||
m := 0
|
||||
n.EachNeighbour(val, func(v Val, po int) bool {
|
||||
n.EachNeighbour(val, pof, func(v Val, po int) bool {
|
||||
time.Sleep(d)
|
||||
m++
|
||||
if m == count {
|
||||
|
|
@ -578,11 +593,13 @@ func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
|
|||
|
||||
func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) {
|
||||
t.ReportAllocs()
|
||||
pof := DefaultPof(maxkeylen)
|
||||
pin := randomTestAddr(keylen, 0)
|
||||
n := NewPot(pin, 0, nil)
|
||||
n := NewPot(pin, 0)
|
||||
var found bool
|
||||
for j := 1; j <= max; {
|
||||
v := randomTestAddr(keylen, j)
|
||||
_, found := n.Add(v)
|
||||
n, _, found = Add(n, v, pof)
|
||||
if !found {
|
||||
j++
|
||||
}
|
||||
|
|
@ -590,7 +607,7 @@ func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration)
|
|||
t.ResetTimer()
|
||||
for i := 0; i < t.N; i++ {
|
||||
val := randomTestAddr(keylen, max+1)
|
||||
n.EachNeighbourAsync(val, count, keylen, func(v Val, po int) {
|
||||
n.EachNeighbourAsync(val, pof, count, keylen, func(v Val, po int) {
|
||||
time.Sleep(d)
|
||||
}, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ func newHiveTester(t *testing.T, params *HiveParams) (*bzzTester, *Hive) {
|
|||
}
|
||||
|
||||
func TestRegisterAndConnect(t *testing.T) {
|
||||
t.Skip("deadlocked")
|
||||
params := NewHiveParams()
|
||||
s, pp := newHiveTester(t, params)
|
||||
defer s.Stop()
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
|
@ -47,6 +48,8 @@ a guaranteed constant maximum limit on the number of hops needed to reach one
|
|||
node from the other.
|
||||
*/
|
||||
|
||||
var pof = pot.DefaultPof(256)
|
||||
|
||||
// KadParams holds the config params for Kademlia
|
||||
type KadParams struct {
|
||||
// adjustable parameters
|
||||
|
|
@ -76,11 +79,12 @@ func NewKadParams() *KadParams {
|
|||
|
||||
// Kademlia is a table of live peers and a db of known peers
|
||||
type Kademlia struct {
|
||||
*KadParams // Kademlia configuration parameters
|
||||
base []byte // immutable baseaddress of the table
|
||||
addrs *pot.Pot // pots container for known peer addresses
|
||||
conns *pot.Pot // pots container for live peer connections
|
||||
depth uint8 // stores the last calculated depth
|
||||
lock sync.RWMutex
|
||||
*KadParams // Kademlia configuration parameters
|
||||
base []byte // immutable baseaddress of the table
|
||||
addrs *pot.Pot // pots container for known peer addresses
|
||||
conns *pot.Pot // pots container for live peer connections
|
||||
currentDepth uint8 // stores the last calculated depth
|
||||
}
|
||||
|
||||
// NewKademlia creates a Kademlia table for base address addr
|
||||
|
|
@ -93,8 +97,8 @@ func NewKademlia(addr []byte, params *KadParams) *Kademlia {
|
|||
return &Kademlia{
|
||||
base: addr,
|
||||
KadParams: params,
|
||||
addrs: pot.NewPot(nil, 0, nil),
|
||||
conns: pot.NewPot(nil, 0, nil),
|
||||
addrs: pot.NewPot(nil, 0),
|
||||
conns: pot.NewPot(nil, 0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,15 +177,19 @@ func (e *entry) conn() OverlayConn {
|
|||
// Register enters each OverlayAddr as kademlia peer record into the
|
||||
// database of known peer addresses
|
||||
func (k *Kademlia) Register(peers chan OverlayAddr) error {
|
||||
np := pot.NewPot(nil, 0, nil)
|
||||
|
||||
np := pot.NewPot(nil, 0)
|
||||
for p := range peers {
|
||||
// error if k received, peer should know better
|
||||
if bytes.Equal(p.Address(), k.base) {
|
||||
return fmt.Errorf("add peers: %x is k", k.base)
|
||||
}
|
||||
np, _, _ = pot.Add(np, newEntry(p))
|
||||
np, _, _ = pot.Add(np, newEntry(p), pof)
|
||||
}
|
||||
com := k.addrs.Merge(np)
|
||||
var com int
|
||||
k.lock.Lock()
|
||||
defer k.lock.Unlock()
|
||||
k.addrs, com = pot.Union(k.addrs, np, pof)
|
||||
log.Trace(fmt.Sprintf("%x merged %v peers, %v known, total: %v", k.BaseAddr()[:4], np.Size(), com, k.addrs.Size()))
|
||||
return nil
|
||||
}
|
||||
|
|
@ -191,13 +199,14 @@ func (k *Kademlia) Register(peers chan OverlayAddr) error {
|
|||
// naturally if there is an empty row it returns a peer for that
|
||||
//
|
||||
func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
minsize := k.MinBinSize
|
||||
depth := k.Depth()
|
||||
// empty := k.FirstEmptyBin()
|
||||
depth := k.depth()
|
||||
// if there is a callable neighbour within the current proxBin, connect
|
||||
// this makes sure nearest neighbour set is fully connected
|
||||
var ppo int
|
||||
k.addrs.EachNeighbour(k.base, func(val pot.Val, po int) bool {
|
||||
k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool {
|
||||
if po < depth {
|
||||
return false
|
||||
}
|
||||
|
|
@ -214,7 +223,7 @@ func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
|
|||
|
||||
var bpo []int
|
||||
prev := -1
|
||||
k.conns.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
prev++
|
||||
for ; prev < po; prev++ {
|
||||
bpo = append(bpo, prev)
|
||||
|
|
@ -238,7 +247,7 @@ func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
|
|||
// find the first callable peer
|
||||
i := 0
|
||||
nxt := bpo[0]
|
||||
k.addrs.EachBin(k.base, nxt, func(po, size int, f func(func(pot.Val, int) bool) bool) bool {
|
||||
k.addrs.EachBin(k.base, pof, nxt, func(po, size int, f func(func(pot.Val, int) bool) bool) bool {
|
||||
// for each bin we find callable candidate peers
|
||||
if i >= depth {
|
||||
return false
|
||||
|
|
@ -264,29 +273,34 @@ func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
|
|||
|
||||
// On inserts the peer as a kademlia peer into the live peers
|
||||
func (k *Kademlia) On(p OverlayConn) {
|
||||
k.lock.Lock()
|
||||
defer k.lock.Unlock()
|
||||
e := newEntry(p)
|
||||
k.conns.Swap(p, func(v pot.Val) pot.Val {
|
||||
var ins bool
|
||||
k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val {
|
||||
// if not found live
|
||||
if v == nil {
|
||||
// insert new online peer into addrs
|
||||
k.addrs.Swap(p, func(v pot.Val) pot.Val {
|
||||
return e
|
||||
})
|
||||
ins = true
|
||||
// insert new online peer into conns
|
||||
return e
|
||||
}
|
||||
// found among live peers, do nothing
|
||||
return v
|
||||
})
|
||||
|
||||
if ins {
|
||||
// insert new online peer into addrs
|
||||
k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
|
||||
return e
|
||||
})
|
||||
}
|
||||
np, ok := p.(Notifier)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
depth := uint8(k.Depth())
|
||||
if depth != k.depth {
|
||||
k.depth = depth
|
||||
depth := uint8(k.depth())
|
||||
if depth != k.currentDepth {
|
||||
k.currentDepth = depth
|
||||
} else {
|
||||
depth = 0
|
||||
}
|
||||
|
|
@ -301,33 +315,41 @@ func (k *Kademlia) On(p OverlayConn) {
|
|||
log.Trace(fmt.Sprintf("peer %v notified of new depth %v", dp, depth))
|
||||
}
|
||||
}
|
||||
k.conns.EachNeighbourAsync(e, 1024, 255, f, false)
|
||||
k.conns.EachNeighbourAsync(e, pof, 1024, 255, f, false)
|
||||
}
|
||||
|
||||
// Off removes a peer from among live peers
|
||||
func (k *Kademlia) Off(p OverlayConn) {
|
||||
k.addrs.Swap(p, func(v pot.Val) pot.Val {
|
||||
k.lock.Lock()
|
||||
defer k.lock.Unlock()
|
||||
var del bool
|
||||
k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val {
|
||||
// v cannot be nil, must check otherwise we overwrite entry
|
||||
if v == nil {
|
||||
panic(fmt.Sprintf("connected peer not found %v", p))
|
||||
}
|
||||
k.conns.Swap(p, func(_ pot.Val) pot.Val {
|
||||
del = true
|
||||
return newEntry(p.Off())
|
||||
})
|
||||
if del {
|
||||
k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val {
|
||||
// v cannot be nil, but no need to check
|
||||
return nil
|
||||
})
|
||||
return newEntry(p.Off())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// EachConn is an iterator with args (base, po, f) applies f to each live peer
|
||||
// that has proximity order po or less as measured from the base
|
||||
// if base is nil, kademlia base address is used
|
||||
func (k *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) {
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
if len(base) == 0 {
|
||||
base = k.base
|
||||
}
|
||||
depth := k.Depth()
|
||||
k.conns.EachNeighbour(base, func(val pot.Val, po int) bool {
|
||||
depth := k.depth()
|
||||
k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
|
||||
if po > o {
|
||||
return true
|
||||
}
|
||||
|
|
@ -342,7 +364,9 @@ func (k *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool) {
|
|||
if len(base) == 0 {
|
||||
base = k.base
|
||||
}
|
||||
k.addrs.EachNeighbour(base, func(val pot.Val, po int) bool {
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool {
|
||||
if po > o {
|
||||
return true
|
||||
}
|
||||
|
|
@ -354,6 +378,12 @@ func (k *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool) {
|
|||
// the nearest neighbour set with cardinality >= MinProxBinSize
|
||||
// if there is altogether less than MinProxBinSize peers it returns 0
|
||||
func (k *Kademlia) Depth() (depth int) {
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
return k.depth()
|
||||
}
|
||||
|
||||
func (k *Kademlia) depth() (depth int) {
|
||||
if k.conns.Size() < k.MinProxBinSize {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -363,7 +393,7 @@ func (k *Kademlia) Depth() (depth int) {
|
|||
depth = i
|
||||
return size < k.MinProxBinSize
|
||||
}
|
||||
k.conns.EachNeighbour(k.base, f)
|
||||
k.conns.EachNeighbour(k.base, pof, f)
|
||||
return depth
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +431,9 @@ func (k *Kademlia) BaseAddr() []byte {
|
|||
|
||||
// String returns kademlia table + kaddb table displayed with ascii
|
||||
func (k *Kademlia) String() string {
|
||||
wsrow := " "
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
wsrow := " "
|
||||
var rows []string
|
||||
|
||||
rows = append(rows, "=========================================================================")
|
||||
|
|
@ -414,7 +446,7 @@ func (k *Kademlia) String() string {
|
|||
prev := -1
|
||||
var depthSet bool
|
||||
rest := k.conns.Size()
|
||||
k.conns.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
var rowlen int
|
||||
if po >= k.MaxProxDisplay {
|
||||
po = k.MaxProxDisplay - 1
|
||||
|
|
@ -423,7 +455,7 @@ func (k *Kademlia) String() string {
|
|||
rest -= size
|
||||
f(func(val pot.Val, vpo int) bool {
|
||||
e := val.(*entry)
|
||||
row = append(row, e.String())
|
||||
row = append(row, fmt.Sprintf("%x", e.Address()[:2]))
|
||||
rowlen++
|
||||
return rowlen < 4
|
||||
})
|
||||
|
|
@ -431,14 +463,14 @@ func (k *Kademlia) String() string {
|
|||
depthSet = true
|
||||
depth = prev + 1
|
||||
}
|
||||
row = append(row, wsrow)
|
||||
r := strings.Join(row, " ")
|
||||
liverows[po] = r[:35]
|
||||
r = r + wsrow
|
||||
liverows[po] = r[:31]
|
||||
prev = po
|
||||
return true
|
||||
})
|
||||
|
||||
k.addrs.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
var rowlen int
|
||||
if po >= k.MaxProxDisplay {
|
||||
po = k.MaxProxDisplay - 1
|
||||
|
|
@ -464,7 +496,7 @@ func (k *Kademlia) String() string {
|
|||
left := liverows[i]
|
||||
right := peersrows[i]
|
||||
if len(left) == 0 {
|
||||
left = " 0 "
|
||||
left = " 0 "
|
||||
}
|
||||
if len(right) == 0 {
|
||||
right = " 0"
|
||||
|
|
@ -483,10 +515,12 @@ func (k *Kademlia) String() string {
|
|||
// the bin is reduced to MinBinSize peers thus leaving slots to newly
|
||||
// connecting peers
|
||||
func (k *Kademlia) Prune(c <-chan time.Time) {
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
go func() {
|
||||
for range c {
|
||||
total := 0
|
||||
k.conns.EachBin(k.base, 0, func(po, size int, f func(func(pot.Val, int) bool) bool) bool {
|
||||
k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(pot.Val, int) bool) bool) bool {
|
||||
extra := size - k.MinBinSize
|
||||
if size > k.MaxBinSize {
|
||||
n := 0
|
||||
|
|
@ -507,17 +541,17 @@ func (k *Kademlia) Prune(c <-chan time.Time) {
|
|||
// NewPeerPot just creates a new pot record OverlayAddr
|
||||
func NewPeerPot(kadMinProxSize int, ids ...discover.NodeID) map[discover.NodeID][][]byte {
|
||||
// create a table of all nodes for health check
|
||||
np := pot.NewPot(nil, 0, nil)
|
||||
np := pot.NewPot(nil, 0)
|
||||
for _, id := range ids {
|
||||
o := ToOverlayAddr(id.Bytes())
|
||||
np, _, _ = pot.Add(np, o)
|
||||
np, _, _ = pot.Add(np, o, pof)
|
||||
}
|
||||
nnmap := make(map[discover.NodeID][][]byte)
|
||||
|
||||
for _, id := range ids {
|
||||
pl := 0
|
||||
var nns [][]byte
|
||||
np.EachNeighbour(id.Bytes(), func(val pot.Val, po int) bool {
|
||||
np.EachNeighbour(id.Bytes(), pof, func(val pot.Val, po int) bool {
|
||||
// a := val.(pot.BytesAddress).Address()
|
||||
// nns = append(nns, a)
|
||||
a := val.([]byte)
|
||||
|
|
@ -533,9 +567,9 @@ func NewPeerPot(kadMinProxSize int, ids ...discover.NodeID) map[discover.NodeID]
|
|||
}
|
||||
|
||||
// FirstEmptyBin returns the farthest proximity order (int) that has no peer records
|
||||
func (k *Kademlia) FirstEmptyBin() (i int) {
|
||||
func (k *Kademlia) firstEmptyBin() (i int) {
|
||||
i = -1
|
||||
k.conns.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
|
||||
if po > i+1 {
|
||||
i = po
|
||||
return false
|
||||
|
|
@ -547,13 +581,15 @@ func (k *Kademlia) FirstEmptyBin() (i int) {
|
|||
}
|
||||
|
||||
// Full returns a bool if the kademlia table is healthy and complete
|
||||
func (k *Kademlia) Full() bool {
|
||||
return k.FirstEmptyBin() >= k.Depth()
|
||||
func (k *Kademlia) full() bool {
|
||||
return k.firstEmptyBin() >= k.depth()
|
||||
}
|
||||
|
||||
// Healthy reports the health state of the kademlia connectivity
|
||||
func (k *Kademlia) Healthy(peers [][]byte) bool {
|
||||
return k.gotNearestNeighbours(peers) && k.Full()
|
||||
k.lock.RLock()
|
||||
defer k.lock.RUnlock()
|
||||
return k.gotNearestNeighbours(peers) && k.full()
|
||||
}
|
||||
|
||||
func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool) {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ func testSuggestPeer(t *testing.T, k *testKademlia, expAddr string, expPo int, e
|
|||
if want != expWant {
|
||||
return fmt.Errorf("expected SuggestPeer to want peers: %v", expWant)
|
||||
}
|
||||
// t.Logf("%v", k)
|
||||
t.Logf("%v", k)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -206,9 +206,8 @@ func TestSuggestPeerFindPeers(t *testing.T) {
|
|||
}
|
||||
|
||||
// reintroduce gap, disconnected peer callable
|
||||
log.Info(k.String())
|
||||
// log.Info(k.String())
|
||||
k.Off("01000000")
|
||||
log.Info(k.String())
|
||||
err = testSuggestPeer(t, k, "01000000", 0, false)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
|
|
@ -433,7 +432,7 @@ func TestPruning(t *testing.T) {
|
|||
func TestKademliaHiveString(t *testing.T) {
|
||||
k := newTestKademlia("00000000").On("01000000", "00100000").Register("10000000", "10000001")
|
||||
h := k.String()
|
||||
expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), MinProxBinSize: 2, MinBinSize: 1, MaxBinSize: 4\n============ PROX LIMIT: 0 ==========================================\n000 0 | 2 840000 800000\n001 1 400000 | 1 400000\n002 1 200000 | 1 200000\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n========================================================================="
|
||||
expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), MinProxBinSize: 2, MinBinSize: 1, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 0 | 2 8100 (0) 8000 (0)\n001 1 4000 | 1 4000 (0)\n002 1 2000 | 1 2000 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n========================================================================="
|
||||
if expH[100:] != h[100:] {
|
||||
t.Fatalf("incorrect hive output. expected %v, got %v", expH, h)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue