aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-05-04 01:39:06 +0200
committereldritch horrors <pennae@lix.systems>2024-05-05 18:09:31 +0000
commit6b081389290a5a6a6d143ee7fa4d12ea1296a8d0 (patch)
tree04f2e21120b1ea83ace986816f71694b0d225a73 /src
parent03a20ef1ff11f7ed785f02d2965a1f8314d06132 (diff)
filetransfer: abort transfer on receiver exception
not doing this will cause transfers that had their readers disappear to linger. with lingering transfers the curl thread can't shut down, which will cause nix itself to not shut down until the transfer finishes some other way (most likely network timeouts). also add a new test for this. Change-Id: Id2401b3ac85731c824db05918d4079125be25b57
Diffstat (limited to 'src')
-rw-r--r--src/libstore/filetransfer.cc16
1 files changed, 9 insertions, 7 deletions
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index c9f5d6260..aa8f4be1d 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -708,7 +708,7 @@ struct curlFileTransfer : public FileTransfer
download thread and the calling thread. */
struct State {
- bool quit = false;
+ bool done = false, failed = false;
std::exception_ptr exc;
std::string data;
std::condition_variable avail, request;
@@ -717,18 +717,17 @@ struct curlFileTransfer : public FileTransfer
auto _state = std::make_shared<Sync<State>>();
- /* In case of an exception, wake up the download thread. FIXME:
- abort the download request. */
+ /* In case of an exception, wake up the download thread. */
Finally finally([&]() {
auto state(_state->lock());
- state->quit = true;
+ state->failed |= std::uncaught_exceptions() != 0;
state->request.notify_one();
});
enqueueFileTransfer(request,
{[_state](std::future<FileTransferResult> fut) {
auto state(_state->lock());
- state->quit = true;
+ state->done = true;
try {
fut.get();
} catch (...) {
@@ -740,7 +739,10 @@ struct curlFileTransfer : public FileTransfer
[_state, &sink](TransferItem & transfer, std::string_view data) {
auto state(_state->lock());
- if (state->quit) return;
+ if (state->failed) {
+ // actual exception doesn't matter, the other end is already dead
+ throw std::exception{};
+ }
if (!state->decompressor) {
state->decompressor = makeDecompressionSink(transfer.encoding, sink);
@@ -775,7 +777,7 @@ struct curlFileTransfer : public FileTransfer
if (state->data.empty()) {
- if (state->quit) {
+ if (state->done) {
if (state->exc) std::rethrow_exception(state->exc);
if (state->decompressor) {
state->decompressor->finish();