swarm: codebase split from go-ethereum (#1405)

This commit is contained in:
Rafael Matias
2019-06-03 12:28:18 +02:00
committed by Anton Evangelatov
parent 7a22da98b9
commit b046760db1
1540 changed files with 4654 additions and 129393 deletions

210
pot/address.go Normal file
View File

@@ -0,0 +1,210 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package pot see doc.go
package pot
import (
"encoding/binary"
"fmt"
"math/rand"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common"
)
var (
zerosBin = Address{}.Bin()
)
// Address is an alias for common.Hash
type Address common.Hash
// NewAddressFromBytes constructs an Address from a byte slice
func NewAddressFromBytes(b []byte) Address {
h := common.Hash{}
copy(h[:], b)
return Address(h)
}
func (a Address) String() string {
return fmt.Sprintf("%x", a[:])
}
// MarshalJSON Address serialisation
func (a *Address) MarshalJSON() (out []byte, err error) {
return []byte(`"` + a.String() + `"`), nil
}
// UnmarshalJSON Address deserialisation
func (a *Address) UnmarshalJSON(value []byte) error {
*a = Address(common.HexToHash(string(value[1 : len(value)-1])))
return nil
}
// Bin returns the string form of the binary representation of an address (only first 8 bits)
func (a Address) Bin() string {
return ToBin(a[:])
}
// ToBin converts a byteslice to the string binary representation
func ToBin(a []byte) string {
var bs []string
for _, b := range a {
bs = append(bs, fmt.Sprintf("%08b", b))
}
return strings.Join(bs, "")
}
// Bytes returns the Address as a byte slice
func (a Address) Bytes() []byte {
return a[:]
}
// ProxCmp compares the distances a->target and b->target.
// Returns -1 if a is closer to target, 1 if b is closer to target
// and 0 if they are equal.
func ProxCmp(a, x, y interface{}) int {
return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y))
}
func proxCmp(a, x, y []byte) int {
for i := range a {
dx := x[i] ^ a[i]
dy := y[i] ^ a[i]
if dx > dy {
return 1
} else if dx < dy {
return -1
}
}
return 0
}
// RandomAddressAt (address, prox) generates a random address
// at proximity order prox relative to address
// if prox is negative a random address is generated
func RandomAddressAt(self Address, prox int) (addr Address) {
addr = self
pos := -1
if prox >= 0 {
pos = prox / 8
trans := prox % 8
transbytea := byte(0)
for j := 0; j <= trans; j++ {
transbytea |= 1 << uint8(7-j)
}
flipbyte := byte(1 << uint8(7-trans))
transbyteb := transbytea ^ byte(255)
randbyte := byte(rand.Intn(255))
addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb
}
for i := pos + 1; i < len(addr); i++ {
addr[i] = byte(rand.Intn(255))
}
return
}
// RandomAddress generates a random address
func RandomAddress() Address {
return RandomAddressAt(Address{}, -1)
}
// NewAddressFromString creates a byte slice from a string in binary representation
func NewAddressFromString(s string) []byte {
ha := [32]byte{}
t := s + zerosBin[:len(zerosBin)-len(s)]
for i := 0; i < 4; i++ {
n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64)
if err != nil {
panic("wrong format: " + err.Error())
}
binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n)
}
return ha[:]
}
// BytesAddress is an interface for elements addressable by a byte slice
type BytesAddress interface {
Address() []byte
}
// ToBytes turns the Val into bytes
func ToBytes(v Val) []byte {
if v == nil {
return nil
}
b, ok := v.([]byte)
if !ok {
ba, ok := v.(BytesAddress)
if !ok {
panic(fmt.Sprintf("unsupported value type %T", v))
}
b = ba.Address()
}
return b
}
// DefaultPof returns a proximity order comparison operator function
func DefaultPof(max int) func(one, other Val, pos int) (int, bool) {
return func(one, other Val, pos int) (int, bool) {
po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos)
if po >= max {
eq = true
po = max
}
return po, eq
}
}
// proximityOrder returns two parameters:
// 1. relative proximity order of the arguments one & other;
// 2. boolean indicating whether the full match occurred (one == other).
func proximityOrder(one, other []byte, pos int) (int, bool) {
for i := pos / 8; i < len(one); i++ {
if one[i] == other[i] {
continue
}
oxo := one[i] ^ other[i]
start := 0
if i == pos/8 {
start = pos % 8
}
for j := start; j < 8; j++ {
if (oxo>>uint8(7-j))&0x01 != 0 {
return i*8 + j, false
}
}
}
return len(one) * 8, true
}
// Label displays the node's key in binary format
func Label(v Val) string {
if v == nil {
return "<nil>"
}
if s, ok := v.(fmt.Stringer); ok {
return s.String()
}
if b, ok := v.([]byte); ok {
return ToBin(b)
}
panic(fmt.Sprintf("unsupported value type %T", v))
}

