Skip to content

Commit d6092eb

Browse files
Merge pull request #3182 from ipfs/fix/bitswap/want-cancel
Remove entries from wantlists when their related requests are cancelled
2 parents 1f387af + 1548c8a commit d6092eb

File tree

12 files changed

+190
-94
lines changed

12 files changed

+190
-94
lines changed

exchange/bitswap/bitswap.go

+43-7
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
2323
bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
2424
notifications "github.com/ipfs/go-ipfs/exchange/bitswap/notifications"
25-
wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
2625
flags "github.com/ipfs/go-ipfs/flags"
2726
"github.com/ipfs/go-ipfs/thirdparty/delay"
2827
loggables "github.com/ipfs/go-ipfs/thirdparty/loggables"
@@ -88,7 +87,7 @@ func New(parent context.Context, p peer.ID, network bsnet.BitSwapNetwork,
8887
notifications: notif,
8988
engine: decision.NewEngine(ctx, bstore), // TODO close the engine with Close() method
9089
network: network,
91-
findKeys: make(chan *wantlist.Entry, sizeBatchRequestChan),
90+
findKeys: make(chan *blockRequest, sizeBatchRequestChan),
9291
process: px,
9392
newBlocks: make(chan blocks.Block, HasBlockBufferSize),
9493
provideKeys: make(chan key.Key, provideKeysBufferSize),
@@ -131,7 +130,7 @@ type Bitswap struct {
131130
notifications notifications.PubSub
132131

133132
// send keys to a worker to find and connect to providers for them
134-
findKeys chan *wantlist.Entry
133+
findKeys chan *blockRequest
135134

136135
engine *decision.Engine
137136

@@ -148,8 +147,8 @@ type Bitswap struct {
148147
}
149148

150149
type blockRequest struct {
151-
key key.Key
152-
ctx context.Context
150+
Key key.Key
151+
Ctx context.Context
153152
}
154153

155154
// GetBlock attempts to retrieve a particular block from peers within the
@@ -235,13 +234,50 @@ func (bs *Bitswap) GetBlocks(ctx context.Context, keys []key.Key) (<-chan blocks
235234
// NB: Optimization. Assumes that providers of key[0] are likely to
236235
// be able to provide for all keys. This currently holds true in most
237236
// every situation. Later, this assumption may not hold as true.
238-
req := &wantlist.Entry{
237+
req := &blockRequest{
239238
Key: keys[0],
240239
Ctx: ctx,
241240
}
241+
242+
remaining := make(map[key.Key]struct{})
243+
for _, k := range keys {
244+
remaining[k] = struct{}{}
245+
}
246+
247+
out := make(chan blocks.Block)
248+
go func() {
249+
ctx, cancel := context.WithCancel(ctx)
250+
defer cancel()
251+
defer close(out)
252+
defer func() {
253+
var toCancel []key.Key
254+
for k, _ := range remaining {
255+
toCancel = append(toCancel, k)
256+
}
257+
bs.CancelWants(toCancel)
258+
}()
259+
for {
260+
select {
261+
case blk, ok := <-promise:
262+
if !ok {
263+
return
264+
}
265+
266+
delete(remaining, blk.Key())
267+
select {
268+
case out <- blk:
269+
case <-ctx.Done():
270+
return
271+
}
272+
case <-ctx.Done():
273+
return
274+
}
275+
}
276+
}()
277+
242278
select {
243279
case bs.findKeys <- req:
244-
return promise, nil
280+
return out, nil
245281
case <-ctx.Done():
246282
return nil, ctx.Err()
247283
}

exchange/bitswap/bitswap_test.go

+73-5
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,6 @@ func TestDoubleGet(t *testing.T) {
334334
blocks := bg.Blocks(1)
335335

336336
ctx1, cancel1 := context.WithCancel(context.Background())
337-
338337
blkch1, err := instances[1].Exchange.GetBlocks(ctx1, []key.Key{blocks[0].Key()})
339338
if err != nil {
340339
t.Fatal(err)
@@ -362,11 +361,15 @@ func TestDoubleGet(t *testing.T) {
362361
t.Fatal(err)
363362
}
364363

365-
blk, ok := <-blkch2
366-
if !ok {
367-
t.Fatal("expected to get the block here")
364+
select {
365+
case blk, ok := <-blkch2:
366+
if !ok {
367+
t.Fatal("expected to get the block here")
368+
}
369+
t.Log(blk)
370+
case <-time.After(time.Second * 5):
371+
t.Fatal("timed out waiting on block")
368372
}
369-
t.Log(blk)
370373

371374
for _, inst := range instances {
372375
err := inst.Exchange.Close()
@@ -375,3 +378,68 @@ func TestDoubleGet(t *testing.T) {
375378
}
376379
}
377380
}
381+
382+
func TestWantlistCleanup(t *testing.T) {
383+
net := tn.VirtualNetwork(mockrouting.NewServer(), delay.Fixed(kNetworkDelay))
384+
sg := NewTestSessionGenerator(net)
385+
defer sg.Close()
386+
bg := blocksutil.NewBlockGenerator()
387+
388+
instances := sg.Instances(1)[0]
389+
bswap := instances.Exchange
390+
blocks := bg.Blocks(20)
391+
392+
var keys []key.Key
393+
for _, b := range blocks {
394+
keys = append(keys, b.Key())
395+
}
396+
397+
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
398+
defer cancel()
399+
_, err := bswap.GetBlock(ctx, keys[0])
400+
if err != context.DeadlineExceeded {
401+
t.Fatal("shouldnt have fetched any blocks")
402+
}
403+
404+
time.Sleep(time.Millisecond * 50)
405+
406+
if len(bswap.GetWantlist()) > 0 {
407+
t.Fatal("should not have anyting in wantlist")
408+
}
409+
410+
ctx, cancel = context.WithTimeout(context.Background(), time.Millisecond*50)
411+
defer cancel()
412+
_, err = bswap.GetBlocks(ctx, keys[:10])
413+
if err != nil {
414+
t.Fatal(err)
415+
}
416+
417+
<-ctx.Done()
418+
time.Sleep(time.Millisecond * 50)
419+
420+
if len(bswap.GetWantlist()) > 0 {
421+
t.Fatal("should not have anyting in wantlist")
422+
}
423+
424+
_, err = bswap.GetBlocks(context.Background(), keys[:1])
425+
if err != nil {
426+
t.Fatal(err)
427+
}
428+
429+
ctx, cancel = context.WithCancel(context.Background())
430+
_, err = bswap.GetBlocks(ctx, keys[10:])
431+
if err != nil {
432+
t.Fatal(err)
433+
}
434+
435+
time.Sleep(time.Millisecond * 50)
436+
if len(bswap.GetWantlist()) != 11 {
437+
t.Fatal("should have 11 keys in wantlist")
438+
}
439+
440+
cancel()
441+
time.Sleep(time.Millisecond * 50)
442+
if !(len(bswap.GetWantlist()) == 1 && bswap.GetWantlist()[0] == keys[0]) {
443+
t.Fatal("should only have keys[0] in wantlist")
444+
}
445+
}

exchange/bitswap/decision/bench_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ func BenchmarkTaskQueuePush(b *testing.B) {
2121
}
2222
b.ResetTimer()
2323
for i := 0; i < b.N; i++ {
24-
q.Push(wantlist.Entry{Key: key.Key(i), Priority: math.MaxInt32}, peers[i%len(peers)])
24+
q.Push(&wantlist.Entry{Key: key.Key(i), Priority: math.MaxInt32}, peers[i%len(peers)])
2525
}
2626
}

exchange/bitswap/decision/engine.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func NewEngine(ctx context.Context, bs bstore.Blockstore) *Engine {
104104
return e
105105
}
106106

107-
func (e *Engine) WantlistForPeer(p peer.ID) (out []wl.Entry) {
107+
func (e *Engine) WantlistForPeer(p peer.ID) (out []*wl.Entry) {
108108
e.lock.Lock()
109109
partner, ok := e.ledgerMap[p]
110110
if ok {
@@ -218,7 +218,7 @@ func (e *Engine) MessageReceived(p peer.ID, m bsmsg.BitSwapMessage) error {
218218

219219
for _, entry := range m.Wantlist() {
220220
if entry.Cancel {
221-
log.Debugf("cancel %s", entry.Key)
221+
log.Debugf("%s cancel %s", p, entry.Key)
222222
l.CancelWant(entry.Key)
223223
e.peerRequestQueue.Remove(entry.Key, p)
224224
} else {

exchange/bitswap/decision/ledger.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (l *ledger) CancelWant(k key.Key) {
7979
l.wantList.Remove(k)
8080
}
8181

82-
func (l *ledger) WantListContains(k key.Key) (wl.Entry, bool) {
82+
func (l *ledger) WantListContains(k key.Key) (*wl.Entry, bool) {
8383
return l.wantList.Contains(k)
8484
}
8585

exchange/bitswap/decision/peer_request_queue.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
type peerRequestQueue interface {
1414
// Pop returns the next peerRequestTask. Returns nil if the peerRequestQueue is empty.
1515
Pop() *peerRequestTask
16-
Push(entry wantlist.Entry, to peer.ID)
16+
Push(entry *wantlist.Entry, to peer.ID)
1717
Remove(k key.Key, p peer.ID)
1818

1919
// NB: cannot expose simply expose taskQueue.Len because trashed elements
@@ -45,7 +45,7 @@ type prq struct {
4545
}
4646

4747
// Push currently adds a new peerRequestTask to the end of the list
48-
func (tl *prq) Push(entry wantlist.Entry, to peer.ID) {
48+
func (tl *prq) Push(entry *wantlist.Entry, to peer.ID) {
4949
tl.lock.Lock()
5050
defer tl.lock.Unlock()
5151
partner, ok := tl.partners[to]
@@ -166,7 +166,7 @@ func (tl *prq) thawRound() {
166166
}
167167

168168
type peerRequestTask struct {
169-
Entry wantlist.Entry
169+
Entry *wantlist.Entry
170170
Target peer.ID
171171

172172
// A callback to signal that this task has been completed

exchange/bitswap/decision/peer_request_queue_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func TestPushPop(t *testing.T) {
4141
for _, index := range rand.Perm(len(alphabet)) { // add blocks for all letters
4242
letter := alphabet[index]
4343
t.Log(partner.String())
44-
prq.Push(wantlist.Entry{Key: key.Key(letter), Priority: math.MaxInt32 - index}, partner)
44+
prq.Push(&wantlist.Entry{Key: key.Key(letter), Priority: math.MaxInt32 - index}, partner)
4545
}
4646
for _, consonant := range consonants {
4747
prq.Remove(key.Key(consonant), partner)
@@ -78,10 +78,10 @@ func TestPeerRepeats(t *testing.T) {
7878
// Have each push some blocks
7979

8080
for i := 0; i < 5; i++ {
81-
prq.Push(wantlist.Entry{Key: key.Key(i)}, a)
82-
prq.Push(wantlist.Entry{Key: key.Key(i)}, b)
83-
prq.Push(wantlist.Entry{Key: key.Key(i)}, c)
84-
prq.Push(wantlist.Entry{Key: key.Key(i)}, d)
81+
prq.Push(&wantlist.Entry{Key: key.Key(i)}, a)
82+
prq.Push(&wantlist.Entry{Key: key.Key(i)}, b)
83+
prq.Push(&wantlist.Entry{Key: key.Key(i)}, c)
84+
prq.Push(&wantlist.Entry{Key: key.Key(i)}, d)
8585
}
8686

8787
// now, pop off four entries, there should be one from each

exchange/bitswap/message/message.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func newMsg(full bool) *impl {
6464
}
6565

6666
type Entry struct {
67-
wantlist.Entry
67+
*wantlist.Entry
6868
Cancel bool
6969
}
7070

@@ -120,7 +120,7 @@ func (m *impl) addEntry(k key.Key, priority int, cancel bool) {
120120
e.Cancel = cancel
121121
} else {
122122
m.wantlist[k] = Entry{
123-
Entry: wantlist.Entry{
123+
Entry: &wantlist.Entry{
124124
Key: k,
125125
Priority: priority,
126126
},

0 commit comments

Comments
 (0)