From 1e706da0966a83e9286e099bc9c25346ddc0f227 Mon Sep 17 00:00:00 2001 From: Kenta Iwasaki Date: Fri, 31 Jan 2020 22:04:26 +0800 Subject: [PATCH] map: have eviction policy of connection pool behave as a lru (#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 --- kademlia/protocol_test.go | 8 +++-- map.go | 68 ++++++++++++++++++++++----------------- node_options_test.go | 16 ++++----- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/kademlia/protocol_test.go b/kademlia/protocol_test.go index 3069cfc4..bf9dd323 100644 --- a/kademlia/protocol_test.go +++ b/kademlia/protocol_test.go @@ -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) } @@ -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. diff --git a/map.go b/map.go index d89d095a..11701b89 100644 --- a/map.go +++ b/map.go @@ -1,22 +1,30 @@ 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), } } @@ -24,40 +32,40 @@ 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) } @@ -65,14 +73,14 @@ 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() } } @@ -80,9 +88,9 @@ 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 diff --git a/node_options_test.go b/node_options_test.go index f3fba053..ed46574b 100644 --- a/node_options_test.go +++ b/node_options_test.go @@ -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 { @@ -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 { @@ -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)) @@ -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 @@ -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) @@ -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)) @@ -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)) @@ -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})) }