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
+}