@cryptotaxi247 / kubo / commits / abb85fc19

fix rampant memory leak in providers records storage

address comments from CR use map and array combo for better perf

Jeromy committed Jun 1, 2015 at 08:08 UTC abb85fc19425cf6d2009ac3d1eca9d231261e3ad
1 file changed +46 -24
routing/dht/providers.go
+46 -24
@@ -10,22 +10,25 @@ import (
10 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 )
12
13 -type providerInfo struct {
14 - Creation time.Time
15 - Value peer.ID
16 -}
17 -
13 type ProviderManager struct {
19 - providers map[key.Key][]*providerInfo
14 + // all non channel fields are meant to be accessed only within
15 + // the run method
16 + providers map[key.Key]*providerSet
17 local map[key.Key]struct{}
18 lpeer peer.ID
22 - getlocal chan chan []key.Key
23 - newprovs chan *addProv
24 - getprovs chan *getProv
25 - period time.Duration
19 +
20 + getlocal chan chan []key.Key
21 + newprovs chan *addProv
22 + getprovs chan *getProv
23 + period time.Duration
24 ctxgroup.ContextGroup
25 }
26
27 +type providerSet struct {
28 + providers []peer.ID
29 + set map[peer.ID]time.Time
30 +}
31 +
32 type addProv struct {
33 k key.Key
34 val peer.ID
@@ -40,7 +43,7 @@ func NewProviderManager(ctx context.Context, local peer.ID) *ProviderManager {
43 pm := new(ProviderManager)
44 pm.getprovs = make(chan *getProv)
45 pm.newprovs = make(chan *addProv)
43 - pm.providers = make(map[key.Key][]*providerInfo)
46 + pm.providers = make(map[key.Key]*providerSet)
47 pm.getlocal = make(chan chan []key.Key)
48 pm.local = make(map[key.Key]struct{})
49 pm.ContextGroup = ctxgroup.WithContext(ctx)
@@ -61,18 +64,20 @@ func (pm *ProviderManager) run() {
64 if np.val == pm.lpeer {
65 pm.local[np.k] = struct{}{}
66 }
64 - pi := new(providerInfo)
65 - pi.Creation = time.Now()
66 - pi.Value = np.val
67 - arr := pm.providers[np.k]
68 - pm.providers[np.k] = append(arr, pi)
67 + provs, ok := pm.providers[np.k]
68 + if !ok {
69 + provs = newProviderSet()
70 + pm.providers[np.k] = provs
71 + }
72 + provs.Add(np.val)
73
74 case gp := <-pm.getprovs:
75 var parr []peer.ID
72 - provs := pm.providers[gp.k]
73 - for _, p := range provs {
74 - parr = append(parr, p.Value)
76 + provs, ok := pm.providers[gp.k]
77 + if ok {
78 + parr = provs.providers
79 }
80 +
81 gp.resp <- parr
82
83 case lc := <-pm.getlocal:
@@ -83,14 +88,16 @@ func (pm *ProviderManager) run() {
88 lc <- keys
89
90 case <-tick.C:
86 - for k, provs := range pm.providers {
87 - var filtered []*providerInfo
88 - for _, p := range provs {
89 - if time.Now().Sub(p.Creation) < time.Hour*24 {
91 + for _, provs := range pm.providers {
92 + var filtered []peer.ID
93 + for p, t := range provs.set {
94 + if time.Now().Sub(t) > time.Hour*24 {
95 + delete(provs.set, p)
96 + } else {
97 filtered = append(filtered, p)
98 }
99 }
93 - pm.providers[k] = filtered
100 + provs.providers = filtered
101 }
102
103 case <-pm.Closing():
@@ -133,3 +140,18 @@ func (pm *ProviderManager) GetLocal() []key.Key {
140 pm.getlocal <- resp
141 return <-resp
142 }
143 +
144 +func newProviderSet() *providerSet {
145 + return &providerSet{
146 + set: make(map[peer.ID]time.Time),
147 + }
148 +}
149 +
150 +func (ps *providerSet) Add(p peer.ID) {
151 + _, found := ps.set[p]
152 + if !found {
153 + ps.providers = append(ps.providers, p)
154 + }
155 +
156 + ps.set[p] = time.Now()
157 +}