Used to allocate and distribute re-usable blocks of memory.
Inheritance: IDisposable
コード例 #1
0
        public void CopyToCorrectlyTraversesBlocks()
        {
            using (var pool = new MemoryPool2())
            {
                var block1 = pool.Lease(128);
                var block2 = block1.Next = pool.Lease(128);

                for (int i = 0; i < 128; i++)
                {
                    block1.Array[block1.End++] = (byte)i;
                }
                for (int i = 128; i < 256; i++)
                {
                    block2.Array[block2.End++] = (byte)i;
                }

                var beginIterator = block1.GetIterator();

                var array = new byte[256];
                int actual;
                var endIterator = beginIterator.CopyTo(array, 0, 256, out actual);

                Assert.Equal(256, actual);

                for (int i = 0; i < 256; i++)
                {
                    Assert.Equal(i, array[i]);
                }

                endIterator.CopyTo(array, 0, 256, out actual);
                Assert.Equal(0, actual);
            }
        }
コード例 #2
0
        public void GetLengthBetweenIteratorsWorks()
        {
            using (var pool = new MemoryPool2())
            {
                var block = pool.Lease(256);
                block.End += 256;
                TestAllLengths(block, 256);
                pool.Return(block);
                block = null;

                for (var fragment = 0; fragment < 256; fragment += 4)
                {
                    var next = block;
                    block = pool.Lease(4);
                    block.Next = next;
                    block.End += 4;
                }

                TestAllLengths(block, 256);

                while(block != null)
                {
                    var next = block.Next;
                    pool.Return(block);
                    block = next;
                }
            }
        }
コード例 #3
0
        public void SeekWorks()
        {
            using (var pool = new MemoryPool2())
            {
                var block = pool.Lease(256);
                foreach (var ch in Enumerable.Range(0, 256).Select(x => (byte)x))
                {
                    block.Array[block.End++] = ch;
                }
                var iterator = block.GetIterator();
                foreach (var ch in Enumerable.Range(0, 256).Select(x => (char)x))
                {
                    var hit = iterator;
                    hit.Seek(ch);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(ch, byte.MaxValue);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(byte.MaxValue, ch);
                    Assert.Equal(ch, iterator.GetLength(hit));
                }
            }
        }
コード例 #4
0
 public static MemoryPoolBlock2 Create(int size, MemoryPool2 pool)
 {
     return(new MemoryPoolBlock2
     {
         Data = new ArraySegment <byte>(new byte[size]),
         Pool = pool
     });
 }
コード例 #5
0
        public void SeekWorksAcrossBlocks()
        {
            Console.WriteLine($"Vector.IsHardwareAccelerated == {Vector.IsHardwareAccelerated}");
            Console.WriteLine($"Vector<byte>.Count == {Vector<byte>.Count}");

            using (var pool = new MemoryPool2())
            {
                var block1 = pool.Lease(256);
                var block2 = block1.Next = pool.Lease(256);
                var block3 = block2.Next = pool.Lease(256);

                foreach (var ch in Enumerable.Range(0, 34).Select(x => (byte)x))
                {
                    block1.Array[block1.End++] = ch;
                }
                foreach (var ch in Enumerable.Range(34, 25).Select(x => (byte)x))
                {
                    block2.Array[block2.End++] = ch;
                }
                foreach (var ch in Enumerable.Range(59, 197).Select(x => (byte)x))
                {
                    block3.Array[block3.End++] = ch;
                }

                var vectorMaxValues = new Vector<byte>(byte.MaxValue);

                var iterator = block1.GetIterator();
                foreach (var ch in Enumerable.Range(0, 256).Select(x => (byte)x))
                {
                    var vectorCh = new Vector<byte>(ch);

                    var hit = iterator;
                    hit.Seek(ref vectorCh);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(ref vectorCh, ref vectorMaxValues);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(ref vectorMaxValues, ref vectorCh);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(ref vectorCh, ref vectorMaxValues, ref vectorMaxValues);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(ref vectorMaxValues, ref vectorCh, ref vectorMaxValues);
                    Assert.Equal(ch, iterator.GetLength(hit));

                    hit = iterator;
                    hit.Seek(ref vectorMaxValues, ref vectorMaxValues, ref vectorCh);
                    Assert.Equal(ch, iterator.GetLength(hit));
                }
            }
        }
