From 4984e8cd5c38cf77c8cb978f75f808bce0577f2d Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Thu, 27 Nov 2025 16:05:56 +0100 Subject: automatic scrub on startup (#667) - Improvement: Deeper validation of data when scrub is activated (cas/cache/project) - Improvement: Enabled more multi threading when running scrub operations - Improvement: Added means to force a scrub operation at startup with a new release using ZEN_DATA_FORCE_SCRUB_VERSION variable in xmake.lua --- src/zenstore/scrubcontext.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'src/zenstore/scrubcontext.cpp') diff --git a/src/zenstore/scrubcontext.cpp b/src/zenstore/scrubcontext.cpp index fbcd7d33c..8f8ec09a7 100644 --- a/src/zenstore/scrubcontext.cpp +++ b/src/zenstore/scrubcontext.cpp @@ -2,6 +2,10 @@ #include "zenstore/scrubcontext.h" +#include +#include +#include +#include #include namespace zen { @@ -62,4 +66,64 @@ ScrubContext::ThrowIfDeadlineExpired() const throw ScrubDeadlineExpiredException(); } +bool +ValidateCompressedBuffer(const CompositeBuffer& Buffer, const IoHash* OptionalExpectedHash) +{ + IoHash HeaderRawHash; + uint64_t RawSize = 0; + uint64_t TotalCompressedSize = 0; + if (!CompressedBuffer::ValidateCompressedHeader(Buffer, HeaderRawHash, RawSize, &TotalCompressedSize)) + { + if (OptionalExpectedHash) + { + ZEN_SCOPED_WARN("compressed buffer header validation failed for chunk with hash {}", *OptionalExpectedHash); + } + else + { + ZEN_SCOPED_WARN("compressed buffer header validation failed"); + } + return false; + } + + if (OptionalExpectedHash != nullptr && HeaderRawHash != (*OptionalExpectedHash)) + { + ZEN_SCOPED_WARN("compressed buffer hash {} does not match expected hash {}", HeaderRawHash, *OptionalExpectedHash); + return false; + } + + if (TotalCompressedSize != Buffer.GetSize()) + { + ZEN_SCOPED_WARN("compressed buffer size does not match total compressed size in header for chunk {}", HeaderRawHash); + return false; + } + + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(Buffer, /* out */ HeaderRawHash, /* out */ RawSize); + + IoHashStream HashStream; + if (!Compressed.DecompressToStream( + 0, + RawSize, + [&HashStream](uint64_t SourceOffset, uint64_t SourceSize, uint64_t Offset, const CompositeBuffer& Range) -> bool { + ZEN_UNUSED(SourceOffset, SourceSize, Offset); + for (const SharedBuffer& Segment : Range.GetSegments()) + { + HashStream.Append(Segment); + } + return true; + })) + { + ZEN_SCOPED_WARN("compressed buffer could not be decompressed for chunk {}", HeaderRawHash); + return false; + } + + IoHash DecompressedHash = HashStream.GetHash(); + + if (HeaderRawHash != DecompressedHash) + { + ZEN_SCOPED_WARN("decompressed hash {} differs from header hash {}", DecompressedHash, HeaderRawHash); + return false; + } + return true; +} + } // namespace zen -- cgit v1.2.3