public async ReusableTask WriteAsync(ITorrentFileInfo file, long offset, byte[] buffer, int bufferOffset, int count) { Check.File(file); Check.Buffer(buffer); if (offset < 0 || offset + count > file.Length) { throw new ArgumentOutOfRangeException(nameof(offset)); } using (await Limiter.EnterAsync()) { using var rented = await StreamCache.GetOrCreateStreamAsync(file, FileAccess.ReadWrite).ConfigureAwait(false); // FileStream.WriteAsync does some work synchronously, according to the profiler. // It looks like if the file is too small it is expanded (SetLength is called) // synchronously before the asynchronous Write is performed. // // We also want the Seek operation to execute on the threadpool. await MainLoop.SwitchToThreadpool(); await rented.Stream.SeekAsync(offset).ConfigureAwait(false); await rented.Stream.WriteAsync(buffer, bufferOffset, count).ConfigureAwait(false); WriteMonitor?.AddDelta(count); } }
public async ReusableTask <int> ReadAsync(ITorrentFileInfo file, long offset, byte[] buffer, int bufferOffset, int count) { Check.File(file); Check.Buffer(buffer); if (offset < 0 || offset + count > file.Length) { throw new ArgumentOutOfRangeException(nameof(offset)); } using (await Limiter.EnterAsync()) { using var rented = await StreamCache.GetOrCreateStreamAsync(file, FileAccess.Read).ConfigureAwait(false); await MainLoop.SwitchToThreadpool(); if (rented.Stream.Length < offset + count) { return(0); } if (rented.Stream.Position != offset) { await rented.Stream.SeekAsync(offset); } ReadMonitor?.AddDelta(count); return(await rented.Stream.ReadAsync(buffer, bufferOffset, count)); } }