示例#1
0
        internal async Task <bool> InternalDoConnectSocket(string hostname, int port, bool throwOnError)
        {
            var index = Interlocked.Increment(ref _counter);

            // read and write threads should not be running at this point
            if (_readThreadRunning)
            {
                throw new Exception("Read thread should not be running");
            }
            if (_writeThreadRunning)
            {
                throw new Exception("Write thread should not be running");
            }

            var result = await _socketHolder.Connect(hostname, port, index, throwOnError).ConfigureAwait(false);

            if (!result)
            {
                // Interlocked.Decrement(ref _counter);
                return(false);
            }

            if (LogAdapter.IsDebugEnabled)
            {
                LogAdapter.LogDebug(LogSource, "Connected socket to " + hostname + " port " + port);
            }

            DrainCommandsAndResetErrorState();

            if (_threadCancelSource != null)
            {
                if (LogAdapter.IsDebugEnabled)
                {
                    LogAdapter.LogDebug(LogSource, "Disposing existing cancellation token source");
                }

                _threadCancelSource.Dispose();
            }

            _threadCancelSource = new CancellationTokenSource();
            _threadCancelToken  = _threadCancelSource.Token;

            _socketHolder.WireStreams(_threadCancelToken, OnSocketClosed);

            _amqpWriter.Initialize(_socketHolder.Writer);
            _amqpReader.Initialize(_socketHolder.Reader);
            _frameReader.Initialize(_socketHolder.Reader, _amqpReader, this);

            ThreadFactory.BackgroundThread(WriteFramesLoop, WriteFrameThreadNamePrefix + index);
            ThreadFactory.BackgroundThread(ReadFramesLoop, ReadFrameThreadNamePrefix + index);

            return(true);
        }
        public void MultiThreaded_TrySetComplete(bool isSetCompleteTest, int howManyThreads)
        {
            int continuationCalledCounter = 0;
            int completedGainedCounter    = 0;
            int completedLossedCounter    = 0;

            var taskSlim = new TaskSlim(null);

            taskSlim.SetContinuation(() =>
            {
                Interlocked.Increment(ref continuationCalledCounter);
            });

            var @syncEvent = new ManualResetEventSlim(false);

            for (int i = 0; i < howManyThreads; i++)
            {
                ThreadFactory.BackgroundThread((index) =>
                {
                    @syncEvent.Wait();

                    var result = isSetCompleteTest ?
                                 taskSlim.TrySetCompleted() :
                                 taskSlim.TrySetException(new Exception("bah"));

                    if (result)
                    {
                        Interlocked.Increment(ref completedGainedCounter);
                    }
                    else
                    {
                        Interlocked.Increment(ref completedLossedCounter);
                    }
                }, "T_" + i, i);
            }

            Thread.Sleep(0);

            @syncEvent.Set();

            Thread.Sleep(1000);

            continuationCalledCounter.Should().Be(1, "continuation cannot be called more than once");
            completedGainedCounter.Should().Be(1, "only 1 thread could have taken the lock successfully");
            completedLossedCounter.Should().Be(howManyThreads - 1, "all other threads should have been unsuccessful");
        }
