// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; namespace EpicGames.Horde.Storage { /// /// Request for a chunk to be read before being written to disk /// /// File to read from /// Offset within the output file /// Handle to the blob data record class ChunkReadRequest(OutputFile File, long Offset, IHashedBlobRef Handle) : BlobReadRequest(Handle); /// /// Implementation of designed for reading leaf chunks of data from storage /// class BatchChunkReader : BatchBlobReader, IDisposable { public const int DefaultMaxBatchSize = 20; /// /// Maximum number of exports to write in a single request /// public int MaxBatchSize { get => _maxBatchSize; init { if (value > 0) { _maxBatchSize = value; } } } readonly int _maxBatchSize = DefaultMaxBatchSize; readonly ChannelWriter _writer; /// /// Constructor /// public BatchChunkReader(ChannelWriter writer) { _writer = writer; } /// protected override async ValueTask HandleResponsesAsync(List> responses, CancellationToken cancellationToken) { for (int idx = 0; idx < responses.Count;) { int firstIdx = idx; List batch = new List(); for (; idx < responses.Count && batch.Count < MaxBatchSize && responses[idx].Request.File == responses[firstIdx].Request.File; idx++) { BlobReadResponse response = responses[idx]; OutputChunk chunk = new OutputChunk(response.Request.File, response.Request.Offset, response.Data.Data, response.Request.Handle, response.Data); batch.Add(chunk); } await _writer.WriteAsync(batch.ToArray(), cancellationToken); } } } }