コード例 #1
0
        public async Task TestMap()
        {
            IEventLoopGroup group = new MultithreadEventLoopGroup();
            LocalAddress    addr  = new LocalAddress(ChannelPoolTestUtils.GetLocalAddrId());

            // Start server
            IChannel sc = await StartServerBootstrapAsync(group, addr);

            Bootstrap cb = new Bootstrap();

            cb.RemoteAddress(addr);
            cb.Group(group).Channel <LocalChannel>();
            var poolMap = new TestChannelPoolMap0(cb);

            IEventLoop loop = group.GetNext();

            Assert.True(poolMap.IsEmpty);
            Assert.Equal(0, poolMap.Count);

            SimpleChannelPool pool = poolMap.Get(loop);

            Assert.Equal(1, poolMap.Count);

            Assert.Same(pool, poolMap.Get(loop));
            Assert.True(poolMap.Remove(loop));
            Assert.False(poolMap.Remove(loop));

            Assert.Equal(0, poolMap.Count);

            await pool.AcquireAsync();

            poolMap.Close();

            await sc.CloseAsync();
        }
コード例 #2
0
        public async Task TestDeadlockOnAcquire()
        {
            IEventLoop threadA1    = new SingleThreadEventLoop();
            Bootstrap  bootstrapA1 = new Bootstrap()
                                     .Channel <LocalChannel>().Group(threadA1).LocalAddress(new LocalAddress("A1"));
            IEventLoop threadA2    = new SingleThreadEventLoop();
            Bootstrap  bootstrapA2 = new Bootstrap()
                                     .Channel <LocalChannel>().Group(threadA2).LocalAddress(new LocalAddress("A2"));
            IEventLoop threadB1    = new SingleThreadEventLoop();
            Bootstrap  bootstrapB1 = new Bootstrap()
                                     .Channel <LocalChannel>().Group(threadB1).LocalAddress(new LocalAddress("B1"));
            IEventLoop threadB2    = new SingleThreadEventLoop();
            Bootstrap  bootstrapB2 = new Bootstrap()
                                     .Channel <LocalChannel>().Group(threadB2).LocalAddress(new LocalAddress("B2"));

            FixedChannelPool poolA1 = new FixedChannelPool(bootstrapA1, NoopHandler.Instance, 1);
            FixedChannelPool poolA2 = new FixedChannelPool(bootstrapB2, NoopHandler.Instance, 1);
            FixedChannelPool poolB1 = new FixedChannelPool(bootstrapB1, NoopHandler.Instance, 1);
            FixedChannelPool poolB2 = new FixedChannelPool(bootstrapA2, NoopHandler.Instance, 1);

            // Synchronize threads on these barriers to ensure order of execution, first wait until each thread is inside
            // the newPool callbak, then hold the two threads that should lose the match until the first two returns, then
            // release them to test if they deadlock when trying to release their pools on each other's threads.
            Barrier arrivalBarrier = new Barrier(4);
            Barrier releaseBarrier = new Barrier(3);

            var channelPoolMap = new TestChannelPoolMap0(
                threadA1, threadA2, threadB1, threadB2,
                poolA1, poolA2, poolB1, poolB2, arrivalBarrier, releaseBarrier);

            // Thread A1 calls ChannelPoolMap.get(A)
            // Thread A2 calls ChannelPoolMap.get(A)
            // Thread B1 calls ChannelPoolMap.get(B)
            // Thread B2 calls ChannelPoolMap.get(B)

            var futureA1 = threadA1.SubmitAsync(() =>
            {
                return(channelPoolMap.Get("A"));
            });

            var futureA2 = threadA2.SubmitAsync(() =>
            {
                return(channelPoolMap.Get("A"));
            });

            var futureB1 = threadB1.SubmitAsync(() =>
            {
                return(channelPoolMap.Get("B"));
            });

            var futureB2 = threadB2.SubmitAsync(() =>
            {
                return(channelPoolMap.Get("B"));
            });

            // Thread A1 succeeds on updating the map and moves on
            // Thread B1 succeeds on updating the map and moves on
            // These should always succeed and return with new pools
            try
            {
                var result = await TaskUtil.WaitAsync(futureA1, TimeSpan.FromSeconds(1));

                if (!result || !futureA1.IsSuccess())
                {
                    throw new TimeoutException();
                }
                Assert.Same(poolA1, futureA1.Result);

                result = await TaskUtil.WaitAsync(futureB1, TimeSpan.FromSeconds(1));

                if (!result || !futureB1.IsSuccess())
                {
                    throw new TimeoutException();
                }
                Assert.Same(poolB1, futureB1.Result);
            }
            catch (Exception e)
            {
                Shutdown(threadA1, threadA2, threadB1, threadB2);
                throw e;
            }

            // Now release the other two threads which at this point lost the race and will try to clean up the acquired
            // pools. The expected scenario is that both pools close, in case of a deadlock they will hang.
            if (!releaseBarrier.SignalAndWait(TimeSpan.FromSeconds(1)))
            {
                Assert.False(true);
            }

            // Thread A2 fails to update the map and submits close to thread B2
            // Thread B2 fails to update the map and submits close to thread A2
            // If the close is blocking, then these calls will time out as the threads are waiting for each other
            // If the close is not blocking, then the previously created pools will be returned
            try
            {
                var result = await TaskUtil.WaitAsync(futureA2, TimeSpan.FromSeconds(1));

                if (!result || !futureA2.IsSuccess())
                {
                    throw new TimeoutException();
                }
                Assert.Same(poolA1, futureA2.Result);

                result = await TaskUtil.WaitAsync(futureB2, TimeSpan.FromSeconds(1));

                if (!result || !futureB2.IsSuccess())
                {
                    throw new TimeoutException();
                }
                Assert.Same(poolB1, futureB2.Result);
            }
            catch (TimeoutException)
            {
                Assert.False(true); // Fail the test on timeout to distinguish from other errors
                throw;
            }
            finally
            {
                poolA1.Close();
                poolA2.Close();
                poolB1.Close();
                poolB2.Close();
                channelPoolMap.Close();
                Shutdown(threadA1, threadA2, threadB1, threadB2);
            }
        }