aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2025-03-28 14:12:42 +0100
committerGitHub Enterprise <[email protected]>2025-03-28 14:12:42 +0100
commit8f192ab154ff9de41d4c063138478400fe2aef24 (patch)
tree3ec414b7c268959ec19769b86d12512bb15f6a7a /src
parentbuild cache prime (#327) (diff)
downloadzen-8f192ab154ff9de41d4c063138478400fe2aef24.tar.xz
zen-8f192ab154ff9de41d4c063138478400fe2aef24.zip
temp path options and reduced scanning of target folder (#328)
- Feature: zen: `--zen-folder-path` added to `builds` command, `list`, `upload`, `download`, `fetch-blob`, `validate-part` to control where `.zen` folder is placed and named - Improvement: Only check known files from remote state when downloading to a target folder with no local state file - Improvement: Don't move existing local to cache and back if they are untouched
Diffstat (limited to 'src')
-rw-r--r--src/zen/cmds/builds_cmd.cpp812
-rw-r--r--src/zen/cmds/builds_cmd.h2
-rw-r--r--src/zenutil/chunkedcontent.cpp18
3 files changed, 580 insertions, 252 deletions
diff --git a/src/zen/cmds/builds_cmd.cpp b/src/zen/cmds/builds_cmd.cpp
index 3a54de935..d4add0e04 100644
--- a/src/zen/cmds/builds_cmd.cpp
+++ b/src/zen/cmds/builds_cmd.cpp
@@ -104,22 +104,34 @@ namespace {
const uint64_t MinimumSizeForCompressInBlock = 2u * 1024u;
- const std::string ZenFolderName = ".zen";
- const std::string ZenStateFilePath = fmt::format("{}/current_state.cbo", ZenFolderName);
- const std::string ZenStateFileJsonPath = fmt::format("{}/current_state.json", ZenFolderName);
- const std::string ZenTempFolderName = fmt::format("{}/tmp", ZenFolderName);
+ const std::string ZenFolderName = ".zen";
+ std::filesystem::path ZenStateFilePath(const std::filesystem::path& ZenFolderPath) { return ZenFolderPath / "current_state.cbo"; }
+ // std::filesystem::path ZenStateFileJsonPath(const std::filesystem::path& ZenFolderPath) { return ZenFolderPath / "current_state.json";
+ // }
+ std::filesystem::path ZenTempFolderPath(const std::filesystem::path& ZenFolderPath) { return ZenFolderPath / "tmp"; }
- const std::string ZenTempCacheFolderName =
- fmt::format("{}/cache", ZenTempFolderName); // Decompressed and verified data - chunks & sequences
- const std::string ZenTempBlockFolderName = fmt::format("{}/blocks", ZenTempFolderName); // Temp storage for whole and partial blocks
- const std::string ZenTempChunkFolderName =
- fmt::format("{}/chunks", ZenTempFolderName); // Temp storage for decompressed and validated chunks
+ std::filesystem::path ZenTempCacheFolderPath(const std::filesystem::path& ZenFolderPath)
+ {
+ return ZenTempFolderPath(ZenFolderPath) / "cache"; // Decompressed and verified data - chunks & sequences
+ }
+ std::filesystem::path ZenTempBlockFolderPath(const std::filesystem::path& ZenFolderPath)
+ {
+ return ZenTempFolderPath(ZenFolderPath) / "blocks"; // Temp storage for whole and partial blocks
+ }
+ std::filesystem::path ZenTempChunkFolderPath(const std::filesystem::path& ZenFolderPath)
+ {
+ return ZenTempFolderPath(ZenFolderPath) / "chunks"; // Temp storage for decompressed and validated chunks
+ }
- const std::string ZenTempDownloadFolderName =
- fmt::format("{}/download", ZenTempFolderName); // Temp storage for unverfied downloaded blobs
+ std::filesystem::path ZenTempDownloadFolderPath(const std::filesystem::path& ZenFolderPath)
+ {
+ return ZenTempFolderPath(ZenFolderPath) / "download"; // Temp storage for decompressed and validated chunks
+ }
- const std::string ZenTempStorageFolderName =
- fmt::format("{}/storage", ZenTempFolderName); // Temp storage folder for BuildStorage implementations
+ // std::filesystem::path ZenTempStorageFolderPath(const std::filesystem::path& ZenFolderPath)
+ // {
+ // return ZenTempFolderPath(ZenFolderPath) / "storage"; // Temp storage folder for BuildStorage implementations
+ // }
const std::string ZenExcludeManifestName = ".zen_exclude_manifest.txt";
@@ -150,6 +162,23 @@ namespace {
);
+ std::filesystem::path MakeSafeAbsolutePath(const std::string Path)
+ {
+ std::filesystem::path AbsolutePath = std::filesystem::absolute(StringToPath(Path)).make_preferred();
+#if ZEN_PLATFORM_WINDOWS && \
+ 0 // TODO: We need UNC for long file names but we need to stop using std::filesystem for those paths - std::filesystem::* functions
+ const std::string_view Prefix = "\\\\?\\";
+ const std::u8string PrefixU8(Prefix.begin(), Prefix.end());
+ std::u8string PathString = AbsolutePath.u8string();
+ if (!PathString.starts_with(PrefixU8))
+ {
+ PathString.insert(0, PrefixU8);
+ return std::filesystem::path(PathString);
+ }
+#endif
+ return AbsolutePath;
+ }
+
uint32_t SetNativeFileAttributes(const std::filesystem::path FilePath, SourcePlatform SourcePlatform, uint32_t Attributes)
{
#if ZEN_PLATFORM_WINDOWS
@@ -2141,6 +2170,7 @@ namespace {
void UploadPartBlobs(StorageInstance& Storage,
const Oid& BuildId,
const std::filesystem::path& Path,
+ const std::filesystem::path& ZenFolderPath,
const ChunkedFolderContent& Content,
const ChunkedContentLookup& Lookup,
std::span<IoHash> RawHashes,
@@ -2214,7 +2244,7 @@ namespace {
if (QueuedPendingInMemoryBlocksForUpload.load() > 16)
{
ZEN_TRACE_CPU("AsyncUploadBlock_WriteTempBlock");
- Payload = CompositeBuffer(WriteToTempFile(std::move(Payload), Path / ZenTempBlockFolderName, BlockHash));
+ Payload = CompositeBuffer(WriteToTempFile(std::move(Payload), ZenTempBlockFolderPath(ZenFolderPath), BlockHash));
IsInMemoryBlock = false;
}
else
@@ -2437,7 +2467,7 @@ namespace {
FilteredCompressedBytesPerSecond.Start();
CompositeBuffer Payload =
- CompressChunk(Path, Content, Lookup, ChunkIndex, Path / ZenTempChunkFolderName, LooseChunksStats);
+ CompressChunk(Path, Content, Lookup, ChunkIndex, ZenTempChunkFolderPath(ZenFolderPath), LooseChunksStats);
ZEN_CONSOLE_VERBOSE("Compressed chunk {} ({} -> {})",
Content.ChunkedContent.ChunkHashes[ChunkIndex],
NiceBytes(Content.ChunkedContent.ChunkRawSizes[ChunkIndex]),
@@ -2668,6 +2698,7 @@ namespace {
const Oid& BuildPartId,
const std::string_view BuildPartName,
const std::filesystem::path& Path,
+ const std::filesystem::path& ZenFolderPath,
const std::filesystem::path& ManifestPath,
const uint8_t BlockReuseMinPercentLimit,
bool AllowMultiparts,
@@ -2678,7 +2709,7 @@ namespace {
{
Stopwatch ProcessTimer;
- const std::filesystem::path ZenTempFolder = Path / ZenTempFolderName;
+ const std::filesystem::path ZenTempFolder = ZenTempFolderPath(ZenFolderPath);
CreateDirectories(ZenTempFolder);
CleanDirectory(ZenTempFolder, {});
auto _ = MakeGuard([&]() {
@@ -2687,8 +2718,8 @@ namespace {
std::filesystem::remove(ZenTempFolder);
}
});
- CreateDirectories(Path / ZenTempBlockFolderName);
- CreateDirectories(Path / ZenTempChunkFolderName);
+ CreateDirectories(ZenTempBlockFolderPath(ZenFolderPath));
+ CreateDirectories(ZenTempChunkFolderPath(ZenFolderPath));
std::uint64_t TotalRawSize = 0;
@@ -3308,6 +3339,7 @@ namespace {
UploadPartBlobs(Storage,
BuildId,
Path,
+ ZenFolderPath,
LocalContent,
LocalLookup,
RawHashes,
@@ -4579,7 +4611,7 @@ namespace {
return false;
}
- void AsyncWriteDownloadedChunk(const std::filesystem::path& Path,
+ void AsyncWriteDownloadedChunk(const std::filesystem::path& ZenFolderPath,
const ChunkedFolderContent& RemoteContent,
const ChunkedContentLookup& RemoteLookup,
uint32_t RemoteChunkIndex,
@@ -4613,7 +4645,7 @@ namespace {
{
Payload.SetDeleteOnClose(false);
Payload = {};
- CompressedChunkPath = Path / ZenTempDownloadFolderName / ChunkHash.ToHexString();
+ CompressedChunkPath = ZenTempDownloadFolderPath(ZenFolderPath) / ChunkHash.ToHexString();
std::filesystem::rename(TempBlobPath, CompressedChunkPath, Ec);
if (Ec)
{
@@ -4632,7 +4664,7 @@ namespace {
{
ZEN_TRACE_CPU("WriteTempChunk");
// Could not be moved and rather large, lets store it on disk
- CompressedChunkPath = Path / ZenTempDownloadFolderName / ChunkHash.ToHexString();
+ CompressedChunkPath = ZenTempDownloadFolderPath(ZenFolderPath) / ChunkHash.ToHexString();
TemporaryFile::SafeWriteFile(CompressedChunkPath, Payload);
Payload = {};
}
@@ -4668,7 +4700,7 @@ namespace {
}
}
- std::filesystem::path TargetFolder = Path / ZenTempCacheFolderName;
+ std::filesystem::path TargetFolder = ZenTempCacheFolderPath(ZenFolderPath);
bool NeedHashVerify = WriteCompressedChunk(TargetFolder,
RemoteContent,
@@ -4711,6 +4743,7 @@ namespace {
void UpdateFolder(StorageInstance& Storage,
const Oid& BuildId,
const std::filesystem::path& Path,
+ const std::filesystem::path& ZenFolderPath,
const std::uint64_t LargeAttachmentSize,
const std::uint64_t PreferredMultipartChunkSize,
const ChunkedFolderContent& LocalContent,
@@ -4739,7 +4772,7 @@ namespace {
ZEN_CONSOLE("Indexed local and remote content in {}", NiceTimeSpanMs(IndexTimer.GetElapsedTimeMs()));
- const std::filesystem::path CacheFolderPath = Path / ZenTempCacheFolderName;
+ const std::filesystem::path CacheFolderPath = ZenTempCacheFolderPath(ZenFolderPath);
Stopwatch CacheMappingTimer;
@@ -4786,6 +4819,12 @@ namespace {
CachedSequenceHashesFound.insert({FileHash, SequenceIndex});
CacheMappingStats.CacheSequenceHashesCount++;
CacheMappingStats.CacheSequenceHashesByteCount += SequenceSize;
+
+ const std::filesystem::path CacheFilePath =
+ GetFinalChunkedSequenceFileName(CacheFolderPath,
+ RemoteContent.ChunkedContent.SequenceRawHashes[SequenceIndex]);
+ ZEN_ASSERT_SLOW(std::filesystem::is_regular_file(CacheFilePath));
+
continue;
}
}
@@ -4808,7 +4847,7 @@ namespace {
}
DirectoryContent BlockDirContent;
- GetDirectoryContent(Path / ZenTempBlockFolderName,
+ GetDirectoryContent(ZenTempBlockFolderPath(ZenFolderPath),
DirectoryContentFlags::IncludeFiles | DirectoryContentFlags::IncludeFileSizes,
BlockDirContent);
CachedBlocksFound.reserve(BlockDirContent.Files.size());
@@ -4856,6 +4895,8 @@ namespace {
// const uint32_t RemoteSequenceIndex = CacheSequenceIt->second;
// const uint32_t RemotePathIndex = GetFirstPathIndexForSeqeuenceIndex(RemoteLookup, RemoteSequenceIndex);
// RemoteSequenceByteCountFoundInCache += RemoteContent.RawSizes[RemotePathIndex];
+ const std::filesystem::path CacheFilePath = GetFinalChunkedSequenceFileName(CacheFolderPath, RemoteSequenceRawHash);
+ ZEN_ASSERT_SLOW(std::filesystem::is_regular_file(CacheFilePath));
}
else if (auto CacheChunkIt = CachedChunkHashesFound.find(RemoteSequenceRawHash);
CacheChunkIt != CachedChunkHashesFound.end())
@@ -4863,13 +4904,16 @@ namespace {
// const uint32_t RemoteChunkIndex = CacheChunkIt->second;
// const uint32_t RemotePathIndex = GetFirstPathIndexForSeqeuenceIndex(RemoteLookup, RemoteSequenceIndex);
// RemoteSequenceByteCountFoundInCache += RemoteContent.RawSizes[RemotePathIndex];
+ const std::filesystem::path CacheFilePath = GetFinalChunkedSequenceFileName(CacheFolderPath, RemoteSequenceRawHash);
+ ZEN_ASSERT_SLOW(std::filesystem::is_regular_file(CacheFilePath));
}
else if (auto It = LocalLookup.RawHashToSequenceIndex.find(RemoteSequenceRawHash);
It != LocalLookup.RawHashToSequenceIndex.end())
{
const uint32_t LocalSequenceIndex = It->second;
const uint32_t LocalPathIndex = GetFirstPathIndexForSeqeuenceIndex(LocalLookup, LocalSequenceIndex);
- uint64_t RawSize = LocalContent.RawSizes[LocalPathIndex];
+ ZEN_ASSERT_SLOW(std::filesystem::is_regular_file(Path / LocalContent.Paths[LocalPathIndex]));
+ uint64_t RawSize = LocalContent.RawSizes[LocalPathIndex];
LocalPathIndexesMatchingSequenceIndexes.push_back(LocalPathIndex);
CacheMappingStats.LocalPathsMatchingSequencesCount++;
CacheMappingStats.LocalPathsMatchingSequencesByteCount += RawSize;
@@ -5135,7 +5179,8 @@ namespace {
TotalPartWriteCount++;
- std::filesystem::path BlockPath = Path / ZenTempBlockFolderName / BlockDescription.BlockHash.ToHexString();
+ std::filesystem::path BlockPath =
+ ZenTempBlockFolderPath(ZenFolderPath) / BlockDescription.BlockHash.ToHexString();
if (std::filesystem::exists(BlockPath))
{
CachedChunkBlockIndexes.push_back(BlockIndex);
@@ -5414,8 +5459,9 @@ namespace {
std::filesystem::path ExistingCompressedChunkPath;
if (!PrimeCacheOnly)
{
- const IoHash& ChunkHash = RemoteContent.ChunkedContent.ChunkHashes[RemoteChunkIndex];
- std::filesystem::path CompressedChunkPath = Path / ZenTempDownloadFolderName / ChunkHash.ToHexString();
+ const IoHash& ChunkHash = RemoteContent.ChunkedContent.ChunkHashes[RemoteChunkIndex];
+ std::filesystem::path CompressedChunkPath =
+ ZenTempDownloadFolderPath(ZenFolderPath) / ChunkHash.ToHexString();
if (std::filesystem::exists(CompressedChunkPath))
{
IoBuffer ExistingCompressedPart = IoBufferBuilder::MakeFromFile(ExistingCompressedChunkPath);
@@ -5448,6 +5494,7 @@ namespace {
Work.ScheduleWork(
WritePool,
[&Path,
+ &ZenFolderPath,
&RemoteContent,
&RemoteLookup,
&CacheFolderPath,
@@ -5479,7 +5526,7 @@ namespace {
CompressedChunkPath));
}
- std::filesystem::path TargetFolder = Path / ZenTempCacheFolderName;
+ std::filesystem::path TargetFolder = ZenTempCacheFolderPath(ZenFolderPath);
bool NeedHashVerify = WriteCompressedChunk(TargetFolder,
RemoteContent,
RemoteLookup,
@@ -5523,9 +5570,10 @@ namespace {
Work.ScheduleWork(
NetworkPool,
[&Path,
+ &ZenFolderPath,
&Storage,
- PrimeCacheOnly,
BuildId,
+ &PrimeCacheOnly,
&RemoteContent,
&RemoteLookup,
&ExistsResult,
@@ -5563,7 +5611,7 @@ namespace {
ZEN_TRACE_CPU("UpdateFolder_GetLargeChunk");
DownloadLargeBlob(
*Storage.BuildStorage,
- Path / ZenTempDownloadFolderName,
+ ZenTempDownloadFolderPath(ZenFolderPath),
BuildId,
ChunkHash,
PreferredMultipartChunkSize,
@@ -5588,7 +5636,7 @@ namespace {
{
if (!AbortFlag)
{
- AsyncWriteDownloadedChunk(Path,
+ AsyncWriteDownloadedChunk(ZenFolderPath,
RemoteContent,
RemoteLookup,
RemoteChunkIndex,
@@ -5633,7 +5681,7 @@ namespace {
{
FilteredDownloadedBytesPerSecond.Stop();
}
- AsyncWriteDownloadedChunk(Path,
+ AsyncWriteDownloadedChunk(ZenFolderPath,
RemoteContent,
RemoteLookup,
RemoteChunkIndex,
@@ -5852,8 +5900,9 @@ namespace {
const ChunkBlockDescription& BlockDescription = BlockDescriptions[BlockIndex];
FilteredWrittenBytesPerSecond.Start();
- std::filesystem::path BlockChunkPath = Path / ZenTempBlockFolderName / BlockDescription.BlockHash.ToHexString();
- IoBuffer BlockBuffer = IoBufferBuilder::MakeFromFile(BlockChunkPath);
+ std::filesystem::path BlockChunkPath =
+ ZenTempBlockFolderPath(ZenFolderPath) / BlockDescription.BlockHash.ToHexString();
+ IoBuffer BlockBuffer = IoBufferBuilder::MakeFromFile(BlockChunkPath);
if (!BlockBuffer)
{
throw std::runtime_error(
@@ -5955,11 +6004,10 @@ namespace {
{
BlockBuffer.SetDeleteOnClose(false);
BlockBuffer = {};
- BlockChunkPath = Path / ZenTempBlockFolderName /
- fmt::format("{}_{:x}_{:x}",
- BlockDescription.BlockHash,
- BlockRange.RangeStart,
- BlockRange.RangeLength);
+ BlockChunkPath = ZenTempBlockFolderPath(ZenFolderPath) / fmt::format("{}_{:x}_{:x}",
+ BlockDescription.BlockHash,
+ BlockRange.RangeStart,
+ BlockRange.RangeLength);
std::filesystem::rename(TempBlobPath, BlockChunkPath, Ec);
if (Ec)
{
@@ -5978,11 +6026,10 @@ namespace {
{
ZEN_TRACE_CPU("UpdateFolder_WriteTempBlock");
// Could not be moved and rather large, lets store it on disk
- BlockChunkPath = Path / ZenTempBlockFolderName /
- fmt::format("{}_{:x}_{:x}",
- BlockDescription.BlockHash,
- BlockRange.RangeStart,
- BlockRange.RangeLength);
+ BlockChunkPath = ZenTempBlockFolderPath(ZenFolderPath) / fmt::format("{}_{:x}_{:x}",
+ BlockDescription.BlockHash,
+ BlockRange.RangeStart,
+ BlockRange.RangeLength);
TemporaryFile::SafeWriteFile(BlockChunkPath, BlockBuffer);
BlockBuffer = {};
}
@@ -6130,8 +6177,9 @@ namespace {
if (!Ec)
{
BlockBuffer.SetDeleteOnClose(false);
- BlockBuffer = {};
- BlockChunkPath = Path / ZenTempBlockFolderName / BlockDescription.BlockHash.ToHexString();
+ BlockBuffer = {};
+ BlockChunkPath =
+ ZenTempBlockFolderPath(ZenFolderPath) / BlockDescription.BlockHash.ToHexString();
std::filesystem::rename(TempBlobPath, BlockChunkPath, Ec);
if (Ec)
{
@@ -6150,7 +6198,7 @@ namespace {
{
ZEN_TRACE_CPU("UpdateFolder_WriteTempBlock");
// Could not be moved and rather large, lets store it on disk
- BlockChunkPath = Path / ZenTempBlockFolderName / BlockDescription.BlockHash.ToHexString();
+ BlockChunkPath = ZenTempBlockFolderPath(ZenFolderPath) / BlockDescription.BlockHash.ToHexString();
TemporaryFile::SafeWriteFile(BlockChunkPath, BlockBuffer);
BlockBuffer = {};
}
@@ -6323,36 +6371,106 @@ namespace {
return;
}
- // Move all files we will reuse to cache folder
- // TODO: If WipeTargetFolder is false we could check which files are already correct and leave them in place
- if (!LocalPathIndexesMatchingSequenceIndexes.empty())
+ tsl::robin_map<uint32_t, uint32_t> RemotePathIndexToLocalPathIndex;
+ RemotePathIndexToLocalPathIndex.reserve(RemoteContent.Paths.size());
+
+ tsl::robin_map<IoHash, uint32_t, IoHash::Hasher> SequenceHashToLocalPathIndex;
+ std::vector<uint32_t> RemoveLocalPathIndexes;
+
+ if (!WipeTargetFolder)
{
- ZEN_TRACE_CPU("UpdateFolder_CacheReused");
- uint64_t TotalFullFileSizeCached = 0;
- for (uint32_t LocalPathIndex : LocalPathIndexesMatchingSequenceIndexes)
+ tsl::robin_set<IoHash, IoHash::Hasher> CachedRemoteSequences;
+ tsl::robin_map<std::string, uint32_t> RemotePathToRemoteIndex;
+ RemotePathToRemoteIndex.reserve(RemoteContent.Paths.size());
+ for (uint32_t RemotePathIndex = 0; RemotePathIndex < RemoteContent.Paths.size(); RemotePathIndex++)
{
- const IoHash& RawHash = LocalContent.RawHashes[LocalPathIndex];
- const std::filesystem::path LocalFilePath = (Path / LocalContent.Paths[LocalPathIndex]).make_preferred();
- const std::filesystem::path CacheFilePath = GetFinalChunkedSequenceFileName(CacheFolderPath, RawHash);
- ZEN_ASSERT_SLOW(std::filesystem::exists(LocalFilePath));
- SetFileReadOnly(LocalFilePath, false);
- ZEN_ASSERT_SLOW(!std::filesystem::exists(CacheFilePath));
- std::error_code Ec;
- std::filesystem::rename(LocalFilePath, CacheFilePath, Ec);
- for (size_t Retries = 0; Ec && Retries < 3; Retries++)
+ RemotePathToRemoteIndex.insert({RemoteContent.Paths[RemotePathIndex].generic_string(), RemotePathIndex});
+ }
+
+ uint64_t MatchCount = 0;
+ uint64_t PathMismatchCount = 0;
+ uint64_t HashMismatchCount = 0;
+ uint64_t CachedCount = 0;
+ uint64_t SkippedCount = 0;
+ uint64_t DeleteCount = 0;
+ for (uint32_t LocalPathIndex = 0; LocalPathIndex < LocalContent.Paths.size(); LocalPathIndex++)
+ {
+ const IoHash& RawHash = LocalContent.RawHashes[LocalPathIndex];
+ const std::filesystem::path& LocalPath = LocalContent.Paths[LocalPathIndex];
+
+ ZEN_ASSERT_SLOW(std::filesystem::is_regular_file(Path / LocalContent.Paths[LocalPathIndex]));
+
+ if (!WipeTargetFolder)
{
- Sleep(100);
- std::filesystem::rename(LocalFilePath, CacheFilePath, Ec);
+ if (auto RemotePathIt = RemotePathToRemoteIndex.find(LocalPath.generic_string());
+ RemotePathIt != RemotePathToRemoteIndex.end())
+ {
+ const uint32_t RemotePathIndex = RemotePathIt->second;
+ if (RemoteContent.RawHashes[RemotePathIndex] == RawHash)
+ {
+ // It is already in it's desired place
+ RemotePathIndexToLocalPathIndex[RemotePathIndex] = LocalPathIndex;
+ SequenceHashToLocalPathIndex.insert({RawHash, LocalPathIndex});
+ MatchCount++;
+ continue;
+ }
+ else
+ {
+ HashMismatchCount++;
+ }
+ }
+ else
+ {
+ PathMismatchCount++;
+ }
}
- if (Ec)
+ if (RemoteLookup.RawHashToSequenceIndex.contains(RawHash))
+ {
+ const std::filesystem::path CacheFilePath = GetFinalChunkedSequenceFileName(CacheFolderPath, RawHash);
+ if (!CachedRemoteSequences.contains(RawHash))
+ {
+ // We need it
+ ZEN_ASSERT_SLOW(!std::filesystem::exists(CacheFilePath));
+ const std::filesystem::path LocalFilePath = (Path / LocalPath).make_preferred();
+
+ std::error_code Ec;
+ std::filesystem::rename(LocalFilePath, CacheFilePath, Ec);
+ for (size_t Retries = 0; Ec && Retries < 3; Retries++)
+ {
+ Sleep(100);
+ std::filesystem::rename(LocalFilePath, CacheFilePath, Ec);
+ }
+ if (Ec)
+ {
+ zen::ThrowSystemError(Ec.value(), Ec.message());
+ }
+ CachedRemoteSequences.insert(RawHash);
+ CachedCount++;
+ }
+ else
+ {
+ // We already have it
+ ZEN_ASSERT_SLOW(std::filesystem::exists(CacheFilePath));
+ SkippedCount++;
+ }
+ }
+ else if (!WipeTargetFolder)
{
- zen::ThrowSystemError(Ec.value(), Ec.message());
+ // We don't need it
+ RemoveLocalPathIndexes.push_back(LocalPathIndex);
+ DeleteCount++;
}
- TotalFullFileSizeCached += std::filesystem::file_size(CacheFilePath);
}
- ZEN_CONSOLE("Saved {} ({}) unchanged files in cache",
- LocalPathIndexesMatchingSequenceIndexes.size(),
- NiceBytes(TotalFullFileSizeCached));
+
+ ZEN_DEBUG(
+ "Local state prep: MatchCount: {}, PathMismatchCount: {}, HashMismatchCount: {}, CachedCount: {}, SkippedCount: {}, "
+ "DeleteCount: {}",
+ MatchCount,
+ PathMismatchCount,
+ HashMismatchCount,
+ CachedCount,
+ SkippedCount,
+ DeleteCount);
}
if (WipeTargetFolder)
@@ -6374,34 +6492,17 @@ namespace {
Stopwatch Timer;
// Remove unused tracked files
- tsl::robin_map<std::string, uint32_t> RemotePathToRemoteIndex;
- RemotePathToRemoteIndex.reserve(RemoteContent.Paths.size());
- for (uint32_t RemotePathIndex = 0; RemotePathIndex < RemoteContent.Paths.size(); RemotePathIndex++)
- {
- RemotePathToRemoteIndex.insert({RemoteContent.Paths[RemotePathIndex].generic_string(), RemotePathIndex});
- }
- std::vector<std::filesystem::path> LocalFilesToRemove;
- for (uint32_t LocalPathIndex = 0; LocalPathIndex < LocalContent.Paths.size(); LocalPathIndex++)
+
+ if (!RemoveLocalPathIndexes.empty())
{
- if (!RemotePathToRemoteIndex.contains(LocalContent.Paths[LocalPathIndex].generic_string()))
+ ZEN_CONSOLE("Cleaning {} removed files from {}", RemoveLocalPathIndexes.size(), Path);
+ for (uint32_t LocalPathIndex : RemoveLocalPathIndexes)
{
const std::filesystem::path LocalFilePath = (Path / LocalContent.Paths[LocalPathIndex]).make_preferred();
- if (std::filesystem::exists(LocalFilePath))
- {
- LocalFilesToRemove.emplace_back(std::move(LocalFilePath));
- }
- }
- }
- if (!LocalFilesToRemove.empty())
- {
- ZEN_CONSOLE("Cleaning {} removed files from {}", LocalFilesToRemove.size(), Path);
- for (const std::filesystem::path& LocalFilePath : LocalFilesToRemove)
- {
SetFileReadOnly(LocalFilePath, false);
std::filesystem::remove(LocalFilePath);
}
}
- RebuildFolderStateStats.CleanFolderElapsedWallTimeUs = Timer.GetElapsedTimeUs();
}
{
@@ -6420,14 +6521,28 @@ namespace {
std::atomic<uint64_t> TargetsComplete = 0;
- std::vector<std::pair<IoHash, uint32_t>> Targets;
+ struct FinalizeTarget
+ {
+ IoHash RawHash;
+ uint32_t RemotePathIndex;
+ };
+
+ std::vector<FinalizeTarget> Targets;
Targets.reserve(RemoteContent.Paths.size());
for (uint32_t RemotePathIndex = 0; RemotePathIndex < RemoteContent.Paths.size(); RemotePathIndex++)
{
- Targets.push_back(std::make_pair(RemoteContent.RawHashes[RemotePathIndex], RemotePathIndex));
+ Targets.push_back(FinalizeTarget{.RawHash = RemoteContent.RawHashes[RemotePathIndex], .RemotePathIndex = RemotePathIndex});
}
- std::sort(Targets.begin(), Targets.end(), [](const std::pair<IoHash, uint32_t>& Lhs, const std::pair<IoHash, uint32_t>& Rhs) {
- return Lhs.first < Rhs.first;
+ std::sort(Targets.begin(), Targets.end(), [](const FinalizeTarget& Lhs, const FinalizeTarget& Rhs) {
+ if (Lhs.RawHash < Rhs.RawHash)
+ {
+ return true;
+ }
+ else if (Lhs.RawHash > Rhs.RawHash)
+ {
+ return false;
+ }
+ return Lhs.RemotePathIndex < Rhs.RemotePathIndex;
});
size_t TargetOffset = 0;
@@ -6438,9 +6553,8 @@ namespace {
break;
}
- size_t TargetCount = 1;
- const IoHash& RawHash = Targets[TargetOffset].first;
- while (Targets[TargetOffset + TargetCount].first == RawHash)
+ size_t TargetCount = 1;
+ while (Targets[TargetOffset + TargetCount].RawHash == Targets[TargetOffset].RawHash)
{
TargetCount++;
}
@@ -6452,93 +6566,157 @@ namespace {
{
ZEN_TRACE_CPU("FinalizeTree_Work");
- size_t TargetOffset = BaseTargetOffset;
- const IoHash& RawHash = Targets[TargetOffset].first;
- const uint32_t FirstTargetPathIndex = Targets[TargetOffset].second;
- const std::filesystem::path& FirstTargetPath = RemoteContent.Paths[FirstTargetPathIndex];
- OutLocalFolderState.Paths[FirstTargetPathIndex] = FirstTargetPath;
- OutLocalFolderState.RawSizes[FirstTargetPathIndex] = RemoteContent.RawSizes[FirstTargetPathIndex];
- const std::filesystem::path FirstTargetFilePath = (Path / FirstTargetPath).make_preferred();
+ size_t TargetOffset = BaseTargetOffset;
+ const IoHash& RawHash = Targets[TargetOffset].RawHash;
+
if (RawHash == IoHash::Zero)
{
- if (std::filesystem::exists(FirstTargetFilePath))
+ while (TargetOffset < (BaseTargetOffset + TargetCount))
{
- SetFileReadOnly(FirstTargetFilePath, false);
- }
- CreateDirectories(FirstTargetFilePath.parent_path());
- {
- BasicFile OutputFile;
- OutputFile.Open(FirstTargetFilePath, BasicFile::Mode::kTruncate);
+ const uint32_t RemotePathIndex = Targets[TargetOffset].RemotePathIndex;
+ ZEN_ASSERT(Targets[TargetOffset].RawHash == RawHash);
+ const std::filesystem::path& TargetPath = RemoteContent.Paths[RemotePathIndex];
+ std::filesystem::path TargetFilePath = (Path / TargetPath).make_preferred();
+ if (!RemotePathIndexToLocalPathIndex[RemotePathIndex])
+ {
+ if (std::filesystem::exists(TargetFilePath))
+ {
+ SetFileReadOnly(TargetFilePath, false);
+ }
+ else
+ {
+ CreateDirectories(TargetFilePath.parent_path());
+ }
+ BasicFile OutputFile;
+ OutputFile.Open(TargetFilePath, BasicFile::Mode::kTruncate);
+ }
+ OutLocalFolderState.Paths[RemotePathIndex] = TargetPath;
+ OutLocalFolderState.RawSizes[RemotePathIndex] = RemoteContent.RawSizes[RemotePathIndex];
+
+ OutLocalFolderState.Attributes[RemotePathIndex] =
+ RemoteContent.Attributes.empty()
+ ? GetNativeFileAttributes(TargetFilePath)
+ : SetNativeFileAttributes(TargetFilePath,
+ RemoteContent.Platform,
+ RemoteContent.Attributes[RemotePathIndex]);
+ OutLocalFolderState.ModificationTicks[RemotePathIndex] = GetModificationTickFromPath(TargetFilePath);
+
+ TargetOffset++;
+ TargetsComplete++;
}
}
else
{
- ZEN_TRACE_CPU("FinalizeTree_MoveIntoPlace");
+ ZEN_ASSERT(RemoteLookup.RawHashToSequenceIndex.contains(RawHash));
+ const uint32_t FirstRemotePathIndex = Targets[TargetOffset].RemotePathIndex;
+ const std::filesystem::path& FirstTargetPath = RemoteContent.Paths[FirstRemotePathIndex];
+ std::filesystem::path FirstTargetFilePath = (Path / FirstTargetPath).make_preferred();
- const std::filesystem::path CacheFilePath = GetFinalChunkedSequenceFileName(CacheFolderPath, RawHash);
- ZEN_ASSERT_SLOW(std::filesystem::exists(CacheFilePath));
- CreateDirectories(FirstTargetFilePath.parent_path());
- if (std::filesystem::exists(FirstTargetFilePath))
- {
- SetFileReadOnly(FirstTargetFilePath, false);
- }
- std::error_code Ec;
- std::filesystem::rename(CacheFilePath, FirstTargetFilePath, Ec);
- for (size_t Retries = 0; Ec && Retries < 3; Retries++)
+ if (auto InPlaceIt = RemotePathIndexToLocalPathIndex.find(FirstRemotePathIndex);
+ InPlaceIt != RemotePathIndexToLocalPathIndex.end())
{
- Sleep(100);
- std::filesystem::rename(CacheFilePath, FirstTargetFilePath, Ec);
+ ZEN_ASSERT_SLOW(std::filesystem::exists(FirstTargetFilePath));
}
- if (Ec)
+ else
{
- zen::ThrowSystemError(Ec.value(), Ec.message());
- }
- RebuildFolderStateStats.FinalizeTreeFilesMovedCount++;
- }
+ if (std::filesystem::exists(FirstTargetFilePath))
+ {
+ SetFileReadOnly(FirstTargetFilePath, false);
+ }
+ else
+ {
+ CreateDirectories(FirstTargetFilePath.parent_path());
+ }
- OutLocalFolderState.Attributes[FirstTargetPathIndex] =
- RemoteContent.Attributes.empty() ? GetNativeFileAttributes(FirstTargetFilePath)
- : SetNativeFileAttributes(FirstTargetFilePath,
- RemoteContent.Platform,
- RemoteContent.Attributes[FirstTargetPathIndex]);
- OutLocalFolderState.ModificationTicks[FirstTargetPathIndex] = GetModificationTickFromPath(FirstTargetFilePath);
+ if (auto InplaceIt = SequenceHashToLocalPathIndex.find(RawHash);
+ InplaceIt != SequenceHashToLocalPathIndex.end())
+ {
+ const uint32_t LocalPathIndex = InplaceIt->second;
+ const std::filesystem::path& SourcePath = LocalContent.Paths[LocalPathIndex];
+ std::filesystem::path SourceFilePath = (Path / SourcePath).make_preferred();
+ ZEN_ASSERT_SLOW(std::filesystem::exists(SourceFilePath));
- TargetOffset++;
- TargetsComplete++;
- while (TargetOffset < (BaseTargetOffset + TargetCount))
- {
- if (AbortFlag)
- {
- break;
- }
- ZEN_TRACE_CPU("FinalizeTree_Copy");
-
- ZEN_ASSERT(Targets[TargetOffset].first == RawHash);
- ZEN_ASSERT_SLOW(std::filesystem::exists(FirstTargetFilePath));
- const uint32_t ExtraTargetPathIndex = Targets[TargetOffset].second;
- const std::filesystem::path& ExtraTargetPath = RemoteContent.Paths[ExtraTargetPathIndex];
- const std::filesystem::path ExtraTargetFilePath = (Path / ExtraTargetPath).make_preferred();
- OutLocalFolderState.Paths[ExtraTargetPathIndex] = ExtraTargetPath;
- OutLocalFolderState.RawSizes[ExtraTargetPathIndex] = RemoteContent.RawSizes[ExtraTargetPathIndex];
- CreateDirectories(ExtraTargetFilePath.parent_path());
- if (std::filesystem::exists(ExtraTargetFilePath))
- {
- SetFileReadOnly(ExtraTargetFilePath, false);
+ CopyFile(SourceFilePath, FirstTargetFilePath, {.EnableClone = false});
+ RebuildFolderStateStats.FinalizeTreeFilesCopiedCount++;
+ }
+ else
+ {
+ const std::filesystem::path CacheFilePath =
+ GetFinalChunkedSequenceFileName(CacheFolderPath, RawHash);
+ ZEN_ASSERT_SLOW(std::filesystem::exists(CacheFilePath));
+
+ std::error_code Ec;
+ std::filesystem::rename(CacheFilePath, FirstTargetFilePath, Ec);
+ for (size_t Retries = 0; Ec && Retries < 3; Retries++)
+ {
+ Sleep(100);
+ std::filesystem::rename(CacheFilePath, FirstTargetFilePath, Ec);
+ }
+ if (Ec)
+ {
+ zen::ThrowSystemError(Ec.value(), Ec.message());
+ }
+ RebuildFolderStateStats.FinalizeTreeFilesMovedCount++;
+ }
}
- CopyFile(FirstTargetFilePath, ExtraTargetFilePath, {.EnableClone = false});
- RebuildFolderStateStats.FinalizeTreeFilesCopiedCount++;
- OutLocalFolderState.Attributes[ExtraTargetPathIndex] =
+ OutLocalFolderState.Paths[FirstRemotePathIndex] = FirstTargetPath;
+ OutLocalFolderState.RawSizes[FirstRemotePathIndex] = RemoteContent.RawSizes[FirstRemotePathIndex];
+
+ OutLocalFolderState.Attributes[FirstRemotePathIndex] =
RemoteContent.Attributes.empty()
- ? GetNativeFileAttributes(ExtraTargetFilePath)
- : SetNativeFileAttributes(ExtraTargetFilePath,
+ ? GetNativeFileAttributes(FirstTargetFilePath)
+ : SetNativeFileAttributes(FirstTargetFilePath,
RemoteContent.Platform,
- RemoteContent.Attributes[ExtraTargetPathIndex]);
- OutLocalFolderState.ModificationTicks[ExtraTargetPathIndex] =
- GetModificationTickFromPath(ExtraTargetFilePath);
+ RemoteContent.Attributes[FirstRemotePathIndex]);
+ OutLocalFolderState.ModificationTicks[FirstRemotePathIndex] =
+ GetModificationTickFromPath(FirstTargetFilePath);
TargetOffset++;
TargetsComplete++;
+
+ while (TargetOffset < (BaseTargetOffset + TargetCount))
+ {
+ const uint32_t RemotePathIndex = Targets[TargetOffset].RemotePathIndex;
+ ZEN_ASSERT(Targets[TargetOffset].RawHash == RawHash);
+ const std::filesystem::path& TargetPath = RemoteContent.Paths[RemotePathIndex];
+ std::filesystem::path TargetFilePath = (Path / TargetPath).make_preferred();
+
+ if (auto InPlaceIt = RemotePathIndexToLocalPathIndex.find(RemotePathIndex);
+ InPlaceIt != RemotePathIndexToLocalPathIndex.end())
+ {
+ ZEN_ASSERT_SLOW(std::filesystem::exists(TargetFilePath));
+ }
+ else
+ {
+ if (std::filesystem::exists(TargetFilePath))
+ {
+ SetFileReadOnly(TargetFilePath, false);
+ }
+ else
+ {
+ CreateDirectories(TargetFilePath.parent_path());
+ }
+
+ ZEN_ASSERT_SLOW(std::filesystem::exists(FirstTargetFilePath));
+ CopyFile(FirstTargetFilePath, TargetFilePath, {.EnableClone = false});
+ RebuildFolderStateStats.FinalizeTreeFilesCopiedCount++;
+ }
+
+ OutLocalFolderState.Paths[RemotePathIndex] = TargetPath;
+ OutLocalFolderState.RawSizes[RemotePathIndex] = RemoteContent.RawSizes[RemotePathIndex];
+
+ OutLocalFolderState.Attributes[RemotePathIndex] =
+ RemoteContent.Attributes.empty()
+ ? GetNativeFileAttributes(TargetFilePath)
+ : SetNativeFileAttributes(TargetFilePath,
+ RemoteContent.Platform,
+ RemoteContent.Attributes[RemotePathIndex]);
+ OutLocalFolderState.ModificationTicks[RemotePathIndex] = GetModificationTickFromPath(TargetFilePath);
+
+ TargetOffset++;
+ TargetsComplete++;
+ }
}
}
},
@@ -6980,66 +7158,111 @@ namespace {
ChunkedFolderContent GetLocalContent(GetFolderContentStatistics& LocalFolderScanStats,
ChunkingStatistics& ChunkingStats,
const std::filesystem::path& Path,
- ChunkingController& ChunkController)
+ const std::filesystem::path& ZenFolderPath,
+ ChunkingController& ChunkController,
+ const ChunkedFolderContent& ReferenceContent,
+ FolderContent& OutLocalFolderContent)
{
- ChunkedFolderContent LocalContent;
+ {
+ const uint32_t PathCount = gsl::narrow<uint32_t>(ReferenceContent.Paths.size());
+ OutLocalFolderContent.Paths.resize(PathCount);
+ OutLocalFolderContent.RawSizes.resize(PathCount);
+ OutLocalFolderContent.Attributes.resize(PathCount);
+ OutLocalFolderContent.ModificationTicks.resize(PathCount);
- auto IsAcceptedFolder = [ExcludeFolders = DefaultExcludeFolders](const std::string_view& RelativePath) -> bool {
- for (const std::string_view& ExcludeFolder : ExcludeFolders)
{
- if (RelativePath.starts_with(ExcludeFolder))
+ Stopwatch Timer;
+ auto _ =
+ MakeGuard([&LocalFolderScanStats, &Timer]() { LocalFolderScanStats.ElapsedWallTimeUS = Timer.GetElapsedTimeUs(); });
+
+ ProgressBar ProgressBar(UsePlainProgress);
+
+ ParallellWork Work(AbortFlag);
+ std::atomic<uint64_t> CompletedPathCount = 0;
+ uint32_t PathIndex = 0;
+
+ while (PathIndex < PathCount)
{
- if (RelativePath.length() == ExcludeFolder.length())
- {
- return false;
- }
- else if (RelativePath[ExcludeFolder.length()] == '/')
- {
- return false;
- }
+ uint32_t PathRangeCount = Min(1024u, PathCount - PathIndex);
+ Work.ScheduleWork(
+ GetIOWorkerPool(),
+ [PathIndex,
+ PathRangeCount,
+ &ReferenceContent,
+ &Path,
+ &OutLocalFolderContent,
+ &CompletedPathCount,
+ &LocalFolderScanStats](std::atomic<bool>&) {
+ for (uint32_t PathRangeIndex = PathIndex; PathRangeIndex < PathIndex + PathRangeCount; PathRangeIndex++)
+ {
+ const std::filesystem::path& FilePath = ReferenceContent.Paths[PathRangeIndex];
+ std::filesystem::path LocalFilePath = (Path / FilePath).make_preferred();
+ if (std::filesystem::exists(LocalFilePath))
+ {
+ const uint64_t FileSize = std::filesystem::file_size(LocalFilePath);
+ OutLocalFolderContent.Paths[PathRangeIndex] = FilePath;
+ OutLocalFolderContent.RawSizes[PathRangeIndex] = FileSize;
+ OutLocalFolderContent.Attributes[PathRangeIndex] = GetNativeFileAttributes(LocalFilePath);
+ OutLocalFolderContent.ModificationTicks[PathRangeIndex] = GetModificationTickFromPath(LocalFilePath);
+ LocalFolderScanStats.FoundFileCount++;
+ LocalFolderScanStats.FoundFileByteCount += FileSize;
+ LocalFolderScanStats.AcceptedFileCount++;
+ LocalFolderScanStats.AcceptedFileByteCount += FileSize;
+ }
+ CompletedPathCount++;
+ }
+ },
+ Work.DefaultErrorFunction());
+ PathIndex += PathRangeCount;
}
+ Work.Wait(200, [&](bool, ptrdiff_t) {
+ // FilteredBytesHashed.Update(ChunkingStats.BytesHashed.load());
+ std::string Details = fmt::format("{}/{} checked, {} found",
+ CompletedPathCount.load(),
+ PathCount,
+ LocalFolderScanStats.FoundFileCount.load());
+ ProgressBar.UpdateState({.Task = "Checking files ",
+ .Details = Details,
+ .TotalCount = PathCount,
+ .RemainingCount = PathCount - CompletedPathCount.load()},
+ false);
+ });
+ ProgressBar.Finish();
}
- return true;
- };
- auto IsAcceptedFile = [ExcludeExtensions =
- DefaultExcludeExtensions](const std::string_view& RelativePath, uint64_t, uint32_t) -> bool {
- for (const std::string_view& ExcludeExtension : ExcludeExtensions)
+ uint32_t WritePathIndex = 0;
+ for (uint32_t ReadPathIndex = 0; ReadPathIndex < PathCount; ReadPathIndex++)
{
- if (RelativePath.ends_with(ExcludeExtension))
+ if (!OutLocalFolderContent.Paths[ReadPathIndex].empty())
{
- return false;
+ if (WritePathIndex < ReadPathIndex)
+ {
+ OutLocalFolderContent.Paths[WritePathIndex] = std::move(OutLocalFolderContent.Paths[ReadPathIndex]);
+ OutLocalFolderContent.RawSizes[WritePathIndex] = OutLocalFolderContent.RawSizes[ReadPathIndex];
+ OutLocalFolderContent.Attributes[WritePathIndex] = OutLocalFolderContent.Attributes[ReadPathIndex];
+ OutLocalFolderContent.ModificationTicks[WritePathIndex] = OutLocalFolderContent.ModificationTicks[ReadPathIndex];
+ }
+ WritePathIndex++;
}
}
- return true;
- };
- FolderContent CurrentLocalFolderContent = GetFolderContent(
- LocalFolderScanStats,
- Path,
- std::move(IsAcceptedFolder),
- std::move(IsAcceptedFile),
- GetIOWorkerPool(),
- UsePlainProgress ? 5000 : 200,
- [&](bool, std::ptrdiff_t) {
- ZEN_CONSOLE_VERBOSE("Found {} files in '{}'...", LocalFolderScanStats.AcceptedFileCount.load(), Path);
- },
- AbortFlag);
- if (AbortFlag)
- {
- return {};
+ OutLocalFolderContent.Paths.resize(WritePathIndex);
+ OutLocalFolderContent.RawSizes.resize(WritePathIndex);
+ OutLocalFolderContent.Attributes.resize(WritePathIndex);
+ OutLocalFolderContent.ModificationTicks.resize(WritePathIndex);
}
- FolderContent LocalFolderState;
+ FolderContent LocalFolderState;
+ ChunkedFolderContent LocalContent;
bool ScanContent = true;
std::vector<uint32_t> PathIndexesOufOfDate;
- if (std::filesystem::is_regular_file(Path / ZenStateFilePath))
+ if (std::filesystem::is_regular_file(ZenStateFilePath(ZenFolderPath)))
{
try
{
Stopwatch ReadStateTimer;
- CbObject CurrentStateObject = LoadCompactBinaryObject(Path / ZenStateFilePath).Object;
+ CbObject CurrentStateObject = LoadCompactBinaryObject(ZenStateFilePath(ZenFolderPath)).Object;
if (CurrentStateObject)
{
Oid CurrentBuildId;
@@ -7066,11 +7289,11 @@ namespace {
std::span<const ChunkedFolderContent>(SavedPartContents).subspan(1));
}
- if (!LocalFolderState.AreKnownFilesEqual(CurrentLocalFolderContent))
+ if (!LocalFolderState.AreKnownFilesEqual(OutLocalFolderContent))
{
const size_t LocaStatePathCount = LocalFolderState.Paths.size();
std::vector<std::filesystem::path> DeletedPaths;
- FolderContent UpdatedContent = GetUpdatedContent(LocalFolderState, CurrentLocalFolderContent, DeletedPaths);
+ FolderContent UpdatedContent = GetUpdatedContent(LocalFolderState, OutLocalFolderContent, DeletedPaths);
if (!DeletedPaths.empty())
{
LocalContent = DeletePathsFromChunkedContent(LocalContent, DeletedPaths);
@@ -7160,27 +7383,27 @@ namespace {
if (ScanContent)
{
uint64_t ByteCountToScan = 0;
- for (const uint64_t RawSize : CurrentLocalFolderContent.RawSizes)
+ for (const uint64_t RawSize : OutLocalFolderContent.RawSizes)
{
ByteCountToScan += RawSize;
}
ProgressBar ProgressBar(false);
FilteredRate FilteredBytesHashed;
FilteredBytesHashed.Start();
- ChunkedFolderContent UpdatedLocalContent = ChunkFolderContent(
+ LocalContent = ChunkFolderContent(
ChunkingStats,
GetIOWorkerPool(),
Path,
- CurrentLocalFolderContent,
+ OutLocalFolderContent,
ChunkController,
UsePlainProgress ? 5000 : 200,
[&](bool, std::ptrdiff_t) {
FilteredBytesHashed.Update(ChunkingStats.BytesHashed.load());
std::string Details = fmt::format("{}/{} ({}/{}, {}B/s) scanned, {} ({}) chunks found",
ChunkingStats.FilesProcessed.load(),
- CurrentLocalFolderContent.Paths.size(),
+ OutLocalFolderContent.Paths.size(),
NiceBytes(ChunkingStats.BytesHashed.load()),
- ByteCountToScan,
+ NiceBytes(ByteCountToScan),
NiceNum(FilteredBytesHashed.GetCurrent()),
ChunkingStats.UniqueChunksFound.load(),
NiceBytes(ChunkingStats.UniqueBytesFound.load()));
@@ -7208,6 +7431,7 @@ namespace {
const std::vector<Oid>& BuildPartIds,
std::span<const std::string> BuildPartNames,
const std::filesystem::path& Path,
+ const std::filesystem::path& ZenFolderPath,
bool AllowMultiparts,
bool AllowPartialBlockRequests,
bool WipeTargetFolder,
@@ -7220,12 +7444,12 @@ namespace {
Stopwatch DownloadTimer;
- const std::filesystem::path ZenTempFolder = Path / ZenTempFolderName;
+ const std::filesystem::path ZenTempFolder = ZenTempFolderPath(ZenFolderPath);
CreateDirectories(ZenTempFolder);
- CreateDirectories(Path / ZenTempBlockFolderName);
- CreateDirectories(Path / ZenTempCacheFolderName);
- CreateDirectories(Path / ZenTempDownloadFolderName);
+ CreateDirectories(ZenTempBlockFolderPath(ZenFolderPath));
+ CreateDirectories(ZenTempCacheFolderPath(ZenFolderPath));
+ CreateDirectories(ZenTempDownloadFolderPath(ZenFolderPath));
std::uint64_t PreferredMultipartChunkSize = 32u * 1024u * 1024u;
@@ -7246,6 +7470,7 @@ namespace {
GetFolderContentStatistics LocalFolderScanStats;
ChunkingStatistics ChunkingStats;
ChunkedFolderContent LocalContent;
+ FolderContent LocalFolderContent;
if (!PrimeCacheOnly)
{
if (std::filesystem::is_directory(Path))
@@ -7258,7 +7483,13 @@ namespace {
ChunkController = CreateBasicChunkingController();
}
- LocalContent = GetLocalContent(LocalFolderScanStats, ChunkingStats, Path, *ChunkController);
+ LocalContent = GetLocalContent(LocalFolderScanStats,
+ ChunkingStats,
+ Path,
+ ZenFolderPath,
+ *ChunkController,
+ RemoteContent,
+ LocalFolderContent);
}
}
else
@@ -7317,6 +7548,12 @@ namespace {
{
ZEN_CONSOLE("Local state is identical to build to download. All done. Completed in {}.",
NiceTimeSpanMs(DownloadTimer.GetElapsedTimeMs()));
+
+ Stopwatch WriteStateTimer;
+ CbObject StateObject = CreateStateObject(BuildId, AllBuildParts, PartContents, LocalFolderContent);
+ CreateDirectories(ZenStateFilePath(ZenFolderPath).parent_path());
+ TemporaryFile::SafeWriteFile(ZenStateFilePath(ZenFolderPath), StateObject.GetView());
+ ZEN_CONSOLE("Wrote local state in {}", NiceTimeSpanMs(WriteStateTimer.GetElapsedTimeMs()));
}
else
{
@@ -7338,6 +7575,7 @@ namespace {
UpdateFolder(Storage,
BuildId,
Path,
+ ZenFolderPath,
LargeAttachmentSize,
PreferredMultipartChunkSize,
LocalContent,
@@ -7363,14 +7601,14 @@ namespace {
Stopwatch WriteStateTimer;
CbObject StateObject = CreateStateObject(BuildId, AllBuildParts, PartContents, LocalFolderState);
- CreateDirectories((Path / ZenStateFilePath).parent_path());
- TemporaryFile::SafeWriteFile(Path / ZenStateFilePath, StateObject.GetView());
+ CreateDirectories(ZenStateFilePath(ZenFolderPath).parent_path());
+ TemporaryFile::SafeWriteFile(ZenStateFilePath(ZenFolderPath), StateObject.GetView());
ZEN_CONSOLE("Wrote local state in {}", NiceTimeSpanMs(WriteStateTimer.GetElapsedTimeMs()));
#if 0
ExtendableStringBuilder<1024> SB;
CompactBinaryToJson(StateObject, SB);
- WriteFile(Path / ZenStateFileJsonPath, IoBuffer(IoBuffer::Wrap, SB.Data(), SB.Size()));
+ WriteFile(ZenStateFileJsonPath(ZenFolderPath), IoBuffer(IoBuffer::Wrap, SB.Data(), SB.Size()));
#endif // 0
}
const uint64_t DownloadCount = DownloadStats.DownloadedChunkCount.load() + DownloadStats.DownloadedBlockCount.load() +
@@ -7709,6 +7947,14 @@ BuildsCommand::BuildsCommand()
"<boostworkers>");
};
+ auto AddZenFolderOptions = [this](cxxopts::Options& Ops) {
+ Ops.add_option("",
+ "",
+ "zen-folder-path",
+ fmt::format("Path to zen state and temp folders. Defaults to [--local-path/]{}", ZenFolderName),
+ cxxopts::value(m_ZenFolderPath),
+ "<boostworkers>");
+ };
m_Options.add_option("",
"v",
"verb",
@@ -7722,6 +7968,7 @@ BuildsCommand::BuildsCommand()
AddCloudOptions(m_ListOptions);
AddFileOptions(m_ListOptions);
AddOutputOptions(m_ListOptions);
+ AddZenFolderOptions(m_ListOptions);
m_ListOptions.add_options()("h,help", "Print help");
m_ListOptions.add_option("",
"",
@@ -7744,6 +7991,7 @@ BuildsCommand::BuildsCommand()
AddOutputOptions(m_UploadOptions);
AddCacheOptions(m_UploadOptions);
AddWorkerOptions(m_UploadOptions);
+ AddZenFolderOptions(m_UploadOptions);
m_UploadOptions.add_options()("h,help", "Print help");
m_UploadOptions.add_option("", "l", "local-path", "Root file system folder for build", cxxopts::value(m_Path), "<local-path>");
m_UploadOptions.add_option("",
@@ -7808,7 +8056,8 @@ BuildsCommand::BuildsCommand()
AddFileOptions(m_DownloadOptions);
AddOutputOptions(m_DownloadOptions);
AddCacheOptions(m_DownloadOptions);
-
+ AddZenFolderOptions(m_DownloadOptions);
+ AddWorkerOptions(m_DownloadOptions);
m_DownloadOptions.add_option("cache",
"",
"cache-prime-only",
@@ -7816,7 +8065,6 @@ BuildsCommand::BuildsCommand()
cxxopts::value(m_PrimeCacheOnly),
"<cacheprimeonly>");
- AddWorkerOptions(m_DownloadOptions);
m_DownloadOptions.add_options()("h,help", "Print help");
m_DownloadOptions.add_option("", "l", "local-path", "Root file system folder for build", cxxopts::value(m_Path), "<local-path>");
m_DownloadOptions.add_option("", "", "build-id", "Build Id", cxxopts::value(m_BuildId), "<id>");
@@ -7848,6 +8096,7 @@ BuildsCommand::BuildsCommand()
"Allow request for partial chunk blocks. Defaults to true.",
cxxopts::value(m_AllowPartialBlockRequests),
"<allowpartialblockrequests>");
+
m_DownloadOptions
.add_option("", "", "verify", "Enable post download verify of all tracked files", cxxopts::value(m_PostDownloadVerify), "<verify>");
m_DownloadOptions.parse_positional({"local-path", "build-id", "build-part-name"});
@@ -7893,6 +8142,7 @@ BuildsCommand::BuildsCommand()
AddFileOptions(m_FetchBlobOptions);
AddOutputOptions(m_FetchBlobOptions);
AddCacheOptions(m_FetchBlobOptions);
+ AddZenFolderOptions(m_FetchBlobOptions);
m_FetchBlobOptions.add_option("", "", "build-id", "Build Id", cxxopts::value(m_BuildId), "<id>");
m_FetchBlobOptions
.add_option("", "", "blob-hash", "IoHash in hex form identifying the blob to download", cxxopts::value(m_BlobHash), "<blob-hash>");
@@ -7903,6 +8153,7 @@ BuildsCommand::BuildsCommand()
AddFileOptions(m_ValidateBuildPartOptions);
AddOutputOptions(m_ValidateBuildPartOptions);
AddWorkerOptions(m_ValidateBuildPartOptions);
+ AddZenFolderOptions(m_ValidateBuildPartOptions);
m_ValidateBuildPartOptions.add_option("", "", "build-id", "Build Id", cxxopts::value(m_BuildId), "<id>");
m_ValidateBuildPartOptions.add_option("",
"",
@@ -7989,10 +8240,8 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
auto CreateAuthMgr = [&]() {
if (!Auth)
{
- std::filesystem::path DataRoot = m_SystemRootDir.empty()
- ? PickDefaultSystemRootDirectory()
- : std::filesystem::absolute(StringToPath(m_SystemRootDir)).make_preferred();
-
+ std::filesystem::path DataRoot =
+ m_SystemRootDir.empty() ? PickDefaultSystemRootDirectory() : MakeSafeAbsolutePath(m_SystemRootDir);
if (m_EncryptionKey.empty())
{
m_EncryptionKey = "abcdefghijklmnopqrstuvxyz0123456";
@@ -8046,8 +8295,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
}
else if (!m_AccessTokenPath.empty())
{
- std::string ResolvedAccessToken =
- ReadAccessTokenFromFile(std::filesystem::absolute(StringToPath(m_AccessTokenPath)).make_preferred());
+ std::string ResolvedAccessToken = ReadAccessTokenFromFile(MakeSafeAbsolutePath(m_AccessTokenPath));
if (!ResolvedAccessToken.empty())
{
ClientSettings.AccessTokenProvider = httpclientauth::CreateFromStaticToken(ResolvedAccessToken);
@@ -8110,7 +8358,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
}
else if (!m_StoragePath.empty())
{
- std::filesystem::path StoragePath = std::filesystem::absolute(StringToPath(m_StoragePath)).make_preferred();
+ std::filesystem::path StoragePath = MakeSafeAbsolutePath(m_StoragePath);
StorageDescription = fmt::format("folder {}", StoragePath);
Result.BuildStorage = CreateFileBuildStorage(StoragePath, StorageStats, false, DefaultLatency, DefaultDelayPerKBSec);
Result.StorageName = fmt::format("Disk {}", StoragePath.stem());
@@ -8173,7 +8421,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
}
else
{
- std::filesystem::path ListQueryPath = std::filesystem::absolute(StringToPath(m_ListQueryPath)).make_preferred();
+ std::filesystem::path ListQueryPath = MakeSafeAbsolutePath(m_ListQueryPath);
if (ToLower(ListQueryPath.extension().string()) == ".cbo")
{
QueryObject = LoadCompactBinaryObject(IoBufferBuilder::MakeFromFile(ListQueryPath));
@@ -8195,7 +8443,18 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderName);
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? MakeSafeAbsolutePath(".") / ZenFolderName : MakeSafeAbsolutePath(m_ZenFolderPath);
+ CreateDirectories(ZenFolderPath);
+ auto _ = MakeGuard([ZenFolderPath]() {
+ if (CleanDirectory(ZenFolderPath, {}))
+ {
+ std::error_code DummyEc;
+ std::filesystem::remove(ZenFolderPath, DummyEc);
+ }
+ });
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
CbObject Response = Storage.BuildStorage->ListBuilds(QueryObject);
ZEN_ASSERT(ValidateCompactBinary(Response.GetView(), CbValidateMode::All) == CbValidateError::None);
@@ -8207,7 +8466,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
}
else
{
- std::filesystem::path ListResultPath = std::filesystem::absolute(StringToPath(m_ListResultPath)).make_preferred();
+ std::filesystem::path ListResultPath = MakeSafeAbsolutePath(m_ListResultPath);
if (ToLower(ListResultPath.extension().string()) == ".cbo")
{
MemoryView ResponseView = Response.GetView();
@@ -8256,7 +8515,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
}
}
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path));
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
if (m_BuildPartName.empty())
{
@@ -8297,14 +8556,25 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, Path / ZenTempFolderName);
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? MakeSafeAbsolutePath(".") / ZenFolderName : MakeSafeAbsolutePath(m_ZenFolderPath);
+ CreateDirectories(ZenFolderPath);
+ auto _ = MakeGuard([ZenFolderPath]() {
+ if (CleanDirectory(ZenFolderPath, {}))
+ {
+ std::error_code DummyEc;
+ std::filesystem::remove(ZenFolderPath, DummyEc);
+ }
+ });
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
CbObject MetaData;
if (m_CreateBuild)
{
if (!m_BuildMetadataPath.empty())
{
- std::filesystem::path MetadataPath = std::filesystem::absolute(StringToPath(m_BuildMetadataPath));
+ std::filesystem::path MetadataPath = MakeSafeAbsolutePath(m_BuildMetadataPath);
IoBuffer MetaDataJson = ReadFile(MetadataPath).Flatten();
std::string_view Json(reinterpret_cast<const char*>(MetaDataJson.GetData()), MetaDataJson.GetSize());
std::string JsonError;
@@ -8336,7 +8606,8 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
BuildPartId,
m_BuildPartName,
Path,
- std::filesystem::absolute(StringToPath(m_ManifestPath)).make_preferred(),
+ ZenFolderPath,
+ MakeSafeAbsolutePath(m_ManifestPath),
m_BlockReuseMinPercentLimit,
m_AllowMultiparts,
MetaData,
@@ -8415,18 +8686,22 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
}
}
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path)).make_preferred();
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, Path / ZenTempFolderName);
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? (Path / ZenFolderName).make_preferred() : MakeSafeAbsolutePath(m_ZenFolderPath);
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
DownloadFolder(Storage,
BuildId,
BuildPartIds,
m_BuildPartNames,
Path,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests && !m_PrimeCacheOnly,
m_Clean,
@@ -8466,8 +8741,8 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
throw zen::OptionParseException(fmt::format("compare-path is required\n{}", m_DownloadOptions.help()));
}
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path)).make_preferred();
- std::filesystem::path DiffPath = std::filesystem::absolute(StringToPath(m_DiffPath)).make_preferred();
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
+ std::filesystem::path DiffPath = MakeSafeAbsolutePath(m_DiffPath);
DiffFolders(Path, DiffPath, m_OnlyChunked);
return AbortFlag ? 11 : 0;
}
@@ -8489,12 +8764,15 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
// "07d3964f919d577a321a1fdd",
// "07d396a6ce875004e16b9528"};
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path)).make_preferred();
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, Path / ZenTempFolderName);
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? (Path / ZenFolderName).make_preferred() : MakeSafeAbsolutePath(m_ZenFolderPath);
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
Stopwatch Timer;
for (const std::string& BuildIdString : m_BuildIds)
@@ -8509,6 +8787,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{},
{},
Path,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
BuildIdString == m_BuildIds.front(),
@@ -8532,7 +8811,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
throw zen::OptionParseException(fmt::format("local-path is required\n{}", m_DownloadOptions.help()));
}
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path)).make_preferred();
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
m_BuildId = Oid::NewOid().ToString();
m_BuildPartName = Path.filename().string();
@@ -8542,7 +8821,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
const Oid BuildId = Oid::FromHexString(m_BuildId);
const Oid BuildPartId = Oid::FromHexString(m_BuildPartId);
- std::filesystem::path StoragePath = std::filesystem::absolute(StringToPath(m_StoragePath)).make_preferred();
+ std::filesystem::path StoragePath = MakeSafeAbsolutePath(m_StoragePath);
if (m_BuildsUrl.empty() && StoragePath.empty())
{
@@ -8561,7 +8840,11 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, Path / ZenTempFolderName);
+ const std::filesystem::path DownloadPath = Path.parent_path() / (m_BuildPartName + "_test");
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? (DownloadPath / ZenFolderName) : MakeSafeAbsolutePath(m_ZenFolderPath);
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
auto MakeMetaData = [](const Oid& BuildId) -> CbObject {
CbObjectWriter BuildMetaDataWriter;
@@ -8589,6 +8872,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
BuildPartId,
m_BuildPartName,
Path,
+ ZenFolderPath,
{},
m_BlockReuseMinPercentLimit,
m_AllowMultiparts,
@@ -8602,13 +8886,13 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
return 11;
}
- const std::filesystem::path DownloadPath = Path.parent_path() / (m_BuildPartName + "_download");
ZEN_CONSOLE("\nDownload Build {}, Part {} ({}) to '{}'", BuildId, BuildPartId, m_BuildPartName, DownloadPath);
DownloadFolder(Storage,
BuildId,
{BuildPartId},
{},
DownloadPath,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
true,
@@ -8630,6 +8914,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{BuildPartId},
{},
DownloadPath,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
false,
@@ -8743,6 +9028,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{BuildPartId},
{},
DownloadPath,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
false,
@@ -8771,6 +9057,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
BuildPartId2,
m_BuildPartName,
DownloadPath,
+ ZenFolderPath,
{},
m_BlockReuseMinPercentLimit,
m_AllowMultiparts,
@@ -8790,6 +9077,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{BuildPartId},
{},
DownloadPath,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
false,
@@ -8807,6 +9095,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{BuildPartId2},
{},
DownloadPath,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
false,
@@ -8824,6 +9113,7 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{BuildPartId2},
{},
DownloadPath,
+ ZenFolderPath,
m_AllowMultiparts,
m_AllowPartialBlockRequests,
false,
@@ -8853,12 +9143,23 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
const Oid BuildId = Oid::FromHexString(m_BuildId);
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path)).make_preferred();
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, Path / ZenTempFolderName);
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? MakeSafeAbsolutePath(".") / ZenFolderName : MakeSafeAbsolutePath(m_ZenFolderPath);
+ CreateDirectories(ZenFolderPath);
+ auto _ = MakeGuard([ZenFolderPath]() {
+ if (CleanDirectory(ZenFolderPath, {}))
+ {
+ std::error_code DummyEc;
+ std::filesystem::remove(ZenFolderPath, DummyEc);
+ }
+ });
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
uint64_t CompressedSize;
uint64_t DecompressedSize;
@@ -8898,12 +9199,23 @@ BuildsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
throw zen::OptionParseException(fmt::format("build-part-id conflicts with build-part-name\n{}", m_DownloadOptions.help()));
}
- std::filesystem::path Path = std::filesystem::absolute(StringToPath(m_Path)).make_preferred();
+ std::filesystem::path Path = MakeSafeAbsolutePath(m_Path);
BuildStorage::Statistics StorageStats;
BuildStorageCache::Statistics StorageCacheStats;
- StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, Path / ZenTempFolderName);
+ const std::filesystem::path ZenFolderPath =
+ m_ZenFolderPath.empty() ? MakeSafeAbsolutePath(".") / ZenFolderName : MakeSafeAbsolutePath(m_ZenFolderPath);
+ CreateDirectories(ZenFolderPath);
+ auto _ = MakeGuard([ZenFolderPath]() {
+ if (CleanDirectory(ZenFolderPath, {}))
+ {
+ std::error_code DummyEc;
+ std::filesystem::remove(ZenFolderPath, DummyEc);
+ }
+ });
+
+ StorageInstance Storage = CreateBuildStorage(StorageStats, StorageCacheStats, ZenTempFolderPath(ZenFolderPath));
Oid BuildPartId = Oid::TryFromHexString(m_BuildPartId);
diff --git a/src/zen/cmds/builds_cmd.h b/src/zen/cmds/builds_cmd.h
index 46257a567..4a77f8bd7 100644
--- a/src/zen/cmds/builds_cmd.h
+++ b/src/zen/cmds/builds_cmd.h
@@ -31,6 +31,8 @@ private:
bool m_Verbose = false;
bool m_BoostWorkerThreads = false;
+ std::string m_ZenFolderPath;
+
// cloud builds
std::string m_BuildsUrl;
bool m_AssumeHttp2 = false;
diff --git a/src/zenutil/chunkedcontent.cpp b/src/zenutil/chunkedcontent.cpp
index bb1ee5183..1e8447a57 100644
--- a/src/zenutil/chunkedcontent.cpp
+++ b/src/zenutil/chunkedcontent.cpp
@@ -304,14 +304,22 @@ FolderContent
GetUpdatedContent(const FolderContent& Old, const FolderContent& New, std::vector<std::filesystem::path>& OutDeletedPathIndexes)
{
ZEN_TRACE_CPU("FolderContent::GetUpdatedContent");
- FolderContent Result = {.Platform = Old.Platform};
+
+ const uint32_t NewPathCount = gsl::narrow<uint32_t>(New.Paths.size());
+
+ FolderContent Result = {.Platform = Old.Platform};
+ Result.Paths.reserve(NewPathCount);
+ Result.RawSizes.reserve(NewPathCount);
+ Result.Attributes.reserve(NewPathCount);
+ Result.ModificationTicks.reserve(NewPathCount);
+
tsl::robin_map<std::string, uint32_t> NewPathToIndex;
- const uint32_t NewPathCount = gsl::narrow<uint32_t>(New.Paths.size());
NewPathToIndex.reserve(NewPathCount);
for (uint32_t NewPathIndex = 0; NewPathIndex < NewPathCount; NewPathIndex++)
{
NewPathToIndex.insert({New.Paths[NewPathIndex].generic_string(), NewPathIndex});
}
+
uint32_t OldPathCount = gsl::narrow<uint32_t>(Old.Paths.size());
for (uint32_t OldPathIndex = 0; OldPathIndex < OldPathCount; OldPathIndex++)
{
@@ -667,6 +675,12 @@ DeletePathsFromChunkedContent(const ChunkedFolderContent& BaseContent, std::span
const ChunkedContentLookup BaseLookup = BuildChunkedContentLookup(BaseContent);
tsl::robin_map<IoHash, uint32_t, IoHash::Hasher> ChunkHashToChunkIndex;
+ const size_t ExpectedCount = BaseContent.Paths.size() - DeletedPaths.size();
+ Result.Paths.reserve(ExpectedCount);
+ Result.RawSizes.reserve(ExpectedCount);
+ Result.Attributes.reserve(ExpectedCount);
+ Result.RawHashes.reserve(ExpectedCount);
+
tsl::robin_map<IoHash, uint32_t, IoHash::Hasher> RawHashToSequenceRawHashIndex;
for (uint32_t PathIndex = 0; PathIndex < BaseContent.Paths.size(); PathIndex++)
{