Commit 8211a95f authored by Jeromy's avatar Jeromy

fix rampant memory leak in providers records storage

address comments from CR

use map and array combo for better perf
parent a84b8b7b
...@@ -10,15 +10,13 @@ import ( ...@@ -10,15 +10,13 @@ import (
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
) )
type providerInfo struct {
Creation time.Time
Value peer.ID
}
type ProviderManager struct { type ProviderManager struct {
providers map[key.Key][]*providerInfo // all non channel fields are meant to be accessed only within
// the run method
providers map[key.Key]*providerSet
local map[key.Key]struct{} local map[key.Key]struct{}
lpeer peer.ID lpeer peer.ID
getlocal chan chan []key.Key getlocal chan chan []key.Key
newprovs chan *addProv newprovs chan *addProv
getprovs chan *getProv getprovs chan *getProv
...@@ -26,6 +24,11 @@ type ProviderManager struct { ...@@ -26,6 +24,11 @@ type ProviderManager struct {
ctxgroup.ContextGroup ctxgroup.ContextGroup
} }
type providerSet struct {
providers []peer.ID
set map[peer.ID]time.Time
}
type addProv struct { type addProv struct {
k key.Key k key.Key
val peer.ID val peer.ID
...@@ -40,7 +43,7 @@ func NewProviderManager(ctx context.Context, local peer.ID) *ProviderManager { ...@@ -40,7 +43,7 @@ func NewProviderManager(ctx context.Context, local peer.ID) *ProviderManager {
pm := new(ProviderManager) pm := new(ProviderManager)
pm.getprovs = make(chan *getProv) pm.getprovs = make(chan *getProv)
pm.newprovs = make(chan *addProv) pm.newprovs = make(chan *addProv)
pm.providers = make(map[key.Key][]*providerInfo) pm.providers = make(map[key.Key]*providerSet)
pm.getlocal = make(chan chan []key.Key) pm.getlocal = make(chan chan []key.Key)
pm.local = make(map[key.Key]struct{}) pm.local = make(map[key.Key]struct{})
pm.ContextGroup = ctxgroup.WithContext(ctx) pm.ContextGroup = ctxgroup.WithContext(ctx)
...@@ -61,18 +64,20 @@ func (pm *ProviderManager) run() { ...@@ -61,18 +64,20 @@ func (pm *ProviderManager) run() {
if np.val == pm.lpeer { if np.val == pm.lpeer {
pm.local[np.k] = struct{}{} pm.local[np.k] = struct{}{}
} }
pi := new(providerInfo) provs, ok := pm.providers[np.k]
pi.Creation = time.Now() if !ok {
pi.Value = np.val provs = newProviderSet()
arr := pm.providers[np.k] pm.providers[np.k] = provs
pm.providers[np.k] = append(arr, pi) }
provs.Add(np.val)
case gp := <-pm.getprovs: case gp := <-pm.getprovs:
var parr []peer.ID var parr []peer.ID
provs := pm.providers[gp.k] provs, ok := pm.providers[gp.k]
for _, p := range provs { if ok {
parr = append(parr, p.Value) parr = provs.providers
} }
gp.resp <- parr gp.resp <- parr
case lc := <-pm.getlocal: case lc := <-pm.getlocal:
...@@ -83,14 +88,16 @@ func (pm *ProviderManager) run() { ...@@ -83,14 +88,16 @@ func (pm *ProviderManager) run() {
lc <- keys lc <- keys
case <-tick.C: case <-tick.C:
for k, provs := range pm.providers { for _, provs := range pm.providers {
var filtered []*providerInfo var filtered []peer.ID
for _, p := range provs { for p, t := range provs.set {
if time.Now().Sub(p.Creation) < time.Hour*24 { if time.Now().Sub(t) > time.Hour*24 {
delete(provs.set, p)
} else {
filtered = append(filtered, p) filtered = append(filtered, p)
} }
} }
pm.providers[k] = filtered provs.providers = filtered
} }
case <-pm.Closing(): case <-pm.Closing():
...@@ -133,3 +140,18 @@ func (pm *ProviderManager) GetLocal() []key.Key { ...@@ -133,3 +140,18 @@ func (pm *ProviderManager) GetLocal() []key.Key {
pm.getlocal <- resp pm.getlocal <- resp
return <-resp return <-resp
} }
func newProviderSet() *providerSet {
return &providerSet{
set: make(map[peer.ID]time.Time),
}
}
func (ps *providerSet) Add(p peer.ID) {
_, found := ps.set[p]
if !found {
ps.providers = append(ps.providers, p)
}
ps.set[p] = time.Now()
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment