p2p/discover: fix goroutine leak due to blocking on sync.Once

This commit is contained in:
Péter Szilágyi 2015-04-28 10:28:04 +03:00
parent 437cf4b3ac
commit 4992765032
2 changed files with 24 additions and 13 deletions

View File

@ -177,23 +177,34 @@ func (db *nodeDB) updateNode(node *Node) error {
return db.lvl.Put(makeKey(node.ID, nodeDBDiscoverRoot), blob, nil)
}
// ensureExpirer is a small helper method ensuring that the data expiration
// mechanism is running. If the expiration goroutine is already running, this
// method simply returns.
//
// The goal is to start the data evacuation only after the network successfully
// bootstrapped itself (to prevent dumping potentially useful seed nodes). Since
// it would require significant overhead to exactly trace the first successful
// convergence, it's simpler to "ensure" the correct state when an appropriate
// condition occurs (i.e. a successful bonding), and discard further events.
func (db *nodeDB) ensureExpirer() {
db.runner.Do(func() { go db.expirer() })
}
// expirer should be started in a go routine, and is responsible for looping ad
// infinitum and dropping stale data from the database.
func (db *nodeDB) expirer() {
db.runner.Do(func() {
tick := time.Tick(nodeDBCleanupCycle)
for {
select {
case <-tick:
if err := db.expireNodes(); err != nil {
glog.V(logger.Error).Infof("Failed to expire nodedb items: %v", err)
}
case <-db.quit:
return
tick := time.Tick(nodeDBCleanupCycle)
for {
select {
case <-tick:
if err := db.expireNodes(); err != nil {
glog.V(logger.Error).Infof("Failed to expire nodedb items: %v", err)
}
case <-db.quit:
return
}
})
}
}
// expireNodes iterates over the database and deletes all nodes that have not

View File

@ -335,7 +335,7 @@ func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error {
}
// Pong received, update the database and return
tab.db.updateLastPong(id, time.Now())
go tab.db.expirer()
tab.db.ensureExpirer()
return nil
}