aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2024-03-20 15:13:03 +0100
committerGitHub Enterprise <[email protected]>2024-03-20 15:13:03 +0100
commitd6071e029b7cb9eec6abfa612b16abc16c84e6a3 (patch)
tree21745ab3bb73594a56b2fc548022d900df8ea62f /src
parentremove hv tags on actions since they are no longer useful (diff)
downloadzen-d6071e029b7cb9eec6abfa612b16abc16c84e6a3.tar.xz
zen-d6071e029b7cb9eec6abfa612b16abc16c84e6a3.zip
non memory copy compressed range (#13)
* Add CompressedBuffer::GetRange that references source data rather than make a memory copy * Use Compressed.CopyRange in project store GetChunkRange * docs for CompressedBuffer::CopyRange and CompressedBuffer::GetRange
Diffstat (limited to 'src')
-rw-r--r--src/zencore/compress.cpp192
-rw-r--r--src/zencore/include/zencore/compress.h32
-rw-r--r--src/zenserver/projectstore/httpprojectstore.cpp9
-rw-r--r--src/zenserver/projectstore/projectstore.cpp56
-rw-r--r--src/zenserver/projectstore/projectstore.h6
-rw-r--r--src/zenserver/vfs/vfsimpl.cpp26
6 files changed, 277 insertions, 44 deletions
diff --git a/src/zencore/compress.cpp b/src/zencore/compress.cpp
index a8e8a79f4..58be65f13 100644
--- a/src/zencore/compress.cpp
+++ b/src/zencore/compress.cpp
@@ -1097,6 +1097,88 @@ ValidBufferOrEmpty(BufferType&& CompressedData, IoHash& OutRawHash, uint64_t& Ou
}
CompositeBuffer
+GetCompressedRange(const BufferHeader& Header, const CompositeBuffer& CompressedData, uint64_t RawOffset, uint64_t RawSize)
+{
+ if (Header.TotalRawSize < RawOffset + RawSize)
+ {
+ return CompositeBuffer();
+ }
+ if (Header.Method == CompressionMethod::None)
+ {
+ BufferHeader NewHeader = Header;
+ NewHeader.Crc32 = 0;
+ NewHeader.TotalRawSize = RawSize;
+ NewHeader.TotalCompressedSize = NewHeader.TotalRawSize + sizeof(BufferHeader);
+ NewHeader.RawHash = BLAKE3();
+
+ UniqueBuffer HeaderData = UniqueBuffer::Alloc(sizeof(BufferHeader));
+ NewHeader.Write(HeaderData);
+
+ return CompositeBuffer(HeaderData.MoveToShared(), CompressedData.Mid(sizeof(BufferHeader) + RawOffset, RawSize).MakeOwned());
+ }
+ else
+ {
+ UniqueBuffer BlockSizeBuffer;
+ MemoryView BlockSizeView =
+ CompressedData.ViewOrCopyRange(sizeof(BufferHeader), Header.BlockCount * sizeof(uint32_t), BlockSizeBuffer);
+ std::span<uint32_t const> CompressedBlockSizes(reinterpret_cast<const uint32_t*>(BlockSizeView.GetData()), Header.BlockCount);
+
+ const uint64_t BlockSize = uint64_t(1) << Header.BlockSizeExponent;
+ const uint64_t LastBlockSize = BlockSize - ((Header.BlockCount * BlockSize) - Header.TotalRawSize);
+ const size_t FirstBlock = uint64_t(RawOffset / BlockSize);
+ const size_t LastBlock = uint64_t((RawOffset + RawSize - 1) / BlockSize);
+ uint64_t CompressedOffset = sizeof(BufferHeader) + uint64_t(Header.BlockCount) * sizeof(uint32_t);
+
+ const uint64_t NewBlockCount = LastBlock - FirstBlock + 1;
+ const uint64_t NewMetaSize = NewBlockCount * sizeof(uint32_t);
+ uint64_t NewCompressedSize = 0;
+ uint64_t NewTotalRawSize = 0;
+ std::vector<uint32_t> NewCompressedBlockSizes;
+
+ NewCompressedBlockSizes.reserve(NewBlockCount);
+ for (size_t BlockIndex = FirstBlock; BlockIndex <= LastBlock; ++BlockIndex)
+ {
+ const uint64_t UncompressedBlockSize = (BlockIndex == Header.BlockCount - 1) ? LastBlockSize : BlockSize;
+ NewTotalRawSize += UncompressedBlockSize;
+
+ const uint32_t CompressedBlockSize = CompressedBlockSizes[BlockIndex];
+ NewCompressedBlockSizes.push_back(CompressedBlockSize);
+ NewCompressedSize += ByteSwap(CompressedBlockSize);
+ }
+
+ const uint64_t NewTotalCompressedSize = sizeof(BufferHeader) + NewBlockCount * sizeof(uint32_t) + NewCompressedSize;
+ const uint64_t NewCompressedHeaderSize = sizeof(BufferHeader) + NewBlockCount * sizeof(uint32_t);
+ UniqueBuffer NewCompressedHeaderData = UniqueBuffer::Alloc(NewCompressedHeaderSize);
+
+ // Seek to first compressed block
+ for (size_t BlockIndex = 0; BlockIndex < FirstBlock; ++BlockIndex)
+ {
+ const uint64_t CompressedBlockSize = ByteSwap(CompressedBlockSizes[BlockIndex]);
+ CompressedOffset += CompressedBlockSize;
+ }
+
+ CompositeBuffer NewCompressedData = CompressedData.Mid(CompressedOffset, NewCompressedSize).MakeOwned();
+
+ // Copy block sizes
+ NewCompressedHeaderData.GetMutableView().Mid(sizeof(BufferHeader), NewMetaSize).CopyFrom(MakeMemoryView(NewCompressedBlockSizes));
+
+ BufferHeader NewHeader;
+ NewHeader.Crc32 = 0;
+ NewHeader.Method = Header.Method;
+ NewHeader.Compressor = Header.Compressor;
+ NewHeader.CompressionLevel = Header.CompressionLevel;
+ NewHeader.BlockSizeExponent = Header.BlockSizeExponent;
+ NewHeader.BlockCount = static_cast<uint32_t>(NewBlockCount);
+ NewHeader.TotalRawSize = NewTotalRawSize;
+ NewHeader.TotalCompressedSize = NewTotalCompressedSize;
+ NewHeader.RawHash = BLAKE3();
+ NewHeader.Write(NewCompressedHeaderData.GetMutableView().Left(sizeof(BufferHeader) + NewMetaSize));
+
+ return CompositeBuffer(NewCompressedHeaderData.MoveToShared(), NewCompressedData);
+ }
+}
+
+CompositeBuffer
CopyCompressedRange(const BufferHeader& Header, const CompositeBuffer& CompressedData, uint64_t RawOffset, uint64_t RawSize)
{
if (Header.TotalRawSize < RawOffset + RawSize)
@@ -1338,6 +1420,19 @@ CompressedBuffer::CopyRange(uint64_t RawOffset, uint64_t RawSize) const
return Range;
}
+CompressedBuffer
+CompressedBuffer::GetRange(uint64_t RawOffset, uint64_t RawSize) const
+{
+ using namespace detail;
+ const BufferHeader Header = BufferHeader::Read(CompressedData);
+ const uint64_t TotalRawSize = RawSize < ~uint64_t(0) ? RawSize : Header.TotalRawSize - RawOffset;
+
+ CompressedBuffer Range;
+ Range.CompressedData = GetCompressedRange(Header, CompressedData, RawOffset, TotalRawSize);
+
+ return Range;
+}
+
bool
CompressedBuffer::TryDecompressTo(MutableMemoryView RawView, uint64_t RawOffset) const
{
@@ -1920,6 +2015,66 @@ TEST_CASE("CompressedBuffer")
}
}
+ SUBCASE("get range")
+ {
+ const uint64_t BlockSize = 64 * sizeof(uint64_t);
+ const uint64_t N = 1000;
+ std::vector<uint64_t> ExpectedValues = GenerateData(N);
+
+ CompressedBuffer Compressed = CompressedBuffer::Compress(SharedBuffer::MakeView(MakeMemoryView(ExpectedValues)),
+ OodleCompressor::Mermaid,
+ OodleCompressionLevel::Optimal4,
+ BlockSize);
+
+ {
+ const uint64_t OffsetCount = 0;
+ const uint64_t Count = N;
+ SharedBuffer Uncompressed = Compressed.GetRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress();
+ std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+
+ {
+ const uint64_t OffsetCount = 64;
+ const uint64_t Count = N - 64;
+ SharedBuffer Uncompressed = Compressed.GetRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress();
+ std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+
+ {
+ const uint64_t OffsetCount = 64 * 2 + 32;
+ const uint64_t Count = N - OffsetCount;
+ const uint64_t RawOffset = OffsetCount * sizeof(uint64_t);
+ const uint64_t RawSize = Count * sizeof(uint64_t);
+ uint64_t FirstBlockOffset = RawOffset % BlockSize;
+
+ SharedBuffer Uncompressed = Compressed.GetRange(RawOffset, RawSize).Decompress();
+ std::span<uint64_t const> AllValues((const uint64_t*)Uncompressed.GetData(), RawSize / sizeof(uint64_t));
+ std::span<uint64_t const> Values((const uint64_t*)(((const uint8_t*)(Uncompressed.GetData()) + FirstBlockOffset)),
+ RawSize / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+
+ {
+ const uint64_t OffsetCount = 64 * 2 + 63;
+ const uint64_t Count = N - OffsetCount - 5;
+ const uint64_t RawOffset = OffsetCount * sizeof(uint64_t);
+ const uint64_t RawSize = Count * sizeof(uint64_t);
+ uint64_t FirstBlockOffset = RawOffset % BlockSize;
+
+ SharedBuffer Uncompressed = Compressed.GetRange(RawOffset, RawSize).Decompress();
+ std::span<uint64_t const> AllValues((const uint64_t*)Uncompressed.GetData(), RawSize / sizeof(uint64_t));
+ std::span<uint64_t const> Values((const uint64_t*)(((const uint8_t*)(Uncompressed.GetData()) + FirstBlockOffset)),
+ RawSize / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+ }
+
SUBCASE("copy uncompressed range")
{
const uint64_t N = 1000;
@@ -1956,6 +2111,43 @@ TEST_CASE("CompressedBuffer")
ValidateData(Values, ExpectedValues, OffsetCount);
}
}
+
+ SUBCASE("get uncompressed range")
+ {
+ const uint64_t N = 1000;
+ std::vector<uint64_t> ExpectedValues = GenerateData(N);
+
+ CompressedBuffer Compressed = CompressedBuffer::Compress(SharedBuffer::MakeView(MakeMemoryView(ExpectedValues)),
+ OodleCompressor::NotSet,
+ OodleCompressionLevel::None);
+
+ {
+ const uint64_t OffsetCount = 0;
+ const uint64_t Count = N;
+ SharedBuffer Uncompressed = Compressed.GetRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress();
+ std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+
+ {
+ const uint64_t OffsetCount = 1;
+ const uint64_t Count = N - OffsetCount;
+ SharedBuffer Uncompressed = Compressed.GetRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress();
+ std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+
+ {
+ const uint64_t OffsetCount = 42;
+ const uint64_t Count = 100;
+ SharedBuffer Uncompressed = Compressed.GetRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress();
+ std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t));
+ CHECK(Values.size() == Count);
+ ValidateData(Values, ExpectedValues, OffsetCount);
+ }
+ }
}
TEST_CASE("CompressedBufferReader")
diff --git a/src/zencore/include/zencore/compress.h b/src/zencore/include/zencore/compress.h
index c51b5407f..5e761ceef 100644
--- a/src/zencore/include/zencore/compress.h
+++ b/src/zencore/include/zencore/compress.h
@@ -130,9 +130,41 @@ public:
/** Returns the hash of the raw data. Zero on error or if this is null. */
[[nodiscard]] ZENCORE_API IoHash DecodeRawHash() const;
+ /**
+ * Returns a block aligned range of a compressed buffer.
+ *
+ * This extracts a sub-range from the compressed buffer, if the buffer is block-compressed
+ * it will align start and end to end up on block boundaries.
+ *
+ * The resulting segments in the CompressedBuffer will are allocated and the data is copied
+ * from the source buffers.
+ *
+ * A new header will be allocated and generated.
+ *
+ * The RawHash field of the header will be zero as we do not calculate the raw hash for the sub-range
+ *
+ * @return A sub-range from the compressed buffer that encompasses RawOffset and RawSize
+ */
[[nodiscard]] ZENCORE_API CompressedBuffer CopyRange(uint64_t RawOffset, uint64_t RawSize = ~uint64_t(0)) const;
/**
+ * Returns a block aligned range of a compressed buffer.
+ *
+ * This extracts a sub-range from the compressed buffer, if the buffer is block-compressed
+ * it will align start and end to end up on block boundaries.
+ *
+ * The resulting segments in the CompressedBuffer will reference the source buffers so it won't
+ * allocate memory and copy data for the compressed data blocks.
+ *
+ * A new header will be allocated and generated.
+ *
+ * The RawHash field of the header will be zero as we do not calculate the raw hash for the sub-range
+ *
+ * @return A sub-range from the compressed buffer that encompasses RawOffset and RawSize
+ */
+ [[nodiscard]] ZENCORE_API CompressedBuffer GetRange(uint64_t RawOffset, uint64_t RawSize = ~uint64_t(0)) const;
+
+ /**
* Returns the compressor and compression level used by this buffer.
*
* The compressor and compression level may differ from those specified when creating the buffer
diff --git a/src/zenserver/projectstore/httpprojectstore.cpp b/src/zenserver/projectstore/httpprojectstore.cpp
index 0ba49cf8a..bc71e2fa0 100644
--- a/src/zenserver/projectstore/httpprojectstore.cpp
+++ b/src/zenserver/projectstore/httpprojectstore.cpp
@@ -768,14 +768,15 @@ HttpProjectService::HandleChunkByIdRequest(HttpRouterRequest& Req)
HttpContentType AcceptType = HttpReq.AcceptContentType();
- IoBuffer Chunk;
+ CompositeBuffer Chunk;
+ HttpContentType ContentType;
std::pair<HttpResponseCode, std::string> Result =
- m_ProjectStore->GetChunkRange(ProjectId, OplogId, ChunkId, Offset, Size, AcceptType, Chunk);
+ m_ProjectStore->GetChunkRange(ProjectId, OplogId, ChunkId, Offset, Size, AcceptType, Chunk, ContentType);
if (Result.first == HttpResponseCode::OK)
{
m_ProjectStats.ChunkHitCount++;
- ZEN_DEBUG("chunk - '{}/{}/{}' '{}'", ProjectId, OplogId, ChunkId, ToString(Chunk.GetContentType()));
- return HttpReq.WriteResponse(HttpResponseCode::OK, Chunk.GetContentType(), Chunk);
+ ZEN_DEBUG("chunk - '{}/{}/{}' '{}'", ProjectId, OplogId, ChunkId, ToString(ContentType));
+ return HttpReq.WriteResponse(HttpResponseCode::OK, ContentType, Chunk);
}
else if (Result.first == HttpResponseCode::NotFound)
{
diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp
index cfa53c080..e4a39e55f 100644
--- a/src/zenserver/projectstore/projectstore.cpp
+++ b/src/zenserver/projectstore/projectstore.cpp
@@ -2647,7 +2647,8 @@ ProjectStore::GetChunkRange(const std::string_view ProjectId,
uint64_t Offset,
uint64_t Size,
ZenContentType AcceptType,
- IoBuffer& OutChunk)
+ CompositeBuffer& OutChunk,
+ ZenContentType& OutContentType)
{
if (ChunkId.size() != 2 * sizeof(Oid::OidBits))
{
@@ -2656,7 +2657,7 @@ ProjectStore::GetChunkRange(const std::string_view ProjectId,
const Oid Obj = Oid::FromHexString(ChunkId);
- return GetChunkRange(ProjectId, OplogId, Obj, Offset, Size, AcceptType, OutChunk);
+ return GetChunkRange(ProjectId, OplogId, Obj, Offset, Size, AcceptType, OutChunk, OutContentType);
}
std::pair<HttpResponseCode, std::string>
@@ -2666,7 +2667,8 @@ ProjectStore::GetChunkRange(const std::string_view ProjectId,
uint64_t Offset,
uint64_t Size,
ZenContentType AcceptType,
- IoBuffer& OutChunk)
+ CompositeBuffer& OutChunk,
+ ZenContentType& OutContentType)
{
bool IsOffset = Offset != 0 || Size != ~(0ull);
@@ -2690,10 +2692,9 @@ ProjectStore::GetChunkRange(const std::string_view ProjectId,
return {HttpResponseCode::NotFound, {}};
}
- OutChunk = Chunk;
- HttpContentType ContentType = Chunk.GetContentType();
+ OutContentType = Chunk.GetContentType();
- if (Chunk.GetContentType() == HttpContentType::kCompressedBinary)
+ if (OutContentType == ZenContentType::kCompressedBinary)
{
IoHash RawHash;
uint64_t RawSize;
@@ -2702,46 +2703,47 @@ ProjectStore::GetChunkRange(const std::string_view ProjectId,
if (IsOffset)
{
- if ((Offset + Size) > RawSize)
+ if (Size == ~(0ull) || (Offset + Size) > RawSize)
{
Size = RawSize - Offset;
}
- if (AcceptType == HttpContentType::kBinary)
+ if (AcceptType == ZenContentType::kBinary)
{
- OutChunk = Compressed.Decompress(Offset, Size).AsIoBuffer();
- OutChunk.SetContentType(HttpContentType::kBinary);
+ OutChunk = CompositeBuffer(Compressed.Decompress(Offset, Size));
+ OutContentType = ZenContentType::kBinary;
}
else
{
// Value will be a range of compressed blocks that covers the requested range
// The client will have to compensate for any offsets that do not land on an even block size multiple
- OutChunk = Compressed.CopyRange(Offset, Size).GetCompressed().Flatten().AsIoBuffer();
- OutChunk.SetContentType(HttpContentType::kCompressedBinary);
+ OutChunk = Compressed.GetRange(Offset, Size).GetCompressed();
}
}
else
{
- if (AcceptType == HttpContentType::kBinary)
+ if (AcceptType == ZenContentType::kBinary)
{
- OutChunk = Compressed.Decompress().AsIoBuffer();
- OutChunk.SetContentType(HttpContentType::kBinary);
+ OutChunk = Compressed.DecompressToComposite();
}
else
{
- OutChunk = Compressed.GetCompressed().Flatten().AsIoBuffer();
- OutChunk.SetContentType(HttpContentType::kCompressedBinary);
+ OutChunk = Compressed.GetCompressed();
+ OutContentType = ZenContentType::kCompressedBinary;
}
}
}
else if (IsOffset)
{
- if ((Offset + Size) > Chunk.GetSize())
+ if (Size == ~(0ull) || (Offset + Size) > Chunk.GetSize())
{
Size = Chunk.GetSize() - Offset;
}
- OutChunk = IoBuffer(std::move(Chunk), Offset, Size);
- OutChunk.SetContentType(ContentType);
+ OutChunk = CompositeBuffer(SharedBuffer(IoBuffer(std::move(Chunk), Offset, Size)));
+ }
+ else
+ {
+ OutChunk = CompositeBuffer(SharedBuffer(std::move(Chunk)));
}
return {HttpResponseCode::OK, {}};
@@ -4428,7 +4430,8 @@ TEST_CASE("project.store.partial.read")
CHECK(RawSize == Attachments[OpIds[1]][0].second.DecodeRawSize());
}
- IoBuffer ChunkResult;
+ CompositeBuffer ChunkResult;
+ HttpContentType ContentType;
CHECK(ProjectStore
.GetChunkRange("proj1"sv,
"oplog1"sv,
@@ -4436,13 +4439,14 @@ TEST_CASE("project.store.partial.read")
0,
~0ull,
HttpContentType::kCompressedBinary,
- ChunkResult)
+ ChunkResult,
+ ContentType)
.first == HttpResponseCode::OK);
CHECK(ChunkResult);
CHECK(CompressedBuffer::FromCompressedNoValidate(std::move(ChunkResult)).DecodeRawSize() ==
Attachments[OpIds[2]][1].second.DecodeRawSize());
- IoBuffer PartialChunkResult;
+ CompositeBuffer PartialChunkResult;
CHECK(ProjectStore
.GetChunkRange("proj1"sv,
"oplog1"sv,
@@ -4450,13 +4454,13 @@ TEST_CASE("project.store.partial.read")
5,
1773,
HttpContentType::kCompressedBinary,
- PartialChunkResult)
+ PartialChunkResult,
+ ContentType)
.first == HttpResponseCode::OK);
CHECK(PartialChunkResult);
IoHash PartialRawHash;
uint64_t PartialRawSize;
- CompressedBuffer PartialCompressedResult =
- CompressedBuffer::FromCompressed(SharedBuffer(PartialChunkResult), PartialRawHash, PartialRawSize);
+ CompressedBuffer PartialCompressedResult = CompressedBuffer::FromCompressed(PartialChunkResult, PartialRawHash, PartialRawSize);
CHECK(PartialRawSize >= 1773);
uint64_t RawOffsetInPartialCompressed = GetCompressedOffset(PartialCompressedResult, 5);
diff --git a/src/zenserver/projectstore/projectstore.h b/src/zenserver/projectstore/projectstore.h
index d8c053649..eda336150 100644
--- a/src/zenserver/projectstore/projectstore.h
+++ b/src/zenserver/projectstore/projectstore.h
@@ -333,14 +333,16 @@ public:
uint64_t Offset,
uint64_t Size,
ZenContentType AcceptType,
- IoBuffer& OutChunk);
+ CompositeBuffer& OutChunk,
+ ZenContentType& OutContentType);
std::pair<HttpResponseCode, std::string> GetChunkRange(const std::string_view ProjectId,
const std::string_view OplogId,
const std::string_view ChunkId,
uint64_t Offset,
uint64_t Size,
ZenContentType AcceptType,
- IoBuffer& OutChunk);
+ CompositeBuffer& OutChunk,
+ ZenContentType& OutContentType);
std::pair<HttpResponseCode, std::string> GetChunk(const std::string_view ProjectId,
const std::string_view OplogId,
const std::string_view Cid,
diff --git a/src/zenserver/vfs/vfsimpl.cpp b/src/zenserver/vfs/vfsimpl.cpp
index f528b2620..5ef89ee77 100644
--- a/src/zenserver/vfs/vfsimpl.cpp
+++ b/src/zenserver/vfs/vfsimpl.cpp
@@ -38,21 +38,23 @@ VfsOplogDataSource::ReadNamedData(std::string_view Path, void* Buffer, uint64_t
void
VfsOplogDataSource::ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount)
{
- IoBuffer ChunkBuffer;
- auto Result =
- m_ProjectStore->GetChunkRange(m_ProjectId, m_OplogId, ChunkId, 0, ~0ull, ZenContentType::kCompressedBinary, /* out */ ChunkBuffer);
+ CompositeBuffer ChunkBuffer;
+ ZenContentType ContentType;
+ auto Result = m_ProjectStore->GetChunkRange(m_ProjectId,
+ m_OplogId,
+ ChunkId,
+ 0,
+ ~0ull,
+ ZenContentType::kCompressedBinary,
+ /* out */ ChunkBuffer,
+ /* out */ ContentType);
if (Result.first == HttpResponseCode::OK)
{
- const uint8_t* SourceBuffer = reinterpret_cast<const uint8_t*>(ChunkBuffer.GetData());
- uint64_t AvailableBufferBytes = ChunkBuffer.GetSize();
-
- ZEN_ASSERT(AvailableBufferBytes >= ByteOffset);
- AvailableBufferBytes -= ByteOffset;
- SourceBuffer += ByteOffset;
-
- ZEN_ASSERT(AvailableBufferBytes >= ByteCount);
- memcpy(Buffer, SourceBuffer, ByteCount);
+ ZEN_ASSERT(ChunkBuffer.GetSize() >= ByteOffset);
+ ZEN_ASSERT(ChunkBuffer.GetSize() - ByteOffset >= ByteCount);
+ MutableMemoryView Target(Buffer, ByteCount);
+ ChunkBuffer.CopyTo(Target, ByteOffset);
}
}