lix/src/libstore/http-binary-cache-store.cc
Eelco Dolstra 66adbdfd97 HttpBinaryCacheStore: Retry on transient HTTP errors
This makes us more robust against 500 errors from CloudFront or S3
(assuming the 500 error isn't cached by CloudFront...).
2016-08-10 18:08:23 +02:00

110 lines
3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "binary-cache-store.hh"
#include "download.hh"
#include "globals.hh"
#include "nar-info-disk-cache.hh"
namespace nix {
MakeError(UploadToHTTP, Error);
class HttpBinaryCacheStore : public BinaryCacheStore
{
private:
Path cacheUri;
Pool<Downloader> downloaders;
public:
HttpBinaryCacheStore(
const Params & params, const Path & _cacheUri)
: BinaryCacheStore(params)
, cacheUri(_cacheUri)
, downloaders(
std::numeric_limits<size_t>::max(),
[]() { return makeDownloader(); })
{
if (cacheUri.back() == '/')
cacheUri.pop_back();
diskCache = getNarInfoDiskCache();
}
std::string getUri() override
{
return cacheUri;
}
void init() override
{
// FIXME: do this lazily?
if (!diskCache->cacheExists(cacheUri, wantMassQuery_, priority)) {
try {
BinaryCacheStore::init();
} catch (UploadToHTTP &) {
throw Error(format("%s does not appear to be a binary cache") % cacheUri);
}
diskCache->createCache(cacheUri, storeDir, wantMassQuery_, priority);
}
}
protected:
bool fileExists(const std::string & path) override
{
try {
auto downloader(downloaders.get());
DownloadOptions options;
options.showProgress = DownloadOptions::no;
options.head = true;
options.tries = 5;
downloader->download(cacheUri + "/" + path, options);
return true;
} catch (DownloadError & e) {
/* S3 buckets return 403 if a file doesn't exist and the
bucket is unlistable, so treat 403 as 404. */
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
return false;
throw;
}
}
void upsertFile(const std::string & path, const std::string & data) override
{
throw UploadToHTTP("uploading to an HTTP binary cache is not supported");
}
std::shared_ptr<std::string> getFile(const std::string & path) override
{
auto downloader(downloaders.get());
DownloadOptions options;
options.showProgress = DownloadOptions::no;
options.tries = 3;
try {
return downloader->download(cacheUri + "/" + path, options).data;
} catch (DownloadError & e) {
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
return 0;
throw;
}
}
};
static RegisterStoreImplementation regStore([](
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (std::string(uri, 0, 7) != "http://" &&
std::string(uri, 0, 8) != "https://" &&
(getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") != "1" || std::string(uri, 0, 7) != "file://")
) return 0;
auto store = std::make_shared<HttpBinaryCacheStore>(params, uri);
store->init();
return store;
});
}