Closed MichaelMure closed 2 years ago
cc @Jorropo
@MichaelMure i dont think its quite the right thingy to do here.
Afait bitswap was dedupping concurrent getblocks while what you propose would have a put per getblock.
I think bitswap should do puts but only when the block is receved from the network. Or am I missing something here ?
Afait bitswap was dedupping concurrent getblocks while what you propose would have a put per getblock.
I believe this is still happening, the same way it was done before:
The diff in the PR is quite unreadable, I'd suggest looking at the resulting code where it's much clearer.
I think bitswap should do puts but only when the block is receved from the network. Or am I missing something here ?
This PR removes the put done in HasBlock
(that were unnecessary) and move the puts for blocks from the network to https://github.com/ipfs/go-blockservice/pull/92. The former for performance reason, the latter for better separation of concerns and composability.
One thing that this PR does change is that Puts are no longer batched together, or rather no longer batched the same way. Before, there would be a PutMany
for each bitswap message. Now, BlockService only get a channel of blocks and doesn't know how to batch Put together. At first it looks like it would reduce performance but I believe it makes sense in the long run, as batching with a time window in the BlockService side could result in a better batching, instead of following strictly the network messages. How often is there more than one block in a message?
Not sure what's happening with the CI, test are OK for me locally.
Unfortunately, it looks like this will act like we have a block before that block actually gets written locally. I.e., on receive, we'll:
This creates a race where we might, in some cases (performance, canceled requests, etc.) fail to send blocks to peer when we have them.
As discussed in person (written here so we're on the same page), a simple solution is to just not tell the network anything until the blockservice calls HasBlock
. Basically:
Basically, this is the same as this PR but taken to the extreme. The receive side is completely disconnected from the send side (except for the bandwidth ledger).
Changes required:
Engine.ReceiveFrom
into Engine.ReceivedBlocks
(from network) and Engine.HaveBlocks
(or something like that). The former will update ledgers, etc. The latter will enqueue work for sending blocks to peers.Has
on read.Tricky parts:
HasBlocks
method, and/or rename to NotifyNewBlocks
?).
- This is a silent breaking change and will need to be advertised accordingly. I'd consider making breaking changes to the exchange interface at the same time (maybe add a
HasBlocks
method, and/or rename toNotifyNewBlocks
?).
I like that idea. Does that sounds good to you? Anything else?
// Interface defines the functionality of the IPFS block exchange protocol.
type Interface interface { // type Exchanger interface
Fetcher
- // TODO Should callers be concerned with whether the block was made
- // available on the network?
- HasBlock(context.Context, blocks.Block) error
+ // NotifyNewBlocks tells the exchange that a new block is available and can be served.
+ NotifyNewBlocks(ctx context.Context, block blocks.Block) error
IsOnline() bool
io.Closer
}
I'd make it take multiple blocks (or have a second function that takes multiple blocks), but yeah, something like that.
@Stebalien let's make it variadic then: https://github.com/ipfs/go-ipfs-exchange-interface/pull/23
@Stebalien I think I'm done now, tests are green at least on some platform, but I don't fully know what I'm doing here.
This leave the responsibility and choice to do so to the caller, typically go-blockservice.
This has several benefit:
Close https://github.com/ipfs/kubo/issues/7956