@cryptotaxi247 / kubo / commits / a29c0fc75

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