BinaryCacheStore::readFile(): Return a shared_ptr to a string
This allows readFile() to indicate that a file doesn't exist, and might eliminate some large string copying.
This commit is contained in:
parent
99851c6f06
commit
d1b0909894
11 changed files with 52 additions and 28 deletions
|
@ -119,7 +119,10 @@ NarInfo BinaryCacheStore::readNarInfo(const Path & storePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto narInfoFile = narInfoFileFor(storePath);
|
auto narInfoFile = narInfoFileFor(storePath);
|
||||||
auto narInfo = make_ref<NarInfo>(getFile(narInfoFile), narInfoFile);
|
auto data = getFile(narInfoFile);
|
||||||
|
if (!data)
|
||||||
|
throw InvalidPath(format("path ‘%s’ is not valid") % storePath);
|
||||||
|
auto narInfo = make_ref<NarInfo>(*data, narInfoFile);
|
||||||
if (narInfo->path != storePath)
|
if (narInfo->path != storePath)
|
||||||
throw Error(format("NAR info file for store path ‘%1%’ does not match ‘%2%’") % narInfo->path % storePath);
|
throw Error(format("NAR info file for store path ‘%1%’ does not match ‘%2%’") % narInfo->path % storePath);
|
||||||
|
|
||||||
|
@ -162,25 +165,27 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
|
||||||
|
|
||||||
auto nar = getFile(res.url);
|
auto nar = getFile(res.url);
|
||||||
|
|
||||||
|
if (!nar) throw Error(format("file ‘%s’ missing from binary cache") % res.url);
|
||||||
|
|
||||||
stats.narRead++;
|
stats.narRead++;
|
||||||
stats.narReadCompressedBytes += nar.size();
|
stats.narReadCompressedBytes += nar->size();
|
||||||
|
|
||||||
/* Decompress the NAR. FIXME: would be nice to have the remote
|
/* Decompress the NAR. FIXME: would be nice to have the remote
|
||||||
side do this. */
|
side do this. */
|
||||||
if (res.compression == "none")
|
if (res.compression == "none")
|
||||||
;
|
;
|
||||||
else if (res.compression == "xz")
|
else if (res.compression == "xz")
|
||||||
nar = decompressXZ(nar);
|
nar = decompressXZ(*nar);
|
||||||
else
|
else
|
||||||
throw Error(format("unknown NAR compression type ‘%1%’") % nar);
|
throw Error(format("unknown NAR compression type ‘%1%’") % nar);
|
||||||
|
|
||||||
stats.narReadBytes += nar.size();
|
stats.narReadBytes += nar->size();
|
||||||
|
|
||||||
printMsg(lvlTalkative, format("exporting path ‘%1%’ (%2% bytes)") % storePath % nar.size());
|
printMsg(lvlTalkative, format("exporting path ‘%1%’ (%2% bytes)") % storePath % nar->size());
|
||||||
|
|
||||||
assert(nar.size() % 8 == 0);
|
assert(nar->size() % 8 == 0);
|
||||||
|
|
||||||
sink((unsigned char *) nar.c_str(), nar.size());
|
sink((unsigned char *) nar->c_str(), nar->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryCacheStore::exportPath(const Path & storePath, bool sign, Sink & sink)
|
void BinaryCacheStore::exportPath(const Path & storePath, bool sign, Sink & sink)
|
||||||
|
|
|
@ -39,7 +39,9 @@ protected:
|
||||||
|
|
||||||
virtual void upsertFile(const std::string & path, const std::string & data) = 0;
|
virtual void upsertFile(const std::string & path, const std::string & data) = 0;
|
||||||
|
|
||||||
virtual std::string getFile(const std::string & path) = 0;
|
/* Return the contents of the specified file, or null if it
|
||||||
|
doesn't exist. */
|
||||||
|
virtual std::shared_ptr<std::string> getFile(const std::string & path) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ void builtinFetchurl(const BasicDerivation & drv)
|
||||||
options.showProgress = DownloadOptions::yes;
|
options.showProgress = DownloadOptions::yes;
|
||||||
|
|
||||||
auto data = makeDownloader()->download(url->second, options);
|
auto data = makeDownloader()->download(url->second, options);
|
||||||
|
assert(data.data);
|
||||||
|
|
||||||
auto out = drv.env.find("out");
|
auto out = drv.env.find("out");
|
||||||
if (out == drv.env.end()) throw Error("attribute ‘url’ missing");
|
if (out == drv.env.end()) throw Error("attribute ‘url’ missing");
|
||||||
|
@ -29,12 +30,12 @@ void builtinFetchurl(const BasicDerivation & drv)
|
||||||
|
|
||||||
auto unpack = drv.env.find("unpack");
|
auto unpack = drv.env.find("unpack");
|
||||||
if (unpack != drv.env.end() && unpack->second == "1") {
|
if (unpack != drv.env.end() && unpack->second == "1") {
|
||||||
if (string(data.data, 0, 6) == string("\xfd" "7zXZ\0", 6))
|
if (string(*data.data, 0, 6) == string("\xfd" "7zXZ\0", 6))
|
||||||
data.data = decompressXZ(data.data);
|
data.data = decompressXZ(*data.data);
|
||||||
StringSource source(data.data);
|
StringSource source(*data.data);
|
||||||
restorePath(storePath, source);
|
restorePath(storePath, source);
|
||||||
} else
|
} else
|
||||||
writeFile(storePath, data.data);
|
writeFile(storePath, *data.data);
|
||||||
|
|
||||||
auto executable = drv.env.find("executable");
|
auto executable = drv.env.find("executable");
|
||||||
if (executable != drv.env.end() && executable->second == "1") {
|
if (executable != drv.env.end() && executable->second == "1") {
|
||||||
|
|
|
@ -29,7 +29,7 @@ std::string resolveUri(const std::string & uri)
|
||||||
struct CurlDownloader : public Downloader
|
struct CurlDownloader : public Downloader
|
||||||
{
|
{
|
||||||
CURL * curl;
|
CURL * curl;
|
||||||
string data;
|
ref<std::string> data;
|
||||||
string etag, status, expectedETag;
|
string etag, status, expectedETag;
|
||||||
|
|
||||||
struct curl_slist * requestHeaders;
|
struct curl_slist * requestHeaders;
|
||||||
|
@ -41,7 +41,7 @@ struct CurlDownloader : public Downloader
|
||||||
size_t writeCallback(void * contents, size_t size, size_t nmemb)
|
size_t writeCallback(void * contents, size_t size, size_t nmemb)
|
||||||
{
|
{
|
||||||
size_t realSize = size * nmemb;
|
size_t realSize = size * nmemb;
|
||||||
data.append((char *) contents, realSize);
|
data->append((char *) contents, realSize);
|
||||||
return realSize;
|
return realSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,7 @@ struct CurlDownloader : public Downloader
|
||||||
}
|
}
|
||||||
|
|
||||||
CurlDownloader()
|
CurlDownloader()
|
||||||
|
: data(make_ref<std::string>())
|
||||||
{
|
{
|
||||||
requestHeaders = 0;
|
requestHeaders = 0;
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ struct CurlDownloader : public Downloader
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.clear();
|
data->clear();
|
||||||
|
|
||||||
if (requestHeaders) {
|
if (requestHeaders) {
|
||||||
curl_slist_free_all(requestHeaders);
|
curl_slist_free_all(requestHeaders);
|
||||||
|
@ -269,7 +270,7 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
|
||||||
auto res = download(url, options);
|
auto res = download(url, options);
|
||||||
|
|
||||||
if (!res.cached)
|
if (!res.cached)
|
||||||
storePath = store->addTextToStore(name, res.data, PathSet(), false);
|
storePath = store->addTextToStore(name, *res.data, PathSet(), false);
|
||||||
|
|
||||||
assert(!storePath.empty());
|
assert(!storePath.empty());
|
||||||
replaceSymlink(storePath, fileLink);
|
replaceSymlink(storePath, fileLink);
|
||||||
|
|
|
@ -17,7 +17,8 @@ struct DownloadOptions
|
||||||
struct DownloadResult
|
struct DownloadResult
|
||||||
{
|
{
|
||||||
bool cached;
|
bool cached;
|
||||||
string data, etag;
|
string etag;
|
||||||
|
std::shared_ptr<std::string> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Store;
|
class Store;
|
||||||
|
|
|
@ -58,12 +58,18 @@ protected:
|
||||||
throw Error("uploading to an HTTP binary cache is not supported");
|
throw Error("uploading to an HTTP binary cache is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getFile(const std::string & path) override
|
std::shared_ptr<std::string> getFile(const std::string & path) override
|
||||||
{
|
{
|
||||||
auto downloader(downloaders.get());
|
auto downloader(downloaders.get());
|
||||||
DownloadOptions options;
|
DownloadOptions options;
|
||||||
options.showProgress = DownloadOptions::no;
|
options.showProgress = DownloadOptions::no;
|
||||||
return downloader->download(cacheUri + "/" + path, options).data;
|
try {
|
||||||
|
return downloader->download(cacheUri + "/" + path, options).data;
|
||||||
|
} catch (DownloadError & e) {
|
||||||
|
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
|
||||||
|
return 0;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@ protected:
|
||||||
|
|
||||||
void upsertFile(const std::string & path, const std::string & data) override;
|
void upsertFile(const std::string & path, const std::string & data) override;
|
||||||
|
|
||||||
std::string getFile(const std::string & path) override;
|
std::shared_ptr<std::string> getFile(const std::string & path) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,9 +59,14 @@ void LocalBinaryCacheStore::upsertFile(const std::string & path, const std::stri
|
||||||
atomicWrite(binaryCacheDir + "/" + path, data);
|
atomicWrite(binaryCacheDir + "/" + path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LocalBinaryCacheStore::getFile(const std::string & path)
|
std::shared_ptr<std::string> LocalBinaryCacheStore::getFile(const std::string & path)
|
||||||
{
|
{
|
||||||
return readFile(binaryCacheDir + "/" + path);
|
try {
|
||||||
|
return std::make_shared<std::string>(readFile(binaryCacheDir + "/" + path));
|
||||||
|
} catch (SysError & e) {
|
||||||
|
if (e.errNo == ENOENT) return 0;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<Store> openLocalBinaryCacheStore(std::shared_ptr<Store> localStore,
|
ref<Store> openLocalBinaryCacheStore(std::shared_ptr<Store> localStore,
|
||||||
|
|
|
@ -511,6 +511,7 @@ ValidPathInfo decodeValidPathInfo(std::istream & str,
|
||||||
|
|
||||||
MakeError(SubstError, Error)
|
MakeError(SubstError, Error)
|
||||||
MakeError(BuildError, Error) /* denotes a permanent build failure */
|
MakeError(BuildError, Error) /* denotes a permanent build failure */
|
||||||
|
MakeError(InvalidPath, Error)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ std::string compressXZ(const std::string & in)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string decompressXZ(const std::string & in)
|
ref<std::string> decompressXZ(const std::string & in)
|
||||||
{
|
{
|
||||||
LzmaStream strm;
|
LzmaStream strm;
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ std::string decompressXZ(const std::string & in)
|
||||||
|
|
||||||
lzma_action action = LZMA_RUN;
|
lzma_action action = LZMA_RUN;
|
||||||
uint8_t outbuf[BUFSIZ];
|
uint8_t outbuf[BUFSIZ];
|
||||||
string res;
|
ref<std::string> res = make_ref<std::string>();
|
||||||
strm().next_in = (uint8_t *) in.c_str();
|
strm().next_in = (uint8_t *) in.c_str();
|
||||||
strm().avail_in = in.size();
|
strm().avail_in = in.size();
|
||||||
strm().next_out = outbuf;
|
strm().next_out = outbuf;
|
||||||
|
@ -80,7 +80,7 @@ std::string decompressXZ(const std::string & in)
|
||||||
lzma_ret ret = lzma_code(&strm(), action);
|
lzma_ret ret = lzma_code(&strm(), action);
|
||||||
|
|
||||||
if (strm().avail_out == 0 || ret == LZMA_STREAM_END) {
|
if (strm().avail_out == 0 || ret == LZMA_STREAM_END) {
|
||||||
res.append((char *) outbuf, sizeof(outbuf) - strm().avail_out);
|
res->append((char *) outbuf, sizeof(outbuf) - strm().avail_out);
|
||||||
strm().next_out = outbuf;
|
strm().next_out = outbuf;
|
||||||
strm().avail_out = sizeof(outbuf);
|
strm().avail_out = sizeof(outbuf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ref.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
std::string compressXZ(const std::string & in);
|
std::string compressXZ(const std::string & in);
|
||||||
|
|
||||||
std::string decompressXZ(const std::string & in);
|
ref<std::string> decompressXZ(const std::string & in);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
AutoDelete tmpDir(createTempDir(), true);
|
AutoDelete tmpDir(createTempDir(), true);
|
||||||
Path tmpFile = (Path) tmpDir + "/tmp";
|
Path tmpFile = (Path) tmpDir + "/tmp";
|
||||||
writeFile(tmpFile, result.data);
|
writeFile(tmpFile, *result.data);
|
||||||
|
|
||||||
/* Optionally unpack the file. */
|
/* Optionally unpack the file. */
|
||||||
if (unpack) {
|
if (unpack) {
|
||||||
|
@ -186,7 +186,7 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
/* FIXME: inefficient; addToStore() will also hash
|
/* FIXME: inefficient; addToStore() will also hash
|
||||||
this. */
|
this. */
|
||||||
hash = unpack ? hashPath(ht, tmpFile).first : hashString(ht, result.data);
|
hash = unpack ? hashPath(ht, tmpFile).first : hashString(ht, *result.data);
|
||||||
|
|
||||||
if (expectedHash != Hash(ht) && expectedHash != hash)
|
if (expectedHash != Hash(ht) && expectedHash != hash)
|
||||||
throw Error(format("hash mismatch for ‘%1%’") % uri);
|
throw Error(format("hash mismatch for ‘%1%’") % uri);
|
||||||
|
|
Loading…
Reference in a new issue