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();
            }
Beispiel #3
0
        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);
     }
 }
Beispiel #7
0
        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);
            }
        }
Beispiel #8
0
        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); });
        }
Beispiel #11
0
        public void should_throw_argumentnullexception_if_null_buffer()
        {
            BufferManager manager = new BufferManager(10, 1000, 0);

            manager.CheckIn(null);
        }
 public void should_accept_a_checked_out_buffer()
 {
     BufferManager manager = new BufferManager(10, 1000, 0);
     manager.CheckIn(manager.CheckOut());
 }
 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));
 }
 public void should_throw_argumentnullexception_if_null_buffer()
 {
     BufferManager manager = new BufferManager(10, 1000, 0);
     manager.CheckIn(null);
 }
 public void should_increment_available_buffers()
 {
     BufferManager manager = new BufferManager(10, 1000, 0);
     manager.CheckIn(manager.CheckOut());
     Assert.AreEqual(10, manager.AvailableBuffers);
 }