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"); }
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)"); }
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); }
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"); } } }