コード例 #6
0
        public void WritesDontCompleteImmediatelyWhenTooManyBytesAreAlreadyPreCompleted()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue = new Queue<Action<int>>();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                var bufferSize = maxBytesPreCompleted;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
                var completedWh = new ManualResetEventSlim();
                Action<Task> onCompleted = (Task t) =>
                {
                    Assert.Null(t.Exception);
                    completedWh.Set();
                };

                // Act 
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                // Assert
                // The first write should pre-complete since it is <= _maxBytesPreCompleted.
                Assert.True(completedWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                // Act
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                // Assert 
                // Too many bytes are already pre-completed for the second write to pre-complete.
                Assert.False(completedWh.Wait(1000));
                // Act
                completeQueue.Dequeue()(0);
                // Assert
                // Finishing the first write should allow the second write to pre-complete.
                Assert.True(completedWh.Wait(1000));
            }
        }
コード例 #7
0
 public TestInput()
 {
     var trace = new KestrelTrace(new TestKestrelTrace());
     var ltp = new LoggingThreadPool(trace);
     var memory2 = new MemoryPool2();
     FrameContext = new FrameContext
     {
         SocketInput = new SocketInput(memory2, ltp),
         ConnectionControl = this,
         FrameControl = this
     };
 }
コード例 #8
0
 public TestInput()
 {
     var memory = new MemoryPool();
     var memory2 = new MemoryPool2();
     FrameContext = new FrameContext
     {
         SocketInput = new SocketInput(memory2),
         Memory = memory,
         ConnectionControl = this,
         FrameControl = this
     };
 }
コード例 #9
0
 public static MemoryPoolBlock2 Create(
     ArraySegment <byte> data,
     IntPtr dataPtr,
     MemoryPool2 pool,
     MemoryPoolSlab2 slab)
 {
     return(new MemoryPoolBlock2
     {
         Data = data,
         _dataArrayPtr = dataPtr,
         Pool = pool,
         Slab = slab,
         Start = data.Offset,
         End = data.Offset,
     });
 }
コード例 #10
0
        public FilteredStreamAdapter(
            Stream filteredStream,
            MemoryPool2 memory,
            IKestrelTrace logger)
        {
            SocketInput = new SocketInput(memory);
            SocketOutput = new StreamSocketOutput(filteredStream);

            _log = logger;
            _filteredStream = filteredStream;
            _socketInputStream = new SocketInputStream(SocketInput);

            _filteredStream.CopyToAsync(_socketInputStream).ContinueWith((task, state) =>
            {
                ((FilteredStreamAdapter)state).OnStreamClose(task);
            }, this);
        }
コード例 #11
0
        public void CanWrite1MB()
        {
            // This test was added because when initially implementing write-behind buffering in
            // SocketOutput, the write callback would never be invoked for writes larger than
            // _maxBytesPreCompleted even after the write actually completed.

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    triggerCompleted(0);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
                var bufferSize = 1048576;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
                var completedWh = new ManualResetEventSlim();

                // Act
                socketOutput.WriteAsync(buffer).ContinueWith(
                    (t) =>
                    {
                        Assert.Null(t.Exception);
                        completedWh.Set();
                    }
                );

                // Assert
                Assert.True(completedWh.Wait(1000));
            }
        }
コード例 #12
0
        public FilteredStreamAdapter(
            Stream filteredStream,
            MemoryPool2 memory,
            IKestrelTrace logger,
            IThreadPool threadPool)
        {
            SocketInput = new SocketInput(memory, threadPool);
            SocketOutput = new StreamSocketOutput(filteredStream, memory);

            _log = logger;
            _filteredStream = filteredStream;
            _socketInputStream = new SocketInputStream(SocketInput);

            var block = memory.Lease();
            // Use pooled block for copy
            _filteredStream.CopyToAsync(_socketInputStream, block).ContinueWith((task, state) =>
            {
                var returnedBlock = task.Result;
                returnedBlock.Pool.Return(returnedBlock);

                ((FilteredStreamAdapter)state).OnStreamClose(task);
            }, this);
        }
コード例 #13
0
        public void AddDoesNotAdvanceAtEndOfCurrentBlock()
        {
            using (var pool = new MemoryPool2())
            {
                var block1 = pool.Lease(256);
                var block2 = block1.Next = pool.Lease(256);

                block1.End += 100;
                block2.End += 200;

                var iter0 = block1.GetIterator();
                var iter100 = iter0.Add(100);

                var iter200a = iter0.Add(200);
                var iter200b = iter100.Add(100);

                var iter300a = iter0.Add(300);
                var iter300b = iter100.Add(200);
                var iter300c = iter200a.Add(100);

                var iter300a2 = iter300a.Add(1);
                var iter300b2 = iter300b.Add(1);
                var iter300c2 = iter300c.Add(1);

                AssertIterator(iter0, block1, block1.Start);
                AssertIterator(iter100, block1, block1.End);
                AssertIterator(iter200a, block2, block2.Start+100);
                AssertIterator(iter200b, block2, block2.Start + 100);
                AssertIterator(iter300a, block2, block2.End);
                AssertIterator(iter300b, block2, block2.End);
                AssertIterator(iter300c, block2, block2.End);
                AssertIterator(iter300a2, block2, block2.End);
                AssertIterator(iter300b2, block2, block2.End);
                AssertIterator(iter300c2, block2, block2.End);
            }
        }
