private Result <int, ErrorCodes?> MultyThreadedDecompression(Stream inputStream, Stream outputStream) { using (var writerFinished = new ManualResetEvent(false)) using (var workersPool = new WorkersPool.WorkersPool(settings.ThreadsCount, log)) using (var tasksQueue = new BlockingTasksQueue(settings.CompressingQueueSize, workersPool, log)) { var outputFile = new OutputFileWithoutOffsetStore(outputStream); var blockId = 0; var writeDecompressedTask = RunDequeueingOutputWriteDecompressedBlocks(writerFinished, outputFile, tasksQueue); workersPool.PushTask(writeDecompressedTask); var needWaitTasksFinished = false; var needEndTasks = true; StreamingGzipBlock streamingGzipBlock = null; try { foreach (var block in gzipBlockSplitter.SplitBlocks(inputStream)) { if (block is StreamingGzipBlock gzipBlock) { tasksQueue.EndTasks(); needEndTasks = false; if (needWaitTasksFinished) { writerFinished.WaitOne(); needWaitTasksFinished = false; } streamingGzipBlock = gzipBlock; break; } tasksQueue.EnqueueTask( new DelegateTask( blockId++.ToString(), () => ((IndependentGzipBlock)block).Decompress()) ); needWaitTasksFinished = true; } } finally { if (needEndTasks) { tasksQueue.EndTasks(); } } if (needWaitTasksFinished) { writerFinished.WaitOne(); } streamingGzipBlock?.WriteDecompressedDataTo(outputStream); return(outputFile.CompressionRatio(inputStream.Length)); } }
private static IWorkerTask RunDequeueingOutputWriteDecompressedBlocks( ManualResetEvent writerFinished, OutputFileWithoutOffsetStore outputFile, BlockingTasksQueue tasksQueue) { return(new DelegateWorkerTask( "Writer", () => { var error = WriteCompressedBlocks(); if (error != null) { throw new CompressorException(error.Value); } })); ErrorCodes?WriteCompressedBlocks() { try { foreach (var result in tasksQueue.ConsumeTaskResults()) { if (result.IsFailed) { if (result.Exception is CompressorException fileSystemException) { return(fileSystemException.Error); } throw result.Exception; } var decompressedBlock = (byte[])result.Result; var error = outputFile.Append(decompressedBlock.ToSegment()); if (error != null) { return(error.Value); } } return(null); } finally { writerFinished.Set(); } } }