Skip to content

Commit 720d617

Browse files
authored
do not send cancel message to peer that sent block (#784)
* do not send CANCEL to peer we got block from The serving peer cleans the client's wantlint after serving the block, making sending CANCEL to the serving peer redundant. So, exclude the serving peer when sending cancels after receiving a block. Closes #694
1 parent b7d0d20 commit 720d617

10 files changed

+64
-19
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ The following emojis are used to highlight certain changes:
1919
- `gateway` Support for custom DNSLink / DoH resolvers on `localhost` to simplify integration with non-ICANN DNS systems [#645](https://github.com/ipfs/boxo/pull/645)
2020

2121
### Changed
22+
- Do not send CANCEL to peer that block was received from, as this is redundant. [#784](https://github.com/ipfs/boxo/pull/784)
2223

2324
- `gateway` The default DNSLink resolver for `.eth` TLD changed to `https://dns.eth.limo/dns-query` [#781](https://github.com/ipfs/boxo/pull/781)
2425
- `gateway` The default DNSLink resolver for `.crypto` TLD changed to `https://resolver.unstoppable.io/dns-query` [#782](https://github.com/ipfs/boxo/pull/782)

bitswap/client/internal/peermanager/peermanager.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ func (pm *PeerManager) SendWants(ctx context.Context, p peer.ID, wantBlocks []ci
156156

157157
// SendCancels sends cancels for the given keys to all peers who had previously
158158
// received a want for those keys.
159-
func (pm *PeerManager) SendCancels(ctx context.Context, cancelKs []cid.Cid) {
159+
func (pm *PeerManager) SendCancels(ctx context.Context, cancelKs []cid.Cid, excludePeer peer.ID) {
160160
pm.pqLk.Lock()
161161
defer pm.pqLk.Unlock()
162162

163163
// Send a CANCEL to each peer that has been sent a want-block or want-have
164-
pm.pwm.sendCancels(cancelKs)
164+
pm.pwm.sendCancels(cancelKs, excludePeer)
165165
}
166166

167167
// CurrentWants returns the list of pending wants (both want-haves and want-blocks).

bitswap/client/internal/peermanager/peermanager_test.go

+46-3
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ func TestSendCancels(t *testing.T) {
239239
collectMessages(msgs, 2*time.Millisecond)
240240

241241
// Send cancels for 1 want-block and 1 want-have
242-
peerManager.SendCancels(ctx, []cid.Cid{cids[0], cids[2]})
242+
peerManager.SendCancels(ctx, []cid.Cid{cids[0], cids[2]}, "")
243243
collected := collectMessages(msgs, 2*time.Millisecond)
244244

245245
if _, ok := collected[peer2]; ok {
@@ -250,7 +250,7 @@ func TestSendCancels(t *testing.T) {
250250
}
251251

252252
// Send cancels for all cids
253-
peerManager.SendCancels(ctx, cids)
253+
peerManager.SendCancels(ctx, cids, "")
254254
collected = collectMessages(msgs, 2*time.Millisecond)
255255

256256
if _, ok := collected[peer2]; ok {
@@ -261,6 +261,49 @@ func TestSendCancels(t *testing.T) {
261261
}
262262
}
263263

264+
func TestSendCancelsExclude(t *testing.T) {
265+
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
266+
defer cancel()
267+
msgs := make(chan msg, 16)
268+
peerQueueFactory := makePeerQueueFactory(msgs)
269+
tp := random.Peers(3)
270+
self, peer1, peer2 := tp[0], tp[1], tp[2]
271+
peerManager := New(ctx, peerQueueFactory, self)
272+
cids := random.Cids(4)
273+
274+
// Connect to peer1 and peer2
275+
peerManager.Connected(peer1)
276+
peerManager.Connected(peer2)
277+
278+
// Send 2 want-blocks and 1 want-have to peer1
279+
peerManager.SendWants(ctx, peer1, []cid.Cid{cids[0], cids[1]}, []cid.Cid{cids[2]})
280+
281+
// Clear messages
282+
collectMessages(msgs, 2*time.Millisecond)
283+
284+
// Send cancels for 1 want-block and 1 want-have
285+
peerManager.SendCancels(ctx, []cid.Cid{cids[0], cids[2]}, peer1)
286+
collected := collectMessages(msgs, 2*time.Millisecond)
287+
288+
if _, ok := collected[peer2]; ok {
289+
t.Fatal("Expected no cancels to be sent to peer that was not sent messages")
290+
}
291+
if len(collected[peer1].cancels) != 0 {
292+
t.Fatal("Expected no cancels to be sent to excluded peer")
293+
}
294+
295+
// Send cancels for all cids
296+
peerManager.SendCancels(ctx, cids, "")
297+
collected = collectMessages(msgs, 2*time.Millisecond)
298+
299+
if _, ok := collected[peer2]; ok {
300+
t.Fatal("Expected no cancels to be sent to peer that was not sent messages")
301+
}
302+
if len(collected[peer1].cancels) != 3 {
303+
t.Fatal("Expected cancel to be sent for want-blocks")
304+
}
305+
}
306+
264307
func (s *sess) ID() uint64 {
265308
return s.id
266309
}
@@ -376,7 +419,7 @@ func BenchmarkPeerManager(b *testing.B) {
376419
limit := len(wanted) / 10
377420
cancel := wanted[:limit]
378421
wanted = wanted[limit:]
379-
peerManager.SendCancels(ctx, cancel)
422+
peerManager.SendCancels(ctx, cancel, "")
380423
}
381424
}
382425
}

bitswap/client/internal/peermanager/peerwantmanager.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ func (pwm *peerWantManager) sendWants(p peer.ID, wantBlocks []cid.Cid, wantHaves
233233

234234
// sendCancels sends a cancel to each peer to which a corresponding want was
235235
// sent
236-
func (pwm *peerWantManager) sendCancels(cancelKs []cid.Cid) {
236+
func (pwm *peerWantManager) sendCancels(cancelKs []cid.Cid, excludePeer peer.ID) {
237237
if len(cancelKs) == 0 {
238238
return
239239
}
@@ -298,6 +298,7 @@ func (pwm *peerWantManager) sendCancels(cancelKs []cid.Cid) {
298298
cancelPeers[p] = struct{}{}
299299
}
300300
}
301+
delete(cancelPeers, excludePeer)
301302
for p := range cancelPeers {
302303
pws, ok := pwm.peerWants[p]
303304
if !ok {

bitswap/client/internal/peermanager/peerwantmanager_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func TestPWMSendCancels(t *testing.T) {
245245

246246
// Cancel 1 want-block and 1 want-have that were sent to p0
247247
clearSent(peerQueues)
248-
pwm.sendCancels([]cid.Cid{wb1[0], wh1[0]})
248+
pwm.sendCancels([]cid.Cid{wb1[0], wh1[0]}, "")
249249
// Should cancel the want-block and want-have
250250
require.Empty(t, pq1.cancels, "Expected no cancels sent to p1")
251251
require.ElementsMatch(t, pq0.cancels, []cid.Cid{wb1[0], wh1[0]}, "Expected 2 cids to be cancelled")
@@ -255,7 +255,7 @@ func TestPWMSendCancels(t *testing.T) {
255255
// Cancel everything
256256
clearSent(peerQueues)
257257
allCids := append(allwb, allwh...)
258-
pwm.sendCancels(allCids)
258+
pwm.sendCancels(allCids, "")
259259
// Should cancel the remaining want-blocks and want-haves for p0
260260
require.ElementsMatch(t, pq0.cancels, []cid.Cid{wb1[1], wh1[1]}, "Expected un-cancelled cids to be cancelled")
261261

@@ -312,7 +312,7 @@ func TestStats(t *testing.T) {
312312
// Cancel 1 want-block that was sent to p0
313313
// and 1 want-block that was not sent
314314
cids5 := random.Cids(1)
315-
pwm.sendCancels(append(cids5, cids[0]))
315+
pwm.sendCancels(append(cids5, cids[0]), "")
316316

317317
require.Equal(t, 7, g.count, "Expected 7 wants")
318318
require.Equal(t, 3, wbg.count, "Expected 3 want-blocks")
@@ -332,7 +332,7 @@ func TestStats(t *testing.T) {
332332
require.Zero(t, wbg.count, "Expected 0 want-blocks")
333333

334334
// Cancel one remaining broadcast want-have
335-
pwm.sendCancels(cids2[:1])
335+
pwm.sendCancels(cids2[:1], "")
336336
require.Equal(t, 2, g.count, "Expected 2 wants")
337337
require.Zero(t, wbg.count, "Expected 0 want-blocks")
338338
}
@@ -362,7 +362,7 @@ func TestStatsOverlappingWantBlockWantHave(t *testing.T) {
362362
require.Equal(t, 4, wbg.count, "Expected 4 want-blocks")
363363

364364
// Cancel 1 of each group of cids
365-
pwm.sendCancels([]cid.Cid{cids[0], cids2[0]})
365+
pwm.sendCancels([]cid.Cid{cids[0], cids2[0]}, "")
366366

367367
require.Equal(t, 2, g.count, "Expected 2 wants")
368368
require.Equal(t, 2, wbg.count, "Expected 2 want-blocks")

bitswap/client/internal/session/session.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type PeerManager interface {
4343
// session discovery)
4444
BroadcastWantHaves(context.Context, []cid.Cid)
4545
// SendCancels tells the PeerManager to send cancels to all peers
46-
SendCancels(context.Context, []cid.Cid)
46+
SendCancels(context.Context, []cid.Cid, peer.ID)
4747
}
4848

4949
// SessionManager manages all the sessions

bitswap/client/internal/session/session_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func (pm *fakePeerManager) BroadcastWantHaves(ctx context.Context, cids []cid.Ci
151151
case <-ctx.Done():
152152
}
153153
}
154-
func (pm *fakePeerManager) SendCancels(ctx context.Context, cancels []cid.Cid) {}
154+
func (pm *fakePeerManager) SendCancels(ctx context.Context, cancels []cid.Cid, excludePeer peer.ID) {}
155155

156156
func TestSessionGetBlocks(t *testing.T) {
157157
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)

bitswap/client/internal/session/sessionwantsender_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ func (pm *mockPeerManager) has(p peer.ID, sid uint64) bool {
7878
return false
7979
}
8080

81-
func (*mockPeerManager) UnregisterSession(uint64) {}
82-
func (*mockPeerManager) BroadcastWantHaves(context.Context, []cid.Cid) {}
83-
func (*mockPeerManager) SendCancels(context.Context, []cid.Cid) {}
81+
func (*mockPeerManager) UnregisterSession(uint64) {}
82+
func (*mockPeerManager) BroadcastWantHaves(context.Context, []cid.Cid) {}
83+
func (*mockPeerManager) SendCancels(context.Context, []cid.Cid, peer.ID) {}
8484

8585
func (pm *mockPeerManager) SendWants(ctx context.Context, p peer.ID, wantBlocks []cid.Cid, wantHaves []cid.Cid) bool {
8686
pm.lk.Lock()

bitswap/client/internal/sessionmanager/sessionmanager.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (sm *SessionManager) ReceiveFrom(ctx context.Context, p peer.ID, blks []cid
173173
}
174174

175175
// Send CANCEL to all peers with want-have / want-block
176-
sm.peerManager.SendCancels(ctx, blks)
176+
sm.peerManager.SendCancels(ctx, blks, p)
177177
}
178178

179179
// CancelSessionWants is called when a session cancels wants because a call to
@@ -193,5 +193,5 @@ func (sm *SessionManager) cancelWants(wants []cid.Cid) {
193193
// Send CANCEL to all peers for blocks that no session is interested in
194194
// anymore.
195195
// Note: use bitswap context because session context may already be Done.
196-
sm.peerManager.SendCancels(sm.ctx, wants)
196+
sm.peerManager.SendCancels(sm.ctx, wants, "")
197197
}

bitswap/client/internal/sessionmanager/sessionmanager_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (*fakePeerManager) RegisterSession(peer.ID, bspm.Session)
7070
func (*fakePeerManager) UnregisterSession(uint64) {}
7171
func (*fakePeerManager) SendWants(context.Context, peer.ID, []cid.Cid, []cid.Cid) bool { return true }
7272
func (*fakePeerManager) BroadcastWantHaves(context.Context, []cid.Cid) {}
73-
func (fpm *fakePeerManager) SendCancels(ctx context.Context, cancels []cid.Cid) {
73+
func (fpm *fakePeerManager) SendCancels(ctx context.Context, cancels []cid.Cid, excludePeer peer.ID) {
7474
fpm.lk.Lock()
7575
defer fpm.lk.Unlock()
7676
fpm.cancels = append(fpm.cancels, cancels...)

0 commit comments

Comments
 (0)