83
pot/doc.go Normal file
View File

@@ -0,0 +1,83 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
/*
Package pot (proximity order tree) implements a container similar to a binary tree.
The elements are generic Val interface types.
Each fork in the trie is itself a value. Values of the subtree contained under
a node all share the same order when compared to other elements in the tree.
Example of proximity order is the length of the common prefix over bitvectors.
(which is equivalent to the reverse rank of order of magnitude of the MSB first X
OR distance over finite set of integers).
Methods take a comparison operator (pof, proximity order function) to compare two
value types. The default pof assumes Val to be or project to a byte slice using
the reverse rank on the MSB first XOR logarithmic distance.
If the address space if limited, equality is defined as the maximum proximity order.
The container offers applicative (functional) style methods on PO trees:
* adding/removing en element
* swap (value based add/remove)
* merging two PO trees (union)
as well as iterator accessors that respect proximity order
When synchronicity of membership if not 100% requirement (e.g. used as a database
of network connections), applicative structures have the advantage that nodes
are immutable therefore manipulation does not need locking allowing for
concurrent retrievals.
For the use case where the entire container is supposed to allow changes by
concurrent routines,
Pot
* retrieval, insertion and deletion by key involves log(n) pointer lookups
* for any item retrieval (defined as common prefix on the binary key)
* provide synchronous iterators respecting proximity ordering wrt any item
* provide asynchronous iterator (for parallel execution of operations) over n items
* allows cheap iteration over ranges
* asymmetric concurrent merge (union)
Note:
* as is, union only makes sense for set representations since which of two values
with equal keys survives is random
* intersection is not implemented
* simple get accessor is not implemented (but derivable from EachNeighbour)
Pinned value on the node implies no need to copy keys of the item type.
Note that
* the same set of values allows for a large number of alternative
POT representations.
* values on the top are accessed faster than lower ones and the steps needed to
retrieve items has a logarithmic distribution.
As a consequence one can organise the tree so that items that need faster access
are torwards the top. In particular for any subset where popularity has a power
distriution that is independent of proximity order (content addressed storage of
chunks), it is in principle possible to create a pot where the steps needed to
access an item is inversely proportional to its popularity.
Such organisation is not implemented as yet.
TODO:
* overwrite-style merge
* intersection
* access frequency based optimisations
*/
package pot

787
pot/pot.go Normal file
View File

