diff options
| author | Dan Engelbrecht <[email protected]> | 2022-12-07 11:21:41 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-12-07 02:21:41 -0800 |
| commit | 100c8f966b1c5b2fb190748f0177600562d1c5fe (patch) | |
| tree | fc85e350dea47330149a1d42eb7a6c7ae0a06111 | |
| parent | Cache request record/replay (#198) (diff) | |
| download | zen-100c8f966b1c5b2fb190748f0177600562d1c5fe.tar.xz zen-100c8f966b1c5b2fb190748f0177600562d1c5fe.zip | |
optimizations (#200)
* Use direct file read and direct buffer allocation for small IoBuffer materalization
* Reduce range of materialized data in CompositeBuffer reading
CompressedBuffer header reading often only need a small part and not the whole file
* reduce lock contention in IoBuffer::Materialize
* Reduce parsing of compressed headers
Validate header type at decompression
* faster CreateDirectories - start from leaf going up and recurse back
* optimized BufferHeader::IsValid
* Add ValidateCompressedHeader to use when we don't need the actual compressed data
Validate that we always get compressed data in CidStore::AddChunk
* changelog
27 files changed, 539 insertions, 350 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index cb083345c..18cbb84d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Feature: Disk size triggered GC, a soft disk usage limit for cache data. - Feature: New option `--gc-disk-size-soft-limit` (command line), `gc.cache.disksizesoftlimit` (lua config) controlling limit for soft disk usage limit. Defaults to zero which disables soft disk usage limit. - Improvement: Disk write pressure in GC log and cleaned up clutter in GC logging. +- Improvement: Much improved performance, between 2x to 9x improvement under heavy load (excluding http service overhead). See https://github.com/EpicGames/zen/pull/200 for details. - Bugfix: Always store records or oplog entries before storing attachments to avoid GC finding unreferenced chunks i CidStore - Changed: Reduced GC `INFO` spam by converting to `DEBUG` log messages - Changed: Use Iso8601 format for logging start and end message diff --git a/zen/cmds/exportproject.cpp b/zen/cmds/exportproject.cpp index 5d8c7d536..36d37bb60 100644 --- a/zen/cmds/exportproject.cpp +++ b/zen/cmds/exportproject.cpp @@ -22,23 +22,6 @@ ZEN_THIRD_PARTY_INCLUDES_START #include <gsl/gsl-lite.hpp> ZEN_THIRD_PARTY_INCLUDES_END -namespace { - -void -EnsureDirectoryExists(const std::filesystem::path& Path) -{ - while (!std::filesystem::is_directory(Path)) - { - if (Path.has_parent_path()) - { - EnsureDirectoryExists(Path.parent_path()); - } - std::filesystem::create_directory(Path); - } -} - -} // namespace - ExportProjectCommand::ExportProjectCommand() { m_Options.add_options()("h,help", "Print help"); @@ -147,7 +130,7 @@ ExportProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a return 1; } zen::IoBuffer CompressedPayload(zen::IoBuffer::Wrap, Response.text.data(), Response.text.size()); - zen::IoBuffer Payload = zen::CompressedBuffer::FromCompressed(zen::SharedBuffer(CompressedPayload)).Decompress().AsIoBuffer(); + zen::IoBuffer Payload = zen::CompressedBuffer::FromCompressedNoValidate(std::move(CompressedPayload)).Decompress().AsIoBuffer(); OplogResponses.emplace_back(zen::ParsePackageMessage(Payload)); zen::CbPackage& ResponsePackage = OplogResponses.back(); @@ -291,7 +274,7 @@ ExportProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a JobCount.fetch_add(1); WorkerPool.ScheduleWork([this, AttachmentBody, &Chunk, &JobCount]() { std::filesystem::path Path = GetLargeChunkPath(m_TargetPath, Chunk.ChunkHash); - EnsureDirectoryExists(Path.parent_path()); + zen::CreateDirectories(Path.parent_path()); zen::BasicFile ChunkFile; ChunkFile.Open(Path, zen::BasicFile::Mode::kTruncate); uint64_t Offset = 0; diff --git a/zen/cmds/print.cpp b/zen/cmds/print.cpp index a8b2215a2..abfb8eee9 100644 --- a/zen/cmds/print.cpp +++ b/zen/cmds/print.cpp @@ -79,12 +79,11 @@ PrintCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) IoBuffer Data = Fc.Flatten(); - if (CompressedBuffer Compressed{CompressedBuffer::FromCompressed(SharedBuffer(Data))}) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer::ValidateCompressedHeader(Data, RawHash, RawSize)) { - zen::ConsoleLog().info("Compressed binary: size {}, raw size {}, hash: {}", - Compressed.GetCompressedSize(), - Compressed.GetRawSize(), - IoHash::FromBLAKE3(Compressed.GetRawHash())); + zen::ConsoleLog().info("Compressed binary: size {}, raw size {}, hash: {}", Data.GetSize(), RawSize, RawHash); } else if (IsPackageMessage(Data)) { @@ -108,7 +107,7 @@ PrintCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) AttachmentType = "Compressed"; AttachmentSize = fmt::format("{} ({} uncompressed)", Attachment.AsCompressedBinary().GetCompressedSize(), - Attachment.AsCompressedBinary().GetRawSize()); + Attachment.AsCompressedBinary().DecodeRawSize()); } else if (Attachment.IsBinary()) { diff --git a/zencore/compactbinarypackage.cpp b/zencore/compactbinarypackage.cpp index 19675b9cf..a4fa38a1d 100644 --- a/zencore/compactbinarypackage.cpp +++ b/zencore/compactbinarypackage.cpp @@ -135,10 +135,12 @@ CbAttachment::TryLoad(CbFieldIterator& Fields) if (BinaryView.GetSize() > 0) { // Is a compressed binary blob + IoHash RawHash; + uint64_t RawSize; CompressedBuffer Compressed = - CompressedBuffer::FromCompressed(SharedBuffer::MakeView(BinaryView, Fields.GetOuterBuffer())).MakeOwned(); + CompressedBuffer::FromCompressed(SharedBuffer::MakeView(BinaryView, Fields.GetOuterBuffer()), RawHash, RawSize).MakeOwned(); Value.emplace<CompressedBuffer>(Compressed); - Hash = IoHash::FromBLAKE3(Compressed.GetRawHash()); + Hash = RawHash; ++Fields; } else @@ -191,8 +193,10 @@ TryLoad_ArchiveFieldIntoAttachment(CbAttachment& TargetAttachment, CbField&& Fie if (Buffer.GetSize() > 0) { // Is a compressed binary blob - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(std::move(Buffer)); - TargetAttachment = CbAttachment(Compressed, IoHash::FromBLAKE3(Compressed.GetRawHash())); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(std::move(Buffer), RawHash, RawSize); + TargetAttachment = CbAttachment(Compressed, RawHash); } else { @@ -715,9 +719,11 @@ namespace legacy { { return false; } - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(Buffer)) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(Buffer, RawHash, RawSize)) { - if (IoHash::FromBLAKE3(Compressed.GetRawHash()) != Hash) + if (RawHash != Hash) { return false; } @@ -747,8 +753,14 @@ namespace legacy { ZEN_ASSERT(Mapper); if (SharedBuffer AttachmentData = (*Mapper)(Hash)) { - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(AttachmentData)) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(AttachmentData, RawHash, RawSize)) { + if (RawHash != Hash) + { + return false; + } Package.AddAttachment(CbAttachment(Compressed, Hash)); } else diff --git a/zencore/compactbinaryvalidation.cpp b/zencore/compactbinaryvalidation.cpp index a787e88ab..02148d96a 100644 --- a/zencore/compactbinaryvalidation.cpp +++ b/zencore/compactbinaryvalidation.cpp @@ -463,17 +463,18 @@ ValidateCbPackageAttachment(CbFieldView& Value, MemoryView& View, CbValidateMode { if (BinaryView.GetSize() > 0) { - CompressedBuffer Buffer = CompressedBuffer::FromCompressed(SharedBuffer::MakeView(BinaryView)); + IoHash DecodedHash; + uint64_t DecodedRawSize; + CompressedBuffer Buffer = CompressedBuffer::FromCompressed(SharedBuffer::MakeView(BinaryView), DecodedHash, DecodedRawSize); if (EnumHasAnyFlags(Mode, CbValidateMode::Package) && Buffer.IsNull()) { AddError(Error, CbValidateError::NullPackageAttachment); } - if (EnumHasAnyFlags(Mode, CbValidateMode::PackageHash) && - (IoHash::FromBLAKE3(Buffer.GetRawHash()) != IoHash::HashBuffer(Buffer.DecompressToComposite()))) + if (EnumHasAnyFlags(Mode, CbValidateMode::PackageHash) && (DecodedHash != IoHash::HashBuffer(Buffer.DecompressToComposite()))) { AddError(Error, CbValidateError::InvalidPackageHash); } - return IoHash::FromBLAKE3(Buffer.GetRawHash()); + return DecodedHash; } else { diff --git a/zencore/compositebuffer.cpp b/zencore/compositebuffer.cpp index e4ca93cc2..735020451 100644 --- a/zencore/compositebuffer.cpp +++ b/zencore/compositebuffer.cpp @@ -145,6 +145,12 @@ CompositeBuffer::GetIterator(uint64_t Offset) const MemoryView CompositeBuffer::ViewOrCopyRange(Iterator& It, uint64_t Size, UniqueBuffer& CopyBuffer) const { + // We use a sub range IoBuffer when we want to copy data from a segment. + // This means we will only materialize that range of the segment when doing + // GetView() rather than the full segment. + // A hot path for this code is when we call CompressedBuffer::FromCompressed which + // is only interested in reading the header (first 64 bytes or so) and then throws + // away the materialized data. MutableMemoryView WriteView; size_t SegmentCount = m_Segments.size(); ZEN_ASSERT(It.SegmentIndex < SegmentCount); @@ -155,9 +161,8 @@ CompositeBuffer::ViewOrCopyRange(Iterator& It, uint64_t Size, UniqueBuffer& Copy size_t SegmentSize = Segment.GetSize(); if (Size == SizeLeft && Size <= (SegmentSize - It.OffsetInSegment)) { - MemoryView View = Segment.GetView(); - View.RightChopInline(It.OffsetInSegment); - View.LeftInline(SizeLeft); + IoBuffer SubSegment(Segment.AsIoBuffer(), It.OffsetInSegment, SizeLeft); + MemoryView View = SubSegment.GetView(); It.OffsetInSegment += SizeLeft; ZEN_ASSERT_SLOW(It.OffsetInSegment <= SegmentSize); if (It.OffsetInSegment == SegmentSize) @@ -176,10 +181,9 @@ CompositeBuffer::ViewOrCopyRange(Iterator& It, uint64_t Size, UniqueBuffer& Copy WriteView = CopyBuffer.GetMutableView(); } size_t CopySize = zen::Min(SegmentSize - It.OffsetInSegment, SizeLeft); - MemoryView ReadView = Segment.GetView(); - ReadView.RightChopInline(It.OffsetInSegment); - ReadView.LeftInline(CopySize); - WriteView = WriteView.CopyFrom(ReadView); + IoBuffer SubSegment(Segment.AsIoBuffer(), It.OffsetInSegment, CopySize); + MemoryView ReadView = SubSegment.GetView(); + WriteView = WriteView.CopyFrom(ReadView); It.OffsetInSegment += CopySize; ZEN_ASSERT_SLOW(It.OffsetInSegment <= SegmentSize); if (It.OffsetInSegment == SegmentSize) @@ -195,6 +199,13 @@ CompositeBuffer::ViewOrCopyRange(Iterator& It, uint64_t Size, UniqueBuffer& Copy void CompositeBuffer::CopyTo(MutableMemoryView WriteView, Iterator& It) const { + // We use a sub range IoBuffer when we want to copy data from a segment. + // This means we will only materialize that range of the segment when doing + // GetView() rather than the full segment. + // A hot path for this code is when we call CompressedBuffer::FromCompressed which + // is only interested in reading the header (first 64 bytes or so) and then throws + // away the materialized data. + size_t SizeLeft = WriteView.GetSize(); size_t SegmentCount = m_Segments.size(); ZEN_ASSERT(It.SegmentIndex < SegmentCount); @@ -203,10 +214,9 @@ CompositeBuffer::CopyTo(MutableMemoryView WriteView, Iterator& It) const const SharedBuffer& Segment = m_Segments[It.SegmentIndex]; size_t SegmentSize = Segment.GetSize(); size_t CopySize = zen::Min(SegmentSize - It.OffsetInSegment, SizeLeft); - MemoryView ReadView = Segment.GetView(); - ReadView.RightChopInline(It.OffsetInSegment); - ReadView.LeftInline(CopySize); - WriteView = WriteView.CopyFrom(ReadView); + IoBuffer SubSegment(Segment.AsIoBuffer(), It.OffsetInSegment, CopySize); + MemoryView ReadView = SubSegment.GetView(); + WriteView = WriteView.CopyFrom(ReadView); It.OffsetInSegment += CopySize; ZEN_ASSERT_SLOW(It.OffsetInSegment <= SegmentSize); if (It.OffsetInSegment == SegmentSize) diff --git a/zencore/compress.cpp b/zencore/compress.cpp index 15cc5f6a7..6e06739ea 100644 --- a/zencore/compress.cpp +++ b/zencore/compress.cpp @@ -6,6 +6,7 @@ #include <zencore/compositebuffer.h> #include <zencore/crc32.h> #include <zencore/endian.h> +#include <zencore/iohash.h> #include <zencore/testing.h> #include "../thirdparty/Oodle/include/oodle2.h" @@ -56,8 +57,11 @@ struct BufferHeader BLAKE3 RawHash; // The hash of the uncompressed data /** Checks validity of the buffer based on the magic number, method, and CRC-32. */ - static bool IsValid(const CompositeBuffer& CompressedData); - static bool IsValid(const SharedBuffer& CompressedData) { return IsValid(CompositeBuffer(CompressedData)); } + static bool IsValid(const CompositeBuffer& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize); + static bool IsValid(const SharedBuffer& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) + { + return IsValid(CompositeBuffer(CompressedData), OutRawHash, OutRawSize); + } /** Read a header from a buffer that is at least sizeof(BufferHeader) without any validation. */ static BufferHeader Read(const CompositeBuffer& CompressedData) @@ -65,6 +69,10 @@ struct BufferHeader BufferHeader Header; if (sizeof(BufferHeader) <= CompressedData.GetSize()) { + // if (CompressedData.GetSegments()[0].AsIoBuffer().IsWholeFile()) + // { + // ZEN_ASSERT(true); + // } CompositeBuffer::Iterator It; CompressedData.CopyTo(MakeMutableMemoryView(&Header, &Header + 1), It); Header.ByteSwap(); @@ -664,36 +672,68 @@ GetDecoder(CompressionMethod Method) ////////////////////////////////////////////////////////////////////////// bool -BufferHeader::IsValid(const CompositeBuffer& CompressedData) +BufferHeader::IsValid(const CompositeBuffer& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) { - if (sizeof(BufferHeader) <= CompressedData.GetSize()) + uint64_t Size = CompressedData.GetSize(); + if (Size < sizeof(BufferHeader)) { - const BufferHeader Header = Read(CompressedData); - if (Header.Magic == BufferHeader::ExpectedMagic) + return false; + } + const size_t StackBufferSize = 256; + uint8_t StackBuffer[StackBufferSize]; + uint64_t ReadSize = Min(Size, StackBufferSize); + BufferHeader* Header = reinterpret_cast<BufferHeader*>(StackBuffer); + { + CompositeBuffer::Iterator It; + CompressedData.CopyTo(MutableMemoryView(StackBuffer, StackBuffer + StackBufferSize), It); + } + Header->ByteSwap(); + if (Header->Magic != BufferHeader::ExpectedMagic) + { + return false; + } + const BaseDecoder* const Decoder = GetDecoder(Header->Method); + if (!Decoder) + { + return false; + } + uint32_t Crc32 = Header->Crc32; + OutRawHash = IoHash::FromBLAKE3(Header->RawHash); + OutRawSize = Header->TotalRawSize; + uint64_t HeaderSize = Decoder->GetHeaderSize(*Header); + Header->ByteSwap(); + + if (HeaderSize > ReadSize) + { + // 0.004% of cases on a Fortnite hot cache cook + UniqueBuffer HeaderCopy = UniqueBuffer::Alloc(HeaderSize); + CompositeBuffer::Iterator It; + CompressedData.CopyTo(HeaderCopy.GetMutableView(), It); + const MemoryView HeaderView = HeaderCopy.GetView(); + if (Crc32 != BufferHeader::CalculateCrc32(HeaderView)) { - if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) - { - UniqueBuffer HeaderCopy = UniqueBuffer::Alloc(Decoder->GetHeaderSize(Header)); - CompositeBuffer::Iterator It; - CompressedData.CopyTo(HeaderCopy.GetMutableView(), It); - const MemoryView HeaderView = HeaderCopy.GetView(); - if (Header.Crc32 == BufferHeader::CalculateCrc32(HeaderView)) - { - return true; - } - } + return false; } } - return false; + else + { + MemoryView FullHeaderView(StackBuffer, StackBuffer + HeaderSize); + if (Crc32 != BufferHeader::CalculateCrc32(FullHeaderView)) + { + return false; + } + } + return true; } ////////////////////////////////////////////////////////////////////////// template<typename BufferType> inline CompositeBuffer -ValidBufferOrEmpty(BufferType&& CompressedData) +ValidBufferOrEmpty(BufferType&& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) { - return BufferHeader::IsValid(CompressedData) ? CompositeBuffer(std::forward<BufferType>(CompressedData)) : CompositeBuffer(); + return BufferHeader::IsValid(CompressedData, OutRawHash, OutRawSize) ? CompositeBuffer(std::forward<BufferType>(CompressedData)) + : CompositeBuffer(); } CompositeBuffer @@ -826,34 +866,34 @@ CompressedBuffer::Compress(const SharedBuffer& RawData, } CompressedBuffer -CompressedBuffer::FromCompressed(const CompositeBuffer& InCompressedData) +CompressedBuffer::FromCompressed(const CompositeBuffer& InCompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) { CompressedBuffer Local; - Local.CompressedData = detail::ValidBufferOrEmpty(InCompressedData); + Local.CompressedData = detail::ValidBufferOrEmpty(InCompressedData, OutRawHash, OutRawSize); return Local; } CompressedBuffer -CompressedBuffer::FromCompressed(CompositeBuffer&& InCompressedData) +CompressedBuffer::FromCompressed(CompositeBuffer&& InCompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) { CompressedBuffer Local; - Local.CompressedData = detail::ValidBufferOrEmpty(std::move(InCompressedData)); + Local.CompressedData = detail::ValidBufferOrEmpty(std::move(InCompressedData), OutRawHash, OutRawSize); return Local; } CompressedBuffer -CompressedBuffer::FromCompressed(const SharedBuffer& InCompressedData) +CompressedBuffer::FromCompressed(const SharedBuffer& InCompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) { CompressedBuffer Local; - Local.CompressedData = detail::ValidBufferOrEmpty(InCompressedData); + Local.CompressedData = detail::ValidBufferOrEmpty(InCompressedData, OutRawHash, OutRawSize); return Local; } CompressedBuffer -CompressedBuffer::FromCompressed(SharedBuffer&& InCompressedData) +CompressedBuffer::FromCompressed(SharedBuffer&& InCompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) { CompressedBuffer Local; - Local.CompressedData = detail::ValidBufferOrEmpty(std::move(InCompressedData)); + Local.CompressedData = detail::ValidBufferOrEmpty(std::move(InCompressedData), OutRawHash, OutRawSize); return Local; } @@ -881,14 +921,26 @@ CompressedBuffer::FromCompressedNoValidate(CompositeBuffer&& InCompressedData) return Local; } +bool +CompressedBuffer::ValidateCompressedHeader(IoBuffer&& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) +{ + return detail::BufferHeader::IsValid(SharedBuffer(std::move(CompressedData)), OutRawHash, OutRawSize); +} + +bool +CompressedBuffer::ValidateCompressedHeader(const IoBuffer& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize) +{ + return detail::BufferHeader::IsValid(SharedBuffer(CompressedData), OutRawHash, OutRawSize); +} + uint64_t -CompressedBuffer::GetRawSize() const +CompressedBuffer::DecodeRawSize() const { return CompressedData ? detail::BufferHeader::Read(CompressedData).TotalRawSize : 0; } BLAKE3 -CompressedBuffer::GetRawHash() const +CompressedBuffer::DecodeRawHash() const { return CompressedData ? detail::BufferHeader::Read(CompressedData).RawHash : BLAKE3(); } @@ -913,9 +965,12 @@ CompressedBuffer::TryDecompressTo(MutableMemoryView RawView, uint64_t RawOffset) if (CompressedData) { const BufferHeader Header = BufferHeader::Read(CompressedData); - if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) + if (Header.Magic == BufferHeader::ExpectedMagic) { - return Decoder->TryDecompressTo(Header, CompressedData, RawView, RawOffset); + if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) + { + return Decoder->TryDecompressTo(Header, CompressedData, RawView, RawOffset); + } } } return false; @@ -928,13 +983,16 @@ CompressedBuffer::Decompress(uint64_t RawOffset, uint64_t RawSize) const if (CompressedData && RawSize > 0) { const BufferHeader Header = BufferHeader::Read(CompressedData); - if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) + if (Header.Magic == BufferHeader::ExpectedMagic) { - const uint64_t TotalRawSize = RawSize < ~uint64_t(0) ? RawSize : Header.TotalRawSize - RawOffset; - UniqueBuffer RawData = UniqueBuffer::Alloc(TotalRawSize); - if (Decoder->TryDecompressTo(Header, CompressedData, RawData, RawOffset)) + if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) { - return RawData.MoveToShared(); + const uint64_t TotalRawSize = RawSize < ~uint64_t(0) ? RawSize : Header.TotalRawSize - RawOffset; + UniqueBuffer RawData = UniqueBuffer::Alloc(TotalRawSize); + if (Decoder->TryDecompressTo(Header, CompressedData, RawData, RawOffset)) + { + return RawData.MoveToShared(); + } } } } @@ -948,9 +1006,12 @@ CompressedBuffer::DecompressToComposite() const if (CompressedData) { const BufferHeader Header = BufferHeader::Read(CompressedData); - if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) + if (Header.Magic == BufferHeader::ExpectedMagic) { - return Decoder->Decompress(Header, CompressedData); + if (const BaseDecoder* const Decoder = GetDecoder(Header.Method)) + { + return Decoder->Decompress(Header, CompressedData); + } } } return CompositeBuffer(); @@ -1005,18 +1066,20 @@ TEST_CASE("CompressedBuffer") OodleCompressor::NotSet, OodleCompressionLevel::None); - CHECK(Buffer.GetRawSize() == sizeof(Zeroes)); + CHECK(Buffer.DecodeRawSize() == sizeof(Zeroes)); CHECK(Buffer.GetCompressedSize() == (sizeof(Zeroes) + sizeof(detail::BufferHeader))); CompositeBuffer Compressed = Buffer.GetCompressed(); - CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed); + IoHash DecodedHash; + uint64_t DecodedRawSize; + CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed, DecodedHash, DecodedRawSize); CHECK(BufferD.IsNull() == false); CompositeBuffer Decomp = BufferD.DecompressToComposite(); - CHECK(Decomp.GetSize() == Buffer.GetRawSize()); - CHECK(BLAKE3::HashBuffer(Decomp) == BufferD.GetRawHash()); + CHECK(Decomp.GetSize() == DecodedRawSize); + CHECK(IoHash::HashBuffer(Decomp) == DecodedHash); } { @@ -1025,53 +1088,59 @@ TEST_CASE("CompressedBuffer") OodleCompressor::NotSet, OodleCompressionLevel::None); - CHECK(Buffer.GetRawSize() == (sizeof(Zeroes) + sizeof(Ones))); + CHECK(Buffer.DecodeRawSize() == (sizeof(Zeroes) + sizeof(Ones))); CHECK(Buffer.GetCompressedSize() == (sizeof(Zeroes) + sizeof(Ones) + sizeof(detail::BufferHeader))); CompositeBuffer Compressed = Buffer.GetCompressed(); - CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed); + IoHash DecodedHash; + uint64_t DecodedRawSize; + CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed, DecodedHash, DecodedRawSize); CHECK(BufferD.IsNull() == false); CompositeBuffer Decomp = BufferD.DecompressToComposite(); - CHECK(Decomp.GetSize() == Buffer.GetRawSize()); - CHECK(BLAKE3::HashBuffer(Decomp) == BufferD.GetRawHash()); + CHECK(Decomp.GetSize() == DecodedRawSize); + CHECK(IoHash::HashBuffer(Decomp) == DecodedHash); } { CompressedBuffer Buffer = CompressedBuffer::Compress(CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes)))); - CHECK(Buffer.GetRawSize() == sizeof(Zeroes)); + CHECK(Buffer.DecodeRawSize() == sizeof(Zeroes)); CHECK(Buffer.GetCompressedSize() < sizeof(Zeroes)); CompositeBuffer Compressed = Buffer.GetCompressed(); - CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed); + IoHash DecodedHash; + uint64_t DecodedRawSize; + CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed, DecodedHash, DecodedRawSize); CHECK(BufferD.IsNull() == false); CompositeBuffer Decomp = BufferD.DecompressToComposite(); - CHECK(Decomp.GetSize() == Buffer.GetRawSize()); - CHECK(BLAKE3::HashBuffer(Decomp) == BufferD.GetRawHash()); + CHECK(Decomp.GetSize() == DecodedRawSize); + CHECK(IoHash::HashBuffer(Decomp) == DecodedHash); } { CompressedBuffer Buffer = CompressedBuffer::Compress( CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes)), SharedBuffer::MakeView(MakeMemoryView(Ones)))); - CHECK(Buffer.GetRawSize() == (sizeof(Zeroes) + sizeof(Ones))); + CHECK(Buffer.DecodeRawSize() == (sizeof(Zeroes) + sizeof(Ones))); CHECK(Buffer.GetCompressedSize() < (sizeof(Zeroes) + sizeof(Ones))); CompositeBuffer Compressed = Buffer.GetCompressed(); - CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed); + IoHash DecodedHash; + uint64_t DecodedRawSize; + CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed, DecodedHash, DecodedRawSize); CHECK(BufferD.IsNull() == false); CompositeBuffer Decomp = BufferD.DecompressToComposite(); - CHECK(Decomp.GetSize() == Buffer.GetRawSize()); - CHECK(BLAKE3::HashBuffer(Decomp) == BufferD.GetRawHash()); + CHECK(Decomp.GetSize() == DecodedRawSize); + CHECK(IoHash::HashBuffer(Decomp) == DecodedHash); } auto GenerateData = [](uint64_t N) -> std::vector<uint64_t> { diff --git a/zencore/filesystem.cpp b/zencore/filesystem.cpp index 0aa478404..1e4a52638 100644 --- a/zencore/filesystem.cpp +++ b/zencore/filesystem.cpp @@ -188,13 +188,21 @@ CleanDirectory(const wchar_t* DirPath) bool CreateDirectories(const std::filesystem::path& Dir) { - std::error_code ErrorCode; - bool WasCreated = std::filesystem::create_directories(Dir, ErrorCode); - if (ErrorCode) + while (!std::filesystem::is_directory(Dir)) { - throw std::system_error(ErrorCode, fmt::format("Failed to create directories for '{}'", Dir.string())); + if (Dir.has_parent_path()) + { + CreateDirectories(Dir.parent_path()); + } + std::error_code ErrorCode; + std::filesystem::create_directory(Dir, ErrorCode); + if (ErrorCode) + { + throw std::system_error(ErrorCode, fmt::format("Failed to create directories for '{}'", Dir.string())); + } + return true; } - return WasCreated; + return false; } bool diff --git a/zencore/include/zencore/compress.h b/zencore/include/zencore/compress.h index 92dc1fb76..5bf6d3001 100644 --- a/zencore/include/zencore/compress.h +++ b/zencore/include/zencore/compress.h @@ -71,12 +71,24 @@ public: * * @return A compressed buffer, or null on error, such as an invalid format or corrupt header. */ - [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(const CompositeBuffer& CompressedData); - [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(CompositeBuffer&& CompressedData); - [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(const SharedBuffer& CompressedData); - [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(SharedBuffer&& CompressedData); + [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(const CompositeBuffer& CompressedData, + IoHash& OutRawHash, + uint64_t& OutRawSize); + [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(CompositeBuffer&& CompressedData, + IoHash& OutRawHash, + uint64_t& OutRawSize); + [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(const SharedBuffer& CompressedData, + IoHash& OutRawHash, + uint64_t& OutRawSize); + [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressed(SharedBuffer&& CompressedData, + IoHash& OutRawHash, + uint64_t& OutRawSize); [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressedNoValidate(IoBuffer&& CompressedData); [[nodiscard]] ZENCORE_API static CompressedBuffer FromCompressedNoValidate(CompositeBuffer&& CompressedData); + [[nodiscard]] ZENCORE_API static bool ValidateCompressedHeader(IoBuffer&& CompressedData, IoHash& OutRawHash, uint64_t& OutRawSize); + [[nodiscard]] ZENCORE_API static bool ValidateCompressedHeader(const IoBuffer& CompressedData, + IoHash& OutRawHash, + uint64_t& OutRawSize); /** Reset this to null. */ inline void Reset() { CompressedData.Reset(); } @@ -102,10 +114,10 @@ public: [[nodiscard]] inline uint64_t GetCompressedSize() const { return CompressedData.GetSize(); } /** Returns the size of the raw data. Zero on error or if this is empty or null. */ - [[nodiscard]] ZENCORE_API uint64_t GetRawSize() const; + [[nodiscard]] ZENCORE_API uint64_t DecodeRawSize() const; /** Returns the hash of the raw data. Zero on error or if this is null. */ - [[nodiscard]] ZENCORE_API BLAKE3 GetRawHash() const; + [[nodiscard]] ZENCORE_API BLAKE3 DecodeRawHash() const; [[nodiscard]] ZENCORE_API CompressedBuffer CopyRange(uint64_t RawOffset, uint64_t RawSize = ~uint64_t(0)) const; diff --git a/zencore/include/zencore/iobuffer.h b/zencore/include/zencore/iobuffer.h index 7f107cc0f..a39dbf6d6 100644 --- a/zencore/include/zencore/iobuffer.h +++ b/zencore/include/zencore/iobuffer.h @@ -254,7 +254,7 @@ protected: kContentTypeBit3 = 1 << (24 + 3), // bits are reserved }; - void AllocateBuffer(size_t InSize, size_t Alignment); + void AllocateBuffer(size_t InSize, size_t Alignment) const; void FreeBuffer(); }; diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp index 16dd22a58..2522daf35 100644 --- a/zencore/iobuffer.cpp +++ b/zencore/iobuffer.cpp @@ -34,7 +34,7 @@ namespace zen { ////////////////////////////////////////////////////////////////////////// void -IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) +IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) const { #if ZEN_PLATFORM_WINDOWS if (((InSize & 0xffFF) == 0) && (Alignment == 0x10000)) @@ -238,7 +238,7 @@ IoBufferExtendedCore::~IoBufferExtendedCore() m_DataPtr = nullptr; } -static constexpr size_t MappingLockCount = 64; +static constexpr size_t MappingLockCount = 128; static_assert(IsPow2(MappingLockCount), "MappingLockCount must be power of two"); static RwLock g_MappingLocks[MappingLockCount]; @@ -247,7 +247,7 @@ static RwLock& MappingLockForInstance(const IoBufferExtendedCore* instance) { intptr_t base = (intptr_t)instance; - size_t lock_index = ((base >> 8) ^ (base >> 16)) & (MappingLockCount - 1u); + size_t lock_index = ((base >> 5) ^ (base >> 13)) & (MappingLockCount - 1u); return g_MappingLocks[lock_index]; } @@ -271,9 +271,38 @@ IoBufferExtendedCore::Materialize() const if (m_DataBytes == 0) { - m_Flags.fetch_or(NewFlags, std::memory_order_release); // Fake a "valid" pointer, nobody should read this as size is zero m_DataPtr = reinterpret_cast<uint8_t*>(&m_MmapHandle); + m_Flags.fetch_or(NewFlags, std::memory_order_release); + return; + } + + const size_t DisableMMapSizeLimit = 0x1000ull; + + if (m_DataBytes < DisableMMapSizeLimit) + { + AllocateBuffer(m_DataBytes, sizeof(void*)); + NewFlags |= kIsOwnedByThis; + +#if ZEN_PLATFORM_WINDOWS + OVERLAPPED Ovl{}; + + Ovl.Offset = DWORD(m_FileOffset & 0xffff'ffffu); + Ovl.OffsetHigh = DWORD(m_FileOffset >> 32); + + DWORD dwNumberOfBytesRead = 0; + BOOL Success = ::ReadFile(m_FileHandle, (void*)m_DataPtr, DWORD(m_DataBytes), &dwNumberOfBytesRead, &Ovl); + + ZEN_ASSERT(Success); + ZEN_ASSERT(dwNumberOfBytesRead == m_DataBytes); +#else + static_assert(sizeof(off_t) >= sizeof(uint64_t), "sizeof(off_t) does not support large files"); + int Fd = int(uintptr_t(m_FileHandle)); + int BytesRead = pread(Fd, (void*)m_DataPtr, m_DataBytes, m_FileOffset); + bool Success = (BytesRead > 0); +#endif // ZEN_PLATFORM_WINDOWS + + m_Flags.fetch_or(NewFlags, std::memory_order_release); return; } diff --git a/zenhttp/httpshared.cpp b/zenhttp/httpshared.cpp index e2f061a87..568585639 100644 --- a/zenhttp/httpshared.cpp +++ b/zenhttp/httpshared.cpp @@ -344,7 +344,7 @@ ParsePackageMessage(IoBuffer Payload, std::function<IoBuffer(const IoHash&, uint { if (i == 0) { - CompressedBuffer CompBuf(CompressedBuffer::FromCompressed(SharedBuffer(AttachmentBuffer))); + CompressedBuffer CompBuf(CompressedBuffer::FromCompressedNoValidate(IoBuffer(AttachmentBuffer))); if (!CompBuf) { throw std::runtime_error(fmt::format("invalid format for chunk #{} expected compressed buffer for CbObject", i)); @@ -359,18 +359,11 @@ ParsePackageMessage(IoBuffer Payload, std::function<IoBuffer(const IoHash&, uint } else { - // Make a copy of the buffer so we attachements don't reference the entire payload - IoBuffer AttachmentBufferCopy = CreateBuffer(Entry.AttachmentHash, AttachmentSize); - ZEN_ASSERT(AttachmentBufferCopy); - ZEN_ASSERT(AttachmentBufferCopy.Size() == AttachmentSize); - AttachmentBufferCopy.GetMutableView().CopyFrom(AttachmentBuffer.GetView()); - - CompressedBuffer CompBuf(CompressedBuffer::FromCompressed(SharedBuffer(AttachmentBufferCopy))); + CompressedBuffer CompBuf(CompressedBuffer::FromCompressedNoValidate(IoBuffer(AttachmentBuffer))); if (!CompBuf) { throw std::runtime_error(fmt::format("invalid format for chunk #{} expected compressed buffer for attachment", i)); } - Attachments.emplace_back(CbAttachment(std::move(CompBuf), Entry.AttachmentHash)); } } @@ -531,7 +524,13 @@ CbPackageReader::Finalize() } else if (Entry.Flags & CbAttachmentEntry::kIsCompressed) { - m_RootObject = LoadCompactBinaryObject(CompressedBuffer::FromCompressed(SharedBuffer(AttachmentBuffer))); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(AttachmentBuffer), RawHash, RawSize); + if (RawHash == Entry.AttachmentHash) + { + m_RootObject = LoadCompactBinaryObject(Compressed); + } } else { @@ -549,13 +548,19 @@ CbPackageReader::Finalize() if (Entry.Flags & CbAttachmentEntry::kIsCompressed) { - m_Attachments.push_back(CbAttachment(CompressedBuffer::FromCompressed(SharedBuffer(ChunkReference)), Entry.AttachmentHash)); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(ChunkReference), RawHash, RawSize); + if (RawHash == Entry.AttachmentHash) + { + m_Attachments.push_back(CbAttachment(Compressed, Entry.AttachmentHash)); + } } else { CompressedBuffer Compressed = CompressedBuffer::Compress(SharedBuffer(ChunkReference), OodleCompressor::NotSet, OodleCompressionLevel::None); - m_Attachments.push_back(CbAttachment(std::move(Compressed), IoHash::FromBLAKE3(Compressed.GetRawHash()))); + m_Attachments.push_back(CbAttachment(std::move(Compressed), IoHash::FromBLAKE3(Compressed.DecodeRawHash()))); } } diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp index 1d0596c29..c72410173 100644 --- a/zenserver-test/zenserver-test.cpp +++ b/zenserver-test/zenserver-test.cpp @@ -524,7 +524,7 @@ TEST_CASE("project.basic") uint8_t AttachData[] = {1, 2, 3}; zen::CompressedBuffer Attachment = zen::CompressedBuffer::Compress(zen::SharedBuffer::Clone(zen::MemoryView{AttachData, 3})); - zen::CbAttachment Attach{Attachment, IoHash::FromBLAKE3(Attachment.GetRawHash())}; + zen::CbAttachment Attach{Attachment, IoHash::FromBLAKE3(Attachment.DecodeRawHash())}; zen::CbObjectWriter OpWriter; OpWriter << "key" @@ -765,7 +765,7 @@ TEST_CASE("zcache.cbpackage") auto Data = zen::SharedBuffer::Clone(zen::MakeMemoryView<uint8_t>({1, 2, 3, 4, 5, 6, 7, 8, 9})); auto CompressedData = zen::CompressedBuffer::Compress(Data); - OutAttachmentKey = zen::IoHash::FromBLAKE3(CompressedData.GetRawHash()); + OutAttachmentKey = zen::IoHash::FromBLAKE3(CompressedData.DecodeRawHash()); zen::CbWriter Obj; Obj.BeginObject("obj"sv); @@ -988,7 +988,7 @@ TEST_CASE("zcache.policy") auto GeneratePackage = [](zen::IoHash& OutRecordKey, zen::IoHash& OutAttachmentKey) -> zen::CbPackage { auto Data = zen::SharedBuffer::Clone(zen::MakeMemoryView<uint8_t>({1, 2, 3, 4, 5, 6, 7, 8, 9})); auto CompressedData = zen::CompressedBuffer::Compress(Data); - OutAttachmentKey = zen::IoHash::FromBLAKE3(CompressedData.GetRawHash()); + OutAttachmentKey = zen::IoHash::FromBLAKE3(CompressedData.DecodeRawHash()); zen::CbWriter Writer; Writer.BeginObject("obj"sv); @@ -1961,8 +1961,8 @@ TEST_CASE("zcache.rpc.allpolicies") { Builder.BeginObject(); Builder.AddObjectId("Id"sv, ValueIds[ValueIndex]); - Builder.AddBinaryAttachment("RawHash"sv, IoHash::FromBLAKE3(KeyData.BufferValues[ValueIndex].GetRawHash())); - Builder.AddInteger("RawSize"sv, KeyData.BufferValues[ValueIndex].GetRawSize()); + Builder.AddBinaryAttachment("RawHash"sv, IoHash::FromBLAKE3(KeyData.BufferValues[ValueIndex].DecodeRawHash())); + Builder.AddInteger("RawSize"sv, KeyData.BufferValues[ValueIndex].DecodeRawSize()); Builder.EndObject(); } Builder.EndArray(); @@ -2138,9 +2138,9 @@ TEST_CASE("zcache.rpc.allpolicies") WriteToString<32> ValueName("Get(", KeyData->KeyIndex, ",", ExpectedValueIndex, ")"); CompressedBuffer ExpectedValue = KeyData->BufferValues[ExpectedValueIndex]; - CHECK_MESSAGE(Value.RawHash == IoHash::FromBLAKE3(ExpectedValue.GetRawHash()), + CHECK_MESSAGE(Value.RawHash == IoHash::FromBLAKE3(ExpectedValue.DecodeRawHash()), WriteToString<32>(ValueName, " RawHash did not match.").c_str()); - CHECK_MESSAGE(Value.RawSize == ExpectedValue.GetRawSize(), + CHECK_MESSAGE(Value.RawSize == ExpectedValue.DecodeRawSize(), WriteToString<32>(ValueName, " RawSize did not match.").c_str()); if (KeyData->GetRequestsData) @@ -2203,9 +2203,9 @@ TEST_CASE("zcache.rpc.allpolicies") if (!KeyData->ForceMiss && Succeeded) { CompressedBuffer ExpectedValue = KeyData->BufferValues[0]; - CHECK_MESSAGE(ValueResult.RawHash == IoHash::FromBLAKE3(ExpectedValue.GetRawHash()), + CHECK_MESSAGE(ValueResult.RawHash == IoHash::FromBLAKE3(ExpectedValue.DecodeRawHash()), WriteToString<32>(Name, " RawHash did not match.").c_str()); - CHECK_MESSAGE(ValueResult.RawSize == ExpectedValue.GetRawSize(), + CHECK_MESSAGE(ValueResult.RawSize == ExpectedValue.DecodeRawSize(), WriteToString<32>(Name, " RawSize did not match.").c_str()); if (KeyData->GetRequestsData) @@ -2277,9 +2277,9 @@ TEST_CASE("zcache.rpc.allpolicies") if (KeyData->ShouldBeHit && Succeeded) { CompressedBuffer ExpectedValue = KeyData->BufferValues[ValueIndex]; - CHECK_MESSAGE(ValueResult.RawHash == IoHash::FromBLAKE3(ExpectedValue.GetRawHash()), + CHECK_MESSAGE(ValueResult.RawHash == IoHash::FromBLAKE3(ExpectedValue.DecodeRawHash()), WriteToString<32>(Name, " had unexpected RawHash.").c_str()); - CHECK_MESSAGE(ValueResult.RawSize == ExpectedValue.GetRawSize(), + CHECK_MESSAGE(ValueResult.RawSize == ExpectedValue.DecodeRawSize(), WriteToString<32>(Name, " had unexpected RawSize.").c_str()); if (KeyData->GetRequestsData) @@ -2659,11 +2659,11 @@ TEST_CASE("http.package") zen::CompressedBuffer AttachmentData1 = zen::CompressedBuffer::Compress(zen::SharedBuffer::Clone({Data1, 4}), zen::OodleCompressor::NotSet, zen::OodleCompressionLevel::None); - zen::CbAttachment Attach1{AttachmentData1, IoHash::FromBLAKE3(AttachmentData1.GetRawHash())}; + zen::CbAttachment Attach1{AttachmentData1, IoHash::FromBLAKE3(AttachmentData1.DecodeRawHash())}; zen::CompressedBuffer AttachmentData2 = zen::CompressedBuffer::Compress(zen::SharedBuffer::Clone({Data2, 8}), zen::OodleCompressor::NotSet, zen::OodleCompressionLevel::None); - zen::CbAttachment Attach2{AttachmentData2, IoHash::FromBLAKE3(AttachmentData2.GetRawHash())}; + zen::CbAttachment Attach2{AttachmentData2, IoHash::FromBLAKE3(AttachmentData2.DecodeRawHash())}; zen::CbObjectWriter Writer; diff --git a/zenserver/cache/structuredcache.cpp b/zenserver/cache/structuredcache.cpp index baaf94dd0..f649efa01 100644 --- a/zenserver/cache/structuredcache.cpp +++ b/zenserver/cache/structuredcache.cpp @@ -747,8 +747,8 @@ HttpStructuredCacheService::HandleGetCacheRecord(zen::HttpServerRequest& Request { if (IoBuffer Chunk = m_CidStore.FindChunkByCid(AttachmentHash.AsHash())) { - Package.AddAttachment( - CbAttachment(CompressedBuffer::FromCompressed(SharedBuffer(Chunk)), AttachmentHash.AsHash())); + CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(Chunk)); + Package.AddAttachment(CbAttachment(Compressed, AttachmentHash.AsHash())); } else { @@ -907,7 +907,7 @@ HttpStructuredCacheService::HandleGetCacheRecord(zen::HttpServerRequest& Request } else if (IoBuffer Chunk = m_CidStore.FindChunkByCid(Hash)) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk)); + CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(Chunk)); if (Compressed) { Package.AddAttachment(CbAttachment(Compressed, Hash)); @@ -939,8 +939,9 @@ HttpStructuredCacheService::HandleGetCacheRecord(zen::HttpServerRequest& Request for (const CbAttachment* Attachment : AttachmentsToStoreLocally) { - CompressedBuffer Chunk = Attachment->AsCompressedBinary(); - CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Chunk); + CompressedBuffer Chunk = Attachment->AsCompressedBinary(); + CidStore::InsertResult InsertResult = + m_CidStore.AddChunk(Chunk.GetCompressed().Flatten().AsIoBuffer(), Attachment->GetHash()); if (InsertResult.New) { Count.New++; @@ -1173,7 +1174,7 @@ HttpStructuredCacheService::HandlePutCacheRecord(zen::HttpServerRequest& Request for (const CbAttachment* Attachment : AttachmentsToStoreLocally) { CompressedBuffer Chunk = Attachment->AsCompressedBinary(); - CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Chunk); + CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Chunk.GetCompressed().Flatten().AsIoBuffer(), Attachment->GetHash()); if (InsertResult.New) { Count.New++; @@ -1243,10 +1244,19 @@ HttpStructuredCacheService::HandleGetCacheChunk(zen::HttpServerRequest& Request, m_UpstreamCache.GetCacheChunk(Ref.Namespace, {Ref.BucketSegment, Ref.HashKey}, Ref.ValueContentId); UpstreamResult.Status.Success) { - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(UpstreamResult.Value))) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer::ValidateCompressedHeader(UpstreamResult.Value, RawHash, RawSize)) { - m_CidStore.AddChunk(Compressed); - Source = UpstreamResult.Source; + if (RawHash == Ref.ValueContentId) + { + m_CidStore.AddChunk(UpstreamResult.Value, RawHash); + Source = UpstreamResult.Source; + } + else + { + ZEN_WARN("got missmatching upstream cache value"); + } } else { @@ -1312,21 +1322,21 @@ HttpStructuredCacheService::HandlePutCacheChunk(zen::HttpServerRequest& Request, Body.SetContentType(Request.RequestContentType()); - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Body)); - - if (!Compressed) + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Body, RawHash, RawSize)) { return Request.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Attachments must be compressed"sv); } - if (IoHash::FromBLAKE3(Compressed.GetRawHash()) != Ref.ValueContentId) + if (RawHash != Ref.ValueContentId) { return Request.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "ValueContentId does not match attachment hash"sv); } - CidStore::InsertResult Result = m_CidStore.AddChunk(Compressed); + CidStore::InsertResult Result = m_CidStore.AddChunk(Body, RawHash); ZEN_DEBUG("PUTCACHECHUNK - '{}/{}/{}/{}' {} '{}' ({}) in {}", Ref.Namespace, @@ -1625,7 +1635,7 @@ HttpStructuredCacheService::PutCacheRecord(PutRequestData& Request, const CbPack for (const CbAttachment* Attachment : AttachmentsToStoreLocally) { CompressedBuffer Chunk = Attachment->AsCompressedBinary(); - CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Chunk); + CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Chunk.GetCompressed().Flatten().AsIoBuffer(), Attachment->GetHash()); if (InsertResult.New) { Count.New++; @@ -1788,7 +1798,7 @@ HttpStructuredCacheService::HandleRpcGetCacheRecords(CbObjectView RpcRequest) if (IoBuffer Chunk = m_CidStore.FindChunkByCid(Value.ContentId)) { ZEN_ASSERT(Chunk.GetSize() > 0); - Value.Payload = CompressedBuffer::FromCompressed(SharedBuffer(Chunk)); + Value.Payload = CompressedBuffer::FromCompressedNoValidate(std::move(Chunk)); Value.Exists = true; } else @@ -1900,7 +1910,7 @@ HttpStructuredCacheService::HandleRpcGetCacheRecords(CbObjectView RpcRequest) Value.Exists = true; if (EnumHasAllFlags(ValuePolicy, CachePolicy::StoreLocal)) { - m_CidStore.AddChunk(Compressed); + m_CidStore.AddChunk(Compressed.GetCompressed().Flatten().AsIoBuffer(), Attachment->GetHash()); } if (!EnumHasAllFlags(ValuePolicy, CachePolicy::SkipData)) { @@ -1947,7 +1957,7 @@ HttpStructuredCacheService::HandleRpcGetCacheRecords(CbObjectView RpcRequest) { if (!EnumHasAllFlags(Value.DownstreamPolicy, CachePolicy::SkipData) && Value.Payload) { - ResponsePackage.AddAttachment(CbAttachment(Value.Payload, IoHash::FromBLAKE3(Value.Payload.GetRawHash()))); + ResponsePackage.AddAttachment(CbAttachment(Value.Payload, Value.ContentId)); } } @@ -2139,25 +2149,24 @@ HttpStructuredCacheService::HandleRpcGetCacheValues(CbObjectView RpcRequest) PolicyText = RequestObject["Policy"sv].AsString(); Request.Policy = !PolicyText.empty() ? ParseCachePolicy(PolicyText) : DefaultPolicy; - CacheKey& Key = Request.Key; - CachePolicy Policy = Request.Policy; - CompressedBuffer& Result = Request.Result; + CacheKey& Key = Request.Key; + CachePolicy Policy = Request.Policy; ZenCacheValue CacheValue; if (EnumHasAllFlags(Policy, CachePolicy::QueryLocal)) { if (m_CacheStore.Get(*Namespace, Key.Bucket, Key.Hash, CacheValue) && IsCompressedBinary(CacheValue.Value.GetContentType())) { - Result = CompressedBuffer::FromCompressed(SharedBuffer(CacheValue.Value)); + Request.Result = CompressedBuffer::FromCompressed(SharedBuffer(CacheValue.Value), Request.RawHash, Request.RawSize); } } - if (Result) + if (Request.Result) { ZEN_DEBUG("GETCACHEVALUES HIT - '{}/{}/{}' {} ({}) in {}", *Namespace, Key.Bucket, Key.Hash, - NiceBytes(Result.GetCompressed().GetSize()), + NiceBytes(Request.Result.GetCompressed().GetSize()), "LOCAL"sv, NiceLatencyNs(Timer.GetElapsedTimeUs() * 1000)); m_CacheStats.HitCount++; @@ -2216,7 +2225,7 @@ HttpStructuredCacheService::HandleRpcGetCacheValues(CbObjectView RpcRequest) { if (HasData && !SkipData) { - Request.Result = CompressedBuffer::FromCompressed(SharedBuffer(Params.Value)); + Request.Result = CompressedBuffer::FromCompressed(SharedBuffer(Params.Value), Request.RawHash, Request.RawSize); } if (HasData && StoreData) @@ -2261,15 +2270,14 @@ HttpStructuredCacheService::HandleRpcGetCacheValues(CbObjectView RpcRequest) const CompressedBuffer& Result = Request.Result; if (Result) { - IoHash Hash = IoHash::FromBLAKE3(Result.GetRawHash()); - ResponseObject.AddHash("RawHash"sv, Hash); + ResponseObject.AddHash("RawHash"sv, Request.RawHash); if (!EnumHasAllFlags(Request.Policy, CachePolicy::SkipData)) { - RpcResponse.AddAttachment(CbAttachment(Result, Hash)); + RpcResponse.AddAttachment(CbAttachment(Result, Request.RawHash)); } else { - ResponseObject.AddInteger("RawSize"sv, Result.GetRawSize()); + ResponseObject.AddInteger("RawSize"sv, Request.RawSize); } } else if (Request.RawHash != IoHash::Zero) @@ -2310,12 +2318,12 @@ namespace cache::detail { RecordBody* Record = nullptr; CompressedBuffer Value; const UpstreamEndpointInfo* Source = nullptr; - uint64_t TotalSize = 0; + uint64_t RawSize = 0; uint64_t RequestedSize = 0; uint64_t RequestedOffset = 0; CachePolicy DownstreamPolicy; bool Exists = false; - bool TotalSizeKnown = false; + bool RawSizeKnown = false; bool IsRecordRequest = false; uint64_t ElapsedTimeUs = 0; }; @@ -2569,9 +2577,9 @@ HttpStructuredCacheService::GetLocalCacheRecords(std::string_view Namespac { if (Value.ValueId == Request->Key->ValueId) { - Request->Key->ChunkId = Value.ContentId; - Request->TotalSize = Value.RawSize; - Request->TotalSizeKnown = true; + Request->Key->ChunkId = Value.ContentId; + Request->RawSize = Value.RawSize; + Request->RawSizeKnown = true; break; } } @@ -2582,7 +2590,7 @@ HttpStructuredCacheService::GetLocalCacheRecords(std::string_view Namespac { if (EnumHasAllFlags(Request->DownstreamPolicy, CachePolicy::QueryLocal)) { - if (EnumHasAllFlags(Request->DownstreamPolicy, CachePolicy::SkipData) && Request->TotalSizeKnown) + if (EnumHasAllFlags(Request->DownstreamPolicy, CachePolicy::SkipData) && Request->RawSizeKnown) { if (m_CidStore.ContainsChunk(Request->Key->ChunkId)) { @@ -2591,16 +2599,16 @@ HttpStructuredCacheService::GetLocalCacheRecords(std::string_view Namespac } else if (IoBuffer Payload = m_CidStore.FindChunkByCid(Request->Key->ChunkId)) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); + IoHash RawHash; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload), RawHash, Request->RawSize); if (Compressed) { if (!EnumHasAllFlags(Request->DownstreamPolicy, CachePolicy::SkipData)) { Request->Value = Compressed; } - Request->Exists = true; - Request->TotalSize = Compressed.GetRawSize(); - Request->TotalSizeKnown = true; + Request->Exists = true; + Request->RawSizeKnown = true; } } } @@ -2631,17 +2639,19 @@ HttpStructuredCacheService::GetLocalCacheValues(std::string_view Namespa { if (IsCompressedBinary(CacheValue.Value.GetContentType())) { - CompressedBuffer Result = CompressedBuffer::FromCompressed(SharedBuffer(CacheValue.Value)); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Result = CompressedBuffer::FromCompressed(SharedBuffer(CacheValue.Value), RawHash, RawSize); if (Result) { if (!EnumHasAllFlags(Request->DownstreamPolicy, CachePolicy::SkipData)) { Request->Value = Result; } - Request->Key->ChunkId = IoHash::FromBLAKE3(Result.GetRawHash()); - Request->Exists = true; - Request->TotalSize = Result.GetRawSize(); - Request->TotalSizeKnown = true; + Request->Key->ChunkId = RawHash; + Request->Exists = true; + Request->RawSize = RawSize; + Request->RawSizeKnown = true; } } } @@ -2683,9 +2693,10 @@ HttpStructuredCacheService::GetUpstreamCacheChunks(std::string_view Names if (EnumHasAllFlags(Request.DownstreamPolicy, CachePolicy::StoreLocal) || !EnumHasAllFlags(Request.DownstreamPolicy, CachePolicy::SkipData)) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Params.Value)); - if (!Compressed || Compressed.GetRawSize() != Params.RawSize || - IoHash::FromBLAKE3(Compressed.GetRawHash()) != Params.RawHash) + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Params.Value), RawHash, RawSize); + if (!Compressed || RawSize != Params.RawSize || RawHash != Params.RawHash) { return; } @@ -2694,7 +2705,7 @@ HttpStructuredCacheService::GetUpstreamCacheChunks(std::string_view Names { if (Request.IsRecordRequest) { - m_CidStore.AddChunk(Compressed); + m_CidStore.AddChunk(Params.Value, RawHash); } else { @@ -2706,11 +2717,11 @@ HttpStructuredCacheService::GetUpstreamCacheChunks(std::string_view Names Request.Value = std::move(Compressed); } } - Key.ChunkId = Params.RawHash; - Request.Exists = true; - Request.TotalSize = Params.RawSize; - Request.TotalSizeKnown = true; - Request.Source = Params.Source; + Key.ChunkId = Params.RawHash; + Request.Exists = true; + Request.RawSize = Params.RawSize; + Request.RawSizeKnown = true; + Request.Source = Params.Source; m_CacheStats.UpstreamHitCount++; }; @@ -2741,7 +2752,7 @@ HttpStructuredCacheService::WriteGetCacheChunksResponse(std::string_view Namespa } else { - Writer.AddInteger("RawSize"sv, Request.TotalSize); + Writer.AddInteger("RawSize"sv, Request.RawSize); } ZEN_DEBUG("GETCACHECHUNKS HIT - '{}/{}/{}/{}' {} '{}' ({}) in {}", @@ -2749,7 +2760,7 @@ HttpStructuredCacheService::WriteGetCacheChunksResponse(std::string_view Namespa Request.Key->Key.Bucket, Request.Key->Key.Hash, Request.Key->ValueId, - NiceBytes(Request.TotalSize), + NiceBytes(Request.RawSize), Request.IsRecordRequest ? "Record"sv : "Value"sv, Request.Source ? Request.Source->Url : "LOCAL"sv, NiceLatencyNs(Request.ElapsedTimeUs * 1000)); diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index 1f48aaebe..75f845cbf 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -491,7 +491,7 @@ ZenCacheMemoryLayer::CacheBucket::Scrub(ScrubContext& Ctx) std::vector<IoHash> BadHashes; - auto ValidateEntry = [](ZenContentType ContentType, IoBuffer Buffer) { + auto ValidateEntry = [](const IoHash& Hash, ZenContentType ContentType, IoBuffer Buffer) { if (ContentType == ZenContentType::kCbObject) { CbValidateError Error = ValidateCompactBinary(Buffer, CbValidateMode::All); @@ -499,7 +499,13 @@ ZenCacheMemoryLayer::CacheBucket::Scrub(ScrubContext& Ctx) } if (ContentType == ZenContentType::kCompressedBinary) { - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Buffer)); !Compressed) + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Buffer, RawHash, RawSize)) + { + return false; + } + if (Hash != RawHash) { return false; } @@ -509,7 +515,7 @@ ZenCacheMemoryLayer::CacheBucket::Scrub(ScrubContext& Ctx) for (auto& Kv : m_CacheMap) { - if (!ValidateEntry(Kv.second.Payload.GetContentType(), Kv.second.Payload)) + if (!ValidateEntry(Kv.first, Kv.second.Payload.GetContentType(), Kv.second.Payload)) { BadHashes.push_back(Kv.first); } @@ -1021,7 +1027,7 @@ ZenCacheDiskLayer::CacheBucket::Scrub(ScrubContext& Ctx) std::vector<BlockStoreLocation> ChunkLocations; std::vector<IoHash> ChunkIndexToChunkHash; - auto ValidateEntry = [](ZenContentType ContentType, IoBuffer Buffer) { + auto ValidateEntry = [](const IoHash& Hash, ZenContentType ContentType, IoBuffer Buffer) { if (ContentType == ZenContentType::kCbObject) { CbValidateError Error = ValidateCompactBinary(Buffer, CbValidateMode::All); @@ -1029,7 +1035,13 @@ ZenCacheDiskLayer::CacheBucket::Scrub(ScrubContext& Ctx) } if (ContentType == ZenContentType::kCompressedBinary) { - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Buffer)); !Compressed) + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Buffer, RawHash, RawSize)) + { + return false; + } + if (RawHash != Hash) { return false; } @@ -1077,7 +1089,7 @@ ZenCacheDiskLayer::CacheBucket::Scrub(ScrubContext& Ctx) BadKeys.push_back(HashKey); continue; } - if (!ValidateEntry(Loc.GetContentType(), Value.Value)) + if (!ValidateEntry(HashKey, Loc.GetContentType(), Value.Value)) { BadKeys.push_back(HashKey); continue; @@ -1108,7 +1120,7 @@ ZenCacheDiskLayer::CacheBucket::Scrub(ScrubContext& Ctx) return; } ZenContentType ContentType = m_Index.at(Hash).Location.GetContentType(); - if (!ValidateEntry(ContentType, Buffer)) + if (!ValidateEntry(Hash, ContentType, Buffer)) { BadKeys.push_back(Hash); return; @@ -1127,7 +1139,7 @@ ZenCacheDiskLayer::CacheBucket::Scrub(ScrubContext& Ctx) return; } ZenContentType ContentType = m_Index.at(Hash).Location.GetContentType(); - if (!ValidateEntry(ContentType, Buffer)) + if (!ValidateEntry(Hash, ContentType, Buffer)) { BadKeys.push_back(Hash); return; @@ -1678,18 +1690,8 @@ ZenCacheDiskLayer::CacheBucket::PutStandaloneCacheValue(const IoHash& HashKey, c DataFile.MoveTemporaryIntoPlace(FsPath, Ec); if (Ec) { - std::filesystem::path ParentPath = FsPath.parent_path(); - if (!std::filesystem::is_directory(ParentPath)) - { - Ec.clear(); - std::filesystem::create_directories(ParentPath, Ec); - if (Ec) - { - throw std::system_error( - Ec, - fmt::format("Failed to create parent directory '{}' for file '{}' for put in '{}'", ParentPath, FsPath, m_BucketDir)); - } - } + CreateDirectories(FsPath.parent_path()); + Ec.clear(); // Try again DataFile.MoveTemporaryIntoPlace(FsPath, Ec); @@ -3100,7 +3102,8 @@ TEST_CASE("z$.scrub") { IoBuffer AttachmentData = CreateBinaryCacheValue(AttachmentSizes[Index]); CompressedBuffer CompressedAttachmentData = CompressedBuffer::Compress(SharedBuffer(AttachmentData)); - Record.AddBinaryAttachment(fmt::format("attachment-{}", Index), IoHash::FromBLAKE3(CompressedAttachmentData.GetRawHash())); + Record.AddBinaryAttachment(fmt::format("attachment-{}", Index), + IoHash::FromBLAKE3(CompressedAttachmentData.DecodeRawHash())); Result.Attachments[Index] = CompressedAttachmentData; } Result.Record = Record.Save().GetBuffer().AsIoBuffer(); @@ -3142,7 +3145,7 @@ TEST_CASE("z$.scrub") Zcs.Put("mybucket", Cid, {.Value = Record.Record}); for (const CompressedBuffer& Attachment : Record.Attachments) { - CidStore.AddChunk(Attachment); + CidStore.AddChunk(Attachment.GetCompressed().Flatten().AsIoBuffer(), IoHash::FromBLAKE3(Attachment.DecodeRawHash())); } } }; diff --git a/zenserver/cidstore.cpp b/zenserver/cidstore.cpp index 5de347a17..bce4f1dfb 100644 --- a/zenserver/cidstore.cpp +++ b/zenserver/cidstore.cpp @@ -39,22 +39,21 @@ HttpCidService::HttpCidService(CidStore& Store) : m_CidStore(Store) case HttpVerb::kPut: { - IoBuffer Payload = ServerRequest.ReadPayload(); - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); - if (!Compressed) + IoBuffer Payload = ServerRequest.ReadPayload(); + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize)) { return ServerRequest.WriteResponse(HttpResponseCode::UnsupportedMediaType); } - IoHash PayloadHash = IoHash::FromBLAKE3(Compressed.GetRawHash()); - // URI hash must match content hash - if (PayloadHash != Hash) + if (RawHash != Hash) { return ServerRequest.WriteResponse(HttpResponseCode::BadRequest); } - m_CidStore.AddChunk(Compressed); + m_CidStore.AddChunk(Payload, RawHash); return ServerRequest.WriteResponse(HttpResponseCode::OK); } @@ -85,18 +84,17 @@ HttpCidService::HandleRequest(zen::HttpServerRequest& Request) case HttpVerb::kPut: case HttpVerb::kPost: { - IoBuffer Payload = Request.ReadPayload(); - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); - if (!Compressed) + IoBuffer Payload = Request.ReadPayload(); + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize)) { return Request.WriteResponse(HttpResponseCode::UnsupportedMediaType); } - IoHash PayloadHash = IoHash::FromBLAKE3(Compressed.GetRawHash()); - - ZEN_DEBUG("CID POST request for {} ({} bytes)", PayloadHash, Payload.Size()); + ZEN_DEBUG("CID POST request for {} ({} bytes)", RawHash, Payload.Size()); - auto InsertResult = m_CidStore.AddChunk(Compressed); + auto InsertResult = m_CidStore.AddChunk(Payload, RawHash); if (InsertResult.New) { diff --git a/zenserver/compute/function.cpp b/zenserver/compute/function.cpp index d7316ac64..493e2666e 100644 --- a/zenserver/compute/function.cpp +++ b/zenserver/compute/function.cpp @@ -162,7 +162,8 @@ HttpFunctionService::HttpFunctionService(CidStore& InCidStore, TotalAttachmentBytes += Buffer.GetCompressedSize(); ++AttachmentCount; - const CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Buffer); + const CidStore::InsertResult InsertResult = + m_CidStore.AddChunk(Buffer.GetCompressed().Flatten().AsIoBuffer(), DataHash); if (InsertResult.New) { @@ -404,7 +405,8 @@ HttpFunctionService::HttpFunctionService(CidStore& InCidStore, TotalAttachmentBytes += CompressedSize; ++AttachmentCount; - const CidStore::InsertResult InsertResult = m_CidStore.AddChunk(DataView); + const CidStore::InsertResult InsertResult = + m_CidStore.AddChunk(DataView.GetCompressed().Flatten().AsIoBuffer(), DataHash); if (InsertResult.New) { diff --git a/zenserver/projectstore.cpp b/zenserver/projectstore.cpp index 3a65feb0f..2c44beaee 100644 --- a/zenserver/projectstore.cpp +++ b/zenserver/projectstore.cpp @@ -643,8 +643,8 @@ ProjectStore::Oplog::AppendNewOplogEntry(CbPackage OpPackage) ZEN_ASSERT(Attach.IsCompressedBinary()); CompressedBuffer AttachmentData = Attach.AsCompressedBinary(); - const uint64_t AttachmentSize = AttachmentData.GetRawSize(); - CidStore::InsertResult InsertResult = m_CidStore.AddChunk(AttachmentData); + const uint64_t AttachmentSize = AttachmentData.DecodeRawSize(); + CidStore::InsertResult InsertResult = m_CidStore.AddChunk(AttachmentData.GetCompressed().Flatten().AsIoBuffer(), Attach.GetHash()); if (InsertResult.New) { @@ -1410,9 +1410,11 @@ ProjectStore::GetChunkInfo(const std::string_view ProjectId, uint64_t ChunkSize = Chunk.GetSize(); if (Chunk.GetContentType() == HttpContentType::kCompressedBinary) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk)); - ZEN_ASSERT(!Compressed.IsNull()); - ChunkSize = Compressed.GetRawSize(); + IoHash RawHash; + uint64_t RawSize; + bool IsCompressed = CompressedBuffer::ValidateCompressedHeader(Chunk, RawHash, RawSize); + ZEN_ASSERT(IsCompressed); + ChunkSize = RawSize; } CbObjectWriter Response; @@ -1467,12 +1469,13 @@ ProjectStore::GetChunk(const std::string_view ProjectId, if (Chunk.GetContentType() == HttpContentType::kCompressedBinary) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk)); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk), RawHash, RawSize); ZEN_ASSERT(!Compressed.IsNull()); if (IsOffset) { - uint64_t RawSize = Compressed.GetRawSize(); if ((Offset + Size) > RawSize) { Size = RawSize - Offset; @@ -1542,7 +1545,7 @@ ProjectStore::GetChunk(const std::string_view Cid, ZenContentType AcceptType, Io if (AcceptType == HttpContentType::kBinary) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(OutChunk)); + CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(OutChunk)); OutChunk = Compressed.Decompress().AsIoBuffer(); OutChunk.SetContentType(HttpContentType::kBinary); } @@ -1824,7 +1827,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) if (AcceptType == HttpContentType::kBinary) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Value)); + CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(Value)); Value = Compressed.Decompress().AsIoBuffer(); ContentType = HttpContentType::kBinary; } @@ -2069,7 +2072,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) break; case ZenContentType::kCompressedBinary: - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload))) + if (CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(Payload))) { Package.AddAttachment(CbAttachment(Compressed, AttachmentHash)); } @@ -2202,7 +2205,8 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) { ZEN_INFO("Importing oplog '{}/{}'", ProjectId, OplogId); IoBuffer CompressedPayload = HttpReq.ReadPayload(); - IoBuffer Payload = CompressedBuffer::FromCompressed(SharedBuffer(CompressedPayload)).Decompress().AsIoBuffer(); + IoBuffer Payload = + CompressedBuffer::FromCompressedNoValidate(std::move(CompressedPayload)).Decompress().AsIoBuffer(); CbPackage RequestPackage = ParsePackageMessage(Payload); CbObject Request = RequestPackage.GetObject(); @@ -2278,7 +2282,9 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) try { CompressedBuffer AttachmentBody = Attachment.AsCompressedBinary(); - m_CidStore.AddChunk(AttachmentBody, CidStore::InsertMode::kCopyOnly); + m_CidStore.AddChunk(AttachmentBody.GetCompressed().Flatten().AsIoBuffer(), + Attachment.GetHash(), + CidStore::InsertMode::kCopyOnly); } catch (std::exception& e) { @@ -2572,7 +2578,7 @@ namespace testutils { Object.BeginArray("bulkdata"); for (const auto& Attachment : Attachments) { - CbAttachment Attach(Attachment.second, IoHash::FromBLAKE3(Attachment.second.GetRawHash())); + CbAttachment Attach(Attachment.second, IoHash::FromBLAKE3(Attachment.second.DecodeRawHash())); Object.BeginObject(); Object << "id"sv << Attachment.first; Object << "type"sv @@ -2828,11 +2834,13 @@ TEST_CASE("project.store.partial.read") } { IoBuffer Chunk; - CHECK(ProjectStore.GetChunk(IoHash::FromBLAKE3(Attachments[OpIds[1]][0].second.GetRawHash()).ToHexString(), + CHECK(ProjectStore.GetChunk(IoHash::FromBLAKE3(Attachments[OpIds[1]][0].second.DecodeRawHash()).ToHexString(), HttpContentType::kCompressedBinary, Chunk) == HttpResponseCode::OK); - CompressedBuffer Attachment = CompressedBuffer::FromCompressed(SharedBuffer(Chunk)); - CHECK(Attachment.GetRawSize() == Attachments[OpIds[1]][0].second.GetRawSize()); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Attachment = CompressedBuffer::FromCompressed(SharedBuffer(Chunk), RawHash, RawSize); + CHECK(RawSize == Attachments[OpIds[1]][0].second.DecodeRawSize()); } IoBuffer ChunkResult; @@ -2844,7 +2852,8 @@ TEST_CASE("project.store.partial.read") HttpContentType::kCompressedBinary, ChunkResult) == HttpResponseCode::OK); CHECK(ChunkResult); - CHECK(CompressedBuffer::FromCompressed(SharedBuffer(ChunkResult)).GetRawSize() == Attachments[OpIds[2]][1].second.GetRawSize()); + CHECK(CompressedBuffer::FromCompressedNoValidate(std::move(ChunkResult)).DecodeRawSize() == + Attachments[OpIds[2]][1].second.DecodeRawSize()); IoBuffer PartialChunkResult; CHECK(ProjectStore.GetChunk("proj1"sv, @@ -2855,8 +2864,11 @@ TEST_CASE("project.store.partial.read") HttpContentType::kCompressedBinary, PartialChunkResult) == HttpResponseCode::OK); CHECK(PartialChunkResult); - CompressedBuffer PartialCompressedResult = CompressedBuffer::FromCompressed(SharedBuffer(PartialChunkResult)); - CHECK(PartialCompressedResult.GetRawSize() >= 1773); + IoHash PartialRawHash; + uint64_t PartialRawSize; + CompressedBuffer PartialCompressedResult = + CompressedBuffer::FromCompressed(SharedBuffer(PartialChunkResult), PartialRawHash, PartialRawSize); + CHECK(PartialRawSize >= 1773); uint64_t RawOffsetInPartialCompressed = GetCompressedOffset(PartialCompressedResult, 5); SharedBuffer PartialDecompressed = PartialCompressedResult.Decompress(RawOffsetInPartialCompressed); diff --git a/zenserver/testing/launch.cpp b/zenserver/testing/launch.cpp index 0e46fff94..b26f9e437 100644 --- a/zenserver/testing/launch.cpp +++ b/zenserver/testing/launch.cpp @@ -477,7 +477,11 @@ HttpLaunchService::HttpLaunchService(CidStore& Store, const std::filesystem::pat { std::filesystem::path FullPath = SandboxDir / FileName; - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk)); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk), RawHash, RawSize); + ZEN_ASSERT(Compressed); + ZEN_ASSERT(FileHash == RawHash); CompositeBuffer CompositeBuffer = Compressed.DecompressToComposite(); std::span<const SharedBuffer> Segments = CompositeBuffer.GetSegments(); std::vector<IoBuffer> Chunks(Segments.size()); diff --git a/zenserver/upstream/hordecompute.cpp b/zenserver/upstream/hordecompute.cpp index 988386726..64d9fff72 100644 --- a/zenserver/upstream/hordecompute.cpp +++ b/zenserver/upstream/hordecompute.cpp @@ -983,10 +983,12 @@ namespace detail { return; } + IoHash RawHash; + uint64_t RawSize; CompressedBuffer AttachmentBuffer = - CompressedBuffer::FromCompressed(SharedBuffer(BinaryData[CompressedId])); + CompressedBuffer::FromCompressed(SharedBuffer(BinaryData[CompressedId]), RawHash, RawSize); - if (!AttachmentBuffer) + if (!AttachmentBuffer || RawHash != DecompressedId) { Log().warn( "Invalid output encountered (not valid CompressedBuffer format) {} compressed {} uncompressed", @@ -997,7 +999,7 @@ namespace detail { } ApplyResult.TotalAttachmentBytes += AttachmentBuffer.GetCompressedSize(); - ApplyResult.TotalRawAttachmentBytes += AttachmentBuffer.GetRawSize(); + ApplyResult.TotalRawAttachmentBytes += RawSize; CbAttachment Attachment(AttachmentBuffer, DecompressedId); OutputPackage.AddAttachment(Attachment); diff --git a/zenserver/upstream/upstreamcache.cpp b/zenserver/upstream/upstreamcache.cpp index bc06653b9..6e5422007 100644 --- a/zenserver/upstream/upstreamcache.cpp +++ b/zenserver/upstream/upstreamcache.cpp @@ -214,7 +214,9 @@ namespace detail { Result.ElapsedSeconds += AttachmentResult.ElapsedSeconds; Result.ErrorCode = AttachmentResult.ErrorCode; - if (CompressedBuffer Chunk = CompressedBuffer::FromCompressed(SharedBuffer(AttachmentResult.Response))) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer::ValidateCompressedHeader(AttachmentResult.Response, RawHash, RawSize)) { Result.Response = AttachmentResult.Response; ++NumAttachments; @@ -251,7 +253,10 @@ namespace detail { Result.ElapsedSeconds += AttachmentResult.ElapsedSeconds; Result.ErrorCode = AttachmentResult.ErrorCode; - if (CompressedBuffer Chunk = CompressedBuffer::FromCompressed(SharedBuffer(AttachmentResult.Response))) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer Chunk = + CompressedBuffer::FromCompressed(SharedBuffer(AttachmentResult.Response), RawHash, RawSize)) { Package.AddAttachment(CbAttachment(Chunk, AttachmentHash.AsHash())); } @@ -335,9 +340,15 @@ namespace detail { if (BlobResult.ErrorCode == 0) { - if (CompressedBuffer Chunk = CompressedBuffer::FromCompressed(SharedBuffer(BlobResult.Response))) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer Chunk = + CompressedBuffer::FromCompressed(SharedBuffer(BlobResult.Response), RawHash, RawSize)) { - Package.AddAttachment(CbAttachment(Chunk, AttachmentHash.AsHash())); + if (RawHash == AttachmentHash.AsHash()) + { + Package.AddAttachment(CbAttachment(Chunk, RawHash)); + } } } }); @@ -398,9 +409,11 @@ namespace detail { { CacheChunkRequest& Request = *RequestPtr; IoBuffer Payload; + IoHash RawHash = IoHash::Zero; + uint64_t RawSize = 0; - double ElapsedSeconds = 0.0; - CompressedBuffer Compressed; + double ElapsedSeconds = 0.0; + bool IsCompressed = false; if (!Result.Error) { std::string_view BlobStoreNamespace = GetActualBlobStoreNamespace(Session, Namespace); @@ -416,15 +429,15 @@ namespace detail { m_Status.SetFromErrorCode(BlobResult.ErrorCode, BlobResult.Reason); if (Payload && IsCompressedBinary(Payload.GetContentType())) { - Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); + IsCompressed = CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize); } } - if (Compressed) + if (IsCompressed) { OnComplete({.Request = Request, - .RawHash = IoHash::FromBLAKE3(Compressed.GetRawHash()), - .RawSize = Compressed.GetRawSize(), + .RawHash = RawHash, + .RawSize = RawSize, .Value = Payload, .ElapsedSeconds = ElapsedSeconds, .Source = &m_Info}); @@ -451,9 +464,11 @@ namespace detail { { CacheValueRequest& Request = *RequestPtr; IoBuffer Payload; + IoHash RawHash = IoHash::Zero; + uint64_t RawSize = 0; - double ElapsedSeconds = 0.0; - CompressedBuffer Compressed; + double ElapsedSeconds = 0.0; + bool IsCompressed = false; if (!Result.Error) { std::string_view BlobStoreNamespace = GetActualBlobStoreNamespace(Session, Namespace); @@ -470,13 +485,17 @@ namespace detail { { if (IsCompressedBinary(Payload.GetContentType())) { - Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload)); + IsCompressed = CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize) && RawHash != PayloadHash; } else { - Compressed = CompressedBuffer::Compress(SharedBuffer(Payload)); - IoHash RawHash = IoHash::FromBLAKE3(Compressed.GetRawHash()); - if (RawHash != PayloadHash) + CompressedBuffer Compressed = CompressedBuffer::Compress(SharedBuffer(Payload)); + RawHash = IoHash::FromBLAKE3(Compressed.DecodeRawHash()); + if (RawHash == PayloadHash) + { + IsCompressed = true; + } + else { ZEN_WARN("Horde request for inline payload of {}/{}/{} has hash {}, expected hash {} from header", Namespace, @@ -484,17 +503,16 @@ namespace detail { Request.Key.Hash.ToHexString(), RawHash.ToHexString(), PayloadHash.ToHexString()); - Compressed.Reset(); } } } } - if (Compressed) + if (IsCompressed) { OnComplete({.Request = Request, - .RawHash = IoHash::FromBLAKE3(Compressed.GetRawHash()), - .RawSize = Compressed.GetRawSize(), + .RawHash = RawHash, + .RawSize = RawSize, .Value = Payload, .ElapsedSeconds = ElapsedSeconds, .Source = &m_Info}); @@ -543,17 +561,16 @@ namespace detail { } else if (CacheRecord.Type == ZenContentType::kCompressedBinary) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(RecordValue)); - if (!Compressed) + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(RecordValue, RawHash, RawSize)) { return {.Reason = std::string("Invalid compressed value buffer"), .Success = false}; } - IoHash RawHash = IoHash::FromBLAKE3(Compressed.GetRawHash()); - CbObjectWriter ReferencingObject; ReferencingObject.AddBinaryAttachment("RawHash", RawHash); - ReferencingObject.AddInteger("RawSize", Compressed.GetRawSize()); + ReferencingObject.AddInteger("RawSize", RawSize); return PerformStructuredPut( Session, @@ -1053,7 +1070,7 @@ namespace detail { { Payload = Compressed.GetCompressed().Flatten().AsIoBuffer(); Payload.SetContentType(ZenContentType::kCompressedBinary); - RawSize = Compressed.GetRawSize(); + RawSize = Compressed.DecodeRawSize(); Success = true; } } @@ -1189,7 +1206,7 @@ namespace detail { { Payload = Compressed.GetCompressed().Flatten().AsIoBuffer(); Payload.SetContentType(ZenContentType::kCompressedBinary); - RawSize = Compressed.GetRawSize(); + RawSize = Compressed.DecodeRawSize(); Success = true; } } @@ -1252,9 +1269,11 @@ namespace detail { for (const IoBuffer& Value : Values) { - if (CompressedBuffer AttachmentBuffer = CompressedBuffer::FromCompressed(SharedBuffer(Value))) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer AttachmentBuffer = CompressedBuffer::FromCompressed(SharedBuffer(Value), RawHash, RawSize)) { - Package.AddAttachment(CbAttachment(AttachmentBuffer, IoHash::FromBLAKE3(AttachmentBuffer.GetRawHash()))); + Package.AddAttachment(CbAttachment(AttachmentBuffer, RawHash)); } else { @@ -1282,7 +1301,9 @@ namespace detail { } else if (CacheRecord.Type == ZenContentType::kCompressedBinary) { - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(RecordValue)); + IoHash RawHash; + uint64_t RawSize; + CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(RecordValue), RawHash, RawSize); if (!Compressed) { return {.Reason = std::string("Invalid value compressed buffer"), .Success = false}; @@ -1312,9 +1333,8 @@ namespace detail { } BatchWriter.EndObject(); // Policy unspecified and expected to be Default - IoHash Hash = IoHash::FromBLAKE3(Compressed.GetRawHash()); - BatchWriter.AddBinaryAttachment("RawHash"sv, Hash); - BatchPackage.AddAttachment(CbAttachment(Compressed, Hash)); + BatchWriter.AddBinaryAttachment("RawHash"sv, RawHash); + BatchPackage.AddAttachment(CbAttachment(Compressed, RawHash)); } BatchWriter.EndObject(); } diff --git a/zenstore/cidstore.cpp b/zenstore/cidstore.cpp index 8b2797ce9..5a5116faf 100644 --- a/zenstore/cidstore.cpp +++ b/zenstore/cidstore.cpp @@ -23,14 +23,17 @@ struct CidStore::Impl void Initialize(const CidStoreConfiguration& Config) { m_CasStore.Initialize(Config); } - CidStore::InsertResult AddChunk(const CompressedBuffer& ChunkData, CidStore::InsertMode Mode) + CidStore::InsertResult AddChunk(const IoBuffer& ChunkData, const IoHash& RawHash, CidStore::InsertMode Mode) { - const IoHash DecompressedId = IoHash::FromBLAKE3(ChunkData.GetRawHash()); - IoBuffer Payload = ChunkData.GetCompressed().Flatten().AsIoBuffer(); - +#ifndef NDEBUG + IoHash VerifyRawHash; + uint64_t _; + ZEN_ASSERT(CompressedBuffer::ValidateCompressedHeader(ChunkData, VerifyRawHash, _) && RawHash == VerifyRawHash); +#endif // NDEBUG + IoBuffer Payload(ChunkData); Payload.SetContentType(ZenContentType::kCompressedBinary); - CasStore::InsertResult Result = m_CasStore.InsertChunk(Payload, DecompressedId, static_cast<CasStore::InsertMode>(Mode)); + CasStore::InsertResult Result = m_CasStore.InsertChunk(Payload, RawHash, static_cast<CasStore::InsertMode>(Mode)); return {.New = Result.New}; } @@ -78,9 +81,9 @@ CidStore::Initialize(const CidStoreConfiguration& Config) } CidStore::InsertResult -CidStore::AddChunk(const CompressedBuffer& ChunkData, InsertMode Mode) +CidStore::AddChunk(const IoBuffer& ChunkData, const IoHash& RawHash, InsertMode Mode) { - return m_Impl->AddChunk(ChunkData, Mode); + return m_Impl->AddChunk(ChunkData, RawHash, Mode); } IoBuffer diff --git a/zenstore/compactcas.cpp b/zenstore/compactcas.cpp index 7507a82f6..8679eb95e 100644 --- a/zenstore/compactcas.cpp +++ b/zenstore/compactcas.cpp @@ -269,9 +269,11 @@ CasContainerStrategy::Scrub(ScrubContext& Ctx) } IoBuffer Buffer(IoBuffer::Wrap, Data, Size); - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Buffer)); Compressed) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer::ValidateCompressedHeader(Buffer, RawHash, RawSize)) { - if (IoHash::FromBLAKE3(Compressed.GetRawHash()) != Hash) + if (RawHash != Hash) { // Hash mismatch BadKeys.push_back(Hash); @@ -295,10 +297,13 @@ CasContainerStrategy::Scrub(ScrubContext& Ctx) const IoHash& Hash = ChunkIndexToChunkHash[ChunkIndex]; IoBuffer Buffer(IoBuffer::BorrowedFile, File.GetBasicFile().Handle(), Offset, Size); + + IoHash RawHash; + uint64_t RawSize; // TODO: Add API to verify compressed buffer without having to memorymap the whole file - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Buffer)); Compressed) + if (CompressedBuffer::ValidateCompressedHeader(Buffer, RawHash, RawSize)) { - if (IoHash::FromBLAKE3(Compressed.GetRawHash()) != Hash) + if (RawHash != Hash) { // Hash mismatch BadKeys.push_back(Hash); diff --git a/zenstore/filecas.cpp b/zenstore/filecas.cpp index 38d7898cf..e67653e8a 100644 --- a/zenstore/filecas.cpp +++ b/zenstore/filecas.cpp @@ -519,9 +519,7 @@ FileCasStrategy::InsertChunk(const void* const ChunkData, const size_t ChunkSize if (hRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { // Ensure parent directories exist and retry file creation - - std::filesystem::create_directories(std::wstring_view(Name.ShardedPath.c_str(), Name.Shard2len)); - + CreateDirectories(std::wstring_view(Name.ShardedPath.c_str(), Name.Shard2len)); hRes = InternalCreateFile(); } @@ -789,9 +787,11 @@ FileCasStrategy::Scrub(ScrubContext& Ctx) ChunkBytes += Payload.FileSize(); IoBuffer Buffer(IoBuffer::BorrowedFile, Payload.Handle(), 0, Payload.FileSize()); - if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Buffer)); Compressed) + IoHash RawHash; + uint64_t RawSize; + if (CompressedBuffer::ValidateCompressedHeader(Buffer, RawHash, RawSize)) { - if (IoHash::FromBLAKE3(Compressed.GetRawHash()) != Hash) + if (RawHash != Hash) { // Hash mismatch BadHashes.push_back(Hash); diff --git a/zenstore/gc.cpp b/zenstore/gc.cpp index 4094716ae..c50f59b64 100644 --- a/zenstore/gc.cpp +++ b/zenstore/gc.cpp @@ -917,7 +917,8 @@ TEST_CASE("gc.basic") IoBuffer Chunk = CreateChunk(128); auto CompressedChunk = Compress(Chunk); - const auto InsertResult = CidStore.AddChunk(CompressedChunk); + const auto InsertResult = + CidStore.AddChunk(CompressedChunk.GetCompressed().Flatten().AsIoBuffer(), IoHash::FromBLAKE3(CompressedChunk.DecodeRawHash())); CHECK(InsertResult.New); GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); @@ -926,7 +927,7 @@ TEST_CASE("gc.basic") CidStore.Flush(); Gc.CollectGarbage(GcCtx); - CHECK(!CidStore.ContainsChunk(IoHash::FromBLAKE3(CompressedChunk.GetRawHash()))); + CHECK(!CidStore.ContainsChunk(IoHash::FromBLAKE3(CompressedChunk.DecodeRawHash()))); } TEST_CASE("gc.full") diff --git a/zenstore/include/zenstore/cidstore.h b/zenstore/include/zenstore/cidstore.h index e8984a83d..16ca78225 100644 --- a/zenstore/include/zenstore/cidstore.h +++ b/zenstore/include/zenstore/cidstore.h @@ -70,7 +70,7 @@ public: }; void Initialize(const CidStoreConfiguration& Config); - InsertResult AddChunk(const CompressedBuffer& ChunkData, InsertMode Mode = InsertMode::kMayBeMovedInPlace); + InsertResult AddChunk(const IoBuffer& ChunkData, const IoHash& RawHash, InsertMode Mode = InsertMode::kMayBeMovedInPlace); IoBuffer FindChunkByCid(const IoHash& DecompressedId); bool ContainsChunk(const IoHash& DecompressedId); void FilterChunks(HashKeySet& InOutChunks); diff --git a/zenutil/cache/cacherequests.cpp b/zenutil/cache/cacherequests.cpp index 1ba2721b6..e6df4b4aa 100644 --- a/zenutil/cache/cacherequests.cpp +++ b/zenutil/cache/cacherequests.cpp @@ -227,7 +227,7 @@ namespace cacherequests { PutCacheRecordRequestValue& Value = Request.Values[It->second]; ZEN_ASSERT(Value.RawHash == ValueHash); Value.Body = Attachment->AsCompressedBinary(); - ZEN_ASSERT(IoHash::FromBLAKE3(Value.Body.GetRawHash()) == Value.RawHash); + ZEN_ASSERT_SLOW(IoHash::FromBLAKE3(Value.Body.DecodeRawHash()) == Value.RawHash); } } }); @@ -268,10 +268,10 @@ namespace cacherequests { const CompressedBuffer& Buffer = Value.Body; if (Buffer) { - IoHash AttachmentHash = IoHash::FromBLAKE3(Buffer.GetRawHash()); + IoHash AttachmentHash = IoHash::FromBLAKE3(Buffer.DecodeRawHash()); // TODO: Slow! Writer.AddBinaryAttachment("RawHash", AttachmentHash); OutPackage.AddAttachment(CbAttachment(Buffer, AttachmentHash)); - Writer.AddInteger("RawSize", Buffer.GetRawSize()); + Writer.AddInteger("RawSize", Buffer.DecodeRawSize()); // TODO: Slow! } else { @@ -500,12 +500,12 @@ namespace cacherequests { Writer.BeginArray("Values"); for (const GetCacheRecordResultValue& Value : RecordResult->Values) { - IoHash AttachmentHash = Value.Body ? IoHash::FromBLAKE3(Value.Body.GetRawHash()) : Value.RawHash; + IoHash AttachmentHash = Value.Body ? IoHash::FromBLAKE3(Value.Body.DecodeRawHash()) : Value.RawHash; Writer.BeginObject(); { Writer.AddObjectId("Id", Value.Id); Writer.AddHash("RawHash", AttachmentHash); - Writer.AddInteger("RawSize", Value.Body ? Value.Body.GetRawSize() : Value.RawSize); + Writer.AddInteger("RawSize", Value.Body ? Value.Body.DecodeRawSize() : Value.RawSize); } Writer.EndObject(); if (Value.Body) @@ -591,12 +591,11 @@ namespace cacherequests { WriteCacheRequestKey(Writer, ValueRequest.Key); if (ValueRequest.Body) { - if (ValueRequest.RawHash != IoHash::Zero && - IoHash::FromBLAKE3(ValueRequest.Body.GetRawHash()) != ValueRequest.RawHash) + IoHash AttachmentHash = IoHash::FromBLAKE3(ValueRequest.Body.DecodeRawHash()); + if (ValueRequest.RawHash != IoHash::Zero && AttachmentHash != ValueRequest.RawHash) { return false; } - IoHash AttachmentHash = IoHash::FromBLAKE3(ValueRequest.Body.GetRawHash()); Writer.AddBinaryAttachment("RawHash", AttachmentHash); OutPackage.AddAttachment(CbAttachment(ValueRequest.Body, AttachmentHash)); } @@ -776,7 +775,7 @@ namespace cacherequests { ValueResult.Body = Attachment ? Attachment->AsCompressedBinary() : CompressedBuffer(); if (ValueResult.Body) { - ValueResult.RawSize = ValueResult.Body.GetRawSize(); + ValueResult.RawSize = ValueResult.Body.DecodeRawSize(); } else { @@ -1042,8 +1041,8 @@ namespace cacherequests { static bool operator==(const PutCacheRecordRequestValue& Lhs, const PutCacheRecordRequestValue& Rhs) { - const IoHash LhsRawHash = Lhs.RawHash != IoHash::Zero ? Lhs.RawHash : IoHash::FromBLAKE3(Lhs.Body.GetRawHash()); - const IoHash RhsRawHash = Rhs.RawHash != IoHash::Zero ? Rhs.RawHash : IoHash::FromBLAKE3(Rhs.Body.GetRawHash()); + const IoHash LhsRawHash = Lhs.RawHash != IoHash::Zero ? Lhs.RawHash : IoHash::FromBLAKE3(Lhs.Body.DecodeRawHash()); + const IoHash RhsRawHash = Rhs.RawHash != IoHash::Zero ? Rhs.RawHash : IoHash::FromBLAKE3(Rhs.Body.DecodeRawHash()); return Lhs.Id == Rhs.Id && LhsRawHash == RhsRawHash && Lhs.Body.GetCompressed().Flatten().GetView().EqualBytes(Rhs.Body.GetCompressed().Flatten().GetView()); } @@ -1112,7 +1111,7 @@ namespace cacherequests { { return false; } - if (bool(Lhs.Body) && Lhs.Body.GetRawHash() != Rhs.Body.GetRawHash()) + if (bool(Lhs.Body) && Lhs.Body.DecodeRawHash() != Rhs.Body.DecodeRawHash()) { return false; } @@ -1313,31 +1312,31 @@ namespace cacherequests { GetCacheRecordsResult FullResult = { {GetCacheRecordResult{.Key = FullPutRequestCopy.Requests[0].Key, .Values = {{.Id = FullPutRequestCopy.Requests[0].Values[0].Id, - .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[0].Values[0].Body.GetRawHash()), - .RawSize = FullPutRequestCopy.Requests[0].Values[0].Body.GetRawSize(), + .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[0].Values[0].Body.DecodeRawHash()), + .RawSize = FullPutRequestCopy.Requests[0].Values[0].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[0].Values[0].Body}, {.Id = FullPutRequestCopy.Requests[0].Values[1].Id, - .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[0].Values[1].Body.GetRawHash()), - .RawSize = FullPutRequestCopy.Requests[0].Values[1].Body.GetRawSize(), + .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[0].Values[1].Body.DecodeRawHash()), + .RawSize = FullPutRequestCopy.Requests[0].Values[1].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[0].Values[1].Body}, {.Id = FullPutRequestCopy.Requests[0].Values[2].Id, - .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[0].Values[2].Body.GetRawHash()), - .RawSize = FullPutRequestCopy.Requests[0].Values[2].Body.GetRawSize(), + .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[0].Values[2].Body.DecodeRawHash()), + .RawSize = FullPutRequestCopy.Requests[0].Values[2].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[0].Values[2].Body}}}, {}, // Simulate not have! GetCacheRecordResult{.Key = FullPutRequestCopy.Requests[2].Key, .Values = {{.Id = FullPutRequestCopy.Requests[2].Values[0].Id, - .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[2].Values[0].Body.GetRawHash()), - .RawSize = FullPutRequestCopy.Requests[2].Values[0].Body.GetRawSize(), + .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[2].Values[0].Body.DecodeRawHash()), + .RawSize = FullPutRequestCopy.Requests[2].Values[0].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[2].Values[0].Body}, {.Id = FullPutRequestCopy.Requests[2].Values[1].Id, - .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[2].Values[1].Body.GetRawHash()), - .RawSize = FullPutRequestCopy.Requests[2].Values[1].Body.GetRawSize(), + .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[2].Values[1].Body.DecodeRawHash()), + .RawSize = FullPutRequestCopy.Requests[2].Values[1].Body.DecodeRawSize(), .Body = {}}, // Simulate not have {.Id = FullPutRequestCopy.Requests[2].Values[2].Id, - .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[2].Values[2].Body.GetRawHash()), - .RawSize = FullPutRequestCopy.Requests[2].Values[2].Body.GetRawSize(), + .RawHash = IoHash::FromBLAKE3(FullPutRequestCopy.Requests[2].Values[2].Body.DecodeRawHash()), + .RawSize = FullPutRequestCopy.Requests[2].Values[2].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[2].Values[2].Body}}}}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); @@ -1369,15 +1368,15 @@ namespace cacherequests { .DefaultPolicy = CachePolicy::StoreLocal, .Namespace = "other_namespace", .Requests = {{.Key = {.Bucket = "finebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, - .RawHash = IoHash::FromBLAKE3(Buffers[0].GetRawHash()), + .RawHash = IoHash::FromBLAKE3(Buffers[0].DecodeRawHash()), .Body = Buffers[0], .Policy = CachePolicy::Local}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, - .RawHash = IoHash::FromBLAKE3(Buffers[1].GetRawHash()), + .RawHash = IoHash::FromBLAKE3(Buffers[1].DecodeRawHash()), .Body = Buffers[1], .Policy = CachePolicy::Remote}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}, - .RawHash = IoHash::FromBLAKE3(Buffers[2].GetRawHash())}}}; + .RawHash = IoHash::FromBLAKE3(Buffers[2].DecodeRawHash())}}}; CbPackage FullRequestPackage; CHECK(FullRequest.Format(FullRequestPackage)); @@ -1441,12 +1440,12 @@ namespace cacherequests { {MakeCompressedBuffer(5123), MakeCompressedBuffer(2321), MakeCompressedBuffer(2333)}}; CacheValuesResult FullResult = { .Results = { - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][0].GetRawHash()), .Body = Buffers[0][0]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][1].GetRawHash()), .Body = Buffers[0][1]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][2].GetRawHash()), .Body = Buffers[0][2]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][0].GetRawHash()), .Body = Buffers[2][0]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][1].GetRawHash()), .Body = Buffers[2][1]}, - CacheValueResult{.RawSize = Buffers[2][2].GetRawSize(), .RawHash = IoHash::FromBLAKE3(Buffers[2][2].GetRawHash())}}}; + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][0].DecodeRawHash()), .Body = Buffers[0][0]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][1].DecodeRawHash()), .Body = Buffers[0][1]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][2].DecodeRawHash()), .Body = Buffers[0][2]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][0].DecodeRawHash()), .Body = Buffers[2][0]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][1].DecodeRawHash()), .Body = Buffers[2][1]}, + CacheValueResult{.RawSize = Buffers[2][2].DecodeRawSize(), .RawHash = IoHash::FromBLAKE3(Buffers[2][2].DecodeRawHash())}}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); CacheValuesResult FullResultCopy; @@ -1511,12 +1510,12 @@ namespace cacherequests { {MakeCompressedBuffer(5123), MakeCompressedBuffer(2321), MakeCompressedBuffer(2333)}}; GetCacheChunksResult FullResult = { .Results = { - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][0].GetRawHash()), .Body = Buffers[0][0]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][1].GetRawHash()), .Body = Buffers[0][1]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][2].GetRawHash()), .Body = Buffers[0][2]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][0].GetRawHash()), .Body = Buffers[2][0]}, - CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][1].GetRawHash()), .Body = Buffers[2][1]}, - CacheValueResult{.RawSize = Buffers[2][2].GetRawSize(), .RawHash = IoHash::FromBLAKE3(Buffers[2][2].GetRawHash())}}}; + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][0].DecodeRawHash()), .Body = Buffers[0][0]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][1].DecodeRawHash()), .Body = Buffers[0][1]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[0][2].DecodeRawHash()), .Body = Buffers[0][2]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][0].DecodeRawHash()), .Body = Buffers[2][0]}, + CacheValueResult{.RawSize = 0, .RawHash = IoHash::FromBLAKE3(Buffers[2][1].DecodeRawHash()), .Body = Buffers[2][1]}, + CacheValueResult{.RawSize = Buffers[2][2].DecodeRawSize(), .RawHash = IoHash::FromBLAKE3(Buffers[2][2].DecodeRawHash())}}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); GetCacheChunksResult FullResultCopy; |