/// <summary>
        /// Try to write the item provided. Thread safe.
        /// </summary>
        private void SendQueueProcess(OperationState state)
        {
            if (!_canWriteNext)
            {
                //Double-checked locking for best performance
                _writeQueue.Enqueue(state);
                return;
            }
            short streamId = -1;

            lock (_writeQueueLock)
            {
                if (!_canWriteNext)
                {
                    //We have to recheck as the world can change since the last instruction
                    _writeQueue.Enqueue(state);
                    return;
                }
                //Check if Cassandra can process a new operation
                if (!_freeOperations.TryPop(out streamId))
                {
                    //Queue it up for later.
                    //When receiving the next complete message, we can process it.
                    _writeQueue.Enqueue(state);
                    _logger.Info("Enqueued: " + _writeQueue.Count + ", if this message is recurrent consider configuring more connections per host or lower the pressure");
                    return;
                }
                //Prevent the next to process
                _canWriteNext = false;
            }

            //At this point:
            //We have a valid stream id
            //Only 1 thread at a time can be here.
            try
            {
                _logger.Verbose("Sending #" + streamId + " for " + state.Request.GetType().Name);
                var frameStream = state.Request.GetFrame(streamId).Stream;
                _pendingOperations.AddOrUpdate(streamId, state, (k, oldValue) => state);
                //We will not use the request, stop reference it.
                state.Request = null;
                //Start sending it
                _tcpSocket.Write(frameStream);
            }
            catch (Exception ex)
            {
                //Prevent dead locking
                _canWriteNext = true;
                _logger.Error(ex);
                //The request was not written
                _pendingOperations.TryRemove(streamId, out state);
                _freeOperations.Push(streamId);
                throw;
            }
        }
Beispiel #2
0
        private void SendQueueProcessItem(OperationState state)
        {
            short streamId;

            //Check if Cassandra can process a new operation
            if (!_freeOperations.TryPop(out streamId))
            {
                //Queue it up for later.
                //When receiving the next complete message, we can process it.
                _writeQueue.Enqueue(state);
                _logger.Info("Enqueued: {0}, if this message is recurrent consider configuring more connections per host or lower the pressure", _writeQueue.Count);
                Interlocked.Exchange(ref _canWriteNext, 1);
                return;
            }
            //We have a valid stream id
            //Only 1 thread at a time can be here.
            _logger.Verbose("Sending #" + streamId + " for " + state.Request.GetType().Name);
            _pendingOperations.AddOrUpdate(streamId, state, (k, oldValue) => state);
            try
            {
                var frameStream = state.Request.GetFrame(streamId).Stream;
                //We will not use the request any more, stop reference it.
                state.Request = null;
                //Start sending it
                _tcpSocket.Write(frameStream);
                //Closure state variable
                var delegateState = state;
                if (Configuration.SocketOptions.ReadTimeoutMillis > 0 && Configuration.Timer != null)
                {
                    state.Timeout = Configuration.Timer.NewTimeout(() => OnTimeout(delegateState), Configuration.SocketOptions.ReadTimeoutMillis);
                }
            }
            catch (Exception ex)
            {
                //There was an error while serializing or begin sending
                _logger.Error(ex);
                //The request was not written, clear it from pending operations
                RemoveFromPending(streamId);
                //Callback with the Exception
                state.InvokeCallback(ex);
            }
        }
Beispiel #3
0
        private void RunWriteQueueAction()
        {
            //Dequeue all items until threshold is passed
            long totalLength = 0;
            RecyclableMemoryStream stream = null;

            while (totalLength < CoalescingThreshold)
            {
                OperationState state;
                if (!_writeQueue.TryDequeue(out state))
                {
                    //No more items in the write queue
                    break;
                }
                short streamId;
                if (!_freeOperations.TryPop(out streamId))
                {
                    //Queue it up for later.
                    _writeQueue.Enqueue(state);
                    //When receiving the next complete message, we can process it.
                    Logger.Info("Enqueued, no streamIds available. If this message is recurrent consider configuring more connections per host or lower the pressure");
                    break;
                }
                Logger.Verbose("Sending #{0} for {1} to {2}", streamId, state.Request.GetType().Name, Address);
                if (_isCanceled)
                {
                    state.InvokeCallback(new SocketException((int)SocketError.NotConnected));
                    break;
                }
                _pendingOperations.AddOrUpdate(streamId, state, (k, oldValue) => state);
                Interlocked.Increment(ref _inFlight);
                int frameLength;
                try
                {
                    //lazy initialize the stream
                    stream      = stream ?? (RecyclableMemoryStream)Configuration.BufferPool.GetStream(StreamWriteTag);
                    frameLength = state.Request.WriteFrame(streamId, stream, _serializer);
                    if (state.TimeoutMillis > 0)
                    {
                        var requestTimeout = Configuration.Timer.NewTimeout(OnTimeout, streamId, state.TimeoutMillis);
                        state.SetTimeout(requestTimeout);
                    }
                }
                catch (Exception ex)
                {
                    //There was an error while serializing or begin sending
                    Logger.Error(ex);
                    //The request was not written, clear it from pending operations
                    RemoveFromPending(streamId);
                    //Callback with the Exception
                    state.InvokeCallback(ex);
                    break;
                }
                //We will not use the request any more, stop reference it.
                state.Request = null;
                totalLength  += frameLength;
            }
            if (totalLength == 0L)
            {
                // Nothing to write, set the queue as not running
                Interlocked.CompareExchange(ref _writeState, WriteStateInit, WriteStateRunning);
                // Until now, we were preventing other threads to running the queue.
                // Check if we can now write:
                // a read could have finished (freeing streamIds) or new request could have been added to the queue
                if (!_freeOperations.IsEmpty && !_writeQueue.IsEmpty)
                {
                    //The write queue is not empty
                    //An item was added to the queue but we were running: try to launch a new queue
                    RunWriteQueue();
                }
                if (stream != null)
                {
                    //The stream instance could be created if there was an exception while generating the frame
                    stream.Dispose();
                }
                return;
            }
            //Write and close the stream when flushed
            // ReSharper disable once PossibleNullReferenceException : if totalLength > 0 the stream is initialized
            _tcpSocket.Write(stream, () => stream.Dispose());
        }