Skip to content

Commit a1cede0

Browse files
feat: add unwantBlocks method
1 parent b1a5eff commit a1cede0

File tree

5 files changed

+253
-146
lines changed

5 files changed

+253
-146
lines changed

API.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ Fetch a single block.
2727

2828
Fetch multiple blocks.
2929

30+
### `unwantBlocks(keys)`
31+
32+
- `keys: []Multihash`
33+
34+
Cancel previously requested keys, forcefully. That means they are removed from the
35+
wantlist independent of how many other resources requested these keys. Callbacks
36+
attached to `getBlock` are errored with `Error('manual unwant: key')`.
37+
3038
### `cancelWants(keys)`
3139

3240
- `keys: []Multihash`

src/index.js

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,9 @@ module.exports = class Bitwap {
137137
cb(err, block)
138138
}
139139

140-
this.getBlocks([key], (err, res) => {
141-
if (err) {
142-
return done(err)
140+
this.getBlocks([key], (errs, res) => {
141+
if (errs) {
142+
return done(errs[0])
143143
}
144144

145145
done(null, res[0])
@@ -153,36 +153,80 @@ module.exports = class Bitwap {
153153

154154
getBlocks (keys, cb) {
155155
const blocks = []
156-
const finish = (block) => {
157-
blocks.push(block)
158-
if (blocks.length === keys.length) {
156+
const errs = []
157+
const unwantListeners = {}
158+
const blockListeners = {}
159+
const unwantEvent = (key) => `unwant:${key.toString('hex')}`
160+
const blockEvent = (key) => `block:${key.toString('hex')}`
161+
162+
const cleanupListeners = () => {
163+
keys.forEach((key) => {
164+
this.notifications.removeListener(unwantEvent(key), unwantListeners[key])
165+
this.notifications.removeListener(blockEvent(key), blockListeners[key])
166+
})
167+
}
168+
169+
const addListeners = () => {
170+
keys.forEach((key) => {
171+
unwantListeners[key] = () => {
172+
finish(new Error(`manual unwant: ${key.toString('hex')}`))
173+
}
174+
175+
blockListeners[key] = (block) => {
176+
finish(null, block)
177+
}
178+
179+
this.notifications.once(unwantEvent(key), unwantListeners[key])
180+
this.notifications.once(blockEvent(key), blockListeners[key])
181+
})
182+
}
183+
184+
const finish = (err, block) => {
185+
if (err) {
186+
errs.push(err)
187+
}
188+
if (block) {
189+
blocks.push(block)
190+
}
191+
192+
if (blocks.length + errs.length === keys.length) {
193+
cleanupListeners()
194+
if (errs.length > 0) {
195+
return cb(errs, blocks)
196+
}
159197
cb(null, blocks)
160198
}
161199
}
162200

201+
addListeners()
202+
163203
keys.forEach((key) => {
164204
// Sanity check, we don't want to announce looking for blocks
165205
// when we might have them ourselves
166206
this.datastore.get(key, (err, res) => {
167207
if (!err && res) {
168208
this.wm.cancelWants([key])
169-
finish(res)
209+
finish(null, res)
170210
return
171211
}
172212

173213
if (err) {
174214
log('error in datastore.get: ', err.message)
175215
}
176-
177-
this.notifications.once(`block:${key.toString('hex')}`, (block) => {
178-
finish(block)
179-
})
180216
})
181217
})
182218

183219
this.wm.wantBlocks(keys)
184220
}
185221

222+
// removes the given keys from the want list independent of any ref counts
223+
unwantBlocks (keys) {
224+
this.wm.unwantBlocks(keys)
225+
keys.forEach((key) => {
226+
this.notifications.emit(`unwant:${key.toString('hex')}`)
227+
})
228+
}
229+
186230
// removes the given keys from the want list
187231
cancelWants (keys) {
188232
this.wm.cancelWants(keys)

src/wantlist/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ class Wantlist {
3535
this.set.delete(key)
3636
}
3737

38+
removeForce (key) {
39+
if (this.set.has(key)) {
40+
this.set.delete(key)
41+
}
42+
}
43+
3844
entries () {
3945
return this.set.entries()
4046
}

src/wantmanager/index.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module.exports = class Wantmanager {
2323
return new MsgQueue(peerId, this.network)
2424
}
2525

26-
_addEntries (keys, cancel) {
26+
_addEntries (keys, cancel, force) {
2727
let i = -1
2828
_(keys)
2929
.map((key) => {
@@ -33,7 +33,11 @@ module.exports = class Wantmanager {
3333
.tap((e) => {
3434
// add changes to our wantlist
3535
if (e.cancel) {
36-
this.wl.remove(e.key)
36+
if (force) {
37+
this.wl.removeForce(e.key)
38+
} else {
39+
this.wl.remove(e.key)
40+
}
3741
} else {
3842
this.wl.add(e.key, e.priority)
3943
}
@@ -90,6 +94,12 @@ module.exports = class Wantmanager {
9094
this._addEntries(keys, false)
9195
}
9296

97+
// remove blocks of all the given keys without respecting refcounts
98+
unwantBlocks (keys) {
99+
log('unwant blocks:', keys)
100+
this._addEntries(keys, true, true)
101+
}
102+
93103
// cancel wanting all of the given keys
94104
cancelWants (keys) {
95105
log('cancel wants: ', keys)

0 commit comments

Comments
 (0)