aboutsummaryrefslogtreecommitdiff
path: root/src/zenremotestore/projectstore/fileremoteprojectstore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenremotestore/projectstore/fileremoteprojectstore.cpp')
-rw-r--r--src/zenremotestore/projectstore/fileremoteprojectstore.cpp255
1 files changed, 221 insertions, 34 deletions
diff --git a/src/zenremotestore/projectstore/fileremoteprojectstore.cpp b/src/zenremotestore/projectstore/fileremoteprojectstore.cpp
index 3a67d3842..bb21de12c 100644
--- a/src/zenremotestore/projectstore/fileremoteprojectstore.cpp
+++ b/src/zenremotestore/projectstore/fileremoteprojectstore.cpp
@@ -7,8 +7,12 @@
#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
#include <zencore/logging.h>
+#include <zencore/scopeguard.h>
#include <zencore/timer.h>
#include <zenhttp/httpcommon.h>
+#include <zenremotestore/builds/buildstoragecache.h>
+
+#include <numeric>
namespace zen {
@@ -74,9 +78,11 @@ public:
virtual SaveResult SaveContainer(const IoBuffer& Payload) override
{
- Stopwatch Timer;
SaveResult Result;
+ Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
+
{
CbObject ContainerObject = LoadCompactBinaryObject(Payload);
@@ -87,6 +93,10 @@ public:
{
Result.Needs.insert(AttachmentHash);
}
+ else if (std::filesystem::path AttachmentMetaPath = GetAttachmentMetaPath(AttachmentHash); IsFile(AttachmentMetaPath))
+ {
+ BasicFile TouchIt(AttachmentMetaPath, BasicFile::Mode::kWrite);
+ }
});
}
@@ -112,14 +122,18 @@ public:
Result.Reason = fmt::format("Failed saving oplog container to '{}'. Reason: {}", ContainerPath, Ex.what());
}
AddStats(Payload.GetSize(), 0, Timer.GetElapsedTimeUs() * 1000);
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
return Result;
}
- virtual SaveAttachmentResult SaveAttachment(const CompositeBuffer& Payload, const IoHash& RawHash, ChunkBlockDescription&&) override
+ virtual SaveAttachmentResult SaveAttachment(const CompositeBuffer& Payload,
+ const IoHash& RawHash,
+ ChunkBlockDescription&& BlockDescription) override
{
- Stopwatch Timer;
- SaveAttachmentResult Result;
+ SaveAttachmentResult Result;
+
+ Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
+
std::filesystem::path ChunkPath = GetAttachmentPath(RawHash);
if (!IsFile(ChunkPath))
{
@@ -142,14 +156,33 @@ public:
Result.Reason = fmt::format("Failed saving oplog attachment to '{}'. Reason: {}", ChunkPath, Ex.what());
}
}
+ if (!Result.ErrorCode && BlockDescription.BlockHash != IoHash::Zero)
+ {
+ try
+ {
+ std::filesystem::path MetaPath = GetAttachmentMetaPath(RawHash);
+ CbObject MetaData = BuildChunkBlockDescription(BlockDescription, {});
+ SharedBuffer MetaBuffer = MetaData.GetBuffer();
+ BasicFile MetaFile;
+ MetaFile.Open(MetaPath, BasicFile::Mode::kTruncate);
+ MetaFile.Write(MetaBuffer.GetView(), 0);
+ }
+ catch (const std::exception& Ex)
+ {
+ Result.ErrorCode = gsl::narrow<int32_t>(HttpResponseCode::InternalServerError);
+ Result.Reason = fmt::format("Failed saving block description to '{}'. Reason: {}", RawHash, Ex.what());
+ }
+ }
AddStats(Payload.GetSize(), 0, Timer.GetElapsedTimeUs() * 1000);
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
return Result;
}
virtual SaveAttachmentsResult SaveAttachments(const std::vector<SharedBuffer>& Chunks) override
{
+ SaveAttachmentsResult Result;
+
Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
for (const SharedBuffer& Chunk : Chunks)
{
@@ -157,12 +190,10 @@ public:
SaveAttachmentResult ChunkResult = SaveAttachment(Compressed.GetCompressed(), Compressed.DecodeRawHash(), {});
if (ChunkResult.ErrorCode)
{
- ChunkResult.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
- return SaveAttachmentsResult{ChunkResult};
+ Result = SaveAttachmentsResult{ChunkResult};
+ break;
}
}
- SaveAttachmentsResult Result;
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
return Result;
}
@@ -172,21 +203,60 @@ public:
virtual GetKnownBlocksResult GetKnownBlocks() override
{
+ Stopwatch Timer;
if (m_OptionalBaseName.empty())
{
- return GetKnownBlocksResult{{.ErrorCode = static_cast<int>(HttpResponseCode::NoContent)}};
+ size_t MaxBlockCount = 10000;
+
+ GetKnownBlocksResult Result;
+
+ DirectoryContent Content;
+ GetDirectoryContent(
+ m_OutputPath,
+ DirectoryContentFlags::IncludeFiles | DirectoryContentFlags::Recursive | DirectoryContentFlags::IncludeModificationTick,
+ Content);
+ std::vector<size_t> RecentOrder(Content.Files.size());
+ std::iota(RecentOrder.begin(), RecentOrder.end(), 0u);
+ std::sort(RecentOrder.begin(), RecentOrder.end(), [&Content](size_t Lhs, size_t Rhs) {
+ return Content.FileModificationTicks[Lhs] > Content.FileModificationTicks[Rhs];
+ });
+
+ for (size_t FileIndex : RecentOrder)
+ {
+ std::filesystem::path MetaPath = Content.Files[FileIndex];
+ if (MetaPath.extension() == MetaExtension)
+ {
+ IoBuffer MetaFile = ReadFile(MetaPath).Flatten();
+ CbValidateError Err;
+ CbObject ValidatedObject = ValidateAndReadCompactBinaryObject(std::move(MetaFile), Err);
+ if (Err == CbValidateError::None)
+ {
+ ChunkBlockDescription Description = ParseChunkBlockDescription(ValidatedObject);
+ if (Description.BlockHash != IoHash::Zero)
+ {
+ Result.Blocks.emplace_back(std::move(Description));
+ if (Result.Blocks.size() == MaxBlockCount)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
+ return Result;
}
LoadContainerResult LoadResult = LoadContainer(m_OptionalBaseName);
if (LoadResult.ErrorCode)
{
return GetKnownBlocksResult{LoadResult};
}
- Stopwatch Timer;
std::vector<IoHash> BlockHashes = GetBlockHashesFromOplog(LoadResult.ContainerObject);
if (BlockHashes.empty())
{
return GetKnownBlocksResult{{.ErrorCode = static_cast<int>(HttpResponseCode::NoContent),
- .ElapsedSeconds = LoadResult.ElapsedSeconds + Timer.GetElapsedTimeUs() * 1000}};
+ .ElapsedSeconds = LoadResult.ElapsedSeconds + Timer.GetElapsedTimeMs() / 1000.0}};
}
std::vector<IoHash> ExistingBlockHashes;
for (const IoHash& RawHash : BlockHashes)
@@ -200,15 +270,15 @@ public:
if (ExistingBlockHashes.empty())
{
return GetKnownBlocksResult{{.ErrorCode = static_cast<int>(HttpResponseCode::NoContent),
- .ElapsedSeconds = LoadResult.ElapsedSeconds + Timer.GetElapsedTimeUs() * 1000}};
+ .ElapsedSeconds = LoadResult.ElapsedSeconds + Timer.GetElapsedTimeMs() / 1000.0}};
}
std::vector<ThinChunkBlockDescription> ThinKnownBlocks = GetBlocksFromOplog(LoadResult.ContainerObject, ExistingBlockHashes);
- const size_t KnowBlockCount = ThinKnownBlocks.size();
+ const size_t KnownBlockCount = ThinKnownBlocks.size();
- GetKnownBlocksResult Result{{.ElapsedSeconds = LoadResult.ElapsedSeconds + Timer.GetElapsedTimeUs() * 1000}};
- Result.Blocks.resize(KnowBlockCount);
- for (size_t BlockIndex = 0; BlockIndex < KnowBlockCount; BlockIndex++)
+ GetKnownBlocksResult Result{{.ElapsedSeconds = LoadResult.ElapsedSeconds + Timer.GetElapsedTimeMs() / 1000.0}};
+ Result.Blocks.resize(KnownBlockCount);
+ for (size_t BlockIndex = 0; BlockIndex < KnownBlockCount; BlockIndex++)
{
Result.Blocks[BlockIndex].BlockHash = ThinKnownBlocks[BlockIndex].BlockHash;
Result.Blocks[BlockIndex].ChunkRawHashes = std::move(ThinKnownBlocks[BlockIndex].ChunkRawHashes);
@@ -217,16 +287,88 @@ public:
return Result;
}
+ virtual GetBlockDescriptionsResult GetBlockDescriptions(std::span<const IoHash> BlockHashes,
+ BuildStorageCache* OptionalCache,
+ const Oid& CacheBuildId) override
+ {
+ GetBlockDescriptionsResult Result;
+
+ Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
+
+ Result.Blocks.reserve(BlockHashes.size());
+
+ uint64_t ByteCount = 0;
+
+ std::vector<ChunkBlockDescription> UnorderedList;
+ {
+ if (OptionalCache)
+ {
+ std::vector<CbObject> CacheBlockMetadatas = OptionalCache->GetBlobMetadatas(CacheBuildId, BlockHashes);
+ for (const CbObject& BlockObject : CacheBlockMetadatas)
+ {
+ ByteCount += BlockObject.GetSize();
+ }
+ UnorderedList = ParseBlockMetadatas(CacheBlockMetadatas);
+ }
+
+ tsl::robin_map<IoHash, size_t, IoHash::Hasher> BlockDescriptionLookup;
+ BlockDescriptionLookup.reserve(BlockHashes.size());
+ for (size_t DescriptionIndex = 0; DescriptionIndex < UnorderedList.size(); DescriptionIndex++)
+ {
+ const ChunkBlockDescription& Description = UnorderedList[DescriptionIndex];
+ BlockDescriptionLookup.insert_or_assign(Description.BlockHash, DescriptionIndex);
+ }
+
+ if (UnorderedList.size() < BlockHashes.size())
+ {
+ for (const IoHash& RawHash : BlockHashes)
+ {
+ if (!BlockDescriptionLookup.contains(RawHash))
+ {
+ std::filesystem::path MetaPath = GetAttachmentMetaPath(RawHash);
+ IoBuffer MetaFile = ReadFile(MetaPath).Flatten();
+ ByteCount += MetaFile.GetSize();
+ CbValidateError Err;
+ CbObject ValidatedObject = ValidateAndReadCompactBinaryObject(std::move(MetaFile), Err);
+ if (Err == CbValidateError::None)
+ {
+ ChunkBlockDescription Description = ParseChunkBlockDescription(ValidatedObject);
+ if (Description.BlockHash != IoHash::Zero)
+ {
+ BlockDescriptionLookup.insert_or_assign(Description.BlockHash, UnorderedList.size());
+ UnorderedList.emplace_back(std::move(Description));
+ }
+ }
+ }
+ }
+ }
+
+ Result.Blocks.reserve(UnorderedList.size());
+ for (const IoHash& RawHash : BlockHashes)
+ {
+ if (auto It = BlockDescriptionLookup.find(RawHash); It != BlockDescriptionLookup.end())
+ {
+ Result.Blocks.emplace_back(std::move(UnorderedList[It->second]));
+ }
+ }
+ }
+ AddStats(0, ByteCount, Timer.GetElapsedTimeUs() * 1000);
+ return Result;
+ }
+
virtual LoadAttachmentResult LoadAttachment(const IoHash& RawHash) override
{
- Stopwatch Timer;
- LoadAttachmentResult Result;
+ LoadAttachmentResult Result;
+
+ Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
+
std::filesystem::path ChunkPath = GetAttachmentPath(RawHash);
if (!IsFile(ChunkPath))
{
Result.ErrorCode = gsl::narrow<int>(HttpResponseCode::NotFound);
Result.Reason = fmt::format("Failed loading oplog attachment from '{}'. Reason: 'The file does not exist'", ChunkPath.string());
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
return Result;
}
{
@@ -235,7 +377,41 @@ public:
Result.Bytes = ChunkFile.ReadAll();
}
AddStats(0, Result.Bytes.GetSize(), Timer.GetElapsedTimeUs() * 1000);
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
+ return Result;
+ }
+
+ virtual LoadAttachmentRangesResult LoadAttachmentRanges(const IoHash& RawHash,
+ std::span<const std::pair<uint64_t, uint64_t>> Ranges) override
+ {
+ ZEN_ASSERT(!Ranges.empty());
+ LoadAttachmentRangesResult Result;
+
+ Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
+
+ std::filesystem::path ChunkPath = GetAttachmentPath(RawHash);
+ if (!IsFile(ChunkPath))
+ {
+ Result.ErrorCode = gsl::narrow<int>(HttpResponseCode::NotFound);
+ Result.Reason = fmt::format("Failed loading oplog attachment from '{}'. Reason: 'The file does not exist'", ChunkPath.string());
+ return Result;
+ }
+ {
+ uint64_t Start = Ranges.front().first;
+ uint64_t Length = Ranges.back().first + Ranges.back().second - Ranges.front().first;
+ Result.Bytes = IoBufferBuilder::MakeFromFile(ChunkPath, Start, Length);
+ Result.Ranges.reserve(Ranges.size());
+ for (const std::pair<uint64_t, uint64_t>& Range : Ranges)
+ {
+ Result.Ranges.push_back(std::make_pair(Range.first - Start, Range.second));
+ }
+ }
+ AddStats(0,
+ std::accumulate(Result.Ranges.begin(),
+ Result.Ranges.end(),
+ uint64_t(0),
+ [](uint64_t Current, const std::pair<uint64_t, uint64_t>& Value) { return Current + Value.second; }),
+ Timer.GetElapsedTimeUs() * 1000);
return Result;
}
@@ -258,20 +434,20 @@ public:
return Result;
}
- virtual void Flush() override {}
-
private:
LoadContainerResult LoadContainer(const std::string& Name)
{
- Stopwatch Timer;
- LoadContainerResult Result;
+ LoadContainerResult Result;
+
+ Stopwatch Timer;
+ auto _ = MakeGuard([&Result, &Timer]() { Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0; });
+
std::filesystem::path SourcePath = m_OutputPath;
SourcePath.append(Name);
if (!IsFile(SourcePath))
{
Result.ErrorCode = gsl::narrow<int>(HttpResponseCode::NotFound);
Result.Reason = fmt::format("Failed loading oplog container from '{}'. Reason: 'The file does not exist'", SourcePath.string());
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
return Result;
}
IoBuffer ContainerPayload;
@@ -285,18 +461,16 @@ private:
if (Result.ContainerObject = ValidateAndReadCompactBinaryObject(std::move(ContainerPayload), ValidateResult);
ValidateResult != CbValidateError::None || !Result.ContainerObject)
{
- Result.ErrorCode = gsl::narrow<int32_t>(HttpResponseCode::InternalServerError);
- Result.Reason = fmt::format("The file {} is not formatted as a compact binary object ('{}')",
- SourcePath.string(),
- ToString(ValidateResult));
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
+ Result.ErrorCode = gsl::narrow<int32_t>(HttpResponseCode::InternalServerError);
+ Result.Reason = fmt::format("The file {} is not formatted as a compact binary object ('{}')",
+ SourcePath.string(),
+ ToString(ValidateResult));
return Result;
}
- Result.ElapsedSeconds = Timer.GetElapsedTimeMs() / 1000.0;
return Result;
}
- std::filesystem::path GetAttachmentPath(const IoHash& RawHash) const
+ std::filesystem::path GetAttachmentBasePath(const IoHash& RawHash) const
{
ExtendablePathBuilder<128> ShardedPath;
ShardedPath.Append(m_OutputPath.c_str());
@@ -315,6 +489,19 @@ private:
return ShardedPath.ToPath();
}
+ static constexpr std::string_view BlobExtension = ".blob";
+ static constexpr std::string_view MetaExtension = ".meta";
+
+ std::filesystem::path GetAttachmentPath(const IoHash& RawHash)
+ {
+ return GetAttachmentBasePath(RawHash).replace_extension(BlobExtension);
+ }
+
+ std::filesystem::path GetAttachmentMetaPath(const IoHash& RawHash)
+ {
+ return GetAttachmentBasePath(RawHash).replace_extension(MetaExtension);
+ }
+
void AddStats(uint64_t UploadedBytes, uint64_t DownloadedBytes, uint64_t ElapsedNS)
{
m_SentBytes.fetch_add(UploadedBytes);