mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
p2p/netutil: GC also when adding statements and contacts
This prevents indefinite memory growth if Predict* isn't called.
This commit is contained in:
parent
b4a7d56fe3
commit
05f55dc0af
2 changed files with 49 additions and 8 deletions
|
|
@ -31,6 +31,8 @@ type IPTracker struct {
|
||||||
clock mclock.Clock
|
clock mclock.Clock
|
||||||
statements map[string]ipStatement
|
statements map[string]ipStatement
|
||||||
contact map[string]mclock.AbsTime
|
contact map[string]mclock.AbsTime
|
||||||
|
lastStatementGC mclock.AbsTime
|
||||||
|
lastContactGC mclock.AbsTime
|
||||||
}
|
}
|
||||||
|
|
||||||
type ipStatement struct {
|
type ipStatement struct {
|
||||||
|
|
@ -90,16 +92,25 @@ func (it *IPTracker) PredictEndpoint() string {
|
||||||
|
|
||||||
// AddStatement records that a certain host thinks our external endpoint is the one given.
|
// AddStatement records that a certain host thinks our external endpoint is the one given.
|
||||||
func (it *IPTracker) AddStatement(host, endpoint string) {
|
func (it *IPTracker) AddStatement(host, endpoint string) {
|
||||||
it.statements[host] = ipStatement{endpoint, it.clock.Now()}
|
now := it.clock.Now()
|
||||||
|
it.statements[host] = ipStatement{endpoint, now}
|
||||||
|
if time.Duration(now-it.lastStatementGC) >= it.window {
|
||||||
|
it.gcStatements(now)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddContact records that a packet containing our endpoint information has been sent to a
|
// AddContact records that a packet containing our endpoint information has been sent to a
|
||||||
// certain host.
|
// certain host.
|
||||||
func (it *IPTracker) AddContact(host string) {
|
func (it *IPTracker) AddContact(host string) {
|
||||||
it.contact[host] = it.clock.Now()
|
now := it.clock.Now()
|
||||||
|
it.contact[host] = now
|
||||||
|
if time.Duration(now-it.lastContactGC) >= it.contactWindow {
|
||||||
|
it.gcContact(now)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *IPTracker) gcStatements(now mclock.AbsTime) {
|
func (it *IPTracker) gcStatements(now mclock.AbsTime) {
|
||||||
|
it.lastStatementGC = now
|
||||||
cutoff := now.Add(-it.window)
|
cutoff := now.Add(-it.window)
|
||||||
for host, s := range it.statements {
|
for host, s := range it.statements {
|
||||||
if s.time < cutoff {
|
if s.time < cutoff {
|
||||||
|
|
@ -109,6 +120,7 @@ func (it *IPTracker) gcStatements(now mclock.AbsTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *IPTracker) gcContact(now mclock.AbsTime) {
|
func (it *IPTracker) gcContact(now mclock.AbsTime) {
|
||||||
|
it.lastContactGC = now
|
||||||
cutoff := now.Add(-it.contactWindow)
|
cutoff := now.Add(-it.contactWindow)
|
||||||
for host, ct := range it.contact {
|
for host, ct := range it.contact {
|
||||||
if ct < cutoff {
|
if ct < cutoff {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
mrand "math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -107,3 +108,31 @@ func runIPTrackerTest(t *testing.T, evs []iptrackTestEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This checks that old statements and contacts are GCed even if Predict* isn't called.
|
||||||
|
func TestIPTrackerForceGC(t *testing.T) {
|
||||||
|
var (
|
||||||
|
clock mclock.Simulated
|
||||||
|
window = 10 * time.Second
|
||||||
|
rate = 50 * time.Millisecond
|
||||||
|
max = int(window/rate) + 1
|
||||||
|
it = NewIPTracker(window, window, 3)
|
||||||
|
)
|
||||||
|
it.clock = &clock
|
||||||
|
|
||||||
|
for i := 0; i < 5*max; i++ {
|
||||||
|
e1 := make([]byte, 4)
|
||||||
|
e2 := make([]byte, 4)
|
||||||
|
mrand.Read(e1)
|
||||||
|
mrand.Read(e2)
|
||||||
|
it.AddStatement(string(e1), string(e2))
|
||||||
|
it.AddContact(string(e1))
|
||||||
|
clock.Run(rate)
|
||||||
|
}
|
||||||
|
if len(it.contact) > 2*max {
|
||||||
|
t.Errorf("contacts not GCed, have %d", len(it.contact))
|
||||||
|
}
|
||||||
|
if len(it.statements) > 2*max {
|
||||||
|
t.Errorf("statements not GCed, have %d", len(it.statements))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue