Timeout `get-file` faster when we already know we won't have enough blocks to make the file
Description
Currently the get-file function times out after 10s which is long, the goal is to reduce this.
Problem
The reason for which we can't exit faster has to do with mpsc channel Receiver not being dropped properly when there is one Sender left. If we take a look at the function which downloads the first k blocks (k minimum number of blocks required to make a file) we have a tokio::select
in a loop. A simplified version looks like this:
let (block_sender, mut block_receiver) = mpsc::unbounded_channel();
'download_first_k_blocks: loop {
tokio::select! {
biased;
Some(response) = info_receiver.recv() => {
// response contains information about all the blocks a peer has for the file we are trying to get
// clone the `block_sender` as many times as there are blocks in the response
},
Some(response) = block_receiver.recv() => {
// check that the block that was received is correct, if we have k blocks, break out of the loop
}
}
}
We create the Sender
out of the loop and clone it each time we need to inside of the loop. The original Sender
(the one being cloned over and over) is never dropped. We don't know before starting how many times we will need to clone it, so we can't just drop it like that, what if we need to clone it again after ?
Thus the block_receiver.recv()
is always awaiting because there is always at least one Sender
in scope. This is not a problem if we receive k blocks and break out of the loop, but if we don't receive k blocks then we are stuck waiting for more answers, which might never come.
Proposed solution
Even though we don't know how many times we will need to clone the Sender
when we start, at one point we can know when to stop cloning it as we loop. In the case in which all peers answer to the request for information about the blocks they provide, it is possible to then drop the original Sender
.
We know how many people we sent a request to (this is done earlier in get-file
), it's the number of peer in the result of the get-providers
command. Let's say 4 people provide the file. Each time we receive information, we add 1 to a counter. When we get to 4, everyone sent us the information about the blocks they have. At that point, it's possible to drop the original Sender
as we know we won't need to clone it anymore.
A problem which might arose has to do with scope, will Rust allow dropping a Sender
from an outer scope ? If not, maybe a move
will solve the issue.