public void Write(TorrentFile file, long offset, byte[] buffer, int bufferOffset, int count, bool forceWrite) { if (forceWrite) { Writer.Write(file, offset, buffer, bufferOffset, count); } else { if (CacheUsed > (Capacity - count)) { Flush(0); } var releaser = ClientEngine.BufferPool.Rent(count, out byte[] cacheBuffer); Buffer.BlockCopy(buffer, bufferOffset, cacheBuffer, 0, count); var block = new CachedBlock { Buffer = cacheBuffer, BufferReleaser = releaser, Count = count, Offset = offset, File = file }; CachedBlocks.Add(block); Interlocked.Add(ref cacheUsed, block.Count); } }
public ReusableTask <bool> ReadFromCacheAsync(ITorrentData torrent, BlockInfo block, Memory <byte> buffer) { if (torrent == null) { throw new ArgumentNullException(nameof(torrent)); } if (CachedBlocks.TryGetValue(torrent, out List <CachedBlock> blocks)) { for (int i = 0; i < blocks.Count; i++) { var cached = blocks[i]; if (cached.Block != block) { continue; } cached.Buffer.CopyTo(buffer); if (!cached.Flushing) { blocks[i] = cached.SetFlushing(); FlushBlockAsync(torrent, blocks, cached); } Interlocked.Add(ref cacheHits, block.RequestLength); ReadFromCache?.Invoke(this, block); return(ReusableTask.FromResult(true)); } } return(ReusableTask.FromResult(false)); }
public async ReusableTask WriteAsync(ITorrentFileInfo file, long offset, byte[] buffer, int bufferOffset, int count, bool forceWrite) { if (forceWrite) { await Writer.WriteAsync(file, offset, buffer, bufferOffset, count); } else { if (CacheUsed > (Capacity - count)) { await FlushAsync(0); } var releaser = DiskManager.BufferPool.Rent(count, out byte[] cacheBuffer); Buffer.BlockCopy(buffer, bufferOffset, cacheBuffer, 0, count); var block = new CachedBlock { Buffer = cacheBuffer, BufferReleaser = releaser, Count = count, Offset = offset, File = file }; CachedBlocks.Add(block); Interlocked.Add(ref cacheUsed, block.Count); } }
public void Write(TorrentFile file, long offset, byte[] buffer, int bufferOffset, int count, bool forceWrite) { if (forceWrite) { Writer.Write(file, offset, buffer, bufferOffset, count); } else { if (CacheUsed > (Capacity - count)) { Flush(0); } byte[] cacheBuffer = ClientEngine.BufferManager.GetBuffer(count); Buffer.BlockCopy(buffer, bufferOffset, cacheBuffer, 0, count); CachedBlock block = new CachedBlock(); block.Buffer = cacheBuffer; block.Count = count; block.Offset = offset; block.File = file; CachedBlocks.Add(block); Interlocked.Add(ref cacheUsed, block.Count); } }
void Flush (int index) { CachedBlock b = CachedBlocks[index]; CachedBlocks.RemoveAt (index); Interlocked.Add (ref cacheUsed, -b.Count); Write (b.File, b.Offset, b.Buffer, 0, b.Count, true); ClientEngine.BufferPool.Return (b.Buffer); }
void Flush(int index) { CachedBlock b = CachedBlocks[index]; CachedBlocks.RemoveAt(index); Interlocked.Add(ref cacheUsed, -b.Count); using (b.BufferReleaser) Write(b.File, b.Offset, b.Buffer, 0, b.Count, true); }
async ReusableTask FlushAsync(int index) { CachedBlock b = CachedBlocks[index]; CachedBlocks.RemoveAt(index); Interlocked.Add(ref cacheUsed, -b.Count); using (b.BufferReleaser) await WriteAsync(b.File, b.Offset, b.Buffer, 0, b.Count, true); }
public async ReusableTask WriteAsync(ITorrentData torrent, BlockInfo block, Memory <byte> buffer, bool preferSkipCache) { if (preferSkipCache || Capacity < block.RequestLength) { await WriteToFilesAsync(torrent, block, buffer); } else { if (!CachedBlocks.TryGetValue(torrent, out List <CachedBlock> blocks)) { CachedBlocks[torrent] = blocks = new List <CachedBlock> (); } if (CacheUsed > (Capacity - block.RequestLength)) { var firstFlushable = FindFirstFlushable(blocks); if (firstFlushable < 0) { await WriteToFilesAsync(torrent, block, buffer); return; } else { var cached = blocks[firstFlushable]; blocks[firstFlushable] = cached.SetFlushing(); using (cached.BufferReleaser) await WriteToFilesAsync(torrent, cached.Block, cached.Buffer); Interlocked.Add(ref cacheUsed, -cached.Block.RequestLength); blocks.Remove(cached); } } CachedBlock?cache = null; for (int i = 0; i < blocks.Count && !cache.HasValue; i++) { if (blocks[i].Block == block) { cache = blocks[i]; } } if (!cache.HasValue) { var releaser = BufferPool.Rent(block.RequestLength, out Memory <byte> memory); cache = new CachedBlock(block, releaser, memory); blocks.Add(cache.Value); Interlocked.Add(ref cacheUsed, block.RequestLength); } buffer.CopyTo(cache.Value.Buffer); WrittenToCache?.Invoke(this, block); } }
public void Flush (TorrentFile file) { CachedBlocks.RemoveAll (delegate (CachedBlock b) { if (b.File != file) return false; Interlocked.Add (ref cacheUsed, -b.Count); Writer.Write (b.File, b.Offset, b.Buffer, 0, b.Count); ClientEngine.BufferPool.Return (b.Buffer); return true; }); }
public void Flush(TorrentFile file) { CachedBlocks.RemoveAll(delegate(CachedBlock b) { if (b.File != file) { return(false); } Interlocked.Add(ref cacheUsed, -b.Count); Writer.Write(b.File, b.Offset, b.Buffer, 0, b.Count); ClientEngine.BufferManager.FreeBuffer(b.Buffer); return(true); }); }
public async ReusableTask FlushAsync(ITorrentFileInfo file) { foreach (var block in CachedBlocks) { if (block.File != file) { continue; } Interlocked.Add(ref cacheUsed, -block.Count); using (block.BufferReleaser) await Writer.WriteAsync(block.File, block.Offset, block.Buffer, 0, block.Count); } CachedBlocks.RemoveAll(b => b.File == file); }
public void Flush(TorrentFile file) { CachedBlocks.RemoveAll(delegate(CachedBlock b) { if (b.File != file) { return(false); } Interlocked.Add(ref cacheUsed, -b.Count); using (b.BufferReleaser) Writer.Write(b.File, b.Offset, b.Buffer, 0, b.Count); return(true); }); }
public async ReusableTask WriteAsync(ITorrentData torrent, BlockInfo block, byte[] buffer, bool preferSkipCache) { if (preferSkipCache || Capacity < block.RequestLength) { await WriteToFilesAsync(torrent, block, buffer); } else { if (!CachedBlocks.TryGetValue(torrent, out List <CachedBlock> blocks)) { CachedBlocks[torrent] = blocks = new List <CachedBlock> (); } if (CacheUsed > (Capacity - block.RequestLength)) { var cached = blocks[0]; blocks.RemoveAt(0); Interlocked.Add(ref cacheUsed, -block.RequestLength); using (cached.BufferReleaser) await WriteToFilesAsync(torrent, cached.Block, cached.Buffer); } CachedBlock?cache = null; for (int i = 0; i < blocks.Count && !cache.HasValue; i++) { if (blocks[i].Block == block) { cache = blocks[i]; } } if (!cache.HasValue) { cache = new CachedBlock { Block = block, BufferReleaser = DiskManager.BufferPool.Rent(block.RequestLength, out byte[] _), }; blocks.Add(cache.Value); Interlocked.Add(ref cacheUsed, block.RequestLength); } Buffer.BlockCopy(buffer, 0, cache.Value.Buffer, 0, block.RequestLength); } }
public async ReusableTask <int> ReadAsync(ITorrentData torrent, BlockInfo block, byte[] buffer) { if (torrent == null) { throw new ArgumentNullException(nameof(torrent)); } if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (!CachedBlocks.TryGetValue(torrent, out List <CachedBlock> blocks)) { CachedBlocks[torrent] = blocks = new List <CachedBlock> (); } for (int i = 0; i < blocks.Count; i++) { var cached = blocks[i]; if (cached.Block != block) { continue; } blocks.RemoveAt(i); Interlocked.Add(ref cacheUsed, -block.RequestLength); using (cached.BufferReleaser) { var asyncWrite = WriteToFilesAsync(torrent, block, cached.Buffer); Buffer.BlockCopy(cached.Buffer, 0, buffer, 0, block.RequestLength); Interlocked.Add(ref cacheHits, block.RequestLength); await asyncWrite.ConfigureAwait(false); return(block.RequestLength); } } Interlocked.Add(ref cacheMisses, block.RequestLength); return(await ReadFromFilesAsync(torrent, block, buffer).ConfigureAwait(false)); }