コード例 #14
0
        public SocketOutput(
            KestrelThread thread,
            UvStreamHandle socket,
            MemoryPool2 memory,
            Connection connection,
            long connectionId,
            IKestrelTrace log,
            IThreadPool threadPool,
            Queue<UvWriteReq> writeReqPool)
        {
            _thread = thread;
            _socket = socket;
            _connection = connection;
            _connectionId = connectionId;
            _log = log;
            _threadPool = threadPool;
            _tasksPending = new Queue<TaskCompletionSource<object>>(_initialTaskQueues);
            _tasksCompleted = new Queue<TaskCompletionSource<object>>(_initialTaskQueues);
            _writeContextPool = new Queue<WriteContext>(_maxPooledWriteContexts);
            _writeReqPool = writeReqPool;

            _head = memory.Lease();
            _tail = _head;
        }
コード例 #15
0
 public ListenerContext(ServiceContext serviceContext)
     : base(serviceContext)
 {
     Memory2 = new MemoryPool2();
 }
コード例 #16
0
 public ListenerContext()
 {
     Memory2 = new MemoryPool2();
 }
コード例 #17
0
 public static MemoryPoolBlock2 Create(int size, MemoryPool2 pool)
 {
     return new MemoryPoolBlock2
     {
         Data = new ArraySegment<byte>(new byte[size]),
         Pool = pool
     };
 }
コード例 #18
0
 public ListenerContext(ServiceContext serviceContext) 
     : base(serviceContext)
 {
     Memory2 = new MemoryPool2();
     WriteReqPool = new Queue<UvWriteReq>(SocketOutput.MaxPooledWriteReqs);
 }
コード例 #19
0
        public void CopyFromCorrectlyTraversesBlocks()
        {
            using (var pool = new MemoryPool2())
            {
                var block1 = pool.Lease(128);
                var start = block1.GetIterator();
                var end = start;
                var bufferSize = block1.Data.Count * 3;
                var buffer = new byte[bufferSize];

                for (int i = 0; i < bufferSize; i++)
                {
                    buffer[i] = (byte)(i % 73);
                }

                Assert.Null(block1.Next);

                end.CopyFrom(new ArraySegment<byte>(buffer));

                Assert.NotNull(block1.Next);

                for (int i = 0; i < bufferSize; i++)
                {
                    Assert.Equal(i % 73, start.Take());
                }

                Assert.Equal(-1, start.Take());
                Assert.Equal(start.Block, end.Block);
                Assert.Equal(start.Index, end.Index);
            }
        }
コード例 #20
0
 public SocketInput(MemoryPool2 memory)
 {
     _memory = memory;
     _awaitableState = _awaitableIsNotCompleted;
 }
コード例 #21
0
 public StreamSocketOutput(Stream outputStream, MemoryPool2 memory)
 {
     _outputStream = outputStream;
     _memory = memory;
 }
コード例 #22
0
        public async Task ConcurrentReadsFailGracefully()
        {
            // Arrange
            var trace = new KestrelTrace(new TestKestrelTrace());
            var ltp = new LoggingThreadPool(trace);
            using (var memory2 = new MemoryPool2())
            {
                var socketInput = new SocketInput(memory2, ltp);

                var task0Threw = false;
                var task1Threw = false;
                var task2Threw = false;


                var task0 = AwaitAsTaskAsync(socketInput);

                Assert.False(task0.IsFaulted);

                var task = task0.ContinueWith(
                    (t) =>
                    {
                        TestConcurrentFaultedTask(t);
                        task0Threw = true;
                    },
                    TaskContinuationOptions.OnlyOnFaulted);

                Assert.False(task0.IsFaulted);

                // Awaiting/continuing two tasks faults both

                var task1 = AwaitAsTaskAsync(socketInput);

                await task1.ContinueWith(
                    (t) =>
                    {
                        TestConcurrentFaultedTask(t);
                        task1Threw = true;
                    },
                    TaskContinuationOptions.OnlyOnFaulted);

                await task;

                Assert.True(task0.IsFaulted);
                Assert.True(task1.IsFaulted);

                Assert.True(task0Threw);
                Assert.True(task1Threw);

                // socket stays faulted

                var task2 = AwaitAsTaskAsync(socketInput);

                await task2.ContinueWith(
                    (t) =>
                    {
                        TestConcurrentFaultedTask(t);
                        task2Threw = true;
                    },
                    TaskContinuationOptions.OnlyOnFaulted);

                Assert.True(task2.IsFaulted);
                Assert.True(task2Threw);
            }
        }
