Esempio n. 1
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));
        }
Esempio n. 2
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);
            }
        }
Esempio n. 3
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);
            }
        }
Esempio n. 4
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));
        }