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); } }
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; } } }
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)); } } }
public static MemoryPoolBlock2 Create(int size, MemoryPool2 pool) { return(new MemoryPoolBlock2 { Data = new ArraySegment <byte>(new byte[size]), Pool = pool }); }
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)); } } }
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)); } }
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 }; }
public TestInput() { var memory = new MemoryPool(); var memory2 = new MemoryPool2(); FrameContext = new FrameContext { SocketInput = new SocketInput(memory2), Memory = memory, ConnectionControl = this, FrameControl = this }; }
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, }); }
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); }
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)); } }
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); }
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); } }
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; }
public ListenerContext(ServiceContext serviceContext) : base(serviceContext) { Memory2 = new MemoryPool2(); }
public ListenerContext() { Memory2 = new MemoryPool2(); }
public static MemoryPoolBlock2 Create(int size, MemoryPool2 pool) { return new MemoryPoolBlock2 { Data = new ArraySegment<byte>(new byte[size]), Pool = pool }; }
public ListenerContext(ServiceContext serviceContext) : base(serviceContext) { Memory2 = new MemoryPool2(); WriteReqPool = new Queue<UvWriteReq>(SocketOutput.MaxPooledWriteReqs); }
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); } }
public SocketInput(MemoryPool2 memory) { _memory = memory; _awaitableState = _awaitableIsNotCompleted; }
public StreamSocketOutput(Stream outputStream, MemoryPool2 memory) { _outputStream = outputStream; _memory = memory; }
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); } }
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); } }
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, }; }
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)); } }
public SocketInput(MemoryPool2 memory, IThreadPool threadPool) { _memory = memory; _threadPool = threadPool; _awaitableState = _awaitableIsNotCompleted; }
public MemoryPoolIterator2Tests() { _pool = new MemoryPool2(); }
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); } }