コード例 #23
0
        public void IsEndCorrectlyTraversesBlocks()
        {
            using (var pool = new MemoryPool2())
            {
                var block1 = pool.Lease(128);
                var block2 = block1.Next = pool.Lease(128);
                var block3 = block2.Next = pool.Lease(128);
                var block4 = block3.Next = pool.Lease(128);

                // There is no data in block2 or block4, so IsEnd should be true after 256 bytes are read.
                block1.End += 128;
                block3.End += 128;

                var iterStart = block1.GetIterator();
                var iterMid = iterStart.Add(128);
                var iterEnd = iterMid.Add(128);

                Assert.False(iterStart.IsEnd);
                Assert.False(iterMid.IsEnd);
                Assert.True(iterEnd.IsEnd);
            }
        }
コード例 #24
0
 public static MemoryPoolBlock2 Create(
     ArraySegment<byte> data,
     IntPtr dataPtr,
     MemoryPool2 pool,
     MemoryPoolSlab2 slab)
 {
     return new MemoryPoolBlock2
     {
         Data = data,
         _dataArrayPtr = dataPtr,
         Pool = pool,
         Slab = slab,
         Start = data.Offset,
         End = data.Offset,
     };
 }
コード例 #25
0
        public void WritesDontGetCompletedTooQuickly()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue = new Queue<Action<int>>();
            var onWriteWh = new ManualResetEventSlim();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    onWriteWh.Set();

                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                var bufferSize = maxBytesPreCompleted;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);

                var completedWh = new ManualResetEventSlim();
                Action<Task> onCompleted = (Task t) =>
                {
                    Assert.Null(t.Exception);
                    completedWh.Set();
                };

                var completedWh2 = new ManualResetEventSlim();
                Action<Task> onCompleted2 = (Task t) =>
                {
                    Assert.Null(t.Exception);
                    completedWh2.Set();
                };

                // Act (Pre-complete the maximum number of bytes in preparation for the rest of the test)
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                // Assert
                // The first write should pre-complete since it is <= _maxBytesPreCompleted.
                Assert.True(completedWh.Wait(1000));
                Assert.True(onWriteWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                onWriteWh.Reset();

                // Act
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted2);

                Assert.True(onWriteWh.Wait(1000));
                completeQueue.Dequeue()(0);

                // Assert 
                // Too many bytes are already pre-completed for the third but not the second write to pre-complete.
                // https://github.com/aspnet/KestrelHttpServer/issues/356
                Assert.True(completedWh.Wait(1000));
                Assert.False(completedWh2.Wait(1000));

                // Act
                completeQueue.Dequeue()(0);

                // Assert
                // Finishing the first write should allow the second write to pre-complete.
                Assert.True(completedWh2.Wait(1000));
            }
        }
コード例 #26
0
 public SocketInput(MemoryPool2 memory, IThreadPool threadPool)
 {
     _memory = memory;
     _threadPool = threadPool;
     _awaitableState = _awaitableIsNotCompleted;
 }
コード例 #27
0
 public MemoryPoolIterator2Tests()
 {
     _pool = new MemoryPool2();
 }
コード例 #28
0
        public void ProducingStartAndProducingCompleteCanBeUsedDirectly()
        {
            int nBuffers = 0;
            var nBufferWh = new ManualResetEventSlim();

            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    nBuffers = buffers;
                    nBufferWh.Set();
                    triggerCompleted(0);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                // block 1
                var start = socketOutput.ProducingStart();
                start.Block.End = start.Block.Data.Offset + start.Block.Data.Count;

                // block 2
                var block2 = memory.Lease();
                block2.End = block2.Data.Offset + block2.Data.Count;
                start.Block.Next = block2;

                var end = new MemoryPoolIterator2(block2, block2.End);

                socketOutput.ProducingComplete(end);

                // A call to Write is required to ensure a write is scheduled
                socketOutput.WriteAsync(default(ArraySegment<byte>));

                Assert.True(nBufferWh.Wait(1000));
                Assert.Equal(2, nBuffers);
            }
        }