move blocking calls out of single threaded loops, cancel contexts ASAP
Jeromy committed
Feb 19, 2015 at 00:31 UTC
a29c0fc751f24e32f1a569632bd83615a4e30a31
4 files changed
+79
-29
core/core.go
+3
-3
@@ -249,9 +249,6 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin
249
// startOnlineServicesWithHost is the set of services which need to be
250
// initialized with the host and _before_ we start listening.
251
func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost.Host, routingOption RoutingOption) error {
252
- // Wrap standard peer host with routing system to allow unknown peer lookups
253
- n.PeerHost = rhost.Wrap(host, n.Routing)
254
-
252
// setup diagnostics service
253
n.Diagnostics = diag.NewDiagnostics(n.Identity, host)
254
@@ -262,6 +259,9 @@ func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost
259
}
260
n.Routing = r
261
262
+ // Wrap standard peer host with routing system to allow unknown peer lookups
263
+ n.PeerHost = rhost.Wrap(host, n.Routing)
264
+
265
// setup exchange service
266
const alwaysSendToPeer = true // use YesManStrategy
267
bitswapNetwork := bsnet.NewFromIpfsHost(n.PeerHost, n.Routing)
exchange/bitswap/bitswap.go
+67
-25
@@ -84,7 +84,7 @@ func New(parent context.Context, p peer.ID, network bsnet.BitSwapNetwork,
84
engine: decision.NewEngine(ctx, bstore), // TODO close the engine with Close() method
85
network: network,
86
wantlist: wantlist.NewThreadSafe(),
87
- batchRequests: make(chan []u.Key, sizeBatchRequestChan),
87
+ batchRequests: make(chan *blockRequest, sizeBatchRequestChan),
88
process: px,
89
}
90
network.SetDelegate(bs)
@@ -94,6 +94,9 @@ func New(parent context.Context, p peer.ID, network bsnet.BitSwapNetwork,
94
px.Go(func(px process.Process) {
95
bs.taskWorker(ctx)
96
})
97
+ px.Go(func(px process.Process) {
98
+ bs.rebroadcastWorker(ctx)
99
+ })
100
101
return bs
102
}
@@ -116,7 +119,7 @@ type bitswap struct {
119
// Requests for a set of related blocks
120
// the assumption is made that the same peer is likely to
121
// have more than a single block in the set
119
- batchRequests chan []u.Key
122
+ batchRequests chan *blockRequest
123
124
engine *decision.Engine
125
@@ -125,6 +128,11 @@ type bitswap struct {
128
process process.Process
129
}
130
131
+type blockRequest struct {
132
+ keys []u.Key
133
+ ctx context.Context
134
+}
135
+
136
// GetBlock attempts to retrieve a particular block from peers within the
137
// deadline enforced by the context.
138
func (bs *bitswap) GetBlock(parent context.Context, k u.Key) (*blocks.Block, error) {
@@ -175,15 +183,19 @@ func (bs *bitswap) GetBlock(parent context.Context, k u.Key) (*blocks.Block, err
183
// resources, provide a context with a reasonably short deadline (ie. not one
184
// that lasts throughout the lifetime of the server)
185
func (bs *bitswap) GetBlocks(ctx context.Context, keys []u.Key) (<-chan *blocks.Block, error) {
178
-
186
select {
187
case <-bs.process.Closing():
188
return nil, errors.New("bitswap is closed")
189
default:
190
}
191
promise := bs.notifications.Subscribe(ctx, keys...)
192
+
193
+ req := &blockRequest{
194
+ keys: keys,
195
+ ctx: ctx,
196
+ }
197
select {
186
- case bs.batchRequests <- keys:
198
+ case bs.batchRequests <- req:
199
return promise, nil
200
case <-ctx.Done():
201
return nil, ctx.Err()
@@ -321,8 +333,8 @@ func (bs *bitswap) PeerConnected(p peer.ID) {
333
}
334
335
// Connected/Disconnected warns bitswap about peer connections
324
-func (bs *bitswap) PeerDisconnected(peer.ID) {
325
- // TODO: release resources.
336
+func (bs *bitswap) PeerDisconnected(p peer.ID) {
337
+ bs.engine.PeerDisconnected(p)
338
}
339
340
func (bs *bitswap) cancelBlocks(ctx context.Context, bkeys []u.Key) {
@@ -342,6 +354,24 @@ func (bs *bitswap) cancelBlocks(ctx context.Context, bkeys []u.Key) {
354
}
355
}
356
357
+func (bs *bitswap) wantNewBlocks(ctx context.Context, bkeys []u.Key) {
358
+ if len(bkeys) < 1 {
359
+ return
360
+ }
361
+
362
+ message := bsmsg.New()
363
+ message.SetFull(false)
364
+ for i, k := range bkeys {
365
+ message.AddEntry(k, kMaxPriority-i)
366
+ }
367
+ for _, p := range bs.engine.Peers() {
368
+ err := bs.send(ctx, p, message)
369
+ if err != nil {
370
+ log.Debugf("Error sending message: %s", err)
371
+ }
372
+ }
373
+}
374
+
375
func (bs *bitswap) ReceiveError(err error) {
376
log.Debugf("Bitswap ReceiveError: %s", err)
377
// TODO log the network error
@@ -385,13 +415,42 @@ func (bs *bitswap) taskWorker(ctx context.Context) {
415
416
// TODO ensure only one active request per key
417
func (bs *bitswap) clientWorker(parent context.Context) {
388
-
418
defer log.Info("bitswap client worker shutting down...")
419
420
+ for {
421
+ select {
422
+ case req := <-bs.batchRequests:
423
+ keys := req.keys
424
+ if len(keys) == 0 {
425
+ log.Warning("Received batch request for zero blocks")
426
+ continue
427
+ }
428
+ for i, k := range keys {
429
+ bs.wantlist.Add(k, kMaxPriority-i)
430
+ }
431
+
432
+ bs.wantNewBlocks(req.ctx, keys)
433
+
434
+ // NB: Optimization. Assumes that providers of key[0] are likely to
435
+ // be able to provide for all keys. This currently holds true in most
436
+ // every situation. Later, this assumption may not hold as true.
437
+ child, _ := context.WithTimeout(req.ctx, providerRequestTimeout)
438
+ providers := bs.network.FindProvidersAsync(child, keys[0], maxProvidersPerRequest)
439
+ err := bs.sendWantlistToPeers(req.ctx, providers)
440
+ if err != nil {
441
+ log.Debugf("error sending wantlist: %s", err)
442
+ }
443
+ case <-parent.Done():
444
+ return
445
+ }
446
+ }
447
+}
448
+
449
+func (bs *bitswap) rebroadcastWorker(parent context.Context) {
450
ctx, cancel := context.WithCancel(parent)
451
+ defer cancel()
452
453
broadcastSignal := time.After(rebroadcastDelay.Get())
394
- defer cancel()
454
455
for {
456
select {
@@ -406,23 +465,6 @@ func (bs *bitswap) clientWorker(parent context.Context) {
465
bs.sendWantlistToProviders(ctx, entries)
466
}
467
broadcastSignal = time.After(rebroadcastDelay.Get())
409
- case keys := <-bs.batchRequests:
410
- if len(keys) == 0 {
411
- log.Warning("Received batch request for zero blocks")
412
- continue
413
- }
414
- for i, k := range keys {
415
- bs.wantlist.Add(k, kMaxPriority-i)
416
- }
417
- // NB: Optimization. Assumes that providers of key[0] are likely to
418
- // be able to provide for all keys. This currently holds true in most
419
- // every situation. Later, this assumption may not hold as true.
420
- child, _ := context.WithTimeout(ctx, providerRequestTimeout)
421
- providers := bs.network.FindProvidersAsync(child, keys[0], maxProvidersPerRequest)
422
- err := bs.sendWantlistToPeers(ctx, providers)
423
- if err != nil {
424
- log.Debugf("error sending wantlist: %s", err)
425
- }
468
case <-parent.Done():
469
return
470
}
exchange/bitswap/decision/engine.go
+4
@@ -228,6 +228,10 @@ func (e *Engine) MessageSent(p peer.ID, m bsmsg.BitSwapMessage) error {
228
return nil
229
}
230
231
+func (e *Engine) PeerDisconnected(p peer.ID) {
232
+ // TODO: release ledger
233
+}
234
+
235
func (e *Engine) numBytesSentTo(p peer.ID) uint64 {
236
// NB not threadsafe
237
return e.findOrCreate(p).Accounting.BytesSent
merkledag/merkledag.go
+5
-1
@@ -187,9 +187,12 @@ func (ds *dagService) GetNodes(ctx context.Context, keys []u.Key) []NodeGetter {
187
}
188
189
go func() {
190
+ ctx, cancel := context.WithCancel(ctx)
191
+ defer cancel()
192
+
193
blkchan := ds.Blocks.GetBlocks(ctx, keys)
194
192
- for {
195
+ for count := 0; count < len(keys); {
196
select {
197
case blk, ok := <-blkchan:
198
if !ok {
@@ -205,6 +208,7 @@ func (ds *dagService) GetNodes(ctx context.Context, keys []u.Key) []NodeGetter {
208
is := FindLinks(keys, blk.Key(), 0)
209
for _, i := range is {
210
sendChans[i] <- nd
211
+ count++
212
}
213
case <-ctx.Done():
214
return