1
1
package dht
2
2
3
3
import (
4
- "error "
4
+ "errors "
5
5
"sync"
6
6
7
7
notif "github.com/jbenet/go-ipfs/notifications"
@@ -13,7 +13,8 @@ import (
13
13
pset "github.com/jbenet/go-ipfs/util/peerset"
14
14
todoctr "github.com/jbenet/go-ipfs/util/todocounter"
15
15
16
- ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
16
+ process "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
17
+ ctxproc "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
17
18
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
18
19
)
19
20
@@ -63,7 +64,7 @@ func (q *dhtQuery) Run(ctx context.Context, peers []peer.ID) (*dhtQueryResult, e
63
64
defer cancel ()
64
65
65
66
runner := newQueryRunner (ctx , q )
66
- return runner .Run (peers )
67
+ return runner .Run (ctx , peers )
67
68
}
68
69
69
70
type dhtQueryRunner struct {
@@ -78,7 +79,7 @@ type dhtQueryRunner struct {
78
79
rateLimit chan struct {} // processing semaphore
79
80
log eventlog.EventLogger
80
81
81
- cg ctxgroup. ContextGroup
82
+ proc process. Process
82
83
sync.RWMutex
83
84
}
84
85
@@ -89,11 +90,11 @@ func newQueryRunner(ctx context.Context, q *dhtQuery) *dhtQueryRunner {
89
90
peersRemaining : todoctr .NewSyncCounter (),
90
91
peersSeen : pset .New (),
91
92
rateLimit : make (chan struct {}, q .concurrency ),
92
- cg : ctxgroup . WithContext ( ctx ),
93
+ proc : process . WithParent ( process . Background () ),
93
94
}
94
95
}
95
96
96
- func (r * dhtQueryRunner ) Run (peers []peer.ID ) (* dhtQueryResult , error ) {
97
+ func (r * dhtQueryRunner ) Run (ctx context. Context , peers []peer.ID ) (* dhtQueryResult , error ) {
97
98
r .log = log
98
99
99
100
if len (peers ) == 0 {
@@ -107,31 +108,30 @@ func (r *dhtQueryRunner) Run(peers []peer.ID) (*dhtQueryResult, error) {
107
108
108
109
// add all the peers we got first.
109
110
for _ , p := range peers {
110
- r .addPeerToQuery (r .cg .Context (), p )
111
- }
112
-
113
- // may be closed already. this caused an odd race (where we attempt to
114
- // add a child to an already closed ctxgroup). this is a temp workaround
115
- // as we'll switch to using a proc here soon.
116
- select {
117
- case <- r .cg .Closed ():
118
- return nil , r .cg .Context ().Err ()
119
- default :
111
+ r .addPeerToQuery (p )
120
112
}
121
113
122
114
// go do this thing.
123
- // do it as a child func to make sure Run exits
115
+ // do it as a child proc to make sure Run exits
124
116
// ONLY AFTER spawn workers has exited.
125
- r .cg . AddChildFunc (r .spawnWorkers )
117
+ r .proc . Go (r .spawnWorkers )
126
118
127
119
// so workers are working.
128
120
129
121
// wait until they're done.
130
122
err := routing .ErrNotFound
131
123
124
+ // now, if the context finishes, close the proc.
125
+ // we have to do it here because the logic before is setup, which
126
+ // should run without closing the proc.
127
+ go func () {
128
+ <- ctx .Done ()
129
+ r .proc .Close ()
130
+ }()
131
+
132
132
select {
133
133
case <- r .peersRemaining .Done ():
134
- r .cg .Close ()
134
+ r .proc .Close ()
135
135
r .RLock ()
136
136
defer r .RUnlock ()
137
137
@@ -143,12 +143,10 @@ func (r *dhtQueryRunner) Run(peers []peer.ID) (*dhtQueryResult, error) {
143
143
err = r .errs [0 ]
144
144
}
145
145
146
- case <- r .cg .Closed ():
147
- log .Debug ("r.cg.Closed()" )
148
-
146
+ case <- r .proc .Closed ():
149
147
r .RLock ()
150
148
defer r .RUnlock ()
151
- err = r . cg . Context (). Err () // collect the error.
149
+ err = context . DeadlineExceeded
152
150
}
153
151
154
152
if r .result != nil && r .result .success {
@@ -158,7 +156,7 @@ func (r *dhtQueryRunner) Run(peers []peer.ID) (*dhtQueryResult, error) {
158
156
return nil , err
159
157
}
160
158
161
- func (r * dhtQueryRunner ) addPeerToQuery (ctx context. Context , next peer.ID ) {
159
+ func (r * dhtQueryRunner ) addPeerToQuery (next peer.ID ) {
162
160
// if new peer is ourselves...
163
161
if next == r .query .dht .self {
164
162
r .log .Debug ("addPeerToQuery skip self" )
@@ -172,18 +170,18 @@ func (r *dhtQueryRunner) addPeerToQuery(ctx context.Context, next peer.ID) {
172
170
r .peersRemaining .Increment (1 )
173
171
select {
174
172
case r .peersToQuery .EnqChan <- next :
175
- case <- ctx . Done ():
173
+ case <- r . proc . Closing ():
176
174
}
177
175
}
178
176
179
- func (r * dhtQueryRunner ) spawnWorkers (parent ctxgroup. ContextGroup ) {
177
+ func (r * dhtQueryRunner ) spawnWorkers (proc process. Process ) {
180
178
for {
181
179
182
180
select {
183
181
case <- r .peersRemaining .Done ():
184
182
return
185
183
186
- case <- r .cg .Closing ():
184
+ case <- r .proc .Closing ():
187
185
return
188
186
189
187
case p , more := <- r .peersToQuery .DeqChan :
@@ -193,24 +191,27 @@ func (r *dhtQueryRunner) spawnWorkers(parent ctxgroup.ContextGroup) {
193
191
194
192
// do it as a child func to make sure Run exits
195
193
// ONLY AFTER spawn workers has exited.
196
- parent . AddChildFunc (func (cg ctxgroup. ContextGroup ) {
197
- r .queryPeer (cg , p )
194
+ proc . Go (func (proc process. Process ) {
195
+ r .queryPeer (proc , p )
198
196
})
199
197
}
200
198
}
201
199
}
202
200
203
- func (r * dhtQueryRunner ) queryPeer (cg ctxgroup. ContextGroup , p peer.ID ) {
201
+ func (r * dhtQueryRunner ) queryPeer (proc process. Process , p peer.ID ) {
204
202
// make sure we rate limit concurrency.
205
203
select {
206
204
case <- r .rateLimit :
207
- case <- cg .Closing ():
205
+ case <- proc .Closing ():
208
206
r .peersRemaining .Decrement (1 )
209
207
return
210
208
}
211
209
212
210
// ok let's do this!
213
211
212
+ // create a context from our proc.
213
+ ctx := ctxproc .WithProcessClosing (context .Background (), proc )
214
+
214
215
// make sure we do this when we exit
215
216
defer func () {
216
217
// signal we're done proccessing peer p
@@ -227,10 +228,11 @@ func (r *dhtQueryRunner) queryPeer(cg ctxgroup.ContextGroup, p peer.ID) {
227
228
r .rateLimit <- struct {}{}
228
229
229
230
pi := peer.PeerInfo {ID : p }
230
- if err := r .query .dht .host .Connect (cg .Context (), pi ); err != nil {
231
+
232
+ if err := r .query .dht .host .Connect (ctx , pi ); err != nil {
231
233
log .Debugf ("Error connecting: %s" , err )
232
234
233
- notif .PublishQueryEvent (cg . Context () , & notif.QueryEvent {
235
+ notif .PublishQueryEvent (ctx , & notif.QueryEvent {
234
236
Type : notif .QueryError ,
235
237
Extra : err .Error (),
236
238
})
@@ -246,7 +248,7 @@ func (r *dhtQueryRunner) queryPeer(cg ctxgroup.ContextGroup, p peer.ID) {
246
248
}
247
249
248
250
// finally, run the query against this peer
249
- res , err := r .query .qfunc (cg . Context () , p )
251
+ res , err := r .query .qfunc (ctx , p )
250
252
251
253
if err != nil {
252
254
log .Debugf ("ERROR worker for: %v %v" , p , err )
@@ -259,7 +261,7 @@ func (r *dhtQueryRunner) queryPeer(cg ctxgroup.ContextGroup, p peer.ID) {
259
261
r .Lock ()
260
262
r .result = res
261
263
r .Unlock ()
262
- go r .cg .Close () // signal to everyone that we're done.
264
+ go r .proc .Close () // signal to everyone that we're done.
263
265
// must be async, as we're one of the children, and Close blocks.
264
266
265
267
} else if len (res .closerPeers ) > 0 {
@@ -272,7 +274,7 @@ func (r *dhtQueryRunner) queryPeer(cg ctxgroup.ContextGroup, p peer.ID) {
272
274
273
275
// add their addresses to the dialer's peerstore
274
276
r .query .dht .peerstore .AddAddrs (next .ID , next .Addrs , peer .TempAddrTTL )
275
- r .addPeerToQuery (cg . Context (), next .ID )
277
+ r .addPeerToQuery (next .ID )
276
278
log .Debugf ("PEERS CLOSER -- worker for: %v added %v (%v)" , p , next .ID , next .Addrs )
277
279
}
278
280
} else {
0 commit comments