Skip to content

Commit

Permalink
map: have eviction policy of connection pool behave as a lru (perlin-…
Browse files Browse the repository at this point in the history
…network#269)

kademlia/test: assert that all inbound connections to leader node are ready
node/opts/test: have quickcheck run only 10 iterations per option to reduce testing time
  • Loading branch information
iwasaki-kenta committed Jan 31, 2020
1 parent 64da665 commit 1e706da
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 40 deletions.
8 changes: 6 additions & 2 deletions kademlia/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ func TestTableEviction(t *testing.T) {
_, err = node.Ping(context.Background(), leader.Addr())
assert.NoError(t, err)

leader.Inbound()[i].WaitUntilReady()
for _, client := range leader.Inbound() {
client.WaitUntilReady()
}

nodes = append(nodes, node)
}
Expand Down Expand Up @@ -109,7 +111,9 @@ func TestTableEviction(t *testing.T) {
_, err = follower.Ping(context.Background(), leader.Addr())
assert.NoError(t, err)

leader.Inbound()[len(leader.Inbound())-1].WaitUntilReady()
for _, client := range leader.Inbound() {
client.WaitUntilReady()
}

// Query all peer IDs that the leader node knows about again, and check that node 0 was evicted and that
// the follower node has been put to the head of the bucket.
Expand Down
68 changes: 38 additions & 30 deletions map.go
Original file line number Diff line number Diff line change
@@ -1,88 +1,96 @@
package noise

import (
"container/list"
"errors"
"math"
"sync"
)

type clientMapEntry struct {
el *list.Element
client *Client
}

type clientMap struct {
sync.Mutex

order []string
entries map[string]*Client
cap int
order *list.List
entries map[string]clientMapEntry
}

func newClientMap(cap int) *clientMap {
return &clientMap{
order: make([]string, 0, cap),
entries: make(map[string]*Client, cap),
cap: cap,
order: list.New(),
entries: make(map[string]clientMapEntry, cap),
}
}

func (c *clientMap) get(n *Node, addr string) (*Client, bool) {
c.Lock()
defer c.Unlock()

client, exists := c.entries[addr]
entry, exists := c.entries[addr]
if !exists {
if len(c.entries) == n.maxInboundConnections {
closing := c.order[0]
c.order = c.order[1:]
el := c.order.Back()
evicted := c.order.Remove(el).(string)

client := c.entries[closing]
delete(c.entries, closing)
e := c.entries[evicted]
delete(c.entries, evicted)

client.close()
client.waitUntilClosed()
e.client.close()
e.client.waitUntilClosed()
}

client = newClient(n)
c.entries[addr] = client
c.order = append(c.order, addr)
entry.el = c.order.PushFront(addr)
entry.client = newClient(n)

c.entries[addr] = entry
} else {
c.order.MoveToFront(entry.el)
}

return client, exists
return entry.client, exists
}

func (c *clientMap) remove(addr string) {
c.Lock()
defer c.Unlock()

var order []string

for _, entry := range c.order {
if entry != addr {
order = append(order, entry)
}
entry, exists := c.entries[addr]
if !exists {
return
}

c.order = order
c.order.Remove(entry.el)
delete(c.entries, addr)
}

func (c *clientMap) release() {
c.Lock()

entries := c.entries
c.entries = make(map[string]*Client, cap(c.order))
c.order = make([]string, 0, cap(c.order))
c.entries = make(map[string]clientMapEntry, c.cap)
c.order.Init()

c.Unlock()

for _, client := range entries {
client.close()
client.waitUntilClosed()
for _, e := range entries {
e.client.close()
e.client.waitUntilClosed()
}
}

func (c *clientMap) slice() []*Client {
c.Lock()
defer c.Unlock()

clients := make([]*Client, len(c.entries))
for i := 0; i < len(c.entries); i++ {
clients[i] = c.entries[c.order[i]]
clients := make([]*Client, 0, len(c.entries))
for el := c.order.Front(); el != nil; el = el.Next() {
clients = append(clients, c.entries[el.Value.(string)].client)
}

return clients
Expand Down
16 changes: 8 additions & 8 deletions node_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(a, nil))
assert.NoError(t, quick.Check(a, &quick.Config{MaxCount: 10}))

b := func(a int) bool {
if a <= 0 {
Expand All @@ -48,7 +48,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(b, nil))
assert.NoError(t, quick.Check(b, &quick.Config{MaxCount: 10}))

c := func(a int) bool {
if a <= 0 {
Expand All @@ -69,7 +69,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(c, nil))
assert.NoError(t, quick.Check(c, &quick.Config{MaxCount: 10}))

d := func(a time.Duration) bool {
n, err := NewNode(WithNodeIdleTimeout(a))
Expand All @@ -84,7 +84,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(d, nil))
assert.NoError(t, quick.Check(d, &quick.Config{MaxCount: 10}))

e := func(a bool) bool {
var logger *zap.Logger
Expand All @@ -104,7 +104,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(e, nil))
assert.NoError(t, quick.Check(e, &quick.Config{MaxCount: 10}))

f := func(publicKey PublicKey, host net.IP, port uint16) bool {
id := NewID(publicKey, host, port)
Expand All @@ -121,7 +121,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(f, nil))
assert.NoError(t, quick.Check(f, &quick.Config{MaxCount: 10}))

g := func(privateKey PrivateKey) bool {
n, err := NewNode(WithNodePrivateKey(privateKey))
Expand All @@ -140,7 +140,7 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(g, nil))
assert.NoError(t, quick.Check(g, &quick.Config{MaxCount: 10}))

h := func(host net.IP, port uint16, address string) bool {
n, err := NewNode(WithNodeBindHost(host), WithNodeBindPort(port), WithNodeAddress(address))
Expand All @@ -163,5 +163,5 @@ func TestNodeOptions(t *testing.T) {
return true
}

assert.NoError(t, quick.Check(h, nil))
assert.NoError(t, quick.Check(h, &quick.Config{MaxCount: 10}))
}

0 comments on commit 1e706da

Please sign in to comment.