aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/http-binary-cache-store.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-06-24 21:48:52 +0200
committerEelco Dolstra <edolstra@gmail.com>2019-06-24 21:59:51 +0200
commit78fa47a7f08a4cb6ee7061bf0bd86a40e1d6dc91 (patch)
tree96a4b4079640ca3435a929fa163bb07e921c3ecb /src/libstore/http-binary-cache-store.cc
parent2fef4dd29673ef383b695480c9b8212f2e8d4711 (diff)
Fix 'error 9 while decompressing xz file'
Once we've started writing data to a Sink, we can't restart a download request, because then we end up writing duplicate data to the Sink. Therefore we shouldn't handle retries in Downloader but at a higher level (in particular, in copyStorePath()). Fixes #2952. (cherry picked from commit a67cf5a3585c41dd9f219a2c7aa9cf67fa69520b)
Diffstat (limited to 'src/libstore/http-binary-cache-store.cc')
-rw-r--r--src/libstore/http-binary-cache-store.cc57
1 files changed, 41 insertions, 16 deletions
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 8da0e2f9d..5133dba57 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -2,6 +2,7 @@
#include "download.hh"
#include "globals.hh"
#include "nar-info-disk-cache.hh"
+#include "retry.hh"
namespace nix {
@@ -114,7 +115,6 @@ protected:
DownloadRequest makeRequest(const std::string & path)
{
DownloadRequest request(cacheUri + "/" + path);
- request.tries = 8;
return request;
}
@@ -137,21 +137,46 @@ protected:
{
checkEnabled();
- auto request(makeRequest(path));
-
- getDownloader()->enqueueDownload(request,
- {[callback, this](std::future<DownloadResult> result) {
- try {
- callback(result.get().data);
- } catch (DownloadError & e) {
- if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
- return callback(std::shared_ptr<std::string>());
- maybeDisable();
- callback.rethrow();
- } catch (...) {
- callback.rethrow();
- }
- }});
+ struct State
+ {
+ DownloadRequest request;
+ std::function<void()> tryDownload;
+ unsigned int attempt = 0;
+ State(DownloadRequest && request) : request(request) {}
+ };
+
+ auto state = std::make_shared<State>(makeRequest(path));
+
+ state->tryDownload = [callback, state, this]() {
+ getDownloader()->enqueueDownload(state->request,
+ {[callback, state, this](std::future<DownloadResult> result) {
+ try {
+ callback(result.get().data);
+ } catch (DownloadError & e) {
+ if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
+ return callback(std::shared_ptr<std::string>());
+ ++state->attempt;
+ if (state->attempt < state->request.tries && e.isTransient()) {
+ auto ms = retrySleepTime(state->attempt);
+ warn("%s; retrying in %d ms", e.what(), ms);
+ /* We can't sleep here because that would
+ block the download thread. So use a
+ separate thread for sleeping. */
+ std::thread([state, ms]() {
+ std::this_thread::sleep_for(std::chrono::milliseconds(ms));
+ state->tryDownload();
+ }).detach();
+ } else {
+ maybeDisable();
+ callback.rethrow();
+ }
+ } catch (...) {
+ callback.rethrow();
+ }
+ }});
+ };
+
+ state->tryDownload();
}
};