示例#3
0
        public void ConsistencyCheck(int howManyThreads, int poolSize)
        {
            var iterations = 100000;

            _pool = new ObjectPoolArray <FakeRecycleableObj>(
                () => new FakeRecycleableObj(i => _pool.PutObject(i)),
                poolSize, preInitialize: true, ignoreDispose: false);

            var countDown = new CountdownEvent(howManyThreads);
            var hasError  = false;

            for (int i = 0; i < howManyThreads; i++)
            {
                ThreadFactory.BackgroundThread(() =>
                {
                    try
                    {
                        for (int j = 0; j < iterations; j++)
                        {
                            var obj = _pool.GetObject();
                            if (i % 20 == 0)
                            {
                                Thread.Sleep(_rnd.Next(1, 3));                // some entropy
                            }
                            obj.Use("something");                             // Use will recycle itself
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.Error.WriteLine(ex);
                        hasError = true;
                    }
                    finally
                    {
                        countDown.Signal();
                    }
                }, "Test_" + i);
            }

            countDown.Wait();

            _pool.DumpDiagnostics();

            Assert.False(hasError, "Not expecting to have error(s)");
        }
示例#4
0
        internal async Task <bool> InternalDoConnectSocket(string hostname, int port, bool throwOnError)
        {
            var index = Interlocked.Increment(ref _counter);

            var result = await _socketHolder.Connect(hostname, port, index, throwOnError).ConfigureAwait(false);

            if (!throwOnError && !result)
            {
                Interlocked.Decrement(ref _counter);
                return(false);
            }

            // Reset state
            _lastError = null;
            while (!_commandOutbox.IsEmpty)
            {
                CommandToSend cmd;
                _commandOutbox.TryDequeue(out cmd);
            }

            if (_threadCancelSource != null)
            {
                _threadCancelSource.Dispose();
            }

            _threadCancelSource = new CancellationTokenSource();
            _threadCancelToken  = _threadCancelSource.Token;

            _socketHolder.WireStreams(_threadCancelToken, OnSocketClosed);

            _amqpWriter.Initialize(_socketHolder.Writer);
            _amqpReader.Initialize(_socketHolder.Reader);
            _frameReader.Initialize(_socketHolder.Reader, _amqpReader, this);

            ThreadFactory.BackgroundThread(WriteFramesLoop, "WriteFramesLoop_" + index);
            ThreadFactory.BackgroundThread(ReadFramesLoop, "ReadFramesLoop_" + index);

            return(true);
        }
示例#5
0
        internal void DispatchDeliveredMessage(
            string consumerTag, ulong deliveryTag, bool redelivered,
            string exchange, string routingKey, int bodySize,
            BasicProperties properties, BaseLightStream lightStream)
        {
            BasicConsumerSubscriptionInfo consumer;

            if (!_consumerSubscriptions.TryGetValue(consumerTag, out consumer))
            {
                // received msg but nobody was subscribed to get it (?)
                LogAdapter.LogWarn(LogSource, "Received message without a matching subscription. Discarding. " +
                                   "Exchange: " + exchange + " routing: " + routingKey +
                                   " consumer tag: " + consumerTag + " and channel " + this.ChannelNumber);

                // Ensure moved cursor ahead
                var marker = new RingBufferPositionMarker(lightStream);
                marker.EnsureConsumed(bodySize);
                return;
            }

            var delivery = new MessageDelivery
            {
                bodySize    = bodySize,
                properties  = properties,
                routingKey  = routingKey,
                deliveryTag = deliveryTag + this._deliveryTagOffset,                 // adds tag offset
                redelivered = redelivered,
            };

            var mode             = consumer.Mode;
            var cb               = consumer.Callback;
            var consumerInstance = consumer._consumer;

            if (mode == ConsumeMode.SingleThreaded)
            {
                // run with scissors, we're letting
                // the user code mess with the ring buffer in the name of performance
                delivery.stream = bodySize == 0 ? EmptyStream : lightStream;

                // upon return it's assumed the user has consumed from the stream and is done with it
                var marker = new RingBufferPositionMarker(lightStream);

                try
                {
                    if (cb != null)
                    {
                        cb(delivery).GetAwaiter().GetResult();
                    }
                    else
                    {
                        consumerInstance.Consume(delivery).GetAwaiter().GetResult();
                    }
                }
                finally
                {
                    if (!delivery.TakenOver)
                    {
                        delivery.Dispose();
                    }

                    // fingers crossed the user cloned the buffer if she needs it later
                    marker.EnsureConsumed(bodySize);
                }
            }
            else
            {
                // parallel mode. it cannot hold the frame handler, so we copy the buffer (yuck) and move forward

                if (mode == ConsumeMode.ParallelWithBufferCopy ||
                    mode == ConsumeMode.SerializedWithBufferCopy)
                {
                    delivery.stream = delivery.bodySize == 0
                                                ? EmptyStream
                                                : lightStream.CloneStream(bodySize);
                }

                if (mode == ConsumeMode.SerializedWithBufferCopy)                 // Posts to a thread
                {
                    if (consumer._consumerThread == null)
                    {
                        // Initialization. safe since this delivery call always happen from the same thread
                        consumer._receivedMessages   = new ConcurrentQueue <MessageDelivery>();
                        consumer._messageAvailableEv = new AutoResetEvent(false);
                        consumer._consumerThread     = ThreadFactory.BackgroundThread(SerializedDelivery, "Delivery_" + consumer.ConsumerTag,
                                                                                      consumer);
                    }

                    consumer._receivedMessages.Enqueue(delivery);
                    consumer._messageAvailableEv.Set();
                }
                else if (mode == ConsumeMode.ParallelWithBufferCopy)                 // Posts to TaskScheduler
                {
                    new Task(async state =>
                    {
                        var tuple       = (Tuple <MessageDelivery, Func <MessageDelivery, Task>, IQueueConsumer, Channel>)state;
                        var delivery1   = tuple.Item1;
                        var cb1         = tuple.Item2;
                        var conInstance = tuple.Item3;

                        try
                        {
                            if (cb1 != null)
                            {
                                await cb1(delivery1).ConfigureAwait(false);
                            }
                            else
                            {
                                await conInstance.Consume(delivery1).ConfigureAwait(false);
                            }
                        }
                        catch (Exception e)
                        {
                            if (LogAdapter.IsErrorEnabled)
                            {
                                LogAdapter.LogError(LogSource, "Error processing message (user code)", e);
                            }
                        }
                        finally
                        {
                            if (!delivery1.TakenOver)
                            {
                                delivery1.Dispose();
                            }
                        }
                    }, Tuple.Create(delivery, cb, consumerInstance, this))                     // tuple avoids the closure capture
                    // Start task in the given scheduler
                    .Start(_schedulerToDeliverMessages);
                }
            }
        }
        private void TryInitiateRecovery()
        {
            if (Interlocked.CompareExchange(ref _inRecovery, 1, 0) == 0)
            {
                if (LogAdapter.IsWarningEnabled)
                {
                    LogAdapter.LogWarn(LogSource, "TryInitiateRecovery starting recovery process");
                }

                // block all channels

                lock (_channelRecoveries)
                    foreach (var recoveryEnabledChannel in _channelRecoveries)
                    {
                        recoveryEnabledChannel.Disconnected();
                    }

                // from this point on, no api calls are allowed on the channel decorators

                ThreadFactory.BackgroundThread(async(pthis) =>
                {
                    try
                    {
                        if (LogAdapter.IsWarningEnabled)
                        {
                            LogAdapter.LogWarn(LogSource, "Starting Recovery. Waiting for connection clean up");
                        }

                        await pthis.AwaitConnectionReset();

                        if (LogAdapter.IsWarningEnabled)
                        {
                            LogAdapter.LogWarn(LogSource, "Connection is ready");
                        }

                        pthis.FireWillRecover();

                        pthis.ResetConnection();

                        var didConnect = await pthis.CycleReconnect().ConfigureAwait(false);
                        if (!didConnect)
                        {
                            // Cancelled
                            pthis.FireRecoveryFailed(new Exception("Could not connect to any host"));
                            return;
                        }

                        if (LogAdapter.IsWarningEnabled)
                        {
                            LogAdapter.LogWarn(LogSource, "Reconnected");
                        }

                        await pthis.Recover().ConfigureAwait(false);

                        pthis.FireRecoveryCompleted();

                        if (LogAdapter.IsWarningEnabled)
                        {
                            LogAdapter.LogWarn(LogSource, "Completed");
                        }
                    }
                    catch (Exception ex)
                    {
                        if (LogAdapter.IsWarningEnabled)
                        {
                            LogAdapter.LogWarn(LogSource, "TryInitiateRecovery error", ex);
                        }

                        pthis.HandleRecoveryFatalError(ex);

                        pthis.FireRecoveryFailed(ex);
                    }
                    finally
                    {
                        Interlocked.Exchange(ref pthis._inRecovery, 0);
                    }
                }, "RecoveryProc", this);
            }
            else
            {
                if (LogAdapter.IsDebugEnabled)
                {
                    LogAdapter.LogDebug(LogSource, "TryInitiateRecovery: recovery in progress. skipping");
                }
            }
        }