@@ -0,0 +1,787 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package pot see doc.go
package pot
import (
"fmt"
"sync"
)
const (
maxkeylen = 256
)
// Pot is the node type (same for root, branching node and leaf)
type Pot struct {
pin Val
bins []*Pot
size int
po int
}
// Val is the element type for Pots
type Val interface{}
// Pof is the proximity order comparison operator function
type Pof func(Val, Val, int) (int, bool)
// NewPot constructor. Requires a 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) *Pot {
var size int
if v != nil {
size++
}
return &Pot{
pin: v,
po: po,
size: size,
}
}
// Pin returns the pinned element (key) of the Pot
func (t *Pot) Pin() Val {
return t.pin
}
// Size returns the number of values in the Pot
func (t *Pot) Size() int {
if t == nil {
return 0
}
return t.size
}
// Add inserts a new value into the Pot and
// returns the proximity order of v and a boolean
// indicating if the item was 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
func Add(t *Pot, val Val, pof Pof) (*Pot, int, bool) {
return add(t, val, pof)
}
func (t *Pot) clone() *Pot {
return &Pot{
pin: t.pin,
size: t.size,
po: t.po,
bins: t.bins,
}
}
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 := pof(t.pin, val, t.po)
if found {
r = t.clone()
r.pin = val
return r, po, true
}
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, pof)
if !found {
size++
}
j++
break
}
if n.po > po {
break
}
i++
j++
}
if p == nil {
size++
p = &Pot{
pin: val,
size: 1,
po: po,
}
}
bins := append([]*Pot{}, t.bins[:i]...)
bins = append(bins, p)
bins = append(bins, t.bins[j:]...)
r = &Pot{
pin: t.pin,
size: size,
po: t.po,
bins: bins,
}
return r, po, found
}
// Remove deletes element v from the Pot t and returns three parameters:
// 1. new Pot that contains all the elements of t minus the element v;
// 2. proximity order of the removed element v;
// 3. boolean indicating whether the item was found.
func Remove(t *Pot, v Val, pof Pof) (*Pot, int, bool) {
return remove(t, v, pof)
}
func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) {
size := t.size
po, found = pof(t.pin, val, t.po)
if found {
size--
if size == 0 {
return &Pot{}, po, true
}
i := len(t.bins) - 1
last := t.bins[i]
r = &Pot{
pin: last.pin,
bins: append(t.bins[:i], last.bins...),
size: size,
po: t.po,
}
return r, t.po, true
}
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, pof)
if found {
size--
}
j++
break
}
if n.po > po {
return t, po, false
}
i++
j++
}
bins := t.bins[:i]
if p != nil && p.pin != nil {
bins = append(bins, p)
}
bins = append(bins, t.bins[j:]...)
r = &Pot{
pin: t.pin,
size: size,
po: t.po,
bins: bins,
}
return r, po, found
}
// Swap called on (k, f) looks up the item at k
// and applies the function f to the value v at k or to nil if the item is not found
// if f(v) returns nil, the element is removed
// if f(v) returns v' <> v then v' is inserted into the Pot
// if (v) == v the Pot is not changed
// it panics if Pof(f(v), k) show that v' and v are not key-equal
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.pin == nil {
val = f(nil)
if val == nil {
return nil, 0, false, false
}
return NewPot(val, t.po), 0, false, true
}
size := t.size
po, found = pof(k, t.pin, t.po)
if found {
val = f(t.pin)
// remove element
if val == nil {
size--
if size == 0 {
r = &Pot{
po: t.po,
}
// return empty pot
return r, po, true, true
}
// actually remove pin, by merging last bin
i := len(t.bins) - 1
last := t.bins[i]
r = &Pot{
pin: last.pin,
bins: append(t.bins[:i], last.bins...),
size: size,
po: t.po,
}
return r, po, true, true
}
// element found but no change
if val == t.pin {
return t, po, true, false
}
// actually modify the pinned element, but no change in structure
r = t.clone()
r.pin = val
return r, po, true, true
}
// recursive step
var p *Pot
n, i := t.getPos(po)
if n != nil {
p, po, found, change = Swap(n, k, pof, f)
// recursive no change
if !change {
return t, po, found, false
}
// recursive change
bins := append([]*Pot{}, t.bins[:i]...)
if p.size == 0 {
size--
} else {
size += p.size - n.size
bins = append(bins, p)
}
i++
if i < len(t.bins) {
bins = append(bins, t.bins[i:]...)
}
r = t.clone()
r.bins = bins
r.size = size
return r, po, found, true
}
// key does not exist
val = f(nil)
if val == nil {
// and it should not be created
return t, po, false, false
}
// otherwise check val if equal to k
if _, eq := pof(val, k, po); !eq {
panic("invalid value")
}
///
size++
p = &Pot{
pin: val,
size: 1,
po: po,
}
bins := append([]*Pot{}, t.bins[:i]...)
bins = append(bins, p)
if i < len(t.bins) {
bins = append(bins, t.bins[i:]...)
}
r = t.clone()
r.bins = bins
r.size = size
return r, po, found, true
}
// Union called on (t0, t1, pof) returns the union of t0 and t1
// calculates the union using the applicative union
// the second return value is the number of common elements
func Union(t0, t1 *Pot, pof Pof) (*Pot, int) {
return union(t0, t1, pof)
}
func union(t0, t1 *Pot, pof Pof) (*Pot, int) {
if t0 == nil || t0.size == 0 {
return t1, 0
}
if t1 == nil || t1.size == 0 {
return t0, 0
}
var pin Val
var bins []*Pot
var mis []int
wg := &sync.WaitGroup{}
wg.Add(1)
pin0 := t0.pin
pin1 := t1.pin
bins0 := t0.bins
bins1 := t1.bins
var i0, i1 int
var common int
po, eq := pof(pin0, pin1, 0)
for {
l0 := len(bins0)
l1 := len(bins1)
var n0, n1 *Pot
var p0, p1 int
var a0, a1 bool
for {
if !a0 && i0 < l0 && bins0[i0] != nil && bins0[i0].po <= po {
n0 = bins0[i0]
p0 = n0.po
a0 = p0 == po
} else {
a0 = true
}
if !a1 && i1 < l1 && bins1[i1] != nil && bins1[i1].po <= po {
n1 = bins1[i1]
p1 = n1.po
a1 = p1 == po
} else {
a1 = true
}
if a0 && a1 {
break
}
switch {
case (p0 < p1 || a1) && !a0:
bins = append(bins, n0)
i0++
n0 = nil
case (p1 < p0 || a0) && !a1:
bins = append(bins, n1)
i1++
n1 = nil
case p1 < po:
bl := len(bins)
bins = append(bins, nil)
ml := len(mis)
mis = append(mis, 0)
// wg.Add(1)
// go func(b, m int, m0, m1 *Pot) {
// defer wg.Done()
// bins[b], mis[m] = union(m0, m1, pof)
// }(bl, ml, n0, n1)
bins[bl], mis[ml] = union(n0, n1, pof)
i0++
i1++
n0 = nil
n1 = nil
}
}
if eq {
common++
pin = pin1
break
}
i := i0
if len(bins0) > i && bins0[i].po == po {
i++
}
var size0 int
for _, n := range bins0[i:] {
size0 += n.size
}
np := &Pot{
pin: pin0,
bins: bins0[i:],
size: size0 + 1,
po: po,
}
bins2 := []*Pot{np}
if n0 == nil {
pin0 = pin1
po = maxkeylen + 1
eq = true
common--
} else {
bins2 = append(bins2, n0.bins...)
pin0 = pin1
pin1 = n0.pin
po, eq = pof(pin0, pin1, n0.po)
}
bins0 = bins1
bins1 = bins2
i0 = i1
i1 = 0
}
wg.Done()
wg.Wait()
for _, c := range mis {
common += c
}
n := &Pot{
pin: pin,
bins: bins,
size: t0.size + t1.size - common,
po: t0.po,
}
return n, common
}
// Each is a synchronous iterator over the elements of pot with function f.
func (t *Pot) Each(f func(Val) bool) bool {
return t.each(f)
}
// each is a synchronous iterator over the elements of pot with function f.
// the iteration ends if the function return false or there are no more elements.
func (t *Pot) each(f func(Val) bool) bool {
if t == nil || t.size == 0 {
return false
}
for _, n := range t.bins {
if !n.each(f) {
return false
}
}
return f(t.pin)
}
// eachFrom is a synchronous iterator over the elements of pot with function f,
// starting from certain proximity order po, which is passed as a second parameter.
// the iteration ends if the function return false or there are no more elements.
func (t *Pot) eachFrom(f func(Val) bool, po int) bool {
if t == nil || t.size == 0 {
return false
}
_, beg := t.getPos(po)
for i := beg; i < len(t.bins); i++ {
if !t.bins[i].each(f) {
return false
}
}
return f(t.pin)
}
// EachBin iterates over bins of the pivot node and offers iterators to the caller on each
// 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, pof Pof, po int, f func(int, int, func(func(val Val) bool) bool) bool) {
t.eachBin(val, pof, po, f)
}
func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val) bool) bool) bool) {
if t == nil || t.size == 0 {
return
}
spr, _ := pof(t.pin, val, t.po)
_, lim := t.getPos(spr)
var size int
var n *Pot
for i := 0; i < lim; i++ {
n = t.bins[i]
size += n.size
if n.po < po {
continue
}
if !f(n.po, n.size, n.each) {
return
}
}
if lim == len(t.bins) {
if spr >= po {
f(spr, 1, func(g func(Val) bool) bool {
return g(t.pin)
})
}
return
}
n = t.bins[lim]
spo := spr
if n.po == spr {
spo++
size += n.size
}
if spr >= po {
if !f(spr, t.size-size, func(g func(Val) bool) bool {
return t.eachFrom(func(v Val) bool {
return g(v)
}, spo)
}) {
return
}
}
if n.po == spr {
n.eachBin(val, pof, po, f)
}
}
// EachNeighbour is a synchronous 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, pof Pof, f func(Val, int) bool) bool {
return t.eachNeighbour(val, pof, f)
}
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
ir := l
il := l
po, eq := pof(t.pin, val, t.po)
if !eq {
n, il = t.getPos(po)
if n != nil {
next = n.eachNeighbour(val, pof, f)
if !next {
return false
}
ir = il
} else {
ir = il - 1
}
}
next = f(t.pin, po)
if !next {
return false
}
for i := l - 1; i > ir; i-- {
next = t.bins[i].each(func(v Val) bool {
return f(v, po)
})
if !next {
return false
}
}
for i := il - 1; i >= 0; i-- {
n := t.bins[i]
next = n.each(func(v Val) bool {
return f(v, n.po)
})
if !next {
return false
}
}
return true
}
// EachNeighbourAsync called on (val, max, maxPos, f, wait) is an asynchronous 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
// 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
// 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, pof Pof, max int, maxPos int, f func(Val, int), wait bool) {
if max > t.size {
max = t.size
}
var wg *sync.WaitGroup
if wait {
wg = &sync.WaitGroup{}
}
t.eachNeighbourAsync(val, pof, max, maxPos, f, wg)
if wait {
wg.Wait()
}
}
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)
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
// if pivot branch exists and po is not too close, iterate on the pivot branch
if pom == po {
if n != nil {
m := n.size
if max < m {
m = max
}
max -= m
extra = n.eachNeighbourAsync(val, pof, m, maxPos, f, wg)
} else {
if !eq {
ir--
}
}
} else {
extra++
max--
if n != nil {
il++
}
// before checking max, add up the extra elements
// on the close branches that are skipped (if po is too close)
for i := l - 1; i >= il; i-- {
s := t.bins[i]
m := s.size
if max < m {
m = max
}
max -= m
extra += m
}
}
var m int
if pom == po {
m, max, extra = need(1, max, extra)
if m <= 0 {
return
}
if wg != nil {
wg.Add(1)
}
go func() {
if wg != nil {
defer wg.Done()
}
f(t.pin, po)
}()
// otherwise iterats
for i := l - 1; i > ir; i-- {
n := t.bins[i]
m, max, extra = need(n.size, max, extra)
if m <= 0 {
return
}
if wg != nil {
wg.Add(m)
}
go func(pn *Pot, pm int) {
pn.each(func(v Val) bool {
if wg != nil {
defer wg.Done()
}
f(v, po)
pm--
return pm > 0
})
}(n, m)
}
}
// iterate branches that are farther tham pom with their own po
for i := il - 1; i >= 0; i-- {
n := t.bins[i]
// the first time max is less than the size of the entire branch
// wait for the pivot thread to release extra elements
m, max, extra = need(n.size, max, extra)
if m <= 0 {
return
}
if wg != nil {
wg.Add(m)
}
go func(pn *Pot, pm int) {
pn.each(func(v Val) bool {
if wg != nil {
defer wg.Done()
}
f(v, pn.po)
pm--
return pm > 0
})
}(n, m)
}
return max + extra
}
// getPos called on (n) returns the forking node at PO n and its index if it exists
// otherwise nil
// caller is supposed to hold the lock
func (t *Pot) getPos(po int) (n *Pot, i int) {
for i, n = range t.bins {
if po > n.po {
continue
}
if po < n.po {
return nil, i
}
return n, i
}
return nil, len(t.bins)
}
// need called on (m, max, extra) uses max m out of extra, and then max
// if needed, returns the adjusted counts
func need(m, max, extra int) (int, int, int) {
if m <= extra {
return m, max, extra - m
}
max += extra - m
if max <= 0 {
return m + max, 0, 0
}
return m, max, 0
}
func (t *Pot) String() string {
return t.sstring("")
}
func (t *Pot) sstring(indent string) string {
if t == nil {
return "<nil>"
}
var s string
indent += " "
s += fmt.Sprintf("%v%v (%v) %v \n", indent, t.pin, t.po, t.size)
for _, n := range t.bins {
s += fmt.Sprintf("%v%v\n", indent, n.sstring(indent))
}
return s
}

