示例#1
0
        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);
            }
        }
示例#2
0
        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));
        }
示例#3
0
        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);
            }
        }
示例#4
0
        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);
            }
        }
示例#5
0
 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);
 }
示例#6
0
        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);
        }
示例#7
0
        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);
        }
示例#8
0
        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);
            }
        }
示例#9
0
        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;
            });
        }
示例#10
0
        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);
            });
        }
示例#11
0
 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);
 }
示例#12
0
        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);
            });
        }
示例#13
0
        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);
            }
        }
示例#14
0
        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));
        }