snix/third_party/nix/src/libstore/http-binary-cache-store.cc
Vincent Ambo 1cf11317ca refactor(tvix/libutil): Mark single-argument constructors explicit
This is the clang-tidy lint 'google-explicit-constructor'.

There's a whole bunch of breakage that was introduced by this, and we
had to opt out a few types of this (esp. the string formatting crap).

In some cases minor other changes have been done to keep the code
working, instead of converting between types (e.g. an explicit
comparison operator implementation for nix::Pid).

Change-Id: I12e1ca51a6bc2c882dba81a2526b9729d26988e7
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1832
Tested-by: BuildkiteCI
Reviewed-by: kanepyork <rikingcoding@gmail.com>
Reviewed-by: glittershark <grfn@gws.fyi>
2020-08-23 11:58:44 +00:00

171 lines
4.9 KiB
C++

#include <utility>
#include <glog/logging.h>
#include "libstore/binary-cache-store.hh"
#include "libstore/download.hh"
#include "libstore/globals.hh"
#include "libstore/nar-info-disk-cache.hh"
namespace nix {
MakeError(UploadToHTTP, Error);
class HttpBinaryCacheStore : public BinaryCacheStore {
private:
Path cacheUri;
struct State {
bool enabled = true;
std::chrono::steady_clock::time_point disabledUntil;
};
Sync<State> _state;
public:
HttpBinaryCacheStore(const Params& params, Path _cacheUri)
: BinaryCacheStore(params), cacheUri(std::move(_cacheUri)) {
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("'%s' does not appear to be a binary cache", cacheUri);
}
diskCache->createCache(cacheUri, storeDir, wantMassQuery_, priority);
}
}
protected:
void maybeDisable() {
auto state(_state.lock());
if (state->enabled && settings.tryFallback) {
int t = 60;
LOG(WARNING) << "disabling binary cache '" << getUri() << "' for " << t
<< " seconds";
state->enabled = false;
state->disabledUntil =
std::chrono::steady_clock::now() + std::chrono::seconds(t);
}
}
void checkEnabled() {
auto state(_state.lock());
if (state->enabled) {
return;
}
if (std::chrono::steady_clock::now() > state->disabledUntil) {
state->enabled = true;
DLOG(INFO) << "re-enabling binary cache '" << getUri() << "'";
return;
}
throw SubstituterDisabled("substituter '%s' is disabled", getUri());
}
bool fileExists(const std::string& path) override {
checkEnabled();
try {
DownloadRequest request(cacheUri + "/" + path);
request.head = true;
getDownloader()->download(request);
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;
}
maybeDisable();
throw;
}
}
void upsertFile(const std::string& path, const std::string& data,
const std::string& mimeType) override {
auto req = DownloadRequest(cacheUri + "/" + path);
req.data = std::make_shared<std::string>(data); // FIXME: inefficient
req.mimeType = mimeType;
try {
getDownloader()->download(req);
} catch (DownloadError& e) {
throw UploadToHTTP("while uploading to HTTP binary cache at '%s': %s",
cacheUri, e.msg());
}
}
DownloadRequest makeRequest(const std::string& path) {
DownloadRequest request(cacheUri + "/" + path);
return request;
}
void getFile(const std::string& path, Sink& sink) override {
checkEnabled();
auto request(makeRequest(path));
try {
getDownloader()->download(std::move(request), sink);
} catch (DownloadError& e) {
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden) {
throw NoSuchBinaryCacheFile(
"file '%s' does not exist in binary cache '%s'", path, getUri());
}
maybeDisable();
throw;
}
}
void getFile(
const std::string& path,
Callback<std::shared_ptr<std::string>> callback) noexcept override {
checkEnabled();
auto request(makeRequest(path));
auto callbackPtr =
std::make_shared<decltype(callback)>(std::move(callback));
getDownloader()->enqueueDownload(
request,
Callback<DownloadResult>{
[callbackPtr, this](std::future<DownloadResult> result) {
try {
(*callbackPtr)(result.get().data);
} catch (DownloadError& e) {
if (e.error == Downloader::NotFound ||
e.error == Downloader::Forbidden) {
return (*callbackPtr)(std::shared_ptr<std::string>());
}
maybeDisable();
callbackPtr->rethrow();
} catch (...) {
callbackPtr->rethrow();
}
}});
}
};
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 nullptr;
}
auto store = std::make_shared<HttpBinaryCacheStore>(params, uri);
store->init();
return store;
});
} // namespace nix