741
pot/pot_test.go Normal file
View File

@@ -0,0 +1,741 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package pot
import (
"errors"
"fmt"
"math/rand"
"runtime"
"sync"
"testing"
"time"
"github.com/ethersphere/swarm/log"
)
const (
maxEachNeighbourTests = 420
maxEachNeighbour = 420
maxSwap = 420
maxSwapTests = 420
)
// func init() {
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
// }
type testAddr struct {
a []byte
i int
}
func newTestAddr(s string, i int) *testAddr {
return &testAddr{NewAddressFromString(s), i}
}
func (a *testAddr) Address() []byte {
return a.a
}
func (a *testAddr) String() string {
return Label(a.a)
}
func randomTestAddr(n int, i int) *testAddr {
v := RandomAddress().Bin()[:n]
return newTestAddr(v, i)
}
func randomtestAddr(n int, i int) *testAddr {
v := RandomAddress().Bin()[:n]
return newTestAddr(v, i)
}
func indexes(t *Pot) (i []int) {
t.Each(func(v Val) bool {
a := v.(*testAddr)
i = append(i, a.i)
return true
})
return i
}
func testAdd(t *Pot, pof Pof, j int, values ...string) (_ *Pot, n int, f bool) {
for i, val := range values {
t, n, f = Add(t, newTestAddr(val, i+j), pof)
}
return t, n, f
}
// removing non-existing element from pot
func TestPotRemoveNonExisting(t *testing.T) {
pof := DefaultPof(8)
n := NewPot(newTestAddr("00111100", 0), 0)
n, _, _ = Remove(n, newTestAddr("00000101", 0), pof)
exp := "00111100"
got := Label(n.Pin())
if got[:8] != exp {
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got[:8])
}
}
// this test creates hierarchical pot tree, and therefore any child node will have
// child_po = parent_po + 1.
// then removes a node from the middle of the tree.
func TestPotRemoveSameBin(t *testing.T) {
pof := DefaultPof(8)
n := NewPot(newTestAddr("11111111", 0), 0)
n, _, _ = testAdd(n, pof, 1, "00000000", "01000000", "01100000", "01110000", "01111000")
n, _, _ = Remove(n, newTestAddr("01110000", 0), pof)
inds := indexes(n)
goti := n.Size()
expi := 5
if goti != expi {
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
}
inds = indexes(n)
got := fmt.Sprintf("%v", inds)
exp := "[5 3 2 1 0]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
}
// this test creates a flat pot tree (all the elements are leafs of one root),
// and therefore they all have the same po.
// then removes an arbitrary element from the pot.
func TestPotRemoveDifferentBins(t *testing.T) {
pof := DefaultPof(8)
n := NewPot(newTestAddr("11111111", 0), 0)
n, _, _ = testAdd(n, pof, 1, "00000000", "10000000", "11000000", "11100000", "11110000")
n, _, _ = Remove(n, newTestAddr("11100000", 0), pof)
inds := indexes(n)
goti := n.Size()
expi := 5
if goti != expi {
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
}
inds = indexes(n)
got := fmt.Sprintf("%v", inds)
exp := "[1 2 3 5 0]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
n, _, _ = testAdd(n, pof, 4, "11100000")
inds = indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[1 2 3 4 5 0]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
}
func TestPotAdd(t *testing.T) {
pof := DefaultPof(8)
n := NewPot(newTestAddr("00111100", 0), 0)
// Pin set correctly
exp := "00111100"
got := Label(n.Pin())[:8]
if got != exp {
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got)
}
// check size
goti := n.Size()
expi := 1
if goti != expi {
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
}
n, _, _ = testAdd(n, pof, 1, "01111100", "00111100", "01111100", "00011100")
// check size
goti = n.Size()
expi = 3
if goti != expi {
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
}
inds := indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[3 4 2]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
}
func TestPotRemove(t *testing.T) {
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)
}
n, _, _ = testAdd(n, pof, 1, "00000000", "01111100", "00111100", "00011100")
n, _, _ = Remove(n, newTestAddr("00111100", 0), pof)
goti := n.Size()
expi := 3
if goti != expi {
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
}
inds := indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[2 4 1]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) // remove again same element
inds = indexes(n)
got = fmt.Sprintf("%v", inds)
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
n, _, _ = Remove(n, newTestAddr("00000000", 0), pof) // remove the first element
inds = indexes(n)
got = fmt.Sprintf("%v", inds)
exp = "[2 4]"
if got != exp {
t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got)
}
}
func TestPotSwap(t *testing.T) {
for i := 0; i < maxSwapTests; i++ {
alen := maxkeylen
pof := DefaultPof(alen)
max := rand.Intn(maxSwap)
n := NewPot(nil, 0)
var m []*testAddr
var found bool
for j := 0; j < 2*max; {
v := randomtestAddr(alen, j)
n, _, found = Add(n, v, pof)
if !found {
m = append(m, v)
j++
}
}
k := make(map[string]*testAddr)
for j := 0; j < max; {
v := randomtestAddr(alen, 1)
_, found := k[Label(v)]
if !found {
k[Label(v)] = v
j++
}
}
for _, v := range k {
m = append(m, v)
}
f := func(v Val) Val {
tv := v.(*testAddr)
if tv.i < max {
return nil
}
tv.i = 0
return v
}
for _, val := range m {
n, _, _, _ = Swap(n, val, pof, func(v Val) Val {
if v == nil {
return val
}
return f(v)
})
}
sum := 0
n.Each(func(v Val) bool {
if v == nil {
return true
}
sum++
tv := v.(*testAddr)
if tv.i > 1 {
t.Fatalf("item value incorrect, expected 0, got %v", tv.i)
}
return true
})
if sum != 2*max {
t.Fatalf("incorrect number of elements. expected %v, got %v", 2*max, sum)
}
if sum != n.Size() {
t.Fatalf("incorrect size. expected %v, got %v", sum, n.Size())
}
}
}
func checkPo(val Val, pof Pof) func(Val, int) error {
return func(v Val, po int) error {
// check the po
exp, _ := pof(val, v, 0)
if po != exp {
return fmt.Errorf("incorrect prox order for item %v in neighbour iteration for %v. Expected %v, got %v", v, val, exp, po)
}
return nil
}
}
func checkOrder(val Val) func(Val, int) error {
po := maxkeylen
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)
}
po = p
return nil
}
}
func checkValues(m map[string]bool, val Val) func(Val, int) error {
return func(v Val, po int) error {
duplicate, ok := m[Label(v)]
if !ok {
return fmt.Errorf("alien value %v", v)
}
if duplicate {
return fmt.Errorf("duplicate value returned: %v", v)
}
m[Label(v)] = true
return nil
}
}
var errNoCount = errors.New("not count")
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, pof, func(v Val, po int) bool {
for _, f := range fs {
err = f(v, po)
if err != nil {
return err.Error() == errNoCount.Error()
}
}
count++
return count != expCount
})
if err == nil && count < expCount {
return fmt.Errorf("not enough neighbours returned, expected %v, got %v", expCount, count)
}
return err
}
const (
mergeTestCount = 5
mergeTestChoose = 5
)
func TestPotMergeCommon(t *testing.T) {
vs := make([]*testAddr, mergeTestCount)
for i := 0; i < maxEachNeighbourTests; i++ {
alen := maxkeylen
pof := DefaultPof(alen)
for j := 0; j < len(vs); j++ {
vs[j] = randomtestAddr(alen, j)
}
max0 := rand.Intn(mergeTestChoose) + 1
max1 := rand.Intn(mergeTestChoose) + 1
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]
n0, _, found = Add(n0, v, pof)
if !found {
m[Label(v)] = false
j++
}
}
expAdded := 0
for j := 0; j < max1; {
r := rand.Intn(max1)
v := vs[r]
n1, _, found = Add(n1, v, pof)
if !found {
j++
}
_, found = m[Label(v)]
if !found {
expAdded++
m[Label(v)] = false
}
}
if i < 6 {
continue
}
expSize := len(m)
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, pof)
added := n1.Size() - common
size := n.Size()
if expSize != size {
t.Fatalf("%v: incorrect number of elements in merged pot, expected %v, got %v\n%v", i, expSize, size, n)
}
if expAdded != added {
t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added)
}
if !checkDuplicates(n) {
t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n)
}
for k := range m {
_, _, found = Add(n, newTestAddr(k, 0), pof)
if !found {
t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v", i, size, added, k)
}
}
}
}
func TestPotMergeScale(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ {
alen := maxkeylen
pof := DefaultPof(alen)
max0 := rand.Intn(maxEachNeighbour) + 1
max1 := rand.Intn(maxEachNeighbour) + 1
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(alen, j)
n0, _, found = Add(n0, v, pof)
if !found {
m[Label(v)] = false
j++
}
}
expAdded := 0
for j := 0; j < max1; {
v := randomtestAddr(alen, j)
n1, _, found = Add(n1, v, pof)
if !found {
j++
}
_, found = m[Label(v)]
if !found {
expAdded++
m[Label(v)] = false
}
}
if i < 6 {
continue
}
expSize := len(m)
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, pof)
added := n1.Size() - common
size := n.Size()
if expSize != size {
t.Fatalf("%v: incorrect number of elements in merged pot, expected %v, got %v", i, expSize, size)
}
if expAdded != added {
t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added)
}
if !checkDuplicates(n) {
t.Fatalf("%v: merged pot contains duplicates", i)
}
for k := range m {
_, _, found = Add(n, newTestAddr(k, 0), pof)
if !found {
t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v", i, size, added, k)
}
}
}
}
func checkDuplicates(t *Pot) bool {
po := -1
for _, c := range t.bins {
if c == nil {
return false
}
if c.po <= po || !checkDuplicates(c) {
return false
}
po = c.po
}
return true
}
func TestPotEachNeighbourSync(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ {
alen := maxkeylen
pof := DefaultPof(maxkeylen)
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
pin := randomTestAddr(alen, 0)
n := NewPot(pin, 0)
m := make(map[string]bool)
m[Label(pin)] = false
for j := 1; j <= max; j++ {
v := randomTestAddr(alen, j)
n, _, _ = Add(n, v, pof)
m[Label(v)] = false
}
size := n.Size()
if size < 2 {
continue
}
count := rand.Intn(size/2) + size/2
val := randomTestAddr(alen, max+1)
log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count))
err := testPotEachNeighbour(n, pof, val, count, checkPo(val, pof), checkOrder(val), checkValues(m, val))
if err != nil {
t.Fatal(err)
}
minPoFound := alen
maxPoNotFound := 0
for k, found := range m {
po, _ := pof(val, newTestAddr(k, 0), 0)
if found {
if po < minPoFound {
minPoFound = po
}
} else {
if po > maxPoNotFound {
maxPoNotFound = po
}
}
}
if minPoFound < maxPoNotFound {
t.Fatalf("incorrect neighbours returned: found one with PO %v < there was one not found with PO %v", minPoFound, maxPoNotFound)
}
}
}
func TestPotEachNeighbourAsync(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ {
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
alen := maxkeylen
pof := DefaultPof(alen)
n := NewPot(randomTestAddr(alen, 0), 0)
size := 1
var found bool
for j := 1; j <= max; j++ {
v := randomTestAddr(alen, j)
n, _, found = Add(n, v, pof)
if !found {
size++
}
}
if size != n.Size() {
t.Fatal(n)
}
if size < 2 {
continue
}
count := rand.Intn(size/2) + size/2
val := randomTestAddr(alen, max+1)
mu := sync.Mutex{}
m := make(map[string]bool)
maxPos := rand.Intn(alen)
log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v, maxPos: %v", i, n.Pin(), size, val, count, maxPos))
msize := 0
remember := func(v Val, po int) error {
if po > maxPos {
return errNoCount
}
m[Label(v)] = true
msize++
return nil
}
if i == 0 {
continue
}
testPotEachNeighbour(n, pof, val, count, remember)
d := 0
forget := func(v Val, po int) {
mu.Lock()
defer mu.Unlock()
d++
delete(m, Label(v))
}
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)
}
if len(m) != 0 {
t.Fatalf("incorrect neighbour calls in async iterator. %v items missed:\n%v", len(m), n)
}
}
}
func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
t.ReportAllocs()
alen := maxkeylen
pof := DefaultPof(alen)
pin := randomTestAddr(alen, 0)
n := NewPot(pin, 0)
var found bool
for j := 1; j <= max; {
v := randomTestAddr(alen, j)
n, _, found = Add(n, v, pof)
if !found {
j++
}
}
t.ResetTimer()
for i := 0; i < t.N; i++ {
val := randomTestAddr(alen, max+1)
m := 0
n.EachNeighbour(val, pof, func(v Val, po int) bool {
time.Sleep(d)
m++
return m != count
})
}
t.StopTimer()
stats := new(runtime.MemStats)
runtime.ReadMemStats(stats)
}
func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) {
t.ReportAllocs()
alen := maxkeylen
pof := DefaultPof(alen)
pin := randomTestAddr(alen, 0)
n := NewPot(pin, 0)
var found bool
for j := 1; j <= max; {
v := randomTestAddr(alen, j)
n, _, found = Add(n, v, pof)
if !found {
j++
}
}
t.ResetTimer()
for i := 0; i < t.N; i++ {
val := randomTestAddr(alen, max+1)
n.EachNeighbourAsync(val, pof, count, alen, func(v Val, po int) {
time.Sleep(d)
}, true)
}
t.StopTimer()
stats := new(runtime.MemStats)
runtime.ReadMemStats(stats)
}
func BenchmarkEachNeighbourSync_3_1_0(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 1*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_0(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 1*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_0(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 1*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_0(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 1*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_0(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 1*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_0(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 1*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_1(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 2*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_1(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 2*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_1(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 2*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_1(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 2*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_1(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 2*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_1(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 2*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_2(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 4*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_2(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 4*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_2(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 4*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_2(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 4*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_2(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 4*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_2(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 4*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_3(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 8*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_3(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 8*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_3(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 8*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_3(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 8*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_3(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 8*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_3(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 8*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_1_4(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 10, 16*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_1_4(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 10, 16*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_2_4(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 100, 16*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_2_4(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 100, 16*time.Microsecond)
}
func BenchmarkEachNeighbourSync_3_3_4(t *testing.B) {
benchmarkEachNeighbourSync(t, 1000, 1000, 16*time.Microsecond)
}
func BenchmarkEachNeighboursAsync_3_3_4(t *testing.B) {
benchmarkEachNeighbourAsync(t, 1000, 1000, 16*time.Microsecond)
}