private void TryDequeueReceivedData() { while (_receiveQueue.Count > 0 && Interlocked.CompareExchange(ref _receiving, 1, 0) == 0) { if (_receiveQueue.Count > 0 && _receiveCallback != null) { var callback = Interlocked.Exchange(ref _receiveCallback, null); if (callback == null) { Log.Fatal("Some threading issue in TryDequeueReceivedData! Callback is null!"); throw new Exception("Some threading issue in TryDequeueReceivedData! Callback is null!"); } var dequeueResultList = new List <Tuple <ArraySegment <byte>, int> >(_receiveQueue.Count); Tuple <ArraySegment <byte>, int> piece; while (_receiveQueue.TryDequeue(out piece)) { dequeueResultList.Add(piece); } callback(this, dequeueResultList.Select(v => v.Item1)); int bytes = 0; for (int i = 0, n = dequeueResultList.Count; i < n; ++i) { var tuple = dequeueResultList[i]; bytes += tuple.Item1.Count; BufferManager.CheckIn(new ArraySegment <byte>(tuple.Item1.Array, tuple.Item1.Offset, tuple.Item2)); } NotifyReceiveDispatched(bytes); } Interlocked.Exchange(ref _receiving, 0); } }
private void OnReceiveAsyncCompleted(IAsyncResult ar) { Interlocked.Increment(ref _recvAsyncCallbacks); int receivedBytes; try { receivedBytes = _socket.EndReceive(ar); } catch (SocketException exc) { BufferManager.CheckIn(_currentBuffer); CloseInternal(exc.SocketErrorCode); return; } catch (Exception) { BufferManager.CheckIn(_currentBuffer); CloseInternal(SocketError.Shutdown); return; } var receivedPackages = Interlocked.Increment(ref _packagesReceived); var totalReceivedBytes = Interlocked.Add(ref _bytesReceived, receivedBytes); if (receivedBytes == 0) // correct socket closing { BufferManager.CheckIn(_currentBuffer); CloseInternal(SocketError.Success); return; } //Console.WriteLine(String.Format("{0:mmss.fff}", DateTime.UtcNow) + " received " + receivedBytes + " bytes."); // OK, so what does this line of code do? It makes an ArraySegment<byte> representing the data // that we actually read. // Then it constructs a little array to meet the IEnumerable interface. // Then it makes original buffer (ArraySegment<byte>) we used for receive operation. // Then it builds an IEnumerable that will dispose of our buffer (returning it to the buffer pool) // later (as in later when some other thread (but it may be on this thread, we aren't sure) processes // this buffer). // This should be benchmarked vs copying the byte array every time into a new byte array var receiveBufferSegment = new[] { new ArraySegment <byte>(_currentBuffer.Array, _currentBuffer.Offset, receivedBytes) }; lock (_receivingLock) { _receiveQueue.Enqueue(receiveBufferSegment.CallAfterEvaluation( x => BufferManager.CheckIn(x), _currentBuffer)); } StartReceive(); TryDequeueReceivedData(); }
private void ProcessReceive(SocketAsyncEventArgs socketArgs) { if (socketArgs != _receiveSocketArgs) { throw new Exception("Invalid socket args received"); } Interlocked.Increment(ref _recvAsyncCallbacks); // socket closed normally or some error occured if (socketArgs.BytesTransferred == 0 || socketArgs.SocketError != SocketError.Success) { NotifyReceiveCompleted(0); ReturnReceivingSocketArgs(); CloseInternal(socketArgs.SocketError); return; } NotifyReceiveCompleted((uint)socketArgs.BytesTransferred); Interlocked.Increment(ref _packagesReceived); Interlocked.Add(ref _bytesReceived, socketArgs.BytesTransferred); //Console.WriteLine(String.Format("{0:mmss.fff}", DateTime.UtcNow) + " received " + socketArgs.BytesTransferred + " bytes."); // OK, so what does this line of code do? It makes an ArraySegment<byte> representing the data // that we actually read. // Then it constructs a little array to meet the IEnumerable interface. // Then it makes original buffer (ArraySegment<byte>) we used for receive operation. // Then it builds an IEnumerable that will dispose of our buffer (returning it to the buffer pool) // later (as in later when some other thread (but it may be on this thread, we aren't sure) processes // this buffer). // This should be benchmarked vs copying the byte array every time into a new byte array var receiveBufferSegment = new ArraySegment <byte>(socketArgs.Buffer, socketArgs.Offset, socketArgs.BytesTransferred); lock (_receivingLock) { var fullBuffer = new ArraySegment <byte>(socketArgs.Buffer, socketArgs.Offset, socketArgs.Count); Action disposeBufferAction = () => BufferManager.CheckIn(fullBuffer); _receiveQueue.Enqueue(Tuple.Create(receiveBufferSegment, disposeBufferAction)); } lock (_receiveSocketArgs) { if (socketArgs.Buffer == null) { throw new Exception("Cleaning already null buffer"); } socketArgs.SetBuffer(null, 0, 0); } StartReceive(); TryDequeueReceivedData(); }
public void should_throw_argumentexception_if_buffer_wrong_size() { BufferManager manager = new BufferManager(10, 1000, 0); byte[] data = new byte[10000]; Assert.Throws <ArgumentException>(() => { manager.CheckIn(new ArraySegment <byte>(data)); }); }
public void should_increment_available_buffers() { BufferManager manager = new BufferManager(10, 1000, 0); manager.CheckIn(manager.CheckOut()); Assert.AreEqual(10, manager.AvailableBuffers); }
protected internal void CheckIn(BufferSegment segment) { if (m_mgr != null) { m_mgr.CheckIn(segment); } }
public static byte[] CompressResponse(byte[] response, string compressionAlgorithm) { if (string.IsNullOrEmpty(compressionAlgorithm) || !SupportedCompressionAlgorithms.Contains(compressionAlgorithm)) { return(response); } MemoryStream outputStream; var useBufferManager = 10L * response.Length <= 9L * _compressionBufferManager .ChunkSize; //in some rare cases, compression can result in larger outputs. Added a 10% overhead just to be sure. var bufferManagerArraySegment = new ArraySegment <byte>(); if (useBufferManager) { //use buffer manager to handle responses less than ~50kb long to prevent excessive memory allocations bufferManagerArraySegment = _compressionBufferManager.CheckOut(); outputStream = new MemoryStream(bufferManagerArraySegment.Array, bufferManagerArraySegment.Offset, bufferManagerArraySegment.Count); outputStream.SetLength(0); } else { //since Gzip/Deflate compression ratio doesn't go below 20% in most cases, we can initialize the array to a quarter of the original response length //this also limits memory stream growth operations to at most 2. outputStream = new MemoryStream((response.Length + 4 - 1) / 4); } using (outputStream) { Stream compressedStream = null; if (compressionAlgorithm.Equals(CompressionAlgorithms.Gzip)) { compressedStream = new GZipStream(outputStream, CompressionLevel.Fastest); } else if (compressionAlgorithm.Equals(CompressionAlgorithms.Deflate)) { compressedStream = new DeflateStream(outputStream, CompressionLevel.Fastest); } using (compressedStream) using (var dataStream = new MemoryStream(response)) { dataStream.CopyTo(compressedStream); } var result = outputStream.ToArray(); if (useBufferManager) { _compressionBufferManager.CheckIn(bufferManagerArraySegment); } return(result); } }
private void TryDequeueReceivedData() { Action <ITcpConnection, IEnumerable <ArraySegment <byte> > > callback; List <Tuple <ArraySegment <byte>, int> > res; lock (_receivingLock) { // no awaiting callback or no data to dequeue if (_receiveCallback == null || _receiveQueue.Count == 0) { return; } res = new List <Tuple <ArraySegment <byte>, int> >(_receiveQueue.Count); while (_receiveQueue.Count > 0) { var arraySegments = _receiveQueue.Dequeue(); res.Add(arraySegments); } callback = _receiveCallback; _receiveCallback = null; } callback(this, res.Select(v => v.Item1).ToArray()); int bytes = 0; for (int i = 0, n = res.Count; i < n; ++i) { var tuple = res[i]; bytes += tuple.Item1.Count; BufferManager.CheckIn(new ArraySegment <byte>(tuple.Item1.Array, tuple.Item1.Offset, tuple.Item2)); // dispose buffers } NotifyReceiveDispatched(bytes); }
public void should_accept_a_checked_out_buffer() { BufferManager manager = new BufferManager(10, 1000, 0); manager.CheckIn(manager.CheckOut()); }
public void should_throw_argumentnullexception_if_null_buffer() { BufferManager manager = new BufferManager(10, 1000, 0); Assert.Throws <ArgumentNullException>(() => { manager.CheckIn((IEnumerable <ArraySegment <byte> >)null); }); }
public void should_throw_argumentnullexception_if_null_buffer() { BufferManager manager = new BufferManager(10, 1000, 0); manager.CheckIn(null); }
public void should_throw_argumentexception_if_buffer_wrong_size() { BufferManager manager = new BufferManager(10, 1000, 0); byte[] data = new byte[10000]; manager.CheckIn(new ArraySegment<byte>(data)); }