Skip to content

Commit

Permalink
[core] Flush blocks asynchronously when hashing from memory
Browse files Browse the repository at this point in the history
If we're reading data from the in-memory cache, we should not
block on the flush-to-disk aspect. As we are holding the
incremental hash lock for that piece we need to avoid lengthy
delays from operations like flushing to disk.
  • Loading branch information
alanmcgovern committed Feb 25, 2021
1 parent a0de480 commit 882f536
Showing 1 changed file with 16 additions and 13 deletions.
29 changes: 16 additions & 13 deletions src/MonoTorrent/MonoTorrent.Client.PieceWriters/MemoryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public async ReusableTask<bool> ReadAsync (ITorrentData torrent, BlockInfo block
return await ReadFromFilesAsync (torrent, block, buffer).ConfigureAwait (false) == block.RequestLength;
}

public async ReusableTask<bool> ReadFromCacheAsync (ITorrentData torrent, BlockInfo block, byte[] buffer)
public ReusableTask<bool> ReadFromCacheAsync (ITorrentData torrent, BlockInfo block, byte[] buffer)
{
if (torrent == null)
throw new ArgumentNullException (nameof (torrent));
Expand All @@ -146,24 +146,27 @@ public async ReusableTask<bool> ReadFromCacheAsync (ITorrentData torrent, BlockI
if (cached.Block != block)
continue;

if (cached.Flushing) {
Buffer.BlockCopy (cached.Buffer, 0, buffer, 0, block.RequestLength);
} else {
Buffer.BlockCopy (cached.Buffer, 0, buffer, 0, block.RequestLength);
if (!cached.Flushing) {
blocks[i] = cached.SetFlushing ();
using (cached.BufferReleaser) {
var asyncWrite = WriteToFilesAsync (torrent, block, cached.Buffer);
Buffer.BlockCopy (cached.Buffer, 0, buffer, 0, block.RequestLength);
Interlocked.Add (ref cacheUsed, -block.RequestLength);
await asyncWrite;
blocks.Remove (cached);
}
FlushBlockAsync (torrent, blocks, cached);
}
Interlocked.Add (ref cacheHits, block.RequestLength);
return true;
return ReusableTask.FromResult(true);
}
}

return false;
return ReusableTask.FromResult (false);
}

async void FlushBlockAsync (ITorrentData torrent, List<CachedBlock> blocks, CachedBlock cached)
{
// FIXME: How do we handle failures from this?
using (cached.BufferReleaser) {
await WriteToFilesAsync (torrent, cached.Block, cached.Buffer);
Interlocked.Add (ref cacheUsed, -cached.Block.RequestLength);
blocks.Remove (cached);
}
}

public async ReusableTask WriteAsync (ITorrentData torrent, BlockInfo block, byte[] buffer, bool preferSkipCache)
Expand Down

0 comments on commit 882f536

Please sign in to comment.